@lodashventure/medusa-quotation 1.5.30 → 1.5.31

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.
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { defineRouteConfig } from "@medusajs/admin-sdk";
3
3
  import { DocumentText, CheckCircleSolid, Plus, Trash } from "@medusajs/icons";
4
- import { clx, FocusModal, Heading, Text, Button, Table, Badge, Label, DatePicker, Input, toast, Container, Select, Textarea, createDataTableColumnHelper, useDataTable, DataTable, Toaster, usePrompt, Hint, CurrencyInput, IconButton } from "@medusajs/ui";
4
+ import { clx, FocusModal, Heading, Text, Button, Table, Badge, Label, DatePicker, Input, toast, Container, Select, Textarea, createDataTableColumnHelper, useDataTable, DataTable, Toaster, usePrompt, IconButton, Hint, CurrencyInput } from "@medusajs/ui";
5
5
  import { useState, useCallback, useEffect, useMemo } from "react";
6
6
  import { useNavigate, useParams, Link } from "react-router-dom";
7
7
  import { XCircle, CheckCircle, Clock } from "lucide-react";
@@ -2764,160 +2764,77 @@ const QuoteDetails = () => {
2764
2764
  /* @__PURE__ */ jsx(Toaster, {})
2765
2765
  ] });
2766
2766
  };
