@medusajs/draft-order 2.11.1-snapshot-20251021083840 → 2.11.1-snapshot-20251021090705

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.
@@ -9850,1712 +9850,1606 @@ const EmailForm = ({ order }) => {
9850
9850
  const schema$3 = objectType({
9851
9851
  email: stringType().email()
9852
9852
  });
9853
- const NumberInput = React.forwardRef(
9854
- ({
9855
- value,
9856
- onChange,
9857
- size = "base",
9858
- min = 0,
9859
- max = 100,
9860
- step = 1,
9861
- className,
9862
- disabled,
9863
- ...props
9864
- }, ref) => {
9865
- const handleChange = (event) => {
9866
- const newValue = event.target.value === "" ? min : Number(event.target.value);
9867
- if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
9868
- onChange(newValue);
9869
- }
9870
- };
9871
- const handleIncrement = () => {
9872
- const newValue = value + step;
9873
- if (max === void 0 || newValue <= max) {
9874
- onChange(newValue);
9875
- }
9876
- };
9877
- const handleDecrement = () => {
9878
- const newValue = value - step;
9879
- if (min === void 0 || newValue >= min) {
9880
- onChange(newValue);
9881
- }
9882
- };
9853
+ const InlineTip = React.forwardRef(
9854
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
9855
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
9883
9856
  return /* @__PURE__ */ jsxRuntime.jsxs(
9884
9857
  "div",
9885
9858
  {
9859
+ ref,
9886
9860
  className: ui.clx(
9887
- "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
9888
- "[&:has(input:focus)]:shadow-borders-interactive-with-active",
9889
- {
9890
- "h-7": size === "small",
9891
- "h-8": size === "base"
9892
- },
9861
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
9893
9862
  className
9894
9863
  ),
9864
+ ...props,
9895
9865
  children: [
9896
9866
  /* @__PURE__ */ jsxRuntime.jsx(
9897
- "input",
9898
- {
9899
- ref,
9900
- type: "number",
9901
- value,
9902
- onChange: handleChange,
9903
- min,
9904
- max,
9905
- step,
9906
- className: ui.clx(
9907
- "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
9908
- "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
9909
- "placeholder:text-ui-fg-muted"
9910
- ),
9911
- ...props
9912
- }
9913
- ),
9914
- /* @__PURE__ */ jsxRuntime.jsxs(
9915
- "button",
9867
+ "div",
9916
9868
  {
9917
- className: ui.clx(
9918
- "flex items-center justify-center outline-none transition-fg",
9919
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9920
- "focus:bg-ui-bg-field-component-hover",
9921
- "hover:bg-ui-bg-field-component-hover",
9922
- {
9923
- "size-7": size === "small",
9924
- "size-8": size === "base"
9925
- }
9926
- ),
9927
- type: "button",
9928
- onClick: handleDecrement,
9929
- disabled: min !== void 0 && value <= min || disabled,
9930
- children: [
9931
- /* @__PURE__ */ jsxRuntime.jsx(icons.Minus, {}),
9932
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
9933
- ]
9869
+ role: "presentation",
9870
+ className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
9871
+ "bg-ui-tag-orange-icon": variant === "warning"
9872
+ })
9934
9873
  }
9935
9874
  ),
9936
- /* @__PURE__ */ jsxRuntime.jsxs(
9937
- "button",
9938
- {
9939
- className: ui.clx(
9940
- "flex items-center justify-center outline-none transition-fg",
9941
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9942
- "focus:bg-ui-bg-field-hover",
9943
- "hover:bg-ui-bg-field-hover",
9944
- {
9945
- "size-7": size === "small",
9946
- "size-8": size === "base"
9947
- }
9948
- ),
9949
- type: "button",
9950
- onClick: handleIncrement,
9951
- disabled: max !== void 0 && value >= max || disabled,
9952
- children: [
9953
- /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
9954
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Increase by ${step}` })
9955
- ]
9956
- }
9957
- )
9875
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
9876
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
9877
+ labelValue,
9878
+ ":"
9879
+ ] }),
9880
+ " ",
9881
+ children
9882
+ ] })
9958
9883
  ]
9959
9884
  }
9960
9885
  );
9961
9886
  }
9962
9887
  );
9963
- const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
9964
- const productVariantsQueryKeys = {
9965
- list: (query2) => [
9966
- PRODUCT_VARIANTS_QUERY_KEY,
9967
- query2 ? query2 : void 0
9968
- ]
9969
- };
9970
- const useProductVariants = (query2, options) => {
9971
- const { data, ...rest } = reactQuery.useQuery({
9972
- queryKey: productVariantsQueryKeys.list(query2),
9973
- queryFn: async () => await sdk.admin.productVariant.list(query2),
9974
- ...options
9975
- });
9976
- return { ...data, ...rest };
9977
- };
9978
- const useCancelOrderEdit = ({ preview }) => {
9979
- const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
9980
- const onCancel = React.useCallback(async () => {
9981
- if (!preview) {
9982
- return true;
9983
- }
9984
- let res = false;
9985
- await cancelOrderEdit(void 0, {
9986
- onError: (e) => {
9987
- ui.toast.error(e.message);
9988
- },
9989
- onSuccess: () => {
9990
- res = true;
9991
- }
9992
- });
9993
- return res;
9994
- }, [preview, cancelOrderEdit]);
9995
- return { onCancel };
9996
- };
9997
- let IS_REQUEST_RUNNING = false;
9998
- const useInitiateOrderEdit = ({
9999
- preview
10000
- }) => {
10001
- const navigate = reactRouterDom.useNavigate();
10002
- const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10003
- React.useEffect(() => {
10004
- async function run() {
10005
- if (IS_REQUEST_RUNNING || !preview) {
10006
- return;
10007
- }
10008
- if (preview.order_change) {
10009
- return;
10010
- }
10011
- IS_REQUEST_RUNNING = true;
10012
- await mutateAsync(void 0, {
10013
- onError: (e) => {
10014
- ui.toast.error(e.message);
10015
- navigate(`/draft-orders/${preview.id}`, { replace: true });
10016
- return;
10017
- }
10018
- });
10019
- IS_REQUEST_RUNNING = false;
10020
- }
10021
- run();
10022
- }, [preview, navigate, mutateAsync]);
10023
- };
10024
- function convertNumber(value) {
10025
- return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10026
- }
10027
- const STACKED_MODAL_ID = "items_stacked_modal";
10028
- const Items = () => {
9888
+ InlineTip.displayName = "InlineTip";
9889
+ const MetadataFieldSchema = objectType({
9890
+ key: stringType(),
9891
+ disabled: booleanType().optional(),
9892
+ value: anyType()
9893
+ });
9894
+ const MetadataSchema = objectType({
9895
+ metadata: arrayType(MetadataFieldSchema)
9896
+ });
9897
+ const Metadata = () => {
10029
9898
  const { id } = reactRouterDom.useParams();
10030
- const {
10031
- order: preview,
10032
- isPending: isPreviewPending,
10033
- isError: isPreviewError,
10034
- error: previewError
10035
- } = useOrderPreview(id, void 0, {
10036
- placeholderData: reactQuery.keepPreviousData
9899
+ const { order, isPending, isError, error } = useOrder(id, {
9900
+ fields: "metadata"
10037
9901
  });
10038
- useInitiateOrderEdit({ preview });
10039
- const { draft_order, isPending, isError, error } = useDraftOrder(
10040
- id,
10041
- {
10042
- fields: "currency_code"
10043
- },
10044
- {
10045
- enabled: !!id
10046
- }
10047
- );
10048
- const { onCancel } = useCancelOrderEdit({ preview });
10049
9902
  if (isError) {
10050
9903
  throw error;
10051
9904
  }
10052
- if (isPreviewError) {
10053
- throw previewError;
10054
- }
10055
- const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10056
- return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsxRuntime.jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10057
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10058
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10059
- ] }) });
9905
+ const isReady = !isPending && !!order;
9906
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9907
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
9908
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
9909
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
9910
+ ] }),
9911
+ !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
9912
+ ] });
10060
9913
  };
10061
- const ItemsForm = ({ preview, currencyCode }) => {
10062
- var _a;
10063
- const [isSubmitting, setIsSubmitting] = React.useState(false);
10064
- const [modalContent, setModalContent] = React.useState(
10065
- null
10066
- );
9914
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
9915
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
9916
+ const MetadataForm = ({ orderId, metadata }) => {
10067
9917
  const { handleSuccess } = useRouteModal();
10068
- const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10069
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10070
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10071
- const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10072
- const matches = React.useMemo(() => {
10073
- return matchSorter.matchSorter(preview.items, query2, {
10074
- keys: ["product_title", "variant_title", "variant_sku", "title"]
10075
- });
10076
- }, [preview.items, query2]);
10077
- const onSubmit = async () => {
10078
- setIsSubmitting(true);
10079
- let requestSucceeded = false;
10080
- await requestOrderEdit(void 0, {
10081
- onError: (e) => {
10082
- ui.toast.error(`Failed to request order edit: ${e.message}`);
10083
- },
10084
- onSuccess: () => {
10085
- requestSucceeded = true;
10086
- }
10087
- });
10088
- if (!requestSucceeded) {
10089
- setIsSubmitting(false);
10090
- return;
10091
- }
10092
- await confirmOrderEdit(void 0, {
10093
- onError: (e) => {
10094
- ui.toast.error(`Failed to confirm order edit: ${e.message}`);
10095
- },
10096
- onSuccess: () => {
10097
- handleSuccess();
10098
- },
10099
- onSettled: () => {
10100
- setIsSubmitting(false);
10101
- }
10102
- });
10103
- };
10104
- const onKeyDown = React.useCallback(
10105
- (e) => {
10106
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10107
- if (modalContent || isSubmitting) {
10108
- return;
10109
- }
10110
- onSubmit();
10111
- }
10112
- },
10113
- [modalContent, isSubmitting, onSubmit]
10114
- );
10115
- React.useEffect(() => {
10116
- document.addEventListener("keydown", onKeyDown);
10117
- return () => {
10118
- document.removeEventListener("keydown", onKeyDown);
10119
- };
10120
- }, [onKeyDown]);
10121
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10122
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
10123
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
10124
- StackedFocusModal,
10125
- {
10126
- id: STACKED_MODAL_ID,
10127
- onOpenChangeCallback: (open) => {
10128
- if (!open) {
10129
- setModalContent(null);
10130
- }
10131
- },
10132
- children: [
10133
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-6 py-16", children: [
10134
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10135
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Items" }) }),
10136
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Edit the items in the draft order" }) })
10137
- ] }),
10138
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10139
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-6", children: [
10140
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10141
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10142
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10143
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10144
- ] }),
10145
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10146
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10147
- ui.Input,
10148
- {
10149
- type: "search",
10150
- placeholder: "Search items",
10151
- value: searchValue,
10152
- onChange: (e) => onSearchValueChange(e.target.value)
10153
- }
10154
- ) }),
10155
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10156
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { type: "button", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}) }) }),
10157
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
10158
- /* @__PURE__ */ jsxRuntime.jsx(
10159
- StackedModalTrigger$1,
10160
- {
10161
- type: "add-items",
10162
- setModalContent
10163
- }
10164
- ),
10165
- /* @__PURE__ */ jsxRuntime.jsx(
10166
- StackedModalTrigger$1,
10167
- {
10168
- type: "add-custom-item",
10169
- setModalContent
10170
- }
10171
- )
10172
- ] })
10173
- ] })
10174
- ] })
10175
- ] }),
10176
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10177
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[5px]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-muted grid grid-cols-[2fr_1fr_2fr_28px] gap-3 px-4 py-2", children: [
10178
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Item" }) }),
10179
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10180
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Price" }) }),
10181
- /* @__PURE__ */ jsxRuntime.jsx("div", {})
10182
- ] }) }),
10183
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest flex flex-col items-center justify-center gap-1 gap-x-3 rounded-lg p-4", children: [
10184
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10185
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10186
- ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
10187
- Item,
10188
- {
10189
- item,
10190
- preview,
10191
- currencyCode
10192
- },
10193
- item.id
10194
- )) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest flex flex-col items-center justify-center gap-1 gap-x-3 rounded-lg p-4", children: [
10195
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10196
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: [
10197
- 'No items found for "',
10198
- query2,
10199
- '".'
10200
- ] })
10201
- ] }) })
10202
- ] })
10203
- ] }),
10204
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10205
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10206
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10207
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
10208
- ui.Text,
10209
- {
10210
- size: "small",
10211
- leading: "compact",
10212
- className: "text-ui-fg-subtle",
10213
- children: [
10214
- itemCount,
10215
- " ",
10216
- itemCount === 1 ? "item" : "items"
10217
- ]
10218
- }
10219
- ) }),
10220
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
10221
- ] })
10222
- ] }) }),
10223
- modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsxRuntime.jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsxRuntime.jsx(
10224
- CustomItemForm,
10225
- {
10226
- orderId: preview.id,
10227
- currencyCode
10228
- }
10229
- ) : null)
10230
- ]
10231
- }
10232
- ) }),
10233
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10234
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10235
- /* @__PURE__ */ jsxRuntime.jsx(
10236
- ui.Button,
10237
- {
10238
- size: "small",
10239
- type: "button",
10240
- onClick: onSubmit,
10241
- isLoading: isSubmitting,
10242
- children: "Save"
10243
- }
10244
- )
10245
- ] }) })
10246
- ] });
10247
- };
10248
- const Item = ({ item, preview, currencyCode }) => {
10249
- if (item.variant_id) {
10250
- return /* @__PURE__ */ jsxRuntime.jsx(VariantItem, { item, preview, currencyCode });
10251
- }
10252
- return /* @__PURE__ */ jsxRuntime.jsx(CustomItem, { item, preview, currencyCode });
10253
- };
10254
- const VariantItem = ({ item, preview, currencyCode }) => {
10255
- const [editing, setEditing] = React.useState(false);
9918
+ const hasUneditableRows = getHasUneditableRows(metadata);
9919
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10256
9920
  const form = reactHookForm.useForm({
10257
9921
  defaultValues: {
10258
- quantity: item.quantity,
10259
- unit_price: item.unit_price
9922
+ metadata: getDefaultValues(metadata)
10260
9923
  },
10261
- resolver: zod.zodResolver(variantItemSchema)
9924
+ resolver: zod.zodResolver(MetadataSchema)
10262
9925
  });
10263
- const actionId = React.useMemo(() => {
10264
- var _a, _b;
10265
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10266
- }, [item]);
10267
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10268
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10269
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10270
- const onSubmit = form.handleSubmit(async (data) => {
10271
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10272
- setEditing(false);
10273
- return;
10274
- }
10275
- if (!actionId) {
10276
- await updateOriginalItem(
10277
- {
10278
- item_id: item.id,
10279
- quantity: data.quantity,
10280
- unit_price: convertNumber(data.unit_price)
10281
- },
10282
- {
10283
- onSuccess: () => {
10284
- setEditing(false);
10285
- },
10286
- onError: (e) => {
10287
- ui.toast.error(e.message);
10288
- }
10289
- }
10290
- );
10291
- return;
10292
- }
10293
- await updateActionItem(
9926
+ const handleSubmit = form.handleSubmit(async (data) => {
9927
+ const parsedData = parseValues(data);
9928
+ await mutateAsync(
10294
9929
  {
10295
- action_id: actionId,
10296
- quantity: data.quantity,
10297
- unit_price: convertNumber(data.unit_price)
9930
+ metadata: parsedData
10298
9931
  },
10299
9932
  {
10300
9933
  onSuccess: () => {
10301
- setEditing(false);
9934
+ ui.toast.success("Metadata updated");
9935
+ handleSuccess();
10302
9936
  },
10303
- onError: (e) => {
10304
- ui.toast.error(e.message);
9937
+ onError: (error) => {
9938
+ ui.toast.error(error.message);
10305
9939
  }
10306
9940
  }
10307
9941
  );
10308
9942
  });
10309
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
10310
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
10311
- /* @__PURE__ */ jsxRuntime.jsx(
10312
- Thumbnail,
10313
- {
10314
- thumbnail: item.thumbnail,
10315
- alt: item.product_title ?? void 0
10316
- }
10317
- ),
10318
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10319
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-1", children: [
10320
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10321
- /* @__PURE__ */ jsxRuntime.jsxs(
10322
- ui.Text,
10323
- {
10324
- size: "small",
10325
- leading: "compact",
10326
- className: "text-ui-fg-subtle",
10327
- children: [
10328
- "(",
10329
- item.variant_title,
10330
- ")"
10331
- ]
10332
- }
10333
- )
10334
- ] }),
10335
- /* @__PURE__ */ jsxRuntime.jsx(
10336
- ui.Text,
10337
- {
10338
- size: "small",
10339
- leading: "compact",
10340
- className: "text-ui-fg-subtle",
10341
- children: item.variant_sku
10342
- }
10343
- )
10344
- ] })
10345
- ] }),
10346
- editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10347
- Form$2.Field,
10348
- {
10349
- control: form.control,
10350
- name: "quantity",
10351
- render: ({ field }) => {
10352
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
10353
- }
10354
- }
10355
- ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }) }),
10356
- editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10357
- Form$2.Field,
10358
- {
10359
- control: form.control,
10360
- name: "unit_price",
10361
- render: ({ field: { onChange, ...field } }) => {
10362
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10363
- ui.CurrencyInput,
10364
- {
10365
- ...field,
10366
- symbol: getNativeSymbol(currencyCode),
10367
- code: currencyCode,
10368
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10369
- }
10370
- ) }) });
10371
- }
10372
- }
10373
- ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full flex-1 items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10374
- /* @__PURE__ */ jsxRuntime.jsx(
10375
- ui.IconButton,
10376
- {
10377
- type: "button",
10378
- size: "small",
10379
- onClick: editing ? onSubmit : () => {
10380
- setEditing(true);
10381
- },
10382
- disabled: isPending,
10383
- children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
10384
- }
10385
- )
10386
- ] }) }) });
10387
- };
10388
- const variantItemSchema = objectType({
10389
- quantity: numberType(),
10390
- unit_price: unionType([numberType(), stringType()])
10391
- });
10392
- const CustomItem = ({ item, preview, currencyCode }) => {
10393
- const [editing, setEditing] = React.useState(false);
10394
- const { quantity, unit_price, title } = item;
10395
- const form = reactHookForm.useForm({
10396
- defaultValues: {
10397
- title,
10398
- quantity,
10399
- unit_price
10400
- },
10401
- resolver: zod.zodResolver(customItemSchema)
9943
+ const { fields, insert, remove } = reactHookForm.useFieldArray({
9944
+ control: form.control,
9945
+ name: "metadata"
10402
9946
  });
10403
- React.useEffect(() => {
10404
- form.reset({
10405
- title,
10406
- quantity,
10407
- unit_price
9947
+ function deleteRow(index) {
9948
+ remove(index);
9949
+ if (fields.length === 1) {
9950
+ insert(0, {
9951
+ key: "",
9952
+ value: "",
9953
+ disabled: false
9954
+ });
9955
+ }
9956
+ }
9957
+ function insertRow(index, position) {
9958
+ insert(index + (position === "above" ? 0 : 1), {
9959
+ key: "",
9960
+ value: "",
9961
+ disabled: false
10408
9962
  });
10409
- }, [form, title, quantity, unit_price]);
10410
- const actionId = React.useMemo(() => {
10411
- var _a, _b;
10412
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10413
- }, [item]);
10414
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10415
- const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10416
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10417
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10418
- const onSubmit = form.handleSubmit(async (data) => {
10419
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10420
- setEditing(false);
10421
- return;
9963
+ }
9964
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
9965
+ KeyboundForm,
9966
+ {
9967
+ onSubmit: handleSubmit,
9968
+ className: "flex flex-1 flex-col overflow-hidden",
9969
+ children: [
9970
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
9971
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
9972
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
9973
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
9974
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
9975
+ ] }),
9976
+ fields.map((field, index) => {
9977
+ const isDisabled = field.disabled || false;
9978
+ let placeholder = "-";
9979
+ if (typeof field.value === "object") {
9980
+ placeholder = "{ ... }";
9981
+ }
9982
+ if (Array.isArray(field.value)) {
9983
+ placeholder = "[ ... ]";
9984
+ }
9985
+ return /* @__PURE__ */ jsxRuntime.jsx(
9986
+ ConditionalTooltip,
9987
+ {
9988
+ showTooltip: isDisabled,
9989
+ content: "This row is disabled because it contains non-primitive data.",
9990
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
9991
+ /* @__PURE__ */ jsxRuntime.jsxs(
9992
+ "div",
9993
+ {
9994
+ className: ui.clx("grid grid-cols-2 divide-x", {
9995
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
9996
+ }),
9997
+ children: [
9998
+ /* @__PURE__ */ jsxRuntime.jsx(
9999
+ Form$2.Field,
10000
+ {
10001
+ control: form.control,
10002
+ name: `metadata.${index}.key`,
10003
+ render: ({ field: field2 }) => {
10004
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10005
+ GridInput,
10006
+ {
10007
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
10008
+ ...field2,
10009
+ disabled: isDisabled,
10010
+ placeholder: "Key"
10011
+ }
10012
+ ) }) });
10013
+ }
10014
+ }
10015
+ ),
10016
+ /* @__PURE__ */ jsxRuntime.jsx(
10017
+ Form$2.Field,
10018
+ {
10019
+ control: form.control,
10020
+ name: `metadata.${index}.value`,
10021
+ render: ({ field: { value, ...field2 } }) => {
10022
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10023
+ GridInput,
10024
+ {
10025
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
10026
+ ...field2,
10027
+ value: isDisabled ? placeholder : value,
10028
+ disabled: isDisabled,
10029
+ placeholder: "Value"
10030
+ }
10031
+ ) }) });
10032
+ }
10033
+ }
10034
+ )
10035
+ ]
10036
+ }
10037
+ ),
10038
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10039
+ /* @__PURE__ */ jsxRuntime.jsx(
10040
+ ui.DropdownMenu.Trigger,
10041
+ {
10042
+ className: ui.clx(
10043
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
10044
+ {
10045
+ hidden: isDisabled
10046
+ }
10047
+ ),
10048
+ disabled: isDisabled,
10049
+ asChild: true,
10050
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
10051
+ }
10052
+ ),
10053
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
10054
+ /* @__PURE__ */ jsxRuntime.jsxs(
10055
+ ui.DropdownMenu.Item,
10056
+ {
10057
+ className: "gap-x-2",
10058
+ onClick: () => insertRow(index, "above"),
10059
+ children: [
10060
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
10061
+ "Insert row above"
10062
+ ]
10063
+ }
10064
+ ),
10065
+ /* @__PURE__ */ jsxRuntime.jsxs(
10066
+ ui.DropdownMenu.Item,
10067
+ {
10068
+ className: "gap-x-2",
10069
+ onClick: () => insertRow(index, "below"),
10070
+ children: [
10071
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
10072
+ "Insert row below"
10073
+ ]
10074
+ }
10075
+ ),
10076
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
10077
+ /* @__PURE__ */ jsxRuntime.jsxs(
10078
+ ui.DropdownMenu.Item,
10079
+ {
10080
+ className: "gap-x-2",
10081
+ onClick: () => deleteRow(index),
10082
+ children: [
10083
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
10084
+ "Delete row"
10085
+ ]
10086
+ }
10087
+ )
10088
+ ] })
10089
+ ] })
10090
+ ] })
10091
+ },
10092
+ field.id
10093
+ );
10094
+ })
10095
+ ] }),
10096
+ hasUneditableRows && /* @__PURE__ */ jsxRuntime.jsx(InlineTip, { variant: "warning", label: "Some rows are disabled", children: "This object contains non-primitive metadata, such as arrays or objects, that can't be edited here. To edit the disabled rows, use the API directly." })
10097
+ ] }),
10098
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10099
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10100
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10101
+ ] }) })
10102
+ ]
10103
+ }
10104
+ ) });
10105
+ };
10106
+ const GridInput = React.forwardRef(({ className, ...props }, ref) => {
10107
+ return /* @__PURE__ */ jsxRuntime.jsx(
10108
+ "input",
10109
+ {
10110
+ ref,
10111
+ ...props,
10112
+ autoComplete: "off",
10113
+ className: ui.clx(
10114
+ "txt-compact-small text-ui-fg-base placeholder:text-ui-fg-muted disabled:text-ui-fg-disabled disabled:bg-ui-bg-base bg-transparent px-2 py-1.5 outline-none",
10115
+ className
10116
+ )
10117
+ }
10118
+ );
10119
+ });
10120
+ GridInput.displayName = "MetadataForm.GridInput";
10121
+ const PlaceholderInner = () => {
10122
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
10123
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
10124
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10125
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
10126
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
10127
+ ] }) })
10128
+ ] });
10129
+ };
10130
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
10131
+ function getDefaultValues(metadata) {
10132
+ if (!metadata || !Object.keys(metadata).length) {
10133
+ return [
10134
+ {
10135
+ key: "",
10136
+ value: "",
10137
+ disabled: false
10138
+ }
10139
+ ];
10140
+ }
10141
+ return Object.entries(metadata).map(([key, value]) => {
10142
+ if (!EDITABLE_TYPES.includes(typeof value)) {
10143
+ return {
10144
+ key,
10145
+ value,
10146
+ disabled: true
10147
+ };
10148
+ }
10149
+ let stringValue = value;
10150
+ if (typeof value !== "string") {
10151
+ stringValue = JSON.stringify(value);
10422
10152
  }
10423
- if (!actionId) {
10424
- await updateOriginalItem(
10425
- {
10426
- item_id: item.id,
10427
- quantity: data.quantity,
10428
- unit_price: convertNumber(data.unit_price)
10429
- },
10430
- {
10431
- onSuccess: () => {
10432
- setEditing(false);
10433
- },
10434
- onError: (e) => {
10435
- ui.toast.error(e.message);
10436
- }
10437
- }
10438
- );
10153
+ return {
10154
+ key,
10155
+ value: stringValue,
10156
+ original_key: key
10157
+ };
10158
+ });
10159
+ }
10160
+ function parseValues(values) {
10161
+ const metadata = values.metadata;
10162
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
10163
+ if (isEmpty) {
10164
+ return null;
10165
+ }
10166
+ const update = {};
10167
+ metadata.forEach((field) => {
10168
+ let key = field.key;
10169
+ let value = field.value;
10170
+ const disabled = field.disabled;
10171
+ if (!key || !value) {
10439
10172
  return;
10440
10173
  }
10441
- if (data.quantity === 0) {
10442
- await removeActionItem(actionId, {
10443
- onSuccess: () => {
10444
- setEditing(false);
10445
- },
10446
- onError: (e) => {
10447
- ui.toast.error(e.message);
10448
- }
10449
- });
10174
+ if (disabled) {
10175
+ update[key] = value;
10450
10176
  return;
10451
10177
  }
10452
- await updateActionItem(
10453
- {
10454
- action_id: actionId,
10455
- quantity: data.quantity,
10456
- unit_price: convertNumber(data.unit_price)
10457
- },
10458
- {
10459
- onSuccess: () => {
10460
- setEditing(false);
10461
- },
10462
- onError: (e) => {
10463
- ui.toast.error(e.message);
10464
- }
10178
+ key = key.trim();
10179
+ value = value.trim();
10180
+ if (value === "true") {
10181
+ update[key] = true;
10182
+ } else if (value === "false") {
10183
+ update[key] = false;
10184
+ } else {
10185
+ const parsedNumber = parseFloat(value);
10186
+ if (!isNaN(parsedNumber)) {
10187
+ update[key] = parsedNumber;
10188
+ } else {
10189
+ update[key] = value;
10465
10190
  }
10466
- );
10191
+ }
10467
10192
  });
10468
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
10469
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
10470
- /* @__PURE__ */ jsxRuntime.jsx(
10471
- Thumbnail,
10472
- {
10473
- thumbnail: item.thumbnail,
10474
- alt: item.title ?? void 0
10475
- }
10476
- ),
10477
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10478
- Form$2.Field,
10479
- {
10480
- control: form.control,
10481
- name: "title",
10482
- render: ({ field }) => {
10483
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }) });
10484
- }
10485
- }
10486
- ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.title })
10487
- ] }),
10488
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10489
- Form$2.Field,
10490
- {
10491
- control: form.control,
10492
- name: "quantity",
10493
- render: ({ field }) => {
10494
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
10495
- }
10496
- }
10497
- ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }),
10498
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10499
- Form$2.Field,
10500
- {
10501
- control: form.control,
10502
- name: "unit_price",
10503
- render: ({ field: { onChange, ...field } }) => {
10504
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10505
- ui.CurrencyInput,
10506
- {
10507
- ...field,
10508
- symbol: getNativeSymbol(currencyCode),
10509
- code: currencyCode,
10510
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10511
- }
10512
- ) }) });
10513
- }
10514
- }
10515
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10516
- /* @__PURE__ */ jsxRuntime.jsx(
10517
- ui.IconButton,
10518
- {
10519
- type: "button",
10520
- size: "small",
10521
- onClick: editing ? onSubmit : () => {
10522
- setEditing(true);
10523
- },
10524
- disabled: isPending,
10525
- children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
10193
+ return update;
10194
+ }
10195
+ function getHasUneditableRows(metadata) {
10196
+ if (!metadata) {
10197
+ return false;
10198
+ }
10199
+ return Object.values(metadata).some(
10200
+ (value) => !EDITABLE_TYPES.includes(typeof value)
10201
+ );
10202
+ }
10203
+ const PROMOTION_QUERY_KEY = "promotions";
10204
+ const promotionsQueryKeys = {
10205
+ list: (query2) => [
10206
+ PROMOTION_QUERY_KEY,
10207
+ query2 ? query2 : void 0
10208
+ ],
10209
+ detail: (id, query2) => [
10210
+ PROMOTION_QUERY_KEY,
10211
+ id,
10212
+ query2 ? query2 : void 0
10213
+ ]
10214
+ };
10215
+ const usePromotions = (query2, options) => {
10216
+ const { data, ...rest } = reactQuery.useQuery({
10217
+ queryKey: promotionsQueryKeys.list(query2),
10218
+ queryFn: async () => sdk.admin.promotion.list(query2),
10219
+ ...options
10220
+ });
10221
+ return { ...data, ...rest };
10222
+ };
10223
+ const useCancelOrderEdit = ({ preview }) => {
10224
+ const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
10225
+ const onCancel = React.useCallback(async () => {
10226
+ if (!preview) {
10227
+ return true;
10228
+ }
10229
+ let res = false;
10230
+ await cancelOrderEdit(void 0, {
10231
+ onError: (e) => {
10232
+ ui.toast.error(e.message);
10233
+ },
10234
+ onSuccess: () => {
10235
+ res = true;
10526
10236
  }
10527
- )
10528
- ] }) }) });
10237
+ });
10238
+ return res;
10239
+ }, [preview, cancelOrderEdit]);
10240
+ return { onCancel };
10529
10241
  };
10530
- const StackedModalTrigger$1 = ({
10531
- type,
10532
- setModalContent
10242
+ let IS_REQUEST_RUNNING = false;
10243
+ const useInitiateOrderEdit = ({
10244
+ preview
10533
10245
  }) => {
10534
- const { setIsOpen } = useStackedModal();
10535
- const onClick = React.useCallback(() => {
10536
- setModalContent(type);
10537
- setIsOpen(STACKED_MODAL_ID, true);
10538
- }, [setModalContent, setIsOpen, type]);
10539
- return /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10540
- };
10541
- const VARIANT_PREFIX = "items";
10542
- const LIMIT = 50;
10543
- const ExistingItemsForm = ({ orderId, items }) => {
10544
- const { setIsOpen } = useStackedModal();
10545
- const [rowSelection, setRowSelection] = React.useState(
10546
- items.reduce((acc, item) => {
10547
- acc[item.variant_id] = true;
10548
- return acc;
10549
- }, {})
10550
- );
10246
+ const navigate = reactRouterDom.useNavigate();
10247
+ const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10551
10248
  React.useEffect(() => {
10552
- setRowSelection(
10553
- items.reduce((acc, item) => {
10554
- if (item.variant_id) {
10555
- acc[item.variant_id] = true;
10249
+ async function run() {
10250
+ if (IS_REQUEST_RUNNING || !preview) {
10251
+ return;
10252
+ }
10253
+ if (preview.order_change) {
10254
+ return;
10255
+ }
10256
+ IS_REQUEST_RUNNING = true;
10257
+ await mutateAsync(void 0, {
10258
+ onError: (e) => {
10259
+ ui.toast.error(e.message);
10260
+ navigate(`/draft-orders/${preview.id}`, { replace: true });
10261
+ return;
10556
10262
  }
10557
- return acc;
10558
- }, {})
10559
- );
10560
- }, [items]);
10561
- const { q, order, offset } = useQueryParams(
10562
- ["q", "order", "offset"],
10563
- VARIANT_PREFIX
10564
- );
10565
- const { variants, count, isPending, isError, error } = useProductVariants(
10263
+ });
10264
+ IS_REQUEST_RUNNING = false;
10265
+ }
10266
+ run();
10267
+ }, [preview, navigate, mutateAsync]);
10268
+ };
10269
+ const Promotions = () => {
10270
+ const { id } = reactRouterDom.useParams();
10271
+ const {
10272
+ order: preview,
10273
+ isError: isPreviewError,
10274
+ error: previewError
10275
+ } = useOrderPreview(id, void 0);
10276
+ useInitiateOrderEdit({ preview });
10277
+ const { onCancel } = useCancelOrderEdit({ preview });
10278
+ if (isPreviewError) {
10279
+ throw previewError;
10280
+ }
10281
+ const isReady = !!preview;
10282
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
10283
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
10284
+ isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
10285
+ ] });
10286
+ };
10287
+ const PromotionForm = ({ preview }) => {
10288
+ const { items, shipping_methods } = preview;
10289
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
10290
+ const [comboboxValue, setComboboxValue] = React.useState("");
10291
+ const { handleSuccess } = useRouteModal();
10292
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
10293
+ const promoIds = getPromotionIds(items, shipping_methods);
10294
+ const { promotions, isPending, isError, error } = usePromotions(
10566
10295
  {
10567
- q,
10568
- order,
10569
- offset: offset ? parseInt(offset) : void 0,
10570
- limit: LIMIT
10296
+ id: promoIds
10571
10297
  },
10572
10298
  {
10573
- placeholderData: reactQuery.keepPreviousData
10299
+ enabled: !!promoIds.length
10574
10300
  }
10575
10301
  );
10576
- const columns = useColumns();
10577
- const { mutateAsync } = useDraftOrderAddItems(orderId);
10578
- const onSubmit = async () => {
10579
- const ids = Object.keys(rowSelection).filter(
10580
- (id) => !items.find((i) => i.variant_id === id)
10581
- );
10582
- await mutateAsync(
10302
+ const comboboxData = useComboboxData({
10303
+ queryKey: ["promotions", "combobox", promoIds],
10304
+ queryFn: async (params) => {
10305
+ return await sdk.admin.promotion.list({
10306
+ ...params,
10307
+ id: {
10308
+ $nin: promoIds
10309
+ }
10310
+ });
10311
+ },
10312
+ getOptions: (data) => {
10313
+ return data.promotions.map((promotion) => ({
10314
+ label: promotion.code,
10315
+ value: promotion.code
10316
+ }));
10317
+ }
10318
+ });
10319
+ const add = async (value) => {
10320
+ if (!value) {
10321
+ return;
10322
+ }
10323
+ addPromotions(
10583
10324
  {
10584
- items: ids.map((id) => ({
10585
- variant_id: id,
10586
- quantity: 1
10587
- }))
10325
+ promo_codes: [value]
10588
10326
  },
10589
10327
  {
10590
- onSuccess: () => {
10591
- setRowSelection({});
10592
- setIsOpen(STACKED_MODAL_ID, false);
10593
- },
10594
10328
  onError: (e) => {
10595
10329
  ui.toast.error(e.message);
10330
+ comboboxData.onSearchValueChange("");
10331
+ setComboboxValue("");
10332
+ },
10333
+ onSuccess: () => {
10334
+ comboboxData.onSearchValueChange("");
10335
+ setComboboxValue("");
10596
10336
  }
10597
10337
  }
10598
10338
  );
10599
10339
  };
10340
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10341
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10342
+ const onSubmit = async () => {
10343
+ setIsSubmitting(true);
10344
+ let requestSucceeded = false;
10345
+ await requestOrderEdit(void 0, {
10346
+ onError: (e) => {
10347
+ ui.toast.error(e.message);
10348
+ },
10349
+ onSuccess: () => {
10350
+ requestSucceeded = true;
10351
+ }
10352
+ });
10353
+ if (!requestSucceeded) {
10354
+ setIsSubmitting(false);
10355
+ return;
10356
+ }
10357
+ await confirmOrderEdit(void 0, {
10358
+ onError: (e) => {
10359
+ ui.toast.error(e.message);
10360
+ },
10361
+ onSuccess: () => {
10362
+ handleSuccess();
10363
+ },
10364
+ onSettled: () => {
10365
+ setIsSubmitting(false);
10366
+ }
10367
+ });
10368
+ };
10600
10369
  if (isError) {
10601
10370
  throw error;
10602
10371
  }
10603
- return /* @__PURE__ */ jsxRuntime.jsxs(
10604
- StackedFocusModal.Content,
10605
- {
10606
- onOpenAutoFocus: (e) => {
10607
- e.preventDefault();
10608
- const searchInput = document.querySelector(
10609
- "[data-modal-id='modal-search-input']"
10610
- );
10611
- if (searchInput) {
10612
- searchInput.focus();
10613
- }
10614
- },
10615
- children: [
10616
- /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Header, { children: [
10617
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10618
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
10372
+ return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10373
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
10374
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
10375
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10376
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10377
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
10619
10378
  ] }),
10620
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
10621
- DataTable,
10379
+ /* @__PURE__ */ jsxRuntime.jsx(
10380
+ Combobox,
10622
10381
  {
10623
- data: variants,
10624
- columns,
10625
- isLoading: isPending,
10626
- getRowId: (row) => row.id,
10627
- rowCount: count,
10628
- prefix: VARIANT_PREFIX,
10629
- layout: "fill",
10630
- rowSelection: {
10631
- state: rowSelection,
10632
- onRowSelectionChange: setRowSelection,
10633
- enableRowSelection: (row) => {
10634
- return !items.find((i) => i.variant_id === row.original.id);
10635
- }
10636
- },
10637
- autoFocusSearch: true
10382
+ id: "promotion-combobox",
10383
+ "aria-describedby": "promotion-combobox-hint",
10384
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
10385
+ fetchNextPage: comboboxData.fetchNextPage,
10386
+ options: comboboxData.options,
10387
+ onSearchValueChange: comboboxData.onSearchValueChange,
10388
+ searchValue: comboboxData.searchValue,
10389
+ disabled: comboboxData.disabled || isAddingPromotions,
10390
+ onChange: add,
10391
+ value: comboboxValue
10638
10392
  }
10639
- ) }),
10640
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10641
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10642
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
10643
- ] }) })
10644
- ]
10645
- }
10646
- );
10647
- };
10648
- const columnHelper = ui.createDataTableColumnHelper();
10649
- const useColumns = () => {
10650
- return React.useMemo(() => {
10651
- return [
10652
- columnHelper.select(),
10653
- columnHelper.accessor("product.title", {
10654
- header: "Product",
10655
- cell: ({ row }) => {
10656
- var _a, _b, _c;
10657
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
10658
- /* @__PURE__ */ jsxRuntime.jsx(
10659
- Thumbnail,
10660
- {
10661
- thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
10662
- alt: (_b = row.original.product) == null ? void 0 : _b.title
10663
- }
10664
- ),
10665
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
10666
- ] });
10667
- },
10668
- enableSorting: true
10669
- }),
10670
- columnHelper.accessor("title", {
10671
- header: "Variant",
10672
- enableSorting: true
10673
- }),
10674
- columnHelper.accessor("sku", {
10675
- header: "SKU",
10676
- cell: ({ getValue }) => {
10677
- return getValue() ?? "-";
10678
- },
10679
- enableSorting: true
10680
- }),
10681
- columnHelper.accessor("updated_at", {
10682
- header: "Updated",
10683
- cell: ({ getValue }) => {
10684
- return /* @__PURE__ */ jsxRuntime.jsx(
10685
- ui.Tooltip,
10686
- {
10687
- content: getFullDate({ date: getValue(), includeTime: true }),
10688
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
10689
- }
10690
- );
10691
- },
10692
- enableSorting: true,
10693
- sortAscLabel: "Oldest first",
10694
- sortDescLabel: "Newest first"
10695
- }),
10696
- columnHelper.accessor("created_at", {
10697
- header: "Created",
10698
- cell: ({ getValue }) => {
10699
- return /* @__PURE__ */ jsxRuntime.jsx(
10700
- ui.Tooltip,
10701
- {
10702
- content: getFullDate({ date: getValue(), includeTime: true }),
10703
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
10704
- }
10705
- );
10393
+ )
10394
+ ] }),
10395
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10396
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
10397
+ PromotionItem,
10398
+ {
10399
+ promotion,
10400
+ orderId: preview.id,
10401
+ isLoading: isPending
10706
10402
  },
10707
- enableSorting: true,
10708
- sortAscLabel: "Oldest first",
10709
- sortDescLabel: "Newest first"
10710
- })
10711
- ];
10712
- }, []);
10403
+ promotion.id
10404
+ )) })
10405
+ ] }) }),
10406
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
10407
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10408
+ /* @__PURE__ */ jsxRuntime.jsx(
10409
+ ui.Button,
10410
+ {
10411
+ size: "small",
10412
+ type: "submit",
10413
+ isLoading: isSubmitting || isAddingPromotions,
10414
+ children: "Save"
10415
+ }
10416
+ )
10417
+ ] }) })
10418
+ ] });
10713
10419
  };
10714
- const CustomItemForm = ({ orderId, currencyCode }) => {
10715
- const { setIsOpen } = useStackedModal();
10716
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
10717
- const form = reactHookForm.useForm({
10718
- defaultValues: {
10719
- title: "",
10720
- quantity: 1,
10721
- unit_price: ""
10722
- },
10723
- resolver: zod.zodResolver(customItemSchema)
10724
- });
10725
- const onSubmit = form.handleSubmit(async (data) => {
10726
- await addItems(
10420
+ const PromotionItem = ({
10421
+ promotion,
10422
+ orderId,
10423
+ isLoading
10424
+ }) => {
10425
+ var _a;
10426
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10427
+ const onRemove = async () => {
10428
+ removePromotions(
10727
10429
  {
10728
- items: [
10729
- {
10730
- title: data.title,
10731
- quantity: data.quantity,
10732
- unit_price: convertNumber(data.unit_price)
10733
- }
10734
- ]
10430
+ promo_codes: [promotion.code]
10735
10431
  },
10736
10432
  {
10737
- onSuccess: () => {
10738
- setIsOpen(STACKED_MODAL_ID, false);
10739
- },
10740
10433
  onError: (e) => {
10741
10434
  ui.toast.error(e.message);
10742
10435
  }
10743
10436
  }
10744
10437
  );
10745
- });
10746
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Content, { children: [
10747
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Header, {}),
10748
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-2 py-16", children: [
10749
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10750
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Add custom item" }) }),
10751
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add a custom item to the order. This will add a new line item that is not associated with an existing product." }) })
10752
- ] }),
10753
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10754
- /* @__PURE__ */ jsxRuntime.jsx(
10755
- Form$2.Field,
10756
- {
10757
- control: form.control,
10758
- name: "title",
10759
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10760
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10761
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Title" }),
10762
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the title of the item" })
10763
- ] }),
10764
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10765
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
10766
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10767
- ] })
10768
- ] }) })
10769
- }
10770
- ),
10771
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10772
- /* @__PURE__ */ jsxRuntime.jsx(
10773
- Form$2.Field,
10438
+ };
10439
+ const displayValue = getDisplayValue(promotion);
10440
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10441
+ "div",
10442
+ {
10443
+ className: ui.clx(
10444
+ "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
10774
10445
  {
10775
- control: form.control,
10776
- name: "unit_price",
10777
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10778
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10779
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Unit price" }),
10780
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
10781
- ] }),
10782
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10783
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10784
- ui.CurrencyInput,
10785
- {
10786
- symbol: getNativeSymbol(currencyCode),
10787
- code: currencyCode,
10788
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
10789
- ...field
10790
- }
10791
- ) }),
10792
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10793
- ] })
10794
- ] }) })
10446
+ "animate-pulse": isLoading
10795
10447
  }
10796
10448
  ),
10797
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10798
- /* @__PURE__ */ jsxRuntime.jsx(
10799
- Form$2.Field,
10800
- {
10801
- control: form.control,
10802
- name: "quantity",
10803
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10804
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10805
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Quantity" }),
10806
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
10449
+ children: [
10450
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10451
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
10452
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
10453
+ displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
10454
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
10455
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
10807
10456
  ] }),
10808
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex-1", children: [
10809
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field, className: "w-full" }) }) }),
10810
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10811
- ] })
10812
- ] }) })
10813
- }
10814
- )
10815
- ] }) }) }),
10816
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10817
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10818
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
10819
- ] }) })
10820
- ] }) }) });
10457
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
10458
+ ] })
10459
+ ] }),
10460
+ /* @__PURE__ */ jsxRuntime.jsx(
10461
+ ui.IconButton,
10462
+ {
10463
+ size: "small",
10464
+ type: "button",
10465
+ variant: "transparent",
10466
+ onClick: onRemove,
10467
+ isLoading: isPending || isLoading,
10468
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
10469
+ }
10470
+ )
10471
+ ]
10472
+ },
10473
+ promotion.id
10474
+ );
10821
10475
  };
10822
- const customItemSchema = objectType({
10823
- title: stringType().min(1),
10824
- quantity: numberType(),
10825
- unit_price: unionType([numberType(), stringType()])
10476
+ function getDisplayValue(promotion) {
10477
+ var _a, _b, _c, _d;
10478
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
10479
+ if (!value) {
10480
+ return null;
10481
+ }
10482
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
10483
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
10484
+ if (!currency) {
10485
+ return null;
10486
+ }
10487
+ return getLocaleAmount(value, currency);
10488
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
10489
+ return formatPercentage(value);
10490
+ }
10491
+ return null;
10492
+ }
10493
+ const formatter = new Intl.NumberFormat([], {
10494
+ style: "percent",
10495
+ minimumFractionDigits: 2
10826
10496
  });
10827
- const InlineTip = React.forwardRef(
10828
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10829
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10497
+ const formatPercentage = (value, isPercentageValue = false) => {
10498
+ let val = value || 0;
10499
+ if (!isPercentageValue) {
10500
+ val = val / 100;
10501
+ }
10502
+ return formatter.format(val);
10503
+ };
10504
+ function getPromotionIds(items, shippingMethods) {
10505
+ const promotionIds = /* @__PURE__ */ new Set();
10506
+ for (const item of items) {
10507
+ if (item.adjustments) {
10508
+ for (const adjustment of item.adjustments) {
10509
+ if (adjustment.promotion_id) {
10510
+ promotionIds.add(adjustment.promotion_id);
10511
+ }
10512
+ }
10513
+ }
10514
+ }
10515
+ for (const shippingMethod of shippingMethods) {
10516
+ if (shippingMethod.adjustments) {
10517
+ for (const adjustment of shippingMethod.adjustments) {
10518
+ if (adjustment.promotion_id) {
10519
+ promotionIds.add(adjustment.promotion_id);
10520
+ }
10521
+ }
10522
+ }
10523
+ }
10524
+ return Array.from(promotionIds);
10525
+ }
10526
+ const NumberInput = React.forwardRef(
10527
+ ({
10528
+ value,
10529
+ onChange,
10530
+ size = "base",
10531
+ min = 0,
10532
+ max = 100,
10533
+ step = 1,
10534
+ className,
10535
+ disabled,
10536
+ ...props
10537
+ }, ref) => {
10538
+ const handleChange = (event) => {
10539
+ const newValue = event.target.value === "" ? min : Number(event.target.value);
10540
+ if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
10541
+ onChange(newValue);
10542
+ }
10543
+ };
10544
+ const handleIncrement = () => {
10545
+ const newValue = value + step;
10546
+ if (max === void 0 || newValue <= max) {
10547
+ onChange(newValue);
10548
+ }
10549
+ };
10550
+ const handleDecrement = () => {
10551
+ const newValue = value - step;
10552
+ if (min === void 0 || newValue >= min) {
10553
+ onChange(newValue);
10554
+ }
10555
+ };
10830
10556
  return /* @__PURE__ */ jsxRuntime.jsxs(
10831
10557
  "div",
10832
10558
  {
10833
- ref,
10834
10559
  className: ui.clx(
10835
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10560
+ "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
10561
+ "[&:has(input:focus)]:shadow-borders-interactive-with-active",
10562
+ {
10563
+ "h-7": size === "small",
10564
+ "h-8": size === "base"
10565
+ },
10836
10566
  className
10837
10567
  ),
10838
- ...props,
10839
10568
  children: [
10840
10569
  /* @__PURE__ */ jsxRuntime.jsx(
10841
- "div",
10570
+ "input",
10842
10571
  {
10843
- role: "presentation",
10844
- className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10845
- "bg-ui-tag-orange-icon": variant === "warning"
10846
- })
10572
+ ref,
10573
+ type: "number",
10574
+ value,
10575
+ onChange: handleChange,
10576
+ min,
10577
+ max,
10578
+ step,
10579
+ className: ui.clx(
10580
+ "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
10581
+ "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
10582
+ "placeholder:text-ui-fg-muted"
10583
+ ),
10584
+ ...props
10585
+ }
10586
+ ),
10587
+ /* @__PURE__ */ jsxRuntime.jsxs(
10588
+ "button",
10589
+ {
10590
+ className: ui.clx(
10591
+ "flex items-center justify-center outline-none transition-fg",
10592
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10593
+ "focus:bg-ui-bg-field-component-hover",
10594
+ "hover:bg-ui-bg-field-component-hover",
10595
+ {
10596
+ "size-7": size === "small",
10597
+ "size-8": size === "base"
10598
+ }
10599
+ ),
10600
+ type: "button",
10601
+ onClick: handleDecrement,
10602
+ disabled: min !== void 0 && value <= min || disabled,
10603
+ children: [
10604
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Minus, {}),
10605
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
10606
+ ]
10847
10607
  }
10848
10608
  ),
10849
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
10850
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10851
- labelValue,
10852
- ":"
10853
- ] }),
10854
- " ",
10855
- children
10856
- ] })
10609
+ /* @__PURE__ */ jsxRuntime.jsxs(
10610
+ "button",
10611
+ {
10612
+ className: ui.clx(
10613
+ "flex items-center justify-center outline-none transition-fg",
10614
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10615
+ "focus:bg-ui-bg-field-hover",
10616
+ "hover:bg-ui-bg-field-hover",
10617
+ {
10618
+ "size-7": size === "small",
10619
+ "size-8": size === "base"
10620
+ }
10621
+ ),
10622
+ type: "button",
10623
+ onClick: handleIncrement,
10624
+ disabled: max !== void 0 && value >= max || disabled,
10625
+ children: [
10626
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
10627
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Increase by ${step}` })
10628
+ ]
10629
+ }
10630
+ )
10857
10631
  ]
10858
10632
  }
