@eztrak/shared 0.8.1 → 0.11.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/dist/index.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
+ CardSkeleton: () => CardSkeleton,
33
34
  CustomCellEditor: () => CustomCellEditor,
34
35
  CustomPagination: () => CustomPagination,
35
36
  EztrakTabs: () => EztrakTabs,
@@ -41,6 +42,7 @@ __export(src_exports, {
41
42
  TableLayoutToolbarControls: () => TableLayoutToolbarControls,
42
43
  ToolTip: () => ToolTip,
43
44
  TooltipText: () => TooltipText,
45
+ USER_STATE_STORAGE_KEY: () => USER_STATE_STORAGE_KEY,
44
46
  capitalizeText: () => capitalizeText,
45
47
  checkIfExistsInArray: () => checkIfExistsInArray,
46
48
  cn: () => cn,
@@ -53,16 +55,26 @@ __export(src_exports, {
53
55
  formatDateTime: () => formatDateTime,
54
56
  formatNumber: () => formatNumber,
55
57
  formatValidationErrorsHtml: () => formatValidationErrorsHtml,
58
+ get: () => get,
56
59
  getApiError: () => getApiError,
57
60
  getErrorMessages: () => getErrorMessages,
58
61
  getFieldsByCategory: () => getFieldsByCategory,
59
62
  getFieldsByInputType: () => getFieldsByInputType,
60
63
  getFieldsByName: () => getFieldsByName,
64
+ getItem: () => getItem,
65
+ getItemFromLocalStorage: () => getItemFromLocalStorage,
61
66
  handleApiError: () => handleApiError,
62
67
  isEmpty: () => isEmpty,
68
+ loadUserState: () => loadUserState,
63
69
  normalizeApiListItems: () => normalizeApiListItems,
64
70
  parseCurrencyValueToNumber: () => parseCurrencyValueToNumber,
65
71
  removeByPropertyValues: () => removeByPropertyValues,
72
+ removeItem: () => removeItem,
73
+ saveItemLocalStorage: () => saveItemLocalStorage,
74
+ saveUserState: () => saveUserState,
75
+ set: () => set,
76
+ setItem: () => setItem,
77
+ storeItemInLocalStorage: () => storeItemInLocalStorage,
66
78
  toDateInputValue: () => toDateInputValue,
67
79
  toLowerCaseText: () => toLowerCaseText,
68
80
  truncateFileName: () => truncateFileName,
@@ -277,6 +289,48 @@ var getFieldsByInputType = (fields = [], key) => {
277
289
  return fields.filter(({ inputType = "" }) => inputType === key);
278
290
  };
279
291
 
292
+ // src/utils/localStorage.ts
293
+ var USER_STATE_STORAGE_KEY = "authState";
294
+ function getStorage() {
295
+ if (typeof window === "undefined") return null;
296
+ return window.localStorage;
297
+ }
298
+ function getItem(key, fallback = null) {
299
+ try {
300
+ const raw = getStorage()?.getItem(key);
301
+ if (raw === null || raw === void 0) {
302
+ return fallback;
303
+ }
304
+ return JSON.parse(raw);
305
+ } catch {
306
+ return fallback;
307
+ }
308
+ }
309
+ function setItem(key, value) {
310
+ try {
311
+ getStorage()?.setItem(key, JSON.stringify(value));
312
+ } catch {
313
+ }
314
+ }
315
+ function removeItem(key) {
316
+ try {
317
+ getStorage()?.removeItem(key);
318
+ } catch {
319
+ }
320
+ }
321
+ function loadUserState(key = USER_STATE_STORAGE_KEY) {
322
+ const value = getItem(key, void 0);
323
+ return value === null ? void 0 : value;
324
+ }
325
+ function saveUserState(state, key = USER_STATE_STORAGE_KEY) {
326
+ setItem(key, state);
327
+ }
328
+ var get = getItem;
329
+ var set = setItem;
330
+ var getItemFromLocalStorage = getItem;
331
+ var storeItemInLocalStorage = setItem;
332
+ var saveItemLocalStorage = setItem;
333
+
280
334
  // src/utils/handleApiError.ts
281
335
  var import_react_hot_toast = __toESM(require("react-hot-toast"));
282
336
  var import_sweetalert2 = __toESM(require("sweetalert2"));
@@ -329,18 +383,92 @@ function handleApiError(error, { showAlert = false, fallbackMessage } = {}) {
329
383
  const message = fallbackMessage || data?.message || data?.title || error.error || "An error occurred. Please try again.";
330
384
  import_react_hot_toast.default.error(message);
331
385
  }
386
+ var BRAND_ORANGE = "#FF7335";
387
+ var CANCEL_RED = "#ff0000";
388
+ function getConfirmErrorMessage(error) {
389
+ if (error && typeof error === "object") {
390
+ const err = error;
391
+ return err.data?.message || err.data?.title || err.message || "Something went wrong. Please try again.";
392
+ }
393
+ return "Something went wrong. Please try again.";
394
+ }
332
395
  function confirmationAlert(onConfirm, options = {}) {
333
- void import_sweetalert2.default.fire({
334
- title: options.title ?? "Are you sure?",
335
- text: options.text,
336
- icon: options.icon ?? "warning",
396
+ const {
397
+ title = options.inputExpectedValue ? "Confirmation Required" : "Are you sure?",
398
+ text,
399
+ html,
400
+ icon = "warning",
401
+ confirmButtonText = "Yes",
402
+ cancelButtonText = "Cancel",
403
+ confirmButtonColor = BRAND_ORANGE,
404
+ cancelButtonColor = CANCEL_RED,
405
+ showLoaderOnConfirm = false,
406
+ inputExpectedValue,
407
+ inputPlaceholder = "Type confirmation text to proceed",
408
+ reverseButtons,
409
+ focusCancel,
410
+ zIndex
411
+ } = options;
412
+ const hasInput = Boolean(inputExpectedValue);
413
+ const useLoader = showLoaderOnConfirm || hasInput;
414
+ const inputHtml = html ?? (hasInput ? `
415
+ ${text ? `<p style="margin-bottom: 15px;">${text}</p>` : ""}
416
+ <p style="margin-bottom: 10px; font-weight: bold; color: #666;">
417
+ Please type "<span style="color: ${BRAND_ORANGE}; font-weight: bold;">${inputExpectedValue}</span>" to confirm:
418
+ </p>
419
+ ` : void 0);
420
+ const swalOptions = {
421
+ title,
422
+ icon,
337
423
  showCancelButton: true,
338
- confirmButtonText: options.confirmButtonText ?? "Yes",
339
- cancelButtonText: options.cancelButtonText ?? "Cancel",
340
- confirmButtonColor: "#FF7335"
341
- }).then((result) => {
342
- if (result.isConfirmed) {
343
- onConfirm();
424
+ confirmButtonText,
425
+ cancelButtonText,
426
+ confirmButtonColor,
427
+ cancelButtonColor,
428
+ reverseButtons,
429
+ focusCancel,
430
+ allowOutsideClick: () => !import_sweetalert2.default.isLoading(),
431
+ allowEscapeKey: () => !import_sweetalert2.default.isLoading(),
432
+ didOpen: () => {
433
+ if (zIndex == null) return;
434
+ const container = import_sweetalert2.default.getContainer();
435
+ if (container) container.style.zIndex = String(zIndex);
436
+ }
437
+ };
438
+ if (hasInput) {
439
+ swalOptions.html = inputHtml;
440
+ swalOptions.input = "text";
441
+ swalOptions.inputPlaceholder = inputPlaceholder;
442
+ swalOptions.inputValidator = (value) => {
443
+ if (!value?.trim()) return "You need to enter the confirmation text!";
444
+ if (value.trim() !== inputExpectedValue.trim()) {
445
+ return `Please type "${inputExpectedValue}" exactly as shown!`;
446
+ }
447
+ return null;
448
+ };
449
+ } else if (html) {
450
+ swalOptions.html = html;
451
+ } else {
452
+ swalOptions.text = text;
453
+ }
454
+ if (useLoader) {
455
+ swalOptions.showLoaderOnConfirm = true;
456
+ swalOptions.preConfirm = (inputValue) => {
457
+ if (hasInput && inputValue?.trim() !== inputExpectedValue.trim()) {
458
+ import_sweetalert2.default.showValidationMessage(
459
+ `Please type "${inputExpectedValue}" exactly as shown!`
460
+ );
461
+ return false;
462
+ }
463
+ return Promise.resolve().then(() => onConfirm()).catch((error) => {
464
+ import_sweetalert2.default.showValidationMessage(getConfirmErrorMessage(error));
465
+ throw error;
466
+ });
467
+ };
468
+ }
469
+ void import_sweetalert2.default.fire(swalOptions).then((result) => {
470
+ if (result.isConfirmed && !useLoader) {
471
+ void Promise.resolve(onConfirm());
344
472
  }
345
473
  });
346
474
  }
@@ -1318,10 +1446,106 @@ function Modal({
1318
1446
  return (0, import_react_dom.createPortal)(modalContent, modalRoot);
1319
1447
  }
1320
1448
 
1449
+ // src/components/skeleton/CardSkeleton.tsx
1450
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1451
+ var DEFAULT_LINE_WIDTHS = ["w-32", "w-48"];
1452
+ function shouldShowAvatar(variant, showAvatar) {
1453
+ return showAvatar ?? variant === "profile";
1454
+ }
1455
+ function shouldShowImage(variant, showImage) {
1456
+ return showImage ?? variant === "image";
1457
+ }
1458
+ function AvatarSkeleton({ className }) {
1459
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1460
+ "svg",
1461
+ {
1462
+ className: cn("w-10 h-10 text-gray-200 dark:text-gray-700", className),
1463
+ "aria-hidden": "true",
1464
+ xmlns: "http://www.w3.org/2000/svg",
1465
+ fill: "currentColor",
1466
+ viewBox: "0 0 20 20",
1467
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M10 0a10 10 0 1 0 10 10A10.011 10.011 0 0 0 10 0Zm0 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm0 13a8.949 8.949 0 0 1-4.951-1.488A3.987 3.987 0 0 1 9 13h2a3.987 3.987 0 0 1 3.951 3.512A8.949 8.949 0 0 1 10 18Z" })
1468
+ }
1469
+ );
1470
+ }
1471
+ function SkeletonBlock({
1472
+ widthClass,
1473
+ className,
1474
+ isFirst
1475
+ }) {
1476
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1477
+ "div",
1478
+ {
1479
+ className: cn(
1480
+ isFirst ? "h-2.5 mb-2" : "h-2",
1481
+ "bg-gray-200 rounded-full dark:bg-gray-700",
1482
+ widthClass,
1483
+ className
1484
+ )
1485
+ }
1486
+ );
1487
+ }
1488
+ function CardSkeleton({
1489
+ variant = "profile",
1490
+ count = 1,
1491
+ lines = 2,
1492
+ lineWidths = DEFAULT_LINE_WIDTHS,
1493
+ showAvatar,
1494
+ showImage,
1495
+ animationDuration = "0.7s",
1496
+ className,
1497
+ style,
1498
+ avatarClassName,
1499
+ imageClassName,
1500
+ contentClassName,
1501
+ lineClassName,
1502
+ srLabel = "Loading...",
1503
+ ...props
1504
+ }) {
1505
+ const skeletons = Array.from({ length: Math.max(1, count) }, (_, index) => {
1506
+ const renderAvatar = shouldShowAvatar(variant, showAvatar);
1507
+ const renderImage = shouldShowImage(variant, showImage);
1508
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1509
+ "div",
1510
+ {
1511
+ className: cn("animate-pulse md:p-6 dark:border-gray-700", className),
1512
+ style: { animationDuration, ...style },
1513
+ ...props,
1514
+ children: [
1515
+ renderImage ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1516
+ "div",
1517
+ {
1518
+ className: cn(
1519
+ "mb-4 h-32 w-full rounded-xl bg-gray-200 dark:bg-gray-700",
1520
+ imageClassName
1521
+ )
1522
+ }
1523
+ ) : null,
1524
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cn("flex items-center mt-4 gap-4", contentClassName), children: [
1525
+ renderAvatar ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AvatarSkeleton, { className: avatarClassName }) : null,
1526
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: Array.from({ length: Math.max(1, lines) }, (_2, lineIndex) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1527
+ SkeletonBlock,
1528
+ {
1529
+ widthClass: lineWidths[lineIndex] ?? lineWidths[lineWidths.length - 1] ?? DEFAULT_LINE_WIDTHS[1],
1530
+ className: lineClassName,
1531
+ isFirst: lineIndex === 0
1532
+ },
1533
+ lineIndex
1534
+ )) })
1535
+ ] }),
1536
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "sr-only", children: srLabel })
1537
+ ]
1538
+ },
1539
+ index
1540
+ );
1541
+ });
1542
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: skeletons });
1543
+ }
1544
+
1321
1545
  // src/components/tooltip/ToolTip.tsx
