@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,59 +1,59 @@
1
- import { LucideIcon, LayoutDashboard, Users, FileText } from 'lucide-react'
2
-
3
- export interface NavItem {
4
- title: string
5
- href: string
6
- icon?: LucideIcon
7
- disabled?: boolean
8
- external?: boolean
9
- badge?: string
10
- }
11
-
12
- export interface NavSection {
13
- title?: string
14
- items: NavItem[]
15
- }
16
-
17
- export const mainNav: NavItem[] = [
18
- {
19
- title: 'Dashboard',
20
- href: '/dashboard',
21
- },
22
- {
23
- title: 'Usuarios',
24
- href: '/users',
25
- },
26
- ]
27
-
28
- export const sidebarNav: NavSection[] = [
29
- {
30
- items: [
31
- {
32
- title: 'Dashboard',
33
- href: '/dashboard',
34
- icon: LayoutDashboard,
35
- },
36
- {
37
- title: 'Usuarios',
38
- href: '/users',
39
- icon: Users,
40
- },
41
- {
42
- title: 'Reportes',
43
- href: '/reports',
44
- icon: FileText,
45
- },
46
- ],
47
- },
48
- ]
49
-
50
- export const footerNav: NavItem[] = [
51
- {
52
- title: 'Términos',
53
- href: '/terms',
54
- },
55
- {
56
- title: 'Privacidad',
57
- href: '/privacy',
58
- },
59
- ]
1
+ import { LucideIcon, LayoutDashboard, Users, FileText } from 'lucide-react'
2
+
3
+ export interface NavItem {
4
+ title: string
5
+ href: string
6
+ icon?: LucideIcon
7
+ disabled?: boolean
8
+ external?: boolean
9
+ badge?: string
10
+ }
11
+
12
+ export interface NavSection {
13
+ title?: string
14
+ items: NavItem[]
15
+ }
16
+
17
+ export const mainNav: NavItem[] = [
18
+ {
19
+ title: 'Dashboard',
20
+ href: '/dashboard',
21
+ },
22
+ {
23
+ title: 'Usuarios',
24
+ href: '/users',
25
+ },
26
+ ]
27
+
28
+ export const sidebarNav: NavSection[] = [
29
+ {
30
+ items: [
31
+ {
32
+ title: 'Dashboard',
33
+ href: '/dashboard',
34
+ icon: LayoutDashboard,
35
+ },
36
+ {
37
+ title: 'Usuarios',
38
+ href: '/users',
39
+ icon: Users,
40
+ },
41
+ {
42
+ title: 'Reportes',
43
+ href: '/reports',
44
+ icon: FileText,
45
+ },
46
+ ],
47
+ },
48
+ ]
49
+
50
+ export const footerNav: NavItem[] = [
51
+ {
52
+ title: 'Términos',
53
+ href: '/terms',
54
+ },
55
+ {
56
+ title: 'Privacidad',
57
+ href: '/privacy',
58
+ },
59
+ ]
@@ -1,27 +1,27 @@
1
- /**
2
- * Configuración centralizada de roles de usuario.
3
- * Modificar aquí para agregar/quitar roles en toda la aplicación.
4
- */
5
-
6
- export const USER_ROLES = ['admin', 'user', 'viewer'] as const
7
-
8
- export type UserRole = (typeof USER_ROLES)[number]
9
-
10
- export const DEFAULT_ROLE: UserRole = 'user'
11
-
12
- /**
13
- * Labels para mostrar en UI (traducidos al español)
14
- */
15
- export const ROLE_LABELS: Record<UserRole, string> = {
16
- admin: 'Administrador',
17
- user: 'Usuario',
18
- viewer: 'Visualizador',
19
- }
20
-
21
- /**
22
- * Opciones para selects/filtros de roles
23
- */
24
- export const ROLE_OPTIONS = USER_ROLES.map((role) => ({
25
- value: role,
26
- label: ROLE_LABELS[role],
27
- }))
1
+ /**
2
+ * Configuración centralizada de roles de usuario.
3
+ * Modificar aquí para agregar/quitar roles en toda la aplicación.
4
+ */
5
+
6
+ export const USER_ROLES = ['admin', 'user', 'viewer'] as const
7
+
8
+ export type UserRole = (typeof USER_ROLES)[number]
9
+
10
+ export const DEFAULT_ROLE: UserRole = 'user'
11
+
12
+ /**
13
+ * Labels para mostrar en UI (traducidos al español)
14
+ */
15
+ export const ROLE_LABELS: Record<UserRole, string> = {
16
+ admin: 'Administrador',
17
+ user: 'Usuario',
18
+ viewer: 'Visualizador',
19
+ }
20
+
21
+ /**
22
+ * Opciones para selects/filtros de roles
23
+ */
24
+ export const ROLE_OPTIONS = USER_ROLES.map((role) => ({
25
+ value: role,
26
+ label: ROLE_LABELS[role],
27
+ }))
@@ -1,12 +1,12 @@
1
- export const siteConfig = {
2
- name: 'LFT App',
3
- description: 'Next.js application with LFT stack',
4
- url: process.env.NEXT_PUBLIC_APP_URL ?? 'http://localhost:3000',
5
- ogImage: '/og.png',
6
- links: {
7
- github: 'https://github.com',
8
- },
9
- creator: 'LFT Team',
10
- }
11
-
12
- export type SiteConfig = typeof siteConfig
1
+ export const siteConfig = {
2
+ name: 'LFT App',
3
+ description: 'Next.js application with LFT stack',
4
+ url: process.env.NEXT_PUBLIC_APP_URL ?? 'http://localhost:3000',
5
+ ogImage: '/og.png',
6
+ links: {
7
+ github: 'https://github.com',
8
+ },
9
+ creator: 'LFT Team',
10
+ }
11
+
12
+ export type SiteConfig = typeof siteConfig
@@ -1,12 +1,12 @@
1
- import { drizzle } from 'drizzle-orm/postgres-js'
2
- import postgres from 'postgres'
3
- import * as schema from './schema'
4
-
5
- const connectionString = process.env.DATABASE_URL!
6
-
7
- // Disable prefetch as it is not supported for "Transaction" pool mode
8
- const client = postgres(connectionString, { prepare: false })
9
-
10
- export const db = drizzle(client, { schema })
11
-
12
- export type Database = typeof db
1
+ import { drizzle } from 'drizzle-orm/postgres-js'
2
+ import postgres from 'postgres'
3
+ import * as schema from './schema'
4
+
5
+ const connectionString = process.env.DATABASE_URL!
6
+
7
+ // Disable prefetch as it is not supported for "Transaction" pool mode
8
+ const client = postgres(connectionString, { prepare: false })
9
+
10
+ export const db = drizzle(client, { schema })
11
+
12
+ export type Database = typeof db
@@ -1 +1 @@
1
- export * from './users'
1
+ export * from './users'
@@ -1,16 +1,16 @@
1
- import { pgTable, uuid, varchar, text, timestamp, pgEnum } from 'drizzle-orm/pg-core'
2
-
3
- export const userRoleEnum = pgEnum('user_role', ['admin', 'user', 'viewer'])
4
-
5
- export const users = pgTable('users', {
6
- id: uuid('id').primaryKey().defaultRandom(),
7
- email: varchar('email', { length: 255 }).notNull().unique(),
8
- name: varchar('name', { length: 255 }).notNull(),
9
- role: userRoleEnum('role').default('user').notNull(),
10
- avatarUrl: text('avatar_url'),
11
- createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
12
- updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
13
- })
14
-
15
- export type User = typeof users.$inferSelect
16
- export type NewUser = typeof users.$inferInsert
1
+ import { pgTable, uuid, varchar, text, timestamp, pgEnum } from 'drizzle-orm/pg-core'
2
+
3
+ export const userRoleEnum = pgEnum('user_role', ['admin', 'user', 'viewer'])
4
+
5
+ export const users = pgTable('users', {
6
+ id: uuid('id').primaryKey().defaultRandom(),
7
+ email: varchar('email', { length: 255 }).notNull().unique(),
8
+ name: varchar('name', { length: 255 }).notNull(),
9
+ role: userRoleEnum('role').default('user').notNull(),
10
+ avatarUrl: text('avatar_url'),
11
+ createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
12
+ updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
13
+ })
14
+
15
+ export type User = typeof users.$inferSelect
16
+ export type NewUser = typeof users.$inferInsert
@@ -1,39 +1,39 @@
1
- import { db } from './index'
2
- import { users } from './schema'
3
-
4
- async function seed() {
5
- console.log('🌱 Seeding database...')
6
-
7
- // Clear existing data
8
- await db.delete(users)
9
-
10
- // Insert seed data
11
- await db.insert(users).values([
12
- {
13
- email: 'admin@example.com',
14
- name: 'Admin User',
15
- role: 'admin',
16
- },
17
- {
18
- email: 'user@example.com',
19
- name: 'Regular User',
20
- role: 'user',
21
- },
22
- {
23
- email: 'viewer@example.com',
24
- name: 'Viewer User',
25
- role: 'viewer',
26
- },
27
- ])
28
-
29
- console.log('✅ Database seeded successfully!')
30
- }
31
-
32
- seed()
33
- .catch((error) => {
34
- console.error('❌ Seed failed:', error)
35
- process.exit(1)
36
- })
37
- .finally(() => {
38
- process.exit(0)
39
- })
1
+ import { db } from './index'
2
+ import { users } from './schema'
3
+
4
+ async function seed() {
5
+ console.log('🌱 Seeding database...')
6
+
7
+ // Clear existing data
8
+ await db.delete(users)
9
+
10
+ // Insert seed data
11
+ await db.insert(users).values([
12
+ {
13
+ email: 'admin@example.com',
14
+ name: 'Admin User',
15
+ role: 'admin',
16
+ },
17
+ {
18
+ email: 'user@example.com',
19
+ name: 'Regular User',
20
+ role: 'user',
21
+ },
22
+ {
23
+ email: 'viewer@example.com',
24
+ name: 'Viewer User',
25
+ role: 'viewer',
26
+ },
27
+ ])
28
+
29
+ console.log('✅ Database seeded successfully!')
30
+ }
31
+
32
+ seed()
33
+ .catch((error) => {
34
+ console.error('❌ Seed failed:', error)
35
+ process.exit(1)
36
+ })
37
+ .finally(() => {
38
+ process.exit(0)
39
+ })
@@ -1,3 +1,3 @@
1
- export { useMediaQuery, useIsMobile, useIsTablet, useIsDesktop } from './useMediaQuery'
2
- export { useDebounce, useDebouncedCallback } from './useDebounce'
3
- export { useDataTable } from './useDataTable'
1
+ export { useMediaQuery, useIsMobile, useIsTablet, useIsDesktop } from './useMediaQuery'
2
+ export { useDebounce, useDebouncedCallback } from './useDebounce'
3
+ export { useDataTable } from './useDataTable'
@@ -1,21 +1,21 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
-
5
- const MOBILE_BREAKPOINT = 768
6
-
7
- export function useIsMobile() {
8
- const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
9
-
10
- React.useEffect(() => {
11
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
12
- const onChange = () => {
13
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
14
- }
15
- mql.addEventListener("change", onChange)
16
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
17
- return () => mql.removeEventListener("change", onChange)
18
- }, [])
19
-
20
- return !!isMobile
21
- }
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+
5
+ const MOBILE_BREAKPOINT = 768
6
+
7
+ export function useIsMobile() {
8
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
9
+
10
+ React.useEffect(() => {
11
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
12
+ const onChange = () => {
13
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
14
+ }
15
+ mql.addEventListener("change", onChange)
16
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
17
+ return () => mql.removeEventListener("change", onChange)
18
+ }, [])
19
+
20
+ return !!isMobile
21
+ }
@@ -1,82 +1,82 @@
1
- 'use client'
2
-
3
- import { useState, useMemo } from 'react'
4
- import {
5
- ColumnDef,
6
- ColumnFiltersState,
7
- SortingState,
8
- VisibilityState,
9
- getCoreRowModel,
10
- getFilteredRowModel,
11
- getPaginationRowModel,
12
- getSortedRowModel,
13
- useReactTable,
14
- TableOptions,
15
- } from '@tanstack/react-table'
16
-
17
- interface UseDataTableOptions<TData> {
18
- data: TData[]
19
- columns: ColumnDef<TData, unknown>[]
20
- initialPageSize?: number
21
- enableRowSelection?: boolean
22
- }
23
-
24
- export function useDataTable<TData>({
25
- data,
26
- columns,
27
- initialPageSize = 10,
28
- enableRowSelection = false,
29
- }: UseDataTableOptions<TData>) {
30
- const [sorting, setSorting] = useState<SortingState>([])
31
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
32
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
33
- const [rowSelection, setRowSelection] = useState({})
34
-
35
- const tableOptions: TableOptions<TData> = useMemo(
36
- () => ({
37
- data,
38
- columns,
39
- getCoreRowModel: getCoreRowModel(),
40
- getPaginationRowModel: getPaginationRowModel(),
41
- onSortingChange: setSorting,
42
- getSortedRowModel: getSortedRowModel(),
43
- onColumnFiltersChange: setColumnFilters,
44
- getFilteredRowModel: getFilteredRowModel(),
45
- onColumnVisibilityChange: setColumnVisibility,
46
- onRowSelectionChange: setRowSelection,
47
- enableRowSelection,
48
- state: {
49
- sorting,
50
- columnFilters,
51
- columnVisibility,
52
- rowSelection,
53
- },
54
- initialState: {
55
- pagination: {
56
- pageSize: initialPageSize,
57
- },
58
- },
59
- }),
60
- [data, columns, sorting, columnFilters, columnVisibility, rowSelection, enableRowSelection, initialPageSize]
61
- )
62
-
63
- const table = useReactTable(tableOptions)
64
-
65
- const selectedRows = useMemo(
66
- () => table.getFilteredSelectedRowModel().rows.map((row) => row.original),
67
- [table]
68
- )
69
-
70
- return {
71
- table,
72
- sorting,
73
- columnFilters,
74
- columnVisibility,
75
- rowSelection,
76
- selectedRows,
77
- setSorting,
78
- setColumnFilters,
79
- setColumnVisibility,
80
- setRowSelection,
81
- }
82
- }
1
+ 'use client'
2
+
3
+ import { useState, useMemo } from 'react'
4
+ import {
5
+ ColumnDef,
6
+ ColumnFiltersState,
7
+ SortingState,
8
+ VisibilityState,
9
+ getCoreRowModel,
10
+ getFilteredRowModel,
11
+ getPaginationRowModel,
12
+ getSortedRowModel,
13
+ useReactTable,
14
+ TableOptions,
15
+ } from '@tanstack/react-table'
16
+
17
+ interface UseDataTableOptions<TData> {
18
+ data: TData[]
19
+ columns: ColumnDef<TData, unknown>[]
20
+ initialPageSize?: number
21
+ enableRowSelection?: boolean
22
+ }
23
+
24
+ export function useDataTable<TData>({
25
+ data,
26
+ columns,
27
+ initialPageSize = 10,
28
+ enableRowSelection = false,
29
+ }: UseDataTableOptions<TData>) {
30
+ const [sorting, setSorting] = useState<SortingState>([])
31
+ const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
32
+ const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
33
+ const [rowSelection, setRowSelection] = useState({})
34
+
35
+ const tableOptions: TableOptions<TData> = useMemo(
36
+ () => ({
37
+ data,
38
+ columns,
39
+ getCoreRowModel: getCoreRowModel(),
40
+ getPaginationRowModel: getPaginationRowModel(),
41
+ onSortingChange: setSorting,
42
+ getSortedRowModel: getSortedRowModel(),
43
+ onColumnFiltersChange: setColumnFilters,
44
+ getFilteredRowModel: getFilteredRowModel(),
45
+ onColumnVisibilityChange: setColumnVisibility,
46
+ onRowSelectionChange: setRowSelection,
47
+ enableRowSelection,
48
+ state: {
49
+ sorting,
50
+ columnFilters,
51
+ columnVisibility,
52
+ rowSelection,
53
+ },
54
+ initialState: {
55
+ pagination: {
56
+ pageSize: initialPageSize,
57
+ },
58
+ },
59
+ }),
60
+ [data, columns, sorting, columnFilters, columnVisibility, rowSelection, enableRowSelection, initialPageSize]
61
+ )
62
+
63
+ const table = useReactTable(tableOptions)
64
+
65
+ const selectedRows = useMemo(
66
+ () => table.getFilteredSelectedRowModel().rows.map((row) => row.original),
67
+ [table]
68
+ )
69
+
70
+ return {
71
+ table,
72
+ sorting,
73
+ columnFilters,
74
+ columnVisibility,
75
+ rowSelection,
76
+ selectedRows,
77
+ setSorting,
78
+ setColumnFilters,
79
+ setColumnVisibility,
80
+ setRowSelection,
81
+ }
82
+ }
@@ -1,49 +1,49 @@
1
- 'use client'
2
-
3
- import { useEffect, useState, useCallback, useRef } from 'react'
4
-
5
- export function useDebounce<T>(value: T, delay: number): T {
6
- const [debouncedValue, setDebouncedValue] = useState<T>(value)
7
-
8
- useEffect(() => {
9
- const timer = setTimeout(() => {
10
- setDebouncedValue(value)
11
- }, delay)
12
-
13
- return () => {
14
- clearTimeout(timer)
15
- }
16
- }, [value, delay])
17
-
18
- return debouncedValue
19
- }
20
-
21
- export function useDebouncedCallback<T extends (...args: Parameters<T>) => ReturnType<T>>(
22
- callback: T,
23
- delay: number
24
- ): T {
25
- const timeoutRef = useRef<NodeJS.Timeout | null>(null)
26
-
27
- const debouncedCallback = useCallback(
28
- (...args: Parameters<T>) => {
29
- if (timeoutRef.current) {
30
- clearTimeout(timeoutRef.current)
31
- }
32
-
33
- timeoutRef.current = setTimeout(() => {
34
- callback(...args)
35
- }, delay)
36
- },
37
- [callback, delay]
38
- ) as T
39
-
40
- useEffect(() => {
41
- return () => {
42
- if (timeoutRef.current) {
43
- clearTimeout(timeoutRef.current)
44
- }
45
- }
46
- }, [])
47
-
48
- return debouncedCallback
49
- }
1
+ 'use client'
2
+
3
+ import { useEffect, useState, useCallback, useRef } from 'react'
4
+
5
+ export function useDebounce<T>(value: T, delay: number): T {
6
+ const [debouncedValue, setDebouncedValue] = useState<T>(value)
7
+
8
+ useEffect(() => {
9
+ const timer = setTimeout(() => {
10
+ setDebouncedValue(value)
11
+ }, delay)
12
+
13
+ return () => {
14
+ clearTimeout(timer)
15
+ }
16
+ }, [value, delay])
17
+
18
+ return debouncedValue
19
+ }
20
+
21
+ export function useDebouncedCallback<T extends (...args: Parameters<T>) => ReturnType<T>>(
22
+ callback: T,
23
+ delay: number
24
+ ): T {
25
+ const timeoutRef = useRef<NodeJS.Timeout | null>(null)
26
+
27
+ const debouncedCallback = useCallback(
28
+ (...args: Parameters<T>) => {
29
+ if (timeoutRef.current) {
30
+ clearTimeout(timeoutRef.current)
31
+ }
32
+
33
+ timeoutRef.current = setTimeout(() => {
34
+ callback(...args)
35
+ }, delay)
36
+ },
37
+ [callback, delay]
38
+ ) as T
39
+
40
+ useEffect(() => {
41
+ return () => {
42
+ if (timeoutRef.current) {
43
+ clearTimeout(timeoutRef.current)
44
+ }
45
+ }
46
+ }, [])
47
+
48
+ return debouncedCallback
49
+ }