10859
10633
  );
10860
10634
  }
10861
10635
  );
10862
- InlineTip.displayName = "InlineTip";
10863
- const MetadataFieldSchema = objectType({
10864
- key: stringType(),
10865
- disabled: booleanType().optional(),
10866
- value: anyType()
10867
- });
10868
- const MetadataSchema = objectType({
10869
- metadata: arrayType(MetadataFieldSchema)
10870
- });
10871
- const Metadata = () => {
10872
- const { id } = reactRouterDom.useParams();
10873
- const { order, isPending, isError, error } = useOrder(id, {
10874
- fields: "metadata"
10875
- });
10876
- if (isError) {
10877
- throw error;
10878
- }
10879
- const isReady = !isPending && !!order;
10880
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10881
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10882
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
10883
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10884
- ] }),
10885
- !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10886
- ] });
10636
+ const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
10637
+ const productVariantsQueryKeys = {
10638
+ list: (query2) => [
10639
+ PRODUCT_VARIANTS_QUERY_KEY,
10640
+ query2 ? query2 : void 0
10641
+ ]
10887
10642
  };
10888
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10889
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10890
- const MetadataForm = ({ orderId, metadata }) => {
10891
- const { handleSuccess } = useRouteModal();
10892
- const hasUneditableRows = getHasUneditableRows(metadata);
10893
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10894
- const form = reactHookForm.useForm({
10895
- defaultValues: {
10896
- metadata: getDefaultValues(metadata)
10897
- },
10898
- resolver: zod.zodResolver(MetadataSchema)
10899
- });
10900
- const handleSubmit = form.handleSubmit(async (data) => {
10901
- const parsedData = parseValues(data);
10902
- await mutateAsync(
10903
- {
10904
- metadata: parsedData
10905
- },
10906
- {
10907
- onSuccess: () => {
10908
- ui.toast.success("Metadata updated");
10909
- handleSuccess();
10910
- },
10911
- onError: (error) => {
10912
- ui.toast.error(error.message);
10913
- }
10914
- }
10915
- );
10916
- });
10917
- const { fields, insert, remove } = reactHookForm.useFieldArray({
10918
- control: form.control,
10919
- name: "metadata"
10920
- });
10921
- function deleteRow(index) {
10922
- remove(index);
10923
- if (fields.length === 1) {
10924
- insert(0, {
10925
- key: "",
10926
- value: "",
10927
- disabled: false
10928
- });
10929
- }
10930
- }
10931
- function insertRow(index, position) {
10932
- insert(index + (position === "above" ? 0 : 1), {
10933
- key: "",
10934
- value: "",
10935
- disabled: false
10936
- });
10937
- }
10938
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10939
- KeyboundForm,
10940
- {
10941
- onSubmit: handleSubmit,
10942
- className: "flex flex-1 flex-col overflow-hidden",
10943
- children: [
10944
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10945
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10946
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10947
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
10948
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
10949
- ] }),
10950
- fields.map((field, index) => {
10951
- const isDisabled = field.disabled || false;
10952
- let placeholder = "-";
10953
- if (typeof field.value === "object") {
10954
- placeholder = "{ ... }";
10955
- }
10956
- if (Array.isArray(field.value)) {
10957
- placeholder = "[ ... ]";
10958
- }
10959
- return /* @__PURE__ */ jsxRuntime.jsx(
10960
- ConditionalTooltip,
10961
- {
10962
- showTooltip: isDisabled,
10963
- content: "This row is disabled because it contains non-primitive data.",
10964
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
10965
- /* @__PURE__ */ jsxRuntime.jsxs(
10966
- "div",
10967
- {
10968
- className: ui.clx("grid grid-cols-2 divide-x", {
10969
- "overflow-hidden rounded-b-lg": index === fields.length - 1
10970
- }),
10971
- children: [
10972
- /* @__PURE__ */ jsxRuntime.jsx(
10973
- Form$2.Field,
10974
- {
10975
- control: form.control,
10976
- name: `metadata.${index}.key`,
10977
- render: ({ field: field2 }) => {
10978
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10979
- GridInput,
10980
- {
10981
- "aria-labelledby": METADATA_KEY_LABEL_ID,
10982
- ...field2,
10983
- disabled: isDisabled,
10984
- placeholder: "Key"
10985
- }
10986
- ) }) });
10987
- }
10988
- }
10989
- ),
10990
- /* @__PURE__ */ jsxRuntime.jsx(
10991
- Form$2.Field,
10992
- {
10993
- control: form.control,
10994
- name: `metadata.${index}.value`,
10995
- render: ({ field: { value, ...field2 } }) => {
10996
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10997
- GridInput,
10998
- {
10999
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
11000
- ...field2,
11001
- value: isDisabled ? placeholder : value,
11002
- disabled: isDisabled,
11003
- placeholder: "Value"
11004
- }
11005
- ) }) });
11006
- }
11007
- }
11008
- )
11009
- ]
11010
- }
11011
- ),
11012
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
11013
- /* @__PURE__ */ jsxRuntime.jsx(
11014
- ui.DropdownMenu.Trigger,
11015
- {
11016
- className: ui.clx(
11017
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11018
- {
11019
- hidden: isDisabled
11020
- }
11021
- ),
11022
- disabled: isDisabled,
11023
- asChild: true,
11024
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
11025
- }
11026
- ),
11027
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
11028
- /* @__PURE__ */ jsxRuntime.jsxs(
11029
- ui.DropdownMenu.Item,
11030
- {
11031
- className: "gap-x-2",
11032
- onClick: () => insertRow(index, "above"),
11033
- children: [
11034
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
11035
- "Insert row above"
11036
- ]
11037
- }
11038
- ),
11039
- /* @__PURE__ */ jsxRuntime.jsxs(
11040
- ui.DropdownMenu.Item,
11041
- {
11042
- className: "gap-x-2",
11043
- onClick: () => insertRow(index, "below"),
11044
- children: [
11045
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
11046
- "Insert row below"
11047
- ]
11048
- }
11049
- ),
11050
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
11051
- /* @__PURE__ */ jsxRuntime.jsxs(
11052
- ui.DropdownMenu.Item,
11053
- {
11054
- className: "gap-x-2",
11055
- onClick: () => deleteRow(index),
11056
- children: [
11057
- /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
11058
- "Delete row"
11059
- ]
11060
- }
11061
- )
11062
- ] })
11063
- ] })
11064
- ] })
11065
- },
11066
- field.id
11067
- );
11068
- })
11069
- ] }),
11070
- hasUneditableRows && /* @__PURE__ */ jsxRuntime.jsx(InlineTip, { variant: "warning", label: "Some rows are disabled", children: "This object contains non-primitive metadata, such as arrays or objects, that can't be edited here. To edit the disabled rows, use the API directly." })
11071
- ] }),
11072
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11073
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11074
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11075
- ] }) })
11076
- ]
11077
- }
11078
- ) });
10643
+ const useProductVariants = (query2, options) => {
10644
+ const { data, ...rest } = reactQuery.useQuery({
10645
+ queryKey: productVariantsQueryKeys.list(query2),
10646
+ queryFn: async () => await sdk.admin.productVariant.list(query2),
10647
+ ...options
10648
+ });
10649
+ return { ...data, ...rest };
11079
10650
  };
