@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.mjs
CHANGED
|
@@ -168,6 +168,32 @@ var HuskelAPI = class {
|
|
|
168
168
|
if (!res.ok) throw new Error("Failed to fetch checkout config");
|
|
169
169
|
return res.json();
|
|
170
170
|
}
|
|
171
|
+
async initiatePayment(phoneNumber, email, firstName, lastName) {
|
|
172
|
+
const res = await fetch(`${this.apiUrl}/payment/initiate`, {
|
|
173
|
+
method: "POST",
|
|
174
|
+
headers: this.buildHeaders(),
|
|
175
|
+
body: JSON.stringify({
|
|
176
|
+
siteId: this.siteId,
|
|
177
|
+
phoneNumber,
|
|
178
|
+
email,
|
|
179
|
+
firstName,
|
|
180
|
+
lastName
|
|
181
|
+
})
|
|
182
|
+
});
|
|
183
|
+
if (!res.ok) {
|
|
184
|
+
const errText = await res.text();
|
|
185
|
+
throw new Error("Failed to initiate payment: " + errText);
|
|
186
|
+
}
|
|
187
|
+
return res.json();
|
|
188
|
+
}
|
|
189
|
+
async getPaymentStatus(ref) {
|
|
190
|
+
const res = await fetch(`${this.apiUrl}/payment/status?ref=${ref}`, {
|
|
191
|
+
method: "GET",
|
|
192
|
+
headers: this.buildHeaders()
|
|
193
|
+
});
|
|
194
|
+
if (!res.ok) throw new Error("Failed to get payment status");
|
|
195
|
+
return res.json();
|
|
196
|
+
}
|
|
171
197
|
};
|
|
172
198
|
|
|
173
199
|
// src/client.ts
|
|
@@ -588,9 +614,10 @@ function useChat() {
|
|
|
588
614
|
const [sources, setSources] = useState3([]);
|
|
589
615
|
const [loading, setLoading] = useState3(false);
|
|
590
616
|
const [error, setError] = useState3(null);
|
|
617
|
+
const [lastAction, setLastAction] = useState3(null);
|
|
591
618
|
const abortRef = useRef5(null);
|
|
592
619
|
const send = useCallback3(async (query, displayQuery) => {
|
|
593
|
-
var _a, _b, _c, _d, _e;
|
|
620
|
+
var _a, _b, _c, _d, _e, _f;
|
|
594
621
|
if (!query.trim() || loading) return;
|
|
595
622
|
(_a = abortRef.current) == null ? void 0 : _a.abort();
|
|
596
623
|
abortRef.current = new AbortController();
|
|
@@ -621,6 +648,7 @@ function useChat() {
|
|
|
621
648
|
}
|
|
622
649
|
if (signal.aborted) return;
|
|
623
650
|
setSources((_b = res.sources) != null ? _b : []);
|
|
651
|
+
if (res.action) setLastAction(res.action);
|
|
624
652
|
if (((_c = res.action) == null ? void 0 : _c.type) === "add_to_cart" || res.checkout) {
|
|
625
653
|
if (typeof window !== "undefined") {
|
|
626
654
|
window.dispatchEvent(new CustomEvent("huskel:cart_updated", { detail: res.checkout }));
|
|
@@ -631,12 +659,17 @@ function useChat() {
|
|
|
631
659
|
window.dispatchEvent(new CustomEvent("huskel:trigger_checkout", { detail: res.checkout }));
|
|
632
660
|
}
|
|
633
661
|
}
|
|
662
|
+
if (((_e = res.action) == null ? void 0 : _e.type) === "awaiting_payment") {
|
|
663
|
+
if (typeof window !== "undefined") {
|
|
664
|
+
window.dispatchEvent(new CustomEvent("huskel:awaiting_payment", { detail: res.action }));
|
|
665
|
+
}
|
|
666
|
+
}
|
|
634
667
|
if (res.checkout && client.onCheckout) {
|
|
635
668
|
client.onCheckout(res.checkout);
|
|
636
669
|
}
|
|
637
670
|
} catch (e) {
|
|
638
671
|
if (signal.aborted) return;
|
|
639
|
-
let msg = (
|
|
672
|
+
let msg = (_f = e == null ? void 0 : e.message) != null ? _f : "Chat request failed";
|
|
640
673
|
try {
|
|
641
674
|
const parsed = JSON.parse(msg);
|
|
642
675
|
if (parsed && parsed.error) {
|
|
@@ -659,8 +692,9 @@ function useChat() {
|
|
|
659
692
|
setSources([]);
|
|
660
693
|
setError(null);
|
|
661
694
|
setLoading(false);
|
|
695
|
+
setLastAction(null);
|
|
662
696
|
}, []);
|
|
663
|
-
return { messages, sources, loading, error, send, reset };
|
|
697
|
+
return { messages, sources, loading, error, lastAction, send, reset };
|
|
664
698
|
}
|
|
665
699
|
|
|
666
700
|
// src/hooks/useCart.ts
|
|
@@ -699,8 +733,71 @@ function useCart() {
|
|
|
699
733
|
return { cart, loading, fetchCart };
|
|
700
734
|
}
|
|
701
735
|
|
|
702
|
-
// src/
|
|
736
|
+
// src/hooks/usePaymentPolling.ts
|
|
703
737
|
import { useState as useState5, useEffect as useEffect4, useRef as useRef6 } from "react";
|
|
738
|
+
function usePaymentPolling({
|
|
739
|
+
client,
|
|
740
|
+
merchantReference,
|
|
741
|
+
onSuccess,
|
|
742
|
+
onFailure,
|
|
743
|
+
intervalMs = 3e3,
|
|
744
|
+
timeoutMs = 3e5
|
|
745
|
+
// 5 minutes default
|
|
746
|
+
}) {
|
|
747
|
+
const [status, setStatus] = useState5("IDLE");
|
|
748
|
+
const [error, setError] = useState5(null);
|
|
749
|
+
const onSuccessRef = useRef6(onSuccess);
|
|
750
|
+
const onFailureRef = useRef6(onFailure);
|
|
751
|
+
useEffect4(() => {
|
|
752
|
+
onSuccessRef.current = onSuccess;
|
|
753
|
+
onFailureRef.current = onFailure;
|
|
754
|
+
}, [onSuccess, onFailure]);
|
|
755
|
+
useEffect4(() => {
|
|
756
|
+
if (!merchantReference) {
|
|
757
|
+
setStatus("IDLE");
|
|
758
|
+
setError(null);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
setStatus("PENDING");
|
|
762
|
+
setError(null);
|
|
763
|
+
const startTime = Date.now();
|
|
764
|
+
let timerId = null;
|
|
765
|
+
async function checkStatus() {
|
|
766
|
+
try {
|
|
767
|
+
if (Date.now() - startTime >= timeoutMs) {
|
|
768
|
+
setStatus("FAILED");
|
|
769
|
+
setError("Payment session timed out");
|
|
770
|
+
if (onFailureRef.current) onFailureRef.current("Payment session timed out");
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
const res = await client.getPaymentStatus(merchantReference);
|
|
774
|
+
if (res.status === "COMPLETED") {
|
|
775
|
+
setStatus("COMPLETED");
|
|
776
|
+
if (onSuccessRef.current) onSuccessRef.current();
|
|
777
|
+
} else if (res.status === "FAILED") {
|
|
778
|
+
setStatus("FAILED");
|
|
779
|
+
setError("Payment failed");
|
|
780
|
+
if (onFailureRef.current) onFailureRef.current("Payment failed");
|
|
781
|
+
} else {
|
|
782
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
783
|
+
}
|
|
784
|
+
} catch (err) {
|
|
785
|
+
console.error("[Huskel Polling Error]", err);
|
|
786
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
790
|
+
return () => {
|
|
791
|
+
if (timerId) {
|
|
792
|
+
clearTimeout(timerId);
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
}, [client, merchantReference, intervalMs, timeoutMs]);
|
|
796
|
+
return { status, error };
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// src/components/SearchBar.tsx
|
|
800
|
+
import { useState as useState6, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
704
801
|
|
|
705
802
|
// src/utils/cn.ts
|
|
706
803
|
import { clsx } from "clsx";
|
|
@@ -727,15 +824,15 @@ function SearchBar({
|
|
|
727
824
|
theme,
|
|
728
825
|
classNames = {}
|
|
729
826
|
}) {
|
|
730
|
-
const [query, setQuery] =
|
|
731
|
-
const [open, setOpen] =
|
|
732
|
-
const [isDebouncing, setIsDebouncing] =
|
|
827
|
+
const [query, setQuery] = useState6("");
|
|
828
|
+
const [open, setOpen] = useState6(false);
|
|
829
|
+
const [isDebouncing, setIsDebouncing] = useState6(false);
|
|
733
830
|
const { results, loading, search, clear } = useSearch();
|
|
734
831
|
const client = useHuskelContext();
|
|
735
|
-
const timer =
|
|
736
|
-
const wrap =
|
|
737
|
-
const ignoreNextQueryChange =
|
|
738
|
-
|
|
832
|
+
const timer = useRef7();
|
|
833
|
+
const wrap = useRef7(null);
|
|
834
|
+
const ignoreNextQueryChange = useRef7(false);
|
|
835
|
+
useEffect5(() => {
|
|
739
836
|
if (ignoreNextQueryChange.current) {
|
|
740
837
|
ignoreNextQueryChange.current = false;
|
|
741
838
|
return;
|
|
@@ -755,7 +852,7 @@ function SearchBar({
|
|
|
755
852
|
}, debounceMs);
|
|
756
853
|
return () => clearTimeout(timer.current);
|
|
757
854
|
}, [query]);
|
|
758
|
-
|
|
855
|
+
useEffect5(() => {
|
|
759
856
|
const h = (e) => {
|
|
760
857
|
if (wrap.current && !wrap.current.contains(e.target)) setOpen(false);
|
|
761
858
|
};
|
|
@@ -859,7 +956,7 @@ function SearchBar({
|
|
|
859
956
|
}
|
|
860
957
|
|
|
861
958
|
// src/components/Sparkle.tsx
|
|
862
|
-
import { useState as
|
|
959
|
+
import { useState as useState7, useEffect as useEffect6, useRef as useRef8 } from "react";
|
|
863
960
|
import { createPortal } from "react-dom";
|
|
864
961
|
|
|
865
962
|
// src/utils/markdown.tsx
|
|
@@ -991,14 +1088,14 @@ function SparkleModal({
|
|
|
991
1088
|
}) {
|
|
992
1089
|
var _a, _b, _c;
|
|
993
1090
|
const client = useHuskelContext();
|
|
994
|
-
const [fetchedProduct, setFetchedProduct] =
|
|
1091
|
+
const [fetchedProduct, setFetchedProduct] = useState7(null);
|
|
995
1092
|
const displayProduct = initialProduct || fetchedProduct;
|
|
996
1093
|
const { results, loading: searchLoading, search } = useSearch();
|
|
997
1094
|
const { messages, sources, loading: chatLoading, error: chatError, send } = useChat();
|
|
998
|
-
const [chatInput, setChatInput] =
|
|
999
|
-
const chatBottomRef =
|
|
1000
|
-
const chatTextareaRef =
|
|
1001
|
-
|
|
1095
|
+
const [chatInput, setChatInput] = useState7("");
|
|
1096
|
+
const chatBottomRef = useRef8(null);
|
|
1097
|
+
const chatTextareaRef = useRef8(null);
|
|
1098
|
+
useEffect6(() => {
|
|
1002
1099
|
if (!initialProduct && !fetchedProduct) {
|
|
1003
1100
|
client.api.searchVector(productName, 1).then((res) => {
|
|
1004
1101
|
if (res.results && res.results.length > 0) {
|
|
@@ -1008,17 +1105,17 @@ function SparkleModal({
|
|
|
1008
1105
|
}
|
|
1009
1106
|
search(productName, limit);
|
|
1010
1107
|
}, [productName, initialProduct, fetchedProduct, client, limit, search]);
|
|
1011
|
-
|
|
1108
|
+
useEffect6(() => {
|
|
1012
1109
|
if (results.length > 0) onResult == null ? void 0 : onResult(results);
|
|
1013
1110
|
}, [results, onResult]);
|
|
1014
|
-
|
|
1111
|
+
useEffect6(() => {
|
|
1015
1112
|
const h = (e) => {
|
|
1016
1113
|
if (e.key === "Escape") onClose();
|
|
1017
1114
|
};
|
|
1018
1115
|
document.addEventListener("keydown", h);
|
|
1019
1116
|
return () => document.removeEventListener("keydown", h);
|
|
1020
1117
|
}, [onClose]);
|
|
1021
|
-
|
|
1118
|
+
useEffect6(() => {
|
|
1022
1119
|
var _a2;
|
|
1023
1120
|
(_a2 = chatBottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1024
1121
|
}, [messages, chatLoading]);
|
|
@@ -1250,9 +1347,9 @@ function Sparkle({
|
|
|
1250
1347
|
classNames = {},
|
|
1251
1348
|
product
|
|
1252
1349
|
}) {
|
|
1253
|
-
const [open, setOpen] =
|
|
1254
|
-
const [mounted, setMounted] =
|
|
1255
|
-
|
|
1350
|
+
const [open, setOpen] = useState7(false);
|
|
1351
|
+
const [mounted, setMounted] = useState7(false);
|
|
1352
|
+
useEffect6(() => {
|
|
1256
1353
|
setMounted(true);
|
|
1257
1354
|
}, []);
|
|
1258
1355
|
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 });
|
|
@@ -1290,7 +1387,7 @@ function Sparkle({
|
|
|
1290
1387
|
}
|
|
1291
1388
|
|
|
1292
1389
|
// src/components/ChatWidget.tsx
|
|
1293
|
-
import { useState as
|
|
1390
|
+
import { useState as useState8, useRef as useRef9, useEffect as useEffect7 } from "react";
|
|
1294
1391
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1295
1392
|
var SparkleIcon2 = () => /* @__PURE__ */ jsx5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx5("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" }) });
|
|
1296
1393
|
var ArrowUpIcon2 = () => /* @__PURE__ */ jsxs3("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
@@ -1323,10 +1420,10 @@ function ChatWidget({
|
|
|
1323
1420
|
onSelectSource
|
|
1324
1421
|
}) {
|
|
1325
1422
|
const { messages, sources, loading, error, send, reset } = useChat();
|
|
1326
|
-
const [input, setInput] =
|
|
1327
|
-
const bottomRef =
|
|
1328
|
-
const textareaRef =
|
|
1329
|
-
|
|
1423
|
+
const [input, setInput] = useState8("");
|
|
1424
|
+
const bottomRef = useRef9(null);
|
|
1425
|
+
const textareaRef = useRef9(null);
|
|
1426
|
+
useEffect7(() => {
|
|
1330
1427
|
var _a;
|
|
1331
1428
|
(_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
1332
1429
|
}, [messages, loading]);
|
|
@@ -1423,7 +1520,7 @@ function ChatWidget({
|
|
|
1423
1520
|
}
|
|
1424
1521
|
|
|
1425
1522
|
// src/components/AIChatButton.tsx
|
|
1426
|
-
import { useState as
|
|
1523
|
+
import { useState as useState9, useEffect as useEffect8, useRef as useRef10, useCallback as useCallback5 } from "react";
|
|
1427
1524
|
import { createPortal as createPortal2 } from "react-dom";
|
|
1428
1525
|
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1429
1526
|
var SparkleIcon3 = ({ className }) => /* @__PURE__ */ jsx6("svg", { className, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx6("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" }) });
|
|
@@ -1443,15 +1540,15 @@ var DEFAULT_CHIPS = [
|
|
|
1443
1540
|
"Best laptop for students"
|
|
1444
1541
|
];
|
|
1445
1542
|
function SourcesCarousel({ sources, defaultCurrency, onSelectSource }) {
|
|
1446
|
-
const railRef =
|
|
1447
|
-
const [showNext, setShowNext] =
|
|
1543
|
+
const railRef = useRef10(null);
|
|
1544
|
+
const [showNext, setShowNext] = useState9(false);
|
|
1448
1545
|
const measure = useCallback5(() => {
|
|
1449
1546
|
const el = railRef.current;
|
|
1450
1547
|
if (!el) return;
|
|
1451
1548
|
const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 8;
|
|
1452
1549
|
setShowNext(el.scrollWidth > el.clientWidth + 4 && !atEnd);
|
|
1453
1550
|
}, []);
|
|
1454
|
-
|
|
1551
|
+
useEffect8(() => {
|
|
1455
1552
|
measure();
|
|
1456
1553
|
const el = railRef.current;
|
|
1457
1554
|
if (!el) return;
|
|
@@ -1516,16 +1613,53 @@ function ChatModal({
|
|
|
1516
1613
|
classNames = {}
|
|
1517
1614
|
}) {
|
|
1518
1615
|
var _a, _b;
|
|
1519
|
-
const
|
|
1520
|
-
const
|
|
1521
|
-
const [
|
|
1522
|
-
const
|
|
1523
|
-
const
|
|
1524
|
-
|
|
1616
|
+
const client = useHuskelContext();
|
|
1617
|
+
const { messages, sources, loading, error, lastAction, send, reset } = useChat();
|
|
1618
|
+
const [input, setInput] = useState9("");
|
|
1619
|
+
const [selectedProduct, setSelectedProduct] = useState9(null);
|
|
1620
|
+
const bottomRef = useRef10(null);
|
|
1621
|
+
const textareaRef = useRef10(null);
|
|
1622
|
+
const [phoneInput, setPhoneInput] = useState9("");
|
|
1623
|
+
const [merchantRef, setMerchantRef] = useState9(null);
|
|
1624
|
+
const [paymentPhase, setPaymentPhase] = useState9("idle");
|
|
1625
|
+
const { status: pollStatus } = usePaymentPolling({
|
|
1626
|
+
client: client.api,
|
|
1627
|
+
merchantReference: merchantRef,
|
|
1628
|
+
onSuccess: () => {
|
|
1629
|
+
setPaymentPhase("done");
|
|
1630
|
+
setMerchantRef(null);
|
|
1631
|
+
},
|
|
1632
|
+
onFailure: () => {
|
|
1633
|
+
setPaymentPhase("failed");
|
|
1634
|
+
setMerchantRef(null);
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
useEffect8(() => {
|
|
1638
|
+
var _a2;
|
|
1639
|
+
if (!lastAction) return;
|
|
1640
|
+
if (lastAction.type === "request_phone") {
|
|
1641
|
+
setPaymentPhase("prompt_phone");
|
|
1642
|
+
} else if (lastAction.type === "awaiting_payment") {
|
|
1643
|
+
setMerchantRef((_a2 = lastAction.merchantReference) != null ? _a2 : null);
|
|
1644
|
+
setPaymentPhase("awaiting");
|
|
1645
|
+
}
|
|
1646
|
+
}, [lastAction]);
|
|
1647
|
+
const handlePhoneSubmit = async () => {
|
|
1648
|
+
if (!phoneInput.trim()) return;
|
|
1649
|
+
try {
|
|
1650
|
+
const res = await client.api.initiatePayment(phoneInput);
|
|
1651
|
+
setMerchantRef(res.merchantReference);
|
|
1652
|
+
setPaymentPhase("awaiting");
|
|
1653
|
+
} catch (e) {
|
|
1654
|
+
console.error("[Huskel] initiatePayment error", e);
|
|
1655
|
+
setPaymentPhase("failed");
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
useEffect8(() => {
|
|
1525
1659
|
var _a2;
|
|
1526
1660
|
(_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1527
1661
|
}, [messages, loading, selectedProduct]);
|
|
1528
|
-
|
|
1662
|
+
useEffect8(() => {
|
|
1529
1663
|
const h = (e) => {
|
|
1530
1664
|
if (e.key === "Escape") onClose();
|
|
1531
1665
|
};
|
|
@@ -1641,6 +1775,39 @@ function ChatModal({
|
|
|
1641
1775
|
] })
|
|
1642
1776
|
] }),
|
|
1643
1777
|
error && /* @__PURE__ */ jsx6("div", { className: "hsk-cb-error", children: error }),
|
|
1778
|
+
paymentPhase === "prompt_phone" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1779
|
+
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-payment-icon", children: "\u{1F4F1}" }),
|
|
1780
|
+
/* @__PURE__ */ jsx6("p", { className: "hsk-cb-payment-label", children: "Enter your M-Pesa number to pay" }),
|
|
1781
|
+
/* @__PURE__ */ jsx6(
|
|
1782
|
+
"input",
|
|
1783
|
+
{
|
|
1784
|
+
type: "tel",
|
|
1785
|
+
className: "hsk-cb-phone-input",
|
|
1786
|
+
placeholder: "e.g. 0712 345 678",
|
|
1787
|
+
value: phoneInput,
|
|
1788
|
+
onChange: (e) => setPhoneInput(e.target.value),
|
|
1789
|
+
onKeyDown: (e) => e.key === "Enter" && handlePhoneSubmit()
|
|
1790
|
+
}
|
|
1791
|
+
),
|
|
1792
|
+
/* @__PURE__ */ jsx6("button", { className: "hsk-cb-pay-submit", onClick: handlePhoneSubmit, children: "Send STK Push \u2192" })
|
|
1793
|
+
] }),
|
|
1794
|
+
paymentPhase === "awaiting" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1795
|
+
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-payment-icon", style: { fontSize: "2rem" }, children: "\u23F3" }),
|
|
1796
|
+
/* @__PURE__ */ jsx6("p", { className: "hsk-cb-payment-label", style: { fontWeight: 600 }, children: "Check your phone" }),
|
|
1797
|
+
/* @__PURE__ */ jsx6("p", { style: { fontSize: "0.8rem", opacity: 0.6 }, children: "An M-Pesa STK push has been sent. Enter your PIN to complete payment." })
|
|
1798
|
+
] }),
|
|
1799
|
+
paymentPhase === "done" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1800
|
+
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-payment-icon", style: { color: "#22c55e", fontSize: "2rem" }, children: "\u2705" }),
|
|
1801
|
+
/* @__PURE__ */ jsx6("p", { className: "hsk-cb-payment-label", children: "Payment complete! Thank you." })
|
|
1802
|
+
] }),
|
|
1803
|
+
paymentPhase === "failed" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1804
|
+
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-payment-icon", style: { color: "#ef4444", fontSize: "2rem" }, children: "\u274C" }),
|
|
1805
|
+
/* @__PURE__ */ jsx6("p", { className: "hsk-cb-payment-label", children: "Payment failed or timed out." }),
|
|
1806
|
+
/* @__PURE__ */ jsx6("button", { className: "hsk-cb-pay-submit", onClick: () => {
|
|
1807
|
+
setPaymentPhase("idle");
|
|
1808
|
+
setMerchantRef(null);
|
|
1809
|
+
}, children: "Try again" })
|
|
1810
|
+
] }),
|
|
1644
1811
|
/* @__PURE__ */ jsx6("div", { ref: bottomRef, style: { height: 1 } })
|
|
1645
1812
|
] }),
|
|
1646
1813
|
/* @__PURE__ */ jsxs4("div", { className: "hsk-cb-input-wrap", children: [
|
|
@@ -1689,9 +1856,9 @@ function AIChatButton({
|
|
|
1689
1856
|
theme,
|
|
1690
1857
|
classNames = {}
|
|
1691
1858
|
}) {
|
|
1692
|
-
const [open, setOpen] =
|
|
1693
|
-
const [mounted, setMounted] =
|
|
1694
|
-
|
|
1859
|
+
const [open, setOpen] = useState9(false);
|
|
1860
|
+
const [mounted, setMounted] = useState9(false);
|
|
1861
|
+
useEffect8(() => {
|
|
1695
1862
|
setMounted(true);
|
|
1696
1863
|
}, []);
|
|
1697
1864
|
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 });
|
|
@@ -1739,11 +1906,11 @@ function CartBadge({ className }) {
|
|
|
1739
1906
|
}
|
|
1740
1907
|
|
|
1741
1908
|
// src/components/CartDrawer.tsx
|
|
1742
|
-
import { useState as
|
|
1909
|
+
import { useState as useState11, useEffect as useEffect10 } from "react";
|
|
1743
1910
|
import { createPortal as createPortal4 } from "react-dom";
|
|
1744
1911
|
|
|
1745
1912
|
// src/components/CheckoutModal.tsx
|
|
1746
|
-
import { useState as
|
|
1913
|
+
import { useState as useState10, useEffect as useEffect9 } from "react";
|
|
1747
1914
|
import { createPortal as createPortal3 } from "react-dom";
|
|
1748
1915
|
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1749
1916
|
function CheckoutModal({
|
|
@@ -1755,11 +1922,11 @@ function CheckoutModal({
|
|
|
1755
1922
|
var _a, _b, _c, _d;
|
|
1756
1923
|
const { cart, loading: cartLoading } = useCart();
|
|
1757
1924
|
const client = useHuskelContext();
|
|
1758
|
-
const [config, setConfig] =
|
|
1759
|
-
const [loading, setLoading] =
|
|
1760
|
-
const [checkingOut, setCheckingOut] =
|
|
1761
|
-
const [paymentSuccess, setPaymentSuccess] =
|
|
1762
|
-
|
|
1925
|
+
const [config, setConfig] = useState10(null);
|
|
1926
|
+
const [loading, setLoading] = useState10(true);
|
|
1927
|
+
const [checkingOut, setCheckingOut] = useState10(false);
|
|
1928
|
+
const [paymentSuccess, setPaymentSuccess] = useState10(false);
|
|
1929
|
+
useEffect9(() => {
|
|
1763
1930
|
client.api.getCheckoutConfig().then((res) => setConfig(res.payment_methods)).catch((e) => console.error("[Huskel] Failed to fetch checkout config", e)).finally(() => setLoading(false));
|
|
1764
1931
|
}, [client]);
|
|
1765
1932
|
const handlePay = async (method) => {
|
|
@@ -1861,11 +2028,11 @@ function CartDrawer({
|
|
|
1861
2028
|
theme
|
|
1862
2029
|
}) {
|
|
1863
2030
|
const { cart, loading } = useCart();
|
|
1864
|
-
const [open, setOpen] =
|
|
1865
|
-
const [showCheckout, setShowCheckout] =
|
|
1866
|
-
const [mounted, setMounted] =
|
|
2031
|
+
const [open, setOpen] = useState11(false);
|
|
2032
|
+
const [showCheckout, setShowCheckout] = useState11(false);
|
|
2033
|
+
const [mounted, setMounted] = useState11(false);
|
|
1867
2034
|
const client = useHuskelContext();
|
|
1868
|
-
|
|
2035
|
+
useEffect10(() => {
|
|
1869
2036
|
setMounted(true);
|
|
1870
2037
|
const handleTriggerCheckout = () => {
|
|
1871
2038
|
setShowCheckout(true);
|
|
@@ -1876,7 +2043,7 @@ function CartDrawer({
|
|
|
1876
2043
|
window.removeEventListener("huskel:trigger_checkout", handleTriggerCheckout);
|
|
1877
2044
|
};
|
|
1878
2045
|
}, []);
|
|
1879
|
-
|
|
2046
|
+
useEffect10(() => {
|
|
1880
2047
|
if (open) {
|
|
1881
2048
|
document.body.style.overflow = "hidden";
|
|
1882
2049
|
} else {
|
|
@@ -1994,8 +2161,10 @@ export {
|
|
|
1994
2161
|
useCart,
|
|
1995
2162
|
useChat,
|
|
1996
2163
|
useHuskel,
|
|
2164
|
+
useHuskelContext,
|
|
1997
2165
|
useIngest,
|
|
1998
2166
|
usePageIngest,
|
|
2167
|
+
usePaymentPolling,
|
|
1999
2168
|
useSearch
|
|
2000
2169
|
};
|
|
2001
2170
|
//# sourceMappingURL=index.mjs.map
|