@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,10 +1,11 @@
1
1
  import { jsx, jsxs, Fragment } from '@emotion/react/jsx-runtime';
2
- import { useRef, useState, useMemo, useEffect, useCallback } from 'react';
2
+ import { useSortableQuery } from '../../hooks/use-sortable-query.js';
3
+ import { useRef, useMemo, useEffect, useCallback } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
  import { TagColor, Next, Typography, Tag, TagVariant, EmptyState, Button } from '@shipengine/giger';
5
6
  import { useLabelsGrid } from './hooks/use-labels-grid.js';
6
7
  import { styles } from './labels-grid.styles.js';
7
- import { SortableHeader } from '../../components/grid-controller/sortable-header.js';
8
+ import { SortableHeader } from '../../components/grid-controller/sortable-header/sortable-header.js';
8
9
  import { CellFormattedDate } from '../../components/grid-controller/cell-formatted-date.js';
9
10
  import { ActionsMenu, Actions } from '../../components/actions-menu/actions-menu.js';
10
11
  import { ErrorState } from '../../components/error-state/error-state.js';
@@ -13,7 +14,6 @@ import { GridFilters } from '../../components/grid-filters/grid-filters.js';
13
14
  import { GridFooter } from '../../components/grid-controller/grid-footer.js';
14
15
  import en from '../../locales/en/index.js';
15
16
  import { useElements } from '../../elements-provider/elements-context-provider.js';
16
- import { Loader } from '../../components/loader/loader.js';
17
17
  import { Spacer } from '../../components/spacer/spacer.js';
18
18
  import { PoweredByShipEngine } from '../../components/powered-by-shipengine/powered-by-shipengine.js';
19
19
  import { createElement } from '../../create-element/create-element.js';
