@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.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 = (_e = e == null ? void 0 : e.message) != null ? _e : "Chat request failed";
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/components/SearchBar.tsx
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] = useState5("");
731
- const [open, setOpen] = useState5(false);
732
- const [isDebouncing, setIsDebouncing] = useState5(false);
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 = useRef6();
736
- const wrap = useRef6(null);
737
- const ignoreNextQueryChange = useRef6(false);
738
- useEffect4(() => {
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
- useEffect4(() => {
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 useState6, useEffect as useEffect5, useRef as useRef7 } from "react";
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] = useState6(null);
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] = useState6("");
999
- const chatBottomRef = useRef7(null);
1000
- const chatTextareaRef = useRef7(null);
1001
- useEffect5(() => {
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
- useEffect5(() => {
1120
+ useEffect6(() => {
1012
1121
  if (results.length > 0) onResult == null ? void 0 : onResult(results);
1013
1122
  }, [results, onResult]);
1014
- useEffect5(() => {
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
- useEffect5(() => {
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] = useState6(false);
1254
- const [mounted, setMounted] = useState6(false);
1255
- useEffect5(() => {
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 useState7, useRef as useRef8, useEffect as useEffect6 } from "react";
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] = useState7("");
1327
- const bottomRef = useRef8(null);
1328
- const textareaRef = useRef8(null);
1329
- useEffect6(() => {
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 useState8, useEffect as useEffect7, useRef as useRef9, useCallback as useCallback5 } from "react";
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 = useRef9(null);
1447
- const [showNext, setShowNext] = useState8(false);
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
- useEffect7(() => {
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 { messages, sources, loading, error, send, reset } = useChat();
1520
- const [input, setInput] = useState8("");
1521
- const [selectedProduct, setSelectedProduct] = useState8(null);
1522
- const bottomRef = useRef9(null);
1523
- const textareaRef = useRef9(null);
1524
- useEffect7(() => {
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
- useEffect7(() => {
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] = useState8(false);
1693
- const [mounted, setMounted] = useState8(false);
1694
- useEffect7(() => {
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 useState10, useEffect as useEffect9 } from "react";
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 useState9, useEffect as useEffect8 } from "react";
1933
+ import { useState as useState10, useEffect as useEffect9 } from "react";
1747
1934
  import { createPortal as createPortal3 } from "react-dom";
1748
- import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
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] = useState9(null);
1759
- const [loading, setLoading] = useState9(true);
1760
- const [checkingOut, setCheckingOut] = useState9(false);
1761
- const [paymentSuccess, setPaymentSuccess] = useState9(false);
1762
- useEffect8(() => {
1763
- client.api.getCheckoutConfig().then((res) => setConfig(res.payment_methods)).catch((e) => console.error("[Huskel] Failed to fetch checkout config", e)).finally(() => setLoading(false));
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 handlePay = async (method) => {
1766
- setCheckingOut(true);
1767
- setTimeout(async () => {
1768
- try {
1769
- const payload = await client.api.checkoutCart();
1770
- if (client.onCheckout) {
1771
- client.onCheckout(payload);
1772
- }
1773
- setPaymentSuccess(true);
1774
- setTimeout(() => {
1775
- onClose();
1776
- }, 3e3);
1777
- } catch (e) {
1778
- console.error("[Huskel] Checkout failed", e);
1779
- setCheckingOut(false);
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
- }, 1500);
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 hasPaymentMethods = config && Object.values(config).some((m) => m.enabled);
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-cart-backdrop",
1789
- style: __spreadProps(__spreadValues({}, customStyles), { zIndex: 999999 }),
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-header", children: [
1801
- /* @__PURE__ */ jsx8("h2", { children: "Secure Checkout" }),
1802
- /* @__PURE__ */ jsx8("button", { onClick: onClose, className: "hsk-close-btn", children: "\xD7" })
1803
- ] }),
1804
- /* @__PURE__ */ jsx8("div", { className: "hsk-checkout-content", children: paymentSuccess ? /* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-success", children: [
1805
- /* @__PURE__ */ jsxs5("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "hsk-success-icon", children: [
1806
- /* @__PURE__ */ jsx8("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
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("h3", { children: "Payment Successful!" }),
1810
- /* @__PURE__ */ jsx8("p", { children: "Thank you for your order." })
1811
- ] }) : /* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-split", children: [
1812
- /* @__PURE__ */ jsxs5("div", { className: "hsk-checkout-summary", children: [
1813
- /* @__PURE__ */ jsx8("h3", { children: "Order Summary" }),
1814
- cartLoading || !cart ? /* @__PURE__ */ jsx8("p", { className: "hsk-cart-loading", children: "Loading order..." }) : /* @__PURE__ */ jsxs5(Fragment5, { children: [
1815
- /* @__PURE__ */ jsx8("ul", { className: "hsk-checkout-items", children: cart.items.map((item) => /* @__PURE__ */ jsxs5("li", { children: [
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__ */ jsxs5("div", { className: "hsk-checkout-payment", children: [
1838
- /* @__PURE__ */ jsx8("h3", { children: "Payment Method" }),
1839
- loading ? /* @__PURE__ */ jsx8("p", { className: "hsk-cart-loading", children: "Loading secure payment methods..." }) : !hasPaymentMethods ? /* @__PURE__ */ jsx8("p", { className: "hsk-checkout-error", children: "No payment methods are currently available for this store." }) : /* @__PURE__ */ jsxs5("div", { className: "hsk-payment-options", children: [
1840
- ((_a = config == null ? void 0 : config.mpesa) == null ? void 0 : _a.enabled) && /* @__PURE__ */ jsx8("button", { onClick: () => handlePay("mpesa"), disabled: checkingOut, className: "hsk-pay-btn hsk-pay-mpesa", children: checkingOut ? "Processing..." : "Pay with M-Pesa" }),
1841
- ((_b = config == null ? void 0 : config.equity) == null ? void 0 : _b.enabled) && /* @__PURE__ */ jsx8("button", { onClick: () => handlePay("equity"), disabled: checkingOut, className: "hsk-pay-btn hsk-pay-equity", children: checkingOut ? "Processing..." : "Pay with Equity Bank" }),
1842
- ((_c = config == null ? void 0 : config.stripe) == null ? void 0 : _c.enabled) && /* @__PURE__ */ jsx8("button", { onClick: () => handlePay("stripe"), disabled: checkingOut, className: "hsk-pay-btn hsk-pay-stripe", children: checkingOut ? "Processing..." : "Pay with Card (Stripe)" }),
1843
- ((_d = config == null ? void 0 : config.paypal) == null ? void 0 : _d.enabled) && /* @__PURE__ */ jsx8("button", { onClick: () => handlePay("paypal"), disabled: checkingOut, className: "hsk-pay-btn hsk-pay-paypal", children: checkingOut ? "Processing..." : "Pay with PayPal" })
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 Fragment6, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
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] = useState10(false);
1865
- const [showCheckout, setShowCheckout] = useState10(false);
1866
- const [mounted, setMounted] = useState10(false);
2195
+ const [open, setOpen] = useState11(false);
2196
+ const [showCheckout, setShowCheckout] = useState11(false);
2197
+ const [mounted, setMounted] = useState11(false);
1867
2198
  const client = useHuskelContext();
1868
- useEffect9(() => {
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
- useEffect9(() => {
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(Fragment6, { children: [
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