@shipengine/elements 2.21.0 → 2.22.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.
Files changed (87) hide show
  1. package/cjs/components/grid-controller/grid-controller.cjs +25 -7
  2. package/cjs/components/grid-controller/grid-controller.styles.cjs +7 -2
  3. package/cjs/components/grid-controller/grid-footer.cjs +30 -15
  4. package/cjs/components/grid-controller/grid-footer.styles.cjs +24 -0
  5. package/cjs/components/grid-controller/index.cjs +1 -1
  6. package/cjs/components/grid-controller/sortable-header/index.cjs +9 -0
  7. package/cjs/components/grid-controller/{sortable-header.cjs → sortable-header/sortable-header.cjs} +3 -5
  8. package/cjs/components/grid-controller/sortable-header/sortable-header.styles.cjs +18 -0
  9. package/cjs/components/grid-filters/components/created-date-filter/created-date-filter.cjs +3 -0
  10. package/cjs/components/grid-filters/components/label-id-filter/label-id-filter.cjs +2 -0
  11. package/cjs/components/grid-filters/components/shipment-id-filter/shipment-id-filter.cjs +2 -0
  12. package/cjs/components/grid-filters/components/tracking-status-filter/tracking-status-filter.cjs +2 -0
  13. package/cjs/components/grid-filters/grid-filters.cjs +6 -0
  14. package/cjs/elements/labels-grid/hooks/use-labels-grid.cjs +63 -29
  15. package/cjs/elements/labels-grid/hooks/use-tracking-status-filter.cjs +109 -0
  16. package/cjs/elements/labels-grid/labels-grid.cjs +47 -30
  17. package/cjs/elements/purchase-label/components/fund-and-purchase/fund-and-purchase.cjs +22 -14
  18. package/cjs/elements/purchase-label/components/rate-form/rate-form.cjs +1 -1
  19. package/cjs/elements/shipments-grid/hooks/use-shipments-grid.cjs +6 -5
  20. package/cjs/elements/shipments-grid/shipments-grid.cjs +56 -24
  21. package/cjs/hooks/use-sortable-query.cjs +36 -0
  22. package/cjs/locales/en/common.cjs +1 -0
  23. package/cjs/package.cjs +1 -1
  24. package/cjs/utilities/feature-flags/feature-flags.cjs +1 -1
  25. package/esm/components/grid-controller/grid-controller.js +27 -9
  26. package/esm/components/grid-controller/grid-controller.styles.js +7 -2
  27. package/esm/components/grid-controller/grid-footer.js +32 -17
  28. package/esm/components/grid-controller/grid-footer.styles.js +20 -0
  29. package/esm/components/grid-controller/index.js +1 -1
  30. package/esm/components/grid-controller/sortable-header/index.js +1 -0
  31. package/esm/components/grid-controller/{sortable-header.js → sortable-header/sortable-header.js} +3 -5
  32. package/esm/components/grid-controller/sortable-header/sortable-header.styles.js +14 -0
  33. package/esm/components/grid-filters/components/created-date-filter/created-date-filter.js +3 -0
  34. package/esm/components/grid-filters/components/label-id-filter/label-id-filter.js +2 -0
  35. package/esm/components/grid-filters/components/shipment-id-filter/shipment-id-filter.js +2 -0
  36. package/esm/components/grid-filters/components/tracking-status-filter/tracking-status-filter.js +2 -0
  37. package/esm/components/grid-filters/grid-filters.js +6 -0
  38. package/esm/elements/labels-grid/hooks/use-labels-grid.js +64 -30
  39. package/esm/elements/labels-grid/hooks/use-tracking-status-filter.js +105 -0
  40. package/esm/elements/labels-grid/labels-grid.js +48 -31
  41. package/esm/elements/purchase-label/components/fund-and-purchase/fund-and-purchase.js +22 -14
  42. package/esm/elements/purchase-label/components/rate-form/rate-form.js +1 -1
  43. package/esm/elements/shipments-grid/hooks/use-shipments-grid.js +6 -5
  44. package/esm/elements/shipments-grid/shipments-grid.js +57 -25
  45. package/esm/hooks/use-sortable-query.js +32 -0
  46. package/esm/locales/en/common.js +1 -0
  47. package/esm/package.js +1 -1
  48. package/esm/utilities/feature-flags/feature-flags.js +1 -1
  49. package/package.json +3 -3
  50. package/types/src/components/grid-controller/grid-controller.d.ts +2 -1
  51. package/types/src/components/grid-controller/grid-controller.styles.d.ts +6 -1
  52. package/types/src/components/grid-controller/grid-footer.d.ts +9 -1
  53. package/types/src/components/grid-controller/grid-footer.styles.d.ts +16 -0
  54. package/types/src/components/grid-controller/sortable-header/index.d.ts +1 -0
  55. package/types/src/components/grid-controller/{sortable-header.d.ts → sortable-header/sortable-header.d.ts} +2 -2
  56. package/types/src/components/grid-controller/sortable-header/sortable-header.styles.d.ts +10 -0
  57. package/types/src/components/grid-filters/components/created-date-filter/created-date-filter.d.ts +2 -1
  58. package/types/src/components/grid-filters/components/label-id-filter/label-id-filter.d.ts +2 -1
  59. package/types/src/components/grid-filters/components/shipment-id-filter/shipment-id-filter.d.ts +2 -1
  60. package/types/src/components/grid-filters/components/tracking-status-filter/tracking-status-filter.d.ts +2 -1
  61. package/types/src/components/grid-filters/grid-filters.d.ts +2 -1
  62. package/types/src/elements/labels-grid/hooks/use-labels-grid.d.ts +4 -3
  63. package/types/src/elements/labels-grid/hooks/use-tracking-status-filter.d.ts +25 -0
  64. package/types/src/elements/labels-grid/labels-grid.d.ts +36 -21
  65. package/types/src/elements/manage-carriers/manage-carriers.d.ts +1 -0
  66. package/types/src/elements/manage-external-carriers/manage-external-carriers.d.ts +1 -0
  67. package/types/src/elements/manage-funding/manage-funding-element.d.ts +1 -0
  68. package/types/src/elements/manage-warehouses/manage-warehouses.d.ts +1 -0
  69. package/types/src/elements/payment-method-settings/payment-method-settings-element.d.ts +1 -0
  70. package/types/src/elements/purchase-label/components/fund-and-purchase/fund-and-purchase.d.ts +2 -2
  71. package/types/src/elements/purchase-label/purchase-label.d.ts +1 -0
  72. package/types/src/elements/select-label-layout/select-label-layout-element.d.ts +1 -0
  73. package/types/src/elements/shipment-summary/shipment-summary.d.ts +1 -0
  74. package/types/src/elements/shipments-grid/hooks/use-shipments-grid.d.ts +7 -1
  75. package/types/src/elements/shipments-grid/shipments-grid.d.ts +10 -1
  76. package/types/src/elements/theme-creator/theme-creator.d.ts +1 -0
  77. package/types/src/elements/transaction-history/transaction-history-element.d.ts +1 -0
  78. package/types/src/elements/unit-settings/unit-settings-element.d.ts +1 -0
  79. package/types/src/elements/vat-settings/vat-settings-element.d.ts +1 -0
  80. package/types/src/elements/void-label/void-label.d.ts +1 -0
  81. package/types/src/hooks/use-sortable-query.d.ts +13 -0
  82. package/types/src/locales/en/index.d.ts +1 -0
  83. package/types/src/workflows/account-settings/account-settings.d.ts +1 -0
  84. package/types/src/workflows/carrier-services/carrier-services.d.ts +1 -0
  85. package/types/src/workflows/connect-external-carrier/connect-external-carrier.d.ts +1 -0
  86. package/types/src/workflows/label-workflow/label-workflow.d.ts +1 -0
  87. package/types/src/workflows/onboarding/onboarding.d.ts +1 -0
