@wilshop/dashboard 3.5.5 → 3.5.7

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 (133) hide show
  1. package/dist/plugin/dashboard.plugin.d.ts +1 -1
  2. package/dist/plugin/dashboard.plugin.js +1 -1
  3. package/dist/vite/utils/compiler.js +50 -24
  4. package/dist/vite/utils/path-transformer.d.ts +20 -0
  5. package/dist/vite/utils/path-transformer.js +116 -0
  6. package/dist/vite/utils/plugin-discovery.js +3 -2
  7. package/dist/vite/utils/ui-config.js +15 -1
  8. package/dist/vite/vite-plugin-lingui-babel.d.ts +15 -2
  9. package/dist/vite/vite-plugin-lingui-babel.js +92 -17
  10. package/dist/vite/vite-plugin-translations.js +2 -2
  11. package/dist/vite/vite-plugin-ui-config.d.ts +31 -0
  12. package/package.json +10 -6
  13. package/src/app/common/delete-bulk-action.tsx +1 -1
  14. package/src/app/common/duplicate-bulk-action.tsx +1 -1
  15. package/src/app/routes/_authenticated/_collections/collections.graphql.ts +1 -3
  16. package/src/app/routes/_authenticated/_collections/collections.tsx +169 -48
  17. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +36 -5
  18. package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +1 -1
  19. package/src/app/routes/_authenticated/_collections/components/collection-filters-selector.tsx +7 -1
  20. package/src/app/routes/_authenticated/_customers/components/customer-history/default-customer-history-components.tsx +31 -29
  21. package/src/app/routes/_authenticated/_customers/customers.graphql.ts +1 -0
  22. package/src/app/routes/_authenticated/_customers/customers.tsx +3 -0
  23. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +1 -1
  24. package/src/app/routes/_authenticated/_orders/components/draft-order-status.tsx +48 -0
  25. package/src/app/routes/_authenticated/_orders/components/fulfill-order-dialog.tsx +8 -5
  26. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +79 -54
  27. package/src/app/routes/_authenticated/_orders/components/order-history/default-order-history-components.tsx +43 -3
  28. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-utils.tsx +19 -3
  29. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +1 -0
  30. package/src/app/routes/_authenticated/_orders/components/refund-order-dialog.tsx +372 -0
  31. package/src/app/routes/_authenticated/_orders/hooks/use-refund-order.ts +345 -0
  32. package/src/app/routes/_authenticated/_orders/orders.graphql.ts +41 -0
  33. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +22 -6
  34. package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +51 -0
  35. package/src/app/routes/_authenticated/_orders/utils/refund-utils.ts +100 -0
  36. package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +1 -1
  37. package/src/app/routes/_authenticated/_payment-methods/components/payment-eligibility-checker-selector.tsx +4 -1
  38. package/src/app/routes/_authenticated/_payment-methods/components/payment-handler-selector.tsx +7 -1
  39. package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +18 -2
  40. package/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx +1 -1
  41. package/src/app/routes/_authenticated/_product-variants/components/variant-price-detail.tsx +6 -2
  42. package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +9 -3
  43. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +49 -30
  44. package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +1 -1
  45. package/src/app/routes/_authenticated/_profile/profile.graphql.ts +7 -0
  46. package/src/app/routes/_authenticated/_profile/profile.tsx +25 -1
  47. package/src/app/routes/_authenticated/_promotions/components/promotion-actions-selector.tsx +7 -1
  48. package/src/app/routes/_authenticated/_promotions/components/promotion-conditions-selector.tsx +7 -1
  49. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +18 -2
  50. package/src/app/routes/_authenticated/_shipping-methods/components/shipping-calculator-selector.tsx +7 -1
  51. package/src/app/routes/_authenticated/_shipping-methods/components/shipping-eligibility-checker-selector.tsx +4 -1
  52. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +14 -2
  53. package/src/i18n/common-strings.ts +7 -0
  54. package/src/i18n/locales/ar.po +669 -399
  55. package/src/i18n/locales/bg.po +1889 -46
  56. package/src/i18n/locales/cs.po +676 -406
  57. package/src/i18n/locales/de.po +676 -406
  58. package/src/i18n/locales/en.po +669 -399
  59. package/src/i18n/locales/es.po +676 -406
  60. package/src/i18n/locales/fa.po +676 -406
  61. package/src/i18n/locales/fr.po +676 -406
  62. package/src/i18n/locales/he.po +676 -406
  63. package/src/i18n/locales/hr.po +676 -406
  64. package/src/i18n/locales/it.po +676 -406
  65. package/src/i18n/locales/ja.po +676 -406
  66. package/src/i18n/locales/nb.po +676 -406
  67. package/src/i18n/locales/ne.po +676 -406
  68. package/src/i18n/locales/pl.po +676 -406
  69. package/src/i18n/locales/pt_BR.po +676 -406
  70. package/src/i18n/locales/pt_PT.po +676 -406
  71. package/src/i18n/locales/ru.po +676 -406
  72. package/src/i18n/locales/sv.po +676 -406
  73. package/src/i18n/locales/tr.po +676 -406
  74. package/src/i18n/locales/uk.po +676 -406
  75. package/src/i18n/locales/zh_Hans.po +676 -406
  76. package/src/i18n/locales/zh_Hant.po +676 -406
  77. package/src/lib/components/data-input/facet-value-input.tsx +2 -2
  78. package/src/lib/components/data-input/index.ts +1 -0
  79. package/src/lib/components/data-input/select-with-options.tsx +23 -7
  80. package/src/lib/components/data-input/struct-form-input.tsx +53 -21
  81. package/src/lib/components/data-input/text-input.tsx +1 -1
  82. package/src/lib/components/data-table/data-table-bulk-actions.tsx +2 -1
  83. package/src/lib/components/data-table/data-table-context.tsx +2 -10
  84. package/src/lib/components/data-table/data-table-utils.ts +34 -12
  85. package/src/lib/components/data-table/data-table.tsx +68 -30
  86. package/src/lib/components/data-table/global-views-bar.tsx +1 -1
  87. package/src/lib/components/data-table/my-views-button.tsx +1 -1
  88. package/src/lib/components/data-table/save-view-button.tsx +1 -1
  89. package/src/lib/components/data-table/use-generated-columns.tsx +9 -2
  90. package/src/lib/components/data-table/views-sheet.tsx +1 -1
  91. package/src/lib/components/layout/channel-switcher.tsx +16 -17
  92. package/src/lib/components/layout/manage-languages-dialog.tsx +1 -1
  93. package/src/lib/components/shared/assign-to-channel-bulk-action.tsx +1 -1
  94. package/src/lib/components/shared/configurable-operation-input.tsx +23 -0
  95. package/src/lib/components/shared/configurable-operation-multi-selector.tsx +45 -0
  96. package/src/lib/components/shared/configurable-operation-selector.tsx +5 -0
  97. package/src/lib/components/shared/paginated-list-context.ts +10 -0
  98. package/src/lib/components/shared/paginated-list-data-table.tsx +6 -32
  99. package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +1 -1
  100. package/src/lib/components/ui/alert.tsx +2 -0
  101. package/src/lib/constants.ts +7 -319
  102. package/src/lib/framework/dashboard-widget/base-widget.tsx +3 -12
  103. package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +1 -1
  104. package/src/lib/framework/dashboard-widget/metrics-widget/chart.tsx +1 -1
  105. package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +1 -1
  106. package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +1 -1
  107. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +2 -20
  108. package/src/lib/framework/extension-api/input-component-extensions.tsx +4 -0
  109. package/src/lib/framework/form-engine/custom-form-component.tsx +13 -3
  110. package/src/lib/framework/form-engine/form-engine-types.ts +3 -5
  111. package/src/lib/framework/form-engine/form-schema-tools.ts +4 -1
  112. package/src/lib/framework/form-engine/use-generated-form.tsx +6 -2
  113. package/src/lib/framework/form-engine/utils.spec.ts +129 -2
  114. package/src/lib/framework/form-engine/utils.ts +36 -9
  115. package/src/lib/framework/form-engine/value-transformers.ts +6 -0
  116. package/src/lib/framework/page/detail-page-route-loader.tsx +6 -4
  117. package/src/lib/framework/page/detail-page.tsx +22 -37
  118. package/src/lib/framework/page/list-page.stories.tsx +41 -2
  119. package/src/lib/framework/page/list-page.tsx +8 -0
  120. package/src/lib/graphql/graphql-env.d.ts +33 -16
  121. package/src/lib/graphql/schema-enums.ts +13 -0
  122. package/src/lib/hooks/use-alerts-context.ts +10 -0
  123. package/src/lib/hooks/use-alerts.ts +1 -1
  124. package/src/lib/hooks/use-data-table-context.ts +11 -0
  125. package/src/lib/hooks/use-dynamic-translations.ts +7 -0
  126. package/src/lib/hooks/use-job-queue-polling.ts +160 -0
  127. package/src/lib/hooks/use-paginated-list.ts +28 -0
  128. package/src/lib/hooks/use-widget-dimensions.ts +12 -0
  129. package/src/lib/hooks/use-widget-filters.ts +21 -0
  130. package/src/lib/index.ts +12 -0
  131. package/src/lib/providers/alerts-provider.tsx +3 -11
  132. package/src/lib/virtual.d.ts +5 -0
  133. package/src/lib/utils/global-languages.ts +0 -268