11080
- const GridInput = React.forwardRef(({ className, ...props }, ref) => {
11081
- return /* @__PURE__ */ jsxRuntime.jsx(
11082
- "input",
10651
+ function convertNumber(value) {
10652
+ return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10653
+ }
10654
+ const STACKED_MODAL_ID = "items_stacked_modal";
10655
+ const Items = () => {
10656
+ const { id } = reactRouterDom.useParams();
10657
+ const {
10658
+ order: preview,
10659
+ isPending: isPreviewPending,
10660
+ isError: isPreviewError,
10661
+ error: previewError
10662
+ } = useOrderPreview(id, void 0, {
10663
+ placeholderData: reactQuery.keepPreviousData
10664
+ });
10665
+ useInitiateOrderEdit({ preview });
10666
+ const { draft_order, isPending, isError, error } = useDraftOrder(
10667
+ id,
11083
10668
  {
11084
- ref,
11085
- ...props,
11086
- autoComplete: "off",
11087
- className: ui.clx(
11088
- "txt-compact-small text-ui-fg-base placeholder:text-ui-fg-muted disabled:text-ui-fg-disabled disabled:bg-ui-bg-base bg-transparent px-2 py-1.5 outline-none",
11089
- className
11090
- )
10669
+ fields: "currency_code"
10670
+ },
10671
+ {
10672
+ enabled: !!id
11091
10673
  }
11092
10674
  );
11093
- });
11094
- GridInput.displayName = "MetadataForm.GridInput";
11095
- const PlaceholderInner = () => {
11096
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11097
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11098
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11099
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
11100
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
11101
- ] }) })
11102
- ] });
11103
- };
11104
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11105
- function getDefaultValues(metadata) {
11106
- if (!metadata || !Object.keys(metadata).length) {
11107
- return [
11108
- {
11109
- key: "",
11110
- value: "",
11111
- disabled: false
11112
- }
11113
- ];
10675
+ const { onCancel } = useCancelOrderEdit({ preview });
10676
+ if (isError) {
10677
+ throw error;
11114
10678
  }
11115
- return Object.entries(metadata).map(([key, value]) => {
11116
- if (!EDITABLE_TYPES.includes(typeof value)) {
11117
- return {
11118
- key,
11119
- value,
11120
- disabled: true
11121
- };
11122
- }
11123
- let stringValue = value;
11124
- if (typeof value !== "string") {
11125
- stringValue = JSON.stringify(value);
11126
- }
11127
- return {
11128
- key,
11129
- value: stringValue,
11130
- original_key: key
11131
- };
11132
- });
11133
- }
11134
- function parseValues(values) {
11135
- const metadata = values.metadata;
11136
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11137
- if (isEmpty) {
11138
- return null;
10679
+ if (isPreviewError) {
10680
+ throw previewError;
11139
10681
  }
11140
- const update = {};
11141
- metadata.forEach((field) => {
11142
- let key = field.key;
11143
- let value = field.value;
11144
- const disabled = field.disabled;
11145
- if (!key || !value) {
11146
- return;
11147
- }
11148
- if (disabled) {
11149
- update[key] = value;
10682
+ const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10683
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsxRuntime.jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10684
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10685
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10686
+ ] }) });
10687
+ };
10688
+ const ItemsForm = ({ preview, currencyCode }) => {
10689
+ var _a;
10690
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
10691
+ const [modalContent, setModalContent] = React.useState(
10692
+ null
10693
+ );
10694
+ const { handleSuccess } = useRouteModal();
10695
+ const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10696
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10697
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10698
+ const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10699
+ const matches = React.useMemo(() => {
10700
+ return matchSorter.matchSorter(preview.items, query2, {
10701
+ keys: ["product_title", "variant_title", "variant_sku", "title"]
10702
+ });
10703
+ }, [preview.items, query2]);
10704
+ const onSubmit = async () => {
10705
+ setIsSubmitting(true);
10706
+ let requestSucceeded = false;
10707
+ await requestOrderEdit(void 0, {
10708
+ onError: (e) => {
10709
+ ui.toast.error(`Failed to request order edit: ${e.message}`);
10710
+ },
10711
+ onSuccess: () => {
10712
+ requestSucceeded = true;
10713
+ }
10714
+ });
10715
+ if (!requestSucceeded) {
10716
+ setIsSubmitting(false);
11150
10717
  return;
11151
10718
  }
11152
- key = key.trim();
11153
- value = value.trim();
11154
- if (value === "true") {
11155
- update[key] = true;
11156
- } else if (value === "false") {
11157
- update[key] = false;
11158
- } else {
11159
- const parsedNumber = parseFloat(value);
11160
- if (!isNaN(parsedNumber)) {
11161
- update[key] = parsedNumber;
11162
- } else {
11163
- update[key] = value;
10719
+ await confirmOrderEdit(void 0, {
10720
+ onError: (e) => {
10721
+ ui.toast.error(`Failed to confirm order edit: ${e.message}`);
10722
+ },
10723
+ onSuccess: () => {
10724
+ handleSuccess();
10725
+ },
10726
+ onSettled: () => {
10727
+ setIsSubmitting(false);
10728
+ }
10729
+ });
10730
+ };
10731
+ const onKeyDown = React.useCallback(
10732
+ (e) => {
10733
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10734
+ if (modalContent || isSubmitting) {
10735
+ return;
10736
+ }
10737
+ onSubmit();
10738
+ }
10739
+ },
10740
+ [modalContent, isSubmitting, onSubmit]
10741
+ );
10742
+ React.useEffect(() => {
10743
+ document.addEventListener("keydown", onKeyDown);
10744
+ return () => {
10745
+ document.removeEventListener("keydown", onKeyDown);
10746
+ };
10747
+ }, [onKeyDown]);
10748
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10749
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
10750
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
10751
+ StackedFocusModal,
10752
+ {
10753
+ id: STACKED_MODAL_ID,
10754
+ onOpenChangeCallback: (open) => {
10755
+ if (!open) {
10756
+ setModalContent(null);
10757
+ }
10758
+ },
10759
+ children: [
10760
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-6 py-16", children: [
10761
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10762
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Items" }) }),
10763
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Edit the items in the draft order" }) })
10764
+ ] }),
10765
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10766
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-6", children: [
10767
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10768
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10769
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10770
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10771
+ ] }),
10772
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10773
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10774
+ ui.Input,
10775
+ {
10776
+ type: "search",
10777
+ placeholder: "Search items",
10778
+ value: searchValue,
10779
+ onChange: (e) => onSearchValueChange(e.target.value)
10780
+ }
10781
+ ) }),
10782
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10783
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { type: "button", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}) }) }),
10784
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
10785
+ /* @__PURE__ */ jsxRuntime.jsx(
10786
+ StackedModalTrigger$1,
10787
+ {
10788
+ type: "add-items",
10789
+ setModalContent
10790
+ }
10791
+ ),
10792
+ /* @__PURE__ */ jsxRuntime.jsx(
10793
+ StackedModalTrigger$1,
10794
+ {
10795
+ type: "add-custom-item",
10796
+ setModalContent
10797
+ }
10798
+ )
10799
+ ] })
10800
+ ] })
10801
+ ] })
10802
+ ] }),
10803
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10804
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[5px]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-muted grid grid-cols-[2fr_1fr_2fr_28px] gap-3 px-4 py-2", children: [
10805
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Item" }) }),
10806
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10807
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Price" }) }),
10808
+ /* @__PURE__ */ jsxRuntime.jsx("div", {})
10809
+ ] }) }),
10810
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest flex flex-col items-center justify-center gap-1 gap-x-3 rounded-lg p-4", children: [
10811
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10812
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10813
+ ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
10814
+ Item,
10815
+ {
10816
+ item,
10817
+ preview,
10818
+ currencyCode
10819
+ },
10820
+ item.id
10821
+ )) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest flex flex-col items-center justify-center gap-1 gap-x-3 rounded-lg p-4", children: [
10822
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10823
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: [
10824
+ 'No items found for "',
10825
+ query2,
10826
+ '".'
10827
+ ] })
10828
+ ] }) })
10829
+ ] })
10830
+ ] }),
10831
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10832
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10833
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10834
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
10835
+ ui.Text,
10836
+ {
10837
+ size: "small",
10838
+ leading: "compact",
10839
+ className: "text-ui-fg-subtle",
10840
+ children: [
10841
+ itemCount,
10842
+ " ",
10843
+ itemCount === 1 ? "item" : "items"
10844
+ ]
10845
+ }
10846
+ ) }),
10847
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
10848
+ ] })
10849
+ ] }) }),
10850
+ modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsxRuntime.jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsxRuntime.jsx(
10851
+ CustomItemForm,
10852
+ {
10853
+ orderId: preview.id,
10854
+ currencyCode
10855
+ }
10856
+ ) : null)
10857
+ ]
11164
10858
  }
