@create-lft-app/cli 1.0.14 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +150 -171
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/index.js +148 -169
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/app/auth/login/page.tsx +0 -153
- package/templates/app/dashboard/page.tsx +0 -102
- package/templates/app/globals.css +0 -249
- package/templates/app/layout.tsx +0 -40
- package/templates/app/page.tsx +0 -5
- package/templates/components/dashboard/widget.tsx +0 -113
- package/templates/components/layout/admin-midday-sidebar.tsx +0 -247
- package/templates/components/layout/admin-sidebar.tsx +0 -146
- package/templates/components/layout/header.tsx +0 -71
- package/templates/components/layout/main-content.tsx +0 -28
- package/templates/components/layout/midday-sidebar.tsx +0 -381
- package/templates/components/layout/nav-user.tsx +0 -108
- package/templates/components/layout/page-header.tsx +0 -95
- package/templates/components/layout/sidebar-context.tsx +0 -33
- package/templates/components/layout/sidebar.tsx +0 -194
- package/templates/components/layout/suspension-banner.tsx +0 -21
- package/templates/components/ui/accordion.tsx +0 -58
- package/templates/components/ui/alert-dialog.tsx +0 -165
- package/templates/components/ui/alert.tsx +0 -66
- package/templates/components/ui/avatar.tsx +0 -55
- package/templates/components/ui/badge.tsx +0 -50
- package/templates/components/ui/button.tsx +0 -89
- package/templates/components/ui/calendar.tsx +0 -220
- package/templates/components/ui/card.tsx +0 -89
- package/templates/components/ui/checkbox.tsx +0 -38
- package/templates/components/ui/collapsible.tsx +0 -33
- package/templates/components/ui/command.tsx +0 -196
- package/templates/components/ui/dialog.tsx +0 -153
- package/templates/components/ui/dropdown-menu.tsx +0 -280
- package/templates/components/ui/form.tsx +0 -171
- package/templates/components/ui/icons.tsx +0 -167
- package/templates/components/ui/input.tsx +0 -28
- package/templates/components/ui/label.tsx +0 -25
- package/templates/components/ui/popover.tsx +0 -59
- package/templates/components/ui/progress.tsx +0 -32
- package/templates/components/ui/radio-group.tsx +0 -45
- package/templates/components/ui/scroll-area.tsx +0 -63
- package/templates/components/ui/select.tsx +0 -208
- package/templates/components/ui/separator.tsx +0 -28
- package/templates/components/ui/sheet.tsx +0 -146
- package/templates/components/ui/sidebar.tsx +0 -726
- package/templates/components/ui/skeleton.tsx +0 -15
- package/templates/components/ui/slider.tsx +0 -58
- package/templates/components/ui/sonner.tsx +0 -47
- package/templates/components/ui/spinner.tsx +0 -27
- package/templates/components/ui/submit-button.tsx +0 -47
- package/templates/components/ui/switch.tsx +0 -31
- package/templates/components/ui/table.tsx +0 -120
- package/templates/components/ui/tabs.tsx +0 -75
- package/templates/components/ui/textarea.tsx +0 -26
- package/templates/components/ui/tooltip.tsx +0 -70
- package/templates/hooks/use-mobile.ts +0 -21
- package/templates/lib/supabase/client.ts +0 -8
- package/templates/lib/supabase/server.ts +0 -29
- package/templates/lib/utils.ts +0 -6
- package/templates/modules/auth/actions/auth-actions.ts +0 -12
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import Link from 'next/link'
|
|
4
|
-
import { usePathname } from 'next/navigation'
|
|
5
|
-
import {
|
|
6
|
-
LayoutDashboard,
|
|
7
|
-
Building2,
|
|
8
|
-
Users,
|
|
9
|
-
CreditCard,
|
|
10
|
-
Settings,
|
|
11
|
-
Shield,
|
|
12
|
-
Clock,
|
|
13
|
-
} from 'lucide-react'
|
|
14
|
-
import {
|
|
15
|
-
Sidebar,
|
|
16
|
-
SidebarContent,
|
|
17
|
-
SidebarGroup,
|
|
18
|
-
SidebarGroupContent,
|
|
19
|
-
SidebarGroupLabel,
|
|
20
|
-
SidebarMenu,
|
|
21
|
-
SidebarMenuButton,
|
|
22
|
-
SidebarMenuItem,
|
|
23
|
-
SidebarHeader,
|
|
24
|
-
SidebarFooter,
|
|
25
|
-
} from '@/components/ui/sidebar'
|
|
26
|
-
import { NavUser } from './nav-user'
|
|
27
|
-
|
|
28
|
-
const adminNavItems = [
|
|
29
|
-
{
|
|
30
|
-
title: 'Dashboard',
|
|
31
|
-
url: '/admin',
|
|
32
|
-
icon: LayoutDashboard,
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
title: 'Organizaciones',
|
|
36
|
-
url: '/admin/organizations',
|
|
37
|
-
icon: Building2,
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
title: 'Usuarios',
|
|
41
|
-
url: '/admin/users',
|
|
42
|
-
icon: Users,
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
title: 'Suscripciones',
|
|
46
|
-
url: '/admin/subscriptions',
|
|
47
|
-
icon: CreditCard,
|
|
48
|
-
},
|
|
49
|
-
]
|
|
50
|
-
|
|
51
|
-
const systemNavItems = [
|
|
52
|
-
{
|
|
53
|
-
title: 'Jobs',
|
|
54
|
-
url: '/admin/jobs',
|
|
55
|
-
icon: Clock,
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
title: 'Configuración',
|
|
59
|
-
url: '/admin/settings',
|
|
60
|
-
icon: Settings,
|
|
61
|
-
},
|
|
62
|
-
]
|
|
63
|
-
|
|
64
|
-
interface AdminSidebarProps {
|
|
65
|
-
user: {
|
|
66
|
-
email: string
|
|
67
|
-
full_name: string | null
|
|
68
|
-
role: string
|
|
69
|
-
} | null
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function AdminSidebar({ user }: AdminSidebarProps) {
|
|
73
|
-
const pathname = usePathname()
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<Sidebar>
|
|
77
|
-
<SidebarHeader className="border-b border-sidebar-border">
|
|
78
|
-
<div className="flex items-center gap-2 px-4 py-3">
|
|
79
|
-
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-destructive text-destructive-foreground font-bold">
|
|
80
|
-
<Shield className="h-4 w-4" />
|
|
81
|
-
</div>
|
|
82
|
-
<div className="flex flex-col">
|
|
83
|
-
<span className="text-sm font-semibold">
|
|
84
|
-
{user?.full_name?.split(' ')[0] || 'Admin'}
|
|
85
|
-
</span>
|
|
86
|
-
<span className="text-xs text-muted-foreground">
|
|
87
|
-
Super Admin
|
|
88
|
-
</span>
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
</SidebarHeader>
|
|
92
|
-
|
|
93
|
-
<SidebarContent>
|
|
94
|
-
<SidebarGroup>
|
|
95
|
-
<SidebarGroupLabel>Gestión</SidebarGroupLabel>
|
|
96
|
-
<SidebarGroupContent>
|
|
97
|
-
<SidebarMenu>
|
|
98
|
-
{adminNavItems.map((item) => (
|
|
99
|
-
<SidebarMenuItem key={item.title}>
|
|
100
|
-
<SidebarMenuButton
|
|
101
|
-
asChild
|
|
102
|
-
isActive={
|
|
103
|
-
item.url === '/admin'
|
|
104
|
-
? pathname === '/admin'
|
|
105
|
-
: pathname.startsWith(item.url)
|
|
106
|
-
}
|
|
107
|
-
>
|
|
108
|
-
<Link href={item.url}>
|
|
109
|
-
<item.icon className="h-4 w-4" />
|
|
110
|
-
<span>{item.title}</span>
|
|
111
|
-
</Link>
|
|
112
|
-
</SidebarMenuButton>
|
|
113
|
-
</SidebarMenuItem>
|
|
114
|
-
))}
|
|
115
|
-
</SidebarMenu>
|
|
116
|
-
</SidebarGroupContent>
|
|
117
|
-
</SidebarGroup>
|
|
118
|
-
|
|
119
|
-
<SidebarGroup>
|
|
120
|
-
<SidebarGroupLabel>Sistema</SidebarGroupLabel>
|
|
121
|
-
<SidebarGroupContent>
|
|
122
|
-
<SidebarMenu>
|
|
123
|
-
{systemNavItems.map((item) => (
|
|
124
|
-
<SidebarMenuItem key={item.title}>
|
|
125
|
-
<SidebarMenuButton
|
|
126
|
-
asChild
|
|
127
|
-
isActive={pathname.startsWith(item.url)}
|
|
128
|
-
>
|
|
129
|
-
<Link href={item.url}>
|
|
130
|
-
<item.icon className="h-4 w-4" />
|
|
131
|
-
<span>{item.title}</span>
|
|
132
|
-
</Link>
|
|
133
|
-
</SidebarMenuButton>
|
|
134
|
-
</SidebarMenuItem>
|
|
135
|
-
))}
|
|
136
|
-
</SidebarMenu>
|
|
137
|
-
</SidebarGroupContent>
|
|
138
|
-
</SidebarGroup>
|
|
139
|
-
</SidebarContent>
|
|
140
|
-
|
|
141
|
-
<SidebarFooter className="border-t border-sidebar-border">
|
|
142
|
-
<NavUser user={user} />
|
|
143
|
-
</SidebarFooter>
|
|
144
|
-
</Sidebar>
|
|
145
|
-
)
|
|
146
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Bell } from 'lucide-react'
|
|
4
|
-
import { Button } from '@/components/ui/button'
|
|
5
|
-
import { SidebarTrigger } from '@/components/ui/sidebar'
|
|
6
|
-
import { Separator } from '@/components/ui/separator'
|
|
7
|
-
import {
|
|
8
|
-
DropdownMenu,
|
|
9
|
-
DropdownMenuContent,
|
|
10
|
-
DropdownMenuItem,
|
|
11
|
-
DropdownMenuLabel,
|
|
12
|
-
DropdownMenuSeparator,
|
|
13
|
-
DropdownMenuTrigger,
|
|
14
|
-
} from '@/components/ui/dropdown-menu'
|
|
15
|
-
import { Badge } from '@/components/ui/badge'
|
|
16
|
-
|
|
17
|
-
interface HeaderProps {
|
|
18
|
-
title?: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function Header({ title }: HeaderProps) {
|
|
22
|
-
return (
|
|
23
|
-
<header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
|
|
24
|
-
<SidebarTrigger className="-ml-1" />
|
|
25
|
-
<Separator orientation="vertical" className="mr-2 h-4" />
|
|
26
|
-
{title && <h1 className="text-lg font-semibold">{title}</h1>}
|
|
27
|
-
|
|
28
|
-
<div className="ml-auto flex items-center gap-2">
|
|
29
|
-
<DropdownMenu>
|
|
30
|
-
<DropdownMenuTrigger asChild>
|
|
31
|
-
<Button variant="ghost" size="icon" className="relative">
|
|
32
|
-
<Bell className="h-5 w-5" />
|
|
33
|
-
<Badge
|
|
34
|
-
variant="destructive"
|
|
35
|
-
className="absolute -right-1 -top-1 h-5 w-5 rounded-full p-0 text-xs flex items-center justify-center"
|
|
36
|
-
>
|
|
37
|
-
3
|
|
38
|
-
</Badge>
|
|
39
|
-
</Button>
|
|
40
|
-
</DropdownMenuTrigger>
|
|
41
|
-
<DropdownMenuContent align="end" className="w-80">
|
|
42
|
-
<DropdownMenuLabel>Notificaciones</DropdownMenuLabel>
|
|
43
|
-
<DropdownMenuSeparator />
|
|
44
|
-
<DropdownMenuItem className="flex flex-col items-start gap-1 cursor-pointer">
|
|
45
|
-
<span className="font-medium">Documento por vencer</span>
|
|
46
|
-
<span className="text-xs text-muted-foreground">
|
|
47
|
-
Balance de Empresa ABC S.A. vence en 7 días
|
|
48
|
-
</span>
|
|
49
|
-
</DropdownMenuItem>
|
|
50
|
-
<DropdownMenuItem className="flex flex-col items-start gap-1 cursor-pointer">
|
|
51
|
-
<span className="font-medium">Nueva alerta BCRA</span>
|
|
52
|
-
<span className="text-xs text-muted-foreground">
|
|
53
|
-
Se detectó deuda en situación 3 para cliente
|
|
54
|
-
</span>
|
|
55
|
-
</DropdownMenuItem>
|
|
56
|
-
<DropdownMenuItem className="flex flex-col items-start gap-1 cursor-pointer">
|
|
57
|
-
<span className="font-medium">Cliente pendiente</span>
|
|
58
|
-
<span className="text-xs text-muted-foreground">
|
|
59
|
-
Juan Pérez está esperando aprobación
|
|
60
|
-
</span>
|
|
61
|
-
</DropdownMenuItem>
|
|
62
|
-
<DropdownMenuSeparator />
|
|
63
|
-
<DropdownMenuItem className="text-center cursor-pointer">
|
|
64
|
-
<span className="text-sm text-primary">Ver todas</span>
|
|
65
|
-
</DropdownMenuItem>
|
|
66
|
-
</DropdownMenuContent>
|
|
67
|
-
</DropdownMenu>
|
|
68
|
-
</div>
|
|
69
|
-
</header>
|
|
70
|
-
)
|
|
71
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { cn } from '@/lib/utils'
|
|
4
|
-
import { useSidebar } from './sidebar-context'
|
|
5
|
-
import { ReactNode } from 'react'
|
|
6
|
-
|
|
7
|
-
interface MainContentProps {
|
|
8
|
-
children: ReactNode
|
|
9
|
-
className?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function MainContent({ children, className }: MainContentProps) {
|
|
13
|
-
const { isExpanded } = useSidebar()
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<main
|
|
17
|
-
className={cn(
|
|
18
|
-
'min-h-screen bg-background',
|
|
19
|
-
'transition-all duration-200 ease-[cubic-bezier(0.4,0,0.2,1)]',
|
|
20
|
-
isExpanded ? 'md:ml-[240px] md:w-[calc(100%-240px)]' : 'md:ml-[70px] md:w-[calc(100%-70px)]',
|
|
21
|
-
'w-full',
|
|
22
|
-
className
|
|
23
|
-
)}
|
|
24
|
-
>
|
|
25
|
-
{children}
|
|
26
|
-
</main>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import Link from 'next/link'
|
|
4
|
-
import { usePathname } from 'next/navigation'
|
|
5
|
-
import { useState, useRef, useCallback, useEffect } from 'react'
|
|
6
|
-
import { cn } from '@/lib/utils'
|
|
7
|
-
import { Icons } from '@/components/ui/icons'
|
|
8
|
-
import { useSidebar } from './sidebar-context'
|
|
9
|
-
import {
|
|
10
|
-
DropdownMenu,
|
|
11
|
-
DropdownMenuContent,
|
|
12
|
-
DropdownMenuItem,
|
|
13
|
-
DropdownMenuSeparator,
|
|
14
|
-
DropdownMenuTrigger,
|
|
15
|
-
} from '@/components/ui/dropdown-menu'
|
|
16
|
-
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
|
|
17
|
-
import { logoutAction } from '@/modules/auth/actions/auth-actions'
|
|
18
|
-
|
|
19
|
-
interface NavItem {
|
|
20
|
-
path: string
|
|
21
|
-
name: string
|
|
22
|
-
icon: keyof typeof Icons
|
|
23
|
-
children?: { path: string; name: string }[]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const mainNavItems: NavItem[] = [
|
|
27
|
-
{
|
|
28
|
-
path: '/dashboard',
|
|
29
|
-
name: 'Dashboard',
|
|
30
|
-
icon: 'Dashboard',
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
path: '/clientes',
|
|
34
|
-
name: 'Clientes',
|
|
35
|
-
icon: 'Users',
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
path: '/onboarding',
|
|
39
|
-
name: 'Onboarding',
|
|
40
|
-
icon: 'UserPlus',
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
path: '/documents',
|
|
44
|
-
name: 'Documentos',
|
|
45
|
-
icon: 'Documents',
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
path: '/alerts',
|
|
49
|
-
name: 'Alertas',
|
|
50
|
-
icon: 'Alert',
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
path: '/operations',
|
|
54
|
-
name: 'Operaciones',
|
|
55
|
-
icon: 'Operations',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
path: '/calendar',
|
|
59
|
-
name: 'Calendario',
|
|
60
|
-
icon: 'Calendar',
|
|
61
|
-
},
|
|
62
|
-
]
|
|
63
|
-
|
|
64
|
-
const getConfigNavItems = (isSuperAdmin: boolean): NavItem[] => [
|
|
65
|
-
{
|
|
66
|
-
path: '/settings',
|
|
67
|
-
name: 'Configuración',
|
|
68
|
-
icon: 'Settings',
|
|
69
|
-
children: [
|
|
70
|
-
{ path: '/settings', name: 'General' },
|
|
71
|
-
{ path: '/settings/organization', name: 'Organización' },
|
|
72
|
-
{ path: '/settings/documents', name: 'Documentos' },
|
|
73
|
-
{ path: '/settings/onboarding', name: 'Onboarding' },
|
|
74
|
-
{ path: '/settings/integrations', name: 'Integraciones' },
|
|
75
|
-
...(isSuperAdmin ? [{ path: '/admin', name: 'Super Admin' }] : []),
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
]
|
|
79
|
-
|
|
80
|
-
interface MiddaySidebarProps {
|
|
81
|
-
user: {
|
|
82
|
-
email: string
|
|
83
|
-
full_name: string | null
|
|
84
|
-
role: string
|
|
85
|
-
organization?: {
|
|
86
|
-
name: string
|
|
87
|
-
} | null
|
|
88
|
-
} | null
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function MenuItem({
|
|
92
|
-
item,
|
|
93
|
-
isExpanded,
|
|
94
|
-
pathname,
|
|
95
|
-
onNavigate,
|
|
96
|
-
}: {
|
|
97
|
-
item: NavItem
|
|
98
|
-
isExpanded: boolean
|
|
99
|
-
pathname: string
|
|
100
|
-
onNavigate?: () => void
|
|
101
|
-
}) {
|
|
102
|
-
const [isSubmenuOpen, setIsSubmenuOpen] = useState(false)
|
|
103
|
-
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
|
|
104
|
-
const IconComponent = Icons[item.icon]
|
|
105
|
-
|
|
106
|
-
const isExactMatch = pathname === item.path
|
|
107
|
-
const isChildMatch = item.children?.some(child => pathname === child.path)
|
|
108
|
-
const isActive = isExactMatch || isChildMatch
|
|
109
|
-
const hasChildren = item.children && item.children.length > 0
|
|
110
|
-
|
|
111
|
-
const handleMouseEnter = useCallback(() => {
|
|
112
|
-
if (timeoutRef.current) {
|
|
113
|
-
clearTimeout(timeoutRef.current)
|
|
114
|
-
}
|
|
115
|
-
if (hasChildren) {
|
|
116
|
-
setIsSubmenuOpen(true)
|
|
117
|
-
}
|
|
118
|
-
}, [hasChildren])
|
|
119
|
-
|
|
120
|
-
const handleMouseLeave = useCallback(() => {
|
|
121
|
-
timeoutRef.current = setTimeout(() => {
|
|
122
|
-
setIsSubmenuOpen(false)
|
|
123
|
-
}, 150)
|
|
124
|
-
}, [])
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<li
|
|
128
|
-
className="relative"
|
|
129
|
-
onMouseEnter={handleMouseEnter}
|
|
130
|
-
onMouseLeave={handleMouseLeave}
|
|
131
|
-
>
|
|
132
|
-
<Link
|
|
133
|
-
href={hasChildren && item.children ? item.children[0].path : item.path}
|
|
134
|
-
onClick={onNavigate}
|
|
135
|
-
className={cn(
|
|
136
|
-
'h-[40px] flex items-center gap-3',
|
|
137
|
-
'mx-[10px] px-[10px]',
|
|
138
|
-
'rounded-md',
|
|
139
|
-
'transition-all duration-150',
|
|
140
|
-
!isActive && 'hover:bg-[#f7f7f7] dark:hover:bg-[#1a1a1a]',
|
|
141
|
-
isActive && [
|
|
142
|
-
'bg-[#f7f7f7] dark:bg-[#131313]',
|
|
143
|
-
'border border-border',
|
|
144
|
-
]
|
|
145
|
-
)}
|
|
146
|
-
>
|
|
147
|
-
<div className="w-5 h-5 flex items-center justify-center flex-shrink-0">
|
|
148
|
-
<IconComponent
|
|
149
|
-
size={20}
|
|
150
|
-
className={cn(
|
|
151
|
-
'transition-colors',
|
|
152
|
-
isActive ? 'text-foreground' : 'text-[#878787]'
|
|
153
|
-
)}
|
|
154
|
-
/>
|
|
155
|
-
</div>
|
|
156
|
-
{isExpanded && (
|
|
157
|
-
<>
|
|
158
|
-
<span
|
|
159
|
-
className={cn(
|
|
160
|
-
'text-sm whitespace-nowrap',
|
|
161
|
-
'transition-all duration-150',
|
|
162
|
-
isActive ? 'font-medium text-foreground' : 'text-[#878787]'
|
|
163
|
-
)}
|
|
164
|
-
>
|
|
165
|
-
{item.name}
|
|
166
|
-
</span>
|
|
167
|
-
{hasChildren && (
|
|
168
|
-
<Icons.ChevronRight
|
|
169
|
-
size={14}
|
|
170
|
-
className={cn(
|
|
171
|
-
'ml-auto text-[#878787]',
|
|
172
|
-
'transition-transform duration-200',
|
|
173
|
-
isSubmenuOpen && 'rotate-90'
|
|
174
|
-
)}
|
|
175
|
-
/>
|
|
176
|
-
)}
|
|
177
|
-
</>
|
|
178
|
-
)}
|
|
179
|
-
</Link>
|
|
180
|
-
|
|
181
|
-
{/* Submenu - Midday style with staggered animation */}
|
|
182
|
-
{hasChildren && isExpanded && isSubmenuOpen && (
|
|
183
|
-
<ul className="mt-1 space-y-0.5">
|
|
184
|
-
{item.children?.map((child, index) => {
|
|
185
|
-
const isChildActive = pathname === child.path
|
|
186
|
-
return (
|
|
187
|
-
<li
|
|
188
|
-
key={child.path}
|
|
189
|
-
className="animate-in fade-in-0 slide-in-from-left-1"
|
|
190
|
-
style={{
|
|
191
|
-
animationDuration: '150ms',
|
|
192
|
-
animationDelay: `${40 + index * 20}ms`,
|
|
193
|
-
animationFillMode: 'backwards'
|
|
194
|
-
}}
|
|
195
|
-
>
|
|
196
|
-
<div className="ml-[35px] border-l border-[#e6e6e6] dark:border-[#2c2c2c]">
|
|
197
|
-
<Link
|
|
198
|
-
href={child.path}
|
|
199
|
-
onClick={onNavigate}
|
|
200
|
-
className={cn(
|
|
201
|
-
'block py-1.5 pl-3 pr-4',
|
|
202
|
-
'text-xs',
|
|
203
|
-
'transition-colors duration-150',
|
|
204
|
-
isChildActive
|
|
205
|
-
? 'text-foreground font-medium'
|
|
206
|
-
: 'text-[#888] hover:text-foreground'
|
|
207
|
-
)}
|
|
208
|
-
>
|
|
209
|
-
{child.name}
|
|
210
|
-
</Link>
|
|
211
|
-
</div>
|
|
212
|
-
</li>
|
|
213
|
-
)
|
|
214
|
-
})}
|
|
215
|
-
</ul>
|
|
216
|
-
)}
|
|
217
|
-
</li>
|
|
218
|
-
)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function UserDropdown({
|
|
222
|
-
user,
|
|
223
|
-
isExpanded,
|
|
224
|
-
}: {
|
|
225
|
-
user: MiddaySidebarProps['user']
|
|
226
|
-
isExpanded: boolean
|
|
227
|
-
}) {
|
|
228
|
-
const initials = user?.full_name
|
|
229
|
-
? user.full_name
|
|
230
|
-
.split(' ')
|
|
231
|
-
.map((n) => n[0])
|
|
232
|
-
.join('')
|
|
233
|
-
.toUpperCase()
|
|
234
|
-
.slice(0, 2)
|
|
235
|
-
: user?.email?.slice(0, 2).toUpperCase() || 'U'
|
|
236
|
-
|
|
237
|
-
return (
|
|
238
|
-
<DropdownMenu>
|
|
239
|
-
<DropdownMenuTrigger asChild>
|
|
240
|
-
<button
|
|
241
|
-
className={cn(
|
|
242
|
-
'flex items-center gap-3',
|
|
243
|
-
'w-[calc(100%-20px)] mx-[10px] px-[10px] py-2',
|
|
244
|
-
'rounded-md',
|
|
245
|
-
'hover:bg-[#f7f7f7] dark:hover:bg-[#1a1a1a]',
|
|
246
|
-
'transition-colors duration-150',
|
|
247
|
-
'focus:outline-none focus-visible:ring-1 focus-visible:ring-ring'
|
|
248
|
-
)}
|
|
249
|
-
>
|
|
250
|
-
<Avatar className="h-8 w-8 flex-shrink-0">
|
|
251
|
-
<AvatarFallback className="bg-primary text-primary-foreground text-xs font-medium">
|
|
252
|
-
{initials}
|
|
253
|
-
</AvatarFallback>
|
|
254
|
-
</Avatar>
|
|
255
|
-
{isExpanded && (
|
|
256
|
-
<div className="flex-1 text-left overflow-hidden min-w-0">
|
|
257
|
-
<p className="text-sm font-medium truncate leading-tight">
|
|
258
|
-
{user?.full_name || 'Usuario'}
|
|
259
|
-
</p>
|
|
260
|
-
<p className="text-xs text-[#878787] truncate leading-tight">
|
|
261
|
-
{user?.email}
|
|
262
|
-
</p>
|
|
263
|
-
</div>
|
|
264
|
-
)}
|
|
265
|
-
</button>
|
|
266
|
-
</DropdownMenuTrigger>
|
|
267
|
-
<DropdownMenuContent
|
|
268
|
-
align="start"
|
|
269
|
-
side="top"
|
|
270
|
-
sideOffset={8}
|
|
271
|
-
className="w-56"
|
|
272
|
-
>
|
|
273
|
-
<div className="px-2 py-1.5">
|
|
274
|
-
<p className="text-sm font-medium">{user?.full_name || 'Usuario'}</p>
|
|
275
|
-
<p className="text-xs text-[#878787]">{user?.email}</p>
|
|
276
|
-
</div>
|
|
277
|
-
<DropdownMenuSeparator />
|
|
278
|
-
<DropdownMenuItem asChild>
|
|
279
|
-
<Link href="/settings" className="cursor-pointer">
|
|
280
|
-
<Icons.Settings size={16} className="mr-2 text-[#878787]" />
|
|
281
|
-
<span>Configuración</span>
|
|
282
|
-
</Link>
|
|
283
|
-
</DropdownMenuItem>
|
|
284
|
-
<DropdownMenuSeparator />
|
|
285
|
-
<DropdownMenuItem
|
|
286
|
-
className="text-destructive focus:text-destructive cursor-pointer"
|
|
287
|
-
onClick={() => logoutAction()}
|
|
288
|
-
>
|
|
289
|
-
<Icons.LogOut size={16} className="mr-2" />
|
|
290
|
-
<span>Cerrar sesión</span>
|
|
291
|
-
</DropdownMenuItem>
|
|
292
|
-
</DropdownMenuContent>
|
|
293
|
-
</DropdownMenu>
|
|
294
|
-
)
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export function MiddaySidebar({ user }: MiddaySidebarProps) {
|
|
298
|
-
const { isExpanded, setIsExpanded } = useSidebar()
|
|
299
|
-
const pathname = usePathname()
|
|
300
|
-
const sidebarRef = useRef<HTMLDivElement>(null)
|
|
301
|
-
const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
|
302
|
-
|
|
303
|
-
const isAdmin = user?.role && ['admin', 'super_admin'].includes(user.role)
|
|
304
|
-
const isSuperAdmin = user?.role === 'super_admin'
|
|
305
|
-
const configNavItems = getConfigNavItems(isSuperAdmin)
|
|
306
|
-
|
|
307
|
-
const handleMouseEnter = useCallback(() => {
|
|
308
|
-
if (hoverTimeoutRef.current) {
|
|
309
|
-
clearTimeout(hoverTimeoutRef.current)
|
|
310
|
-
}
|
|
311
|
-
setIsExpanded(true)
|
|
312
|
-
}, [setIsExpanded])
|
|
313
|
-
|
|
314
|
-
const handleMouseLeave = useCallback(() => {
|
|
315
|
-
hoverTimeoutRef.current = setTimeout(() => {
|
|
316
|
-
setIsExpanded(false)
|
|
317
|
-
}, 100)
|
|
318
|
-
}, [setIsExpanded])
|
|
319
|
-
|
|
320
|
-
return (
|
|
321
|
-
<aside
|
|
322
|
-
ref={sidebarRef}
|
|
323
|
-
className={cn(
|
|
324
|
-
'h-screen flex-shrink-0 flex-col justify-between fixed top-0 left-0 hidden md:flex z-50',
|
|
325
|
-
'bg-background border-r border-border',
|
|
326
|
-
'transition-[width] duration-200 ease-[cubic-bezier(0.4,0,0.2,1)]',
|
|
327
|
-
isExpanded ? 'w-[240px]' : 'w-[70px]'
|
|
328
|
-
)}
|
|
329
|
-
onMouseEnter={handleMouseEnter}
|
|
330
|
-
onMouseLeave={handleMouseLeave}
|
|
331
|
-
>
|
|
332
|
-
{/* Header / Logo - Midday style */}
|
|
333
|
-
<div
|
|
334
|
-
className={cn(
|
|
335
|
-
"absolute top-0 left-0 h-[70px] flex items-center justify-center bg-background border-b border-border transition-all duration-200 ease-[cubic-bezier(0.4,0,0.2,1)]",
|
|
336
|
-
isExpanded ? "w-full" : "w-[69px]"
|
|
337
|
-
)}
|
|
338
|
-
>
|
|
339
|
-
<Link href="/dashboard" className="absolute left-[22px] transition-none">
|
|
340
|
-
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
341
|
-
<img src="/logolft.svg" alt="Logo" className="h-7 w-7" />
|
|
342
|
-
</Link>
|
|
343
|
-
</div>
|
|
344
|
-
|
|
345
|
-
{/* Navigation - Midday style */}
|
|
346
|
-
<nav className="flex-1 pt-[70px] pb-4 overflow-y-auto scrollbar-hide border-b border-border">
|
|
347
|
-
<ul className="space-y-1">
|
|
348
|
-
{mainNavItems.map((item) => (
|
|
349
|
-
<MenuItem
|
|
350
|
-
key={item.path}
|
|
351
|
-
item={item}
|
|
352
|
-
isExpanded={isExpanded}
|
|
353
|
-
pathname={pathname}
|
|
354
|
-
/>
|
|
355
|
-
))}
|
|
356
|
-
</ul>
|
|
357
|
-
|
|
358
|
-
{/* Admin section with separator */}
|
|
359
|
-
{isAdmin && (
|
|
360
|
-
<div className="mt-6 pt-4 mx-[10px] border-t border-border">
|
|
361
|
-
<ul className="space-y-1">
|
|
362
|
-
{configNavItems.map((item) => (
|
|
363
|
-
<MenuItem
|
|
364
|
-
key={item.path}
|
|
365
|
-
item={item}
|
|
366
|
-
isExpanded={isExpanded}
|
|
367
|
-
pathname={pathname}
|
|
368
|
-
/>
|
|
369
|
-
))}
|
|
370
|
-
</ul>
|
|
371
|
-
</div>
|
|
372
|
-
)}
|
|
373
|
-
</nav>
|
|
374
|
-
|
|
375
|
-
{/* User section - Midday style */}
|
|
376
|
-
<div className="border-t border-border py-3">
|
|
377
|
-
<UserDropdown user={user} isExpanded={isExpanded} />
|
|
378
|
-
</div>
|
|
379
|
-
</aside>
|
|
380
|
-
)
|
|
381
|
-
}
|