@create-lft-app/nextjs 3.2.0 → 3.3.0

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.
Files changed (133) hide show
  1. package/README.md +549 -549
  2. package/package.json +48 -48
  3. package/template/.claude/skills/anti-patterns.md +150 -0
  4. package/template/.claude/skills/drizzle-schema.md +178 -0
  5. package/template/.claude/skills/formatting.md +56 -0
  6. package/template/.claude/skills/module-architecture.md +143 -0
  7. package/template/.claude/skills/supabase-server-actions.md +199 -0
  8. package/template/.claude/skills/ui-patterns.md +161 -0
  9. package/template/CLAUDE.md +114 -1239
  10. package/template/drizzle.config.ts +12 -12
  11. package/template/eslint.config.mjs +16 -16
  12. package/template/gitignore +36 -36
  13. package/template/next.config.ts +7 -7
  14. package/template/package.json +86 -86
  15. package/template/postcss.config.mjs +7 -7
  16. package/template/proxy.ts +12 -12
  17. package/template/public/logolft.svg +11 -11
  18. package/template/src/app/(auth)/dashboard/dashboard-content.tsx +124 -124
  19. package/template/src/app/(auth)/dashboard/page.tsx +9 -9
  20. package/template/src/app/(auth)/layout.tsx +7 -7
  21. package/template/src/app/(auth)/users/page.tsx +9 -9
  22. package/template/src/app/(auth)/users/users-content.tsx +26 -26
  23. package/template/src/app/(public)/layout.tsx +7 -7
  24. package/template/src/app/(public)/login/page.tsx +17 -17
  25. package/template/src/app/api/webhooks/route.ts +20 -20
  26. package/template/src/app/globals.css +249 -249
  27. package/template/src/app/layout.tsx +37 -37
  28. package/template/src/app/page.tsx +5 -5
  29. package/template/src/app/providers.tsx +27 -27
  30. package/template/src/components/layout/main-content.tsx +28 -28
  31. package/template/src/components/layout/sidebar-context.tsx +33 -33
  32. package/template/src/components/layout/sidebar.tsx +141 -141
  33. package/template/src/components/tables/data-table-column-header.tsx +68 -68
  34. package/template/src/components/tables/data-table-date-filter.tsx +203 -203
  35. package/template/src/components/tables/data-table-faceted-filter.tsx +185 -185
  36. package/template/src/components/tables/data-table-filters-dropdown.tsx +130 -130
  37. package/template/src/components/tables/data-table-number-filter.tsx +295 -295
  38. package/template/src/components/tables/data-table-pagination.tsx +99 -99
  39. package/template/src/components/tables/data-table-toolbar.tsx +140 -140
  40. package/template/src/components/tables/data-table-view-options.tsx +63 -63
  41. package/template/src/components/tables/data-table.tsx +148 -148
  42. package/template/src/components/tables/index.ts +9 -9
  43. package/template/src/components/ui/accordion.tsx +58 -58
  44. package/template/src/components/ui/alert-dialog.tsx +165 -165
  45. package/template/src/components/ui/alert.tsx +66 -66
  46. package/template/src/components/ui/animations/index.ts +44 -44
  47. package/template/src/components/ui/avatar.tsx +55 -55
  48. package/template/src/components/ui/badge.tsx +50 -50
  49. package/template/src/components/ui/button.tsx +118 -118
  50. package/template/src/components/ui/calendar.tsx +220 -220
  51. package/template/src/components/ui/card.tsx +113 -113
  52. package/template/src/components/ui/checkbox.tsx +38 -38
  53. package/template/src/components/ui/collapsible.tsx +33 -33
  54. package/template/src/components/ui/command.tsx +196 -196
  55. package/template/src/components/ui/dialog.tsx +156 -156
  56. package/template/src/components/ui/dropdown-menu.tsx +280 -280
  57. package/template/src/components/ui/form.tsx +171 -171
  58. package/template/src/components/ui/icons.tsx +167 -167
  59. package/template/src/components/ui/input.tsx +28 -28
  60. package/template/src/components/ui/label.tsx +25 -25
  61. package/template/src/components/ui/motion.tsx +197 -197
  62. package/template/src/components/ui/page-transition.tsx +166 -166
  63. package/template/src/components/ui/popover.tsx +59 -59
  64. package/template/src/components/ui/progress.tsx +32 -32
  65. package/template/src/components/ui/radio-group.tsx +45 -45
  66. package/template/src/components/ui/scroll-area.tsx +63 -63
  67. package/template/src/components/ui/select.tsx +208 -208
  68. package/template/src/components/ui/separator.tsx +28 -28
  69. package/template/src/components/ui/sheet.tsx +170 -170
  70. package/template/src/components/ui/sidebar.tsx +726 -726
  71. package/template/src/components/ui/skeleton.tsx +15 -15
  72. package/template/src/components/ui/slider.tsx +58 -58
  73. package/template/src/components/ui/sonner.tsx +47 -47
  74. package/template/src/components/ui/spinner.tsx +27 -27
  75. package/template/src/components/ui/submit-button.tsx +47 -47
  76. package/template/src/components/ui/switch.tsx +31 -31
  77. package/template/src/components/ui/table.tsx +120 -120
  78. package/template/src/components/ui/tabs.tsx +75 -75
  79. package/template/src/components/ui/textarea.tsx +26 -26
  80. package/template/src/components/ui/tooltip.tsx +70 -70
  81. package/template/src/config/navigation.ts +59 -59
  82. package/template/src/config/roles.ts +27 -27
  83. package/template/src/config/site.ts +12 -12
  84. package/template/src/db/index.ts +12 -12
  85. package/template/src/db/schema/index.ts +1 -1
  86. package/template/src/db/schema/users.ts +16 -16
  87. package/template/src/db/seed.ts +39 -39
  88. package/template/src/hooks/index.ts +3 -3
  89. package/template/src/hooks/use-mobile.ts +21 -21
  90. package/template/src/hooks/useDataTable.ts +82 -82
  91. package/template/src/hooks/useDebounce.ts +49 -49
  92. package/template/src/hooks/useMediaQuery.ts +36 -36
  93. package/template/src/lib/date/config.ts +36 -36
  94. package/template/src/lib/date/formatters.ts +127 -127
  95. package/template/src/lib/date/index.ts +26 -26
  96. package/template/src/lib/excel/exporter.ts +89 -89
  97. package/template/src/lib/excel/index.ts +14 -14
  98. package/template/src/lib/excel/parser.ts +96 -96
  99. package/template/src/lib/query-client.ts +35 -35
  100. package/template/src/lib/supabase/admin.ts +23 -23
  101. package/template/src/lib/supabase/client.ts +11 -11
  102. package/template/src/lib/supabase/proxy.ts +67 -67
  103. package/template/src/lib/supabase/server.ts +38 -38
  104. package/template/src/lib/supabase/types.ts +53 -53
  105. package/template/src/lib/utils.ts +6 -6
  106. package/template/src/lib/validations/common.ts +75 -75
  107. package/template/src/lib/validations/index.ts +20 -20
  108. package/template/src/modules/auth/actions/auth-actions.ts +59 -59
  109. package/template/src/modules/auth/components/login-form.tsx +68 -68
  110. package/template/src/modules/auth/hooks/useAuth.ts +38 -38
  111. package/template/src/modules/auth/hooks/useAuthMutations.ts +43 -43
  112. package/template/src/modules/auth/hooks/useAuthQueries.ts +43 -43
  113. package/template/src/modules/auth/index.ts +12 -12
  114. package/template/src/modules/auth/schemas/auth.schema.ts +32 -32
  115. package/template/src/modules/auth/stores/useAuthStore.ts +37 -37
  116. package/template/src/modules/users/actions/users-actions.ts +166 -166
  117. package/template/src/modules/users/columns.tsx +106 -106
  118. package/template/src/modules/users/components/users-list.tsx +48 -48
  119. package/template/src/modules/users/hooks/useUsers.ts +39 -39
  120. package/template/src/modules/users/hooks/useUsersMutations.ts +55 -55
  121. package/template/src/modules/users/hooks/useUsersQueries.ts +35 -35
  122. package/template/src/modules/users/index.ts +30 -30
  123. package/template/src/modules/users/schemas/users.schema.ts +51 -51
  124. package/template/src/modules/users/stores/useUsersStore.ts +60 -60
  125. package/template/src/modules/users/types/auth-user.types.ts +42 -42
  126. package/template/src/modules/users/utils/user-mapper.ts +32 -32
  127. package/template/src/stores/index.ts +1 -1
  128. package/template/src/stores/useUiStore.ts +55 -55
  129. package/template/src/types/api.ts +28 -28
  130. package/template/src/types/index.ts +2 -2
  131. package/template/src/types/table.ts +34 -34
  132. package/template/supabase/config.toml +94 -94
  133. package/template/tsconfig.json +42 -42
