@medusajs/draft-order 0.0.1

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 (82) hide show
  1. package/.medusa/server/src/admin/components/common/action-menu.js +77 -0
  2. package/.medusa/server/src/admin/components/common/conditional-tooltip.js +15 -0
  3. package/.medusa/server/src/admin/components/common/data-table.js +249 -0
  4. package/.medusa/server/src/admin/components/common/form.js +151 -0
  5. package/.medusa/server/src/admin/components/common/inline-tip.js +42 -0
  6. package/.medusa/server/src/admin/components/common/keybound-form.js +32 -0
  7. package/.medusa/server/src/admin/components/common/page-skeleton.js +51 -0
  8. package/.medusa/server/src/admin/components/common/thumbnail.js +15 -0
  9. package/.medusa/server/src/admin/components/draft-orders/activity-section.js +205 -0
  10. package/.medusa/server/src/admin/components/draft-orders/customer-section.js +165 -0
  11. package/.medusa/server/src/admin/components/draft-orders/general-section.js +36 -0
  12. package/.medusa/server/src/admin/components/draft-orders/json-view-section.js +140 -0
  13. package/.medusa/server/src/admin/components/draft-orders/metadata-section.js +28 -0
  14. package/.medusa/server/src/admin/components/draft-orders/shipping-section.js +211 -0
  15. package/.medusa/server/src/admin/components/draft-orders/summary-section.js +148 -0
  16. package/.medusa/server/src/admin/components/inputs/combobox.js +311 -0
  17. package/.medusa/server/src/admin/components/inputs/country-select.js +59 -0
  18. package/.medusa/server/src/admin/components/inputs/number-input.js +100 -0
  19. package/.medusa/server/src/admin/components/inputs/switch-block.js +30 -0
  20. package/.medusa/server/src/admin/components/modals/index.js +19 -0
  21. package/.medusa/server/src/admin/components/modals/route-drawer/index.js +4 -0
  22. package/.medusa/server/src/admin/components/modals/route-drawer/route-drawer.js +57 -0
  23. package/.medusa/server/src/admin/components/modals/route-focus-modal/index.js +4 -0
  24. package/.medusa/server/src/admin/components/modals/route-focus-modal/route-focus-modal.js +71 -0
  25. package/.medusa/server/src/admin/components/modals/route-modal-form/index.js +4 -0
  26. package/.medusa/server/src/admin/components/modals/route-modal-form/route-modal-form.js +60 -0
  27. package/.medusa/server/src/admin/components/modals/route-modal-provider/index.js +6 -0
  28. package/.medusa/server/src/admin/components/modals/route-modal-provider/route-modal-context.js +5 -0
  29. package/.medusa/server/src/admin/components/modals/route-modal-provider/route-provider.js +30 -0
  30. package/.medusa/server/src/admin/components/modals/route-modal-provider/use-route-modal.js +12 -0
  31. package/.medusa/server/src/admin/components/modals/stacked-drawer/index.js +5 -0
  32. package/.medusa/server/src/admin/components/modals/stacked-drawer/stacked-drawer.js +55 -0
  33. package/.medusa/server/src/admin/components/modals/stacked-focus-modal/index.js +5 -0
  34. package/.medusa/server/src/admin/components/modals/stacked-focus-modal/stacked-focus-modal.js +63 -0
  35. package/.medusa/server/src/admin/components/modals/stacked-modal-provider/index.js +6 -0
  36. package/.medusa/server/src/admin/components/modals/stacked-modal-provider/stacked-modal-context.js +5 -0
  37. package/.medusa/server/src/admin/components/modals/stacked-modal-provider/stacked-modal-provider.js +47 -0
  38. package/.medusa/server/src/admin/components/modals/stacked-modal-provider/use-stacked-modal.js +14 -0
  39. package/.medusa/server/src/admin/components/utilities/generic-forward-ref.js +7 -0
  40. package/.medusa/server/src/admin/hooks/api/customers.js +53 -0
  41. package/.medusa/server/src/admin/hooks/api/draft-orders.js +161 -0
  42. package/.medusa/server/src/admin/hooks/api/orders.js +274 -0
  43. package/.medusa/server/src/admin/hooks/api/product-variants.js +21 -0
  44. package/.medusa/server/src/admin/hooks/api/regions.js +35 -0
  45. package/.medusa/server/src/admin/hooks/api/sales-channels.js +35 -0
  46. package/.medusa/server/src/admin/hooks/api/shipping-options.js +35 -0
  47. package/.medusa/server/src/admin/hooks/api/users.js +26 -0
  48. package/.medusa/server/src/admin/hooks/common/use-combobox-data.js +61 -0
  49. package/.medusa/server/src/admin/hooks/common/use-data-table-date-filters.js +89 -0
  50. package/.medusa/server/src/admin/hooks/common/use-debounced-search.js +22 -0
  51. package/.medusa/server/src/admin/hooks/common/use-query-params.js +14 -0
  52. package/.medusa/server/src/admin/hooks/order-edits/use-cancel-order-edit.js +25 -0
  53. package/.medusa/server/src/admin/hooks/order-edits/use-initiate-order-edit.js +39 -0
  54. package/.medusa/server/src/admin/lib/data/countries.js +1762 -0
  55. package/.medusa/server/src/admin/lib/data/currencies.js +36 -0
  56. package/.medusa/server/src/admin/lib/queries/draft-order-details.js +1 -0
  57. package/.medusa/server/src/admin/lib/queries/sdk.js +10 -0
  58. package/.medusa/server/src/admin/lib/schemas/address.js +16 -0
  59. package/.medusa/server/src/admin/lib/utils/address-utils.js +57 -0
  60. package/.medusa/server/src/admin/lib/utils/date-utils.js +27 -0
  61. package/.medusa/server/src/admin/lib/utils/order-utils.js +13 -0
  62. package/.medusa/server/src/admin/routes/draft-orders/@create/page.js +659 -0
  63. package/.medusa/server/src/admin/routes/draft-orders/_id_/@billing-address/page.js +228 -0
  64. package/.medusa/server/src/admin/routes/draft-orders/_id_/@custom-items/page.js +38 -0
  65. package/.medusa/server/src/admin/routes/draft-orders/_id_/@email/page.js +89 -0
  66. package/.medusa/server/src/admin/routes/draft-orders/_id_/@items/page.js +576 -0
  67. package/.medusa/server/src/admin/routes/draft-orders/_id_/@metadata/page.js +338 -0
  68. package/.medusa/server/src/admin/routes/draft-orders/_id_/@promotions/page.js +70 -0
  69. package/.medusa/server/src/admin/routes/draft-orders/_id_/@sales-channel/page.js +113 -0
  70. package/.medusa/server/src/admin/routes/draft-orders/_id_/@shipping/page.js +465 -0
  71. package/.medusa/server/src/admin/routes/draft-orders/_id_/@shipping-address/page.js +241 -0
  72. package/.medusa/server/src/admin/routes/draft-orders/_id_/page.js +70 -0
  73. package/.medusa/server/src/admin/routes/draft-orders/page.js +148 -0
  74. package/.medusa/server/src/api/admin/draft-orders/[id]/convert/route.js +18 -0
  75. package/.medusa/server/src/types/http/draft-orders/payloads.js +3 -0
  76. package/.medusa/server/src/types/http/draft-orders/responses.js +3 -0
  77. package/.medusa/server/src/types/http/orders/entity.js +3 -0
  78. package/.medusa/server/src/types/http/orders/requests.js +3 -0
  79. package/.medusa/server/src/workflows/draft-orders/convert-draft-order-workflow.js +54 -0
  80. package/.medusa/server/tailwind.config.js +12 -0
  81. package/README.md +64 -0
  82. package/package.json +104 -0