11165
- }
11166
- });
11167
- return update;
11168
- }
11169
- function getHasUneditableRows(metadata) {
11170
- if (!metadata) {
11171
- return false;
11172
- }
11173
- return Object.values(metadata).some(
11174
- (value) => !EDITABLE_TYPES.includes(typeof value)
11175
- );
11176
- }
11177
- const PROMOTION_QUERY_KEY = "promotions";
11178
- const promotionsQueryKeys = {
11179
- list: (query2) => [
11180
- PROMOTION_QUERY_KEY,
11181
- query2 ? query2 : void 0
11182
- ],
11183
- detail: (id, query2) => [
11184
- PROMOTION_QUERY_KEY,
11185
- id,
11186
- query2 ? query2 : void 0
11187
- ]
11188
- };
11189
- const usePromotions = (query2, options) => {
11190
- const { data, ...rest } = reactQuery.useQuery({
11191
- queryKey: promotionsQueryKeys.list(query2),
11192
- queryFn: async () => sdk.admin.promotion.list(query2),
11193
- ...options
11194
- });
11195
- return { ...data, ...rest };
10859
+ ) }),
10860
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10861
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10862
+ /* @__PURE__ */ jsxRuntime.jsx(
10863
+ ui.Button,
10864
+ {
10865
+ size: "small",
10866
+ type: "button",
10867
+ onClick: onSubmit,
10868
+ isLoading: isSubmitting,
10869
+ children: "Save"
10870
+ }
10871
+ )
10872
+ ] }) })
10873
+ ] });
11196
10874
  };
