ui: degradado de cabeceras y ajustes responsive
This commit is contained in:
parent
f4c885031b
commit
d209959d0e
|
|
@ -72,7 +72,17 @@
|
||||||
|
|
||||||
--sidebar-border: 220 13% 91%;
|
--sidebar-border: 220 13% 91%;
|
||||||
|
|
||||||
--sidebar-ring: 217.2 91.2% 59.8%}
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
|
|
||||||
|
--header-gradient: linear-gradient(
|
||||||
|
120deg,
|
||||||
|
hsl(220 95% 94% / 0.95) 0%,
|
||||||
|
hsl(232 95% 95% / 0.92) 22%,
|
||||||
|
hsl(246 95% 96% / 0.9) 48%,
|
||||||
|
hsl(260 95% 95% / 0.88) 72%,
|
||||||
|
hsl(214 95% 94% / 0.95) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
.dark {
|
.dark {
|
||||||
|
|
||||||
--background: 0 0% 3.9%;
|
--background: 0 0% 3.9%;
|
||||||
|
|
@ -138,7 +148,17 @@
|
||||||
|
|
||||||
--sidebar-border: 240 3.7% 15.9%;
|
--sidebar-border: 240 3.7% 15.9%;
|
||||||
|
|
||||||
--sidebar-ring: 217.2 91.2% 59.8%}
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
|
|
||||||
|
--header-gradient: linear-gradient(
|
||||||
|
120deg,
|
||||||
|
hsl(220 45% 12% / 0.9) 0%,
|
||||||
|
hsl(232 45% 14% / 0.88) 22%,
|
||||||
|
hsl(246 45% 15% / 0.86) 48%,
|
||||||
|
hsl(260 45% 14% / 0.86) 72%,
|
||||||
|
hsl(214 45% 12% / 0.9) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -182,3 +202,11 @@
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.header-gradient {
|
||||||
|
background-image: var(--header-gradient);
|
||||||
|
background-size: 200% 200%;
|
||||||
|
background-position: 50% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,23 @@ import { ProjectsTable } from "@/components/projects/projects-table";
|
||||||
|
|
||||||
export default function ProjectsPage() {
|
export default function ProjectsPage() {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-6 p-6">
|
<div className="flex min-w-0 flex-col gap-6">
|
||||||
{/* Header */}
|
<header className="header-gradient border-b px-6 py-6">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FolderKanban className="h-6 w-6 text-primary" />
|
<FolderKanban className="h-6 w-6 text-primary" />
|
||||||
<h1 className="text-2xl font-bold tracking-tight">Proyectos</h1>
|
<h1 className="text-2xl font-bold tracking-tight">Proyectos</h1>
|
||||||
|
</div>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
Gestiona y visualiza todos tus proyectos en un solo lugar.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-muted-foreground">
|
</header>
|
||||||
Gestiona y visualiza todos tus proyectos en un solo lugar.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Data Table */}
|
{/* Data Table */}
|
||||||
<ProjectsTable />
|
<div className="p-6">
|
||||||
|
<ProjectsTable />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export default function DashboardHeader({
|
||||||
onCreateProject
|
onCreateProject
|
||||||
}: DashboardHeaderProps) {
|
}: DashboardHeaderProps) {
|
||||||
return (
|
return (
|
||||||
<header className="bg-card border-b">
|
<header className="header-gradient border-b">
|
||||||
<div className="px-4 sm:px-6 lg:px-8 py-4">
|
<div className="px-4 sm:px-6 lg:px-8 py-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -62,4 +62,4 @@ export default function DashboardHeader({
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ export default function GanttPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<section className="border-b bg-gradient-to-r from-blue-50/70 via-background to-violet-50/70 dark:from-blue-950/25 dark:via-background dark:to-violet-950/25">
|
<section className="border-b header-gradient">
|
||||||
<div className="px-4 sm:px-6 lg:px-8 py-5 space-y-4">
|
<div className="px-4 sm:px-6 lg:px-8 py-5 space-y-4">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,11 @@ export function MainLayout({ children }: MainLayoutProps) {
|
||||||
<AppSidebar />
|
<AppSidebar />
|
||||||
<SidebarInset>
|
<SidebarInset>
|
||||||
<main>
|
<main>
|
||||||
<SidebarTrigger />
|
<div className="header-gradient border-b">
|
||||||
|
<div className="flex items-center px-4 py-2">
|
||||||
|
<SidebarTrigger />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
</SidebarInset>
|
</SidebarInset>
|
||||||
|
|
|
||||||
|
|
@ -185,13 +185,13 @@ export function ProjectDetailView({ project: initialProject }: ProjectDetailView
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Contenido principal */}
|
{/* Contenido principal */}
|
||||||
<div className="p-6 space-y-6">
|
<div className="min-w-0 p-6 space-y-6">
|
||||||
{/* Stats cards */}
|
{/* Stats cards */}
|
||||||
<ProjectStats project={project} taskStats={taskStats} />
|
<ProjectStats project={project} taskStats={taskStats} />
|
||||||
|
|
||||||
{/* Tabs de contenido */}
|
{/* Tabs de contenido */}
|
||||||
<Tabs defaultValue="overview" className="space-y-6">
|
<Tabs defaultValue="overview" className="space-y-6">
|
||||||
<TabsList>
|
<TabsList className="flex flex-wrap items-center gap-1">
|
||||||
<TabsTrigger value="overview" className="gap-2">
|
<TabsTrigger value="overview" className="gap-2">
|
||||||
<LayoutDashboard className="h-4 w-4" />
|
<LayoutDashboard className="h-4 w-4" />
|
||||||
Resumen
|
Resumen
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ export function ProjectHeader({ project, tasks = [], onProjectUpdated, onProject
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-b bg-card">
|
<div className="border-b header-gradient">
|
||||||
<div className="px-6 py-4">
|
<div className="px-6 py-4">
|
||||||
{/* Navegación */}
|
{/* Navegación */}
|
||||||
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-4">
|
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-4">
|
||||||
|
|
@ -84,8 +84,8 @@ export function ProjectHeader({ project, tasks = [], onProjectUpdated, onProject
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Header principal */}
|
{/* Header principal */}
|
||||||
<div className="flex items-start justify-between gap-4">
|
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
||||||
<div className="flex items-start gap-4">
|
<div className="flex min-w-0 items-start gap-4">
|
||||||
{/* Avatar */}
|
{/* Avatar */}
|
||||||
<Avatar className="h-16 w-16 shrink-0">
|
<Avatar className="h-16 w-16 shrink-0">
|
||||||
<AvatarFallback className="bg-gradient-to-br from-blue-500 to-purple-600 text-white font-semibold text-xl">
|
<AvatarFallback className="bg-gradient-to-br from-blue-500 to-purple-600 text-white font-semibold text-xl">
|
||||||
|
|
@ -94,13 +94,15 @@ export function ProjectHeader({ project, tasks = [], onProjectUpdated, onProject
|
||||||
</Avatar>
|
</Avatar>
|
||||||
|
|
||||||
{/* Info principal */}
|
{/* Info principal */}
|
||||||
<div className="space-y-1">
|
<div className="min-w-0 space-y-1">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex flex-wrap items-center gap-3">
|
||||||
<h1 className="text-2xl font-bold tracking-tight">{project.name}</h1>
|
<h1 className="text-2xl font-bold tracking-tight break-words">
|
||||||
|
{project.name}
|
||||||
|
</h1>
|
||||||
<ProjectStatusBadge status={project.status} className="text-sm px-3 py-1" />
|
<ProjectStatusBadge status={project.status} className="text-sm px-3 py-1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
<div className="flex flex-wrap items-center gap-3 text-sm text-muted-foreground">
|
||||||
<button
|
<button
|
||||||
onClick={handleCopyRef}
|
onClick={handleCopyRef}
|
||||||
className="flex items-center gap-1.5 hover:text-foreground transition-colors font-mono"
|
className="flex items-center gap-1.5 hover:text-foreground transition-colors font-mono"
|
||||||
|
|
@ -109,19 +111,16 @@ export function ProjectHeader({ project, tasks = [], onProjectUpdated, onProject
|
||||||
{project.ref}
|
{project.ref}
|
||||||
<Copy className="h-3.5 w-3.5" />
|
<Copy className="h-3.5 w-3.5" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{project.client !== "Sin cliente" && (
|
{project.client !== "Sin cliente" && (
|
||||||
<>
|
<span>{project.client}</span>
|
||||||
<span className="text-muted-foreground/50">|</span>
|
|
||||||
<span>{project.client}</span>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Acciones */}
|
{/* Acciones */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<Button variant="outline" size="sm" onClick={handleExportPDF}>
|
<Button variant="outline" size="sm" onClick={handleExportPDF}>
|
||||||
<Download className="h-4 w-4 mr-2" />
|
<Download className="h-4 w-4 mr-2" />
|
||||||
Exportar PDF
|
Exportar PDF
|
||||||
|
|
|
||||||
|
|
@ -195,8 +195,9 @@ export function ProjectTaskGantt({ tasks }: ProjectTaskGanttProps) {
|
||||||
|
|
||||||
const maxTimelineWidth = Math.max(320, fitTimelineWidth);
|
const maxTimelineWidth = Math.max(320, fitTimelineWidth);
|
||||||
const baseTickWidth = zoom === "fit" ? 72 : zoom === "week" ? 84 : 36;
|
const baseTickWidth = zoom === "fit" ? 72 : zoom === "week" ? 84 : 36;
|
||||||
const tickWidth = Math.min(baseTickWidth, maxTimelineWidth / Math.max(1, ticks.length));
|
const rawTimelineWidth = ticks.length * baseTickWidth;
|
||||||
const timelineWidth = Math.max(320, ticks.length * tickWidth);
|
const timelineWidth = Math.max(320, Math.min(maxTimelineWidth, rawTimelineWidth));
|
||||||
|
const tickWidth = timelineWidth / Math.max(1, ticks.length);
|
||||||
|
|
||||||
const today = startOfDay(new Date());
|
const today = startOfDay(new Date());
|
||||||
const showToday = today >= visibleStart && today <= visibleEnd;
|
const showToday = today >= visibleStart && today <= visibleEnd;
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ export function TasksSection({ tasks, projectId, isLoading, onTaskCreated, onTas
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="min-w-0 space-y-4">
|
||||||
{/* Stats rápidos */}
|
{/* Stats rápidos */}
|
||||||
<div className="flex flex-wrap items-center gap-4 text-sm">
|
<div className="flex flex-wrap items-center gap-4 text-sm">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|
@ -282,10 +282,10 @@ export function TasksSection({ tasks, projectId, isLoading, onTaskCreated, onTas
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Toolbar */}
|
{/* Toolbar */}
|
||||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-4 xl:flex-row xl:items-center xl:justify-between">
|
||||||
<div className="flex flex-1 items-center gap-2">
|
<div className="flex flex-1 flex-wrap items-center gap-2">
|
||||||
{/* Búsqueda */}
|
{/* Búsqueda */}
|
||||||
<div className="relative w-full sm:w-[250px]">
|
<div className="relative w-full sm:w-[240px]">
|
||||||
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="Buscar tareas..."
|
placeholder="Buscar tareas..."
|
||||||
|
|
@ -297,7 +297,7 @@ export function TasksSection({ tasks, projectId, isLoading, onTaskCreated, onTas
|
||||||
|
|
||||||
{/* Filtro estado */}
|
{/* Filtro estado */}
|
||||||
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||||
<SelectTrigger className="w-[130px] h-9">
|
<SelectTrigger className="w-full sm:w-[130px] h-9">
|
||||||
<SelectValue placeholder="Estado" />
|
<SelectValue placeholder="Estado" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
|
@ -310,7 +310,7 @@ export function TasksSection({ tasks, projectId, isLoading, onTaskCreated, onTas
|
||||||
|
|
||||||
{/* Filtro prioridad */}
|
{/* Filtro prioridad */}
|
||||||
<Select value={priorityFilter} onValueChange={setPriorityFilter}>
|
<Select value={priorityFilter} onValueChange={setPriorityFilter}>
|
||||||
<SelectTrigger className="w-[130px] h-9">
|
<SelectTrigger className="w-full sm:w-[130px] h-9">
|
||||||
<SelectValue placeholder="Prioridad" />
|
<SelectValue placeholder="Prioridad" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
|
@ -331,7 +331,7 @@ export function TasksSection({ tasks, projectId, isLoading, onTaskCreated, onTas
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
{/* Toggle vista */}
|
{/* Toggle vista */}
|
||||||
<div className="flex items-center border rounded-md">
|
<div className="flex items-center border rounded-md">
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -76,10 +76,10 @@ export function DataTableToolbar({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-4 xl:flex-row xl:items-center xl:justify-between">
|
||||||
<div className="flex flex-1 items-center gap-2">
|
<div className="flex flex-1 flex-wrap items-center gap-2">
|
||||||
{/* Búsqueda */}
|
{/* Búsqueda */}
|
||||||
<div className="relative w-full sm:w-[300px]">
|
<div className="relative w-full sm:w-[260px]">
|
||||||
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="Buscar proyectos..."
|
placeholder="Buscar proyectos..."
|
||||||
|
|
@ -91,7 +91,7 @@ export function DataTableToolbar({
|
||||||
|
|
||||||
{/* Filtro por estado */}
|
{/* Filtro por estado */}
|
||||||
<Select value={statusFilter} onValueChange={onStatusFilterChange}>
|
<Select value={statusFilter} onValueChange={onStatusFilterChange}>
|
||||||
<SelectTrigger className="w-[150px]">
|
<SelectTrigger className="w-full sm:w-[150px]">
|
||||||
<SelectValue placeholder="Estado" />
|
<SelectValue placeholder="Estado" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
|
@ -119,7 +119,7 @@ export function DataTableToolbar({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
{/* Contador de seleccionados */}
|
{/* Contador de seleccionados */}
|
||||||
{selectedCount > 0 && (
|
{selectedCount > 0 && (
|
||||||
<Badge variant="secondary" className="rounded-sm px-2 font-normal">
|
<Badge variant="secondary" className="rounded-sm px-2 font-normal">
|
||||||
|
|
@ -136,7 +136,7 @@ export function DataTableToolbar({
|
||||||
Vista
|
Vista
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="w-[180px]">
|
<DropdownMenuContent align="end" className="w-[200px]">
|
||||||
<DropdownMenuLabel>Columnas visibles</DropdownMenuLabel>
|
<DropdownMenuLabel>Columnas visibles</DropdownMenuLabel>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
{columns
|
{columns
|
||||||
|
|
@ -158,9 +158,9 @@ export function DataTableToolbar({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Exportar */}
|
{/* Exportar */}
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-9"
|
className="h-9"
|
||||||
onClick={handleExport}
|
onClick={handleExport}
|
||||||
disabled={!onExport}
|
disabled={!onExport}
|
||||||
|
|
|
||||||
|
|
@ -120,9 +120,9 @@ export function DataTable<TData, TValue>({
|
||||||
}, [searchKey, searchValue, table]);
|
}, [searchKey, searchValue, table]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="min-w-0 space-y-4">
|
||||||
{/* Tabla */}
|
{/* Tabla */}
|
||||||
<div className="rounded-md border">
|
<div className="min-w-0 rounded-md border">
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ export function ProjectsTable() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
||||||
<DataTableToolbar
|
<DataTableToolbar
|
||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
onSearchChange={setSearchValue}
|
onSearchChange={setSearchValue}
|
||||||
|
|
@ -193,7 +193,7 @@ export function ProjectsTable() {
|
||||||
getSelectedProjects={tableInfo?.getSelectedRows}
|
getSelectedProjects={tableInfo?.getSelectedRows}
|
||||||
getAllVisibleProjects={tableInfo?.getAllVisibleRows}
|
getAllVisibleProjects={tableInfo?.getAllVisibleRows}
|
||||||
/>
|
/>
|
||||||
<Button onClick={() => setIsCreateSheetOpen(true)} size="sm">
|
<Button onClick={() => setIsCreateSheetOpen(true)} size="sm" className="shrink-0">
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
Nuevo proyecto
|
Nuevo proyecto
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1058,7 +1058,7 @@ export default function StatisticsPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<header className="bg-card border-b sticky top-0 z-10">
|
<header className="header-gradient border-b sticky top-0 z-10">
|
||||||
<div className="px-6 py-6">
|
<div className="px-6 py-6">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-2 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg">
|
<div className="p-2 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg">
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ export function TaskHeader({ task, project, onTaskUpdated, onTaskDeleted }: Task
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-b bg-card">
|
<div className="border-b header-gradient">
|
||||||
<div className="px-6 py-4">
|
<div className="px-6 py-4">
|
||||||
{/* Breadcrumb */}
|
{/* Breadcrumb */}
|
||||||
<nav className="flex items-center gap-2 text-sm text-muted-foreground mb-4">
|
<nav className="flex items-center gap-2 text-sm text-muted-foreground mb-4">
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,17 @@ const AUTH_USER_KEY = "dolibarr_auth_user";
|
||||||
* Obtiene la URL base de la API de Dolibarr
|
* Obtiene la URL base de la API de Dolibarr
|
||||||
*/
|
*/
|
||||||
function getApiUrl(): string {
|
function getApiUrl(): string {
|
||||||
// Intentar obtener del entorno (cliente usa NEXT_PUBLIC_)
|
// En cliente, usar proxy para evitar problemas de red/CORS
|
||||||
const url = typeof window !== "undefined"
|
if (typeof window !== "undefined") {
|
||||||
? process.env.NEXT_PUBLIC_API_URL
|
return "/api/dolibarr";
|
||||||
: process.env.DOLIBARR_API_URL || process.env.NEXT_PUBLIC_API_URL;
|
}
|
||||||
|
|
||||||
|
const url = process.env.DOLIBARR_API_URL || process.env.NEXT_PUBLIC_API_URL;
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
throw new Error("API URL not configured");
|
throw new Error("API URL not configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue