@akropolys/kiku 1.1.0 → 1.2.3

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
@@ -1161,6 +1161,15 @@ function ChatModal({
1161
1161
  if (typeof window !== "undefined") {
1162
1162
  localStorage.setItem("akropolys_user_phone", phoneInput.trim());
1163
1163
  }
1164
+ const isHistoryIntent = lastIntent === "capture" || lastIntent === "delete" || lastIntent === "view_history";
1165
+ if (isHistoryIntent) {
1166
+ setPaymentPhase("idle");
1167
+ const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
1168
+ if (lastUserMsg) {
1169
+ await send(lastUserMsg.content);
1170
+ }
1171
+ return;
1172
+ }
1164
1173
  const res = await client.api.initiatePayment(phoneInput.trim());
1165
1174
  setMerchantRef(res.merchantReference);
1166
1175
  setPaymentPhase("awaiting");
@@ -1427,22 +1436,31 @@ function ChatModal({
1427
1436
  ] })
1428
1437
  ] }),
1429
1438
  error && /* @__PURE__ */ jsx5("div", { className: "hsk-cb-error", children: getFriendlyError(error) }),
1430
- !replayMessages && paymentPhase === "prompt_phone" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt", children: [
1431
- /* @__PURE__ */ jsx5("div", { className: "hsk-cb-payment-icon", children: "\u{1F4F1}" }),
1432
- /* @__PURE__ */ jsx5("p", { className: "hsk-cb-payment-label", children: "Enter your M-Pesa number to pay" }),
1433
- /* @__PURE__ */ jsx5(
1434
- "input",
1435
- {
1436
- type: "tel",
1437
- className: "hsk-cb-phone-input",
1438
- placeholder: "e.g. 0712 345 678",
1439
- value: phoneInput,
1440
- onChange: (e) => setPhoneInput(e.target.value),
1441
- onKeyDown: (e) => e.key === "Enter" && handlePhoneSubmit()
1442
- }
1443
- ),
1444
- /* @__PURE__ */ jsx5("button", { className: "hsk-cb-pay-submit", onClick: handlePhoneSubmit, children: "Send STK Push \u2192" })
1445
- ] }),
1439
+ !replayMessages && paymentPhase === "prompt_phone" && (() => {
1440
+ const isHistoryIntent = lastIntent === "capture" || lastIntent === "delete" || lastIntent === "view_history";
1441
+ if (isHistoryIntent) {
1442
+ return null;
1443
+ }
1444
+ return /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-ai-msg", children: [
1445
+ /* @__PURE__ */ jsx5("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx5(SparkleIcon2, {}) }),
1446
+ /* @__PURE__ */ jsx5("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx5("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-phone-form", children: [
1447
+ /* @__PURE__ */ jsx5("label", { className: "hsk-cb-phone-label", children: "Enter your M-Pesa number to pay" }),
1448
+ /* @__PURE__ */ jsx5(
1449
+ "input",
1450
+ {
1451
+ type: "tel",
1452
+ className: "hsk-cb-phone-input",
1453
+ placeholder: "0712 345 678",
1454
+ value: phoneInput,
1455
+ onChange: (e) => setPhoneInput(e.target.value.replace(/\D/g, "")),
1456
+ onKeyDown: (e) => e.key === "Enter" && handlePhoneSubmit(),
1457
+ autoFocus: true
1458
+ }
1459
+ ),
1460
+ /* @__PURE__ */ jsx5("button", { className: "hsk-cb-phone-submit", onClick: handlePhoneSubmit, children: "Send STK push" })
1461
+ ] }) }) })
1462
+ ] });
1463
+ })(),
1446
1464
  !replayMessages && paymentPhase === "awaiting" && /* @__PURE__ */ jsxs4("div", { className: "hsk-cb-payment-prompt hsk-cb-payment-prompt--awaiting", children: [
1447
1465
  /* @__PURE__ */ jsx5("div", { className: "hsk-cb-payment-pulse-ring" }),
1448
1466
  /* @__PURE__ */ jsx5("div", { className: "hsk-cb-payment-icon-wrap", children: /* @__PURE__ */ jsx5("span", { style: { fontSize: "2rem" }, children: "\u{1F4F1}" }) }),
@@ -1734,6 +1752,9 @@ function SparkleModal({
1734
1752
  const { results, loading: searchLoading, search } = useSearch2();
1735
1753
  const { messages, sources, loading: chatLoading, error: chatError, send } = useKiku3();
1736
1754
  const [chatInput, setChatInput] = useState4("");
1755
+ const [isMobile, setIsMobile] = useState4(false);
1756
+ const [showSpecs, setShowSpecs] = useState4(false);
1757
+ const [collapseSimilar, setCollapseSimilar] = useState4(false);
1737
1758
  const chatBottomRef = useRef4(null);
1738
1759
  const chatTextareaRef = useRef4(null);
1739
1760
  useEffect4(() => {
@@ -1746,6 +1767,14 @@ function SparkleModal({
1746
1767
  }
1747
1768
  search(productName, limit);
1748
1769
  }, [productName, initialProduct, fetchedProduct, client, limit, search]);
1770
+ useEffect4(() => {
1771
+ const handleResize = () => setIsMobile(window.innerWidth <= 768);
1772
+ handleResize();
1773
+ if (typeof window !== "undefined") {
1774
+ window.addEventListener("resize", handleResize);
1775
+ return () => window.removeEventListener("resize", handleResize);
1776
+ }
1777
+ }, []);
1749
1778
  useEffect4(() => {
1750
1779
  if (results.length > 0) onResult?.(results);
1751
1780
  }, [results, onResult]);
@@ -1809,6 +1838,170 @@ Question: ${q}`;
1809
1838
  content: `Hi! I can help you with **${displayProduct.name}**. Ask me about its specifications, features, compare it with other options, or find alternatives!`
1810
1839
  }
1811
1840
  ] : messages;
1841
+ if (isMobile) {
1842
+ return /* @__PURE__ */ jsx6(
1843
+ "div",
1844
+ {
1845
+ className: cn("hsk-sp-backdrop hsk-sp-mobile-view", classNames.backdrop),
1846
+ onClick: onClose,
1847
+ style: {
1848
+ backdropFilter: `blur(${blurVal})`,
1849
+ WebkitBackdropFilter: `blur(${blurVal})`,
1850
+ background: bg ?? void 0,
1851
+ ...customStyles
1852
+ },
1853
+ children: /* @__PURE__ */ jsxs5("div", { className: cn("hsk-sp-card hsk-sp-fullscreen hsk-sp-mobile-card", classNames.card), onClick: (e) => e.stopPropagation(), children: [
1854
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-header", children: [
1855
+ /* @__PURE__ */ jsx6("span", { className: "hsk-sp-header-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx6(SparkleIcon3, {}) }),
1856
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-header-body", children: [
1857
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-header-title-row", children: [
1858
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-header-title", children: displayProduct?.name || productName }),
1859
+ displayProduct && /* @__PURE__ */ jsx6(
1860
+ "button",
1861
+ {
1862
+ type: "button",
1863
+ className: "hsk-sp-header-specs-btn",
1864
+ onClick: () => setShowSpecs(true),
1865
+ children: "Specs"
1866
+ }
1867
+ )
1868
+ ] }),
1869
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-header-sub", children: "Akropolys AI Shopping Assistant" })
1870
+ ] }),
1871
+ /* @__PURE__ */ jsx6("button", { className: "hsk-sp-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx6(CloseIcon2, {}) })
1872
+ ] }),
1873
+ searchLoading && /* @__PURE__ */ jsx6("div", { className: "hsk-sp-bar" }),
1874
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-chat-container", children: [
1875
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-cb-msgs", children: [
1876
+ displayMessages.map((msg, idx) => {
1877
+ const isUser = msg.role === "user";
1878
+ return /* @__PURE__ */ jsx6("div", { className: "hsk-cb-msg-group", children: isUser ? /* @__PURE__ */ jsx6("div", { className: "hsk-cb-user-msg", children: /* @__PURE__ */ jsx6("div", { className: "hsk-cb-user-bubble", children: msg.content }) }) : /* @__PURE__ */ jsxs5("div", { className: "hsk-cb-ai-msg", children: [
1879
+ /* @__PURE__ */ jsx6("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx6(SparkleIcon3, {}) }),
1880
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-cb-ai-body", children: [
1881
+ /* @__PURE__ */ jsx6("div", { className: "hsk-cb-ai-text", children: renderMarkdown(msg.content) }),
1882
+ idx === 0 && displayProduct && /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-attachment-deck", children: [
1883
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-main-card", children: [
1884
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-mobile-main-card-img", children: displayProduct.images?.[0] ? /* @__PURE__ */ jsx6("img", { src: displayProduct.images[0], alt: displayProduct.name }) : /* @__PURE__ */ jsx6("span", { children: "\u{1F6CD}" }) }),
1885
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-main-card-info", children: [
1886
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-mobile-main-card-brand", children: displayProduct.brand || displayProduct.category || "Product" }),
1887
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-mobile-main-card-name", children: displayProduct.name }),
1888
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-main-card-price", children: [
1889
+ displayProduct.currency ?? "KES",
1890
+ " ",
1891
+ parseFloat(displayProduct.price?.replace(/[^0-9.]/g, "") || "0").toLocaleString()
1892
+ ] })
1893
+ ] }),
1894
+ (displayProduct.specs && Object.keys(displayProduct.specs).length > 0 || displayProduct.description) && /* @__PURE__ */ jsx6(
1895
+ "button",
1896
+ {
1897
+ type: "button",
1898
+ className: "hsk-sp-mobile-main-card-specs-btn",
1899
+ onClick: () => setShowSpecs(true),
1900
+ children: "Specs"
1901
+ }
1902
+ )
1903
+ ] }),
1904
+ (() => {
1905
+ const similarProducts = results.filter(
1906
+ (r) => {
1907
+ const isSameName = r.product.name.toLowerCase() === displayProduct?.name?.toLowerCase();
1908
+ const isSameSlug = r.product.slug && displayProduct?.slug && r.product.slug.toLowerCase() === displayProduct.slug.toLowerCase();
1909
+ return !isSameName && !isSameSlug;
1910
+ }
1911
+ );
1912
+ if (similarProducts.length === 0) return null;
1913
+ return /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-similar-carousel-inline", children: [
1914
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-mobile-similar-carousel-title", children: "Similar Products" }),
1915
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-mobile-similar-carousel-list", children: similarProducts.map((r) => {
1916
+ const price = parseFloat(r.product.price?.replace(/[^0-9.]/g, "") || "0");
1917
+ const currency = r.product.currency ?? "KES";
1918
+ return /* @__PURE__ */ jsxs5(
1919
+ "div",
1920
+ {
1921
+ className: "hsk-sp-mobile-similar-carousel-item",
1922
+ onClick: () => handleNav(r),
1923
+ children: [
1924
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-mobile-similar-carousel-img", children: r.product.images?.[0] ? /* @__PURE__ */ jsx6("img", { src: r.product.images[0], alt: r.product.name }) : /* @__PURE__ */ jsx6("span", { children: "\u{1F6CD}" }) }),
1925
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-similar-carousel-meta", children: [
1926
+ /* @__PURE__ */ jsx6("div", { className: "hsk-sp-mobile-similar-carousel-name", title: r.product.name, children: r.product.name }),
1927
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-similar-carousel-price", children: [
1928
+ currency,
1929
+ " ",
1930
+ price.toLocaleString()
1931
+ ] })
1932
+ ] })
1933
+ ]
1934
+ },
1935
+ r.id
1936
+ );
1937
+ }) })
1938
+ ] });
1939
+ })()
1940
+ ] })
1941
+ ] })
1942
+ ] }) }, idx);
1943
+ }),
1944
+ chatLoading && /* @__PURE__ */ jsxs5("div", { className: "hsk-cb-typing-row", children: [
1945
+ /* @__PURE__ */ jsx6("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx6(SparkleIcon3, {}) }),
1946
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-cb-typing", children: [
1947
+ /* @__PURE__ */ jsx6("div", { className: "hsk-cb-dot" }),
1948
+ /* @__PURE__ */ jsx6("div", { className: "hsk-cb-dot" }),
1949
+ /* @__PURE__ */ jsx6("div", { className: "hsk-cb-dot" })
1950
+ ] })
1951
+ ] }),
1952
+ chatError && /* @__PURE__ */ jsx6("div", { className: "hsk-cb-error", children: getFriendlyError2(chatError) }),
1953
+ /* @__PURE__ */ jsx6("div", { ref: chatBottomRef, style: { height: 1 } })
1954
+ ] }),
1955
+ /* @__PURE__ */ jsx6("div", { className: "hsk-cb-input-wrap", children: /* @__PURE__ */ jsxs5("div", { className: "hsk-cb-input-box", children: [
1956
+ /* @__PURE__ */ jsx6(
1957
+ "textarea",
1958
+ {
1959
+ ref: chatTextareaRef,
1960
+ className: "hsk-cb-textarea",
1961
+ value: chatInput,
1962
+ onChange: handleInput,
1963
+ onKeyDown: handleKeyDown,
1964
+ placeholder: "Ask about this product, specs, or comparison...",
1965
+ rows: 1,
1966
+ disabled: chatLoading
1967
+ }
1968
+ ),
1969
+ /* @__PURE__ */ jsx6(
1970
+ "button",
1971
+ {
1972
+ className: "hsk-cb-send",
1973
+ onClick: () => handleSend(),
1974
+ disabled: !chatInput.trim() || chatLoading,
1975
+ "aria-label": "Send message",
1976
+ children: /* @__PURE__ */ jsx6(ArrowUpIcon3, {})
1977
+ }
1978
+ )
1979
+ ] }) })
1980
+ ] }),
1981
+ showSpecs && displayProduct && /* @__PURE__ */ jsx6("div", { className: "hsk-sp-mobile-specs-overlay", onClick: () => setShowSpecs(false), children: /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-specs-drawer", onClick: (e) => e.stopPropagation(), children: [
1982
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-specs-header", children: [
1983
+ /* @__PURE__ */ jsx6("h3", { children: "Specifications" }),
1984
+ /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => setShowSpecs(false), children: "Close" })
1985
+ ] }),
1986
+ /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-specs-body", children: [
1987
+ /* @__PURE__ */ jsx6("h4", { className: "hsk-sp-mobile-specs-title", children: displayProduct.name }),
1988
+ displayProduct.description && /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-specs-desc", children: [
1989
+ /* @__PURE__ */ jsx6("h5", { children: "Description" }),
1990
+ /* @__PURE__ */ jsx6("p", { children: displayProduct.description })
1991
+ ] }),
1992
+ displayProduct.specs && Object.keys(displayProduct.specs).length > 0 && /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-specs-list", children: [
1993
+ /* @__PURE__ */ jsx6("h5", { children: "Details" }),
1994
+ Object.entries(displayProduct.specs).map(([key, val]) => /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-mobile-spec-row", children: [
1995
+ /* @__PURE__ */ jsx6("span", { className: "hsk-sp-mobile-spec-label", children: key }),
1996
+ /* @__PURE__ */ jsx6("span", { className: "hsk-sp-mobile-spec-value", children: val })
1997
+ ] }, key))
1998
+ ] })
1999
+ ] })
2000
+ ] }) })
2001
+ ] })
2002
+ }
2003
+ );
2004
+ }
1812
2005
  return /* @__PURE__ */ jsx6(
1813
2006
  "div",
1814
2007
  {
@@ -1896,7 +2089,8 @@ Question: ${q}`;
1896
2089
  "div",
1897
2090
  {
1898
2091
  className: cn("hsk-sp-item", classNames.item),
1899
- style: { animationDelay: `${i * 55}ms` },
2092
+ style: { animationDelay: `${i * 55}ms`, cursor: "pointer" },
2093
+ onClick: () => handleNav(r),
1900
2094
  children: [
1901
2095
  /* @__PURE__ */ jsx6("div", { className: "hsk-sp-img-wrap", children: r.product.images?.[0] ? /* @__PURE__ */ jsx6("img", { src: r.product.images[0], alt: r.product.name }) : /* @__PURE__ */ jsx6("span", { className: "hsk-sp-img-placeholder", children: "\u{1F6CD}" }) }),
1902
2096
  /* @__PURE__ */ jsxs5("div", { className: "hsk-sp-item-body", children: [
@@ -1912,7 +2106,10 @@ Question: ${q}`;
1912
2106
  "button",
1913
2107
  {
1914
2108
  className: "hsk-sp-action hsk-sp-action-primary",
1915
- onClick: () => handleNav(r),
2109
+ onClick: (e) => {
2110
+ e.stopPropagation();
2111
+ handleNav(r);
2112
+ },
1916
2113
  children: "View"
1917
2114
  }
1918
2115
  ) })