11197
- const Promotions = () => {
11198
- const { id } = reactRouterDom.useParams();
11199
- const {
11200
- order: preview,
11201
- isError: isPreviewError,
11202
- error: previewError
11203
- } = useOrderPreview(id, void 0);
11204
- useInitiateOrderEdit({ preview });
11205
- const { onCancel } = useCancelOrderEdit({ preview });
11206
- if (isPreviewError) {
11207
- throw previewError;
10875
+ const Item = ({ item, preview, currencyCode }) => {
10876
+ if (item.variant_id) {
10877
+ return /* @__PURE__ */ jsxRuntime.jsx(VariantItem, { item, preview, currencyCode });
11208
10878
  }
11209
- const isReady = !!preview;
11210
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
11211
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
11212
- isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
11213
- ] });
10879
+ return /* @__PURE__ */ jsxRuntime.jsx(CustomItem, { item, preview, currencyCode });
11214
10880
  };
11215
- const PromotionForm = ({ preview }) => {
11216
- const { items, shipping_methods } = preview;
11217
- const [isSubmitting, setIsSubmitting] = React.useState(false);
11218
- const [comboboxValue, setComboboxValue] = React.useState("");
11219
- const { handleSuccess } = useRouteModal();
11220
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11221
- const promoIds = getPromotionIds(items, shipping_methods);
11222
- const { promotions, isPending, isError, error } = usePromotions(
11223
- {
11224
- id: promoIds
10881
+ const VariantItem = ({ item, preview, currencyCode }) => {
10882
+ const [editing, setEditing] = React.useState(false);
10883
+ const form = reactHookForm.useForm({
10884
+ defaultValues: {
10885
+ quantity: item.quantity,
10886
+ unit_price: item.unit_price
11225
10887
  },
11226
- {
11227
- enabled: !!promoIds.length
10888
+ resolver: zod.zodResolver(variantItemSchema)
10889
+ });
10890
+ const actionId = React.useMemo(() => {
10891
+ var _a, _b;
10892
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10893
+ }, [item]);
10894
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10895
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10896
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10897
+ const onSubmit = form.handleSubmit(async (data) => {
10898
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10899
+ setEditing(false);
10900
+ return;
11228
10901
  }
11229
- );
11230
- const comboboxData = useComboboxData({
11231
- queryKey: ["promotions", "combobox", promoIds],
11232
- queryFn: async (params) => {
11233
- return await sdk.admin.promotion.list({
11234
- ...params,
11235
- id: {
11236
- $nin: promoIds
10902
+ if (!actionId) {
10903
+ await updateOriginalItem(
10904
+ {
10905
+ item_id: item.id,
10906
+ quantity: data.quantity,
10907
+ unit_price: convertNumber(data.unit_price)
10908
+ },
10909
+ {
10910
+ onSuccess: () => {
10911
+ setEditing(false);
10912
+ },
10913
+ onError: (e) => {
10914
+ ui.toast.error(e.message);
10915
+ }
11237
10916
  }
11238
- });
11239
- },
11240
- getOptions: (data) => {
11241
- return data.promotions.map((promotion) => ({
11242
- label: promotion.code,
11243
- value: promotion.code
11244
- }));
10917
+ );
10918
+ return;
11245
10919
  }
10920
+ await updateActionItem(
10921
+ {
10922
+ action_id: actionId,
10923
+ quantity: data.quantity,
10924
+ unit_price: convertNumber(data.unit_price)
10925
+ },
10926
+ {
10927
+ onSuccess: () => {
10928
+ setEditing(false);
10929
+ },
10930
+ onError: (e) => {
10931
+ ui.toast.error(e.message);
10932
+ }
10933
+ }
10934
+ );
10935
+ });
10936
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
10937
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
10938
+ /* @__PURE__ */ jsxRuntime.jsx(
10939
+ Thumbnail,
10940
+ {
10941
+ thumbnail: item.thumbnail,
10942
+ alt: item.product_title ?? void 0
10943
+ }
10944
+ ),
10945
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10946
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-1", children: [
10947
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10948
+ /* @__PURE__ */ jsxRuntime.jsxs(
10949
+ ui.Text,
10950
+ {
10951
+ size: "small",
10952
+ leading: "compact",
10953
+ className: "text-ui-fg-subtle",
10954
+ children: [
10955
+ "(",
10956
+ item.variant_title,
10957
+ ")"
10958
+ ]
10959
+ }
10960
+ )
10961
+ ] }),
10962
+ /* @__PURE__ */ jsxRuntime.jsx(
10963
+ ui.Text,
10964
+ {
10965
+ size: "small",
10966
+ leading: "compact",
10967
+ className: "text-ui-fg-subtle",
10968
+ children: item.variant_sku
10969
+ }
10970
+ )
10971
+ ] })
10972
+ ] }),
10973
+ editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10974
+ Form$2.Field,
10975
+ {
10976
+ control: form.control,
10977
+ name: "quantity",
10978
+ render: ({ field }) => {
10979
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
10980
+ }
10981
+ }
10982
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }) }),
10983
+ editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10984
+ Form$2.Field,
10985
+ {
10986
+ control: form.control,
10987
+ name: "unit_price",
10988
+ render: ({ field: { onChange, ...field } }) => {
10989
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10990
+ ui.CurrencyInput,
10991
+ {
10992
+ ...field,
10993
+ symbol: getNativeSymbol(currencyCode),
10994
+ code: currencyCode,
10995
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10996
+ }
10997
+ ) }) });
10998
+ }
10999
+ }
11000
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full flex-1 items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
11001
+ /* @__PURE__ */ jsxRuntime.jsx(
11002
+ ui.IconButton,
11003
+ {
11004
+ type: "button",
11005
+ size: "small",
11006
+ onClick: editing ? onSubmit : () => {
11007
+ setEditing(true);
11008
+ },
11009
+ disabled: isPending,
11010
+ children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
11011
+ }
11012
+ )
11013
+ ] }) }) });
11014
+ };
11015
+ const variantItemSchema = objectType({
11016
+ quantity: numberType(),
11017
+ unit_price: unionType([numberType(), stringType()])
11018
+ });
11019
+ const CustomItem = ({ item, preview, currencyCode }) => {
11020
+ const [editing, setEditing] = React.useState(false);
11021
+ const { quantity, unit_price, title } = item;
11022
+ const form = reactHookForm.useForm({
11023
+ defaultValues: {
11024
+ title,
11025
+ quantity,
11026
+ unit_price
11027
+ },
11028
+ resolver: zod.zodResolver(customItemSchema)
11246
11029
  });
11247
- const add = async (value) => {
11248
- if (!value) {
11030
+ React.useEffect(() => {
11031
+ form.reset({
11032
+ title,
11033
+ quantity,
11034
+ unit_price
11035
+ });
11036
+ }, [form, title, quantity, unit_price]);
11037
+ const actionId = React.useMemo(() => {
11038
+ var _a, _b;
11039
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
11040
+ }, [item]);
11041
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
11042
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
11043
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
11044
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
11045
+ const onSubmit = form.handleSubmit(async (data) => {
11046
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
11047
+ setEditing(false);
11249
11048
  return;
11250
11049
  }
11251
- addPromotions(
11252
- {
11253
- promo_codes: [value]
11254
- },
11255
- {
11256
- onError: (e) => {
11257
- ui.toast.error(e.message);
11258
- comboboxData.onSearchValueChange("");
11259
- setComboboxValue("");
11050
+ if (!actionId) {
11051
+ await updateOriginalItem(
11052
+ {
11053
+ item_id: item.id,
11054
+ quantity: data.quantity,
11055
+ unit_price: convertNumber(data.unit_price)
11260
11056
  },
11261
- onSuccess: () => {
11262
- comboboxData.onSearchValueChange("");
11263
- setComboboxValue("");
11057
+ {
11058
+ onSuccess: () => {
11059
+ setEditing(false);
11060
+ },
11061
+ onError: (e) => {
11062
+ ui.toast.error(e.message);
11063
+ }
11264
11064
  }
11265
- }
11266
- );
11267
- };
11268
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11269
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
11270
- const onSubmit = async () => {
11271
- setIsSubmitting(true);
11272
- let requestSucceeded = false;
11273
- await requestOrderEdit(void 0, {
11274
- onError: (e) => {
11275
- ui.toast.error(e.message);
11276
- },
11277
- onSuccess: () => {
11278
- requestSucceeded = true;
11279
- }
11280
- });
11281
- if (!requestSucceeded) {
11282
- setIsSubmitting(false);
11065
+ );
11283
11066
  return;
11284
11067
  }
11285
- await confirmOrderEdit(void 0, {
11286
- onError: (e) => {
11287
- ui.toast.error(e.message);
11288
- },
11289
- onSuccess: () => {
11290
- handleSuccess();
11291
- },
11292
- onSettled: () => {
11293
- setIsSubmitting(false);
11294
- }
11295
- });
11296
- };
11297
- if (isError) {
11298
- throw error;
11299
- }
11300
- return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11301
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
11302
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
11303
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
11304
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11305
- /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11306
- ] }),
11307
- /* @__PURE__ */ jsxRuntime.jsx(
11308
- Combobox,
11309
- {
11310
- id: "promotion-combobox",
11311
- "aria-describedby": "promotion-combobox-hint",
11312
- isFetchingNextPage: comboboxData.isFetchingNextPage,
11313
- fetchNextPage: comboboxData.fetchNextPage,
11314
- options: comboboxData.options,
11315
- onSearchValueChange: comboboxData.onSearchValueChange,
11316
- searchValue: comboboxData.searchValue,
11317
- disabled: comboboxData.disabled || isAddingPromotions,
11318
- onChange: add,
11319
- value: comboboxValue
11320
- }
11321
- )
11322
- ] }),
11323
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11324
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
11325
- PromotionItem,
11326
- {
11327
- promotion,
11328
- orderId: preview.id,
11329
- isLoading: isPending
11068
+ if (data.quantity === 0) {
11069
+ await removeActionItem(actionId, {
11070
+ onSuccess: () => {
11071
+ setEditing(false);
11330
11072
  },
11331
- promotion.id
11332
- )) })
11333
- ] }) }),
11334
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11335
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11336
- /* @__PURE__ */ jsxRuntime.jsx(
11337
- ui.Button,
11338
- {
11339
- size: "small",
11340
- type: "submit",
11341
- isLoading: isSubmitting || isAddingPromotions,
11342
- children: "Save"
11073
+ onError: (e) => {
11074
+ ui.toast.error(e.message);
11343
11075
  }
11344
- )
11345
- ] }) })
11346
- ] });
11347
- };
11348
- const PromotionItem = ({
11349
- promotion,
11350
- orderId,
11351
- isLoading
11352
- }) => {
11353
- var _a;
11354
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11355
- const onRemove = async () => {
11356
- removePromotions(
11076
+ });
11077
+ return;
11078
+ }
11079
+ await updateActionItem(
11357
11080
  {
11358
- promo_codes: [promotion.code]
11081
+ action_id: actionId,
11082
+ quantity: data.quantity,
11083
+ unit_price: convertNumber(data.unit_price)
11359
11084
  },
11360
11085
  {
11086
+ onSuccess: () => {
11087
+ setEditing(false);
11088
+ },
11361
11089
  onError: (e) => {
11362
11090
  ui.toast.error(e.message);
11363
11091
  }
11364
11092
  }
11365
11093
  );
