@nestledjs/data-browser 0.1.2 → 0.1.4

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 (83) hide show
  1. package/index.d.ts +15 -0
  2. package/index.js +64 -0
  3. package/lib/admin-data.d.ts +2 -0
  4. package/lib/components/filters/DateRangeFilter.d.ts +7 -0
  5. package/lib/components/filters/DateRangeFilter.js +105 -0
  6. package/lib/components/filters/NumberRangeFilter.d.ts +8 -0
  7. package/lib/components/filters/NumberRangeFilter.js +115 -0
  8. package/lib/components/filters/RelationComponents.d.ts +32 -0
  9. package/lib/components/filters/RelationComponents.js +265 -0
  10. package/lib/components/filters/RelationFilterField.d.ts +8 -0
  11. package/lib/components/filters/RelationFilterField.js +116 -0
  12. package/lib/components/filters/index.d.ts +4 -0
  13. package/lib/components/index.d.ts +2 -0
  14. package/lib/components/shared/AdminBreadcrumbs.d.ts +13 -0
  15. package/lib/components/shared/AdminBreadcrumbs.js +103 -0
  16. package/lib/components/shared/AdminErrorStates.d.ts +30 -0
  17. package/lib/components/shared/AdminErrorStates.js +214 -0
  18. package/lib/components/shared/AdminStatusDisplay.d.ts +21 -0
  19. package/lib/components/shared/AdminStatusDisplay.js +205 -0
  20. package/lib/components/shared/index.d.ts +3 -0
  21. package/lib/context/AdminDataContext.d.ts +47 -0
  22. package/lib/context/AdminDataContext.js +28 -0
  23. package/lib/hooks/useAdminList.d.ts +5 -0
  24. package/lib/hooks/useAdminList.js +41 -0
  25. package/lib/hooks/useClickOutside.d.ts +2 -0
  26. package/lib/hooks/useClickOutside.js +13 -0
  27. package/lib/hooks/useDebounce.d.ts +1 -0
  28. package/lib/hooks/useDebounce.js +13 -0
  29. package/lib/hooks/useRelationData.d.ts +7 -0
  30. package/lib/hooks/useRelationData.js +64 -0
  31. package/lib/layouts/AdminDataLayout.d.ts +5 -0
  32. package/lib/layouts/AdminDataLayout.js +315 -0
  33. package/lib/pages/AdminDataCreatePage.d.ts +4 -0
  34. package/lib/pages/AdminDataCreatePage.js +487 -0
  35. package/lib/pages/AdminDataEditPage.d.ts +4 -0
  36. package/lib/pages/AdminDataEditPage.js +903 -0
  37. package/lib/pages/AdminDataIndexPage.d.ts +4 -0
  38. package/lib/pages/AdminDataIndexPage.js +91 -0
  39. package/lib/pages/AdminDataListPage.d.ts +9 -0
  40. package/lib/pages/AdminDataListPage.js +1218 -0
  41. package/lib/types/index.d.ts +60 -0
  42. package/lib/types/index.js +16 -0
  43. package/lib/utils/graphql-utils.d.ts +25 -0
  44. package/lib/utils/graphql-utils.js +265 -0
  45. package/lib/utils/secure-storage.d.ts +50 -0
  46. package/lib/utils/secure-storage.js +145 -0
  47. package/lib/utils/string-utils.d.ts +6 -0
  48. package/lib/utils/string-utils.js +27 -0
  49. package/package.json +8 -2
  50. package/.babelrc +0 -12
  51. package/LICENSE +0 -21
  52. package/eslint.config.mjs +0 -12
  53. package/project.json +0 -35
  54. package/src/index.ts +0 -28
  55. package/src/lib/admin-data.spec.tsx +0 -10
  56. package/src/lib/admin-data.tsx +0 -9
  57. package/src/lib/components/filters/DateRangeFilter.tsx +0 -88
  58. package/src/lib/components/filters/NumberRangeFilter.tsx +0 -111
  59. package/src/lib/components/filters/RelationComponents.tsx +0 -176
  60. package/src/lib/components/filters/RelationFilterField.tsx +0 -106
  61. package/src/lib/components/filters/index.ts +0 -5
  62. package/src/lib/components/index.ts +0 -2
  63. package/src/lib/components/shared/AdminBreadcrumbs.tsx +0 -88
  64. package/src/lib/components/shared/AdminErrorStates.tsx +0 -180
  65. package/src/lib/components/shared/AdminStatusDisplay.tsx +0 -292
  66. package/src/lib/components/shared/index.ts +0 -3
  67. package/src/lib/context/AdminDataContext.tsx +0 -74
  68. package/src/lib/hooks/useAdminList.ts +0 -42
  69. package/src/lib/hooks/useClickOutside.ts +0 -21
  70. package/src/lib/hooks/useDebounce.ts +0 -16
  71. package/src/lib/hooks/useRelationData.ts +0 -114
  72. package/src/lib/layouts/AdminDataLayout.tsx +0 -251
  73. package/src/lib/pages/AdminDataCreatePage.tsx +0 -415
  74. package/src/lib/pages/AdminDataEditPage.tsx +0 -777
  75. package/src/lib/pages/AdminDataIndexPage.tsx +0 -50
  76. package/src/lib/pages/AdminDataListPage.tsx +0 -921
  77. package/src/lib/types/index.ts +0 -51
  78. package/src/lib/utils/graphql-utils.ts +0 -538
  79. package/src/lib/utils/secure-storage.ts +0 -305
  80. package/src/lib/utils/string-utils.ts +0 -53
  81. package/tsconfig.json +0 -17
  82. package/tsconfig.lib.json +0 -20
  83. package/vite.config.ts +0 -35
