@vendure/dashboard 3.5.0-minor-202510071456 → 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.
- package/dist/plugin/dashboard.plugin.js +1 -1
- package/dist/vite/utils/ast-utils.spec.js +3 -3
- package/dist/vite/vite-plugin-hmr.d.ts +8 -0
- package/dist/vite/vite-plugin-hmr.js +34 -0
- package/dist/vite/vite-plugin-theme.js +6 -6
- package/dist/vite/vite-plugin-transform-index.js +6 -1
- package/dist/vite/vite-plugin-vendure-dashboard.d.ts +31 -4
- package/dist/vite/vite-plugin-vendure-dashboard.js +89 -34
- package/package.json +17 -5
- package/src/app/app-providers.tsx +4 -1
- package/src/app/common/map-faceted-filter-fields.ts +21 -0
- package/src/app/main.tsx +3 -1
- package/src/app/routes/_authenticated/_administrators/administrators.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_administrators/administrators.tsx +13 -3
- package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +6 -13
- package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +1 -1
- package/src/app/routes/_authenticated/_assets/assets.tsx +17 -1
- package/src/app/routes/_authenticated/_collections/collections.graphql.ts +1 -0
- package/src/app/routes/_authenticated/_collections/collections.tsx +5 -0
- package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +0 -1
- package/src/app/routes/_authenticated/_customers/customers.tsx +9 -5
- package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +0 -6
- package/src/app/routes/_authenticated/_facets/components/facet-value-bulk-actions.tsx +16 -0
- package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +43 -12
- package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +14 -5
- package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +117 -92
- package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +1 -1
- package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +2 -1
- package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +26 -27
- package/src/app/routes/_authenticated/_orders/components/order-table.tsx +5 -3
- package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +6 -9
- package/src/app/routes/_authenticated/_orders/orders.graphql.ts +17 -1
- package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +48 -281
- package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +59 -40
- package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +73 -0
- package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +312 -0
- package/src/app/routes/_authenticated/_payment-methods/payment-methods.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +4 -0
- package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +0 -6
- package/src/app/routes/_authenticated/_products/products.tsx +6 -2
- package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +4 -8
- package/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx +0 -10
- package/src/app/routes/_authenticated/_promotions/promotions.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_promotions/promotions.tsx +12 -0
- package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +6 -2
- package/src/app/routes/_authenticated/_sellers/sellers.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +4 -0
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +4 -10
- package/src/app/routes/_authenticated/_stock-locations/stock-locations.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_tax-categories/tax-categories.graphql.ts +2 -2
- package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +9 -0
- package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +1 -0
- package/src/app/routes/_authenticated/_zones/zones.graphql.ts +2 -2
- package/src/app/routes/login.tsx +2 -2
- package/src/i18n/locales/ar.po +420 -289
- package/src/i18n/locales/cs.po +420 -289
- package/src/i18n/locales/de.po +420 -289
- package/src/i18n/locales/en.po +420 -289
- package/src/i18n/locales/es.po +420 -289
- package/src/i18n/locales/fa.po +420 -289
- package/src/i18n/locales/fr.po +468 -337
- package/src/i18n/locales/he.po +420 -289
- package/src/i18n/locales/hr.po +420 -289
- package/src/i18n/locales/it.po +420 -289
- package/src/i18n/locales/ja.po +420 -289
- package/src/i18n/locales/nb.po +420 -289
- package/src/i18n/locales/ne.po +420 -289
- package/src/i18n/locales/pl.po +420 -289
- package/src/i18n/locales/pt_BR.po +420 -289
- package/src/i18n/locales/pt_PT.po +420 -289
- package/src/i18n/locales/ru.po +420 -289
- package/src/i18n/locales/sv.po +420 -289
- package/src/i18n/locales/tr.po +420 -289
- package/src/i18n/locales/uk.po +420 -289
- package/src/i18n/locales/zh_Hans.po +420 -289
- package/src/i18n/locales/zh_Hant.po +420 -289
- package/src/lib/components/data-input/affixed-input.stories.tsx +93 -0
- package/src/lib/components/data-input/affixed-input.tsx +5 -2
- package/src/lib/components/data-input/boolean-input.stories.tsx +102 -0
- package/src/lib/components/data-input/checkbox-input.stories.tsx +61 -0
- package/src/lib/components/data-input/datetime-input.stories.tsx +62 -0
- package/src/lib/components/data-input/datetime-input.tsx +27 -13
- package/src/lib/components/data-input/default-relation-input.tsx +18 -12
- package/src/lib/components/data-input/money-input.stories.tsx +88 -0
- package/src/lib/components/data-input/number-input.stories.tsx +103 -0
- package/src/lib/components/data-input/number-input.tsx +10 -4
- package/src/lib/components/data-input/password-input.stories.tsx +65 -0
- package/src/lib/components/data-input/rich-text-input.stories.tsx +92 -0
- package/src/lib/components/data-input/slug-input.stories.tsx +232 -0
- package/src/lib/components/data-input/slug-input.tsx +9 -10
- package/src/lib/components/data-input/text-input.stories.tsx +52 -0
- package/src/lib/components/data-input/textarea-input.stories.tsx +55 -0
- package/src/lib/components/data-table/add-filter-menu.tsx +6 -1
- package/src/lib/components/data-table/column-header-wrapper.tsx +106 -0
- package/src/lib/components/data-table/data-table-bulk-action-item.tsx +11 -9
- package/src/lib/components/data-table/data-table-bulk-actions.tsx +4 -4
- package/src/lib/components/data-table/data-table-column-header.tsx +17 -14
- package/src/lib/components/data-table/data-table-faceted-filter.tsx +33 -11
- package/src/lib/components/data-table/data-table-filter-badge-editable.tsx +35 -0
- package/src/lib/components/data-table/data-table-filter-badge.tsx +23 -16
- package/src/lib/components/data-table/data-table-filter-dialog.tsx +28 -8
- package/src/lib/components/data-table/data-table-pagination.tsx +23 -7
- package/src/lib/components/data-table/data-table.stories.tsx +249 -0
- package/src/lib/components/data-table/data-table.tsx +37 -9
- package/src/lib/components/data-table/filters/data-table-datetime-filter.tsx +79 -34
- package/src/lib/components/data-table/use-generated-columns.tsx +55 -27
- package/src/lib/components/layout/nav-user.tsx +19 -13
- package/src/lib/components/login/login-form.tsx +39 -123
- package/src/lib/components/shared/alerts.tsx +29 -17
- package/src/lib/components/shared/asset/asset-bulk-actions.tsx +3 -3
- package/src/lib/components/shared/asset/asset-gallery.stories.tsx +76 -0
- package/src/lib/components/shared/asset/asset-gallery.tsx +147 -113
- package/src/lib/components/shared/asset/asset-picker-dialog.stories.tsx +58 -0
- package/src/lib/components/shared/customer-group-selector.tsx +5 -2
- package/src/lib/components/shared/detail-page-button.stories.tsx +52 -0
- package/src/lib/components/shared/facet-value-selector.stories.tsx +48 -0
- package/src/lib/components/shared/facet-value-selector.tsx +130 -34
- package/src/lib/components/shared/paginated-list-data-table.stories.tsx +212 -0
- package/src/lib/components/shared/paginated-list-data-table.tsx +12 -12
- package/src/lib/components/shared/permission-guard.stories.tsx +46 -0
- package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +2 -0
- package/src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx +8 -4
- package/src/lib/components/shared/rich-text-editor/rich-text-editor.tsx +1 -0
- package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +40 -0
- package/src/lib/components/shared/vendure-image.stories.tsx +167 -0
- package/src/lib/components/shared/vendure-image.tsx +6 -7
- package/src/lib/components/ui/accordion.stories.tsx +33 -0
- package/src/lib/components/ui/alert-dialog.stories.tsx +48 -0
- package/src/lib/components/ui/alert.stories.tsx +35 -0
- package/src/lib/components/ui/aspect-ratio.stories.tsx +28 -0
- package/src/lib/components/ui/badge.stories.tsx +28 -0
- package/src/lib/components/ui/breadcrumb.stories.tsx +41 -0
- package/src/lib/components/ui/button.stories.tsx +38 -0
- package/src/lib/components/ui/calendar.stories.tsx +22 -0
- package/src/lib/components/ui/card.stories.tsx +28 -0
- package/src/lib/components/ui/carousel.stories.tsx +34 -0
- package/src/lib/components/ui/checkbox.stories.tsx +31 -0
- package/src/lib/components/ui/collapsible.stories.tsx +39 -0
- package/src/lib/components/ui/command.stories.tsx +44 -0
- package/src/lib/components/ui/context-menu.stories.tsx +38 -0
- package/src/lib/components/ui/dialog.stories.tsx +52 -0
- package/src/lib/components/ui/drawer.stories.tsx +50 -0
- package/src/lib/components/ui/dropdown-menu.stories.tsx +41 -0
- package/src/lib/components/ui/hover-card.stories.tsx +38 -0
- package/src/lib/components/ui/input-group.tsx +148 -0
- package/src/lib/components/ui/input-otp.stories.tsx +30 -0
- package/src/lib/components/ui/input.stories.tsx +38 -0
- package/src/lib/components/ui/label.stories.tsx +24 -0
- package/src/lib/components/ui/menubar.stories.tsx +53 -0
- package/src/lib/components/ui/navigation-menu.stories.tsx +54 -0
- package/src/lib/components/ui/pagination.stories.tsx +51 -0
- package/src/lib/components/ui/password-input.stories.tsx +32 -0
- package/src/lib/components/ui/password-input.tsx +33 -0
- package/src/lib/components/ui/popover.stories.tsx +33 -0
- package/src/lib/components/ui/progress.stories.tsx +27 -0
- package/src/lib/components/ui/radio-group.stories.tsx +34 -0
- package/src/lib/components/ui/resizable.stories.tsx +32 -0
- package/src/lib/components/ui/scroll-area.stories.tsx +31 -0
- package/src/lib/components/ui/select.stories.tsx +36 -0
- package/src/lib/components/ui/separator.stories.tsx +35 -0
- package/src/lib/components/ui/sheet.stories.tsx +50 -0
- package/src/lib/components/ui/sidebar-context.ts +16 -0
- package/src/lib/components/ui/sidebar.tsx +2 -13
- package/src/lib/components/ui/skeleton.stories.tsx +26 -0
- package/src/lib/components/ui/slider.stories.tsx +37 -0
- package/src/lib/components/ui/switch.stories.tsx +31 -0
- package/src/lib/components/ui/table.stories.tsx +52 -0
- package/src/lib/components/ui/tabs.stories.tsx +29 -0
- package/src/lib/components/ui/textarea.stories.tsx +32 -0
- package/src/lib/components/ui/toggle-group.stories.tsx +31 -0
- package/src/lib/components/ui/toggle.stories.tsx +39 -0
- package/src/lib/components/ui/tooltip.stories.tsx +30 -0
- package/src/lib/components/ui/tooltip.tsx +2 -2
- package/src/lib/framework/alert/alert-extensions.tsx +0 -11
- package/src/lib/framework/alert/alert-item.tsx +14 -19
- package/src/lib/framework/alert/alerts-indicator.tsx +14 -15
- package/src/lib/framework/alert/search-index-buffer-alert/search-index-buffer-alert.ts +41 -0
- package/src/lib/framework/component-registry/component-registry.tsx +3 -14
- package/src/lib/framework/dashboard-widget/base-widget.tsx +18 -9
- package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +12 -11
- package/src/lib/framework/defaults.ts +9 -13
- package/src/lib/framework/extension-api/input-component-extensions.tsx +6 -1
- package/src/lib/framework/extension-api/logic/alerts.ts +3 -2
- package/src/lib/framework/extension-api/types/alerts.ts +12 -6
- package/src/lib/framework/extension-api/types/data-table.ts +5 -2
- package/src/lib/framework/extension-api/types/login.ts +0 -21
- package/src/lib/framework/layout-engine/custom-form-page.stories.tsx +344 -0
- package/src/lib/framework/layout-engine/page-layout.tsx +11 -9
- package/src/lib/framework/layout-engine/page.stories.tsx +275 -0
- package/src/lib/framework/nav-menu/nav-menu-extensions.ts +32 -19
- package/src/lib/framework/page/detail-page.stories.tsx +151 -0
- package/src/lib/framework/page/list-page.stories.tsx +217 -0
- package/src/lib/framework/page/list-page.tsx +8 -1
- package/src/lib/graphql/api.ts +18 -1
- package/src/lib/graphql/graphql-env.d.ts +1 -1
- package/src/lib/hooks/use-alerts.ts +84 -0
- package/src/lib/hooks/use-floating-bulk-actions.ts +2 -3
- package/src/lib/index.ts +12 -5
- package/src/lib/providers/alerts-provider.tsx +60 -0
- package/src/lib/providers/theme-provider.tsx +6 -3
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { VariablesOf } from 'gql.tada';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { modifyOrderDocument } from '../orders.graphql.js';
|
|
5
|
+
|
|
6
|
+
import { AddressFragment, Order } from './order-types.js';
|
|
7
|
+
|
|
8
|
+
type ModifyOrderInput = VariablesOf<typeof modifyOrderDocument>['input'];
|
|
9
|
+
|
|
10
|
+
export type ProductVariantInfo = {
|
|
11
|
+
productVariantId: string;
|
|
12
|
+
productVariantName: string;
|
|
13
|
+
sku: string;
|
|
14
|
+
productAsset: {
|
|
15
|
+
preview: string;
|
|
16
|
+
};
|
|
17
|
+
price?: number;
|
|
18
|
+
priceWithTax?: number;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export interface UseModifyOrderReturn {
|
|
22
|
+
modifyOrderInput: ModifyOrderInput;
|
|
23
|
+
addedVariants: Map<string, ProductVariantInfo>;
|
|
24
|
+
addItem: (variant: ProductVariantInfo) => void;
|
|
25
|
+
adjustLine: (params: {
|
|
26
|
+
lineId: string;
|
|
27
|
+
quantity: number;
|
|
28
|
+
customFields: Record<string, any> | undefined;
|
|
29
|
+
}) => void;
|
|
30
|
+
removeLine: (params: { lineId: string }) => void;
|
|
31
|
+
setShippingMethod: (params: { shippingMethodId: string }) => void;
|
|
32
|
+
applyCouponCode: (params: { couponCode: string }) => void;
|
|
33
|
+
removeCouponCode: (params: { couponCode: string }) => void;
|
|
34
|
+
updateShippingAddress: (address: AddressFragment) => void;
|
|
35
|
+
updateBillingAddress: (address: AddressFragment) => void;
|
|
36
|
+
hasModifications: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Custom hook to manage order modification state and operations
|
|
41
|
+
*/
|
|
42
|
+
export function useModifyOrder(order: Order | null | undefined): UseModifyOrderReturn {
|
|
43
|
+
const [modifyOrderInput, setModifyOrderInput] = useState<ModifyOrderInput>({
|
|
44
|
+
orderId: '',
|
|
45
|
+
addItems: [],
|
|
46
|
+
adjustOrderLines: [],
|
|
47
|
+
surcharges: [],
|
|
48
|
+
note: '',
|
|
49
|
+
couponCodes: [],
|
|
50
|
+
options: {
|
|
51
|
+
recalculateShipping: true,
|
|
52
|
+
},
|
|
53
|
+
dryRun: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const [addedVariants, setAddedVariants] = useState<Map<string, ProductVariantInfo>>(new Map());
|
|
57
|
+
|
|
58
|
+
// Sync orderId and couponCodes when order changes
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setModifyOrderInput(prev => ({
|
|
61
|
+
...prev,
|
|
62
|
+
orderId: order?.id ?? '',
|
|
63
|
+
couponCodes: order?.couponCodes ?? [],
|
|
64
|
+
}));
|
|
65
|
+
}, [order?.id]);
|
|
66
|
+
|
|
67
|
+
// Add item or increment existing line
|
|
68
|
+
const addItem = useCallback(
|
|
69
|
+
(variant: ProductVariantInfo) => {
|
|
70
|
+
setModifyOrderInput(prev => {
|
|
71
|
+
const existingLine = order?.lines.find(
|
|
72
|
+
line => line.productVariant.id === variant.productVariantId,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (existingLine) {
|
|
76
|
+
const existingAdjustment = prev.adjustOrderLines?.find(
|
|
77
|
+
adj => adj.orderLineId === existingLine.id,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (existingAdjustment) {
|
|
81
|
+
const newQuantity = existingAdjustment.quantity + 1;
|
|
82
|
+
|
|
83
|
+
// If back to original quantity, remove from adjustments
|
|
84
|
+
if (newQuantity === existingLine.quantity) {
|
|
85
|
+
return {
|
|
86
|
+
...prev,
|
|
87
|
+
adjustOrderLines: (prev.adjustOrderLines ?? []).filter(
|
|
88
|
+
adj => adj.orderLineId !== existingLine.id,
|
|
89
|
+
),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
...prev,
|
|
95
|
+
adjustOrderLines:
|
|
96
|
+
prev.adjustOrderLines?.map(adj =>
|
|
97
|
+
adj.orderLineId === existingLine.id
|
|
98
|
+
? { ...adj, quantity: newQuantity }
|
|
99
|
+
: adj,
|
|
100
|
+
) ?? [],
|
|
101
|
+
};
|
|
102
|
+
} else {
|
|
103
|
+
return {
|
|
104
|
+
...prev,
|
|
105
|
+
adjustOrderLines: [
|
|
106
|
+
...(prev.adjustOrderLines ?? []),
|
|
107
|
+
{ orderLineId: existingLine.id, quantity: existingLine.quantity + 1 },
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
return {
|
|
113
|
+
...prev,
|
|
114
|
+
addItems: [
|
|
115
|
+
...(prev.addItems ?? []),
|
|
116
|
+
{ productVariantId: variant.productVariantId, quantity: 1 },
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
setAddedVariants(prev => {
|
|
123
|
+
const newMap = new Map(prev);
|
|
124
|
+
newMap.set(variant.productVariantId, variant);
|
|
125
|
+
return newMap;
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
[order],
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// Adjust line quantity or custom fields
|
|
132
|
+
const adjustLine = useCallback(
|
|
133
|
+
({
|
|
134
|
+
lineId,
|
|
135
|
+
quantity,
|
|
136
|
+
customFields,
|
|
137
|
+
}: {
|
|
138
|
+
lineId: string;
|
|
139
|
+
quantity: number;
|
|
140
|
+
customFields: Record<string, any> | undefined;
|
|
141
|
+
}) => {
|
|
142
|
+
if (lineId.startsWith('added-')) {
|
|
143
|
+
const productVariantId = lineId.replace('added-', '');
|
|
144
|
+
setModifyOrderInput(prev => ({
|
|
145
|
+
...prev,
|
|
146
|
+
addItems: (prev.addItems ?? []).map(item =>
|
|
147
|
+
item.productVariantId === productVariantId ? { ...item, quantity } : item,
|
|
148
|
+
),
|
|
149
|
+
}));
|
|
150
|
+
} else {
|
|
151
|
+
let normalizedCustomFields: Record<string, any> | undefined = customFields;
|
|
152
|
+
if (normalizedCustomFields) {
|
|
153
|
+
delete normalizedCustomFields.__entityId__;
|
|
154
|
+
}
|
|
155
|
+
if (normalizedCustomFields && Object.keys(normalizedCustomFields).length === 0) {
|
|
156
|
+
normalizedCustomFields = undefined;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
setModifyOrderInput(prev => {
|
|
160
|
+
const originalLine = order?.lines.find(l => l.id === lineId);
|
|
161
|
+
const isBackToOriginal = originalLine && originalLine.quantity === quantity;
|
|
162
|
+
|
|
163
|
+
const originalCustomFields = (originalLine as any)?.customFields;
|
|
164
|
+
const customFieldsChanged =
|
|
165
|
+
JSON.stringify(normalizedCustomFields) !== JSON.stringify(originalCustomFields);
|
|
166
|
+
|
|
167
|
+
const existing = (prev.adjustOrderLines ?? []).find(l => l.orderLineId === lineId);
|
|
168
|
+
|
|
169
|
+
// If back to original and custom fields unchanged, remove from adjustments
|
|
170
|
+
if (isBackToOriginal && !customFieldsChanged) {
|
|
171
|
+
return {
|
|
172
|
+
...prev,
|
|
173
|
+
adjustOrderLines: (prev.adjustOrderLines ?? []).filter(
|
|
174
|
+
l => l.orderLineId !== lineId,
|
|
175
|
+
),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const adjustOrderLines = existing
|
|
180
|
+
? (prev.adjustOrderLines ?? []).map(l =>
|
|
181
|
+
l.orderLineId === lineId
|
|
182
|
+
? { ...l, quantity, customFields: normalizedCustomFields }
|
|
183
|
+
: l,
|
|
184
|
+
)
|
|
185
|
+
: [
|
|
186
|
+
...(prev.adjustOrderLines ?? []),
|
|
187
|
+
{ orderLineId: lineId, quantity, customFields: normalizedCustomFields },
|
|
188
|
+
];
|
|
189
|
+
return { ...prev, adjustOrderLines };
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
[order],
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
// Remove line
|
|
197
|
+
const removeLine = useCallback(({ lineId }: { lineId: string }) => {
|
|
198
|
+
if (lineId.startsWith('added-')) {
|
|
199
|
+
const productVariantId = lineId.replace('added-', '');
|
|
200
|
+
setModifyOrderInput(prev => ({
|
|
201
|
+
...prev,
|
|
202
|
+
addItems: (prev.addItems ?? []).filter(item => item.productVariantId !== productVariantId),
|
|
203
|
+
}));
|
|
204
|
+
setAddedVariants(prev => {
|
|
205
|
+
const newMap = new Map(prev);
|
|
206
|
+
newMap.delete(productVariantId);
|
|
207
|
+
return newMap;
|
|
208
|
+
});
|
|
209
|
+
} else {
|
|
210
|
+
setModifyOrderInput(prev => {
|
|
211
|
+
const existingAdjustment = (prev.adjustOrderLines ?? []).find(l => l.orderLineId === lineId);
|
|
212
|
+
const adjustOrderLines = existingAdjustment
|
|
213
|
+
? (prev.adjustOrderLines ?? []).map(l =>
|
|
214
|
+
l.orderLineId === lineId ? { ...l, quantity: 0 } : l,
|
|
215
|
+
)
|
|
216
|
+
: [...(prev.adjustOrderLines ?? []), { orderLineId: lineId, quantity: 0 }];
|
|
217
|
+
return {
|
|
218
|
+
...prev,
|
|
219
|
+
adjustOrderLines,
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}, []);
|
|
224
|
+
|
|
225
|
+
// Set shipping method
|
|
226
|
+
const setShippingMethod = useCallback(({ shippingMethodId }: { shippingMethodId: string }) => {
|
|
227
|
+
setModifyOrderInput(prev => ({
|
|
228
|
+
...prev,
|
|
229
|
+
shippingMethodIds: [shippingMethodId],
|
|
230
|
+
}));
|
|
231
|
+
}, []);
|
|
232
|
+
|
|
233
|
+
// Apply coupon code
|
|
234
|
+
const applyCouponCode = useCallback(({ couponCode }: { couponCode: string }) => {
|
|
235
|
+
setModifyOrderInput(prev => ({
|
|
236
|
+
...prev,
|
|
237
|
+
couponCodes: prev.couponCodes?.includes(couponCode)
|
|
238
|
+
? prev.couponCodes
|
|
239
|
+
: [...(prev.couponCodes ?? []), couponCode],
|
|
240
|
+
}));
|
|
241
|
+
}, []);
|
|
242
|
+
|
|
243
|
+
// Remove coupon code
|
|
244
|
+
const removeCouponCode = useCallback(({ couponCode }: { couponCode: string }) => {
|
|
245
|
+
setModifyOrderInput(prev => ({
|
|
246
|
+
...prev,
|
|
247
|
+
couponCodes: (prev.couponCodes ?? []).filter(code => code !== couponCode),
|
|
248
|
+
}));
|
|
249
|
+
}, []);
|
|
250
|
+
|
|
251
|
+
// Update shipping address
|
|
252
|
+
const updateShippingAddress = useCallback((address: AddressFragment) => {
|
|
253
|
+
setModifyOrderInput(prev => ({
|
|
254
|
+
...prev,
|
|
255
|
+
updateShippingAddress: {
|
|
256
|
+
streetLine1: address.streetLine1,
|
|
257
|
+
streetLine2: address.streetLine2,
|
|
258
|
+
city: address.city,
|
|
259
|
+
countryCode: address.country.code,
|
|
260
|
+
fullName: address.fullName,
|
|
261
|
+
postalCode: address.postalCode,
|
|
262
|
+
province: address.province,
|
|
263
|
+
company: address.company,
|
|
264
|
+
phoneNumber: address.phoneNumber,
|
|
265
|
+
},
|
|
266
|
+
}));
|
|
267
|
+
}, []);
|
|
268
|
+
|
|
269
|
+
// Update billing address
|
|
270
|
+
const updateBillingAddress = useCallback((address: AddressFragment) => {
|
|
271
|
+
setModifyOrderInput(prev => ({
|
|
272
|
+
...prev,
|
|
273
|
+
updateBillingAddress: {
|
|
274
|
+
streetLine1: address.streetLine1,
|
|
275
|
+
streetLine2: address.streetLine2,
|
|
276
|
+
city: address.city,
|
|
277
|
+
countryCode: address.country.code,
|
|
278
|
+
fullName: address.fullName,
|
|
279
|
+
postalCode: address.postalCode,
|
|
280
|
+
province: address.province,
|
|
281
|
+
company: address.company,
|
|
282
|
+
phoneNumber: address.phoneNumber,
|
|
283
|
+
},
|
|
284
|
+
}));
|
|
285
|
+
}, []);
|
|
286
|
+
|
|
287
|
+
// Check if there are modifications
|
|
288
|
+
const hasModifications = useMemo(() => {
|
|
289
|
+
return (
|
|
290
|
+
(modifyOrderInput.addItems?.length ?? 0) > 0 ||
|
|
291
|
+
(modifyOrderInput.adjustOrderLines?.length ?? 0) > 0 ||
|
|
292
|
+
(modifyOrderInput.couponCodes?.length ?? 0) > 0 ||
|
|
293
|
+
(modifyOrderInput.shippingMethodIds?.length ?? 0) > 0 ||
|
|
294
|
+
!!modifyOrderInput.updateShippingAddress ||
|
|
295
|
+
!!modifyOrderInput.updateBillingAddress
|
|
296
|
+
);
|
|
297
|
+
}, [modifyOrderInput]);
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
modifyOrderInput,
|
|
301
|
+
addedVariants,
|
|
302
|
+
addItem,
|
|
303
|
+
adjustLine,
|
|
304
|
+
removeLine,
|
|
305
|
+
setShippingMethod,
|
|
306
|
+
applyCouponCode,
|
|
307
|
+
removeCouponCode,
|
|
308
|
+
updateShippingAddress,
|
|
309
|
+
updateBillingAddress,
|
|
310
|
+
hasModifications,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
@@ -15,8 +15,8 @@ export const paymentMethodItemFragment = graphql(`
|
|
|
15
15
|
|
|
16
16
|
export const paymentMethodListQuery = graphql(
|
|
17
17
|
`
|
|
18
|
-
query PaymentMethodList {
|
|
19
|
-
paymentMethods {
|
|
18
|
+
query PaymentMethodList($options: PaymentMethodListOptions) {
|
|
19
|
+
paymentMethods(options: $options) {
|
|
20
20
|
items {
|
|
21
21
|
...PaymentMethodItem
|
|
22
22
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BooleanDisplayBadge } from '@/vdb/components/data-display/boolean.js';
|
|
2
2
|
import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
|
|
3
3
|
import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
|
|
4
|
+
import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
|
|
4
5
|
import { Button } from '@/vdb/components/ui/button.js';
|
|
5
6
|
import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
|
|
6
7
|
import { ListPage } from '@/vdb/framework/page/list-page.js';
|
|
@@ -53,6 +54,9 @@ function PaymentMethodListPage() {
|
|
|
53
54
|
enabled: {
|
|
54
55
|
cell: ({ row }) => <BooleanDisplayBadge value={row.original.enabled} />,
|
|
55
56
|
},
|
|
57
|
+
description: {
|
|
58
|
+
cell: RichTextDescriptionCell,
|
|
59
|
+
},
|
|
56
60
|
}}
|
|
57
61
|
bulkActions={[
|
|
58
62
|
{
|
|
@@ -108,12 +108,6 @@ export const DuplicateProductsBulkAction: BulkActionComponent<any> = ({ selectio
|
|
|
108
108
|
<DuplicateBulkAction
|
|
109
109
|
entityType="Product"
|
|
110
110
|
duplicatorCode="product-duplicator"
|
|
111
|
-
duplicatorArguments={[
|
|
112
|
-
{
|
|
113
|
-
name: 'includeVariants',
|
|
114
|
-
value: 'true',
|
|
115
|
-
},
|
|
116
|
-
]}
|
|
117
111
|
requiredPermissions={['UpdateCatalog', 'UpdateProduct']}
|
|
118
112
|
entityName="Product"
|
|
119
113
|
selection={selection}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
|
|
2
2
|
import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
|
|
3
|
+
import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
|
|
3
4
|
import { Button } from '@/vdb/components/ui/button.js';
|
|
4
5
|
import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
|
|
5
6
|
import { ListPage } from '@/vdb/framework/page/list-page.js';
|
|
@@ -7,7 +8,7 @@ import { api } from '@/vdb/graphql/api.js';
|
|
|
7
8
|
import { Trans, useLingui } from '@lingui/react/macro';
|
|
8
9
|
import { useMutation } from '@tanstack/react-query';
|
|
9
10
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
10
|
-
import {
|
|
11
|
+
import { ListRestart, PlusIcon } from 'lucide-react';
|
|
11
12
|
import { toast } from 'sonner';
|
|
12
13
|
import {
|
|
13
14
|
AssignFacetValuesToProductsBulkAction,
|
|
@@ -48,6 +49,9 @@ function ProductListPage() {
|
|
|
48
49
|
name: {
|
|
49
50
|
cell: ({ row }) => <DetailPageButton id={row.original.id} label={row.original.name} />,
|
|
50
51
|
},
|
|
52
|
+
description: {
|
|
53
|
+
cell: RichTextDescriptionCell,
|
|
54
|
+
},
|
|
51
55
|
}}
|
|
52
56
|
onSearchTermChange={searchTerm => {
|
|
53
57
|
return {
|
|
@@ -87,7 +91,7 @@ function ProductListPage() {
|
|
|
87
91
|
<PageActionBarRight>
|
|
88
92
|
<PermissionGuard requires={['UpdateCatalog']}>
|
|
89
93
|
<Button variant="outline" onClick={handleRebuildSearchIndex}>
|
|
90
|
-
<
|
|
94
|
+
<ListRestart />
|
|
91
95
|
<Trans>Rebuild search index</Trans>
|
|
92
96
|
</Button>
|
|
93
97
|
</PermissionGuard>
|
|
@@ -124,11 +124,9 @@ function ProductOptionDetailPage() {
|
|
|
124
124
|
params: { id: params.id },
|
|
125
125
|
onSuccess: async data => {
|
|
126
126
|
toast(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
: 'Successfully updated product option',
|
|
131
|
-
),
|
|
127
|
+
creatingNewEntity
|
|
128
|
+
? t`Successfully created product option`
|
|
129
|
+
: t`Successfully updated product option`,
|
|
132
130
|
);
|
|
133
131
|
resetForm();
|
|
134
132
|
const created = Array.isArray(data) ? data[0] : data;
|
|
@@ -138,9 +136,7 @@ function ProductOptionDetailPage() {
|
|
|
138
136
|
},
|
|
139
137
|
onError: err => {
|
|
140
138
|
toast(
|
|
141
|
-
|
|
142
|
-
creatingNewEntity ? 'Failed to create product option' : 'Failed to update product option',
|
|
143
|
-
),
|
|
139
|
+
creatingNewEntity ? t`Failed to create product option` : t`Failed to update product option`,
|
|
144
140
|
{
|
|
145
141
|
description: err instanceof Error ? err.message : 'Unknown error',
|
|
146
142
|
},
|
|
@@ -63,16 +63,6 @@ export const DuplicatePromotionsBulkAction: BulkActionComponent<any> = ({ select
|
|
|
63
63
|
<DuplicateBulkAction
|
|
64
64
|
entityType="Promotion"
|
|
65
65
|
duplicatorCode="promotion-duplicator"
|
|
66
|
-
duplicatorArguments={[
|
|
67
|
-
{
|
|
68
|
-
name: 'includeConditions',
|
|
69
|
-
value: 'true',
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
name: 'includeActions',
|
|
73
|
-
value: 'true',
|
|
74
|
-
},
|
|
75
|
-
]}
|
|
76
66
|
requiredPermissions={['CreatePromotion']}
|
|
77
67
|
entityName="Promotion"
|
|
78
68
|
selection={selection}
|
|
@@ -2,8 +2,8 @@ import { configurableOperationFragment } from '@/vdb/graphql/fragments.js';
|
|
|
2
2
|
import { graphql } from '@/vdb/graphql/graphql.js';
|
|
3
3
|
|
|
4
4
|
export const promotionListDocument = graphql(`
|
|
5
|
-
query PromotionList {
|
|
6
|
-
promotions {
|
|
5
|
+
query PromotionList($options: PromotionListOptions) {
|
|
6
|
+
promotions(options: $options) {
|
|
7
7
|
items {
|
|
8
8
|
id
|
|
9
9
|
createdAt
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BooleanDisplayBadge } from '@/vdb/components/data-display/boolean.js';
|
|
2
2
|
import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
|
|
3
3
|
import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
|
|
4
|
+
import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
|
|
4
5
|
import { Button } from '@/vdb/components/ui/button.js';
|
|
5
6
|
import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
|
|
6
7
|
import { ListPage } from '@/vdb/framework/page/list-page.js';
|
|
@@ -40,6 +41,14 @@ function PromotionListPage() {
|
|
|
40
41
|
couponCode: { contains: searchTerm },
|
|
41
42
|
};
|
|
42
43
|
}}
|
|
44
|
+
transformVariables={variables => {
|
|
45
|
+
return {
|
|
46
|
+
options: {
|
|
47
|
+
...variables.options,
|
|
48
|
+
filterOperator: 'OR' as const,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}}
|
|
43
52
|
customizeColumns={{
|
|
44
53
|
name: {
|
|
45
54
|
cell: ({ row }) => <DetailPageButton id={row.original.id} label={row.original.name} />,
|
|
@@ -47,6 +56,9 @@ function PromotionListPage() {
|
|
|
47
56
|
enabled: {
|
|
48
57
|
cell: ({ row }) => <BooleanDisplayBadge value={row.original.enabled} />,
|
|
49
58
|
},
|
|
59
|
+
description: {
|
|
60
|
+
cell: RichTextDescriptionCell,
|
|
61
|
+
},
|
|
50
62
|
}}
|
|
51
63
|
bulkActions={[
|
|
52
64
|
{
|
|
@@ -203,13 +203,17 @@ function PromotionDetailPage() {
|
|
|
203
203
|
control={form.control}
|
|
204
204
|
name="perCustomerUsageLimit"
|
|
205
205
|
label={<Trans>Per customer usage limit</Trans>}
|
|
206
|
-
render={({ field }) =>
|
|
206
|
+
render={({ field }) => (
|
|
207
|
+
<NumberInput {...field} value={field.value ?? ''} min={0} max={1000} />
|
|
208
|
+
)}
|
|
207
209
|
/>
|
|
208
210
|
<FormFieldWrapper
|
|
209
211
|
control={form.control}
|
|
210
212
|
name="usageLimit"
|
|
211
213
|
label={<Trans>Usage limit</Trans>}
|
|
212
|
-
render={({ field }) =>
|
|
214
|
+
render={({ field }) => (
|
|
215
|
+
<NumberInput {...field} value={field.value ?? ''} min={0} max={1000} />
|
|
216
|
+
)}
|
|
213
217
|
/>
|
|
214
218
|
</DetailFormGrid>
|
|
215
219
|
</PageBlock>
|
|
@@ -15,8 +15,8 @@ export const shippingMethodItemFragment = graphql(`
|
|
|
15
15
|
|
|
16
16
|
export const shippingMethodListQuery = graphql(
|
|
17
17
|
`
|
|
18
|
-
query ShippingMethodList {
|
|
19
|
-
shippingMethods {
|
|
18
|
+
query ShippingMethodList($options: ShippingMethodListOptions) {
|
|
19
|
+
shippingMethods(options: $options) {
|
|
20
20
|
items {
|
|
21
21
|
...ShippingMethodItem
|
|
22
22
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
|
|
2
2
|
import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
|
|
3
|
+
import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
|
|
3
4
|
import { Button } from '@/vdb/components/ui/button.js';
|
|
4
5
|
import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
|
|
5
6
|
import { ListPage } from '@/vdb/framework/page/list-page.js';
|
|
@@ -35,6 +36,9 @@ function ShippingMethodListPage() {
|
|
|
35
36
|
name: {
|
|
36
37
|
cell: ({ row }) => <DetailPageButton id={row.original.id} label={row.original.name} />,
|
|
37
38
|
},
|
|
39
|
+
description: {
|
|
40
|
+
cell: RichTextDescriptionCell,
|
|
41
|
+
},
|
|
38
42
|
}}
|
|
39
43
|
onSearchTermChange={searchTerm => {
|
|
40
44
|
return {
|
|
@@ -86,11 +86,9 @@ function ShippingMethodDetailPage() {
|
|
|
86
86
|
params: { id: params.id },
|
|
87
87
|
onSuccess: async data => {
|
|
88
88
|
toast.success(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
: 'Successfully updated shipping method',
|
|
93
|
-
),
|
|
89
|
+
creatingNewEntity
|
|
90
|
+
? t`Successfully created shipping method`
|
|
91
|
+
: t`Successfully updated shipping method`,
|
|
94
92
|
);
|
|
95
93
|
resetForm();
|
|
96
94
|
if (creatingNewEntity) {
|
|
@@ -99,11 +97,7 @@ function ShippingMethodDetailPage() {
|
|
|
99
97
|
},
|
|
100
98
|
onError: err => {
|
|
101
99
|
toast.error(
|
|
102
|
-
|
|
103
|
-
creatingNewEntity
|
|
104
|
-
? 'Failed to create shipping method'
|
|
105
|
-
: 'Failed to update shipping method',
|
|
106
|
-
),
|
|
100
|
+
creatingNewEntity ? t`Failed to create shipping method` : t`Failed to update shipping method`,
|
|
107
101
|
{
|
|
108
102
|
description: err instanceof Error ? err.message : 'Unknown error',
|
|
109
103
|
},
|
|
@@ -12,8 +12,8 @@ export const stockLocationFragment = graphql(`
|
|
|
12
12
|
|
|
13
13
|
export const stockLocationListQuery = graphql(
|
|
14
14
|
`
|
|
15
|
-
query StockLocationList {
|
|
16
|
-
stockLocations {
|
|
15
|
+
query StockLocationList($options: StockLocationListOptions) {
|
|
16
|
+
stockLocations(options: $options) {
|
|
17
17
|
items {
|
|
18
18
|
...StockLocationItem
|
|
19
19
|
}
|
|
@@ -12,8 +12,8 @@ export const taxCategoryItemFragment = graphql(`
|
|
|
12
12
|
|
|
13
13
|
export const taxCategoryListQuery = graphql(
|
|
14
14
|
`
|
|
15
|
-
query TaxCategoryList {
|
|
16
|
-
taxCategories {
|
|
15
|
+
query TaxCategoryList($options: TaxCategoryListOptions) {
|
|
16
|
+
taxCategories(options: $options) {
|
|
17
17
|
items {
|
|
18
18
|
...TaxCategoryItem
|
|
19
19
|
}
|
|
@@ -8,6 +8,7 @@ import { api } from '@/vdb/graphql/api.js';
|
|
|
8
8
|
import { Trans, useLingui } from '@lingui/react/macro';
|
|
9
9
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
10
10
|
import { PlusIcon } from 'lucide-react';
|
|
11
|
+
import { mapFacetedFilterFields } from '../../../common/map-faceted-filter-fields.js';
|
|
11
12
|
import { taxCategoryListQuery } from '../_tax-categories/tax-categories.graphql.js';
|
|
12
13
|
import { zoneListQuery } from '../_zones/zones.graphql.js';
|
|
13
14
|
import { DeleteTaxRatesBulkAction } from './components/tax-rate-bulk-actions.js';
|
|
@@ -42,6 +43,14 @@ function TaxRateListPage() {
|
|
|
42
43
|
name: { contains: searchTerm },
|
|
43
44
|
};
|
|
44
45
|
}}
|
|
46
|
+
transformVariables={input => {
|
|
47
|
+
const facetedFilters = input.options?.filter?._and ?? [];
|
|
48
|
+
mapFacetedFilterFields(facetedFilters, {
|
|
49
|
+
category: 'categoryId',
|
|
50
|
+
zone: 'zoneId',
|
|
51
|
+
});
|
|
52
|
+
return input;
|
|
53
|
+
}}
|
|
45
54
|
facetedFilters={{
|
|
46
55
|
enabled: {
|
|
47
56
|
title: t`Enabled`,
|
package/src/app/routes/login.tsx
CHANGED
|
@@ -36,8 +36,8 @@ function LoginPage() {
|
|
|
36
36
|
const isVerifying = isLoading || auth.status === 'verifying';
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
|
-
<div className="flex min-h-svh flex-col items-center justify-center p-6 md:p-10">
|
|
40
|
-
<div className="w-full max-w-sm md:max-w-
|
|
39
|
+
<div className="flex min-h-svh flex-col items-center justify-center p-6 md:p-10 bg-sidebar">
|
|
40
|
+
<div className="w-full max-w-sm md:max-w-md">
|
|
41
41
|
<LoginForm
|
|
42
42
|
onFormSubmit={onFormSubmit}
|
|
43
43
|
isVerifying={isVerifying}
|