@htlkg/components 0.0.2 → 0.0.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 (60) hide show
  1. package/README.md +52 -0
  2. package/dist/AdminWrapper.vue_vue_type_script_setup_true_lang-B32IylcT.js +367 -0
  3. package/dist/AdminWrapper.vue_vue_type_script_setup_true_lang-B32IylcT.js.map +1 -0
  4. package/dist/Alert.vue_vue_type_script_setup_true_lang-DxPCS-Hx.js +263 -0
  5. package/dist/Alert.vue_vue_type_script_setup_true_lang-DxPCS-Hx.js.map +1 -0
  6. package/dist/DateRange.vue_vue_type_script_setup_true_lang-BLVg1Hah.js +580 -0
  7. package/dist/DateRange.vue_vue_type_script_setup_true_lang-BLVg1Hah.js.map +1 -0
  8. package/dist/ProductBadge.vue_vue_type_script_setup_true_lang-Cmr2f4Cy.js +187 -0
  9. package/dist/ProductBadge.vue_vue_type_script_setup_true_lang-Cmr2f4Cy.js.map +1 -0
  10. package/dist/_plugin-vue_export-helper-1tPrXgE0.js +11 -0
  11. package/dist/_plugin-vue_export-helper-1tPrXgE0.js.map +1 -0
  12. package/dist/components.css +15 -0
  13. package/dist/composables/index.js +32 -573
  14. package/dist/composables/index.js.map +1 -1
  15. package/dist/data/index.js +18 -0
  16. package/dist/data/index.js.map +1 -0
  17. package/dist/domain/index.js +8 -0
  18. package/dist/domain/index.js.map +1 -0
  19. package/dist/filterHelpers-DgRyoYSa.js +1386 -0
  20. package/dist/filterHelpers-DgRyoYSa.js.map +1 -0
  21. package/dist/forms/index.js +6 -0
  22. package/dist/forms/index.js.map +1 -0
  23. package/dist/index-DGO_pNgG.js +79 -0
  24. package/dist/index-DGO_pNgG.js.map +1 -0
  25. package/dist/index-QK97OdqQ.js +25 -0
  26. package/dist/index-QK97OdqQ.js.map +1 -0
  27. package/dist/index.js +67 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/navigation/index.js +8 -0
  30. package/dist/navigation/index.js.map +1 -0
  31. package/dist/overlays/index.js +8 -0
  32. package/dist/overlays/index.js.map +1 -0
  33. package/dist/stores/index.js +14 -0
  34. package/dist/stores/index.js.map +1 -0
  35. package/dist/useAdminPage-GhgXp0x8.js +1070 -0
  36. package/dist/useAdminPage-GhgXp0x8.js.map +1 -0
  37. package/dist/useTable-DutR1gkg.js +293 -0
  38. package/dist/useTable-DutR1gkg.js.map +1 -0
  39. package/package.json +43 -14
  40. package/src/composables/composables.md +109 -0
  41. package/src/composables/index.ts +69 -0
  42. package/src/composables/useAdminPage.ts +462 -0
  43. package/src/composables/useConfirmation.ts +358 -0
  44. package/src/composables/usePageContext.ts +171 -0
  45. package/src/composables/useStats.ts +361 -0
  46. package/src/composables/useTable.ts +26 -5
  47. package/src/composables/useWizard.ts +448 -0
  48. package/src/data/DataTable.vue +553 -0
  49. package/src/data/Table/Table.vue +295 -0
  50. package/src/data/columnHelpers.ts +503 -0
  51. package/src/data/data.md +106 -0
  52. package/src/data/filterHelpers.ts +358 -0
  53. package/src/data/index.ts +31 -0
  54. package/src/domain/domain.md +102 -0
  55. package/src/forms/JsonSchemaForm.vue +4 -1
  56. package/src/forms/forms.md +89 -0
  57. package/src/index.ts +4 -3
  58. package/src/navigation/navigation.md +80 -0
  59. package/src/overlays/overlays.md +86 -0
  60. package/src/stores/stores.md +82 -0
