@create-lft-app/nextjs 1.0.0 → 1.0.2
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/package.json +1 -1
- package/template/next-env.d.ts +6 -0
- package/template/package-lock.json +8454 -0
- package/template/package.json +1 -1
- package/template/public/logolft.svg +12 -0
- package/template/src/app/dashboard/page.tsx +93 -84
- package/template/src/app/layout.tsx +9 -13
- package/template/src/components/layout/midday-sidebar.tsx +22 -252
- package/template/src/modules/auth/actions/auth-actions.ts +4 -4
- package/template/tsconfig.json +19 -5
- package/template/src/app/auth/login/page.tsx +0 -153
- package/template/src/components/layout/admin-midday-sidebar.tsx +0 -247
- package/template/src/components/layout/admin-sidebar.tsx +0 -146
- package/template/src/components/layout/header.tsx +0 -71
- package/template/src/components/layout/nav-user.tsx +0 -108
- package/template/src/components/layout/page-header.tsx +0 -95
- package/template/src/components/layout/sidebar.tsx +0 -194
- package/template/src/components/layout/suspension-banner.tsx +0 -21
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { logout } from '@/modules/auth/actions/auth-actions'
|
|
4
|
-
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
|
|
5
|
-
import {
|
|
6
|
-
DropdownMenu,
|
|
7
|
-
DropdownMenuContent,
|
|
8
|
-
DropdownMenuItem,
|
|
9
|
-
DropdownMenuLabel,
|
|
10
|
-
DropdownMenuSeparator,
|
|
11
|
-
DropdownMenuTrigger,
|
|
12
|
-
} from '@/components/ui/dropdown-menu'
|
|
13
|
-
import { SidebarMenuButton } from '@/components/ui/sidebar'
|
|
14
|
-
import { ChevronsUpDown, LogOut, User } from 'lucide-react'
|
|
15
|
-
import { Badge } from '@/components/ui/badge'
|
|
16
|
-
|
|
17
|
-
interface NavUserProps {
|
|
18
|
-
user: {
|
|
19
|
-
email: string
|
|
20
|
-
full_name: string | null
|
|
21
|
-
role: string
|
|
22
|
-
} | null
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const roleLabels: Record<string, string> = {
|
|
26
|
-
super_admin: 'Super Admin',
|
|
27
|
-
admin: 'Administrador',
|
|
28
|
-
compliance: 'Compliance',
|
|
29
|
-
analyst: 'Analista',
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function NavUser({ user }: NavUserProps) {
|
|
33
|
-
if (!user) return null
|
|
34
|
-
|
|
35
|
-
const initials = user.full_name
|
|
36
|
-
? user.full_name
|
|
37
|
-
.split(' ')
|
|
38
|
-
.map((n) => n[0])
|
|
39
|
-
.join('')
|
|
40
|
-
.toUpperCase()
|
|
41
|
-
.slice(0, 2)
|
|
42
|
-
: user.email.slice(0, 2).toUpperCase()
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<DropdownMenu>
|
|
46
|
-
<DropdownMenuTrigger asChild>
|
|
47
|
-
<SidebarMenuButton
|
|
48
|
-
size="lg"
|
|
49
|
-
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
50
|
-
>
|
|
51
|
-
<Avatar className="h-8 w-8">
|
|
52
|
-
<AvatarFallback className="bg-primary text-primary-foreground text-xs">
|
|
53
|
-
{initials}
|
|
54
|
-
</AvatarFallback>
|
|
55
|
-
</Avatar>
|
|
56
|
-
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
57
|
-
<span className="truncate font-semibold">
|
|
58
|
-
{user.full_name || user.email}
|
|
59
|
-
</span>
|
|
60
|
-
<span className="truncate text-xs text-muted-foreground">
|
|
61
|
-
{user.email}
|
|
62
|
-
</span>
|
|
63
|
-
</div>
|
|
64
|
-
<ChevronsUpDown className="ml-auto size-4" />
|
|
65
|
-
</SidebarMenuButton>
|
|
66
|
-
</DropdownMenuTrigger>
|
|
67
|
-
<DropdownMenuContent
|
|
68
|
-
className="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
|
|
69
|
-
side="bottom"
|
|
70
|
-
align="end"
|
|
71
|
-
sideOffset={4}
|
|
72
|
-
>
|
|
73
|
-
<DropdownMenuLabel className="p-0 font-normal">
|
|
74
|
-
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
|
75
|
-
<Avatar className="h-8 w-8">
|
|
76
|
-
<AvatarFallback className="bg-primary text-primary-foreground text-xs">
|
|
77
|
-
{initials}
|
|
78
|
-
</AvatarFallback>
|
|
79
|
-
</Avatar>
|
|
80
|
-
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
81
|
-
<span className="truncate font-semibold">
|
|
82
|
-
{user.full_name || user.email}
|
|
83
|
-
</span>
|
|
84
|
-
<Badge variant="secondary" className="w-fit text-xs">
|
|
85
|
-
{roleLabels[user.role] || user.role}
|
|
86
|
-
</Badge>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
</DropdownMenuLabel>
|
|
90
|
-
<DropdownMenuSeparator />
|
|
91
|
-
<DropdownMenuItem asChild>
|
|
92
|
-
<a href="/settings/profile" className="cursor-pointer">
|
|
93
|
-
<User className="mr-2 h-4 w-4" />
|
|
94
|
-
Mi Perfil
|
|
95
|
-
</a>
|
|
96
|
-
</DropdownMenuItem>
|
|
97
|
-
<DropdownMenuSeparator />
|
|
98
|
-
<DropdownMenuItem
|
|
99
|
-
className="cursor-pointer text-destructive focus:text-destructive"
|
|
100
|
-
onClick={() => logout()}
|
|
101
|
-
>
|
|
102
|
-
<LogOut className="mr-2 h-4 w-4" />
|
|
103
|
-
Cerrar sesión
|
|
104
|
-
</DropdownMenuItem>
|
|
105
|
-
</DropdownMenuContent>
|
|
106
|
-
</DropdownMenu>
|
|
107
|
-
)
|
|
108
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { cn } from '@/lib/utils'
|
|
2
|
-
|
|
3
|
-
interface PageHeaderProps {
|
|
4
|
-
title: string
|
|
5
|
-
description?: string
|
|
6
|
-
children?: React.ReactNode
|
|
7
|
-
className?: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function PageHeader({ title, description, children, className }: PageHeaderProps) {
|
|
11
|
-
return (
|
|
12
|
-
<header className={cn('h-[70px] flex items-center border-b border-border px-6', className)}>
|
|
13
|
-
<div className="flex items-center justify-between w-full">
|
|
14
|
-
<div>
|
|
15
|
-
<h1 className="text-lg font-medium">{title}</h1>
|
|
16
|
-
{description && (
|
|
17
|
-
<p className="text-xs text-[#878787]">{description}</p>
|
|
18
|
-
)}
|
|
19
|
-
</div>
|
|
20
|
-
{children && (
|
|
21
|
-
<div className="flex items-center gap-2">
|
|
22
|
-
{children}
|
|
23
|
-
</div>
|
|
24
|
-
)}
|
|
25
|
-
</div>
|
|
26
|
-
</header>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface PageContentProps {
|
|
31
|
-
children: React.ReactNode
|
|
32
|
-
className?: string
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function PageContent({ children, className }: PageContentProps) {
|
|
36
|
-
return (
|
|
37
|
-
<div className={cn('flex-1 overflow-auto p-6', className)}>
|
|
38
|
-
{children}
|
|
39
|
-
</div>
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
interface PageContainerProps {
|
|
44
|
-
children: React.ReactNode
|
|
45
|
-
className?: string
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function PageContainer({ children, className }: PageContainerProps) {
|
|
49
|
-
return (
|
|
50
|
-
<div className={cn('flex flex-col h-screen', className)}>
|
|
51
|
-
{children}
|
|
52
|
-
</div>
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
interface StatItemProps {
|
|
57
|
-
label: string
|
|
58
|
-
value: string | number
|
|
59
|
-
trend?: {
|
|
60
|
-
value: number
|
|
61
|
-
positive?: boolean
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function StatItem({ label, value, trend }: StatItemProps) {
|
|
66
|
-
return (
|
|
67
|
-
<div className="border border-border bg-background p-6">
|
|
68
|
-
<p className="text-sm text-[#878787] mb-3">{label}</p>
|
|
69
|
-
<div className="flex items-baseline gap-2">
|
|
70
|
-
<span className="text-2xl font-normal tabular-nums">{value}</span>
|
|
71
|
-
{trend && (
|
|
72
|
-
<span className={cn(
|
|
73
|
-
'text-xs',
|
|
74
|
-
trend.positive ? 'text-[#00C48C]' : 'text-[#FF3B3B]'
|
|
75
|
-
)}>
|
|
76
|
-
{trend.positive ? '+' : ''}{trend.value}%
|
|
77
|
-
</span>
|
|
78
|
-
)}
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
interface StatsRowProps {
|
|
85
|
-
children: React.ReactNode
|
|
86
|
-
className?: string
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function StatsRow({ children, className }: StatsRowProps) {
|
|
90
|
-
return (
|
|
91
|
-
<div className={cn('grid grid-cols-4 gap-6', className)}>
|
|
92
|
-
{children}
|
|
93
|
-
</div>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import Link from 'next/link'
|
|
4
|
-
import { usePathname } from 'next/navigation'
|
|
5
|
-
import {
|
|
6
|
-
LayoutDashboard,
|
|
7
|
-
Users,
|
|
8
|
-
FileText,
|
|
9
|
-
AlertTriangle,
|
|
10
|
-
BarChart3,
|
|
11
|
-
Calendar,
|
|
12
|
-
Settings,
|
|
13
|
-
Building2,
|
|
14
|
-
Shield,
|
|
15
|
-
UserPlus,
|
|
16
|
-
} from 'lucide-react'
|
|
17
|
-
import { cn } from '@/lib/utils'
|
|
18
|
-
import {
|
|
19
|
-
Sidebar,
|
|
20
|
-
SidebarContent,
|
|
21
|
-
SidebarGroup,
|
|
22
|
-
SidebarGroupContent,
|
|
23
|
-
SidebarGroupLabel,
|
|
24
|
-
SidebarMenu,
|
|
25
|
-
SidebarMenuButton,
|
|
26
|
-
SidebarMenuItem,
|
|
27
|
-
SidebarHeader,
|
|
28
|
-
SidebarFooter,
|
|
29
|
-
} from '@/components/ui/sidebar'
|
|
30
|
-
import { NavUser } from './nav-user'
|
|
31
|
-
|
|
32
|
-
const mainNavItems = [
|
|
33
|
-
{
|
|
34
|
-
title: 'Dashboard',
|
|
35
|
-
url: '/',
|
|
36
|
-
icon: LayoutDashboard,
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
title: 'Clientes',
|
|
40
|
-
url: '/clientes',
|
|
41
|
-
icon: Users,
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
title: 'Onboarding',
|
|
45
|
-
url: '/onboarding',
|
|
46
|
-
icon: UserPlus,
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
title: 'Documentos',
|
|
50
|
-
url: '/documents',
|
|
51
|
-
icon: FileText,
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
title: 'Alertas',
|
|
55
|
-
url: '/alerts',
|
|
56
|
-
icon: AlertTriangle,
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
title: 'Operaciones',
|
|
60
|
-
url: '/operations',
|
|
61
|
-
icon: BarChart3,
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
title: 'Reportes',
|
|
65
|
-
url: '/reports',
|
|
66
|
-
icon: FileText,
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
title: 'Calendario',
|
|
70
|
-
url: '/calendar',
|
|
71
|
-
icon: Calendar,
|
|
72
|
-
},
|
|
73
|
-
]
|
|
74
|
-
|
|
75
|
-
const configNavItems = [
|
|
76
|
-
{
|
|
77
|
-
title: 'Configuración',
|
|
78
|
-
url: '/settings',
|
|
79
|
-
icon: Settings,
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
title: 'Organización',
|
|
83
|
-
url: '/settings/organization',
|
|
84
|
-
icon: Building2,
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
title: 'Onboarding',
|
|
88
|
-
url: '/settings/onboarding',
|
|
89
|
-
icon: UserPlus,
|
|
90
|
-
},
|
|
91
|
-
]
|
|
92
|
-
|
|
93
|
-
interface AppSidebarProps {
|
|
94
|
-
user: {
|
|
95
|
-
email: string
|
|
96
|
-
full_name: string | null
|
|
97
|
-
role: string
|
|
98
|
-
organization?: {
|
|
99
|
-
name: string
|
|
100
|
-
} | null
|
|
101
|
-
} | null
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function AppSidebar({ user }: AppSidebarProps) {
|
|
105
|
-
const pathname = usePathname()
|
|
106
|
-
|
|
107
|
-
return (
|
|
108
|
-
<Sidebar>
|
|
109
|
-
<SidebarHeader className="border-b border-sidebar-border">
|
|
110
|
-
<div className="flex items-center gap-2 px-4 py-3">
|
|
111
|
-
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary text-primary-foreground font-bold">
|
|
112
|
-
R
|
|
113
|
-
</div>
|
|
114
|
-
<div className="flex flex-col">
|
|
115
|
-
<span className="text-sm font-semibold">Radiant Compliance</span>
|
|
116
|
-
{user?.organization && (
|
|
117
|
-
<span className="text-xs text-muted-foreground">
|
|
118
|
-
{user.organization.name}
|
|
119
|
-
</span>
|
|
120
|
-
)}
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
</SidebarHeader>
|
|
124
|
-
|
|
125
|
-
<SidebarContent>
|
|
126
|
-
<SidebarGroup>
|
|
127
|
-
<SidebarGroupLabel>Principal</SidebarGroupLabel>
|
|
128
|
-
<SidebarGroupContent>
|
|
129
|
-
<SidebarMenu>
|
|
130
|
-
{mainNavItems.map((item) => (
|
|
131
|
-
<SidebarMenuItem key={item.title}>
|
|
132
|
-
<SidebarMenuButton
|
|
133
|
-
asChild
|
|
134
|
-
isActive={pathname === item.url}
|
|
135
|
-
>
|
|
136
|
-
<Link href={item.url}>
|
|
137
|
-
<item.icon className="h-4 w-4" />
|
|
138
|
-
<span>{item.title}</span>
|
|
139
|
-
</Link>
|
|
140
|
-
</SidebarMenuButton>
|
|
141
|
-
</SidebarMenuItem>
|
|
142
|
-
))}
|
|
143
|
-
</SidebarMenu>
|
|
144
|
-
</SidebarGroupContent>
|
|
145
|
-
</SidebarGroup>
|
|
146
|
-
|
|
147
|
-
{user?.role && ['admin', 'super_admin'].includes(user.role) && (
|
|
148
|
-
<SidebarGroup>
|
|
149
|
-
<SidebarGroupLabel>Administración</SidebarGroupLabel>
|
|
150
|
-
<SidebarGroupContent>
|
|
151
|
-
<SidebarMenu>
|
|
152
|
-
{configNavItems.map((item) => (
|
|
153
|
-
<SidebarMenuItem key={item.title}>
|
|
154
|
-
<SidebarMenuButton
|
|
155
|
-
asChild
|
|
156
|
-
isActive={pathname === item.url || pathname.startsWith(item.url + '/')}
|
|
157
|
-
>
|
|
158
|
-
<Link href={item.url}>
|
|
159
|
-
<item.icon className="h-4 w-4" />
|
|
160
|
-
<span>{item.title}</span>
|
|
161
|
-
</Link>
|
|
162
|
-
</SidebarMenuButton>
|
|
163
|
-
</SidebarMenuItem>
|
|
164
|
-
))}
|
|
165
|
-
</SidebarMenu>
|
|
166
|
-
</SidebarGroupContent>
|
|
167
|
-
</SidebarGroup>
|
|
168
|
-
)}
|
|
169
|
-
|
|
170
|
-
{user?.role === 'super_admin' && (
|
|
171
|
-
<SidebarGroup>
|
|
172
|
-
<SidebarGroupLabel>Super Admin</SidebarGroupLabel>
|
|
173
|
-
<SidebarGroupContent>
|
|
174
|
-
<SidebarMenu>
|
|
175
|
-
<SidebarMenuItem>
|
|
176
|
-
<SidebarMenuButton asChild>
|
|
177
|
-
<Link href="/admin">
|
|
178
|
-
<Shield className="h-4 w-4" />
|
|
179
|
-
<span>Panel de Admin</span>
|
|
180
|
-
</Link>
|
|
181
|
-
</SidebarMenuButton>
|
|
182
|
-
</SidebarMenuItem>
|
|
183
|
-
</SidebarMenu>
|
|
184
|
-
</SidebarGroupContent>
|
|
185
|
-
</SidebarGroup>
|
|
186
|
-
)}
|
|
187
|
-
</SidebarContent>
|
|
188
|
-
|
|
189
|
-
<SidebarFooter className="border-t border-sidebar-border">
|
|
190
|
-
<NavUser user={user} />
|
|
191
|
-
</SidebarFooter>
|
|
192
|
-
</Sidebar>
|
|
193
|
-
)
|
|
194
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { AlertTriangle } from 'lucide-react'
|
|
4
|
-
|
|
5
|
-
interface SuspensionBannerProps {
|
|
6
|
-
organizationName: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function SuspensionBanner({ organizationName }: SuspensionBannerProps) {
|
|
10
|
-
return (
|
|
11
|
-
<div className="bg-red-500 text-white px-4 py-3">
|
|
12
|
-
<div className="flex items-center justify-center gap-2 text-sm font-medium">
|
|
13
|
-
<AlertTriangle className="h-4 w-4" />
|
|
14
|
-
<span>
|
|
15
|
-
La organización <strong>{organizationName}</strong> se encuentra suspendida.
|
|
16
|
-
Contacte al administrador para más información.
|
|
17
|
-
</span>
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
)
|
|
21
|
-
}
|