1322
1546
  var import_react6 = require("react");
1323
1547
  var import_react_tooltip = require("react-tooltip");
1324
- var import_jsx_runtime7 = require("react/jsx-runtime");
1548
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1325
1549
  var defaultTooltipStyle = {
1326
1550
  color: "#fff",
1327
1551
  borderRadius: "5px",
@@ -1348,10 +1572,10 @@ function ToolTip({
1348
1572
  const tooltipId = `eztrak-tooltip-${generatedId.replace(/:/g, "")}`;
1349
1573
  const tooltipText = String(text ?? "");
1350
1574
  if (disabled || !tooltipText) {
1351
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className, children });
1575
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className, children });
1352
1576
  }
1353
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1354
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1577
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1578
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1355
1579
  "span",
1356
1580
  {
1357
1581
  className,
@@ -1361,7 +1585,7 @@ function ToolTip({
1361
1585
  children
1362
1586
  }
1363
1587
  ),
1364
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1588
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1365
1589
  import_react_tooltip.Tooltip,
1366
1590
  {
1367
1591
  id: tooltipId,
@@ -1377,7 +1601,7 @@ function ToolTip({
1377
1601
  }
1378
1602
 
1379
1603
  // src/components/tooltip/TooltipText.tsx
1380
- var import_jsx_runtime8 = require("react/jsx-runtime");
1604
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1381
1605
  function TooltipText({
1382
1606
  text = "",
1383
1607
  maxLength = 20,
@@ -1397,7 +1621,7 @@ function TooltipText({
1397
1621
  const displayText = truncateText(fullText, maxLength);
1398
1622
  const isTruncated = displayText !== fullText;
1399
1623
  const tooltipDisabled = !showTooltip || !hasValue || tooltipWhenTruncatedOnly && !isTruncated;
1400
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1624
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1401
1625
  ToolTip,
1402
1626
  {
1403
1627
  text: fullText,
@@ -1409,7 +1633,7 @@ function TooltipText({
1409
1633
  tooltipStyle,
1410
1634
  wrapperTabIndex: tooltipDisabled ? void 0 : 0,
1411
1635
  disabled: tooltipDisabled,
1412
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: cn("inline-block max-w-full align-bottom", textClassName), children: displayText })
1636
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: cn("inline-block max-w-full align-bottom", textClassName), children: displayText })
1413
1637
  }
1414
1638
  );
1415
1639
  }
@@ -1417,9 +1641,9 @@ function TooltipText({
1417
1641
  // src/components/cell-editor/CustomCellEditor.tsx
1418
1642
  var import_react7 = require("react");
1419
1643
  var import_react_hot_toast2 = __toESM(require("react-hot-toast"));
1420
- var import_jsx_runtime9 = require("react/jsx-runtime");
1644
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1421
1645
  function ButtonSpinner() {
1422
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1646
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1423
1647
  "svg",
1424
1648
  {
1425
1649
  className: "animate-spin",
@@ -1429,7 +1653,7 @@ function ButtonSpinner() {
1429
1653
  fill: "none",
1430
1654
  "aria-hidden": true,
1431
1655
  children: [
1432
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1656
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1433
1657
  "circle",
1434
1658
  {
1435
1659
  cx: "12",
@@ -1440,7 +1664,7 @@ function ButtonSpinner() {
1440
1664
  strokeOpacity: "0.25"
1441
1665
  }
1442
1666
  ),
1443
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1667
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1444
1668
  "path",
1445
1669
  {
1446
1670
  d: "M12 2a10 10 0 0 1 10 10",
@@ -1576,7 +1800,7 @@ var CustomCellEditor = (0, import_react7.forwardRef)(
1576
1800
  const defaultInputClass = "w-48 px-2 py-1 text-sm border border-gray-200 rounded-md bg-white focus:outline-none focus:ring-1 focus:ring-blue-400";
1577
1801
  const defaultSaveBtnClass = "px-3 py-1 text-sm font-medium text-white bg-green-500 rounded-md hover:bg-green-600 disabled:opacity-50 whitespace-nowrap shrink-0";
1578
1802
  const defaultCancelBtnClass = "px-3 py-1 text-sm font-medium text-white bg-red-500 rounded-md hover:bg-red-600 disabled:opacity-50 whitespace-nowrap shrink-0";
1579
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1803
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1580
1804
  "div",
1581
1805
  {
1582
1806
  className: cn(
@@ -1585,7 +1809,7 @@ var CustomCellEditor = (0, import_react7.forwardRef)(
1585
1809
  ),
1586
1810
  style: containerStyle,
1587
1811
  children: [
1588
- isDropdown ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1812
+ isDropdown ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1589
1813
  "select",
1590
1814
  {
1591
1815
  ref: selectRef,
@@ -1595,11 +1819,11 @@ var CustomCellEditor = (0, import_react7.forwardRef)(
1595
1819
  className: inputClassName ?? defaultInputClass,
1596
1820
  disabled: isLoading,
1597
1821
  children: [
1598
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "", disabled: true, children: "Select option..." }),
1599
- normalizedOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
1822
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", disabled: true, children: "Select option..." }),
1823
+ normalizedOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
1600
1824
  ]
1601
1825
  }
1602
- ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1826
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1603
1827
  "input",
1604
1828
  {
1605
1829
  ref: inputRef,
@@ -1612,7 +1836,7 @@ var CustomCellEditor = (0, import_react7.forwardRef)(
1612
1836
  disabled: isLoading
1613
1837
  }
1614
1838
  ),
1615
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1839
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1616
1840
  "button",
1617
1841
  {
1618
1842
  type: "button",
@@ -1621,10 +1845,10 @@ var CustomCellEditor = (0, import_react7.forwardRef)(
1621
1845
  className: saveButtonClassName ?? (saveButtonStyle ? void 0 : defaultSaveBtnClass),
1622
1846
  style: saveButtonStyle,
1623
1847
  title: "Save (Enter)",
1624
- children: isLoading ? loadingIndicator ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ButtonSpinner, {}) : saveButtonContent ?? "Save"
1848
+ children: isLoading ? loadingIndicator ?? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ButtonSpinner, {}) : saveButtonContent ?? "Save"
1625
1849
  }
1626
1850
  ),
1627
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1851
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1628
1852
  "button",
1629
1853
  {
1630
1854
  type: "button",
@@ -1644,6 +1868,7 @@ var CustomCellEditor = (0, import_react7.forwardRef)(
1644
1868
  CustomCellEditor.displayName = "CustomCellEditor";
1645
1869
  // Annotate the CommonJS export names for ESM import in node:
1646
1870
  0 && (module.exports = {
1871
+ CardSkeleton,
1647
1872
  CustomCellEditor,
1648
1873
  CustomPagination,
1649
1874
  EztrakTabs,
@@ -1655,6 +1880,7 @@ CustomCellEditor.displayName = "CustomCellEditor";
1655
1880
  TableLayoutToolbarControls,
1656
1881
  ToolTip,
1657
1882
  TooltipText,
1883
+ USER_STATE_STORAGE_KEY,
1658
1884
  capitalizeText,
1659
1885
  checkIfExistsInArray,
1660
1886
  cn,
@@ -1667,16 +1893,26 @@ CustomCellEditor.displayName = "CustomCellEditor";
1667
1893
  formatDateTime,
1668
1894
  formatNumber,
1669
1895
  formatValidationErrorsHtml,
1896
+ get,
1670
1897
  getApiError,
1671
1898
  getErrorMessages,
1672
1899
  getFieldsByCategory,
1673
1900
  getFieldsByInputType,
1674
1901
  getFieldsByName,
1902
+ getItem,
1903
+ getItemFromLocalStorage,
1675
1904
  handleApiError,
1676
1905
  isEmpty,
1906
+ loadUserState,
1677
1907
  normalizeApiListItems,
1678
1908
  parseCurrencyValueToNumber,
1679
1909
  removeByPropertyValues,
1910
+ removeItem,
1911
+ saveItemLocalStorage,
1912
+ saveUserState,
1913
+ set,
1914
+ setItem,
1915
+ storeItemInLocalStorage,
1680
1916
  toDateInputValue,
1681
1917
  toLowerCaseText,
1682
1918
  truncateFileName,