11366
- };
11367
- const displayValue = getDisplayValue(promotion);
11368
- return /* @__PURE__ */ jsxRuntime.jsxs(
11369
- "div",
11370
- {
11371
- className: ui.clx(
11372
- "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
11094
+ });
11095
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
11096
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
11097
+ /* @__PURE__ */ jsxRuntime.jsx(
11098
+ Thumbnail,
11373
11099
  {
11374
- "animate-pulse": isLoading
11100
+ thumbnail: item.thumbnail,
11101
+ alt: item.title ?? void 0
11375
11102
  }
11376
11103
  ),
11377
- children: [
11378
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11379
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11380
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
11381
- displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
11382
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
11383
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
11384
- ] }),
11385
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11386
- ] })
11387
- ] }),
11388
- /* @__PURE__ */ jsxRuntime.jsx(
11389
- ui.IconButton,
11390
- {
11391
- size: "small",
11392
- type: "button",
11393
- variant: "transparent",
11394
- onClick: onRemove,
11395
- isLoading: isPending || isLoading,
11396
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
11104
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
11105
+ Form$2.Field,
11106
+ {
11107
+ control: form.control,
11108
+ name: "title",
11109
+ render: ({ field }) => {
11110
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }) });
11397
11111
  }
11398
- )
11399
- ]
11400
- },
11401
- promotion.id
11402
- );
11403
- };
11404
- function getDisplayValue(promotion) {
11405
- var _a, _b, _c, _d;
11406
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11407
- if (!value) {
11408
- return null;
11409
- }
11410
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11411
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11412
- if (!currency) {
11413
- return null;
11414
- }
11415
- return getLocaleAmount(value, currency);
11416
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11417
- return formatPercentage(value);
11418
- }
11419
- return null;
11420
- }
11421
- const formatter = new Intl.NumberFormat([], {
11422
- style: "percent",
11423
- minimumFractionDigits: 2
11424
- });
11425
- const formatPercentage = (value, isPercentageValue = false) => {
11426
- let val = value || 0;
11427
- if (!isPercentageValue) {
11428
- val = val / 100;
11429
- }
11430
- return formatter.format(val);
11431
- };
11432
- function getPromotionIds(items, shippingMethods) {
11433
- const promotionIds = /* @__PURE__ */ new Set();
11434
- for (const item of items) {
11435
- if (item.adjustments) {
11436
- for (const adjustment of item.adjustments) {
11437
- if (adjustment.promotion_id) {
11438
- promotionIds.add(adjustment.promotion_id);
11112
+ }
11113
+ ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.title })
11114
+ ] }),
11115
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
11116
+ Form$2.Field,
11117
+ {
11118
+ control: form.control,
11119
+ name: "quantity",
11120
+ render: ({ field }) => {
11121
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
11122
+ }
11123
+ }
11124
+ ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }),
11125
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
11126
+ Form$2.Field,
11127
+ {
11128
+ control: form.control,
11129
+ name: "unit_price",
11130
+ render: ({ field: { onChange, ...field } }) => {
11131
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11132
+ ui.CurrencyInput,
11133
+ {
11134
+ ...field,
11135
+ symbol: getNativeSymbol(currencyCode),
11136
+ code: currencyCode,
11137
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
11138
+ }
11139
+ ) }) });
11439
11140
  }
