@huskel/sdk 0.4.6 → 0.4.7
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/index.css +54 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +227 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +224 -55
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -52,8 +52,10 @@ __export(index_exports, {
|
|
|
52
52
|
useCart: () => useCart,
|
|
53
53
|
useChat: () => useChat,
|
|
54
54
|
useHuskel: () => useHuskel,
|
|
55
|
+
useHuskelContext: () => useHuskelContext,
|
|
55
56
|
useIngest: () => useIngest,
|
|
56
57
|
usePageIngest: () => usePageIngest,
|
|
58
|
+
usePaymentPolling: () => usePaymentPolling,
|
|
57
59
|
useSearch: () => useSearch
|
|
58
60
|
});
|
|
59
61
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -207,6 +209,32 @@ var HuskelAPI = class {
|
|
|
207
209
|
if (!res.ok) throw new Error("Failed to fetch checkout config");
|
|
208
210
|
return res.json();
|
|
209
211
|
}
|
|
212
|
+
async initiatePayment(phoneNumber, email, firstName, lastName) {
|
|
213
|
+
const res = await fetch(`${this.apiUrl}/payment/initiate`, {
|
|
214
|
+
method: "POST",
|
|
215
|
+
headers: this.buildHeaders(),
|
|
216
|
+
body: JSON.stringify({
|
|
217
|
+
siteId: this.siteId,
|
|
218
|
+
phoneNumber,
|
|
219
|
+
email,
|
|
220
|
+
firstName,
|
|
221
|
+
lastName
|
|
222
|
+
})
|
|
223
|
+
});
|
|
224
|
+
if (!res.ok) {
|
|
225
|
+
const errText = await res.text();
|
|
226
|
+
throw new Error("Failed to initiate payment: " + errText);
|
|
227
|
+
}
|
|
228
|
+
return res.json();
|
|
229
|
+
}
|
|
230
|
+
async getPaymentStatus(ref) {
|
|
231
|
+
const res = await fetch(`${this.apiUrl}/payment/status?ref=${ref}`, {
|
|
232
|
+
method: "GET",
|
|
233
|
+
headers: this.buildHeaders()
|
|
234
|
+
});
|
|
235
|
+
if (!res.ok) throw new Error("Failed to get payment status");
|
|
236
|
+
return res.json();
|
|
237
|
+
}
|
|
210
238
|
};
|
|
211
239
|
|
|
212
240
|
// src/client.ts
|
|
@@ -627,9 +655,10 @@ function useChat() {
|
|
|
627
655
|
const [sources, setSources] = (0, import_react6.useState)([]);
|
|
628
656
|
const [loading, setLoading] = (0, import_react6.useState)(false);
|
|
629
657
|
const [error, setError] = (0, import_react6.useState)(null);
|
|
658
|
+
const [lastAction, setLastAction] = (0, import_react6.useState)(null);
|
|
630
659
|
const abortRef = (0, import_react6.useRef)(null);
|
|
631
660
|
const send = (0, import_react6.useCallback)(async (query, displayQuery) => {
|
|
632
|
-
var _a, _b, _c, _d, _e;
|
|
661
|
+
var _a, _b, _c, _d, _e, _f;
|
|
633
662
|
if (!query.trim() || loading) return;
|
|
634
663
|
(_a = abortRef.current) == null ? void 0 : _a.abort();
|
|
635
664
|
abortRef.current = new AbortController();
|
|
@@ -660,6 +689,7 @@ function useChat() {
|
|
|
660
689
|
}
|
|
661
690
|
if (signal.aborted) return;
|
|
662
691
|
setSources((_b = res.sources) != null ? _b : []);
|
|
692
|
+
if (res.action) setLastAction(res.action);
|
|
663
693
|
if (((_c = res.action) == null ? void 0 : _c.type) === "add_to_cart" || res.checkout) {
|
|
664
694
|
if (typeof window !== "undefined") {
|
|
665
695
|
window.dispatchEvent(new CustomEvent("huskel:cart_updated", { detail: res.checkout }));
|
|
@@ -670,12 +700,17 @@ function useChat() {
|
|
|
670
700
|
window.dispatchEvent(new CustomEvent("huskel:trigger_checkout", { detail: res.checkout }));
|
|
671
701
|
}
|
|
672
702
|
}
|
|
703
|
+
if (((_e = res.action) == null ? void 0 : _e.type) === "awaiting_payment") {
|
|
704
|
+
if (typeof window !== "undefined") {
|
|
705
|
+
window.dispatchEvent(new CustomEvent("huskel:awaiting_payment", { detail: res.action }));
|
|
706
|
+
}
|
|
707
|
+
}
|
|
673
708
|
if (res.checkout && client.onCheckout) {
|
|
674
709
|
client.onCheckout(res.checkout);
|
|
675
710
|
}
|
|
676
711
|
} catch (e) {
|
|
677
712
|
if (signal.aborted) return;
|
|
678
|
-
let msg = (
|
|
713
|
+
let msg = (_f = e == null ? void 0 : e.message) != null ? _f : "Chat request failed";
|
|
679
714
|
try {
|
|
680
715
|
const parsed = JSON.parse(msg);
|
|
681
716
|
if (parsed && parsed.error) {
|
|
@@ -698,8 +733,9 @@ function useChat() {
|
|
|
698
733
|
setSources([]);
|
|
699
734
|
setError(null);
|
|
700
735
|
setLoading(false);
|
|
736
|
+
setLastAction(null);
|
|
701
737
|
}, []);
|
|
702
|
-
return { messages, sources, loading, error, send, reset };
|
|
738
|
+
return { messages, sources, loading, error, lastAction, send, reset };
|
|
703
739
|
}
|
|
704
740
|
|
|
705
741
|
// src/hooks/useCart.ts
|
|
@@ -738,8 +774,71 @@ function useCart() {
|
|
|
738
774
|
return { cart, loading, fetchCart };
|
|
739
775
|
}
|
|
740
776
|
|
|
741
|
-
// src/
|
|
777
|
+
// src/hooks/usePaymentPolling.ts
|
|
742
778
|
var import_react8 = require("react");
|
|
779
|
+
function usePaymentPolling({
|
|
780
|
+
client,
|
|
781
|
+
merchantReference,
|
|
782
|
+
onSuccess,
|
|
783
|
+
onFailure,
|
|
784
|
+
intervalMs = 3e3,
|
|
785
|
+
timeoutMs = 3e5
|
|
786
|
+
// 5 minutes default
|
|
787
|
+
}) {
|
|
788
|
+
const [status, setStatus] = (0, import_react8.useState)("IDLE");
|
|
789
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
790
|
+
const onSuccessRef = (0, import_react8.useRef)(onSuccess);
|
|
791
|
+
const onFailureRef = (0, import_react8.useRef)(onFailure);
|
|
792
|
+
(0, import_react8.useEffect)(() => {
|
|
793
|
+
onSuccessRef.current = onSuccess;
|
|
794
|
+
onFailureRef.current = onFailure;
|
|
795
|
+
}, [onSuccess, onFailure]);
|
|
796
|
+
(0, import_react8.useEffect)(() => {
|
|
797
|
+
if (!merchantReference) {
|
|
798
|
+
setStatus("IDLE");
|
|
799
|
+
setError(null);
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
setStatus("PENDING");
|
|
803
|
+
setError(null);
|
|
804
|
+
const startTime = Date.now();
|
|
805
|
+
let timerId = null;
|
|
806
|
+
async function checkStatus() {
|
|
807
|
+
try {
|
|
808
|
+
if (Date.now() - startTime >= timeoutMs) {
|
|
809
|
+
setStatus("FAILED");
|
|
810
|
+
setError("Payment session timed out");
|
|
811
|
+
if (onFailureRef.current) onFailureRef.current("Payment session timed out");
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
const res = await client.getPaymentStatus(merchantReference);
|
|
815
|
+
if (res.status === "COMPLETED") {
|
|
816
|
+
setStatus("COMPLETED");
|
|
817
|
+
if (onSuccessRef.current) onSuccessRef.current();
|
|
818
|
+
} else if (res.status === "FAILED") {
|
|
819
|
+
setStatus("FAILED");
|
|
820
|
+
setError("Payment failed");
|
|
821
|
+
if (onFailureRef.current) onFailureRef.current("Payment failed");
|
|
822
|
+
} else {
|
|
823
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
824
|
+
}
|
|
825
|
+
} catch (err) {
|
|
826
|
+
console.error("[Huskel Polling Error]", err);
|
|
827
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
831
|
+
return () => {
|
|
832
|
+
if (timerId) {
|
|
833
|
+
clearTimeout(timerId);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
}, [client, merchantReference, intervalMs, timeoutMs]);
|
|
837
|
+
return { status, error };
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// src/components/SearchBar.tsx
|
|
841
|
+
var import_react9 = require("react");
|
|
743
842
|
|
|
744
843
|
// src/utils/cn.ts
|
|
745
844
|
var import_clsx = require("clsx");
|
|
@@ -766,15 +865,15 @@ function SearchBar({
|
|
|
766
865
|
theme,
|
|
767
866
|
classNames = {}
|
|
768
867
|
}) {
|
|
769
|
-
const [query, setQuery] = (0,
|
|
770
|
-
const [open, setOpen] = (0,
|
|
771
|
-
const [isDebouncing, setIsDebouncing] = (0,
|
|
868
|
+
const [query, setQuery] = (0, import_react9.useState)("");
|
|
869
|
+
const [open, setOpen] = (0, import_react9.useState)(false);
|
|
870
|
+
const [isDebouncing, setIsDebouncing] = (0, import_react9.useState)(false);
|
|
772
871
|
const { results, loading, search, clear } = useSearch();
|
|
773
872
|
const client = useHuskelContext();
|
|
774
|
-
const timer = (0,
|
|
775
|
-
const wrap = (0,
|
|
776
|
-
const ignoreNextQueryChange = (0,
|
|
777
|
-
(0,
|
|
873
|
+
const timer = (0, import_react9.useRef)();
|
|
874
|
+
const wrap = (0, import_react9.useRef)(null);
|
|
875
|
+
const ignoreNextQueryChange = (0, import_react9.useRef)(false);
|
|
876
|
+
(0, import_react9.useEffect)(() => {
|
|
778
877
|
if (ignoreNextQueryChange.current) {
|
|
779
878
|
ignoreNextQueryChange.current = false;
|
|
780
879
|
return;
|
|
@@ -794,7 +893,7 @@ function SearchBar({
|
|
|
794
893
|
}, debounceMs);
|
|
795
894
|
return () => clearTimeout(timer.current);
|
|
796
895
|
}, [query]);
|
|
797
|
-
(0,
|
|
896
|
+
(0, import_react9.useEffect)(() => {
|
|
798
897
|
const h = (e) => {
|
|
799
898
|
if (wrap.current && !wrap.current.contains(e.target)) setOpen(false);
|
|
800
899
|
};
|
|
@@ -898,7 +997,7 @@ function SearchBar({
|
|
|
898
997
|
}
|
|
899
998
|
|
|
900
999
|
// src/components/Sparkle.tsx
|
|
901
|
-
var
|
|
1000
|
+
var import_react10 = require("react");
|
|
902
1001
|
var import_react_dom = require("react-dom");
|
|
903
1002
|
|
|
904
1003
|
// src/utils/markdown.tsx
|
|
@@ -1030,14 +1129,14 @@ function SparkleModal({
|
|
|
1030
1129
|
}) {
|
|
1031
1130
|
var _a, _b, _c;
|
|
1032
1131
|
const client = useHuskelContext();
|
|
1033
|
-
const [fetchedProduct, setFetchedProduct] = (0,
|
|
1132
|
+
const [fetchedProduct, setFetchedProduct] = (0, import_react10.useState)(null);
|
|
1034
1133
|
const displayProduct = initialProduct || fetchedProduct;
|
|
1035
1134
|
const { results, loading: searchLoading, search } = useSearch();
|
|
1036
1135
|
const { messages, sources, loading: chatLoading, error: chatError, send } = useChat();
|
|
1037
|
-
const [chatInput, setChatInput] = (0,
|
|
1038
|
-
const chatBottomRef = (0,
|
|
1039
|
-
const chatTextareaRef = (0,
|
|
1040
|
-
(0,
|
|
1136
|
+
const [chatInput, setChatInput] = (0, import_react10.useState)("");
|
|
1137
|
+
const chatBottomRef = (0, import_react10.useRef)(null);
|
|
1138
|
+
const chatTextareaRef = (0, import_react10.useRef)(null);
|
|
1139
|
+
(0, import_react10.useEffect)(() => {
|
|
1041
1140
|
if (!initialProduct && !fetchedProduct) {
|
|
1042
1141
|
client.api.searchVector(productName, 1).then((res) => {
|
|
1043
1142
|
if (res.results && res.results.length > 0) {
|
|
@@ -1047,17 +1146,17 @@ function SparkleModal({
|
|
|
1047
1146
|
}
|
|
1048
1147
|
search(productName, limit);
|
|
1049
1148
|
}, [productName, initialProduct, fetchedProduct, client, limit, search]);
|
|
1050
|
-
(0,
|
|
1149
|
+
(0, import_react10.useEffect)(() => {
|
|
1051
1150
|
if (results.length > 0) onResult == null ? void 0 : onResult(results);
|
|
1052
1151
|
}, [results, onResult]);
|
|
1053
|
-
(0,
|
|
1152
|
+
(0, import_react10.useEffect)(() => {
|
|
1054
1153
|
const h = (e) => {
|
|
1055
1154
|
if (e.key === "Escape") onClose();
|
|
1056
1155
|
};
|
|
1057
1156
|
document.addEventListener("keydown", h);
|
|
1058
1157
|
return () => document.removeEventListener("keydown", h);
|
|
1059
1158
|
}, [onClose]);
|
|
1060
|
-
(0,
|
|
1159
|
+
(0, import_react10.useEffect)(() => {
|
|
1061
1160
|
var _a2;
|
|
1062
1161
|
(_a2 = chatBottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1063
1162
|
}, [messages, chatLoading]);
|
|
@@ -1289,9 +1388,9 @@ function Sparkle({
|
|
|
1289
1388
|
classNames = {},
|
|
1290
1389
|
product
|
|
1291
1390
|
}) {
|
|
1292
|
-
const [open, setOpen] = (0,
|
|
1293
|
-
const [mounted, setMounted] = (0,
|
|
1294
|
-
(0,
|
|
1391
|
+
const [open, setOpen] = (0, import_react10.useState)(false);
|
|
1392
|
+
const [mounted, setMounted] = (0, import_react10.useState)(false);
|
|
1393
|
+
(0, import_react10.useEffect)(() => {
|
|
1295
1394
|
setMounted(true);
|
|
1296
1395
|
}, []);
|
|
1297
1396
|
const customStyles = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, (theme == null ? void 0 : theme.primaryColor) && { "--hsk-primary": theme.primaryColor }), (theme == null ? void 0 : theme.backgroundColor) && { "--hsk-bg": theme.backgroundColor }), (theme == null ? void 0 : theme.textColor) && { "--hsk-text": theme.textColor }), (theme == null ? void 0 : theme.fontFamily) && { "--hsk-font": theme.fontFamily }), (theme == null ? void 0 : theme.borderRadius) && { "--hsk-border-radius": theme.borderRadius });
|
|
@@ -1329,7 +1428,7 @@ function Sparkle({
|
|
|
1329
1428
|
}
|
|
1330
1429
|
|
|
1331
1430
|
// src/components/ChatWidget.tsx
|
|
1332
|
-
var
|
|
1431
|
+
var import_react11 = require("react");
|
|
1333
1432
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1334
1433
|
var SparkleIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z" }) });
|
|
1335
1434
|
var ArrowUpIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
@@ -1362,10 +1461,10 @@ function ChatWidget({
|
|
|
1362
1461
|
onSelectSource
|
|
1363
1462
|
}) {
|
|
1364
1463
|
const { messages, sources, loading, error, send, reset } = useChat();
|
|
1365
|
-
const [input, setInput] = (0,
|
|
1366
|
-
const bottomRef = (0,
|
|
1367
|
-
const textareaRef = (0,
|
|
1368
|
-
(0,
|
|
1464
|
+
const [input, setInput] = (0, import_react11.useState)("");
|
|
1465
|
+
const bottomRef = (0, import_react11.useRef)(null);
|
|
1466
|
+
const textareaRef = (0, import_react11.useRef)(null);
|
|
1467
|
+
(0, import_react11.useEffect)(() => {
|
|
1369
1468
|
var _a;
|
|
1370
1469
|
(_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
1371
1470
|
}, [messages, loading]);
|
|
@@ -1462,7 +1561,7 @@ function ChatWidget({
|
|
|
1462
1561
|
}
|
|
1463
1562
|
|
|
1464
1563
|
// src/components/AIChatButton.tsx
|
|
1465
|
-
var
|
|
1564
|
+
var import_react12 = require("react");
|
|
1466
1565
|
var import_react_dom2 = require("react-dom");
|
|
1467
1566
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1468
1567
|
var SparkleIcon3 = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z" }) });
|
|
@@ -1482,15 +1581,15 @@ var DEFAULT_CHIPS = [
|
|
|
1482
1581
|
"Best laptop for students"
|
|
1483
1582
|
];
|
|
1484
1583
|
function SourcesCarousel({ sources, defaultCurrency, onSelectSource }) {
|
|
1485
|
-
const railRef = (0,
|
|
1486
|
-
const [showNext, setShowNext] = (0,
|
|
1487
|
-
const measure = (0,
|
|
1584
|
+
const railRef = (0, import_react12.useRef)(null);
|
|
1585
|
+
const [showNext, setShowNext] = (0, import_react12.useState)(false);
|
|
1586
|
+
const measure = (0, import_react12.useCallback)(() => {
|
|
1488
1587
|
const el = railRef.current;
|
|
1489
1588
|
if (!el) return;
|
|
1490
1589
|
const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 8;
|
|
1491
1590
|
setShowNext(el.scrollWidth > el.clientWidth + 4 && !atEnd);
|
|
1492
1591
|
}, []);
|
|
1493
|
-
(0,
|
|
1592
|
+
(0, import_react12.useEffect)(() => {
|
|
1494
1593
|
measure();
|
|
1495
1594
|
const el = railRef.current;
|
|
1496
1595
|
if (!el) return;
|
|
@@ -1555,16 +1654,53 @@ function ChatModal({
|
|
|
1555
1654
|
classNames = {}
|
|
1556
1655
|
}) {
|
|
1557
1656
|
var _a, _b;
|
|
1558
|
-
const
|
|
1559
|
-
const
|
|
1560
|
-
const [
|
|
1561
|
-
const
|
|
1562
|
-
const
|
|
1563
|
-
(0,
|
|
1657
|
+
const client = useHuskelContext();
|
|
1658
|
+
const { messages, sources, loading, error, lastAction, send, reset } = useChat();
|
|
1659
|
+
const [input, setInput] = (0, import_react12.useState)("");
|
|
1660
|
+
const [selectedProduct, setSelectedProduct] = (0, import_react12.useState)(null);
|
|
1661
|
+
const bottomRef = (0, import_react12.useRef)(null);
|
|
1662
|
+
const textareaRef = (0, import_react12.useRef)(null);
|
|
1663
|
+
const [phoneInput, setPhoneInput] = (0, import_react12.useState)("");
|
|
1664
|
+
const [merchantRef, setMerchantRef] = (0, import_react12.useState)(null);
|
|
1665
|
+
const [paymentPhase, setPaymentPhase] = (0, import_react12.useState)("idle");
|
|
1666
|
+
const { status: pollStatus } = usePaymentPolling({
|
|
1667
|
+
client: client.api,
|
|
1668
|
+
merchantReference: merchantRef,
|
|
1669
|
+
onSuccess: () => {
|
|
1670
|
+
setPaymentPhase("done");
|
|
1671
|
+
setMerchantRef(null);
|
|
1672
|
+
},
|
|
1673
|
+
onFailure: () => {
|
|
1674
|
+
setPaymentPhase("failed");
|
|
1675
|
+
setMerchantRef(null);
|
|
1676
|
+
}
|
|
1677
|
+
});
|
|
1678
|
+
(0, import_react12.useEffect)(() => {
|
|
1679
|
+
var _a2;
|
|
1680
|
+
if (!lastAction) return;
|
|
1681
|
+
if (lastAction.type === "request_phone") {
|
|
1682
|
+
setPaymentPhase("prompt_phone");
|
|
1683
|
+
} else if (lastAction.type === "awaiting_payment") {
|
|
1684
|
+
setMerchantRef((_a2 = lastAction.merchantReference) != null ? _a2 : null);
|
|
1685
|
+
setPaymentPhase("awaiting");
|
|
1686
|
+
}
|
|
1687
|
+
}, [lastAction]);
|
|
1688
|
+
const handlePhoneSubmit = async () => {
|
|
1689
|
+
if (!phoneInput.trim()) return;
|
|
1690
|
+
try {
|
|
1691
|
+
const res = await client.api.initiatePayment(phoneInput);
|
|
1692
|
+
setMerchantRef(res.merchantReference);
|
|
1693
|
+
setPaymentPhase("awaiting");
|
|
1694
|
+
} catch (e) {
|
|
1695
|
+
console.error("[Huskel] initiatePayment error", e);
|
|
1696
|
+
setPaymentPhase("failed");
|
|
1697
|
+
}
|
|
1698
|
+
};
|
|
1699
|
+
(0, import_react12.useEffect)(() => {
|
|
1564
1700
|
var _a2;
|
|
1565
1701
|
(_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1566
1702
|
}, [messages, loading, selectedProduct]);
|
|
1567
|
-
(0,
|
|
1703
|
+
(0, import_react12.useEffect)(() => {
|
|
1568
1704
|
const h = (e) => {
|
|
1569
1705
|
if (e.key === "Escape") onClose();
|
|
1570
1706
|
};
|
|
@@ -1680,6 +1816,39 @@ function ChatModal({
|
|
|
1680
1816
|
] })
|
|
1681
1817
|
] }),
|
|
1682
1818
|
error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-error", children: error }),
|
|
1819
|
+
paymentPhase === "prompt_phone" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1820
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-payment-icon", children: "\u{1F4F1}" }),
|
|
1821
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "hsk-cb-payment-label", children: "Enter your M-Pesa number to pay" }),
|
|
1822
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1823
|
+
"input",
|
|
1824
|
+
{
|
|
1825
|
+
type: "tel",
|
|
1826
|
+
className: "hsk-cb-phone-input",
|
|
1827
|
+
placeholder: "e.g. 0712 345 678",
|
|
1828
|
+
value: phoneInput,
|
|
1829
|
+
onChange: (e) => setPhoneInput(e.target.value),
|
|
1830
|
+
onKeyDown: (e) => e.key === "Enter" && handlePhoneSubmit()
|
|
1831
|
+
}
|
|
1832
|
+
),
|
|
1833
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "hsk-cb-pay-submit", onClick: handlePhoneSubmit, children: "Send STK Push \u2192" })
|
|
1834
|
+
] }),
|
|
1835
|
+
paymentPhase === "awaiting" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-payment-icon", style: { fontSize: "2rem" }, children: "\u23F3" }),
|
|
1837
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "hsk-cb-payment-label", style: { fontWeight: 600 }, children: "Check your phone" }),
|
|
1838
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { fontSize: "0.8rem", opacity: 0.6 }, children: "An M-Pesa STK push has been sent. Enter your PIN to complete payment." })
|
|
1839
|
+
] }),
|
|
1840
|
+
paymentPhase === "done" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1841
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-payment-icon", style: { color: "#22c55e", fontSize: "2rem" }, children: "\u2705" }),
|
|
1842
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "hsk-cb-payment-label", children: "Payment complete! Thank you." })
|
|
1843
|
+
] }),
|
|
1844
|
+
paymentPhase === "failed" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1845
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-payment-icon", style: { color: "#ef4444", fontSize: "2rem" }, children: "\u274C" }),
|
|
1846
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "hsk-cb-payment-label", children: "Payment failed or timed out." }),
|
|
1847
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "hsk-cb-pay-submit", onClick: () => {
|
|
1848
|
+
setPaymentPhase("idle");
|
|
1849
|
+
setMerchantRef(null);
|
|
1850
|
+
}, children: "Try again" })
|
|
1851
|
+
] }),
|
|
1683
1852
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: bottomRef, style: { height: 1 } })
|
|
1684
1853
|
] }),
|
|
1685
1854
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-input-wrap", children: [
|
|
@@ -1728,9 +1897,9 @@ function AIChatButton({
|
|
|
1728
1897
|
theme,
|
|
1729
1898
|
classNames = {}
|
|
1730
1899
|
}) {
|
|
1731
|
-
const [open, setOpen] = (0,
|
|
1732
|
-
const [mounted, setMounted] = (0,
|
|
1733
|
-
(0,
|
|
1900
|
+
const [open, setOpen] = (0, import_react12.useState)(false);
|
|
1901
|
+
const [mounted, setMounted] = (0, import_react12.useState)(false);
|
|
1902
|
+
(0, import_react12.useEffect)(() => {
|
|
1734
1903
|
setMounted(true);
|
|
1735
1904
|
}, []);
|
|
1736
1905
|
const customStyles = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, (theme == null ? void 0 : theme.primaryColor) && { "--hsk-primary": theme.primaryColor }), (theme == null ? void 0 : theme.backgroundColor) && { "--hsk-bg": theme.backgroundColor }), (theme == null ? void 0 : theme.textColor) && { "--hsk-text": theme.textColor }), (theme == null ? void 0 : theme.fontFamily) && { "--hsk-font": theme.fontFamily }), (theme == null ? void 0 : theme.borderRadius) && { "--hsk-border-radius": theme.borderRadius });
|
|
@@ -1778,11 +1947,11 @@ function CartBadge({ className }) {
|
|
|
1778
1947
|
}
|
|
1779
1948
|
|
|
1780
1949
|
// src/components/CartDrawer.tsx
|
|
1781
|
-
var
|
|
1950
|
+
var import_react14 = require("react");
|
|
1782
1951
|
var import_react_dom4 = require("react-dom");
|
|
1783
1952
|
|
|
1784
1953
|
// src/components/CheckoutModal.tsx
|
|
1785
|
-
var
|
|
1954
|
+
var import_react13 = require("react");
|
|
1786
1955
|
var import_react_dom3 = require("react-dom");
|
|
1787
1956
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1788
1957
|
function CheckoutModal({
|
|
@@ -1794,11 +1963,11 @@ function CheckoutModal({
|
|
|
1794
1963
|
var _a, _b, _c, _d;
|
|
1795
1964
|
const { cart, loading: cartLoading } = useCart();
|
|
1796
1965
|
const client = useHuskelContext();
|
|
1797
|
-
const [config, setConfig] = (0,
|
|
1798
|
-
const [loading, setLoading] = (0,
|
|
1799
|
-
const [checkingOut, setCheckingOut] = (0,
|
|
1800
|
-
const [paymentSuccess, setPaymentSuccess] = (0,
|
|
1801
|
-
(0,
|
|
1966
|
+
const [config, setConfig] = (0, import_react13.useState)(null);
|
|
1967
|
+
const [loading, setLoading] = (0, import_react13.useState)(true);
|
|
1968
|
+
const [checkingOut, setCheckingOut] = (0, import_react13.useState)(false);
|
|
1969
|
+
const [paymentSuccess, setPaymentSuccess] = (0, import_react13.useState)(false);
|
|
1970
|
+
(0, import_react13.useEffect)(() => {
|
|
1802
1971
|
client.api.getCheckoutConfig().then((res) => setConfig(res.payment_methods)).catch((e) => console.error("[Huskel] Failed to fetch checkout config", e)).finally(() => setLoading(false));
|
|
1803
1972
|
}, [client]);
|
|
1804
1973
|
const handlePay = async (method) => {
|
|
@@ -1900,11 +2069,11 @@ function CartDrawer({
|
|
|
1900
2069
|
theme
|
|
1901
2070
|
}) {
|
|
1902
2071
|
const { cart, loading } = useCart();
|
|
1903
|
-
const [open, setOpen] = (0,
|
|
1904
|
-
const [showCheckout, setShowCheckout] = (0,
|
|
1905
|
-
const [mounted, setMounted] = (0,
|
|
2072
|
+
const [open, setOpen] = (0, import_react14.useState)(false);
|
|
2073
|
+
const [showCheckout, setShowCheckout] = (0, import_react14.useState)(false);
|
|
2074
|
+
const [mounted, setMounted] = (0, import_react14.useState)(false);
|
|
1906
2075
|
const client = useHuskelContext();
|
|
1907
|
-
(0,
|
|
2076
|
+
(0, import_react14.useEffect)(() => {
|
|
1908
2077
|
setMounted(true);
|
|
1909
2078
|
const handleTriggerCheckout = () => {
|
|
1910
2079
|
setShowCheckout(true);
|
|
@@ -1915,7 +2084,7 @@ function CartDrawer({
|
|
|
1915
2084
|
window.removeEventListener("huskel:trigger_checkout", handleTriggerCheckout);
|
|
1916
2085
|
};
|
|
1917
2086
|
}, []);
|
|
1918
|
-
(0,
|
|
2087
|
+
(0, import_react14.useEffect)(() => {
|
|
1919
2088
|
if (open) {
|
|
1920
2089
|
document.body.style.overflow = "hidden";
|
|
1921
2090
|
} else {
|
|
@@ -2034,8 +2203,10 @@ function CartDrawer({
|
|
|
2034
2203
|
useCart,
|
|
2035
2204
|
useChat,
|
|
2036
2205
|
useHuskel,
|
|
2206
|
+
useHuskelContext,
|
|
2037
2207
|
useIngest,
|
|
2038
2208
|
usePageIngest,
|
|
2209
|
+
usePaymentPolling,
|
|
2039
2210
|
useSearch
|
|
2040
2211
|
});
|
|
2041
2212
|
//# sourceMappingURL=index.js.map
|