@@ -0,0 +1,1070 @@
1
+ import { ref, computed, inject, watch, onMounted } from "vue";
2
+ import { routes } from "@htlkg/core";
3
+ import { a as atom } from "./index-DGO_pNgG.js";
4
+ import { u as useStore } from "./index-QK97OdqQ.js";
5
+ function useModal(options = {}) {
6
+ const isOpen = ref(options.initialOpen ?? false);
7
+ function open() {
8
+ var _a;
9
+ isOpen.value = true;
10
+ (_a = options.onOpen) == null ? void 0 : _a.call(options);
11
+ }
12
+ function close() {
13
+ var _a;
14
+ isOpen.value = false;
15
+ (_a = options.onClose) == null ? void 0 : _a.call(options);
16
+ }
17
+ function toggle() {
18
+ if (isOpen.value) {
19
+ close();
20
+ } else {
21
+ open();
22
+ }
23
+ }
24
+ return {
25
+ isOpen,
26
+ open,
27
+ close,
28
+ toggle
29
+ };
30
+ }
31
+ function useTabs(options) {
32
+ const tabs = ref(options.tabs);
33
+ const activeTab = ref(
34
+ options.initialTab || (tabs.value.length > 0 ? tabs.value[0].id : "")
35
+ );
36
+ const currentTabIndex = computed(
37
+ () => tabs.value.findIndex((tab) => tab.id === activeTab.value)
38
+ );
39
+ const isFirstTab = computed(() => currentTabIndex.value === 0);
40
+ const isLastTab = computed(
41
+ () => currentTabIndex.value === tabs.value.length - 1
42
+ );
43
+ function setActiveTab(tabId) {
44
+ var _a;
45
+ const tab = tabs.value.find((t) => t.id === tabId);
46
+ if (tab && !tab.disabled) {
47
+ activeTab.value = tabId;
48
+ (_a = options.onChange) == null ? void 0 : _a.call(options, tabId);
49
+ }
50
+ }
51
+ function nextTab() {
52
+ if (!isLastTab.value) {
53
+ const nextIndex = currentTabIndex.value + 1;
54
+ const nextTab2 = tabs.value[nextIndex];
55
+ if (nextTab2 && !nextTab2.disabled) {
56
+ setActiveTab(nextTab2.id);
57
+ } else if (nextIndex < tabs.value.length - 1) {
58
+ activeTab.value = nextTab2.id;
59
+ nextTab2();
60
+ }
61
+ }
62
+ }
63
+ function previousTab() {
64
+ if (!isFirstTab.value) {
65
+ const prevIndex = currentTabIndex.value - 1;
66
+ const prevTab = tabs.value[prevIndex];
67
+ if (prevTab && !prevTab.disabled) {
68
+ setActiveTab(prevTab.id);
69
+ } else if (prevIndex > 0) {
70
+ activeTab.value = prevTab.id;
71
+ previousTab();
72
+ }
73
+ }
74
+ }
75
+ function isTabActive(tabId) {
76
+ return activeTab.value === tabId;
77
+ }
78
+ function isTabDisabled(tabId) {
79
+ const tab = tabs.value.find((t) => t.id === tabId);
80
+ return (tab == null ? void 0 : tab.disabled) ?? false;
81
+ }
82
+ return {
83
+ activeTab,
84
+ tabs,
85
+ currentTabIndex,
86
+ isFirstTab,
87
+ isLastTab,
88
+ setActiveTab,
89
+ nextTab,
90
+ previousTab,
91
+ isTabActive,
92
+ isTabDisabled
93
+ };
94
+ }
95
+ function useForm(options) {
96
+ const values = ref({ ...options.initialValues });
97
+ const errors = ref({});
98
+ const touched = ref({});
99
+ const isSubmitting = ref(false);
100
+ const isValid = computed(() => Object.keys(errors.value).length === 0);
101
+ function setFieldValue(field, value) {
102
+ values.value[field] = value;
103
+ }
104
+ function setFieldError(field, error) {
105
+ errors.value[field] = error;
106
+ }
107
+ function setFieldTouched(field, isTouched) {
108
+ touched.value[field] = isTouched;
109
+ }
110
+ async function validateField(field) {
111
+ var _a;
112
+ const rules = (_a = options.validationRules) == null ? void 0 : _a[field];
113
+ if (!rules || rules.length === 0) return true;
114
+ const value = values.value[field];
115
+ for (const rule of rules) {
116
+ const isValid2 = await rule.validate(value);
117
+ if (!isValid2) {
118
+ setFieldError(field, rule.message);
119
+ return false;
120
+ }
121
+ }
122
+ delete errors.value[field];
123
+ return true;
124
+ }
125
+ async function validateForm() {
126
+ const fields = Object.keys(values.value);
127
+ const validationResults = await Promise.all(
128
+ fields.map((field) => validateField(field))
129
+ );
130
+ return validationResults.every((result) => result);
131
+ }
132
+ async function handleSubmit(event) {
133
+ var _a;
134
+ if (event) {
135
+ event.preventDefault();
136
+ }
137
+ if (isSubmitting.value) return;
138
+ for (const field of Object.keys(values.value)) {
139
+ setFieldTouched(field, true);
140
+ }
141
+ const isFormValid = await validateForm();
142
+ if (!isFormValid) return;
143
+ isSubmitting.value = true;
144
+ try {
145
+ await ((_a = options.onSubmit) == null ? void 0 : _a.call(options, values.value));
146
+ } finally {
147
+ isSubmitting.value = false;
148
+ }
149
+ }
150
+ function resetForm() {
151
+ values.value = { ...options.initialValues };
152
+ errors.value = {};
153
+ touched.value = {};
154
+ isSubmitting.value = false;
155
+ }
156
+ return {
157
+ values,
158
+ errors,
159
+ touched,
160
+ isSubmitting,
161
+ isValid,
162
+ setFieldValue,
163
+ setFieldError,
164
+ setFieldTouched,
165
+ validateField,
166
+ validateForm,
167
+ handleSubmit,
168
+ resetForm
169
+ };
170
+ }
171
+ const required = (message = "This field is required") => ({
172
+ validate: (value) => {
173
+ if (value === null || value === void 0) return false;
174
+ if (typeof value === "string") return value.trim().length > 0;
175
+ if (Array.isArray(value)) return value.length > 0;
176
+ return true;
177
+ },
178
+ message
179
+ });
180
+ const minLength = (min2, message) => ({
181
+ validate: (value) => {
182
+ if (!value) return true;
183
+ return value.length >= min2;
184
+ },
185
+ message: message || `Must be at least ${min2} characters`
186
+ });
187
+ const maxLength = (max2, message) => ({
188
+ validate: (value) => {
189
+ if (!value) return true;
190
+ return value.length <= max2;
191
+ },
192
+ message: message || `Must be at most ${max2} characters`
193
+ });
194
+ const email = (message = "Invalid email address") => ({
195
+ validate: (value) => {
196
+ if (!value) return true;
197
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
198
+ return emailRegex.test(value);
199
+ },
200
+ message
201
+ });
202
+ const pattern = (regex, message = "Invalid format") => ({
203
+ validate: (value) => {
204
+ if (!value) return true;
205
+ return regex.test(value);
206
+ },
207
+ message
208
+ });
209
+ const min = (minValue, message) => ({
210
+ validate: (value) => {
211
+ if (value === null || value === void 0) return true;
212
+ return value >= minValue;
213
+ },
214
+ message: message || `Must be at least ${minValue}`
215
+ });
216
+ const max = (maxValue, message) => ({
217
+ validate: (value) => {
218
+ if (value === null || value === void 0) return true;
219
+ return value <= maxValue;
220
+ },
221
+ message: message || `Must be at most ${maxValue}`
222
+ });
223
+ const custom = (validator, message) => ({
224
+ validate: validator,
225
+ message
226
+ });
227
+ function useFormValidation() {
228
+ return {
229
+ required,
230
+ minLength,
231
+ maxLength,
232
+ email,
233
+ pattern,
234
+ min,
235
+ max,
236
+ custom
237
+ };
238
+ }
239
+ const notifications = ref([]);
240
+ function useNotifications() {
241
+ function addNotification(notification) {
242
+ const id = `notification-${Date.now()}-${Math.random()}`;
243
+ const newNotification = {
244
+ ...notification,
245
+ id
246
+ };
247
+ notifications.value.push(newNotification);
248
+ if (notification.duration) {
249
+ setTimeout(() => {
250
+ removeNotification(id);
251
+ }, notification.duration);
252
+ }
253
+ return id;
254
+ }
255
+ function removeNotification(id) {
256
+ const index = notifications.value.findIndex((n) => n.id === id);
257
+ if (index !== -1) {
258
+ notifications.value.splice(index, 1);
259
+ }
260
+ }
261
+ function clearAll() {
262
+ notifications.value = [];
263
+ }
264
+ function info(message, duration = 3e3) {
265
+ return addNotification({ message, type: "info", duration });
266
+ }
267
+ function success(message, duration = 3e3) {
268
+ return addNotification({ message, type: "success", duration });
269
+ }
270
+ function warning(message, duration = 3e3) {
271
+ return addNotification({ message, type: "warning", duration });
272
+ }
273
+ function error(message, duration = 5e3) {
274
+ return addNotification({ message, type: "error", duration });
275
+ }
276
+ return {
277
+ notifications,
278
+ addNotification,
279
+ removeNotification,
280
+ clearAll,
281
+ info,
282
+ success,
283
+ warning,
284
+ error
285
+ };
286
+ }
287
+ const PAGE_CONTEXT_KEY = Symbol("pageContext");
288
+ const $user = atom(null);
289
+ const $currentBrand = atom(null);
290
+ function setUser(user) {
291
+ $user.set(user);
292
+ }
293
+ function setCurrentBrand(brand) {
294
+ $currentBrand.set(brand);
295
+ }
296
+ function usePageContext() {
297
+ const injected = inject(PAGE_CONTEXT_KEY, null);
298
+ if (injected) {
299
+ return computed(() => injected);
300
+ }
301
+ const user = useStore($user);
302
+ const brand = useStore($currentBrand);
303
+ return computed(() => {
304
+ var _a, _b, _c;
305
+ return {
306
+ user: user.value,
307
+ brand: brand.value ?? void 0,
308
+ brandId: (_a = brand.value) == null ? void 0 : _a.id,
309
+ isAdmin: ((_b = user.value) == null ? void 0 : _b.isAdmin) ?? false,
310
+ isSuperAdmin: ((_c = user.value) == null ? void 0 : _c.isSuperAdmin) ?? false,
311
+ routes
312
+ };
313
+ });
314
+ }
315
+ function useHasAccessToBrand(brandId) {
316
+ const context = usePageContext();
317
+ return computed(() => {
318
+ var _a;
319
+ const user = context.value.user;
320
+ if (!user) return false;
321
+ if (user.isAdmin || user.isSuperAdmin) return true;
322
+ return ((_a = user.brandIds) == null ? void 0 : _a.includes(brandId)) ?? false;
323
+ });
324
+ }
325
+ function useHasAccessToAccount(accountId) {
326
+ const context = usePageContext();
327
+ return computed(() => {
328
+ var _a;
329
+ const user = context.value.user;
330
+ if (!user) return false;
331
+ if (user.isAdmin || user.isSuperAdmin) return true;
332
+ return ((_a = user.accountIds) == null ? void 0 : _a.includes(accountId)) ?? false;
333
+ });
334
+ }
335
+ function useUserRoles() {
336
+ const context = usePageContext();
337
+ return computed(() => {
338
+ var _a;
339
+ return ((_a = context.value.user) == null ? void 0 : _a.roles) ?? [];
340
+ });
341
+ }
342
+ function useHasRole(role) {
343
+ const roles = useUserRoles();
344
+ return computed(() => roles.value.includes(role));
345
+ }
346
+ function useWizard(options) {
347
+ const {
348
+ steps,
349
+ initialData = {},
350
+ onComplete,
351
+ onStepChange,
352
+ validateOnNext = true,
353
+ allowBackWithoutValidation = true
354
+ } = options;
355
+ const currentStepIndex = ref(0);
356
+ const data = ref({ ...initialData });
357
+ const isCompleting = ref(false);
358
+ const stepValidation = ref({});
359
+ const stepErrors = ref({});
360
+ const currentStep = computed(() => steps[currentStepIndex.value]);
361
+ const isFirstStep = computed(() => currentStepIndex.value === 0);
362
+ const isLastStep = computed(() => currentStepIndex.value === steps.length - 1);
363
+ const progress = computed(
364
+ () => Math.round((currentStepIndex.value + 1) / steps.length * 100)
365
+ );
366
+ const currentStepValid = computed(() => {
367
+ const step = currentStep.value;
368
+ if (!step) return false;
369
+ if (step.optional) return true;
370
+ return stepValidation.value[step.id] !== false;
371
+ });
372
+ const allStepsValid = computed(() => {
373
+ return steps.every((step) => {
374
+ if (step.optional) return true;
375
+ return stepValidation.value[step.id] === true;
376
+ });
377
+ });
378
+ const stepperSteps = computed(
379
+ () => steps.map((step, index) => {
380
+ let status;
381
+ if (index < currentStepIndex.value) {
382
+ status = stepValidation.value[step.id] === false ? "error" : "complete";
383
+ } else if (index === currentStepIndex.value) {
384
+ status = "current";
385
+ } else {
386
+ status = "upcoming";
387
+ }
388
+ return {
389
+ id: step.id,
390
+ label: step.label,
391
+ status,
392
+ valid: stepValidation.value[step.id] ?? true
393
+ };
394
+ })
395
+ );
396
+ function getStepIndex(stepId) {
397
+ return steps.findIndex((s) => s.id === stepId);
398
+ }
399
+ function getStep(stepId) {
400
+ return steps.find((s) => s.id === stepId);
401
+ }
402
+ async function validateStep(stepIndex) {
403
+ const step = steps[stepIndex];
404
+ if (!step) return false;
405
+ if (step.optional) {
406
+ stepValidation.value[step.id] = true;
407
+ return true;
408
+ }
409
+ if (step.validate) {
410
+ try {
411
+ const result = await step.validate(data.value);
412
+ stepValidation.value[step.id] = result;
413
+ if (!result) {
414
+ stepErrors.value[step.id] = "Validation failed";
415
+ } else {
416
+ delete stepErrors.value[step.id];
417
+ }
418
+ return result;
419
+ } catch (error) {
420
+ stepValidation.value[step.id] = false;
421
+ stepErrors.value[step.id] = error instanceof Error ? error.message : "Validation error";
422
+ return false;
423
+ }
424
+ }
425
+ if (stepValidation.value[step.id] === void 0) {
426
+ stepValidation.value[step.id] = true;
427
+ }
428
+ return stepValidation.value[step.id] !== false;
429
+ }
430
+ function canGoToStep(targetIndex) {
431
+ if (targetIndex < 0 || targetIndex >= steps.length) return false;
432
+ if (targetIndex < currentStepIndex.value && allowBackWithoutValidation) {
433
+ return true;
434
+ }
435
+ if (targetIndex > currentStepIndex.value && validateOnNext) {
436
+ for (let i = 0; i < targetIndex; i++) {
437
+ const step = steps[i];
438
+ if (!step.optional && stepValidation.value[step.id] === false) {
439
+ return false;
440
+ }
441
+ }
442
+ }
443
+ return true;
444
+ }
445
+ async function goToNext() {
446
+ if (isLastStep.value) return false;
447
+ if (validateOnNext) {
448
+ const isValid = await validateStep(currentStepIndex.value);
449
+ if (!isValid) return false;
450
+ }
451
+ const fromIndex = currentStepIndex.value;
452
+ currentStepIndex.value++;
453
+ onStepChange == null ? void 0 : onStepChange(fromIndex, currentStepIndex.value, data.value);
454
+ return true;
455
+ }
456
+ function goToPrevious() {
457
+ if (isFirstStep.value) return false;
458
+ const fromIndex = currentStepIndex.value;
459
+ currentStepIndex.value--;
460
+ onStepChange == null ? void 0 : onStepChange(fromIndex, currentStepIndex.value, data.value);
461
+ return true;
462
+ }
463
+ async function goToStep(targetIndex) {
464
+ if (!canGoToStep(targetIndex)) return false;
465
+ if (targetIndex > currentStepIndex.value && validateOnNext) {
466
+ const isValid = await validateStep(currentStepIndex.value);
467
+ if (!isValid) return false;
468
+ }
469
+ const fromIndex = currentStepIndex.value;
470
+ currentStepIndex.value = targetIndex;
471
+ onStepChange == null ? void 0 : onStepChange(fromIndex, currentStepIndex.value, data.value);
472
+ return true;
473
+ }
474
+ function updateData(newData) {
475
+ data.value = { ...data.value, ...newData };
476
+ }
477
+ function updateStepData(stepId, stepData) {
478
+ updateData(stepData);
479
+ delete stepErrors.value[stepId];
480
+ }
481
+ function setStepValid(stepId, valid) {
482
+ stepValidation.value[stepId] = valid;
483
+ if (valid) {
484
+ delete stepErrors.value[stepId];
485
+ }
486
+ }
487
+ function setStepError(stepId, error) {
488
+ if (error) {
489
+ stepErrors.value[stepId] = error;
490
+ stepValidation.value[stepId] = false;
491
+ } else {
492
+ delete stepErrors.value[stepId];
493
+ }
494
+ }
495
+ function resetStep(stepId) {
496
+ delete stepValidation.value[stepId];
497
+ delete stepErrors.value[stepId];
498
+ }
499
+ function reset() {
500
+ currentStepIndex.value = 0;
501
+ data.value = { ...initialData };
502
+ stepValidation.value = {};
503
+ stepErrors.value = {};
504
+ isCompleting.value = false;
505
+ }
506
+ async function complete() {
507
+ if (isCompleting.value) return false;
508
+ isCompleting.value = true;
509
+ try {
510
+ for (let i = 0; i < steps.length; i++) {
511
+ const isValid = await validateStep(i);
512
+ if (!isValid && !steps[i].optional) {
513
+ currentStepIndex.value = i;
514
+ isCompleting.value = false;
515
+ return false;
516
+ }
517
+ }
518
+ if (onComplete) {
519
+ await onComplete(data.value);
520
+ }
521
+ return true;
522
+ } catch (error) {
523
+ console.error("[useWizard] Completion error:", error);
524
+ return false;
525
+ } finally {
526
+ isCompleting.value = false;
527
+ }
528
+ }
529
+ return {
530
+ // State
531
+ currentStepIndex,
532
+ currentStep,
533
+ data,
534
+ isFirstStep,
535
+ isLastStep,
536
+ isCompleting,
537
+ stepErrors,
538
+ // Stepper integration
539
+ stepperSteps,
540
+ // Validation
541
+ stepValidation,
542
+ currentStepValid,
543
+ allStepsValid,
544
+ // Navigation
545
+ goToNext,
546
+ goToPrevious,
547
+ goToStep,
548
+ canGoToStep,
549
+ // Data management
550
+ updateData,
551
+ updateStepData,
552
+ setStepValid,
553
+ setStepError,
554
+ resetStep,
555
+ reset,
556
+ // Completion
557
+ complete,
558
+ // Utilities
559
+ getStepIndex,
560
+ getStep,
561
+ progress
562
+ };
563
+ }
564
+ function useStats(options) {
565
+ const {
566
+ data,
567
+ loading,
568
+ definitions,
569
+ staggerDelay = 100,
570
+ initialDelay = 0,
571
+ previousData
572
+ } = options;
573
+ const loadingStates = ref(definitions.map(() => true));
574
+ let timers = [];
575
+ function clearTimers() {
576
+ timers.forEach((timer) => clearTimeout(timer));
577
+ timers = [];
578
+ }
579
+ function triggerStaggeredReveal() {
580
+ clearTimers();
581
+ loadingStates.value = definitions.map(() => true);
582
+ definitions.forEach((_, index) => {
583
+ const timer = setTimeout(() => {
584
+ loadingStates.value[index] = false;
585
+ }, initialDelay + staggerDelay * (index + 1));
586
+ timers.push(timer);
587
+ });
588
+ }
589
+ watch(
590
+ () => loading.value,
591
+ (isLoading, wasLoading) => {
592
+ if (wasLoading && !isLoading) {
593
+ triggerStaggeredReveal();
594
+ } else if (isLoading && !wasLoading) {
595
+ clearTimers();
596
+ loadingStates.value = definitions.map(() => true);
597
+ }
598
+ },
599
+ { immediate: true }
600
+ );
601
+ if (!loading.value) {
602
+ triggerStaggeredReveal();
603
+ }
604
+ const stats = computed(() => {
605
+ const items = data.value;
606
+ const prevItems = previousData == null ? void 0 : previousData.value;
607
+ return definitions.map((def) => {
608
+ const stat = {
609
+ id: def.id,
610
+ name: def.name,
611
+ stat: def.compute(items),
612
+ icon: def.icon,
613
+ color: def.color ?? "gray"
614
+ };
615
+ if (def.computeChange) {
616
+ stat.change = def.computeChange(items, prevItems);
617
+ }
618
+ if (def.computeChangeType) {
619
+ stat.changeType = def.computeChangeType(items, prevItems);
620
+ }
621
+ if (def.showFooter !== void 0) {
622
+ stat.showFooter = def.showFooter;
623
+ }
624
+ if (def.actionText) {
625
+ stat.actionText = def.actionText;
626
+ }
627
+ return stat;
628
+ });
629
+ });
630
+ const statsWithLoading = computed(
631
+ () => stats.value.map((stat, index) => ({
632
+ ...stat,
633
+ loading: loading.value || loadingStates.value[index]
634
+ }))
635
+ );
636
+ const allLoaded = computed(
637
+ () => !loading.value && loadingStates.value.every((s) => !s)
638
+ );
639
+ function getStat(id) {
640
+ return stats.value.find((s) => s.id === id);
641
+ }
642
+ function refreshAnimation() {
643
+ triggerStaggeredReveal();
644
+ }
645
+ return {
646
+ stats,
647
+ loadingStates,
648
+ statsWithLoading,
649
+ allLoaded,
650
+ refreshAnimation,
651
+ getStat
652
+ };
653
+ }
654
+ function countStat(id, name, icon, filter, options) {
655
+ return {
656
+ id,
657
+ name,
658
+ icon,
659
+ color: (options == null ? void 0 : options.color) ?? "gray",
660
+ compute: (items) => items.filter(filter).length
661
+ };
662
+ }
663
+ function sumStat(id, name, icon, getValue, options) {
664
+ return {
665
+ id,
666
+ name,
667
+ icon,
668
+ color: (options == null ? void 0 : options.color) ?? "gray",
669
+ compute: (items) => {
670
+ const sum = items.reduce((total, item) => total + getValue(item), 0);
671
+ return (options == null ? void 0 : options.format) ? options.format(sum) : sum.toLocaleString();
672
+ }
673
+ };
674
+ }
675
+ function averageStat(id, name, icon, getValue, options) {
676
+ return {
677
+ id,
678
+ name,
679
+ icon,
680
+ color: (options == null ? void 0 : options.color) ?? "gray",
681
+ compute: (items) => {
682
+ if (items.length === 0) return "0";
683
+ const sum = items.reduce((total, item) => total + getValue(item), 0);
684
+ const avg = sum / items.length;
685
+ const formatted = avg.toFixed((options == null ? void 0 : options.decimals) ?? 1);
686
+ return (options == null ? void 0 : options.suffix) ? `${formatted}${options.suffix}` : formatted;
687
+ }
688
+ };
689
+ }
690
+ function percentageStat(id, name, icon, filter, options) {
691
+ return {
692
+ id,
693
+ name,
694
+ icon,
695
+ color: (options == null ? void 0 : options.color) ?? "gray",
696
+ compute: (items) => {
697
+ if (items.length === 0) return "0%";
698
+ const count = items.filter(filter).length;
699
+ const percentage = count / items.length * 100;
700
+ return `${percentage.toFixed((options == null ? void 0 : options.decimals) ?? 1)}%`;
701
+ }
702
+ };
703
+ }
704
+ function useConfirmation(options = {}) {
705
+ const {
706
+ defaultConfirmText = "Confirm",
707
+ defaultCancelText = "Cancel",
708
+ defaultVariant = "default"
709
+ } = options;
710
+ const isOpen = ref(false);
711
+ const isLoading = ref(false);
712
+ const config = ref({
713
+ title: "",
714
+ message: "",
715
+ confirmText: defaultConfirmText,
716
+ cancelText: defaultCancelText,
717
+ variant: defaultVariant
718
+ });
719
+ let pending = null;
720
+ function confirm(confirmConfig) {
721
+ config.value = {
722
+ ...confirmConfig,
723
+ confirmText: confirmConfig.confirmText ?? defaultConfirmText,
724
+ cancelText: confirmConfig.cancelText ?? defaultCancelText,
725
+ variant: confirmConfig.variant ?? defaultVariant
726
+ };
727
+ isOpen.value = true;
728
+ isLoading.value = false;
729
+ return new Promise((resolve, reject) => {
730
+ pending = { resolve, reject };
731
+ });
732
+ }
733
+ function handleConfirm() {
734
+ if (pending) {
735
+ pending.resolve(true);
736
+ pending = null;
737
+ }
738
+ isOpen.value = false;
739
+ isLoading.value = false;
740
+ }
741
+ function handleCancel() {
742
+ if (pending) {
743
+ pending.resolve(false);
744
+ pending = null;
745
+ }
746
+ isOpen.value = false;
747
+ isLoading.value = false;
748
+ }
749
+ function close() {
750
+ if (pending) {
751
+ pending.resolve(false);
752
+ pending = null;
753
+ }
754
+ isOpen.value = false;
755
+ isLoading.value = false;
756
+ }
757
+ function confirmDelete(itemName, confirmConfig) {
758
+ return confirm({
759
+ title: "Delete Item",
760
+ message: `Are you sure you want to delete "${itemName}"? This action cannot be undone.`,
761
+ confirmText: "Delete",
762
+ cancelText: "Cancel",
763
+ variant: "danger",
764
+ ...confirmConfig
765
+ });
766
+ }
767
+ function confirmBulkDelete(count, itemType = "items", confirmConfig) {
768
+ return confirm({
769
+ title: `Delete ${count} ${itemType}`,
770
+ message: `Are you sure you want to delete ${count} ${itemType}? This action cannot be undone.`,
771
+ confirmText: "Delete All",
772
+ cancelText: "Cancel",
773
+ variant: "danger",
774
+ ...confirmConfig
775
+ });
776
+ }
777
+ function confirmDestructive(actionName, confirmConfig) {
778
+ return confirm({
779
+ title: `Confirm ${actionName}`,
780
+ message: `Are you sure you want to ${actionName.toLowerCase()}? This action cannot be undone.`,
781
+ confirmText: actionName,
782
+ cancelText: "Cancel",
783
+ variant: "danger",
784
+ ...confirmConfig
785
+ });
786
+ }
787
+ async function confirmWithAction(confirmConfig, action) {
788
+ const confirmed = await confirm(confirmConfig);
789
+ if (!confirmed) {
790
+ return { confirmed: false };
791
+ }
792
+ isLoading.value = true;
793
+ try {
794
+ const result = await action();
795
+ isOpen.value = false;
796
+ isLoading.value = false;
797
+ return { confirmed: true, result };
798
+ } catch (error) {
799
+ isLoading.value = false;
800
+ return {
801
+ confirmed: true,
802
+ error: error instanceof Error ? error : new Error(String(error))
803
+ };
804
+ }
805
+ }
806
+ const modalProps = computed(() => ({
807
+ title: config.value.title,
808
+ open: isOpen.value,
809
+ modalName: "confirmation-dialog",
810
+ actions: [
811
+ {
812
+ name: config.value.cancelText ?? defaultCancelText,
813
+ value: "cancel"
814
+ },
815
+ {
816
+ name: config.value.confirmText ?? defaultConfirmText,
817
+ value: "confirm"
818
+ }
819
+ ]
820
+ }));
821
+ return {
822
+ // State
823
+ isOpen,
824
+ config,
825
+ isLoading,
826
+ // Core methods
827
+ confirm,
828
+ handleConfirm,
829
+ handleCancel,
830
+ close,
831
+ // Convenience methods
832
+ confirmDelete,
833
+ confirmBulkDelete,
834
+ confirmDestructive,
835
+ confirmWithAction,
836
+ // Modal props
837
+ modalProps
838
+ };
839
+ }
840
+ let globalConfirmation = null;
841
+ function useGlobalConfirmation() {
842
+ if (!globalConfirmation) {
843
+ globalConfirmation = useConfirmation();
844
+ }
845
+ return globalConfirmation;
846
+ }
847
+ function resetGlobalConfirmation() {
848
+ globalConfirmation = null;
849
+ }
850
+ function useAdminPage(options) {
851
+ const {
852
+ title,
853
+ subtitle,
854
+ description,
855
+ breadcrumbs: initialBreadcrumbs = [],
856
+ sidebarActive,
857
+ actions: initialActions = [],
858
+ loading: initialLoading = true,
859
+ loadingDelay = 200
860
+ } = options;
861
+ const context = usePageContext();
862
+ const loadingHeader = ref(initialLoading);
863
+ const loadingContent = ref(initialLoading);
864
+ const actions = ref([...initialActions]);
865
+ onMounted(() => {
866
+ if (initialLoading) {
867
+ setTimeout(() => {
868
+ loadingHeader.value = false;
869
+ }, loadingDelay);
870
+ setTimeout(() => {
871
+ loadingContent.value = false;
872
+ }, loadingDelay * 2);
873
+ }
874
+ });
875
+ const user = computed(() => context.value.user);
876
+ const brand = computed(() => context.value.brand);
877
+ const isAdmin = computed(() => {
878
+ var _a;
879
+ return ((_a = user.value) == null ? void 0 : _a.isAdmin) ?? false;
880
+ });
881
+ const isSuperAdmin = computed(() => {
882
+ var _a;
883
+ return ((_a = user.value) == null ? void 0 : _a.isSuperAdmin) ?? false;
884
+ });
885
+ const breadcrumbs = computed(() => [
886
+ ...initialBreadcrumbs.map((b) => ({ ...b, current: false })),
887
+ { name: title, current: true }
888
+ ]);
889
+ const wrapperProps = computed(() => ({
890
+ currentPage: sidebarActive
891
+ }));
892
+ const headerProps = computed(() => ({
893
+ title,
894
+ subtitle,
895
+ description,
896
+ pages: breadcrumbs.value,
897
+ loading: loadingHeader.value
898
+ }));
899
+ function setLoading(loading) {
900
+ if (loading) {
901
+ loadingHeader.value = true;
902
+ loadingContent.value = true;
903
+ } else {
904
+ setTimeout(() => {
905
+ loadingHeader.value = false;
906
+ }, loadingDelay);
907
+ setTimeout(() => {
908
+ loadingContent.value = false;
909
+ }, loadingDelay * 2);
910
+ }
911
+ }
912
+ function updateAction(id, updates) {
913
+ const index = actions.value.findIndex((a) => a.id === id);
914
+ if (index !== -1) {
915
+ actions.value[index] = { ...actions.value[index], ...updates };
916
+ }
917
+ }
918
+ function setActionLoading(id, loading) {
919
+ updateAction(id, { loading });
920
+ }
921
+ return {
922
+ // Page info
923
+ title,
924
+ subtitle,
925
+ description,
926
+ // Breadcrumbs
927
+ breadcrumbs,
928
+ // Loading
929
+ loadingHeader,
930
+ loadingContent,
931
+ setLoading,
932
+ // Context
933
+ user,
934
+ brand,
935
+ isAdmin,
936
+ isSuperAdmin,
937
+ // Actions
938
+ actions,
939
+ updateAction,
940
+ setActionLoading,
941
+ // Props
942
+ wrapperProps,
943
+ headerProps
944
+ };
945
+ }
946
+ function useListPage(options) {
947
+ const {
948
+ entityName,
949
+ onCreateClick,
950
+ createIcon,
951
+ hideCreate = false,
952
+ ...pageOptions
953
+ } = options;
954
+ const actions = [];
955
+ if (!hideCreate && entityName) {
956
+ actions.push({
957
+ id: "create",
958
+ text: `Create ${entityName.charAt(0).toUpperCase() + entityName.slice(1)}`,
959
+ icon: createIcon,
960
+ color: "primary",
961
+ onClick: onCreateClick
962
+ });
963
+ }
964
+ return useAdminPage({
965
+ ...pageOptions,
966
+ actions
967
+ });
968
+ }
969
+ function useDetailPage(options) {
970
+ const {
971
+ entityName,
972
+ onEditClick,
973
+ onDeleteClick,
974
+ editIcon,
975
+ deleteIcon,
976
+ hideEdit = false,
977
+ hideDelete = false,
978
+ ...pageOptions
979
+ } = options;
980
+ const actions = [];
981
+ if (!hideEdit && onEditClick) {
982
+ actions.push({
983
+ id: "edit",
984
+ text: "Edit",
985
+ icon: editIcon,
986
+ color: "secondary",
987
+ onClick: onEditClick
988
+ });
989
+ }
990
+ if (!hideDelete && onDeleteClick) {
991
+ actions.push({
992
+ id: "delete",
993
+ text: "Delete",
994
+ icon: deleteIcon,
995
+ color: "danger",
996
+ onClick: onDeleteClick
997
+ });
998
+ }
999
+ return useAdminPage({
1000
+ ...pageOptions,
1001
+ actions
1002
+ });
1003
+ }
1004
+ function useFormPage(options) {
1005
+ const {
1006
+ onSaveClick,
1007
+ onCancelClick,
1008
+ saveText = "Save",
1009
+ cancelText = "Cancel",
1010
+ saveIcon,
1011
+ cancelIcon,
1012
+ hideSave = false,
1013
+ hideCancel = false,
1014
+ ...pageOptions
1015
+ } = options;
1016
+ const actions = [];
1017
+ if (!hideCancel && onCancelClick) {
1018
+ actions.push({
1019
+ id: "cancel",
1020
+ text: cancelText,
1021
+ icon: cancelIcon,
1022
+ color: "secondary",
1023
+ onClick: onCancelClick
1024
+ });
1025
+ }
1026
+ if (!hideSave && onSaveClick) {
1027
+ actions.push({
1028
+ id: "save",
1029
+ text: saveText,
1030
+ icon: saveIcon,
1031
+ color: "primary",
1032
+ onClick: onSaveClick
1033
+ });
1034
+ }
1035
+ return useAdminPage({
1036
+ ...pageOptions,
1037
+ actions
1038
+ });
1039
+ }
1040
+ export {
1041
+ $user as $,
1042
+ PAGE_CONTEXT_KEY as P,
1043
+ useTabs as a,
1044
+ useForm as b,
1045
+ useFormValidation as c,
1046
+ useNotifications as d,
1047
+ usePageContext as e,
1048
+ useHasAccessToBrand as f,
1049
+ useHasAccessToAccount as g,
1050
+ useUserRoles as h,
1051
+ useHasRole as i,
1052
+ setCurrentBrand as j,
1053
+ $currentBrand as k,
1054
+ useWizard as l,
1055
+ useStats as m,
1056
+ countStat as n,
1057
+ sumStat as o,
1058
+ averageStat as p,
1059
+ percentageStat as q,
1060
+ useConfirmation as r,
1061
+ setUser as s,
1062
+ useGlobalConfirmation as t,
1063
+ useModal as u,
1064
+ resetGlobalConfirmation as v,
1065
+ useAdminPage as w,
1066
+ useListPage as x,
1067
+ useDetailPage as y,
1068
+ useFormPage as z
1069
+ };
1070
+ //# sourceMappingURL=useAdminPage-GhgXp0x8.js.map