@akropolys/kiku 1.0.0

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.js ADDED
@@ -0,0 +1,2538 @@
1
+ 'use client';
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var src_exports = {};
23
+ __export(src_exports, {
24
+ CartBadge: () => CartBadge,
25
+ CartDrawer: () => CartDrawer,
26
+ ChatWidget: () => ChatWidget,
27
+ CheckoutModal: () => CheckoutModal,
28
+ ComparisonMatrix: () => ComparisonMatrix,
29
+ KikuButton: () => KikuButton,
30
+ KikuChat: () => ChatWidget,
31
+ SearchBar: () => SearchBar,
32
+ Sparkle: () => Sparkle
33
+ });
34
+ module.exports = __toCommonJS(src_exports);
35
+
36
+ // src/components/SearchBar.tsx
37
+ var import_react = require("react");
38
+ var import_sdk = require("@akropolys/sdk");
39
+
40
+ // src/utils/cn.ts
41
+ var import_clsx = require("clsx");
42
+ var import_tailwind_merge = require("tailwind-merge");
43
+ function cn(...inputs) {
44
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
45
+ }
46
+
47
+ // src/components/SearchBar.tsx
48
+ var import_jsx_runtime = require("react/jsx-runtime");
49
+ var SearchIcon = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "15", height: "15", viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
50
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8.5", cy: "8.5", r: "5.5" }),
51
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "13", y1: "13", x2: "18", y2: "18" })
52
+ ] });
53
+ function SearchBar({
54
+ placeholder = "Search products\u2026",
55
+ limit = 10,
56
+ debounceMs = 300,
57
+ onSelect,
58
+ className,
59
+ inputClassName,
60
+ dropdownClassName,
61
+ renderResult,
62
+ theme,
63
+ classNames = {}
64
+ }) {
65
+ const [query, setQuery] = (0, import_react.useState)("");
66
+ const [open, setOpen] = (0, import_react.useState)(false);
67
+ const [isDebouncing, setIsDebouncing] = (0, import_react.useState)(false);
68
+ const { results, loading, search, clear } = (0, import_sdk.useSearch)();
69
+ const client = (0, import_sdk.useAkropolysContext)();
70
+ const timer = (0, import_react.useRef)();
71
+ const wrap = (0, import_react.useRef)(null);
72
+ const ignoreNextQueryChange = (0, import_react.useRef)(false);
73
+ (0, import_react.useEffect)(() => {
74
+ if (ignoreNextQueryChange.current) {
75
+ ignoreNextQueryChange.current = false;
76
+ return;
77
+ }
78
+ clearTimeout(timer.current);
79
+ if (!query.trim()) {
80
+ clear();
81
+ setOpen(false);
82
+ setIsDebouncing(false);
83
+ return;
84
+ }
85
+ setOpen(true);
86
+ setIsDebouncing(true);
87
+ timer.current = setTimeout(() => {
88
+ setIsDebouncing(false);
89
+ search(query, limit);
90
+ }, debounceMs);
91
+ return () => clearTimeout(timer.current);
92
+ }, [query]);
93
+ (0, import_react.useEffect)(() => {
94
+ const h = (e) => {
95
+ if (wrap.current && !wrap.current.contains(e.target)) setOpen(false);
96
+ };
97
+ document.addEventListener("mousedown", h);
98
+ return () => document.removeEventListener("mousedown", h);
99
+ }, []);
100
+ const handleSelect = (r) => {
101
+ if (query.trim()) {
102
+ client.api.searchVector(query, 1).catch(() => {
103
+ });
104
+ }
105
+ ignoreNextQueryChange.current = true;
106
+ setOpen(false);
107
+ setQuery(r.product.name);
108
+ onSelect?.(r);
109
+ };
110
+ const handleCommitSearch = () => {
111
+ if (!query.trim()) return;
112
+ client.api.searchVector(query, 1).catch(() => {
113
+ });
114
+ if (results.length > 0) {
115
+ handleSelect(results[0]);
116
+ }
117
+ };
118
+ const showDrop = open && query.trim().length > 0;
119
+ const customStyles = {
120
+ ...theme?.primaryColor && { "--hsk-primary": theme.primaryColor },
121
+ ...theme?.backgroundColor && { "--hsk-bg": theme.backgroundColor },
122
+ ...theme?.textColor && { "--hsk-text": theme.textColor },
123
+ ...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
124
+ ...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
125
+ };
126
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("hsk-sb-wrap", classNames.root, className), ref: wrap, style: customStyles, children: [
127
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-icon", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchIcon, {}) }),
128
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
129
+ "input",
130
+ {
131
+ className: cn("hsk-sb-input", classNames.input, inputClassName),
132
+ type: "text",
133
+ value: query,
134
+ placeholder,
135
+ onChange: (e) => setQuery(e.target.value),
136
+ onFocus: () => results.length > 0 && query.trim() && setOpen(true),
137
+ onKeyDown: (e) => {
138
+ if (e.key === "Enter") {
139
+ handleCommitSearch();
140
+ }
141
+ },
142
+ autoComplete: "off",
143
+ spellCheck: false
144
+ }
145
+ ),
146
+ showDrop && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("hsk-sb-drop", classNames.dropdown, dropdownClassName), style: { position: "absolute" }, children: [
147
+ (loading || isDebouncing) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-loading-bar" }),
148
+ (loading || isDebouncing) && results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
149
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-skeleton-row", children: [
150
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-skeleton-icon" }),
151
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-row-body", children: [
152
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-skeleton-text1" }),
153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-skeleton-text2" })
154
+ ] })
155
+ ] }),
156
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-skeleton-row", children: [
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-skeleton-icon" }),
158
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-row-body", children: [
159
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-skeleton-text1", style: { width: "45%" } }),
160
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-skeleton-text2", style: { width: "25%" } })
161
+ ] })
162
+ ] })
163
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
164
+ results.length === 0 && !loading && !isDebouncing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-empty", children: [
165
+ "No results for \u201C",
166
+ query,
167
+ "\u201D"
168
+ ] }),
169
+ results.map((r, i) => renderResult ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
170
+ "div",
171
+ {
172
+ onClick: () => handleSelect(r),
173
+ className: "hsk-sb-fade",
174
+ style: { animationDelay: `${i * 18}ms` },
175
+ children: renderResult(r)
176
+ },
177
+ r.id
178
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
179
+ "div",
180
+ {
181
+ className: cn("hsk-sb-row hsk-sb-fade", classNames.row),
182
+ style: { animationDelay: `${i * 18}ms` },
183
+ onClick: () => handleSelect(r),
184
+ children: [
185
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-row-icon", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchIcon, {}) }),
186
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-row-body", children: [
187
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-row-title", children: r.product.name }),
188
+ (r.product.category || r.product.brand) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-row-sub", children: r.product.category ?? r.product.brand })
189
+ ] })
190
+ ]
191
+ },
192
+ r.id
193
+ ))
194
+ ] })
195
+ ] })
196
+ ] });
197
+ }
198
+
199
+ // src/components/ChatWidget.tsx
200
+ var import_react2 = require("react");
201
+ var import_sdk2 = require("@akropolys/sdk");
202
+
203
+ // src/utils/markdown.tsx
204
+ var import_jsx_runtime2 = require("react/jsx-runtime");
205
+ var parseInline = (text, keyPrefix) => {
206
+ const tokenRegex = /(\[[^\]]+\]\([^)]+\)|\*\*[^*]+\*\*|`[^`]+`)/g;
207
+ const parts = text.split(tokenRegex);
208
+ return parts.map((part, index) => {
209
+ if (!part) return null;
210
+ const key = `${keyPrefix}-inline-${index}`;
211
+ if (part.startsWith("`") && part.endsWith("`")) {
212
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { className: "hsk-markdown-code", children: part.slice(1, -1) }, key);
213
+ }
214
+ if (part.startsWith("**") && part.endsWith("**")) {
215
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: parseInline(part.slice(2, -2), key) }, key);
216
+ }
217
+ const linkMatch = part.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
218
+ if (linkMatch) {
219
+ const url = linkMatch[2];
220
+ const isSafeUrl = /^(https?|mailto|tel):/i.test(url) || url.startsWith("/");
221
+ if (isSafeUrl) {
222
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "hsk-markdown-link", children: parseInline(linkMatch[1], key) }, key);
223
+ }
224
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: parseInline(linkMatch[1], key) }, key);
225
+ }
226
+ return part;
227
+ });
228
+ };
229
+ function renderMarkdown(content) {
230
+ const lines = content.split("\n");
231
+ const elements = [];
232
+ let i = 0;
233
+ while (i < lines.length) {
234
+ const line = lines[i];
235
+ const key = `md-line-${i}`;
236
+ if (!line.trim()) {
237
+ i++;
238
+ continue;
239
+ }
240
+ const headerMatch = line.match(/^(#{1,3})\s+(.*)/);
241
+ if (headerMatch) {
242
+ const level = headerMatch[1].length;
243
+ const Tag = `h${level + 3}`;
244
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Tag, { className: `hsk-markdown-h${level}`, children: parseInline(headerMatch[2], key) }, key));
245
+ i++;
246
+ continue;
247
+ }
248
+ if (line.match(/^[-*]\s+/)) {
249
+ const listItems = [];
250
+ while (i < lines.length && lines[i].match(/^[-*]\s+/)) {
251
+ const itemText = lines[i].replace(/^[-*]\s+/, "");
252
+ listItems.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: parseInline(itemText, `li-${i}`) }, `li-${i}`));
253
+ i++;
254
+ }
255
+ elements.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "hsk-markdown-list", children: listItems }, `ul-${key}`));
256
+ continue;
257
+ }
258
+ if (line.trim().startsWith("|")) {
259
+ const tableRows = [];
260
+ let isHeader = true;
261
+ while (i < lines.length && lines[i].trim().startsWith("|")) {
262
+ const rowLine = lines[i].trim();
263
+ if (rowLine.match(/^\|[-:| ]+\|$/)) {
264
+ i++;
265
+ isHeader = false;
266
+ continue;
267
+ }
268
+ const cells = rowLine.split("|").slice(1, -1).map((c) => c.trim());
269
+ const Tag = isHeader ? "th" : "td";
270
+ tableRows.push(
271
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: cells.map((cell, cIdx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Tag, { children: parseInline(cell, `td-${i}-${cIdx}`) }, `td-${i}-${cIdx}`)) }, `tr-${i}`)
272
+ );
273
+ i++;
274
+ }
275
+ elements.push(
276
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hsk-table-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("table", { className: "hsk-markdown-table", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: tableRows }) }) }, `table-wrapper-${key}`)
277
+ );
278
+ continue;
279
+ }
280
+ elements.push(
281
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "hsk-markdown-p", children: parseInline(line, key) }, key)
282
+ );
283
+ i++;
284
+ }
285
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: elements });
286
+ }
287
+
288
+ // src/components/ChatWidget.tsx
289
+ var import_jsx_runtime3 = require("react/jsx-runtime");
290
+ var SparkleIcon = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z" }) });
291
+ var ArrowUpIcon = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
292
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m5 12 7-7 7 7" }),
293
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 19V5" })
294
+ ] });
295
+ function SourceCard({ source, defaultCurrency, onSelect }) {
296
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-source-card", onClick: () => onSelect?.(source), children: [
297
+ source.image && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("img", { src: source.image, alt: source.name, className: "hsk-source-img" }),
298
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
299
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "hsk-source-name", children: source.name }),
300
+ source.price && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-source-price", children: [
301
+ source.currency ?? defaultCurrency,
302
+ " ",
303
+ source.price
304
+ ] })
305
+ ] })
306
+ ] });
307
+ }
308
+ function ChatWidget({
309
+ title = "AI Shopping Assistant",
310
+ placeholder = "Ask about anything in our store\u2026",
311
+ emptyStateText = "Ask me anything about our products",
312
+ emptyStateSuggestions = '"Find me headphones under KSh 5,000" \xB7 "Gift ideas"',
313
+ defaultCurrency = "KES",
314
+ className,
315
+ theme,
316
+ classNames = {},
317
+ onSelectSource
318
+ }) {
319
+ const { messages, sources, loading, error, send, reset } = (0, import_sdk2.useKiku)();
320
+ const [input, setInput] = (0, import_react2.useState)("");
321
+ const bottomRef = (0, import_react2.useRef)(null);
322
+ const textareaRef = (0, import_react2.useRef)(null);
323
+ (0, import_react2.useEffect)(() => {
324
+ bottomRef.current?.scrollIntoView({ behavior: "smooth" });
325
+ }, [messages, loading]);
326
+ const handleSend = async () => {
327
+ const q = input.trim();
328
+ if (!q || loading) return;
329
+ setInput("");
330
+ if (textareaRef.current) textareaRef.current.style.height = "auto";
331
+ await send(q);
332
+ };
333
+ const handleKey = (e) => {
334
+ if (e.key === "Enter" && !e.shiftKey) {
335
+ e.preventDefault();
336
+ handleSend();
337
+ }
338
+ };
339
+ const handleInput = (e) => {
340
+ setInput(e.target.value);
341
+ const t = e.target;
342
+ t.style.height = "auto";
343
+ t.style.height = Math.min(t.scrollHeight, 120) + "px";
344
+ };
345
+ const customStyles = {
346
+ ...theme?.primaryColor && { "--hsk-primary": theme.primaryColor },
347
+ ...theme?.backgroundColor && { "--hsk-bg": theme.backgroundColor },
348
+ ...theme?.textColor && { "--hsk-text": theme.textColor },
349
+ ...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
350
+ ...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
351
+ };
352
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
353
+ "div",
354
+ {
355
+ className: cn("hsk-chat-widget", classNames.root, className),
356
+ style: customStyles,
357
+ children: [
358
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: cn("hsk-chat-header", classNames.header), children: [
359
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "hsk-chat-header-icon", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SparkleIcon, {}) }),
360
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "hsk-chat-title", children: title }),
361
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "hsk-chat-badge", children: "AI" }),
362
+ messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "hsk-chat-reset", onClick: reset, style: { marginLeft: "auto" }, children: "Clear" })
363
+ ] }),
364
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-chat-messages", children: [
365
+ messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-chat-empty", children: [
366
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "hsk-chat-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SparkleIcon, {}) }),
367
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: emptyStateText }),
368
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "hsk-chat-empty-suggestions", children: emptyStateSuggestions })
369
+ ] }) : messages.map((msg, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `hsk-msg-row ${msg.role}`, children: [
371
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: cn("hsk-msg-avatar", msg.role === "assistant" ? "ai" : "user"), children: msg.role === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SparkleIcon, {}) : "U" }),
372
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: cn("hsk-msg-bubble", msg.role, classNames.messageBubble), children: renderMarkdown(msg.content) })
373
+ ] }),
374
+ msg.role === "assistant" && idx === messages.length - 1 && sources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "hsk-sources-container", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "hsk-sources", children: sources.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SourceCard, { source: src, defaultCurrency, onSelect: onSelectSource }, si)) }) })
375
+ ] }, idx)),
376
+ loading && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-msg-row", children: [
377
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "hsk-msg-avatar ai", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SparkleIcon, {}) }),
378
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-pending", role: "status", "aria-live": "polite", children: [
379
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-pending-glyph", children: [
380
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "hsk-pending-ring" }),
381
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "hsk-pending-dot" })
382
+ ] }),
383
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-pending-text", children: [
384
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "hsk-pending-step step-1", children: "Searching catalog" }),
385
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "hsk-pending-step step-2", children: "Reasoning" }),
386
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "hsk-pending-step step-3", children: "Composing" })
387
+ ] })
388
+ ] })
389
+ ] }),
390
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "hsk-chat-error", children: (() => {
391
+ try {
392
+ const parsed = JSON.parse(error);
393
+ return parsed.error || parsed.message || error;
394
+ } catch {
395
+ return error;
396
+ }
397
+ })() }),
398
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: bottomRef })
399
+ ] }),
400
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hsk-chat-input-area", children: [
401
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
402
+ "textarea",
403
+ {
404
+ ref: textareaRef,
405
+ className: cn("hsk-chat-input", classNames.input),
406
+ value: input,
407
+ onChange: handleInput,
408
+ onKeyDown: handleKey,
409
+ placeholder,
410
+ rows: 1,
411
+ disabled: loading
412
+ }
413
+ ),
414
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
415
+ "button",
416
+ {
417
+ className: "hsk-chat-send",
418
+ onClick: handleSend,
419
+ disabled: !input.trim() || loading,
420
+ "aria-label": "Send message",
421
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowUpIcon, {})
422
+ }
423
+ )
424
+ ] })
425
+ ]
426
+ }
427
+ );
428
+ }
429
+
430
+ // src/components/KikuButton.tsx
431
+ var import_react3 = require("react");
432
+ var import_react_dom = require("react-dom");
433
+ var import_sdk3 = require("@akropolys/sdk");
434
+ var import_sdk4 = require("@akropolys/sdk");
435
+ var import_sdk5 = require("@akropolys/sdk");
436
+
437
+ // src/components/ComparisonMatrix.tsx
438
+ var import_jsx_runtime4 = require("react/jsx-runtime");
439
+ function extractSize(p) {
440
+ const name = p.name;
441
+ const cat = (p.category || "").toLowerCase();
442
+ const mExplicit = name.match(/(\d+(?:\.\d+)?)\s*(?:inch(?:es)?|["'″])/i);
443
+ if (mExplicit) {
444
+ return `${mExplicit[1]} inches`;
445
+ }
446
+ if (cat.includes("tv") || cat.includes("audio")) {
447
+ const mTv = name.match(/\b(\d{2})(?:[a-zA-Z]|\b)/);
448
+ if (mTv) {
449
+ const size = parseInt(mTv[1], 10);
450
+ if (size >= 24 && size <= 120) {
451
+ return `${size} inches`;
452
+ }
453
+ }
454
+ }
455
+ return null;
456
+ }
457
+ function extractResolution(name) {
458
+ if (/\b4K\b/i.test(name)) return "4K Ultra HD (2160p)";
459
+ if (/\bUHD\b/i.test(name)) return "Ultra HD (2160p)";
460
+ if (/\b(?:Full HD|FHD|1080p)\b/i.test(name)) return "Full HD (1080p)";
461
+ if (/\b(?:HD|720p)\b/i.test(name)) return "HD (720p)";
462
+ return null;
463
+ }
464
+ function extractStorage(name) {
465
+ const m = name.match(/(\d+)\s*GB(?!\s*RAM)/i);
466
+ return m ? `${m[1]} GB` : null;
467
+ }
468
+ function extractRAM(name) {
469
+ const m = name.match(/(\d+)\s*GB\s*RAM/i);
470
+ return m ? `${m[1]} GB` : null;
471
+ }
472
+ function extractCamera(name) {
473
+ const m = name.match(/(\d+)\s*MP/i);
474
+ return m ? `${m[1]} MP` : null;
475
+ }
476
+ function extractBattery(name) {
477
+ const m = name.match(/(\d{3,5})\s*mAh/i);
478
+ return m ? `${m[1]} mAh` : null;
479
+ }
480
+ function buildRows(products, currency) {
481
+ const rows = [];
482
+ rows.push({
483
+ label: "Product Preview",
484
+ values: products.map((s) => s.image || null),
485
+ type: "image"
486
+ });
487
+ const prices = products.map((s) => {
488
+ const n = parseFloat(String(s.price ?? "").replace(/[^0-9.]/g, ""));
489
+ return isNaN(n) ? null : n;
490
+ });
491
+ const priceLabels = products.map((s, i) => {
492
+ const c = s.currency || currency;
493
+ const n = prices[i];
494
+ return n !== null ? `${c} ${n.toLocaleString("en-KE", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : null;
495
+ });
496
+ const validPrices = prices.filter((p) => p !== null);
497
+ const minPrice = validPrices.length ? Math.min(...validPrices) : null;
498
+ rows.push({
499
+ label: "Price",
500
+ values: priceLabels,
501
+ type: "price",
502
+ bestIdx: minPrice !== null ? prices.indexOf(minPrice) : void 0
503
+ });
504
+ const brands = products.map((s) => s.brand || null);
505
+ if (brands.some(Boolean)) rows.push({ label: "Brand", values: brands });
506
+ const specDefs = [
507
+ { label: "Display Size", fn: extractSize },
508
+ { label: "Resolution", fn: (p) => extractResolution(p.name), higherIsBetter: true },
509
+ { label: "Storage", fn: (p) => extractStorage(p.name), higherIsBetter: true },
510
+ { label: "RAM", fn: (p) => extractRAM(p.name), higherIsBetter: true },
511
+ { label: "Camera", fn: (p) => extractCamera(p.name), higherIsBetter: true },
512
+ { label: "Battery", fn: (p) => extractBattery(p.name), higherIsBetter: true }
513
+ ];
514
+ const resOrder = ["4K Ultra HD (2160p)", "Ultra HD (2160p)", "Full HD (1080p)", "HD (720p)"];
515
+ for (const { label, fn, higherIsBetter } of specDefs) {
516
+ const vals = products.map((s) => fn(s));
517
+ if (!vals.some(Boolean)) continue;
518
+ let bestIdx;
519
+ if (higherIsBetter && vals.filter(Boolean).length > 1) {
520
+ if (label === "Resolution") {
521
+ bestIdx = vals.reduce((best, v, i) => {
522
+ const rank = resOrder.indexOf(v ?? "");
523
+ const bestRank = resOrder.indexOf(vals[best] ?? "");
524
+ return rank !== -1 && (bestRank === -1 || rank < bestRank) ? i : best;
525
+ }, 0);
526
+ } else {
527
+ const nums = vals.map((v) => parseFloat((v ?? "").replace(/[^0-9.]/g, "")));
528
+ const max = Math.max(...nums.filter((n) => !isNaN(n)));
529
+ bestIdx = nums.indexOf(max);
530
+ }
531
+ }
532
+ rows.push({ label, values: vals, bestIdx });
533
+ }
534
+ const avail = products.map((s) => {
535
+ const a = s.availability ?? "";
536
+ if (!a) return null;
537
+ if (/in.?stock/i.test(a)) return "In-Stock";
538
+ if (/out.?of.?stock/i.test(a)) return "Out of Stock";
539
+ return a;
540
+ });
541
+ if (avail.some(Boolean)) {
542
+ rows.push({ label: "Availability", values: avail, type: "availability" });
543
+ }
544
+ const cats = products.map((s) => s.category || null);
545
+ if (cats.some(Boolean)) rows.push({ label: "Category", values: cats });
546
+ return rows;
547
+ }
548
+ function ImageCell({ value, name }) {
549
+ if (!value) {
550
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: 28, textAlign: "center" }, children: "\u{1F4E6}" });
551
+ }
552
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
553
+ "img",
554
+ {
555
+ src: value,
556
+ alt: name,
557
+ style: {
558
+ width: 72,
559
+ height: 72,
560
+ objectFit: "contain",
561
+ borderRadius: 8,
562
+ background: "#f5f5f5",
563
+ display: "block"
564
+ }
565
+ }
566
+ );
567
+ }
568
+ function AvailabilityCell({ value }) {
569
+ if (!value) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#9ca3af" }, children: "\u2014" });
570
+ const inStock = /in.?stock/i.test(value);
571
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: 13, color: "var(--hsk-text, #111827)" }, children: [
572
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: {
573
+ width: 8,
574
+ height: 8,
575
+ borderRadius: "50%",
576
+ flexShrink: 0,
577
+ background: inStock ? "#22c55e" : "#ef4444",
578
+ boxShadow: inStock ? "0 0 0 3px rgba(34,197,94,0.2)" : "0 0 0 3px rgba(239,68,68,0.2)",
579
+ display: "inline-block"
580
+ } }),
581
+ value
582
+ ] });
583
+ }
584
+ function ComparisonMatrix({ sources, defaultCurrency = "KES" }) {
585
+ if (sources.length < 2) return null;
586
+ const products = sources.slice(0, 3);
587
+ const rows = buildRows(products, defaultCurrency);
588
+ const colTemplate = `140px repeat(${products.length}, 1fr)`;
589
+ const labelStyle = {
590
+ padding: "10px 12px",
591
+ fontSize: 11,
592
+ fontWeight: 700,
593
+ // Solid dark fallback — never inherit a muted ancestor color
594
+ color: "var(--hsk-text-muted, #4b5563)",
595
+ textTransform: "uppercase",
596
+ letterSpacing: "0.05em",
597
+ borderBottom: "1px solid var(--hsk-border, rgba(0,0,0,0.07))",
598
+ verticalAlign: "middle",
599
+ whiteSpace: "nowrap",
600
+ display: "flex",
601
+ alignItems: "center"
602
+ };
603
+ const cellBase = {
604
+ padding: "10px 14px",
605
+ fontSize: 13,
606
+ // Explicit color so cells are always readable regardless of parent theme
607
+ color: "var(--hsk-text, #111827)",
608
+ borderBottom: "1px solid var(--hsk-border, rgba(0,0,0,0.07))",
609
+ verticalAlign: "middle",
610
+ display: "flex",
611
+ alignItems: "center"
612
+ };
613
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
614
+ "div",
615
+ {
616
+ className: "hsk-compare-matrix",
617
+ style: {
618
+ marginTop: 10,
619
+ borderRadius: 12,
620
+ overflow: "hidden",
621
+ border: "1px solid var(--hsk-border, rgba(0,0,0,0.09))",
622
+ background: "var(--hsk-surface, #fff)",
623
+ fontSize: 13
624
+ },
625
+ children: [
626
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "grid", gridTemplateColumns: colTemplate, background: "var(--hsk-surface2, #f9fafb)", borderBottom: "2px solid var(--hsk-border, rgba(0,0,0,0.09))" }, children: [
627
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...labelStyle, borderBottom: "none", color: "var(--hsk-text, #111)", fontSize: 12 }, children: "Feature" }),
628
+ products.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
629
+ "a",
630
+ {
631
+ href: p.url || "#",
632
+ target: "_blank",
633
+ rel: "noopener noreferrer",
634
+ style: {
635
+ display: "flex",
636
+ alignItems: "center",
637
+ padding: "10px 14px",
638
+ fontSize: 12,
639
+ fontWeight: 700,
640
+ color: "var(--hsk-primary, #16a34a)",
641
+ textDecoration: "none",
642
+ lineHeight: 1.3,
643
+ borderLeft: i > 0 ? "1px solid var(--hsk-border, rgba(0,0,0,0.07))" : "none"
644
+ },
645
+ children: p.name
646
+ },
647
+ i
648
+ ))
649
+ ] }),
650
+ rows.map((row, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
651
+ "div",
652
+ {
653
+ style: {
654
+ display: "grid",
655
+ gridTemplateColumns: colTemplate,
656
+ background: rowIdx % 2 === 1 ? "var(--hsk-surface2, rgba(0,0,0,0.015))" : "transparent"
657
+ },
658
+ children: [
659
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: labelStyle, children: row.label }),
660
+ products.map((p, i) => {
661
+ const val = row.values[i];
662
+ const isBest = row.bestIdx === i && row.values.filter(Boolean).length > 1;
663
+ if (row.type === "image") {
664
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...cellBase, justifyContent: "center", padding: "12px", borderLeft: i > 0 ? "1px solid var(--hsk-border, rgba(0,0,0,0.07))" : "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ImageCell, { value: val, name: p.name }) }, i);
665
+ }
666
+ if (row.type === "availability") {
667
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...cellBase, borderLeft: i > 0 ? "1px solid var(--hsk-border, rgba(0,0,0,0.07))" : "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AvailabilityCell, { value: val }) }, i);
668
+ }
669
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
670
+ "div",
671
+ {
672
+ style: {
673
+ ...cellBase,
674
+ fontWeight: isBest ? 700 : 400,
675
+ // Always use a solid dark fallback — never 'inherit' which can be muted/invisible
676
+ color: isBest ? "var(--hsk-primary, #ea580c)" : row.type === "price" ? "var(--hsk-text, #374151)" : "var(--hsk-text, #111827)",
677
+ borderLeft: i > 0 ? "1px solid var(--hsk-border, rgba(0,0,0,0.07))" : "none"
678
+ },
679
+ children: val ?? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#9ca3af" }, children: "\u2014" })
680
+ },
681
+ i
682
+ );
683
+ })
684
+ ]
685
+ },
686
+ rowIdx
687
+ ))
688
+ ]
689
+ }
690
+ );
691
+ }
692
+
693
+ // src/components/KikuButton.tsx
694
+ var import_jsx_runtime5 = require("react/jsx-runtime");
695
+ var AkropolysAIcon = ({ className, size = 18 }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
696
+ "svg",
697
+ {
698
+ className: cn("hsk-brand-a", className),
699
+ width: size,
700
+ height: size,
701
+ viewBox: "0 0 28 30",
702
+ fill: "none",
703
+ xmlns: "http://www.w3.org/2000/svg",
704
+ "aria-label": "Akropolys",
705
+ children: [
706
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
707
+ "path",
708
+ {
709
+ d: "M14.5 4.5 L6.5 25",
710
+ stroke: "currentColor",
711
+ strokeWidth: "2.2",
712
+ strokeLinecap: "round"
713
+ }
714
+ ),
715
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
716
+ "path",
717
+ {
718
+ d: "M14.5 4.5 L22.5 25",
719
+ stroke: "currentColor",
720
+ strokeWidth: "4.2",
721
+ strokeLinecap: "round"
722
+ }
723
+ ),
724
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
725
+ "path",
726
+ {
727
+ d: "M9.5 17 H19.5",
728
+ stroke: "currentColor",
729
+ strokeWidth: "2",
730
+ strokeLinecap: "round"
731
+ }
732
+ ),
733
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
734
+ "path",
735
+ {
736
+ d: "M3 25 H10",
737
+ stroke: "currentColor",
738
+ strokeWidth: "2",
739
+ strokeLinecap: "round"
740
+ }
741
+ ),
742
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
743
+ "path",
744
+ {
745
+ d: "M19 25 H26",
746
+ stroke: "currentColor",
747
+ strokeWidth: "2.5",
748
+ strokeLinecap: "round"
749
+ }
750
+ ),
751
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
752
+ "path",
753
+ {
754
+ d: "M8.5 2.5 C10 2.5, 11 3.5, 11 5 C11 7, 8.5 8.5, 7.5 9.5",
755
+ stroke: "currentColor",
756
+ strokeWidth: "2",
757
+ strokeLinecap: "round",
758
+ fill: "none",
759
+ className: "hsk-akr-breath"
760
+ }
761
+ )
762
+ ]
763
+ }
764
+ );
765
+ var SparkleIcon2 = AkropolysAIcon;
766
+ var ArrowUpIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
767
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m5 12 7-7 7 7" }),
768
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 19V5" })
769
+ ] });
770
+ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
771
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
772
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
773
+ ] });
774
+ var ChevronRightIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m9 18 6-6-6-6" }) });
775
+ var HistoryIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
776
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
777
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 3v5h5" }),
778
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 7v5l4 2" })
779
+ ] });
780
+ var NewChatIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 5v14M5 12h14" }) });
781
+ var ShoppingBagIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
782
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z" }),
783
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
784
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M16 10a4 4 0 0 1-8 0" })
785
+ ] });
786
+ var DEFAULT_CHIPS = [
787
+ "Cheapest smartphone",
788
+ "Smart TV under KSh 20,000",
789
+ "Noise-cancelling headphones",
790
+ "Best laptop for students"
791
+ ];
792
+ var SESSIONS_KEY = "akropolys_chat_sessions";
793
+ var MAX_SESSIONS = 20;
794
+ function loadSessions() {
795
+ try {
796
+ if (typeof window === "undefined") return [];
797
+ const raw = localStorage.getItem(SESSIONS_KEY);
798
+ return raw ? JSON.parse(raw) : [];
799
+ } catch {
800
+ return [];
801
+ }
802
+ }
803
+ function saveSessions(sessions) {
804
+ try {
805
+ if (typeof window === "undefined") return;
806
+ localStorage.setItem(SESSIONS_KEY, JSON.stringify(sessions.slice(0, MAX_SESSIONS)));
807
+ } catch {
808
+ }
809
+ }
810
+ function relativeTime(ts) {
811
+ const diff = Date.now() - ts;
812
+ const mins = Math.floor(diff / 6e4);
813
+ if (mins < 1) return "just now";
814
+ if (mins < 60) return `${mins}m ago`;
815
+ const hrs = Math.floor(mins / 60);
816
+ if (hrs < 24) return `${hrs}h ago`;
817
+ const days = Math.floor(hrs / 24);
818
+ return `${days}d ago`;
819
+ }
820
+ function CartContextCard({ cart, defaultCurrency }) {
821
+ if (!cart.items || cart.items.length === 0) return null;
822
+ const currency = cart.currency || defaultCurrency;
823
+ const total = cart.total ?? cart.items.reduce((s, i) => s + i.price_numeric * i.quantity, 0);
824
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cart-card", children: [
825
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cart-card-header", children: [
826
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ShoppingBagIcon, {}),
827
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
828
+ "Your cart \xB7 ",
829
+ cart.item_count ?? cart.items.length,
830
+ " item",
831
+ (cart.item_count ?? cart.items.length) !== 1 ? "s" : ""
832
+ ] })
833
+ ] }),
834
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cart-items", children: cart.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cart-item", children: [
835
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cart-item-img-wrap", children: [
836
+ item.image ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { className: "hsk-cart-item-img", src: item.image, alt: item.name, loading: "lazy" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cart-item-img-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ShoppingBagIcon, {}) }),
837
+ item.quantity > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hsk-cart-item-qty", children: item.quantity })
838
+ ] }),
839
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cart-item-info", children: [
840
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cart-item-name", children: item.name }),
841
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cart-item-price", children: [
842
+ item.quantity > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "hsk-cart-item-qty-label", children: [
843
+ item.quantity,
844
+ "\xD7 "
845
+ ] }),
846
+ currency,
847
+ " ",
848
+ (item.price_numeric * item.quantity).toLocaleString()
849
+ ] })
850
+ ] })
851
+ ] }, item.id)) }),
852
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cart-total", children: [
853
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Total" }),
854
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "hsk-cart-total-amount", children: [
855
+ currency,
856
+ " ",
857
+ total.toLocaleString()
858
+ ] })
859
+ ] })
860
+ ] });
861
+ }
862
+ function ActionPills({ cart, actionType, onSend, loading }) {
863
+ const hasItems = cart.items && cart.items.length > 0;
864
+ const lastItem = hasItems ? cart.items[cart.items.length - 1] : null;
865
+ const pills = [];
866
+ if (hasItems && lastItem) {
867
+ if (actionType === "add_to_cart") {
868
+ pills.push({ emoji: "\u2795", label: "Add 1 more", query: `Add one more ${lastItem.name} to my cart` });
869
+ pills.push({ emoji: "\u{1F5D1}\uFE0F", label: `Remove ${lastItem.name.split(" ")[0]}`, query: `Remove the ${lastItem.name} from my cart` });
870
+ }
871
+ if (cart.items.length > 1) {
872
+ pills.push({ emoji: "\u{1F6D2}", label: "View cart", query: "Show me my cart" });
873
+ }
874
+ pills.push({ emoji: "\u{1F4B3}", label: "Checkout", query: "Proceed to checkout" });
875
+ pills.push({ emoji: "\u{1F6CD}\uFE0F", label: "Keep shopping", query: "What else do you recommend?" });
876
+ } else if (actionType === "clear_cart" || actionType === "remove_from_cart") {
877
+ pills.push({ emoji: "\u{1F6CD}\uFE0F", label: "Continue shopping", query: "Show me popular products" });
878
+ pills.push({ emoji: "\u{1F50D}", label: "Search again", query: "Help me find something" });
879
+ } else if (actionType === "view_cart") {
880
+ if (hasItems) {
881
+ pills.push({ emoji: "\u{1F4B3}", label: "Checkout", query: "Proceed to checkout" });
882
+ pills.push({ emoji: "\u{1F5D1}\uFE0F", label: "Clear cart", query: "Clear my cart" });
883
+ }
884
+ }
885
+ if (pills.length === 0) return null;
886
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-action-pills", children: pills.map((pill) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
887
+ "button",
888
+ {
889
+ className: "hsk-action-pill",
890
+ onClick: () => onSend(pill.query),
891
+ disabled: loading,
892
+ children: [
893
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hsk-pill-emoji", children: pill.emoji }),
894
+ pill.label
895
+ ]
896
+ },
897
+ pill.query
898
+ )) });
899
+ }
900
+ function SourcesCarousel({ sources, defaultCurrency, onSelectSource }) {
901
+ const client = (0, import_sdk5.useAkropolysContext)();
902
+ const isProperty = client?.vertical === "property";
903
+ const railRef = (0, import_react3.useRef)(null);
904
+ const [showNext, setShowNext] = (0, import_react3.useState)(false);
905
+ const measure = (0, import_react3.useCallback)(() => {
906
+ const el = railRef.current;
907
+ if (!el) return;
908
+ const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 8;
909
+ setShowNext(el.scrollWidth > el.clientWidth + 4 && !atEnd);
910
+ }, []);
911
+ (0, import_react3.useEffect)(() => {
912
+ measure();
913
+ const el = railRef.current;
914
+ if (!el) return;
915
+ const ro = new ResizeObserver(measure);
916
+ ro.observe(el);
917
+ el.addEventListener("scroll", measure, { passive: true });
918
+ return () => {
919
+ ro.disconnect();
920
+ el.removeEventListener("scroll", measure);
921
+ };
922
+ }, [measure, sources]);
923
+ const scrollNext = () => {
924
+ railRef.current?.scrollBy({ left: 170, behavior: "smooth" });
925
+ };
926
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-sources-wrap", children: [
927
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-sources", ref: railRef, children: sources.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
928
+ "div",
929
+ {
930
+ className: "hsk-cb-source",
931
+ style: { animationDelay: `${si * 50}ms` },
932
+ onClick: () => onSelectSource?.(src),
933
+ children: [
934
+ src.image ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-src-imgwrap", style: { position: "relative" }, children: [
935
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: src.image, alt: src.name, loading: "lazy" }),
936
+ isProperty && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
937
+ position: "absolute",
938
+ top: "6px",
939
+ right: "6px",
940
+ background: "rgba(14, 14, 15, 0.75)",
941
+ backdropFilter: "blur(4px)",
942
+ borderRadius: "50%",
943
+ width: "24px",
944
+ height: "24px",
945
+ display: "flex",
946
+ alignItems: "center",
947
+ justifyContent: "center",
948
+ color: "#fbbf24",
949
+ // Gold sparkle badge
950
+ boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
951
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon2, { size: 12 }) })
952
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-src-imgwrap-empty", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon2, {}) }),
953
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-src-info", children: [
954
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-src-name", children: src.name }),
955
+ src.price && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-src-price", children: [
956
+ src.currency ?? defaultCurrency,
957
+ " ",
958
+ parseFloat(String(src.price).replace(/[^0-9.]/g, "") || "0").toLocaleString()
959
+ ] })
960
+ ] })
961
+ ]
962
+ },
963
+ si
964
+ )) }),
965
+ showNext && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
966
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
967
+ "div",
968
+ {
969
+ className: "hsk-cb-sources-fade",
970
+ style: { background: "linear-gradient(to right, transparent, var(--hsk-fade-bg, #0e0e0f))" }
971
+ }
972
+ ),
973
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "hsk-cb-sources-next", onClick: scrollNext, "aria-label": "See more", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronRightIcon, {}) })
974
+ ] })
975
+ ] });
976
+ }
977
+ function stripMarkdownTables(content) {
978
+ const lines = content.split("\n");
979
+ const out = [];
980
+ for (const line of lines) {
981
+ if (line.trim().startsWith("|")) continue;
982
+ out.push(line);
983
+ }
984
+ return out.join("\n").replace(/\n{3,}/g, "\n\n").trim();
985
+ }
986
+ function SmartContextPills({
987
+ intent,
988
+ sources,
989
+ onSend,
990
+ loading
991
+ }) {
992
+ const client = (0, import_sdk5.useAkropolysContext)();
993
+ const isProperty = client?.vertical === "property";
994
+ if (!intent) return null;
995
+ const pills = [];
996
+ const cheapest = sources.length > 0 ? sources.reduce((min, s) => {
997
+ const p = parseFloat(String(s.price ?? "").replace(/[^0-9.]/g, ""));
998
+ const m = parseFloat(String(min.price ?? "").replace(/[^0-9.]/g, ""));
999
+ return !isNaN(p) && (isNaN(m) || p < m) ? s : min;
1000
+ }, sources[0]) : null;
1001
+ const firstName = sources[0]?.name ?? "";
1002
+ const firstTwo = sources.slice(0, 2).map((s) => s.name);
1003
+ if (intent === "search" && sources.length > 0) {
1004
+ if (firstTwo.length >= 2) {
1005
+ pills.push({
1006
+ emoji: "\u2696\uFE0F",
1007
+ label: "Compare top 2",
1008
+ query: `Compare the ${firstTwo[0]} and ${firstTwo[1]}`
1009
+ });
1010
+ }
1011
+ if (cheapest && !isProperty) {
1012
+ const short = cheapest.name.split(" ").slice(0, 3).join(" ");
1013
+ pills.push({
1014
+ emoji: "\u{1F6D2}",
1015
+ label: `Add ${short}`,
1016
+ query: `Add the ${cheapest.name} to my cart`
1017
+ });
1018
+ }
1019
+ if (isProperty) {
1020
+ pills.push({ emoji: "\u{1F4B0}", label: "Under KSh 5M", query: "Show me options under KSh 5,000,000" });
1021
+ } else {
1022
+ pills.push({ emoji: "\u{1F4B0}", label: "Under KSh 20K", query: "Show me options under KSh 20,000" });
1023
+ }
1024
+ } else if (intent === "compare" && sources.length > 0) {
1025
+ if (cheapest && !isProperty) {
1026
+ const short = cheapest.name.split(" ").slice(0, 3).join(" ");
1027
+ pills.push({
1028
+ emoji: "\u{1F6D2}",
1029
+ label: `Add ${short}`,
1030
+ query: `Add the ${cheapest.name} to my cart`
1031
+ });
1032
+ }
1033
+ if (firstName) {
1034
+ pills.push({
1035
+ emoji: "\u{1F50D}",
1036
+ label: "Similar options",
1037
+ query: isProperty ? `Show me more properties similar to the ${firstName}` : `Show me more products similar to the ${firstName}`
1038
+ });
1039
+ }
1040
+ pills.push({ emoji: "\u{1F4A1}", label: "Which is best?", query: "Which one would you recommend and why?" });
1041
+ } else if (intent === "specs" && sources.length > 0) {
1042
+ if (firstName) {
1043
+ if (!isProperty) {
1044
+ pills.push({ emoji: "\u{1F6D2}", label: "Add to cart", query: `Add the ${firstName} to my cart` });
1045
+ }
1046
+ pills.push({
1047
+ emoji: "\u{1F504}",
1048
+ label: "Find alternatives",
1049
+ query: `What are good alternatives to the ${firstName}?`
1050
+ });
1051
+ }
1052
+ } else if (intent === "general") {
1053
+ if (isProperty) {
1054
+ pills.push({ emoji: "\u{1F50D}", label: "Show popular listings", query: "What are your most popular properties?" });
1055
+ } else {
1056
+ pills.push({ emoji: "\u{1F50D}", label: "Show popular items", query: "What are your most popular products?" });
1057
+ }
1058
+ pills.push({ emoji: "\u{1F4A1}", label: "Recommend something", query: "What do you recommend for me?" });
1059
+ }
1060
+ if (pills.length === 0) return null;
1061
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-action-pills", children: pills.map((pill) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1062
+ "button",
1063
+ {
1064
+ className: "hsk-action-pill",
1065
+ onClick: () => onSend(pill.query),
1066
+ disabled: loading,
1067
+ children: [
1068
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hsk-pill-emoji", children: pill.emoji }),
1069
+ pill.label
1070
+ ]
1071
+ },
1072
+ pill.query
1073
+ )) });
1074
+ }
1075
+ var getFriendlyError = (err) => {
1076
+ let str = "";
1077
+ if (typeof err === "string") str = err;
1078
+ else if (err && typeof err === "object" && err.message) str = err.message;
1079
+ else try {
1080
+ str = JSON.stringify(err);
1081
+ } catch {
1082
+ str = String(err);
1083
+ }
1084
+ const lower = str.toLowerCase();
1085
+ if (lower.includes("429") || lower.includes("too many requests") || lower.includes("requests per minute limit exceeded") || lower.includes("too_many_requests_error") || lower.includes("request_quota_exceeded") || lower.includes("quota")) {
1086
+ return "The assistant is currently receiving too many requests. Please try again in a few moments.";
1087
+ }
1088
+ if (lower.includes("token limit")) {
1089
+ return "You've reached your usage limit. Please update your billing limits in your dashboard to continue.";
1090
+ }
1091
+ try {
1092
+ const parsed = JSON.parse(str);
1093
+ return parsed.error || parsed.message || str;
1094
+ } catch {
1095
+ return str;
1096
+ }
1097
+ };
1098
+ var LOADING_MESSAGES = [
1099
+ "Walking down the aisle...",
1100
+ "Consulting the blueprints...",
1101
+ "Polishing the keys...",
1102
+ "Checking the backyard...",
1103
+ "Checking the inventory...",
1104
+ "Inspecting the plumbing...",
1105
+ "Asking the concierge...",
1106
+ "Searching the shelves...",
1107
+ "Measuring the square footage...",
1108
+ "Dusting off the fireplace...",
1109
+ "Asking the store clerk..."
1110
+ ];
1111
+ var PROPERTY_CHIPS = [
1112
+ "3 bedroom apartments",
1113
+ "Houses under KSh 5,000,000",
1114
+ "Properties in Palm Beach",
1115
+ "Studio apartments with pool"
1116
+ ];
1117
+ function ChatModal({
1118
+ title = "Shopping Assistant",
1119
+ placeholder = "Ask me anything \u2014 gifts, budget, use case\u2026",
1120
+ backdropColor,
1121
+ backdropBlur,
1122
+ onClose,
1123
+ onSelectSource,
1124
+ defaultCurrency = "KES",
1125
+ chips = DEFAULT_CHIPS,
1126
+ theme,
1127
+ classNames = {}
1128
+ }) {
1129
+ const client = (0, import_sdk5.useAkropolysContext)();
1130
+ const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, reset } = (0, import_sdk3.useKiku)();
1131
+ const [input, setInput] = (0, import_react3.useState)("");
1132
+ const [loadingMessageIndex, setLoadingMessageIndex] = (0, import_react3.useState)(0);
1133
+ const isProperty = client.vertical === "property";
1134
+ const activeChips = chips === DEFAULT_CHIPS && isProperty ? PROPERTY_CHIPS : chips;
1135
+ const activeTitle = title === "Shopping Assistant" && isProperty ? "Property Assistant" : title;
1136
+ const activePlaceholder = placeholder === "Ask me anything \u2014 gifts, budget, use case\u2026" && isProperty ? "Ask me anything \u2014 location, budget, bedrooms\u2026" : placeholder;
1137
+ (0, import_react3.useEffect)(() => {
1138
+ if (loading && !streaming) {
1139
+ const interval = setInterval(() => {
1140
+ setLoadingMessageIndex((prev) => (prev + 1) % LOADING_MESSAGES.length);
1141
+ }, 1500);
1142
+ return () => clearInterval(interval);
1143
+ } else {
1144
+ setLoadingMessageIndex(0);
1145
+ }
1146
+ }, [loading, streaming]);
1147
+ const [selectedProduct, setSelectedProduct] = (0, import_react3.useState)(null);
1148
+ const bottomRef = (0, import_react3.useRef)(null);
1149
+ const textareaRef = (0, import_react3.useRef)(null);
1150
+ const [phoneInput, setPhoneInput] = (0, import_react3.useState)(() => {
1151
+ if (typeof window !== "undefined") {
1152
+ return localStorage.getItem("akropolys_user_phone") || "";
1153
+ }
1154
+ return "";
1155
+ });
1156
+ const [merchantRef, setMerchantRef] = (0, import_react3.useState)(null);
1157
+ const [paymentPhase, setPaymentPhase] = (0, import_react3.useState)("idle");
1158
+ const [sessions, setSessions] = (0, import_react3.useState)(() => loadSessions());
1159
+ const [sidebarOpen, setSidebarOpen] = (0, import_react3.useState)(false);
1160
+ const [replayMessages, setReplayMessages] = (0, import_react3.useState)(null);
1161
+ const { status: pollStatus } = (0, import_sdk4.usePaymentPolling)({
1162
+ client: client.api,
1163
+ merchantReference: merchantRef,
1164
+ onSuccess: () => {
1165
+ setPaymentPhase("done");
1166
+ setMerchantRef(null);
1167
+ },
1168
+ onFailure: () => {
1169
+ setPaymentPhase("failed");
1170
+ setMerchantRef(null);
1171
+ }
1172
+ });
1173
+ (0, import_react3.useEffect)(() => {
1174
+ if (!lastAction) return;
1175
+ if (lastAction.type === "request_phone") {
1176
+ setPaymentPhase("prompt_phone");
1177
+ } else if (lastAction.type === "awaiting_payment") {
1178
+ setMerchantRef(lastAction.merchantReference ?? null);
1179
+ setPaymentPhase("awaiting");
1180
+ }
1181
+ }, [lastAction]);
1182
+ const isStringTheme = typeof theme === "string";
1183
+ const hskThemeAttr = isStringTheme ? theme : void 0;
1184
+ const customStyles = !isStringTheme && theme ? {
1185
+ ...theme?.primaryColor && { "--hsk-primary": theme.primaryColor },
1186
+ ...theme?.backgroundColor && { "--hsk-bg": theme.backgroundColor },
1187
+ ...theme?.textColor && { "--hsk-text": theme.textColor },
1188
+ ...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
1189
+ ...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
1190
+ } : void 0;
1191
+ const handlePhoneSubmit = async () => {
1192
+ if (!phoneInput.trim()) return;
1193
+ try {
1194
+ if (typeof window !== "undefined") {
1195
+ localStorage.setItem("akropolys_user_phone", phoneInput.trim());
1196
+ }
1197
+ const res = await client.api.initiatePayment(phoneInput.trim());
1198
+ setMerchantRef(res.merchantReference);
1199
+ setPaymentPhase("awaiting");
1200
+ } catch (e) {
1201
+ console.error("[Akropolys] initiatePayment error", e);
1202
+ setPaymentPhase("failed");
1203
+ }
1204
+ };
1205
+ const msgsContainerRef = (0, import_react3.useRef)(null);
1206
+ (0, import_react3.useEffect)(() => {
1207
+ const container = msgsContainerRef.current;
1208
+ if (!container) return;
1209
+ const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
1210
+ if (distanceFromBottom < 120) {
1211
+ bottomRef.current?.scrollIntoView({ behavior: "smooth" });
1212
+ }
1213
+ }, [messages, loading, selectedProduct]);
1214
+ (0, import_react3.useEffect)(() => {
1215
+ const h = (e) => {
1216
+ if (e.key === "Escape") onClose();
1217
+ };
1218
+ document.addEventListener("keydown", h);
1219
+ return () => document.removeEventListener("keydown", h);
1220
+ }, []);
1221
+ const saveCurrentSession = (0, import_react3.useCallback)(() => {
1222
+ if (messages.length < 2) return;
1223
+ const firstUser = messages.find((m) => m.role === "user");
1224
+ const session = {
1225
+ id: `session_${Date.now()}`,
1226
+ title: firstUser ? firstUser.content.slice(0, 60) : "Chat session",
1227
+ messages,
1228
+ ts: Date.now()
1229
+ };
1230
+ const updated = [session, ...sessions].slice(0, MAX_SESSIONS);
1231
+ setSessions(updated);
1232
+ saveSessions(updated);
1233
+ }, [messages, sessions]);
1234
+ const handleReset = (0, import_react3.useCallback)(() => {
1235
+ saveCurrentSession();
1236
+ reset();
1237
+ setReplayMessages(null);
1238
+ setPaymentPhase("idle");
1239
+ setMerchantRef(null);
1240
+ }, [reset, saveCurrentSession]);
1241
+ const handleSourceClick = (src) => {
1242
+ setSelectedProduct(src);
1243
+ onSelectSource?.(src);
1244
+ const q = `Tell me more about the ${src.name}${src.price ? ` (${src.currency ?? defaultCurrency} ${src.price})` : ""} \u2014 what are its key specs, who is it best for, and is it worth buying?`;
1245
+ send(q);
1246
+ };
1247
+ const handleSend = async (text) => {
1248
+ const q = (text ?? input).trim();
1249
+ if (!q || loading) return;
1250
+ setReplayMessages(null);
1251
+ setSelectedProduct(null);
1252
+ setInput("");
1253
+ if (textareaRef.current) {
1254
+ textareaRef.current.style.height = "auto";
1255
+ }
1256
+ await send(q);
1257
+ };
1258
+ const handleKeyDown = (e) => {
1259
+ if (e.key === "Enter" && !e.shiftKey) {
1260
+ e.preventDefault();
1261
+ handleSend();
1262
+ }
1263
+ };
1264
+ const handleInput = (e) => {
1265
+ setInput(e.target.value);
1266
+ const t = e.target;
1267
+ t.style.height = "auto";
1268
+ t.style.height = `${Math.min(t.scrollHeight, 140)}px`;
1269
+ };
1270
+ const blurVal = typeof backdropBlur === "number" ? `${backdropBlur}px` : backdropBlur ?? "20px";
1271
+ const displayMessages = replayMessages ?? messages;
1272
+ const loadSession = (session) => {
1273
+ setReplayMessages(session.messages);
1274
+ setSidebarOpen(false);
1275
+ };
1276
+ const deleteSession = (id, e) => {
1277
+ e.stopPropagation();
1278
+ const updated = sessions.filter((s) => s.id !== id);
1279
+ setSessions(updated);
1280
+ saveSessions(updated);
1281
+ };
1282
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1283
+ "div",
1284
+ {
1285
+ className: cn("hsk-cb-overlay", classNames.overlay),
1286
+ onClick: onClose,
1287
+ "data-hsk-theme": hskThemeAttr,
1288
+ style: {
1289
+ backdropFilter: `blur(${blurVal})`,
1290
+ WebkitBackdropFilter: `blur(${blurVal})`,
1291
+ ...backdropColor ? { background: backdropColor } : {},
1292
+ ...customStyles
1293
+ },
1294
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: cn("hsk-cb-panel hsk-cb-panel--with-sidebar", classNames.panel), onClick: (e) => e.stopPropagation(), children: [
1295
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: cn("hsk-cb-sidebar", sidebarOpen && "hsk-cb-sidebar--open"), children: [
1296
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-sidebar-header", children: [
1297
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hsk-cb-sidebar-title", children: "History" }),
1298
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1299
+ "button",
1300
+ {
1301
+ className: "hsk-cb-sidebar-new",
1302
+ onClick: handleReset,
1303
+ title: "New chat",
1304
+ children: [
1305
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(NewChatIcon, {}),
1306
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "New chat" })
1307
+ ]
1308
+ }
1309
+ )
1310
+ ] }),
1311
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-sidebar-list", children: sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-sidebar-empty", children: [
1312
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HistoryIcon, {}),
1313
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "No history yet" })
1314
+ ] }) : sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1315
+ "div",
1316
+ {
1317
+ className: cn(
1318
+ "hsk-cb-sidebar-session",
1319
+ replayMessages === session.messages && "hsk-cb-sidebar-session--active"
1320
+ ),
1321
+ onClick: () => loadSession(session),
1322
+ children: [
1323
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-sidebar-session-title", children: session.title }),
1324
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-sidebar-session-meta", children: relativeTime(session.ts) }),
1325
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1326
+ "button",
1327
+ {
1328
+ className: "hsk-cb-sidebar-session-del",
1329
+ onClick: (e) => deleteSession(session.id, e),
1330
+ title: "Delete",
1331
+ children: "\xD7"
1332
+ }
1333
+ )
1334
+ ]
1335
+ },
1336
+ session.id
1337
+ )) })
1338
+ ] }),
1339
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-main", children: [
1340
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-topbar", children: [
1341
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-topbar-left", children: [
1342
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1343
+ "button",
1344
+ {
1345
+ className: cn("hsk-cb-sidebar-toggle", sidebarOpen && "hsk-cb-sidebar-toggle--active"),
1346
+ onClick: (e) => {
1347
+ e.stopPropagation();
1348
+ setSidebarOpen((v) => !v);
1349
+ },
1350
+ "aria-label": "Toggle history",
1351
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HistoryIcon, {})
1352
+ }
1353
+ ),
1354
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hsk-cb-topbar-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon2, {}) }),
1355
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-topbar-title", children: activeTitle }) })
1356
+ ] }),
1357
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-topbar-actions", children: [
1358
+ replayMessages ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "hsk-cb-topbar-btn", onClick: () => {
1359
+ setReplayMessages(null);
1360
+ }, children: "\u2190 Live chat" }) : messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "hsk-cb-topbar-btn", onClick: handleReset, children: "Clear chat" }),
1361
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "hsk-cb-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseIcon, {}) })
1362
+ ] })
1363
+ ] }),
1364
+ replayMessages && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-replay-banner", children: [
1365
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HistoryIcon, {}),
1366
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "You're viewing a past conversation." }),
1367
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { onClick: () => setReplayMessages(null), children: "Back to chat \u2192" })
1368
+ ] }),
1369
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-msgs", ref: msgsContainerRef, children: [
1370
+ displayMessages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-empty", children: [
1371
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-empty-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon2, {}) }),
1372
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-empty-title", children: "Find exactly what you need" }),
1373
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-chips", children: activeChips.map((chip) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1374
+ "button",
1375
+ {
1376
+ className: "hsk-cb-chip",
1377
+ onClick: () => handleSend(chip),
1378
+ children: chip
1379
+ },
1380
+ chip
1381
+ )) })
1382
+ ] }) : displayMessages.map((msg, idx) => {
1383
+ const isLast = idx === displayMessages.length - 1 && !replayMessages;
1384
+ const isUser = msg.role === "user";
1385
+ const displayContent = !isUser && isLast && lastIntent === "compare" && sources.length >= 2 && !replayMessages ? stripMarkdownTables(msg.content) : msg.content;
1386
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-msg-group", children: isUser ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-user-msg", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-user-bubble", children: msg.content }) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-ai-msg", children: [
1387
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon2, {}) }),
1388
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-ai-body", children: [
1389
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-ai-text", children: renderMarkdown(displayContent) }),
1390
+ isLast && lastIntent === "compare" && sources.length >= 2 && !replayMessages && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ComparisonMatrix, { sources, defaultCurrency }),
1391
+ isLast && sources.length > 0 && lastIntent !== "compare" && lastAction?.type !== "request_phone" && lastAction?.type !== "awaiting_payment" && lastAction?.type !== "checkout" && !msg.cartSnapshot && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1392
+ SourcesCarousel,
1393
+ {
1394
+ sources,
1395
+ defaultCurrency,
1396
+ onSelectSource: handleSourceClick
1397
+ }
1398
+ ),
1399
+ msg.cartSnapshot && msg.cartSnapshot.items?.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1400
+ CartContextCard,
1401
+ {
1402
+ cart: msg.cartSnapshot,
1403
+ defaultCurrency
1404
+ }
1405
+ ),
1406
+ isLast && msg.cartSnapshot && !loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1407
+ ActionPills,
1408
+ {
1409
+ cart: msg.cartSnapshot,
1410
+ actionType: msg.actionType,
1411
+ onSend: handleSend,
1412
+ loading
1413
+ }
1414
+ ),
1415
+ isLast && !loading && !msg.cartSnapshot && !replayMessages && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1416
+ SmartContextPills,
1417
+ {
1418
+ intent: lastIntent,
1419
+ sources,
1420
+ onSend: handleSend,
1421
+ loading
1422
+ }
1423
+ )
1424
+ ] })
1425
+ ] }) }, idx);
1426
+ }),
1427
+ selectedProduct && loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1428
+ "div",
1429
+ {
1430
+ className: "hsk-cb-selected-product",
1431
+ onClick: () => selectedProduct.url && window.open(selectedProduct.url, "_blank"),
1432
+ children: [
1433
+ selectedProduct.image && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { className: "hsk-cb-selected-img", src: selectedProduct.image, alt: selectedProduct.name }),
1434
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-selected-info", children: [
1435
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-selected-name", children: selectedProduct.name }),
1436
+ selectedProduct.price && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-selected-price", children: [
1437
+ selectedProduct.currency ?? defaultCurrency,
1438
+ " ",
1439
+ parseFloat(String(selectedProduct.price ?? "").replace(/[^0-9.]/g, "") || "0").toLocaleString()
1440
+ ] })
1441
+ ] })
1442
+ ]
1443
+ }
1444
+ ),
1445
+ loading && !streaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-typing-row", style: { display: "flex", alignItems: "flex-start", gap: "10px" }, children: [
1446
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center", marginTop: "4px" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon2, {}) }),
1447
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [
1448
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
1449
+ @keyframes hsk-pulse {
1450
+ 0%, 100% { opacity: 0.6; }
1451
+ 50% { opacity: 1; }
1452
+ }
1453
+ ` }),
1454
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "0.85rem", color: "#6b7280", fontStyle: "italic", animation: "hsk-pulse 1.5s infinite ease-in-out" }, children: LOADING_MESSAGES[loadingMessageIndex] }),
1455
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-typing", style: { margin: 0, alignSelf: "flex-start" }, children: [
1456
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-dot" }),
1457
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-dot" }),
1458
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-dot" })
1459
+ ] })
1460
+ ] })
1461
+ ] }),
1462
+ error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-error", children: getFriendlyError(error) }),
1463
+ !replayMessages && paymentPhase === "prompt_phone" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-payment-prompt", children: [
1464
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-payment-icon", children: "\u{1F4F1}" }),
1465
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "hsk-cb-payment-label", children: "Enter your M-Pesa number to pay" }),
1466
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1467
+ "input",
1468
+ {
1469
+ type: "tel",
1470
+ className: "hsk-cb-phone-input",
1471
+ placeholder: "e.g. 0712 345 678",
1472
+ value: phoneInput,
1473
+ onChange: (e) => setPhoneInput(e.target.value),
1474
+ onKeyDown: (e) => e.key === "Enter" && handlePhoneSubmit()
1475
+ }
1476
+ ),
1477
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "hsk-cb-pay-submit", onClick: handlePhoneSubmit, children: "Send STK Push \u2192" })
1478
+ ] }),
1479
+ !replayMessages && paymentPhase === "awaiting" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-payment-prompt hsk-cb-payment-prompt--awaiting", children: [
1480
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-payment-pulse-ring" }),
1481
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-payment-icon-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { fontSize: "2rem" }, children: "\u{1F4F1}" }) }),
1482
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "hsk-cb-payment-label", style: { fontWeight: 600 }, children: "Check your phone" }),
1483
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "hsk-cb-payment-sub", children: [
1484
+ "An M-Pesa STK push has been sent.",
1485
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("br", {}),
1486
+ "Enter your PIN to complete payment."
1487
+ ] }),
1488
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-payment-dots", children: [
1489
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-dot hsk-cb-dot--amber" }),
1490
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-dot hsk-cb-dot--amber" }),
1491
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-dot hsk-cb-dot--amber" })
1492
+ ] })
1493
+ ] }),
1494
+ !replayMessages && paymentPhase === "done" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-payment-prompt hsk-cb-payment-prompt--success", children: [
1495
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-payment-success-ring" }),
1496
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-payment-icon-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { fontSize: "2.5rem" }, children: "\u2705" }) }),
1497
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "hsk-cb-payment-label", children: "Payment complete!" }),
1498
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "hsk-cb-payment-sub", children: "Thank you for your order. A confirmation has been sent." })
1499
+ ] }),
1500
+ !replayMessages && paymentPhase === "failed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-payment-prompt hsk-cb-payment-prompt--failed", children: [
1501
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-payment-icon-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { fontSize: "2.5rem" }, children: "\u274C" }) }),
1502
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "hsk-cb-payment-label", children: "Payment failed or timed out" }),
1503
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "hsk-cb-payment-sub", children: "Please check your M-Pesa PIN and try again, or contact support." }),
1504
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-payment-actions", children: [
1505
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1506
+ "button",
1507
+ {
1508
+ className: "hsk-cb-pay-submit",
1509
+ onClick: () => {
1510
+ setPaymentPhase("prompt_phone");
1511
+ setMerchantRef(null);
1512
+ },
1513
+ children: "Try again"
1514
+ }
1515
+ ),
1516
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1517
+ "button",
1518
+ {
1519
+ className: "hsk-cb-pay-secondary",
1520
+ onClick: () => {
1521
+ setPaymentPhase("idle");
1522
+ setMerchantRef(null);
1523
+ },
1524
+ children: "Cancel"
1525
+ }
1526
+ )
1527
+ ] })
1528
+ ] }),
1529
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: bottomRef, style: { height: 1 } })
1530
+ ] }),
1531
+ !replayMessages && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-input-wrap", children: [
1532
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-cb-input-box", children: [
1533
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1534
+ "textarea",
1535
+ {
1536
+ ref: textareaRef,
1537
+ className: cn("hsk-cb-textarea", classNames.input),
1538
+ value: input,
1539
+ onChange: handleInput,
1540
+ onKeyDown: handleKeyDown,
1541
+ placeholder: activePlaceholder,
1542
+ rows: 1,
1543
+ disabled: loading,
1544
+ autoFocus: true
1545
+ }
1546
+ ),
1547
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1548
+ "button",
1549
+ {
1550
+ className: cn("hsk-cb-send", classNames.sendButton),
1551
+ onClick: () => handleSend(),
1552
+ disabled: !input.trim() || loading,
1553
+ "aria-label": "Send message",
1554
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ArrowUpIcon2, {})
1555
+ }
1556
+ )
1557
+ ] }),
1558
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-hint", children: "Akropolys AI \xB7 searches the whole catalogue in real time" })
1559
+ ] })
1560
+ ] })
1561
+ ] })
1562
+ }
1563
+ );
1564
+ }
1565
+ function KikuButton({
1566
+ label,
1567
+ title,
1568
+ placeholder,
1569
+ backdropColor,
1570
+ backdropBlur,
1571
+ className,
1572
+ onSelectSource,
1573
+ defaultCurrency,
1574
+ chips,
1575
+ theme,
1576
+ classNames = {}
1577
+ }) {
1578
+ const [open, setOpen] = (0, import_react3.useState)(false);
1579
+ const [mounted, setMounted] = (0, import_react3.useState)(false);
1580
+ (0, import_react3.useEffect)(() => {
1581
+ setMounted(true);
1582
+ if (typeof window !== "undefined" && !window.__akropolys_nav_patched) {
1583
+ window.__akropolys_nav_patched = true;
1584
+ const originalPush = window.history.pushState;
1585
+ const originalReplace = window.history.replaceState;
1586
+ window.history.pushState = function(...args) {
1587
+ originalPush.apply(this, args);
1588
+ window.dispatchEvent(new CustomEvent("akropolys:navigation"));
1589
+ };
1590
+ window.history.replaceState = function(...args) {
1591
+ originalReplace.apply(this, args);
1592
+ window.dispatchEvent(new CustomEvent("akropolys:navigation"));
1593
+ };
1594
+ }
1595
+ const handleNavigation = () => {
1596
+ setOpen(false);
1597
+ };
1598
+ window.addEventListener("popstate", handleNavigation);
1599
+ window.addEventListener("akropolys:navigation", handleNavigation);
1600
+ return () => {
1601
+ window.removeEventListener("popstate", handleNavigation);
1602
+ window.removeEventListener("akropolys:navigation", handleNavigation);
1603
+ };
1604
+ }, []);
1605
+ const isStringTheme = typeof theme === "string";
1606
+ const hskThemeAttr = isStringTheme ? theme : void 0;
1607
+ const customStyles = !isStringTheme && theme ? {
1608
+ ...theme?.primaryColor && { "--hsk-primary": theme.primaryColor },
1609
+ ...theme?.backgroundColor && { "--hsk-bg": theme.backgroundColor },
1610
+ ...theme?.textColor && { "--hsk-text": theme.textColor },
1611
+ ...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
1612
+ ...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
1613
+ } : void 0;
1614
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1615
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1616
+ "button",
1617
+ {
1618
+ className: cn("hsk-cb-btn", classNames.button, className),
1619
+ onClick: () => setOpen(true),
1620
+ style: customStyles,
1621
+ "data-hsk-theme": hskThemeAttr,
1622
+ "aria-label": "Open AI chat",
1623
+ children: [
1624
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hsk-cb-btn-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon2, {}) }),
1625
+ label !== void 0 ? label : null
1626
+ ]
1627
+ }
1628
+ ),
1629
+ open && mounted && (0, import_react_dom.createPortal)(
1630
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1631
+ ChatModal,
1632
+ {
1633
+ title,
1634
+ placeholder,
1635
+ backdropColor,
1636
+ backdropBlur,
1637
+ onClose: () => setOpen(false),
1638
+ onSelectSource,
1639
+ defaultCurrency,
1640
+ chips,
1641
+ theme,
1642
+ classNames
1643
+ }
1644
+ ),
1645
+ document.body
1646
+ )
1647
+ ] });
1648
+ }
1649
+
1650
+ // src/components/Sparkle.tsx
1651
+ var import_react4 = require("react");
1652
+ var import_react_dom2 = require("react-dom");
1653
+ var import_sdk6 = require("@akropolys/sdk");
1654
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1655
+ var SparkleIcon3 = ({ className, size = 16 }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1656
+ "svg",
1657
+ {
1658
+ className: cn("hsk-brand-a", className),
1659
+ width: size,
1660
+ height: size,
1661
+ viewBox: "0 0 28 30",
1662
+ fill: "none",
1663
+ xmlns: "http://www.w3.org/2000/svg",
1664
+ "aria-label": "Akropolys",
1665
+ children: [
1666
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1667
+ "path",
1668
+ {
1669
+ d: "M14.5 4.5 L6.5 25",
1670
+ stroke: "currentColor",
1671
+ strokeWidth: "2.2",
1672
+ strokeLinecap: "round"
1673
+ }
1674
+ ),
1675
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1676
+ "path",
1677
+ {
1678
+ d: "M14.5 4.5 L22.5 25",
1679
+ stroke: "currentColor",
1680
+ strokeWidth: "4.2",
1681
+ strokeLinecap: "round"
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1685
+ "path",
1686
+ {
1687
+ d: "M9.5 17 H19.5",
1688
+ stroke: "currentColor",
1689
+ strokeWidth: "2",
1690
+ strokeLinecap: "round"
1691
+ }
1692
+ ),
1693
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1694
+ "path",
1695
+ {
1696
+ d: "M3 25 H10",
1697
+ stroke: "currentColor",
1698
+ strokeWidth: "2",
1699
+ strokeLinecap: "round"
1700
+ }
1701
+ ),
1702
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1703
+ "path",
1704
+ {
1705
+ d: "M19 25 H26",
1706
+ stroke: "currentColor",
1707
+ strokeWidth: "2.5",
1708
+ strokeLinecap: "round"
1709
+ }
1710
+ ),
1711
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1712
+ "path",
1713
+ {
1714
+ d: "M8.5 2.5 C10 2.5, 11 3.5, 11 5 C11 7, 8.5 8.5, 7.5 9.5",
1715
+ stroke: "currentColor",
1716
+ strokeWidth: "2",
1717
+ strokeLinecap: "round",
1718
+ fill: "none",
1719
+ className: "hsk-akr-breath"
1720
+ }
1721
+ )
1722
+ ]
1723
+ }
1724
+ );
1725
+ var CloseIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
1726
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1727
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1728
+ ] });
1729
+ var ArrowUpIcon3 = () => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1730
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m5 12 7-7 7 7" }),
1731
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 19V5" })
1732
+ ] });
1733
+ var getFriendlyError2 = (err) => {
1734
+ let str = "";
1735
+ if (typeof err === "string") str = err;
1736
+ else if (err && typeof err === "object" && err.message) str = err.message;
1737
+ else try {
1738
+ str = JSON.stringify(err);
1739
+ } catch {
1740
+ str = String(err);
1741
+ }
1742
+ if (str.toLowerCase().includes("token limit")) {
1743
+ return "You've reached your usage limit. Please update your billing limits in your dashboard to continue.";
1744
+ }
1745
+ try {
1746
+ const parsed = JSON.parse(str);
1747
+ return parsed.error || parsed.message || str;
1748
+ } catch {
1749
+ return str;
1750
+ }
1751
+ };
1752
+ function SparkleModal({
1753
+ productName,
1754
+ limit,
1755
+ backdropColor,
1756
+ backdropBlur,
1757
+ onClose,
1758
+ onNavigate,
1759
+ onResult,
1760
+ theme,
1761
+ classNames = {},
1762
+ product: initialProduct
1763
+ }) {
1764
+ const client = (0, import_sdk6.useAkropolysContext)();
1765
+ const [fetchedProduct, setFetchedProduct] = (0, import_react4.useState)(null);
1766
+ const displayProduct = initialProduct || fetchedProduct;
1767
+ const { results, loading: searchLoading, search } = (0, import_sdk6.useSearch)();
1768
+ const { messages, sources, loading: chatLoading, error: chatError, send } = (0, import_sdk6.useKiku)();
1769
+ const [chatInput, setChatInput] = (0, import_react4.useState)("");
1770
+ const chatBottomRef = (0, import_react4.useRef)(null);
1771
+ const chatTextareaRef = (0, import_react4.useRef)(null);
1772
+ (0, import_react4.useEffect)(() => {
1773
+ if (!initialProduct && !fetchedProduct) {
1774
+ client.api.searchVector(productName, 1).then((res) => {
1775
+ if (res.results && res.results.length > 0) {
1776
+ setFetchedProduct(res.results[0].product);
1777
+ }
1778
+ }).catch((err) => console.error("[Akropolys] Failed to fetch product details", err));
1779
+ }
1780
+ search(productName, limit);
1781
+ }, [productName, initialProduct, fetchedProduct, client, limit, search]);
1782
+ (0, import_react4.useEffect)(() => {
1783
+ if (results.length > 0) onResult?.(results);
1784
+ }, [results, onResult]);
1785
+ (0, import_react4.useEffect)(() => {
1786
+ const h = (e) => {
1787
+ if (e.key === "Escape") onClose();
1788
+ };
1789
+ document.addEventListener("keydown", h);
1790
+ return () => document.removeEventListener("keydown", h);
1791
+ }, [onClose]);
1792
+ (0, import_react4.useEffect)(() => {
1793
+ chatBottomRef.current?.scrollIntoView({ behavior: "smooth" });
1794
+ }, [messages, chatLoading]);
1795
+ const blurVal = typeof backdropBlur === "number" ? `${backdropBlur}px` : backdropBlur ?? "16px";
1796
+ const bg = backdropColor ?? void 0;
1797
+ const handleNav = (r) => {
1798
+ const prevent = onNavigate?.(r);
1799
+ if (prevent !== false) {
1800
+ onClose();
1801
+ if (r.product.url) window.location.href = r.product.url;
1802
+ }
1803
+ };
1804
+ const handleSend = async (text) => {
1805
+ const q = (text ?? chatInput).trim();
1806
+ if (!q || chatLoading) return;
1807
+ setChatInput("");
1808
+ if (chatTextareaRef.current) {
1809
+ chatTextareaRef.current.style.height = "auto";
1810
+ }
1811
+ if (messages.length === 0 && displayProduct) {
1812
+ const contextQuery = `[Context: Shopper is viewing "${displayProduct.name}". Price: ${displayProduct.price}. Description: ${displayProduct.description || ""}]
1813
+
1814
+ Question: ${q}`;
1815
+ await send(contextQuery, q);
1816
+ } else {
1817
+ await send(q);
1818
+ }
1819
+ };
1820
+ const handleKeyDown = (e) => {
1821
+ if (e.key === "Enter" && !e.shiftKey) {
1822
+ e.preventDefault();
1823
+ handleSend();
1824
+ }
1825
+ };
1826
+ const handleInput = (e) => {
1827
+ setChatInput(e.target.value);
1828
+ const t = e.target;
1829
+ t.style.height = "auto";
1830
+ t.style.height = `${Math.min(t.scrollHeight, 140)}px`;
1831
+ };
1832
+ const customStyles = {
1833
+ ...theme?.primaryColor && { "--hsk-primary": theme.primaryColor },
1834
+ ...theme?.backgroundColor && { "--hsk-bg": theme.backgroundColor },
1835
+ ...theme?.textColor && { "--hsk-text": theme.textColor },
1836
+ ...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
1837
+ ...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
1838
+ };
1839
+ const displayMessages = messages.length === 0 && displayProduct ? [
1840
+ {
1841
+ role: "assistant",
1842
+ content: `Hi! I can help you with **${displayProduct.name}**. Ask me about its specifications, features, compare it with other options, or find alternatives!`
1843
+ }
1844
+ ] : messages;
1845
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1846
+ "div",
1847
+ {
1848
+ className: cn("hsk-sp-backdrop", classNames.backdrop),
1849
+ onClick: onClose,
1850
+ style: {
1851
+ backdropFilter: `blur(${blurVal})`,
1852
+ WebkitBackdropFilter: `blur(${blurVal})`,
1853
+ background: bg ?? void 0,
1854
+ ...customStyles
1855
+ },
1856
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: cn("hsk-sp-card hsk-sp-fullscreen", classNames.card), onClick: (e) => e.stopPropagation(), children: [
1857
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-header", children: [
1858
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-header-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparkleIcon3, {}) }),
1859
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-header-body", children: [
1860
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-header-title", children: displayProduct?.name || productName }),
1861
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-header-sub", children: "Ask questions, compare specs, or check similar products" })
1862
+ ] }),
1863
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "hsk-sp-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon2, {}) })
1864
+ ] }),
1865
+ searchLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-bar" }),
1866
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-body", children: [
1867
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-details-pane", children: [
1868
+ displayProduct && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-product-profile-container", children: [
1869
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-product-profile", children: [
1870
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-details-imgwrap", children: displayProduct.images?.[0] ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: displayProduct.images[0], alt: displayProduct.name }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-img-placeholder", children: "\u{1F6CD}" }) }),
1871
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-details-meta", children: [
1872
+ displayProduct.brand && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-item-brand", children: displayProduct.brand }),
1873
+ displayProduct.category && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-item-cat", children: displayProduct.category }),
1874
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "hsk-sp-details-name", children: displayProduct.name }),
1875
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-item-price-row", children: [
1876
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-item-currency", children: displayProduct.currency ?? "KES" }),
1877
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-item-price", children: parseFloat(displayProduct.price?.replace(/[^0-9.]/g, "") || "0").toLocaleString() }),
1878
+ displayProduct.originalPrice && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-item-original-price", children: parseFloat(displayProduct.originalPrice.replace(/[^0-9.]/g, "") || "0").toLocaleString() }),
1879
+ displayProduct.discount && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "hsk-sp-item-discount", children: [
1880
+ "(",
1881
+ displayProduct.discount,
1882
+ ")"
1883
+ ] })
1884
+ ] }),
1885
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-item-meta-badges", children: [
1886
+ displayProduct.rating && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "hsk-sp-meta-badge hsk-sp-meta-badge-rating", children: [
1887
+ "\u2605 ",
1888
+ parseFloat(displayProduct.rating.toString()).toFixed(1),
1889
+ " ",
1890
+ displayProduct.reviewCount ? `(${displayProduct.reviewCount})` : ""
1891
+ ] }),
1892
+ displayProduct.availability && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `hsk-sp-meta-badge hsk-sp-meta-badge-avail ${displayProduct.availability.toLowerCase().includes("in") ? "in-stock" : "out-stock"}`, children: displayProduct.availability }),
1893
+ displayProduct.stock && !displayProduct.availability && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "hsk-sp-meta-badge hsk-sp-meta-badge-stock", children: [
1894
+ "Stock: ",
1895
+ displayProduct.stock
1896
+ ] })
1897
+ ] })
1898
+ ] })
1899
+ ] }),
1900
+ displayProduct.specs && Object.keys(displayProduct.specs).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-specs-horizontal", children: Object.entries(displayProduct.specs).map(([key, val]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-spec-item-horizontal", children: [
1901
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "hsk-sp-spec-label-horizontal", children: [
1902
+ key,
1903
+ ":"
1904
+ ] }),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-spec-value-horizontal", title: val, children: val })
1906
+ ] }, key)) }),
1907
+ displayProduct.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-details-desc", children: [
1908
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h4", { children: "Description" }),
1909
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: displayProduct.description })
1910
+ ] })
1911
+ ] }),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-similar-section", children: [
1913
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: "Similar Products" }),
1914
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-results", children: (() => {
1915
+ const similarProducts = results.filter(
1916
+ (r) => {
1917
+ const isSameName = r.product.name.toLowerCase() === displayProduct?.name?.toLowerCase();
1918
+ const isSameSlug = r.product.slug && displayProduct?.slug && r.product.slug.toLowerCase() === displayProduct.slug.toLowerCase();
1919
+ return !isSameName && !isSameSlug;
1920
+ }
1921
+ );
1922
+ if (!searchLoading && similarProducts.length === 0) {
1923
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-empty", children: "No similar products found." });
1924
+ }
1925
+ return similarProducts.map((r, i) => {
1926
+ const price = parseFloat(r.product.price?.replace(/[^0-9.]/g, "") || "0");
1927
+ const currency = r.product.currency ?? "KES";
1928
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1929
+ "div",
1930
+ {
1931
+ className: cn("hsk-sp-item", classNames.item),
1932
+ style: { animationDelay: `${i * 55}ms` },
1933
+ children: [
1934
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-img-wrap", children: r.product.images?.[0] ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: r.product.images[0], alt: r.product.name }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-img-placeholder", children: "\u{1F6CD}" }) }),
1935
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-item-body", children: [
1936
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
1937
+ r.product.category && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-item-cat", children: r.product.category }),
1938
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-item-name", title: r.product.name, children: r.product.name })
1939
+ ] }),
1940
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-item-price-row", children: [
1941
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-item-currency", children: currency }),
1942
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-item-price", children: price.toLocaleString() })
1943
+ ] }),
1944
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-actions", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1945
+ "button",
1946
+ {
1947
+ className: "hsk-sp-action hsk-sp-action-primary",
1948
+ onClick: () => handleNav(r),
1949
+ children: "View"
1950
+ }
1951
+ ) })
1952
+ ] })
1953
+ ]
1954
+ },
1955
+ r.id
1956
+ );
1957
+ });
1958
+ })() })
1959
+ ] })
1960
+ ] }),
1961
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-sp-chat-pane", children: [
1962
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-msgs", children: [
1963
+ displayMessages.map((msg, idx) => {
1964
+ const isUser = msg.role === "user";
1965
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-msg-group", children: isUser ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-user-msg", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-user-bubble", children: msg.content }) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-ai-msg", children: [
1966
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparkleIcon3, {}) }),
1967
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-ai-text", children: renderMarkdown(msg.content) }) })
1968
+ ] }) }, idx);
1969
+ }),
1970
+ chatLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-typing-row", children: [
1971
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparkleIcon3, {}) }),
1972
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-typing", children: [
1973
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-dot" }),
1974
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-dot" }),
1975
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-dot" })
1976
+ ] })
1977
+ ] }),
1978
+ chatError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-error", children: getFriendlyError2(chatError) }),
1979
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: chatBottomRef, style: { height: 1 } })
1980
+ ] }),
1981
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-input-wrap", children: [
1982
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "hsk-cb-input-box", children: [
1983
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1984
+ "textarea",
1985
+ {
1986
+ ref: chatTextareaRef,
1987
+ className: "hsk-cb-textarea",
1988
+ value: chatInput,
1989
+ onChange: handleInput,
1990
+ onKeyDown: handleKeyDown,
1991
+ placeholder: "Ask about this product, specs, or comparison...",
1992
+ rows: 1,
1993
+ disabled: chatLoading
1994
+ }
1995
+ ),
1996
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1997
+ "button",
1998
+ {
1999
+ className: "hsk-cb-send",
2000
+ onClick: () => handleSend(),
2001
+ disabled: !chatInput.trim() || chatLoading,
2002
+ "aria-label": "Send message",
2003
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ArrowUpIcon3, {})
2004
+ }
2005
+ )
2006
+ ] }),
2007
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-cb-hint", children: "Akropolys \xB7 instant product knowledge" })
2008
+ ] })
2009
+ ] })
2010
+ ] }),
2011
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "hsk-sp-footer", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hsk-sp-esc", children: "Esc to close" }) })
2012
+ ] })
2013
+ }
2014
+ );
2015
+ }
2016
+ function Sparkle({
2017
+ productName,
2018
+ limit = 8,
2019
+ onResult,
2020
+ backdropColor,
2021
+ backdropBlur,
2022
+ className,
2023
+ onNavigate,
2024
+ theme,
2025
+ classNames = {},
2026
+ product
2027
+ }) {
2028
+ const [open, setOpen] = (0, import_react4.useState)(false);
2029
+ const [mounted, setMounted] = (0, import_react4.useState)(false);
2030
+ (0, import_react4.useEffect)(() => {
2031
+ setMounted(true);
2032
+ }, []);
2033
+ const customStyles = {
2034
+ ...theme?.primaryColor && { "--hsk-primary": theme.primaryColor },
2035
+ ...theme?.backgroundColor && { "--hsk-bg": theme.backgroundColor },
2036
+ ...theme?.textColor && { "--hsk-text": theme.textColor },
2037
+ ...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
2038
+ ...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
2039
+ };
2040
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2041
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2042
+ "button",
2043
+ {
2044
+ className: cn("hsk-sp-btn", classNames.button, className),
2045
+ onClick: () => setOpen(true),
2046
+ style: customStyles,
2047
+ title: "Find similar products",
2048
+ "aria-label": "Find similar products",
2049
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparkleIcon3, {})
2050
+ }
2051
+ ),
2052
+ open && mounted && (0, import_react_dom2.createPortal)(
2053
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2054
+ SparkleModal,
2055
+ {
2056
+ productName,
2057
+ limit,
2058
+ onResult,
2059
+ backdropColor,
2060
+ backdropBlur,
2061
+ onClose: () => setOpen(false),
2062
+ onNavigate,
2063
+ theme,
2064
+ classNames,
2065
+ product
2066
+ }
2067
+ ),
2068
+ document.body
2069
+ )
2070
+ ] });
2071
+ }
2072
+
2073
+ // src/components/CartBadge.tsx
2074
+ var import_sdk7 = require("@akropolys/sdk");
2075
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2076
+ function CartBadge({ className }) {
2077
+ const { cart } = (0, import_sdk7.useCart)();
2078
+ if (!cart || cart.item_count === 0) return null;
2079
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: cn("hsk-cart-badge", className), children: cart.item_count });
2080
+ }
2081
+
2082
+ // src/components/CartDrawer.tsx
2083
+ var import_react6 = require("react");
2084
+ var import_react_dom4 = require("react-dom");
2085
+ var import_sdk9 = require("@akropolys/sdk");
2086
+
2087
+ // src/components/CheckoutModal.tsx
2088
+ var import_react5 = require("react");
2089
+ var import_react_dom3 = require("react-dom");
2090
+ var import_sdk8 = require("@akropolys/sdk");
2091
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2092
+ function CheckoutModal({
2093
+ onClose,
2094
+ theme,
2095
+ customStyles,
2096
+ hskThemeAttr
2097
+ }) {
2098
+ const { cart, loading: cartLoading } = (0, import_sdk8.useCart)();
2099
+ const client = (0, import_sdk8.useAkropolysContext)();
2100
+ const [config, setConfig] = (0, import_react5.useState)(null);
2101
+ const [loadingConfig, setLoadingConfig] = (0, import_react5.useState)(true);
2102
+ const [phone, setPhone] = (0, import_react5.useState)(() => {
2103
+ if (typeof window !== "undefined") {
2104
+ return localStorage.getItem("akropolys_user_phone") || "";
2105
+ }
2106
+ return "";
2107
+ });
2108
+ const [email, setEmail] = (0, import_react5.useState)(() => {
2109
+ if (typeof window !== "undefined") {
2110
+ return localStorage.getItem("akropolys_user_email") || "";
2111
+ }
2112
+ return "";
2113
+ });
2114
+ const [firstName, setFirstName] = (0, import_react5.useState)(() => {
2115
+ if (typeof window !== "undefined") {
2116
+ return localStorage.getItem("akropolys_user_firstname") || "";
2117
+ }
2118
+ return "";
2119
+ });
2120
+ const [lastName, setLastName] = (0, import_react5.useState)(() => {
2121
+ if (typeof window !== "undefined") {
2122
+ return localStorage.getItem("akropolys_user_lastname") || "";
2123
+ }
2124
+ return "";
2125
+ });
2126
+ const [phase, setPhase] = (0, import_react5.useState)("idle");
2127
+ const [merchantRef, setMerchantRef] = (0, import_react5.useState)(null);
2128
+ const [payError, setPayError] = (0, import_react5.useState)(null);
2129
+ const {} = (0, import_sdk8.usePaymentPolling)({
2130
+ client: client.api,
2131
+ merchantReference: merchantRef,
2132
+ onSuccess: () => {
2133
+ setPhase("done");
2134
+ setMerchantRef(null);
2135
+ },
2136
+ onFailure: () => {
2137
+ setPhase("failed");
2138
+ setPayError("Payment failed or timed out. Please try again.");
2139
+ setMerchantRef(null);
2140
+ }
2141
+ });
2142
+ (0, import_react5.useEffect)(() => {
2143
+ client.api.getCheckoutConfig().then((res) => setConfig(res.payment_methods)).catch(() => {
2144
+ }).finally(() => setLoadingConfig(false));
2145
+ }, [client]);
2146
+ const hasPaymentMethods = config && Object.values(config).some((m) => m.enabled);
2147
+ const handlePay = async (e) => {
2148
+ e.preventDefault();
2149
+ if (!phone.trim()) {
2150
+ setPayError("Phone number is required.");
2151
+ return;
2152
+ }
2153
+ setPayError(null);
2154
+ setPhase("awaiting");
2155
+ try {
2156
+ if (typeof window !== "undefined") {
2157
+ localStorage.setItem("akropolys_user_phone", phone.trim());
2158
+ localStorage.setItem("akropolys_user_email", email.trim());
2159
+ localStorage.setItem("akropolys_user_firstname", firstName.trim());
2160
+ localStorage.setItem("akropolys_user_lastname", lastName.trim());
2161
+ }
2162
+ const res = await client.api.initiatePayment(phone.trim(), email, firstName, lastName);
2163
+ if (res?.merchantReference) {
2164
+ setMerchantRef(res.merchantReference);
2165
+ } else {
2166
+ throw new Error("No merchant reference returned.");
2167
+ }
2168
+ } catch (err) {
2169
+ setPhase("failed");
2170
+ setPayError(err.message || "Could not connect to payment processor.");
2171
+ }
2172
+ };
2173
+ const currency = cart?.currency || "KES";
2174
+ const total = cart?.total || 0;
2175
+ const backdropStyle = { ...customStyles, fontSize: "15px", fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif', zIndex: 999999 };
2176
+ return (0, import_react_dom3.createPortal)(
2177
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2178
+ "div",
2179
+ {
2180
+ className: "hsk-checkout-backdrop-full",
2181
+ style: backdropStyle,
2182
+ "data-hsk-theme": hskThemeAttr,
2183
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2184
+ "div",
2185
+ {
2186
+ className: "hsk-checkout-modal-full",
2187
+ style: customStyles,
2188
+ "data-hsk-theme": hskThemeAttr,
2189
+ children: [
2190
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2191
+ "button",
2192
+ {
2193
+ onClick: (e) => {
2194
+ e.preventDefault();
2195
+ e.stopPropagation();
2196
+ onClose();
2197
+ },
2198
+ className: "hsk-checkout-close-x",
2199
+ "aria-label": "Close checkout",
2200
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2201
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2202
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2203
+ ] })
2204
+ }
2205
+ ),
2206
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-checkout-panel-left", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-left-content", children: [
2207
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { onClick: (e) => {
2208
+ e.preventDefault();
2209
+ e.stopPropagation();
2210
+ onClose();
2211
+ }, className: "hsk-checkout-back-btn", children: [
2212
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2213
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "19", y1: "12", x2: "5", y2: "12" }),
2214
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "12 19 5 12 12 5" })
2215
+ ] }),
2216
+ "Back to store"
2217
+ ] }),
2218
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-checkout-store-info", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { children: "Secure Checkout" }) }),
2219
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-amount-due", children: [
2220
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "hsk-checkout-label-muted", children: "Pay total" }),
2221
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-grand-total", children: [
2222
+ currency,
2223
+ " ",
2224
+ total.toLocaleString(void 0, { minimumFractionDigits: 2 })
2225
+ ] })
2226
+ ] }),
2227
+ cartLoading || !cart ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "hsk-cart-loading", children: "Loading order..." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-checkout-items-list-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "hsk-checkout-items-list", children: cart.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { className: "hsk-checkout-item-row", children: [
2228
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-item-img-container", children: [
2229
+ item.image ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("img", { src: item.image, alt: item.name, className: "hsk-checkout-item-img" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-checkout-item-img-placeholder", children: "\u{1F6D2}" }),
2230
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "hsk-checkout-item-qty-badge", children: item.quantity })
2231
+ ] }),
2232
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-checkout-item-details", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "hsk-checkout-item-name", children: item.name }) }),
2233
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "hsk-checkout-item-price", children: [
2234
+ item.currency,
2235
+ " ",
2236
+ (item.price_numeric * item.quantity).toLocaleString(void 0, { minimumFractionDigits: 2 })
2237
+ ] })
2238
+ ] }, item.id)) }) })
2239
+ ] }) }),
2240
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-checkout-panel-right", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-checkout-right-content", children: phase === "done" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-status-card success", children: [
2241
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-status-icon-wrap success", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2242
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
2243
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "22 4 12 14.01 9 11.01" })
2244
+ ] }) }),
2245
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "Payment Successful!" }),
2246
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "Your transaction has been confirmed. Thank you for your order!" }),
2247
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: onClose, className: "hsk-pay-btn hsk-btn-primary", style: { marginTop: "1.5rem" }, children: "Continue Shopping" })
2248
+ ] }) : phase === "awaiting" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-status-card awaiting", children: [
2249
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-status-spinner-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-status-spinner" }) }),
2250
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "Confirm payment on your phone" }),
2251
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { children: [
2252
+ "We've sent an M-Pesa STK push prompt to ",
2253
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("strong", { children: [
2254
+ "254",
2255
+ phone
2256
+ ] }),
2257
+ "."
2258
+ ] }),
2259
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-stk-instructions", children: [
2260
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "1. Check your phone lockscreen for the M-Pesa prompt." }),
2261
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "2. Enter your M-Pesa PIN and press OK." }),
2262
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "3. Wait here \u2014 this page auto-updates once confirmed." })
2263
+ ] }),
2264
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2265
+ "button",
2266
+ {
2267
+ onClick: () => {
2268
+ setPhase("cancelled");
2269
+ setMerchantRef(null);
2270
+ },
2271
+ className: "hsk-checkout-cancel-btn",
2272
+ children: "Cancel payment"
2273
+ }
2274
+ )
2275
+ ] }) : phase === "cancelled" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-status-card cancelled", children: [
2276
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-status-icon-wrap cancelled", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2277
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "m15 9-6 6M9 9l6 6" }),
2278
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "10" })
2279
+ ] }) }),
2280
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "Payment Cancelled" }),
2281
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "No charge was made. You can update your phone number and try again whenever you're ready." }),
2282
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-status-actions", children: [
2283
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: () => {
2284
+ setPhase("idle");
2285
+ setPayError(null);
2286
+ }, className: "hsk-pay-btn hsk-btn-primary", children: "Try again" }),
2287
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: onClose, className: "hsk-checkout-cancel-btn", children: "Back to cart" })
2288
+ ] })
2289
+ ] }) : phase === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-status-card failed", children: [
2290
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-status-icon-wrap failed", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2291
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
2292
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
2293
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
2294
+ ] }) }),
2295
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "Payment Failed" }),
2296
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "hsk-checkout-error-text", children: payError || "Could not verify M-Pesa transaction. Please check your phone and try again." }),
2297
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-status-actions", children: [
2298
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: () => {
2299
+ setPhase("idle");
2300
+ setPayError(null);
2301
+ }, className: "hsk-pay-btn hsk-btn-primary", children: "Try again" }),
2302
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: onClose, className: "hsk-checkout-cancel-btn", children: "Back to cart" })
2303
+ ] })
2304
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-checkout-payment-form-wrap", children: [
2305
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: "hsk-checkout-section-title", children: "Payment details" }),
2306
+ loadingConfig ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "hsk-cart-loading", children: "Loading payment configuration..." }) : !hasPaymentMethods ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "hsk-checkout-error", children: "No payment methods configured for this store." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { onSubmit: handlePay, className: "hsk-stripe-checkout-form", children: [
2307
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-form-group", children: [
2308
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "hsk-form-label", children: "M-Pesa Mobile Number" }),
2309
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-phone-input-container", children: [
2310
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "hsk-phone-prefix", children: "254" }),
2311
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2312
+ "input",
2313
+ {
2314
+ type: "tel",
2315
+ required: true,
2316
+ placeholder: "712345678",
2317
+ pattern: "[0-9]{9}",
2318
+ maxLength: 9,
2319
+ value: phone,
2320
+ onChange: (e) => setPhone(e.target.value.replace(/\D/g, "")),
2321
+ className: "hsk-phone-input-field"
2322
+ }
2323
+ )
2324
+ ] }),
2325
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "hsk-form-hint", children: "Enter your 9-digit number (e.g. 712345678)" })
2326
+ ] }),
2327
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-form-group", children: [
2328
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "hsk-form-label", children: "Email address" }),
2329
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2330
+ "input",
2331
+ {
2332
+ type: "email",
2333
+ placeholder: "john.doe@example.com",
2334
+ value: email,
2335
+ onChange: (e) => setEmail(e.target.value),
2336
+ className: "hsk-form-input"
2337
+ }
2338
+ )
2339
+ ] }),
2340
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-form-row", children: [
2341
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-form-group", children: [
2342
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "hsk-form-label", children: "First Name" }),
2343
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2344
+ "input",
2345
+ {
2346
+ type: "text",
2347
+ placeholder: "John",
2348
+ value: firstName,
2349
+ onChange: (e) => setFirstName(e.target.value),
2350
+ className: "hsk-form-input"
2351
+ }
2352
+ )
2353
+ ] }),
2354
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "hsk-form-group", children: [
2355
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "hsk-form-label", children: "Last Name" }),
2356
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2357
+ "input",
2358
+ {
2359
+ type: "text",
2360
+ placeholder: "Doe",
2361
+ value: lastName,
2362
+ onChange: (e) => setLastName(e.target.value),
2363
+ className: "hsk-form-input"
2364
+ }
2365
+ )
2366
+ ] })
2367
+ ] }),
2368
+ payError && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-form-error-banner", children: payError }),
2369
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { type: "submit", className: "hsk-checkout-submit-btn", children: [
2370
+ "Pay ",
2371
+ currency,
2372
+ " ",
2373
+ total.toLocaleString()
2374
+ ] }),
2375
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-checkout-footer-brand", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Powered by Akropolys" }) })
2376
+ ] })
2377
+ ] }) }) })
2378
+ ]
2379
+ }
2380
+ )
2381
+ }
2382
+ ),
2383
+ document.body
2384
+ );
2385
+ }
2386
+
2387
+ // src/components/CartDrawer.tsx
2388
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2389
+ function CartDrawer({
2390
+ trigger,
2391
+ className,
2392
+ theme
2393
+ }) {
2394
+ const { cart, loading } = (0, import_sdk9.useCart)();
2395
+ const [open, setOpen] = (0, import_react6.useState)(false);
2396
+ const [showCheckout, setShowCheckout] = (0, import_react6.useState)(false);
2397
+ const [mounted, setMounted] = (0, import_react6.useState)(false);
2398
+ const client = (0, import_sdk9.useAkropolysContext)();
2399
+ (0, import_react6.useEffect)(() => {
2400
+ setMounted(true);
2401
+ const handleTriggerCheckout = () => {
2402
+ setShowCheckout(true);
2403
+ setOpen(false);
2404
+ };
2405
+ window.addEventListener("akropolys:trigger_checkout", handleTriggerCheckout);
2406
+ return () => {
2407
+ window.removeEventListener("akropolys:trigger_checkout", handleTriggerCheckout);
2408
+ };
2409
+ }, []);
2410
+ (0, import_react6.useEffect)(() => {
2411
+ if (open) {
2412
+ document.body.style.overflow = "hidden";
2413
+ } else {
2414
+ document.body.style.overflow = "";
2415
+ }
2416
+ return () => {
2417
+ document.body.style.overflow = "";
2418
+ };
2419
+ }, [open]);
2420
+ const handleCheckout = async () => {
2421
+ if (!cart || cart.items.length === 0) return;
2422
+ const event = new CustomEvent("akropolys:trigger_checkout", { cancelable: true });
2423
+ window.dispatchEvent(event);
2424
+ if (event.defaultPrevented) {
2425
+ setOpen(false);
2426
+ return;
2427
+ }
2428
+ setShowCheckout(true);
2429
+ };
2430
+ const isStringTheme = typeof theme === "string";
2431
+ const hskThemeAttr = isStringTheme ? theme : void 0;
2432
+ const customStyles = !isStringTheme && theme ? {
2433
+ ...theme?.primaryColor && { "--hsk-primary": theme.primaryColor, "--hsk-primary-color": theme.primaryColor },
2434
+ ...theme?.backgroundColor && { "--hsk-bg": theme.backgroundColor },
2435
+ ...theme?.textColor && { "--hsk-text": theme.textColor },
2436
+ ...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
2437
+ ...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
2438
+ } : void 0;
2439
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2440
+ trigger ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { onClick: () => setOpen(true), style: { display: "inline-block" }, children: trigger }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2441
+ "button",
2442
+ {
2443
+ onClick: () => setOpen(true),
2444
+ className: cn("hsk-cart-trigger", className),
2445
+ style: customStyles,
2446
+ "data-hsk-theme": hskThemeAttr,
2447
+ "aria-label": "Open cart",
2448
+ children: [
2449
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2450
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("circle", { cx: "9", cy: "21", r: "1" }),
2451
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("circle", { cx: "20", cy: "21", r: "1" }),
2452
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6" })
2453
+ ] }),
2454
+ cart && cart.item_count > 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "hsk-cart-trigger-badge", children: cart.item_count }) : null
2455
+ ]
2456
+ }
2457
+ ),
2458
+ open && mounted && (0, import_react_dom4.createPortal)(
2459
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2460
+ "div",
2461
+ {
2462
+ className: "hsk-cart-backdrop",
2463
+ style: customStyles,
2464
+ "data-hsk-theme": hskThemeAttr,
2465
+ onClick: () => setOpen(false),
2466
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2467
+ "div",
2468
+ {
2469
+ className: "hsk-cart-bottom-sheet",
2470
+ style: customStyles,
2471
+ "data-hsk-theme": hskThemeAttr,
2472
+ onClick: (e) => e.stopPropagation(),
2473
+ children: [
2474
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "hsk-cart-sheet-handle" }),
2475
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "hsk-cart-sheet-header", children: [
2476
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { children: "Your Cart" }),
2477
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { onClick: () => setOpen(false), className: "hsk-close-btn", children: "\xD7" })
2478
+ ] }),
2479
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "hsk-cart-sheet-content", children: loading && !cart ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "hsk-cart-loading", children: "Loading cart..." }) : !cart || cart.items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "hsk-cart-empty", children: "Your cart is empty." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className: "hsk-cart-items", children: cart.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { className: "hsk-cart-item", children: [
2480
+ item.image && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: item.image, alt: item.name, className: "hsk-cart-item-img" }),
2481
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "hsk-cart-item-info", children: [
2482
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "hsk-cart-item-name", children: item.name }),
2483
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "hsk-cart-item-price", children: [
2484
+ item.currency,
2485
+ " ",
2486
+ item.price_numeric.toLocaleString(void 0, { minimumFractionDigits: 2 })
2487
+ ] })
2488
+ ] }),
2489
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "hsk-cart-item-qty", children: [
2490
+ "x",
2491
+ item.quantity
2492
+ ] })
2493
+ ] }, item.id)) }) }),
2494
+ cart && cart.items.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "hsk-cart-sheet-footer", children: [
2495
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "hsk-cart-total", children: [
2496
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Total" }),
2497
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
2498
+ cart.currency,
2499
+ " ",
2500
+ cart.total.toLocaleString(void 0, { minimumFractionDigits: 2 })
2501
+ ] })
2502
+ ] }),
2503
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { onClick: handleCheckout, className: "hsk-checkout-btn", children: "Checkout securely" })
2504
+ ] })
2505
+ ]
2506
+ }
2507
+ )
2508
+ }
2509
+ ),
2510
+ document.body
2511
+ ),
2512
+ showCheckout && mounted && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2513
+ CheckoutModal,
2514
+ {
2515
+ onClose: () => {
2516
+ setShowCheckout(false);
2517
+ setOpen(false);
2518
+ },
2519
+ theme: isStringTheme ? theme : void 0,
2520
+ customStyles,
2521
+ hskThemeAttr
2522
+ }
2523
+ )
2524
+ ] });
2525
+ }
2526
+ // Annotate the CommonJS export names for ESM import in node:
2527
+ 0 && (module.exports = {
2528
+ CartBadge,
2529
+ CartDrawer,
2530
+ ChatWidget,
2531
+ CheckoutModal,
2532
+ ComparisonMatrix,
2533
+ KikuButton,
2534
+ KikuChat,
2535
+ SearchBar,
2536
+ Sparkle
2537
+ });
2538
+ //# sourceMappingURL=index.js.map