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