@cimplify/sdk 0.29.0 → 0.31.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-REXW2PET.mjs → chunk-46BDUSJX.mjs} +46 -1
- package/dist/{chunk-R4AKAGZQ.js → chunk-6HCBOIZ4.js} +46 -0
- package/dist/{index-Cjfczg2W.d.ts → index-BHVJgyqM.d.ts} +2 -2
- package/dist/{index-DijjnO-u.d.mts → index-BpyFcJVv.d.ts} +92 -15
- package/dist/{index-D4-b5OZO.d.mts → index-D4oNCc37.d.mts} +2 -2
- package/dist/{index-DwvzjdGi.d.ts → index-m8zGQUda.d.mts} +92 -15
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +17 -13
- package/dist/index.mjs +1 -1
- package/dist/{payment-BeLHpQMo.d.ts → payment-DnU_eLuT.d.mts} +19 -3
- package/dist/{payment-BeLHpQMo.d.mts → payment-DnU_eLuT.d.ts} +19 -3
- package/dist/{price-Dvl1p9AM.d.mts → price-D-hso3np.d.mts} +1 -1
- package/dist/{price-C6gfys5B.d.ts → price-DUVmRTaz.d.ts} +1 -1
- package/dist/react.d.mts +54 -4
- package/dist/react.d.ts +54 -4
- package/dist/react.js +741 -69
- package/dist/react.mjs +696 -26
- 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/chat-widget.json +15 -0
- package/registry/index.json +9 -0
- package/registry/product-customizer.json +1 -1
- package/registry/schedule-service-card.json +1 -1
- package/registry/service-product-layout.json +1 -1
- package/registry/subscription-card.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { DURATION_UNIT, getVariantDisplayName, INPUT_FIELD_TYPE, 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-46BDUSJX.mjs';
|
|
3
|
+
export { getVariantDisplayName } from './chunk-46BDUSJX.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
6
|
import React10, { createContext, useRef, useState, useCallback, useEffect, useContext, useMemo, useSyncExternalStore, useId } from 'react';
|
|
@@ -3310,6 +3310,182 @@ function useBootstrap(options = {}) {
|
|
|
3310
3310
|
const { data, isLoading, error, refetch } = bootstrapQuery(options);
|
|
3311
3311
|
return { bootstrap: data, isLoading, error, refetch };
|
|
3312
3312
|
}
|
|
3313
|
+
var POLL_INTERVAL_MS = 3e3;
|
|
3314
|
+
var POLL_IDLE_INTERVAL_MS = 15e3;
|
|
3315
|
+
var IDLE_TIMEOUT_MS = 6e4;
|
|
3316
|
+
var WS_MAX_RECONNECT_ATTEMPTS = 10;
|
|
3317
|
+
var WS_PATH = "/api/v1/support/conversation/ws";
|
|
3318
|
+
function useChat(options = {}) {
|
|
3319
|
+
const context = useOptionalCimplifyClient();
|
|
3320
|
+
const client = options.client ?? context?.client;
|
|
3321
|
+
const [messages, setMessages] = useState([]);
|
|
3322
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
3323
|
+
const [isSending, setIsSending] = useState(false);
|
|
3324
|
+
const [error, setError] = useState(null);
|
|
3325
|
+
const [conversationOpened, setConversationOpened] = useState(false);
|
|
3326
|
+
const pollRef = useRef(null);
|
|
3327
|
+
const lastActivityRef = useRef(Date.now());
|
|
3328
|
+
const openedRef = useRef(false);
|
|
3329
|
+
const messagesRef = useRef([]);
|
|
3330
|
+
const clientRef = useRef(client);
|
|
3331
|
+
const wsRef = useRef(null);
|
|
3332
|
+
const wsReconnectAttemptRef = useRef(0);
|
|
3333
|
+
const wsReconnectTimerRef = useRef(null);
|
|
3334
|
+
messagesRef.current = messages;
|
|
3335
|
+
clientRef.current = client;
|
|
3336
|
+
const pollInterval = options.pollInterval ?? POLL_INTERVAL_MS;
|
|
3337
|
+
const pollIdleInterval = options.pollIdleInterval ?? POLL_IDLE_INTERVAL_MS;
|
|
3338
|
+
const appendMessages = useCallback((incoming) => {
|
|
3339
|
+
setMessages((prev) => {
|
|
3340
|
+
const ids = new Set(prev.map((m) => m.id));
|
|
3341
|
+
const fresh = incoming.filter((m) => !ids.has(m.id));
|
|
3342
|
+
return fresh.length > 0 ? [...prev, ...fresh] : prev;
|
|
3343
|
+
});
|
|
3344
|
+
}, []);
|
|
3345
|
+
const pollMessages = useCallback(async () => {
|
|
3346
|
+
const c = clientRef.current;
|
|
3347
|
+
if (!c) return;
|
|
3348
|
+
if (Date.now() - lastActivityRef.current > IDLE_TIMEOUT_MS) return;
|
|
3349
|
+
const last = messagesRef.current[messagesRef.current.length - 1];
|
|
3350
|
+
const result = await c.support.getMessages({
|
|
3351
|
+
after: last?.created_at,
|
|
3352
|
+
limit: 50
|
|
3353
|
+
});
|
|
3354
|
+
if (result.ok && result.value.length > 0) {
|
|
3355
|
+
appendMessages(result.value);
|
|
3356
|
+
}
|
|
3357
|
+
}, [appendMessages]);
|
|
3358
|
+
const startPolling = useCallback(() => {
|
|
3359
|
+
if (pollRef.current) clearInterval(pollRef.current);
|
|
3360
|
+
const interval = Date.now() - lastActivityRef.current > IDLE_TIMEOUT_MS ? pollIdleInterval : pollInterval;
|
|
3361
|
+
pollRef.current = setInterval(pollMessages, interval);
|
|
3362
|
+
}, [pollMessages, pollInterval, pollIdleInterval]);
|
|
3363
|
+
const stopPolling = useCallback(() => {
|
|
3364
|
+
if (pollRef.current) {
|
|
3365
|
+
clearInterval(pollRef.current);
|
|
3366
|
+
pollRef.current = null;
|
|
3367
|
+
}
|
|
3368
|
+
}, []);
|
|
3369
|
+
const connectWebSocket = useCallback(() => {
|
|
3370
|
+
const c = clientRef.current;
|
|
3371
|
+
if (!c || typeof WebSocket === "undefined") {
|
|
3372
|
+
startPolling();
|
|
3373
|
+
return;
|
|
3374
|
+
}
|
|
3375
|
+
if (wsRef.current) {
|
|
3376
|
+
wsRef.current.close();
|
|
3377
|
+
wsRef.current = null;
|
|
3378
|
+
}
|
|
3379
|
+
const url = c.buildWsUrl(WS_PATH);
|
|
3380
|
+
const ws = new WebSocket(url);
|
|
3381
|
+
ws.onopen = () => {
|
|
3382
|
+
wsReconnectAttemptRef.current = 0;
|
|
3383
|
+
stopPolling();
|
|
3384
|
+
};
|
|
3385
|
+
ws.onmessage = (event) => {
|
|
3386
|
+
try {
|
|
3387
|
+
const envelope = JSON.parse(event.data);
|
|
3388
|
+
if (envelope.type === "message.created" && envelope.data) {
|
|
3389
|
+
appendMessages([envelope.data]);
|
|
3390
|
+
}
|
|
3391
|
+
} catch {
|
|
3392
|
+
}
|
|
3393
|
+
};
|
|
3394
|
+
ws.onclose = () => {
|
|
3395
|
+
wsRef.current = null;
|
|
3396
|
+
if (!openedRef.current) return;
|
|
3397
|
+
pollMessages();
|
|
3398
|
+
if (wsReconnectAttemptRef.current < WS_MAX_RECONNECT_ATTEMPTS) {
|
|
3399
|
+
const attempt = wsReconnectAttemptRef.current++;
|
|
3400
|
+
const delay = Math.min(1e3 * Math.pow(2, attempt) + Math.random() * 500, 3e4);
|
|
3401
|
+
wsReconnectTimerRef.current = setTimeout(connectWebSocket, delay);
|
|
3402
|
+
} else {
|
|
3403
|
+
startPolling();
|
|
3404
|
+
}
|
|
3405
|
+
};
|
|
3406
|
+
ws.onerror = () => {
|
|
3407
|
+
};
|
|
3408
|
+
wsRef.current = ws;
|
|
3409
|
+
}, [appendMessages, startPolling, stopPolling, pollMessages]);
|
|
3410
|
+
useEffect(() => {
|
|
3411
|
+
return () => {
|
|
3412
|
+
if (pollRef.current) clearInterval(pollRef.current);
|
|
3413
|
+
if (wsReconnectTimerRef.current) clearTimeout(wsReconnectTimerRef.current);
|
|
3414
|
+
if (wsRef.current) {
|
|
3415
|
+
wsRef.current.onclose = null;
|
|
3416
|
+
wsRef.current.close();
|
|
3417
|
+
}
|
|
3418
|
+
};
|
|
3419
|
+
}, []);
|
|
3420
|
+
const openConversation = useCallback(async () => {
|
|
3421
|
+
if (openedRef.current || !client) return;
|
|
3422
|
+
openedRef.current = true;
|
|
3423
|
+
setIsLoading(true);
|
|
3424
|
+
setError(null);
|
|
3425
|
+
const result = await client.support.openConversation();
|
|
3426
|
+
if (result.ok) {
|
|
3427
|
+
setMessages(result.value.messages);
|
|
3428
|
+
setConversationOpened(true);
|
|
3429
|
+
connectWebSocket();
|
|
3430
|
+
} else {
|
|
3431
|
+
openedRef.current = false;
|
|
3432
|
+
setError(result.error);
|
|
3433
|
+
}
|
|
3434
|
+
setIsLoading(false);
|
|
3435
|
+
}, [client, connectWebSocket]);
|
|
3436
|
+
const send = useCallback(
|
|
3437
|
+
async (content) => {
|
|
3438
|
+
if (!client || !content.trim()) return;
|
|
3439
|
+
setError(null);
|
|
3440
|
+
lastActivityRef.current = Date.now();
|
|
3441
|
+
if (!openedRef.current) {
|
|
3442
|
+
await openConversation();
|
|
3443
|
+
if (!openedRef.current) return;
|
|
3444
|
+
}
|
|
3445
|
+
const optimisticId = `opt_${Date.now()}`;
|
|
3446
|
+
const optimistic = {
|
|
3447
|
+
id: optimisticId,
|
|
3448
|
+
sender_type: "customer",
|
|
3449
|
+
content: content.trim(),
|
|
3450
|
+
content_type: "text",
|
|
3451
|
+
attachments: [],
|
|
3452
|
+
metadata: {},
|
|
3453
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3454
|
+
};
|
|
3455
|
+
setMessages((prev) => [...prev, optimistic]);
|
|
3456
|
+
setIsSending(true);
|
|
3457
|
+
const result = await client.support.sendMessage(content.trim());
|
|
3458
|
+
if (result.ok) {
|
|
3459
|
+
setMessages(
|
|
3460
|
+
(prev) => prev.map((m) => m.id === optimisticId ? result.value : m)
|
|
3461
|
+
);
|
|
3462
|
+
} else {
|
|
3463
|
+
setMessages((prev) => prev.filter((m) => m.id !== optimisticId));
|
|
3464
|
+
setError(result.error);
|
|
3465
|
+
}
|
|
3466
|
+
setIsSending(false);
|
|
3467
|
+
},
|
|
3468
|
+
[client, openConversation]
|
|
3469
|
+
);
|
|
3470
|
+
const startConversation = useCallback(
|
|
3471
|
+
async (starterText) => {
|
|
3472
|
+
await openConversation();
|
|
3473
|
+
if (starterText) {
|
|
3474
|
+
await send(starterText);
|
|
3475
|
+
}
|
|
3476
|
+
},
|
|
3477
|
+
[openConversation, send]
|
|
3478
|
+
);
|
|
3479
|
+
return {
|
|
3480
|
+
messages,
|
|
3481
|
+
isLoading,
|
|
3482
|
+
isSending,
|
|
3483
|
+
error,
|
|
3484
|
+
isActive: conversationOpened && messages.length > 0,
|
|
3485
|
+
send,
|
|
3486
|
+
startConversation
|
|
3487
|
+
};
|
|
3488
|
+
}
|
|
3313
3489
|
var ElementsContext = createContext({
|
|
3314
3490
|
elements: null,
|
|
3315
3491
|
isReady: false
|
|
@@ -4661,8 +4837,26 @@ function CompositeSelector({
|
|
|
4661
4837
|
)
|
|
4662
4838
|
] });
|
|
4663
4839
|
}
|
|
4840
|
+
|
|
4841
|
+
// src/react/utils/format-duration.ts
|
|
4842
|
+
var UNIT_LABELS = {
|
|
4843
|
+
minutes: { singular: "min", plural: "min" },
|
|
4844
|
+
hours: { singular: "hr", plural: "hrs" },
|
|
4845
|
+
days: { singular: "day", plural: "days" },
|
|
4846
|
+
nights: { singular: "night", plural: "nights" },
|
|
4847
|
+
weeks: { singular: "week", plural: "weeks" },
|
|
4848
|
+
months: { singular: "month", plural: "months" },
|
|
4849
|
+
years: { singular: "year", plural: "years" }
|
|
4850
|
+
};
|
|
4851
|
+
function formatDuration2(value, unit) {
|
|
4852
|
+
const resolved = unit ?? "minutes";
|
|
4853
|
+
const labels = UNIT_LABELS[resolved];
|
|
4854
|
+
const label = value === 1 ? labels.singular : labels.plural;
|
|
4855
|
+
return `${value} ${label}`;
|
|
4856
|
+
}
|
|
4664
4857
|
var FREQUENCY_LABELS = {
|
|
4665
4858
|
weekly: "Weekly",
|
|
4859
|
+
biweekly: "Biweekly",
|
|
4666
4860
|
monthly: "Monthly",
|
|
4667
4861
|
quarterly: "Quarterly",
|
|
4668
4862
|
annually: "Annually"
|
|
@@ -5986,9 +6180,7 @@ function ProductCustomizer({
|
|
|
5986
6180
|
)) }),
|
|
5987
6181
|
isService && product.duration_minutes != null && /* @__PURE__ */ jsxs("div", { "data-cimplify-customizer-duration": true, className: cn("text-sm text-muted-foreground", classNames?.duration), children: [
|
|
5988
6182
|
"Duration: ",
|
|
5989
|
-
product.duration_minutes,
|
|
5990
|
-
" ",
|
|
5991
|
-
product.duration_unit ?? "minutes"
|
|
6183
|
+
formatDuration2(product.duration_minutes, product.duration_unit)
|
|
5992
6184
|
] }),
|
|
5993
6185
|
showSpecialInstructions && !isDigital && /* @__PURE__ */ jsx("div", { "data-cimplify-customizer-special-instructions": true, children: /* @__PURE__ */ jsx(
|
|
5994
6186
|
"textarea",
|
|
@@ -6951,7 +7143,7 @@ function CompositeProductCard({
|
|
|
6951
7143
|
] })
|
|
6952
7144
|
] });
|
|
6953
7145
|
}
|
|
6954
|
-
function
|
|
7146
|
+
function formatDuration3(minutes, unit) {
|
|
6955
7147
|
if (unit && unit !== "minutes") return `${minutes} ${unit}`;
|
|
6956
7148
|
if (minutes >= 60) {
|
|
6957
7149
|
const h = Math.floor(minutes / 60);
|
|
@@ -6972,7 +7164,7 @@ function StandardServiceCard({
|
|
|
6972
7164
|
return /* @__PURE__ */ jsxs(CardShell, { product, renderLink, className, children: [
|
|
6973
7165
|
/* @__PURE__ */ jsxs(CardImage, { src: image, alt: product.name, aspectRatio: "16/9", renderImage, children: [
|
|
6974
7166
|
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/50 to-transparent pointer-events-none" }),
|
|
6975
|
-
product.duration_minutes != null && /* @__PURE__ */ jsx("span", { className: "absolute bottom-3 left-3 inline-flex items-center gap-1 text-[12px] font-semibold px-2.5 py-1 rounded-lg bg-background/92 backdrop-blur-xl text-foreground shadow-sm", children:
|
|
7167
|
+
product.duration_minutes != null && /* @__PURE__ */ jsx("span", { className: "absolute bottom-3 left-3 inline-flex items-center gap-1 text-[12px] font-semibold px-2.5 py-1 rounded-lg bg-background/92 backdrop-blur-xl text-foreground shadow-sm", children: formatDuration3(product.duration_minutes, product.duration_unit) }),
|
|
6976
7168
|
/* @__PURE__ */ jsx("span", { className: "absolute bottom-3 right-3 text-white font-bold text-lg drop-shadow-sm", children: /* @__PURE__ */ jsx(Price, { amount: product.default_price }) })
|
|
6977
7169
|
] }),
|
|
6978
7170
|
/* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
@@ -7006,7 +7198,7 @@ function StandardServiceCard({
|
|
|
7006
7198
|
] })
|
|
7007
7199
|
] });
|
|
7008
7200
|
}
|
|
7009
|
-
function
|
|
7201
|
+
function formatDuration4(minutes, unit) {
|
|
7010
7202
|
if (unit && unit !== "minutes") return `${minutes} ${unit}`;
|
|
7011
7203
|
if (minutes >= 60) {
|
|
7012
7204
|
const h = Math.floor(minutes / 60);
|
|
@@ -7031,7 +7223,7 @@ function CompactServiceCard({
|
|
|
7031
7223
|
/* @__PURE__ */ jsx("h3", { className: "text-[14px] font-semibold text-foreground leading-tight truncate", children: product.name }),
|
|
7032
7224
|
product.description && /* @__PURE__ */ jsx("p", { className: "text-[12px] text-muted-foreground mt-0.5 truncate", children: product.description }),
|
|
7033
7225
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-2 flex-wrap", children: [
|
|
7034
|
-
product.duration_minutes != null && /* @__PURE__ */ jsx("span", { className: "text-[10.5px] font-medium text-muted-foreground px-1.5 py-0.5 bg-muted rounded", children:
|
|
7226
|
+
product.duration_minutes != null && /* @__PURE__ */ jsx("span", { className: "text-[10.5px] font-medium text-muted-foreground px-1.5 py-0.5 bg-muted rounded", children: formatDuration4(product.duration_minutes, product.duration_unit) }),
|
|
7035
7227
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-[10.5px] font-medium text-emerald-600", children: [
|
|
7036
7228
|
/* @__PURE__ */ jsx("span", { className: "w-[6px] h-[6px] rounded-full bg-emerald-500" }),
|
|
7037
7229
|
"Available"
|
|
@@ -7071,7 +7263,7 @@ function ScheduleServiceCard({
|
|
|
7071
7263
|
}) {
|
|
7072
7264
|
const image = product.image_url || product.images?.[0] || "";
|
|
7073
7265
|
const href = `/products/${product.slug}`;
|
|
7074
|
-
const durationLabel = product.duration_minutes != null ?
|
|
7266
|
+
const durationLabel = product.duration_minutes != null ? formatDuration2(product.duration_minutes, product.duration_unit) : null;
|
|
7075
7267
|
const displaySlots = (slots || []).slice(0, 3);
|
|
7076
7268
|
const shellClass = cn(
|
|
7077
7269
|
"group block text-left cursor-pointer bg-card rounded-[14px] overflow-hidden",
|
|
@@ -7124,7 +7316,7 @@ function ScheduleServiceCard({
|
|
|
7124
7316
|
}
|
|
7125
7317
|
return /* @__PURE__ */ jsx("a", { href, className: shellClass, "data-cimplify-card": true, children: inner });
|
|
7126
7318
|
}
|
|
7127
|
-
var
|
|
7319
|
+
var UNIT_LABELS2 = {
|
|
7128
7320
|
minutes: "min",
|
|
7129
7321
|
hours: "hr",
|
|
7130
7322
|
days: "day",
|
|
@@ -7142,7 +7334,7 @@ function RentalServiceCard({
|
|
|
7142
7334
|
}) {
|
|
7143
7335
|
const image = product.image_url || product.images?.[0] || "";
|
|
7144
7336
|
const hasDeposit = product.deposit_type && product.deposit_type !== "none" && product.deposit_amount;
|
|
7145
|
-
const unit = product.duration_unit ?
|
|
7337
|
+
const unit = product.duration_unit ? UNIT_LABELS2[product.duration_unit] || product.duration_unit : "day";
|
|
7146
7338
|
const status = product.inventory_status;
|
|
7147
7339
|
return /* @__PURE__ */ jsxs(CardShell, { product, renderLink, className, children: [
|
|
7148
7340
|
/* @__PURE__ */ jsxs(CardImage, { src: image, alt: product.name, aspectRatio: "16/9", renderImage, children: [
|
|
@@ -7262,7 +7454,7 @@ function AccommodationCard({
|
|
|
7262
7454
|
] })
|
|
7263
7455
|
] });
|
|
7264
7456
|
}
|
|
7265
|
-
var
|
|
7457
|
+
var UNIT_LABELS3 = {
|
|
7266
7458
|
weeks: "week",
|
|
7267
7459
|
months: "mo",
|
|
7268
7460
|
years: "yr"
|
|
@@ -7277,7 +7469,7 @@ function LeaseServiceCard({
|
|
|
7277
7469
|
const image = product.image_url || product.images?.[0] || "";
|
|
7278
7470
|
const hasDeposit = product.deposit_type && product.deposit_type !== "none" && product.deposit_amount;
|
|
7279
7471
|
const hasTiers = product.quantity_pricing && product.quantity_pricing.length > 1;
|
|
7280
|
-
const unit = product.duration_unit ?
|
|
7472
|
+
const unit = product.duration_unit ? UNIT_LABELS3[product.duration_unit] || product.duration_unit : "mo";
|
|
7281
7473
|
const tags = product.tags || [];
|
|
7282
7474
|
const cancellationHours = product.cancellation_window_minutes ? Math.floor(product.cancellation_window_minutes / 60) : null;
|
|
7283
7475
|
return /* @__PURE__ */ jsxs(CardShell, { product, renderLink, className, children: [
|
|
@@ -7335,6 +7527,7 @@ function LeaseServiceCard({
|
|
|
7335
7527
|
}
|
|
7336
7528
|
var FREQUENCY_LABELS2 = {
|
|
7337
7529
|
weekly: "/week",
|
|
7530
|
+
biweekly: "/2wk",
|
|
7338
7531
|
monthly: "/mo",
|
|
7339
7532
|
quarterly: "/qtr",
|
|
7340
7533
|
annually: "/yr"
|
|
@@ -9837,15 +10030,6 @@ function WholesaleProductLayout({
|
|
|
9837
10030
|
)
|
|
9838
10031
|
] });
|
|
9839
10032
|
}
|
|
9840
|
-
function formatMinutes(minutes) {
|
|
9841
|
-
if (minutes >= 1440) return `${Math.floor(minutes / 1440)} day${minutes >= 2880 ? "s" : ""}`;
|
|
9842
|
-
if (minutes >= 60) {
|
|
9843
|
-
const h = Math.floor(minutes / 60);
|
|
9844
|
-
const m = minutes % 60;
|
|
9845
|
-
return m > 0 ? `${h}h ${m}min` : `${h} hour${h > 1 ? "s" : ""}`;
|
|
9846
|
-
}
|
|
9847
|
-
return `${minutes} min`;
|
|
9848
|
-
}
|
|
9849
10033
|
function ServiceProductLayout({
|
|
9850
10034
|
product,
|
|
9851
10035
|
onAddToCart,
|
|
@@ -9877,7 +10061,7 @@ function ServiceProductLayout({
|
|
|
9877
10061
|
/* @__PURE__ */ jsx(Price, { amount: product.default_price, className: "text-2xl font-bold text-primary mt-2 block" })
|
|
9878
10062
|
] }),
|
|
9879
10063
|
/* @__PURE__ */ jsxs("div", { "data-cimplify-product-layout-service-info": true, className: "flex flex-wrap gap-2", children: [
|
|
9880
|
-
product.duration_minutes != null && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children:
|
|
10064
|
+
product.duration_minutes != null && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children: formatDuration2(product.duration_minutes, product.duration_unit) }),
|
|
9881
10065
|
hasDeposit && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children: [
|
|
9882
10066
|
/* @__PURE__ */ jsx(Price, { amount: depositAmount }),
|
|
9883
10067
|
" deposit"
|
|
@@ -9914,7 +10098,7 @@ function ServiceProductLayout({
|
|
|
9914
10098
|
cancellationHours,
|
|
9915
10099
|
" hours"
|
|
9916
10100
|
] }),
|
|
9917
|
-
" before the
|
|
10101
|
+
" before the booking"
|
|
9918
10102
|
] }),
|
|
9919
10103
|
product.no_show_fee && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground", children: [
|
|
9920
10104
|
"No-show fee: ",
|
|
@@ -11838,5 +12022,491 @@ function ResourcePicker({
|
|
|
11838
12022
|
}
|
|
11839
12023
|
);
|
|
11840
12024
|
}
|
|
12025
|
+
function ChatWidget({
|
|
12026
|
+
client: clientProp,
|
|
12027
|
+
businessName = "Support",
|
|
12028
|
+
greeting = "Hi there!",
|
|
12029
|
+
subtitle = "Ask us anything \u2014 we typically reply in a few seconds.",
|
|
12030
|
+
starters,
|
|
12031
|
+
placeholder = "Type a message\u2026",
|
|
12032
|
+
position = "bottom-right",
|
|
12033
|
+
defaultOpen = false,
|
|
12034
|
+
pollInterval,
|
|
12035
|
+
className,
|
|
12036
|
+
classNames
|
|
12037
|
+
}) {
|
|
12038
|
+
const context = useOptionalCimplifyClient();
|
|
12039
|
+
const client = clientProp ?? context?.client;
|
|
12040
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
12041
|
+
const [unread, setUnread] = useState(0);
|
|
12042
|
+
const { messages, isLoading, isSending, error, isActive, send, startConversation } = useChat({ client, pollInterval });
|
|
12043
|
+
const prevCountRef = useRef(messages.length);
|
|
12044
|
+
useEffect(() => {
|
|
12045
|
+
if (!open && messages.length > prevCountRef.current) {
|
|
12046
|
+
const newMessages = messages.slice(prevCountRef.current);
|
|
12047
|
+
const incomingCount = newMessages.filter(
|
|
12048
|
+
(m) => m.sender_type !== "customer"
|
|
12049
|
+
).length;
|
|
12050
|
+
if (incomingCount > 0) setUnread((n) => n + incomingCount);
|
|
12051
|
+
}
|
|
12052
|
+
prevCountRef.current = messages.length;
|
|
12053
|
+
}, [messages, open]);
|
|
12054
|
+
const handleOpen = useCallback(() => {
|
|
12055
|
+
setOpen(true);
|
|
12056
|
+
setUnread(0);
|
|
12057
|
+
}, []);
|
|
12058
|
+
const handleClose = useCallback(() => setOpen(false), []);
|
|
12059
|
+
const isLeft = position === "bottom-left";
|
|
12060
|
+
return /* @__PURE__ */ jsxs(
|
|
12061
|
+
"div",
|
|
12062
|
+
{
|
|
12063
|
+
className: cn(
|
|
12064
|
+
"fixed bottom-6 z-[9999]",
|
|
12065
|
+
isLeft ? "left-6" : "right-6",
|
|
12066
|
+
className,
|
|
12067
|
+
classNames?.root
|
|
12068
|
+
),
|
|
12069
|
+
children: [
|
|
12070
|
+
!open && /* @__PURE__ */ jsx(
|
|
12071
|
+
Bubble,
|
|
12072
|
+
{
|
|
12073
|
+
unread,
|
|
12074
|
+
onClick: handleOpen,
|
|
12075
|
+
className: classNames?.bubble
|
|
12076
|
+
}
|
|
12077
|
+
),
|
|
12078
|
+
open && /* @__PURE__ */ jsx(
|
|
12079
|
+
Panel,
|
|
12080
|
+
{
|
|
12081
|
+
businessName,
|
|
12082
|
+
greeting,
|
|
12083
|
+
subtitle,
|
|
12084
|
+
starters,
|
|
12085
|
+
placeholder,
|
|
12086
|
+
messages,
|
|
12087
|
+
isLoading,
|
|
12088
|
+
isSending,
|
|
12089
|
+
error,
|
|
12090
|
+
isActive,
|
|
12091
|
+
isLeft,
|
|
12092
|
+
onClose: handleClose,
|
|
12093
|
+
onSend: send,
|
|
12094
|
+
onStartConversation: startConversation,
|
|
12095
|
+
classNames
|
|
12096
|
+
}
|
|
12097
|
+
)
|
|
12098
|
+
]
|
|
12099
|
+
}
|
|
12100
|
+
);
|
|
12101
|
+
}
|
|
12102
|
+
function Bubble({
|
|
12103
|
+
unread,
|
|
12104
|
+
onClick,
|
|
12105
|
+
className
|
|
12106
|
+
}) {
|
|
12107
|
+
return /* @__PURE__ */ jsxs(
|
|
12108
|
+
"button",
|
|
12109
|
+
{
|
|
12110
|
+
type: "button",
|
|
12111
|
+
onClick,
|
|
12112
|
+
"aria-label": "Open chat",
|
|
12113
|
+
className: cn(
|
|
12114
|
+
"relative flex h-14 w-14 items-center justify-center rounded-full",
|
|
12115
|
+
"bg-foreground text-background shadow-lg",
|
|
12116
|
+
"transition-transform duration-300 ease-out",
|
|
12117
|
+
"hover:scale-[1.08] active:scale-95",
|
|
12118
|
+
className
|
|
12119
|
+
),
|
|
12120
|
+
children: [
|
|
12121
|
+
/* @__PURE__ */ jsx(ChatIcon, { className: "h-6 w-6" }),
|
|
12122
|
+
unread > 0 && /* @__PURE__ */ jsx(
|
|
12123
|
+
"span",
|
|
12124
|
+
{
|
|
12125
|
+
className: cn(
|
|
12126
|
+
"absolute -right-0.5 -top-0.5 flex h-5 w-5 items-center justify-center",
|
|
12127
|
+
"rounded-full bg-red-500 text-[10px] font-bold text-white",
|
|
12128
|
+
"ring-2 ring-background"
|
|
12129
|
+
),
|
|
12130
|
+
children: unread > 9 ? "9+" : unread
|
|
12131
|
+
}
|
|
12132
|
+
)
|
|
12133
|
+
]
|
|
12134
|
+
}
|
|
12135
|
+
);
|
|
12136
|
+
}
|
|
12137
|
+
function Panel({
|
|
12138
|
+
businessName,
|
|
12139
|
+
greeting,
|
|
12140
|
+
subtitle,
|
|
12141
|
+
starters,
|
|
12142
|
+
placeholder,
|
|
12143
|
+
messages,
|
|
12144
|
+
isLoading,
|
|
12145
|
+
isSending,
|
|
12146
|
+
error,
|
|
12147
|
+
isActive,
|
|
12148
|
+
isLeft,
|
|
12149
|
+
onClose,
|
|
12150
|
+
onSend,
|
|
12151
|
+
onStartConversation,
|
|
12152
|
+
classNames
|
|
12153
|
+
}) {
|
|
12154
|
+
return /* @__PURE__ */ jsxs(
|
|
12155
|
+
"div",
|
|
12156
|
+
{
|
|
12157
|
+
className: cn(
|
|
12158
|
+
"flex flex-col overflow-hidden rounded-2xl bg-background shadow-2xl",
|
|
12159
|
+
"w-[400px] max-w-[calc(100vw-3rem)]",
|
|
12160
|
+
"h-[min(600px,calc(100vh-6rem))]",
|
|
12161
|
+
"animate-in fade-in slide-in-from-bottom-4 duration-300",
|
|
12162
|
+
isLeft ? "origin-bottom-left" : "origin-bottom-right",
|
|
12163
|
+
classNames?.panel
|
|
12164
|
+
),
|
|
12165
|
+
children: [
|
|
12166
|
+
/* @__PURE__ */ jsx(
|
|
12167
|
+
Header,
|
|
12168
|
+
{
|
|
12169
|
+
businessName,
|
|
12170
|
+
onClose,
|
|
12171
|
+
className: classNames?.header
|
|
12172
|
+
}
|
|
12173
|
+
),
|
|
12174
|
+
!isActive && !isLoading ? /* @__PURE__ */ jsx(
|
|
12175
|
+
Welcome,
|
|
12176
|
+
{
|
|
12177
|
+
greeting,
|
|
12178
|
+
subtitle,
|
|
12179
|
+
starters,
|
|
12180
|
+
onStarter: onStartConversation,
|
|
12181
|
+
className: classNames?.welcome
|
|
12182
|
+
}
|
|
12183
|
+
) : /* @__PURE__ */ jsx(
|
|
12184
|
+
MessageList,
|
|
12185
|
+
{
|
|
12186
|
+
messages,
|
|
12187
|
+
isLoading,
|
|
12188
|
+
isSending,
|
|
12189
|
+
className: classNames?.messages
|
|
12190
|
+
}
|
|
12191
|
+
),
|
|
12192
|
+
error != null && /* @__PURE__ */ jsx("div", { className: "border-t border-red-200 bg-red-50 px-4 py-2 text-xs text-red-600", children: "Something went wrong. Please try again." }),
|
|
12193
|
+
(isActive || isLoading) && /* @__PURE__ */ jsx(
|
|
12194
|
+
ChatInput,
|
|
12195
|
+
{
|
|
12196
|
+
placeholder,
|
|
12197
|
+
isSending,
|
|
12198
|
+
onSend,
|
|
12199
|
+
className: classNames?.input
|
|
12200
|
+
}
|
|
12201
|
+
),
|
|
12202
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 border-t border-border bg-background px-4 py-1.5 text-center text-[10px] text-muted-foreground", children: [
|
|
12203
|
+
"Powered by",
|
|
12204
|
+
" ",
|
|
12205
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "Cimplify" })
|
|
12206
|
+
] })
|
|
12207
|
+
]
|
|
12208
|
+
}
|
|
12209
|
+
);
|
|
12210
|
+
}
|
|
12211
|
+
function Header({
|
|
12212
|
+
businessName,
|
|
12213
|
+
onClose,
|
|
12214
|
+
className
|
|
12215
|
+
}) {
|
|
12216
|
+
return /* @__PURE__ */ jsxs(
|
|
12217
|
+
"div",
|
|
12218
|
+
{
|
|
12219
|
+
className: cn(
|
|
12220
|
+
"flex flex-shrink-0 items-center gap-3 bg-foreground px-5 py-4 text-background",
|
|
12221
|
+
className
|
|
12222
|
+
),
|
|
12223
|
+
children: [
|
|
12224
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-[10px] bg-white/15", children: /* @__PURE__ */ jsx(ChatIcon, { className: "h-5 w-5" }) }),
|
|
12225
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
12226
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-[15px] font-semibold leading-tight", children: businessName }),
|
|
12227
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs text-white/60", children: [
|
|
12228
|
+
/* @__PURE__ */ jsx("span", { className: "h-[7px] w-[7px] flex-shrink-0 rounded-full bg-emerald-400" }),
|
|
12229
|
+
"Online"
|
|
12230
|
+
] })
|
|
12231
|
+
] }),
|
|
12232
|
+
/* @__PURE__ */ jsx(
|
|
12233
|
+
"button",
|
|
12234
|
+
{
|
|
12235
|
+
type: "button",
|
|
12236
|
+
onClick: onClose,
|
|
12237
|
+
"aria-label": "Close chat",
|
|
12238
|
+
className: cn(
|
|
12239
|
+
"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg",
|
|
12240
|
+
"bg-white/10 text-white/70 transition-colors hover:bg-white/20 hover:text-white"
|
|
12241
|
+
),
|
|
12242
|
+
children: /* @__PURE__ */ jsx(CloseIcon, { className: "h-[18px] w-[18px]" })
|
|
12243
|
+
}
|
|
12244
|
+
)
|
|
12245
|
+
]
|
|
12246
|
+
}
|
|
12247
|
+
);
|
|
12248
|
+
}
|
|
12249
|
+
function Welcome({
|
|
12250
|
+
greeting,
|
|
12251
|
+
subtitle,
|
|
12252
|
+
starters,
|
|
12253
|
+
onStarter,
|
|
12254
|
+
className
|
|
12255
|
+
}) {
|
|
12256
|
+
const defaultStarters = [
|
|
12257
|
+
{ icon: "\u{1F50D}", text: "Help me find a product" },
|
|
12258
|
+
{ icon: "\u{1F6D2}", text: "Check my cart" },
|
|
12259
|
+
{ icon: "\u{1F4E6}", text: "Track my order" }
|
|
12260
|
+
];
|
|
12261
|
+
const items = starters ?? defaultStarters;
|
|
12262
|
+
return /* @__PURE__ */ jsxs(
|
|
12263
|
+
"div",
|
|
12264
|
+
{
|
|
12265
|
+
className: cn(
|
|
12266
|
+
"flex flex-1 flex-col items-center justify-center overflow-y-auto bg-muted/50 px-8 py-10 text-center",
|
|
12267
|
+
className
|
|
12268
|
+
),
|
|
12269
|
+
children: [
|
|
12270
|
+
/* @__PURE__ */ jsx("div", { className: "mb-5 flex h-16 w-16 items-center justify-center rounded-2xl bg-muted", children: /* @__PURE__ */ jsx(ChatIcon, { className: "h-7 w-7 text-muted-foreground" }) }),
|
|
12271
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-2 text-xl font-bold text-foreground", children: greeting }),
|
|
12272
|
+
/* @__PURE__ */ jsx("p", { className: "mb-6 max-w-[280px] text-sm leading-relaxed text-muted-foreground", children: subtitle }),
|
|
12273
|
+
/* @__PURE__ */ jsx("div", { className: "flex w-full max-w-[300px] flex-col gap-2", children: items.map((s) => /* @__PURE__ */ jsxs(
|
|
12274
|
+
"button",
|
|
12275
|
+
{
|
|
12276
|
+
type: "button",
|
|
12277
|
+
onClick: () => onStarter(s.text),
|
|
12278
|
+
className: cn(
|
|
12279
|
+
"flex items-center gap-3 rounded-xl border border-border bg-background px-4 py-3",
|
|
12280
|
+
"text-left text-[13px] font-medium text-foreground",
|
|
12281
|
+
"transition-all hover:-translate-y-px hover:border-foreground hover:shadow-sm"
|
|
12282
|
+
),
|
|
12283
|
+
children: [
|
|
12284
|
+
s.icon && /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-muted text-[15px]", children: s.icon }),
|
|
12285
|
+
/* @__PURE__ */ jsx("span", { children: s.text })
|
|
12286
|
+
]
|
|
12287
|
+
},
|
|
12288
|
+
s.text
|
|
12289
|
+
)) })
|
|
12290
|
+
]
|
|
12291
|
+
}
|
|
12292
|
+
);
|
|
12293
|
+
}
|
|
12294
|
+
function MessageList({
|
|
12295
|
+
messages,
|
|
12296
|
+
isLoading,
|
|
12297
|
+
isSending,
|
|
12298
|
+
className
|
|
12299
|
+
}) {
|
|
12300
|
+
const bottomRef = useRef(null);
|
|
12301
|
+
useEffect(() => {
|
|
12302
|
+
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
12303
|
+
}, [messages.length, isSending]);
|
|
12304
|
+
return /* @__PURE__ */ jsxs(
|
|
12305
|
+
"div",
|
|
12306
|
+
{
|
|
12307
|
+
className: cn(
|
|
12308
|
+
"flex flex-1 flex-col gap-1 overflow-y-auto bg-muted/50 px-5 py-5",
|
|
12309
|
+
className
|
|
12310
|
+
),
|
|
12311
|
+
children: [
|
|
12312
|
+
isLoading && messages.length === 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsx(TypingDots, {}) }),
|
|
12313
|
+
messages.map((msg, i) => {
|
|
12314
|
+
const isCustomer = msg.sender_type === "customer";
|
|
12315
|
+
const prev = messages[i - 1];
|
|
12316
|
+
const sameSenderAsPrev = prev?.sender_type === msg.sender_type;
|
|
12317
|
+
const isOptimistic = msg.id.startsWith("opt_");
|
|
12318
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
12319
|
+
!sameSenderAsPrev && i > 0 && /* @__PURE__ */ jsx("div", { className: "h-3" }),
|
|
12320
|
+
/* @__PURE__ */ jsx(
|
|
12321
|
+
"div",
|
|
12322
|
+
{
|
|
12323
|
+
className: cn(
|
|
12324
|
+
"flex max-w-[85%]",
|
|
12325
|
+
isCustomer ? "ml-auto" : "mr-auto"
|
|
12326
|
+
),
|
|
12327
|
+
children: /* @__PURE__ */ jsxs(
|
|
12328
|
+
"div",
|
|
12329
|
+
{
|
|
12330
|
+
className: cn(
|
|
12331
|
+
"rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed",
|
|
12332
|
+
isCustomer ? "bg-foreground text-background" : "border border-border bg-background text-foreground",
|
|
12333
|
+
isCustomer ? sameSenderAsPrev ? "rounded-tr" : "rounded-br" : sameSenderAsPrev ? "rounded-tl" : "rounded-bl",
|
|
12334
|
+
isOptimistic && "opacity-70"
|
|
12335
|
+
),
|
|
12336
|
+
children: [
|
|
12337
|
+
!isCustomer && !sameSenderAsPrev && /* @__PURE__ */ jsxs("span", { className: "mb-1 inline-flex items-center gap-1 rounded bg-violet-100 px-1.5 py-0.5 text-[10px] font-semibold text-violet-600", children: [
|
|
12338
|
+
/* @__PURE__ */ jsx(SparkleIcon, { className: "h-[11px] w-[11px]" }),
|
|
12339
|
+
"AI"
|
|
12340
|
+
] }),
|
|
12341
|
+
/* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap", children: msg.content })
|
|
12342
|
+
]
|
|
12343
|
+
}
|
|
12344
|
+
)
|
|
12345
|
+
}
|
|
12346
|
+
)
|
|
12347
|
+
] }, msg.id);
|
|
12348
|
+
}),
|
|
12349
|
+
isSending && /* @__PURE__ */ jsx("div", { className: "mr-auto mt-1", children: /* @__PURE__ */ jsx(TypingDots, {}) }),
|
|
12350
|
+
/* @__PURE__ */ jsx("div", { ref: bottomRef })
|
|
12351
|
+
]
|
|
12352
|
+
}
|
|
12353
|
+
);
|
|
12354
|
+
}
|
|
12355
|
+
function ChatInput({
|
|
12356
|
+
placeholder,
|
|
12357
|
+
isSending,
|
|
12358
|
+
onSend,
|
|
12359
|
+
className
|
|
12360
|
+
}) {
|
|
12361
|
+
const [value, setValue] = useState("");
|
|
12362
|
+
const textareaRef = useRef(null);
|
|
12363
|
+
const handleSend = useCallback(() => {
|
|
12364
|
+
const trimmed = value.trim();
|
|
12365
|
+
if (!trimmed || isSending) return;
|
|
12366
|
+
setValue("");
|
|
12367
|
+
if (textareaRef.current) {
|
|
12368
|
+
textareaRef.current.style.height = "auto";
|
|
12369
|
+
}
|
|
12370
|
+
onSend(trimmed);
|
|
12371
|
+
}, [value, isSending, onSend]);
|
|
12372
|
+
const handleKeyDown = useCallback(
|
|
12373
|
+
(e) => {
|
|
12374
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
12375
|
+
e.preventDefault();
|
|
12376
|
+
handleSend();
|
|
12377
|
+
}
|
|
12378
|
+
},
|
|
12379
|
+
[handleSend]
|
|
12380
|
+
);
|
|
12381
|
+
const handleInput = useCallback(() => {
|
|
12382
|
+
const el = textareaRef.current;
|
|
12383
|
+
if (!el) return;
|
|
12384
|
+
el.style.height = "auto";
|
|
12385
|
+
el.style.height = `${Math.min(el.scrollHeight, 100)}px`;
|
|
12386
|
+
}, []);
|
|
12387
|
+
const hasContent = value.trim().length > 0;
|
|
12388
|
+
return /* @__PURE__ */ jsxs(
|
|
12389
|
+
"div",
|
|
12390
|
+
{
|
|
12391
|
+
className: cn(
|
|
12392
|
+
"flex flex-shrink-0 items-end gap-2 border-t border-border bg-background px-4 py-3",
|
|
12393
|
+
className
|
|
12394
|
+
),
|
|
12395
|
+
children: [
|
|
12396
|
+
/* @__PURE__ */ jsx(
|
|
12397
|
+
"div",
|
|
12398
|
+
{
|
|
12399
|
+
className: cn(
|
|
12400
|
+
"flex flex-1 items-end rounded-xl border-[1.5px] border-transparent bg-muted px-1",
|
|
12401
|
+
"transition-colors focus-within:border-foreground focus-within:bg-background"
|
|
12402
|
+
),
|
|
12403
|
+
children: /* @__PURE__ */ jsx(
|
|
12404
|
+
"textarea",
|
|
12405
|
+
{
|
|
12406
|
+
ref: textareaRef,
|
|
12407
|
+
value,
|
|
12408
|
+
onChange: (e) => setValue(e.target.value),
|
|
12409
|
+
onKeyDown: handleKeyDown,
|
|
12410
|
+
onInput: handleInput,
|
|
12411
|
+
placeholder,
|
|
12412
|
+
rows: 1,
|
|
12413
|
+
className: cn(
|
|
12414
|
+
"max-h-[100px] min-h-[20px] flex-1 resize-none bg-transparent px-2.5 py-2",
|
|
12415
|
+
"text-sm text-foreground outline-none placeholder:text-muted-foreground"
|
|
12416
|
+
)
|
|
12417
|
+
}
|
|
12418
|
+
)
|
|
12419
|
+
}
|
|
12420
|
+
),
|
|
12421
|
+
/* @__PURE__ */ jsx(
|
|
12422
|
+
"button",
|
|
12423
|
+
{
|
|
12424
|
+
type: "button",
|
|
12425
|
+
onClick: handleSend,
|
|
12426
|
+
disabled: !hasContent || isSending,
|
|
12427
|
+
"aria-label": "Send message",
|
|
12428
|
+
className: cn(
|
|
12429
|
+
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-[10px]",
|
|
12430
|
+
"transition-all duration-200",
|
|
12431
|
+
hasContent && !isSending ? "bg-foreground text-background hover:scale-105 active:scale-95" : "bg-muted text-muted-foreground"
|
|
12432
|
+
),
|
|
12433
|
+
children: /* @__PURE__ */ jsx(SendIcon, { className: "h-[18px] w-[18px]" })
|
|
12434
|
+
}
|
|
12435
|
+
)
|
|
12436
|
+
]
|
|
12437
|
+
}
|
|
12438
|
+
);
|
|
12439
|
+
}
|
|
12440
|
+
function TypingDots() {
|
|
12441
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 px-4 py-3", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
|
|
12442
|
+
"span",
|
|
12443
|
+
{
|
|
12444
|
+
className: "h-[7px] w-[7px] animate-bounce rounded-full bg-muted-foreground/40",
|
|
12445
|
+
style: { animationDelay: `${i * 160}ms` }
|
|
12446
|
+
},
|
|
12447
|
+
i
|
|
12448
|
+
)) });
|
|
12449
|
+
}
|
|
12450
|
+
function ChatIcon({ className }) {
|
|
12451
|
+
return /* @__PURE__ */ jsx(
|
|
12452
|
+
"svg",
|
|
12453
|
+
{
|
|
12454
|
+
className,
|
|
12455
|
+
viewBox: "0 0 24 24",
|
|
12456
|
+
fill: "none",
|
|
12457
|
+
stroke: "currentColor",
|
|
12458
|
+
strokeWidth: 2,
|
|
12459
|
+
strokeLinecap: "round",
|
|
12460
|
+
strokeLinejoin: "round",
|
|
12461
|
+
children: /* @__PURE__ */ jsx("path", { d: "M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z" })
|
|
12462
|
+
}
|
|
12463
|
+
);
|
|
12464
|
+
}
|
|
12465
|
+
function CloseIcon({ className }) {
|
|
12466
|
+
return /* @__PURE__ */ jsx(
|
|
12467
|
+
"svg",
|
|
12468
|
+
{
|
|
12469
|
+
className,
|
|
12470
|
+
viewBox: "0 0 24 24",
|
|
12471
|
+
fill: "none",
|
|
12472
|
+
stroke: "currentColor",
|
|
12473
|
+
strokeWidth: 2,
|
|
12474
|
+
strokeLinecap: "round",
|
|
12475
|
+
strokeLinejoin: "round",
|
|
12476
|
+
children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
|
|
12477
|
+
}
|
|
12478
|
+
);
|
|
12479
|
+
}
|
|
12480
|
+
function SendIcon({ className }) {
|
|
12481
|
+
return /* @__PURE__ */ jsxs(
|
|
12482
|
+
"svg",
|
|
12483
|
+
{
|
|
12484
|
+
className,
|
|
12485
|
+
viewBox: "0 0 24 24",
|
|
12486
|
+
fill: "none",
|
|
12487
|
+
stroke: "currentColor",
|
|
12488
|
+
strokeWidth: 2,
|
|
12489
|
+
strokeLinecap: "round",
|
|
12490
|
+
strokeLinejoin: "round",
|
|
12491
|
+
children: [
|
|
12492
|
+
/* @__PURE__ */ jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
12493
|
+
/* @__PURE__ */ jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
12494
|
+
]
|
|
12495
|
+
}
|
|
12496
|
+
);
|
|
12497
|
+
}
|
|
12498
|
+
function SparkleIcon({ className }) {
|
|
12499
|
+
return /* @__PURE__ */ jsx(
|
|
12500
|
+
"svg",
|
|
12501
|
+
{
|
|
12502
|
+
className,
|
|
12503
|
+
viewBox: "0 0 24 24",
|
|
12504
|
+
fill: "none",
|
|
12505
|
+
stroke: "currentColor",
|
|
12506
|
+
strokeWidth: 2.5,
|
|
12507
|
+
children: /* @__PURE__ */ jsx("path", { d: "M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83" })
|
|
12508
|
+
}
|
|
12509
|
+
);
|
|
12510
|
+
}
|
|
11841
12511
|
|
|
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 };
|
|
12512
|
+
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, ChatWidget, 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, useChat, 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 };
|