11440
11141
  }
11441
- }
11442
- }
11443
- for (const shippingMethod of shippingMethods) {
11444
- if (shippingMethod.adjustments) {
11445
- for (const adjustment of shippingMethod.adjustments) {
11446
- if (adjustment.promotion_id) {
11447
- promotionIds.add(adjustment.promotion_id);
11448
- }
11142
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
11143
+ /* @__PURE__ */ jsxRuntime.jsx(
11144
+ ui.IconButton,
11145
+ {
11146
+ type: "button",
11147
+ size: "small",
11148
+ onClick: editing ? onSubmit : () => {
11149
+ setEditing(true);
11150
+ },
11151
+ disabled: isPending,
11152
+ children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
11449
11153
  }
11450
- }
11451
- }
11452
- return Array.from(promotionIds);
11453
- }
11454
- const SalesChannel = () => {
11455
- const { id } = reactRouterDom.useParams();
11456
- const { draft_order, isPending, isError, error } = useDraftOrder(
11457
- id,
11154
+ )
11155
+ ] }) }) });
11156
+ };
11157
+ const StackedModalTrigger$1 = ({
11158
+ type,
11159
+ setModalContent
11160
+ }) => {
11161
+ const { setIsOpen } = useStackedModal();
11162
+ const onClick = React.useCallback(() => {
11163
+ setModalContent(type);
11164
+ setIsOpen(STACKED_MODAL_ID, true);
11165
+ }, [setModalContent, setIsOpen, type]);
11166
+ return /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
11167
+ };
11168
+ const VARIANT_PREFIX = "items";
11169
+ const LIMIT = 50;
11170
+ const ExistingItemsForm = ({ orderId, items }) => {
11171
+ const { setIsOpen } = useStackedModal();
11172
+ const [rowSelection, setRowSelection] = React.useState(
11173
+ items.reduce((acc, item) => {
11174
+ acc[item.variant_id] = true;
11175
+ return acc;
11176
+ }, {})
11177
+ );
11178
+ React.useEffect(() => {
11179
+ setRowSelection(
11180
+ items.reduce((acc, item) => {
11181
+ if (item.variant_id) {
11182
+ acc[item.variant_id] = true;
11183
+ }
11184
+ return acc;
11185
+ }, {})
11186
+ );
11187
+ }, [items]);
11188
+ const { q, order, offset } = useQueryParams(
11189
+ ["q", "order", "offset"],
11190
+ VARIANT_PREFIX
11191
+ );
11192
+ const { variants, count, isPending, isError, error } = useProductVariants(
11458
11193
  {
11459
- fields: "+sales_channel_id"
11194
+ q,
11195
+ order,
11196
+ offset: offset ? parseInt(offset) : void 0,
11197
+ limit: LIMIT
11460
11198
  },
11461
11199
  {
11462
- enabled: !!id
11200
+ placeholderData: reactQuery.keepPreviousData
11463
11201
  }
11464
11202
  );
11465
- if (isError) {
11466
- throw error;
11467
- }
11468
- const ISrEADY = !!draft_order && !isPending;
11469
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11470
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11471
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
11472
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
11473
- ] }),
11474
- ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
11475
- ] });
11476
- };
11477
- const SalesChannelForm = ({ order }) => {
11478
- const form = reactHookForm.useForm({
11479
- defaultValues: {
11480
- sales_channel_id: order.sales_channel_id || ""
11481
- },
11482
- resolver: zod.zodResolver(schema$2)
11483
- });
11484
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11485
- const { handleSuccess } = useRouteModal();
11486
- const onSubmit = form.handleSubmit(async (data) => {
11203
+ const columns = useColumns();
11204
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
11205
+ const onSubmit = async () => {
11206
+ const ids = Object.keys(rowSelection).filter(
11207
+ (id) => !items.find((i) => i.variant_id === id)
11208
+ );
11487
11209
  await mutateAsync(
11488
11210
  {
11489
- sales_channel_id: data.sales_channel_id
11211
+ items: ids.map((id) => ({
11212
+ variant_id: id,
11213
+ quantity: 1
11214
+ }))
11490
11215
  },
11491
11216
  {
11492
11217
  onSuccess: () => {
11493
- ui.toast.success("Sales channel updated");
11494
- handleSuccess();
11218
+ setRowSelection({});
11219
+ setIsOpen(STACKED_MODAL_ID, false);
11495
11220
  },
11496
- onError: (error) => {
11497
- ui.toast.error(error.message);
11221
+ onError: (e) => {
11222
+ ui.toast.error(e.message);
11498
11223
  }
11499
11224
  }
11500
11225
  );
11501
- });
11502
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
11503
- KeyboundForm,
11226
+ };
11227
+ if (isError) {
11228
+ throw error;
11229
+ }
11230
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11231
+ StackedFocusModal.Content,
11504
11232
  {
11505
- className: "flex flex-1 flex-col overflow-hidden",
11506
- onSubmit,
11233
+ onOpenAutoFocus: (e) => {
11234
+ e.preventDefault();
11235
+ const searchInput = document.querySelector(
11236
+ "[data-modal-id='modal-search-input']"
11237
+ );
11238
+ if (searchInput) {
11239
+ searchInput.focus();
11240
+ }
11241
+ },
11507
11242
  children: [
11508
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
11509
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11510
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11511
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11243
+ /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Header, { children: [
11244
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Product Variants" }) }),
11245
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
11246
+ ] }),
11247
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
11248
+ DataTable,
11249
+ {
11250
+ data: variants,
11251
+ columns,
11252
+ isLoading: isPending,
11253
+ getRowId: (row) => row.id,
11254
+ rowCount: count,
11255
+ prefix: VARIANT_PREFIX,
11256
+ layout: "fill",
11257
+ rowSelection: {
11258
+ state: rowSelection,
11259
+ onRowSelectionChange: setRowSelection,
11260
+ enableRowSelection: (row) => {
11261
+ return !items.find((i) => i.variant_id === row.original.id);
11262
+ }
11263
+ },
11264
+ autoFocusSearch: true
11265
+ }
11266
+ ) }),
11267
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11268
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11269
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
11512
11270
  ] }) })
11513
11271
  ]
11514
11272
  }
11515
- ) });
11273
+ );
11516
11274
  };