@@ -31,7 +31,7 @@ const Component = ({
31
31
  onClickExternalShipmentId,
32
32
  onClickShipmentNumber
33
33
  }) => {
34
- var _a, _b, _c;
34
+ var _a, _b;
35
35
  const {
36
36
  t
37
37
  } = useTranslation(["common", "list-labels"]);
@@ -41,7 +41,13 @@ const Component = ({
41
41
  } = useElements();
42
42
  const defaultFeatures = getFeatures("labelsGridFeatures");
43
43
  const prevStatus = useRef(labelStatus);
44
- const [createdDateSortBy, setCreatedDateSortBy] = useState("desc");
44
+ const {
45
+ toggleSort,
46
+ sortState
47
+ } = useSortableQuery({
48
+ defaultSortBy: "modified_at",
49
+ defaultSortDir: "desc"
50
+ });
45
51
  features = Object.assign(Object.assign({}, defaultFeatures), features !== null && features !== void 0 ? features : {});
46
52
  const labelIdColumn = useMemo(() => {
47
53
  var _a;
@@ -61,12 +67,14 @@ const Component = ({
61
67
  }, [features]);
62
68
  const showLabelIdFilter = labelIdColumn && ((_a = labelIdColumn.allowFilter) !== null && _a !== void 0 ? _a : true);
63
69
  const showShipmentIdFilter = shipmentIdColumn && ((_b = shipmentIdColumn.allowFilter) !== null && _b !== void 0 ? _b : true);
64
- const showTrackingStatusFilter = trackingStatusColumn && ((_c = trackingStatusColumn.allowFilter) !== null && _c !== void 0 ? _c : true);
70
+ const showTrackingStatusFilter = trackingStatusColumn && !!trackingStatusColumn.allowFilter;
65
71
  const {
66
72
  labels,
67
73
  getGridData,
68
74
  isError,
69
75
  isLoading,
76
+ isFetchingNextPage,
77
+ hasMoreUnfetchedResults,
70
78
  filters,
71
79
  setFilters,
72
80
  pageConfig,
@@ -74,12 +82,12 @@ const Component = ({
74
82
  shouldShowFilters,
75
83
  clearAllFilters
76
84
  } = useLabelsGrid({
77
- createdDateSortBy,
78
85
  fetchShipments: !!shipmentNumberColumn,
79
86
  labelStatus,
80
87
  showLabelIdFilter,
81
88
  showShipmentIdFilter,
82
- showTrackingStatusFilter
89
+ showTrackingStatusFilter,
90
+ sortDir: sortState.dir
83
91
  });
84
92
  useEffect(() => {
85
93
  if (prevStatus.current !== labelStatus) {
@@ -101,8 +109,8 @@ const Component = ({
101
109
  };
102
110
  }, [filters, labelIdColumn, shipmentIdColumn, trackingStatusColumn]);
103
111
  const toggleCreatedDateSort = useCallback(() => {
104
- setCreatedDateSortBy(createdDateSortBy === "desc" ? "asc" : "desc");
105
- }, [createdDateSortBy]);
112
+ toggleSort("created_at");
113
+ }, [toggleSort]);
106
114
  const columns = useMemo(() => {
107
115
  var _a;
108
116
  const labelTags = {
@@ -146,7 +154,7 @@ const Component = ({
146
154
  headerContent: jsx(SortableHeader, {
147
155
  headerText: t("list-labels:headers.created"),
148
156
  onToggleSort: toggleCreatedDateSort,
149
- sortDirection: createdDateSortBy
157
+ sortDirection: sortState.createdAtDir
150
158
  }),
151
159
  renderCellContent: label => {
152
160
  return jsx(CellFormattedDate, {
@@ -374,24 +382,13 @@ const Component = ({
374
382
  });
375
383
  }
376
384
  return cols;
377
- }, [t, toggleCreatedDateSort, createdDateSortBy, features === null || features === void 0 ? void 0 : features.columns, features === null || features === void 0 ? void 0 : features.showActions, labels, onClickExternalOrderId, onClickExternalShipmentId, onClickViewDetails, onClickVoidLabel, onClickPrintLabel, onClickPrintForms, onClickShipmentNumber]);
378
- if (isLoading) {
379
- return jsx(Loader, {
380
- message: t("loading.labels")
381
- });
382
- }
383
- if (isError) {
384
- return jsx(ErrorState, {
385
- css: styles.errorState,
386
- subtitle: [t("list-labels:errorMessages.subtitle"), t("errorMessages.refreshAndTryAgain")],
387
- title: t("list-labels:errorMessages.title")
388
- });
389
- }
390
- return jsxs(Fragment, {
391
- children: [jsx(GridController, {
392
- columns: columns,
393
- data: getGridData(),
394
- emptyContent: isAnyFilterActive ? jsx(EmptyState, Object.assign({
385
+ }, [t, toggleCreatedDateSort, sortState.createdAtDir, features === null || features === void 0 ? void 0 : features.columns, features === null || features === void 0 ? void 0 : features.showActions, labels, onClickExternalOrderId, onClickExternalShipmentId, onClickShipmentNumber, onClickVoidLabel, onClickViewDetails, onClickPrintLabel, onClickPrintForms]);
386
+ const emptyContentComponent = useMemo(() => {
387
+ if (isLoading) {
388
+ return undefined;
389
+ }
390
+ if (isAnyFilterActive) {
391
+ return jsx(EmptyState, Object.assign({
395
392
  isElevated: false,
396
393
  subtitle: t("list-labels:emptyWithFilters.subtitle"),
397
394
  title: t("list-labels:emptyWithFilters.title")
@@ -401,17 +398,36 @@ const Component = ({
401
398
  }, {
402
399
  children: t("list-labels:emptyWithFilters.button")
403
400
  }))
404
- })) : jsx(EmptyState, {
401
+ }));
402
+ } else {
403
+ return jsx(EmptyState, {
405
404
  isElevated: false,
406
405
  subtitle: t("list-labels:empty.subtitle"),
407
406
  title: t("list-labels:empty.title")
408
- }),
407
+ });
408
+ }
409
+ }, [clearAllFilters, isAnyFilterActive, isLoading, t]);
410
+ if (isError) {
411
+ return jsx(ErrorState, {
412
+ css: styles.errorState,
413
+ subtitle: [t("list-labels:errorMessages.subtitle"), t("errorMessages.refreshAndTryAgain")],
414
+ title: t("list-labels:errorMessages.title")
415
+ });
416
+ }
417
+ return jsxs(Fragment, {
418
+ children: [jsx(GridController, {
419
+ columns: columns,
420
+ data: getGridData(),
421
+ emptyContent: emptyContentComponent,
409
422
  filters: shouldShowFilters && jsx(GridFilters, {
410
423
  filters: gridFilters,
424
+ filtersDisabled: isLoading,
411
425
  onClearAllFilters: clearAllFilters,
412
426
  onFiltersUpdated: setFilters
413
427
  }),
414
428
  footerContent: jsx(GridFooter, {
429
+ hasMoreUnfetchedResults: hasMoreUnfetchedResults,
430
+ isLoadingMore: isFetchingNextPage,
415
431
  onPageChange: pageConfig.pagerProps.onPageSelect,
416
432
  page: pageConfig.currentPage,
417
433
  pages: pageConfig.pagesAmount,
@@ -419,6 +435,7 @@ const Component = ({
419
435
  showPagination: pageConfig.showPagination,
420
436
  total: pageConfig.totalElements
421
437
  }),
438
+ isLoading: isLoading,
422
439
  onRowClick: onRowClick
423
440
  }), globalFeatures.poweredByShipEngine && jsxs(Fragment, {
424
441
  children: [jsx(Spacer, {}), jsx(PoweredByShipEngine, {})]
@@ -34,12 +34,12 @@ const FundAndPurchase = ({
34
34
  currency,
35
35
  disabled,
36
36
  isFundingEnabled,
37
- showVatSettings,
38
- onSave,
37
+ isInvalidatedByError,
39
38
  onPurchase,
39
+ onSave,
40
40
  onVatRegistrationComplete,
41
- isInvalidatedByError,
42
- rateData
41
+ rateData,
42
+ showVatSettings
43
43
  }) => {
44
44
  var _a, _b, _c;
45
45
  const {
@@ -71,10 +71,18 @@ const FundAndPurchase = ({
71
71
  const purchaseAmount = getTotalRateAmount(rate);
72
72
  const [isSavingRate, setIsSavingRate] = useState(false);
73
73
  const [isSavingError, setIsSavingError] = useState(false);
74
- const [isAddFundsFormOpen, setIsAddFundsFormOpen] = useState(() => {
75
- var _a;
76
- return (_a = isFundingEnabled && isFundingRequired && (fundingOrigin === null || fundingOrigin === void 0 ? void 0 : fundingOrigin.balance) !== undefined && fundingOrigin.balance < purchaseAmount && !isInvalidatedByError) !== null && _a !== void 0 ? _a : false;
77
- });
74
+ const purchaseRequiresAddingFunds = isFundingEnabled && isFundingRequired && (fundingOrigin === null || fundingOrigin === void 0 ? void 0 : fundingOrigin.balance) !== undefined && fundingOrigin.balance < purchaseAmount && !isInvalidatedByError;
75
+ const [isFormManuallyToggled, setIsFormManuallyToggled] = useState(false);
76
+ const isAddFundsFormOpen = purchaseRequiresAddingFunds || isFormManuallyToggled;
77
+ const toggleAddFundsForm = () => {
78
+ if (!purchaseRequiresAddingFunds) {
79
+ // If the label can be purchased without adding funds, allow manual toggling of the form
80
+ setIsFormManuallyToggled(!isFormManuallyToggled);
81
+ } else if (isFormManuallyToggled) {
82
+ // If the form is already open, close it
83
+ setIsFormManuallyToggled(false);
84
+ }
85
+ };
78
86
  useEffect(() => {
79
87
  resetAddFundsMutationState();
80
88
  }, [isAddFundsFormOpen, resetAddFundsMutationState]);
@@ -82,7 +90,7 @@ const FundAndPurchase = ({
82
90
  setIsSavingRate(true);
83
91
  setIsSavingError(false);
84
92
  try {
85
- yield onSave();
93
+ yield onSave === null || onSave === void 0 ? void 0 : onSave();
86
94
  } catch (e) {
87
95
  setIsSavingError(true);
88
96
  } finally {
@@ -108,7 +116,7 @@ const FundAndPurchase = ({
108
116
  breakpoint: "mobileLarge",
109
117
  justify: "end"
110
118
  }, {
111
- children: [jsx(Button, Object.assign({
119
+ children: [onSave && jsx(Button, Object.assign({
112
120
  bold: false,
113
121
  css: styles.saveRateButton,
114
122
  disabled: disableSaveButton,
@@ -139,7 +147,7 @@ const FundAndPurchase = ({
139
147
  }), isFundingEnabled ? jsx(LinkAction, {
140
148
  icon: "add",
141
149
  isDisabled: !isFundingRequired || isAddFundsFormOpen || isRateFormSubmitting,
142
- onClick: () => setIsAddFundsFormOpen(!isAddFundsFormOpen),
150
+ onClick: toggleAddFundsForm,
143
151
  title: t("manage-funding:actions.addFunds")
144
152
  }) : null]
145
153
  }), jsx(Spacer, {
@@ -185,7 +193,7 @@ const FundAndPurchase = ({
185
193
  }), isFundingEnabled && jsx(LinkAction, {
186
194
  icon: "add",
187
195
  isDisabled: isAddFundsFormOpen || isRateFormSubmitting,
188
- onClick: () => setIsAddFundsFormOpen(!isAddFundsFormOpen),
196
+ onClick: toggleAddFundsForm,
189
197
  title: t("manage-funding:actions.addFunds")
190
198
  })]
191
199
  }), jsx(Spacer, {
@@ -206,7 +214,7 @@ const FundAndPurchase = ({
206
214
  currency: currency,
207
215
  minimumAmount: purchaseAmount - balance,
208
216
  onSuccess: () => {
209
- setIsAddFundsFormOpen(false);
217
+ setIsFormManuallyToggled(false);
210
218
  onPurchase();
211
219
  }
212
220
  }, {
@@ -243,7 +251,7 @@ const FundAndPurchase = ({
243
251
  }, {
244
252
  children: jsx(Button, Object.assign({
245
253
  disabled: addFundsForm.isSubmitting || isRateFormSubmitting,
246
- onClick: () => setIsAddFundsFormOpen(false),
254
+ onClick: () => setIsFormManuallyToggled(false),
247
255
  variant: ButtonVariant.TEXT
248
256
  }, {
249
257
  children: t("actions.cancel")
@@ -215,7 +215,7 @@ const RateForm = ({
215
215
  isFundingEnabled: !!(features === null || features === void 0 ? void 0 : features.enableFunding),
216
216
  isInvalidatedByError: !!(labelErrors === null || labelErrors === void 0 ? void 0 : labelErrors.length),
217
217
  onPurchase: handleSubmit,
218
- onSave: handleSaveRate,
218
+ onSave: (features === null || features === void 0 ? void 0 : features.saveRate) ? handleSaveRate : undefined,
219
219
  onVatRegistrationComplete: onVatRegistrationComplete,
220
220
  rateData: {
221
221
  isPreferredRate,
@@ -18,7 +18,9 @@ const getInitialFilters = (showShipmentIdFilter, showCreatedDateFilter) => ({
18
18
  const useShipmentsGrid = ({
19
19
  shipmentStatus,
20
20
  showShipmentIdFilter: _showShipmentIdFilter = true,
21
- showCreatedDateFilter: _showCreatedDateFilter = true
21
+ showCreatedDateFilter: _showCreatedDateFilter = true,
22
+ sortBy,
23
+ sortDir
22
24
  }) => {
23
25
  var _a, _b, _c, _d;
24
26
  const initialFilters = getInitialFilters(_showShipmentIdFilter, _showCreatedDateFilter);
@@ -58,14 +60,13 @@ const useShipmentsGrid = ({
58
60
  page,
59
61
  pageSize,
60
62
  shipmentStatus,
61
- sortBy: "modified_at",
62
- sortDir: "desc"
63
+ sortBy: sortBy,
64
+ sortDir: sortDir
63
65
  }, getCreatedDateFilterValue((_b = (_a = filters.createdDate) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.start, (_d = (_c = filters.createdDate) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.end)));
64
66
  const shipments = useMemo(() => data === null || data === void 0 ? void 0 : data.shipments.map(shipment => Object.assign(Object.assign({}, shipment), {
65
67
  disableOnRowClick: shipment.shipmentStatus === "cancelled",
66
68
  serviceName: getServiceName(shipment)
67
69
  })), [data === null || data === void 0 ? void 0 : data.shipments, getServiceName]);
68
- const shouldShowFilters = isAnyFilterEnabled && (isAnyFilterActive || Boolean(shipments === null || shipments === void 0 ? void 0 : shipments.length));
69
70
  const {
70
71
  data: shipmentById,
71
72
  error: shipmentErrors,
@@ -132,7 +133,7 @@ const useShipmentsGrid = ({
132
133
  },
133
134
  setFilters: onSetFilters,
134
135
  shipments,
135
- shouldShowFilters
136
+ shouldShowFilters: isAnyFilterEnabled
136
137
  };
137
138
  };
138
139
 
@@ -1,14 +1,16 @@
1
1
  import { jsx, jsxs, Fragment } from '@emotion/react/jsx-runtime';
2
+ import { useSortableQuery } from '../../hooks/use-sortable-query.js';
3
+ import { useMemo } from 'react';
2
4
  import { useTranslation } from 'react-i18next';
3
- import { TagColor, Typography, Tag, TagVariant, EmptyState, Button } from '@shipengine/giger';
5
+ import { EmptyState, Button, TagColor, Typography, Tag, TagVariant } from '@shipengine/giger';
4
6
  import { useShipmentsGrid } from './hooks/use-shipments-grid.js';
5
7
  import { styles } from './shipments-grid.styles.js';
6
8
  import { ActionsMenu, Actions } from '../../components/actions-menu/actions-menu.js';
7
9
  import { GridFilters } from '../../components/grid-filters/grid-filters.js';
8
10
  import en from '../../locales/en/index.js';
9
11
  import { useElements } from '../../elements-provider/elements-context-provider.js';
10
- import { Loader } from '../../components/loader/loader.js';
11
12
  import { ErrorState } from '../../components/error-state/error-state.js';
13
+ import { SortableHeader } from '../../components/grid-controller/sortable-header/sortable-header.js';
12
14
  import { CellFormattedDate } from '../../components/grid-controller/cell-formatted-date.js';
13
15
  import { GridController } from '../../components/grid-controller/grid-controller.js';
14
16
  import { GridFooter } from '../../components/grid-controller/grid-footer.js';
@@ -51,6 +53,13 @@ const Component = ({
51
53
  const {
52
54
  globalFeatures
53
55
  } = useElements();
56
+ const {
57
+ toggleSort,
58
+ sortState
59
+ } = useSortableQuery({
60
+ defaultSortBy: "modified_at",
61
+ defaultSortDir: "desc"
62
+ });
54
63
  const {
55
64
  isLoading,
56
65
  isError,
@@ -64,13 +73,40 @@ const Component = ({
64
73
  } = useShipmentsGrid({
65
74
  shipmentStatus,
66
75
  showCreatedDateFilter: _showCreatedDateFilter,
67
- showShipmentIdFilter: _showShipmentIdFilter
76
+ showShipmentIdFilter: _showShipmentIdFilter,
77
+ sortBy: sortState.by,
78
+ sortDir: sortState.dir
68
79
  });
69
- if (isLoading) {
70
- return jsx(Loader, {
71
- message: t("loading.shipments")
72
- });
73
- }
80
+ const handleCreatedDateSort = () => {
81
+ toggleSort("created_at");
82
+ };
83
+ const handleUpdatedDateSort = () => {
84
+ toggleSort("modified_at");
85
+ };
86
+ const emptyContentComponent = useMemo(() => {
87
+ if (isLoading) {
88
+ return undefined;
89
+ }
90
+ if (isAnyFilterActive) {
91
+ return jsx(EmptyState, Object.assign({
92
+ isElevated: false,
93
+ subtitle: t("list-shipments:emptyState.filtersSubtitle"),
94
+ title: t("list-shipments:emptyState.filtersTitle")
95
+ }, {
96
+ children: jsx(Button, Object.assign({
97
+ onClick: clearAllFilters
98
+ }, {
99
+ children: t("list-shipments:emptyState.viewAll")
100
+ }))
101
+ }));
102
+ } else {
103
+ return jsx(EmptyState, {
104
+ isElevated: false,
105
+ subtitle: t("list-shipments:emptyState.subtitle"),
106
+ title: t("list-shipments:emptyState.title")
107
+ });
108
+ }
109
+ }, [clearAllFilters, isAnyFilterActive, isLoading, t]);
74
110
  if (isError) {
75
111
  return jsx(ErrorState, {
76
112
  css: styles.errorState,
@@ -156,7 +192,11 @@ const Component = ({
156
192
  }));
157
193
  }
158
194
  }, {
159
- headerContent: t("list-shipments:headers.created"),
195
+ headerContent: jsx(SortableHeader, {
196
+ headerText: t("list-shipments:headers.created"),
197
+ onToggleSort: handleCreatedDateSort,
198
+ sortDirection: sortState.createdAtDir
199
+ }),
160
200
  renderCellContent: shipment => {
161
201
  return jsx(CellFormattedDate, {
162
202
  date: shipment.createdAt,
@@ -164,7 +204,11 @@ const Component = ({
164
204
  });
165
205
  }
166
206
  }, {
167
- headerContent: t("list-shipments:headers.modified"),
207
+ headerContent: jsx(SortableHeader, {
208
+ headerText: t("list-shipments:headers.modified"),
209
+ onToggleSort: handleUpdatedDateSort,
210
+ sortDirection: sortState.modifiedAtDir
211
+ }),
168
212
  renderCellContent: shipment => {
169
213
  return jsx(CellFormattedDate, {
170
214
  date: shipment.modifiedAt,
@@ -196,23 +240,10 @@ const Component = ({
196
240
  children: [jsx(GridController, {
197
241
  columns: columns,
198
242
  data: getGridData(),
199
- emptyContent: isAnyFilterActive ? jsx(EmptyState, Object.assign({
200
- isElevated: false,
201
- subtitle: t("list-shipments:emptyState.filtersSubtitle"),
202
- title: t("list-shipments:emptyState.filtersTitle")
203
- }, {
204
- children: jsx(Button, Object.assign({
205
- onClick: clearAllFilters
206
- }, {
207
- children: t("list-shipments:emptyState.viewAll")
208
- }))
209
- })) : jsx(EmptyState, {
210
- isElevated: false,
211
- subtitle: t("list-shipments:emptyState.subtitle"),
212
- title: t("list-shipments:emptyState.title")
213
- }),
243
+ emptyContent: emptyContentComponent,
214
244
  filters: shouldShowFilters && jsx(GridFilters, {
215
245
  filters: filters,
246
+ filtersDisabled: isLoading,
216
247
  onClearAllFilters: clearAllFilters,
217
248
  onFiltersUpdated: setFilters
218
249
  }),
@@ -224,6 +255,7 @@ const Component = ({
224
255
  showPagination: pageConfig.showPagination,
225
256
  total: pageConfig.totalElements
226
257
  }),
258
+ isLoading: isLoading,
227
259
  onRowClick: onRowClick
228
260
  }), globalFeatures.poweredByShipEngine && jsxs(Fragment, {
229
261
  children: [jsx(Spacer, {}), jsx(PoweredByShipEngine, {})]
@@ -0,0 +1,32 @@
1
+ import { useState } from 'react';
2
+
3
+ const useSortableQuery = ({
4
+ defaultSortBy: _defaultSortBy = "modified_at",
5
+ defaultSortDir: _defaultSortDir = "desc"
6
+ }) => {
7
+ const [sortState, setSortState] = useState({
8
+ by: _defaultSortBy,
9
+ createdAtDir: _defaultSortDir,
10
+ dir: _defaultSortDir,
11
+ modifiedAtDir: _defaultSortDir
12
+ });
13
+ const toggleSort = sortQuery => {
14
+ const newSortState = Object.assign({}, sortState);
15
+ if (sortQuery === "created_at") {
16
+ newSortState.createdAtDir = sortState.createdAtDir === "asc" ? "desc" : "asc";
17
+ newSortState.dir = newSortState.createdAtDir;
18
+ newSortState.by = "created_at";
19
+ } else if (sortQuery === "modified_at") {
20
+ newSortState.modifiedAtDir = sortState.modifiedAtDir === "asc" ? "desc" : "asc";
21
+ newSortState.dir = newSortState.modifiedAtDir;
22
+ newSortState.by = "modified_at";
23
+ }
24
+ setSortState(newSortState);
25
+ };
26
+ return {
27
+ sortState,
28
+ toggleSort
29
+ };
30
+ };
31
+
32
+ export { useSortableQuery };
@@ -212,6 +212,7 @@ var common = {
212
212
  grid: {
213
213
  "row-count_one": "Showing {{firstIndex}}-{{lastIndex}} of <0>{{count}} item</0>",
214
214
  "row-count_other": "Showing {{firstIndex}}-{{lastIndex}} of <0>{{count}} items</0>",
215
+ "row-count-plus_other": "Showing {{firstIndex}}-{{lastIndex}} of <0>{{count}}+ items</0>",
215
216
  rows: "Rows",
216
217
  clearAll: "Clear all",
217
218
  shipmentId: "Shipment ID",
package/esm/package.js CHANGED
@@ -1,3 +1,3 @@
1
- var version = "2.21.0";
1
+ var version = "2.22.0";
2
2
 
3
3
  export { version };
@@ -4,7 +4,7 @@ const defaultLabelsGridColumns = [{
4
4
  allowFilter: true,
5
5
  name: "labelId"
6
6
  }, {
7
- allowFilter: true,
7
+ allowFilter: false,
8
8
  name: "trackingStatus"
9
9
  }, {
10
10
  name: "recipient"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipengine/elements",
3
- "version": "2.21.0",
3
+ "version": "2.22.0",
4
4
  "module": "./index.js",
5
5
  "main": "./index.js",
6
6
  "types": "./src/index.d.ts",
@@ -269,8 +269,8 @@
269
269
  "@rollup/plugin-node-resolve": "13.3.0",
270
270
  "@shipengine/giger": "1.20.18",
271
271
  "@shipengine/giger-theme": "1.8.1",
272
- "@shipengine/js-api": "3.6.0",
273
- "@shipengine/react-api": "3.10.3",
272
+ "@shipengine/js-api": "3.8.0",
273
+ "@shipengine/react-api": "3.11.0",
274
274
  "@tanstack/react-query": "4.36.1",
275
275
  "@testing-library/dom": "8.19.0",
276
276
  "axios": "1.8.4",
@@ -22,6 +22,7 @@ type GridProps<T extends GridDataType> = {
22
22
  emptyContent?: ReactNode;
23
23
  filters?: ReactNode;
24
24
  footerContent?: ReactNode;
25
+ isLoading?: boolean;
25
26
  onRowClick?: (data: T) => void;
26
27
  useCheckboxes?: boolean;
27
28
  };
@@ -34,5 +35,5 @@ type GridProps<T extends GridDataType> = {
34
35
  *
35
36
  * @see {@link GridProps | The props for the `<GridController />` component}
36
37
  */
37
- export declare const GridController: <T extends GridDataType>({ columns, data, footerContent, onRowClick, useCheckboxes, filters, emptyContent, }: GridProps<T>) => import("@emotion/react/jsx-runtime").JSX.Element;
38
+ export declare const GridController: <T extends GridDataType>({ columns, data, footerContent, onRowClick, isLoading, useCheckboxes, filters, emptyContent, }: GridProps<T>) => import("@emotion/react/jsx-runtime").JSX.Element;
38
39
  export {};
@@ -3,8 +3,12 @@ export declare const styles: {
3
3
  width: number;
4
4
  };
5
5
  filters: (theme: import("../../utilities/styles").ScopedGigerTheme) => {
6
+ backgroundColor: string;
6
7
  borderBottom: string;
7
- padding: string;
8
+ padding: number;
9
+ };
10
+ skeletonTableRow: () => {
11
+ height: string;
8
12
  };
9
13
  table: {
10
14
  tableLayout: "initial";
@@ -24,5 +28,6 @@ export declare const styles: {
24
28
  borderRadius?: string | undefined;
25
29
  boxShadow?: string | undefined;
26
30
  height: string;
31
+ overflow: "hidden";
27
32
  };
28
33
  };
@@ -7,6 +7,14 @@
7
7
  * @see {@link GridFooter | The `<GridFooter />` component}
8
8
  */
9
9
  interface GridFooterProps {
10
+ /**
11
+ * If true, indicates there might be more results beyond what's been fetched
12
+ */
13
+ hasMoreUnfetchedResults?: boolean;
14
+ /**
15
+ * If true, displays a loading indicator in the pagination area
16
+ */
17
+ isLoadingMore?: boolean;
10
18
  onPageChange: (nextPage: number) => void;
11
19
  page: number;
12
20
  pages: number;
@@ -23,5 +31,5 @@ interface GridFooterProps {
23
31
  *
24
32
  * @see {@link GridFooterProps | The props for the `<GridFooter />` component}
25
33
  */
26
- export declare const GridFooter: ({ page, pages, pageSize, total, showPagination, onPageChange, }: GridFooterProps) => JSX.Element;
34
+ export declare const GridFooter: ({ page, pages, pageSize, total, showPagination, onPageChange, isLoadingMore, hasMoreUnfetchedResults, }: GridFooterProps) => JSX.Element;
27
35
  export {};
@@ -0,0 +1,16 @@
1
+ export declare const styles: {
2
+ countWrapper: (theme: import("../../utilities/styles").ScopedGigerTheme) => {
3
+ alignItems: "center";
4
+ display: "flex";
5
+ gap: number;
6
+ };
7
+ loader: (theme: import("../../utilities/styles").ScopedGigerTheme) => {
8
+ color: string;
9
+ };
10
+ wrapper: {
11
+ alignItems: "center";
12
+ display: "flex";
13
+ justifyContent: "space-between";
14
+ width: string;
15
+ };
16
+ };
@@ -0,0 +1 @@
1
+ export * from "./sortable-header";
@@ -1,4 +1,4 @@
1
- export type SortDirection = "asc" | "desc";
1
+ import { SE } from "@shipengine/js-api";
2
2
  export interface SortableHeaderProps {
3
3
  /**
4
4
  * The text to display in the header
@@ -11,7 +11,7 @@ export interface SortableHeaderProps {
11
11
  /**
12
12
  * The current sort direction
13
13
  */
14
- sortDirection: SortDirection;
14
+ sortDirection: SE.SortableQuery["sortDir"];
15
15
  }
16
16
  /**
17
17
  * A reusable component for creating sortable table headers
@@ -0,0 +1,10 @@
1
+ export declare const styles: {
2
+ icon: (theme: import("../../../utilities/styles").ScopedGigerTheme) => {
3
+ paddingLeft: number;
4
+ };
5
+ span: () => {
6
+ alignItems: "center";
7
+ cursor: "pointer";
8
+ display: "flex";
9
+ };
10
+ };
@@ -7,6 +7,7 @@ import { IGridFilters } from "../../grid-filters";
7
7
  * @see {@link CreatedDateFilter | The `<CreatedDateFilter />` component}
8
8
  */
9
9
  type CreatedDateFilterProps = {
10
+ disabled?: boolean;
10
11
  filters: IGridFilters;
11
12
  onFiltersUpdated: (params: IGridFilters) => void;
12
13
  };
@@ -19,5 +20,5 @@ type CreatedDateFilterProps = {
19
20
  *
20
21
  * @see {@link CreatedDateFilterProps | The props for the `<CreatedDateFilter />` component}
21
22
  */
22
- export declare const CreatedDateFilter: ({ filters, onFiltersUpdated }: CreatedDateFilterProps) => import("@emotion/react/jsx-runtime").JSX.Element;
23
+ export declare const CreatedDateFilter: ({ disabled, filters, onFiltersUpdated, }: CreatedDateFilterProps) => import("@emotion/react/jsx-runtime").JSX.Element;
23
24
  export {};