@wilshop/dashboard 3.5.6 → 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 +90 -8
  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
@@ -0,0 +1,372 @@
1
+ import { VendureImage } from '@/vdb/components/shared/vendure-image.js';
2
+ import { Alert, AlertDescription } from '@/vdb/components/ui/alert.js';
3
+ import { Button } from '@/vdb/components/ui/button.js';
4
+ import { Checkbox } from '@/vdb/components/ui/checkbox.js';
5
+ import {
6
+ Dialog,
7
+ DialogContent,
8
+ DialogDescription,
9
+ DialogFooter,
10
+ DialogHeader,
11
+ DialogTitle,
12
+ } from '@/vdb/components/ui/dialog.js';
13
+ import { Input } from '@/vdb/components/ui/input.js';
14
+ import { Label } from '@/vdb/components/ui/label.js';
15
+ import {
16
+ Select,
17
+ SelectContent,
18
+ SelectItem,
19
+ SelectTrigger,
20
+ SelectValue,
21
+ } from '@/vdb/components/ui/select.js';
22
+ import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
23
+ import { useLocalFormat } from '@/vdb/hooks/use-local-format.js';
24
+ import { Trans, useLingui } from '@lingui/react/macro';
25
+ import { AlertCircle } from 'lucide-react';
26
+ import { forwardRef, useImperativeHandle, useState } from 'react';
27
+ import { uiConfig } from 'virtual:vendure-ui-config';
28
+
29
+ import { useRefundOrder } from '../hooks/use-refund-order.js';
30
+ import { Order } from '../utils/order-types.js';
31
+ import { getMaxRefundableQuantity, lineCanBeRefunded } from '../utils/order-utils.js';
32
+
33
+ interface RefundOrderDialogProps {
34
+ readonly order: Order;
35
+ readonly onSuccess?: () => void;
36
+ }
37
+
38
+ export interface RefundOrderDialogRef {
39
+ open: () => void;
40
+ }
41
+
42
+ export const RefundOrderDialog = forwardRef<RefundOrderDialogRef, RefundOrderDialogProps>(
43
+ function RefundOrderDialog({ order, onSuccess }, ref) {
44
+ const { t } = useLingui();
45
+ const { getTranslatedRefundReason } = useDynamicTranslations();
46
+ const { formatCurrency, toMajorUnits, toMinorUnits } = useLocalFormat();
47
+ const [open, setOpen] = useState(false);
48
+
49
+ const refund = useRefundOrder(order, () => {
50
+ setOpen(false);
51
+ onSuccess?.();
52
+ });
53
+
54
+ useImperativeHandle(ref, () => ({
55
+ open: () => {
56
+ refund.resetState();
57
+ setOpen(true);
58
+ },
59
+ }));
60
+
61
+ const { refundReasons } = uiConfig.orders;
62
+
63
+ const handleClose = () => {
64
+ setOpen(false);
65
+ };
66
+
67
+ return (
68
+ <Dialog open={open} onOpenChange={setOpen}>
69
+ <DialogContent className="!max-w-4xl max-h-[90vh] overflow-y-auto">
70
+ <DialogHeader>
71
+ <DialogTitle>
72
+ <Trans>Refund and cancel order</Trans>
73
+ </DialogTitle>
74
+ <DialogDescription>
75
+ <Trans>Select items to refund and optionally return to stock</Trans>
76
+ </DialogDescription>
77
+ </DialogHeader>
78
+
79
+ <div className="space-y-6">
80
+ {/* Order Lines Table */}
81
+ <div className="space-y-2">
82
+ <Label className="text-base font-medium">
83
+ <Trans>Order lines</Trans>
84
+ </Label>
85
+ <div className="border rounded-md overflow-hidden">
86
+ <table className="w-full text-sm">
87
+ <thead className="bg-muted">
88
+ <tr>
89
+ <th className="p-2 text-left w-16">
90
+ <Trans>Image</Trans>
91
+ </th>
92
+ <th className="p-2 text-left">
93
+ <Trans>Product</Trans>
94
+ </th>
95
+ <th className="p-2 text-right">
96
+ <Trans>Unit price</Trans>
97
+ </th>
98
+ <th className="p-2 text-center">
99
+ <Trans>Qty</Trans>
100
+ </th>
101
+ <th className="p-2 text-center w-24">
102
+ <Trans>Refund</Trans>
103
+ </th>
104
+ <th className="p-2 text-center">
105
+ <Trans>Return to stock</Trans>
106
+ </th>
107
+ </tr>
108
+ </thead>
109
+ <tbody>
110
+ {order.lines.map(line => {
111
+ const canRefund = lineCanBeRefunded(order, line);
112
+ const maxRefundable = getMaxRefundableQuantity(order, line);
113
+ const selection = refund.lineSelections[line.id];
114
+
115
+ if (!canRefund) return null;
116
+
117
+ return (
118
+ <tr key={line.id} className="border-t">
119
+ <td className="p-2">
120
+ <VendureImage
121
+ asset={line.featuredAsset}
122
+ preset="tiny"
123
+ className="w-10 h-10 object-cover"
124
+ />
125
+ </td>
126
+ <td className="p-2">
127
+ <div className="font-medium">
128
+ {line.productVariant.name}
129
+ </div>
130
+ <div className="text-muted-foreground text-xs">
131
+ <Trans>SKU:</Trans> {line.productVariant.sku}
132
+ </div>
133
+ </td>
134
+ <td className="p-2 text-right">
135
+ {formatCurrency(
136
+ line.proratedUnitPriceWithTax,
137
+ order.currencyCode,
138
+ )}
139
+ </td>
140
+ <td className="p-2 text-center">
141
+ {line.orderPlacedQuantity}
142
+ {maxRefundable < line.orderPlacedQuantity && (
143
+ <div className="text-xs text-muted-foreground">
144
+ <Trans>({maxRefundable} refundable)</Trans>
145
+ </div>
146
+ )}
147
+ </td>
148
+ <td className="p-2 text-center">
149
+ <Input
150
+ type="number"
151
+ min={0}
152
+ max={maxRefundable}
153
+ value={selection?.quantity || ''}
154
+ placeholder="0"
155
+ onChange={e => {
156
+ const value = Math.min(
157
+ Math.max(0, Number.parseInt(e.target.value, 10) || 0),
158
+ maxRefundable,
159
+ );
160
+ refund.onRefundQuantityChange(line.id, value);
161
+ }}
162
+ className="w-20 text-right"
163
+ />
164
+ </td>
165
+ <td className="p-2 text-center">
166
+ <div className="flex items-center justify-center">
167
+ <Checkbox
168
+ checked={selection?.cancel ?? false}
169
+ disabled={!selection?.quantity}
170
+ onCheckedChange={checked =>
171
+ refund.onCancelChange(line.id, !!checked)
172
+ }
173
+ />
174
+ </div>
175
+ </td>
176
+ </tr>
177
+ );
178
+ })}
179
+ </tbody>
180
+ </table>
181
+ </div>
182
+ </div>
183
+
184
+ {/* Shipping Refund */}
185
+ {order.shippingLines.length > 0 && (
186
+ <div className="space-y-2">
187
+ <Label className="text-base font-medium">
188
+ <Trans>Shipping</Trans>
189
+ </Label>
190
+ <div className="space-y-2">
191
+ {order.shippingLines.map(shippingLine => (
192
+ <div key={shippingLine.id} className="flex items-center gap-2">
193
+ <Checkbox
194
+ checked={refund.refundShippingLineIds.includes(shippingLine.id)}
195
+ onCheckedChange={() =>
196
+ refund.toggleShippingRefund(shippingLine.id)
197
+ }
198
+ />
199
+ <Label className="font-normal">
200
+ <Trans>Refund shipping</Trans>:{' '}
201
+ {shippingLine.shippingMethod?.name} -{' '}
202
+ {formatCurrency(
203
+ shippingLine.discountedPriceWithTax,
204
+ order.currencyCode,
205
+ )}
206
+ </Label>
207
+ </div>
208
+ ))}
209
+ </div>
210
+ </div>
211
+ )}
212
+
213
+ {/* Reason Selection */}
214
+ <div className="space-y-2">
215
+ <Label className="text-base font-medium">
216
+ <Trans>Reason</Trans>
217
+ </Label>
218
+ <Select value={refund.selectedReason} onValueChange={refund.setSelectedReason}>
219
+ <SelectTrigger className="w-full">
220
+ <SelectValue placeholder={t`Select a reason...`} />
221
+ </SelectTrigger>
222
+ <SelectContent>
223
+ {refundReasons.map(reasonOption => (
224
+ <SelectItem key={reasonOption.value} value={reasonOption.value}>
225
+ {getTranslatedRefundReason(reasonOption.label)}
226
+ </SelectItem>
227
+ ))}
228
+ </SelectContent>
229
+ </Select>
230
+ {refund.selectedReason === 'other' && (
231
+ <Input
232
+ placeholder={t`Enter custom reason...`}
233
+ value={refund.customReason}
234
+ onChange={e => refund.setCustomReason(e.target.value)}
235
+ className="mt-2"
236
+ />
237
+ )}
238
+ </div>
239
+
240
+ {/* Refund Total */}
241
+ <div className="space-y-2">
242
+ <div className="flex items-center gap-2">
243
+ <Label className="text-base font-medium">
244
+ <Trans>Refund total</Trans>
245
+ </Label>
246
+ <div className="flex items-center gap-2">
247
+ <Checkbox
248
+ checked={refund.manuallySetRefundTotal}
249
+ onCheckedChange={checked => {
250
+ refund.setManuallySetRefundTotal(!!checked);
251
+ if (!checked) {
252
+ const calculated = refund.recalculateRefundTotal();
253
+ refund.onManualRefundTotalChange(calculated);
254
+ }
255
+ }}
256
+ />
257
+ <Label className="font-normal text-sm text-muted-foreground">
258
+ <Trans>Override</Trans>
259
+ </Label>
260
+ </div>
261
+ </div>
262
+ <div className="flex items-center gap-2">
263
+ <Input
264
+ type="number"
265
+ step="0.01"
266
+ value={toMajorUnits(refund.refundTotal)}
267
+ onChange={e =>
268
+ refund.onManualRefundTotalChange(
269
+ toMinorUnits(Number.parseFloat(e.target.value) || 0),
270
+ )
271
+ }
272
+ disabled={!refund.manuallySetRefundTotal}
273
+ className="w-32"
274
+ />
275
+ <span className="text-muted-foreground">{order.currencyCode}</span>
276
+ <span className="text-muted-foreground text-sm">
277
+ <Trans>(max: {formatCurrency(refund.totalRefundableAmount, order.currencyCode)})</Trans>
278
+ </span>
279
+ </div>
280
+ </div>
281
+
282
+ {/* Payment Selection */}
283
+ <div className="space-y-2">
284
+ <Label className="text-base font-medium">
285
+ <Trans>Select payments to refund</Trans>
286
+ </Label>
287
+ <div className="space-y-3">
288
+ {refund.refundablePayments.map(payment => (
289
+ <div key={payment.id} className="border rounded-md p-3 space-y-2">
290
+ <div className="flex items-center justify-between">
291
+ <div className="flex items-center gap-2">
292
+ <Checkbox
293
+ checked={payment.selected}
294
+ onCheckedChange={checked =>
295
+ refund.onPaymentSelected(payment.id, !!checked)
296
+ }
297
+ />
298
+ <div>
299
+ <div className="font-medium">{payment.method}</div>
300
+ <div className="text-sm text-muted-foreground">
301
+ <Trans>Available</Trans>:{' '}
302
+ {formatCurrency(
303
+ payment.refundableAmount,
304
+ order.currencyCode,
305
+ )}
306
+ </div>
307
+ </div>
308
+ </div>
309
+ {payment.selected && (
310
+ <div className="flex items-center gap-2">
311
+ <Label className="text-sm">
312
+ <Trans>Amount</Trans>:
313
+ </Label>
314
+ <Input
315
+ type="number"
316
+ step="0.01"
317
+ value={toMajorUnits(payment.amountToRefund)}
318
+ onChange={e =>
319
+ refund.onPaymentAmountChange(
320
+ payment.id,
321
+ toMinorUnits(Number.parseFloat(e.target.value) || 0),
322
+ )
323
+ }
324
+ className="w-24"
325
+ max={toMajorUnits(payment.refundableAmount)}
326
+ />
327
+ <span className="text-muted-foreground text-sm">
328
+ {order.currencyCode}
329
+ </span>
330
+ </div>
331
+ )}
332
+ </div>
333
+ </div>
334
+ ))}
335
+ </div>
336
+ </div>
337
+
338
+ {/* Validation Errors */}
339
+ {refund.validationErrors.length > 0 && (
340
+ <div className="space-y-2">
341
+ {refund.validationErrors.map(error => (
342
+ <Alert key={error} variant="destructive">
343
+ <AlertCircle className="h-4 w-4" />
344
+ <AlertDescription>{error}</AlertDescription>
345
+ </Alert>
346
+ ))}
347
+ </div>
348
+ )}
349
+ </div>
350
+
351
+ <DialogFooter>
352
+ <Button variant="outline" onClick={handleClose} disabled={refund.isSubmitting}>
353
+ <Trans>Cancel</Trans>
354
+ </Button>
355
+ <Button
356
+ onClick={() => void refund.handleSubmit()}
357
+ disabled={!refund.canSubmit || refund.isSubmitting}
358
+ >
359
+ {refund.isSubmitting ? (
360
+ <Trans>Processing...</Trans>
361
+ ) : (
362
+ <Trans>
363
+ Refund {formatCurrency(refund.amountToRefundTotal, order.currencyCode)}
364
+ </Trans>
365
+ )}
366
+ </Button>
367
+ </DialogFooter>
368
+ </DialogContent>
369
+ </Dialog>
370
+ );
371
+ },
372
+ );