@vendure/dashboard 3.5.0-minor-202510031341 → 3.5.0-minor-202510161257

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 (220) hide show
  1. package/dist/plugin/dashboard.plugin.js +1 -1
  2. package/dist/plugin/default-page.html +1 -1
  3. package/dist/vite/utils/ast-utils.spec.js +3 -3
  4. package/dist/vite/utils/tsconfig-utils.js +2 -1
  5. package/dist/vite/vite-plugin-hmr.d.ts +8 -0
  6. package/dist/vite/vite-plugin-hmr.js +34 -0
  7. package/dist/vite/vite-plugin-theme.js +6 -6
  8. package/dist/vite/vite-plugin-transform-index.js +6 -1
  9. package/dist/vite/vite-plugin-vendure-dashboard.d.ts +31 -4
  10. package/dist/vite/vite-plugin-vendure-dashboard.js +89 -34
  11. package/package.json +18 -5
  12. package/src/app/app-providers.tsx +4 -1
  13. package/src/app/common/map-faceted-filter-fields.ts +21 -0
  14. package/src/app/main.tsx +3 -1
  15. package/src/app/routes/_authenticated/_administrators/administrators.graphql.ts +2 -2
  16. package/src/app/routes/_authenticated/_administrators/administrators.tsx +13 -3
  17. package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +6 -13
  18. package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +1 -1
  19. package/src/app/routes/_authenticated/_assets/assets.tsx +17 -1
  20. package/src/app/routes/_authenticated/_collections/collections.graphql.ts +1 -0
  21. package/src/app/routes/_authenticated/_collections/collections.tsx +5 -0
  22. package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +0 -1
  23. package/src/app/routes/_authenticated/_customers/customers.tsx +9 -5
  24. package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +0 -6
  25. package/src/app/routes/_authenticated/_facets/components/facet-value-bulk-actions.tsx +16 -0
  26. package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +43 -12
  27. package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +14 -5
  28. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +4 -8
  29. package/src/app/routes/_authenticated/_global-settings/utils/global-languages.ts +268 -0
  30. package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +117 -92
  31. package/src/app/routes/_authenticated/_orders/components/order-address.tsx +15 -15
  32. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +5 -5
  33. package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +2 -1
  34. package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +26 -27
  35. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +5 -3
  36. package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +6 -9
  37. package/src/app/routes/_authenticated/_orders/orders.graphql.ts +17 -1
  38. package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +48 -281
  39. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +59 -40
  40. package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +73 -0
  41. package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +312 -0
  42. package/src/app/routes/_authenticated/_payment-methods/payment-methods.graphql.ts +2 -2
  43. package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +4 -0
  44. package/src/app/routes/_authenticated/_product-variants/components/add-currency-dropdown.tsx +49 -0
  45. package/src/app/routes/_authenticated/_product-variants/components/add-stock-location-dropdown.tsx +56 -0
  46. package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +12 -0
  47. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +178 -50
  48. package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +0 -6
  49. package/src/app/routes/_authenticated/_products/components/product-variants-table.tsx +0 -11
  50. package/src/app/routes/_authenticated/_products/products.tsx +6 -2
  51. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +4 -8
  52. package/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx +0 -10
  53. package/src/app/routes/_authenticated/_promotions/promotions.graphql.ts +2 -2
  54. package/src/app/routes/_authenticated/_promotions/promotions.tsx +12 -0
  55. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +3 -10
  56. package/src/app/routes/_authenticated/_sellers/sellers.graphql.ts +2 -2
  57. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.graphql.ts +2 -2
  58. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +4 -0
  59. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +4 -10
  60. package/src/app/routes/_authenticated/_stock-locations/stock-locations.graphql.ts +2 -2
  61. package/src/app/routes/_authenticated/_tax-categories/tax-categories.graphql.ts +2 -2
  62. package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +9 -0
  63. package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +1 -0
  64. package/src/app/routes/_authenticated/_zones/zones.graphql.ts +2 -2
  65. package/src/app/routes/login.tsx +2 -2
  66. package/src/i18n/locales/ar.po +420 -289
  67. package/src/i18n/locales/cs.po +420 -289
  68. package/src/i18n/locales/de.po +420 -289
  69. package/src/i18n/locales/en.po +420 -289
  70. package/src/i18n/locales/es.po +420 -289
  71. package/src/i18n/locales/fa.po +420 -289
  72. package/src/i18n/locales/fr.po +468 -337
  73. package/src/i18n/locales/he.po +420 -289
  74. package/src/i18n/locales/hr.po +420 -289
  75. package/src/i18n/locales/it.po +420 -289
  76. package/src/i18n/locales/ja.po +420 -289
  77. package/src/i18n/locales/nb.po +420 -289
  78. package/src/i18n/locales/ne.po +420 -289
  79. package/src/i18n/locales/pl.po +420 -289
  80. package/src/i18n/locales/pt_BR.po +420 -289
  81. package/src/i18n/locales/pt_PT.po +420 -289
  82. package/src/i18n/locales/ru.po +420 -289
  83. package/src/i18n/locales/sv.po +420 -289
  84. package/src/i18n/locales/tr.po +420 -289
  85. package/src/i18n/locales/uk.po +420 -289
  86. package/src/i18n/locales/zh_Hans.po +420 -289
  87. package/src/i18n/locales/zh_Hant.po +420 -289
  88. package/src/lib/components/data-input/affixed-input.stories.tsx +93 -0
  89. package/src/lib/components/data-input/affixed-input.tsx +5 -2
  90. package/src/lib/components/data-input/boolean-input.stories.tsx +102 -0
  91. package/src/lib/components/data-input/checkbox-input.stories.tsx +61 -0
  92. package/src/lib/components/data-input/customer-group-input.tsx +0 -1
  93. package/src/lib/components/data-input/datetime-input.stories.tsx +62 -0
  94. package/src/lib/components/data-input/datetime-input.tsx +27 -13
  95. package/src/lib/components/data-input/default-relation-input.tsx +18 -12
  96. package/src/lib/components/data-input/money-input.stories.tsx +88 -0
  97. package/src/lib/components/data-input/money-input.tsx +7 -11
  98. package/src/lib/components/data-input/number-input.stories.tsx +103 -0
  99. package/src/lib/components/data-input/number-input.tsx +16 -5
  100. package/src/lib/components/data-input/password-input.stories.tsx +65 -0
  101. package/src/lib/components/data-input/rich-text-input.stories.tsx +92 -0
  102. package/src/lib/components/data-input/slug-input.stories.tsx +232 -0
  103. package/src/lib/components/data-input/slug-input.tsx +9 -10
  104. package/src/lib/components/data-input/text-input.stories.tsx +52 -0
  105. package/src/lib/components/data-input/textarea-input.stories.tsx +55 -0
  106. package/src/lib/components/data-table/add-filter-menu.tsx +6 -1
  107. package/src/lib/components/data-table/column-header-wrapper.tsx +106 -0
  108. package/src/lib/components/data-table/data-table-bulk-action-item.tsx +11 -9
  109. package/src/lib/components/data-table/data-table-bulk-actions.tsx +4 -4
  110. package/src/lib/components/data-table/data-table-column-header.tsx +17 -14
  111. package/src/lib/components/data-table/data-table-faceted-filter.tsx +33 -11
  112. package/src/lib/components/data-table/data-table-filter-badge-editable.tsx +35 -0
  113. package/src/lib/components/data-table/data-table-filter-badge.tsx +28 -14
  114. package/src/lib/components/data-table/data-table-filter-dialog.tsx +28 -8
  115. package/src/lib/components/data-table/data-table-pagination.tsx +23 -7
  116. package/src/lib/components/data-table/data-table.stories.tsx +249 -0
  117. package/src/lib/components/data-table/data-table.tsx +39 -11
  118. package/src/lib/components/data-table/filters/data-table-datetime-filter.tsx +79 -34
  119. package/src/lib/components/data-table/use-generated-columns.tsx +55 -27
  120. package/src/lib/components/layout/generated-breadcrumbs.tsx +4 -12
  121. package/src/lib/components/layout/nav-user.tsx +19 -13
  122. package/src/lib/components/login/login-form.tsx +39 -123
  123. package/src/lib/components/shared/alerts.tsx +29 -17
  124. package/src/lib/components/shared/asset/asset-bulk-actions.tsx +3 -3
  125. package/src/lib/components/shared/asset/asset-gallery.stories.tsx +76 -0
  126. package/src/lib/components/shared/asset/asset-gallery.tsx +147 -113
  127. package/src/lib/components/shared/asset/asset-picker-dialog.stories.tsx +58 -0
  128. package/src/lib/components/shared/configurable-operation-input.tsx +1 -1
  129. package/src/lib/components/shared/customer-group-selector.tsx +5 -2
  130. package/src/lib/components/shared/detail-page-button.stories.tsx +52 -0
  131. package/src/lib/components/shared/facet-value-selector.stories.tsx +48 -0
  132. package/src/lib/components/shared/facet-value-selector.tsx +130 -34
  133. package/src/lib/components/shared/paginated-list-data-table.stories.tsx +212 -0
  134. package/src/lib/components/shared/paginated-list-data-table.tsx +12 -12
  135. package/src/lib/components/shared/permission-guard.stories.tsx +46 -0
  136. package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +2 -0
  137. package/src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx +8 -4
  138. package/src/lib/components/shared/rich-text-editor/rich-text-editor.tsx +1 -0
  139. package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +40 -0
  140. package/src/lib/components/shared/vendure-image.stories.tsx +167 -0
  141. package/src/lib/components/shared/vendure-image.tsx +6 -7
  142. package/src/lib/components/ui/accordion.stories.tsx +33 -0
  143. package/src/lib/components/ui/alert-dialog.stories.tsx +48 -0
  144. package/src/lib/components/ui/alert.stories.tsx +35 -0
  145. package/src/lib/components/ui/aspect-ratio.stories.tsx +28 -0
  146. package/src/lib/components/ui/badge.stories.tsx +28 -0
  147. package/src/lib/components/ui/breadcrumb.stories.tsx +41 -0
  148. package/src/lib/components/ui/button.stories.tsx +38 -0
  149. package/src/lib/components/ui/calendar.stories.tsx +22 -0
  150. package/src/lib/components/ui/card.stories.tsx +28 -0
  151. package/src/lib/components/ui/carousel.stories.tsx +34 -0
  152. package/src/lib/components/ui/checkbox.stories.tsx +31 -0
  153. package/src/lib/components/ui/collapsible.stories.tsx +39 -0
  154. package/src/lib/components/ui/command.stories.tsx +44 -0
  155. package/src/lib/components/ui/context-menu.stories.tsx +38 -0
  156. package/src/lib/components/ui/dialog.stories.tsx +52 -0
  157. package/src/lib/components/ui/drawer.stories.tsx +50 -0
  158. package/src/lib/components/ui/dropdown-menu.stories.tsx +41 -0
  159. package/src/lib/components/ui/hover-card.stories.tsx +38 -0
  160. package/src/lib/components/ui/input-group.tsx +148 -0
  161. package/src/lib/components/ui/input-otp.stories.tsx +30 -0
  162. package/src/lib/components/ui/input.stories.tsx +38 -0
  163. package/src/lib/components/ui/label.stories.tsx +24 -0
  164. package/src/lib/components/ui/menubar.stories.tsx +53 -0
  165. package/src/lib/components/ui/navigation-menu.stories.tsx +54 -0
  166. package/src/lib/components/ui/pagination.stories.tsx +51 -0
  167. package/src/lib/components/ui/password-input.stories.tsx +32 -0
  168. package/src/lib/components/ui/password-input.tsx +33 -0
  169. package/src/lib/components/ui/popover.stories.tsx +33 -0
  170. package/src/lib/components/ui/progress.stories.tsx +27 -0
  171. package/src/lib/components/ui/radio-group.stories.tsx +34 -0
  172. package/src/lib/components/ui/resizable.stories.tsx +32 -0
  173. package/src/lib/components/ui/scroll-area.stories.tsx +31 -0
  174. package/src/lib/components/ui/select.stories.tsx +36 -0
  175. package/src/lib/components/ui/separator.stories.tsx +35 -0
  176. package/src/lib/components/ui/sheet.stories.tsx +50 -0
  177. package/src/lib/components/ui/sidebar-context.ts +16 -0
  178. package/src/lib/components/ui/sidebar.tsx +2 -13
  179. package/src/lib/components/ui/skeleton.stories.tsx +26 -0
  180. package/src/lib/components/ui/slider.stories.tsx +37 -0
  181. package/src/lib/components/ui/switch.stories.tsx +31 -0
  182. package/src/lib/components/ui/table.stories.tsx +52 -0
  183. package/src/lib/components/ui/tabs.stories.tsx +29 -0
  184. package/src/lib/components/ui/textarea.stories.tsx +32 -0
  185. package/src/lib/components/ui/toggle-group.stories.tsx +31 -0
  186. package/src/lib/components/ui/toggle.stories.tsx +39 -0
  187. package/src/lib/components/ui/tooltip.stories.tsx +30 -0
  188. package/src/lib/components/ui/tooltip.tsx +2 -2
  189. package/src/lib/framework/alert/alert-extensions.tsx +0 -11
  190. package/src/lib/framework/alert/alert-item.tsx +14 -19
  191. package/src/lib/framework/alert/alerts-indicator.tsx +14 -15
  192. package/src/lib/framework/alert/search-index-buffer-alert/search-index-buffer-alert.ts +41 -0
  193. package/src/lib/framework/component-registry/component-registry.tsx +3 -14
  194. package/src/lib/framework/dashboard-widget/base-widget.tsx +18 -9
  195. package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +0 -2
  196. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +12 -11
  197. package/src/lib/framework/defaults.ts +9 -13
  198. package/src/lib/framework/extension-api/input-component-extensions.tsx +6 -1
  199. package/src/lib/framework/extension-api/logic/alerts.ts +3 -2
  200. package/src/lib/framework/extension-api/types/alerts.ts +12 -6
  201. package/src/lib/framework/extension-api/types/data-table.ts +5 -2
  202. package/src/lib/framework/extension-api/types/layout.ts +41 -1
  203. package/src/lib/framework/extension-api/types/login.ts +0 -21
  204. package/src/lib/framework/form-engine/value-transformers.ts +8 -1
  205. package/src/lib/framework/layout-engine/custom-form-page.stories.tsx +344 -0
  206. package/src/lib/framework/layout-engine/page-layout.tsx +69 -57
  207. package/src/lib/framework/layout-engine/page.stories.tsx +275 -0
  208. package/src/lib/framework/nav-menu/nav-menu-extensions.ts +32 -19
  209. package/src/lib/framework/page/detail-page.stories.tsx +151 -0
  210. package/src/lib/framework/page/detail-page.tsx +12 -15
  211. package/src/lib/framework/page/list-page.stories.tsx +217 -0
  212. package/src/lib/framework/page/list-page.tsx +8 -1
  213. package/src/lib/graphql/api.ts +18 -1
  214. package/src/lib/graphql/graphql-env.d.ts +1 -1
  215. package/src/lib/hooks/use-alerts.ts +84 -0
  216. package/src/lib/hooks/use-floating-bulk-actions.ts +2 -3
  217. package/src/lib/index.ts +12 -5
  218. package/src/lib/providers/alerts-provider.tsx +60 -0
  219. package/src/lib/providers/channel-provider.tsx +1 -0
  220. package/src/lib/providers/theme-provider.tsx +6 -3
