@cimplify/sdk 0.96.0 → 0.98.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/{chunk-RRBY35TJ.mjs → chunk-4G5UWFC3.mjs} +7 -1
- package/dist/{chunk-HKN3YG76.js → chunk-QPRI2NII.js} +7 -0
- package/dist/index.js +22 -25
- package/dist/index.mjs +2 -8
- package/dist/react.d.mts +382 -261
- package/dist/react.d.ts +382 -261
- package/dist/react.js +1016 -218
- package/dist/react.mjs +947 -168
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/registry/chat-widget.json +1 -1
package/dist/react.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkQPRI2NII_js = require('./chunk-QPRI2NII.js');
|
|
5
5
|
var chunkXREIZ56K_js = require('./chunk-XREIZ56K.js');
|
|
6
6
|
var chunkW5PH7SPK_js = require('./chunk-W5PH7SPK.js');
|
|
7
7
|
var chunkVEOAMBEX_js = require('./chunk-VEOAMBEX.js');
|
|
@@ -1298,7 +1298,7 @@ function CimplifyProvider({
|
|
|
1298
1298
|
const apiCredentials = resolvedClient.getCredentialsMode() === "include" ? "use-credentials" : "anonymous";
|
|
1299
1299
|
preconnectOrigin(resolvedClient.getBaseUrl(), apiCredentials);
|
|
1300
1300
|
preconnectOrigin(resolvedClient.getLinkApiUrl(), apiCredentials);
|
|
1301
|
-
preconnectOrigin(
|
|
1301
|
+
preconnectOrigin(chunkQPRI2NII_js.DEFAULT_CDN_BASE_URL);
|
|
1302
1302
|
}
|
|
1303
1303
|
const setCurrentLocation = React14.useCallback(
|
|
1304
1304
|
(location) => {
|
|
@@ -3115,8 +3115,8 @@ function fmtScheduleWindow(start, end) {
|
|
|
3115
3115
|
const startStr = dateFns.format(s, "EEE, MMM d \xB7 h:mm a");
|
|
3116
3116
|
const e = end ? dateFns.parseISO(end) : null;
|
|
3117
3117
|
if (e && dateFns.isValid(e)) {
|
|
3118
|
-
const
|
|
3119
|
-
return `${startStr} \u2013 ${dateFns.format(e,
|
|
3118
|
+
const sameDay2 = s.toDateString() === e.toDateString();
|
|
3119
|
+
return `${startStr} \u2013 ${dateFns.format(e, sameDay2 ? "h:mm a" : "EEE, MMM d \xB7 h:mm a")}`;
|
|
3120
3120
|
}
|
|
3121
3121
|
return startStr;
|
|
3122
3122
|
}
|
|
@@ -5907,6 +5907,33 @@ function useBootstrap(options = {}) {
|
|
|
5907
5907
|
const { data, isLoading, error, refetch } = bootstrapQuery(options);
|
|
5908
5908
|
return { bootstrap: data, isLoading, error, refetch };
|
|
5909
5909
|
}
|
|
5910
|
+
|
|
5911
|
+
// src/react/chat-model.ts
|
|
5912
|
+
var OPTIMISTIC_ID_PREFIX = "opt_";
|
|
5913
|
+
function optimisticId(clientId) {
|
|
5914
|
+
return `${OPTIMISTIC_ID_PREFIX}${clientId}`;
|
|
5915
|
+
}
|
|
5916
|
+
function isOptimistic(message) {
|
|
5917
|
+
return message.id.startsWith(OPTIMISTIC_ID_PREFIX);
|
|
5918
|
+
}
|
|
5919
|
+
function partitionMessages(messages) {
|
|
5920
|
+
const bubbles = [];
|
|
5921
|
+
const reactionsByTarget = /* @__PURE__ */ new Map();
|
|
5922
|
+
for (const message of messages) {
|
|
5923
|
+
if (message.content_type === "reaction") {
|
|
5924
|
+
const targetId = message.reply_to?.id;
|
|
5925
|
+
if (!targetId) continue;
|
|
5926
|
+
const list = reactionsByTarget.get(targetId);
|
|
5927
|
+
if (list) list.push(message);
|
|
5928
|
+
else reactionsByTarget.set(targetId, [message]);
|
|
5929
|
+
continue;
|
|
5930
|
+
}
|
|
5931
|
+
bubbles.push(message);
|
|
5932
|
+
}
|
|
5933
|
+
return { bubbles, reactionsByTarget };
|
|
5934
|
+
}
|
|
5935
|
+
|
|
5936
|
+
// src/react/hooks/use-chat.ts
|
|
5910
5937
|
var POLL_INTERVAL_MS = 3e3;
|
|
5911
5938
|
var POLL_IDLE_INTERVAL_MS = 15e3;
|
|
5912
5939
|
var IDLE_TIMEOUT_MS = 6e4;
|
|
@@ -5921,10 +5948,10 @@ function mergeMessages(prev, incoming) {
|
|
|
5921
5948
|
(a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
5922
5949
|
);
|
|
5923
5950
|
const confirmed = new Set(
|
|
5924
|
-
merged.filter((m) => !m
|
|
5951
|
+
merged.filter((m) => !isOptimistic(m) && m.client_id).map((m) => m.client_id)
|
|
5925
5952
|
);
|
|
5926
5953
|
return merged.filter(
|
|
5927
|
-
(m) => !(m
|
|
5954
|
+
(m) => !(isOptimistic(m) && m.client_id && confirmed.has(m.client_id))
|
|
5928
5955
|
);
|
|
5929
5956
|
}
|
|
5930
5957
|
function useChat(options = {}) {
|
|
@@ -5987,7 +6014,7 @@ function useChat(options = {}) {
|
|
|
5987
6014
|
const lastConfirmedMessage = React14.useCallback(() => {
|
|
5988
6015
|
const list = messagesRef.current;
|
|
5989
6016
|
for (let i = list.length - 1; i >= 0; i--) {
|
|
5990
|
-
if (!list[i]
|
|
6017
|
+
if (!isOptimistic(list[i])) return list[i];
|
|
5991
6018
|
}
|
|
5992
6019
|
return void 0;
|
|
5993
6020
|
}, []);
|
|
@@ -6035,7 +6062,7 @@ function useChat(options = {}) {
|
|
|
6035
6062
|
const snapshotIds = new Set(snapshot.map((m) => m.id));
|
|
6036
6063
|
const tail = snapshot.length > 0 ? new Date(snapshot[snapshot.length - 1].created_at).getTime() : 0;
|
|
6037
6064
|
const extras = prev.filter(
|
|
6038
|
-
(m) => !snapshotIds.has(m.id) && (m
|
|
6065
|
+
(m) => !snapshotIds.has(m.id) && (isOptimistic(m) || new Date(m.created_at).getTime() > tail)
|
|
6039
6066
|
);
|
|
6040
6067
|
return mergeMessages(snapshot, extras);
|
|
6041
6068
|
});
|
|
@@ -6221,9 +6248,9 @@ function useChat(options = {}) {
|
|
|
6221
6248
|
}
|
|
6222
6249
|
const replyTo = opts?.replyTo;
|
|
6223
6250
|
const clientId = chunkVEOAMBEX_js.generateIdempotencyKey();
|
|
6224
|
-
const
|
|
6251
|
+
const localId = optimisticId(clientId);
|
|
6225
6252
|
const optimistic = {
|
|
6226
|
-
id:
|
|
6253
|
+
id: localId,
|
|
6227
6254
|
sender_type: "customer",
|
|
6228
6255
|
content: content.trim(),
|
|
6229
6256
|
content_type: attachments.length > 0 ? "image" : "text",
|
|
@@ -6253,14 +6280,14 @@ function useChat(options = {}) {
|
|
|
6253
6280
|
// The websocket may have already streamed the confirmed message
|
|
6254
6281
|
// in while the POST was in flight; drop the optimistic bubble
|
|
6255
6282
|
// instead of inserting a duplicate.
|
|
6256
|
-
prev.some((m) => m.id === confirmed.id) ? prev.filter((m) => m.id !==
|
|
6283
|
+
prev.some((m) => m.id === confirmed.id) ? prev.filter((m) => m.id !== localId) : prev.map((m) => m.id === localId ? confirmed : m)
|
|
6257
6284
|
)
|
|
6258
6285
|
);
|
|
6259
6286
|
if (aiEnabledRef.current && !humanRequestedRef.current) {
|
|
6260
6287
|
startAwaitingReply();
|
|
6261
6288
|
}
|
|
6262
6289
|
} else {
|
|
6263
|
-
setMessages((prev) => prev.filter((m) => m.id !==
|
|
6290
|
+
setMessages((prev) => prev.filter((m) => m.id !== localId));
|
|
6264
6291
|
setError(result.error);
|
|
6265
6292
|
}
|
|
6266
6293
|
setIsSending(false);
|
|
@@ -6279,7 +6306,7 @@ function useChat(options = {}) {
|
|
|
6279
6306
|
);
|
|
6280
6307
|
const react = React14.useCallback(
|
|
6281
6308
|
async (message, emoji) => {
|
|
6282
|
-
if (!client || message
|
|
6309
|
+
if (!client || isOptimistic(message)) return false;
|
|
6283
6310
|
const result = await client.support.reactToMessage(message.id, emoji);
|
|
6284
6311
|
if (result.ok) appendMessages([result.value]);
|
|
6285
6312
|
return result.ok;
|
|
@@ -6783,7 +6810,7 @@ function VariantSelector({
|
|
|
6783
6810
|
{
|
|
6784
6811
|
"data-cimplify-variant-name": true,
|
|
6785
6812
|
className: cn("flex-1 min-w-0 text-sm", classNames?.name),
|
|
6786
|
-
children:
|
|
6813
|
+
children: chunkQPRI2NII_js.getVariantDisplayName(variant, productName)
|
|
6787
6814
|
}
|
|
6788
6815
|
),
|
|
6789
6816
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-variant-pricing": true, className: cn("text-sm text-muted-foreground", classNames?.pricing), children: [
|
|
@@ -8576,12 +8603,12 @@ function FieldInput({
|
|
|
8576
8603
|
classNames?.input
|
|
8577
8604
|
);
|
|
8578
8605
|
switch (field.field_type) {
|
|
8579
|
-
case
|
|
8580
|
-
case
|
|
8606
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Text:
|
|
8607
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Url:
|
|
8581
8608
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8582
8609
|
"input",
|
|
8583
8610
|
{
|
|
8584
|
-
type: field.field_type ===
|
|
8611
|
+
type: field.field_type === chunkQPRI2NII_js.INPUT_FIELD_TYPE.Url ? "url" : "text",
|
|
8585
8612
|
value: typeof value === "string" ? value : "",
|
|
8586
8613
|
onChange: (e) => onValueChange(e.target.value),
|
|
8587
8614
|
placeholder: field.placeholder,
|
|
@@ -8590,7 +8617,7 @@ function FieldInput({
|
|
|
8590
8617
|
className: inputClass
|
|
8591
8618
|
}
|
|
8592
8619
|
);
|
|
8593
|
-
case
|
|
8620
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Textarea:
|
|
8594
8621
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8595
8622
|
"textarea",
|
|
8596
8623
|
{
|
|
@@ -8603,7 +8630,7 @@ function FieldInput({
|
|
|
8603
8630
|
className: cn(inputClass, "resize-none", classNames?.textarea)
|
|
8604
8631
|
}
|
|
8605
8632
|
);
|
|
8606
|
-
case
|
|
8633
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Number:
|
|
8607
8634
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8608
8635
|
"input",
|
|
8609
8636
|
{
|
|
@@ -8617,7 +8644,7 @@ function FieldInput({
|
|
|
8617
8644
|
className: inputClass
|
|
8618
8645
|
}
|
|
8619
8646
|
);
|
|
8620
|
-
case
|
|
8647
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Select:
|
|
8621
8648
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8622
8649
|
"select",
|
|
8623
8650
|
{
|
|
@@ -8631,7 +8658,7 @@ function FieldInput({
|
|
|
8631
8658
|
]
|
|
8632
8659
|
}
|
|
8633
8660
|
);
|
|
8634
|
-
case
|
|
8661
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Radio:
|
|
8635
8662
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("space-y-2", classNames?.radioGroup), children: (field.options || []).map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8636
8663
|
"label",
|
|
8637
8664
|
{
|
|
@@ -8656,7 +8683,7 @@ function FieldInput({
|
|
|
8656
8683
|
},
|
|
8657
8684
|
opt
|
|
8658
8685
|
)) });
|
|
8659
|
-
case
|
|
8686
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Checkbox:
|
|
8660
8687
|
return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: cn("flex items-center gap-2 text-sm cursor-pointer", classNames?.checkboxLabel), children: [
|
|
8661
8688
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8662
8689
|
"input",
|
|
@@ -8669,7 +8696,7 @@ function FieldInput({
|
|
|
8669
8696
|
),
|
|
8670
8697
|
field.placeholder || field.name
|
|
8671
8698
|
] });
|
|
8672
|
-
case
|
|
8699
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Color:
|
|
8673
8700
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8674
8701
|
"input",
|
|
8675
8702
|
{
|
|
@@ -8679,7 +8706,7 @@ function FieldInput({
|
|
|
8679
8706
|
className: cn("w-12 h-10 rounded-md border border-input cursor-pointer", classNames?.colorInput)
|
|
8680
8707
|
}
|
|
8681
8708
|
);
|
|
8682
|
-
case
|
|
8709
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Date:
|
|
8683
8710
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8684
8711
|
DatePicker,
|
|
8685
8712
|
{
|
|
@@ -8690,8 +8717,8 @@ function FieldInput({
|
|
|
8690
8717
|
"aria-label": field.name
|
|
8691
8718
|
}
|
|
8692
8719
|
);
|
|
8693
|
-
case
|
|
8694
|
-
case
|
|
8720
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.File:
|
|
8721
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Image:
|
|
8695
8722
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8696
8723
|
FileUploadInput,
|
|
8697
8724
|
{
|
|
@@ -8702,7 +8729,7 @@ function FieldInput({
|
|
|
8702
8729
|
classNames
|
|
8703
8730
|
}
|
|
8704
8731
|
);
|
|
8705
|
-
case
|
|
8732
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Email:
|
|
8706
8733
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8707
8734
|
"input",
|
|
8708
8735
|
{
|
|
@@ -8714,7 +8741,7 @@ function FieldInput({
|
|
|
8714
8741
|
className: inputClass
|
|
8715
8742
|
}
|
|
8716
8743
|
);
|
|
8717
|
-
case
|
|
8744
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.DateTime: {
|
|
8718
8745
|
const stringValue = typeof value === "string" ? value : "";
|
|
8719
8746
|
const [datePart, timePartRaw] = stringValue.includes("T") ? stringValue.split("T", 2) : [stringValue, ""];
|
|
8720
8747
|
const timePart = (timePartRaw ?? "").slice(0, 5);
|
|
@@ -8753,7 +8780,7 @@ function FieldInput({
|
|
|
8753
8780
|
)
|
|
8754
8781
|
] });
|
|
8755
8782
|
}
|
|
8756
|
-
case
|
|
8783
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Time:
|
|
8757
8784
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8758
8785
|
TimePicker,
|
|
8759
8786
|
{
|
|
@@ -8764,7 +8791,7 @@ function FieldInput({
|
|
|
8764
8791
|
"aria-label": field.name
|
|
8765
8792
|
}
|
|
8766
8793
|
);
|
|
8767
|
-
case
|
|
8794
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.MultiSelect:
|
|
8768
8795
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8769
8796
|
MultiSelectInput,
|
|
8770
8797
|
{
|
|
@@ -8774,7 +8801,7 @@ function FieldInput({
|
|
|
8774
8801
|
classNames
|
|
8775
8802
|
}
|
|
8776
8803
|
);
|
|
8777
|
-
case
|
|
8804
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.DateRange:
|
|
8778
8805
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8779
8806
|
DateRangeInput,
|
|
8780
8807
|
{
|
|
@@ -8784,7 +8811,7 @@ function FieldInput({
|
|
|
8784
8811
|
classNames
|
|
8785
8812
|
}
|
|
8786
8813
|
);
|
|
8787
|
-
case
|
|
8814
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Address:
|
|
8788
8815
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8789
8816
|
AddressInput,
|
|
8790
8817
|
{
|
|
@@ -8795,7 +8822,7 @@ function FieldInput({
|
|
|
8795
8822
|
inputClass
|
|
8796
8823
|
}
|
|
8797
8824
|
);
|
|
8798
|
-
case
|
|
8825
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Location:
|
|
8799
8826
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8800
8827
|
LocationInput,
|
|
8801
8828
|
{
|
|
@@ -8806,7 +8833,7 @@ function FieldInput({
|
|
|
8806
8833
|
inputClass
|
|
8807
8834
|
}
|
|
8808
8835
|
);
|
|
8809
|
-
case
|
|
8836
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Phone:
|
|
8810
8837
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8811
8838
|
PhoneInput,
|
|
8812
8839
|
{
|
|
@@ -8817,7 +8844,7 @@ function FieldInput({
|
|
|
8817
8844
|
inputClass
|
|
8818
8845
|
}
|
|
8819
8846
|
);
|
|
8820
|
-
case
|
|
8847
|
+
case chunkQPRI2NII_js.INPUT_FIELD_TYPE.Signature:
|
|
8821
8848
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8822
8849
|
SignatureInput,
|
|
8823
8850
|
{
|
|
@@ -8850,7 +8877,7 @@ function FileUploadInput({
|
|
|
8850
8877
|
const [isUploading, setIsUploading] = React14__default.default.useState(false);
|
|
8851
8878
|
const fileUrl = typeof value === "string" ? value : void 0;
|
|
8852
8879
|
const acceptedFormats = field.validation?.accepted_formats;
|
|
8853
|
-
const accept = acceptedFormats ? acceptedFormats.map((f) => `.${f}`).join(",") : field.field_type ===
|
|
8880
|
+
const accept = acceptedFormats ? acceptedFormats.map((f) => `.${f}`).join(",") : field.field_type === chunkQPRI2NII_js.INPUT_FIELD_TYPE.Image ? "image/*" : void 0;
|
|
8854
8881
|
const handleFile = async (file) => {
|
|
8855
8882
|
if (!onFileUpload) return;
|
|
8856
8883
|
if (field.validation?.max_size_mb) {
|
|
@@ -8868,7 +8895,7 @@ function FileUploadInput({
|
|
|
8868
8895
|
}
|
|
8869
8896
|
};
|
|
8870
8897
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("space-y-2", classNames?.fileInput), children: fileUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
8871
|
-
field.field_type ===
|
|
8898
|
+
field.field_type === chunkQPRI2NII_js.INPUT_FIELD_TYPE.Image && /* @__PURE__ */ jsxRuntime.jsx("img", { src: fileUrl, alt: "Uploaded", className: "w-16 h-16 object-cover rounded-md border border-border" }),
|
|
8872
8899
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground truncate", children: fileUrl.split("/").pop() }) }),
|
|
8873
8900
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8874
8901
|
"button",
|
|
@@ -8894,7 +8921,7 @@ function FileUploadInput({
|
|
|
8894
8921
|
}
|
|
8895
8922
|
),
|
|
8896
8923
|
isUploading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Uploading..." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8897
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: field.placeholder || `Upload ${field.field_type ===
|
|
8924
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: field.placeholder || `Upload ${field.field_type === chunkQPRI2NII_js.INPUT_FIELD_TYPE.Image ? "image" : "file"}` }),
|
|
8898
8925
|
acceptedFormats && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground/60 mt-1", children: [
|
|
8899
8926
|
acceptedFormats.map((f) => f.toUpperCase()).join(", "),
|
|
8900
8927
|
field.validation?.max_size_mb && ` \xB7 Max ${field.validation.max_size_mb}MB`
|
|
@@ -9628,7 +9655,7 @@ function ProductCustomizer({
|
|
|
9628
9655
|
const isBundle = productType === "bundle";
|
|
9629
9656
|
const isDigital = productType === "digital";
|
|
9630
9657
|
const isService = productType === "service";
|
|
9631
|
-
const offersUnits = isService &&
|
|
9658
|
+
const offersUnits = isService && chunkQPRI2NII_js.isMultiDayService(product);
|
|
9632
9659
|
const isStandard = !isComposite && !isBundle;
|
|
9633
9660
|
const hasVariants = isStandard && product.variants && product.variants.length > 0;
|
|
9634
9661
|
const hasAddOns = isStandard && product.add_ons && product.add_ons.length > 0;
|
|
@@ -9742,7 +9769,7 @@ function ProductCustomizer({
|
|
|
9742
9769
|
}, [quote, quantity]);
|
|
9743
9770
|
const displayTotalPrice = React14.useMemo(() => {
|
|
9744
9771
|
const total = quotedTotalPrice ?? localTotalPrice;
|
|
9745
|
-
const multiplier =
|
|
9772
|
+
const multiplier = chunkQPRI2NII_js.serviceBillingMultiplier(product, {
|
|
9746
9773
|
quantity,
|
|
9747
9774
|
units: unitsCount,
|
|
9748
9775
|
scheduledStart: selectedSlot?.start_time,
|
|
@@ -10453,18 +10480,18 @@ function CartLineItemRow({
|
|
|
10453
10480
|
});
|
|
10454
10481
|
const hasComposite = item.compositeSelections && item.compositeSelections.length > 0;
|
|
10455
10482
|
const hasBundle = item.bundleSelections && item.bundleSelections.length > 0;
|
|
10456
|
-
const
|
|
10483
|
+
const isOptimistic2 = item.isOptimistic === true;
|
|
10457
10484
|
const lineTotal = chunkPTPOQVXS_js.parsePrice(unitPrice) * item.quantity;
|
|
10458
10485
|
const imageUrl = item.product.image_url;
|
|
10459
|
-
const variantLabel2 = item.variant ?
|
|
10486
|
+
const variantLabel2 = item.variant ? chunkQPRI2NII_js.getVariantDisplayName(item.variant, item.product.name) : null;
|
|
10460
10487
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10461
10488
|
"div",
|
|
10462
10489
|
{
|
|
10463
10490
|
"data-cimplify-cart-item": true,
|
|
10464
|
-
"data-optimistic":
|
|
10491
|
+
"data-optimistic": isOptimistic2 ? "true" : void 0,
|
|
10465
10492
|
className: cn(
|
|
10466
10493
|
"group relative flex gap-3 py-4 border-b border-border last:border-b-0 transition-opacity",
|
|
10467
|
-
|
|
10494
|
+
isOptimistic2 && "opacity-60",
|
|
10468
10495
|
classNames?.item
|
|
10469
10496
|
),
|
|
10470
10497
|
children: [
|
|
@@ -10556,7 +10583,7 @@ function CartLineItemRow({
|
|
|
10556
10583
|
input.field_name,
|
|
10557
10584
|
":"
|
|
10558
10585
|
] }),
|
|
10559
|
-
/* @__PURE__ */ jsxRuntime.jsx("dd", { "data-cimplify-cart-input-value": true, className: "text-foreground m-0 truncate", children: input.field_type ===
|
|
10586
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { "data-cimplify-cart-input-value": true, className: "text-foreground m-0 truncate", children: input.field_type === chunkQPRI2NII_js.INPUT_FIELD_TYPE.File || input.field_type === chunkQPRI2NII_js.INPUT_FIELD_TYPE.Image ? String(input.value).split("/").pop() || "Uploaded file" : String(input.value) })
|
|
10560
10587
|
] }, input.field_id)) }),
|
|
10561
10588
|
(item.lineType === "service" || item.product.type === "service") && item.scheduledStart && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-service-info": true, className: cn("mt-1.5 flex items-center gap-1.5 text-xs text-muted-foreground", classNames?.serviceInfo), children: [
|
|
10562
10589
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3.5 h-3.5 shrink-0", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
|
|
@@ -10631,7 +10658,7 @@ function CartSummary({
|
|
|
10631
10658
|
tax,
|
|
10632
10659
|
total,
|
|
10633
10660
|
isEmpty,
|
|
10634
|
-
isOptimistic,
|
|
10661
|
+
isOptimistic: isOptimistic2,
|
|
10635
10662
|
pendingOpCount,
|
|
10636
10663
|
removeItem,
|
|
10637
10664
|
updateQuantity
|
|
@@ -10657,7 +10684,7 @@ function CartSummary({
|
|
|
10657
10684
|
"div",
|
|
10658
10685
|
{
|
|
10659
10686
|
"data-cimplify-cart-summary": true,
|
|
10660
|
-
"data-optimistic":
|
|
10687
|
+
"data-optimistic": isOptimistic2 ? "true" : void 0,
|
|
10661
10688
|
"data-pending-ops": pendingOpCount > 0 ? pendingOpCount : void 0,
|
|
10662
10689
|
className: cn(className, classNames?.root),
|
|
10663
10690
|
children: isEmpty ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-empty": true, className: classNames?.empty, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: emptyMessage }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -11441,7 +11468,7 @@ function FoodProductCard({
|
|
|
11441
11468
|
const tags = product.tags || [];
|
|
11442
11469
|
const isSignature = product.metadata?.is_signature === true;
|
|
11443
11470
|
const isNew = product.metadata?.is_new === true;
|
|
11444
|
-
const isComposite = product.type ===
|
|
11471
|
+
const isComposite = product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Composite;
|
|
11445
11472
|
return /* @__PURE__ */ jsxRuntime.jsxs(CardShell, { product, renderLink, className, children: [
|
|
11446
11473
|
/* @__PURE__ */ jsxRuntime.jsxs(CardImage, { src: image, alt: product.name, aspectRatio: "square", renderImage, children: [
|
|
11447
11474
|
isSignature && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "absolute top-3 left-3 inline-flex items-center gap-1 text-[11px] font-semibold tracking-wide bg-amber-50 text-amber-700 border border-amber-200/60 px-2 py-0.5 rounded-md", children: [
|
|
@@ -12208,36 +12235,36 @@ var BUILT_IN_CARDS = {
|
|
|
12208
12235
|
["composite" /* Composite */]: CompositeProductCard,
|
|
12209
12236
|
["subscription" /* Subscription */]: SubscriptionCard
|
|
12210
12237
|
};
|
|
12211
|
-
var RENTAL_UNITS = /* @__PURE__ */ new Set([
|
|
12212
|
-
var LEASE_UNITS = /* @__PURE__ */ new Set([
|
|
12238
|
+
var RENTAL_UNITS = /* @__PURE__ */ new Set([chunkQPRI2NII_js.DURATION_UNIT.Days, chunkQPRI2NII_js.DURATION_UNIT.Hours]);
|
|
12239
|
+
var LEASE_UNITS = /* @__PURE__ */ new Set([chunkQPRI2NII_js.DURATION_UNIT.Weeks, chunkQPRI2NII_js.DURATION_UNIT.Months, chunkQPRI2NII_js.DURATION_UNIT.Years]);
|
|
12213
12240
|
function resolveCardVariant(product) {
|
|
12214
|
-
if (product.type ===
|
|
12241
|
+
if (product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Bundle) {
|
|
12215
12242
|
return "bundle" /* Bundle */;
|
|
12216
12243
|
}
|
|
12217
|
-
if (product.type ===
|
|
12244
|
+
if (product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Composite) {
|
|
12218
12245
|
return "composite" /* Composite */;
|
|
12219
12246
|
}
|
|
12220
12247
|
if (product.quantity_pricing && product.quantity_pricing.length > 1) {
|
|
12221
12248
|
return "wholesale" /* Wholesale */;
|
|
12222
12249
|
}
|
|
12223
|
-
if (product.type ===
|
|
12250
|
+
if (product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Digital) {
|
|
12224
12251
|
return "digital" /* Digital */;
|
|
12225
12252
|
}
|
|
12226
|
-
if (product.type ===
|
|
12253
|
+
if (product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Service) {
|
|
12227
12254
|
switch (product.boundary_kind) {
|
|
12228
|
-
case
|
|
12255
|
+
case chunkQPRI2NII_js.BOUNDARY_KIND.CheckInOut:
|
|
12229
12256
|
return "accommodation" /* Accommodation */;
|
|
12230
|
-
case
|
|
12257
|
+
case chunkQPRI2NII_js.BOUNDARY_KIND.MoveInOut:
|
|
12231
12258
|
return "lease" /* Lease */;
|
|
12232
|
-
case
|
|
12233
|
-
case
|
|
12234
|
-
case
|
|
12259
|
+
case chunkQPRI2NII_js.BOUNDARY_KIND.PickupReturn:
|
|
12260
|
+
case chunkQPRI2NII_js.BOUNDARY_KIND.DeliveryCollection:
|
|
12261
|
+
case chunkQPRI2NII_js.BOUNDARY_KIND.AccessVacate:
|
|
12235
12262
|
return "rental" /* Rental */;
|
|
12236
12263
|
}
|
|
12237
12264
|
if (product.duration_unit && RENTAL_UNITS.has(product.duration_unit)) {
|
|
12238
12265
|
return "rental" /* Rental */;
|
|
12239
12266
|
}
|
|
12240
|
-
if (product.duration_unit ===
|
|
12267
|
+
if (product.duration_unit === chunkQPRI2NII_js.DURATION_UNIT.Nights) {
|
|
12241
12268
|
return "accommodation" /* Accommodation */;
|
|
12242
12269
|
}
|
|
12243
12270
|
if (product.duration_unit && LEASE_UNITS.has(product.duration_unit)) {
|
|
@@ -12248,10 +12275,10 @@ function resolveCardVariant(product) {
|
|
|
12248
12275
|
}
|
|
12249
12276
|
return "standard" /* Standard */;
|
|
12250
12277
|
}
|
|
12251
|
-
if (product.render_hint ===
|
|
12278
|
+
if (product.render_hint === chunkQPRI2NII_js.RENDER_HINT.Food) {
|
|
12252
12279
|
return "food" /* Food */;
|
|
12253
12280
|
}
|
|
12254
|
-
if (product.render_hint ===
|
|
12281
|
+
if (product.render_hint === chunkQPRI2NII_js.RENDER_HINT.Physical) {
|
|
12255
12282
|
return "retail" /* Retail */;
|
|
12256
12283
|
}
|
|
12257
12284
|
return "retail" /* Retail */;
|
|
@@ -12531,14 +12558,14 @@ var PRESET_LABELS = {
|
|
|
12531
12558
|
move_in_out: { start: "Move-in", end: "Move-out" }
|
|
12532
12559
|
};
|
|
12533
12560
|
function defaultBoundaryKind(unit) {
|
|
12534
|
-
return unit ===
|
|
12561
|
+
return unit === chunkQPRI2NII_js.DURATION_UNIT.Nights ? chunkQPRI2NII_js.BOUNDARY_KIND.CheckInOut : chunkQPRI2NII_js.BOUNDARY_KIND.PickupReturn;
|
|
12535
12562
|
}
|
|
12536
12563
|
function resolveBoundaryKind(product) {
|
|
12537
12564
|
return product.boundary_kind ?? defaultBoundaryKind(product.duration_unit);
|
|
12538
12565
|
}
|
|
12539
12566
|
function getBoundaryLabels(product) {
|
|
12540
12567
|
const kind = resolveBoundaryKind(product);
|
|
12541
|
-
if (kind ===
|
|
12568
|
+
if (kind === chunkQPRI2NII_js.BOUNDARY_KIND.Custom) {
|
|
12542
12569
|
return {
|
|
12543
12570
|
start: product.boundary_start_label?.trim() || "Start",
|
|
12544
12571
|
end: product.boundary_end_label?.trim() || "End"
|
|
@@ -14626,7 +14653,7 @@ function DefaultProductLayout({
|
|
|
14626
14653
|
className
|
|
14627
14654
|
}) {
|
|
14628
14655
|
const [selectedVariantId, setSelectedVariantId] = React14__default.default.useState();
|
|
14629
|
-
const images =
|
|
14656
|
+
const images = chunkQPRI2NII_js.resolveGallery(product, selectedVariantId);
|
|
14630
14657
|
const currency = chunkPTPOQVXS_js.getProductCurrency(product);
|
|
14631
14658
|
const hasRange = product.quantity_pricing && product.quantity_pricing.length > 1 || product.variants && product.variants.length > 1;
|
|
14632
14659
|
const onSale = chunkPTPOQVXS_js.isOnSale(product);
|
|
@@ -15273,25 +15300,25 @@ function resolveTemplateKey(product) {
|
|
|
15273
15300
|
if (typeof metaTemplate === "string" && metaTemplate.trim()) {
|
|
15274
15301
|
return metaTemplate.trim();
|
|
15275
15302
|
}
|
|
15276
|
-
if (product.type ===
|
|
15303
|
+
if (product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Bundle) {
|
|
15277
15304
|
return "bundle" /* Bundle */;
|
|
15278
15305
|
}
|
|
15279
|
-
if (product.type ===
|
|
15306
|
+
if (product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Composite) {
|
|
15280
15307
|
return "composite" /* Composite */;
|
|
15281
15308
|
}
|
|
15282
15309
|
if (product.quantity_pricing && product.quantity_pricing.length > 1) {
|
|
15283
15310
|
return "wholesale" /* Wholesale */;
|
|
15284
15311
|
}
|
|
15285
|
-
if (product.type ===
|
|
15312
|
+
if (product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Service) {
|
|
15286
15313
|
return "service" /* Service */;
|
|
15287
15314
|
}
|
|
15288
|
-
if (product.type ===
|
|
15315
|
+
if (product.type === chunkQPRI2NII_js.PRODUCT_TYPE.Digital) {
|
|
15289
15316
|
return "digital" /* Digital */;
|
|
15290
15317
|
}
|
|
15291
|
-
if (product.render_hint ===
|
|
15318
|
+
if (product.render_hint === chunkQPRI2NII_js.RENDER_HINT.Food) {
|
|
15292
15319
|
return "food" /* Food */;
|
|
15293
15320
|
}
|
|
15294
|
-
if (product.render_hint ===
|
|
15321
|
+
if (product.render_hint === chunkQPRI2NII_js.RENDER_HINT.Physical) {
|
|
15295
15322
|
return "physical" /* Physical */;
|
|
15296
15323
|
}
|
|
15297
15324
|
return "default" /* Default */;
|
|
@@ -17144,24 +17171,581 @@ var ChatMarkdown = React14.memo(function ChatMarkdown2({
|
|
|
17144
17171
|
return /* @__PURE__ */ jsxRuntime.jsx(SettledMarkdown, { text, className });
|
|
17145
17172
|
});
|
|
17146
17173
|
|
|
17147
|
-
// src/react/chat-
|
|
17148
|
-
function
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
|
|
17152
|
-
|
|
17153
|
-
|
|
17154
|
-
|
|
17155
|
-
|
|
17156
|
-
|
|
17157
|
-
|
|
17158
|
-
|
|
17174
|
+
// src/react/chat-kit/motion.ts
|
|
17175
|
+
function prefersReducedMotion() {
|
|
17176
|
+
return typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
17177
|
+
}
|
|
17178
|
+
function scrollBehavior() {
|
|
17179
|
+
return prefersReducedMotion() ? "auto" : "smooth";
|
|
17180
|
+
}
|
|
17181
|
+
function QuoteBlock({
|
|
17182
|
+
quote,
|
|
17183
|
+
inCustomerBubble,
|
|
17184
|
+
businessName,
|
|
17185
|
+
onMissing
|
|
17186
|
+
}) {
|
|
17187
|
+
const quotedIsCustomer = quote.sender_type === "customer";
|
|
17188
|
+
const jumpToOriginal = async () => {
|
|
17189
|
+
let original = document.getElementById(`chat-msg-${quote.id}`);
|
|
17190
|
+
if (!original && onMissing && await onMissing()) {
|
|
17191
|
+
original = document.getElementById(`chat-msg-${quote.id}`);
|
|
17192
|
+
}
|
|
17193
|
+
if (!original) return;
|
|
17194
|
+
original.scrollIntoView({ behavior: scrollBehavior(), block: "center" });
|
|
17195
|
+
original.classList.remove("animate-quote-flash");
|
|
17196
|
+
void original.offsetWidth;
|
|
17197
|
+
original.classList.add("animate-quote-flash");
|
|
17198
|
+
};
|
|
17199
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17200
|
+
"button",
|
|
17201
|
+
{
|
|
17202
|
+
type: "button",
|
|
17203
|
+
onClick: () => void jumpToOriginal(),
|
|
17204
|
+
className: cn(
|
|
17205
|
+
"flex w-full gap-2 rounded-[10px] px-2.5 py-1.5 text-left",
|
|
17206
|
+
inCustomerBubble ? "bg-primary-foreground/15" : "bg-background/70"
|
|
17207
|
+
),
|
|
17208
|
+
children: [
|
|
17209
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17210
|
+
"span",
|
|
17211
|
+
{
|
|
17212
|
+
className: cn(
|
|
17213
|
+
"w-[3px] shrink-0 self-stretch rounded-full",
|
|
17214
|
+
inCustomerBubble ? "bg-primary-foreground/50" : quotedIsCustomer ? "bg-primary" : "bg-muted-foreground/50"
|
|
17215
|
+
)
|
|
17216
|
+
}
|
|
17217
|
+
),
|
|
17218
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
17219
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17220
|
+
"span",
|
|
17221
|
+
{
|
|
17222
|
+
className: cn(
|
|
17223
|
+
"text-[11px] leading-4 font-semibold",
|
|
17224
|
+
inCustomerBubble ? "text-primary-foreground" : "text-foreground"
|
|
17225
|
+
),
|
|
17226
|
+
children: quotedIsCustomer ? "You" : businessName
|
|
17227
|
+
}
|
|
17228
|
+
),
|
|
17229
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17230
|
+
"span",
|
|
17231
|
+
{
|
|
17232
|
+
className: cn(
|
|
17233
|
+
"truncate text-xs leading-4",
|
|
17234
|
+
inCustomerBubble ? "text-primary-foreground/75" : "text-muted-foreground"
|
|
17235
|
+
),
|
|
17236
|
+
children: quote.preview
|
|
17237
|
+
}
|
|
17238
|
+
)
|
|
17239
|
+
] })
|
|
17240
|
+
]
|
|
17159
17241
|
}
|
|
17160
|
-
|
|
17242
|
+
);
|
|
17243
|
+
}
|
|
17244
|
+
var SWIPE_COMMIT_PX = 48;
|
|
17245
|
+
var SWIPE_ARM_PX = 10;
|
|
17246
|
+
var OVERDRAG_RATE = 0.25;
|
|
17247
|
+
var LONG_PRESS_MS = 450;
|
|
17248
|
+
var RETURN_TRANSITION = "transform 0.25s cubic-bezier(0.2, 0, 0, 1)";
|
|
17249
|
+
function swipeTravel(distance) {
|
|
17250
|
+
if (distance <= 0) return 0;
|
|
17251
|
+
if (distance <= SWIPE_COMMIT_PX) return distance;
|
|
17252
|
+
return SWIPE_COMMIT_PX + (distance - SWIPE_COMMIT_PX) * OVERDRAG_RATE;
|
|
17253
|
+
}
|
|
17254
|
+
function swipeCommitted(distance) {
|
|
17255
|
+
return distance >= SWIPE_COMMIT_PX;
|
|
17256
|
+
}
|
|
17257
|
+
function swipeProgress(distance) {
|
|
17258
|
+
return Math.min(Math.max(distance / SWIPE_COMMIT_PX, 0), 1);
|
|
17259
|
+
}
|
|
17260
|
+
function useSwipeReply({ onReply, onLongPress }) {
|
|
17261
|
+
const rowRef = React14.useRef(null);
|
|
17262
|
+
const glyphRef = React14.useRef(null);
|
|
17263
|
+
const gestureRef = React14.useRef(null);
|
|
17264
|
+
const suppressClickRef = React14.useRef(false);
|
|
17265
|
+
const optionsRef = React14.useRef({ onReply, onLongPress });
|
|
17266
|
+
optionsRef.current = { onReply, onLongPress };
|
|
17267
|
+
const settle = React14.useCallback((glyphVisible) => {
|
|
17268
|
+
const row = rowRef.current;
|
|
17269
|
+
const glyph = glyphRef.current;
|
|
17270
|
+
if (row) {
|
|
17271
|
+
row.style.transition = RETURN_TRANSITION;
|
|
17272
|
+
row.style.transform = "translateX(0px)";
|
|
17273
|
+
}
|
|
17274
|
+
if (glyph && !glyphVisible) {
|
|
17275
|
+
glyph.style.transition = "opacity 0.2s ease-out";
|
|
17276
|
+
glyph.style.opacity = "0";
|
|
17277
|
+
}
|
|
17278
|
+
}, []);
|
|
17279
|
+
const clearGesture = React14.useCallback(() => {
|
|
17280
|
+
const gesture = gestureRef.current;
|
|
17281
|
+
if (gesture?.longPressTimer) clearTimeout(gesture.longPressTimer);
|
|
17282
|
+
gestureRef.current = null;
|
|
17283
|
+
}, []);
|
|
17284
|
+
const onPointerDown = React14.useCallback((event) => {
|
|
17285
|
+
if (!event.isPrimary) return;
|
|
17286
|
+
suppressClickRef.current = false;
|
|
17287
|
+
gestureRef.current = {
|
|
17288
|
+
pointerId: event.pointerId,
|
|
17289
|
+
startX: event.clientX,
|
|
17290
|
+
startY: event.clientY,
|
|
17291
|
+
armed: false,
|
|
17292
|
+
distance: 0,
|
|
17293
|
+
longPressTimer: setTimeout(() => {
|
|
17294
|
+
gestureRef.current = null;
|
|
17295
|
+
suppressClickRef.current = true;
|
|
17296
|
+
optionsRef.current.onLongPress();
|
|
17297
|
+
}, LONG_PRESS_MS)
|
|
17298
|
+
};
|
|
17299
|
+
}, []);
|
|
17300
|
+
const onPointerMove = React14.useCallback((event) => {
|
|
17301
|
+
const gesture = gestureRef.current;
|
|
17302
|
+
if (!gesture || gesture.pointerId !== event.pointerId) return;
|
|
17303
|
+
const leftward = gesture.startX - event.clientX;
|
|
17304
|
+
const vertical = Math.abs(event.clientY - gesture.startY);
|
|
17305
|
+
if (!gesture.armed) {
|
|
17306
|
+
const scrolling = vertical > SWIPE_ARM_PX && vertical >= leftward;
|
|
17307
|
+
const rightward = leftward < -SWIPE_ARM_PX;
|
|
17308
|
+
if (scrolling || rightward) {
|
|
17309
|
+
clearGesture();
|
|
17310
|
+
return;
|
|
17311
|
+
}
|
|
17312
|
+
if (leftward <= SWIPE_ARM_PX || leftward <= vertical) return;
|
|
17313
|
+
if (prefersReducedMotion()) {
|
|
17314
|
+
clearGesture();
|
|
17315
|
+
return;
|
|
17316
|
+
}
|
|
17317
|
+
gesture.armed = true;
|
|
17318
|
+
if (gesture.longPressTimer) clearTimeout(gesture.longPressTimer);
|
|
17319
|
+
gesture.longPressTimer = null;
|
|
17320
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
17321
|
+
if (rowRef.current) rowRef.current.style.transition = "none";
|
|
17322
|
+
if (glyphRef.current) glyphRef.current.style.transition = "none";
|
|
17323
|
+
}
|
|
17324
|
+
gesture.distance = leftward;
|
|
17325
|
+
if (rowRef.current) {
|
|
17326
|
+
rowRef.current.style.transform = `translateX(-${swipeTravel(leftward)}px)`;
|
|
17327
|
+
}
|
|
17328
|
+
if (glyphRef.current) {
|
|
17329
|
+
glyphRef.current.style.opacity = String(swipeProgress(leftward));
|
|
17330
|
+
}
|
|
17331
|
+
}, [clearGesture]);
|
|
17332
|
+
const onPointerUp = React14.useCallback(
|
|
17333
|
+
(event) => {
|
|
17334
|
+
const gesture = gestureRef.current;
|
|
17335
|
+
if (!gesture || gesture.pointerId !== event.pointerId) return;
|
|
17336
|
+
const commit = gesture.armed && swipeCommitted(gesture.distance);
|
|
17337
|
+
const wasArmed = gesture.armed;
|
|
17338
|
+
clearGesture();
|
|
17339
|
+
if (wasArmed) {
|
|
17340
|
+
suppressClickRef.current = true;
|
|
17341
|
+
settle(false);
|
|
17342
|
+
}
|
|
17343
|
+
if (commit) optionsRef.current.onReply();
|
|
17344
|
+
},
|
|
17345
|
+
[clearGesture, settle]
|
|
17346
|
+
);
|
|
17347
|
+
const onPointerCancel = React14.useCallback(
|
|
17348
|
+
(event) => {
|
|
17349
|
+
const gesture = gestureRef.current;
|
|
17350
|
+
if (!gesture || gesture.pointerId !== event.pointerId) return;
|
|
17351
|
+
const wasArmed = gesture.armed;
|
|
17352
|
+
clearGesture();
|
|
17353
|
+
if (wasArmed) settle(false);
|
|
17354
|
+
},
|
|
17355
|
+
[clearGesture, settle]
|
|
17356
|
+
);
|
|
17357
|
+
const onClickCapture = React14.useCallback((event) => {
|
|
17358
|
+
if (!suppressClickRef.current) return;
|
|
17359
|
+
suppressClickRef.current = false;
|
|
17360
|
+
event.preventDefault();
|
|
17361
|
+
event.stopPropagation();
|
|
17362
|
+
}, []);
|
|
17363
|
+
return {
|
|
17364
|
+
rowRef,
|
|
17365
|
+
glyphRef,
|
|
17366
|
+
handlers: { onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onClickCapture }
|
|
17367
|
+
};
|
|
17368
|
+
}
|
|
17369
|
+
var PROSE_CLASS = "[&_p]:my-0 [&_p+p]:mt-1.5 [&_ul]:my-1 [&_ul]:list-disc [&_ul]:pl-4 [&_ol]:my-1 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:my-0.5 [&_h1]:text-[15px] [&_h1]:font-bold [&_h2]:text-[15px] [&_h2]:font-bold [&_h3]:text-sm [&_h3]:font-semibold [&_hr]:my-2 [&_hr]:border-border [&_table]:my-1 [&_table]:w-full [&_th]:pb-1 [&_th]:text-left [&_th]:text-[11px] [&_th]:font-semibold [&_th]:uppercase [&_th]:text-muted-foreground [&_td]:border-b [&_td]:border-border/50 [&_td]:py-1 [&_td:last-child]:text-right [&_td:last-child]:font-semibold [&_td:last-child]:tabular-nums [&_tr:last-child_td]:border-b-0 [&_a]:underline [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:text-[13px]";
|
|
17370
|
+
function bubbleShape(isCustomer, group) {
|
|
17371
|
+
if (!hasTail(group)) return "rounded-[18px]";
|
|
17372
|
+
return isCustomer ? "rounded-[18px] rounded-br-none" : "rounded-[18px] rounded-bl-none";
|
|
17373
|
+
}
|
|
17374
|
+
function hasTail(group) {
|
|
17375
|
+
return group === "single" || group === "last";
|
|
17376
|
+
}
|
|
17377
|
+
var TAIL_SWEEP = "M21 0 L21 5 C21 15 25 16 25 16 C20.93 16.43 16.84 14.94 13.96 11.96 C9 16 5 16 0 16";
|
|
17378
|
+
var TAIL_FILL = `${TAIL_SWEEP} Z`;
|
|
17379
|
+
var TAIL_NOTCH = "M25 16 C20.93 16.43 16.84 14.94 13.96 11.96 C9 16 5 16 0 16 Z";
|
|
17380
|
+
function BubbleTail({ isCustomer }) {
|
|
17381
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17382
|
+
"svg",
|
|
17383
|
+
{
|
|
17384
|
+
width: "25",
|
|
17385
|
+
height: "16",
|
|
17386
|
+
viewBox: "0 0 25 16",
|
|
17387
|
+
"aria-hidden": "true",
|
|
17388
|
+
className: cn(
|
|
17389
|
+
"absolute bottom-0",
|
|
17390
|
+
isCustomer ? "-right-[4px] fill-primary" : "-left-[4px] -scale-x-100 fill-background"
|
|
17391
|
+
),
|
|
17392
|
+
children: [
|
|
17393
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: TAIL_FILL }),
|
|
17394
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: TAIL_NOTCH, style: { fill: "var(--color-chat-canvas, var(--color-muted, #f3f5f3))" } }),
|
|
17395
|
+
!isCustomer && /* @__PURE__ */ jsxRuntime.jsx("path", { d: TAIL_SWEEP, fill: "none", strokeWidth: "1", className: "stroke-foreground/[0.07]" })
|
|
17396
|
+
]
|
|
17397
|
+
}
|
|
17398
|
+
);
|
|
17399
|
+
}
|
|
17400
|
+
function clockLabel(at) {
|
|
17401
|
+
const date = new Date(at);
|
|
17402
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
17403
|
+
const hour = date.getHours() % 12 || 12;
|
|
17404
|
+
return `${hour}:${String(date.getMinutes()).padStart(2, "0")}`;
|
|
17405
|
+
}
|
|
17406
|
+
function DoubleTick() {
|
|
17407
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "15", height: "9", viewBox: "0 0 15 9", fill: "none", "aria-hidden": "true", children: [
|
|
17408
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 4.5L4 7.5L9.5 1.5", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
17409
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6.5 4.5L9.5 7.5L14 2.5", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
17410
|
+
] });
|
|
17411
|
+
}
|
|
17412
|
+
function SendingClock() {
|
|
17413
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "11", height: "11", viewBox: "0 0 11 11", fill: "none", "aria-hidden": "true", children: [
|
|
17414
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "5.5", cy: "5.5", r: "4.5", stroke: "currentColor", strokeWidth: "1.2" }),
|
|
17415
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5.5 3v2.7l1.8 1", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
|
|
17416
|
+
] });
|
|
17417
|
+
}
|
|
17418
|
+
function PaperclipIcon() {
|
|
17419
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17420
|
+
"svg",
|
|
17421
|
+
{
|
|
17422
|
+
width: "14",
|
|
17423
|
+
height: "14",
|
|
17424
|
+
viewBox: "0 0 24 24",
|
|
17425
|
+
fill: "none",
|
|
17426
|
+
stroke: "currentColor",
|
|
17427
|
+
strokeWidth: "2",
|
|
17428
|
+
strokeLinecap: "round",
|
|
17429
|
+
strokeLinejoin: "round",
|
|
17430
|
+
"aria-hidden": "true",
|
|
17431
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" })
|
|
17432
|
+
}
|
|
17433
|
+
);
|
|
17434
|
+
}
|
|
17435
|
+
function ReplyGlyph() {
|
|
17436
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17437
|
+
"svg",
|
|
17438
|
+
{
|
|
17439
|
+
width: "18",
|
|
17440
|
+
height: "18",
|
|
17441
|
+
viewBox: "0 0 24 24",
|
|
17442
|
+
fill: "none",
|
|
17443
|
+
stroke: "currentColor",
|
|
17444
|
+
strokeWidth: "2.2",
|
|
17445
|
+
strokeLinecap: "round",
|
|
17446
|
+
strokeLinejoin: "round",
|
|
17447
|
+
"aria-hidden": "true",
|
|
17448
|
+
children: [
|
|
17449
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 17 4 12 9 7" }),
|
|
17450
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 18v-2a4 4 0 0 0-4-4H4" })
|
|
17451
|
+
]
|
|
17452
|
+
}
|
|
17453
|
+
);
|
|
17454
|
+
}
|
|
17455
|
+
var DELIVERY_LABELS = {
|
|
17456
|
+
sending: "Sending",
|
|
17457
|
+
delivered: "Delivered",
|
|
17458
|
+
seen: "Seen"
|
|
17459
|
+
};
|
|
17460
|
+
function BubbleMeta({
|
|
17461
|
+
at,
|
|
17462
|
+
isCustomer,
|
|
17463
|
+
delivery
|
|
17464
|
+
}) {
|
|
17465
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17466
|
+
"span",
|
|
17467
|
+
{
|
|
17468
|
+
className: cn(
|
|
17469
|
+
"ml-auto flex shrink-0 items-center gap-[3px] self-end pb-px whitespace-nowrap",
|
|
17470
|
+
isCustomer ? "text-primary-foreground/70" : "text-muted-foreground"
|
|
17471
|
+
),
|
|
17472
|
+
children: [
|
|
17473
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10.5px] leading-[13px] font-medium", children: clockLabel(at) }),
|
|
17474
|
+
isCustomer && delivery && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17475
|
+
"span",
|
|
17476
|
+
{
|
|
17477
|
+
role: "img",
|
|
17478
|
+
"aria-label": DELIVERY_LABELS[delivery],
|
|
17479
|
+
className: cn(
|
|
17480
|
+
"flex items-center text-primary-foreground",
|
|
17481
|
+
delivery !== "seen" && "opacity-55"
|
|
17482
|
+
),
|
|
17483
|
+
children: delivery === "sending" ? /* @__PURE__ */ jsxRuntime.jsx(SendingClock, {}) : /* @__PURE__ */ jsxRuntime.jsx(DoubleTick, {})
|
|
17484
|
+
}
|
|
17485
|
+
)
|
|
17486
|
+
]
|
|
17487
|
+
}
|
|
17488
|
+
);
|
|
17489
|
+
}
|
|
17490
|
+
function reactionPills(reactions) {
|
|
17491
|
+
const counts = /* @__PURE__ */ new Map();
|
|
17492
|
+
for (const reaction of reactions) {
|
|
17493
|
+
const emoji = reaction.content.trim();
|
|
17494
|
+
if (emoji) counts.set(emoji, (counts.get(emoji) ?? 0) + 1);
|
|
17161
17495
|
}
|
|
17162
|
-
return {
|
|
17496
|
+
return [...counts.entries()].map(([emoji, count]) => ({ emoji, count }));
|
|
17497
|
+
}
|
|
17498
|
+
var MessageBubble = React14.memo(function MessageBubble2({
|
|
17499
|
+
message,
|
|
17500
|
+
reactions,
|
|
17501
|
+
businessName,
|
|
17502
|
+
group = "single",
|
|
17503
|
+
delivery,
|
|
17504
|
+
onReply,
|
|
17505
|
+
onLongPress,
|
|
17506
|
+
avatar,
|
|
17507
|
+
overlay,
|
|
17508
|
+
renderCards,
|
|
17509
|
+
renderProgram,
|
|
17510
|
+
onQuoteMiss
|
|
17511
|
+
}) {
|
|
17512
|
+
const showAvatar = group === "single" || group === "last";
|
|
17513
|
+
const isCustomer = message.sender_type === "customer";
|
|
17514
|
+
const isBusiness = !isCustomer;
|
|
17515
|
+
const segments = React14.useMemo(
|
|
17516
|
+
() => isCustomer ? [{ kind: "prose", text: message.content }] : chunkXREIZ56K_js.splitGenUIContent(message.content),
|
|
17517
|
+
[isCustomer, message.content]
|
|
17518
|
+
);
|
|
17519
|
+
const drawable = React14.useMemo(
|
|
17520
|
+
() => segments.filter(
|
|
17521
|
+
(segment) => segment.kind === "prose" && segment.text.trim() !== "" || segment.kind === "program" && renderProgram != null
|
|
17522
|
+
),
|
|
17523
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17524
|
+
[segments, renderProgram != null]
|
|
17525
|
+
);
|
|
17526
|
+
const swipe = useSwipeReply({
|
|
17527
|
+
onReply: () => onReply(message),
|
|
17528
|
+
onLongPress: () => onLongPress?.(message)
|
|
17529
|
+
});
|
|
17530
|
+
const quote = message.reply_to ?? null;
|
|
17531
|
+
const pills = reactions ? reactionPills(reactions) : [];
|
|
17532
|
+
const cards = renderCards?.(message);
|
|
17533
|
+
const proseSegments = drawable.filter((segment) => segment.kind === "prose");
|
|
17534
|
+
const lastProseIndex = drawable.lastIndexOf(proseSegments[proseSegments.length - 1]);
|
|
17535
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: `chat-msg-${message.id}`, className: "relative rounded-xl", children: [
|
|
17536
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17537
|
+
"span",
|
|
17538
|
+
{
|
|
17539
|
+
ref: swipe.glyphRef,
|
|
17540
|
+
"aria-hidden": "true",
|
|
17541
|
+
className: "absolute top-1/2 right-1 -translate-y-1/2 text-muted-foreground opacity-0",
|
|
17542
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ReplyGlyph, {})
|
|
17543
|
+
}
|
|
17544
|
+
),
|
|
17545
|
+
overlay,
|
|
17546
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
17547
|
+
"div",
|
|
17548
|
+
{
|
|
17549
|
+
ref: swipe.rowRef,
|
|
17550
|
+
...swipe.handlers,
|
|
17551
|
+
onContextMenu: onLongPress ? (event) => {
|
|
17552
|
+
event.preventDefault();
|
|
17553
|
+
onLongPress(message);
|
|
17554
|
+
} : void 0,
|
|
17555
|
+
className: cn(
|
|
17556
|
+
"flex touch-pan-y flex-col gap-[3px] select-none [-webkit-touch-callout:none]",
|
|
17557
|
+
isCustomer ? "items-end" : "items-start"
|
|
17558
|
+
),
|
|
17559
|
+
children: [
|
|
17560
|
+
quote && drawable[0]?.kind !== "prose" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[280px] rounded-[14px] border border-foreground/[0.07] bg-background p-1.5 shadow-[0_1px_1px_rgba(15,23,42,0.03)]", children: /* @__PURE__ */ jsxRuntime.jsx(QuoteBlock, { quote, inCustomerBubble: false, businessName, onMissing: onQuoteMiss }) }),
|
|
17561
|
+
message.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-w-[280px] flex-wrap gap-1.5", children: message.attachments.map((attachment, index) => {
|
|
17562
|
+
const url = safeAttachmentUrl(attachment.url);
|
|
17563
|
+
if (!url) return null;
|
|
17564
|
+
return isImageAttachment(attachment) ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: url, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
17565
|
+
"img",
|
|
17566
|
+
{
|
|
17567
|
+
src: url,
|
|
17568
|
+
alt: attachment.filename ?? "Photo",
|
|
17569
|
+
loading: "lazy",
|
|
17570
|
+
className: "max-h-[240px] max-w-[240px] rounded-[16px] object-cover"
|
|
17571
|
+
}
|
|
17572
|
+
) }, index) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17573
|
+
"a",
|
|
17574
|
+
{
|
|
17575
|
+
href: url,
|
|
17576
|
+
target: "_blank",
|
|
17577
|
+
rel: "noreferrer",
|
|
17578
|
+
className: "flex items-center gap-2 rounded-[14px] border border-foreground/[0.07] bg-background px-3 py-2 text-[13px] font-medium text-foreground shadow-[0_1px_1px_rgba(15,23,42,0.03)]",
|
|
17579
|
+
children: [
|
|
17580
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(PaperclipIcon, {}) }),
|
|
17581
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-[200px] truncate", children: attachment.filename ?? "Attachment" })
|
|
17582
|
+
]
|
|
17583
|
+
},
|
|
17584
|
+
index
|
|
17585
|
+
);
|
|
17586
|
+
}) }),
|
|
17587
|
+
drawable.map(
|
|
17588
|
+
(segment, index) => segment.kind === "program" ? /* @__PURE__ */ jsxRuntime.jsx(React14__default.default.Fragment, { children: renderProgram?.(segment.source) }, index) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-w-full items-end gap-1.5", children: [
|
|
17589
|
+
isBusiness && avatar && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17590
|
+
"span",
|
|
17591
|
+
{
|
|
17592
|
+
"aria-label": businessName,
|
|
17593
|
+
className: cn(
|
|
17594
|
+
"shrink-0",
|
|
17595
|
+
// One avatar per run, anchored to its last bubble.
|
|
17596
|
+
showAvatar && index === lastProseIndex ? "visible" : "invisible"
|
|
17597
|
+
),
|
|
17598
|
+
children: avatar
|
|
17599
|
+
}
|
|
17600
|
+
),
|
|
17601
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
17602
|
+
"div",
|
|
17603
|
+
{
|
|
17604
|
+
className: cn(
|
|
17605
|
+
"relative flex max-w-[280px] min-w-0 flex-col gap-1.5 py-2 pr-[11px] pl-3.5 text-[15px] leading-[21px] font-[450] break-words",
|
|
17606
|
+
bubbleShape(isCustomer, index === lastProseIndex ? group : "middle"),
|
|
17607
|
+
isCustomer ? "bg-primary text-primary-foreground" : "border border-foreground/[0.07] bg-background text-foreground shadow-[0_1px_1px_rgba(15,23,42,0.03)]"
|
|
17608
|
+
),
|
|
17609
|
+
children: [
|
|
17610
|
+
index === 0 && quote && /* @__PURE__ */ jsxRuntime.jsx(QuoteBlock, { quote, inCustomerBubble: isCustomer, businessName, onMissing: onQuoteMiss }),
|
|
17611
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-wrap items-end gap-x-2 gap-y-0.5", children: [
|
|
17612
|
+
isCustomer ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-pre-wrap", children: segment.text }) : /* @__PURE__ */ jsxRuntime.jsx(ChatMarkdown, { text: segment.text, className: cn("min-w-0", PROSE_CLASS) }),
|
|
17613
|
+
index === lastProseIndex && /* @__PURE__ */ jsxRuntime.jsx(BubbleMeta, { at: message.created_at, isCustomer, delivery })
|
|
17614
|
+
] }),
|
|
17615
|
+
index === lastProseIndex && hasTail(group) && /* @__PURE__ */ jsxRuntime.jsx(BubbleTail, { isCustomer })
|
|
17616
|
+
]
|
|
17617
|
+
}
|
|
17618
|
+
)
|
|
17619
|
+
] }, index)
|
|
17620
|
+
),
|
|
17621
|
+
cards,
|
|
17622
|
+
pills.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17623
|
+
"div",
|
|
17624
|
+
{
|
|
17625
|
+
className: cn(
|
|
17626
|
+
"z-[1] -mt-3 flex gap-1",
|
|
17627
|
+
// Overlap the bubble corner by ~9px, tucked inside the tail side.
|
|
17628
|
+
isCustomer ? "mr-2.5" : "ml-10"
|
|
17629
|
+
),
|
|
17630
|
+
children: pills.map((pill) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17631
|
+
"span",
|
|
17632
|
+
{
|
|
17633
|
+
className: "flex items-center gap-[3px] rounded-full border border-foreground/[0.08] bg-background px-[7px] py-[2px] shadow-[0_1px_3px_rgba(15,23,42,0.08)]",
|
|
17634
|
+
children: [
|
|
17635
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs leading-4", children: pill.emoji }),
|
|
17636
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] leading-[13px] font-semibold text-muted-foreground", children: pill.count })
|
|
17637
|
+
]
|
|
17638
|
+
},
|
|
17639
|
+
pill.emoji
|
|
17640
|
+
))
|
|
17641
|
+
}
|
|
17642
|
+
)
|
|
17643
|
+
]
|
|
17644
|
+
}
|
|
17645
|
+
)
|
|
17646
|
+
] });
|
|
17647
|
+
});
|
|
17648
|
+
function Seam({
|
|
17649
|
+
label,
|
|
17650
|
+
variant = "line"
|
|
17651
|
+
}) {
|
|
17652
|
+
if (variant === "chip") {
|
|
17653
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full border border-foreground/[0.06] bg-background px-3 py-1 text-[11px] leading-[14px] font-semibold tracking-[0.04em] text-muted-foreground uppercase shadow-[0_1px_2px_rgba(15,23,42,0.04)]", children: label }) });
|
|
17654
|
+
}
|
|
17655
|
+
const unread = variant === "unread";
|
|
17656
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 py-1.5", children: [
|
|
17657
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17658
|
+
"span",
|
|
17659
|
+
{
|
|
17660
|
+
className: cn("h-px flex-1", unread ? "bg-primary/35" : "bg-foreground/[0.08]"),
|
|
17661
|
+
"aria-hidden": "true"
|
|
17662
|
+
}
|
|
17663
|
+
),
|
|
17664
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17665
|
+
"span",
|
|
17666
|
+
{
|
|
17667
|
+
className: cn(
|
|
17668
|
+
"whitespace-nowrap",
|
|
17669
|
+
unread ? "text-[11px] leading-[14px] font-semibold tracking-[0.04em] text-primary uppercase" : "text-[11.5px] leading-[15px] font-medium text-muted-foreground"
|
|
17670
|
+
),
|
|
17671
|
+
children: label
|
|
17672
|
+
}
|
|
17673
|
+
),
|
|
17674
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17675
|
+
"span",
|
|
17676
|
+
{
|
|
17677
|
+
className: cn("h-px flex-1", unread ? "bg-primary/35" : "bg-foreground/[0.08]"),
|
|
17678
|
+
"aria-hidden": "true"
|
|
17679
|
+
}
|
|
17680
|
+
)
|
|
17681
|
+
] });
|
|
17682
|
+
}
|
|
17683
|
+
|
|
17684
|
+
// src/react/chat-kit/timeline.ts
|
|
17685
|
+
function sameDay(a, b) {
|
|
17686
|
+
return new Date(a).toDateString() === new Date(b).toDateString();
|
|
17687
|
+
}
|
|
17688
|
+
function dayLabel(at) {
|
|
17689
|
+
const date = new Date(at);
|
|
17690
|
+
const today = /* @__PURE__ */ new Date();
|
|
17691
|
+
if (date.toDateString() === today.toDateString()) return "Today";
|
|
17692
|
+
const yesterday = new Date(today);
|
|
17693
|
+
yesterday.setDate(today.getDate() - 1);
|
|
17694
|
+
if (date.toDateString() === yesterday.toDateString()) return "Yesterday";
|
|
17695
|
+
return date.toLocaleDateString([], { weekday: "short", day: "numeric", month: "short" });
|
|
17696
|
+
}
|
|
17697
|
+
function proseOf(content) {
|
|
17698
|
+
return chunkXREIZ56K_js.splitGenUIContent(content).filter((segment) => segment.kind === "prose").map((segment) => segment.text).join("\n\n").trim();
|
|
17699
|
+
}
|
|
17700
|
+
function hasProgram(content) {
|
|
17701
|
+
return chunkXREIZ56K_js.splitGenUIContent(content).some((segment) => segment.kind === "program");
|
|
17702
|
+
}
|
|
17703
|
+
function chatTimeline(messages, options = {}) {
|
|
17704
|
+
const { readAt = null, rendersPrograms = false } = options;
|
|
17705
|
+
const partitioned = partitionMessages(messages);
|
|
17706
|
+
const bubbles = partitioned.bubbles.filter(
|
|
17707
|
+
(message) => message.sender_type === "system" || message.attachments.length > 0 || chunkQPRI2NII_js.chatMessageCards(message).length > 0 || rendersPrograms && hasProgram(message.content) || (message.sender_type === "customer" ? message.content.trim() !== "" : proseOf(message.content) !== "")
|
|
17708
|
+
);
|
|
17709
|
+
let firstUnreadId;
|
|
17710
|
+
let unreadOnOpen = 0;
|
|
17711
|
+
if (readAt) {
|
|
17712
|
+
const readAtMs = new Date(readAt).getTime();
|
|
17713
|
+
for (const message of bubbles) {
|
|
17714
|
+
if (message.sender_type === "customer" || new Date(message.created_at).getTime() <= readAtMs)
|
|
17715
|
+
continue;
|
|
17716
|
+
firstUnreadId ?? (firstUnreadId = message.id);
|
|
17717
|
+
unreadOnOpen += 1;
|
|
17718
|
+
}
|
|
17719
|
+
}
|
|
17720
|
+
return {
|
|
17721
|
+
bubbles,
|
|
17722
|
+
reactionsByTarget: partitioned.reactionsByTarget,
|
|
17723
|
+
firstUnreadId,
|
|
17724
|
+
unreadOnOpen,
|
|
17725
|
+
firstAgentMessageId: bubbles.find((m) => m.sender_type === "agent")?.id
|
|
17726
|
+
};
|
|
17727
|
+
}
|
|
17728
|
+
function groupPosition(timeline, index) {
|
|
17729
|
+
const { bubbles, firstAgentMessageId, firstUnreadId } = timeline;
|
|
17730
|
+
const message = bubbles[index];
|
|
17731
|
+
const previous = bubbles[index - 1];
|
|
17732
|
+
const next = bubbles[index + 1];
|
|
17733
|
+
const startsRun = !previous || !sameDay(previous.created_at, message.created_at) || previous.sender_type !== message.sender_type || message.id === firstAgentMessageId || message.id === firstUnreadId || previous.sender_type === "system";
|
|
17734
|
+
const endsRun = !next || next.sender_type !== message.sender_type || next.sender_type === "system" || !sameDay(message.created_at, next.created_at);
|
|
17735
|
+
if (startsRun && endsRun) return "single";
|
|
17736
|
+
if (startsRun) return "first";
|
|
17737
|
+
if (endsRun) return "last";
|
|
17738
|
+
return "middle";
|
|
17739
|
+
}
|
|
17740
|
+
function deliveryState(message, timeline, seenAt, isOptimistic2) {
|
|
17741
|
+
if (message.sender_type !== "customer") return void 0;
|
|
17742
|
+
if (isOptimistic2(message)) return "sending";
|
|
17743
|
+
const seenCutoff = timeline.firstAgentMessageId ? seenAt : null;
|
|
17744
|
+
return seenCutoff && message.created_at <= seenCutoff ? "seen" : "delivered";
|
|
17163
17745
|
}
|
|
17164
17746
|
var MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;
|
|
17747
|
+
var KEEP_DISMISSED_KEY = "cimplify_keep_chat_dismissed";
|
|
17748
|
+
var AT_BOTTOM_SLACK_PX = 48;
|
|
17165
17749
|
function ChatWidget({
|
|
17166
17750
|
client: clientProp,
|
|
17167
17751
|
businessName = "Support",
|
|
@@ -17180,6 +17764,7 @@ function ChatWidget({
|
|
|
17180
17764
|
const [open, setOpen] = React14.useState(defaultOpen);
|
|
17181
17765
|
const [readAt, setReadAt] = React14.useState(null);
|
|
17182
17766
|
const [attachError, setAttachError] = React14.useState(null);
|
|
17767
|
+
const [replyTo, setReplyTo] = React14.useState(null);
|
|
17183
17768
|
const {
|
|
17184
17769
|
messages,
|
|
17185
17770
|
isLoading,
|
|
@@ -17188,11 +17773,15 @@ function ChatWidget({
|
|
|
17188
17773
|
seenAt,
|
|
17189
17774
|
error,
|
|
17190
17775
|
isActive,
|
|
17776
|
+
humanRequested,
|
|
17191
17777
|
claimedAs,
|
|
17192
17778
|
signOut,
|
|
17193
17779
|
send,
|
|
17194
17780
|
react,
|
|
17781
|
+
requestHuman,
|
|
17195
17782
|
startConversation,
|
|
17783
|
+
loadOlder,
|
|
17784
|
+
mayHaveOlder,
|
|
17196
17785
|
openIfExisting
|
|
17197
17786
|
} = useChat({ client, pollInterval });
|
|
17198
17787
|
const showTyping = isSending || awaitingReply;
|
|
@@ -17227,9 +17816,11 @@ function ChatWidget({
|
|
|
17227
17816
|
const handleSend = React14.useCallback(
|
|
17228
17817
|
(content) => {
|
|
17229
17818
|
setAttachError(null);
|
|
17230
|
-
|
|
17819
|
+
const target = replyTo;
|
|
17820
|
+
setReplyTo(null);
|
|
17821
|
+
return send(content, target ? { replyTo: target } : void 0);
|
|
17231
17822
|
},
|
|
17232
|
-
[send]
|
|
17823
|
+
[send, replyTo]
|
|
17233
17824
|
);
|
|
17234
17825
|
const unread = open ? 0 : messages.filter(
|
|
17235
17826
|
(m) => m.sender_type !== "customer" && (!readAt || m.created_at > readAt)
|
|
@@ -17268,6 +17859,7 @@ function ChatWidget({
|
|
|
17268
17859
|
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17269
17860
|
Panel,
|
|
17270
17861
|
{
|
|
17862
|
+
client,
|
|
17271
17863
|
businessName,
|
|
17272
17864
|
greeting,
|
|
17273
17865
|
subtitle,
|
|
@@ -17278,14 +17870,22 @@ function ChatWidget({
|
|
|
17278
17870
|
isSending,
|
|
17279
17871
|
isTyping: showTyping,
|
|
17280
17872
|
seenAt,
|
|
17873
|
+
readAt,
|
|
17281
17874
|
error: error ?? attachError,
|
|
17282
17875
|
isActive,
|
|
17283
17876
|
isLeft,
|
|
17877
|
+
humanRequested,
|
|
17878
|
+
mayHaveOlder,
|
|
17879
|
+
replyTo,
|
|
17284
17880
|
claimedAs,
|
|
17285
17881
|
onSignOut: () => void signOut(),
|
|
17286
17882
|
onClose: handleClose,
|
|
17287
17883
|
onSend: handleSend,
|
|
17288
17884
|
onReact: react,
|
|
17885
|
+
onReply: setReplyTo,
|
|
17886
|
+
onCancelReply: () => setReplyTo(null),
|
|
17887
|
+
onRequestHuman: () => void requestHuman(),
|
|
17888
|
+
onLoadOlder: () => void loadOlder(),
|
|
17289
17889
|
onAttach: attachPhoto,
|
|
17290
17890
|
onStartConversation: startConversation,
|
|
17291
17891
|
classNames
|
|
@@ -17320,7 +17920,7 @@ function Bubble({
|
|
|
17320
17920
|
{
|
|
17321
17921
|
className: cn(
|
|
17322
17922
|
"absolute -right-0.5 -top-0.5 flex h-5 w-5 items-center justify-center",
|
|
17323
|
-
"rounded-full bg-
|
|
17923
|
+
"rounded-full bg-destructive text-[10px] font-bold text-white",
|
|
17324
17924
|
"ring-2 ring-background"
|
|
17325
17925
|
),
|
|
17326
17926
|
children: unread > 9 ? "9+" : unread
|
|
@@ -17331,6 +17931,7 @@ function Bubble({
|
|
|
17331
17931
|
);
|
|
17332
17932
|
}
|
|
17333
17933
|
function Panel({
|
|
17934
|
+
client,
|
|
17334
17935
|
businessName,
|
|
17335
17936
|
greeting,
|
|
17336
17937
|
subtitle,
|
|
@@ -17341,14 +17942,22 @@ function Panel({
|
|
|
17341
17942
|
isSending,
|
|
17342
17943
|
isTyping,
|
|
17343
17944
|
seenAt,
|
|
17945
|
+
readAt,
|
|
17344
17946
|
error,
|
|
17345
17947
|
isActive,
|
|
17346
17948
|
isLeft,
|
|
17949
|
+
humanRequested,
|
|
17950
|
+
mayHaveOlder,
|
|
17951
|
+
replyTo,
|
|
17347
17952
|
claimedAs,
|
|
17348
17953
|
onSignOut,
|
|
17349
17954
|
onClose,
|
|
17350
17955
|
onSend,
|
|
17351
17956
|
onReact,
|
|
17957
|
+
onReply,
|
|
17958
|
+
onCancelReply,
|
|
17959
|
+
onRequestHuman,
|
|
17960
|
+
onLoadOlder,
|
|
17352
17961
|
onAttach,
|
|
17353
17962
|
onStartConversation,
|
|
17354
17963
|
classNames
|
|
@@ -17388,20 +17997,57 @@ function Panel({
|
|
|
17388
17997
|
MessageList,
|
|
17389
17998
|
{
|
|
17390
17999
|
messages,
|
|
18000
|
+
businessName,
|
|
17391
18001
|
isLoading,
|
|
17392
18002
|
isSending: isTyping,
|
|
17393
18003
|
seenAt,
|
|
18004
|
+
readAt,
|
|
18005
|
+
humanRequested,
|
|
18006
|
+
mayHaveOlder,
|
|
17394
18007
|
onReact,
|
|
18008
|
+
onReply,
|
|
18009
|
+
onRequestHuman,
|
|
18010
|
+
onLoadOlder,
|
|
17395
18011
|
className: classNames?.messages
|
|
17396
18012
|
}
|
|
17397
18013
|
),
|
|
17398
|
-
|
|
18014
|
+
isActive && !claimedAs && client && /* @__PURE__ */ jsxRuntime.jsx(KeepConversation, { client }),
|
|
18015
|
+
humanRequested && isActive && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-t border-border bg-muted/50 px-4 py-2 text-[11px] text-muted-foreground", children: [
|
|
18016
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 flex-shrink-0 animate-pulse rounded-full bg-amber-500" }),
|
|
18017
|
+
"Waiting for ",
|
|
18018
|
+
businessName,
|
|
18019
|
+
" \u2014 usually replies in minutes"
|
|
18020
|
+
] }),
|
|
18021
|
+
error != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-destructive/20 bg-destructive/10 px-4 py-2 text-xs text-destructive", children: error.userMessage || "Something went wrong. Please try again." }),
|
|
18022
|
+
replyTo && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 border-t border-border bg-muted/50 px-4 py-2", children: [
|
|
18023
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[3px] shrink-0 self-stretch rounded-full bg-foreground/40" }),
|
|
18024
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
18025
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[11px] font-semibold text-foreground", children: [
|
|
18026
|
+
"Replying to ",
|
|
18027
|
+
replyTo.sender_type === "customer" ? "yourself" : businessName
|
|
18028
|
+
] }),
|
|
18029
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-[11px] text-muted-foreground", children: proseOf(replyTo.content) || "Photo" })
|
|
18030
|
+
] }),
|
|
18031
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18032
|
+
"button",
|
|
18033
|
+
{
|
|
18034
|
+
type: "button",
|
|
18035
|
+
"aria-label": "Cancel reply",
|
|
18036
|
+
onClick: onCancelReply,
|
|
18037
|
+
className: "flex-shrink-0 p-0.5 text-muted-foreground hover:text-foreground",
|
|
18038
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "h-3.5 w-3.5" })
|
|
18039
|
+
}
|
|
18040
|
+
)
|
|
18041
|
+
] }),
|
|
17399
18042
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17400
18043
|
ChatInput,
|
|
17401
18044
|
{
|
|
17402
18045
|
placeholder,
|
|
17403
18046
|
isSending,
|
|
17404
|
-
onSend: isActive ? onSend :
|
|
18047
|
+
onSend: isActive ? onSend : async (text) => {
|
|
18048
|
+
await onStartConversation(text);
|
|
18049
|
+
return true;
|
|
18050
|
+
},
|
|
17405
18051
|
onAttach,
|
|
17406
18052
|
className: classNames?.input
|
|
17407
18053
|
}
|
|
@@ -17430,10 +18076,10 @@ function Header({
|
|
|
17430
18076
|
className
|
|
17431
18077
|
),
|
|
17432
18078
|
children: [
|
|
17433
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-[10px] bg-
|
|
18079
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-[10px] bg-background/15", children: /* @__PURE__ */ jsxRuntime.jsx(ChatIcon, { className: "h-5 w-5" }) }),
|
|
17434
18080
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
17435
18081
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-[15px] font-semibold leading-tight", children: businessName }),
|
|
17436
|
-
claimedAs ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 truncate text-xs text-
|
|
18082
|
+
claimedAs ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 truncate text-xs text-background/60", children: [
|
|
17437
18083
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "truncate", children: [
|
|
17438
18084
|
"Chatting as ",
|
|
17439
18085
|
claimedAs
|
|
@@ -17444,11 +18090,11 @@ function Header({
|
|
|
17444
18090
|
{
|
|
17445
18091
|
type: "button",
|
|
17446
18092
|
onClick: onSignOut,
|
|
17447
|
-
className: "flex-shrink-0 underline underline-offset-2 hover:text-
|
|
18093
|
+
className: "flex-shrink-0 underline underline-offset-2 hover:text-background",
|
|
17448
18094
|
children: "Not you?"
|
|
17449
18095
|
}
|
|
17450
18096
|
)
|
|
17451
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs text-
|
|
18097
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs text-background/60", children: [
|
|
17452
18098
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-[7px] w-[7px] flex-shrink-0 rounded-full bg-emerald-400" }),
|
|
17453
18099
|
"Online"
|
|
17454
18100
|
] })
|
|
@@ -17461,7 +18107,7 @@ function Header({
|
|
|
17461
18107
|
"aria-label": "Close chat",
|
|
17462
18108
|
className: cn(
|
|
17463
18109
|
"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg",
|
|
17464
|
-
"bg-
|
|
18110
|
+
"bg-background/10 text-background/70 transition-colors hover:bg-background/20 hover:text-background"
|
|
17465
18111
|
),
|
|
17466
18112
|
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "h-[18px] w-[18px]" })
|
|
17467
18113
|
}
|
|
@@ -17516,148 +18162,109 @@ function Welcome({
|
|
|
17516
18162
|
);
|
|
17517
18163
|
}
|
|
17518
18164
|
var QUICK_REACTIONS = ["\u{1F44D}", "\u2764\uFE0F"];
|
|
17519
|
-
function
|
|
17520
|
-
|
|
17521
|
-
for (let i = bubbles.length - 1; i >= 0; i--) {
|
|
17522
|
-
if (bubbles[i].sender_type !== "customer") continue;
|
|
17523
|
-
return bubbles[i].created_at <= seenAt ? bubbles[i].id : null;
|
|
17524
|
-
}
|
|
17525
|
-
return null;
|
|
18165
|
+
function LetterAvatar({ name }) {
|
|
18166
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-6 items-center justify-center rounded-full bg-foreground text-[10px] font-bold text-background", children: name.charAt(0).toUpperCase() });
|
|
17526
18167
|
}
|
|
17527
18168
|
function MessageList({
|
|
17528
18169
|
messages,
|
|
18170
|
+
businessName,
|
|
17529
18171
|
isLoading,
|
|
17530
18172
|
isSending,
|
|
17531
18173
|
seenAt,
|
|
18174
|
+
readAt,
|
|
18175
|
+
humanRequested,
|
|
18176
|
+
mayHaveOlder,
|
|
17532
18177
|
onReact,
|
|
18178
|
+
onReply,
|
|
18179
|
+
onRequestHuman,
|
|
18180
|
+
onLoadOlder,
|
|
17533
18181
|
className
|
|
17534
18182
|
}) {
|
|
17535
|
-
const
|
|
17536
|
-
const
|
|
18183
|
+
const scrolledUpRef = React14.useRef(false);
|
|
18184
|
+
const timeline = chatTimeline(messages, { readAt });
|
|
18185
|
+
const { bubbles, reactionsByTarget, firstUnreadId, unreadOnOpen, firstAgentMessageId } = timeline;
|
|
18186
|
+
const lastBubble = bubbles[bubbles.length - 1];
|
|
18187
|
+
const offerHuman = !humanRequested && lastBubble?.sender_type === "bot" && !isSending;
|
|
18188
|
+
const handleScroll = (event) => {
|
|
18189
|
+
const node = event.currentTarget;
|
|
18190
|
+
scrolledUpRef.current = node.scrollHeight - node.scrollTop - node.clientHeight >= AT_BOTTOM_SLACK_PX;
|
|
18191
|
+
};
|
|
17537
18192
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17538
18193
|
"div",
|
|
17539
18194
|
{
|
|
17540
|
-
|
|
17541
|
-
|
|
17542
|
-
|
|
17543
|
-
),
|
|
18195
|
+
onScroll: handleScroll,
|
|
18196
|
+
style: { background: "var(--color-chat-canvas, var(--color-muted, #f3f5f3))" },
|
|
18197
|
+
className: cn("flex flex-1 flex-col gap-0.5 overflow-y-auto px-3.5 py-3.5", className),
|
|
17544
18198
|
children: [
|
|
17545
18199
|
isLoading && messages.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {}) }),
|
|
18200
|
+
mayHaveOlder && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center pb-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18201
|
+
"button",
|
|
18202
|
+
{
|
|
18203
|
+
type: "button",
|
|
18204
|
+
onClick: onLoadOlder,
|
|
18205
|
+
className: "rounded-full border border-foreground/[0.06] bg-background px-3.5 py-[7px] text-xs font-semibold text-muted-foreground shadow-[0_1px_2px_rgba(15,23,42,0.04)]",
|
|
18206
|
+
children: "Show earlier messages"
|
|
18207
|
+
}
|
|
18208
|
+
) }),
|
|
17546
18209
|
bubbles.map((msg, i) => {
|
|
17547
|
-
const isCustomer = msg.sender_type === "customer";
|
|
17548
18210
|
const prev = bubbles[i - 1];
|
|
17549
|
-
const
|
|
17550
|
-
const
|
|
17551
|
-
const
|
|
17552
|
-
|
|
17553
|
-
|
|
17554
|
-
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
|
|
17559
|
-
|
|
18211
|
+
const newDay = !prev || !sameDay(prev.created_at, msg.created_at);
|
|
18212
|
+
const group = groupPosition(timeline, i);
|
|
18213
|
+
const startsRun = group === "single" || group === "first";
|
|
18214
|
+
const delivery = deliveryState(msg, timeline, seenAt, isOptimistic);
|
|
18215
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18216
|
+
"div",
|
|
18217
|
+
{
|
|
18218
|
+
className: cn("flex flex-col gap-1.5", startsRun && i > 0 && "mt-2.5"),
|
|
18219
|
+
children: [
|
|
18220
|
+
newDay && /* @__PURE__ */ jsxRuntime.jsx(Seam, { variant: "chip", label: dayLabel(msg.created_at) }),
|
|
18221
|
+
msg.id === firstUnreadId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18222
|
+
Seam,
|
|
18223
|
+
{
|
|
18224
|
+
variant: "unread",
|
|
18225
|
+
label: `${unreadOnOpen} new message${unreadOnOpen === 1 ? "" : "s"}`
|
|
18226
|
+
}
|
|
17560
18227
|
),
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
"aria-label": `React ${emoji}`,
|
|
17567
|
-
onClick: () => void onReact(msg, emoji),
|
|
17568
|
-
className: "flex h-6 w-6 items-center justify-center rounded-full text-[13px] hover:bg-muted",
|
|
17569
|
-
children: emoji
|
|
17570
|
-
},
|
|
17571
|
-
emoji
|
|
17572
|
-
)) }),
|
|
17573
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
17574
|
-
"div",
|
|
18228
|
+
msg.id === firstAgentMessageId && /* @__PURE__ */ jsxRuntime.jsx(Seam, { label: "A person joined" }),
|
|
18229
|
+
msg.sender_type === "system" ? /* @__PURE__ */ jsxRuntime.jsx(Seam, { label: "Passing you to the team" }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative", children: [
|
|
18230
|
+
msg.sender_type !== "customer" && !isOptimistic(msg) && /* @__PURE__ */ jsxRuntime.jsx(HoverRail, { message: msg, onReact, onReply }),
|
|
18231
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18232
|
+
MessageBubble,
|
|
17575
18233
|
{
|
|
17576
|
-
|
|
17577
|
-
|
|
17578
|
-
|
|
17579
|
-
|
|
17580
|
-
|
|
17581
|
-
|
|
17582
|
-
|
|
17583
|
-
|
|
17584
|
-
|
|
17585
|
-
|
|
17586
|
-
|
|
17587
|
-
msg.reply_to && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17588
|
-
"div",
|
|
17589
|
-
{
|
|
17590
|
-
className: cn(
|
|
17591
|
-
"mb-1.5 flex gap-1.5 rounded-lg px-2 py-1 text-xs",
|
|
17592
|
-
isCustomer ? "bg-background/15" : "bg-muted"
|
|
17593
|
-
),
|
|
17594
|
-
children: [
|
|
17595
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17596
|
-
"span",
|
|
17597
|
-
{
|
|
17598
|
-
className: cn(
|
|
17599
|
-
"w-[3px] shrink-0 self-stretch rounded-full",
|
|
17600
|
-
isCustomer ? "bg-background/40" : "bg-muted-foreground/40"
|
|
17601
|
-
)
|
|
17602
|
-
}
|
|
17603
|
-
),
|
|
17604
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate opacity-80", children: msg.reply_to.preview })
|
|
17605
|
-
]
|
|
17606
|
-
}
|
|
17607
|
-
),
|
|
17608
|
-
msg.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-wrap gap-1.5", msg.content && "mb-1.5"), children: msg.attachments.map((attachment, index) => {
|
|
17609
|
-
const url = safeAttachmentUrl(attachment.url);
|
|
17610
|
-
if (!url) return null;
|
|
17611
|
-
return attachment.mime_type?.startsWith("image/") ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: url, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
17612
|
-
"img",
|
|
17613
|
-
{
|
|
17614
|
-
src: url,
|
|
17615
|
-
alt: attachment.filename ?? "Photo",
|
|
17616
|
-
loading: "lazy",
|
|
17617
|
-
className: "max-h-48 max-w-full rounded-lg object-cover"
|
|
17618
|
-
}
|
|
17619
|
-
) }, index) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
17620
|
-
"a",
|
|
17621
|
-
{
|
|
17622
|
-
href: url,
|
|
17623
|
-
target: "_blank",
|
|
17624
|
-
rel: "noreferrer",
|
|
17625
|
-
className: "truncate text-xs underline",
|
|
17626
|
-
children: attachment.filename ?? "Attachment"
|
|
17627
|
-
},
|
|
17628
|
-
index
|
|
17629
|
-
);
|
|
17630
|
-
}) }),
|
|
17631
|
-
isCustomer ? msg.content && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-pre-wrap", children: msg.content }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
17632
|
-
ChatMarkdown,
|
|
17633
|
-
{
|
|
17634
|
-
text: msg.content,
|
|
17635
|
-
className: "[&_p]:my-0 [&_p+p]:mt-1.5 [&_ul]:my-1 [&_ul]:list-disc [&_ul]:pl-4 [&_ol]:my-1 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:my-0.5 [&_h1]:text-sm [&_h1]:font-bold [&_h2]:text-sm [&_h2]:font-bold [&_h3]:text-sm [&_h3]:font-semibold [&_hr]:my-2 [&_table]:my-1 [&_table]:w-full [&_th]:pb-1 [&_th]:text-left [&_th]:text-[10px] [&_th]:font-semibold [&_th]:uppercase [&_td]:py-1 [&_td:last-child]:text-right [&_td:last-child]:font-semibold [&_td:last-child]:tabular-nums [&_a]:underline"
|
|
17636
|
-
}
|
|
17637
|
-
)
|
|
17638
|
-
]
|
|
18234
|
+
message: msg,
|
|
18235
|
+
reactions: reactionsByTarget.get(msg.id),
|
|
18236
|
+
businessName,
|
|
18237
|
+
group,
|
|
18238
|
+
delivery,
|
|
18239
|
+
onReply,
|
|
18240
|
+
avatar: /* @__PURE__ */ jsxRuntime.jsx(LetterAvatar, { name: businessName }),
|
|
18241
|
+
onQuoteMiss: async () => {
|
|
18242
|
+
onLoadOlder();
|
|
18243
|
+
return true;
|
|
18244
|
+
}
|
|
17639
18245
|
}
|
|
17640
18246
|
)
|
|
17641
|
-
]
|
|
17642
|
-
|
|
17643
|
-
|
|
17644
|
-
|
|
17645
|
-
|
|
17646
|
-
{
|
|
17647
|
-
className: "rounded-full border border-border bg-background px-1.5 py-0.5 text-xs shadow-sm",
|
|
17648
|
-
children: reaction.content
|
|
17649
|
-
},
|
|
17650
|
-
reaction.id
|
|
17651
|
-
)) }),
|
|
17652
|
-
msg.id === seenMessageId && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 text-right text-[10px] font-medium text-muted-foreground", children: "Seen" })
|
|
17653
|
-
] }, msg.id);
|
|
18247
|
+
] })
|
|
18248
|
+
]
|
|
18249
|
+
},
|
|
18250
|
+
msg.id
|
|
18251
|
+
);
|
|
17654
18252
|
}),
|
|
17655
18253
|
isSending && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mr-auto mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {}) }),
|
|
18254
|
+
offerHuman && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18255
|
+
"button",
|
|
18256
|
+
{
|
|
18257
|
+
type: "button",
|
|
18258
|
+
onClick: onRequestHuman,
|
|
18259
|
+
className: "rounded-full border border-border bg-background px-3 py-1.5 text-xs font-semibold text-foreground hover:border-foreground",
|
|
18260
|
+
children: "Talk to a person"
|
|
18261
|
+
}
|
|
18262
|
+
) }),
|
|
17656
18263
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17657
18264
|
"div",
|
|
17658
18265
|
{
|
|
17659
18266
|
ref: (node) => {
|
|
17660
|
-
node
|
|
18267
|
+
if (node && !scrolledUpRef.current) node.scrollIntoView({ behavior: "smooth" });
|
|
17661
18268
|
}
|
|
17662
18269
|
},
|
|
17663
18270
|
`${messages.length}:${isSending}`
|
|
@@ -17666,6 +18273,172 @@ function MessageList({
|
|
|
17666
18273
|
}
|
|
17667
18274
|
);
|
|
17668
18275
|
}
|
|
18276
|
+
function HoverRail({
|
|
18277
|
+
message,
|
|
18278
|
+
onReact,
|
|
18279
|
+
onReply
|
|
18280
|
+
}) {
|
|
18281
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute -top-3 right-0 z-10 hidden gap-0.5 rounded-full border border-border bg-background px-1 py-0.5 shadow-sm group-hover:flex", children: [
|
|
18282
|
+
QUICK_REACTIONS.map((emoji) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
18283
|
+
"button",
|
|
18284
|
+
{
|
|
18285
|
+
type: "button",
|
|
18286
|
+
"aria-label": `React ${emoji}`,
|
|
18287
|
+
onClick: () => void onReact(message, emoji),
|
|
18288
|
+
className: "flex h-6 w-6 items-center justify-center rounded-full text-[13px] hover:bg-muted",
|
|
18289
|
+
children: emoji
|
|
18290
|
+
},
|
|
18291
|
+
emoji
|
|
18292
|
+
)),
|
|
18293
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18294
|
+
"button",
|
|
18295
|
+
{
|
|
18296
|
+
type: "button",
|
|
18297
|
+
"aria-label": "Reply",
|
|
18298
|
+
onClick: () => onReply(message),
|
|
18299
|
+
className: "flex h-6 w-6 items-center justify-center rounded-full text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
18300
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ReplyIcon, { className: "h-3.5 w-3.5" })
|
|
18301
|
+
}
|
|
18302
|
+
)
|
|
18303
|
+
] });
|
|
18304
|
+
}
|
|
18305
|
+
function readKeepDismissed() {
|
|
18306
|
+
try {
|
|
18307
|
+
return typeof window !== "undefined" && window.localStorage.getItem(KEEP_DISMISSED_KEY) === "1";
|
|
18308
|
+
} catch {
|
|
18309
|
+
return false;
|
|
18310
|
+
}
|
|
18311
|
+
}
|
|
18312
|
+
function writeKeepDismissed() {
|
|
18313
|
+
try {
|
|
18314
|
+
window.localStorage.setItem(KEEP_DISMISSED_KEY, "1");
|
|
18315
|
+
} catch {
|
|
18316
|
+
}
|
|
18317
|
+
}
|
|
18318
|
+
function KeepConversation({ client }) {
|
|
18319
|
+
const [step, setStep] = React14.useState("row");
|
|
18320
|
+
const [dismissed, setDismissed] = React14.useState(readKeepDismissed);
|
|
18321
|
+
const [contact, setContact] = React14.useState("");
|
|
18322
|
+
const [code, setCode] = React14.useState("");
|
|
18323
|
+
const [busy, setBusy] = React14.useState(false);
|
|
18324
|
+
const [verifyError, setVerifyError] = React14.useState(null);
|
|
18325
|
+
if (dismissed) return null;
|
|
18326
|
+
const contactType = contact.includes("@") ? "email" : "phone";
|
|
18327
|
+
const requestCode = async () => {
|
|
18328
|
+
const trimmed = contact.trim();
|
|
18329
|
+
if (!trimmed || busy) return;
|
|
18330
|
+
setBusy(true);
|
|
18331
|
+
setVerifyError(null);
|
|
18332
|
+
const result = await client.link.requestOtp({ contact: trimmed, contact_type: contactType });
|
|
18333
|
+
setBusy(false);
|
|
18334
|
+
if (result.ok) {
|
|
18335
|
+
setCode("");
|
|
18336
|
+
setStep("code");
|
|
18337
|
+
} else {
|
|
18338
|
+
setVerifyError(result.error.userMessage || "Couldn't send a code \u2014 try again.");
|
|
18339
|
+
}
|
|
18340
|
+
};
|
|
18341
|
+
const verify = async (value) => {
|
|
18342
|
+
if (value.length !== 6 || busy) return;
|
|
18343
|
+
setBusy(true);
|
|
18344
|
+
setVerifyError(null);
|
|
18345
|
+
const result = await client.link.verifyOtp({
|
|
18346
|
+
contact: contact.trim(),
|
|
18347
|
+
contact_type: contactType,
|
|
18348
|
+
otp_code: value
|
|
18349
|
+
});
|
|
18350
|
+
setBusy(false);
|
|
18351
|
+
if (!result.ok) {
|
|
18352
|
+
setCode("");
|
|
18353
|
+
setVerifyError(result.error.userMessage || "Invalid or expired code.");
|
|
18354
|
+
}
|
|
18355
|
+
};
|
|
18356
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 border-t border-border bg-muted/50 px-4 py-2.5", children: [
|
|
18357
|
+
step === "row" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
18358
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
18359
|
+
"button",
|
|
18360
|
+
{
|
|
18361
|
+
type: "button",
|
|
18362
|
+
onClick: () => setStep("contact"),
|
|
18363
|
+
className: "flex min-w-0 flex-1 flex-col text-left",
|
|
18364
|
+
children: [
|
|
18365
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-foreground", children: "Keep this conversation" }),
|
|
18366
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: "Verify your number and it follows you \u2014 any device" })
|
|
18367
|
+
]
|
|
18368
|
+
}
|
|
18369
|
+
),
|
|
18370
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18371
|
+
"button",
|
|
18372
|
+
{
|
|
18373
|
+
type: "button",
|
|
18374
|
+
"aria-label": "Dismiss",
|
|
18375
|
+
onClick: () => {
|
|
18376
|
+
writeKeepDismissed();
|
|
18377
|
+
setDismissed(true);
|
|
18378
|
+
},
|
|
18379
|
+
className: "flex-shrink-0 p-1 text-muted-foreground hover:text-foreground",
|
|
18380
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "h-3.5 w-3.5" })
|
|
18381
|
+
}
|
|
18382
|
+
)
|
|
18383
|
+
] }),
|
|
18384
|
+
step === "contact" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
18385
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18386
|
+
"input",
|
|
18387
|
+
{
|
|
18388
|
+
type: "text",
|
|
18389
|
+
inputMode: "email",
|
|
18390
|
+
value: contact,
|
|
18391
|
+
onChange: (e) => setContact(e.target.value),
|
|
18392
|
+
onKeyDown: (e) => e.key === "Enter" && void requestCode(),
|
|
18393
|
+
placeholder: "Phone or email",
|
|
18394
|
+
autoFocus: true,
|
|
18395
|
+
className: "h-9 min-w-0 flex-1 rounded-lg border border-border bg-background px-3 text-xs text-foreground outline-none placeholder:text-muted-foreground focus:border-foreground"
|
|
18396
|
+
}
|
|
18397
|
+
),
|
|
18398
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18399
|
+
"button",
|
|
18400
|
+
{
|
|
18401
|
+
type: "button",
|
|
18402
|
+
onClick: () => void requestCode(),
|
|
18403
|
+
disabled: !contact.trim() || busy,
|
|
18404
|
+
className: "h-9 flex-shrink-0 rounded-lg bg-foreground px-3 text-xs font-semibold text-background disabled:opacity-50",
|
|
18405
|
+
children: busy ? "Sending\u2026" : "Send code"
|
|
18406
|
+
}
|
|
18407
|
+
)
|
|
18408
|
+
] }),
|
|
18409
|
+
step === "code" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
18410
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18411
|
+
"input",
|
|
18412
|
+
{
|
|
18413
|
+
type: "text",
|
|
18414
|
+
inputMode: "numeric",
|
|
18415
|
+
autoComplete: "one-time-code",
|
|
18416
|
+
maxLength: 6,
|
|
18417
|
+
value: code,
|
|
18418
|
+
onChange: (e) => {
|
|
18419
|
+
const digits = e.target.value.replace(/\D/g, "").slice(0, 6);
|
|
18420
|
+
setCode(digits);
|
|
18421
|
+
if (digits.length === 6) void verify(digits);
|
|
18422
|
+
},
|
|
18423
|
+
placeholder: "6-digit code",
|
|
18424
|
+
autoFocus: true,
|
|
18425
|
+
className: "h-9 min-w-0 flex-1 rounded-lg border border-border bg-background px-3 text-xs tracking-[0.2em] text-foreground outline-none placeholder:tracking-normal placeholder:text-muted-foreground focus:border-foreground"
|
|
18426
|
+
}
|
|
18427
|
+
),
|
|
18428
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18429
|
+
"button",
|
|
18430
|
+
{
|
|
18431
|
+
type: "button",
|
|
18432
|
+
onClick: () => void requestCode(),
|
|
18433
|
+
disabled: busy,
|
|
18434
|
+
className: "h-9 flex-shrink-0 rounded-lg px-2 text-[11px] font-medium text-muted-foreground hover:text-foreground disabled:opacity-50",
|
|
18435
|
+
children: "Resend"
|
|
18436
|
+
}
|
|
18437
|
+
)
|
|
18438
|
+
] }),
|
|
18439
|
+
verifyError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-[11px] text-destructive", children: verifyError })
|
|
18440
|
+
] });
|
|
18441
|
+
}
|
|
17669
18442
|
function ChatInput({
|
|
17670
18443
|
placeholder,
|
|
17671
18444
|
isSending,
|
|
@@ -17688,14 +18461,15 @@ function ChatInput({
|
|
|
17688
18461
|
},
|
|
17689
18462
|
[onAttach]
|
|
17690
18463
|
);
|
|
17691
|
-
const handleSend = React14.useCallback(() => {
|
|
18464
|
+
const handleSend = React14.useCallback(async () => {
|
|
17692
18465
|
const trimmed = value.trim();
|
|
17693
18466
|
if (!trimmed || isSending) return;
|
|
17694
18467
|
setValue("");
|
|
17695
18468
|
if (textareaRef.current) {
|
|
17696
18469
|
textareaRef.current.style.height = "auto";
|
|
17697
18470
|
}
|
|
17698
|
-
onSend(trimmed);
|
|
18471
|
+
const sent = await onSend(trimmed);
|
|
18472
|
+
if (!sent) setValue((current) => current || trimmed);
|
|
17699
18473
|
}, [value, isSending, onSend]);
|
|
17700
18474
|
const handleKeyDown = React14.useCallback(
|
|
17701
18475
|
(e) => {
|
|
@@ -17873,16 +18647,21 @@ function ImageIcon({ className }) {
|
|
|
17873
18647
|
}
|
|
17874
18648
|
);
|
|
17875
18649
|
}
|
|
17876
|
-
function
|
|
17877
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
18650
|
+
function ReplyIcon({ className }) {
|
|
18651
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17878
18652
|
"svg",
|
|
17879
18653
|
{
|
|
17880
18654
|
className,
|
|
17881
18655
|
viewBox: "0 0 24 24",
|
|
17882
18656
|
fill: "none",
|
|
17883
18657
|
stroke: "currentColor",
|
|
17884
|
-
strokeWidth: 2
|
|
17885
|
-
|
|
18658
|
+
strokeWidth: 2,
|
|
18659
|
+
strokeLinecap: "round",
|
|
18660
|
+
strokeLinejoin: "round",
|
|
18661
|
+
children: [
|
|
18662
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 17 4 12 9 7" }),
|
|
18663
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 18v-2a4 4 0 0 0-4-4H4" })
|
|
18664
|
+
]
|
|
17886
18665
|
}
|
|
17887
18666
|
);
|
|
17888
18667
|
}
|
|
@@ -19710,7 +20489,7 @@ async function genUIFingerprint(manifest) {
|
|
|
19710
20489
|
|
|
19711
20490
|
Object.defineProperty(exports, "getVariantDisplayName", {
|
|
19712
20491
|
enumerable: true,
|
|
19713
|
-
get: function () { return
|
|
20492
|
+
get: function () { return chunkQPRI2NII_js.getVariantDisplayName; }
|
|
19714
20493
|
});
|
|
19715
20494
|
Object.defineProperty(exports, "messagePreview", {
|
|
19716
20495
|
enumerable: true,
|
|
@@ -19751,6 +20530,7 @@ exports.BookingPage = BookingPage;
|
|
|
19751
20530
|
exports.BookingSummary = BookingSummary;
|
|
19752
20531
|
exports.BookingsPage = BookingsPage;
|
|
19753
20532
|
exports.BoxIcon24 = BoxIcon24;
|
|
20533
|
+
exports.BubbleTail = BubbleTail;
|
|
19754
20534
|
exports.BundleProductCard = BundleProductCard;
|
|
19755
20535
|
exports.BundleProductLayout = BundleProductLayout;
|
|
19756
20536
|
exports.BundleSelector = BundleSelector;
|
|
@@ -19825,6 +20605,7 @@ exports.LeaseServiceCard = LeaseServiceCard;
|
|
|
19825
20605
|
exports.LineItemDetails = LineItemDetails;
|
|
19826
20606
|
exports.LocationPicker = LocationPicker;
|
|
19827
20607
|
exports.MediaGallery = MediaGallery;
|
|
20608
|
+
exports.MessageBubble = MessageBubble;
|
|
19828
20609
|
exports.MetadataStringList = MetadataStringList;
|
|
19829
20610
|
exports.MobileAccountShell = MobileAccountShell;
|
|
19830
20611
|
exports.MobileBackButton = MobileBackButton;
|
|
@@ -19859,6 +20640,7 @@ exports.ProductTemplate = ProductTemplate;
|
|
|
19859
20640
|
exports.PropertiesTable = PropertiesTable;
|
|
19860
20641
|
exports.QuantitySelector = QuantitySelector;
|
|
19861
20642
|
exports.QuickAddButton = QuickAddButton;
|
|
20643
|
+
exports.QuoteBlock = QuoteBlock;
|
|
19862
20644
|
exports.RecentlyViewed = RecentlyViewed;
|
|
19863
20645
|
exports.RecommendationCarousel = RecommendationCarousel;
|
|
19864
20646
|
exports.RelatedProductsSection = RelatedProductsSection;
|
|
@@ -19866,10 +20648,12 @@ exports.RentalServiceCard = RentalServiceCard;
|
|
|
19866
20648
|
exports.ResourcePicker = ResourcePicker;
|
|
19867
20649
|
exports.RetailProductCard = RetailProductCard;
|
|
19868
20650
|
exports.RichText = RichText;
|
|
20651
|
+
exports.SWIPE_COMMIT_PX = SWIPE_COMMIT_PX;
|
|
19869
20652
|
exports.SaleBadge = SaleBadge;
|
|
19870
20653
|
exports.SalePrice = SalePrice;
|
|
19871
20654
|
exports.SaleTeaser = SaleTeaser;
|
|
19872
20655
|
exports.ScheduleServiceCard = ScheduleServiceCard;
|
|
20656
|
+
exports.Seam = Seam;
|
|
19873
20657
|
exports.SearchInput = SearchInput;
|
|
19874
20658
|
exports.SearchPage = SearchPage;
|
|
19875
20659
|
exports.SearchTemplate = SearchTemplate;
|
|
@@ -19901,26 +20685,39 @@ exports.WelcomeCard = WelcomeCard;
|
|
|
19901
20685
|
exports.WholesaleProductCard = WholesaleProductCard;
|
|
19902
20686
|
exports.WholesaleProductLayout = WholesaleProductLayout;
|
|
19903
20687
|
exports.WishlistButton = WishlistButton;
|
|
20688
|
+
exports.chatTimeline = chatTimeline;
|
|
19904
20689
|
exports.clearOrdersCache = clearOrdersCache;
|
|
19905
20690
|
exports.cn = cn;
|
|
19906
20691
|
exports.createPlacesSessionToken = createPlacesSessionToken;
|
|
20692
|
+
exports.dayLabel = dayLabel;
|
|
19907
20693
|
exports.defaultBoundaryKind = defaultBoundaryKind;
|
|
20694
|
+
exports.deliveryState = deliveryState;
|
|
19908
20695
|
exports.genUICatalog = genUICatalog;
|
|
19909
20696
|
exports.genUIFingerprint = genUIFingerprint;
|
|
19910
20697
|
exports.genUIManifest = genUIManifest;
|
|
19911
20698
|
exports.genUIManifestJson = genUIManifestJson;
|
|
19912
20699
|
exports.getBoundaryLabels = getBoundaryLabels;
|
|
20700
|
+
exports.groupPosition = groupPosition;
|
|
19913
20701
|
exports.isImageAttachment = isImageAttachment;
|
|
20702
|
+
exports.isOptimistic = isOptimistic;
|
|
19914
20703
|
exports.isTerminalOrderStatus = isTerminalOrderStatus;
|
|
20704
|
+
exports.optimisticId = optimisticId;
|
|
19915
20705
|
exports.parseGenUIProgram = parse;
|
|
19916
20706
|
exports.partitionMessages = partitionMessages;
|
|
20707
|
+
exports.prefersReducedMotion = prefersReducedMotion;
|
|
19917
20708
|
exports.prefetchProduct = prefetchProduct;
|
|
19918
20709
|
exports.prefetchProducts = prefetchProducts;
|
|
20710
|
+
exports.proseOf = proseOf;
|
|
19919
20711
|
exports.resolveBoundaryKind = resolveBoundaryKind;
|
|
19920
20712
|
exports.roomToResource = roomToResource;
|
|
19921
20713
|
exports.safeAttachmentUrl = safeAttachmentUrl;
|
|
20714
|
+
exports.sameDay = sameDay;
|
|
19922
20715
|
exports.sanitizeRichTextHtml = sanitizeRichTextHtml;
|
|
20716
|
+
exports.scrollBehavior = scrollBehavior;
|
|
19923
20717
|
exports.stripHtmlToText = stripHtmlToText;
|
|
20718
|
+
exports.swipeCommitted = swipeCommitted;
|
|
20719
|
+
exports.swipeProgress = swipeProgress;
|
|
20720
|
+
exports.swipeTravel = swipeTravel;
|
|
19924
20721
|
exports.toAccountLineItem = toAccountLineItem;
|
|
19925
20722
|
exports.toAccountLineItems = toAccountLineItems;
|
|
19926
20723
|
exports.toAccountOrderView = toAccountOrderView;
|
|
@@ -19969,6 +20766,7 @@ exports.useServices = useServices;
|
|
|
19969
20766
|
exports.useStoreCredit = useStoreCredit;
|
|
19970
20767
|
exports.useSubscription = useSubscription;
|
|
19971
20768
|
exports.useSubscriptions = useSubscriptions;
|
|
20769
|
+
exports.useSwipeReply = useSwipeReply;
|
|
19972
20770
|
exports.useTaxonomies = useTaxonomies;
|
|
19973
20771
|
exports.useTaxonomy = useTaxonomy;
|
|
19974
20772
|
exports.useTaxonomyPath = useTaxonomyPath;
|