@huskel/sdk 0.4.6 → 0.4.8
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 +531 -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 +464 -123
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +464 -125
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -56,6 +56,12 @@ var HuskelAPI = class {
|
|
|
56
56
|
if (sessionId) {
|
|
57
57
|
headers["X-Huskel-Session-Id"] = sessionId;
|
|
58
58
|
}
|
|
59
|
+
if (typeof window !== "undefined") {
|
|
60
|
+
const phone = localStorage.getItem("huskel_user_phone");
|
|
61
|
+
if (phone) {
|
|
62
|
+
headers["X-Huskel-Shopper-Phone"] = phone;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
59
65
|
const res = await fetch(url, {
|
|
60
66
|
method: "POST",
|
|
61
67
|
headers,
|
|
@@ -134,6 +140,12 @@ var HuskelAPI = class {
|
|
|
134
140
|
if (shopperId) headers["X-Huskel-Shopper-Id"] = shopperId;
|
|
135
141
|
const sessionId = (_b = this.getSessionId) == null ? void 0 : _b.call(this);
|
|
136
142
|
if (sessionId) headers["X-Huskel-Session-Id"] = sessionId;
|
|
143
|
+
if (typeof window !== "undefined") {
|
|
144
|
+
const phone = localStorage.getItem("huskel_user_phone");
|
|
145
|
+
if (phone) {
|
|
146
|
+
headers["X-Huskel-Shopper-Phone"] = phone;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
137
149
|
return headers;
|
|
138
150
|
}
|
|
139
151
|
async getCart() {
|
|
@@ -168,6 +180,32 @@ var HuskelAPI = class {
|
|
|
168
180
|
if (!res.ok) throw new Error("Failed to fetch checkout config");
|
|
169
181
|
return res.json();
|
|
170
182
|
}
|
|
183
|
+
async initiatePayment(phoneNumber, email, firstName, lastName) {
|
|
184
|
+
const res = await fetch(`${this.apiUrl}/payment/initiate`, {
|
|
185
|
+
method: "POST",
|
|
186
|
+
headers: this.buildHeaders(),
|
|
187
|
+
body: JSON.stringify({
|
|
188
|
+
siteId: this.siteId,
|
|
189
|
+
phoneNumber,
|
|
190
|
+
email,
|
|
191
|
+
firstName,
|
|
192
|
+
lastName
|
|
193
|
+
})
|
|
194
|
+
});
|
|
195
|
+
if (!res.ok) {
|
|
196
|
+
const errText = await res.text();
|
|
197
|
+
throw new Error("Failed to initiate payment: " + errText);
|
|
198
|
+
}
|
|
199
|
+
return res.json();
|
|
200
|
+
}
|
|
201
|
+
async getPaymentStatus(ref) {
|
|
202
|
+
const res = await fetch(`${this.apiUrl}/payment/status?ref=${ref}`, {
|
|
203
|
+
method: "GET",
|
|
204
|
+
headers: this.buildHeaders()
|
|
205
|
+
});
|
|
206
|
+
if (!res.ok) throw new Error("Failed to get payment status");
|
|
207
|
+
return res.json();
|
|
208
|
+
}
|
|
171
209
|
};
|
|
172
210
|
|
|
173
211
|
// src/client.ts
|
|
@@ -588,9 +626,10 @@ function useChat() {
|
|
|
588
626
|
const [sources, setSources] = useState3([]);
|
|
589
627
|
const [loading, setLoading] = useState3(false);
|
|
590
628
|
const [error, setError] = useState3(null);
|
|
629
|
+
const [lastAction, setLastAction] = useState3(null);
|
|
591
630
|
const abortRef = useRef5(null);
|
|
592
631
|
const send = useCallback3(async (query, displayQuery) => {
|
|
593
|
-
var _a, _b, _c, _d, _e;
|
|
632
|
+
var _a, _b, _c, _d, _e, _f;
|
|
594
633
|
if (!query.trim() || loading) return;
|
|
595
634
|
(_a = abortRef.current) == null ? void 0 : _a.abort();
|
|
596
635
|
abortRef.current = new AbortController();
|
|
@@ -621,6 +660,7 @@ function useChat() {
|
|
|
621
660
|
}
|
|
622
661
|
if (signal.aborted) return;
|
|
623
662
|
setSources((_b = res.sources) != null ? _b : []);
|
|
663
|
+
if (res.action) setLastAction(res.action);
|
|
624
664
|
if (((_c = res.action) == null ? void 0 : _c.type) === "add_to_cart" || res.checkout) {
|
|
625
665
|
if (typeof window !== "undefined") {
|
|
626
666
|
window.dispatchEvent(new CustomEvent("huskel:cart_updated", { detail: res.checkout }));
|
|
@@ -631,12 +671,17 @@ function useChat() {
|
|
|
631
671
|
window.dispatchEvent(new CustomEvent("huskel:trigger_checkout", { detail: res.checkout }));
|
|
632
672
|
}
|
|
633
673
|
}
|
|
674
|
+
if (((_e = res.action) == null ? void 0 : _e.type) === "awaiting_payment") {
|
|
675
|
+
if (typeof window !== "undefined") {
|
|
676
|
+
window.dispatchEvent(new CustomEvent("huskel:awaiting_payment", { detail: res.action }));
|
|
677
|
+
}
|
|
678
|
+
}
|
|
634
679
|
if (res.checkout && client.onCheckout) {
|
|
635
680
|
client.onCheckout(res.checkout);
|
|
636
681
|
}
|
|
637
682
|
} catch (e) {
|
|
638
683
|
if (signal.aborted) return;
|
|
639
|
-
let msg = (
|
|
684
|
+
let msg = (_f = e == null ? void 0 : e.message) != null ? _f : "Chat request failed";
|
|
640
685
|
try {
|
|
641
686
|
const parsed = JSON.parse(msg);
|
|
642
687
|
if (parsed && parsed.error) {
|
|
@@ -659,8 +704,9 @@ function useChat() {
|
|
|
659
704
|
setSources([]);
|
|
660
705
|
setError(null);
|
|
661
706
|
setLoading(false);
|
|
707
|
+
setLastAction(null);
|
|
662
708
|
}, []);
|
|
663
|
-
return { messages, sources, loading, error, send, reset };
|
|
709
|
+
return { messages, sources, loading, error, lastAction, send, reset };
|
|
664
710
|
}
|
|
665
711
|
|
|
666
712
|
// src/hooks/useCart.ts
|
|
@@ -699,8 +745,71 @@ function useCart() {
|
|
|
699
745
|
return { cart, loading, fetchCart };
|
|
700
746
|
}
|
|
701
747
|
|
|
702
|
-
// src/
|
|
748
|
+
// src/hooks/usePaymentPolling.ts
|
|
703
749
|
import { useState as useState5, useEffect as useEffect4, useRef as useRef6 } from "react";
|
|
750
|
+
function usePaymentPolling({
|
|
751
|
+
client,
|
|
752
|
+
merchantReference,
|
|
753
|
+
onSuccess,
|
|
754
|
+
onFailure,
|
|
755
|
+
intervalMs = 3e3,
|
|
756
|
+
timeoutMs = 3e5
|
|
757
|
+
// 5 minutes default
|
|
758
|
+
}) {
|
|
759
|
+
const [status, setStatus] = useState5("IDLE");
|
|
760
|
+
const [error, setError] = useState5(null);
|
|
761
|
+
const onSuccessRef = useRef6(onSuccess);
|
|
762
|
+
const onFailureRef = useRef6(onFailure);
|
|
763
|
+
useEffect4(() => {
|
|
764
|
+
onSuccessRef.current = onSuccess;
|
|
765
|
+
onFailureRef.current = onFailure;
|
|
766
|
+
}, [onSuccess, onFailure]);
|
|
767
|
+
useEffect4(() => {
|
|
768
|
+
if (!merchantReference) {
|
|
769
|
+
setStatus("IDLE");
|
|
770
|
+
setError(null);
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
setStatus("PENDING");
|
|
774
|
+
setError(null);
|
|
775
|
+
const startTime = Date.now();
|
|
776
|
+
let timerId = null;
|
|
777
|
+
async function checkStatus() {
|
|
778
|
+
try {
|
|
779
|
+
if (Date.now() - startTime >= timeoutMs) {
|
|
780
|
+
setStatus("FAILED");
|
|
781
|
+
setError("Payment session timed out");
|
|
782
|
+
if (onFailureRef.current) onFailureRef.current("Payment session timed out");
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const res = await client.getPaymentStatus(merchantReference);
|
|
786
|
+
if (res.status === "COMPLETED") {
|
|
787
|
+
setStatus("COMPLETED");
|
|
788
|
+
if (onSuccessRef.current) onSuccessRef.current();
|
|
789
|
+
} else if (res.status === "FAILED") {
|
|
790
|
+
setStatus("FAILED");
|
|
791
|
+
setError("Payment failed");
|
|
792
|
+
if (onFailureRef.current) onFailureRef.current("Payment failed");
|
|
793
|
+
} else {
|
|
794
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
795
|
+
}
|
|
796
|
+
} catch (err) {
|
|
797
|
+
console.error("[Huskel Polling Error]", err);
|
|
798
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
timerId = setTimeout(checkStatus, intervalMs);
|
|
802
|
+
return () => {
|
|
803
|
+
if (timerId) {
|
|
804
|
+
clearTimeout(timerId);
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
}, [client, merchantReference, intervalMs, timeoutMs]);
|
|
808
|
+
return { status, error };
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// src/components/SearchBar.tsx
|
|
812
|
+
import { useState as useState6, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
704
813
|
|
|
705
814
|
// src/utils/cn.ts
|
|
706
815
|
import { clsx } from "clsx";
|
|
@@ -727,15 +836,15 @@ function SearchBar({
|
|
|
727
836
|
theme,
|
|
728
837
|
classNames = {}
|
|
729
838
|
}) {
|
|
730
|
-
const [query, setQuery] =
|
|
731
|
-
const [open, setOpen] =
|
|
732
|
-
const [isDebouncing, setIsDebouncing] =
|
|
839
|
+
const [query, setQuery] = useState6("");
|
|
840
|
+
const [open, setOpen] = useState6(false);
|
|
841
|
+
const [isDebouncing, setIsDebouncing] = useState6(false);
|
|
733
842
|
const { results, loading, search, clear } = useSearch();
|
|
734
843
|
const client = useHuskelContext();
|
|
735
|
-
const timer =
|
|
736
|
-
const wrap =
|
|
737
|
-
const ignoreNextQueryChange =
|
|
738
|
-
|
|
844
|
+
const timer = useRef7();
|
|
845
|
+
const wrap = useRef7(null);
|
|
846
|
+
const ignoreNextQueryChange = useRef7(false);
|
|
847
|
+
useEffect5(() => {
|
|
739
848
|
if (ignoreNextQueryChange.current) {
|
|
740
849
|
ignoreNextQueryChange.current = false;
|
|
741
850
|
return;
|
|
@@ -755,7 +864,7 @@ function SearchBar({
|
|
|
755
864
|
}, debounceMs);
|
|
756
865
|
return () => clearTimeout(timer.current);
|
|
757
866
|
}, [query]);
|
|
758
|
-
|
|
867
|
+
useEffect5(() => {
|
|
759
868
|
const h = (e) => {
|
|
760
869
|
if (wrap.current && !wrap.current.contains(e.target)) setOpen(false);
|
|
761
870
|
};
|
|
@@ -859,7 +968,7 @@ function SearchBar({
|
|
|
859
968
|
}
|
|
860
969
|
|
|
861
970
|
// src/components/Sparkle.tsx
|
|
862
|
-
import { useState as
|
|
971
|
+
import { useState as useState7, useEffect as useEffect6, useRef as useRef8 } from "react";
|
|
863
972
|
import { createPortal } from "react-dom";
|
|
864
973
|
|
|
865
974
|
// src/utils/markdown.tsx
|
|
@@ -991,14 +1100,14 @@ function SparkleModal({
|
|
|
991
1100
|
}) {
|
|
992
1101
|
var _a, _b, _c;
|
|
993
1102
|
const client = useHuskelContext();
|
|
994
|
-
const [fetchedProduct, setFetchedProduct] =
|
|
1103
|
+
const [fetchedProduct, setFetchedProduct] = useState7(null);
|
|
995
1104
|
const displayProduct = initialProduct || fetchedProduct;
|
|
996
1105
|
const { results, loading: searchLoading, search } = useSearch();
|
|
997
1106
|
const { messages, sources, loading: chatLoading, error: chatError, send } = useChat();
|
|
998
|
-
const [chatInput, setChatInput] =
|
|
999
|
-
const chatBottomRef =
|
|
1000
|
-
const chatTextareaRef =
|
|
1001
|
-
|
|
1107
|
+
const [chatInput, setChatInput] = useState7("");
|
|
1108
|
+
const chatBottomRef = useRef8(null);
|
|
1109
|
+
const chatTextareaRef = useRef8(null);
|
|
1110
|
+
useEffect6(() => {
|
|
1002
1111
|
if (!initialProduct && !fetchedProduct) {
|
|
1003
1112
|
client.api.searchVector(productName, 1).then((res) => {
|
|
1004
1113
|
if (res.results && res.results.length > 0) {
|
|
@@ -1008,17 +1117,17 @@ function SparkleModal({
|
|
|
1008
1117
|
}
|
|
1009
1118
|
search(productName, limit);
|
|
1010
1119
|
}, [productName, initialProduct, fetchedProduct, client, limit, search]);
|
|
1011
|
-
|
|
1120
|
+
useEffect6(() => {
|
|
1012
1121
|
if (results.length > 0) onResult == null ? void 0 : onResult(results);
|
|
1013
1122
|
}, [results, onResult]);
|
|
1014
|
-
|
|
1123
|
+
useEffect6(() => {
|
|
1015
1124
|
const h = (e) => {
|
|
1016
1125
|
if (e.key === "Escape") onClose();
|
|
1017
1126
|
};
|
|
1018
1127
|
document.addEventListener("keydown", h);
|
|
1019
1128
|
return () => document.removeEventListener("keydown", h);
|
|
1020
1129
|
}, [onClose]);
|
|
1021
|
-
|
|
1130
|
+
useEffect6(() => {
|
|
1022
1131
|
var _a2;
|
|
1023
1132
|
(_a2 = chatBottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1024
1133
|
}, [messages, chatLoading]);
|
|
@@ -1250,9 +1359,9 @@ function Sparkle({
|
|
|
1250
1359
|
classNames = {},
|
|
1251
1360
|
product
|
|
1252
1361
|
}) {
|
|
1253
|
-
const [open, setOpen] =
|
|
1254
|
-
const [mounted, setMounted] =
|
|
1255
|
-
|
|
1362
|
+
const [open, setOpen] = useState7(false);
|
|
1363
|
+
const [mounted, setMounted] = useState7(false);
|
|
1364
|
+
useEffect6(() => {
|
|
1256
1365
|
setMounted(true);
|
|
1257
1366
|
}, []);
|
|
1258
1367
|
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 +1399,7 @@ function Sparkle({
|
|
|
1290
1399
|
}
|
|
1291
1400
|
|
|
1292
1401
|
// src/components/ChatWidget.tsx
|
|
1293
|
-
import { useState as
|
|
1402
|
+
import { useState as useState8, useRef as useRef9, useEffect as useEffect7 } from "react";
|
|
1294
1403
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1295
1404
|
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
1405
|
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 +1432,10 @@ function ChatWidget({
|
|
|
1323
1432
|
onSelectSource
|
|
1324
1433
|
}) {
|
|
1325
1434
|
const { messages, sources, loading, error, send, reset } = useChat();
|
|
1326
|
-
const [input, setInput] =
|
|
1327
|
-
const bottomRef =
|
|
1328
|
-
const textareaRef =
|
|
1329
|
-
|
|
1435
|
+
const [input, setInput] = useState8("");
|
|
1436
|
+
const bottomRef = useRef9(null);
|
|
1437
|
+
const textareaRef = useRef9(null);
|
|
1438
|
+
useEffect7(() => {
|
|
1330
1439
|
var _a;
|
|
1331
1440
|
(_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
1332
1441
|
}, [messages, loading]);
|
|
@@ -1423,7 +1532,7 @@ function ChatWidget({
|
|
|
1423
1532
|
}
|
|
1424
1533
|
|
|
1425
1534
|
// src/components/AIChatButton.tsx
|
|
1426
|
-
import { useState as
|
|
1535
|
+
import { useState as useState9, useEffect as useEffect8, useRef as useRef10, useCallback as useCallback5 } from "react";
|
|
1427
1536
|
import { createPortal as createPortal2 } from "react-dom";
|
|
1428
1537
|
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1429
1538
|
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 +1552,15 @@ var DEFAULT_CHIPS = [
|
|
|
1443
1552
|
"Best laptop for students"
|
|
1444
1553
|
];
|
|
1445
1554
|
function SourcesCarousel({ sources, defaultCurrency, onSelectSource }) {
|
|
1446
|
-
const railRef =
|
|
1447
|
-
const [showNext, setShowNext] =
|
|
1555
|
+
const railRef = useRef10(null);
|
|
1556
|
+
const [showNext, setShowNext] = useState9(false);
|
|
1448
1557
|
const measure = useCallback5(() => {
|
|
1449
1558
|
const el = railRef.current;
|
|
1450
1559
|
if (!el) return;
|
|
1451
1560
|
const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 8;
|
|
1452
1561
|
setShowNext(el.scrollWidth > el.clientWidth + 4 && !atEnd);
|
|
1453
1562
|
}, []);
|
|
1454
|
-
|
|
1563
|
+
useEffect8(() => {
|
|
1455
1564
|
measure();
|
|
1456
1565
|
const el = railRef.current;
|
|
1457
1566
|
if (!el) return;
|
|
@@ -1516,16 +1625,61 @@ function ChatModal({
|
|
|
1516
1625
|
classNames = {}
|
|
1517
1626
|
}) {
|
|
1518
1627
|
var _a, _b;
|
|
1519
|
-
const
|
|
1520
|
-
const
|
|
1521
|
-
const [
|
|
1522
|
-
const
|
|
1523
|
-
const
|
|
1524
|
-
|
|
1628
|
+
const client = useHuskelContext();
|
|
1629
|
+
const { messages, sources, loading, error, lastAction, send, reset } = useChat();
|
|
1630
|
+
const [input, setInput] = useState9("");
|
|
1631
|
+
const [selectedProduct, setSelectedProduct] = useState9(null);
|
|
1632
|
+
const bottomRef = useRef10(null);
|
|
1633
|
+
const textareaRef = useRef10(null);
|
|
1634
|
+
const [phoneInput, setPhoneInput] = useState9(() => {
|
|
1635
|
+
if (typeof window !== "undefined") {
|
|
1636
|
+
return localStorage.getItem("huskel_user_phone") || "";
|
|
1637
|
+
}
|
|
1638
|
+
return "";
|
|
1639
|
+
});
|
|
1640
|
+
const [merchantRef, setMerchantRef] = useState9(null);
|
|
1641
|
+
const [paymentPhase, setPaymentPhase] = useState9("idle");
|
|
1642
|
+
const { status: pollStatus } = usePaymentPolling({
|
|
1643
|
+
client: client.api,
|
|
1644
|
+
merchantReference: merchantRef,
|
|
1645
|
+
onSuccess: () => {
|
|
1646
|
+
setPaymentPhase("done");
|
|
1647
|
+
setMerchantRef(null);
|
|
1648
|
+
},
|
|
1649
|
+
onFailure: () => {
|
|
1650
|
+
setPaymentPhase("failed");
|
|
1651
|
+
setMerchantRef(null);
|
|
1652
|
+
}
|
|
1653
|
+
});
|
|
1654
|
+
useEffect8(() => {
|
|
1655
|
+
var _a2;
|
|
1656
|
+
if (!lastAction) return;
|
|
1657
|
+
if (lastAction.type === "request_phone") {
|
|
1658
|
+
setPaymentPhase("prompt_phone");
|
|
1659
|
+
} else if (lastAction.type === "awaiting_payment") {
|
|
1660
|
+
setMerchantRef((_a2 = lastAction.merchantReference) != null ? _a2 : null);
|
|
1661
|
+
setPaymentPhase("awaiting");
|
|
1662
|
+
}
|
|
1663
|
+
}, [lastAction]);
|
|
1664
|
+
const handlePhoneSubmit = async () => {
|
|
1665
|
+
if (!phoneInput.trim()) return;
|
|
1666
|
+
try {
|
|
1667
|
+
if (typeof window !== "undefined") {
|
|
1668
|
+
localStorage.setItem("huskel_user_phone", phoneInput.trim());
|
|
1669
|
+
}
|
|
1670
|
+
const res = await client.api.initiatePayment(phoneInput.trim());
|
|
1671
|
+
setMerchantRef(res.merchantReference);
|
|
1672
|
+
setPaymentPhase("awaiting");
|
|
1673
|
+
} catch (e) {
|
|
1674
|
+
console.error("[Huskel] initiatePayment error", e);
|
|
1675
|
+
setPaymentPhase("failed");
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
useEffect8(() => {
|
|
1525
1679
|
var _a2;
|
|
1526
1680
|
(_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1527
1681
|
}, [messages, loading, selectedProduct]);
|
|
1528
|
-
|
|
1682
|
+
useEffect8(() => {
|
|
1529
1683
|
const h = (e) => {
|
|
1530
1684
|
if (e.key === "Escape") onClose();
|
|
1531
1685
|
};
|
|
@@ -1603,7 +1757,7 @@ function ChatModal({
|
|
|
1603
1757
|
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx6(SparkleIcon3, {}) }),
|
|
1604
1758
|
/* @__PURE__ */ jsxs4("div", { className: "hsk-cb-ai-body", children: [
|
|
1605
1759
|
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-ai-text", children: renderMarkdown(msg.content) }),
|
|
1606
|
-
isLast && sources.length > 0 && /* @__PURE__ */ jsx6(
|
|
1760
|
+
isLast && sources.length > 0 && (lastAction == null ? void 0 : lastAction.type) !== "request_phone" && (lastAction == null ? void 0 : lastAction.type) !== "awaiting_payment" && (lastAction == null ? void 0 : lastAction.type) !== "checkout" && /* @__PURE__ */ jsx6(
|
|
1607
1761
|
SourcesCarousel,
|
|
1608
1762
|
{
|
|
1609
1763
|
sources,
|
|
@@ -1641,6 +1795,39 @@ function ChatModal({
|
|
|
1641
1795
|
] })
|
|
1642
1796
|
] }),
|
|
1643
1797
|
error && /* @__PURE__ */ jsx6("div", { className: "hsk-cb-error", children: error }),
|
|
1798
|
+
paymentPhase === "prompt_phone" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1799
|
+
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-payment-icon", children: "\u{1F4F1}" }),
|
|
1800
|
+
/* @__PURE__ */ jsx6("p", { className: "hsk-cb-payment-label", children: "Enter your M-Pesa number to pay" }),
|
|
1801
|
+
/* @__PURE__ */ jsx6(
|
|
1802
|
+
"input",
|
|
1803
|
+
{
|
|
1804
|
+
type: "tel",
|
|
1805
|
+
className: "hsk-cb-phone-input",
|
|
1806
|
+
placeholder: "e.g. 0712 345 678",
|
|
1807
|
+
value: phoneInput,
|
|
1808
|
+
onChange: (e) => setPhoneInput(e.target.value),
|
|
1809
|
+
onKeyDown: (e) => e.key === "Enter" && handlePhoneSubmit()
|
|
1810
|
+
}
|
|
1811
|
+
),
|
|
1812
|
+
/* @__PURE__ */ jsx6("button", { className: "hsk-cb-pay-submit", onClick: handlePhoneSubmit, children: "Send STK Push \u2192" })
|
|
1813
|
+
] }),
|
|
1814
|
+
paymentPhase === "awaiting" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1815
|
+
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-payment-icon", style: { fontSize: "2rem" }, children: "\u23F3" }),
|
|
1816
|
+
/* @__PURE__ */ jsx6("p", { className: "hsk-cb-payment-label", style: { fontWeight: 600 }, children: "Check your phone" }),
|
|
1817
|
+
/* @__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." })
|
|
1818
|
+
] }),
|
|
1819
|
+
paymentPhase === "done" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1820
|
+
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-payment-icon", style: { color: "#22c55e", fontSize: "2rem" }, children: "\u2705" }),
|
|
1821
|
+
/* @__PURE__ */ jsx6("p", { className: "hsk-cb-payment-label", children: "Payment complete! Thank you." })
|
|
1822
|
+
] }),
|
|
1823
|
+
paymentPhase === "failed" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
|
|
1824
|
+
/* @__PURE__ */ jsx6("div", { className: "hsk-cb-payment-icon", style: { color: "#ef4444", fontSize: "2rem" }, children: "\u274C" }),
|
|
1825
|
+
/* @__PURE__ */ jsx6("p", { className: "hsk-cb-payment-label", children: "Payment failed or timed out." }),
|
|
1826
|
+
/* @__PURE__ */ jsx6("button", { className: "hsk-cb-pay-submit", onClick: () => {
|
|
1827
|
+
setPaymentPhase("idle");
|
|
1828
|
+
setMerchantRef(null);
|
|
1829
|
+
}, children: "Try again" })
|
|
1830
|
+
] }),
|
|
1644
1831
|
/* @__PURE__ */ jsx6("div", { ref: bottomRef, style: { height: 1 } })
|
|
1645
1832
|
] }),
|
|
1646
1833
|
/* @__PURE__ */ jsxs4("div", { className: "hsk-cb-input-wrap", children: [
|
|
@@ -1689,9 +1876,9 @@ function AIChatButton({
|
|
|
1689
1876
|
theme,
|
|
1690
1877
|
classNames = {}
|
|
1691
1878
|
}) {
|
|
1692
|
-
const [open, setOpen] =
|
|
1693
|
-
const [mounted, setMounted] =
|
|
1694
|
-
|
|
1879
|
+
const [open, setOpen] = useState9(false);
|
|
1880
|
+
const [mounted, setMounted] = useState9(false);
|
|
1881
|
+
useEffect8(() => {
|
|
1695
1882
|
setMounted(true);
|
|
1696
1883
|
}, []);
|
|
1697
1884
|
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,111 +1926,255 @@ function CartBadge({ className }) {
|
|
|
1739
1926
|
}
|
|
1740
1927
|
|
|
1741
1928
|
// src/components/CartDrawer.tsx
|
|
1742
|
-
import { useState as
|
|
1929
|
+
import { useState as useState11, useEffect as useEffect10 } from "react";
|
|
1743
1930
|
import { createPortal as createPortal4 } from "react-dom";
|
|
1744
1931
|
|
|
1745
1932
|
// src/components/CheckoutModal.tsx
|
|
1746
|
-
import { useState as
|
|
1933
|
+
import { useState as useState10, useEffect as useEffect9 } from "react";
|
|
1747
1934
|
import { createPortal as createPortal3 } from "react-dom";
|
|
1748
|
-
import {
|
|
1935
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1749
1936
|
function CheckoutModal({
|
|
1750
1937
|
onClose,
|
|
1751
1938
|
theme,
|
|
1752
1939
|
customStyles,
|
|
1753
1940
|
hskThemeAttr
|
|
1754
1941
|
}) {
|
|
1755
|
-
var _a, _b, _c, _d;
|
|
1756
1942
|
const { cart, loading: cartLoading } = useCart();
|
|
1757
1943
|
const client = useHuskelContext();
|
|
1758
|
-
const [config, setConfig] =
|
|
1759
|
-
const [
|
|
1760
|
-
const [
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1944
|
+
const [config, setConfig] = useState10(null);
|
|
1945
|
+
const [loadingConfig, setLoadingConfig] = useState10(true);
|
|
1946
|
+
const [phone, setPhone] = useState10(() => {
|
|
1947
|
+
if (typeof window !== "undefined") {
|
|
1948
|
+
return localStorage.getItem("huskel_user_phone") || "";
|
|
1949
|
+
}
|
|
1950
|
+
return "";
|
|
1951
|
+
});
|
|
1952
|
+
const [email, setEmail] = useState10(() => {
|
|
1953
|
+
if (typeof window !== "undefined") {
|
|
1954
|
+
return localStorage.getItem("huskel_user_email") || "";
|
|
1955
|
+
}
|
|
1956
|
+
return "";
|
|
1957
|
+
});
|
|
1958
|
+
const [firstName, setFirstName] = useState10(() => {
|
|
1959
|
+
if (typeof window !== "undefined") {
|
|
1960
|
+
return localStorage.getItem("huskel_user_firstname") || "";
|
|
1961
|
+
}
|
|
1962
|
+
return "";
|
|
1963
|
+
});
|
|
1964
|
+
const [lastName, setLastName] = useState10(() => {
|
|
1965
|
+
if (typeof window !== "undefined") {
|
|
1966
|
+
return localStorage.getItem("huskel_user_lastname") || "";
|
|
1967
|
+
}
|
|
1968
|
+
return "";
|
|
1969
|
+
});
|
|
1970
|
+
const [phase, setPhase] = useState10("idle");
|
|
1971
|
+
const [merchantRef, setMerchantRef] = useState10(null);
|
|
1972
|
+
const [payError, setPayError] = useState10(null);
|
|
1973
|
+
const {} = usePaymentPolling({
|
|
1974
|
+
client: client.api,
|
|
1975
|
+
merchantReference: merchantRef,
|
|
1976
|
+
onSuccess: () => {
|
|
1977
|
+
setPhase("done");
|
|
1978
|
+
setMerchantRef(null);
|
|
1979
|
+
},
|
|
1980
|
+
onFailure: () => {
|
|
1981
|
+
setPhase("failed");
|
|
1982
|
+
setPayError("Payment failed or timed out. Please try again.");
|
|
1983
|
+
setMerchantRef(null);
|
|
1984
|
+
}
|
|
1985
|
+
});
|
|
1986
|
+
useEffect9(() => {
|
|
1987
|
+
client.api.getCheckoutConfig().then((res) => setConfig(res.payment_methods)).catch(() => {
|
|
1988
|
+
}).finally(() => setLoadingConfig(false));
|
|
1764
1989
|
}, [client]);
|
|
1765
|
-
const
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1990
|
+
const hasPaymentMethods = config && Object.values(config).some((m) => m.enabled);
|
|
1991
|
+
const handlePay = async (e) => {
|
|
1992
|
+
e.preventDefault();
|
|
1993
|
+
if (!phone.trim()) {
|
|
1994
|
+
setPayError("Phone number is required.");
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
setPayError(null);
|
|
1998
|
+
setPhase("awaiting");
|
|
1999
|
+
try {
|
|
2000
|
+
if (typeof window !== "undefined") {
|
|
2001
|
+
localStorage.setItem("huskel_user_phone", phone.trim());
|
|
2002
|
+
localStorage.setItem("huskel_user_email", email.trim());
|
|
2003
|
+
localStorage.setItem("huskel_user_firstname", firstName.trim());
|
|
2004
|
+
localStorage.setItem("huskel_user_lastname", lastName.trim());
|
|
1780
2005
|
}
|
|
1781
|
-
|
|
2006
|
+
const res = await client.api.initiatePayment(phone.trim(), email, firstName, lastName);
|
|
2007
|
+
if (res == null ? void 0 : res.merchantReference) {
|
|
2008
|
+
setMerchantRef(res.merchantReference);
|
|
2009
|
+
} else {
|
|
2010
|
+
throw new Error("No merchant reference returned.");
|
|
2011
|
+
}
|
|
2012
|
+
} catch (err) {
|
|
2013
|
+
setPhase("failed");
|
|
2014
|
+
setPayError(err.message || "Could not connect to payment processor.");
|
|
2015
|
+
}
|
|
1782
2016
|
};
|
|
1783
|
-
const
|
|
2017
|
+
const currency = (cart == null ? void 0 : cart.currency) || "KES";
|
|
2018
|
+
const total = (cart == null ? void 0 : cart.total) || 0;
|
|
2019
|
+
const backdropStyle = __spreadProps(__spreadValues({}, customStyles), { fontSize: "15px", fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif', zIndex: 999999 });
|
|
1784
2020
|
return createPortal3(
|
|
1785
2021
|
/* @__PURE__ */ jsx8(
|
|
1786
2022
|
"div",
|
|
1787
2023
|
{
|
|
1788
|
-
className: "hsk-
|
|
1789
|
-
style:
|
|
2024
|
+
className: "hsk-checkout-backdrop-full",
|
|
2025
|
+
style: backdropStyle,
|
|
1790
2026
|
"data-hsk-theme": hskThemeAttr,
|
|
1791
|
-
onClick: onClose,
|
|
1792
2027
|
children: /* @__PURE__ */ jsxs5(
|
|
1793
2028
|
"div",
|
|
1794
2029
|
{
|
|
1795
|
-
className: "hsk-checkout-modal",
|
|
2030
|
+
className: "hsk-checkout-modal-full",
|
|
1796
2031
|
style: customStyles,
|
|
1797
2032
|
"data-hsk-theme": hskThemeAttr,
|
|
1798
|
-
onClick: (e) => e.stopPropagation(),
|
|
1799
2033
|
children: [
|
|
1800
|
-
/* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-
|
|
1801
|
-
/* @__PURE__ */
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
/* @__PURE__ */ jsx8("polyline", { points: "22 4 12 14.01 9 11.01" })
|
|
2034
|
+
/* @__PURE__ */ jsx8("div", { className: "hsk-checkout-panel-left", children: /* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-left-content", children: [
|
|
2035
|
+
/* @__PURE__ */ jsxs5("button", { onClick: onClose, className: "hsk-checkout-back-btn", disabled: phase !== "idle", children: [
|
|
2036
|
+
/* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2037
|
+
/* @__PURE__ */ jsx8("line", { x1: "19", y1: "12", x2: "5", y2: "12" }),
|
|
2038
|
+
/* @__PURE__ */ jsx8("polyline", { points: "12 19 5 12 12 5" })
|
|
2039
|
+
] }),
|
|
2040
|
+
"Back to store"
|
|
1808
2041
|
] }),
|
|
1809
|
-
/* @__PURE__ */ jsx8("
|
|
1810
|
-
/* @__PURE__ */
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
/* @__PURE__ */ jsxs5("span", { children: [
|
|
1817
|
-
item.quantity,
|
|
1818
|
-
"x ",
|
|
1819
|
-
item.name
|
|
1820
|
-
] }),
|
|
1821
|
-
/* @__PURE__ */ jsxs5("span", { children: [
|
|
1822
|
-
item.currency,
|
|
1823
|
-
" ",
|
|
1824
|
-
(item.price_numeric * item.quantity).toLocaleString(void 0, { minimumFractionDigits: 2 })
|
|
1825
|
-
] })
|
|
1826
|
-
] }, item.id)) }),
|
|
1827
|
-
/* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-total", children: [
|
|
1828
|
-
/* @__PURE__ */ jsx8("span", { children: "Total" }),
|
|
1829
|
-
/* @__PURE__ */ jsxs5("span", { children: [
|
|
1830
|
-
cart.currency,
|
|
1831
|
-
" ",
|
|
1832
|
-
cart.total.toLocaleString(void 0, { minimumFractionDigits: 2 })
|
|
1833
|
-
] })
|
|
1834
|
-
] })
|
|
2042
|
+
/* @__PURE__ */ jsx8("div", { className: "hsk-checkout-store-info", children: /* @__PURE__ */ jsx8("h2", { children: "Secure Checkout" }) }),
|
|
2043
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-amount-due", children: [
|
|
2044
|
+
/* @__PURE__ */ jsx8("span", { className: "hsk-checkout-label-muted", children: "Pay total" }),
|
|
2045
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-grand-total", children: [
|
|
2046
|
+
currency,
|
|
2047
|
+
" ",
|
|
2048
|
+
total.toLocaleString(void 0, { minimumFractionDigits: 2 })
|
|
1835
2049
|
] })
|
|
1836
2050
|
] }),
|
|
1837
|
-
/* @__PURE__ */
|
|
1838
|
-
/* @__PURE__ */
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
2051
|
+
cartLoading || !cart ? /* @__PURE__ */ jsx8("p", { className: "hsk-cart-loading", children: "Loading order..." }) : /* @__PURE__ */ jsx8("div", { className: "hsk-checkout-items-list-wrap", children: /* @__PURE__ */ jsx8("ul", { className: "hsk-checkout-items-list", children: cart.items.map((item) => /* @__PURE__ */ jsxs5("li", { className: "hsk-checkout-item-row", children: [
|
|
2052
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-item-img-container", children: [
|
|
2053
|
+
item.image ? /* @__PURE__ */ jsx8("img", { src: item.image, alt: item.name, className: "hsk-checkout-item-img" }) : /* @__PURE__ */ jsx8("div", { className: "hsk-checkout-item-img-placeholder", children: "\u{1F6D2}" }),
|
|
2054
|
+
/* @__PURE__ */ jsx8("span", { className: "hsk-checkout-item-qty-badge", children: item.quantity })
|
|
2055
|
+
] }),
|
|
2056
|
+
/* @__PURE__ */ jsx8("div", { className: "hsk-checkout-item-details", children: /* @__PURE__ */ jsx8("span", { className: "hsk-checkout-item-name", children: item.name }) }),
|
|
2057
|
+
/* @__PURE__ */ jsxs5("span", { className: "hsk-checkout-item-price", children: [
|
|
2058
|
+
item.currency,
|
|
2059
|
+
" ",
|
|
2060
|
+
(item.price_numeric * item.quantity).toLocaleString(void 0, { minimumFractionDigits: 2 })
|
|
1844
2061
|
] })
|
|
2062
|
+
] }, item.id)) }) })
|
|
2063
|
+
] }) }),
|
|
2064
|
+
/* @__PURE__ */ jsx8("div", { className: "hsk-checkout-panel-right", children: /* @__PURE__ */ jsx8("div", { className: "hsk-checkout-right-content", children: phase === "done" ? /* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-status-card success", children: [
|
|
2065
|
+
/* @__PURE__ */ jsx8("div", { className: "hsk-status-icon-wrap success", children: "\u2705" }),
|
|
2066
|
+
/* @__PURE__ */ jsx8("h3", { children: "Payment Successful!" }),
|
|
2067
|
+
/* @__PURE__ */ jsx8("p", { children: "Your transaction has been confirmed successfully. Thank you for your order!" }),
|
|
2068
|
+
/* @__PURE__ */ jsx8("button", { onClick: onClose, className: "hsk-pay-btn hsk-btn-primary", style: { marginTop: "1.5rem" }, children: "Continue Shopping" })
|
|
2069
|
+
] }) : phase === "awaiting" ? /* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-status-card awaiting", children: [
|
|
2070
|
+
/* @__PURE__ */ jsx8("div", { className: "hsk-status-spinner-wrap", children: /* @__PURE__ */ jsx8("div", { className: "hsk-status-spinner" }) }),
|
|
2071
|
+
/* @__PURE__ */ jsx8("h3", { children: "Confirm payment on your phone" }),
|
|
2072
|
+
/* @__PURE__ */ jsxs5("p", { children: [
|
|
2073
|
+
"We've sent an M-Pesa STK push prompt to ",
|
|
2074
|
+
/* @__PURE__ */ jsxs5("strong", { children: [
|
|
2075
|
+
"254",
|
|
2076
|
+
phone
|
|
2077
|
+
] }),
|
|
2078
|
+
"."
|
|
2079
|
+
] }),
|
|
2080
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-stk-instructions", children: [
|
|
2081
|
+
/* @__PURE__ */ jsx8("p", { children: "1. Check your phone lockscreen for the M-Pesa prompt." }),
|
|
2082
|
+
/* @__PURE__ */ jsx8("p", { children: "2. Enter your M-Pesa PIN and press OK." }),
|
|
2083
|
+
/* @__PURE__ */ jsx8("p", { children: "3. Wait here; this page will automatically redirect once confirmed." })
|
|
2084
|
+
] }),
|
|
2085
|
+
/* @__PURE__ */ jsx8(
|
|
2086
|
+
"button",
|
|
2087
|
+
{
|
|
2088
|
+
onClick: () => {
|
|
2089
|
+
setPhase("idle");
|
|
2090
|
+
setMerchantRef(null);
|
|
2091
|
+
},
|
|
2092
|
+
className: "hsk-checkout-cancel-btn",
|
|
2093
|
+
children: "Cancel and change phone number"
|
|
2094
|
+
}
|
|
2095
|
+
)
|
|
2096
|
+
] }) : phase === "failed" ? /* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-status-card failed", children: [
|
|
2097
|
+
/* @__PURE__ */ jsx8("div", { className: "hsk-status-icon-wrap failed", children: "\u274C" }),
|
|
2098
|
+
/* @__PURE__ */ jsx8("h3", { children: "Payment failed or timed out" }),
|
|
2099
|
+
/* @__PURE__ */ jsx8("p", { className: "hsk-checkout-error-text", children: payError || "Could not verify M-Pesa transaction." }),
|
|
2100
|
+
/* @__PURE__ */ jsx8("button", { onClick: () => {
|
|
2101
|
+
setPhase("idle");
|
|
2102
|
+
setPayError(null);
|
|
2103
|
+
}, className: "hsk-pay-btn hsk-btn-primary", style: { marginTop: "1.5rem" }, children: "Try Again" })
|
|
2104
|
+
] }) : /* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-payment-form-wrap", children: [
|
|
2105
|
+
/* @__PURE__ */ jsx8("h3", { className: "hsk-checkout-section-title", children: "Payment details" }),
|
|
2106
|
+
loadingConfig ? /* @__PURE__ */ jsx8("p", { className: "hsk-cart-loading", children: "Loading payment configuration..." }) : !hasPaymentMethods ? /* @__PURE__ */ jsx8("p", { className: "hsk-checkout-error", children: "No payment methods configured for this store." }) : /* @__PURE__ */ jsxs5("form", { onSubmit: handlePay, className: "hsk-stripe-checkout-form", children: [
|
|
2107
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-form-group", children: [
|
|
2108
|
+
/* @__PURE__ */ jsx8("label", { className: "hsk-form-label", children: "M-Pesa Mobile Number" }),
|
|
2109
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-phone-input-container", children: [
|
|
2110
|
+
/* @__PURE__ */ jsx8("span", { className: "hsk-phone-prefix", children: "254" }),
|
|
2111
|
+
/* @__PURE__ */ jsx8(
|
|
2112
|
+
"input",
|
|
2113
|
+
{
|
|
2114
|
+
type: "tel",
|
|
2115
|
+
required: true,
|
|
2116
|
+
placeholder: "712345678",
|
|
2117
|
+
pattern: "[0-9]{9}",
|
|
2118
|
+
maxLength: 9,
|
|
2119
|
+
value: phone,
|
|
2120
|
+
onChange: (e) => setPhone(e.target.value.replace(/\D/g, "")),
|
|
2121
|
+
className: "hsk-phone-input-field"
|
|
2122
|
+
}
|
|
2123
|
+
)
|
|
2124
|
+
] }),
|
|
2125
|
+
/* @__PURE__ */ jsx8("span", { className: "hsk-form-hint", children: "Enter your 9-digit number (e.g. 712345678)" })
|
|
2126
|
+
] }),
|
|
2127
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-form-group", children: [
|
|
2128
|
+
/* @__PURE__ */ jsx8("label", { className: "hsk-form-label", children: "Email address" }),
|
|
2129
|
+
/* @__PURE__ */ jsx8(
|
|
2130
|
+
"input",
|
|
2131
|
+
{
|
|
2132
|
+
type: "email",
|
|
2133
|
+
placeholder: "john.doe@example.com",
|
|
2134
|
+
value: email,
|
|
2135
|
+
onChange: (e) => setEmail(e.target.value),
|
|
2136
|
+
className: "hsk-form-input"
|
|
2137
|
+
}
|
|
2138
|
+
)
|
|
2139
|
+
] }),
|
|
2140
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-form-row", children: [
|
|
2141
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-form-group", children: [
|
|
2142
|
+
/* @__PURE__ */ jsx8("label", { className: "hsk-form-label", children: "First Name" }),
|
|
2143
|
+
/* @__PURE__ */ jsx8(
|
|
2144
|
+
"input",
|
|
2145
|
+
{
|
|
2146
|
+
type: "text",
|
|
2147
|
+
placeholder: "John",
|
|
2148
|
+
value: firstName,
|
|
2149
|
+
onChange: (e) => setFirstName(e.target.value),
|
|
2150
|
+
className: "hsk-form-input"
|
|
2151
|
+
}
|
|
2152
|
+
)
|
|
2153
|
+
] }),
|
|
2154
|
+
/* @__PURE__ */ jsxs5("div", { className: "hsk-form-group", children: [
|
|
2155
|
+
/* @__PURE__ */ jsx8("label", { className: "hsk-form-label", children: "Last Name" }),
|
|
2156
|
+
/* @__PURE__ */ jsx8(
|
|
2157
|
+
"input",
|
|
2158
|
+
{
|
|
2159
|
+
type: "text",
|
|
2160
|
+
placeholder: "Doe",
|
|
2161
|
+
value: lastName,
|
|
2162
|
+
onChange: (e) => setLastName(e.target.value),
|
|
2163
|
+
className: "hsk-form-input"
|
|
2164
|
+
}
|
|
2165
|
+
)
|
|
2166
|
+
] })
|
|
2167
|
+
] }),
|
|
2168
|
+
payError && /* @__PURE__ */ jsx8("div", { className: "hsk-form-error-banner", children: payError }),
|
|
2169
|
+
/* @__PURE__ */ jsxs5("button", { type: "submit", className: "hsk-checkout-submit-btn", children: [
|
|
2170
|
+
"Pay ",
|
|
2171
|
+
currency,
|
|
2172
|
+
" ",
|
|
2173
|
+
total.toLocaleString()
|
|
2174
|
+
] }),
|
|
2175
|
+
/* @__PURE__ */ jsx8("div", { className: "hsk-checkout-footer-brand", children: /* @__PURE__ */ jsx8("span", { children: "Powered by Huskel AI" }) })
|
|
1845
2176
|
] })
|
|
1846
|
-
] }) })
|
|
2177
|
+
] }) }) })
|
|
1847
2178
|
]
|
|
1848
2179
|
}
|
|
1849
2180
|
)
|
|
@@ -1854,18 +2185,18 @@ function CheckoutModal({
|
|
|
1854
2185
|
}
|
|
1855
2186
|
|
|
1856
2187
|
// src/components/CartDrawer.tsx
|
|
1857
|
-
import { Fragment as
|
|
2188
|
+
import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1858
2189
|
function CartDrawer({
|
|
1859
2190
|
trigger,
|
|
1860
2191
|
className,
|
|
1861
2192
|
theme
|
|
1862
2193
|
}) {
|
|
1863
2194
|
const { cart, loading } = useCart();
|
|
1864
|
-
const [open, setOpen] =
|
|
1865
|
-
const [showCheckout, setShowCheckout] =
|
|
1866
|
-
const [mounted, setMounted] =
|
|
2195
|
+
const [open, setOpen] = useState11(false);
|
|
2196
|
+
const [showCheckout, setShowCheckout] = useState11(false);
|
|
2197
|
+
const [mounted, setMounted] = useState11(false);
|
|
1867
2198
|
const client = useHuskelContext();
|
|
1868
|
-
|
|
2199
|
+
useEffect10(() => {
|
|
1869
2200
|
setMounted(true);
|
|
1870
2201
|
const handleTriggerCheckout = () => {
|
|
1871
2202
|
setShowCheckout(true);
|
|
@@ -1876,7 +2207,7 @@ function CartDrawer({
|
|
|
1876
2207
|
window.removeEventListener("huskel:trigger_checkout", handleTriggerCheckout);
|
|
1877
2208
|
};
|
|
1878
2209
|
}, []);
|
|
1879
|
-
|
|
2210
|
+
useEffect10(() => {
|
|
1880
2211
|
if (open) {
|
|
1881
2212
|
document.body.style.overflow = "hidden";
|
|
1882
2213
|
} else {
|
|
@@ -1888,12 +2219,18 @@ function CartDrawer({
|
|
|
1888
2219
|
}, [open]);
|
|
1889
2220
|
const handleCheckout = async () => {
|
|
1890
2221
|
if (!cart || cart.items.length === 0) return;
|
|
2222
|
+
const event = new CustomEvent("huskel:trigger_checkout", { cancelable: true });
|
|
2223
|
+
window.dispatchEvent(event);
|
|
2224
|
+
if (event.defaultPrevented) {
|
|
2225
|
+
setOpen(false);
|
|
2226
|
+
return;
|
|
2227
|
+
}
|
|
1891
2228
|
setShowCheckout(true);
|
|
1892
2229
|
};
|
|
1893
2230
|
const isStringTheme = typeof theme === "string";
|
|
1894
2231
|
const hskThemeAttr = isStringTheme ? theme : void 0;
|
|
1895
2232
|
const customStyles = !isStringTheme && theme ? __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, (theme == null ? void 0 : theme.primaryColor) && { "--hsk-primary": theme.primaryColor, "--hsk-primary-color": 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 }) : void 0;
|
|
1896
|
-
return /* @__PURE__ */ jsxs6(
|
|
2233
|
+
return /* @__PURE__ */ jsxs6(Fragment5, { children: [
|
|
1897
2234
|
/* @__PURE__ */ jsx9("div", { onClick: () => setOpen(true), style: { display: "inline-block" }, children: trigger || /* @__PURE__ */ jsxs6(
|
|
1898
2235
|
"button",
|
|
1899
2236
|
{
|
|
@@ -1994,8 +2331,10 @@ export {
|
|
|
1994
2331
|
useCart,
|
|
1995
2332
|
useChat,
|
|
1996
2333
|
useHuskel,
|
|
2334
|
+
useHuskelContext,
|
|
1997
2335
|
useIngest,
|
|
1998
2336
|
usePageIngest,
|
|
2337
|
+
usePaymentPolling,
|
|
1999
2338
|
useSearch
|
|
2000
2339
|
};
|
|
2001
2340
|
//# sourceMappingURL=index.mjs.map
|