@eztrak/shared 0.16.5 → 0.17.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.
package/README.md CHANGED
@@ -469,6 +469,121 @@ export function createCellEditorOnSave(invalidate = []) {
469
469
 
470
470
  Save is disabled when the value is unchanged (compares as strings so `42` and `"42"` are treated as equal). Pressing Enter while a save is in progress does not submit twice.
471
471
 
472
+ ### Components — Breadcrumbs
473
+
474
+ URL-driven trail for the current page. It reads `useLocation()` from `react-router-dom`, so it must render inside a router. The path is split on `/`, and each segment becomes one crumb. Ancestor crumbs are links. The last crumb is the current page: it is not a link, and it is marked with `aria-current="page"`.
475
+
476
+ On `/events/1q27-crude-coker/coker-ta27/budget` the default trail is:
477
+
478
+ `Events > 1Q27 Crude & Coker > Coker TA27 > Budget`
479
+
480
+ when those segments are labeled with `customTitles`. Without a label, the raw segment is shown.
481
+
482
+ A crumb's label is chosen in this order:
483
+
484
+ 1. `routes` — a matching `BreadcrumbRoute` whose full path equals that crumb
485
+ 2. `customTitles` — the entry for **that crumb's own segment** (not an earlier segment in the path)
486
+ 3. The segment text itself
487
+
488
+ `customIcons` uses the same segment key. An icon on `events` appears only on the Events crumb.
489
+
490
+ The default look is a flat bar: off-white background (`#F7F7F5`), 14px gray ancestor text (`#6B7280`), a 12px chevron (`#9CA3AF`), and a semibold near-black current page (`#111111`). There is no Home crumb unless `showHome` is set. Hover darkens a link without moving it. Keyboard focus draws an outline. Color props are inline styles, so they override the default colors. Class name props still merge for layout and typography.
491
+
492
+ ```tsx
493
+ import { Breadcrumbs } from "@eztrak/shared/components";
494
+
495
+ <Breadcrumbs
496
+ customTitles={{
497
+ events: "Events",
498
+ "1q27-crude-coker": "1Q27 Crude & Coker",
499
+ "coker-ta27": "Coker TA27",
500
+ budget: "Budget",
501
+ }}
502
+ />
503
+ ```
504
+
505
+ #### Colors, separator, and icons
506
+
507
+ ```tsx
508
+ import { HiCalendar } from "react-icons/hi";
509
+
510
+ <Breadcrumbs
511
+ customTitles={titles}
512
+ customIcons={{ events: <HiCalendar size={14} aria-hidden /> }}
513
+ backgroundColor="#EEF2FF"
514
+ inactiveColor="#4338CA"
515
+ activeColor="#1E1B4B"
516
+ separatorColor="#A5B4FC"
517
+ iconColor="#4338CA"
518
+ />
519
+
520
+ // Slash instead of the default chevron
521
+ <Breadcrumbs customTitles={titles} separator="/" />
522
+ ```
523
+
524
+ Omit `iconColor` and each icon inherits that crumb's text color (gray on ancestors, the active color on the current page).
525
+
526
+ #### Home, static crumbs, and route titles
527
+
528
+ ```tsx
529
+ // Prepend Home (links to "/"). Label it with customTitles.home.
530
+ <Breadcrumbs showHome customTitles={{ home: "Dashboard", events: "Events" }} />
531
+
532
+ // Render a segment as text instead of a link
533
+ <Breadcrumbs nonClickablePaths={["coker-ta27"]} customTitles={titles} />
534
+
535
+ // Titles from a route tree. A route title wins over customTitles.
536
+ <Breadcrumbs
537
+ routes={[
538
+ {
539
+ path: "events",
540
+ title: "Events",
541
+ children: [{ path: "budget", title: "Budget" }],
542
+ },
543
+ ]}
544
+ />
545
+ ```
546
+
547
+ `nonClickablePaths` matches a segment exactly, or any crumb whose path includes the token.
548
+
549
+ #### Layout hooks
550
+
551
+ ```tsx
552
+ <Breadcrumbs
553
+ customTitles={titles}
554
+ prefix={<span>App</span>}
555
+ suffix={<span>Draft</span>}
556
+ containerClassName="px-6"
557
+ linkClassName="uppercase tracking-wide"
558
+ activeClassName="font-bold"
559
+ separatorClassName="mx-1"
560
+ iconClassName="h-4 w-4"
561
+ />
562
+ ```
563
+
564
+ | Prop | Type | Default | Description |
565
+ | --- | --- | --- | --- |
566
+ | `routes` | `BreadcrumbRoute[]` | `[]` | Nested `{ path, title?, children? }` used to title a crumb when the built path matches |
567
+ | `customTitles` | `Record<string, string>` | `{}` | Label for a path segment. Key `home` labels the Home crumb |
568
+ | `customIcons` | `Record<string, ReactNode>` | `{}` | Icon for a path segment. Key `home` icons the Home crumb |
569
+ | `showHome` | `boolean` | `false` | Prepend a Home crumb that links to `/` |
570
+ | `nonClickablePaths` | `string[]` | `[]` | Segments (or path substrings) rendered as text instead of links |
571
+ | `separator` | `ReactNode` | chevron | Node between crumbs. Pass `"/"` or your own icon |
572
+ | `prefix` | `ReactNode` | — | Content before the trail |
573
+ | `suffix` | `ReactNode` | — | Content after the trail |
574
+ | `backgroundColor` | `string` | `"#F7F7F5"` | Bar background |
575
+ | `inactiveColor` | `string` | `"#6B7280"` | Ancestor and non-clickable text |
576
+ | `activeColor` | `string` | `"#111111"` | Current page text |
577
+ | `separatorColor` | `string` | `"#9CA3AF"` | Separator color |
578
+ | `iconColor` | `string` | inherits text | Icon color. Omitted icons use the crumb text color |
579
+ | `iconClassName` | `string` | — | Classes for each crumb icon |
580
+ | `containerClassName` | `string` | — | Classes merged onto the `<nav>` |
581
+ | `linkClassName` | `string` | — | Classes for ancestor and non-clickable crumbs |
582
+ | `activeClassName` | `string` | `"font-semibold"` | Classes for the current page |
583
+ | `separatorClassName` | `string` | — | Classes for the separator |
584
+
585
+ Color props win over text and background utilities in the class name props. Use the class name props for spacing, weight, and case.
586
+
472
587
  ### Components — ResetFiltersButton
473
588
 
474
589
  Clears all URL search params (`react-router-dom`) in one click. Self-contained — no app `Button` needed.
@@ -878,6 +993,7 @@ import {
878
993
  useGridHeight,
879
994
  EztrakTabs,
880
995
  CustomPagination,
996
+ Breadcrumbs,
881
997
  SearchInput,
882
998
  DropdownFilter,
883
999
  CustomCellEditor,
@@ -898,7 +1014,7 @@ npm run storybook
898
1014
  npm run storybook
899
1015
  ```
900
1016
 
901
- Opens on [http://localhost:6006](http://localhost:6006) with stories for `EztrakTabs`, `CustomPagination`, `ResetColumnsButton`, `CustomCellEditor`, and `Loader`.
1017
+ Opens on [http://localhost:6006](http://localhost:6006) with stories for `Breadcrumbs`, `EztrakTabs`, `CustomPagination`, `ResetColumnsButton`, `CustomCellEditor`, and `Loader`.
902
1018
 
903
1019
  ## Exports
904
1020
 
@@ -907,7 +1023,7 @@ Opens on [http://localhost:6006](http://localhost:6006) with stories for `Eztrak
907
1023
  | `@eztrak/shared` | Main entry — re-exports utils, hooks, and components |
908
1024
  | `@eztrak/shared/utils` | `cn`, `handleApiError`, `confirmationAlert`, `ConfirmationAlertOptions`, `getItem`, `setItem`, `loadUserState`, `saveUserState`, `resetPageParam`, date/format helpers, API error helpers, form field helpers |
909
1025
  | `@eztrak/shared/hooks` | `usePaginationUrlSync`, `useGridHeight` |
910
- | `@eztrak/shared/components` | `EztrakTabs`, `CustomPagination`, `CustomCellEditor`, `SearchInput`, `DropdownFilter`, `ResetFiltersButton`, `TooltipText`, `ToolTip`, `CardSkeleton`, `Modal`, `Loader`, `TableLayoutToolbarControls`, `ResetColumnsButton`, and related types |
1026
+ | `@eztrak/shared/components` | `EztrakTabs`, `CustomPagination`, `Breadcrumbs`, `CustomCellEditor`, `SearchInput`, `DropdownFilter`, `ResetFiltersButton`, `TooltipText`, `ToolTip`, `CardSkeleton`, `Modal`, `Loader`, `TableLayoutToolbarControls`, `ResetColumnsButton`, and related types |
911
1027
  | `@eztrak/shared/components/tabs.css` | Default tab styles (CSS variables) |
912
1028
  | `@eztrak/shared/components/loader.css` | Loader spinner styles |
913
1029
 
@@ -965,7 +1081,7 @@ Keyboard: Arrow keys move between tabs; Home/End jump to first/last enabled tab.
965
1081
 
966
1082
  - Node.js 18+
967
1083
  - React 18+ (for hooks and components)
968
- - `react-router-dom` — `CustomPagination`, `SearchInput`, `DropdownFilter`, `ResetFiltersButton`, and `usePaginationUrlSync` (optional peer; install if you use these)
1084
+ - `react-router-dom` — `Breadcrumbs`, `CustomPagination`, `SearchInput`, `DropdownFilter`, `ResetFiltersButton`, and `usePaginationUrlSync` (optional peer; install if you use these)
969
1085
  - `react-hot-toast` — toast feedback in `CustomCellEditor` and `handleApiError`
970
1086
  - `sweetalert2` — `ResetColumnsButton` and `confirmationAlert`
971
1087
  - `react-icons` — `CustomCellEditor`, `SearchInput`, and `Modal`
@@ -352,7 +352,138 @@ function handleApiError(error, { showAlert = false, fallbackMessage } = {}) {
352
352
  toast.error(message);
353
353
  }
354
354
  var BRAND_ORANGE = "#FF7335";
355
- var CANCEL_RED = "#ff0000";
355
+ var DANGER_RED = "#DC2626";
356
+ var DANGER_ICON_BG = "#FEE2E2";
357
+ var CANCEL_BG = "#ffffff";
358
+ var CANCEL_TEXT = "#374151";
359
+ var CONFIRM_STYLE_ID = "eztrak-confirm-alert-styles";
360
+ function cssSize(value, fallback) {
361
+ if (value === void 0) return fallback;
362
+ return typeof value === "number" ? `${value}px` : value;
363
+ }
364
+ var DEFAULT_CONFIRM_ICONS = {
365
+ warning: `
366
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
367
+ <path d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
368
+ </svg>
369
+ `.trim()
370
+ };
371
+ var VARIANT_DEFAULTS = {
372
+ brand: {
373
+ confirmButtonText: "Yes",
374
+ confirmButtonColor: BRAND_ORANGE,
375
+ confirmButtonTextColor: "#ffffff",
376
+ cancelButtonColor: CANCEL_BG,
377
+ cancelButtonTextColor: CANCEL_TEXT,
378
+ iconColor: BRAND_ORANGE,
379
+ iconBgColor: "#FFEDD5",
380
+ iconHtml: DEFAULT_CONFIRM_ICONS.warning,
381
+ icon: "warning"
382
+ },
383
+ danger: {
384
+ title: "Delete this item",
385
+ confirmButtonText: "Yes, delete it!",
386
+ confirmButtonColor: DANGER_RED,
387
+ confirmButtonTextColor: "#ffffff",
388
+ cancelButtonColor: CANCEL_BG,
389
+ cancelButtonTextColor: CANCEL_TEXT,
390
+ iconColor: DANGER_RED,
391
+ iconBgColor: DANGER_ICON_BG,
392
+ iconHtml: DEFAULT_CONFIRM_ICONS.warning,
393
+ icon: "warning",
394
+ showLoaderOnConfirm: true
395
+ }
396
+ };
397
+ function ensureConfirmAlertStyles() {
398
+ if (typeof document === "undefined") return;
399
+ if (document.getElementById(CONFIRM_STYLE_ID)) return;
400
+ const style = document.createElement("style");
401
+ style.id = CONFIRM_STYLE_ID;
402
+ style.textContent = `
403
+ .ez-confirm-popup {
404
+ border-radius: var(--ez-confirm-radius, 1rem) !important;
405
+ padding: 1.5rem !important;
406
+ max-width: 24rem !important;
407
+ width: var(--ez-confirm-width, 100%) !important;
408
+ box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25) !important;
409
+ }
410
+ .ez-confirm-title {
411
+ font-size: 1.125rem !important;
412
+ font-weight: 600 !important;
413
+ color: #111827 !important;
414
+ margin: 0 0 0.25rem !important;
415
+ padding: 0 !important;
416
+ }
417
+ .ez-confirm-html {
418
+ font-size: 0.875rem !important;
419
+ color: #6b7280 !important;
420
+ margin: 0 0 1.5rem !important;
421
+ }
422
+ .ez-confirm-icon {
423
+ border: none !important;
424
+ background: var(--ez-confirm-icon-bg, #fee2e2) !important;
425
+ color: var(--ez-confirm-icon-color, #dc2626) !important;
426
+ width: 3rem !important;
427
+ height: 3rem !important;
428
+ margin: 0 auto 1rem !important;
429
+ border-radius: 9999px !important;
430
+ }
431
+ .ez-confirm-icon .swal2-icon-content {
432
+ font-size: inherit !important;
433
+ display: flex !important;
434
+ align-items: center !important;
435
+ justify-content: center !important;
436
+ color: inherit !important;
437
+ }
438
+ .ez-confirm-actions {
439
+ width: 100% !important;
440
+ margin: 0 !important;
441
+ gap: 0.75rem !important;
442
+ }
443
+ .ez-confirm-confirm,
444
+ .ez-confirm-cancel {
445
+ flex: 1 1 0 !important;
446
+ margin: 0 !important;
447
+ border-radius: var(--ez-confirm-btn-radius, 0.5rem) !important;
448
+ font-size: 0.875rem !important;
449
+ font-weight: 500 !important;
450
+ padding: 0.625rem 1rem !important;
451
+ box-shadow: none !important;
452
+ }
453
+ .ez-confirm-confirm {
454
+ background: var(--ez-confirm-confirm-bg, #ff7335) !important;
455
+ color: var(--ez-confirm-confirm-fg, #fff) !important;
456
+ border: none !important;
457
+ }
458
+ .ez-confirm-confirm:hover {
459
+ filter: brightness(0.95);
460
+ }
461
+ .ez-confirm-cancel {
462
+ background: var(--ez-confirm-cancel-bg, #fff) !important;
463
+ color: var(--ez-confirm-cancel-fg, #374151) !important;
464
+ border: 1px solid #d1d5db !important;
465
+ }
466
+ .ez-confirm-cancel:hover {
467
+ background: #f9fafb !important;
468
+ }
469
+ `;
470
+ document.head.appendChild(style);
471
+ }
472
+ function pick(explicit, fromVariant, fallback) {
473
+ if (explicit !== void 0) return explicit;
474
+ if (fromVariant !== void 0) return fromVariant;
475
+ return fallback;
476
+ }
477
+ function mergeCustomClass(base, extra) {
478
+ if (!extra || typeof extra !== "object") return base;
479
+ const merged = { ...base };
480
+ for (const [key, value] of Object.entries(extra)) {
481
+ if (typeof value === "string" && value) {
482
+ merged[key] = merged[key] ? `${merged[key]} ${value}` : value;
483
+ }
484
+ }
485
+ return merged;
486
+ }
356
487
  function getConfirmErrorMessage(error) {
357
488
  if (error && typeof error === "object") {
358
489
  const err = error;
@@ -361,23 +492,59 @@ function getConfirmErrorMessage(error) {
361
492
  return "Something went wrong. Please try again.";
362
493
  }
363
494
  function confirmationAlert(onConfirm, options = {}) {
364
- const {
365
- title = options.inputExpectedValue ? "Confirmation Required" : "Are you sure?",
366
- text,
367
- html,
368
- icon = "warning",
369
- confirmButtonText = "Yes",
370
- cancelButtonText = "Cancel",
371
- confirmButtonColor = BRAND_ORANGE,
372
- cancelButtonColor = CANCEL_RED,
373
- showLoaderOnConfirm = false,
374
- inputExpectedValue,
375
- inputPlaceholder = "Type confirmation text to proceed",
376
- reverseButtons,
377
- focusCancel,
378
- zIndex
379
- } = options;
495
+ ensureConfirmAlertStyles();
496
+ const variant = options.variant ?? "brand";
497
+ const vd = VARIANT_DEFAULTS[variant];
498
+ const inputExpectedValue = options.inputExpectedValue;
380
499
  const hasInput = Boolean(inputExpectedValue);
500
+ const title = pick(
501
+ options.title,
502
+ vd.title,
503
+ hasInput ? "Confirmation Required" : "Delete this item"
504
+ );
505
+ const text = options.text;
506
+ const html = options.html;
507
+ const icon = pick(options.icon, vd.icon, "warning");
508
+ const iconHtml = pick(options.iconHtml, vd.iconHtml, void 0);
509
+ const iconColor = pick(options.iconColor, vd.iconColor, BRAND_ORANGE);
510
+ const iconBgColor = pick(options.iconBgColor, vd.iconBgColor, "#FFEDD5");
511
+ const showIcon = options.showIcon !== false;
512
+ const confirmButtonText = pick(options.confirmButtonText, vd.confirmButtonText, "Yes");
513
+ const cancelButtonText = options.cancelButtonText ?? "Cancel";
514
+ const confirmButtonColor = pick(
515
+ options.confirmButtonColor,
516
+ vd.confirmButtonColor,
517
+ BRAND_ORANGE
518
+ );
519
+ const cancelButtonColor = pick(
520
+ options.cancelButtonColor,
521
+ vd.cancelButtonColor,
522
+ CANCEL_BG
523
+ );
524
+ const confirmButtonTextColor = pick(
525
+ options.confirmButtonTextColor,
526
+ vd.confirmButtonTextColor,
527
+ "#ffffff"
528
+ );
529
+ const cancelButtonTextColor = pick(
530
+ options.cancelButtonTextColor,
531
+ vd.cancelButtonTextColor,
532
+ CANCEL_TEXT
533
+ );
534
+ const showCancelButton = options.showCancelButton !== false;
535
+ const showLoaderOnConfirm = pick(
536
+ options.showLoaderOnConfirm,
537
+ vd.showLoaderOnConfirm,
538
+ false
539
+ );
540
+ const inputPlaceholder = options.inputPlaceholder ?? "Type confirmation text to proceed";
541
+ const reverseButtons = options.reverseButtons ?? false;
542
+ const focusCancel = options.focusCancel;
543
+ const zIndex = options.zIndex;
544
+ const width = options.width;
545
+ const borderRadius = cssSize(options.borderRadius, "1rem");
546
+ const buttonBorderRadius = cssSize(options.buttonBorderRadius, "0.5rem");
547
+ const onCancel = options.onCancel;
381
548
  const useLoader = showLoaderOnConfirm || hasInput;
382
549
  const inputHtml = html ?? (hasInput ? `
383
550
  ${text ? `<p style="margin-bottom: 15px;">${text}</p>` : ""}
@@ -385,24 +552,56 @@ function confirmationAlert(onConfirm, options = {}) {
385
552
  Please type "<span style="color: ${BRAND_ORANGE}; font-weight: bold;">${inputExpectedValue}</span>" to confirm:
386
553
  </p>
387
554
  ` : void 0);
555
+ const baseCustomClass = {
556
+ popup: "ez-confirm-popup",
557
+ title: "ez-confirm-title",
558
+ htmlContainer: "ez-confirm-html",
559
+ actions: "ez-confirm-actions",
560
+ confirmButton: "ez-confirm-confirm",
561
+ cancelButton: "ez-confirm-cancel",
562
+ icon: "ez-confirm-icon"
563
+ };
388
564
  const swalOptions = {
389
565
  title,
390
- icon,
391
- showCancelButton: true,
566
+ showCancelButton,
392
567
  confirmButtonText,
393
568
  cancelButtonText,
394
569
  confirmButtonColor,
395
570
  cancelButtonColor,
396
571
  reverseButtons,
397
572
  focusCancel,
573
+ customClass: mergeCustomClass(baseCustomClass, options.customClass),
398
574
  allowOutsideClick: () => !Swal.isLoading(),
399
575
  allowEscapeKey: () => !Swal.isLoading(),
400
576
  didOpen: () => {
577
+ const popup = Swal.getPopup();
578
+ if (popup) {
579
+ popup.style.setProperty("--ez-confirm-confirm-bg", confirmButtonColor);
580
+ popup.style.setProperty("--ez-confirm-confirm-fg", confirmButtonTextColor);
581
+ popup.style.setProperty("--ez-confirm-cancel-bg", cancelButtonColor);
582
+ popup.style.setProperty("--ez-confirm-cancel-fg", cancelButtonTextColor);
583
+ popup.style.setProperty("--ez-confirm-icon-color", iconColor);
584
+ popup.style.setProperty("--ez-confirm-icon-bg", iconBgColor);
585
+ popup.style.setProperty("--ez-confirm-radius", borderRadius);
586
+ popup.style.setProperty("--ez-confirm-btn-radius", buttonBorderRadius);
587
+ if (width != null) {
588
+ popup.style.setProperty(
589
+ "--ez-confirm-width",
590
+ typeof width === "number" ? `${width}px` : String(width)
591
+ );
592
+ }
593
+ }
401
594
  if (zIndex == null) return;
402
595
  const container = Swal.getContainer();
403
596
  if (container) container.style.zIndex = String(zIndex);
404
597
  }
405
598
  };
599
+ if (showIcon) {
600
+ swalOptions.icon = icon;
601
+ if (iconHtml) {
602
+ swalOptions.iconHtml = iconHtml;
603
+ }
604
+ }
406
605
  if (hasInput) {
407
606
  swalOptions.html = inputHtml;
408
607
  swalOptions.input = "text";
@@ -437,6 +636,10 @@ function confirmationAlert(onConfirm, options = {}) {
437
636
  void Swal.fire(swalOptions).then((result) => {
438
637
  if (result.isConfirmed && !useLoader) {
439
638
  void Promise.resolve(onConfirm());
639
+ return;
640
+ }
641
+ if (result.isDismissed) {
642
+ onCancel?.();
440
643
  }
441
644
  });
442
645
  }
@@ -481,6 +684,7 @@ export {
481
684
  classifyError,
482
685
  formatValidationErrorsHtml,
483
686
  handleApiError,
687
+ DEFAULT_CONFIRM_ICONS,
484
688
  confirmationAlert
485
689
  };
486
- //# sourceMappingURL=chunk-EIX5CUQF.mjs.map
690
+ //# sourceMappingURL=chunk-A5BBQ7X5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/cn.ts","../src/utils/resetPageParam.ts","../src/utils/helpers.ts","../src/utils/localStorage.ts","../src/utils/handleApiError.ts"],"sourcesContent":["import clsx from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: Parameters<typeof clsx>) {\r\n return twMerge(clsx(inputs));\r\n}\r\n","/**\n * Sends pagination back to the first page after a filter changes the result set.\n *\n * Only touches `pageKey` when it is already present, so filter-only screens that\n * never paginate keep their URL clean. Mutates and returns `params` so it can be\n * chained inside a `setSearchParams((prev) => ...)` updater.\n */\nexport function resetPageParam(\n params: URLSearchParams,\n pageKey = \"page\",\n defaultPage = \"1\",\n) {\n if (params.has(pageKey)) {\n params.set(pageKey, defaultPage);\n }\n return params;\n}\n","export const truncateText = (\r\n text: string | number | null | undefined,\r\n maxLength = 20\r\n): string => {\r\n if (text === null || text === undefined) return \"\";\r\n const value = String(text);\r\n if (value.length <= maxLength) {\r\n return value;\r\n }\r\n return value.slice(0, maxLength - 3) + \"...\";\r\n};\r\n\r\nexport const truncateFileName = (\r\n fileName: string | null | undefined,\r\n maxLength = 20\r\n): string => {\r\n if (!fileName) return \"\";\r\n if (fileName.length <= maxLength) {\r\n return fileName;\r\n }\r\n const extension = fileName.slice(fileName.lastIndexOf(\".\"));\r\n const truncatedName =\r\n fileName.slice(0, maxLength - extension.length - 3) + \"...\";\r\n return truncatedName + extension;\r\n};\r\n\r\nexport function getApiError(apiError: unknown): string {\r\n if (!apiError) return \"An unknown error occurred\";\r\n\r\n if (typeof apiError === \"string\") {\r\n return apiError;\r\n }\r\n\r\n const error = apiError as {\r\n response?: { data?: Record<string, unknown> };\r\n message?: string;\r\n };\r\n\r\n if (error.response?.data) {\r\n const responseData = error.response.data;\r\n\r\n if (typeof responseData === \"string\") {\r\n return responseData;\r\n }\r\n\r\n const errors = responseData.errors;\r\n if (errors && typeof errors === \"object\") {\r\n for (const key in errors) {\r\n const messages = (errors as Record<string, unknown>)[key];\r\n if (Array.isArray(messages) && messages.length > 0) {\r\n return String(messages[0]);\r\n }\r\n }\r\n }\r\n\r\n if (responseData.message) {\r\n return String(responseData.message);\r\n }\r\n\r\n if (responseData.title) {\r\n return String(responseData.title);\r\n }\r\n }\r\n\r\n if (error.message) {\r\n return error.message;\r\n }\r\n\r\n return \"An unknown error occurred\";\r\n}\r\n\r\nexport const normalizeApiListItems = (responseData: unknown): unknown[] => {\r\n if (responseData == null) return [];\r\n if (Array.isArray(responseData)) return responseData;\r\n\r\n const record = responseData as Record<string, unknown>;\r\n const data = record.data;\r\n\r\n if (\r\n data &&\r\n typeof data === \"object\" &&\r\n !Array.isArray(data) &&\r\n Array.isArray((data as { items?: unknown[] }).items)\r\n ) {\r\n return (data as { items: unknown[] }).items;\r\n }\r\n\r\n const returnModel = record.returnModel as { items?: unknown[] } | undefined;\r\n if (Array.isArray(returnModel?.items)) return returnModel.items;\r\n if (Array.isArray(data)) return data;\r\n if (typeof data === \"object\" && data !== null) {\r\n return [data];\r\n }\r\n return [];\r\n};\r\n\r\nexport function capitalizeText(name: string | null | undefined): string {\r\n if (!name) return \"\";\r\n return name\r\n .split(\" \")\r\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\r\n .join(\" \");\r\n}\r\n\r\nexport function toLowerCaseText(text: string | null | undefined): string {\r\n if (!text) return \"\";\r\n return text.toLowerCase();\r\n}\r\n\r\nexport const formatDate = (dateString: string | null | undefined): string => {\r\n if (dateString === null || dateString === undefined) return \"-\";\r\n const date = new Date(dateString);\r\n\r\n if (isNaN(date.getTime())) {\r\n return dateString;\r\n }\r\n\r\n const month = (date.getMonth() + 1).toString().padStart(2, \"0\");\r\n const day = date.getDate().toString().padStart(2, \"0\");\r\n const year = date.getFullYear().toString().slice(-2);\r\n return `${month}/${day}/${year}`;\r\n};\r\n\r\nexport const isEmpty = (obj: object): boolean => {\r\n return Object.keys(obj).length === 0;\r\n};\r\n\r\nexport const toDateInputValue = (date: string | Date | null | undefined): string => {\r\n if (!date) return \"\";\r\n\r\n let d: Date;\r\n\r\n if (typeof date === \"string\") {\r\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(date)) {\r\n return date;\r\n }\r\n d = new Date(date);\r\n } else {\r\n d = new Date(date);\r\n }\r\n\r\n if (isNaN(d.getTime())) return \"\";\r\n\r\n const localDate = new Date(d.getTime() - d.getTimezoneOffset() * 60000);\r\n const year = localDate.getFullYear();\r\n const month = (localDate.getMonth() + 1).toString().padStart(2, \"0\");\r\n const day = localDate.getDate().toString().padStart(2, \"0\");\r\n\r\n return `${year}-${month}-${day}`;\r\n};\r\n\r\nexport function convertCommaDataToArray(data: string | null | undefined): string[] {\r\n if (!data || data.trim() === \"\") {\r\n return [];\r\n }\r\n return data.split(\",\").map((item) => item.trim());\r\n}\r\n\r\nexport function checkIfExistsInArray<T>(array: T[], searchValue: T): boolean {\r\n return array.includes(searchValue);\r\n}\r\n\r\nexport const currencyFormatter = (value: number | null | undefined): string => {\r\n return value?.toLocaleString(\"en-US\", {\r\n style: \"currency\",\r\n currency: \"USD\",\r\n }) ?? \"\";\r\n};\r\nexport const formatNumber = (number: number | string | null | undefined): string => {\r\n if (isNaN(Number(number)) || number === null || number === undefined) {\r\n return \"0\";\r\n }\r\n\r\n const formattedNumber = Number(number)\r\n .toString()\r\n .replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\");\r\n\r\n return formattedNumber;\r\n};\r\n\r\nexport const parseCurrencyValueToNumber = (value: unknown): number => {\r\n if (value == null || value === \"\") return 0;\r\n\r\n const raw =\r\n typeof value === \"object\" && value !== null && \"value\" in value\r\n ? (value as { value: unknown }).value\r\n : value;\r\n\r\n const stringValue = raw == null || raw === \"\" ? \"\" : String(raw);\r\n const numericValue = stringValue.replace(/[$,]/g, \"\");\r\n return parseFloat(numericValue) || 0;\r\n};\r\n\r\nexport function flattenTableData<T extends Record<string, unknown>>(\r\n data: T[] | null | undefined,\r\n columns: { field?: string }[] | null | undefined\r\n): T[] {\r\n if (!Array.isArray(data)) return [];\r\n return data.map((row) => {\r\n const flatRow = { ...row };\r\n (columns ?? []).forEach((col) => {\r\n const key = col.field;\r\n if (!key) return;\r\n if (key.includes(\".\")) {\r\n const value = key.split(\".\").reduce<unknown>(\r\n (acc, part) => (acc as Record<string, unknown> | undefined)?.[part],\r\n row\r\n );\r\n (flatRow as Record<string, unknown>)[key] = value ?? \"\";\r\n }\r\n });\r\n return flatRow;\r\n });\r\n}\r\n\r\nexport const getErrorMessages = (error: {\r\n data?: {\r\n errors?: Record<string, string[]>;\r\n title?: string;\r\n error?: { name?: string[] };\r\n };\r\n} | null | undefined): string => {\r\n if (error?.data?.errors) {\r\n return Object.values(error.data.errors).flat().join(\"\\n\");\r\n }\r\n return (\r\n error?.data?.title ??\r\n error?.data?.error?.name?.[0] ??\r\n \"Failed to save\"\r\n );\r\n};\r\n\r\nexport const getFieldsByCategory = <T extends { category?: string }>(\r\n fields: T[] = [],\r\n key: string\r\n): T[] => {\r\n return fields?.filter(({ category = \"\" }) => category === key);\r\n};\r\n\r\nexport const getFieldsByName = <T extends { name?: string }>(\r\n fields: T[] = [],\r\n key: string\r\n): T[] => {\r\n return fields.filter(({ name = \"\" }) => name === key);\r\n};\r\n\r\nexport const deserializeJson = <T = unknown>(jsonString: string): T | null => {\r\n try {\r\n return JSON.parse(jsonString) as T;\r\n } catch (error) {\r\n console.error(\"Error parsing JSON:\", error);\r\n return null;\r\n }\r\n};\r\n\r\nexport const formatDateTime = (dateString: string | null | undefined): string => {\r\n if (!dateString) return \"Invalid Date\";\r\n const date = new Date(dateString);\r\n if (isNaN(date.getTime())) return \"Invalid Date\";\r\n const options: Intl.DateTimeFormatOptions = {\r\n year: \"numeric\",\r\n month: \"numeric\",\r\n day: \"numeric\",\r\n hour: \"numeric\",\r\n minute: \"numeric\",\r\n hour12: true,\r\n };\r\n return date.toLocaleString(\"en-US\", options);\r\n};\r\n\r\nexport const removeByPropertyValues = <T extends Record<string, unknown>>(\r\n items: T[] = [],\r\n property: keyof T & string,\r\n values: unknown[] = [],\r\n { caseInsensitive = false }: { caseInsensitive?: boolean } = {}\r\n): T[] => {\r\n if (!Array.isArray(items) || !property) return Array.isArray(items) ? items : [];\r\n const normalize = (v: unknown) =>\r\n caseInsensitive && typeof v === \"string\" ? v.toLowerCase() : v;\r\n const valuesArr = Array.isArray(values) ? values : [values];\r\n const toRemove = new Set(valuesArr.map(normalize));\r\n return items.filter((item) => !toRemove.has(normalize(item?.[property])));\r\n};\r\n\r\nexport const getFieldsByInputType = <T extends { inputType?: string }>(\r\n fields: T[] = [],\r\n key: string\r\n): T[] => {\r\n return fields.filter(({ inputType = \"\" }) => inputType === key);\r\n};\r\n","export const USER_STATE_STORAGE_KEY = \"authState\";\r\n\r\nfunction getStorage(): Storage | null {\r\n if (typeof window === \"undefined\") return null;\r\n return window.localStorage;\r\n}\r\n\r\nexport function getItem<T>(key: string, fallback: T | null = null): T | null {\r\n try {\r\n const raw = getStorage()?.getItem(key);\r\n if (raw === null || raw === undefined) {\r\n return fallback;\r\n }\r\n return JSON.parse(raw) as T;\r\n } catch {\r\n return fallback;\r\n }\r\n}\r\n\r\nexport function setItem<T>(key: string, value: T): void {\r\n try {\r\n getStorage()?.setItem(key, JSON.stringify(value));\r\n } catch {\r\n // Ignore write errors (quota exceeded, private mode, etc.)\r\n }\r\n}\r\n\r\nexport function removeItem(key: string): void {\r\n try {\r\n getStorage()?.removeItem(key);\r\n } catch {\r\n // Ignore remove errors\r\n }\r\n}\r\n\r\nexport function loadUserState<T = unknown>(\r\n key: string = USER_STATE_STORAGE_KEY\r\n): T | undefined {\r\n const value = getItem<T | undefined>(key, undefined);\r\n return value === null ? undefined : value;\r\n}\r\n\r\nexport function saveUserState<T = unknown>(\r\n state: T,\r\n key: string = USER_STATE_STORAGE_KEY\r\n): void {\r\n setItem(key, state);\r\n}\r\n\r\n/** Task-aligned aliases */\r\nexport const get = getItem;\r\nexport const set = setItem;\r\n\r\n/** Backward-compatible aliases used in federation apps */\r\nexport const getItemFromLocalStorage = getItem;\r\nexport const storeItemInLocalStorage = setItem;\r\nexport const saveItemLocalStorage = setItem;\r\n","import toast from \"react-hot-toast\";\r\nimport Swal, { type SweetAlertOptions, type SweetAlertResult } from \"sweetalert2\";\r\n\r\nexport type RtkQueryError = {\r\n status?: number | string;\r\n originalStatus?: number;\r\n data?: {\r\n errors?: Record<string, string[]>;\r\n message?: string;\r\n title?: string;\r\n };\r\n message?: string;\r\n error?: string;\r\n};\r\n\r\nexport interface HandleApiErrorOptions {\r\n showAlert?: boolean;\r\n fallbackMessage?: string;\r\n}\r\n\r\nexport type ErrorSuggestedAction =\r\n | \"retry\"\r\n | \"refresh\"\r\n | \"contact-support\"\r\n | \"none\";\r\n\r\nexport type ErrorClassification = {\r\n isRetryable: boolean;\r\n userMessage: string;\r\n technicalMessage: string;\r\n suggestedAction: ErrorSuggestedAction;\r\n};\r\n\r\n/** Returns true for transient network/server errors that warrant automatic retry. */\r\nexport function isRetryableError(\r\n error: RtkQueryError | null | undefined\r\n): boolean {\r\n if (!error) return false;\r\n\r\n const status = error.status ?? error.originalStatus;\r\n\r\n if (\r\n status === \"FETCH_ERROR\" ||\r\n status === \"TIMEOUT_ERROR\" ||\r\n status === \"PARSING_ERROR\"\r\n ) {\r\n return true;\r\n }\r\n\r\n if (typeof status === \"number\") {\r\n if (status === 502 || status === 503 || status === 504) return true;\r\n if (status >= 500 && status < 600) return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/** Classifies RTK Query errors for user messaging and retry guidance. */\r\nexport function classifyError(\r\n error: RtkQueryError | null | undefined\r\n): ErrorClassification {\r\n if (!error) {\r\n return {\r\n isRetryable: false,\r\n userMessage: \"An error occurred.\",\r\n technicalMessage: \"Unknown error\",\r\n suggestedAction: \"none\",\r\n };\r\n }\r\n\r\n const status = error.status ?? error.originalStatus;\r\n const data = error.data;\r\n\r\n if (\r\n status === \"FETCH_ERROR\" ||\r\n status === \"TIMEOUT_ERROR\" ||\r\n status === \"PARSING_ERROR\"\r\n ) {\r\n return {\r\n isRetryable: true,\r\n userMessage: \"Network error. Please check your connection.\",\r\n technicalMessage: \"Network request failed\",\r\n suggestedAction: \"retry\",\r\n };\r\n }\r\n\r\n if (typeof status === \"number\" && status >= 500 && status < 600) {\r\n return {\r\n isRetryable: true,\r\n userMessage: \"Server is temporarily unavailable. Please try again.\",\r\n technicalMessage: `Server error: ${status}`,\r\n suggestedAction: \"retry\",\r\n };\r\n }\r\n\r\n return {\r\n isRetryable: false,\r\n userMessage:\r\n data?.message ||\r\n data?.title ||\r\n error.error ||\r\n \"An error occurred. Please try again.\",\r\n technicalMessage:\r\n typeof status === \"number\" || typeof status === \"string\"\r\n ? `Client error: ${status}`\r\n : \"Request failed\",\r\n suggestedAction: \"none\",\r\n };\r\n}\r\n\r\nexport function formatValidationErrorsHtml(\r\n errors: Record<string, string[]>\r\n): string {\r\n const items = Object.keys(errors).flatMap((field) =>\r\n (errors[field] || []).map((msg) => `<li>${msg}</li>`)\r\n );\r\n return `\r\n <div style=\"text-align:left\">\r\n <p>Please review and correct the following:</p>\r\n <ul style=\"margin:8px 0 0 16px; list-style:disc;\">\r\n ${items.join(\"\")}\r\n </ul>\r\n </div>\r\n `;\r\n}\r\n\r\nfunction showValidationAlert(html: string): void {\r\n void Swal.fire({\r\n title: \"Validation errors\",\r\n html,\r\n icon: \"error\",\r\n confirmButtonText: \"OK\",\r\n showCancelButton: false,\r\n confirmButtonColor: \"#FF7335\",\r\n });\r\n}\r\n\r\n/** Handles RTK Query errors with built-in toast.error or SweetAlert (when showAlert is true). */\r\nexport function handleApiError(\r\n error: RtkQueryError | null | undefined,\r\n { showAlert = false, fallbackMessage }: HandleApiErrorOptions = {}\r\n): void {\r\n if (!error) return;\r\n\r\n const status = error.status ?? error.originalStatus;\r\n const data = error.data;\r\n\r\n if (status === 200) {\r\n return;\r\n }\r\n\r\n if (data?.errors && typeof data.errors === \"object\") {\r\n const errors = data.errors;\r\n\r\n if (showAlert) {\r\n showValidationAlert(formatValidationErrorsHtml(errors));\r\n } else {\r\n Object.keys(errors).forEach((field) => {\r\n (errors[field] || []).forEach((errorMessage) => {\r\n toast.error(errorMessage);\r\n });\r\n });\r\n }\r\n return;\r\n }\r\n\r\n if (status === 404) {\r\n return;\r\n }\r\n\r\n const message =\r\n fallbackMessage ||\r\n data?.message ||\r\n data?.title ||\r\n error.error ||\r\n error.message ||\r\n \"An error occurred. Please try again.\";\r\n\r\n toast.error(message);\r\n}\r\n\r\nconst BRAND_ORANGE = \"#FF7335\";\r\nconst DANGER_RED = \"#DC2626\";\r\nconst DANGER_ICON_BG = \"#FEE2E2\";\r\nconst CANCEL_BG = \"#ffffff\";\r\nconst CANCEL_TEXT = \"#374151\";\r\nconst CONFIRM_STYLE_ID = \"eztrak-confirm-alert-styles\";\r\n\r\nexport type ConfirmationAlertVariant = \"brand\" | \"danger\";\r\n\r\nexport interface ConfirmationAlertOptions {\r\n title?: string;\r\n text?: string;\r\n html?: string;\r\n icon?: \"warning\" | \"info\" | \"question\" | \"error\" | \"success\";\r\n /** Custom icon markup. When set, replaces SweetAlert's default icon content. */\r\n iconHtml?: string;\r\n iconColor?: string;\r\n iconBgColor?: string;\r\n showIcon?: boolean;\r\n confirmButtonText?: string;\r\n cancelButtonText?: string;\r\n confirmButtonColor?: string;\r\n cancelButtonColor?: string;\r\n confirmButtonTextColor?: string;\r\n cancelButtonTextColor?: string;\r\n showCancelButton?: boolean;\r\n showLoaderOnConfirm?: boolean;\r\n /** Type exactly — trimmed, case-sensitive. */\r\n inputExpectedValue?: string;\r\n inputPlaceholder?: string;\r\n reverseButtons?: boolean;\r\n focusCancel?: boolean;\r\n zIndex?: number;\r\n width?: string | number;\r\n /** Card corner radius. Default `1rem`. Number = px. */\r\n borderRadius?: string | number;\r\n /** Confirm/cancel button corner radius. Default `0.5rem`. Number = px. */\r\n buttonBorderRadius?: string | number;\r\n /** `danger` = delete look; `brand` = orange confirm. Explicit options win. */\r\n variant?: ConfirmationAlertVariant;\r\n customClass?: SweetAlertOptions[\"customClass\"];\r\n onCancel?: () => void;\r\n}\r\n\r\nfunction cssSize(value: string | number | undefined, fallback: string): string {\r\n if (value === undefined) return fallback;\r\n return typeof value === \"number\" ? `${value}px` : value;\r\n}\r\n\r\n/** Reusable icon markup — override via `iconHtml`. */\r\nexport const DEFAULT_CONFIRM_ICONS = {\r\n warning: `\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z\" />\r\n </svg>\r\n `.trim(),\r\n} as const;\r\n\r\ntype VariantDefaults = Partial<\r\n Pick<\r\n ConfirmationAlertOptions,\r\n | \"title\"\r\n | \"confirmButtonText\"\r\n | \"confirmButtonColor\"\r\n | \"confirmButtonTextColor\"\r\n | \"cancelButtonColor\"\r\n | \"cancelButtonTextColor\"\r\n | \"iconColor\"\r\n | \"iconBgColor\"\r\n | \"iconHtml\"\r\n | \"showLoaderOnConfirm\"\r\n | \"icon\"\r\n >\r\n>;\r\n\r\nconst VARIANT_DEFAULTS: Record<ConfirmationAlertVariant, VariantDefaults> = {\r\n brand: {\r\n confirmButtonText: \"Yes\",\r\n confirmButtonColor: BRAND_ORANGE,\r\n confirmButtonTextColor: \"#ffffff\",\r\n cancelButtonColor: CANCEL_BG,\r\n cancelButtonTextColor: CANCEL_TEXT,\r\n iconColor: BRAND_ORANGE,\r\n iconBgColor: \"#FFEDD5\",\r\n iconHtml: DEFAULT_CONFIRM_ICONS.warning,\r\n icon: \"warning\",\r\n },\r\n danger: {\r\n title: \"Delete this item\",\r\n confirmButtonText: \"Yes, delete it!\",\r\n confirmButtonColor: DANGER_RED,\r\n confirmButtonTextColor: \"#ffffff\",\r\n cancelButtonColor: CANCEL_BG,\r\n cancelButtonTextColor: CANCEL_TEXT,\r\n iconColor: DANGER_RED,\r\n iconBgColor: DANGER_ICON_BG,\r\n iconHtml: DEFAULT_CONFIRM_ICONS.warning,\r\n icon: \"warning\",\r\n showLoaderOnConfirm: true,\r\n },\r\n};\r\n\r\nfunction ensureConfirmAlertStyles(): void {\r\n if (typeof document === \"undefined\") return;\r\n if (document.getElementById(CONFIRM_STYLE_ID)) return;\r\n\r\n const style = document.createElement(\"style\");\r\n style.id = CONFIRM_STYLE_ID;\r\n style.textContent = `\r\n .ez-confirm-popup {\r\n border-radius: var(--ez-confirm-radius, 1rem) !important;\r\n padding: 1.5rem !important;\r\n max-width: 24rem !important;\r\n width: var(--ez-confirm-width, 100%) !important;\r\n box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25) !important;\r\n }\r\n .ez-confirm-title {\r\n font-size: 1.125rem !important;\r\n font-weight: 600 !important;\r\n color: #111827 !important;\r\n margin: 0 0 0.25rem !important;\r\n padding: 0 !important;\r\n }\r\n .ez-confirm-html {\r\n font-size: 0.875rem !important;\r\n color: #6b7280 !important;\r\n margin: 0 0 1.5rem !important;\r\n }\r\n .ez-confirm-icon {\r\n border: none !important;\r\n background: var(--ez-confirm-icon-bg, #fee2e2) !important;\r\n color: var(--ez-confirm-icon-color, #dc2626) !important;\r\n width: 3rem !important;\r\n height: 3rem !important;\r\n margin: 0 auto 1rem !important;\r\n border-radius: 9999px !important;\r\n }\r\n .ez-confirm-icon .swal2-icon-content {\r\n font-size: inherit !important;\r\n display: flex !important;\r\n align-items: center !important;\r\n justify-content: center !important;\r\n color: inherit !important;\r\n }\r\n .ez-confirm-actions {\r\n width: 100% !important;\r\n margin: 0 !important;\r\n gap: 0.75rem !important;\r\n }\r\n .ez-confirm-confirm,\r\n .ez-confirm-cancel {\r\n flex: 1 1 0 !important;\r\n margin: 0 !important;\r\n border-radius: var(--ez-confirm-btn-radius, 0.5rem) !important;\r\n font-size: 0.875rem !important;\r\n font-weight: 500 !important;\r\n padding: 0.625rem 1rem !important;\r\n box-shadow: none !important;\r\n }\r\n .ez-confirm-confirm {\r\n background: var(--ez-confirm-confirm-bg, #ff7335) !important;\r\n color: var(--ez-confirm-confirm-fg, #fff) !important;\r\n border: none !important;\r\n }\r\n .ez-confirm-confirm:hover {\r\n filter: brightness(0.95);\r\n }\r\n .ez-confirm-cancel {\r\n background: var(--ez-confirm-cancel-bg, #fff) !important;\r\n color: var(--ez-confirm-cancel-fg, #374151) !important;\r\n border: 1px solid #d1d5db !important;\r\n }\r\n .ez-confirm-cancel:hover {\r\n background: #f9fafb !important;\r\n }\r\n `;\r\n document.head.appendChild(style);\r\n}\r\n\r\nfunction pick<T>(\r\n explicit: T | undefined,\r\n fromVariant: T | undefined,\r\n fallback: T\r\n): T {\r\n if (explicit !== undefined) return explicit;\r\n if (fromVariant !== undefined) return fromVariant;\r\n return fallback;\r\n}\r\n\r\nfunction mergeCustomClass(\r\n base: NonNullable<SweetAlertOptions[\"customClass\"]>,\r\n extra?: SweetAlertOptions[\"customClass\"]\r\n): SweetAlertOptions[\"customClass\"] {\r\n if (!extra || typeof extra !== \"object\") return base;\r\n const merged: Record<string, string> = { ...(base as Record<string, string>) };\r\n for (const [key, value] of Object.entries(extra)) {\r\n if (typeof value === \"string\" && value) {\r\n merged[key] = merged[key] ? `${merged[key]} ${value}` : value;\r\n }\r\n }\r\n return merged;\r\n}\r\n\r\nfunction getConfirmErrorMessage(error: unknown): string {\r\n if (error && typeof error === \"object\") {\r\n const err = error as {\r\n message?: string;\r\n data?: { message?: string; title?: string };\r\n };\r\n return (\r\n err.data?.message ||\r\n err.data?.title ||\r\n err.message ||\r\n \"Something went wrong. Please try again.\"\r\n );\r\n }\r\n return \"Something went wrong. Please try again.\";\r\n}\r\n\r\nexport function confirmationAlert(\r\n onConfirm: () => void | Promise<void>,\r\n options: ConfirmationAlertOptions = {}\r\n): void {\r\n ensureConfirmAlertStyles();\r\n\r\n const variant = options.variant ?? \"brand\";\r\n const vd = VARIANT_DEFAULTS[variant];\r\n\r\n const inputExpectedValue = options.inputExpectedValue;\r\n const hasInput = Boolean(inputExpectedValue);\r\n\r\n const title = pick(\r\n options.title,\r\n vd.title,\r\n hasInput ? \"Confirmation Required\" : \"Delete this item\"\r\n );\r\n const text = options.text;\r\n const html = options.html;\r\n const icon = pick(options.icon, vd.icon, \"warning\" as const);\r\n const iconHtml = pick(options.iconHtml, vd.iconHtml, undefined);\r\n const iconColor = pick(options.iconColor, vd.iconColor, BRAND_ORANGE);\r\n const iconBgColor = pick(options.iconBgColor, vd.iconBgColor, \"#FFEDD5\");\r\n const showIcon = options.showIcon !== false;\r\n const confirmButtonText = pick(options.confirmButtonText, vd.confirmButtonText, \"Yes\");\r\n const cancelButtonText = options.cancelButtonText ?? \"Cancel\";\r\n const confirmButtonColor = pick(\r\n options.confirmButtonColor,\r\n vd.confirmButtonColor,\r\n BRAND_ORANGE\r\n );\r\n const cancelButtonColor = pick(\r\n options.cancelButtonColor,\r\n vd.cancelButtonColor,\r\n CANCEL_BG\r\n );\r\n const confirmButtonTextColor = pick(\r\n options.confirmButtonTextColor,\r\n vd.confirmButtonTextColor,\r\n \"#ffffff\"\r\n );\r\n const cancelButtonTextColor = pick(\r\n options.cancelButtonTextColor,\r\n vd.cancelButtonTextColor,\r\n CANCEL_TEXT\r\n );\r\n const showCancelButton = options.showCancelButton !== false;\r\n const showLoaderOnConfirm = pick(\r\n options.showLoaderOnConfirm,\r\n vd.showLoaderOnConfirm,\r\n false\r\n );\r\n const inputPlaceholder =\r\n options.inputPlaceholder ?? \"Type confirmation text to proceed\";\r\n // Cancel left, Confirm right (matches gallery delete card)\r\n const reverseButtons = options.reverseButtons ?? false;\r\n const focusCancel = options.focusCancel;\r\n const zIndex = options.zIndex;\r\n const width = options.width;\r\n const borderRadius = cssSize(options.borderRadius, \"1rem\");\r\n const buttonBorderRadius = cssSize(options.buttonBorderRadius, \"0.5rem\");\r\n const onCancel = options.onCancel;\r\n\r\n const useLoader = showLoaderOnConfirm || hasInput;\r\n\r\n const inputHtml =\r\n html ??\r\n (hasInput\r\n ? `\r\n ${text ? `<p style=\"margin-bottom: 15px;\">${text}</p>` : \"\"}\r\n <p style=\"margin-bottom: 10px; font-weight: bold; color: #666;\">\r\n Please type \"<span style=\"color: ${BRAND_ORANGE}; font-weight: bold;\">${inputExpectedValue}</span>\" to confirm:\r\n </p>\r\n `\r\n : undefined);\r\n\r\n const baseCustomClass = {\r\n popup: \"ez-confirm-popup\",\r\n title: \"ez-confirm-title\",\r\n htmlContainer: \"ez-confirm-html\",\r\n actions: \"ez-confirm-actions\",\r\n confirmButton: \"ez-confirm-confirm\",\r\n cancelButton: \"ez-confirm-cancel\",\r\n icon: \"ez-confirm-icon\",\r\n };\r\n\r\n const swalOptions: SweetAlertOptions = {\r\n title,\r\n showCancelButton,\r\n confirmButtonText,\r\n cancelButtonText,\r\n confirmButtonColor,\r\n cancelButtonColor,\r\n reverseButtons,\r\n focusCancel,\r\n customClass: mergeCustomClass(baseCustomClass, options.customClass),\r\n allowOutsideClick: () => !Swal.isLoading(),\r\n allowEscapeKey: () => !Swal.isLoading(),\r\n didOpen: () => {\r\n const popup = Swal.getPopup();\r\n if (popup) {\r\n popup.style.setProperty(\"--ez-confirm-confirm-bg\", confirmButtonColor);\r\n popup.style.setProperty(\"--ez-confirm-confirm-fg\", confirmButtonTextColor);\r\n popup.style.setProperty(\"--ez-confirm-cancel-bg\", cancelButtonColor);\r\n popup.style.setProperty(\"--ez-confirm-cancel-fg\", cancelButtonTextColor);\r\n popup.style.setProperty(\"--ez-confirm-icon-color\", iconColor);\r\n popup.style.setProperty(\"--ez-confirm-icon-bg\", iconBgColor);\r\n popup.style.setProperty(\"--ez-confirm-radius\", borderRadius);\r\n popup.style.setProperty(\"--ez-confirm-btn-radius\", buttonBorderRadius);\r\n if (width != null) {\r\n popup.style.setProperty(\r\n \"--ez-confirm-width\",\r\n typeof width === \"number\" ? `${width}px` : String(width)\r\n );\r\n }\r\n }\r\n if (zIndex == null) return;\r\n const container = Swal.getContainer();\r\n if (container) container.style.zIndex = String(zIndex);\r\n },\r\n };\r\n\r\n if (showIcon) {\r\n swalOptions.icon = icon;\r\n if (iconHtml) {\r\n swalOptions.iconHtml = iconHtml;\r\n }\r\n }\r\n\r\n if (hasInput) {\r\n swalOptions.html = inputHtml;\r\n swalOptions.input = \"text\";\r\n swalOptions.inputPlaceholder = inputPlaceholder;\r\n swalOptions.inputValidator = (value: string) => {\r\n if (!value?.trim()) return \"You need to enter the confirmation text!\";\r\n if (value.trim() !== inputExpectedValue!.trim()) {\r\n return `Please type \"${inputExpectedValue}\" exactly as shown!`;\r\n }\r\n return null;\r\n };\r\n } else if (html) {\r\n swalOptions.html = html;\r\n } else {\r\n swalOptions.text = text;\r\n }\r\n\r\n if (useLoader) {\r\n swalOptions.showLoaderOnConfirm = true;\r\n swalOptions.preConfirm = (inputValue: string) => {\r\n if (hasInput && inputValue?.trim() !== inputExpectedValue!.trim()) {\r\n Swal.showValidationMessage(\r\n `Please type \"${inputExpectedValue}\" exactly as shown!`\r\n );\r\n return false;\r\n }\r\n return Promise.resolve()\r\n .then(() => onConfirm())\r\n .catch((error) => {\r\n Swal.showValidationMessage(getConfirmErrorMessage(error));\r\n throw error;\r\n });\r\n };\r\n }\r\n\r\n void Swal.fire(swalOptions).then((result: SweetAlertResult) => {\r\n if (result.isConfirmed && !useLoader) {\r\n void Promise.resolve(onConfirm());\r\n return;\r\n }\r\n if (result.isDismissed) {\r\n onCancel?.();\r\n }\r\n });\r\n}\r\n"],"mappings":";AAAA,OAAO,UAAU;AACjB,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAiC;AACrD,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;ACEO,SAAS,eACd,QACA,UAAU,QACV,cAAc,KACd;AACA,MAAI,OAAO,IAAI,OAAO,GAAG;AACvB,WAAO,IAAI,SAAS,WAAW;AAAA,EACjC;AACA,SAAO;AACT;;;AChBO,IAAM,eAAe,CAC1B,MACA,YAAY,OACD;AACX,MAAI,SAAS,QAAQ,SAAS,OAAW,QAAO;AAChD,QAAM,QAAQ,OAAO,IAAI;AACzB,MAAI,MAAM,UAAU,WAAW;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI;AACzC;AAEO,IAAM,mBAAmB,CAC9B,UACA,YAAY,OACD;AACX,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,SAAS,UAAU,WAAW;AAChC,WAAO;AAAA,EACT;AACA,QAAM,YAAY,SAAS,MAAM,SAAS,YAAY,GAAG,CAAC;AAC1D,QAAM,gBACJ,SAAS,MAAM,GAAG,YAAY,UAAU,SAAS,CAAC,IAAI;AACxD,SAAO,gBAAgB;AACzB;AAEO,SAAS,YAAY,UAA2B;AACrD,MAAI,CAAC,SAAU,QAAO;AAEtB,MAAI,OAAO,aAAa,UAAU;AAChC,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ;AAKd,MAAI,MAAM,UAAU,MAAM;AACxB,UAAM,eAAe,MAAM,SAAS;AAEpC,QAAI,OAAO,iBAAiB,UAAU;AACpC,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,aAAa;AAC5B,QAAI,UAAU,OAAO,WAAW,UAAU;AACxC,iBAAW,OAAO,QAAQ;AACxB,cAAM,WAAY,OAAmC,GAAG;AACxD,YAAI,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS,GAAG;AAClD,iBAAO,OAAO,SAAS,CAAC,CAAC;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAEA,QAAI,aAAa,SAAS;AACxB,aAAO,OAAO,aAAa,OAAO;AAAA,IACpC;AAEA,QAAI,aAAa,OAAO;AACtB,aAAO,OAAO,aAAa,KAAK;AAAA,IAClC;AAAA,EACF;AAEA,MAAI,MAAM,SAAS;AACjB,WAAO,MAAM;AAAA,EACf;AAEA,SAAO;AACT;AAEO,IAAM,wBAAwB,CAAC,iBAAqC;AACzE,MAAI,gBAAgB,KAAM,QAAO,CAAC;AAClC,MAAI,MAAM,QAAQ,YAAY,EAAG,QAAO;AAExC,QAAM,SAAS;AACf,QAAM,OAAO,OAAO;AAEpB,MACE,QACA,OAAO,SAAS,YAChB,CAAC,MAAM,QAAQ,IAAI,KACnB,MAAM,QAAS,KAA+B,KAAK,GACnD;AACA,WAAQ,KAA8B;AAAA,EACxC;AAEA,QAAM,cAAc,OAAO;AAC3B,MAAI,MAAM,QAAQ,aAAa,KAAK,EAAG,QAAO,YAAY;AAC1D,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,WAAO,CAAC,IAAI;AAAA,EACd;AACA,SAAO,CAAC;AACV;AAEO,SAAS,eAAe,MAAyC;AACtE,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,EAAE,YAAY,CAAC,EACxE,KAAK,GAAG;AACb;AAEO,SAAS,gBAAgB,MAAyC;AACvE,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,YAAY;AAC1B;AAEO,IAAM,aAAa,CAAC,eAAkD;AAC3E,MAAI,eAAe,QAAQ,eAAe,OAAW,QAAO;AAC5D,QAAM,OAAO,IAAI,KAAK,UAAU;AAEhC,MAAI,MAAM,KAAK,QAAQ,CAAC,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,KAAK,SAAS,IAAI,GAAG,SAAS,EAAE,SAAS,GAAG,GAAG;AAC9D,QAAM,MAAM,KAAK,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACrD,QAAM,OAAO,KAAK,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE;AACnD,SAAO,GAAG,KAAK,IAAI,GAAG,IAAI,IAAI;AAChC;AAEO,IAAM,UAAU,CAAC,QAAyB;AAC/C,SAAO,OAAO,KAAK,GAAG,EAAE,WAAW;AACrC;AAEO,IAAM,mBAAmB,CAAC,SAAmD;AAClF,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AAEJ,MAAI,OAAO,SAAS,UAAU;AAC5B,QAAI,sBAAsB,KAAK,IAAI,GAAG;AACpC,aAAO;AAAA,IACT;AACA,QAAI,IAAI,KAAK,IAAI;AAAA,EACnB,OAAO;AACL,QAAI,IAAI,KAAK,IAAI;AAAA,EACnB;AAEA,MAAI,MAAM,EAAE,QAAQ,CAAC,EAAG,QAAO;AAE/B,QAAM,YAAY,IAAI,KAAK,EAAE,QAAQ,IAAI,EAAE,kBAAkB,IAAI,GAAK;AACtE,QAAM,OAAO,UAAU,YAAY;AACnC,QAAM,SAAS,UAAU,SAAS,IAAI,GAAG,SAAS,EAAE,SAAS,GAAG,GAAG;AACnE,QAAM,MAAM,UAAU,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AAE1D,SAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG;AAChC;AAEO,SAAS,wBAAwB,MAA2C;AACjF,MAAI,CAAC,QAAQ,KAAK,KAAK,MAAM,IAAI;AAC/B,WAAO,CAAC;AAAA,EACV;AACA,SAAO,KAAK,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AAClD;AAEO,SAAS,qBAAwB,OAAY,aAAyB;AAC3E,SAAO,MAAM,SAAS,WAAW;AACnC;AAEO,IAAM,oBAAoB,CAAC,UAA6C;AAC7E,SAAO,OAAO,eAAe,SAAS;AAAA,IACpC,OAAO;AAAA,IACP,UAAU;AAAA,EACZ,CAAC,KAAK;AACR;AACO,IAAM,eAAe,CAAC,WAAuD;AAClF,MAAI,MAAM,OAAO,MAAM,CAAC,KAAK,WAAW,QAAQ,WAAW,QAAW;AACpE,WAAO;AAAA,EACT;AAEA,QAAM,kBAAkB,OAAO,MAAM,EAClC,SAAS,EACT,QAAQ,yBAAyB,GAAG;AAEvC,SAAO;AACT;AAEO,IAAM,6BAA6B,CAAC,UAA2B;AACpE,MAAI,SAAS,QAAQ,UAAU,GAAI,QAAO;AAE1C,QAAM,MACJ,OAAO,UAAU,YAAY,UAAU,QAAQ,WAAW,QACrD,MAA6B,QAC9B;AAEN,QAAM,cAAc,OAAO,QAAQ,QAAQ,KAAK,KAAK,OAAO,GAAG;AAC/D,QAAM,eAAe,YAAY,QAAQ,SAAS,EAAE;AACpD,SAAO,WAAW,YAAY,KAAK;AACrC;AAEO,SAAS,iBACd,MACA,SACK;AACL,MAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,QAAO,CAAC;AAClC,SAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,UAAM,UAAU,EAAE,GAAG,IAAI;AACzB,KAAC,WAAW,CAAC,GAAG,QAAQ,CAAC,QAAQ;AAC/B,YAAM,MAAM,IAAI;AAChB,UAAI,CAAC,IAAK;AACV,UAAI,IAAI,SAAS,GAAG,GAAG;AACrB,cAAM,QAAQ,IAAI,MAAM,GAAG,EAAE;AAAA,UAC3B,CAAC,KAAK,SAAU,MAA8C,IAAI;AAAA,UAClE;AAAA,QACF;AACA,QAAC,QAAoC,GAAG,IAAI,SAAS;AAAA,MACvD;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT,CAAC;AACH;AAEO,IAAM,mBAAmB,CAAC,UAMA;AAC/B,MAAI,OAAO,MAAM,QAAQ;AACvB,WAAO,OAAO,OAAO,MAAM,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI;AAAA,EAC1D;AACA,SACE,OAAO,MAAM,SACb,OAAO,MAAM,OAAO,OAAO,CAAC,KAC5B;AAEJ;AAEO,IAAM,sBAAsB,CACjC,SAAc,CAAC,GACf,QACQ;AACR,SAAO,QAAQ,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,aAAa,GAAG;AAC/D;AAEO,IAAM,kBAAkB,CAC7B,SAAc,CAAC,GACf,QACQ;AACR,SAAO,OAAO,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,SAAS,GAAG;AACtD;AAEO,IAAM,kBAAkB,CAAc,eAAiC;AAC5E,MAAI;AACF,WAAO,KAAK,MAAM,UAAU;AAAA,EAC9B,SAAS,OAAO;AACd,YAAQ,MAAM,uBAAuB,KAAK;AAC1C,WAAO;AAAA,EACT;AACF;AAEO,IAAM,iBAAiB,CAAC,eAAkD;AAC/E,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,OAAO,IAAI,KAAK,UAAU;AAChC,MAAI,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AAClC,QAAM,UAAsC;AAAA,IAC1C,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACA,SAAO,KAAK,eAAe,SAAS,OAAO;AAC7C;AAEO,IAAM,yBAAyB,CACpC,QAAa,CAAC,GACd,UACA,SAAoB,CAAC,GACrB,EAAE,kBAAkB,MAAM,IAAmC,CAAC,MACtD;AACR,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,CAAC,SAAU,QAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AAC/E,QAAM,YAAY,CAAC,MACjB,mBAAmB,OAAO,MAAM,WAAW,EAAE,YAAY,IAAI;AAC/D,QAAM,YAAY,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;AAC1D,QAAM,WAAW,IAAI,IAAI,UAAU,IAAI,SAAS,CAAC;AACjD,SAAO,MAAM,OAAO,CAAC,SAAS,CAAC,SAAS,IAAI,UAAU,OAAO,QAAQ,CAAC,CAAC,CAAC;AAC1E;AAEO,IAAM,uBAAuB,CAClC,SAAc,CAAC,GACf,QACQ;AACR,SAAO,OAAO,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,cAAc,GAAG;AAChE;;;ACjSO,IAAM,yBAAyB;AAEtC,SAAS,aAA6B;AACpC,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO,OAAO;AAChB;AAEO,SAAS,QAAW,KAAa,WAAqB,MAAgB;AAC3E,MAAI;AACF,UAAM,MAAM,WAAW,GAAG,QAAQ,GAAG;AACrC,QAAI,QAAQ,QAAQ,QAAQ,QAAW;AACrC,aAAO;AAAA,IACT;AACA,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,QAAW,KAAa,OAAgB;AACtD,MAAI;AACF,eAAW,GAAG,QAAQ,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EAClD,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,WAAW,KAAmB;AAC5C,MAAI;AACF,eAAW,GAAG,WAAW,GAAG;AAAA,EAC9B,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,cACd,MAAc,wBACC;AACf,QAAM,QAAQ,QAAuB,KAAK,MAAS;AACnD,SAAO,UAAU,OAAO,SAAY;AACtC;AAEO,SAAS,cACd,OACA,MAAc,wBACR;AACN,UAAQ,KAAK,KAAK;AACpB;AAGO,IAAM,MAAM;AACZ,IAAM,MAAM;AAGZ,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AAChC,IAAM,uBAAuB;;;ACxDpC,OAAO,WAAW;AAClB,OAAO,UAA6D;AAiC7D,SAAS,iBACd,OACS;AACT,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,SAAS,MAAM,UAAU,MAAM;AAErC,MACE,WAAW,iBACX,WAAW,mBACX,WAAW,iBACX;AACA,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,UAAU;AAC9B,QAAI,WAAW,OAAO,WAAW,OAAO,WAAW,IAAK,QAAO;AAC/D,QAAI,UAAU,OAAO,SAAS,IAAK,QAAO;AAAA,EAC5C;AAEA,SAAO;AACT;AAGO,SAAS,cACd,OACqB;AACrB,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,MACL,aAAa;AAAA,MACb,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,iBAAiB;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,UAAU,MAAM;AACrC,QAAM,OAAO,MAAM;AAEnB,MACE,WAAW,iBACX,WAAW,mBACX,WAAW,iBACX;AACA,WAAO;AAAA,MACL,aAAa;AAAA,MACb,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,iBAAiB;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,OAAO,WAAW,YAAY,UAAU,OAAO,SAAS,KAAK;AAC/D,WAAO;AAAA,MACL,aAAa;AAAA,MACb,aAAa;AAAA,MACb,kBAAkB,iBAAiB,MAAM;AAAA,MACzC,iBAAiB;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,IACb,aACE,MAAM,WACN,MAAM,SACN,MAAM,SACN;AAAA,IACF,kBACE,OAAO,WAAW,YAAY,OAAO,WAAW,WAC5C,iBAAiB,MAAM,KACvB;AAAA,IACN,iBAAiB;AAAA,EACnB;AACF;AAEO,SAAS,2BACd,QACQ;AACR,QAAM,QAAQ,OAAO,KAAK,MAAM,EAAE;AAAA,IAAQ,CAAC,WACxC,OAAO,KAAK,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,OAAO,GAAG,OAAO;AAAA,EACtD;AACA,SAAO;AAAA;AAAA;AAAA;AAAA,cAIK,MAAM,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAI5B;AAEA,SAAS,oBAAoB,MAAoB;AAC/C,OAAK,KAAK,KAAK;AAAA,IACb,OAAO;AAAA,IACP;AAAA,IACA,MAAM;AAAA,IACN,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,EACtB,CAAC;AACH;AAGO,SAAS,eACd,OACA,EAAE,YAAY,OAAO,gBAAgB,IAA2B,CAAC,GAC3D;AACN,MAAI,CAAC,MAAO;AAEZ,QAAM,SAAS,MAAM,UAAU,MAAM;AACrC,QAAM,OAAO,MAAM;AAEnB,MAAI,WAAW,KAAK;AAClB;AAAA,EACF;AAEA,MAAI,MAAM,UAAU,OAAO,KAAK,WAAW,UAAU;AACnD,UAAM,SAAS,KAAK;AAEpB,QAAI,WAAW;AACb,0BAAoB,2BAA2B,MAAM,CAAC;AAAA,IACxD,OAAO;AACL,aAAO,KAAK,MAAM,EAAE,QAAQ,CAAC,UAAU;AACrC,SAAC,OAAO,KAAK,KAAK,CAAC,GAAG,QAAQ,CAAC,iBAAiB;AAC9C,gBAAM,MAAM,YAAY;AAAA,QAC1B,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AACA;AAAA,EACF;AAEA,MAAI,WAAW,KAAK;AAClB;AAAA,EACF;AAEA,QAAM,UACJ,mBACA,MAAM,WACN,MAAM,SACN,MAAM,SACP,MAAM,WACL;AAEF,QAAM,MAAM,OAAO;AACrB;AAEA,IAAM,eAAe;AACrB,IAAM,aAAa;AACnB,IAAM,iBAAiB;AACvB,IAAM,YAAY;AAClB,IAAM,cAAc;AACpB,IAAM,mBAAmB;AAuCzB,SAAS,QAAQ,OAAoC,UAA0B;AAC7E,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AACpD;AAGO,IAAM,wBAAwB;AAAA,EACnC,SAAS;AAAA;AAAA;AAAA;AAAA,IAIP,KAAK;AACT;AAmBA,IAAM,mBAAsE;AAAA,EAC1E,OAAO;AAAA,IACL,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,WAAW;AAAA,IACX,aAAa;AAAA,IACb,UAAU,sBAAsB;AAAA,IAChC,MAAM;AAAA,EACR;AAAA,EACA,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,WAAW;AAAA,IACX,aAAa;AAAA,IACb,UAAU,sBAAsB;AAAA,IAChC,MAAM;AAAA,IACN,qBAAqB;AAAA,EACvB;AACF;AAEA,SAAS,2BAAiC;AACxC,MAAI,OAAO,aAAa,YAAa;AACrC,MAAI,SAAS,eAAe,gBAAgB,EAAG;AAE/C,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,KAAK;AACX,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoEpB,WAAS,KAAK,YAAY,KAAK;AACjC;AAEA,SAAS,KACP,UACA,aACA,UACG;AACH,MAAI,aAAa,OAAW,QAAO;AACnC,MAAI,gBAAgB,OAAW,QAAO;AACtC,SAAO;AACT;AAEA,SAAS,iBACP,MACA,OACkC;AAClC,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,SAAiC,EAAE,GAAI,KAAgC;AAC7E,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,OAAO,UAAU,YAAY,OAAO;AACtC,aAAO,GAAG,IAAI,OAAO,GAAG,IAAI,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,KAAK;AAAA,IAC1D;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,OAAwB;AACtD,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,MAAM;AAIZ,WACE,IAAI,MAAM,WACV,IAAI,MAAM,SACV,IAAI,WACJ;AAAA,EAEJ;AACA,SAAO;AACT;AAEO,SAAS,kBACd,WACA,UAAoC,CAAC,GAC/B;AACN,2BAAyB;AAEzB,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,KAAK,iBAAiB,OAAO;AAEnC,QAAM,qBAAqB,QAAQ;AACnC,QAAM,WAAW,QAAQ,kBAAkB;AAE3C,QAAM,QAAQ;AAAA,IACZ,QAAQ;AAAA,IACR,GAAG;AAAA,IACH,WAAW,0BAA0B;AAAA,EACvC;AACA,QAAM,OAAO,QAAQ;AACrB,QAAM,OAAO,QAAQ;AACrB,QAAM,OAAO,KAAK,QAAQ,MAAM,GAAG,MAAM,SAAkB;AAC3D,QAAM,WAAW,KAAK,QAAQ,UAAU,GAAG,UAAU,MAAS;AAC9D,QAAM,YAAY,KAAK,QAAQ,WAAW,GAAG,WAAW,YAAY;AACpE,QAAM,cAAc,KAAK,QAAQ,aAAa,GAAG,aAAa,SAAS;AACvE,QAAM,WAAW,QAAQ,aAAa;AACtC,QAAM,oBAAoB,KAAK,QAAQ,mBAAmB,GAAG,mBAAmB,KAAK;AACrF,QAAM,mBAAmB,QAAQ,oBAAoB;AACrD,QAAM,qBAAqB;AAAA,IACzB,QAAQ;AAAA,IACR,GAAG;AAAA,IACH;AAAA,EACF;AACA,QAAM,oBAAoB;AAAA,IACxB,QAAQ;AAAA,IACR,GAAG;AAAA,IACH;AAAA,EACF;AACA,QAAM,yBAAyB;AAAA,IAC7B,QAAQ;AAAA,IACR,GAAG;AAAA,IACH;AAAA,EACF;AACA,QAAM,wBAAwB;AAAA,IAC5B,QAAQ;AAAA,IACR,GAAG;AAAA,IACH;AAAA,EACF;AACA,QAAM,mBAAmB,QAAQ,qBAAqB;AACtD,QAAM,sBAAsB;AAAA,IAC1B,QAAQ;AAAA,IACR,GAAG;AAAA,IACH;AAAA,EACF;AACA,QAAM,mBACJ,QAAQ,oBAAoB;AAE9B,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,QAAM,cAAc,QAAQ;AAC5B,QAAM,SAAS,QAAQ;AACvB,QAAM,QAAQ,QAAQ;AACtB,QAAM,eAAe,QAAQ,QAAQ,cAAc,MAAM;AACzD,QAAM,qBAAqB,QAAQ,QAAQ,oBAAoB,QAAQ;AACvE,QAAM,WAAW,QAAQ;AAEzB,QAAM,YAAY,uBAAuB;AAEzC,QAAM,YACJ,SACC,WACG;AAAA,QACA,OAAO,mCAAmC,IAAI,SAAS,EAAE;AAAA;AAAA,2CAEtB,YAAY,yBAAyB,kBAAkB;AAAA;AAAA,QAG1F;AAEN,QAAM,kBAAkB;AAAA,IACtB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,eAAe;AAAA,IACf,SAAS;AAAA,IACT,eAAe;AAAA,IACf,cAAc;AAAA,IACd,MAAM;AAAA,EACR;AAEA,QAAM,cAAiC;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,iBAAiB,iBAAiB,QAAQ,WAAW;AAAA,IAClE,mBAAmB,MAAM,CAAC,KAAK,UAAU;AAAA,IACzC,gBAAgB,MAAM,CAAC,KAAK,UAAU;AAAA,IACtC,SAAS,MAAM;AACb,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,OAAO;AACT,cAAM,MAAM,YAAY,2BAA2B,kBAAkB;AACrE,cAAM,MAAM,YAAY,2BAA2B,sBAAsB;AACzE,cAAM,MAAM,YAAY,0BAA0B,iBAAiB;AACnE,cAAM,MAAM,YAAY,0BAA0B,qBAAqB;AACvE,cAAM,MAAM,YAAY,2BAA2B,SAAS;AAC5D,cAAM,MAAM,YAAY,wBAAwB,WAAW;AAC3D,cAAM,MAAM,YAAY,uBAAuB,YAAY;AAC3D,cAAM,MAAM,YAAY,2BAA2B,kBAAkB;AACrE,YAAI,SAAS,MAAM;AACjB,gBAAM,MAAM;AAAA,YACV;AAAA,YACA,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO,OAAO,KAAK;AAAA,UACzD;AAAA,QACF;AAAA,MACF;AACA,UAAI,UAAU,KAAM;AACpB,YAAM,YAAY,KAAK,aAAa;AACpC,UAAI,UAAW,WAAU,MAAM,SAAS,OAAO,MAAM;AAAA,IACvD;AAAA,EACF;AAEA,MAAI,UAAU;AACZ,gBAAY,OAAO;AACnB,QAAI,UAAU;AACZ,kBAAY,WAAW;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,UAAU;AACZ,gBAAY,OAAO;AACnB,gBAAY,QAAQ;AACpB,gBAAY,mBAAmB;AAC/B,gBAAY,iBAAiB,CAAC,UAAkB;AAC9C,UAAI,CAAC,OAAO,KAAK,EAAG,QAAO;AAC3B,UAAI,MAAM,KAAK,MAAM,mBAAoB,KAAK,GAAG;AAC/C,eAAO,gBAAgB,kBAAkB;AAAA,MAC3C;AACA,aAAO;AAAA,IACT;AAAA,EACF,WAAW,MAAM;AACf,gBAAY,OAAO;AAAA,EACrB,OAAO;AACL,gBAAY,OAAO;AAAA,EACrB;AAEA,MAAI,WAAW;AACb,gBAAY,sBAAsB;AAClC,gBAAY,aAAa,CAAC,eAAuB;AAC/C,UAAI,YAAY,YAAY,KAAK,MAAM,mBAAoB,KAAK,GAAG;AACjE,aAAK;AAAA,UACH,gBAAgB,kBAAkB;AAAA,QACpC;AACA,eAAO;AAAA,MACT;AACA,aAAO,QAAQ,QAAQ,EACpB,KAAK,MAAM,UAAU,CAAC,EACtB,MAAM,CAAC,UAAU;AAChB,aAAK,sBAAsB,uBAAuB,KAAK,CAAC;AACxD,cAAM;AAAA,MACR,CAAC;AAAA,IACL;AAAA,EACF;AAEA,OAAK,KAAK,KAAK,WAAW,EAAE,KAAK,CAAC,WAA6B;AAC7D,QAAI,OAAO,eAAe,CAAC,WAAW;AACpC,WAAK,QAAQ,QAAQ,UAAU,CAAC;AAChC;AAAA,IACF;AACA,QAAI,OAAO,aAAa;AACtB,iBAAW;AAAA,IACb;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isRetryableError
3
- } from "./chunk-EIX5CUQF.mjs";
3
+ } from "./chunk-A5BBQ7X5.mjs";
4
4
 
5
5
  // src/utils/permissions.ts
6
6
  function transformPermissions(permissions) {
@@ -57,4 +57,4 @@ export {
57
57
  transformPermissions,
58
58
  createBaseQueryWithRetry
59
59
  };
60
- //# sourceMappingURL=chunk-WZVYTP6G.mjs.map
60
+ //# sourceMappingURL=chunk-HAW3AKJP.mjs.map