@@ -0,0 +1,576 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { zodResolver } from "/Users/oliverjuhl/Desktop/medusa/draft-order-plugin/node_modules/@hookform/resolvers/zod/dist/zod.mjs";
3
+ import { useForm } from "react-hook-form";
4
+ import { z } from "/Users/oliverjuhl/Desktop/medusa/draft-order-plugin/node_modules/zod/lib/index.mjs";
5
+ import { Check, PencilSquare } from "@medusajs/icons";
6
+ import { createDataTableColumnHelper, toast, Heading, Text, Divider, Input, Button, IconButton, Tooltip } from "@medusajs/ui";
7
+ import { keepPreviousData } from "@tanstack/react-query";
8
+ import { matchSorter } from "match-sorter";
9
+ import { useState, useMemo, useCallback, useEffect } from "react";
10
+ import { useParams } from "react-router-dom";
11
+ import { DataTable } from "../../../../components/common/data-table.js";
12
+ import { KeyboundForm } from "../../../../components/common/keybound-form.js";
13
+ import { Thumbnail } from "../../../../components/common/thumbnail.js";
14
+ import { NumberInput } from "../../../../components/inputs/number-input.js";
15
+ import { SwitchBlock } from "../../../../components/inputs/switch-block.js";
16
+ import "../../../../components/modals/route-drawer/route-drawer.js";
17
+ import { RouteFocusModal } from "../../../../components/modals/route-focus-modal/route-focus-modal.js";
18
+ import "../../../../components/modals/route-modal-provider/route-modal-context.js";
19
+ import { useRouteModal } from "../../../../components/modals/route-modal-provider/use-route-modal.js";
20
+ import "../../../../components/modals/stacked-drawer/stacked-drawer.js";
21
+ import { StackedFocusModal } from "../../../../components/modals/stacked-focus-modal/stacked-focus-modal.js";
22
+ import "../../../../components/modals/stacked-modal-provider/stacked-modal-context.js";
23
+ import { useStackedModal } from "../../../../components/modals/stacked-modal-provider/use-stacked-modal.js";
24
+ import { useDraftOrder } from "../../../../hooks/api/draft-orders.js";
25
+ import { useOrderPreview, useOrderEditConfirm, useOrderEditRequest, useOrderEditUpdateActionItem, useOrderEditUpdateOriginalItem, useOrderEditRemoveActionItem, useOrderEditAddItems } from "../../../../hooks/api/orders.js";
26
+ import { useProductVariants } from "../../../../hooks/api/product-variants.js";
27
+ import { useDebouncedSearch } from "../../../../hooks/common/use-debounced-search.js";
28
+ import { useQueryParams } from "../../../../hooks/common/use-query-params.js";
29
+ import { useCancelOrderEdit } from "../../../../hooks/order-edits/use-cancel-order-edit.js";
30
+ import { useInitiateOrderEdit } from "../../../../hooks/order-edits/use-initiate-order-edit.js";
31
+ import { getStylizedAmount, getLocaleAmount } from "../../../../lib/data/currencies.js";
32
+ import { getFullDate } from "../../../../lib/utils/date-utils.js";
33
+ const STACKED_MODAL_ID = "items_stacked_modal";
34
+ const Items = () => {
35
+ const { id } = useParams();
36
+ const {
37
+ order: preview,
38
+ isPending: isPreviewPending,
39
+ isError: isPreviewError,
40
+ error: previewError
41
+ } = useOrderPreview(id);
42
+ useInitiateOrderEdit({ preview });
43
+ const { draft_order, isPending, isError, error } = useDraftOrder(
44
+ id,
45
+ {
46
+ fields: "currency_code"
47
+ },
48
+ {
49
+ enabled: !!id
50
+ }
51
+ );
52
+ const { onCancel } = useCancelOrderEdit({ preview });
53
+ if (isError) {
54
+ throw error;
55
+ }
56
+ if (isPreviewError) {
57
+ throw previewError;
58
+ }
59
+ const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
60
+ return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: ready && /* @__PURE__ */ jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) });
61
+ };
62
+ const ItemsForm = ({ preview, currencyCode }) => {
63
+ var _a;
64
+ const [isSubmitting, setIsSubmitting] = useState(false);
65
+ const { handleSuccess } = useRouteModal();
66
+ const { searchValue, onSearchValueChange, query } = useDebouncedSearch();
67
+ const form = useForm({
68
+ defaultValues: {
69
+ notify: false
70
+ },
71
+ resolver: zodResolver(schema)
72
+ });
73
+ const { mutateAsync: confirmOrderEdit } = useOrderEditConfirm(preview.id);
74
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
75
+ const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
76
+ const matches = useMemo(() => {
77
+ return matchSorter(preview.items, query, {
78
+ keys: ["product_title", "variant_title", "variant_sku"]
79
+ });
80
+ }, [preview.items, query]);
81
+ const onSubmit = form.handleSubmit(async (_data) => {
82
+ setIsSubmitting(true);
83
+ let requestSucceeded = false;
84
+ await requestOrderEdit(void 0, {
85
+ onError: (e) => {
86
+ toast.error(`Failed to request order edit: ${e.message}`);
87
+ },
88
+ onSuccess: () => {
89
+ requestSucceeded = true;
90
+ }
91
+ });
92
+ if (!requestSucceeded) {
93
+ setIsSubmitting(false);
94
+ return;
95
+ }
96
+ await confirmOrderEdit(void 0, {
97
+ onError: (e) => {
98
+ toast.error(`Failed to confirm order edit: ${e.message}`);
99
+ },
100
+ onSuccess: () => {
101
+ handleSuccess();
102
+ },
103
+ onSettled: () => {
104
+ setIsSubmitting(false);
105
+ }
106
+ });
107
+ });
108
+ return /* @__PURE__ */ jsx(RouteFocusModal.Form, { form, children: /* @__PURE__ */ jsxs(
109
+ KeyboundForm,
110
+ {
111
+ className: "flex h-full flex-col overflow-hidden",
112
+ onSubmit,
113
+ children: [
114
+ /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
115
+ /* @__PURE__ */ jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs(StackedFocusModal, { id: STACKED_MODAL_ID, children: [
116
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-6 py-16", children: [
117
+ /* @__PURE__ */ jsxs("div", { children: [
118
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Items" }) }),
119
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Edit the items in the draft order." }) })
120
+ ] }),
121
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
122
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
123
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
124
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
125
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
126
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
127
+ ] }),
128
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
129
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
130
+ Input,
131
+ {
132
+ type: "search",
133
+ placeholder: "Search items",
134
+ value: searchValue,
135
+ onChange: (e) => onSearchValueChange(e.target.value)
136
+ }
137
+ ) }),
138
+ /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", children: "Add items" }) })
139
+ ] })
140
+ ] }),
141
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
142
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3 px-4 py-2 text-ui-fg-muted", children: [
143
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
144
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) }),
145
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Price" }) })
146
+ ] }),
147
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
148
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
149
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
150
+ ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxs(
151
+ "div",
152
+ {
153
+ className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center",
154
+ children: [
155
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
156
+ /* @__PURE__ */ jsx(
157
+ Thumbnail,
158
+ {
159
+ thumbnail: item.thumbnail,
160
+ alt: item.product_title ?? void 0
161
+ }
162
+ ),
163
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
164
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
165
+ /* @__PURE__ */ jsx(
166
+ Text,
167
+ {
168
+ size: "small",
169
+ weight: "plus",
170
+ leading: "compact",
171
+ children: item.product_title
172
+ }
173
+ ),
174
+ /* @__PURE__ */ jsxs(
175
+ Text,
176
+ {
177
+ size: "small",
178
+ leading: "compact",
179
+ className: "text-ui-fg-subtle",
180
+ children: [
181
+ "(",
182
+ item.variant_title,
183
+ ")"
184
+ ]
185
+ }
186
+ )
187
+ ] }),
188
+ /* @__PURE__ */ jsx(
189
+ Text,
190
+ {
191
+ size: "small",
192
+ leading: "compact",
193
+ className: "text-ui-fg-subtle",
194
+ children: item.variant_sku
195
+ }
196
+ )
197
+ ] })
198
+ ] }),
199
+ /* @__PURE__ */ jsx(QuantityInput, { orderId: preview.id, item }),
200
+ /* @__PURE__ */ jsx(
201
+ UnitPriceInput,
202
+ {
203
+ orderId: preview.id,
204
+ item,
205
+ currencyCode
206
+ }
207
+ )
208
+ ]
209
+ },
210
+ item.id
211
+ )) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
212
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
213
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
214
+ 'No items found for "',
215
+ query,
216
+ '".'
217
+ ] })
218
+ ] }) })
219
+ ] })
220
+ ] }),
221
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
222
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
223
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
224
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
225
+ Text,
226
+ {
227
+ size: "small",
228
+ leading: "compact",
229
+ className: "text-ui-fg-subtle",
230
+ children: [
231
+ itemCount,
232
+ " ",
233
+ itemCount === 1 ? "item" : "items"
234
+ ]
235
+ }
236
+ ) }),
237
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
238
+ ] }),
239
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
240
+ /* @__PURE__ */ jsx(
241
+ SwitchBlock,
242
+ {
243
+ label: "Send notification",
244
+ description: "Notify the customer that the items have been updated.",
245
+ control: form.control,
246
+ name: "notify"
247
+ }
248
+ )
249
+ ] }) }),
250
+ /* @__PURE__ */ jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items })
251
+ ] }) }),
252
+ /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
253
+ /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
254
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isSubmitting, children: "Save" })
255
+ ] }) })
256
+ ]
257
+ }
258
+ ) });
259
+ };
260
+ const UnitPriceInput = ({
261
+ orderId,
262
+ item,
263
+ currencyCode
264
+ }) => {
265
+ const [unitPrice, setUnitPrice] = useState(item.unit_price);
266
+ const [isEditing, setIsEditing] = useState(false);
267
+ const actionId = useMemo(() => {
268
+ var _a, _b;
269
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
270
+ }, [item]);
271
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useOrderEditUpdateActionItem(orderId);
272
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useOrderEditUpdateOriginalItem(orderId);
273
+ const onSubmit = useCallback(async () => {
274
+ if (unitPrice === item.unit_price) {
275
+ setIsEditing(false);
276
+ return;
277
+ }
278
+ if (!actionId) {
279
+ await updateOriginalItem(
280
+ {
281
+ item_id: item.id,
282
+ quantity: item.quantity,
283
+ unit_price: unitPrice
284
+ },
285
+ {
286
+ onSuccess: () => {
287
+ setIsEditing(false);
288
+ },
289
+ onError: (e) => {
290
+ toast.error(e.message);
291
+ }
292
+ }
293
+ );
294
+ return;
295
+ }
296
+ await updateActionItem(
297
+ {
298
+ action_id: actionId,
299
+ unit_price: unitPrice
300
+ },
301
+ {
302
+ onSuccess: () => {
303
+ setIsEditing(false);
304
+ },
305
+ onError: (e) => {
306
+ toast.error(e.message);
307
+ }
308
+ }
309
+ );
310
+ }, [item, actionId, updateActionItem, updateOriginalItem, unitPrice]);
311
+ const onChange = useCallback((e) => {
312
+ const value = e.target.value;
313
+ if (value === "") {
314
+ setUnitPrice(null);
315
+ }
316
+ const unitPrice2 = parseFloat(value);
317
+ if (isNaN(unitPrice2)) {
318
+ return;
319
+ }
320
+ setUnitPrice(unitPrice2);
321
+ }, []);
322
+ const isLoading = isUpdatingActionItem || isUpdatingOriginalItem;
323
+ return isEditing ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-3", children: [
324
+ /* @__PURE__ */ jsx(
325
+ Input,
326
+ {
327
+ size: "small",
328
+ type: "number",
329
+ value: unitPrice || "",
330
+ onChange
331
+ }
332
+ ),
333
+ /* @__PURE__ */ jsx(
334
+ IconButton,
335
+ {
336
+ className: "shrink-0",
337
+ type: "button",
338
+ size: "small",
339
+ onClick: onSubmit,
340
+ isLoading,
341
+ children: /* @__PURE__ */ jsx(Check, {})
342
+ }
343
+ )
344
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-3", children: [
345
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }),
346
+ /* @__PURE__ */ jsx(IconButton, { type: "button", size: "small", onClick: () => setIsEditing(true), children: /* @__PURE__ */ jsx(PencilSquare, {}) })
347
+ ] });
348
+ };
349
+ const QuantityInput = ({ orderId, item }) => {
350
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useOrderEditUpdateActionItem(orderId);
351
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useOrderEditUpdateOriginalItem(orderId);
352
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useOrderEditRemoveActionItem(orderId);
353
+ const onChange = useCallback(
354
+ async (quantity) => {
355
+ var _a, _b;
356
+ if (quantity === item.quantity) {
357
+ return;
358
+ }
359
+ const actionId = (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
360
+ if (actionId) {
361
+ if (quantity === 0) {
362
+ await removeActionItem(actionId, {
363
+ onError: (e) => {
364
+ toast.error(e.message);
365
+ }
366
+ });
367
+ return;
368
+ }
369
+ await updateActionItem(
370
+ {
371
+ action_id: actionId,
372
+ quantity
373
+ },
374
+ {
375
+ onError: (e) => {
376
+ toast.error(e.message);
377
+ }
378
+ }
379
+ );
380
+ return;
381
+ }
382
+ await updateOriginalItem(
383
+ {
384
+ item_id: item.id,
385
+ quantity
386
+ },
387
+ {
388
+ onError: (e) => {
389
+ toast.error(e.message);
390
+ }
391
+ }
392
+ );
393
+ },
394
+ [item, updateActionItem, updateOriginalItem, removeActionItem]
395
+ );
396
+ return /* @__PURE__ */ jsx(
397
+ NumberInput,
398
+ {
399
+ value: item.quantity,
400
+ onChange,
401
+ disabled: isUpdatingActionItem || isUpdatingOriginalItem || isRemovingActionItem
402
+ }
403
+ );
404
+ };
405
+ const VARIANT_PREFIX = "items";
406
+ const LIMIT = 50;
407
+ const ExistingItemsForm = ({ orderId, items }) => {
408
+ const { setIsOpen } = useStackedModal();
409
+ const [rowSelection, setRowSelection] = useState(
410
+ items.reduce((acc, item) => {
411
+ acc[item.variant_id] = true;
412
+ return acc;
413
+ }, {})
414
+ );
415
+ useEffect(() => {
416
+ setRowSelection(
417
+ items.reduce((acc, item) => {
418
+ acc[item.variant_id] = true;
419
+ return acc;
420
+ }, {})
421
+ );
422
+ }, [items]);
423
+ const queryParams = useQueryParams(["q", "order"], VARIANT_PREFIX);
424
+ const { variants, count, isPending, isError, error } = useProductVariants(
425
+ {
426
+ ...queryParams,
427
+ limit: LIMIT
428
+ },
429
+ {
430
+ placeholderData: keepPreviousData
431
+ }
432
+ );
433
+ const columns = useColumns();
434
+ const { mutateAsync } = useOrderEditAddItems(orderId);
435
+ const onSubmit = async () => {
436
+ const ids = Object.keys(rowSelection).filter(
437
+ (id) => !items.find((i) => i.variant_id === id)
438
+ );
439
+ await mutateAsync(
440
+ {
441
+ items: ids.map((id) => ({
442
+ variant_id: id,
443
+ quantity: 1
444
+ }))
445
+ },
446
+ {
447
+ onSuccess: () => {
448
+ setRowSelection({});
449
+ setIsOpen(STACKED_MODAL_ID, false);
450
+ },
451
+ onError: (e) => {
452
+ toast.error(e.message);
453
+ }
454
+ }
455
+ );
456
+ };
457
+ if (isError) {
458
+ throw error;
459
+ }
460
+ return /* @__PURE__ */ jsxs(
461
+ StackedFocusModal.Content,
462
+ {
463
+ onOpenAutoFocus: (e) => {
464
+ e.preventDefault();
465
+ const searchInput = document.querySelector(
466
+ "[data-modal-id='modal-search-input']"
467
+ );
468
+ if (searchInput) {
469
+ searchInput.focus();
470
+ }
471
+ },
472
+ children: [
473
+ /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
474
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
475
+ /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose which product variants to add to the order." }) })
476
+ ] }),
477
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
478
+ DataTable,
479
+ {
480
+ data: variants,
481
+ columns,
482
+ isLoading: isPending,
483
+ getRowId: (row) => row.id,
484
+ rowCount: count,
485
+ prefix: VARIANT_PREFIX,
486
+ layout: "fill",
487
+ rowSelection: {
488
+ state: rowSelection,
489
+ onRowSelectionChange: setRowSelection,
490
+ enableRowSelection: (row) => {
491
+ return !items.find((i) => i.variant_id === row.original.id);
492
+ }
493
+ },
494
+ autoFocusSearch: true
495
+ }
496
+ ) }),
497
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
498
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
499
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
500
+ ] }) })
501
+ ]
502
+ }
503
+ );
504
+ };
505
+ const columnHelper = createDataTableColumnHelper();
506
+ const useColumns = () => {
507
+ return useMemo(() => {
508
+ return [
509
+ columnHelper.select(),
510
+ columnHelper.accessor("product.title", {
511
+ header: "Product",
512
+ cell: ({ row }) => {
513
+ var _a, _b, _c;
514
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
515
+ /* @__PURE__ */ jsx(
516
+ Thumbnail,
517
+ {
518
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
519
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
520
+ }
521
+ ),
522
+ /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
523
+ ] });
524
+ },
525
+ enableSorting: true
526
+ }),
527
+ columnHelper.accessor("title", {
528
+ header: "Variant",
529
+ enableSorting: true
530
+ }),
531
+ columnHelper.accessor("sku", {
532
+ header: "SKU",
533
+ cell: ({ getValue }) => {
534
+ return getValue() ?? "-";
535
+ },
536
+ enableSorting: true
537
+ }),
538
+ columnHelper.accessor("updated_at", {
539
+ header: "Updated",
540
+ cell: ({ getValue }) => {
541
+ return /* @__PURE__ */ jsx(
542
+ Tooltip,
543
+ {
544
+ content: getFullDate({ date: getValue(), includeTime: true }),
545
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
546
+ }
547
+ );
548
+ },
549
+ enableSorting: true,
550
+ sortAscLabel: "Oldest first",
551
+ sortDescLabel: "Newest first"
552
+ }),
553
+ columnHelper.accessor("created_at", {
554
+ header: "Created",
555
+ cell: ({ getValue }) => {
556
+ return /* @__PURE__ */ jsx(
557
+ Tooltip,
558
+ {
559
+ content: getFullDate({ date: getValue(), includeTime: true }),
560
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
561
+ }
562
+ );
563
+ },
564
+ enableSorting: true,
565
+ sortAscLabel: "Oldest first",
566
+ sortDescLabel: "Newest first"
567
+ })
568
+ ];
569
+ }, []);
570
+ };
571
+ const schema = z.object({
572
+ notify: z.boolean()
573
+ });
574
+ export {
575
+ Items as default
576
+ };