@startsimpli/hooks 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.
- package/package.json +6 -12
- package/dist/index.d.mts +0 -223
- package/dist/index.d.ts +0 -223
- package/dist/index.js +0 -398
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -384
- package/dist/index.mjs.map +0 -1
package/dist/index.js
DELETED
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var react = require('react');
|
|
4
|
-
var reactQuery = require('@tanstack/react-query');
|
|
5
|
-
|
|
6
|
-
// src/useTableFilters.ts
|
|
7
|
-
function useTableFilters(initial) {
|
|
8
|
-
const defaultFilters = {
|
|
9
|
-
page: 1,
|
|
10
|
-
pageSize: 20,
|
|
11
|
-
...initial
|
|
12
|
-
};
|
|
13
|
-
const [filters, setFilters] = react.useState(defaultFilters);
|
|
14
|
-
const setFilter = react.useCallback((key, value) => {
|
|
15
|
-
setFilters((prev) => ({ ...prev, [key]: value, page: 1 }));
|
|
16
|
-
}, []);
|
|
17
|
-
const setPage = react.useCallback((page) => {
|
|
18
|
-
setFilters((prev) => ({ ...prev, page }));
|
|
19
|
-
}, []);
|
|
20
|
-
const setPageSize = react.useCallback((pageSize) => {
|
|
21
|
-
setFilters((prev) => ({ ...prev, pageSize, page: 1 }));
|
|
22
|
-
}, []);
|
|
23
|
-
const setSearch = react.useCallback((search) => {
|
|
24
|
-
setFilters((prev) => ({ ...prev, search, page: 1 }));
|
|
25
|
-
}, []);
|
|
26
|
-
const setSort = react.useCallback((field, direction) => {
|
|
27
|
-
setFilters((prev) => ({ ...prev, sortField: field, sortDirection: direction }));
|
|
28
|
-
}, []);
|
|
29
|
-
const resetFilters = react.useCallback(() => {
|
|
30
|
-
setFilters(defaultFilters);
|
|
31
|
-
}, []);
|
|
32
|
-
return {
|
|
33
|
-
filters,
|
|
34
|
-
setFilter,
|
|
35
|
-
setPage,
|
|
36
|
-
setPageSize,
|
|
37
|
-
setSearch,
|
|
38
|
-
setSort,
|
|
39
|
-
resetFilters
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// src/filter-encoding.ts
|
|
44
|
-
function encodeFilterConfig(config) {
|
|
45
|
-
const json = JSON.stringify(config);
|
|
46
|
-
return btoa(json).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
47
|
-
}
|
|
48
|
-
function decodeFilterConfig(encoded) {
|
|
49
|
-
try {
|
|
50
|
-
const standardBase64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
51
|
-
const padded = standardBase64 + "===".slice(0, (4 - standardBase64.length % 4) % 4);
|
|
52
|
-
const decoded = atob(padded);
|
|
53
|
-
return JSON.parse(decoded);
|
|
54
|
-
} catch {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function parseUrlFilters(params) {
|
|
59
|
-
const result = {};
|
|
60
|
-
if (params.has("f")) result.f = params.get("f");
|
|
61
|
-
if (params.has("s")) result.s = params.get("s");
|
|
62
|
-
if (params.has("d")) result.d = params.get("d");
|
|
63
|
-
if (params.has("p")) {
|
|
64
|
-
const page = parseInt(params.get("p"), 10);
|
|
65
|
-
if (!isNaN(page) && page > 0) result.p = page;
|
|
66
|
-
}
|
|
67
|
-
if (params.has("l")) {
|
|
68
|
-
const limit = parseInt(params.get("l"), 10);
|
|
69
|
-
if (!isNaN(limit) && limit > 0 && limit <= 1e3) result.l = limit;
|
|
70
|
-
}
|
|
71
|
-
return result;
|
|
72
|
-
}
|
|
73
|
-
function createSimpleFilter(field, operator, value) {
|
|
74
|
-
return {
|
|
75
|
-
groups: [{ logic: "AND", conditions: [{ field, operator, value }] }],
|
|
76
|
-
globalLogic: "AND"
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
function mergeFilters(...configs) {
|
|
80
|
-
if (configs.length === 0) return { groups: [] };
|
|
81
|
-
if (configs.length === 1) return configs[0];
|
|
82
|
-
return {
|
|
83
|
-
groups: configs.map((config) => ({
|
|
84
|
-
logic: "AND",
|
|
85
|
-
conditions: [],
|
|
86
|
-
groups: config.groups
|
|
87
|
-
})),
|
|
88
|
-
globalLogic: "AND"
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
function getFilterDescription(config) {
|
|
92
|
-
if (config.groups.length === 0) return "No filters applied";
|
|
93
|
-
function describeGroup(group) {
|
|
94
|
-
const conditionDescs = group.conditions.map(
|
|
95
|
-
(c) => `${c.field} ${c.operator} ${c.value}`
|
|
96
|
-
);
|
|
97
|
-
const groupDescs2 = group.groups?.map((g) => `(${describeGroup(g)})`) ?? [];
|
|
98
|
-
return [...conditionDescs, ...groupDescs2].join(` ${group.logic} `);
|
|
99
|
-
}
|
|
100
|
-
const groupDescs = config.groups.map(describeGroup);
|
|
101
|
-
return groupDescs.join(` ${config.globalLogic ?? "AND"} `);
|
|
102
|
-
}
|
|
103
|
-
function useCRUDMutation(mutationFn, opts) {
|
|
104
|
-
const queryClient = reactQuery.useQueryClient();
|
|
105
|
-
return reactQuery.useMutation({
|
|
106
|
-
mutationFn,
|
|
107
|
-
onSuccess: (data, variables) => {
|
|
108
|
-
for (const key of opts.invalidateKeys) {
|
|
109
|
-
queryClient.invalidateQueries({ queryKey: key });
|
|
110
|
-
}
|
|
111
|
-
opts.onSuccess?.(data, variables);
|
|
112
|
-
},
|
|
113
|
-
onError: opts.onError
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
function useSavedViews({
|
|
117
|
-
resource,
|
|
118
|
-
loadFn,
|
|
119
|
-
saveFn,
|
|
120
|
-
updateFn,
|
|
121
|
-
deleteFn
|
|
122
|
-
}) {
|
|
123
|
-
const [state, setState] = react.useState({
|
|
124
|
-
views: [],
|
|
125
|
-
currentViewId: null,
|
|
126
|
-
loading: true,
|
|
127
|
-
error: null
|
|
128
|
-
});
|
|
129
|
-
const fetchViews = react.useCallback(async () => {
|
|
130
|
-
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
131
|
-
try {
|
|
132
|
-
const views = await loadFn(resource);
|
|
133
|
-
const defaultView = views.find((v) => v.isDefault);
|
|
134
|
-
setState((prev) => ({
|
|
135
|
-
...prev,
|
|
136
|
-
views,
|
|
137
|
-
currentViewId: defaultView?.id || null,
|
|
138
|
-
loading: false
|
|
139
|
-
}));
|
|
140
|
-
} catch (error) {
|
|
141
|
-
setState((prev) => ({
|
|
142
|
-
...prev,
|
|
143
|
-
loading: false,
|
|
144
|
-
error: error instanceof Error ? error.message : "Failed to load views"
|
|
145
|
-
}));
|
|
146
|
-
}
|
|
147
|
-
}, [resource, loadFn]);
|
|
148
|
-
react.useEffect(() => {
|
|
149
|
-
fetchViews();
|
|
150
|
-
}, [fetchViews]);
|
|
151
|
-
const saveView = react.useCallback(
|
|
152
|
-
async (viewData) => {
|
|
153
|
-
const newView = await saveFn(resource, viewData);
|
|
154
|
-
setState((prev) => ({
|
|
155
|
-
...prev,
|
|
156
|
-
views: [...prev.views, newView],
|
|
157
|
-
currentViewId: newView.id
|
|
158
|
-
}));
|
|
159
|
-
return newView;
|
|
160
|
-
},
|
|
161
|
-
[resource, saveFn]
|
|
162
|
-
);
|
|
163
|
-
const updateView = react.useCallback(
|
|
164
|
-
async (viewId, updates) => {
|
|
165
|
-
await updateFn(resource, viewId, updates);
|
|
166
|
-
await fetchViews();
|
|
167
|
-
},
|
|
168
|
-
[resource, updateFn, fetchViews]
|
|
169
|
-
);
|
|
170
|
-
const deleteView = react.useCallback(
|
|
171
|
-
async (viewId) => {
|
|
172
|
-
await deleteFn(resource, viewId);
|
|
173
|
-
setState((prev) => ({
|
|
174
|
-
...prev,
|
|
175
|
-
views: prev.views.filter((v) => v.id !== viewId),
|
|
176
|
-
currentViewId: prev.currentViewId === viewId ? null : prev.currentViewId
|
|
177
|
-
}));
|
|
178
|
-
},
|
|
179
|
-
[resource, deleteFn]
|
|
180
|
-
);
|
|
181
|
-
const loadView = react.useCallback((viewId) => {
|
|
182
|
-
setState((prev) => ({ ...prev, currentViewId: viewId }));
|
|
183
|
-
}, []);
|
|
184
|
-
const getCurrentView = react.useCallback(() => {
|
|
185
|
-
return state.views.find((v) => v.id === state.currentViewId) || null;
|
|
186
|
-
}, [state.views, state.currentViewId]);
|
|
187
|
-
return {
|
|
188
|
-
views: state.views,
|
|
189
|
-
currentViewId: state.currentViewId,
|
|
190
|
-
loading: state.loading,
|
|
191
|
-
error: state.error,
|
|
192
|
-
saveView,
|
|
193
|
-
updateView,
|
|
194
|
-
deleteView,
|
|
195
|
-
loadView,
|
|
196
|
-
getCurrentView,
|
|
197
|
-
refreshViews: fetchViews
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
function useRecentlyViewed(storageKey, maxItems = 5) {
|
|
201
|
-
const [items, setItems] = react.useState([]);
|
|
202
|
-
react.useEffect(() => {
|
|
203
|
-
if (typeof window === "undefined") return;
|
|
204
|
-
try {
|
|
205
|
-
const raw = localStorage.getItem(storageKey);
|
|
206
|
-
if (raw) {
|
|
207
|
-
setItems(JSON.parse(raw));
|
|
208
|
-
}
|
|
209
|
-
} catch {
|
|
210
|
-
}
|
|
211
|
-
}, [storageKey]);
|
|
212
|
-
const persist = react.useCallback(
|
|
213
|
-
(updated) => {
|
|
214
|
-
if (typeof window === "undefined") return;
|
|
215
|
-
try {
|
|
216
|
-
localStorage.setItem(storageKey, JSON.stringify(updated));
|
|
217
|
-
} catch {
|
|
218
|
-
}
|
|
219
|
-
},
|
|
220
|
-
[storageKey]
|
|
221
|
-
);
|
|
222
|
-
const trackView = react.useCallback(
|
|
223
|
-
(item) => {
|
|
224
|
-
setItems((prev) => {
|
|
225
|
-
const deduped = prev.filter((entry) => entry.item.id !== item.id);
|
|
226
|
-
const updated = [{ item, viewedAt: Date.now() }, ...deduped].slice(0, maxItems);
|
|
227
|
-
persist(updated);
|
|
228
|
-
return updated;
|
|
229
|
-
});
|
|
230
|
-
},
|
|
231
|
-
[maxItems, persist]
|
|
232
|
-
);
|
|
233
|
-
const clear = react.useCallback(() => {
|
|
234
|
-
setItems([]);
|
|
235
|
-
if (typeof window === "undefined") return;
|
|
236
|
-
try {
|
|
237
|
-
localStorage.removeItem(storageKey);
|
|
238
|
-
} catch {
|
|
239
|
-
}
|
|
240
|
-
}, [storageKey]);
|
|
241
|
-
return {
|
|
242
|
-
items: items.map((entry) => entry.item),
|
|
243
|
-
timestamps: items.map((entry) => ({ id: entry.item.id, viewedAt: entry.viewedAt })),
|
|
244
|
-
trackView,
|
|
245
|
-
clear
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
function useWizard(steps, initialStep) {
|
|
249
|
-
const [currentStep, setCurrentStep] = react.useState(initialStep ?? steps[0]);
|
|
250
|
-
const stepIndex = steps.indexOf(currentStep);
|
|
251
|
-
const totalSteps = steps.length;
|
|
252
|
-
const isFirstStep = stepIndex === 0;
|
|
253
|
-
const isLastStep = stepIndex === totalSteps - 1;
|
|
254
|
-
const goTo = react.useCallback(
|
|
255
|
-
(step) => {
|
|
256
|
-
if (steps.includes(step)) setCurrentStep(step);
|
|
257
|
-
},
|
|
258
|
-
[steps]
|
|
259
|
-
);
|
|
260
|
-
const next = react.useCallback(() => {
|
|
261
|
-
if (!isLastStep) setCurrentStep(steps[stepIndex + 1]);
|
|
262
|
-
}, [isLastStep, stepIndex, steps]);
|
|
263
|
-
const prev = react.useCallback(() => {
|
|
264
|
-
if (!isFirstStep) setCurrentStep(steps[stepIndex - 1]);
|
|
265
|
-
}, [isFirstStep, stepIndex, steps]);
|
|
266
|
-
const reset = react.useCallback(() => {
|
|
267
|
-
setCurrentStep(initialStep ?? steps[0]);
|
|
268
|
-
}, [initialStep, steps]);
|
|
269
|
-
return {
|
|
270
|
-
currentStep,
|
|
271
|
-
stepIndex,
|
|
272
|
-
totalSteps,
|
|
273
|
-
isFirstStep,
|
|
274
|
-
isLastStep,
|
|
275
|
-
canGoBack: !isFirstStep,
|
|
276
|
-
canGoNext: !isLastStep,
|
|
277
|
-
goTo,
|
|
278
|
-
next,
|
|
279
|
-
prev,
|
|
280
|
-
reset
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
function useCSVImport({
|
|
284
|
-
previewFn,
|
|
285
|
-
importFn,
|
|
286
|
-
onSuccess
|
|
287
|
-
}) {
|
|
288
|
-
const [step, setStep] = react.useState("upload");
|
|
289
|
-
const [file, setFile] = react.useState(null);
|
|
290
|
-
const [preview, setPreview] = react.useState(null);
|
|
291
|
-
const [mappings, setMappings] = react.useState([]);
|
|
292
|
-
const [result, setResult] = react.useState(null);
|
|
293
|
-
const [isLoading, setIsLoading] = react.useState(false);
|
|
294
|
-
const [error, setError] = react.useState(null);
|
|
295
|
-
const handleFileSelect = react.useCallback(
|
|
296
|
-
async (selectedFile) => {
|
|
297
|
-
setFile(selectedFile);
|
|
298
|
-
setError(null);
|
|
299
|
-
setIsLoading(true);
|
|
300
|
-
try {
|
|
301
|
-
const previewData = await previewFn(selectedFile);
|
|
302
|
-
setPreview(previewData);
|
|
303
|
-
setMappings(previewData.suggested_mappings ?? []);
|
|
304
|
-
setStep("mapping");
|
|
305
|
-
} catch {
|
|
306
|
-
setError("Failed to preview CSV file");
|
|
307
|
-
} finally {
|
|
308
|
-
setIsLoading(false);
|
|
309
|
-
}
|
|
310
|
-
},
|
|
311
|
-
[previewFn]
|
|
312
|
-
);
|
|
313
|
-
const updateMapping = react.useCallback((csvColumn, targetField) => {
|
|
314
|
-
setMappings((prev) => {
|
|
315
|
-
const existing = prev.find((m) => m.csv_column === csvColumn);
|
|
316
|
-
if (existing) {
|
|
317
|
-
return prev.map(
|
|
318
|
-
(m) => m.csv_column === csvColumn ? { ...m, target_field: targetField } : m
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
return [...prev, { csv_column: csvColumn, target_field: targetField }];
|
|
322
|
-
});
|
|
323
|
-
}, []);
|
|
324
|
-
const startImport = react.useCallback(async () => {
|
|
325
|
-
if (!file) return;
|
|
326
|
-
setStep("importing");
|
|
327
|
-
setError(null);
|
|
328
|
-
try {
|
|
329
|
-
const importResult = await importFn(file, mappings);
|
|
330
|
-
setResult(importResult);
|
|
331
|
-
setStep("complete");
|
|
332
|
-
onSuccess?.(importResult);
|
|
333
|
-
} catch {
|
|
334
|
-
setError("Failed to import CSV");
|
|
335
|
-
setStep("mapping");
|
|
336
|
-
}
|
|
337
|
-
}, [file, mappings, importFn, onSuccess]);
|
|
338
|
-
const reset = react.useCallback(() => {
|
|
339
|
-
setStep("upload");
|
|
340
|
-
setFile(null);
|
|
341
|
-
setPreview(null);
|
|
342
|
-
setMappings([]);
|
|
343
|
-
setResult(null);
|
|
344
|
-
setError(null);
|
|
345
|
-
}, []);
|
|
346
|
-
const goBack = react.useCallback(() => {
|
|
347
|
-
if (step === "mapping") setStep("upload");
|
|
348
|
-
}, [step]);
|
|
349
|
-
return {
|
|
350
|
-
step,
|
|
351
|
-
file,
|
|
352
|
-
preview,
|
|
353
|
-
mappings,
|
|
354
|
-
result,
|
|
355
|
-
isLoading,
|
|
356
|
-
error,
|
|
357
|
-
handleFileSelect,
|
|
358
|
-
updateMapping,
|
|
359
|
-
startImport,
|
|
360
|
-
reset,
|
|
361
|
-
goBack
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
function useCSVExport({ exportFn, filename = "export.csv" }) {
|
|
365
|
-
const [isExporting, setIsExporting] = react.useState(false);
|
|
366
|
-
const exportCSV = react.useCallback(async () => {
|
|
367
|
-
setIsExporting(true);
|
|
368
|
-
try {
|
|
369
|
-
const data = await exportFn();
|
|
370
|
-
const blob = typeof data === "string" ? new Blob([data], { type: "text/csv" }) : data;
|
|
371
|
-
const url = URL.createObjectURL(blob);
|
|
372
|
-
const a = document.createElement("a");
|
|
373
|
-
a.href = url;
|
|
374
|
-
a.download = filename;
|
|
375
|
-
a.click();
|
|
376
|
-
URL.revokeObjectURL(url);
|
|
377
|
-
} finally {
|
|
378
|
-
setIsExporting(false);
|
|
379
|
-
}
|
|
380
|
-
}, [exportFn, filename]);
|
|
381
|
-
return { exportCSV, isExporting };
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
exports.createSimpleFilter = createSimpleFilter;
|
|
385
|
-
exports.decodeFilterConfig = decodeFilterConfig;
|
|
386
|
-
exports.encodeFilterConfig = encodeFilterConfig;
|
|
387
|
-
exports.getFilterDescription = getFilterDescription;
|
|
388
|
-
exports.mergeFilters = mergeFilters;
|
|
389
|
-
exports.parseUrlFilters = parseUrlFilters;
|
|
390
|
-
exports.useCRUDMutation = useCRUDMutation;
|
|
391
|
-
exports.useCSVExport = useCSVExport;
|
|
392
|
-
exports.useCSVImport = useCSVImport;
|
|
393
|
-
exports.useRecentlyViewed = useRecentlyViewed;
|
|
394
|
-
exports.useSavedViews = useSavedViews;
|
|
395
|
-
exports.useTableFilters = useTableFilters;
|
|
396
|
-
exports.useWizard = useWizard;
|
|
397
|
-
//# sourceMappingURL=index.js.map
|
|
398
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useTableFilters.ts","../src/filter-encoding.ts","../src/useCRUDMutation.ts","../src/useSavedViews.ts","../src/useRecentlyViewed.ts","../src/useWizard.ts","../src/useCSV.ts"],"names":["useState","useCallback","groupDescs","useQueryClient","useMutation","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import { useState, useCallback } from 'react'\n\ninterface TableFilterBase {\n page: number\n pageSize: number\n search?: string\n sortField?: string\n sortDirection?: 'asc' | 'desc'\n}\n\ntype TableFilters<TFilters extends Record<string, unknown>> = TFilters & TableFilterBase\n\ninterface UseTableFiltersReturn<TFilters extends Record<string, unknown>> {\n filters: TableFilters<TFilters>\n setFilter: <K extends keyof TFilters>(key: K, value: TFilters[K]) => void\n setPage: (page: number) => void\n setPageSize: (pageSize: number) => void\n setSearch: (search: string) => void\n setSort: (field: string, direction: 'asc' | 'desc') => void\n resetFilters: () => void\n}\n\nexport function useTableFilters<TFilters extends Record<string, unknown>>(\n initial: TFilters & { page?: number; pageSize?: number; sortField?: string; sortDirection?: 'asc' | 'desc' }\n): UseTableFiltersReturn<TFilters> {\n const defaultFilters: TableFilters<TFilters> = {\n page: 1,\n pageSize: 20,\n ...initial,\n } as TableFilters<TFilters>\n\n const [filters, setFilters] = useState<TableFilters<TFilters>>(defaultFilters)\n\n const setFilter = useCallback(<K extends keyof TFilters>(key: K, value: TFilters[K]) => {\n setFilters(prev => ({ ...prev, [key]: value, page: 1 }))\n }, [])\n\n const setPage = useCallback((page: number) => {\n setFilters(prev => ({ ...prev, page }))\n }, [])\n\n const setPageSize = useCallback((pageSize: number) => {\n setFilters(prev => ({ ...prev, pageSize, page: 1 }))\n }, [])\n\n const setSearch = useCallback((search: string) => {\n setFilters(prev => ({ ...prev, search, page: 1 }))\n }, [])\n\n const setSort = useCallback((field: string, direction: 'asc' | 'desc') => {\n setFilters(prev => ({ ...prev, sortField: field, sortDirection: direction }))\n }, [])\n\n const resetFilters = useCallback(() => {\n setFilters(defaultFilters)\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return {\n filters,\n setFilter,\n setPage,\n setPageSize,\n setSearch,\n setSort,\n resetFilters,\n }\n}\n","/**\n * URL filter encoding utilities.\n *\n * Provides base64 encode/decode for FilterConfig (so filter state can be\n * stored in URL query params as compact strings) plus helpers for common\n * filter operations.\n *\n * These are pure functions with no React or Next.js dependencies.\n */\n\nimport type {\n FilterConfig,\n FilterCondition,\n FilterGroup,\n FilterOperator,\n FilterValue,\n EncodedFilterState,\n} from './filter-types'\n\n/**\n * Encode a FilterConfig to a URL-safe base64 string.\n */\nexport function encodeFilterConfig(config: FilterConfig): string {\n const json = JSON.stringify(config)\n return btoa(json).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\n/**\n * Decode a URL-safe base64 string back to a FilterConfig.\n * Returns null if the string is invalid or cannot be parsed.\n */\nexport function decodeFilterConfig(encoded: string): FilterConfig | null {\n try {\n // Convert URL-safe base64 back to standard base64\n const standardBase64 = encoded.replace(/-/g, '+').replace(/_/g, '/')\n // Add padding if needed\n const padded = standardBase64 + '==='.slice(0, (4 - standardBase64.length % 4) % 4)\n const decoded = atob(padded)\n return JSON.parse(decoded) as FilterConfig\n } catch {\n return null\n }\n}\n\n/**\n * Parse URLSearchParams into an EncodedFilterState.\n */\nexport function parseUrlFilters(params: URLSearchParams): EncodedFilterState {\n const result: EncodedFilterState = {}\n\n if (params.has('f')) result.f = params.get('f')!\n if (params.has('s')) result.s = params.get('s')!\n if (params.has('d')) result.d = params.get('d')!\n\n if (params.has('p')) {\n const page = parseInt(params.get('p')!, 10)\n if (!isNaN(page) && page > 0) result.p = page\n }\n\n if (params.has('l')) {\n const limit = parseInt(params.get('l')!, 10)\n if (!isNaN(limit) && limit > 0 && limit <= 1000) result.l = limit\n }\n\n return result\n}\n\n/**\n * Build a single-condition FilterConfig.\n */\nexport function createSimpleFilter(\n field: string,\n operator: FilterOperator,\n value: FilterValue\n): FilterConfig {\n return {\n groups: [{ logic: 'AND', conditions: [{ field, operator, value }] }],\n globalLogic: 'AND',\n }\n}\n\n/**\n * Merge multiple FilterConfigs with AND logic.\n */\nexport function mergeFilters(...configs: FilterConfig[]): FilterConfig {\n if (configs.length === 0) return { groups: [] }\n if (configs.length === 1) return configs[0]\n\n return {\n groups: configs.map(config => ({\n logic: 'AND' as const,\n conditions: [] as FilterCondition[],\n groups: config.groups,\n })),\n globalLogic: 'AND',\n }\n}\n\n/**\n * Get a human-readable description of a FilterConfig.\n */\nexport function getFilterDescription(config: FilterConfig): string {\n if (config.groups.length === 0) return 'No filters applied'\n\n function describeGroup(group: FilterGroup): string {\n const conditionDescs = group.conditions.map(\n c => `${c.field} ${c.operator} ${c.value}`\n )\n const groupDescs = group.groups?.map(g => `(${describeGroup(g)})`) ?? []\n return [...conditionDescs, ...groupDescs].join(` ${group.logic} `)\n }\n\n const groupDescs = config.groups.map(describeGroup)\n return groupDescs.join(` ${config.globalLogic ?? 'AND'} `)\n}\n","import { useMutation, useQueryClient } from '@tanstack/react-query'\nimport type { QueryKey, UseMutationOptions, UseMutationResult } from '@tanstack/react-query'\n\ninterface UseCRUDMutationOptions<TInput, TOutput> {\n invalidateKeys: QueryKey[]\n onSuccess?: (data: TOutput, variables: TInput) => void\n onError?: (error: Error, variables: TInput) => void\n}\n\nexport function useCRUDMutation<TInput, TOutput>(\n mutationFn: (input: TInput) => Promise<TOutput>,\n opts: UseCRUDMutationOptions<TInput, TOutput>\n): UseMutationResult<TOutput, Error, TInput> {\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn,\n onSuccess: (data, variables) => {\n for (const key of opts.invalidateKeys) {\n queryClient.invalidateQueries({ queryKey: key })\n }\n opts.onSuccess?.(data, variables)\n },\n onError: opts.onError,\n })\n}\n","import { useState, useEffect, useCallback } from 'react'\n\nexport interface SavedView {\n id: string\n name: string\n isDefault?: boolean\n createdAt?: string\n [key: string]: unknown\n}\n\ninterface SavedViewsState<T extends SavedView> {\n views: T[]\n currentViewId: string | null\n loading: boolean\n error: string | null\n}\n\ninterface UseSavedViewsOptions<T extends SavedView> {\n resource: string\n loadFn: (resource: string) => Promise<T[]>\n saveFn: (resource: string, view: Omit<T, 'id' | 'createdAt'>) => Promise<T>\n updateFn: (resource: string, viewId: string, updates: Partial<T>) => Promise<T>\n deleteFn: (resource: string, viewId: string) => Promise<void>\n}\n\nexport function useSavedViews<T extends SavedView>({\n resource,\n loadFn,\n saveFn,\n updateFn,\n deleteFn,\n}: UseSavedViewsOptions<T>) {\n const [state, setState] = useState<SavedViewsState<T>>({\n views: [],\n currentViewId: null,\n loading: true,\n error: null,\n })\n\n const fetchViews = useCallback(async () => {\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const views = await loadFn(resource)\n const defaultView = views.find(v => v.isDefault)\n setState(prev => ({\n ...prev,\n views,\n currentViewId: defaultView?.id || null,\n loading: false,\n }))\n } catch (error) {\n setState(prev => ({\n ...prev,\n loading: false,\n error: error instanceof Error ? error.message : 'Failed to load views',\n }))\n }\n }, [resource, loadFn])\n\n useEffect(() => {\n fetchViews()\n }, [fetchViews])\n\n const saveView = useCallback(\n async (viewData: Omit<T, 'id' | 'createdAt'>): Promise<T> => {\n const newView = await saveFn(resource, viewData)\n setState(prev => ({\n ...prev,\n views: [...prev.views, newView],\n currentViewId: newView.id,\n }))\n return newView\n },\n [resource, saveFn]\n )\n\n const updateView = useCallback(\n async (viewId: string, updates: Partial<T>): Promise<void> => {\n await updateFn(resource, viewId, updates)\n await fetchViews()\n },\n [resource, updateFn, fetchViews]\n )\n\n const deleteView = useCallback(\n async (viewId: string): Promise<void> => {\n await deleteFn(resource, viewId)\n setState(prev => ({\n ...prev,\n views: prev.views.filter(v => v.id !== viewId),\n currentViewId: prev.currentViewId === viewId ? null : prev.currentViewId,\n }))\n },\n [resource, deleteFn]\n )\n\n const loadView = useCallback((viewId: string) => {\n setState(prev => ({ ...prev, currentViewId: viewId }))\n }, [])\n\n const getCurrentView = useCallback((): T | null => {\n return state.views.find(v => v.id === state.currentViewId) || null\n }, [state.views, state.currentViewId])\n\n return {\n views: state.views,\n currentViewId: state.currentViewId,\n loading: state.loading,\n error: state.error,\n saveView,\n updateView,\n deleteView,\n loadView,\n getCurrentView,\n refreshViews: fetchViews,\n }\n}\n","import { useState, useCallback, useEffect } from 'react'\n\ninterface StoredItem<T> {\n item: T\n viewedAt: number\n}\n\nexport function useRecentlyViewed<T extends { id: string }>(\n storageKey: string,\n maxItems: number = 5\n) {\n const [items, setItems] = useState<StoredItem<T>[]>([])\n\n // Load from localStorage on mount\n useEffect(() => {\n if (typeof window === 'undefined') return\n try {\n const raw = localStorage.getItem(storageKey)\n if (raw) {\n setItems(JSON.parse(raw) as StoredItem<T>[])\n }\n } catch {\n // Corrupted storage, start fresh\n }\n }, [storageKey])\n\n const persist = useCallback(\n (updated: StoredItem<T>[]) => {\n if (typeof window === 'undefined') return\n try {\n localStorage.setItem(storageKey, JSON.stringify(updated))\n } catch {\n // Storage quota exceeded\n }\n },\n [storageKey]\n )\n\n const trackView = useCallback(\n (item: T) => {\n setItems(prev => {\n const deduped = prev.filter(entry => entry.item.id !== item.id)\n const updated = [{ item, viewedAt: Date.now() }, ...deduped].slice(0, maxItems)\n persist(updated)\n return updated\n })\n },\n [maxItems, persist]\n )\n\n const clear = useCallback(() => {\n setItems([])\n if (typeof window === 'undefined') return\n try {\n localStorage.removeItem(storageKey)\n } catch {\n // ignore\n }\n }, [storageKey])\n\n return {\n items: items.map(entry => entry.item),\n timestamps: items.map(entry => ({ id: entry.item.id, viewedAt: entry.viewedAt })),\n trackView,\n clear,\n }\n}\n","import { useState, useCallback } from 'react'\n\nexport interface WizardState<TStep extends string> {\n currentStep: TStep\n stepIndex: number\n totalSteps: number\n isFirstStep: boolean\n isLastStep: boolean\n canGoBack: boolean\n canGoNext: boolean\n goTo: (step: TStep) => void\n next: () => void\n prev: () => void\n reset: () => void\n}\n\nexport function useWizard<TStep extends string>(\n steps: readonly TStep[],\n initialStep?: TStep\n): WizardState<TStep> {\n const [currentStep, setCurrentStep] = useState<TStep>(initialStep ?? steps[0])\n\n const stepIndex = steps.indexOf(currentStep)\n const totalSteps = steps.length\n const isFirstStep = stepIndex === 0\n const isLastStep = stepIndex === totalSteps - 1\n\n const goTo = useCallback(\n (step: TStep) => {\n if (steps.includes(step)) setCurrentStep(step)\n },\n [steps]\n )\n\n const next = useCallback(() => {\n if (!isLastStep) setCurrentStep(steps[stepIndex + 1])\n }, [isLastStep, stepIndex, steps])\n\n const prev = useCallback(() => {\n if (!isFirstStep) setCurrentStep(steps[stepIndex - 1])\n }, [isFirstStep, stepIndex, steps])\n\n const reset = useCallback(() => {\n setCurrentStep(initialStep ?? steps[0])\n }, [initialStep, steps])\n\n return {\n currentStep,\n stepIndex,\n totalSteps,\n isFirstStep,\n isLastStep,\n canGoBack: !isFirstStep,\n canGoNext: !isLastStep,\n goTo,\n next,\n prev,\n reset,\n }\n}\n","import { useState, useCallback } from 'react'\n\nexport interface CSVColumnMapping {\n csv_column: string\n target_field: string\n}\n\nexport interface CSVPreviewResult<TField extends string = string> {\n columns: string[]\n sample_rows: Record<string, string>[]\n suggested_mappings?: CSVColumnMapping[]\n total_rows?: number\n}\n\nexport interface CSVImportResult {\n total_rows: number\n successful: number\n failed: number\n errors: Array<{ row: number; message: string }>\n}\n\nexport type CSVImportStep = 'upload' | 'mapping' | 'importing' | 'complete'\n\nexport interface UseCSVImportOptions<TField extends string = string> {\n previewFn: (file: File) => Promise<CSVPreviewResult<TField>>\n importFn: (file: File, mappings: CSVColumnMapping[]) => Promise<CSVImportResult>\n onSuccess?: (result: CSVImportResult) => void\n}\n\nexport interface UseCSVImportState {\n step: CSVImportStep\n file: File | null\n preview: CSVPreviewResult | null\n mappings: CSVColumnMapping[]\n result: CSVImportResult | null\n isLoading: boolean\n error: string | null\n handleFileSelect: (file: File) => Promise<void>\n updateMapping: (csvColumn: string, targetField: string) => void\n startImport: () => Promise<void>\n reset: () => void\n goBack: () => void\n}\n\nexport function useCSVImport<TField extends string = string>({\n previewFn,\n importFn,\n onSuccess,\n}: UseCSVImportOptions<TField>): UseCSVImportState {\n const [step, setStep] = useState<CSVImportStep>('upload')\n const [file, setFile] = useState<File | null>(null)\n const [preview, setPreview] = useState<CSVPreviewResult | null>(null)\n const [mappings, setMappings] = useState<CSVColumnMapping[]>([])\n const [result, setResult] = useState<CSVImportResult | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const handleFileSelect = useCallback(\n async (selectedFile: File) => {\n setFile(selectedFile)\n setError(null)\n setIsLoading(true)\n try {\n const previewData = await previewFn(selectedFile)\n setPreview(previewData)\n setMappings(previewData.suggested_mappings ?? [])\n setStep('mapping')\n } catch {\n setError('Failed to preview CSV file')\n } finally {\n setIsLoading(false)\n }\n },\n [previewFn]\n )\n\n const updateMapping = useCallback((csvColumn: string, targetField: string) => {\n setMappings((prev) => {\n const existing = prev.find((m) => m.csv_column === csvColumn)\n if (existing) {\n return prev.map((m) =>\n m.csv_column === csvColumn ? { ...m, target_field: targetField } : m\n )\n }\n return [...prev, { csv_column: csvColumn, target_field: targetField }]\n })\n }, [])\n\n const startImport = useCallback(async () => {\n if (!file) return\n setStep('importing')\n setError(null)\n try {\n const importResult = await importFn(file, mappings)\n setResult(importResult)\n setStep('complete')\n onSuccess?.(importResult)\n } catch {\n setError('Failed to import CSV')\n setStep('mapping')\n }\n }, [file, mappings, importFn, onSuccess])\n\n const reset = useCallback(() => {\n setStep('upload')\n setFile(null)\n setPreview(null)\n setMappings([])\n setResult(null)\n setError(null)\n }, [])\n\n const goBack = useCallback(() => {\n if (step === 'mapping') setStep('upload')\n }, [step])\n\n return {\n step,\n file,\n preview,\n mappings,\n result,\n isLoading,\n error,\n handleFileSelect,\n updateMapping,\n startImport,\n reset,\n goBack,\n }\n}\n\nexport interface UseCSVExportOptions {\n exportFn: () => Promise<Blob | string>\n filename?: string\n}\n\nexport function useCSVExport({ exportFn, filename = 'export.csv' }: UseCSVExportOptions) {\n const [isExporting, setIsExporting] = useState(false)\n\n const exportCSV = useCallback(async () => {\n setIsExporting(true)\n try {\n const data = await exportFn()\n const blob = typeof data === 'string' ? new Blob([data], { type: 'text/csv' }) : data\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n a.click()\n URL.revokeObjectURL(url)\n } finally {\n setIsExporting(false)\n }\n }, [exportFn, filename])\n\n return { exportCSV, isExporting }\n}\n"]}
|