@@ -1,180 +0,0 @@
1
- import React from 'react'
2
- import { ExclamationTriangleIcon, ExclamationCircleIcon, XCircleIcon } from '@heroicons/react/24/outline'
3
-
4
- export type ErrorSeverity = 'warning' | 'error' | 'critical'
5
-
6
- export interface AdminErrorStateProps {
7
- readonly title: string
8
- readonly message?: string
9
- readonly severity?: ErrorSeverity
10
- readonly onRetry?: () => void
11
- readonly onDismiss?: () => void
12
- readonly className?: string
13
- readonly showIcon?: boolean
14
- }
15
-
16
- export interface AdminEmptyStateProps {
17
- readonly title: string
18
- readonly message?: string
19
- readonly actionLabel?: string
20
- readonly onAction?: () => void
21
- readonly className?: string
22
- readonly icon?: React.ComponentType<{ className?: string }>
23
- }
24
-
25
- export interface AdminLoadingStateProps {
26
- readonly title?: string
27
- readonly message?: string
28
- readonly className?: string
29
- readonly size?: 'small' | 'medium' | 'large'
30
- }
31
-
32
- const getSeverityConfig = (severity: ErrorSeverity) => {
33
- const configs = {
34
- warning: {
35
- icon: ExclamationTriangleIcon,
36
- bgColor: 'bg-yellow-50',
37
- borderColor: 'border-yellow-200',
38
- iconColor: 'text-yellow-400',
39
- titleColor: 'text-yellow-800',
40
- messageColor: 'text-yellow-700',
41
- buttonColor: 'bg-yellow-100 text-yellow-800 hover:bg-yellow-200',
42
- },
43
- error: {
44
- icon: ExclamationCircleIcon,
45
- bgColor: 'bg-red-50',
46
- borderColor: 'border-red-200',
47
- iconColor: 'text-red-400',
48
- titleColor: 'text-red-800',
49
- messageColor: 'text-red-700',
50
- buttonColor: 'bg-red-100 text-red-800 hover:bg-red-200',
51
- },
52
- critical: {
53
- icon: XCircleIcon,
54
- bgColor: 'bg-red-100',
55
- borderColor: 'border-red-300',
56
- iconColor: 'text-red-500',
57
- titleColor: 'text-red-900',
58
- messageColor: 'text-red-800',
59
- buttonColor: 'bg-red-200 text-red-900 hover:bg-red-300',
60
- },
61
- }
62
- return configs[severity]
63
- }
64
-
65
- export function AdminErrorState({
66
- title,
67
- message,
68
- severity = 'error',
69
- onRetry,
70
- onDismiss,
71
- className = '',
72
- showIcon = true,
73
- }: Readonly<AdminErrorStateProps>) {
74
- const config = getSeverityConfig(severity)
75
- const IconComponent = config.icon
76
-
77
- return (
78
- <div className={`rounded-md border p-4 ${config.bgColor} ${config.borderColor} ${className}`}>
79
- <div className="flex">
80
- {showIcon && (
81
- <div className="flex-shrink-0">
82
- <IconComponent className={`h-5 w-5 ${config.iconColor}`} aria-hidden="true" />
83
- </div>
84
- )}
85
- <div className={showIcon ? 'ml-3' : ''}>
86
- <h3 className={`text-sm font-medium ${config.titleColor}`}>
87
- {title}
88
- </h3>
89
- {message && (
90
- <div className={`mt-2 text-sm ${config.messageColor}`}>
91
- <p>{message}</p>
92
- </div>
93
- )}
94
- {(onRetry || onDismiss) && (
95
- <div className="mt-4">
96
- <div className="-mx-2 -my-1.5 flex">
97
- {onRetry && (
98
- <button
99
- type="button"
100
- onClick={onRetry}
101
- className={`rounded-md px-2 py-1.5 text-sm font-medium ${config.buttonColor} focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500`}
102
- >
103
- Try Again
104
- </button>
105
- )}
106
- {onDismiss && (
107
- <button
108
- type="button"
109
- onClick={onDismiss}
110
- className={`ml-3 rounded-md px-2 py-1.5 text-sm font-medium ${config.buttonColor} focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500`}
111
- >
112
- Dismiss
113
- </button>
114
- )}
115
- </div>
116
- </div>
117
- )}
118
- </div>
119
- </div>
120
- </div>
121
- )
122
- }
123
-
124
- export function AdminEmptyState({
125
- title,
126
- message,
127
- actionLabel,
128
- onAction,
129
- className = '',
130
- icon: IconComponent,
131
- }: Readonly<AdminEmptyStateProps>) {
132
- return (
133
- <div className={`text-center ${className}`}>
134
- {IconComponent && (
135
- <IconComponent className="mx-auto h-12 w-12 text-gray-400" />
136
- )}
137
- <h3 className="mt-2 text-sm font-medium text-gray-900">{title}</h3>
138
- {message && (
139
- <p className="mt-1 text-sm text-gray-500">{message}</p>
140
- )}
141
- {actionLabel && onAction && (
142
- <div className="mt-6">
143
- <button
144
- type="button"
145
- onClick={onAction}
146
- className="inline-flex items-center rounded-md bg-green-web px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-web-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-web"
147
- >
148
- {actionLabel}
149
- </button>
150
- </div>
151
- )}
152
- </div>
153
- )
154
- }
155
-
156
- export function AdminLoadingState({
157
- title = 'Loading...',
158
- message,
159
- className = '',
160
- size = 'medium',
161
- }: Readonly<AdminLoadingStateProps>) {
162
- const getSizeClasses = () => {
163
- const sizes = {
164
- small: 'h-4 w-4',
165
- medium: 'h-8 w-8',
166
- large: 'h-12 w-12',
167
- }
168
- return sizes[size]
169
- }
170
-
171
- return (
172
- <div className={`flex flex-col items-center justify-center p-8 ${className}`}>
173
- <div className={`animate-spin rounded-full border-b-2 border-green-web ${getSizeClasses()}`}></div>
174
- <h3 className="mt-4 text-sm font-medium text-gray-900">{title}</h3>
175
- {message && (
176
- <p className="mt-1 text-sm text-gray-500">{message}</p>
177
- )}
178
- </div>
179
- )
180
- }
@@ -1,292 +0,0 @@
1
- import React from 'react'
2
- import {
3
- CheckCircleIcon,
4
- XCircleIcon,
5
- ExclamationTriangleIcon,
6
- ClockIcon,
7
- QuestionMarkCircleIcon,
8
- PauseCircleIcon,
9
- } from '@heroicons/react/24/solid'
10
-
11
- export type StatusType =
12
- | 'active'
13
- | 'inactive'
14
- | 'pending'
15
- | 'approved'
16
- | 'rejected'
17
- | 'warning'
18
- | 'error'
19
- | 'success'
20
- | 'paused'
21
- | 'unknown'
22
-
23
- export type StatusSize = 'small' | 'medium' | 'large'
24
- export type StatusVariant = 'badge' | 'pill' | 'dot' | 'full'
25
-
26
- export interface AdminStatusDisplayProps {
27
- readonly status: StatusType
28
- readonly label?: string
29
- readonly size?: StatusSize
30
- readonly variant?: StatusVariant
31
- readonly showIcon?: boolean
32
- readonly className?: string
33
- readonly onClick?: () => void
34
- readonly tooltip?: string
35
- }
36
-
37
- export interface AdminUserStatusProps {
38
- readonly status: 'online' | 'offline' | 'away' | 'busy'
39
- readonly showLabel?: boolean
40
- readonly size?: StatusSize
41
- readonly className?: string
42
- }
43
-
44
- interface StatusConfig {
45
- icon: React.ComponentType<{ className?: string }>
46
- bgColor: string
47
- textColor: string
48
- borderColor: string
49
- defaultLabel: string
50
- }
51
-
52
- // Extract status configuration logic
53
- const getStatusConfig = (status: StatusType): StatusConfig => {
54
- const configs: Record<StatusType, StatusConfig> = {
55
- active: {
56
- icon: CheckCircleIcon,
57
- bgColor: 'bg-green-100',
58
- textColor: 'text-green-800',
59
- borderColor: 'border-green-200',
60
- defaultLabel: 'Active',
61
- },
62
- inactive: {
63
- icon: XCircleIcon,
64
- bgColor: 'bg-gray-100',
65
- textColor: 'text-gray-800',
66
- borderColor: 'border-gray-200',
67
- defaultLabel: 'Inactive',
68
- },
69
- pending: {
70
- icon: ClockIcon,
71
- bgColor: 'bg-yellow-100',
72
- textColor: 'text-yellow-800',
73
- borderColor: 'border-yellow-200',
74
- defaultLabel: 'Pending',
75
- },
76
- approved: {
77
- icon: CheckCircleIcon,
78
- bgColor: 'bg-green-100',
79
- textColor: 'text-green-800',
80
- borderColor: 'border-green-200',
81
- defaultLabel: 'Approved',
82
- },
83
- rejected: {
84
- icon: XCircleIcon,
85
- bgColor: 'bg-red-100',
86
- textColor: 'text-red-800',
87
- borderColor: 'border-red-200',
88
- defaultLabel: 'Rejected',
89
- },
90
- warning: {
91
- icon: ExclamationTriangleIcon,
92
- bgColor: 'bg-yellow-100',
93
- textColor: 'text-yellow-800',
94
- borderColor: 'border-yellow-200',
95
- defaultLabel: 'Warning',
96
- },
97
- error: {
98
- icon: XCircleIcon,
99
- bgColor: 'bg-red-100',
100
- textColor: 'text-red-800',
101
- borderColor: 'border-red-200',
102
- defaultLabel: 'Error',
103
- },
104
- success: {
105
- icon: CheckCircleIcon,
106
- bgColor: 'bg-green-100',
107
- textColor: 'text-green-800',
108
- borderColor: 'border-green-200',
109
- defaultLabel: 'Success',
110
- },
111
- paused: {
112
- icon: PauseCircleIcon,
113
- bgColor: 'bg-blue-100',
114
- textColor: 'text-blue-800',
115
- borderColor: 'border-blue-200',
116
- defaultLabel: 'Paused',
117
- },
118
- unknown: {
119
- icon: QuestionMarkCircleIcon,
120
- bgColor: 'bg-gray-100',
121
- textColor: 'text-gray-800',
122
- borderColor: 'border-gray-200',
123
- defaultLabel: 'Unknown',
124
- },
125
- }
126
-
127
- return configs[status]
128
- }
129
-
130
- // Extract size configuration logic
131
- const getSizeClasses = (size: StatusSize) => {
132
- const sizeClasses = {
133
- small: {
134
- text: 'text-xs',
135
- padding: 'px-2 py-1',
136
- icon: 'h-3 w-3',
137
- dot: 'h-2 w-2',
138
- },
139
- medium: {
140
- text: 'text-sm',
141
- padding: 'px-2.5 py-1.5',
142
- icon: 'h-4 w-4',
143
- dot: 'h-3 w-3',
144
- },
145
- large: {
146
- text: 'text-base',
147
- padding: 'px-3 py-2',
148
- icon: 'h-5 w-5',
149
- dot: 'h-4 w-4',
150
- },
151
- }
152
-
153
- return sizeClasses[size]
154
- }
155
-
156
- // Extract variant styling logic
157
- const getVariantClasses = (variant: StatusVariant) => {
158
- const variantClasses = {
159
- badge: 'inline-flex items-center rounded border font-medium',
160
- pill: 'inline-flex items-center rounded-full border font-medium',
161
- dot: 'inline-flex items-center font-medium',
162
- full: 'flex items-center justify-center rounded border font-medium w-full',
163
- }
164
-
165
- return variantClasses[variant]
166
- }
167
-
168
- // Extract user status configuration logic
169
- const getUserStatusConfig = (status: AdminUserStatusProps['status']) => {
170
- const configs = {
171
- online: {
172
- color: 'bg-green-400',
173
- label: 'Online',
174
- },
175
- offline: {
176
- color: 'bg-gray-400',
177
- label: 'Offline',
178
- },
179
- away: {
180
- color: 'bg-yellow-400',
181
- label: 'Away',
182
- },
183
- busy: {
184
- color: 'bg-red-400',
185
- label: 'Busy',
186
- },
187
- }
188
-
189
- return configs[status]
190
- }
191
-
192
- export function AdminStatusDisplay({
193
- status,
194
- label,
195
- size = 'medium',
196
- variant = 'badge',
197
- showIcon = true,
198
- className = '',
199
- onClick,
200
- tooltip,
201
- }: Readonly<AdminStatusDisplayProps>) {
202
- const config = getStatusConfig(status)
203
- const sizeClasses = getSizeClasses(size)
204
- const variantClasses = getVariantClasses(variant)
205
- const IconComponent = config.icon
206
-
207
- const displayLabel = label || config.defaultLabel
208
-
209
- const shouldShowDot = variant === 'dot'
210
- const shouldShowIcon = showIcon && !shouldShowDot
211
- const isClickable = !!onClick
212
-
213
- const baseClasses = `${variantClasses} ${sizeClasses.text} ${sizeClasses.padding} ${config.bgColor} ${config.textColor} ${config.borderColor}`
214
- const interactiveClasses = isClickable ? 'cursor-pointer hover:opacity-80' : ''
215
- const finalClasses = `${baseClasses} ${interactiveClasses} ${className}`.trim()
216
-
217
- const renderDot = () => {
218
- if (!shouldShowDot) return null
219
-
220
- return (
221
- <span className={`inline-block rounded-full mr-2 ${config.bgColor.replace('bg-', 'bg-').replace('-100', '-400')} ${sizeClasses.dot}`} />
222
- )
223
- }
224
-
225
- const renderIcon = () => {
226
- if (!shouldShowIcon) return null
227
-
228
- return (
229
- <IconComponent className={`${sizeClasses.icon} ${displayLabel ? 'mr-1.5' : ''}`} />
230
- )
231
- }
232
-
233
- const content = (
234
- <>
235
- {renderDot()}
236
- {renderIcon()}
237
- {displayLabel}
238
- </>
239
- )
240
-
241
- const handleClick = () => {
242
- if (onClick) {
243
- onClick()
244
- }
245
- }
246
-
247
- if (isClickable) {
248
- return (
249
- <button
250
- type="button"
251
- onClick={handleClick}
252
- className={finalClasses}
253
- title={tooltip}
254
- >
255
- {content}
256
- </button>
257
- )
258
- }
259
-
260
- return (
261
- <span className={finalClasses} title={tooltip}>
262
- {content}
263
- </span>
264
- )
265
- }
266
-
267
- export function AdminUserStatus({
268
- status,
269
- showLabel = false,
270
- size = 'medium',
271
- className = '',
272
- }: Readonly<AdminUserStatusProps>) {
273
- const config = getUserStatusConfig(status)
274
- const sizeClasses = getSizeClasses(size)
275
-
276
- const dotSizeClass = sizeClasses.dot
277
- const textSizeClass = showLabel ? sizeClasses.text : ''
278
-
279
- return (
280
- <div className={`inline-flex items-center ${className}`}>
281
- <span
282
- className={`inline-block rounded-full ${config.color} ${dotSizeClass}`}
283
- aria-label={config.label}
284
- />
285
- {showLabel && (
286
- <span className={`ml-2 text-gray-700 ${textSizeClass}`}>
287
- {config.label}
288
- </span>
289
- )}
290
- </div>
291
- )
292
- }
@@ -1,3 +0,0 @@
1
- export * from './AdminBreadcrumbs'
2
- export * from './AdminErrorStates'
3
- export * from './AdminStatusDisplay'
@@ -1,74 +0,0 @@
1
- import { createContext, useContext, type ReactNode } from 'react'
2
-
3
- export interface AdminDataContextValue {
4
- /** The SDK namespace for dynamic GraphQL document lookups */
5
- sdk: any
6
- /** Array of database models from Prisma schema */
7
- databaseModels: any[]
8
- /** Base path for admin data routes (e.g., "/admin/data") */
9
- basePath?: string
10
- /** Form theme configuration for @nestledjs/forms */
11
- formTheme: any
12
- }
13
-
14
- const AdminDataContext = createContext<AdminDataContextValue | null>(null)
15
-
16
- export interface AdminDataProviderProps {
17
- children: ReactNode
18
- /** The entire SDK namespace (e.g., import * as Sdk from '@your-project/shared/sdk') */
19
- sdk: any
20
- /** DATABASE_MODELS array from your SDK */
21
- databaseModels: any[]
22
- /** Optional base path for routes (defaults to "/admin/data") */
23
- basePath?: string
24
- /** Form theme configuration for @nestledjs/forms */
25
- formTheme: any
26
- }
27
-
28
- /**
29
- * Provider component that supplies SDK and database models to admin data components
30
- *
31
- * @example
32
- * ```tsx
33
- * import * as Sdk from '@your-project/shared/sdk'
34
- * import { DATABASE_MODELS } from '@your-project/shared/sdk'
35
- * import { AdminDataProvider } from '@nestledjs/admin-data'
36
- *
37
- * <AdminDataProvider
38
- * sdk={Sdk}
39
- * databaseModels={DATABASE_MODELS}
40
- * formTheme={formTheme}
41
- * basePath="/admin/data"
42
- * >
43
- * <AdminDataLayout />
44
- * </AdminDataProvider>
45
- * ```
46
- */
47
- export function AdminDataProvider({
48
- children,
49
- sdk,
50
- databaseModels,
51
- basePath = '/admin/data',
52
- formTheme
53
- }: AdminDataProviderProps) {
54
- return (
55
- <AdminDataContext.Provider value={{ sdk, databaseModels, basePath, formTheme }}>
56
- {children}
57
- </AdminDataContext.Provider>
58
- )
59
- }
60
-
61
- /**
62
- * Hook to access the admin data context
63
- * @throws Error if used outside of AdminDataProvider
64
- */
65
- export function useAdminDataContext() {
66
- const context = useContext(AdminDataContext)
67
- if (!context) {
68
- throw new Error(
69
- 'useAdminDataContext must be used within AdminDataProvider. ' +
70
- 'Make sure to wrap your admin data routes with <AdminDataProvider>.'
71
- )
72
- }
73
- return context
74
- }
@@ -1,42 +0,0 @@
1
- import { useReducer } from 'react'
2
- import { AdminListAction, AdminListState, initialState } from '../types'
3
-
4
- // State reducer for performance optimization
5
- function adminListReducer(state: AdminListState, action: AdminListAction): AdminListState {
6
- switch (action.type) {
7
- case 'SET_SEARCH':
8
- return { ...state, search: action.payload }
9
- case 'SET_DEBOUNCED_SEARCH':
10
- return { ...state, debouncedSearch: action.payload }
11
- case 'SET_SKIP':
12
- return { ...state, skip: action.payload }
13
- case 'SET_PAGE_SIZE':
14
- return { ...state, pageSize: action.payload }
15
- case 'SET_SORT':
16
- return { ...state, sort: action.payload }
17
- case 'SET_VISIBLE_COLUMNS':
18
- return { ...state, visibleColumns: action.payload }
19
- case 'TOGGLE_COLUMN_SELECTOR':
20
- return { ...state, showColumnSelector: !state.showColumnSelector }
21
- case 'SET_SEARCH_FIELDS':
22
- return { ...state, searchFields: action.payload }
23
- case 'TOGGLE_SEARCH_FIELD_SELECTOR':
24
- return { ...state, showSearchFieldSelector: !state.showSearchFieldSelector }
25
- case 'SET_FILTERS':
26
- return { ...state, filters: action.payload }
27
- case 'TOGGLE_FILTERS':
28
- return { ...state, showFilters: !state.showFilters }
29
- case 'RESET_PAGINATION':
30
- return { ...state, skip: 0 }
31
- case 'RESET_FILTERS':
32
- return { ...state, filters: {} }
33
- default:
34
- return state
35
- }
36
- }
37
-
38
- export function useAdminList() {
39
- const [state, dispatch] = useReducer(adminListReducer, initialState)
40
-
41
- return { state, dispatch }
42
- }
@@ -1,21 +0,0 @@
1
- import React, { useEffect } from 'react'
2
-
3
- // Custom hook for click outside detection
4
- export function useClickOutside(
5
- ref: React.RefObject<HTMLDivElement | null>,
6
- handler: () => void,
7
- isActive = true
8
- ) {
9
- useEffect(() => {
10
- if (!isActive) return
11
-
12
- const handleClickOutside = (event: MouseEvent) => {
13
- if (ref.current && !ref.current.contains(event.target as Node)) {
14
- handler()
15
- }
16
- }
17
-
18
- document.addEventListener('mousedown', handleClickOutside)
19
- return () => document.removeEventListener('mousedown', handleClickOutside)
20
- }, [handler, isActive]) // Removed 'ref' from dependency array as refs are stable
21
- }
@@ -1,16 +0,0 @@
1
- import { useEffect, useState } from 'react'
2
-
3
- // Custom hook for debouncing values
4
- export function useDebounce<T>(value: T, delay: number): T {
5
- const [debouncedValue, setDebouncedValue] = useState<T>(value)
6
-
7
- useEffect(() => {
8
- const timer = setTimeout(() => {
9
- setDebouncedValue(value)
10
- }, delay)
11
-
12
- return () => clearTimeout(timer)
13
- }, [value, delay])
14
-
15
- return debouncedValue
16
- }