@@ -5,7 +5,7 @@ import { Button } from '@/vdb/components/ui/button.js';
5
5
  import { Input } from '@/vdb/components/ui/input.js';
6
6
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/vdb/components/ui/table.js';
7
7
  import { ResultOf } from '@/vdb/graphql/graphql.js';
8
- import { Trans } from '@lingui/react/macro';
8
+ import { Trans, useLingui } from '@lingui/react/macro';
9
9
  import {
10
10
  ColumnDef,
11
11
  flexRender,
@@ -14,7 +14,7 @@ import {
14
14
  VisibilityState,
15
15
  } from '@tanstack/react-table';
16
16
  import { Trash2 } from 'lucide-react';
17
- import { useState } from 'react';
17
+ import { useMemo, useState } from 'react';
18
18
  import {
19
19
  couponCodeSelectorPromotionListDocument,
20
20
  draftOrderEligibleShippingMethodsDocument,
@@ -44,7 +44,11 @@ export interface OrderTableProps {
44
44
  price?: any;
45
45
  priceWithTax?: any;
46
46
  }) => void;
47
- onAdjustLine: (event: { lineId: string; quantity: number; customFields: Record<string, any> }) => void;
47
+ onAdjustLine: (event: {
48
+ lineId: string;
49
+ quantity: number;
50
+ customFields: Record<string, any> | undefined;
51
+ }) => void;
48
52
  onRemoveLine: (event: { lineId: string }) => void;
49
53
  onSetShippingMethod: (event: { shippingMethodId: string }) => void;
50
54
  onApplyCouponCode: (event: { couponCode: string }) => void;
@@ -53,95 +57,116 @@ export interface OrderTableProps {
53
57
  }
54
58
 
55
59
  export function EditOrderTable({
56
- order,
57
- eligibleShippingMethods,
58
- onAddItem,
59
- onAdjustLine,
60
- onRemoveLine,
61
- onSetShippingMethod,
62
- onApplyCouponCode,
63
- onRemoveCouponCode,
64
- displayTotals = true,
65
- }: Readonly<OrderTableProps>) {
60
+ order,
61
+ eligibleShippingMethods,
62
+ onAddItem,
63
+ onAdjustLine,
64
+ onRemoveLine,
65
+ onSetShippingMethod,
66
+ onApplyCouponCode,
67
+ onRemoveCouponCode,
68
+ displayTotals = true,
69
+ }: Readonly<OrderTableProps>) {
66
70
  const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
71
+ const { t } = useLingui();
67
72
  const currencyCode = order.currencyCode;
68
- const columns: ColumnDef<OrderLineFragment & { customFields?: Record<string, any> }>[] = [
69
- {
70
- header: 'Image',
71
- accessorKey: 'featuredAsset',
72
- cell: ({ row }) => {
73
- const asset = row.original.featuredAsset;
74
- return <VendureImage asset={asset} preset="tiny" />;
73
+ const columns: ColumnDef<OrderLineFragment & { customFields?: Record<string, any> }>[] = useMemo(
74
+ () => [
75
+ {
76
+ header: '',
77
+ accessorKey: 'featuredAsset',
78
+ cell: ({ row }) => {
79
+ const asset = row.original.featuredAsset;
80
+ const removing = row.original.quantity === 0;
81
+ return (
82
+ <VendureImage className={removing ? 'opacity-50' : ''} asset={asset} preset="tiny" />
83
+ );
84
+ },
75
85
  },
76
- },
77
- {
78
- header: 'Product',
79
- accessorKey: 'productVariant.name',
80
- },
81
- {
82
- header: 'SKU',
83
- accessorKey: 'productVariant.sku',
84
- },
85
- {
86
- header: 'Unit price',
87
- accessorKey: 'unitPriceWithTax',
88
- cell: ({ row }) => {
89
- const value = row.original.unitPriceWithTax;
90
- const netValue = row.original.unitPrice;
91
- return <MoneyGrossNet priceWithTax={value} price={netValue} currencyCode={currencyCode} />;
86
+ {
87
+ header: t`Product`,
88
+ accessorKey: 'productVariant.name',
89
+ cell: ({ row }) => {
90
+ const value = row.original.productVariant.name;
91
+ const removing = row.original.quantity === 0;
92
+ return <div className={removing ? 'text-muted-foreground' : ''}>{value}</div>;
93
+ },
92
94
  },
93
- },
94
- {
95
- header: 'Quantity',
96
- accessorKey: 'quantity',
97
- cell: ({ row }) => {
98
- return (
99
- <div className="flex gap-2">
100
- <Input
101
- type="number"
102
- value={row.original.quantity}
103
- onChange={e =>
104
- onAdjustLine({
105
- lineId: row.original.id,
106
- quantity: e.target.valueAsNumber,
107
- customFields: row.original.customFields ?? {},
108
- })
109
- }
110
- />
111
- <Button
112
- variant="outline"
113
- type="button"
114
- size="icon"
115
- onClick={() => onRemoveLine({ lineId: row.original.id })}
116
- >
117
- <Trash2 />
118
- </Button>
119
- {row.original.customFields && (
120
- <OrderLineCustomFieldsForm
121
- onUpdate={customFields => {
95
+ {
96
+ header: t`SKU`,
97
+ accessorKey: 'productVariant.sku',
98
+ },
99
+ {
100
+ header: t`Unit price`,
101
+ accessorKey: 'unitPriceWithTax',
102
+ cell: ({ row }) => {
103
+ const value = row.original.unitPriceWithTax;
104
+ const netValue = row.original.unitPrice;
105
+ return (
106
+ <MoneyGrossNet priceWithTax={value} price={netValue} currencyCode={currencyCode} />
107
+ );
108
+ },
109
+ },
110
+ {
111
+ header: t`Quantity`,
112
+ accessorKey: 'quantity',
113
+ cell: ({ row }) => {
114
+ return (
115
+ <div className="flex gap-2">
116
+ <Input
117
+ type="number"
118
+ value={row.original.quantity}
119
+ min={0}
120
+ onChange={e => {
121
+ const value = Number.isNaN(e.target.valueAsNumber)
122
+ ? 0
123
+ : e.target.valueAsNumber;
122
124
  onAdjustLine({
123
125
  lineId: row.original.id,
124
- quantity: row.original.quantity,
125
- customFields: customFields,
126
+ quantity: value,
127
+ customFields: row.original.customFields,
126
128
  });
127
129
  }}
128
- value={row.original.customFields}
129
130
  />
130
- )}
131
- </div>
132
- );
131
+ <Button
132
+ variant="outline"
133
+ type="button"
134
+ size="icon"
135
+ disabled={row.original.quantity === 0}
136
+ onClick={() => onRemoveLine({ lineId: row.original.id })}
137
+ >
138
+ <Trash2 />
139
+ </Button>
140
+ {row.original.customFields && (
141
+ <OrderLineCustomFieldsForm
142
+ onUpdate={customFields => {
143
+ onAdjustLine({
144
+ lineId: row.original.id,
145
+ quantity: row.original.quantity,
146
+ customFields: customFields,
147
+ });
148
+ }}
149
+ value={row.original.customFields}
150
+ />
151
+ )}
152
+ </div>
153
+ );
154
+ },
133
155
  },
134
- },
135
- {
136
- header: 'Total',
137
- accessorKey: 'linePriceWithTax',
138
- cell: ({ row }) => {
139
- const value = row.original.linePriceWithTax;
140
- const netValue = row.original.linePrice;
141
- return <MoneyGrossNet priceWithTax={value} price={netValue} currencyCode={currencyCode} />;
156
+ {
157
+ header: t`Total`,
158
+ accessorKey: 'linePriceWithTax',
159
+ cell: ({ row }) => {
160
+ const value = row.original.linePriceWithTax;
161
+ const netValue = row.original.linePrice;
162
+ return (
163
+ <MoneyGrossNet priceWithTax={value} price={netValue} currencyCode={currencyCode} />
164
+ );
165
+ },
142
166
  },
143
- },
144
- ];
167
+ ],
168
+ [],
169
+ );
145
170
 
146
171
  const data = order.lines;
147
172
 
@@ -169,9 +194,9 @@ export function EditOrderTable({
169
194
  {header.isPlaceholder
170
195
  ? null
171
196
  : flexRender(
172
- header.column.columnDef.header,
173
- header.getContext(),
174
- )}
197
+ header.column.columnDef.header,
198
+ header.getContext(),
199
+ )}
175
200
  </TableHead>
176
201
  );
177
202
  })}
@@ -181,14 +206,14 @@ export function EditOrderTable({
181
206
  <TableBody>
182
207
  {table.getRowModel().rows?.length
183
208
  ? table.getRowModel().rows.map(row => (
184
- <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
185
- {row.getVisibleCells().map(cell => (
186
- <TableCell key={cell.id}>
187
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
188
- </TableCell>
189
- ))}
190
- </TableRow>
191
- ))
209
+ <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
210
+ {row.getVisibleCells().map(cell => (
211
+ <TableCell key={cell.id}>
212
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
213
+ </TableCell>
214
+ ))}
215
+ </TableRow>
216
+ ))
192
217
  : null}
193
218
  <TableRow>
194
219
  <TableCell colSpan={columns.length} className="h-12">
@@ -1,15 +1,13 @@
1
- import { Separator } from '@/vdb/components/ui/separator.js';
1
+ import { Trans } from '@lingui/react/macro';
2
2
  import { ResultOf } from 'gql.tada';
3
3
  import { Globe, Phone } from 'lucide-react';
4
4
  import { orderAddressFragment } from '../orders.graphql.js';
5
- import { Trans } from '@lingui/react/macro';
6
5
 
7
6
  type OrderAddress = Omit<ResultOf<typeof orderAddressFragment>, 'country'> & {
8
7
  country: string | { code: string; name: string } | null;
9
8
  };
10
9
 
11
10
  export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>) {
12
-
13
11
  const {
14
12
  fullName,
15
13
  company,
@@ -27,7 +25,11 @@ export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>)
27
25
  const countryCodeString = country && typeof country !== 'string' ? country?.code : countryCode;
28
26
 
29
27
  if (!address || Object.values(address).every(value => !value)) {
30
- return <div className="text-sm text-muted-foreground"><Trans>No address</Trans></div>;
28
+ return (
29
+ <div className="text-sm text-muted-foreground">
30
+ <Trans>No address</Trans>
31
+ </div>
32
+ );
31
33
  }
32
34
 
33
35
  return (
@@ -41,7 +43,7 @@ export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>)
41
43
  <p>{[city, province].filter(Boolean).join(', ')}</p>
42
44
  {postalCode && <p>{postalCode}</p>}
43
45
  {country && (
44
- <div className="flex items-center gap-1.5 mt-1">
46
+ <div className="flex items-center gap-1.5">
45
47
  <Globe className="h-3 w-3 text-muted-foreground" />
46
48
  <span>{countryName}</span>
47
49
  {countryCodeString && (
@@ -49,17 +51,15 @@ export function OrderAddress({ address }: Readonly<{ address?: OrderAddress }>)
49
51
  )}
50
52
  </div>
51
53
  )}
54
+ {phoneNumber && (
55
+ <>
56
+ <div className="flex items-center gap-1.5">
57
+ <Phone className="h-3 w-3 text-muted-foreground" />
58
+ <span className="text-sm">{phoneNumber}</span>
59
+ </div>
60
+ </>
61
+ )}
52
62
  </div>
53
-
54
- {phoneNumber && (
55
- <>
56
- <Separator className="my-2" />
57
- <div className="flex items-center gap-1.5">
58
- <Phone className="h-3 w-3 text-muted-foreground" />
59
- <span className="text-sm">{phoneNumber}</span>
60
- </div>
61
- </>
62
- )}
63
63
  </div>
64
64
  );
65
65
  }
@@ -234,14 +234,14 @@ export function OrderDetailShared({
234
234
  {/* Side Column Blocks */}
235
235
  <PageBlock column="side" blockId="state">
236
236
  <StateTransitionControl
237
- currentState={getTranslatedOrderState(entity?.state)}
237
+ currentState={entity?.state}
238
238
  actions={stateTransitionActions}
239
239
  isLoading={transitionOrderToStateMutation.isPending}
240
240
  />
241
241
  </PageBlock>
242
242
  <PageBlock column="side" blockId="customer" title={<Trans>Customer</Trans>}>
243
243
  {entity?.customer ? (
244
- <Button variant="ghost" asChild>
244
+ <Button variant="outline" asChild>
245
245
  <Link to={`/customers/${entity.customer.id}`}>
246
246
  <User className="w-4 h-4" />
247
247
  {entity.customer.firstName} {entity.customer.lastName}
@@ -255,7 +255,7 @@ export function OrderDetailShared({
255
255
  <div className="mt-4 divide-y">
256
256
  {entity?.shippingAddress && (
257
257
  <div className="pb-6">
258
- <div className="font-medium">
258
+ <div className="font-medium mb-6">
259
259
  <Trans>Shipping address</Trans>
260
260
  </div>
261
261
  <OrderAddress address={entity.shippingAddress} />
@@ -263,7 +263,7 @@ export function OrderDetailShared({
263
263
  )}
264
264
  {entity?.billingAddress && (
265
265
  <div className="pt-4">
266
- <div className="font-medium">
266
+ <div className="font-medium mb-6">
267
267
  <Trans>Billing address</Trans>
268
268
  </div>
269
269
  <OrderAddress address={entity.billingAddress} />
@@ -293,7 +293,7 @@ export function OrderDetailShared({
293
293
  ))}
294
294
  </div>
295
295
  ) : (
296
- <div className="text-muted-foreground text-xs font-medium p-3 border rounded-md">
296
+ <div className="text-muted-foreground text-sm">
297
297
  <Trans>No fulfillments</Trans>
298
298
  </div>
299
299
  )}
@@ -42,7 +42,8 @@ export function OrderModificationSummary({
42
42
  if (
43
43
  orig &&
44
44
  (adj.quantity !== orig.quantity ||
45
- JSON.stringify(adj.customFields) !== JSON.stringify((orig as any).customFields))
45
+ JSON.stringify(adj.customFields) !== JSON.stringify((orig as any).customFields)) &&
46
+ adj.quantity > 0
46
47
  ) {
47
48
  return {
48
49
  orderLineId: adj.orderLineId,
@@ -10,40 +10,39 @@ export interface OrderTableTotalsProps {
10
10
 
11
11
  export function OrderTableTotals({ order, columnCount }: Readonly<OrderTableTotalsProps>) {
12
12
  const currencyCode = order.currencyCode;
13
-
14
13
  return (
15
14
  <>
16
15
  {order.surcharges?.length > 0
17
16
  ? order.surcharges.map((surcharge, index) => (
18
- <TableRow key={`${surcharge.description}-${index}`}>
19
- <TableCell colSpan={columnCount - 1} className="h-12">
20
- <Trans>Surcharge</Trans>: {surcharge.description}
21
- </TableCell>
22
- <TableCell colSpan={1} className="h-12">
23
- <MoneyGrossNet
24
- priceWithTax={surcharge.priceWithTax}
25
- price={surcharge.price}
26
- currencyCode={currencyCode}
27
- />
28
- </TableCell>
29
- </TableRow>
30
- ))
17
+ <TableRow key={`${surcharge.description}-${index}`}>
18
+ <TableCell colSpan={columnCount - 1} className="h-12">
19
+ <Trans>Surcharge</Trans>: {surcharge.description}
20
+ </TableCell>
21
+ <TableCell colSpan={1} className="h-12">
22
+ <MoneyGrossNet
23
+ priceWithTax={surcharge.priceWithTax}
24
+ price={surcharge.price}
25
+ currencyCode={currencyCode}
26
+ />
27
+ </TableCell>
28
+ </TableRow>
29
+ ))
31
30
  : null}
32
31
  {order.discounts?.length > 0
33
32
  ? order.discounts.map((discount, index) => (
34
- <TableRow key={`${discount.description}-${index}`}>
35
- <TableCell colSpan={columnCount - 1} className="h-12">
36
- <Trans>Discount</Trans>: {discount.description}
37
- </TableCell>
38
- <TableCell colSpan={1} className="h-12">
39
- <MoneyGrossNet
40
- priceWithTax={discount.amountWithTax}
41
- price={discount.amount}
42
- currencyCode={currencyCode}
43
- />
44
- </TableCell>
45
- </TableRow>
46
- ))
33
+ <TableRow key={`${discount.description}-${index}`}>
34
+ <TableCell colSpan={columnCount - 1} className="h-12">
35
+ <Trans>Discount</Trans>: {discount.description}
36
+ </TableCell>
37
+ <TableCell colSpan={1} className="h-12">
38
+ <MoneyGrossNet
39
+ priceWithTax={discount.amountWithTax}
40
+ price={discount.amount}
41
+ currencyCode={currencyCode}
42
+ />
43
+ </TableCell>
44
+ </TableRow>
45
+ ))
47
46
  : null}
48
47
  <TableRow>
49
48
  <TableCell colSpan={columnCount - 1} className="h-12">
@@ -34,7 +34,10 @@ function createCustomizeColumns(currencyCode: string) {
34
34
  accessorKey: 'featuredAsset',
35
35
  cell: ({ row }: { row: any }) => {
36
36
  const asset = row.original.featuredAsset;
37
- return <VendureImage asset={asset} preset="tiny" />;
37
+ const fallbackAsset =
38
+ row.original.productVariant?.featuredAsset ??
39
+ row.original.productVariant?.product?.featuredAsset;
40
+ return <VendureImage asset={asset ?? fallbackAsset} preset="tiny" />;
38
41
  },
39
42
  },
40
43
  productVariant: {
@@ -154,14 +157,13 @@ export function OrderTable({ order, pageId }: Readonly<OrderTableProps>) {
154
157
  customizeColumns: customizeColumns as any,
155
158
  deleteMutation: undefined,
156
159
  defaultColumnOrder: columnOrder,
157
- additionalColumns: {},
158
160
  includeSelectionColumn: false,
159
161
  includeActionsColumn: false,
160
162
  enableSorting: false,
161
163
  });
162
164
 
163
165
  const columnVisibility = getColumnVisibility(columns, defaultColumnVisibility, customFieldColumnNames);
164
- const visibleColumnCount = Object.values(columnVisibility).filter(Boolean).length;
166
+ const visibleColumnCount = Object.values(columnVisibility).filter(Boolean).length - 2; // -2 for "actions" and "selection" cols
165
167
  const data = order.lines;
166
168
 
167
169
  return (
@@ -5,9 +5,10 @@ import {
5
5
  DropdownMenuItem,
6
6
  DropdownMenuTrigger,
7
7
  } from '@/vdb/components/ui/dropdown-menu.js';
8
- import { Trans } from '@lingui/react/macro';
8
+ import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
9
9
  import { cn } from '@/vdb/lib/utils.js';
10
- import { EllipsisVertical, CircleDashed, CircleCheck, CircleX } from 'lucide-react';
10
+ import { Trans } from '@lingui/react/macro';
11
+ import { CircleCheck, CircleDashed, CircleX, EllipsisVertical } from 'lucide-react';
11
12
 
12
13
  export type StateType = 'default' | 'destructive' | 'success';
13
14
 
@@ -44,6 +45,7 @@ export function StateTransitionControl({
44
45
  actions,
45
46
  isLoading,
46
47
  }: Readonly<StateTransitionControlProps>) {
48
+ const { getTranslatedOrderState } = useDynamicTranslations();
47
49
  const currentStateType = getTypeForState(currentState);
48
50
  const iconForType = {
49
51
  destructive: <CircleX className="h-4 w-4 text-destructive" />,
@@ -61,9 +63,7 @@ export function StateTransitionControl({
61
63
  title={currentState}
62
64
  >
63
65
  <div className="flex-shrink-0">{iconForType[currentStateType]}</div>
64
- <span className="truncate">
65
- {currentState}
66
- </span>
66
+ <span className="truncate">{getTranslatedOrderState(currentState)}</span>
67
67
  </div>
68
68
  {actions.length > 0 && (
69
69
  <DropdownMenu>
@@ -72,10 +72,7 @@ export function StateTransitionControl({
72
72
  variant="outline"
73
73
  size="sm"
74
74
  disabled={isLoading}
75
- className={cn(
76
- 'rounded-l-none border-l-0 shadow-none',
77
- 'bg-background',
78
- )}
75
+ className={cn('rounded-l-none border-l-0 shadow-none', 'bg-background')}
79
76
  >
80
77
  <EllipsisVertical className="h-4 w-4" />
81
78
  </Button>
@@ -638,8 +638,24 @@ export const modifyOrderDocument = graphql(
638
638
  mutation ModifyOrder($input: ModifyOrderInput!) {
639
639
  modifyOrder(input: $input) {
640
640
  __typename
641
- ...OrderDetail
642
641
  ...ErrorResult
642
+ ... on Order {
643
+ lines {
644
+ productVariant {
645
+ featuredAsset {
646
+ id
647
+ preview
648
+ }
649
+ product {
650
+ featuredAsset {
651
+ id
652
+ preview
653
+ }
654
+ }
655
+ }
656
+ }
657
+ }
658
+ ...OrderDetail
643
659
  }
644
660
  }
645
661
  `,