@@ -1,51 +1,51 @@
1
- import { z } from 'zod'
2
- import { USER_ROLES, DEFAULT_ROLE } from '@/config/roles'
3
-
4
- // Schema de rol reutilizable
5
- const roleSchema = z.enum(USER_ROLES)
6
-
7
- // Schema base del usuario (estructura que devuelve el mapper)
8
- export const userSchema = z.object({
9
- id: z.string().uuid(),
10
- email: z.string().email(),
11
- name: z.string().min(1, 'El nombre es requerido'),
12
- role: roleSchema.default(DEFAULT_ROLE),
13
- avatar_url: z.string().url().nullable().optional(),
14
- created_at: z.string().datetime(),
15
- updated_at: z.string().datetime(),
16
- })
17
-
18
- // Schema para crear usuario via Supabase Auth Admin
19
- export const createAuthUserSchema = z.object({
20
- email: z.string().email('Email inválido'),
21
- password: z.string().min(8, 'Mínimo 8 caracteres').optional(),
22
- name: z.string().min(1, 'El nombre es requerido'),
23
- role: roleSchema.default(DEFAULT_ROLE),
24
- avatar_url: z.string().url().nullable().optional(),
25
- send_invite: z.boolean().default(true),
26
- })
27
-
28
- // Schema para actualizar usuario via Supabase Auth Admin
29
- export const updateAuthUserSchema = z.object({
30
- email: z.string().email('Email inválido').optional(),
31
- password: z.string().min(8, 'Mínimo 8 caracteres').optional(),
32
- name: z.string().min(1, 'El nombre es requerido').optional(),
33
- role: roleSchema.optional(),
34
- avatar_url: z.string().url().nullable().optional(),
35
- })
36
-
37
- // Schemas legacy (mantener compatibilidad)
38
- export const createUserSchema = userSchema.omit({
39
- id: true,
40
- created_at: true,
41
- updated_at: true,
42
- })
43
-
44
- export const updateUserSchema = createUserSchema.partial()
45
-
46
- // Types
47
- export type User = z.infer<typeof userSchema>
48
- export type CreateUserInput = z.infer<typeof createUserSchema>
49
- export type UpdateUserInput = z.infer<typeof updateUserSchema>
50
- export type CreateAuthUserInput = z.infer<typeof createAuthUserSchema>
51
- export type UpdateAuthUserInput = z.infer<typeof updateAuthUserSchema>
1
+ import { z } from 'zod'
2
+ import { USER_ROLES, DEFAULT_ROLE } from '@/config/roles'
3
+
4
+ // Schema de rol reutilizable
5
+ const roleSchema = z.enum(USER_ROLES)
6
+
7
+ // Schema base del usuario (estructura que devuelve el mapper)
8
+ export const userSchema = z.object({
9
+ id: z.string().uuid(),
10
+ email: z.string().email(),
11
+ name: z.string().min(1, 'El nombre es requerido'),
12
+ role: roleSchema.default(DEFAULT_ROLE),
13
+ avatar_url: z.string().url().nullable().optional(),
14
+ created_at: z.string().datetime(),
15
+ updated_at: z.string().datetime(),
16
+ })
17
+
18
+ // Schema para crear usuario via Supabase Auth Admin
19
+ export const createAuthUserSchema = z.object({
20
+ email: z.string().email('Email inválido'),
21
+ password: z.string().min(8, 'Mínimo 8 caracteres').optional(),
22
+ name: z.string().min(1, 'El nombre es requerido'),
23
+ role: roleSchema.default(DEFAULT_ROLE),
24
+ avatar_url: z.string().url().nullable().optional(),
25
+ send_invite: z.boolean().default(true),
26
+ })
27
+
28
+ // Schema para actualizar usuario via Supabase Auth Admin
29
+ export const updateAuthUserSchema = z.object({
30
+ email: z.string().email('Email inválido').optional(),
31
+ password: z.string().min(8, 'Mínimo 8 caracteres').optional(),
32
+ name: z.string().min(1, 'El nombre es requerido').optional(),
33
+ role: roleSchema.optional(),
34
+ avatar_url: z.string().url().nullable().optional(),
35
+ })
36
+
37
+ // Schemas legacy (mantener compatibilidad)
38
+ export const createUserSchema = userSchema.omit({
39
+ id: true,
40
+ created_at: true,
41
+ updated_at: true,
42
+ })
43
+
44
+ export const updateUserSchema = createUserSchema.partial()
45
+
46
+ // Types
47
+ export type User = z.infer<typeof userSchema>
48
+ export type CreateUserInput = z.infer<typeof createUserSchema>
49
+ export type UpdateUserInput = z.infer<typeof updateUserSchema>
50
+ export type CreateAuthUserInput = z.infer<typeof createAuthUserSchema>
51
+ export type UpdateAuthUserInput = z.infer<typeof updateAuthUserSchema>
@@ -1,60 +1,60 @@
1
- import { create } from 'zustand'
2
-
3
- interface UsersState {
4
- state: {
5
- selectedUserId: string | null
6
- isFormOpen: boolean
7
- isDeleteDialogOpen: boolean
8
- searchQuery: string
9
- }
10
- actions: {
11
- setSelectedUserId: (id: string | null) => void
12
- openForm: () => void
13
- closeForm: () => void
14
- openDeleteDialog: (id: string) => void
15
- closeDeleteDialog: () => void
16
- setSearchQuery: (query: string) => void
17
- reset: () => void
18
- }
19
- }
20
-
21
- const initialState = {
22
- selectedUserId: null,
23
- isFormOpen: false,
24
- isDeleteDialogOpen: false,
25
- searchQuery: '',
26
- }
27
-
28
- export const useUsersStore = create<UsersState>()((set) => ({
29
- state: initialState,
30
- actions: {
31
- setSelectedUserId: (id) =>
32
- set((state) => ({
33
- state: { ...state.state, selectedUserId: id },
34
- })),
35
- openForm: () =>
36
- set((state) => ({
37
- state: { ...state.state, isFormOpen: true },
38
- })),
39
- closeForm: () =>
40
- set((state) => ({
41
- state: { ...state.state, isFormOpen: false, selectedUserId: null },
42
- })),
43
- openDeleteDialog: (id) =>
44
- set((state) => ({
45
- state: { ...state.state, isDeleteDialogOpen: true, selectedUserId: id },
46
- })),
47
- closeDeleteDialog: () =>
48
- set((state) => ({
49
- state: { ...state.state, isDeleteDialogOpen: false, selectedUserId: null },
50
- })),
51
- setSearchQuery: (query) =>
52
- set((state) => ({
53
- state: { ...state.state, searchQuery: query },
54
- })),
55
- reset: () =>
56
- set(() => ({
57
- state: initialState,
58
- })),
59
- },
60
- }))
1
+ import { create } from 'zustand'
2
+
3
+ interface UsersState {
4
+ state: {
5
+ selectedUserId: string | null
6
+ isFormOpen: boolean
7
+ isDeleteDialogOpen: boolean
8
+ searchQuery: string
9
+ }
10
+ actions: {
11
+ setSelectedUserId: (id: string | null) => void
12
+ openForm: () => void
13
+ closeForm: () => void
14
+ openDeleteDialog: (id: string) => void
15
+ closeDeleteDialog: () => void
16
+ setSearchQuery: (query: string) => void
17
+ reset: () => void
18
+ }
19
+ }
20
+
21
+ const initialState = {
22
+ selectedUserId: null,
23
+ isFormOpen: false,
24
+ isDeleteDialogOpen: false,
25
+ searchQuery: '',
26
+ }
27
+
28
+ export const useUsersStore = create<UsersState>()((set) => ({
29
+ state: initialState,
30
+ actions: {
31
+ setSelectedUserId: (id) =>
32
+ set((state) => ({
33
+ state: { ...state.state, selectedUserId: id },
34
+ })),
35
+ openForm: () =>
36
+ set((state) => ({
37
+ state: { ...state.state, isFormOpen: true },
38
+ })),
39
+ closeForm: () =>
40
+ set((state) => ({
41
+ state: { ...state.state, isFormOpen: false, selectedUserId: null },
42
+ })),
43
+ openDeleteDialog: (id) =>
44
+ set((state) => ({
45
+ state: { ...state.state, isDeleteDialogOpen: true, selectedUserId: id },
46
+ })),
47
+ closeDeleteDialog: () =>
48
+ set((state) => ({
49
+ state: { ...state.state, isDeleteDialogOpen: false, selectedUserId: null },
50
+ })),
51
+ setSearchQuery: (query) =>
52
+ set((state) => ({
53
+ state: { ...state.state, searchQuery: query },
54
+ })),
55
+ reset: () =>
56
+ set(() => ({
57
+ state: initialState,
58
+ })),
59
+ },
60
+ }))
@@ -1,42 +1,42 @@
1
- import type { User as SupabaseAuthUser } from '@supabase/supabase-js'
2
- import type { UserRole } from '@/config/roles'
3
-
4
- // Re-exportar desde config para mantener compatibilidad
5
- export type { UserRole } from '@/config/roles'
6
-
7
- export interface UserAppMetadata {
8
- role: UserRole
9
- }
10
-
11
- export interface UserMetadata {
12
- name: string
13
- avatar_url?: string | null
14
- }
15
-
16
- export interface AuthUserWithMetadata extends SupabaseAuthUser {
17
- app_metadata: UserAppMetadata
18
- user_metadata: UserMetadata
19
- }
20
-
21
- /**
22
- * Input para crear usuario via auth.admin.createUser
23
- */
24
- export interface CreateAuthUserInput {
25
- email: string
26
- password?: string
27
- name: string
28
- role?: UserRole
29
- avatar_url?: string | null
30
- send_invite?: boolean
31
- }
32
-
33
- /**
34
- * Input para actualizar usuario via auth.admin.updateUserById
35
- */
36
- export interface UpdateAuthUserInput {
37
- email?: string
38
- password?: string
39
- name?: string
40
- role?: UserRole
41
- avatar_url?: string | null
42
- }
1
+ import type { User as SupabaseAuthUser } from '@supabase/supabase-js'
2
+ import type { UserRole } from '@/config/roles'
3
+
4
+ // Re-exportar desde config para mantener compatibilidad
5
+ export type { UserRole } from '@/config/roles'
6
+
7
+ export interface UserAppMetadata {
8
+ role: UserRole
9
+ }
10
+
11
+ export interface UserMetadata {
12
+ name: string
13
+ avatar_url?: string | null
14
+ }
15
+
16
+ export interface AuthUserWithMetadata extends SupabaseAuthUser {
17
+ app_metadata: UserAppMetadata
18
+ user_metadata: UserMetadata
19
+ }
20
+
21
+ /**
22
+ * Input para crear usuario via auth.admin.createUser
23
+ */
24
+ export interface CreateAuthUserInput {
25
+ email: string
26
+ password?: string
27
+ name: string
28
+ role?: UserRole
29
+ avatar_url?: string | null
30
+ send_invite?: boolean
31
+ }
32
+
33
+ /**
34
+ * Input para actualizar usuario via auth.admin.updateUserById
35
+ */
36
+ export interface UpdateAuthUserInput {
37
+ email?: string
38
+ password?: string
39
+ name?: string
40
+ role?: UserRole
41
+ avatar_url?: string | null
42
+ }
@@ -1,32 +1,32 @@
1
- import type { User as SupabaseAuthUser } from '@supabase/supabase-js'
2
- import type { User } from '../schemas/users.schema'
3
- import { DEFAULT_ROLE, type UserRole } from '@/config/roles'
4
-
5
- /**
6
- * Mapea un usuario de auth.users al tipo User de la aplicación.
7
- * Extrae datos de app_metadata (role) y user_metadata (name, avatar_url).
8
- */
9
- export function mapAuthUserToUser(authUser: SupabaseAuthUser): User {
10
- const appMetadata = authUser.app_metadata as { role?: UserRole } | undefined
11
- const userMetadata = authUser.user_metadata as {
12
- name?: string
13
- avatar_url?: string | null
14
- } | undefined
15
-
16
- return {
17
- id: authUser.id,
18
- email: authUser.email ?? '',
19
- name: userMetadata?.name ?? '',
20
- role: appMetadata?.role ?? DEFAULT_ROLE,
21
- avatar_url: userMetadata?.avatar_url ?? null,
22
- created_at: authUser.created_at ?? new Date().toISOString(),
23
- updated_at: authUser.updated_at ?? new Date().toISOString(),
24
- }
25
- }
26
-
27
- /**
28
- * Mapea array de usuarios de auth.users al tipo User[]
29
- */
30
- export function mapAuthUsersToUsers(authUsers: SupabaseAuthUser[]): User[] {
31
- return authUsers.map(mapAuthUserToUser)
32
- }
1
+ import type { User as SupabaseAuthUser } from '@supabase/supabase-js'
2
+ import type { User } from '../schemas/users.schema'
3
+ import { DEFAULT_ROLE, type UserRole } from '@/config/roles'
4
+
5
+ /**
6
+ * Mapea un usuario de auth.users al tipo User de la aplicación.
7
+ * Extrae datos de app_metadata (role) y user_metadata (name, avatar_url).
8
+ */
9
+ export function mapAuthUserToUser(authUser: SupabaseAuthUser): User {
10
+ const appMetadata = authUser.app_metadata as { role?: UserRole } | undefined
11
+ const userMetadata = authUser.user_metadata as {
12
+ name?: string
13
+ avatar_url?: string | null
14
+ } | undefined
15
+
16
+ return {
17
+ id: authUser.id,
18
+ email: authUser.email ?? '',
19
+ name: userMetadata?.name ?? '',
20
+ role: appMetadata?.role ?? DEFAULT_ROLE,
21
+ avatar_url: userMetadata?.avatar_url ?? null,
22
+ created_at: authUser.created_at ?? new Date().toISOString(),
23
+ updated_at: authUser.updated_at ?? new Date().toISOString(),
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Mapea array de usuarios de auth.users al tipo User[]
29
+ */
30
+ export function mapAuthUsersToUsers(authUsers: SupabaseAuthUser[]): User[] {
31
+ return authUsers.map(mapAuthUserToUser)
32
+ }
@@ -1 +1 @@
1
- export { useUiStore } from './useUiStore'
1
+ export { useUiStore } from './useUiStore'
@@ -1,55 +1,55 @@
1
- import { create } from 'zustand'
2
- import { persist } from 'zustand/middleware'
3
-
4
- interface UiState {
5
- state: {
6
- sidebarOpen: boolean
7
- sidebarCollapsed: boolean
8
- theme: 'light' | 'dark' | 'system'
9
- }
10
- actions: {
11
- toggleSidebar: () => void
12
- setSidebarOpen: (open: boolean) => void
13
- toggleSidebarCollapsed: () => void
14
- setSidebarCollapsed: (collapsed: boolean) => void
15
- setTheme: (theme: 'light' | 'dark' | 'system') => void
16
- }
17
- }
18
-
19
- export const useUiStore = create<UiState>()(
20
- persist(
21
- (set) => ({
22
- state: {
23
- sidebarOpen: true,
24
- sidebarCollapsed: false,
25
- theme: 'system',
26
- },
27
- actions: {
28
- toggleSidebar: () =>
29
- set((state) => ({
30
- state: { ...state.state, sidebarOpen: !state.state.sidebarOpen },
31
- })),
32
- setSidebarOpen: (open) =>
33
- set((state) => ({
34
- state: { ...state.state, sidebarOpen: open },
35
- })),
36
- toggleSidebarCollapsed: () =>
37
- set((state) => ({
38
- state: { ...state.state, sidebarCollapsed: !state.state.sidebarCollapsed },
39
- })),
40
- setSidebarCollapsed: (collapsed) =>
41
- set((state) => ({
42
- state: { ...state.state, sidebarCollapsed: collapsed },
43
- })),
44
- setTheme: (theme) =>
45
- set((state) => ({
46
- state: { ...state.state, theme },
47
- })),
48
- },
49
- }),
50
- {
51
- name: 'ui-storage',
52
- partialize: (state) => ({ state: state.state }),
53
- }
54
- )
55
- )
1
+ import { create } from 'zustand'
2
+ import { persist } from 'zustand/middleware'
3
+
4
+ interface UiState {
5
+ state: {
6
+ sidebarOpen: boolean
7
+ sidebarCollapsed: boolean
8
+ theme: 'light' | 'dark' | 'system'
9
+ }
10
+ actions: {
11
+ toggleSidebar: () => void
12
+ setSidebarOpen: (open: boolean) => void
13
+ toggleSidebarCollapsed: () => void
14
+ setSidebarCollapsed: (collapsed: boolean) => void
15
+ setTheme: (theme: 'light' | 'dark' | 'system') => void
16
+ }
17
+ }
18
+
19
+ export const useUiStore = create<UiState>()(
20
+ persist(
21
+ (set) => ({
22
+ state: {
23
+ sidebarOpen: true,
24
+ sidebarCollapsed: false,
25
+ theme: 'system',
26
+ },
27
+ actions: {
28
+ toggleSidebar: () =>
29
+ set((state) => ({
30
+ state: { ...state.state, sidebarOpen: !state.state.sidebarOpen },
31
+ })),
32
+ setSidebarOpen: (open) =>
33
+ set((state) => ({
34
+ state: { ...state.state, sidebarOpen: open },
35
+ })),
36
+ toggleSidebarCollapsed: () =>
37
+ set((state) => ({
38
+ state: { ...state.state, sidebarCollapsed: !state.state.sidebarCollapsed },
39
+ })),
40
+ setSidebarCollapsed: (collapsed) =>
41
+ set((state) => ({
42
+ state: { ...state.state, sidebarCollapsed: collapsed },
43
+ })),
44
+ setTheme: (theme) =>
45
+ set((state) => ({
46
+ state: { ...state.state, theme },
47
+ })),
48
+ },
49
+ }),
50
+ {
51
+ name: 'ui-storage',
52
+ partialize: (state) => ({ state: state.state }),
53
+ }
54
+ )
55
+ )
@@ -1,28 +1,28 @@
1
- export interface ApiResponse<T = unknown> {
2
- data: T
3
- success: boolean
4
- message?: string
5
- }
6
-
7
- export interface ApiError {
8
- message: string
9
- code?: string
10
- status?: number
11
- details?: Record<string, unknown>
12
- }
13
-
14
- export interface PaginatedResponse<T> {
15
- data: T[]
16
- pagination: {
17
- page: number
18
- pageSize: number
19
- total: number
20
- totalPages: number
21
- }
22
- }
23
-
24
- export interface ActionResult<T = void> {
25
- success: boolean
26
- data?: T
27
- error?: string
28
- }
1
+ export interface ApiResponse<T = unknown> {
2
+ data: T
3
+ success: boolean
4
+ message?: string
5
+ }
6
+
7
+ export interface ApiError {
8
+ message: string
9
+ code?: string
10
+ status?: number
11
+ details?: Record<string, unknown>
12
+ }
13
+
14
+ export interface PaginatedResponse<T> {
15
+ data: T[]
16
+ pagination: {
17
+ page: number
18
+ pageSize: number
19
+ total: number
20
+ totalPages: number
21
+ }
22
+ }
23
+
24
+ export interface ActionResult<T = void> {
25
+ success: boolean
26
+ data?: T
27
+ error?: string
28
+ }
@@ -1,2 +1,2 @@
1
- export * from './api'
2
- export * from './table'
1
+ export * from './api'
2
+ export * from './table'
@@ -1,34 +1,34 @@
1
- import type { ColumnDef, Table, Row } from '@tanstack/react-table'
2
-
3
- export type DataTableColumn<TData, TValue = unknown> = ColumnDef<TData, TValue>
4
-
5
- export interface DataTableProps<TData, TValue> {
6
- columns: DataTableColumn<TData, TValue>[]
7
- data: TData[]
8
- searchKey?: string
9
- searchPlaceholder?: string
10
- }
11
-
12
- export interface DataTablePaginationProps<TData> {
13
- table: Table<TData>
14
- }
15
-
16
- export interface DataTableToolbarProps<TData> {
17
- table: Table<TData>
18
- searchKey?: string
19
- searchPlaceholder?: string
20
- }
21
-
22
- export interface DataTableRowActionsProps<TData> {
23
- row: Row<TData>
24
- }
25
-
26
- export interface DataTableFacetedFilterProps<TData, TValue> {
27
- column?: import('@tanstack/react-table').Column<TData, TValue>
28
- title?: string
29
- options: {
30
- label: string
31
- value: string
32
- icon?: React.ComponentType<{ className?: string }>
33
- }[]
34
- }
1
+ import type { ColumnDef, Table, Row } from '@tanstack/react-table'
2
+
3
+ export type DataTableColumn<TData, TValue = unknown> = ColumnDef<TData, TValue>
4
+
5
+ export interface DataTableProps<TData, TValue> {
6
+ columns: DataTableColumn<TData, TValue>[]
7
+ data: TData[]
8
+ searchKey?: string
9
+ searchPlaceholder?: string
10
+ }
11
+
12
+ export interface DataTablePaginationProps<TData> {
13
+ table: Table<TData>
14
+ }
15
+
16
+ export interface DataTableToolbarProps<TData> {
17
+ table: Table<TData>
18
+ searchKey?: string
19
+ searchPlaceholder?: string
20
+ }
21
+
22
+ export interface DataTableRowActionsProps<TData> {
23
+ row: Row<TData>
24
+ }
25
+
26
+ export interface DataTableFacetedFilterProps<TData, TValue> {
27
+ column?: import('@tanstack/react-table').Column<TData, TValue>
28
+ title?: string
29
+ options: {
30
+ label: string
31
+ value: string
32
+ icon?: React.ComponentType<{ className?: string }>
33
+ }[]
34
+ }