@@ -1,6 +1,8 @@
1
- import { jsxs, Fragment, jsx } from '@emotion/react/jsx-runtime';
1
+ import { jsxs, jsx } from '@emotion/react/jsx-runtime';
2
2
  import { Trans } from 'react-i18next';
3
- import { Typography, Pagination } from '@shipengine/giger';
3
+ import { Typography, SpinnerSize, Pagination } from '@shipengine/giger';
4
+ import { styles } from './grid-footer.styles.js';
5
+ import { Loader } from '../loader/loader.js';
4
6
 
5
7
  /**
6
8
  * @internal
@@ -17,30 +19,43 @@ const GridFooter = ({
17
19
  pageSize,
18
20
  total,
19
21
  showPagination,
20
- onPageChange
22
+ onPageChange,
23
+ isLoadingMore,
24
+ hasMoreUnfetchedResults
21
25
  }) => {
22
26
  const firstElementInPage = (page - 1) * pageSize + 1;
23
27
  const lastElementInPage = Math.min(page * pageSize, total);
24
- return jsxs(Fragment, {
25
- children: [jsx(Typography, Object.assign({
26
- component: "span",
27
- variant: "body2"
28
+ return jsxs("div", Object.assign({
29
+ css: styles.wrapper
30
+ }, {
31
+ children: [jsxs("div", Object.assign({
32
+ css: styles.countWrapper
28
33
  }, {
29
- children: jsx(Trans, {
30
- components: [jsx("b", {})],
31
- count: total,
32
- i18nKey: "common:grid.row-count",
33
- values: {
34
- firstIndex: firstElementInPage,
35
- lastIndex: lastElementInPage
36
- }
37
- })
34
+ children: [firstElementInPage > 0 && jsx(Typography, Object.assign({
35
+ component: "span",
36
+ variant: "body2"
37
+ }, {
38
+ children: jsx(Trans, {
39
+ components: [jsx("b", {})],
40
+ count: total,
41
+ i18nKey: hasMoreUnfetchedResults && total > 1 ? "common:grid.row-count-plus_other" : "common:grid.row-count",
42
+ values: {
43
+ firstIndex: firstElementInPage,
44
+ lastIndex: lastElementInPage
45
+ }
46
+ })
47
+ })), isLoadingMore && jsx("div", {
48
+ children: jsx(Loader, {
49
+ css: styles.loader,
50
+ size: SpinnerSize.SIZE_SMALL
51
+ })
52
+ })]
38
53
  })), showPagination && jsx(Pagination, {
39
54
  currentPage: page,
40
55
  onPageChange: onPageChange,
41
56
  totalPages: pages
42
57
  })]
43
- });
58
+ }));
44
59
  };
45
60
 
46
61
  export { GridFooter };
@@ -0,0 +1,20 @@
1
+ import { createStyles, scopeTheme } from '../../utilities/styles.js';
2
+
3
+ const styles = createStyles({
4
+ countWrapper: theme => ({
5
+ alignItems: "center",
6
+ display: "flex",
7
+ gap: scopeTheme(theme).spacing(1)
8
+ }),
9
+ loader: theme => ({
10
+ color: scopeTheme(theme).palette.gray.main
11
+ }),
12
+ wrapper: {
13
+ alignItems: "center",
14
+ display: "flex",
15
+ justifyContent: "space-between",
16
+ width: "100%"
17
+ }
18
+ });
19
+
20
+ export { styles };
@@ -1,4 +1,4 @@
1
1
  export { GridController } from './grid-controller.js';
2
2
  export { CellFormattedDate } from './cell-formatted-date.js';
3
3
  export { GridFooter } from './grid-footer.js';
4
- export { SortableHeader } from './sortable-header.js';
4
+ export { SortableHeader } from './sortable-header/sortable-header.js';
@@ -0,0 +1 @@
1
+ export { SortableHeader } from './sortable-header.js';
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
2
2
  import { Icon, IconSize } from '@shipengine/giger';
3
3
  import { IconNames } from '@shipengine/giger-theme';
4
+ import { styles } from './sortable-header.styles.js';
4
5
 
5
6
  /**
6
7
  * A reusable component for creating sortable table headers
@@ -19,17 +20,14 @@ const SortableHeader = ({
19
20
  };
20
21
  return jsxs("span", Object.assign({
21
22
  "aria-label": headerText,
22
- css: {
23
- alignItems: "center",
24
- cursor: "pointer",
25
- display: "flex"
26
- },
23
+ css: styles.span,
27
24
  onClick: onToggleSort,
28
25
  onKeyDown: handleKeyDown,
29
26
  role: "button",
30
27
  tabIndex: 0
31
28
  }, {
32
29
  children: [headerText, jsx(Icon, {
30
+ css: styles.icon,
33
31
  name: sortDirection === "desc" ? IconNames.SORT_BOTTOM : IconNames.SORT_TOP,
34
32
  size: IconSize.SIZE_SMALL
35
33
  })]
@@ -0,0 +1,14 @@
1
+ import { createStyles, scopeTheme } from '../../../utilities/styles.js';
2
+
3
+ const styles = createStyles({
4
+ icon: theme => ({
5
+ paddingLeft: scopeTheme(theme).spacing()
6
+ }),
7
+ span: () => ({
8
+ alignItems: "center",
9
+ cursor: "pointer",
10
+ display: "flex"
11
+ })
12
+ });
13
+
14
+ export { styles };
@@ -20,6 +20,7 @@ import { useElements } from '../../../../elements-provider/elements-context-prov
20
20
  * @see {@link CreatedDateFilterProps | The props for the `<CreatedDateFilter />` component}
21
21
  */
