@cimplify/sdk 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.d.mts +2 -2
- package/dist/advanced.d.ts +2 -2
- package/dist/{chunk-4JSRPSNA.js → chunk-R4AKAGZQ.js} +162 -0
- package/dist/{chunk-MISITC47.mjs → chunk-REXW2PET.mjs} +159 -1
- package/dist/{index-DBM89ktY.d.ts → index-Cjfczg2W.d.ts} +2 -2
- package/dist/{index-2JxW7TuQ.d.mts → index-D4-b5OZO.d.mts} +2 -2
- package/dist/{index-BAu-zmIP.d.ts → index-DijjnO-u.d.mts} +73 -2
- package/dist/{index-DT-24csu.d.mts → index-DwvzjdGi.d.ts} +73 -2
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +25 -9
- package/dist/index.mjs +1 -1
- package/dist/{payment-5a21yzi7.d.mts → payment-BeLHpQMo.d.mts} +155 -1
- package/dist/{payment-5a21yzi7.d.ts → payment-BeLHpQMo.d.ts} +155 -1
- package/dist/{price-BS0Z5Oi9.d.ts → price-C6gfys5B.d.ts} +1 -1
- package/dist/{price-CGPMlQUk.d.mts → price-Dvl1p9AM.d.mts} +1 -1
- package/dist/react.d.mts +86 -4
- package/dist/react.d.ts +86 -4
- package/dist/react.js +1583 -340
- package/dist/react.mjs +1260 -24
- package/dist/styles.css +1 -1
- package/dist/utils.d.mts +3 -3
- package/dist/utils.d.ts +3 -3
- package/package.json +1 -1
- package/registry/cart-summary.json +1 -1
- package/registry/product-card.json +1 -1
- package/registry/product-customizer.json +1 -1
- package/registry/product-page.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { DURATION_UNIT, getVariantDisplayName, PRODUCT_TYPE, createCimplifyClient, RENDER_HINT } from './chunk-
|
|
3
|
-
export { getVariantDisplayName } from './chunk-
|
|
2
|
+
import { DURATION_UNIT, getVariantDisplayName, INPUT_FIELD_TYPE, PRODUCT_TYPE, createCimplifyClient, RENDER_HINT } from './chunk-REXW2PET.mjs';
|
|
3
|
+
export { getVariantDisplayName } from './chunk-REXW2PET.mjs';
|
|
4
4
|
import { ELEMENT_TYPES, EVENT_TYPES } from './chunk-3J4PPSMI.mjs';
|
|
5
5
|
import { isSupportedCurrency, formatPrice, parsePrice, getUnitPriceAtQuantity, isOnSale, getDiscountPercentage, getBasePrice, getPriceRange, formatPriceRange } from './chunk-E3HC2YAE.mjs';
|
|
6
|
-
import
|
|
6
|
+
import React10, { createContext, useRef, useState, useCallback, useEffect, useContext, useMemo, useSyncExternalStore, useId } from 'react';
|
|
7
7
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
8
8
|
import { clsx } from 'clsx';
|
|
9
9
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -565,7 +565,8 @@ function mapServerCart(serverCart) {
|
|
|
565
565
|
confirmationCode: item.confirmation_code || void 0,
|
|
566
566
|
serviceStatus: item.service_status || void 0,
|
|
567
567
|
bundleResolved: item.bundle_resolved || void 0,
|
|
568
|
-
compositeResolved: item.composite_resolved || void 0
|
|
568
|
+
compositeResolved: item.composite_resolved || void 0,
|
|
569
|
+
customerInputs: item.customer_inputs || void 0
|
|
569
570
|
});
|
|
570
571
|
});
|
|
571
572
|
return {
|
|
@@ -785,7 +786,8 @@ function createCartStore(params) {
|
|
|
785
786
|
scheduled_start: normalizedOptions.scheduledStart,
|
|
786
787
|
scheduled_end: normalizedOptions.scheduledEnd,
|
|
787
788
|
staff_id: normalizedOptions.staffId,
|
|
788
|
-
resource_id: normalizedOptions.resourceId
|
|
789
|
+
resource_id: normalizedOptions.resourceId,
|
|
790
|
+
customer_inputs: normalizedOptions.customerInputs
|
|
789
791
|
});
|
|
790
792
|
if (!result.ok) {
|
|
791
793
|
throw result.error;
|
|
@@ -1423,14 +1425,14 @@ function CimplifyCheckout({
|
|
|
1423
1425
|
resolvedCartRef.current = resolvedCart;
|
|
1424
1426
|
const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
|
|
1425
1427
|
const isDark = appearance?.theme === "dark";
|
|
1426
|
-
const emitStatus =
|
|
1428
|
+
const emitStatus = React10.useEffectEvent(
|
|
1427
1429
|
(nextStatus, context = {}) => {
|
|
1428
1430
|
setStatus(nextStatus);
|
|
1429
1431
|
setStatusText(context.display_text || "");
|
|
1430
1432
|
onStatusChange?.(nextStatus, context);
|
|
1431
1433
|
}
|
|
1432
1434
|
);
|
|
1433
|
-
const fireError =
|
|
1435
|
+
const fireError = React10.useEffectEvent(
|
|
1434
1436
|
(error) => {
|
|
1435
1437
|
onError?.(error);
|
|
1436
1438
|
}
|
|
@@ -1536,7 +1538,7 @@ function CimplifyCheckout({
|
|
|
1536
1538
|
activeCheckoutRef.current = null;
|
|
1537
1539
|
};
|
|
1538
1540
|
}, []);
|
|
1539
|
-
const handleSubmit =
|
|
1541
|
+
const handleSubmit = React10.useEffectEvent(async () => {
|
|
1540
1542
|
if (isSubmitting || isInitializing || !resolvedCartId) {
|
|
1541
1543
|
if (!resolvedCartId && !isInitializing) {
|
|
1542
1544
|
const message = "Your cart is empty. Add items before checkout.";
|
|
@@ -2847,6 +2849,84 @@ function useOrders(options = {}) {
|
|
|
2847
2849
|
const { data, isLoading, error, refetch } = ordersQuery(options);
|
|
2848
2850
|
return { orders: data ?? [], isLoading, error, refetch };
|
|
2849
2851
|
}
|
|
2852
|
+
function useSubscriptions(options = {}) {
|
|
2853
|
+
const { client } = useCimplifyClient();
|
|
2854
|
+
const { status, enabled = true } = options;
|
|
2855
|
+
const [subscriptions, setSubscriptions] = useState([]);
|
|
2856
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
2857
|
+
const [error, setError] = useState(null);
|
|
2858
|
+
const fetch2 = useCallback(async () => {
|
|
2859
|
+
if (!enabled) return;
|
|
2860
|
+
setIsLoading(true);
|
|
2861
|
+
setError(null);
|
|
2862
|
+
try {
|
|
2863
|
+
const result = await client.subscriptions.list();
|
|
2864
|
+
if (result.ok) {
|
|
2865
|
+
const filtered = status ? result.value.filter((s) => s.status === status) : result.value;
|
|
2866
|
+
setSubscriptions(filtered);
|
|
2867
|
+
} else {
|
|
2868
|
+
setError(result.error);
|
|
2869
|
+
}
|
|
2870
|
+
} catch (e) {
|
|
2871
|
+
setError(e);
|
|
2872
|
+
} finally {
|
|
2873
|
+
setIsLoading(false);
|
|
2874
|
+
}
|
|
2875
|
+
}, [client, enabled, status]);
|
|
2876
|
+
useEffect(() => {
|
|
2877
|
+
void fetch2();
|
|
2878
|
+
}, [fetch2]);
|
|
2879
|
+
return { subscriptions, isLoading, error, refetch: fetch2 };
|
|
2880
|
+
}
|
|
2881
|
+
function useSubscription(id, options = {}) {
|
|
2882
|
+
const { client } = useCimplifyClient();
|
|
2883
|
+
const { enabled = true } = options;
|
|
2884
|
+
const normalizedId = (id || "").trim();
|
|
2885
|
+
const [subscription, setSubscription] = useState(null);
|
|
2886
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
2887
|
+
const [error, setError] = useState(null);
|
|
2888
|
+
const fetch2 = useCallback(async () => {
|
|
2889
|
+
if (!enabled || !normalizedId) return;
|
|
2890
|
+
setIsLoading(true);
|
|
2891
|
+
setError(null);
|
|
2892
|
+
try {
|
|
2893
|
+
const result = await client.subscriptions.get(normalizedId);
|
|
2894
|
+
if (result.ok) {
|
|
2895
|
+
setSubscription(result.value);
|
|
2896
|
+
} else {
|
|
2897
|
+
setError(result.error);
|
|
2898
|
+
}
|
|
2899
|
+
} catch (e) {
|
|
2900
|
+
setError(e);
|
|
2901
|
+
} finally {
|
|
2902
|
+
setIsLoading(false);
|
|
2903
|
+
}
|
|
2904
|
+
}, [client, enabled, normalizedId]);
|
|
2905
|
+
useEffect(() => {
|
|
2906
|
+
void fetch2();
|
|
2907
|
+
}, [fetch2]);
|
|
2908
|
+
const cancel = useCallback(async (reason) => {
|
|
2909
|
+
if (!normalizedId) return;
|
|
2910
|
+
await client.subscriptions.cancel(normalizedId, reason);
|
|
2911
|
+
void fetch2();
|
|
2912
|
+
}, [client, normalizedId, fetch2]);
|
|
2913
|
+
const pause = useCallback(async () => {
|
|
2914
|
+
if (!normalizedId) return;
|
|
2915
|
+
await client.subscriptions.pause(normalizedId);
|
|
2916
|
+
void fetch2();
|
|
2917
|
+
}, [client, normalizedId, fetch2]);
|
|
2918
|
+
const resume = useCallback(async () => {
|
|
2919
|
+
if (!normalizedId) return;
|
|
2920
|
+
await client.subscriptions.resume(normalizedId);
|
|
2921
|
+
void fetch2();
|
|
2922
|
+
}, [client, normalizedId, fetch2]);
|
|
2923
|
+
const skipNext = useCallback(async () => {
|
|
2924
|
+
if (!normalizedId) return;
|
|
2925
|
+
await client.subscriptions.skipNextRenewal(normalizedId);
|
|
2926
|
+
void fetch2();
|
|
2927
|
+
}, [client, normalizedId, fetch2]);
|
|
2928
|
+
return { subscription, isLoading, error, cancel, pause, resume, skipNext, refetch: fetch2 };
|
|
2929
|
+
}
|
|
2850
2930
|
|
|
2851
2931
|
// src/react/hooks/use-services.ts
|
|
2852
2932
|
var servicesQuery = createCachedQuery({
|
|
@@ -4770,6 +4850,880 @@ function VolumePricing({
|
|
|
4770
4850
|
}
|
|
4771
4851
|
);
|
|
4772
4852
|
}
|
|
4853
|
+
function CustomerInputFields({
|
|
4854
|
+
fields,
|
|
4855
|
+
values,
|
|
4856
|
+
onChange,
|
|
4857
|
+
onFileUpload,
|
|
4858
|
+
className,
|
|
4859
|
+
classNames
|
|
4860
|
+
}) {
|
|
4861
|
+
const clientContext = useOptionalCimplifyClient();
|
|
4862
|
+
if (fields.length === 0) return null;
|
|
4863
|
+
const sorted = [...fields].sort((a, b) => a.display_order - b.display_order);
|
|
4864
|
+
const setValue = useCallback(
|
|
4865
|
+
(fieldId, value) => {
|
|
4866
|
+
onChange({ ...values, [fieldId]: value });
|
|
4867
|
+
},
|
|
4868
|
+
[values, onChange]
|
|
4869
|
+
);
|
|
4870
|
+
const defaultFileUpload = useCallback(
|
|
4871
|
+
async (file) => {
|
|
4872
|
+
if (onFileUpload) return onFileUpload(file, {});
|
|
4873
|
+
if (!clientContext?.client) throw new Error("No upload provider available");
|
|
4874
|
+
const result = await clientContext.client.uploads.upload(file);
|
|
4875
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
4876
|
+
return result.value.url;
|
|
4877
|
+
},
|
|
4878
|
+
[onFileUpload, clientContext]
|
|
4879
|
+
);
|
|
4880
|
+
return /* @__PURE__ */ jsx("div", { "data-cimplify-customer-inputs": true, className: cn("space-y-4", className, classNames?.root), children: sorted.map((field) => /* @__PURE__ */ jsx(
|
|
4881
|
+
InputField,
|
|
4882
|
+
{
|
|
4883
|
+
field,
|
|
4884
|
+
value: values[field.id],
|
|
4885
|
+
onValueChange: (value) => setValue(field.id, value),
|
|
4886
|
+
onFileUpload: onFileUpload ?? (clientContext?.client ? (_file, _field) => defaultFileUpload(_file) : void 0),
|
|
4887
|
+
classNames
|
|
4888
|
+
},
|
|
4889
|
+
field.id
|
|
4890
|
+
)) });
|
|
4891
|
+
}
|
|
4892
|
+
function InputField({
|
|
4893
|
+
field,
|
|
4894
|
+
value,
|
|
4895
|
+
onValueChange,
|
|
4896
|
+
onFileUpload,
|
|
4897
|
+
classNames
|
|
4898
|
+
}) {
|
|
4899
|
+
const hasPriceAdjustment = field.price_adjustment != null && parsePrice(field.price_adjustment) > 0;
|
|
4900
|
+
return /* @__PURE__ */ jsxs("div", { "data-cimplify-customer-input": true, "data-field-type": field.field_type, className: classNames?.field, children: [
|
|
4901
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
|
|
4902
|
+
/* @__PURE__ */ jsx("label", { className: cn("text-sm font-semibold", classNames?.label), children: field.name }),
|
|
4903
|
+
field.is_required && /* @__PURE__ */ jsx("span", { className: cn("text-xs text-destructive", classNames?.required), children: "Required" }),
|
|
4904
|
+
hasPriceAdjustment && /* @__PURE__ */ jsxs("span", { className: cn("text-xs text-muted-foreground", classNames?.priceAdjustment), children: [
|
|
4905
|
+
"+",
|
|
4906
|
+
/* @__PURE__ */ jsx(Price, { amount: field.price_adjustment })
|
|
4907
|
+
] })
|
|
4908
|
+
] }),
|
|
4909
|
+
field.help_text && /* @__PURE__ */ jsx("p", { className: cn("text-xs text-muted-foreground mb-1.5", classNames?.helpText), children: field.help_text }),
|
|
4910
|
+
/* @__PURE__ */ jsx(
|
|
4911
|
+
FieldInput,
|
|
4912
|
+
{
|
|
4913
|
+
field,
|
|
4914
|
+
value,
|
|
4915
|
+
onValueChange,
|
|
4916
|
+
onFileUpload,
|
|
4917
|
+
classNames
|
|
4918
|
+
}
|
|
4919
|
+
)
|
|
4920
|
+
] });
|
|
4921
|
+
}
|
|
4922
|
+
function FieldInput({
|
|
4923
|
+
field,
|
|
4924
|
+
value,
|
|
4925
|
+
onValueChange,
|
|
4926
|
+
onFileUpload,
|
|
4927
|
+
classNames
|
|
4928
|
+
}) {
|
|
4929
|
+
const inputClass = cn(
|
|
4930
|
+
"w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring",
|
|
4931
|
+
classNames?.input
|
|
4932
|
+
);
|
|
4933
|
+
switch (field.field_type) {
|
|
4934
|
+
case INPUT_FIELD_TYPE.Text:
|
|
4935
|
+
case INPUT_FIELD_TYPE.Url:
|
|
4936
|
+
return /* @__PURE__ */ jsx(
|
|
4937
|
+
"input",
|
|
4938
|
+
{
|
|
4939
|
+
type: field.field_type === INPUT_FIELD_TYPE.Url ? "url" : "text",
|
|
4940
|
+
value: typeof value === "string" ? value : "",
|
|
4941
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
4942
|
+
placeholder: field.placeholder,
|
|
4943
|
+
required: field.is_required,
|
|
4944
|
+
maxLength: field.validation?.max_length ?? void 0,
|
|
4945
|
+
className: inputClass
|
|
4946
|
+
}
|
|
4947
|
+
);
|
|
4948
|
+
case INPUT_FIELD_TYPE.Textarea:
|
|
4949
|
+
return /* @__PURE__ */ jsx(
|
|
4950
|
+
"textarea",
|
|
4951
|
+
{
|
|
4952
|
+
value: typeof value === "string" ? value : "",
|
|
4953
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
4954
|
+
placeholder: field.placeholder,
|
|
4955
|
+
required: field.is_required,
|
|
4956
|
+
maxLength: field.validation?.max_length ?? void 0,
|
|
4957
|
+
rows: 3,
|
|
4958
|
+
className: cn(inputClass, "resize-none", classNames?.textarea)
|
|
4959
|
+
}
|
|
4960
|
+
);
|
|
4961
|
+
case INPUT_FIELD_TYPE.Number:
|
|
4962
|
+
return /* @__PURE__ */ jsx(
|
|
4963
|
+
"input",
|
|
4964
|
+
{
|
|
4965
|
+
type: "number",
|
|
4966
|
+
value: typeof value === "number" ? value : "",
|
|
4967
|
+
onChange: (e) => onValueChange(e.target.value ? parseFloat(e.target.value) : void 0),
|
|
4968
|
+
placeholder: field.placeholder,
|
|
4969
|
+
required: field.is_required,
|
|
4970
|
+
min: field.validation?.min_value ?? void 0,
|
|
4971
|
+
max: field.validation?.max_value ?? void 0,
|
|
4972
|
+
className: inputClass
|
|
4973
|
+
}
|
|
4974
|
+
);
|
|
4975
|
+
case INPUT_FIELD_TYPE.Select:
|
|
4976
|
+
return /* @__PURE__ */ jsxs(
|
|
4977
|
+
"select",
|
|
4978
|
+
{
|
|
4979
|
+
value: typeof value === "string" ? value : "",
|
|
4980
|
+
onChange: (e) => onValueChange(e.target.value || void 0),
|
|
4981
|
+
required: field.is_required,
|
|
4982
|
+
className: cn(inputClass, classNames?.select),
|
|
4983
|
+
children: [
|
|
4984
|
+
/* @__PURE__ */ jsx("option", { value: "", children: field.placeholder || "Select..." }),
|
|
4985
|
+
(field.options || []).map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
|
|
4986
|
+
]
|
|
4987
|
+
}
|
|
4988
|
+
);
|
|
4989
|
+
case INPUT_FIELD_TYPE.Radio:
|
|
4990
|
+
return /* @__PURE__ */ jsx("div", { className: cn("space-y-2", classNames?.radioGroup), children: (field.options || []).map((opt) => /* @__PURE__ */ jsxs(
|
|
4991
|
+
"label",
|
|
4992
|
+
{
|
|
4993
|
+
className: cn(
|
|
4994
|
+
"flex items-center gap-2 text-sm cursor-pointer",
|
|
4995
|
+
classNames?.radioOption
|
|
4996
|
+
),
|
|
4997
|
+
children: [
|
|
4998
|
+
/* @__PURE__ */ jsx(
|
|
4999
|
+
"input",
|
|
5000
|
+
{
|
|
5001
|
+
type: "radio",
|
|
5002
|
+
name: field.id,
|
|
5003
|
+
value: opt,
|
|
5004
|
+
checked: value === opt,
|
|
5005
|
+
onChange: () => onValueChange(opt),
|
|
5006
|
+
className: "accent-primary"
|
|
5007
|
+
}
|
|
5008
|
+
),
|
|
5009
|
+
opt
|
|
5010
|
+
]
|
|
5011
|
+
},
|
|
5012
|
+
opt
|
|
5013
|
+
)) });
|
|
5014
|
+
case INPUT_FIELD_TYPE.Checkbox:
|
|
5015
|
+
return /* @__PURE__ */ jsxs("label", { className: cn("flex items-center gap-2 text-sm cursor-pointer", classNames?.checkboxLabel), children: [
|
|
5016
|
+
/* @__PURE__ */ jsx(
|
|
5017
|
+
"input",
|
|
5018
|
+
{
|
|
5019
|
+
type: "checkbox",
|
|
5020
|
+
checked: value === true,
|
|
5021
|
+
onChange: (e) => onValueChange(e.target.checked),
|
|
5022
|
+
className: "accent-primary w-4 h-4"
|
|
5023
|
+
}
|
|
5024
|
+
),
|
|
5025
|
+
field.placeholder || field.name
|
|
5026
|
+
] });
|
|
5027
|
+
case INPUT_FIELD_TYPE.Color:
|
|
5028
|
+
return /* @__PURE__ */ jsx(
|
|
5029
|
+
"input",
|
|
5030
|
+
{
|
|
5031
|
+
type: "color",
|
|
5032
|
+
value: typeof value === "string" ? value : "#000000",
|
|
5033
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
5034
|
+
className: cn("w-12 h-10 rounded-md border border-input cursor-pointer", classNames?.colorInput)
|
|
5035
|
+
}
|
|
5036
|
+
);
|
|
5037
|
+
case INPUT_FIELD_TYPE.Date:
|
|
5038
|
+
return /* @__PURE__ */ jsx(
|
|
5039
|
+
"input",
|
|
5040
|
+
{
|
|
5041
|
+
type: "date",
|
|
5042
|
+
value: typeof value === "string" ? value : "",
|
|
5043
|
+
onChange: (e) => onValueChange(e.target.value || void 0),
|
|
5044
|
+
required: field.is_required,
|
|
5045
|
+
className: inputClass
|
|
5046
|
+
}
|
|
5047
|
+
);
|
|
5048
|
+
case INPUT_FIELD_TYPE.File:
|
|
5049
|
+
case INPUT_FIELD_TYPE.Image:
|
|
5050
|
+
return /* @__PURE__ */ jsx(
|
|
5051
|
+
FileUploadInput,
|
|
5052
|
+
{
|
|
5053
|
+
field,
|
|
5054
|
+
value,
|
|
5055
|
+
onValueChange,
|
|
5056
|
+
onFileUpload,
|
|
5057
|
+
classNames
|
|
5058
|
+
}
|
|
5059
|
+
);
|
|
5060
|
+
case INPUT_FIELD_TYPE.Email:
|
|
5061
|
+
return /* @__PURE__ */ jsx(
|
|
5062
|
+
"input",
|
|
5063
|
+
{
|
|
5064
|
+
type: "email",
|
|
5065
|
+
value: typeof value === "string" ? value : "",
|
|
5066
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
5067
|
+
placeholder: field.placeholder || "email@example.com",
|
|
5068
|
+
required: field.is_required,
|
|
5069
|
+
className: inputClass
|
|
5070
|
+
}
|
|
5071
|
+
);
|
|
5072
|
+
case INPUT_FIELD_TYPE.DateTime: {
|
|
5073
|
+
const dtLocalValue = typeof value === "string" && value.includes("T") ? value.slice(0, 16) : typeof value === "string" ? value : "";
|
|
5074
|
+
return /* @__PURE__ */ jsx(
|
|
5075
|
+
"input",
|
|
5076
|
+
{
|
|
5077
|
+
type: "datetime-local",
|
|
5078
|
+
value: dtLocalValue,
|
|
5079
|
+
onChange: (e) => {
|
|
5080
|
+
if (!e.target.value) {
|
|
5081
|
+
onValueChange(void 0);
|
|
5082
|
+
return;
|
|
5083
|
+
}
|
|
5084
|
+
const date = new Date(e.target.value);
|
|
5085
|
+
onValueChange(Number.isNaN(date.getTime()) ? e.target.value : date.toISOString());
|
|
5086
|
+
},
|
|
5087
|
+
required: field.is_required,
|
|
5088
|
+
className: inputClass
|
|
5089
|
+
}
|
|
5090
|
+
);
|
|
5091
|
+
}
|
|
5092
|
+
case INPUT_FIELD_TYPE.Time:
|
|
5093
|
+
return /* @__PURE__ */ jsx(
|
|
5094
|
+
"input",
|
|
5095
|
+
{
|
|
5096
|
+
type: "time",
|
|
5097
|
+
value: typeof value === "string" ? value : "",
|
|
5098
|
+
onChange: (e) => onValueChange(e.target.value || void 0),
|
|
5099
|
+
required: field.is_required,
|
|
5100
|
+
className: inputClass
|
|
5101
|
+
}
|
|
5102
|
+
);
|
|
5103
|
+
case INPUT_FIELD_TYPE.MultiSelect:
|
|
5104
|
+
return /* @__PURE__ */ jsx(
|
|
5105
|
+
MultiSelectInput,
|
|
5106
|
+
{
|
|
5107
|
+
field,
|
|
5108
|
+
value,
|
|
5109
|
+
onValueChange,
|
|
5110
|
+
classNames
|
|
5111
|
+
}
|
|
5112
|
+
);
|
|
5113
|
+
case INPUT_FIELD_TYPE.DateRange:
|
|
5114
|
+
return /* @__PURE__ */ jsx(
|
|
5115
|
+
DateRangeInput,
|
|
5116
|
+
{
|
|
5117
|
+
field,
|
|
5118
|
+
value,
|
|
5119
|
+
onValueChange,
|
|
5120
|
+
classNames,
|
|
5121
|
+
inputClass
|
|
5122
|
+
}
|
|
5123
|
+
);
|
|
5124
|
+
case INPUT_FIELD_TYPE.Address:
|
|
5125
|
+
return /* @__PURE__ */ jsx(
|
|
5126
|
+
AddressInput,
|
|
5127
|
+
{
|
|
5128
|
+
field,
|
|
5129
|
+
value,
|
|
5130
|
+
onValueChange,
|
|
5131
|
+
classNames,
|
|
5132
|
+
inputClass
|
|
5133
|
+
}
|
|
5134
|
+
);
|
|
5135
|
+
case INPUT_FIELD_TYPE.Location:
|
|
5136
|
+
return /* @__PURE__ */ jsx(
|
|
5137
|
+
LocationInput,
|
|
5138
|
+
{
|
|
5139
|
+
field,
|
|
5140
|
+
value,
|
|
5141
|
+
onValueChange,
|
|
5142
|
+
classNames,
|
|
5143
|
+
inputClass
|
|
5144
|
+
}
|
|
5145
|
+
);
|
|
5146
|
+
case INPUT_FIELD_TYPE.Phone:
|
|
5147
|
+
return /* @__PURE__ */ jsx(
|
|
5148
|
+
PhoneInput,
|
|
5149
|
+
{
|
|
5150
|
+
field,
|
|
5151
|
+
value,
|
|
5152
|
+
onValueChange,
|
|
5153
|
+
classNames,
|
|
5154
|
+
inputClass
|
|
5155
|
+
}
|
|
5156
|
+
);
|
|
5157
|
+
case INPUT_FIELD_TYPE.Signature:
|
|
5158
|
+
return /* @__PURE__ */ jsx(
|
|
5159
|
+
SignatureInput,
|
|
5160
|
+
{
|
|
5161
|
+
field,
|
|
5162
|
+
value,
|
|
5163
|
+
onValueChange,
|
|
5164
|
+
classNames
|
|
5165
|
+
}
|
|
5166
|
+
);
|
|
5167
|
+
default:
|
|
5168
|
+
return /* @__PURE__ */ jsx(
|
|
5169
|
+
"input",
|
|
5170
|
+
{
|
|
5171
|
+
type: "text",
|
|
5172
|
+
value: typeof value === "string" ? value : "",
|
|
5173
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
5174
|
+
placeholder: field.placeholder,
|
|
5175
|
+
className: inputClass
|
|
5176
|
+
}
|
|
5177
|
+
);
|
|
5178
|
+
}
|
|
5179
|
+
}
|
|
5180
|
+
function FileUploadInput({
|
|
5181
|
+
field,
|
|
5182
|
+
value,
|
|
5183
|
+
onValueChange,
|
|
5184
|
+
onFileUpload,
|
|
5185
|
+
classNames
|
|
5186
|
+
}) {
|
|
5187
|
+
const [isUploading, setIsUploading] = React10.useState(false);
|
|
5188
|
+
const fileUrl = typeof value === "string" ? value : void 0;
|
|
5189
|
+
const acceptedFormats = field.validation?.accepted_formats;
|
|
5190
|
+
const accept = acceptedFormats ? acceptedFormats.map((f) => `.${f}`).join(",") : field.field_type === INPUT_FIELD_TYPE.Image ? "image/*" : void 0;
|
|
5191
|
+
const handleFile = async (file) => {
|
|
5192
|
+
if (!onFileUpload) return;
|
|
5193
|
+
if (field.validation?.max_size_mb) {
|
|
5194
|
+
const maxBytes = field.validation.max_size_mb * 1024 * 1024;
|
|
5195
|
+
if (file.size > maxBytes) {
|
|
5196
|
+
return;
|
|
5197
|
+
}
|
|
5198
|
+
}
|
|
5199
|
+
setIsUploading(true);
|
|
5200
|
+
try {
|
|
5201
|
+
const url = await onFileUpload(file, field);
|
|
5202
|
+
onValueChange(url);
|
|
5203
|
+
} finally {
|
|
5204
|
+
setIsUploading(false);
|
|
5205
|
+
}
|
|
5206
|
+
};
|
|
5207
|
+
return /* @__PURE__ */ jsx("div", { className: cn("space-y-2", classNames?.fileInput), children: fileUrl ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
5208
|
+
field.field_type === INPUT_FIELD_TYPE.Image && /* @__PURE__ */ jsx("img", { src: fileUrl, alt: "Uploaded", className: "w-16 h-16 object-cover rounded-md border border-border" }),
|
|
5209
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground truncate", children: fileUrl.split("/").pop() }) }),
|
|
5210
|
+
/* @__PURE__ */ jsx(
|
|
5211
|
+
"button",
|
|
5212
|
+
{
|
|
5213
|
+
type: "button",
|
|
5214
|
+
onClick: () => onValueChange(void 0),
|
|
5215
|
+
className: "text-xs text-muted-foreground hover:text-destructive transition-colors",
|
|
5216
|
+
children: "Remove"
|
|
5217
|
+
}
|
|
5218
|
+
)
|
|
5219
|
+
] }) : /* @__PURE__ */ jsxs("label", { className: "flex flex-col items-center justify-center w-full h-24 border-2 border-dashed border-border rounded-lg cursor-pointer hover:border-primary/40 transition-colors", children: [
|
|
5220
|
+
/* @__PURE__ */ jsx(
|
|
5221
|
+
"input",
|
|
5222
|
+
{
|
|
5223
|
+
type: "file",
|
|
5224
|
+
accept,
|
|
5225
|
+
onChange: (e) => {
|
|
5226
|
+
const file = e.target.files?.[0];
|
|
5227
|
+
if (file) void handleFile(file);
|
|
5228
|
+
},
|
|
5229
|
+
className: "hidden",
|
|
5230
|
+
disabled: isUploading
|
|
5231
|
+
}
|
|
5232
|
+
),
|
|
5233
|
+
isUploading ? /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Uploading..." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5234
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: field.placeholder || `Upload ${field.field_type === INPUT_FIELD_TYPE.Image ? "image" : "file"}` }),
|
|
5235
|
+
acceptedFormats && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground/60 mt-1", children: [
|
|
5236
|
+
acceptedFormats.map((f) => f.toUpperCase()).join(", "),
|
|
5237
|
+
field.validation?.max_size_mb && ` \xB7 Max ${field.validation.max_size_mb}MB`
|
|
5238
|
+
] })
|
|
5239
|
+
] })
|
|
5240
|
+
] }) });
|
|
5241
|
+
}
|
|
5242
|
+
function MultiSelectInput({
|
|
5243
|
+
field,
|
|
5244
|
+
value,
|
|
5245
|
+
onValueChange,
|
|
5246
|
+
classNames
|
|
5247
|
+
}) {
|
|
5248
|
+
const selected = Array.isArray(value) ? value : [];
|
|
5249
|
+
const options = field.options || [];
|
|
5250
|
+
const maxSelections = field.validation?.max_selections;
|
|
5251
|
+
const toggle = (opt) => {
|
|
5252
|
+
const next = selected.includes(opt) ? selected.filter((s) => s !== opt) : maxSelections && selected.length >= maxSelections ? selected : [...selected, opt];
|
|
5253
|
+
onValueChange(next.length > 0 ? next : void 0);
|
|
5254
|
+
};
|
|
5255
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", classNames?.multiSelectGroup), children: [
|
|
5256
|
+
options.map((opt) => /* @__PURE__ */ jsxs(
|
|
5257
|
+
"label",
|
|
5258
|
+
{
|
|
5259
|
+
className: cn(
|
|
5260
|
+
"flex items-center gap-2 text-sm cursor-pointer",
|
|
5261
|
+
classNames?.multiSelectOption
|
|
5262
|
+
),
|
|
5263
|
+
children: [
|
|
5264
|
+
/* @__PURE__ */ jsx(
|
|
5265
|
+
"input",
|
|
5266
|
+
{
|
|
5267
|
+
type: "checkbox",
|
|
5268
|
+
checked: selected.includes(opt),
|
|
5269
|
+
onChange: () => toggle(opt),
|
|
5270
|
+
className: "accent-primary w-4 h-4"
|
|
5271
|
+
}
|
|
5272
|
+
),
|
|
5273
|
+
opt
|
|
5274
|
+
]
|
|
5275
|
+
},
|
|
5276
|
+
opt
|
|
5277
|
+
)),
|
|
5278
|
+
maxSelections && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
5279
|
+
selected.length,
|
|
5280
|
+
"/",
|
|
5281
|
+
maxSelections,
|
|
5282
|
+
" selected"
|
|
5283
|
+
] })
|
|
5284
|
+
] });
|
|
5285
|
+
}
|
|
5286
|
+
function DateRangeInput({
|
|
5287
|
+
field,
|
|
5288
|
+
value,
|
|
5289
|
+
onValueChange,
|
|
5290
|
+
classNames,
|
|
5291
|
+
inputClass
|
|
5292
|
+
}) {
|
|
5293
|
+
const range = value && typeof value === "object" ? value : {};
|
|
5294
|
+
const update = (key, v) => {
|
|
5295
|
+
const next = { ...range, [key]: v };
|
|
5296
|
+
onValueChange(next.start || next.end ? next : void 0);
|
|
5297
|
+
};
|
|
5298
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-2 gap-3", classNames?.dateRangeInput), children: [
|
|
5299
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5300
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs text-muted-foreground mb-1 block", children: "Start" }),
|
|
5301
|
+
/* @__PURE__ */ jsx(
|
|
5302
|
+
"input",
|
|
5303
|
+
{
|
|
5304
|
+
type: "date",
|
|
5305
|
+
value: range.start || "",
|
|
5306
|
+
onChange: (e) => update("start", e.target.value),
|
|
5307
|
+
required: field.is_required,
|
|
5308
|
+
className: inputClass
|
|
5309
|
+
}
|
|
5310
|
+
)
|
|
5311
|
+
] }),
|
|
5312
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5313
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs text-muted-foreground mb-1 block", children: "End" }),
|
|
5314
|
+
/* @__PURE__ */ jsx(
|
|
5315
|
+
"input",
|
|
5316
|
+
{
|
|
5317
|
+
type: "date",
|
|
5318
|
+
value: range.end || "",
|
|
5319
|
+
onChange: (e) => update("end", e.target.value),
|
|
5320
|
+
required: field.is_required,
|
|
5321
|
+
className: inputClass
|
|
5322
|
+
}
|
|
5323
|
+
)
|
|
5324
|
+
] })
|
|
5325
|
+
] });
|
|
5326
|
+
}
|
|
5327
|
+
function AddressInput({
|
|
5328
|
+
field,
|
|
5329
|
+
value,
|
|
5330
|
+
onValueChange,
|
|
5331
|
+
classNames,
|
|
5332
|
+
inputClass
|
|
5333
|
+
}) {
|
|
5334
|
+
const clientContext = useOptionalCimplifyClient();
|
|
5335
|
+
const addr = value && typeof value === "object" ? value : null;
|
|
5336
|
+
const [inputText, setInputText] = React10.useState(addr?.formatted_address ?? "");
|
|
5337
|
+
const [suggestions, setSuggestions] = React10.useState([]);
|
|
5338
|
+
const [isOpen, setIsOpen] = React10.useState(false);
|
|
5339
|
+
const [highlightedIndex, setHighlightedIndex] = React10.useState(-1);
|
|
5340
|
+
const debounceRef = React10.useRef(null);
|
|
5341
|
+
const seqRef = React10.useRef(0);
|
|
5342
|
+
const sessionTokenRef = React10.useRef(createSessionToken());
|
|
5343
|
+
const blurTimeoutRef = React10.useRef(null);
|
|
5344
|
+
React10.useEffect(() => {
|
|
5345
|
+
return () => {
|
|
5346
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5347
|
+
if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
|
|
5348
|
+
seqRef.current += 1;
|
|
5349
|
+
};
|
|
5350
|
+
}, []);
|
|
5351
|
+
const fetchSuggestions = React10.useCallback(async (query) => {
|
|
5352
|
+
const client = clientContext?.client;
|
|
5353
|
+
if (!client || query.length < 3) {
|
|
5354
|
+
setSuggestions([]);
|
|
5355
|
+
setIsOpen(false);
|
|
5356
|
+
return;
|
|
5357
|
+
}
|
|
5358
|
+
const seq = ++seqRef.current;
|
|
5359
|
+
const result = await client.places.autocomplete(query, sessionTokenRef.current);
|
|
5360
|
+
if (seqRef.current !== seq) return;
|
|
5361
|
+
if (result.ok && result.value.predictions.length > 0) {
|
|
5362
|
+
setSuggestions(result.value.predictions);
|
|
5363
|
+
setHighlightedIndex(0);
|
|
5364
|
+
setIsOpen(true);
|
|
5365
|
+
} else {
|
|
5366
|
+
setSuggestions([]);
|
|
5367
|
+
setIsOpen(false);
|
|
5368
|
+
}
|
|
5369
|
+
}, [clientContext]);
|
|
5370
|
+
const handleInputChange = (nextValue) => {
|
|
5371
|
+
setInputText(nextValue);
|
|
5372
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5373
|
+
debounceRef.current = setTimeout(() => void fetchSuggestions(nextValue.trim()), 300);
|
|
5374
|
+
};
|
|
5375
|
+
const selectSuggestion = React10.useCallback(async (suggestion) => {
|
|
5376
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5377
|
+
if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
|
|
5378
|
+
const fallback = suggestion.description.split(",")[0]?.trim() || suggestion.description;
|
|
5379
|
+
setInputText(fallback);
|
|
5380
|
+
setSuggestions([]);
|
|
5381
|
+
setIsOpen(false);
|
|
5382
|
+
const client = clientContext?.client;
|
|
5383
|
+
if (!client) return;
|
|
5384
|
+
const result = await client.places.details(suggestion.place_id, sessionTokenRef.current);
|
|
5385
|
+
sessionTokenRef.current = createSessionToken();
|
|
5386
|
+
if (result.ok) {
|
|
5387
|
+
const d = result.value;
|
|
5388
|
+
const addressValue = {
|
|
5389
|
+
formatted_address: d.formatted_address || fallback,
|
|
5390
|
+
street_address: d.street_address,
|
|
5391
|
+
apartment: d.apartment,
|
|
5392
|
+
city: d.city,
|
|
5393
|
+
region: d.region,
|
|
5394
|
+
postal_code: d.postal_code,
|
|
5395
|
+
country: d.country,
|
|
5396
|
+
latitude: d.latitude,
|
|
5397
|
+
longitude: d.longitude,
|
|
5398
|
+
place_id: d.place_id
|
|
5399
|
+
};
|
|
5400
|
+
setInputText(addressValue.formatted_address);
|
|
5401
|
+
onValueChange(addressValue);
|
|
5402
|
+
}
|
|
5403
|
+
}, [clientContext, onValueChange]);
|
|
5404
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2 relative", classNames?.addressInput), children: [
|
|
5405
|
+
/* @__PURE__ */ jsx(
|
|
5406
|
+
"input",
|
|
5407
|
+
{
|
|
5408
|
+
type: "text",
|
|
5409
|
+
value: inputText,
|
|
5410
|
+
onChange: (e) => handleInputChange(e.target.value),
|
|
5411
|
+
onFocus: () => {
|
|
5412
|
+
if (suggestions.length > 0) setIsOpen(true);
|
|
5413
|
+
},
|
|
5414
|
+
onBlur: () => {
|
|
5415
|
+
blurTimeoutRef.current = setTimeout(() => setIsOpen(false), 120);
|
|
5416
|
+
},
|
|
5417
|
+
onKeyDown: (e) => {
|
|
5418
|
+
if (e.key === "Escape") {
|
|
5419
|
+
setIsOpen(false);
|
|
5420
|
+
return;
|
|
5421
|
+
}
|
|
5422
|
+
if (!isOpen || suggestions.length === 0) return;
|
|
5423
|
+
if (e.key === "ArrowDown") {
|
|
5424
|
+
e.preventDefault();
|
|
5425
|
+
setHighlightedIndex((i) => i < suggestions.length - 1 ? i + 1 : 0);
|
|
5426
|
+
} else if (e.key === "ArrowUp") {
|
|
5427
|
+
e.preventDefault();
|
|
5428
|
+
setHighlightedIndex((i) => i > 0 ? i - 1 : suggestions.length - 1);
|
|
5429
|
+
} else if (e.key === "Enter" && highlightedIndex >= 0) {
|
|
5430
|
+
e.preventDefault();
|
|
5431
|
+
void selectSuggestion(suggestions[highlightedIndex]);
|
|
5432
|
+
}
|
|
5433
|
+
},
|
|
5434
|
+
placeholder: field.placeholder || "Search for an address...",
|
|
5435
|
+
required: field.is_required,
|
|
5436
|
+
autoComplete: "off",
|
|
5437
|
+
"aria-autocomplete": "list",
|
|
5438
|
+
"aria-expanded": isOpen && suggestions.length > 0,
|
|
5439
|
+
className: inputClass
|
|
5440
|
+
}
|
|
5441
|
+
),
|
|
5442
|
+
isOpen && suggestions.length > 0 && /* @__PURE__ */ jsx("div", { role: "listbox", className: "absolute left-0 right-0 top-full z-20 mt-1 overflow-hidden rounded-md border border-border bg-background shadow-lg", children: suggestions.map((s, i) => /* @__PURE__ */ jsx(
|
|
5443
|
+
"button",
|
|
5444
|
+
{
|
|
5445
|
+
type: "button",
|
|
5446
|
+
role: "option",
|
|
5447
|
+
"aria-selected": i === highlightedIndex,
|
|
5448
|
+
onMouseDown: (e) => {
|
|
5449
|
+
e.preventDefault();
|
|
5450
|
+
void selectSuggestion(s);
|
|
5451
|
+
},
|
|
5452
|
+
className: cn("block w-full px-3 py-2.5 text-left text-sm transition-colors", i === highlightedIndex ? "bg-muted text-foreground" : "text-foreground hover:bg-muted/70"),
|
|
5453
|
+
children: s.description
|
|
5454
|
+
},
|
|
5455
|
+
s.place_id
|
|
5456
|
+
)) }),
|
|
5457
|
+
addr && /* @__PURE__ */ jsx(
|
|
5458
|
+
"input",
|
|
5459
|
+
{
|
|
5460
|
+
type: "text",
|
|
5461
|
+
value: addr.apartment || "",
|
|
5462
|
+
onChange: (e) => onValueChange({ ...addr, apartment: e.target.value || void 0 }),
|
|
5463
|
+
placeholder: "Apt, suite, unit (optional)",
|
|
5464
|
+
className: inputClass
|
|
5465
|
+
}
|
|
5466
|
+
)
|
|
5467
|
+
] });
|
|
5468
|
+
}
|
|
5469
|
+
function LocationInput({
|
|
5470
|
+
field,
|
|
5471
|
+
value,
|
|
5472
|
+
onValueChange,
|
|
5473
|
+
classNames,
|
|
5474
|
+
inputClass
|
|
5475
|
+
}) {
|
|
5476
|
+
const clientContext = useOptionalCimplifyClient();
|
|
5477
|
+
const loc = value && typeof value === "object" ? value : null;
|
|
5478
|
+
const [inputText, setInputText] = React10.useState(loc?.label ?? "");
|
|
5479
|
+
const [suggestions, setSuggestions] = React10.useState([]);
|
|
5480
|
+
const [isOpen, setIsOpen] = React10.useState(false);
|
|
5481
|
+
const [highlightedIndex, setHighlightedIndex] = React10.useState(-1);
|
|
5482
|
+
const debounceRef = React10.useRef(null);
|
|
5483
|
+
const seqRef = React10.useRef(0);
|
|
5484
|
+
const sessionTokenRef = React10.useRef(createSessionToken());
|
|
5485
|
+
const blurTimeoutRef = React10.useRef(null);
|
|
5486
|
+
React10.useEffect(() => {
|
|
5487
|
+
return () => {
|
|
5488
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5489
|
+
if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
|
|
5490
|
+
seqRef.current += 1;
|
|
5491
|
+
};
|
|
5492
|
+
}, []);
|
|
5493
|
+
const fetchSuggestions = React10.useCallback(async (query) => {
|
|
5494
|
+
const client = clientContext?.client;
|
|
5495
|
+
if (!client || query.length < 3) {
|
|
5496
|
+
setSuggestions([]);
|
|
5497
|
+
setIsOpen(false);
|
|
5498
|
+
return;
|
|
5499
|
+
}
|
|
5500
|
+
const seq = ++seqRef.current;
|
|
5501
|
+
const result = await client.places.autocomplete(query, sessionTokenRef.current);
|
|
5502
|
+
if (seqRef.current !== seq) return;
|
|
5503
|
+
if (result.ok && result.value.predictions.length > 0) {
|
|
5504
|
+
setSuggestions(result.value.predictions);
|
|
5505
|
+
setHighlightedIndex(0);
|
|
5506
|
+
setIsOpen(true);
|
|
5507
|
+
} else {
|
|
5508
|
+
setSuggestions([]);
|
|
5509
|
+
setIsOpen(false);
|
|
5510
|
+
}
|
|
5511
|
+
}, [clientContext]);
|
|
5512
|
+
const handleInputChange = (nextValue) => {
|
|
5513
|
+
setInputText(nextValue);
|
|
5514
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5515
|
+
debounceRef.current = setTimeout(() => void fetchSuggestions(nextValue.trim()), 300);
|
|
5516
|
+
};
|
|
5517
|
+
const selectSuggestion = React10.useCallback(async (suggestion) => {
|
|
5518
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5519
|
+
if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
|
|
5520
|
+
const label = suggestion.description.split(",")[0]?.trim() || suggestion.description;
|
|
5521
|
+
setInputText(label);
|
|
5522
|
+
setSuggestions([]);
|
|
5523
|
+
setIsOpen(false);
|
|
5524
|
+
const client = clientContext?.client;
|
|
5525
|
+
if (!client) return;
|
|
5526
|
+
const result = await client.places.details(suggestion.place_id, sessionTokenRef.current);
|
|
5527
|
+
sessionTokenRef.current = createSessionToken();
|
|
5528
|
+
if (result.ok) {
|
|
5529
|
+
const d = result.value;
|
|
5530
|
+
onValueChange({
|
|
5531
|
+
latitude: d.latitude,
|
|
5532
|
+
longitude: d.longitude,
|
|
5533
|
+
label: d.formatted_address || label
|
|
5534
|
+
});
|
|
5535
|
+
setInputText(d.formatted_address || label);
|
|
5536
|
+
}
|
|
5537
|
+
}, [clientContext, onValueChange]);
|
|
5538
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative", classNames?.locationInput), children: [
|
|
5539
|
+
/* @__PURE__ */ jsx(
|
|
5540
|
+
"input",
|
|
5541
|
+
{
|
|
5542
|
+
type: "text",
|
|
5543
|
+
value: inputText,
|
|
5544
|
+
onChange: (e) => handleInputChange(e.target.value),
|
|
5545
|
+
onFocus: () => {
|
|
5546
|
+
if (suggestions.length > 0) setIsOpen(true);
|
|
5547
|
+
},
|
|
5548
|
+
onBlur: () => {
|
|
5549
|
+
blurTimeoutRef.current = setTimeout(() => setIsOpen(false), 120);
|
|
5550
|
+
},
|
|
5551
|
+
onKeyDown: (e) => {
|
|
5552
|
+
if (e.key === "Escape") {
|
|
5553
|
+
setIsOpen(false);
|
|
5554
|
+
return;
|
|
5555
|
+
}
|
|
5556
|
+
if (!isOpen || suggestions.length === 0) return;
|
|
5557
|
+
if (e.key === "ArrowDown") {
|
|
5558
|
+
e.preventDefault();
|
|
5559
|
+
setHighlightedIndex((i) => i < suggestions.length - 1 ? i + 1 : 0);
|
|
5560
|
+
} else if (e.key === "ArrowUp") {
|
|
5561
|
+
e.preventDefault();
|
|
5562
|
+
setHighlightedIndex((i) => i > 0 ? i - 1 : suggestions.length - 1);
|
|
5563
|
+
} else if (e.key === "Enter" && highlightedIndex >= 0) {
|
|
5564
|
+
e.preventDefault();
|
|
5565
|
+
void selectSuggestion(suggestions[highlightedIndex]);
|
|
5566
|
+
}
|
|
5567
|
+
},
|
|
5568
|
+
placeholder: field.placeholder || "Search for a location...",
|
|
5569
|
+
required: field.is_required,
|
|
5570
|
+
autoComplete: "off",
|
|
5571
|
+
"aria-autocomplete": "list",
|
|
5572
|
+
"aria-expanded": isOpen && suggestions.length > 0,
|
|
5573
|
+
className: inputClass
|
|
5574
|
+
}
|
|
5575
|
+
),
|
|
5576
|
+
isOpen && suggestions.length > 0 && /* @__PURE__ */ jsx("div", { role: "listbox", className: "absolute left-0 right-0 top-full z-20 mt-1 overflow-hidden rounded-md border border-border bg-background shadow-lg", children: suggestions.map((s, i) => /* @__PURE__ */ jsx(
|
|
5577
|
+
"button",
|
|
5578
|
+
{
|
|
5579
|
+
type: "button",
|
|
5580
|
+
role: "option",
|
|
5581
|
+
"aria-selected": i === highlightedIndex,
|
|
5582
|
+
onMouseDown: (e) => {
|
|
5583
|
+
e.preventDefault();
|
|
5584
|
+
void selectSuggestion(s);
|
|
5585
|
+
},
|
|
5586
|
+
className: cn("block w-full px-3 py-2.5 text-left text-sm transition-colors", i === highlightedIndex ? "bg-muted text-foreground" : "text-foreground hover:bg-muted/70"),
|
|
5587
|
+
children: s.description
|
|
5588
|
+
},
|
|
5589
|
+
s.place_id
|
|
5590
|
+
)) }),
|
|
5591
|
+
loc && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: [
|
|
5592
|
+
loc.latitude.toFixed(4),
|
|
5593
|
+
", ",
|
|
5594
|
+
loc.longitude.toFixed(4)
|
|
5595
|
+
] })
|
|
5596
|
+
] });
|
|
5597
|
+
}
|
|
5598
|
+
function PhoneInput({
|
|
5599
|
+
field,
|
|
5600
|
+
value,
|
|
5601
|
+
onValueChange,
|
|
5602
|
+
classNames,
|
|
5603
|
+
inputClass
|
|
5604
|
+
}) {
|
|
5605
|
+
const phone = value && typeof value === "object" ? value : null;
|
|
5606
|
+
const [code, setCode] = React10.useState(phone?.country_code ?? "+1");
|
|
5607
|
+
const [number, setNumber] = React10.useState(phone?.number ?? "");
|
|
5608
|
+
const update = (nextCode, nextNumber) => {
|
|
5609
|
+
setCode(nextCode);
|
|
5610
|
+
setNumber(nextNumber);
|
|
5611
|
+
if (nextNumber) {
|
|
5612
|
+
onValueChange({
|
|
5613
|
+
country_code: nextCode,
|
|
5614
|
+
number: nextNumber,
|
|
5615
|
+
formatted: `${nextCode} ${nextNumber}`
|
|
5616
|
+
});
|
|
5617
|
+
} else {
|
|
5618
|
+
onValueChange(void 0);
|
|
5619
|
+
}
|
|
5620
|
+
};
|
|
5621
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-2", classNames?.phoneInput), children: [
|
|
5622
|
+
/* @__PURE__ */ jsx(
|
|
5623
|
+
"input",
|
|
5624
|
+
{
|
|
5625
|
+
type: "text",
|
|
5626
|
+
value: code,
|
|
5627
|
+
onChange: (e) => update(e.target.value, number),
|
|
5628
|
+
placeholder: "+1",
|
|
5629
|
+
className: cn(inputClass, "w-20 shrink-0")
|
|
5630
|
+
}
|
|
5631
|
+
),
|
|
5632
|
+
/* @__PURE__ */ jsx(
|
|
5633
|
+
"input",
|
|
5634
|
+
{
|
|
5635
|
+
type: "tel",
|
|
5636
|
+
value: number,
|
|
5637
|
+
onChange: (e) => update(code, e.target.value),
|
|
5638
|
+
placeholder: field.placeholder || "Phone number",
|
|
5639
|
+
required: field.is_required,
|
|
5640
|
+
className: inputClass
|
|
5641
|
+
}
|
|
5642
|
+
)
|
|
5643
|
+
] });
|
|
5644
|
+
}
|
|
5645
|
+
function SignatureInput({
|
|
5646
|
+
field,
|
|
5647
|
+
value,
|
|
5648
|
+
onValueChange,
|
|
5649
|
+
classNames
|
|
5650
|
+
}) {
|
|
5651
|
+
const sig = value && typeof value === "object" ? value : null;
|
|
5652
|
+
const canvasRef = React10.useRef(null);
|
|
5653
|
+
const isDrawing = React10.useRef(false);
|
|
5654
|
+
const getCtx = () => canvasRef.current?.getContext("2d") ?? null;
|
|
5655
|
+
const startDraw = (e) => {
|
|
5656
|
+
const ctx = getCtx();
|
|
5657
|
+
if (!ctx) return;
|
|
5658
|
+
isDrawing.current = true;
|
|
5659
|
+
const rect = canvasRef.current.getBoundingClientRect();
|
|
5660
|
+
ctx.beginPath();
|
|
5661
|
+
ctx.moveTo(e.clientX - rect.left, e.clientY - rect.top);
|
|
5662
|
+
canvasRef.current.setPointerCapture(e.pointerId);
|
|
5663
|
+
};
|
|
5664
|
+
const draw = (e) => {
|
|
5665
|
+
if (!isDrawing.current) return;
|
|
5666
|
+
const ctx = getCtx();
|
|
5667
|
+
if (!ctx) return;
|
|
5668
|
+
const rect = canvasRef.current.getBoundingClientRect();
|
|
5669
|
+
ctx.lineWidth = 2;
|
|
5670
|
+
ctx.lineCap = "round";
|
|
5671
|
+
const style = getComputedStyle(canvasRef.current);
|
|
5672
|
+
ctx.strokeStyle = style.color || "#000";
|
|
5673
|
+
ctx.lineTo(e.clientX - rect.left, e.clientY - rect.top);
|
|
5674
|
+
ctx.stroke();
|
|
5675
|
+
};
|
|
5676
|
+
const endDraw = () => {
|
|
5677
|
+
if (!isDrawing.current) return;
|
|
5678
|
+
isDrawing.current = false;
|
|
5679
|
+
const canvas = canvasRef.current;
|
|
5680
|
+
if (!canvas) return;
|
|
5681
|
+
onValueChange({
|
|
5682
|
+
data_url: canvas.toDataURL("image/png"),
|
|
5683
|
+
signer_name: sig?.signer_name
|
|
5684
|
+
});
|
|
5685
|
+
};
|
|
5686
|
+
const clear = () => {
|
|
5687
|
+
const canvas = canvasRef.current;
|
|
5688
|
+
if (!canvas) return;
|
|
5689
|
+
const ctx = canvas.getContext("2d");
|
|
5690
|
+
if (ctx) ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
5691
|
+
onValueChange(void 0);
|
|
5692
|
+
};
|
|
5693
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", classNames?.signatureCanvas), children: [
|
|
5694
|
+
/* @__PURE__ */ jsxs("div", { className: "relative rounded-md border border-input overflow-hidden", children: [
|
|
5695
|
+
/* @__PURE__ */ jsx(
|
|
5696
|
+
"canvas",
|
|
5697
|
+
{
|
|
5698
|
+
ref: canvasRef,
|
|
5699
|
+
width: 400,
|
|
5700
|
+
height: 150,
|
|
5701
|
+
className: "w-full touch-none cursor-crosshair bg-background text-foreground",
|
|
5702
|
+
onPointerDown: startDraw,
|
|
5703
|
+
onPointerMove: draw,
|
|
5704
|
+
onPointerUp: endDraw,
|
|
5705
|
+
onPointerLeave: endDraw
|
|
5706
|
+
}
|
|
5707
|
+
),
|
|
5708
|
+
sig?.data_url && /* @__PURE__ */ jsx(
|
|
5709
|
+
"button",
|
|
5710
|
+
{
|
|
5711
|
+
type: "button",
|
|
5712
|
+
onClick: clear,
|
|
5713
|
+
className: "absolute top-1.5 right-1.5 text-xs text-muted-foreground hover:text-destructive transition-colors",
|
|
5714
|
+
children: "Clear"
|
|
5715
|
+
}
|
|
5716
|
+
)
|
|
5717
|
+
] }),
|
|
5718
|
+
!sig?.data_url && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: field.placeholder || "Draw your signature above" })
|
|
5719
|
+
] });
|
|
5720
|
+
}
|
|
5721
|
+
function createSessionToken() {
|
|
5722
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
5723
|
+
return crypto.randomUUID();
|
|
5724
|
+
}
|
|
5725
|
+
return `places_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
5726
|
+
}
|
|
4773
5727
|
function ProductCustomizer({
|
|
4774
5728
|
product,
|
|
4775
5729
|
onAddToCart,
|
|
@@ -4790,6 +5744,7 @@ function ProductCustomizer({
|
|
|
4790
5744
|
const [bundleTotalPrice, setBundleTotalPrice] = useState(null);
|
|
4791
5745
|
const [bundleReady, setBundleReady] = useState(false);
|
|
4792
5746
|
const [selectedBillingPlan, setSelectedBillingPlan] = useState(null);
|
|
5747
|
+
const [customerInputValues, setCustomerInputValues] = useState({});
|
|
4793
5748
|
const [specialInstructions, setSpecialInstructions] = useState("");
|
|
4794
5749
|
const cart = useCart();
|
|
4795
5750
|
const productType = product.type || "product";
|
|
@@ -4814,6 +5769,7 @@ function ProductCustomizer({
|
|
|
4814
5769
|
setBundleTotalPrice(null);
|
|
4815
5770
|
setBundleReady(false);
|
|
4816
5771
|
setSelectedBillingPlan(null);
|
|
5772
|
+
setCustomerInputValues({});
|
|
4817
5773
|
setSpecialInstructions("");
|
|
4818
5774
|
}, [product.id, product.min_order_quantity]);
|
|
4819
5775
|
const selectedAddOnOptions = useMemo(() => {
|
|
@@ -4876,7 +5832,15 @@ function ProductCustomizer({
|
|
|
4876
5832
|
}),
|
|
4877
5833
|
[product.id, quantity, selectedVariantId, normalizedAddOnOptionIds, isBundle, bundleSelections, isComposite, compositeSelections]
|
|
4878
5834
|
);
|
|
4879
|
-
const
|
|
5835
|
+
const requiredInputsSatisfied = useMemo(() => {
|
|
5836
|
+
if (!product.input_fields || product.input_fields.length === 0) return true;
|
|
5837
|
+
return product.input_fields.every((field) => {
|
|
5838
|
+
if (!field.is_required) return true;
|
|
5839
|
+
const val = customerInputValues[field.id];
|
|
5840
|
+
return val !== void 0 && val !== "" && val !== null;
|
|
5841
|
+
});
|
|
5842
|
+
}, [product.input_fields, customerInputValues]);
|
|
5843
|
+
const quoteEnabled = isComposite ? compositeReady && requiredInputsSatisfied : isBundle ? bundleReady && requiredInputsSatisfied : requiredAddOnsSatisfied && requiredInputsSatisfied;
|
|
4880
5844
|
const { quote } = useQuote(quoteInput, {
|
|
4881
5845
|
enabled: quoteEnabled
|
|
4882
5846
|
});
|
|
@@ -4915,6 +5879,7 @@ function ProductCustomizer({
|
|
|
4915
5879
|
compositeSelections: isComposite && compositeSelections.length > 0 ? compositeSelections : void 0,
|
|
4916
5880
|
bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0,
|
|
4917
5881
|
billingPlanId: selectedBillingPlan?.id,
|
|
5882
|
+
customerInputs: Object.keys(customerInputValues).length > 0 ? Object.entries(customerInputValues).filter(([, v]) => v !== void 0 && v !== "").map(([fieldId, value]) => ({ field_id: fieldId, value })) : void 0,
|
|
4918
5883
|
specialInstructions: specialInstructions.trim() || void 0
|
|
4919
5884
|
};
|
|
4920
5885
|
try {
|
|
@@ -4933,7 +5898,7 @@ function ProductCustomizer({
|
|
|
4933
5898
|
} finally {
|
|
4934
5899
|
setIsSubmitting(false);
|
|
4935
5900
|
}
|
|
4936
|
-
}, [product, quantity, selectedVariantId, selectedVariant, quoteId, normalizedAddOnOptionIds, selectedAddOnOptions, isComposite, compositeSelections, isBundle, bundleSelections, selectedBillingPlan, specialInstructions, isSubmitting, onAddToCart, cart]);
|
|
5901
|
+
}, [product, quantity, selectedVariantId, selectedVariant, quoteId, normalizedAddOnOptionIds, selectedAddOnOptions, isComposite, compositeSelections, isBundle, bundleSelections, selectedBillingPlan, customerInputValues, specialInstructions, isSubmitting, onAddToCart, cart]);
|
|
4937
5902
|
return /* @__PURE__ */ jsxs("div", { "data-cimplify-customizer": true, className: cn("space-y-6", className, classNames?.root), children: [
|
|
4938
5903
|
isComposite && product.groups && product.composite_id && /* @__PURE__ */ jsx(
|
|
4939
5904
|
CompositeSelector,
|
|
@@ -4994,6 +5959,14 @@ function ProductCustomizer({
|
|
|
4994
5959
|
currentQuantity: quantity
|
|
4995
5960
|
}
|
|
4996
5961
|
),
|
|
5962
|
+
product.input_fields && product.input_fields.length > 0 && /* @__PURE__ */ jsx(
|
|
5963
|
+
CustomerInputFields,
|
|
5964
|
+
{
|
|
5965
|
+
fields: product.input_fields,
|
|
5966
|
+
values: customerInputValues,
|
|
5967
|
+
onChange: setCustomerInputValues
|
|
5968
|
+
}
|
|
5969
|
+
),
|
|
4997
5970
|
product.deposit_type && product.deposit_type !== "none" && product.deposit_amount && /* @__PURE__ */ jsx("div", { "data-cimplify-customizer-deposit": true, className: cn("text-sm text-muted-foreground", classNames?.depositInfo), children: product.deposit_type === "fixed" ? /* @__PURE__ */ jsxs("span", { children: [
|
|
4998
5971
|
"Deposit required: ",
|
|
4999
5972
|
/* @__PURE__ */ jsx(Price, { amount: product.deposit_amount })
|
|
@@ -5195,6 +6168,10 @@ function CartLineItemRow({
|
|
|
5195
6168
|
] }),
|
|
5196
6169
|
(hasComposite || hasBundle) && /* @__PURE__ */ jsx("span", { "data-cimplify-cart-item-badge": true, children: hasComposite ? "Custom" : "Bundle" }),
|
|
5197
6170
|
item.specialInstructions && /* @__PURE__ */ jsx("span", { "data-cimplify-cart-item-instructions": true, className: "text-xs text-muted-foreground", children: item.specialInstructions }),
|
|
6171
|
+
item.customerInputs && item.customerInputs.length > 0 && /* @__PURE__ */ jsx("div", { "data-cimplify-cart-customer-inputs": true, className: classNames?.customerInputs, children: item.customerInputs.map((input) => /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-input": true, children: [
|
|
6172
|
+
/* @__PURE__ */ jsx("span", { "data-cimplify-cart-input-label": true, children: input.field_name }),
|
|
6173
|
+
/* @__PURE__ */ jsx("span", { "data-cimplify-cart-input-value": true, children: input.field_type === INPUT_FIELD_TYPE.File || input.field_type === INPUT_FIELD_TYPE.Image ? String(input.value).split("/").pop() || "Uploaded file" : String(input.value) })
|
|
6174
|
+
] }, input.field_id)) }),
|
|
5198
6175
|
(item.lineType === "service" || item.product.type === "service") && item.scheduledStart && /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-service-info": true, className: classNames?.serviceInfo, children: [
|
|
5199
6176
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
5200
6177
|
"\u{1F4C5}",
|
|
@@ -5882,6 +6859,98 @@ function DigitalProductCard({
|
|
|
5882
6859
|
] })
|
|
5883
6860
|
] });
|
|
5884
6861
|
}
|
|
6862
|
+
function BundleProductCard({
|
|
6863
|
+
product,
|
|
6864
|
+
onQuickAdd,
|
|
6865
|
+
renderImage,
|
|
6866
|
+
renderLink,
|
|
6867
|
+
className
|
|
6868
|
+
}) {
|
|
6869
|
+
const image = product.image_url || product.images?.[0] || "";
|
|
6870
|
+
const components = product.components || [];
|
|
6871
|
+
const componentCount = components.length;
|
|
6872
|
+
const onSale = isOnSale(product);
|
|
6873
|
+
const discount = getDiscountPercentage(product);
|
|
6874
|
+
const hasVariantChoice = components.some((c) => c.allow_variant_choice);
|
|
6875
|
+
return /* @__PURE__ */ jsxs(CardShell, { product, renderLink, className, children: [
|
|
6876
|
+
/* @__PURE__ */ jsxs(CardImage, { src: image, alt: product.name, aspectRatio: "square", renderImage, children: [
|
|
6877
|
+
/* @__PURE__ */ jsx("span", { className: "absolute top-3 left-3 text-[11px] font-semibold tracking-wide bg-indigo-50 text-indigo-700 border border-indigo-200/60 px-2 py-0.5 rounded-md", children: "Bundle" }),
|
|
6878
|
+
componentCount > 0 && /* @__PURE__ */ jsxs("span", { className: "absolute top-3 right-3 text-[11px] font-semibold tracking-wide bg-background/90 backdrop-blur text-foreground px-2 py-0.5 rounded-md", children: [
|
|
6879
|
+
componentCount,
|
|
6880
|
+
" item",
|
|
6881
|
+
componentCount !== 1 ? "s" : ""
|
|
6882
|
+
] }),
|
|
6883
|
+
/* @__PURE__ */ jsx(
|
|
6884
|
+
QuickAddButton,
|
|
6885
|
+
{
|
|
6886
|
+
onClick: () => onQuickAdd?.(product),
|
|
6887
|
+
className: "absolute bottom-3 right-3"
|
|
6888
|
+
}
|
|
6889
|
+
)
|
|
6890
|
+
] }),
|
|
6891
|
+
/* @__PURE__ */ jsxs("div", { className: "p-3.5", children: [
|
|
6892
|
+
/* @__PURE__ */ jsx("h3", { className: "text-[14.5px] font-semibold text-foreground leading-snug tracking-tight truncate", children: product.name }),
|
|
6893
|
+
componentCount > 0 && /* @__PURE__ */ jsxs("p", { className: "text-[11px] text-muted-foreground mt-1 truncate", children: [
|
|
6894
|
+
"Includes: ",
|
|
6895
|
+
components.map((c) => c.product_name || c.product_id).join(", ")
|
|
6896
|
+
] }),
|
|
6897
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-2.5", children: [
|
|
6898
|
+
/* @__PURE__ */ jsx(Price, { amount: product.default_price, className: "text-sm font-bold" }),
|
|
6899
|
+
onSale && product.bundle_price && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6900
|
+
/* @__PURE__ */ jsx(Price, { amount: getBasePrice(product), className: "text-xs text-muted-foreground line-through" }),
|
|
6901
|
+
discount != null && discount > 0 && /* @__PURE__ */ jsxs("span", { className: "text-[10px] font-semibold text-emerald-600", children: [
|
|
6902
|
+
"Save ",
|
|
6903
|
+
discount,
|
|
6904
|
+
"%"
|
|
6905
|
+
] })
|
|
6906
|
+
] })
|
|
6907
|
+
] }),
|
|
6908
|
+
hasVariantChoice && /* @__PURE__ */ jsx("span", { className: "inline-block mt-2 text-[10px] font-medium text-muted-foreground px-1.5 py-0.5 bg-muted rounded", children: "Customizable" })
|
|
6909
|
+
] })
|
|
6910
|
+
] });
|
|
6911
|
+
}
|
|
6912
|
+
function CompositeProductCard({
|
|
6913
|
+
product,
|
|
6914
|
+
onQuickAdd,
|
|
6915
|
+
renderImage,
|
|
6916
|
+
renderLink,
|
|
6917
|
+
className
|
|
6918
|
+
}) {
|
|
6919
|
+
const image = product.image_url || product.images?.[0] || "";
|
|
6920
|
+
const groups = product.groups || [];
|
|
6921
|
+
const groupCount = groups.length;
|
|
6922
|
+
groups.reduce((sum, g) => sum + g.components.length, 0);
|
|
6923
|
+
const tags = product.tags || [];
|
|
6924
|
+
return /* @__PURE__ */ jsxs(CardShell, { product, renderLink, className, children: [
|
|
6925
|
+
/* @__PURE__ */ jsxs(CardImage, { src: image, alt: product.name, aspectRatio: "square", renderImage, children: [
|
|
6926
|
+
/* @__PURE__ */ jsx("span", { className: "absolute top-3 left-3 text-[11px] font-semibold tracking-wide bg-violet-50 text-violet-700 border border-violet-200/60 px-2 py-0.5 rounded-md", children: "Build Your Own" }),
|
|
6927
|
+
groupCount > 0 && /* @__PURE__ */ jsxs("span", { className: "absolute top-3 right-3 text-[11px] font-semibold tracking-wide bg-background/90 backdrop-blur text-foreground px-2 py-0.5 rounded-md", children: [
|
|
6928
|
+
groupCount,
|
|
6929
|
+
" choice",
|
|
6930
|
+
groupCount !== 1 ? "s" : ""
|
|
6931
|
+
] }),
|
|
6932
|
+
/* @__PURE__ */ jsx(
|
|
6933
|
+
QuickAddButton,
|
|
6934
|
+
{
|
|
6935
|
+
onClick: () => onQuickAdd?.(product),
|
|
6936
|
+
className: "absolute bottom-3 right-3"
|
|
6937
|
+
}
|
|
6938
|
+
)
|
|
6939
|
+
] }),
|
|
6940
|
+
/* @__PURE__ */ jsxs("div", { className: "p-3.5", children: [
|
|
6941
|
+
/* @__PURE__ */ jsx("h3", { className: "text-[14.5px] font-semibold text-foreground leading-snug tracking-tight truncate", children: product.name }),
|
|
6942
|
+
product.description && /* @__PURE__ */ jsx("p", { className: "text-[12px] text-muted-foreground mt-1 line-clamp-1", children: product.description }),
|
|
6943
|
+
groupCount > 0 && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground mt-1 truncate", children: groups.map((g) => g.name).join(" + ") }),
|
|
6944
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-2.5", children: [
|
|
6945
|
+
/* @__PURE__ */ jsxs("span", { className: "text-sm font-bold", children: [
|
|
6946
|
+
"From ",
|
|
6947
|
+
/* @__PURE__ */ jsx(Price, { amount: product.default_price })
|
|
6948
|
+
] }),
|
|
6949
|
+
tags.length > 0 && /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-muted-foreground px-1.5 py-0.5 bg-muted rounded", children: tags[0] })
|
|
6950
|
+
] })
|
|
6951
|
+
] })
|
|
6952
|
+
] });
|
|
6953
|
+
}
|
|
5885
6954
|
function formatDuration2(minutes, unit) {
|
|
5886
6955
|
if (unit && unit !== "minutes") return `${minutes} ${unit}`;
|
|
5887
6956
|
if (minutes >= 60) {
|
|
@@ -6343,6 +7412,8 @@ var CardVariant = /* @__PURE__ */ ((CardVariant2) => {
|
|
|
6343
7412
|
CardVariant2["Retail"] = "retail";
|
|
6344
7413
|
CardVariant2["Wholesale"] = "wholesale";
|
|
6345
7414
|
CardVariant2["Digital"] = "digital";
|
|
7415
|
+
CardVariant2["Bundle"] = "bundle";
|
|
7416
|
+
CardVariant2["Composite"] = "composite";
|
|
6346
7417
|
CardVariant2["Standard"] = "standard";
|
|
6347
7418
|
CardVariant2["Compact"] = "compact";
|
|
6348
7419
|
CardVariant2["Schedule"] = "schedule";
|
|
@@ -6367,11 +7438,19 @@ var BUILT_IN_CARDS = {
|
|
|
6367
7438
|
["rental" /* Rental */]: RentalServiceCard,
|
|
6368
7439
|
["accommodation" /* Accommodation */]: AccommodationCard,
|
|
6369
7440
|
["lease" /* Lease */]: LeaseServiceCard,
|
|
7441
|
+
["bundle" /* Bundle */]: BundleProductCard,
|
|
7442
|
+
["composite" /* Composite */]: CompositeProductCard,
|
|
6370
7443
|
["subscription" /* Subscription */]: SubscriptionCard
|
|
6371
7444
|
};
|
|
6372
7445
|
var RENTAL_UNITS = /* @__PURE__ */ new Set([DURATION_UNIT.Days, DURATION_UNIT.Hours]);
|
|
6373
7446
|
var LEASE_UNITS = /* @__PURE__ */ new Set([DURATION_UNIT.Weeks, DURATION_UNIT.Months, DURATION_UNIT.Years]);
|
|
6374
7447
|
function resolveCardVariant(product) {
|
|
7448
|
+
if (product.type === PRODUCT_TYPE.Bundle) {
|
|
7449
|
+
return "bundle" /* Bundle */;
|
|
7450
|
+
}
|
|
7451
|
+
if (product.type === PRODUCT_TYPE.Composite) {
|
|
7452
|
+
return "composite" /* Composite */;
|
|
7453
|
+
}
|
|
6375
7454
|
if (product.quantity_pricing && product.quantity_pricing.length > 1) {
|
|
6376
7455
|
return "wholesale" /* Wholesale */;
|
|
6377
7456
|
}
|
|
@@ -6561,13 +7640,13 @@ function ProductGrid({
|
|
|
6561
7640
|
className,
|
|
6562
7641
|
classNames
|
|
6563
7642
|
}) {
|
|
6564
|
-
const rawId =
|
|
7643
|
+
const rawId = React10.useId();
|
|
6565
7644
|
const gridId = `cimplify-grid-${rawId.replace(/:/g, "")}`;
|
|
6566
7645
|
const sm = columns?.sm ?? 1;
|
|
6567
7646
|
const md = columns?.md ?? 2;
|
|
6568
7647
|
const lg = columns?.lg ?? 3;
|
|
6569
7648
|
const xl = columns?.xl ?? 4;
|
|
6570
|
-
const css =
|
|
7649
|
+
const css = React10.useMemo(
|
|
6571
7650
|
() => [
|
|
6572
7651
|
`#${gridId}{display:grid;grid-template-columns:repeat(${sm},1fr);gap:1rem}`,
|
|
6573
7652
|
`@media(min-width:768px){#${gridId}{grid-template-columns:repeat(${md},1fr)}}`,
|
|
@@ -6928,7 +8007,7 @@ function CategoryGrid({
|
|
|
6928
8007
|
enabled: categoriesProp === void 0
|
|
6929
8008
|
});
|
|
6930
8009
|
const categories = categoriesProp ?? fetched;
|
|
6931
|
-
const rawId =
|
|
8010
|
+
const rawId = React10.useId();
|
|
6932
8011
|
const gridId = `cimplify-cat-grid-${rawId.replace(/:/g, "")}`;
|
|
6933
8012
|
const sm = columns?.sm ?? 2;
|
|
6934
8013
|
const md = columns?.md ?? 3;
|
|
@@ -7154,7 +8233,7 @@ function OrderSummary({
|
|
|
7154
8233
|
/* @__PURE__ */ jsx("p", { children: order.delivery_address })
|
|
7155
8234
|
] }),
|
|
7156
8235
|
/* @__PURE__ */ jsx("div", { "data-cimplify-order-items": true, className: classNames?.items, children: order.items.map(
|
|
7157
|
-
(item) => renderLineItem ? /* @__PURE__ */ jsx(
|
|
8236
|
+
(item) => renderLineItem ? /* @__PURE__ */ jsx(React10.Fragment, { children: renderLineItem(item) }, item.id) : /* @__PURE__ */ jsxs("div", { "data-cimplify-order-line-item": true, className: classNames?.lineItem, children: [
|
|
7158
8237
|
/* @__PURE__ */ jsxs("div", { "data-cimplify-order-line-info": true, children: [
|
|
7159
8238
|
/* @__PURE__ */ jsxs("span", { "data-cimplify-order-line-qty": true, children: [
|
|
7160
8239
|
item.quantity,
|
|
@@ -8135,7 +9214,7 @@ function DefaultCatalogueLayout({
|
|
|
8135
9214
|
/* @__PURE__ */ jsx("p", { className: "text-lg font-medium", children: "No products found" }),
|
|
8136
9215
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try adjusting your filters" })
|
|
8137
9216
|
] }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-4", children: products.map(
|
|
8138
|
-
(product) => renderCard ? /* @__PURE__ */ jsx(
|
|
9217
|
+
(product) => renderCard ? /* @__PURE__ */ jsx(React10.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsx(
|
|
8139
9218
|
ProductCard,
|
|
8140
9219
|
{
|
|
8141
9220
|
product,
|
|
@@ -8242,7 +9321,7 @@ function CompactCatalogueLayout({
|
|
|
8242
9321
|
/* @__PURE__ */ jsx("p", { className: "text-lg font-medium", children: "No items found" }),
|
|
8243
9322
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try a different category or search" })
|
|
8244
9323
|
] }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 lg:grid-cols-3 gap-5", children: products.map(
|
|
8245
|
-
(product) => renderCard ? /* @__PURE__ */ jsx(
|
|
9324
|
+
(product) => renderCard ? /* @__PURE__ */ jsx(React10.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsx(
|
|
8246
9325
|
ProductCard,
|
|
8247
9326
|
{
|
|
8248
9327
|
product,
|
|
@@ -8265,8 +9344,8 @@ var BUILT_IN_LAYOUTS = {
|
|
|
8265
9344
|
["compact" /* Compact */]: CompactCatalogueLayout
|
|
8266
9345
|
};
|
|
8267
9346
|
function useDebounce(value, delay) {
|
|
8268
|
-
const [debounced, setDebounced] =
|
|
8269
|
-
|
|
9347
|
+
const [debounced, setDebounced] = React10.useState(value);
|
|
9348
|
+
React10.useEffect(() => {
|
|
8270
9349
|
const timer = setTimeout(() => setDebounced(value), delay);
|
|
8271
9350
|
return () => clearTimeout(timer);
|
|
8272
9351
|
}, [value, delay]);
|
|
@@ -8994,12 +10073,161 @@ function DigitalProductLayout({
|
|
|
8994
10073
|
)
|
|
8995
10074
|
] });
|
|
8996
10075
|
}
|
|
10076
|
+
function BundleProductLayout({
|
|
10077
|
+
product,
|
|
10078
|
+
onAddToCart,
|
|
10079
|
+
renderBreadcrumb,
|
|
10080
|
+
relatedProducts,
|
|
10081
|
+
showRelated = true,
|
|
10082
|
+
className
|
|
10083
|
+
}) {
|
|
10084
|
+
const images = product.images || (product.image_url ? [product.image_url] : []);
|
|
10085
|
+
const components = product.components || [];
|
|
10086
|
+
const onSale = isOnSale(product);
|
|
10087
|
+
const discount = getDiscountPercentage(product);
|
|
10088
|
+
const baseTotal = components.reduce(
|
|
10089
|
+
(sum, c) => sum + parsePrice(c.effective_price ?? 0) * (c.quantity ?? 1),
|
|
10090
|
+
0
|
|
10091
|
+
);
|
|
10092
|
+
const bundlePrice = parsePrice(product.default_price);
|
|
10093
|
+
const savings = baseTotal > bundlePrice ? baseTotal - bundlePrice : 0;
|
|
10094
|
+
return /* @__PURE__ */ jsxs("div", { "data-cimplify-product-layout": "bundle", className: cn("space-y-8", className), children: [
|
|
10095
|
+
renderBreadcrumb?.(product),
|
|
10096
|
+
/* @__PURE__ */ jsx(
|
|
10097
|
+
TwoColumnGrid,
|
|
10098
|
+
{
|
|
10099
|
+
left: /* @__PURE__ */ jsx(
|
|
10100
|
+
ProductImageGallery,
|
|
10101
|
+
{
|
|
10102
|
+
images,
|
|
10103
|
+
productName: product.name
|
|
10104
|
+
}
|
|
10105
|
+
),
|
|
10106
|
+
right: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
10107
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
10108
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-indigo-700 bg-indigo-50 border border-indigo-200/60 px-2.5 py-1 rounded-md", children: "Bundle" }),
|
|
10109
|
+
savings > 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-semibold text-emerald-700 bg-emerald-50 border border-emerald-200/60 px-2.5 py-1 rounded-md", children: [
|
|
10110
|
+
"Save ",
|
|
10111
|
+
discount,
|
|
10112
|
+
"%"
|
|
10113
|
+
] }),
|
|
10114
|
+
/* @__PURE__ */ jsx(TagPills, { tags: product.tags || [] })
|
|
10115
|
+
] }),
|
|
10116
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
10117
|
+
/* @__PURE__ */ jsx("h1", { "data-cimplify-product-layout-name": true, className: "text-3xl lg:text-4xl font-bold tracking-tight", children: product.name }),
|
|
10118
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-3 mt-2", children: [
|
|
10119
|
+
/* @__PURE__ */ jsx(Price, { amount: product.default_price, className: "text-2xl font-bold" }),
|
|
10120
|
+
onSale && baseTotal > 0 && /* @__PURE__ */ jsx(Price, { amount: baseTotal, className: "text-lg text-muted-foreground line-through" })
|
|
10121
|
+
] })
|
|
10122
|
+
] }),
|
|
10123
|
+
product.description && /* @__PURE__ */ jsx("p", { "data-cimplify-product-layout-description": true, className: "text-muted-foreground leading-relaxed", children: product.description }),
|
|
10124
|
+
components.length > 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-bundle-components": true, className: "space-y-3", children: [
|
|
10125
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Included in this bundle" }),
|
|
10126
|
+
/* @__PURE__ */ jsx("div", { className: "divide-y divide-border border border-border rounded-lg overflow-hidden", children: components.map((component) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-3", children: [
|
|
10127
|
+
component.product_image_url && /* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-lg overflow-hidden bg-muted shrink-0", children: /* @__PURE__ */ jsx("img", { src: component.product_image_url, alt: component.product_name, className: "w-full h-full object-cover" }) }),
|
|
10128
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
10129
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: component.product_name }),
|
|
10130
|
+
component.quantity > 1 && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
10131
|
+
"Qty: ",
|
|
10132
|
+
component.quantity
|
|
10133
|
+
] }),
|
|
10134
|
+
component.allow_variant_choice && /* @__PURE__ */ jsx("p", { className: "text-xs text-violet-600 font-medium", children: "Choose variant" })
|
|
10135
|
+
] }),
|
|
10136
|
+
/* @__PURE__ */ jsx(Price, { amount: component.effective_price ?? 0, className: "text-sm text-muted-foreground shrink-0" })
|
|
10137
|
+
] }, component.id)) })
|
|
10138
|
+
] }),
|
|
10139
|
+
savings > 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-bundle-savings": true, className: "flex items-center gap-2 p-3 bg-emerald-50 border border-emerald-200/60 text-sm text-emerald-800", children: [
|
|
10140
|
+
/* @__PURE__ */ jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }),
|
|
10141
|
+
"You save ",
|
|
10142
|
+
/* @__PURE__ */ jsx(Price, { amount: savings, className: "font-semibold" }),
|
|
10143
|
+
" with this bundle"
|
|
10144
|
+
] }),
|
|
10145
|
+
/* @__PURE__ */ jsx(CustomAttributesTable, { attributes: product.custom_attributes || [] }),
|
|
10146
|
+
/* @__PURE__ */ jsx(
|
|
10147
|
+
ProductCustomizer,
|
|
10148
|
+
{
|
|
10149
|
+
product,
|
|
10150
|
+
onAddToCart
|
|
10151
|
+
}
|
|
10152
|
+
)
|
|
10153
|
+
] })
|
|
10154
|
+
}
|
|
10155
|
+
),
|
|
10156
|
+
showRelated && relatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsx(RelatedProductsSection, { products: relatedProducts })
|
|
10157
|
+
] });
|
|
10158
|
+
}
|
|
10159
|
+
function CompositeProductLayout({
|
|
10160
|
+
product,
|
|
10161
|
+
onAddToCart,
|
|
10162
|
+
renderBreadcrumb,
|
|
10163
|
+
relatedProducts,
|
|
10164
|
+
showRelated = true,
|
|
10165
|
+
className
|
|
10166
|
+
}) {
|
|
10167
|
+
const images = product.images || (product.image_url ? [product.image_url] : []);
|
|
10168
|
+
const groups = product.groups || [];
|
|
10169
|
+
return /* @__PURE__ */ jsxs("div", { "data-cimplify-product-layout": "composite", className: cn("space-y-8", className), children: [
|
|
10170
|
+
renderBreadcrumb?.(product),
|
|
10171
|
+
/* @__PURE__ */ jsx(
|
|
10172
|
+
TwoColumnGrid,
|
|
10173
|
+
{
|
|
10174
|
+
left: /* @__PURE__ */ jsx(
|
|
10175
|
+
ProductImageGallery,
|
|
10176
|
+
{
|
|
10177
|
+
images,
|
|
10178
|
+
productName: product.name
|
|
10179
|
+
}
|
|
10180
|
+
),
|
|
10181
|
+
right: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
10182
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
10183
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-violet-700 bg-violet-50 border border-violet-200/60 px-2.5 py-1 rounded-md", children: "Build Your Own" }),
|
|
10184
|
+
groups.length > 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-muted-foreground bg-muted px-2.5 py-1 rounded-md", children: [
|
|
10185
|
+
groups.length,
|
|
10186
|
+
" choice",
|
|
10187
|
+
groups.length !== 1 ? "s" : ""
|
|
10188
|
+
] }),
|
|
10189
|
+
/* @__PURE__ */ jsx(TagPills, { tags: product.tags || [] })
|
|
10190
|
+
] }),
|
|
10191
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
10192
|
+
/* @__PURE__ */ jsx("h1", { "data-cimplify-product-layout-name": true, className: "text-3xl lg:text-4xl font-bold tracking-tight", children: product.name }),
|
|
10193
|
+
/* @__PURE__ */ jsxs("p", { className: "text-lg text-muted-foreground mt-2", children: [
|
|
10194
|
+
"From ",
|
|
10195
|
+
/* @__PURE__ */ jsx(Price, { amount: product.default_price, className: "font-semibold text-foreground" })
|
|
10196
|
+
] })
|
|
10197
|
+
] }),
|
|
10198
|
+
product.description && /* @__PURE__ */ jsx("p", { "data-cimplify-product-layout-description": true, className: "text-muted-foreground leading-relaxed", children: product.description }),
|
|
10199
|
+
groups.length > 0 && /* @__PURE__ */ jsx("div", { "data-cimplify-composite-overview": true, className: "flex flex-wrap gap-2", children: groups.map((group) => {
|
|
10200
|
+
const availableCount = group.components.filter((c) => c.is_available && !c.is_archived).length;
|
|
10201
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 bg-muted rounded-lg text-sm", children: [
|
|
10202
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: group.name }),
|
|
10203
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
|
|
10204
|
+
group.min_selections > 0 ? `Pick ${group.min_selections}` : "Optional",
|
|
10205
|
+
` \xB7 ${availableCount} option${availableCount !== 1 ? "s" : ""}`
|
|
10206
|
+
] })
|
|
10207
|
+
] }, group.id);
|
|
10208
|
+
}) }),
|
|
10209
|
+
/* @__PURE__ */ jsx(CustomAttributesTable, { attributes: product.custom_attributes || [] }),
|
|
10210
|
+
/* @__PURE__ */ jsx(
|
|
10211
|
+
ProductCustomizer,
|
|
10212
|
+
{
|
|
10213
|
+
product,
|
|
10214
|
+
onAddToCart
|
|
10215
|
+
}
|
|
10216
|
+
)
|
|
10217
|
+
] })
|
|
10218
|
+
}
|
|
10219
|
+
),
|
|
10220
|
+
showRelated && relatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsx(RelatedProductsSection, { products: relatedProducts })
|
|
10221
|
+
] });
|
|
10222
|
+
}
|
|
8997
10223
|
var ProductTemplate = /* @__PURE__ */ ((ProductTemplate2) => {
|
|
8998
10224
|
ProductTemplate2["Default"] = "default";
|
|
8999
10225
|
ProductTemplate2["Food"] = "food";
|
|
9000
10226
|
ProductTemplate2["Wholesale"] = "wholesale";
|
|
9001
10227
|
ProductTemplate2["Service"] = "service";
|
|
9002
10228
|
ProductTemplate2["Digital"] = "digital";
|
|
10229
|
+
ProductTemplate2["Bundle"] = "bundle";
|
|
10230
|
+
ProductTemplate2["Composite"] = "composite";
|
|
9003
10231
|
ProductTemplate2["Physical"] = "physical";
|
|
9004
10232
|
return ProductTemplate2;
|
|
9005
10233
|
})(ProductTemplate || {});
|
|
@@ -9008,6 +10236,8 @@ var BUILT_IN_LAYOUTS2 = {
|
|
|
9008
10236
|
["wholesale" /* Wholesale */]: WholesaleProductLayout,
|
|
9009
10237
|
["service" /* Service */]: ServiceProductLayout,
|
|
9010
10238
|
["digital" /* Digital */]: DigitalProductLayout,
|
|
10239
|
+
["bundle" /* Bundle */]: BundleProductLayout,
|
|
10240
|
+
["composite" /* Composite */]: CompositeProductLayout,
|
|
9011
10241
|
["default" /* Default */]: DefaultProductLayout
|
|
9012
10242
|
};
|
|
9013
10243
|
function resolveTemplateKey(product) {
|
|
@@ -9015,6 +10245,12 @@ function resolveTemplateKey(product) {
|
|
|
9015
10245
|
if (typeof metaTemplate === "string" && metaTemplate.trim()) {
|
|
9016
10246
|
return metaTemplate.trim();
|
|
9017
10247
|
}
|
|
10248
|
+
if (product.type === PRODUCT_TYPE.Bundle) {
|
|
10249
|
+
return "bundle" /* Bundle */;
|
|
10250
|
+
}
|
|
10251
|
+
if (product.type === PRODUCT_TYPE.Composite) {
|
|
10252
|
+
return "composite" /* Composite */;
|
|
10253
|
+
}
|
|
9018
10254
|
if (product.quantity_pricing && product.quantity_pricing.length > 1) {
|
|
9019
10255
|
return "wholesale" /* Wholesale */;
|
|
9020
10256
|
}
|
|
@@ -9379,7 +10615,7 @@ function DefaultCollectionLayout({
|
|
|
9379
10615
|
] })
|
|
9380
10616
|
] }),
|
|
9381
10617
|
filtered.length > 0 ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4", children: filtered.map(
|
|
9382
|
-
(product) => renderCard ? /* @__PURE__ */ jsx(
|
|
10618
|
+
(product) => renderCard ? /* @__PURE__ */ jsx(React10.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsx(
|
|
9383
10619
|
ProductCard,
|
|
9384
10620
|
{
|
|
9385
10621
|
product,
|
|
@@ -9432,7 +10668,7 @@ function FeaturedCollectionLayout({
|
|
|
9432
10668
|
] })
|
|
9433
10669
|
] }),
|
|
9434
10670
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: products.map(
|
|
9435
|
-
(product) => renderCard ? /* @__PURE__ */ jsx(
|
|
10671
|
+
(product) => renderCard ? /* @__PURE__ */ jsx(React10.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsx(
|
|
9436
10672
|
ProductCard,
|
|
9437
10673
|
{
|
|
9438
10674
|
product,
|
|
@@ -9556,7 +10792,7 @@ function CatalogueCollectionLayout({
|
|
|
9556
10792
|
] })
|
|
9557
10793
|
] }),
|
|
9558
10794
|
filtered.length > 0 ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4", children: filtered.map(
|
|
9559
|
-
(product) => renderCard ? /* @__PURE__ */ jsx(
|
|
10795
|
+
(product) => renderCard ? /* @__PURE__ */ jsx(React10.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsx(
|
|
9560
10796
|
ProductCard,
|
|
9561
10797
|
{
|
|
9562
10798
|
product,
|
|
@@ -9936,7 +11172,7 @@ function DefaultSearchLayout({
|
|
|
9936
11172
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try a different search term" }),
|
|
9937
11173
|
/* @__PURE__ */ jsx("button", { onClick: clear, className: "text-sm font-medium text-primary mt-4 hover:underline", children: "Clear search" })
|
|
9938
11174
|
] }) : results.length > 0 ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-4", children: results.map(
|
|
9939
|
-
(product) => renderCard ? /* @__PURE__ */ jsx(
|
|
11175
|
+
(product) => renderCard ? /* @__PURE__ */ jsx(React10.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsx(
|
|
9940
11176
|
ProductCard,
|
|
9941
11177
|
{
|
|
9942
11178
|
product,
|
|
@@ -10038,7 +11274,7 @@ function CompactSearchLayout({
|
|
|
10038
11274
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try a different search term" }),
|
|
10039
11275
|
/* @__PURE__ */ jsx("button", { onClick: clear, className: "text-sm font-medium text-primary mt-4 hover:underline", children: "Clear search" })
|
|
10040
11276
|
] }) : results.length > 0 ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 lg:grid-cols-3 gap-5", children: results.map(
|
|
10041
|
-
(product) => renderCard ? /* @__PURE__ */ jsx(
|
|
11277
|
+
(product) => renderCard ? /* @__PURE__ */ jsx(React10.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsx(
|
|
10042
11278
|
ProductCard,
|
|
10043
11279
|
{
|
|
10044
11280
|
product,
|
|
@@ -10603,4 +11839,4 @@ function ResourcePicker({
|
|
|
10603
11839
|
);
|
|
10604
11840
|
}
|
|
10605
11841
|
|
|
10606
|
-
export { AccommodationCard, Ad, AdProvider, AddOnSelector, AddressElement, AuthElement, AvailabilityBadge, BillingPlanSelector, BookingCard, BookingList, BundleSelector, CardImage, CardShell, CardVariant, CartPage, CartSummary, CartTemplate, CatalogueCollectionLayout, CataloguePage, CatalogueTemplate, CategoryFilter, CategoryGrid, CheckoutPage, CimplifyAccount, CimplifyCheckout, CimplifyProvider, CollectionPage, CollectionTemplate, CompactCartLayout, CompactCatalogueLayout, CompactSearchLayout, CompactServiceCard, CompositeSelector, CurrencySelector, CustomAttributesTable, DateSlotPicker, DealBanner, DealsPage, DefaultCartLayout, DefaultCatalogueLayout, DefaultCollectionLayout, DefaultProductLayout, DefaultSearchLayout, DeliveryEstimate, DigitalProductCard, DigitalProductLayout, DiscountInput, ElementsProvider, FeaturedCollectionLayout, FoodProductCard, FoodProductLayout, InventoryBadge, LeaseServiceCard, LocationPicker, MetadataStringList, OrderDetailPage, OrderHistory, OrderHistoryPage, OrderSummary, PaymentElement, Price, PriceRange, ProductCard, ProductCustomizer, ProductGrid, ProductImageGallery, ProductPage, ProductSheet, ProductTemplate, PropertiesTable, QuantitySelector, QuickAddButton, RecentlyViewed, RecommendationCarousel, RelatedProductsSection, RentalServiceCard, ResourcePicker, RetailProductCard, SaleBadge, ScheduleServiceCard, SearchInput, SearchPage, SearchTemplate, ServiceProductLayout, SessionMessageBanner, SlotPicker, SoldOutOverlay, StaffPicker, StandardServiceCard, StoreNav, SubscriptionCard, TagPills, TwoColumnGrid, VariantSelector, VolumePricing, WholesaleProductCard, WholesaleProductLayout, WishlistButton, cn, roomToResource, useActivityState, useAds, useAttributeDefinitions, useAvailableSlots, useBillingPlans, useBookings, useBootstrap, useBundles, useCart, useCategories, useCheckout, useCimplify, useCimplifyClient, useCollection, useCollections, useDeals, useDeliveryFee, useElements, useElementsReady, useFxRate, useLocations, useOptionalCimplify, useOrder, useOrders, useProduct, useProductAvailability, useProductDeals, useProductPrice, useProductSchedules, useProducts, useProductsOnSale, usePropertyFacets, useQuote, useRecommendations, useSearch, useServiceAvailability, useServices, useTaxonomies, useTaxonomy, useTaxonomyPath, useValidateDiscount, useVariantSelector };
|
|
11842
|
+
export { AccommodationCard, Ad, AdProvider, AddOnSelector, AddressElement, AuthElement, AvailabilityBadge, BillingPlanSelector, BookingCard, BookingList, BundleProductCard, BundleProductLayout, BundleSelector, CardImage, CardShell, CardVariant, CartPage, CartSummary, CartTemplate, CatalogueCollectionLayout, CataloguePage, CatalogueTemplate, CategoryFilter, CategoryGrid, CheckoutPage, CimplifyAccount, CimplifyCheckout, CimplifyProvider, CollectionPage, CollectionTemplate, CompactCartLayout, CompactCatalogueLayout, CompactSearchLayout, CompactServiceCard, CompositeProductCard, CompositeProductLayout, CompositeSelector, CurrencySelector, CustomAttributesTable, CustomerInputFields, DateSlotPicker, DealBanner, DealsPage, DefaultCartLayout, DefaultCatalogueLayout, DefaultCollectionLayout, DefaultProductLayout, DefaultSearchLayout, DeliveryEstimate, DigitalProductCard, DigitalProductLayout, DiscountInput, ElementsProvider, FeaturedCollectionLayout, FoodProductCard, FoodProductLayout, InventoryBadge, LeaseServiceCard, LocationPicker, MetadataStringList, OrderDetailPage, OrderHistory, OrderHistoryPage, OrderSummary, PaymentElement, Price, PriceRange, ProductCard, ProductCustomizer, ProductGrid, ProductImageGallery, ProductPage, ProductSheet, ProductTemplate, PropertiesTable, QuantitySelector, QuickAddButton, RecentlyViewed, RecommendationCarousel, RelatedProductsSection, RentalServiceCard, ResourcePicker, RetailProductCard, SaleBadge, ScheduleServiceCard, SearchInput, SearchPage, SearchTemplate, ServiceProductLayout, SessionMessageBanner, SlotPicker, SoldOutOverlay, StaffPicker, StandardServiceCard, StoreNav, SubscriptionCard, TagPills, TwoColumnGrid, VariantSelector, VolumePricing, WholesaleProductCard, WholesaleProductLayout, WishlistButton, cn, roomToResource, useActivityState, useAds, useAttributeDefinitions, useAvailableSlots, useBillingPlans, useBookings, useBootstrap, useBundles, useCart, useCategories, useCheckout, useCimplify, useCimplifyClient, useCollection, useCollections, useDeals, useDeliveryFee, useElements, useElementsReady, useFxRate, useLocations, useOptionalCimplify, useOrder, useOrders, useProduct, useProductAvailability, useProductDeals, useProductPrice, useProductSchedules, useProducts, useProductsOnSale, usePropertyFacets, useQuote, useRecommendations, useSearch, useServiceAvailability, useServices, useSubscription, useSubscriptions, useTaxonomies, useTaxonomy, useTaxonomyPath, useValidateDiscount, useVariantSelector };
|