2767
- function ManageItem({
2768
- originalItem,
2769
- item,
2770
- currencyCode,
2771
- orderId
2772
- }) {
2773
- const { mutateAsync: updateItem } = useUpdateQuoteItem(orderId);
2774
- const { mutateAsync: removeItem } = useRemoveQuoteItem(orderId);
2775
- const isItemUpdated = useMemo(
2776
- () => {
2777
- var _a;
2778
- return !!((_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_UPDATE"));
2779
- },
2780
- [item]
2781
- );
2782
- const onUpdate = async ({
2783
- quantity,
2784
- unit_price
2785
- }) => {
2786
- if (typeof quantity === "number" && quantity <= item.detail.fulfilled_quantity) {
2787
- toast.warning("Quantity should be greater than the fulfilled quantity");
2788
- return;
2789
- }
2790
- try {
2791
- await updateItem({
2792
- quantity,
2793
- unit_price,
2794
- itemId: item.id
2795
- });
2796
- } catch (e) {
2797
- toast.error(e.message);
2798
- }
2799
- };
2800
- const onRemove = async () => {
2801
- var _a;
2802
- try {
2803
- const addAction = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD");
2804
- if (addAction == null ? void 0 : addAction.id) {
2805
- await removeItem({
2806
- itemId: addAction.id
2807
- });
2808
- } else {
2809
- toast.warning("Cannot remove item, set quantity to 0 instead");
2810
- await updateItem({
2811
- quantity: 0,
2812
- itemId: item.id
2767
+ const columnHelper$1 = createDataTableColumnHelper();
2768
+ const columns$1 = [
2769
+ columnHelper$1.accessor("email", {
2770
+ header: "Email",
2771
+ cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
2772
+ }),
2773
+ columnHelper$1.accessor("first_name", {
2774
+ header: "First Name",
2775
+ cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
2776
+ }),
2777
+ columnHelper$1.accessor("last_name", {
2778
+ header: "Last Name",
2779
+ cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
2780
+ }),
2781
+ columnHelper$1.accessor("company_name", {
2782
+ header: "Company",
2783
+ cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() || "-" })
2784
+ })
2785
+ ];
2786
+ const CustomerSelector = ({
2787
+ onSelectCustomer
2788
+ }) => {
2789
+ const [search, setSearch] = useState("");
2790
+ const [data, setData] = useState(null);
2791
+ const [isLoading, setIsLoading] = useState(false);
2792
+ const debouncedSearchHandler = debounce((value) => {
2793
+ setSearch(value);
2794
+ }, 500);
2795
+ useEffect(() => {
2796
+ const fetchCustomers = async () => {
2797
+ try {
2798
+ setIsLoading(true);
2799
+ const response = await sdk.admin.customer.list({
2800
+ q: search,
2801
+ limit: 20
2813
2802
  });
2803
+ setData(response);
2804
+ } catch (error) {
2805
+ console.error("Error fetching customers:", error);
2806
+ } finally {
2807
+ setIsLoading(false);
2814
2808
  }
2815
- } catch (e) {
2816
- toast.error(e.message);
2817
- }
2818
- };
2819
- return /* @__PURE__ */ jsxs(
2820
- "div",
2821
- {
2822
- className: "bg-ui-bg-subtle shadow-elevation-card-rest my-2 rounded-xl ",
2823
- children: [
2824
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-x-2 gap-y-2 p-3 text-sm md:flex-row", children: [
2825
- /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center justify-between", children: [
2826
- /* @__PURE__ */ jsx("div", { className: "flex flex-row items-center gap-x-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
2827
- /* @__PURE__ */ jsxs("div", { children: [
2828
- /* @__PURE__ */ jsxs(Text, { className: "txt-small", as: "span", weight: "plus", children: [
2829
- item.title,
2830
- " "
2831
- ] }),
2832
- item.variant_sku && /* @__PURE__ */ jsxs("span", { children: [
2833
- "(",
2834
- item.variant_sku,
2835
- ")"
2836
- ] })
2837
- ] }),
2838
- /* @__PURE__ */ jsx(Text, { as: "div", className: "text-ui-fg-subtle txt-small", children: item.product_title })
2839
- ] }) }),
2840
- isItemUpdated && /* @__PURE__ */ jsx(
2841
- Badge,
2842
- {
2843
- size: "2xsmall",
2844
- rounded: "full",
2845
- color: "orange",
2846
- className: "mr-1",
2847
- children: "Modified"
2848
- }
2849
- )
2850
- ] }),
2851
- /* @__PURE__ */ jsxs("div", { className: "flex flex-1 justify-between", children: [
2852
- /* @__PURE__ */ jsxs("div", { className: "flex flex-grow items-center gap-2", children: [
2853
- /* @__PURE__ */ jsx(
2854
- Input,
2855
- {
2856
- className: "bg-ui-bg-base txt-small w-[67px] rounded-lg [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
2857
- type: "number",
2858
- min: item.detail.fulfilled_quantity,
2859
- defaultValue: item.quantity,
2860
- onBlur: (e) => {
2861
- const val = e.target.value;
2862
- const quantity = val === "" ? null : Number(val);
2863
- if (quantity) {
2864
- onUpdate({ quantity });
2865
- }
2866
- }
2867
- }
2868
- ),
2869
- /* @__PURE__ */ jsx(Text, { className: "txt-small text-ui-fg-subtle", children: "Quantity" })
2870
- ] }),
2871
- /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle txt-small mr-2 flex flex-shrink-0", children: /* @__PURE__ */ jsx(
2872
- Amount,
2873
- {
2874
- currencyCode,
2875
- amount: item.total,
2876
- originalAmount: originalItem == null ? void 0 : originalItem.total
2877
- }
2878
- ) })
2879
- ] })
2880
- ] }),
2881
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-2 p-3 md:grid-cols-2", children: [
2882
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
2883
- /* @__PURE__ */ jsx(Label, { children: "Price" }),
2884
- /* @__PURE__ */ jsx(Hint, { className: "!mt-1", children: "Override the unit price of this product" })
2885
- ] }),
2886
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsx("div", { className: "flex-grow", children: /* @__PURE__ */ jsx(
2887
- CurrencyInput,
2888
- {
2889
- symbol: currencyCode,
2890
- code: currencyCode,
2891
- defaultValue: item.unit_price,
2892
- type: "numeric",
2893
- min: 0,
2894
- onBlur: (e) => {
2895
- onUpdate({
2896
- unit_price: parseFloat(e.target.value),
2897
- quantity: item.quantity
2898
- });
2899
- },
2900
- className: "bg-ui-bg-field-component hover:bg-ui-bg-field-component-hover"
2901
- }
2902
- ) }) })
2903
- ] }),
2904
- /* @__PURE__ */ jsx("div", { className: "flex items-center px-3 pb-3", children: /* @__PURE__ */ jsx(
2905
- Button,
2906
- {
2907
- type: "button",
2908
- variant: "danger",
2909
- size: "small",
2910
- onClick: () => {
2911
- onRemove();
2912
- },
2913
- children: "Remove"
2914
- }
2915
- ) })
2916
- ]
2809
+ };
2810
+ fetchCustomers();
2811
+ }, [search]);
2812
+ const customers = (data == null ? void 0 : data.customers) || [];
2813
+ const table = useDataTable({
2814
+ data: customers,
2815
+ columns: columns$1,
2816
+ search: {
2817
+ state: search,
2818
+ onSearchChange: setSearch
2917
2819
  },
2918
- item.quantity
2919
- );
2920
- }
2820
+ getRowId: (customer) => customer.id,
2821
+ onRowClick: (_, row) => {
2822
+ onSelectCustomer == null ? void 0 : onSelectCustomer(row.original);
2823
+ },
2824
+ isLoading
2825
+ });
2826
+ return /* @__PURE__ */ jsxs(Container, { children: [
2827
+ /* @__PURE__ */ jsx(
2828
+ Input,
2829
+ {
2830
+ className: "text-lg py-2 mb-4",
2831
+ placeholder: "Search customers by email, name...",
2832
+ onChange: (e) => debouncedSearchHandler(e.target.value)
2833
+ }
2834
+ ),
2835
+ /* @__PURE__ */ jsx(DataTable, { instance: table, children: /* @__PURE__ */ jsx(DataTable.Table, {}) })
2836
+ ] });
2837
+ };
2921
2838
  const useProductSearch = (search, selectedProductIds) => {
2922
2839
  const [data, setData] = useState({ variants: [] });
2923
2840
  const [isLoading, setIsLoading] = useState(false);
@@ -2969,21 +2886,21 @@ const useProductSearch = (search, selectedProductIds) => {
2969
2886
  }, [search, selectedProductIds.join(",")]);