11517
- const SalesChannelField = ({ control, order }) => {
11518
- const salesChannels = useComboboxData({
11519
- queryFn: async (params) => {
11520
- return await sdk.admin.salesChannel.list(params);
11521
- },
11522
- queryKey: ["sales-channels"],
11523
- getOptions: (data) => {
11524
- return data.sales_channels.map((salesChannel) => ({
11525
- label: salesChannel.name,
11526
- value: salesChannel.id
11527
- }));
11275
+ const columnHelper = ui.createDataTableColumnHelper();
11276
+ const useColumns = () => {
11277
+ return React.useMemo(() => {
11278
+ return [
11279
+ columnHelper.select(),
11280
+ columnHelper.accessor("product.title", {
11281
+ header: "Product",
11282
+ cell: ({ row }) => {
11283
+ var _a, _b, _c;
11284
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
11285
+ /* @__PURE__ */ jsxRuntime.jsx(
11286
+ Thumbnail,
11287
+ {
11288
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
11289
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
11290
+ }
11291
+ ),
11292
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
11293
+ ] });
11294
+ },
11295
+ enableSorting: true
11296
+ }),
11297
+ columnHelper.accessor("title", {
11298
+ header: "Variant",
11299
+ enableSorting: true
11300
+ }),
11301
+ columnHelper.accessor("sku", {
11302
+ header: "SKU",
11303
+ cell: ({ getValue }) => {
11304
+ return getValue() ?? "-";
11305
+ },
11306
+ enableSorting: true
11307
+ }),
11308
+ columnHelper.accessor("updated_at", {
11309
+ header: "Updated",
11310
+ cell: ({ getValue }) => {
11311
+ return /* @__PURE__ */ jsxRuntime.jsx(
11312
+ ui.Tooltip,
11313
+ {
11314
+ content: getFullDate({ date: getValue(), includeTime: true }),
11315
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
11316
+ }
11317
+ );
11318
+ },
11319
+ enableSorting: true,
11320
+ sortAscLabel: "Oldest first",
11321
+ sortDescLabel: "Newest first"
11322
+ }),
11323
+ columnHelper.accessor("created_at", {
11324
+ header: "Created",
11325
+ cell: ({ getValue }) => {
11326
+ return /* @__PURE__ */ jsxRuntime.jsx(
11327
+ ui.Tooltip,
11328
+ {
11329
+ content: getFullDate({ date: getValue(), includeTime: true }),
11330
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
11331
+ }
11332
+ );
11333
+ },
11334
+ enableSorting: true,
11335
+ sortAscLabel: "Oldest first",
11336
+ sortDescLabel: "Newest first"
11337
+ })
11338
+ ];
11339
+ }, []);
11340
+ };
11341
+ const CustomItemForm = ({ orderId, currencyCode }) => {
11342
+ const { setIsOpen } = useStackedModal();
11343
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
11344
+ const form = reactHookForm.useForm({
11345
+ defaultValues: {
11346
+ title: "",
11347
+ quantity: 1,
11348
+ unit_price: ""
11528
11349
  },
11529
- defaultValue: order.sales_channel_id || void 0
11350
+ resolver: zod.zodResolver(customItemSchema)
11530
11351
  });
11531
- return /* @__PURE__ */ jsxRuntime.jsx(
11532
- Form$2.Field,
11533
- {
11534
- control,
11535
- name: "sales_channel_id",
11536
- render: ({ field }) => {
11537
- return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
11538
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
11539
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11540
- Combobox,
11541
- {
11542
- options: salesChannels.options,
11543
- fetchNextPage: salesChannels.fetchNextPage,
11544
- isFetchingNextPage: salesChannels.isFetchingNextPage,
11545
- searchValue: salesChannels.searchValue,
11546
- onSearchValueChange: salesChannels.onSearchValueChange,
11547
- placeholder: "Select sales channel",
11548
- ...field
11549
- }
11550
- ) }),
11551
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11552
- ] });
11352
+ const onSubmit = form.handleSubmit(async (data) => {
11353
+ await addItems(
11354
+ {
11355
+ items: [
11356
+ {
11357
+ title: data.title,
11358
+ quantity: data.quantity,
11359
+ unit_price: convertNumber(data.unit_price)
11360
+ }
11361
+ ]
11362
+ },
11363
+ {
11364
+ onSuccess: () => {
11365
+ setIsOpen(STACKED_MODAL_ID, false);
11366
+ },
11367
+ onError: (e) => {
11368
+ ui.toast.error(e.message);
11369
+ }
11553
11370
  }
11554
- }
11555
- );
11371
+ );
11372
+ });
11373
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Content, { children: [
11374
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Header, {}),
11375
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-2 py-16", children: [
11376
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11377
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Add custom item" }) }),
11378
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add a custom item to the order. This will add a new line item that is not associated with an existing product." }) })
11379
+ ] }),
11380
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11381
+ /* @__PURE__ */ jsxRuntime.jsx(
11382
+ Form$2.Field,
11383
+ {
11384
+ control: form.control,
11385
+ name: "title",
11386
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11387
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11388
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Title" }),
11389
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the title of the item" })
11390
+ ] }),
11391
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11392
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
11393
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11394
+ ] })
11395
+ ] }) })
11396
+ }
11397
+ ),
11398
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11399
+ /* @__PURE__ */ jsxRuntime.jsx(
11400
+ Form$2.Field,
11401
+ {
11402
+ control: form.control,
11403
+ name: "unit_price",
11404
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11405
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11406
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Unit price" }),
11407
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
11408
+ ] }),
11409
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11410
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11411
+ ui.CurrencyInput,
11412
+ {
11413
+ symbol: getNativeSymbol(currencyCode),
11414
+ code: currencyCode,
11415
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
11416
+ ...field
11417
+ }
11418
+ ) }),
11419
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11420
+ ] })
11421
+ ] }) })
11422
+ }
11423
+ ),
11424
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11425
+ /* @__PURE__ */ jsxRuntime.jsx(
11426
+ Form$2.Field,
11427
+ {
11428
+ control: form.control,
11429
+ name: "quantity",
11430
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11431
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11432
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Quantity" }),
11433
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
11434
+ ] }),
11435
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex-1", children: [
11436
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field, className: "w-full" }) }) }),
11437
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11438
+ ] })
11439
+ ] }) })
11440
+ }
11441
+ )
11442
+ ] }) }) }),
11443
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11444
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11445
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
11446
+ ] }) })
11447
+ ] }) }) });
11556
11448
  };
11557
- const schema$2 = objectType({
11558
- sales_channel_id: stringType().min(1)
11449
+ const customItemSchema = objectType({
11450
+ title: stringType().min(1),
11451
+ quantity: numberType(),
11452
+ unit_price: unionType([numberType(), stringType()])
11559
11453
  });
11560
11454
  const STACKED_FOCUS_MODAL_ID = "shipping-form";
11561
11455
  const Shipping = () => {
@@ -12396,7 +12290,7 @@ const ShippingAddressForm = ({ order }) => {
12396
12290
  postal_code: ((_i = order.shipping_address) == null ? void 0 : _i.postal_code) ?? "",
12397
12291
  phone: ((_j = order.shipping_address) == null ? void 0 : _j.phone) ?? ""
12398
12292
  },
12399
- resolver: zod.zodResolver(schema$1)
12293
+ resolver: zod.zodResolver(schema$2)
12400
12294
  });
12401
12295
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12402
12296
  const { handleSuccess } = useRouteModal();
@@ -12566,7 +12460,7 @@ const ShippingAddressForm = ({ order }) => {
12566
12460
  }
12567
12461
  ) });
12568
12462
  };
12569
- const schema$1 = addressSchema;
12463
+ const schema$2 = addressSchema;
12570
12464
  const TransferOwnership = () => {
12571
12465
  const { id } = reactRouterDom.useParams();
12572
12466
  const { draft_order, isPending, isError, error } = useDraftOrder(id, {
@@ -12590,7 +12484,7 @@ const TransferOwnershipForm = ({ order }) => {
12590
12484
  defaultValues: {
12591
12485
  customer_id: order.customer_id || ""
12592
12486
  },
12593
- resolver: zod.zodResolver(schema)
12487
+ resolver: zod.zodResolver(schema$1)
12594
12488
  });
12595
12489
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12596
12490
  const { handleSuccess } = useRouteModal();
@@ -13040,9 +12934,115 @@ const Illustration = () => {
13040
12934
  }
13041
12935
  );
13042
12936
  };
13043
- const schema = objectType({
12937
+ const schema$1 = objectType({
13044
12938
  customer_id: stringType().min(1)
13045
12939
  });
12940
+ const SalesChannel = () => {
12941
+ const { id } = reactRouterDom.useParams();
12942
+ const { draft_order, isPending, isError, error } = useDraftOrder(
12943
+ id,
12944
+ {
12945
+ fields: "+sales_channel_id"
12946
+ },
12947
+ {
12948
+ enabled: !!id
12949
+ }
12950
+ );
12951
+ if (isError) {
12952
+ throw error;
12953
+ }
12954
+ const ISrEADY = !!draft_order && !isPending;
12955
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
12956
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
12957
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
12958
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
12959
+ ] }),
12960
+ ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
12961
+ ] });
12962
+ };
12963
+ const SalesChannelForm = ({ order }) => {
12964
+ const form = reactHookForm.useForm({
12965
+ defaultValues: {
12966
+ sales_channel_id: order.sales_channel_id || ""
12967
+ },
12968
+ resolver: zod.zodResolver(schema)
12969
+ });
12970
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12971
+ const { handleSuccess } = useRouteModal();
12972
+ const onSubmit = form.handleSubmit(async (data) => {
12973
+ await mutateAsync(
12974
+ {
12975
+ sales_channel_id: data.sales_channel_id
12976
+ },
12977
+ {
12978
+ onSuccess: () => {
12979
+ ui.toast.success("Sales channel updated");
12980
+ handleSuccess();
12981
+ },
12982
+ onError: (error) => {
12983
+ ui.toast.error(error.message);
12984
+ }
12985
+ }
12986
+ );
12987
+ });
12988
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
12989
+ KeyboundForm,
12990
+ {
12991
+ className: "flex flex-1 flex-col overflow-hidden",
12992
+ onSubmit,
12993
+ children: [
12994
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
12995
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
12996
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
12997
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
12998
+ ] }) })
12999
+ ]
13000
+ }
13001
+ ) });
13002
+ };
13003
+ const SalesChannelField = ({ control, order }) => {
13004
+ const salesChannels = useComboboxData({
13005
+ queryFn: async (params) => {
13006
+ return await sdk.admin.salesChannel.list(params);
13007
+ },
13008
+ queryKey: ["sales-channels"],
13009
+ getOptions: (data) => {
13010
+ return data.sales_channels.map((salesChannel) => ({
13011
+ label: salesChannel.name,
13012
+ value: salesChannel.id
13013
+ }));
13014
+ },
13015
+ defaultValue: order.sales_channel_id || void 0
13016
+ });
13017
+ return /* @__PURE__ */ jsxRuntime.jsx(
13018
+ Form$2.Field,
13019
+ {
13020
+ control,
13021
+ name: "sales_channel_id",
13022
+ render: ({ field }) => {
13023
+ return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
13024
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
13025
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
13026
+ Combobox,
13027
+ {
13028
+ options: salesChannels.options,
13029
+ fetchNextPage: salesChannels.fetchNextPage,
13030
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
13031
+ searchValue: salesChannels.searchValue,
13032
+ onSearchValueChange: salesChannels.onSearchValueChange,
13033
+ placeholder: "Select sales channel",
13034
+ ...field
13035
+ }
13036
+ ) }),
13037
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
13038
+ ] });
13039
+ }
13040
+ }
13041
+ );
13042
+ };
13043
+ const schema = objectType({
13044
+ sales_channel_id: stringType().min(1)
13045
+ });
13046
13046
  const widgetModule = { widgets: [] };
13047
13047
  const routeModule = {
13048
13048
  routes: [
@@ -13075,10 +13075,6 @@ const routeModule = {
13075
13075
  Component: Email,
13076
13076
  path: "/draft-orders/:id/email"
13077
13077
  },
13078
- {
13079
- Component: Items,
13080
- path: "/draft-orders/:id/items"
13081
- },
13082
13078
  {
13083
13079
  Component: Metadata,
13084
13080
  path: "/draft-orders/:id/metadata"
@@ -13088,8 +13084,8 @@ const routeModule = {
13088
13084
  path: "/draft-orders/:id/promotions"
13089
13085
  },
13090
13086
  {
13091
- Component: SalesChannel,
13092
- path: "/draft-orders/:id/sales-channel"
13087
+ Component: Items,
13088
+ path: "/draft-orders/:id/items"
13093
13089
  },
13094
13090
  {
13095
13091
  Component: Shipping,
@@ -13102,6 +13098,10 @@ const routeModule = {
13102
13098
  {
13103
13099
  Component: TransferOwnership,
13104
13100
  path: "/draft-orders/:id/transfer-ownership"
13101
+ },
13102
+ {
13103
+ Component: SalesChannel,
13104
+ path: "/draft-orders/:id/sales-channel"
13105
13105
  }
13106
13106
  ]
13107
13107
  }