22
22
  const CreatedDateFilter = ({
23
+ disabled: _disabled = false,
23
24
  filters,
24
25
  onFiltersUpdated
25
26
  }) => {
@@ -101,6 +102,7 @@ const CreatedDateFilter = ({
101
102
  }, [filters.createdDate]);
102
103
  return ((_a = filters.createdDate) === null || _a === void 0 ? void 0 : _a.value) ? jsxs(Button, Object.assign({
103
104
  css: styles.mainButton,
105
+ disabled: _disabled,
104
106
  onClick: onFilterClear,
105
107
  variant: ButtonVariant.TEXT
106
108
  }, {
@@ -119,6 +121,7 @@ const CreatedDateFilter = ({
119
121
  })) : jsxs(Fragment, {
120
122
  children: [jsxs(Button, Object.assign({
121
123
  css: styles.mainButton,
124
+ disabled: _disabled,
122
125
  onClick: onToggleCreatedDateFilter,
123
126
  ref: buttonRef,
124
127
  variant: ButtonVariant.TEXT
@@ -23,6 +23,7 @@ import { SubmitButton } from '../../../field/submit-button/submit-button.js';
23
23
  * @see {@link LabelIdFilterProps | The props for the `<LabelIdFilter />` component}
24
24
  */
25
25
  const LabelIdFilter = ({
26
+ disabled: _disabled = false,
26
27
  filters,
27
28
  onFiltersUpdated
28
29
  }) => {
@@ -58,6 +59,7 @@ const LabelIdFilter = ({
58
59
  jsx(Fragment, {
59
60
  children: jsxs(Fragment, {
60
61
  children: [jsx(Button, Object.assign({
62
+ disabled: _disabled,
61
63
  onClick: toggleLabelIdFilter,
62
64
  ref: buttonRef,
63
65
  variant: ButtonVariant.TEXT
@@ -23,6 +23,7 @@ import { SubmitButton } from '../../../field/submit-button/submit-button.js';
23
23
  * @see {@link ShipmentIdFilterProps | The props for the `<ShipmentIdFilter />` component}
24
24
  */
25
25
  const ShipmentIdFilter = ({
26
+ disabled: _disabled = false,
26
27
  filters,
27
28
  onFiltersUpdated
28
29
  }) => {
@@ -57,6 +58,7 @@ const ShipmentIdFilter = ({
57
58
  children: jsxs(Fragment, {
58
59
  children: [jsx(Button, Object.assign({
59
60
  css: styles.mainButton,
61
+ disabled: _disabled,
60
62
  onClick: toggleShipmentIdFilter,
61
63
  ref: buttonRef,
62
64
  variant: ButtonVariant.TEXT
@@ -21,6 +21,7 @@ import { Spacer } from '../../../spacer/spacer.js';
21
21
  * @see {@link TrackingStatusFilterProps | The props for the `<TrackingStatusFilter />` component}
22
22
  */
23
23
  const TrackingStatusFilter = ({
24
+ disabled: _disabled = false,
24
25
  filters,
25
26
  onFiltersUpdated
26
27
  }) => {
@@ -105,6 +106,7 @@ const TrackingStatusFilter = ({
105
106
  }, [watchedValues]);
106
107
  return jsxs(Fragment, {
107
108
  children: [jsxs(Button, Object.assign({
109
+ disabled: _disabled,
108
110
  onClick: toggleTrackingStatusFilter,
109
111
  ref: buttonRef,
110
112
  variant: ButtonVariant.TEXT
@@ -18,6 +18,7 @@ import { TrackingStatusFilter } from './components/tracking-status-filter/tracki
18
18
  const GridFilters = ({
19
19
  filters,
20
20
  onFiltersUpdated,
21
+ filtersDisabled: _filtersDisabled = false,
21
22
  onClearAllFilters
22
23
  }) => {
23
24
  var _a, _b, _c;
@@ -37,18 +38,23 @@ const GridFilters = ({
37
38
  });
38
39
  return jsxs("section", {
39
40
  children: [filters.shipmentId.enabled && jsx(ShipmentIdFilter, {
41
+ disabled: _filtersDisabled,
40
42
  filters: filters,
41
43
  onFiltersUpdated: onFiltersUpdated
42
44
  }), ((_a = filters.labelId) === null || _a === void 0 ? void 0 : _a.enabled) && jsx(LabelIdFilter, {
45
+ disabled: _filtersDisabled,
43
46
  filters: filters,
44
47
  onFiltersUpdated: onFiltersUpdated
45
48
  }), ((_b = filters.createdDate) === null || _b === void 0 ? void 0 : _b.enabled) && jsx(CreatedDateFilter, {
49
+ disabled: _filtersDisabled,
46
50
  filters: filters,
47
51
  onFiltersUpdated: onFiltersUpdated
48
52
  }), ((_c = filters.trackingStatus) === null || _c === void 0 ? void 0 : _c.enabled) && jsx(TrackingStatusFilter, {
53
+ disabled: _filtersDisabled,
49
54
  filters: filters,
50
55
  onFiltersUpdated: onFiltersUpdated
51
56
  }), shouldShowClearAll && jsx(Button, Object.assign({
57
+ disabled: _filtersDisabled,
52
58
  onClick: () => {
53
59
  onClearAllFilters();
54
60
  },
@@ -1,19 +1,20 @@
1
1
  import { useTheme } from '@emotion/react';
2
2
  import { useGetServiceName } from '../../../hooks/use-get-service-name.js';
3
- import { useState, useEffect, useMemo } from 'react';
3
+ import { useState, useCallback, useEffect, useMemo } from 'react';
4
4
  import { useListLabels, useListSalesOrderShipments, useGetLabel } from '@shipengine/react-api';
5
+ import { useTrackingStatusFilter } from './use-tracking-status-filter.js';
5
6
  import { usePager } from '../../../components/pager/usePager.js';
6
7
 
7
8
  const PAGE_SIZE = 20;
8
9
  const useLabelsGrid = ({
9
- createdDateSortBy,
10
10
  labelStatus,
11
11
  showShipmentIdFilter,
12
12
  showLabelIdFilter,
13
13
  showTrackingStatusFilter,
14
- fetchShipments
14
+ fetchShipments,
15
+ sortDir
15
16
  }) => {
16
- var _a, _b, _c;
17
+ var _a, _b, _c, _d, _e, _f;
17
18
  const initialFilters = {
18
19
  labelId: {
19
20
  enabled: !!showLabelIdFilter,
@@ -46,7 +47,7 @@ const useLabelsGrid = ({
46
47
  pagerProps.onPageSelect(1);
47
48
  setFilters(newFilters);
48
49
  };
49
- const hasActiveFilterValue = value => {
50
+ const hasActiveFilterValue = useCallback(value => {
50
51
  if (value === null || value === undefined) {
51
52
  return false;
52
53
  }
@@ -60,7 +61,7 @@ const useLabelsGrid = ({
60
61
  return value.trim() !== "";
61
62
  }
62
63
  return Boolean(value);
63
- };
64
+ }, []);
64
65
  const isAnyFilterActive = Object.keys(filters).some(key => {
65
66
  const filter = filters[key];
66
67
  return (filter === null || filter === void 0 ? void 0 : filter.enabled) && hasActiveFilterValue(filter === null || filter === void 0 ? void 0 : filter.value);
@@ -86,38 +87,64 @@ const useLabelsGrid = ({
86
87
  };
87
88
  setFilters(updatedFilters);
88
89
  }, [showLabelIdFilter, showShipmentIdFilter, showTrackingStatusFilter]);
90
+ const isTrackingStatusFilterActive = useMemo(() => {
91
+ var _a, _b;
92
+ return !!(((_a = filters.trackingStatus) === null || _a === void 0 ? void 0 : _a.enabled) && hasActiveFilterValue((_b = filters.trackingStatus) === null || _b === void 0 ? void 0 : _b.value));
93
+ }, [(_a = filters.trackingStatus) === null || _a === void 0 ? void 0 : _a.enabled, (_b = filters.trackingStatus) === null || _b === void 0 ? void 0 : _b.value, hasActiveFilterValue]);
94
+ // Use tracking status filter hook when the filter is active
95
+ const {
96
+ labels: trackingFilteredLabels,
97
+ isLoading: isTrackingFilterLoading,
98
+ isFetchingNextPage,
99
+ hasMoreUnfetchedResults,
100
+ paginationInfo: statusFilteredPaginationInfo
101
+ } = useTrackingStatusFilter({
102
+ currentPage: page,
103
+ isActive: isTrackingStatusFilterActive,
104
+ labelStatus,
105
+ pageSize,
106
+ shipmentId: ((_c = filters.shipmentId) === null || _c === void 0 ? void 0 : _c.value) || undefined,
107
+ sortDir: sortDir !== null && sortDir !== void 0 ? sortDir : "desc",
108
+ trackingStatusFilters: ((_d = filters.trackingStatus) === null || _d === void 0 ? void 0 : _d.value) || []
109
+ });
110
+ // Use regular API pagination when tracking status filter is not active
89
111
  const {
90
112
  data: listLabelsData,
91
113
  isLoading: isListLabelsLoading,
92
114
  isError: isListLabelsError
93
115
  } = useListLabels({
116
+ enabled: !isTrackingStatusFilterActive,
94
117
  queryFnParams: {
95
118
  labelStatus,
96
119
  page,
97
120
  pageSize,
98
121
  shipmentId: filters.shipmentId.value || undefined,
99
- sortDir: createdDateSortBy !== null && createdDateSortBy !== void 0 ? createdDateSortBy : "desc"
122
+ sortDir: sortDir !== null && sortDir !== void 0 ? sortDir : "desc"
100
123
  }
101
124
  });
102
125
  const labels = useMemo(() => {
126
+ // If tracking status filter is active, use the filtered labels from the hook
127
+ if (isTrackingStatusFilterActive) {
128
+ return trackingFilteredLabels.map(label => Object.assign(Object.assign({}, label), {
129
+ bodyCellStyles: {
130
+ color: label.status === "voided" ? theme.palette.gray[400] : undefined
131
+ },
132
+ serviceName: getServiceName(label)
133
+ }));
134
+ }
135
+ // Otherwise, use the regular API pagination
103
136
  if (!(listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.labels)) {
104
137
  return [];
105
138
  }
106
- return listLabelsData.labels.filter(label => {
107
- var _a, _b, _c, _d;
108
- // Filter by tracking status
109
- return !((_b = (_a = filters === null || filters === void 0 ? void 0 : filters.trackingStatus) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.length) ||
110
- // Voided labels still have an in_transit tracking status, exclude them if the in_transit filter is selected
111
- label.status !== "voided" && ((_c = filters === null || filters === void 0 ? void 0 : filters.trackingStatus) === null || _c === void 0 ? void 0 : _c.value.includes(label.trackingStatus)) ||
112
- // We show voided labels under tracking status also, include them if the voided filter is selected
113
- label.status === "voided" && ((_d = filters === null || filters === void 0 ? void 0 : filters.trackingStatus) === null || _d === void 0 ? void 0 : _d.value.includes(label.status));
114
- }).map(label => Object.assign(Object.assign({}, label), {
139
+ // No need to filter by tracking status here since that's handled by useTrackingStatusFilter
140
+ // when the tracking status filter is active
141
+ return listLabelsData.labels.map(label => Object.assign(Object.assign({}, label), {
115
142
  bodyCellStyles: {
116
143
  color: label.status === "voided" ? theme.palette.gray[400] : undefined
117
144
  },
118
145
  serviceName: getServiceName(label)
119
146
  }));
120
- }, [listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.labels, (_a = filters === null || filters === void 0 ? void 0 : filters.trackingStatus) === null || _a === void 0 ? void 0 : _a.value, theme.palette.gray, getServiceName]);
147
+ }, [isTrackingStatusFilterActive, trackingFilteredLabels, listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.labels, theme.palette.gray, getServiceName]);
121
148
  const {
122
149
  data: listShipmentsData,
123
150
  isFetching: isListShipmentsLoading,
@@ -126,18 +153,17 @@ const useLabelsGrid = ({
126
153
  // An empty array here should disable the query
127
154
  shipmentIds: fetchShipments ? labels === null || labels === void 0 ? void 0 : labels.map(label => label.shipmentId) : []
128
155
  });
129
- const shouldShowFilters = isAnyFilterEnabled && (isAnyFilterActive || Boolean(labels === null || labels === void 0 ? void 0 : labels.length));
130
156
  const {
131
157
  data: labelFilterData,
132
158
  isError: isLabelFilterError,
133
159
  isInitialLoading: isLabelFilterLoading
134
- } = useGetLabel(((_b = filters.labelId) === null || _b === void 0 ? void 0 : _b.value) || undefined);
135
- const isLabelFilterActive = (_c = filters.labelId) === null || _c === void 0 ? void 0 : _c.value;
160
+ } = useGetLabel(((_e = filters.labelId) === null || _e === void 0 ? void 0 : _e.value) || undefined);
161
+ const isLabelFilterActive = (_f = filters.labelId) === null || _f === void 0 ? void 0 : _f.value;
136
162
  const isStatusFilteredOut = (status, filter) => {
137
163
  return (filter === null || filter === void 0 ? void 0 : filter.length) && !filter.includes(status);
138
164
  };
139
165
  const getLabelById = labelById => {
140
- var _a, _b;
166
+ var _a, _b, _c, _d;
141
167
  // Check if filter by label id is active and there are no errors
142
168
  if (isLabelFilterActive && !isLabelFilterError) {
143
169
  let labelPassFilters = true;
@@ -146,14 +172,14 @@ const useLabelsGrid = ({
146
172
  labelPassFilters = false;
147
173
  }
148
174
  // Check if shipment filter has the same value if defined
149
- if ((filters === null || filters === void 0 ? void 0 : filters.shipmentId.value) !== "" && (filters === null || filters === void 0 ? void 0 : filters.shipmentId.value) !== (labelById === null || labelById === void 0 ? void 0 : labelById.shipmentId)) {
175
+ if (((_a = filters === null || filters === void 0 ? void 0 : filters.shipmentId) === null || _a === void 0 ? void 0 : _a.value) !== "" && ((_b = filters === null || filters === void 0 ? void 0 : filters.shipmentId) === null || _b === void 0 ? void 0 : _b.value) !== (labelById === null || labelById === void 0 ? void 0 : labelById.shipmentId)) {
150
176
  labelPassFilters = false;
151
177
  }
152
178
  if (
153
179
  // If Label status is voided and voided status is filtered out, don't show the label
154
- (labelById === null || labelById === void 0 ? void 0 : labelById.status) === "voided" && isStatusFilteredOut("voided", (_a = filters.trackingStatus) === null || _a === void 0 ? void 0 : _a.value) ||
180
+ (labelById === null || labelById === void 0 ? void 0 : labelById.status) === "voided" && isStatusFilteredOut("voided", (_c = filters.trackingStatus) === null || _c === void 0 ? void 0 : _c.value) ||
155
181
  // If Label status is not voided and tracking status is filtered out, don't show the label
156
- (labelById === null || labelById === void 0 ? void 0 : labelById.status) !== "voided" && (labelById === null || labelById === void 0 ? void 0 : labelById.trackingStatus) && isStatusFilteredOut(labelById.trackingStatus, (_b = filters.trackingStatus) === null || _b === void 0 ? void 0 : _b.value)) {
182
+ (labelById === null || labelById === void 0 ? void 0 : labelById.status) !== "voided" && (labelById === null || labelById === void 0 ? void 0 : labelById.trackingStatus) && isStatusFilteredOut(labelById.trackingStatus, (_d = filters.trackingStatus) === null || _d === void 0 ? void 0 : _d.value)) {
157
183
  labelPassFilters = false;
158
184
  }
159
185
  return labelPassFilters ? labelById : undefined;
@@ -188,20 +214,28 @@ const useLabelsGrid = ({
188
214
  clearAllFilters,
189
215
  filters,
190
216
  getGridData,
217
+ hasMoreUnfetchedResults: isTrackingStatusFilterActive ? hasMoreUnfetchedResults : false,
191
218
  isAnyFilterActive,
192
219
  isError: isListLabelsError || isListShipmentsError && fetchShipments,
193
- isLoading: isListLabelsLoading || isLabelFilterLoading || isListShipmentsLoading && fetchShipments,
220
+ isFetchingNextPage: isTrackingStatusFilterActive ? isFetchingNextPage : false,
221
+ // Calculate isLoading based on which query should be active
222
+ isLoading:
223
+ // Always include label filter loading when label ID filter is active
224
+ isLabelFilterActive && isLabelFilterLoading || (
225
+ // For tracking status filter
226
+ isTrackingStatusFilterActive ? isTrackingFilterLoading // Use tracking filter loading when active
227
+ : isListLabelsLoading || isListShipmentsLoading && fetchShipments),
194
228
  labels,
195
229
  pageConfig: {
196
- currentPage: labelFilteredById ? 1 : (listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.page) || 0,
230
+ currentPage: labelFilteredById ? 1 : isTrackingStatusFilterActive ? statusFilteredPaginationInfo.currentPage : (listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.page) || 0,
197
231
  pagerProps,
198
- pagesAmount: (listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.pages) || 0,
232
+ pagesAmount: labelFilteredById ? 1 : isTrackingStatusFilterActive ? (statusFilteredPaginationInfo === null || statusFilteredPaginationInfo === void 0 ? void 0 : statusFilteredPaginationInfo.totalPages) || 1 : (listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.pages) || 0,
199
233
  pageSize,
200
- showPagination: labelFilteredById ? false : ((listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.total) || 0) > pageSize,
201
- totalElements: labelFilteredById ? 1 : (listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.total) || 0
234
+ showPagination: labelFilteredById ? false : isTrackingStatusFilterActive ? ((statusFilteredPaginationInfo === null || statusFilteredPaginationInfo === void 0 ? void 0 : statusFilteredPaginationInfo.totalCount) || 0) > pageSize : ((listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.total) || 0) > pageSize,
235
+ totalElements: labelFilteredById ? 1 : isTrackingStatusFilterActive ? (statusFilteredPaginationInfo === null || statusFilteredPaginationInfo === void 0 ? void 0 : statusFilteredPaginationInfo.totalCount) || 0 : (listLabelsData === null || listLabelsData === void 0 ? void 0 : listLabelsData.total) || 0
202
236
  },
203
237
  setFilters: onSetFilters,
204
- shouldShowFilters
238
+ shouldShowFilters: isAnyFilterEnabled
205
239
  };
206
240
  };
207
241
 
@@ -0,0 +1,105 @@
1
+ import { useState, useEffect, useMemo } from 'react';
2
+ import { useListLabelsInfinite } from '@shipengine/react-api';
3
+
4
+ const MIN_RESULTS = 20; // Minimum number of filtered results needed to stop fetching
5
+ const MAX_PAGES = 5; // Maximum number of pages to fetch if we have enough results
6
+ const useTrackingStatusFilter = ({
7
+ isActive,
8
+ labelStatus,
9
+ shipmentId,
10
+ trackingStatusFilters,
11
+ sortDir,
12
+ currentPage,
13
+ pageSize
14
+ }) => {
15
+ const [allLabels, setAllLabels] = useState([]);
16
+ const {
17
+ data: infiniteData,
18
+ fetchNextPage,
19
+ hasNextPage,
20
+ isLoading,
21
+ isFetchingNextPage
22
+ } = useListLabelsInfinite({
23
+ enabled: isActive,
24
+ queryFnParams: {
25
+ labelStatus,
26
+ pageSize: 100,
27
+ shipmentId,
28
+ sortDir
29
+ }
30
+ });
31
+ useEffect(() => {
32
+ if (isActive && (infiniteData === null || infiniteData === void 0 ? void 0 : infiniteData.pages)) {
33
+ const allLabelsFromPages = infiniteData.pages.flatMap(page => page.labels || []);
34
+ setAllLabels(allLabelsFromPages);
35
+ }
36
+ }, [isActive, infiniteData === null || infiniteData === void 0 ? void 0 : infiniteData.pages]);
37
+ const filteredLabels = useMemo(() => {
38
+ if (!isActive || !trackingStatusFilters.length) {
39
+ return allLabels;
40
+ }
41
+ return allLabels.filter(label => {
42
+ if (label.status === "voided") {
43
+ return trackingStatusFilters.includes("voided");
44
+ }
45
+ return trackingStatusFilters.includes(label.trackingStatus);
46
+ });
47
+ }, [isActive, allLabels, trackingStatusFilters]);
48
+ const totalCount = filteredLabels.length;
49
+ const totalPages = Math.max(1, Math.ceil(totalCount / pageSize));
50
+ const paginatedLabels = useMemo(() => {
51
+ const startIndex = (currentPage - 1) * pageSize;
52
+ const endIndex = Math.min(startIndex + pageSize, filteredLabels.length);
53
+ return filteredLabels.slice(startIndex, endIndex);
54
+ }, [filteredLabels, currentPage, pageSize]);
55
+ // Check if we have enough data for the next page
56
+ const hasDataForNextPage = useMemo(() => {
57
+ const nextPageStart = currentPage * pageSize;
58
+ return nextPageStart < filteredLabels.length;
59
+ }, [currentPage, pageSize, filteredLabels.length]);
60
+ // Check if we have more unfetched results
61
+ const hasMoreUnfetchedResults = useMemo(() => {
62
+ return hasNextPage && (infiniteData === null || infiniteData === void 0 ? void 0 : infiniteData.pages) && infiniteData.pages.length >= MAX_PAGES && filteredLabels.length >= MIN_RESULTS;
63
+ }, [hasNextPage, infiniteData === null || infiniteData === void 0 ? void 0 : infiniteData.pages, filteredLabels.length]);
64
+ // Trigger fetchNextPage
65
+ useEffect(() => {
66
+ // Don't fetch if not active or already fetching
67
+ if (!isActive || isFetchingNextPage) return;
68
+ // Continue fetching if we don't have minimum results yet
69
+ if (filteredLabels.length < MIN_RESULTS && hasNextPage) {
70
+ fetchNextPage();
71
+ return;
72
+ }
73
+ // Continue fetching if we don't have data for the next page
74
+ if (!hasDataForNextPage && hasNextPage) {
75
+ fetchNextPage();
76
+ return;
77
+ }
78
+ // Stop fetching if we've reached max pages and have enough results
79
+ if ((infiniteData === null || infiniteData === void 0 ? void 0 : infiniteData.pages) && infiniteData.pages.length >= MAX_PAGES && filteredLabels.length >= MIN_RESULTS && hasDataForNextPage) {
80
+ return;
81
+ }
82
+ // Otherwise, fetch next page if available
83
+ if (hasNextPage) {
84
+ fetchNextPage();
85
+ }
86
+ }, [isActive, currentPage, pageSize, filteredLabels.length, hasNextPage, isFetchingNextPage, fetchNextPage, hasDataForNextPage, infiniteData === null || infiniteData === void 0 ? void 0 : infiniteData.pages]);
87
+ return {
88
+ allLabelsCount: totalCount,
89
+ fetchNextPage,
90
+ filteredLabelsCount: totalCount,
91
+ hasMorePages: hasNextPage,
92
+ hasMoreUnfetchedResults,
93
+ isFetchingNextPage,
94
+ isLoading: isLoading || filteredLabels.length === 0 && isFetchingNextPage,
95
+ labels: paginatedLabels,
96
+ paginationInfo: {
97
+ currentPage,
98
+ pageSize,
99
+ totalCount,
100
+ totalPages
101
+ }
102
+ };
103
+ };
104
+
105
+ export { useTrackingStatusFilter };