2970
2887
  return { data, isLoading, error };
2971
2888
  };
2972
- const columnHelper$1 = createDataTableColumnHelper();
2973
- const columns$1 = [
2974
- columnHelper$1.accessor("product.title", {
2889
+ const columnHelper = createDataTableColumnHelper();
2890
+ const columns = [
2891
+ columnHelper.accessor("product.title", {
2975
2892
  header: "Product",
2976
2893
  cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
2977
2894
  }),
2978
- columnHelper$1.accessor("title", {
2895
+ columnHelper.accessor("title", {
2979
2896
  header: "Variant",
2980
2897
  cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
2981
2898
  }),
2982
- columnHelper$1.accessor("sku", {
2899
+ columnHelper.accessor("sku", {
2983
2900
  header: "SKU",
2984
2901
  cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
2985
2902
  }),
2986
- columnHelper$1.accessor("prices", {
2903
+ columnHelper.accessor("prices", {
2987
2904
  header: "Price",
2988
2905
  cell: (info) => {
2989
2906
  var _a, _b;
@@ -3011,7 +2928,7 @@ const ProductSelector = ({
3011
2928
  }, [products == null ? void 0 : products.variants, selectedProductIds]);
3012
2929
  const table = useDataTable({
3013
2930
  data: selectableProducts || [],
3014
- columns: columns$1,
2931
+ columns,
3015
2932
  search: {
3016
2933
  state: search,
3017
2934
  onSearchChange: setSearch
@@ -3033,213 +2950,19 @@ const ProductSelector = ({
3033
2950
  /* @__PURE__ */ jsx(DataTable, { instance: table, children: /* @__PURE__ */ jsx(DataTable.Table, {}) })
3034
2951
  ] });
3035
2952
  };
3036
- const ManageQuoteForm = ({ order }) => {
3037
- const { order: preview } = useOrderPreview(order.id);
2953
+ const CreateQuoteForm = () => {
3038
2954
  const navigate = useNavigate();
3039
- const { id: quoteId } = useParams();
2955
+ const [selectedCustomer, setSelectedCustomer] = useState(null);
2956
+ const [items, setItems] = useState([]);
2957
+ const [openCustomerModal, setOpenCustomerModal] = useState(false);
3040
2958
  const [openProductModal, setOpenProductModal] = useState(false);
3041
- const { mutateAsync: addItem } = useAddQuoteItem(order.id);
3042
- const { mutateAsync: confirmQuote, isPending: isRequesting } = useConfirmQuote(order.id);
3043
- const handleSubmit = async (e) => {
3044
- e.preventDefault();
3045
- try {
3046
- await confirmQuote();
3047
- navigate(`/quotes/${quoteId}`);
3048
- toast.success("Successfully updated quote");
3049
- } catch (e2) {
3050
- toast.error("Error", {
3051
- description: e2.message
3052
- });
3053
- }
3054
- };
3055
- const originalItemsMap = useMemo(() => {
3056
- return new Map(order.items.map((item) => [item.id, item]));
3057
- }, [order]);
3058
- if (!preview) {
3059
- return /* @__PURE__ */ jsx(Fragment, {});
3060
- }
3061
- return /* @__PURE__ */ jsxs(Fragment, { children: [
3062
- /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex h-full flex-col p-4 gap-2", children: [
3063
- /* @__PURE__ */ jsxs("div", { children: [
3064
- /* @__PURE__ */ jsxs("div", { className: "mb-3 mt-8 flex items-center justify-between", children: [
3065
- /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Items" }),
3066
- /* @__PURE__ */ jsx(
3067
- Button,
3068
- {
3069
- type: "button",
3070
- variant: "primary",
3071
- size: "small",
3072
- onClick: () => setOpenProductModal(true),
3073
- children: "Add Item"
3074
- }
3075
- )
3076
- ] }),
3077
- preview.items.map((item) => /* @__PURE__ */ jsx(
3078
- ManageItem,
3079
- {
3080
- originalItem: originalItemsMap.get(item.id),
3081
- item,
3082
- orderId: order.id,
3083
- currencyCode: order.currency_code
3084
- },
3085
- item.id
3086
- ))
3087
- ] }),
3088
- /* @__PURE__ */ jsxs("div", { className: "mt-8 border-y border-dotted py-4", children: [
3089
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
3090
- /* @__PURE__ */ jsx("span", { className: "txt-small text-ui-fg-subtle", children: "Current Total" }),
3091
- /* @__PURE__ */ jsx("span", { className: "txt-small text-ui-fg-subtle", children: formatCurrency(order.total, order.currency_code) })
3092
- ] }),
3093
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
3094
- /* @__PURE__ */ jsx("span", { className: "txt-small text-ui-fg-subtle", children: "New Total" }),
3095
- /* @__PURE__ */ jsx("span", { className: "txt-small text-ui-fg-subtle", children: formatCurrency(preview.total, order.currency_code) })
3096
- ] })
3097
- ] }),
3098
- /* @__PURE__ */ jsx("div", { className: "flex w-full items-center justify-end gap-x-4", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-x-2", children: /* @__PURE__ */ jsx(
3099
- Button,
3100
- {
3101
- type: "submit",
3102
- variant: "primary",
3103
- size: "small",
3104
- disabled: isRequesting,
3105
- children: "Confirm Edit"
3106
- },
3107
- "submit-button"
3108
- ) }) })
3109
- ] }),
3110
- /* @__PURE__ */ jsx(FocusModal, { open: openProductModal, onOpenChange: setOpenProductModal, children: /* @__PURE__ */ jsxs(FocusModal.Content, { children: [
3111
- /* @__PURE__ */ jsx(FocusModal.Header, { children: /* @__PURE__ */ jsx(FocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Add Product" }) }) }),
3112
- /* @__PURE__ */ jsx(FocusModal.Body, { children: /* @__PURE__ */ jsx(
3113
- ProductSelector,
3114
- {
3115
- selectedProductIds: order.items.map(
3116
- (item) => item.variant_id ?? ""
3117
- ),
3118
- onSelectProduct: (variant) => {
3119
- var _a, _b;
3120
- if (!((_a = variant.prices) == null ? void 0 : _a[0].amount)) {
3121
- toast.error("Product price not found");
3122
- return;
3123
- }
3124
- addItem({
3125
- items: [
3126
- {
3127
- variant_id: variant.id,
3128
- quantity: 1,
3129
- unit_price: (_b = variant.prices) == null ? void 0 : _b[0].amount
3130
- }
3131
- ]
3132
- });
3133
- setOpenProductModal(false);
3134
- }
3135
- }
3136
- ) })
3137
- ] }) })
3138
- ] });
3139
- };
3140
- const QuoteManage = () => {
3141
- const { id } = useParams();
3142
- const { quote, isLoading } = useQuote(id, {
3143
- fields: "*draft_order.customer"
3144
- });
3145
- if (isLoading) {
3146
- return /* @__PURE__ */ jsx(Fragment, {});
3147
- }
3148
- if (!quote) {
3149
- throw "quote not found";
3150
- }
3151
- return /* @__PURE__ */ jsxs(Fragment, { children: [
3152
- /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
3153
- /* @__PURE__ */ jsx(Heading, { className: "flex items-center justify-between px-6 py-4", children: "Manage Quote" }),
3154
- /* @__PURE__ */ jsx(ManageQuoteForm, { order: quote.draft_order })
3155
- ] }),
3156
- /* @__PURE__ */ jsx(Toaster, {})
3157
- ] });
3158
- };
3159
- const columnHelper = createDataTableColumnHelper();
3160
- const columns = [
3161
- columnHelper.accessor("email", {
3162
- header: "Email",
3163
- cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
3164
- }),
3165
- columnHelper.accessor("first_name", {
3166
- header: "First Name",
3167
- cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
3168
- }),
3169
- columnHelper.accessor("last_name", {
3170
- header: "Last Name",
3171
- cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() })
3172
- }),
3173
- columnHelper.accessor("company_name", {
3174
- header: "Company",
3175
- cell: (info) => /* @__PURE__ */ jsx(Text, { size: "large", className: "py-2", children: info.getValue() || "-" })
3176
- })
3177
- ];
3178
- const CustomerSelector = ({
3179
- onSelectCustomer
3180
- }) => {
3181
- const [search, setSearch] = useState("");
3182
- const [data, setData] = useState(null);
3183
- const [isLoading, setIsLoading] = useState(false);
3184
- const debouncedSearchHandler = debounce((value) => {
3185
- setSearch(value);
3186
- }, 500);
3187
- useEffect(() => {
3188
- const fetchCustomers = async () => {
3189
- try {
3190
- setIsLoading(true);
3191
- const response = await sdk.admin.customer.list({
3192
- q: search,
3193
- limit: 20
3194
- });
3195
- setData(response);
3196
- } catch (error) {
3197
- console.error("Error fetching customers:", error);
3198
- } finally {
3199
- setIsLoading(false);
3200
- }
3201
- };
3202
- fetchCustomers();
3203
- }, [search]);
3204
- const customers = (data == null ? void 0 : data.customers) || [];
3205
- const table = useDataTable({
3206
- data: customers,
3207
- columns,
3208
- search: {
3209
- state: search,
3210
- onSearchChange: setSearch
3211
- },
3212
- getRowId: (customer) => customer.id,
3213
- onRowClick: (_, row) => {
3214
- onSelectCustomer == null ? void 0 : onSelectCustomer(row.original);
3215
- },
3216
- isLoading
3217
- });
3218
- return /* @__PURE__ */ jsxs(Container, { children: [
3219
- /* @__PURE__ */ jsx(
3220
- Input,
3221
- {
3222
- className: "text-lg py-2 mb-4",
3223
- placeholder: "Search customers by email, name...",
3224
- onChange: (e) => debouncedSearchHandler(e.target.value)
3225
- }
3226
- ),
3227
- /* @__PURE__ */ jsx(DataTable, { instance: table, children: /* @__PURE__ */ jsx(DataTable.Table, {}) })
3228
- ] });
3229
- };
3230
- const CreateQuoteForm = () => {
3231
- const navigate = useNavigate();
3232
- const [selectedCustomer, setSelectedCustomer] = useState(null);
3233
- const [items, setItems] = useState([]);
3234
- const [openCustomerModal, setOpenCustomerModal] = useState(false);
3235
- const [openProductModal, setOpenProductModal] = useState(false);
3236
- const { mutateAsync: createQuote, isPending } = useCreateQuote({
3237
- onSuccess: (data) => {
3238
- toast.success("Quote created successfully");
3239
- navigate(`/quotes/${data.quote.id}`);
3240
- },
3241
- onError: (error) => {
3242
- toast.error(`Failed to create quote: ${error.message}`);
2959
+ const { mutateAsync: createQuote, isPending } = useCreateQuote({
2960
+ onSuccess: (data) => {
2961
+ toast.success("Quote created successfully");
2962
+ navigate(`/quotes/${data.quote.id}`);
2963
+ },
2964
+ onError: (error) => {
2965
+ toast.error(`Failed to create quote: ${error.message}`);
3243
2966
  }
3244
2967
  });
3245
2968
  const handleAddProduct = (variant) => {
@@ -3472,6 +3195,283 @@ const CreateQuote = () => {
3472
3195
  /* @__PURE__ */ jsx(Toaster, {})
3473
3196
  ] });
3474
3197
  };
3198
+ function ManageItem({
3199
+ originalItem,
3200
+ item,
3201
+ currencyCode,
3202
+ orderId
3203
+ }) {
3204
+ const { mutateAsync: updateItem } = useUpdateQuoteItem(orderId);
3205
+ const { mutateAsync: removeItem } = useRemoveQuoteItem(orderId);
3206
+ const isItemUpdated = useMemo(
3207
+ () => {
3208
+ var _a;
3209
+ return !!((_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_UPDATE"));
3210
+ },
3211
+ [item]
3212
+ );
3213
+ const onUpdate = async ({
3214
+ quantity,
3215
+ unit_price
3216
+ }) => {
3217
+ if (typeof quantity === "number" && quantity <= item.detail.fulfilled_quantity) {
3218
+ toast.warning("Quantity should be greater than the fulfilled quantity");
3219
+ return;
3220
+ }
3221
+ try {
3222
+ await updateItem({
3223
+ quantity,
3224
+ unit_price,
3225
+ itemId: item.id
3226
+ });
3227
+ } catch (e) {
3228
+ toast.error(e.message);
3229
+ }
3230
+ };
3231
+ const onRemove = async () => {
3232
+ var _a;
3233
+ try {
3234
+ const addAction = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD");
3235
+ if (addAction == null ? void 0 : addAction.id) {
3236
+ await removeItem({
3237
+ itemId: addAction.id
3238
+ });
3239
+ } else {
3240
+ toast.warning("Cannot remove item, set quantity to 0 instead");
3241
+ await updateItem({
3242
+ quantity: 0,
3243
+ itemId: item.id
3244
+ });
3245
+ }
3246
+ } catch (e) {
3247
+ toast.error(e.message);
3248
+ }
3249
+ };
3250
+ return /* @__PURE__ */ jsxs(
3251
+ "div",
3252
+ {
3253
+ className: "bg-ui-bg-subtle shadow-elevation-card-rest my-2 rounded-xl ",
3254
+ children: [
3255
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-x-2 gap-y-2 p-3 text-sm md:flex-row", children: [
3256
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center justify-between", children: [
3257
+ /* @__PURE__ */ jsx("div", { className: "flex flex-row items-center gap-x-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
3258
+ /* @__PURE__ */ jsxs("div", { children: [
3259
+ /* @__PURE__ */ jsxs(Text, { className: "txt-small", as: "span", weight: "plus", children: [
3260
+ item.title,
3261
+ " "
3262
+ ] }),
3263
+ item.variant_sku && /* @__PURE__ */ jsxs("span", { children: [
3264
+ "(",
3265
+ item.variant_sku,
3266
+ ")"
3267
+ ] })
3268
+ ] }),
3269
+ /* @__PURE__ */ jsx(Text, { as: "div", className: "text-ui-fg-subtle txt-small", children: item.product_title })
3270
+ ] }) }),
3271
+ isItemUpdated && /* @__PURE__ */ jsx(
3272
+ Badge,
3273
+ {
3274
+ size: "2xsmall",
3275
+ rounded: "full",
3276
+ color: "orange",
3277
+ className: "mr-1",
3278
+ children: "Modified"
3279
+ }
3280
+ )
3281
+ ] }),
3282
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 justify-between", children: [
3283
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-grow items-center gap-2", children: [
3284
+ /* @__PURE__ */ jsx(
3285
+ Input,
3286
+ {
3287
+ className: "bg-ui-bg-base txt-small w-[67px] rounded-lg [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
3288
+ type: "number",
3289
+ min: item.detail.fulfilled_quantity,
3290
+ defaultValue: item.quantity,
3291
+ onBlur: (e) => {
3292
+ const val = e.target.value;
3293
+ const quantity = val === "" ? null : Number(val);
3294
+ if (quantity) {
3295
+ onUpdate({ quantity });
3296
+ }
3297
+ }
3298
+ }
3299
+ ),
3300
+ /* @__PURE__ */ jsx(Text, { className: "txt-small text-ui-fg-subtle", children: "Quantity" })
3301
+ ] }),
3302
+ /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle txt-small mr-2 flex flex-shrink-0", children: /* @__PURE__ */ jsx(
3303
+ Amount,
3304
+ {
3305
+ currencyCode,
3306
+ amount: item.total,
3307
+ originalAmount: originalItem == null ? void 0 : originalItem.total
3308
+ }
3309
+ ) })
3310
+ ] })
3311
+ ] }),
3312
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-2 p-3 md:grid-cols-2", children: [
3313
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
3314
+ /* @__PURE__ */ jsx(Label, { children: "Price" }),
3315
+ /* @__PURE__ */ jsx(Hint, { className: "!mt-1", children: "Override the unit price of this product" })
3316
+ ] }),
3317
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsx("div", { className: "flex-grow", children: /* @__PURE__ */ jsx(
3318
+ CurrencyInput,
3319
+ {
3320
+ symbol: currencyCode,
3321
+ code: currencyCode,
3322
+ defaultValue: item.unit_price,
3323
+ type: "numeric",
3324
+ min: 0,
3325
+ onBlur: (e) => {
3326
+ onUpdate({
3327
+ unit_price: parseFloat(e.target.value),
3328
+ quantity: item.quantity
3329
+ });
3330
+ },
3331
+ className: "bg-ui-bg-field-component hover:bg-ui-bg-field-component-hover"
3332
+ }
3333
+ ) }) })
3334
+ ] }),
3335
+ /* @__PURE__ */ jsx("div", { className: "flex items-center px-3 pb-3", children: /* @__PURE__ */ jsx(
3336
+ Button,
3337
+ {
3338
+ type: "button",
3339
+ variant: "danger",
3340
+ size: "small",
3341
+ onClick: () => {
3342
+ onRemove();
3343
+ },
3344
+ children: "Remove"
3345
+ }
3346
+ ) })
3347
+ ]
3348
+ },
3349
+ item.quantity
3350
+ );
3351
+ }
3352
+ const ManageQuoteForm = ({ order }) => {
3353
+ const { order: preview } = useOrderPreview(order.id);
3354
+ const navigate = useNavigate();
3355
+ const { id: quoteId } = useParams();
3356
+ const [openProductModal, setOpenProductModal] = useState(false);
3357
+ const { mutateAsync: addItem } = useAddQuoteItem(order.id);
3358
+ const { mutateAsync: confirmQuote, isPending: isRequesting } = useConfirmQuote(order.id);
3359
+ const handleSubmit = async (e) => {
3360
+ e.preventDefault();
3361
+ try {
3362
+ await confirmQuote();
3363
+ navigate(`/quotes/${quoteId}`);
3364
+ toast.success("Successfully updated quote");
3365
+ } catch (e2) {
3366
+ toast.error("Error", {
3367
+ description: e2.message
3368
+ });
3369
+ }
3370
+ };
3371
+ const originalItemsMap = useMemo(() => {
3372
+ return new Map(order.items.map((item) => [item.id, item]));
3373
+ }, [order]);
3374
+ if (!preview) {
3375
+ return /* @__PURE__ */ jsx(Fragment, {});
3376
+ }
3377
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3378
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex h-full flex-col p-4 gap-2", children: [
3379
+ /* @__PURE__ */ jsxs("div", { children: [
3380
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 mt-8 flex items-center justify-between", children: [
3381
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Items" }),
3382
+ /* @__PURE__ */ jsx(
3383
+ Button,
3384
+ {
3385
+ type: "button",
3386
+ variant: "primary",
3387
+ size: "small",
3388
+ onClick: () => setOpenProductModal(true),
3389
+ children: "Add Item"
3390
+ }
3391
+ )
3392
+ ] }),
3393
+ preview.items.map((item) => /* @__PURE__ */ jsx(
3394
+ ManageItem,
3395
+ {
3396
+ originalItem: originalItemsMap.get(item.id),
3397
+ item,
3398
+ orderId: order.id,
3399
+ currencyCode: order.currency_code
3400
+ },
3401
+ item.id
3402
+ ))
3403
+ ] }),
3404
+ /* @__PURE__ */ jsxs("div", { className: "mt-8 border-y border-dotted py-4", children: [
3405
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
3406
+ /* @__PURE__ */ jsx("span", { className: "txt-small text-ui-fg-subtle", children: "Current Total" }),
3407
+ /* @__PURE__ */ jsx("span", { className: "txt-small text-ui-fg-subtle", children: formatCurrency(order.total, order.currency_code) })
3408
+ ] }),
3409
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
3410
+ /* @__PURE__ */ jsx("span", { className: "txt-small text-ui-fg-subtle", children: "New Total" }),
3411
+ /* @__PURE__ */ jsx("span", { className: "txt-small text-ui-fg-subtle", children: formatCurrency(preview.total, order.currency_code) })
3412
+ ] })
3413
+ ] }),
3414
+ /* @__PURE__ */ jsx("div", { className: "flex w-full items-center justify-end gap-x-4", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-x-2", children: /* @__PURE__ */ jsx(
3415
+ Button,
3416
+ {
3417
+ type: "submit",
3418
+ variant: "primary",
3419
+ size: "small",
3420
+ disabled: isRequesting,
3421
+ children: "Confirm Edit"
3422
+ },
3423
+ "submit-button"
3424
+ ) }) })
3425
+ ] }),
3426
+ /* @__PURE__ */ jsx(FocusModal, { open: openProductModal, onOpenChange: setOpenProductModal, children: /* @__PURE__ */ jsxs(FocusModal.Content, { children: [
3427
+ /* @__PURE__ */ jsx(FocusModal.Header, { children: /* @__PURE__ */ jsx(FocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Add Product" }) }) }),
3428
+ /* @__PURE__ */ jsx(FocusModal.Body, { children: /* @__PURE__ */ jsx(
3429
+ ProductSelector,
3430
+ {
3431
+ selectedProductIds: order.items.map(
3432
+ (item) => item.variant_id ?? ""
3433
+ ),
3434
+ onSelectProduct: (variant) => {
3435
+ var _a, _b;
3436
+ if (!((_a = variant.prices) == null ? void 0 : _a[0].amount)) {
3437
+ toast.error("Product price not found");
3438
+ return;
3439
+ }
3440
+ addItem({
3441
+ items: [
3442
+ {
3443
+ variant_id: variant.id,
3444
+ quantity: 1,
3445
+ unit_price: (_b = variant.prices) == null ? void 0 : _b[0].amount
3446
+ }
3447
+ ]
3448
+ });
3449
+ setOpenProductModal(false);
3450
+ }
3451
+ }
3452
+ ) })
3453
+ ] }) })
3454
+ ] });
3455
+ };
3456
+ const QuoteManage = () => {
3457
+ const { id } = useParams();
3458
+ const { quote, isLoading } = useQuote(id, {
3459
+ fields: "*draft_order.customer"
3460
+ });
3461
+ if (isLoading) {
3462
+ return /* @__PURE__ */ jsx(Fragment, {});
3463
+ }
3464
+ if (!quote) {
3465
+ throw "quote not found";
3466
+ }
3467
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3468
+ /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
3469
+ /* @__PURE__ */ jsx(Heading, { className: "flex items-center justify-between px-6 py-4", children: "Manage Quote" }),
3470
+ /* @__PURE__ */ jsx(ManageQuoteForm, { order: quote.draft_order })
3471
+ ] }),
3472
+ /* @__PURE__ */ jsx(Toaster, {})
3473
+ ] });
3474
+ };
3475
3475
  const widgetModule = { widgets: [] };
3476
3476
  const routeModule = {
3477
3477
  routes: [
@@ -3483,13 +3483,13 @@ const routeModule = {
3483
3483
  Component: QuoteDetails,
3484
3484
  path: "/quotes/:id"
3485
3485
  },
3486
- {
3487
- Component: QuoteManage,
3488
- path: "/quotes/:id/manage"
3489
- },
3490
3486
  {
3491
3487
  Component: CreateQuote,
3492
3488
  path: "/quotes/create"
3489
+ },
3490
+ {
3491
+ Component: QuoteManage,
3492
+ path: "/quotes/:id/manage"
3493
3493
  }
3494
3494
  ]
3495
3495
  };