@@ -44,6 +44,7 @@ export function FulfillOrderDialog({ order, onSuccess }: Readonly<FulfillOrderDi
44
44
  const [fulfillmentQuantities, setFulfillmentQuantities] = useState<{
45
45
  [lineId: string]: FulfillmentQuantity;
46
46
  }>({});
47
+ const [handlerArgsValid, setHandlerArgsValid] = useState(true);
47
48
 
48
49
  // Get fulfillment handlers
49
50
  const { data: fulfillmentHandlersData } = useQuery({
@@ -161,7 +162,7 @@ export function FulfillOrderDialog({ order, onSuccess }: Readonly<FulfillOrderDi
161
162
  ({ fulfillCount, max }) => fulfillCount <= max && fulfillCount >= 0,
162
163
  );
163
164
  const formIsValid = form.formState.isValid;
164
- return formIsValid && totalCount > 0 && fulfillmentQuantityIsValid;
165
+ return formIsValid && totalCount > 0 && fulfillmentQuantityIsValid && handlerArgsValid;
165
166
  };
166
167
 
167
168
  const handleSubmit = async (data: FormData) => {
@@ -195,6 +196,7 @@ export function FulfillOrderDialog({ order, onSuccess }: Readonly<FulfillOrderDi
195
196
  const handleCancel = () => {
196
197
  form.reset();
197
198
  setFulfillmentQuantities({});
199
+ setHandlerArgsValid(true);
198
200
  setOpen(false);
199
201
  };
200
202
 
@@ -218,8 +220,8 @@ export function FulfillOrderDialog({ order, onSuccess }: Readonly<FulfillOrderDi
218
220
  >
219
221
  <Trans>Fulfill order</Trans>
220
222
  </Button>
221
- <Dialog open={open}>
222
- <DialogContent className="sm:max-w-[600px]">
223
+ <Dialog open={open} onOpenChange={setOpen}>
224
+ <DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-hidden flex flex-col">
223
225
  <DialogHeader>
224
226
  <DialogTitle>
225
227
  <Trans>Fulfill order</Trans>
@@ -234,9 +236,9 @@ export function FulfillOrderDialog({ order, onSuccess }: Readonly<FulfillOrderDi
234
236
  e.stopPropagation();
235
237
  form.handleSubmit(handleSubmit)(e);
236
238
  }}
237
- className="space-y-4"
239
+ className="space-y-4 flex-1 overflow-hidden flex flex-col"
238
240
  >
239
- <div className="space-y-4">
241
+ <div className="space-y-4 flex-1 overflow-y-auto">
240
242
  <div className="font-medium">
241
243
  <Trans>Order lines</Trans>
242
244
  </div>
@@ -294,6 +296,7 @@ export function FulfillOrderDialog({ order, onSuccess }: Readonly<FulfillOrderDi
294
296
  onChange={field.onChange}
295
297
  readonly={false}
296
298
  removable={false}
299
+ onValidityChange={setHandlerArgsValid}
297
300
  />
298
301
  )}
299
302
  />
@@ -11,7 +11,7 @@ import {
11
11
  PageLayout,
12
12
  PageTitle,
13
13
  } from '@/vdb/framework/layout-engine/page-layout.js';
14
- import { getDetailQueryOptions, useDetailPage } from '@/vdb/framework/page/use-detail-page.js';
14
+ import { useDetailPage } from '@/vdb/framework/page/use-detail-page.js';
15
15
  import { api } from '@/vdb/graphql/api.js';
16
16
  import { useCustomFieldConfig } from '@/vdb/hooks/use-custom-field-config.js';
17
17
  import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
@@ -19,15 +19,17 @@ import { Trans, useLingui } from '@lingui/react/macro';
19
19
  import { useMutation, useQueryClient } from '@tanstack/react-query';
20
20
  import { Link, useNavigate } from '@tanstack/react-router';
21
21
  import { ResultOf } from 'gql.tada';
22
- import { Pencil, User } from 'lucide-react';
23
- import { useMemo } from 'react';
22
+ import { Pencil, RotateCcw, User } from 'lucide-react';
23
+ import { useCallback, useMemo, useRef } from 'react';
24
24
  import { toast } from 'sonner';
25
+
25
26
  import {
26
27
  orderDetailDocument,
27
28
  setOrderCustomFieldsDocument,
28
29
  transitionOrderToStateDocument,
29
30
  } from '../orders.graphql.js';
30
- import { canAddFulfillment, shouldShowAddManualPaymentButton } from '../utils/order-utils.js';
31
+ import { canAddFulfillment, canRefundOrder, shouldShowAddManualPaymentButton } from '../utils/order-utils.js';
32
+
31
33
  import { AddManualPaymentDialog } from './add-manual-payment-dialog.js';
32
34
  import { FulfillOrderDialog } from './fulfill-order-dialog.js';
33
35
  import { FulfillmentDetails } from './fulfillment-details.js';
@@ -37,6 +39,7 @@ import { orderHistoryQueryKey } from './order-history/use-order-history.js';
37
39
  import { OrderTable } from './order-table.js';
38
40
  import { OrderTaxSummary } from './order-tax-summary.js';
39
41
  import { PaymentDetails } from './payment-details.js';
42
+ import { RefundOrderDialog, RefundOrderDialogRef } from './refund-order-dialog.js';
40
43
  import { getTypeForState, StateTransitionControl } from './state-transition-control.js';
41
44
  import { useTransitionOrderToState } from './use-transition-order-to-state.js';
42
45
 
@@ -101,58 +104,84 @@ export function OrderDetailShared({
101
104
  });
102
105
 
103
106
  const customFieldConfig = useCustomFieldConfig('Order');
107
+ const refundDialogRef = useRef<RefundOrderDialogRef>(null);
108
+
109
+ const refreshPage = useCallback(async () => {
110
+ if (!entity) return;
111
+ await Promise.all([
112
+ refreshEntity(),
113
+ queryClient.refetchQueries({ queryKey: orderHistoryQueryKey(entity.id) }),
114
+ ]);
115
+ }, [refreshEntity, entity, queryClient]);
104
116
 
105
117
  const stateTransitionActions = useMemo(() => {
106
118
  if (!entity) {
107
119
  return [];
108
120
  }
109
- return entity.nextStates.map((state: string) => ({
110
- label: t`Transition to ${getTranslatedOrderState(state)}`,
111
- type: getTypeForState(state),
112
- onClick: async () => {
113
- const transitionError = await transitionToState(state);
114
- if (transitionError) {
115
- toast(t`Failed to transition order to state`, {
116
- description: transitionError,
117
- });
118
- } else {
119
- refreshOrderAndHistory();
120
- }
121
- },
122
- }));
123
- }, [entity, transitionToState, t]);
121
+ return entity.nextStates
122
+ .filter((state: string) => state !== 'Modifying')
123
+ .map((state: string) => ({
124
+ label: t`Transition to ${getTranslatedOrderState(state)}`,
125
+ type: getTypeForState(state),
126
+ onClick: async () => {
127
+ const transitionError = await transitionToState(state);
128
+ if (transitionError) {
129
+ toast(t`Failed to transition order to state`, {
130
+ description: transitionError,
131
+ });
132
+ } else {
133
+ void refreshPage();
134
+ }
135
+ },
136
+ }));
137
+ }, [entity, transitionToState, t, refreshPage]);
124
138
 
125
- if (!entity) {
126
- return null;
127
- }
128
-
129
- const handleModifyClick = async () => {
139
+ const handleModifyClick = useCallback(async () => {
140
+ if (!entity) return;
130
141
  try {
131
142
  await transitionOrderToStateMutation.mutateAsync({
132
143
  id: entity.id,
133
144
  state: 'Modifying',
134
145
  });
135
- const queryKey = getDetailQueryOptions(orderDetailDocument, { id: entity.id }).queryKey;
136
- await queryClient.invalidateQueries({ queryKey });
146
+ await refreshPage();
137
147
  await navigate({ to: `/orders/$id/modify`, params: { id: entity.id } });
138
148
  } catch (error) {
139
149
  toast(t`Failed to modify order`, {
140
150
  description: error instanceof Error ? error.message : 'Unknown error',
141
151
  });
142
152
  }
143
- };
153
+ }, [entity, transitionOrderToStateMutation, refreshPage, navigate, t]);
154
+
155
+ const ModifyMenuItem = useCallback(
156
+ () => (
157
+ <DropdownMenuItem onClick={handleModifyClick}>
158
+ <Pencil className="w-4 h-4" />
159
+ <Trans>Modify</Trans>
160
+ </DropdownMenuItem>
161
+ ),
162
+ [handleModifyClick],
163
+ );
164
+
165
+ const RefundMenuItem = useCallback(
166
+ () => (
167
+ <PermissionGuard requires={['UpdateOrder']}>
168
+ <DropdownMenuItem onClick={() => refundDialogRef.current?.open()}>
169
+ <RotateCcw className="w-4 h-4" />
170
+ <Trans>Refund & Cancel</Trans>
171
+ </DropdownMenuItem>
172
+ </PermissionGuard>
173
+ ),
174
+ [],
175
+ );
176
+
177
+ if (!entity) {
178
+ return null;
179
+ }
144
180
 
145
181
  const nextStates = entity.nextStates;
146
182
  const showAddPaymentButton = shouldShowAddManualPaymentButton(entity);
147
183
  const showFulfillButton = canAddFulfillment(entity);
148
-
149
- async function refreshOrderAndHistory() {
150
- if (entity) {
151
- const queryKey = getDetailQueryOptions(orderDetailDocument, { id: entity.id }).queryKey;
152
- await queryClient.invalidateQueries({ queryKey });
153
- queryClient.refetchQueries({ queryKey: orderHistoryQueryKey(entity.id) });
154
- }
155
- }
184
+ const showRefundOption = canRefundOrder(entity);
156
185
 
157
186
  return (
158
187
  <Page pageId={pageId} form={form} submitHandler={submitHandler} entity={entity}>
@@ -160,18 +189,8 @@ export function OrderDetailShared({
160
189
  <PageActionBar>
161
190
  <PageActionBarRight
162
191
  dropdownMenuItems={[
163
- ...(nextStates.includes('Modifying')
164
- ? [
165
- {
166
- component: () => (
167
- <DropdownMenuItem onClick={handleModifyClick}>
168
- <Pencil className="w-4 h-4" />
169
- <Trans>Modify</Trans>
170
- </DropdownMenuItem>
171
- ),
172
- },
173
- ]
174
- : []),
192
+ ...(nextStates.includes('Modifying') ? [{ component: ModifyMenuItem }] : []),
193
+ ...(showRefundOption ? [{ component: RefundMenuItem }] : []),
175
194
  ]}
176
195
  >
177
196
  {showAddPaymentButton && (
@@ -179,7 +198,7 @@ export function OrderDetailShared({
179
198
  <AddManualPaymentDialog
180
199
  order={entity}
181
200
  onSuccess={() => {
182
- refreshEntity();
201
+ void refreshPage();
183
202
  }}
184
203
  />
185
204
  </PermissionGuard>
@@ -189,13 +208,22 @@ export function OrderDetailShared({
189
208
  <FulfillOrderDialog
190
209
  order={entity}
191
210
  onSuccess={() => {
192
- refreshOrderAndHistory();
211
+ void refreshPage();
193
212
  }}
194
213
  />
195
214
  </PermissionGuard>
196
215
  )}
197
216
  </PageActionBarRight>
198
217
  </PageActionBar>
218
+ {showRefundOption && (
219
+ <RefundOrderDialog
220
+ ref={refundDialogRef}
221
+ order={entity}
222
+ onSuccess={() => {
223
+ void refreshPage();
224
+ }}
225
+ />
226
+ )}
199
227
  <PageLayout>
200
228
  {/* Main Column Blocks */}
201
229
  {beforeOrderTable?.(entity)}
@@ -225,7 +253,7 @@ export function OrderDetailShared({
225
253
  key={payment.id}
226
254
  payment={payment}
227
255
  currencyCode={entity.currencyCode}
228
- onSuccess={refreshOrderAndHistory}
256
+ onSuccess={refreshPage}
229
257
  />
230
258
  ))}
231
259
  </div>
@@ -287,10 +315,7 @@ export function OrderDetailShared({
287
315
  order={entity}
288
316
  fulfillment={fulfillment}
289
317
  onSuccess={() => {
290
- refreshEntity();
291
- queryClient.refetchQueries({
292
- queryKey: orderHistoryQueryKey(entity.id),
293
- });
318
+ void refreshPage();
294
319
  }}
295
320
  />
296
321
  ))}
@@ -1,5 +1,7 @@
1
1
  import { HistoryEntry, HistoryEntryProps } from '@/vdb/framework/history-entry/history-entry.js';
2
+ import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
2
3
  import { Trans } from '@lingui/react/macro';
4
+ import { uiConfig } from 'virtual:vendure-ui-config';
3
5
 
4
6
  export function OrderStateTransitionComponent(props: Readonly<HistoryEntryProps>) {
5
7
  const { entry } = props;
@@ -88,11 +90,49 @@ export function OrderCustomerUpdatedComponent(props: Readonly<HistoryEntryProps>
88
90
  }
89
91
 
90
92
  export function OrderCancellationComponent(props: Readonly<HistoryEntryProps>) {
93
+ const { entry } = props;
94
+ const { getTranslatedRefundReason } = useDynamicTranslations();
95
+
96
+ const lines = entry.data.lines as Array<{ orderLineId: string; quantity: number }> | undefined;
97
+ const reason = entry.data.reason as string | undefined;
98
+ const shippingCancelled = entry.data.shippingCancelled as boolean | undefined;
99
+
100
+ const totalQuantity = lines?.reduce((sum, line) => sum + line.quantity, 0) ?? 0;
101
+ const hasDetails = totalQuantity > 0 || shippingCancelled || reason;
102
+
103
+ const getTranslatedReason = (reasonValue: string) => {
104
+ const { refundReasons } = uiConfig.orders;
105
+ const reasonConfig = refundReasons.find(r => r.value === reasonValue);
106
+ if (reasonConfig) {
107
+ return getTranslatedRefundReason(reasonConfig.label);
108
+ }
109
+ return reasonValue;
110
+ };
111
+
91
112
  return (
92
113
  <HistoryEntry {...props}>
93
- <p className="text-xs text-muted-foreground">
94
- <Trans>Order cancelled</Trans>
95
- </p>
114
+ <div className="text-xs text-muted-foreground space-y-1">
115
+ {totalQuantity > 0 && (
116
+ <p>
117
+ <Trans>{totalQuantity} item(s) refunded</Trans>
118
+ </p>
119
+ )}
120
+ {shippingCancelled && (
121
+ <p>
122
+ <Trans>Shipping refunded</Trans>
123
+ </p>
124
+ )}
125
+ {reason && (
126
+ <p>
127
+ <Trans>Reason:</Trans> {getTranslatedReason(reason)}
128
+ </p>
129
+ )}
130
+ {!hasDetails && (
131
+ <p>
132
+ <Trans>Order cancelled</Trans>
133
+ </p>
134
+ )}
135
+ </div>
96
136
  </HistoryEntry>
97
137
  );
98
138
  }
@@ -6,6 +6,7 @@ import {
6
6
  CheckIcon,
7
7
  CreditCardIcon,
8
8
  Edit3,
9
+ RotateCcw,
9
10
  SquarePen,
10
11
  Truck,
11
12
  UserX,
@@ -40,8 +41,14 @@ export function orderHistoryUtils(order: OrderHistoryOrderDetail) {
40
41
  return <Edit3 className="h-4 w-4" />;
41
42
  case 'ORDER_CUSTOMER_UPDATED':
42
43
  return <UserX className="h-4 w-4" />;
43
- case 'ORDER_CANCELLATION':
44
+ case 'ORDER_CANCELLATION': {
45
+ const lines = entry.data.lines as Array<{ orderLineId: string; quantity: number }> | undefined;
46
+ const hasRefundData = (lines && lines.length > 0) || entry.data.reason;
47
+ if (hasRefundData) {
48
+ return <RotateCcw className="h-4 w-4" />;
49
+ }
44
50
  return <Ban className="h-4 w-4" />;
51
+ }
45
52
  default:
46
53
  return <CheckIcon className="h-4 w-4" />;
47
54
  }
@@ -96,8 +103,14 @@ export function orderHistoryUtils(order: OrderHistoryOrderDetail) {
96
103
  return <Trans>Order modified</Trans>;
97
104
  case 'ORDER_CUSTOMER_UPDATED':
98
105
  return <Trans>Customer updated</Trans>;
99
- case 'ORDER_CANCELLATION':
106
+ case 'ORDER_CANCELLATION': {
107
+ const lines = entry.data.lines as Array<{ orderLineId: string; quantity: number }> | undefined;
108
+ const hasPartialCancellation = lines && lines.length > 0;
109
+ if (hasPartialCancellation || entry.data.reason) {
110
+ return <Trans>Items refunded</Trans>;
111
+ }
100
112
  return <Trans>Order cancelled</Trans>;
113
+ }
101
114
  default:
102
115
  return <Trans>{entry.type.replace(/_/g, ' ').toLowerCase()}</Trans>;
103
116
  }
@@ -106,6 +119,7 @@ export function orderHistoryUtils(order: OrderHistoryOrderDetail) {
106
119
  const getIconColor = ({ type, data }: HistoryEntryItem) => {
107
120
  const success = 'bg-success text-success-foreground';
108
121
  const destructive = 'bg-destructive text-destructive-foreground';
122
+ const warning = 'bg-yellow-400 text-yellow-950 dark:bg-yellow-600 dark:text-yellow-50';
109
123
  const regular = 'bg-muted text-muted-foreground';
110
124
 
111
125
  if (type === 'ORDER_PAYMENT_TRANSITION' && data.to === 'Settled') {
@@ -118,7 +132,9 @@ export function orderHistoryUtils(order: OrderHistoryOrderDetail) {
118
132
  return success;
119
133
  }
120
134
  if (type === 'ORDER_CANCELLATION') {
121
- return destructive;
135
+ const lines = data.lines as Array<{ orderLineId: string; quantity: number }> | undefined;
136
+ const hasRefundData = (lines && lines.length > 0) || data.reason;
137
+ return hasRefundData ? warning : destructive;
122
138
  }
123
139
  if (type === 'ORDER_STATE_TRANSITION' && data.to === 'Cancelled') {
124
140
  return destructive;
@@ -175,6 +175,7 @@ export function OrderTable({ order, pageId }: Readonly<OrderTableProps>) {
175
175
  columns={columns as any}
176
176
  data={data as any}
177
177
  totalItems={data.length}
178
+ itemsPerPage={data.length}
178
179
  disableViewOptions={false}
179
180
  defaultColumnVisibility={columnVisibility}
180
181
  onColumnVisibilityChange={(_, columnVisibility) => {