@huskel/sdk 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +56 -0
- package/dist/index.css.map +1 -1
- package/dist/index.js +214 -104
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +180 -70
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api.ts","../src/client.ts","../src/hooks/useHuskel.ts","../src/hooks/useSearch.ts","../src/components/HuskelProvider.tsx","../src/hooks/useIngest.ts","../src/hooks/usePageIngest.ts","../src/hooks/useChat.ts","../src/components/SearchBar.tsx","../src/components/Sparkle.tsx","../src/components/ChatWidget.tsx","../src/components/AIChatButton.tsx"],"sourcesContent":["import { Product, SearchResponse, IngestResponse, HuskelError } from './types';\r\n\r\nconst MAX_RETRIES = 3;\r\nconst RETRY_DELAYS = [500, 1000, 2000]; // ms\r\n\r\nfunction log(level: 'info' | 'warn' | 'error', msg: string, data?: unknown) {\r\n const prefix = '[Huskel]';\r\n if (level === 'error') console.error(prefix, msg, data ?? '');\r\n else if (level === 'warn') console.warn(prefix, msg, data ?? '');\r\n else console.log(prefix, msg, data ?? '');\r\n}\r\n\r\nasync function sleep(ms: number) {\r\n return new Promise(r => setTimeout(r, ms));\r\n}\r\n\r\nexport class HuskelAPI {\r\n constructor(\r\n private apiUrl: string,\r\n private siteId: string,\r\n private apiToken: string,\r\n private getShopperId?: () => string | undefined,\r\n private getSessionId?: () => string | undefined\r\n ) {}\r\n\r\n private async post<T>(path: string, body: unknown, attempt = 0): Promise<T> {\r\n const url = `${this.apiUrl}${path}`;\r\n\r\n try {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n 'X-Huskel-Token': this.apiToken,\r\n 'X-Huskel-Site': this.siteId,\r\n };\r\n\r\n const shopperId = this.getShopperId?.();\r\n if (shopperId) {\r\n headers['X-Huskel-Shopper-Id'] = shopperId;\r\n }\r\n\r\n const sessionId = this.getSessionId?.();\r\n if (sessionId) {\r\n headers['X-Huskel-Session-Id'] = sessionId;\r\n }\r\n\r\n const res = await fetch(url, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n const err: HuskelError = { status: res.status, message: text };\r\n\r\n // Don't retry 4xx — developer errors\r\n if (res.status >= 400 && res.status < 500) {\r\n log('error', `${path} failed [${res.status}]`, text);\r\n throw err;\r\n }\r\n\r\n // Retry 5xx\r\n if (attempt < MAX_RETRIES - 1) {\r\n log('warn', `${path} [${res.status}] retrying (${attempt + 1}/${MAX_RETRIES})...`);\r\n await sleep(RETRY_DELAYS[attempt]);\r\n return this.post(path, body, attempt + 1);\r\n }\r\n\r\n log('error', `${path} failed after ${MAX_RETRIES} attempts`, err);\r\n throw err;\r\n }\r\n\r\n return res.json();\r\n } catch (e) {\r\n // Network error (offline, DNS, etc.)\r\n if ((e as HuskelError).status === undefined) {\r\n if (attempt < MAX_RETRIES - 1) {\r\n log('warn', `${path} network error, retrying (${attempt + 1}/${MAX_RETRIES})...`);\r\n await sleep(RETRY_DELAYS[attempt]);\r\n return this.post(path, body, attempt + 1);\r\n }\r\n log('error', `${path} unreachable after ${MAX_RETRIES} attempts`);\r\n }\r\n throw e;\r\n }\r\n }\r\n\r\n async ingest(product: Product): Promise<IngestResponse> {\r\n log('info', 'ingesting product', product.name);\r\n return this.post('/ingest', { siteId: this.siteId, product });\r\n }\r\n\r\n async ingestBatch(products: Product[]): Promise<IngestResponse> {\r\n log('info', `ingesting batch of ${products.length} products`);\r\n return this.post('/ingest/batch', { siteId: this.siteId, products });\r\n }\r\n\r\n async search(query: string, limit = 10): Promise<SearchResponse> {\r\n log('info', 'search query', query);\r\n return this.post('/search', { query, siteId: this.siteId, limit });\r\n }\r\n\r\n // Pure vector search — no LLM, instant results. This is what the SearchBar uses.\r\n async searchVector(query: string, limit = 10): Promise<SearchResponse> {\r\n return this.post('/search/vector', { query, siteId: this.siteId, limit });\r\n }\r\n\r\n // Autocomplete — pure in-memory Trie, <1ms, no Upstash call. Only true prefix matches.\r\n async searchAutocomplete(query: string, limit = 8): Promise<SearchResponse> {\r\n return this.post('/search/autocomplete', { query, siteId: this.siteId, limit });\r\n }\r\n\r\n // LLM chat — conversational search with history context.\r\n async chat(query: string, history: Array<{ role: 'user' | 'assistant'; content: string }> = []): Promise<{ answer: string; sources: any[] }> {\r\n log('info', 'chat query', query);\r\n return this.post('/chat', { query, siteId: this.siteId, history });\r\n }\r\n}\r\n","import { HuskelConfig, Product, RawProductInput } from './types';\r\nimport { HuskelAPI } from './api';\r\n\r\nfunction getEnvVar(key: string): string | undefined {\r\n if (typeof globalThis !== 'undefined') {\r\n const g = globalThis as any;\r\n if (g.process && g.process.env) {\r\n return g.process.env[key];\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction mapRawProduct(input: RawProductInput): Product | null {\r\n const name = input.name || input.title || input.productName || '';\r\n \r\n let price = '';\r\n let priceNumeric: number | undefined = undefined;\r\n\r\n if (input.price !== undefined) {\r\n if (typeof input.price === 'number') {\r\n priceNumeric = input.price;\r\n price = String(input.price);\r\n } else {\r\n price = input.price;\r\n const num = parseFloat(input.price.replace(/[^0-9.]/g, ''));\r\n priceNumeric = isNaN(num) ? undefined : num;\r\n }\r\n }\r\n if (input.priceNumeric !== undefined) {\r\n priceNumeric = input.priceNumeric;\r\n }\r\n\r\n let url = input.url || '';\r\n if (!url && typeof window !== 'undefined') {\r\n url = window.location.href;\r\n }\r\n\r\n let slug = input.slug || input.id || input.productId || '';\r\n if (!slug && url) {\r\n slug = url.split('/').filter(Boolean).pop() || '';\r\n }\r\n if (!slug && name) {\r\n slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');\r\n }\r\n\r\n let images: string[] = [];\r\n if (input.images) {\r\n images = input.images;\r\n } else if (input.image) {\r\n images = [input.image];\r\n } else if (input.thumbnail) {\r\n images = [input.thumbnail];\r\n }\r\n\r\n if (!name) {\r\n console.warn('[Huskel] Validation warning: Product name/title is missing. Skipping:', input);\r\n return null;\r\n }\r\n if (!price) {\r\n console.warn('[Huskel] Validation warning: Product price is missing. Skipping:', input);\r\n return null;\r\n }\r\n if (!url) {\r\n console.warn('[Huskel] Validation warning: Product URL is missing. Skipping:', input);\r\n return null;\r\n }\r\n\r\n return {\r\n name,\r\n price,\r\n url,\r\n brand: input.brand,\r\n description: input.description,\r\n originalPrice: input.originalPrice,\r\n discount: input.discount,\r\n currency: input.currency ?? 'KES',\r\n stock: input.stock,\r\n availability: input.availability,\r\n rating: input.rating,\r\n reviewCount: input.reviewCount,\r\n category: input.category,\r\n subCategory: input.subCategory,\r\n tags: input.tags,\r\n images: images.length > 0 ? images : undefined,\r\n specs: input.specs,\r\n priceNumeric,\r\n slug,\r\n };\r\n}\r\n\r\nfunction generateUUID(): string {\r\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\r\n return crypto.randomUUID();\r\n }\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\nexport class HuskelClient {\r\n readonly api: HuskelAPI;\r\n private ingestQueue: Product[] = [];\r\n private ingestTimer: ReturnType<typeof setTimeout> | null = null;\r\n private ingestedUrls = new Set<string>();\r\n private onlineHandler: (() => void) | null = null;\r\n private shopperId?: string;\r\n private sessionId: string = '';\r\n\r\n private static INGEST_CACHE_KEY = 'huskel_ingested_v1';\r\n private static INGEST_CACHE_TTL = 24 * 60 * 60 * 1000; // 24h\r\n\r\n private loadIngestedCache() {\r\n if (typeof window === 'undefined') return;\r\n try {\r\n const raw = localStorage.getItem(HuskelClient.INGEST_CACHE_KEY);\r\n if (!raw) return;\r\n const { ts, urls }: { ts: number; urls: string[] } = JSON.parse(raw);\r\n if (Date.now() - ts > HuskelClient.INGEST_CACHE_TTL) {\r\n localStorage.removeItem(HuskelClient.INGEST_CACHE_KEY);\r\n return;\r\n }\r\n this.ingestedUrls = new Set(urls);\r\n } catch { /* ignore */ }\r\n }\r\n\r\n private saveIngestedCache() {\r\n if (typeof window === 'undefined') return;\r\n try {\r\n localStorage.setItem(\r\n HuskelClient.INGEST_CACHE_KEY,\r\n JSON.stringify({ ts: Date.now(), urls: [...this.ingestedUrls] })\r\n );\r\n } catch { /* ignore */ }\r\n }\r\n\r\n constructor(config: HuskelConfig) {\r\n const siteId = config.siteId || getEnvVar('NEXT_PUBLIC_HUSKEL_SITE_ID') || '';\r\n const apiUrl = config.apiUrl || getEnvVar('NEXT_PUBLIC_HUSKEL_API_URL') || '';\r\n const apiToken = config.apiToken || getEnvVar('NEXT_PUBLIC_HUSKEL_API_TOKEN') || '';\r\n\r\n // Runtime validation — fail loudly so misconfiguration is never silent\r\n if (!siteId) console.error('[Huskel] Missing siteId. Set it via <HuskelProvider siteId=\"...\"> or NEXT_PUBLIC_HUSKEL_SITE_ID.');\r\n if (!apiUrl) console.error('[Huskel] Missing apiUrl. Set it via <HuskelProvider apiUrl=\"...\"> or NEXT_PUBLIC_HUSKEL_API_URL.');\r\n if (!apiToken) console.error('[Huskel] Missing apiToken. Set it via <HuskelProvider apiToken=\"...\"> or NEXT_PUBLIC_HUSKEL_API_TOKEN.');\r\n\r\n this.shopperId = config.shopperId;\r\n this.initSession();\r\n this.loadIngestedCache();\r\n\r\n this.api = new HuskelAPI(\r\n apiUrl,\r\n siteId,\r\n apiToken,\r\n () => this.shopperId,\r\n () => this.sessionId\r\n );\r\n instance = this;\r\n\r\n if (typeof window !== 'undefined') {\r\n this.onlineHandler = () => {\r\n console.log('[Huskel] Connectivity restored, flushing queued ingestions.');\r\n this.flushQueue();\r\n };\r\n window.addEventListener('online', this.onlineHandler);\r\n }\r\n }\r\n\r\n setShopperId(id: string | undefined) {\r\n this.shopperId = id;\r\n }\r\n\r\n getShopperId(): string | undefined {\r\n return this.shopperId;\r\n }\r\n\r\n getSessionId(): string {\r\n return this.sessionId;\r\n }\r\n\r\n private initSession() {\r\n if (typeof window !== 'undefined' && window.sessionStorage) {\r\n try {\r\n let sid = window.sessionStorage.getItem('huskel_session_id');\r\n if (!sid) {\r\n sid = generateUUID();\r\n window.sessionStorage.setItem('huskel_session_id', sid);\r\n }\r\n this.sessionId = sid;\r\n return;\r\n } catch (e) {\r\n // Fallback if sessionStorage is disabled or private mode\r\n }\r\n }\r\n this.sessionId = generateUUID();\r\n }\r\n\r\n destroy() {\r\n if (typeof window !== 'undefined' && this.onlineHandler) {\r\n window.removeEventListener('online', this.onlineHandler);\r\n this.onlineHandler = null;\r\n }\r\n if (this.ingestTimer) {\r\n clearTimeout(this.ingestTimer);\r\n this.ingestTimer = null;\r\n }\r\n if (instance === this) instance = null;\r\n }\r\n\r\n async queueIngest(rawProduct: RawProductInput): Promise<void> {\r\n const product = mapRawProduct(rawProduct);\r\n if (!product) return;\r\n\r\n if (this.ingestedUrls.has(product.url)) {\r\n return; // already indexed in this session or today — skip\r\n }\r\n this.ingestedUrls.add(product.url);\r\n this.saveIngestedCache();\r\n\r\n this.ingestQueue.push(product);\r\n this.scheduleFlush();\r\n }\r\n\r\n async queueIngestBatch(rawProducts: RawProductInput[]): Promise<void> {\r\n rawProducts.forEach(p => {\r\n const product = mapRawProduct(p);\r\n if (!product) return;\r\n\r\n if (this.ingestedUrls.has(product.url)) {\r\n return;\r\n }\r\n this.ingestedUrls.add(product.url);\r\n this.ingestQueue.push(product);\r\n });\r\n\r\n if (this.ingestQueue.length > 0) {\r\n this.saveIngestedCache();\r\n this.scheduleFlush();\r\n }\r\n }\r\n\r\n private scheduleFlush() {\r\n if (this.ingestTimer) return;\r\n this.ingestTimer = setTimeout(() => {\r\n this.flushQueue();\r\n }, 300);\r\n }\r\n\r\n private async flushQueue() {\r\n this.ingestTimer = null;\r\n if (this.ingestQueue.length === 0) return;\r\n\r\n if (typeof navigator !== 'undefined' && !navigator.onLine) {\r\n console.warn('[Huskel] Browser offline. Postponing ingestion.');\r\n return;\r\n }\r\n\r\n const batch = [...this.ingestQueue];\r\n this.ingestQueue = [];\r\n\r\n try {\r\n await this.api.ingestBatch(batch);\r\n } catch (e: any) {\r\n if (e.status && e.status >= 400 && e.status < 500) {\r\n console.error('[Huskel] Ingestion discarded due to client error:', e.message);\r\n return;\r\n }\r\n\r\n // Re-queue and schedule another flush so items are not stuck forever\r\n console.warn('[Huskel] Ingestion failed. Re-queuing to retry.', e);\r\n this.ingestQueue = [...batch, ...this.ingestQueue];\r\n this.scheduleFlush();\r\n }\r\n }\r\n}\r\n\r\nlet instance: HuskelClient | null = null;\r\n\r\nexport function initHuskel(config: HuskelConfig): HuskelClient {\r\n instance = new HuskelClient(config);\r\n return instance;\r\n}\r\n\r\nexport function getHuskelClient(): HuskelClient {\r\n if (!instance) {\r\n const siteId = getEnvVar('NEXT_PUBLIC_HUSKEL_SITE_ID');\r\n const apiUrl = getEnvVar('NEXT_PUBLIC_HUSKEL_API_URL');\r\n const apiToken = getEnvVar('NEXT_PUBLIC_HUSKEL_API_TOKEN');\r\n\r\n if (siteId && apiUrl && apiToken) {\r\n instance = new HuskelClient({ siteId, apiUrl, apiToken });\r\n } else {\r\n throw new Error('[Huskel] Call initHuskel() or set NEXT_PUBLIC_HUSKEL_* environment variables before using the client.');\r\n }\r\n }\r\n return instance;\r\n}\r\n","import { useRef } from 'react';\r\nimport { HuskelConfig } from '../types';\r\nimport { HuskelClient, initHuskel } from '../client';\r\n\r\n/**\r\n * @deprecated Use <HuskelProvider> instead to avoid SSR issues.\r\n */\r\nexport function useHuskel(config: HuskelConfig): HuskelClient {\r\n const clientRef = useRef<HuskelClient | null>(null);\r\n\r\n if (!clientRef.current) {\r\n console.warn('[Huskel] useHuskel() is deprecated. Please wrap your application in <HuskelProvider> instead.');\r\n clientRef.current = initHuskel(config);\r\n }\r\n\r\n return clientRef.current;\r\n}\r\n","import { useState, useCallback, useRef } from 'react';\nimport { SearchResult } from '../types';\nimport { useHuskelContext } from '../components/HuskelProvider';\n\ninterface UseSearchReturn {\n results: SearchResult[];\n loading: boolean;\n error: string | null;\n search: (query: string, limit?: number) => Promise<void>;\n clear: () => void;\n}\n\nexport function useSearch(): UseSearchReturn {\n const client = useHuskelContext();\n const [results, setResults] = useState<SearchResult[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n // Generation counter so stale responses from any in-flight requests don't overwrite newer ones\n const genRef = useRef(0);\n\n const search = useCallback(async (query: string, limit = 8) => {\n if (!query.trim()) { setResults([]); setLoading(false); return; }\n const gen = ++genRef.current;\n // No loading spinner for autocomplete — it's so fast it would just flicker\n setError(null);\n try {\n // searchAutocomplete = pure in-memory Trie, <1ms, no Upstash\n const res = await client.api.searchAutocomplete(query, limit);\n if (gen === genRef.current) {\n setResults(res.results ?? []);\n }\n } catch (e: unknown) {\n if (gen === genRef.current) {\n setError((e as Error).message ?? 'Search failed');\n }\n } finally {\n if (gen === genRef.current) setLoading(false);\n }\n }, [client]);\n\n const clear = useCallback(() => {\n genRef.current++;\n setResults([]);\n setError(null);\n setLoading(false);\n }, []);\n\n return { results, loading, error, search, clear };\n}\n","'use client';\r\n\r\nimport React, { createContext, useContext, useEffect, useRef } from 'react';\r\nimport { HuskelClient, getHuskelClient } from '../client';\r\nimport { HuskelConfig } from '../types';\r\n\r\nexport const HuskelContext = createContext<HuskelClient | null>(null);\r\n\r\ninterface HuskelProviderProps extends HuskelConfig {\r\n children: React.ReactNode;\r\n}\r\n\r\nexport function HuskelProvider({ siteId, apiUrl, apiToken, shopperId, children }: HuskelProviderProps) {\r\n const clientRef = useRef<HuskelClient | null>(null);\r\n\r\n if (!clientRef.current) {\r\n clientRef.current = new HuskelClient({ siteId, apiUrl, apiToken, shopperId });\r\n }\r\n\r\n // Update shopperId dynamically when it changes (e.g., shopper logs in/out)\r\n useEffect(() => {\r\n clientRef.current?.setShopperId(shopperId);\r\n }, [shopperId]);\r\n\r\n // Clean up the online listener and timers when the provider unmounts\r\n // (prevents leaks during hot module reload and React StrictMode double-mount)\r\n useEffect(() => {\r\n return () => {\r\n clientRef.current?.destroy();\r\n };\r\n }, []);\r\n\r\n return (\r\n <HuskelContext.Provider value={clientRef.current}>\r\n {children}\r\n </HuskelContext.Provider>\r\n );\r\n}\r\n\r\nexport function useHuskelContext(): HuskelClient {\r\n const context = useContext(HuskelContext);\r\n if (!context) {\r\n return getHuskelClient();\r\n }\r\n return context;\r\n}\r\n\r\n","import { useCallback, useState } from 'react';\r\nimport { RawProductInput } from '../types';\r\nimport { useHuskelContext } from '../components/HuskelProvider';\r\n\r\ninterface UseIngestReturn {\r\n ingest: (product: RawProductInput) => Promise<void>;\r\n ingestBatch: (products: RawProductInput[]) => Promise<void>;\r\n loading: boolean;\r\n error: string | null;\r\n}\r\n\r\nexport function useIngest(): UseIngestReturn {\r\n const client = useHuskelContext();\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const ingest = useCallback(async (product: RawProductInput) => {\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n await client.queueIngest(product);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Ingest failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n const ingestBatch = useCallback(async (products: RawProductInput[]) => {\r\n if (!products.length) return;\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n await client.queueIngestBatch(products);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Batch ingest failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n return { ingest, ingestBatch, loading, error };\r\n}\r\n","import { useEffect, useRef } from 'react';\nimport { RawProductInput } from '../types';\nimport { getHuskelClient } from '../client';\n\n/**\n * usePageIngest — drop this into any product page component.\n * The moment a customer's browser renders the page, the product is\n * automatically captured and queued for ingestion into the vector index.\n *\n * No configuration needed beyond <HuskelProvider> in your layout.\n *\n * @example\n * // Product detail page — Next.js or React\n * export function ProductPage({ product }) {\n * usePageIngest({\n * name: product.title,\n * price: product.price,\n * url: window.location.href,\n * images: [product.thumbnail],\n * category: product.category,\n * });\n * return <div>...</div>;\n * }\n */\nexport function usePageIngest(product: RawProductInput | null | undefined): void {\n // Use url as the stable key — avoids re-ingesting on unrelated re-renders\n const ingestedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!product) return;\n\n // Resolve URL — falls back to window.location if not provided\n const url =\n product.url ||\n (typeof window !== 'undefined' ? window.location.href : '');\n\n // Guard: only ingest once per URL per component lifecycle\n if (ingestedRef.current === url) return;\n ingestedRef.current = url;\n\n try {\n getHuskelClient().queueIngest({ ...product, url });\n } catch {\n // Client not initialised — silently skip\n }\n }, [product?.url ?? product?.name]);\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { useHuskelContext } from '../components/HuskelProvider';\n\nexport interface ChatMessage {\n role: 'user' | 'assistant';\n content: string;\n}\n\nexport interface ChatSource {\n id?: string;\n name: string;\n price?: string;\n currency?: string;\n category?: string;\n url?: string;\n image?: string;\n}\n\ninterface UseChatReturn {\n messages: ChatMessage[];\n sources: ChatSource[];\n loading: boolean;\n error: string | null;\n send: (query: string) => Promise<void>;\n reset: () => void;\n}\n\nexport function useChat(): UseChatReturn {\n const client = useHuskelContext();\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [sources, setSources] = useState<ChatSource[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n const send = useCallback(async (query: string) => {\n if (!query.trim() || loading) return;\n abortRef.current?.abort();\n abortRef.current = new AbortController();\n\n // Optimistically add the user message\n const userMsg: ChatMessage = { role: 'user', content: query };\n setMessages(prev => [...prev, userMsg]);\n setLoading(true);\n setError(null);\n\n try {\n // Build history from current messages (exclude the one we just added — server will see it as query)\n const history = messages.map(m => ({ role: m.role, content: m.content }));\n const res = await client.api.chat(query, history);\n\n const assistantMsg: ChatMessage = { role: 'assistant', content: res.answer };\n setMessages(prev => [...prev, assistantMsg]);\n setSources(res.sources ?? []);\n } catch (e: any) {\n setError(e?.message ?? 'Chat request failed');\n // Remove the optimistic user message on failure\n setMessages(prev => prev.slice(0, -1));\n } finally {\n setLoading(false);\n }\n }, [client, messages, loading]);\n\n const reset = useCallback(() => {\n setMessages([]);\n setSources([]);\n setError(null);\n }, []);\n\n return { messages, sources, loading, error, send, reset };\n}\n","import React, { useState, useEffect, useRef } from 'react';\nimport { useSearch } from '../hooks/useSearch';\nimport { SearchResult } from '../types';\n\nexport interface SearchBarProps {\n placeholder?: string;\n limit?: number;\n /** Debounce in ms — default 80 for near-instant feel */\n debounceMs?: number;\n onSelect?: (result: SearchResult) => void;\n className?: string;\n inputClassName?: string;\n dropdownClassName?: string;\n renderResult?: (result: SearchResult) => React.ReactNode;\n theme?: {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n fontFamily?: string;\n };\n classNames?: {\n root?: string;\n input?: string;\n dropdown?: string;\n row?: string;\n };\n}\n\n/* SVG search glass — pure inline so no icon dependency */\nconst SearchIcon = () => (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\">\n <circle cx=\"8.5\" cy=\"8.5\" r=\"5.5\"/>\n <line x1=\"13\" y1=\"13\" x2=\"18\" y2=\"18\"/>\n </svg>\n);\n\nexport function SearchBar({\n placeholder = 'Search products…',\n limit = 10,\n debounceMs = 80,\n onSelect,\n className,\n inputClassName,\n dropdownClassName,\n renderResult,\n theme,\n classNames = {},\n}: SearchBarProps) {\n const [query, setQuery] = useState('');\n const [open, setOpen] = useState(false);\n const { results, loading, search, clear } = useSearch();\n const timer = useRef<ReturnType<typeof setTimeout>>();\n const wrap = useRef<HTMLDivElement>(null);\n\n /* Debounce search — but keep stale results visible between calls */\n useEffect(() => {\n clearTimeout(timer.current);\n if (!query.trim()) { clear(); setOpen(false); return; }\n setOpen(true); // open immediately (stale results show while fetching)\n timer.current = setTimeout(() => { search(query, limit); }, debounceMs);\n return () => clearTimeout(timer.current);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [query]);\n\n /* Click-outside to close */\n useEffect(() => {\n const h = (e: MouseEvent) => {\n if (wrap.current && !wrap.current.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener('mousedown', h);\n return () => document.removeEventListener('mousedown', h);\n }, []);\n\n const handleSelect = (r: SearchResult) => {\n setOpen(false);\n setQuery(r.product.name);\n onSelect?.(r);\n };\n\n const showDrop = open && query.trim().length > 0;\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <div className={`hsk-sb-wrap ${classNames.root || ''} ${className || ''}`} ref={wrap} style={customStyles}>\n <span className=\"hsk-sb-icon\"><SearchIcon /></span>\n <input\n className={`hsk-sb-input ${classNames.input || ''} ${inputClassName || ''}`}\n type=\"text\"\n value={query}\n placeholder={placeholder}\n onChange={e => setQuery(e.target.value)}\n onFocus={() => results.length > 0 && query.trim() && setOpen(true)}\n autoComplete=\"off\"\n spellCheck={false}\n />\n {showDrop && (\n <div className={`hsk-sb-drop ${classNames.dropdown || ''} ${dropdownClassName || ''}`} style={{ position: 'absolute' }}>\n {loading && <div className=\"hsk-sb-loading-bar\" />}\n\n {results.length === 0 && !loading && (\n <div className=\"hsk-sb-empty\">No results for “{query}”</div>\n )}\n\n {results.map((r, i) => (\n renderResult ? (\n <div\n key={r.id}\n onClick={() => handleSelect(r)}\n className=\"hsk-sb-fade\"\n style={{ animationDelay: `${i * 18}ms` }}\n >\n {renderResult(r)}\n </div>\n ) : (\n <div\n key={r.id}\n className={`hsk-sb-row hsk-sb-fade ${classNames.row || ''}`}\n style={{ animationDelay: `${i * 18}ms` }}\n onClick={() => handleSelect(r)}\n >\n <span className=\"hsk-sb-row-icon\"><SearchIcon /></span>\n <div className=\"hsk-sb-row-body\">\n <div className=\"hsk-sb-row-title\">{r.product.name}</div>\n {(r.product.category || r.product.brand) && (\n <div className=\"hsk-sb-row-sub\">\n {r.product.category ?? r.product.brand}\n </div>\n )}\n </div>\n </div>\n )\n ))}\n </div>\n )}\n </div>\n );\n}\n","import React, { useState, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useSearch } from '../hooks/useSearch';\nimport { SearchResult } from '../types';\n\nexport interface SparkleProps {\n productName: string;\n limit?: number;\n onResult?: (results: SearchResult[]) => void;\n /** Override the backdrop colour (any CSS colour/gradient) */\n backdropColor?: string;\n /** Override backdrop blur — e.g. \"8px\" or 8 */\n backdropBlur?: string | number;\n /** Extra classes on the trigger button */\n className?: string;\n /** Called when user clicks a result — return false to prevent default navigation */\n onNavigate?: (result: SearchResult) => boolean | void;\n theme?: {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n fontFamily?: string;\n };\n classNames?: {\n button?: string;\n backdrop?: string;\n card?: string;\n item?: string;\n };\n}\n\nconst SparkleIcon = ({ className }: { className?: string }) => (\n <svg className={className} width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <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\"/>\n </svg>\n);\n\nconst CloseIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n);\n\n/* ── Modal ────────────────────────────────────────────────────────────────── */\ninterface ModalProps extends Pick<SparkleProps, 'productName' | 'limit' | 'backdropColor' | 'backdropBlur' | 'onNavigate' | 'onResult' | 'theme' | 'classNames'> {\n onClose: () => void;\n}\n\nfunction SparkleModal({ \n productName, \n limit, \n backdropColor, \n backdropBlur, \n onClose, \n onNavigate, \n onResult,\n theme,\n classNames = {},\n}: ModalProps) {\n const { results, loading, search } = useSearch();\n const initiated = useRef(false);\n\n /* auto-search on open */\n useEffect(() => {\n if (!initiated.current) { initiated.current = true; search(productName, limit); }\n }, []);\n\n /* fire callback */\n useEffect(() => { if (results.length > 0) onResult?.(results); }, [results]);\n\n /* Escape key */\n useEffect(() => {\n const h = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };\n document.addEventListener('keydown', h);\n return () => document.removeEventListener('keydown', h);\n }, []);\n\n const blurVal = typeof backdropBlur === 'number' ? `${backdropBlur}px` : (backdropBlur ?? '16px');\n const bg = backdropColor ?? undefined;\n\n const handleNav = (r: SearchResult) => {\n const prevent = onNavigate?.(r);\n if (prevent !== false) {\n onClose();\n if (r.product.url) window.location.href = r.product.url;\n }\n };\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <div\n className={`hsk-sp-backdrop ${classNames.backdrop || ''}`}\n onClick={onClose}\n style={{\n backdropFilter: `blur(${blurVal})`,\n WebkitBackdropFilter: `blur(${blurVal})`,\n background: bg ?? undefined,\n ...customStyles,\n }}\n >\n <div className={`hsk-sp-card ${classNames.card || ''}`} onClick={e => e.stopPropagation()}>\n <div className=\"hsk-sp-header\">\n <span className=\"hsk-sp-header-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </span>\n <div className=\"hsk-sp-header-body\">\n <div className=\"hsk-sp-header-title\">Similar to “{productName}”</div>\n <div className=\"hsk-sp-header-sub\">AI vector similarity · instant results</div>\n </div>\n <button className=\"hsk-sp-close\" onClick={onClose} aria-label=\"Close\">\n <CloseIcon />\n </button>\n </div>\n\n {loading && <div className=\"hsk-sp-bar\" />}\n\n <div className=\"hsk-sp-results\">\n {!loading && results.length === 0 && (\n <div className=\"hsk-sp-empty\">No similar products found.</div>\n )}\n\n {results.map((r, i) => {\n const price = parseFloat(r.product.price?.replace(/[^0-9.]/g, '') || '0');\n const currency = r.product.currency ?? 'KES';\n return (\n <div\n key={r.id}\n className={`hsk-sp-item ${classNames.item || ''}`}\n style={{ animationDelay: `${i * 55}ms` }}\n >\n <div className=\"hsk-sp-img-wrap\">\n {r.product.images?.[0]\n ? <img src={r.product.images[0]} alt={r.product.name} />\n : <span className=\"hsk-sp-img-placeholder\">🛍</span>\n }\n </div>\n\n <div className=\"hsk-sp-item-body\">\n {r.product.category && (\n <div className=\"hsk-sp-item-cat\">{r.product.category}</div>\n )}\n <div className=\"hsk-sp-item-name\">{r.product.name}</div>\n <div className=\"hsk-sp-item-price-row\">\n <span className=\"hsk-sp-item-currency\">{currency}</span>\n <span className=\"hsk-sp-item-price\">{price.toLocaleString()}</span>\n </div>\n <div className=\"hsk-sp-actions\">\n <button\n className=\"hsk-sp-action hsk-sp-action-primary\"\n onClick={() => handleNav(r)}\n >\n View Product\n </button>\n <button\n className=\"hsk-sp-action hsk-sp-action-secondary\"\n onClick={() => onClose()}\n >\n Add to Cart\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n <div className=\"hsk-sp-footer\">\n <span className=\"hsk-sp-badge\" style={{ display: 'inline-flex', alignItems: 'center', gap: '4px' }}>\n <SparkleIcon /> Huskel AI\n </span>\n <span className=\"hsk-sp-esc\">Esc to close</span>\n </div>\n </div>\n </div>\n );\n}\n\n/* ── Exported component ───────────────────────────────────────────────────── */\nexport function Sparkle({ \n productName, \n limit = 8, \n onResult, \n backdropColor, \n backdropBlur, \n className, \n onNavigate,\n theme,\n classNames = {},\n}: SparkleProps) {\n const [open, setOpen] = useState(false);\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => { setMounted(true); }, []);\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <>\n <button\n className={`hsk-sp-btn ${classNames.button || ''} ${className || ''}`}\n onClick={() => setOpen(true)}\n style={customStyles}\n title=\"Find similar products\"\n aria-label=\"Find similar products\"\n >\n <SparkleIcon />\n </button>\n {open && mounted && createPortal(\n <SparkleModal\n productName={productName}\n limit={limit}\n backdropColor={backdropColor}\n backdropBlur={backdropBlur}\n onClose={() => setOpen(false)}\n onResult={onResult}\n onNavigate={onNavigate}\n theme={theme}\n classNames={classNames}\n />,\n document.body\n )}\n </>\n );\n}\n","import React, { useState, useRef, useEffect } from 'react';\nimport { useChat, ChatMessage, ChatSource } from '../hooks/useChat';\n\n// Better Prop Interface for SDKs\nexport interface ChatWidgetProps {\n title?: string;\n placeholder?: string;\n emptyStateText?: string;\n emptyStateSuggestions?: string;\n defaultCurrency?: string;\n className?: string;\n \n // Allow overriding styles via standard CSS variables\n theme?: {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n fontFamily?: string;\n };\n \n // Allow targeting specific elements with custom classes (e.g. Tailwind)\n classNames?: {\n root?: string;\n header?: string;\n messageBubble?: string;\n input?: string;\n };\n \n onSelectSource?: (source: ChatSource) => void;\n}\n\n// Simple SVG Icons instead of text characters\nconst SparkleIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <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\"/>\n </svg>\n);\n\nconst ArrowUpIcon = () => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 7-7 7 7\"/>\n <path d=\"M12 19V5\"/>\n </svg>\n);\n\nfunction SourceCard({ source, defaultCurrency, onSelect }: { source: ChatSource; defaultCurrency: string; onSelect?: (s: ChatSource) => void }) {\n return (\n <div className=\"hsk-source-card\" onClick={() => onSelect?.(source)}>\n {source.image && <img src={source.image} alt={source.name} className=\"hsk-source-img\" />}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div className=\"hsk-source-name\">{source.name}</div>\n {source.price && (\n <div className=\"hsk-source-price\">{source.currency ?? defaultCurrency} {source.price}</div>\n )}\n </div>\n </div>\n );\n}\n\nexport function ChatWidget({ \n title = 'AI Shopping Assistant',\n placeholder = 'Ask about anything in our store…', \n emptyStateText = 'Ask me anything about our products',\n emptyStateSuggestions = '\"Find me headphones under KSh 5,000\" · \"Gift ideas\"',\n defaultCurrency = 'KES',\n className,\n theme,\n classNames = {},\n onSelectSource \n}: ChatWidgetProps) {\n const { messages, sources, loading, error, send, reset } = useChat();\n const [input, setInput] = useState('');\n const bottomRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages, loading]);\n\n const handleSend = async () => {\n const q = input.trim();\n if (!q || loading) return;\n setInput('');\n if (textareaRef.current) textareaRef.current.style.height = 'auto';\n await send(q);\n };\n\n const handleKey = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const handleInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setInput(e.target.value);\n const t = e.target;\n t.style.height = 'auto';\n t.style.height = Math.min(t.scrollHeight, 120) + 'px';\n };\n\n // Apply custom CSS variables inline to the root wrapper\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <div \n className={`hsk-chat-widget ${classNames.root || ''} ${className || ''}`} \n style={customStyles}\n >\n <div className={`hsk-chat-header ${classNames.header || ''}`}>\n <span className=\"hsk-chat-header-icon\"><SparkleIcon /></span>\n <span className=\"hsk-chat-title\">{title}</span>\n <span className=\"hsk-chat-badge\">AI</span>\n {messages.length > 0 && (\n <button className=\"hsk-chat-reset\" onClick={reset} style={{ marginLeft: 'auto' }}>Clear</button>\n )}\n </div>\n\n <div className=\"hsk-chat-messages\">\n {messages.length === 0 ? (\n <div className=\"hsk-chat-empty\">\n <div className=\"hsk-chat-empty-icon\"><SparkleIcon /></div>\n <div>{emptyStateText}</div>\n <div className=\"hsk-chat-empty-suggestions\">{emptyStateSuggestions}</div>\n </div>\n ) : (\n messages.map((msg, idx) => (\n <div key={idx}>\n <div className={`hsk-msg-row ${msg.role}`}>\n <div className={`hsk-msg-avatar ${msg.role === 'assistant' ? 'ai' : 'user'}`}>\n {msg.role === 'assistant' ? <SparkleIcon /> : 'U'}\n </div>\n <div className={`hsk-msg-bubble ${msg.role} ${classNames.messageBubble || ''}`}>\n {msg.content}\n </div>\n </div>\n {msg.role === 'assistant' && idx === messages.length - 1 && sources.length > 0 && (\n <div className=\"hsk-sources-container\">\n <div className=\"hsk-sources\">\n {sources.map((src, si) => (\n <SourceCard key={si} source={src} defaultCurrency={defaultCurrency} onSelect={onSelectSource} />\n ))}\n </div>\n </div>\n )}\n </div>\n ))\n )}\n\n {loading && (\n <div className=\"hsk-msg-row\">\n <div className=\"hsk-msg-avatar ai\"><SparkleIcon /></div>\n <div className=\"hsk-typing\">\n <div className=\"hsk-typing-dot\" /><div className=\"hsk-typing-dot\" /><div className=\"hsk-typing-dot\" />\n </div>\n </div>\n )}\n\n {error && <div className=\"hsk-chat-error\">{error}</div>}\n <div ref={bottomRef} />\n </div>\n\n <div className=\"hsk-chat-input-area\">\n <textarea\n ref={textareaRef}\n className={`hsk-chat-input ${classNames.input || ''}`}\n value={input}\n onChange={handleInput}\n onKeyDown={handleKey}\n placeholder={placeholder}\n rows={1}\n disabled={loading}\n />\n <button\n className=\"hsk-chat-send\"\n onClick={handleSend}\n disabled={!input.trim() || loading}\n aria-label=\"Send message\"\n >\n <ArrowUpIcon />\n </button>\n </div>\n </div>\n );\n}\n\n","'use client';\n\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useChat, ChatMessage, ChatSource } from '../hooks/useChat';\n\nexport interface AIChatButtonProps {\n label?: string;\n title?: string;\n placeholder?: string;\n backdropColor?: string;\n backdropBlur?: string | number;\n className?: string;\n onSelectSource?: (source: ChatSource) => void;\n defaultCurrency?: string;\n chips?: string[];\n theme?: {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n fontFamily?: string;\n };\n classNames?: {\n button?: string;\n overlay?: string;\n panel?: string;\n input?: string;\n sendButton?: string;\n };\n}\n\nconst SparkleIcon = ({ className }: { className?: string }) => (\n <svg className={className} width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <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\"/>\n </svg>\n);\n\nconst ArrowUpIcon = () => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 7-7 7 7\"/>\n <path d=\"M12 19V5\"/>\n </svg>\n);\n\nconst CloseIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n);\n\nconst ChevronRightIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m9 18 6-6-6-6\"/>\n </svg>\n);\n\nconst DEFAULT_CHIPS = [\n 'Cheapest smartphone',\n 'Smart TV under KSh 20,000',\n 'Noise-cancelling headphones',\n 'Best laptop for students',\n];\n\ninterface SourcesCarouselProps {\n sources: ChatSource[];\n defaultCurrency: string;\n onSelectSource?: (src: ChatSource) => void;\n}\n\nfunction SourcesCarousel({ sources, defaultCurrency, onSelectSource }: SourcesCarouselProps) {\n const railRef = useRef<HTMLDivElement>(null);\n const [showNext, setShowNext] = useState(false);\n\n const measure = useCallback(() => {\n const el = railRef.current;\n if (!el) return;\n const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 8;\n setShowNext(el.scrollWidth > el.clientWidth + 4 && !atEnd);\n }, []);\n\n useEffect(() => {\n measure();\n const el = railRef.current;\n if (!el) return;\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n el.addEventListener('scroll', measure, { passive: true });\n return () => { ro.disconnect(); el.removeEventListener('scroll', measure); };\n }, [measure, sources]);\n\n const scrollNext = () => {\n railRef.current?.scrollBy({ left: 170, behavior: 'smooth' });\n };\n\n return (\n <div className=\"hsk-cb-sources-wrap\">\n <div className=\"hsk-cb-sources\" ref={railRef}>\n {sources.map((src, si) => (\n <div\n key={si}\n className=\"hsk-cb-source\"\n style={{ animationDelay: `${si * 50}ms` }}\n onClick={() => onSelectSource?.(src)}\n >\n {src.image ? (\n <div className=\"hsk-cb-src-imgwrap\">\n <img src={src.image} alt={src.name} loading=\"lazy\" />\n </div>\n ) : (\n <div className=\"hsk-cb-src-imgwrap-empty\">\n <SparkleIcon />\n </div>\n )}\n <div className=\"hsk-cb-src-info\">\n <div className=\"hsk-cb-src-name\">{src.name}</div>\n {src.price && (\n <div className=\"hsk-cb-src-price\">\n {src.currency ?? defaultCurrency}{' '}\n {parseFloat(src.price.replace(/[^0-9.]/g, '') || '0').toLocaleString()}\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n {showNext && (\n <>\n <div\n className=\"hsk-cb-sources-fade\"\n style={{ background: 'linear-gradient(to right, transparent, var(--hsk-fade-bg, #0e0e0f))' }}\n />\n <button className=\"hsk-cb-sources-next\" onClick={scrollNext} aria-label=\"See more\">\n <ChevronRightIcon />\n </button>\n </>\n )}\n </div>\n );\n}\n\ninterface ChatModalProps extends Pick<AIChatButtonProps, 'title' | 'placeholder' | 'backdropColor' | 'backdropBlur' | 'onSelectSource' | 'defaultCurrency' | 'chips' | 'theme' | 'classNames'> {\n onClose: () => void;\n}\n\nfunction ChatModal({\n title = 'AI Shopping Assistant',\n placeholder = 'Ask me anything — gifts, budget, use case…',\n backdropColor,\n backdropBlur,\n onClose,\n onSelectSource,\n defaultCurrency = 'KES',\n chips = DEFAULT_CHIPS,\n theme,\n classNames = {},\n}: ChatModalProps) {\n const { messages, sources, loading, error, send, reset } = useChat();\n const [input, setInput] = useState('');\n const [selectedProduct, setSelectedProduct] = useState<ChatSource | null>(null);\n const bottomRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages, loading, selectedProduct]);\n\n useEffect(() => {\n const h = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };\n document.addEventListener('keydown', h);\n return () => document.removeEventListener('keydown', h);\n }, []);\n\n const handleSourceClick = (src: ChatSource) => {\n setSelectedProduct(src);\n onSelectSource?.(src);\n const q = `Tell me more about the ${src.name}${src.price ? ` (${src.currency ?? defaultCurrency} ${src.price})` : ''} — what are its key specs, who is it best for, and is it worth buying?`;\n send(q);\n };\n\n const handleSend = async (text?: string) => {\n const q = (text ?? input).trim();\n if (!q || loading) return;\n setSelectedProduct(null);\n setInput('');\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto';\n }\n await send(q);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSend(); }\n };\n\n const handleInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setInput(e.target.value);\n const t = e.target;\n t.style.height = 'auto';\n t.style.height = `${Math.min(t.scrollHeight, 140)}px`;\n };\n\n const blurVal = typeof backdropBlur === 'number' ? `${backdropBlur}px` : (backdropBlur ?? '20px');\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <div\n className={`hsk-cb-overlay ${classNames.overlay || ''}`}\n onClick={onClose}\n style={{\n backdropFilter: `blur(${blurVal})`,\n WebkitBackdropFilter: `blur(${blurVal})`,\n ...(backdropColor ? { background: backdropColor } : {}),\n ...customStyles,\n }}\n >\n <div className={`hsk-cb-panel ${classNames.panel || ''}`} onClick={e => e.stopPropagation()}>\n\n {/* Top bar */}\n <div className=\"hsk-cb-topbar\">\n <div className=\"hsk-cb-topbar-left\">\n <span className=\"hsk-cb-topbar-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </span>\n <div>\n <div className=\"hsk-cb-topbar-title\">{title}</div>\n <div className=\"hsk-cb-topbar-sub\">Powered by Huskel AI · searches the whole catalogue</div>\n </div>\n </div>\n <div className=\"hsk-cb-topbar-actions\">\n {messages.length > 0 && (\n <button className=\"hsk-cb-topbar-btn\" onClick={reset}>Clear chat</button>\n )}\n <button className=\"hsk-cb-close\" onClick={onClose} aria-label=\"Close\">\n <CloseIcon />\n </button>\n </div>\n </div>\n\n {/* Messages */}\n <div className=\"hsk-cb-msgs\">\n {messages.length === 0 ? (\n <div className=\"hsk-cb-empty\">\n <div className=\"hsk-cb-empty-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </div>\n <div className=\"hsk-cb-empty-title\">What can I help you find?</div>\n <div className=\"hsk-cb-empty-sub\">\n Ask about products, budgets, gift ideas, specs — I'll search the entire catalogue for you.\n </div>\n <div className=\"hsk-cb-chips\">\n {chips.map(chip => (\n <button\n key={chip}\n className=\"hsk-cb-chip\"\n onClick={() => handleSend(chip)}\n >\n {chip}\n </button>\n ))}\n </div>\n </div>\n ) : (\n messages.map((msg: ChatMessage, idx: number) => {\n const isLast = idx === messages.length - 1;\n const isUser = msg.role === 'user';\n return (\n <div key={idx} className=\"hsk-cb-msg-group\">\n {isUser ? (\n <div className=\"hsk-cb-user-msg\">\n <div className=\"hsk-cb-user-bubble\">{msg.content}</div>\n </div>\n ) : (\n <div className=\"hsk-cb-ai-msg\">\n <div className=\"hsk-cb-ai-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </div>\n <div className=\"hsk-cb-ai-body\">\n <div className=\"hsk-cb-ai-text\">{msg.content}</div>\n\n {/* Sources as horizontal carousel — only after latest assistant reply */}\n {isLast && sources.length > 0 && (\n <SourcesCarousel\n sources={sources}\n defaultCurrency={defaultCurrency}\n onSelectSource={handleSourceClick}\n />\n )}\n </div>\n </div>\n )}\n </div>\n );\n })\n )}\n\n {/* Selected product pinned card — shows while LLM fetches details */}\n {selectedProduct && loading && (\n <div\n className=\"hsk-cb-selected-product\"\n onClick={() => selectedProduct.url && window.open(selectedProduct.url, '_blank')}\n >\n {selectedProduct.image && (\n <img className=\"hsk-cb-selected-img\" src={selectedProduct.image} alt={selectedProduct.name} />\n )}\n <div className=\"hsk-cb-selected-info\">\n <div className=\"hsk-cb-selected-name\">{selectedProduct.name}</div>\n {selectedProduct.price && (\n <div className=\"hsk-cb-selected-price\">\n {selectedProduct.currency ?? defaultCurrency} {parseFloat((selectedProduct.price ?? '').replace(/[^0-9.]/g, '') || '0').toLocaleString()}\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Typing dots */}\n {loading && (\n <div className=\"hsk-cb-typing-row\">\n <div className=\"hsk-cb-ai-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </div>\n <div className=\"hsk-cb-typing\">\n <div className=\"hsk-cb-dot\" />\n <div className=\"hsk-cb-dot\" />\n <div className=\"hsk-cb-dot\" />\n </div>\n </div>\n )}\n\n {error && <div className=\"hsk-cb-error\">{error}</div>}\n <div ref={bottomRef} style={{ height: 1 }} />\n </div>\n\n {/* Input */}\n <div className=\"hsk-cb-input-wrap\">\n <div className=\"hsk-cb-input-box\">\n <textarea\n ref={textareaRef}\n className={`hsk-cb-textarea ${classNames.input || ''}`}\n value={input}\n onChange={handleInput}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n rows={1}\n disabled={loading}\n autoFocus\n />\n <button\n className={`hsk-cb-send ${classNames.sendButton || ''}`}\n onClick={() => handleSend()}\n disabled={!input.trim() || loading}\n aria-label=\"Send message\"\n >\n <ArrowUpIcon />\n </button>\n </div>\n <div className=\"hsk-cb-hint\">Huskel AI · searches the whole catalogue in real time</div>\n </div>\n\n </div>\n </div>\n );\n}\n\nexport function AIChatButton({\n label,\n title,\n placeholder,\n backdropColor,\n backdropBlur,\n className,\n onSelectSource,\n defaultCurrency,\n chips,\n theme,\n classNames = {},\n}: AIChatButtonProps) {\n const [open, setOpen] = useState(false);\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => { setMounted(true); }, []);\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <>\n <button\n className={`hsk-cb-btn ${classNames.button || ''} ${className || ''}`}\n onClick={() => setOpen(true)}\n style={customStyles}\n aria-label=\"Open AI chat\"\n >\n <span className=\"hsk-cb-btn-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </span>\n {label !== undefined ? label : null}\n </button>\n {open && mounted && createPortal(\n <ChatModal\n title={title}\n placeholder={placeholder}\n backdropColor={backdropColor}\n backdropBlur={backdropBlur}\n onClose={() => setOpen(false)}\n onSelectSource={onSelectSource}\n defaultCurrency={defaultCurrency}\n chips={chips}\n theme={theme}\n classNames={classNames}\n />,\n document.body\n )}\n </>\n );\n}\n"],"mappings":"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","names":["useRef","useRef","useRef","useRef","useCallback","useState","useState","useCallback","useEffect","useRef","useRef","useEffect","useState","useCallback","useRef","useState","useRef","useCallback","useState","useEffect","useRef","jsx","useState","useRef","useEffect","useState","useEffect","useRef","jsx","jsxs","useRef","useEffect","useState","useState","useRef","useEffect","jsx","jsxs","SparkleIcon","useState","useRef","useEffect","useState","useEffect","useRef","useCallback","createPortal","Fragment","jsx","jsxs","SparkleIcon","ArrowUpIcon","CloseIcon","useRef","useState","useCallback","useEffect","_a","createPortal"]}
|
|
1
|
+
{"version":3,"sources":["../src/api.ts","../src/client.ts","../src/hooks/useHuskel.ts","../src/hooks/useSearch.ts","../src/components/HuskelProvider.tsx","../src/hooks/useIngest.ts","../src/hooks/usePageIngest.ts","../src/hooks/useChat.ts","../src/components/SearchBar.tsx","../src/components/Sparkle.tsx","../src/components/ChatWidget.tsx","../src/utils/markdown.tsx","../src/components/AIChatButton.tsx"],"sourcesContent":["import { Product, SearchResponse, IngestResponse, HuskelError } from './types';\r\n\r\nconst MAX_RETRIES = 3;\r\nconst RETRY_DELAYS = [500, 1000, 2000]; // ms\r\n\r\nfunction log(level: 'info' | 'warn' | 'error', msg: string, data?: unknown) {\r\n const prefix = '[Huskel]';\r\n if (level === 'error') console.error(prefix, msg, data ?? '');\r\n else if (level === 'warn') console.warn(prefix, msg, data ?? '');\r\n else console.log(prefix, msg, data ?? '');\r\n}\r\n\r\nasync function sleep(ms: number) {\r\n return new Promise(r => setTimeout(r, ms));\r\n}\r\n\r\nexport class HuskelAPI {\r\n constructor(\r\n private apiUrl: string,\r\n private siteId: string,\r\n private apiToken: string,\r\n private getShopperId?: () => string | undefined,\r\n private getSessionId?: () => string | undefined\r\n ) {}\r\n\r\n private async post<T>(path: string, body: unknown, attempt = 0): Promise<T> {\r\n const url = `${this.apiUrl}${path}`;\r\n\r\n try {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n 'X-Huskel-Token': this.apiToken,\r\n 'X-Huskel-Site': this.siteId,\r\n };\r\n\r\n const shopperId = this.getShopperId?.();\r\n if (shopperId) {\r\n headers['X-Huskel-Shopper-Id'] = shopperId;\r\n }\r\n\r\n const sessionId = this.getSessionId?.();\r\n if (sessionId) {\r\n headers['X-Huskel-Session-Id'] = sessionId;\r\n }\r\n\r\n const res = await fetch(url, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n const err: HuskelError = { status: res.status, message: text };\r\n\r\n // Don't retry 4xx — developer errors\r\n if (res.status >= 400 && res.status < 500) {\r\n log('error', `${path} failed [${res.status}]`, text);\r\n throw err;\r\n }\r\n\r\n // Retry 5xx\r\n if (attempt < MAX_RETRIES - 1) {\r\n log('warn', `${path} [${res.status}] retrying (${attempt + 1}/${MAX_RETRIES})...`);\r\n await sleep(RETRY_DELAYS[attempt]);\r\n return this.post(path, body, attempt + 1);\r\n }\r\n\r\n log('error', `${path} failed after ${MAX_RETRIES} attempts`, err);\r\n throw err;\r\n }\r\n\r\n return res.json();\r\n } catch (e) {\r\n // Network error (offline, DNS, etc.)\r\n if ((e as HuskelError).status === undefined) {\r\n if (attempt < MAX_RETRIES - 1) {\r\n log('warn', `${path} network error, retrying (${attempt + 1}/${MAX_RETRIES})...`);\r\n await sleep(RETRY_DELAYS[attempt]);\r\n return this.post(path, body, attempt + 1);\r\n }\r\n log('error', `${path} unreachable after ${MAX_RETRIES} attempts`);\r\n }\r\n throw e;\r\n }\r\n }\r\n\r\n async ingest(product: Product): Promise<IngestResponse> {\r\n log('info', 'ingesting product', product.name);\r\n return this.post('/ingest', { siteId: this.siteId, product });\r\n }\r\n\r\n async ingestBatch(products: Product[]): Promise<IngestResponse> {\r\n log('info', `ingesting batch of ${products.length} products`);\r\n return this.post('/ingest/batch', { siteId: this.siteId, products });\r\n }\r\n\r\n async search(query: string, limit = 10): Promise<SearchResponse> {\r\n log('info', 'search query', query);\r\n return this.post('/search', { query, siteId: this.siteId, limit });\r\n }\r\n\r\n // Pure vector search — no LLM, instant results. This is what the SearchBar uses.\r\n async searchVector(query: string, limit = 10): Promise<SearchResponse> {\r\n return this.post('/search/vector', { query, siteId: this.siteId, limit });\r\n }\r\n\r\n // Autocomplete — pure in-memory Trie, <1ms, no Upstash call. Only true prefix matches.\r\n async searchAutocomplete(query: string, limit = 8): Promise<SearchResponse> {\r\n return this.post('/search/autocomplete', { query, siteId: this.siteId, limit });\r\n }\r\n\r\n // LLM chat — conversational search with history context.\r\n async chat(query: string, history: Array<{ role: 'user' | 'assistant'; content: string }> = []): Promise<{ answer: string; sources: any[] }> {\r\n log('info', 'chat query', query);\r\n return this.post('/chat', { query, siteId: this.siteId, history });\r\n }\r\n}\r\n","import { HuskelConfig, Product, RawProductInput } from './types';\r\nimport { HuskelAPI } from './api';\r\n\r\nfunction getEnvVar(key: string): string | undefined {\r\n if (typeof globalThis !== 'undefined') {\r\n const g = globalThis as any;\r\n if (g.process && g.process.env) {\r\n return g.process.env[key];\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction mapRawProduct(input: RawProductInput): Product | null {\r\n const name = input.name || input.title || input.productName || '';\r\n \r\n let price = '';\r\n let priceNumeric: number | undefined = undefined;\r\n\r\n if (input.price !== undefined) {\r\n if (typeof input.price === 'number') {\r\n priceNumeric = input.price;\r\n price = String(input.price);\r\n } else {\r\n price = input.price;\r\n const num = parseFloat(input.price.replace(/[^0-9.]/g, ''));\r\n priceNumeric = isNaN(num) ? undefined : num;\r\n }\r\n }\r\n if (input.priceNumeric !== undefined) {\r\n priceNumeric = input.priceNumeric;\r\n }\r\n\r\n let url = input.url || '';\r\n if (!url && typeof window !== 'undefined') {\r\n url = window.location.href;\r\n }\r\n\r\n let slug = input.slug || input.id || input.productId || '';\r\n if (!slug && url) {\r\n slug = url.split('/').filter(Boolean).pop() || '';\r\n }\r\n if (!slug && name) {\r\n slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');\r\n }\r\n\r\n let images: string[] = [];\r\n if (input.images) {\r\n images = input.images;\r\n } else if (input.image) {\r\n images = [input.image];\r\n } else if (input.thumbnail) {\r\n images = [input.thumbnail];\r\n }\r\n\r\n if (!name) {\r\n console.warn('[Huskel] Validation warning: Product name/title is missing. Skipping:', input);\r\n return null;\r\n }\r\n if (!price) {\r\n console.warn('[Huskel] Validation warning: Product price is missing. Skipping:', input);\r\n return null;\r\n }\r\n if (!url) {\r\n console.warn('[Huskel] Validation warning: Product URL is missing. Skipping:', input);\r\n return null;\r\n }\r\n\r\n return {\r\n name,\r\n price,\r\n url,\r\n brand: input.brand,\r\n description: input.description,\r\n originalPrice: input.originalPrice,\r\n discount: input.discount,\r\n currency: input.currency ?? 'KES',\r\n stock: input.stock,\r\n availability: input.availability,\r\n rating: input.rating,\r\n reviewCount: input.reviewCount,\r\n category: input.category,\r\n subCategory: input.subCategory,\r\n tags: input.tags,\r\n images: images.length > 0 ? images : undefined,\r\n specs: input.specs,\r\n priceNumeric,\r\n slug,\r\n };\r\n}\r\n\r\nfunction generateUUID(): string {\r\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\r\n return crypto.randomUUID();\r\n }\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\nexport class HuskelClient {\r\n readonly api: HuskelAPI;\r\n private ingestQueue: Product[] = [];\r\n private ingestTimer: ReturnType<typeof setTimeout> | null = null;\r\n private ingestedUrls = new Set<string>();\r\n private onlineHandler: (() => void) | null = null;\r\n private shopperId?: string;\r\n private sessionId: string = '';\r\n\r\n private static INGEST_CACHE_KEY = 'huskel_ingested_v1';\r\n private static INGEST_CACHE_TTL = 24 * 60 * 60 * 1000; // 24h\r\n\r\n private loadIngestedCache() {\r\n if (typeof window === 'undefined') return;\r\n try {\r\n const raw = localStorage.getItem(HuskelClient.INGEST_CACHE_KEY);\r\n if (!raw) return;\r\n const { ts, urls }: { ts: number; urls: string[] } = JSON.parse(raw);\r\n if (Date.now() - ts > HuskelClient.INGEST_CACHE_TTL) {\r\n localStorage.removeItem(HuskelClient.INGEST_CACHE_KEY);\r\n return;\r\n }\r\n this.ingestedUrls = new Set(urls);\r\n } catch { /* ignore */ }\r\n }\r\n\r\n private saveIngestedCache() {\r\n if (typeof window === 'undefined') return;\r\n try {\r\n localStorage.setItem(\r\n HuskelClient.INGEST_CACHE_KEY,\r\n JSON.stringify({ ts: Date.now(), urls: [...this.ingestedUrls] })\r\n );\r\n } catch { /* ignore */ }\r\n }\r\n\r\n constructor(config: HuskelConfig) {\r\n const siteId = config.siteId || getEnvVar('NEXT_PUBLIC_HUSKEL_SITE_ID') || '';\r\n const apiUrl = config.apiUrl || getEnvVar('NEXT_PUBLIC_HUSKEL_API_URL') || '';\r\n const apiToken = config.apiToken || getEnvVar('NEXT_PUBLIC_HUSKEL_API_TOKEN') || '';\r\n\r\n // Runtime validation — fail loudly so misconfiguration is never silent\r\n if (!siteId) console.error('[Huskel] Missing siteId. Set it via <HuskelProvider siteId=\"...\"> or NEXT_PUBLIC_HUSKEL_SITE_ID.');\r\n if (!apiUrl) console.error('[Huskel] Missing apiUrl. Set it via <HuskelProvider apiUrl=\"...\"> or NEXT_PUBLIC_HUSKEL_API_URL.');\r\n if (!apiToken) console.error('[Huskel] Missing apiToken. Set it via <HuskelProvider apiToken=\"...\"> or NEXT_PUBLIC_HUSKEL_API_TOKEN.');\r\n\r\n this.shopperId = config.shopperId;\r\n this.initSession();\r\n this.loadIngestedCache();\r\n\r\n this.api = new HuskelAPI(\r\n apiUrl,\r\n siteId,\r\n apiToken,\r\n () => this.shopperId,\r\n () => this.sessionId\r\n );\r\n instance = this;\r\n\r\n if (typeof window !== 'undefined') {\r\n this.onlineHandler = () => {\r\n console.log('[Huskel] Connectivity restored, flushing queued ingestions.');\r\n this.flushQueue();\r\n };\r\n window.addEventListener('online', this.onlineHandler);\r\n }\r\n }\r\n\r\n setShopperId(id: string | undefined) {\r\n this.shopperId = id;\r\n }\r\n\r\n getShopperId(): string | undefined {\r\n return this.shopperId;\r\n }\r\n\r\n getSessionId(): string {\r\n return this.sessionId;\r\n }\r\n\r\n private initSession() {\r\n if (typeof window !== 'undefined' && window.sessionStorage) {\r\n try {\r\n let sid = window.sessionStorage.getItem('huskel_session_id');\r\n if (!sid) {\r\n sid = generateUUID();\r\n window.sessionStorage.setItem('huskel_session_id', sid);\r\n }\r\n this.sessionId = sid;\r\n return;\r\n } catch (e) {\r\n // Fallback if sessionStorage is disabled or private mode\r\n }\r\n }\r\n this.sessionId = generateUUID();\r\n }\r\n\r\n destroy() {\r\n if (typeof window !== 'undefined' && this.onlineHandler) {\r\n window.removeEventListener('online', this.onlineHandler);\r\n this.onlineHandler = null;\r\n }\r\n if (this.ingestTimer) {\r\n clearTimeout(this.ingestTimer);\r\n this.ingestTimer = null;\r\n }\r\n if (instance === this) instance = null;\r\n }\r\n\r\n async queueIngest(rawProduct: RawProductInput): Promise<void> {\r\n const product = mapRawProduct(rawProduct);\r\n if (!product) return;\r\n\r\n if (this.ingestedUrls.has(product.url)) {\r\n return; // already indexed in this session or today — skip\r\n }\r\n this.ingestedUrls.add(product.url);\r\n this.saveIngestedCache();\r\n\r\n this.ingestQueue.push(product);\r\n this.scheduleFlush();\r\n }\r\n\r\n async queueIngestBatch(rawProducts: RawProductInput[]): Promise<void> {\r\n rawProducts.forEach(p => {\r\n const product = mapRawProduct(p);\r\n if (!product) return;\r\n\r\n if (this.ingestedUrls.has(product.url)) {\r\n return;\r\n }\r\n this.ingestedUrls.add(product.url);\r\n this.ingestQueue.push(product);\r\n });\r\n\r\n if (this.ingestQueue.length > 0) {\r\n this.saveIngestedCache();\r\n this.scheduleFlush();\r\n }\r\n }\r\n\r\n private scheduleFlush() {\r\n if (this.ingestTimer) return;\r\n this.ingestTimer = setTimeout(() => {\r\n this.flushQueue();\r\n }, 300);\r\n }\r\n\r\n private async flushQueue() {\r\n this.ingestTimer = null;\r\n if (this.ingestQueue.length === 0) return;\r\n\r\n if (typeof navigator !== 'undefined' && !navigator.onLine) {\r\n console.warn('[Huskel] Browser offline. Postponing ingestion.');\r\n return;\r\n }\r\n\r\n const batch = [...this.ingestQueue];\r\n this.ingestQueue = [];\r\n\r\n try {\r\n await this.api.ingestBatch(batch);\r\n } catch (e: any) {\r\n if (e.status && e.status >= 400 && e.status < 500) {\r\n console.error('[Huskel] Ingestion discarded due to client error:', e.message);\r\n return;\r\n }\r\n\r\n // Re-queue and schedule another flush so items are not stuck forever\r\n console.warn('[Huskel] Ingestion failed. Re-queuing to retry.', e);\r\n this.ingestQueue = [...batch, ...this.ingestQueue];\r\n this.scheduleFlush();\r\n }\r\n }\r\n}\r\n\r\nlet instance: HuskelClient | null = null;\r\n\r\nexport function initHuskel(config: HuskelConfig): HuskelClient {\r\n instance = new HuskelClient(config);\r\n return instance;\r\n}\r\n\r\nexport function getHuskelClient(): HuskelClient {\r\n if (!instance) {\r\n const siteId = getEnvVar('NEXT_PUBLIC_HUSKEL_SITE_ID');\r\n const apiUrl = getEnvVar('NEXT_PUBLIC_HUSKEL_API_URL');\r\n const apiToken = getEnvVar('NEXT_PUBLIC_HUSKEL_API_TOKEN');\r\n\r\n if (siteId && apiUrl && apiToken) {\r\n instance = new HuskelClient({ siteId, apiUrl, apiToken });\r\n } else {\r\n throw new Error('[Huskel] Call initHuskel() or set NEXT_PUBLIC_HUSKEL_* environment variables before using the client.');\r\n }\r\n }\r\n return instance;\r\n}\r\n","import { useRef } from 'react';\r\nimport { HuskelConfig } from '../types';\r\nimport { HuskelClient, initHuskel } from '../client';\r\n\r\n/**\r\n * @deprecated Use <HuskelProvider> instead to avoid SSR issues.\r\n */\r\nexport function useHuskel(config: HuskelConfig): HuskelClient {\r\n const clientRef = useRef<HuskelClient | null>(null);\r\n\r\n if (!clientRef.current) {\r\n console.warn('[Huskel] useHuskel() is deprecated. Please wrap your application in <HuskelProvider> instead.');\r\n clientRef.current = initHuskel(config);\r\n }\r\n\r\n return clientRef.current;\r\n}\r\n","import { useState, useCallback, useRef } from 'react';\nimport { SearchResult } from '../types';\nimport { useHuskelContext } from '../components/HuskelProvider';\n\ninterface UseSearchReturn {\n results: SearchResult[];\n loading: boolean;\n error: string | null;\n search: (query: string, limit?: number) => Promise<void>;\n clear: () => void;\n}\n\nexport function useSearch(): UseSearchReturn {\n const client = useHuskelContext();\n const [results, setResults] = useState<SearchResult[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n // Generation counter so stale responses from any in-flight requests don't overwrite newer ones\n const genRef = useRef(0);\n\n const search = useCallback(async (query: string, limit = 8) => {\n if (!query.trim()) { setResults([]); setLoading(false); return; }\n const gen = ++genRef.current;\n // No loading spinner for autocomplete — it's so fast it would just flicker\n setError(null);\n try {\n // searchAutocomplete = pure in-memory Trie, <1ms, no Upstash\n const res = await client.api.searchAutocomplete(query, limit);\n if (gen === genRef.current) {\n setResults(res.results ?? []);\n }\n } catch (e: unknown) {\n if (gen === genRef.current) {\n setError((e as Error).message ?? 'Search failed');\n }\n } finally {\n if (gen === genRef.current) setLoading(false);\n }\n }, [client]);\n\n const clear = useCallback(() => {\n genRef.current++;\n setResults([]);\n setError(null);\n setLoading(false);\n }, []);\n\n return { results, loading, error, search, clear };\n}\n","'use client';\r\n\r\nimport React, { createContext, useContext, useEffect, useRef } from 'react';\r\nimport { HuskelClient, getHuskelClient } from '../client';\r\nimport { HuskelConfig } from '../types';\r\n\r\nexport const HuskelContext = createContext<HuskelClient | null>(null);\r\n\r\ninterface HuskelProviderProps extends HuskelConfig {\r\n children: React.ReactNode;\r\n}\r\n\r\nexport function HuskelProvider({ siteId, apiUrl, apiToken, shopperId, children }: HuskelProviderProps) {\r\n const clientRef = useRef<HuskelClient | null>(null);\r\n\r\n if (!clientRef.current) {\r\n clientRef.current = new HuskelClient({ siteId, apiUrl, apiToken, shopperId });\r\n }\r\n\r\n // Update shopperId dynamically when it changes (e.g., shopper logs in/out)\r\n useEffect(() => {\r\n clientRef.current?.setShopperId(shopperId);\r\n }, [shopperId]);\r\n\r\n // Clean up the online listener and timers when the provider unmounts\r\n // (prevents leaks during hot module reload and React StrictMode double-mount)\r\n useEffect(() => {\r\n return () => {\r\n clientRef.current?.destroy();\r\n };\r\n }, []);\r\n\r\n return (\r\n <HuskelContext.Provider value={clientRef.current}>\r\n {children}\r\n </HuskelContext.Provider>\r\n );\r\n}\r\n\r\nexport function useHuskelContext(): HuskelClient {\r\n const context = useContext(HuskelContext);\r\n if (!context) {\r\n return getHuskelClient();\r\n }\r\n return context;\r\n}\r\n\r\n","import { useCallback, useState } from 'react';\r\nimport { RawProductInput } from '../types';\r\nimport { useHuskelContext } from '../components/HuskelProvider';\r\n\r\ninterface UseIngestReturn {\r\n ingest: (product: RawProductInput) => Promise<void>;\r\n ingestBatch: (products: RawProductInput[]) => Promise<void>;\r\n loading: boolean;\r\n error: string | null;\r\n}\r\n\r\nexport function useIngest(): UseIngestReturn {\r\n const client = useHuskelContext();\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const ingest = useCallback(async (product: RawProductInput) => {\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n await client.queueIngest(product);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Ingest failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n const ingestBatch = useCallback(async (products: RawProductInput[]) => {\r\n if (!products.length) return;\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n await client.queueIngestBatch(products);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Batch ingest failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n return { ingest, ingestBatch, loading, error };\r\n}\r\n","import { useEffect, useRef } from 'react';\nimport { RawProductInput } from '../types';\nimport { getHuskelClient } from '../client';\n\n/**\n * usePageIngest — drop this into any product page component.\n * The moment a customer's browser renders the page, the product is\n * automatically captured and queued for ingestion into the vector index.\n *\n * No configuration needed beyond <HuskelProvider> in your layout.\n *\n * @example\n * // Product detail page — Next.js or React\n * export function ProductPage({ product }) {\n * usePageIngest({\n * name: product.title,\n * price: product.price,\n * url: window.location.href,\n * images: [product.thumbnail],\n * category: product.category,\n * });\n * return <div>...</div>;\n * }\n */\nexport function usePageIngest(product: RawProductInput | null | undefined): void {\n // Use url as the stable key — avoids re-ingesting on unrelated re-renders\n const ingestedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!product) return;\n\n // Resolve URL — falls back to window.location if not provided\n const url =\n product.url ||\n (typeof window !== 'undefined' ? window.location.href : '');\n\n // Guard: only ingest once per URL per component lifecycle\n if (ingestedRef.current === url) return;\n ingestedRef.current = url;\n\n try {\n getHuskelClient().queueIngest({ ...product, url });\n } catch {\n // Client not initialised — silently skip\n }\n }, [product?.url ?? product?.name]);\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { useHuskelContext } from '../components/HuskelProvider';\n\nexport interface ChatMessage {\n role: 'user' | 'assistant';\n content: string;\n}\n\nexport interface ChatSource {\n id?: string;\n name: string;\n price?: string;\n currency?: string;\n category?: string;\n url?: string;\n image?: string;\n}\n\ninterface UseChatReturn {\n messages: ChatMessage[];\n sources: ChatSource[];\n loading: boolean;\n error: string | null;\n send: (query: string) => Promise<void>;\n reset: () => void;\n}\n\nexport function useChat(): UseChatReturn {\n const client = useHuskelContext();\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [sources, setSources] = useState<ChatSource[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n const send = useCallback(async (query: string) => {\n if (!query.trim() || loading) return;\n abortRef.current?.abort();\n abortRef.current = new AbortController();\n const signal = abortRef.current.signal;\n\n // Optimistically add the user message\n const userMsg: ChatMessage = { role: 'user', content: query };\n setMessages(prev => [...prev, userMsg]);\n setLoading(true);\n setError(null);\n\n try {\n // Build history from current messages (exclude the one we just added — server will see it as query)\n const history = messages.map(m => ({ role: m.role, content: m.content }));\n const res = await client.api.chat(query, history);\n\n if (signal.aborted) return;\n\n const fullAnswer = res.answer || '';\n const words = fullAnswer.split(/(\\s+)/);\n\n // Initialize empty assistant message\n setMessages(prev => [...prev, { role: 'assistant', content: '' }]);\n\n let currentContent = '';\n for (const word of words) {\n if (signal.aborted) return;\n currentContent += word;\n setMessages(prev => {\n const next = [...prev];\n if (next.length > 0) {\n next[next.length - 1] = { role: 'assistant', content: currentContent };\n }\n return next;\n });\n // 25ms delay per word token to make it read naturally\n await new Promise(resolve => setTimeout(resolve, 25));\n }\n\n if (signal.aborted) return;\n setSources(res.sources ?? []);\n } catch (e: any) {\n if (signal.aborted) return;\n setError(e?.message ?? 'Chat request failed');\n // Remove the optimistic user message on failure\n setMessages(prev => prev.slice(0, -1));\n } finally {\n if (!signal.aborted) {\n setLoading(false);\n }\n }\n }, [client, messages, loading]);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setMessages([]);\n setSources([]);\n setError(null);\n setLoading(false);\n }, []);\n\n return { messages, sources, loading, error, send, reset };\n}\n","import React, { useState, useEffect, useRef } from 'react';\nimport { useSearch } from '../hooks/useSearch';\nimport { SearchResult } from '../types';\n\nexport interface SearchBarProps {\n placeholder?: string;\n limit?: number;\n /** Debounce in ms — default 80 for near-instant feel */\n debounceMs?: number;\n onSelect?: (result: SearchResult) => void;\n className?: string;\n inputClassName?: string;\n dropdownClassName?: string;\n renderResult?: (result: SearchResult) => React.ReactNode;\n theme?: {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n fontFamily?: string;\n };\n classNames?: {\n root?: string;\n input?: string;\n dropdown?: string;\n row?: string;\n };\n}\n\n/* SVG search glass — pure inline so no icon dependency */\nconst SearchIcon = () => (\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\">\n <circle cx=\"8.5\" cy=\"8.5\" r=\"5.5\"/>\n <line x1=\"13\" y1=\"13\" x2=\"18\" y2=\"18\"/>\n </svg>\n);\n\nexport function SearchBar({\n placeholder = 'Search products…',\n limit = 10,\n debounceMs = 80,\n onSelect,\n className,\n inputClassName,\n dropdownClassName,\n renderResult,\n theme,\n classNames = {},\n}: SearchBarProps) {\n const [query, setQuery] = useState('');\n const [open, setOpen] = useState(false);\n const { results, loading, search, clear } = useSearch();\n const timer = useRef<ReturnType<typeof setTimeout>>();\n const wrap = useRef<HTMLDivElement>(null);\n\n /* Debounce search — but keep stale results visible between calls */\n useEffect(() => {\n clearTimeout(timer.current);\n if (!query.trim()) { clear(); setOpen(false); return; }\n setOpen(true); // open immediately (stale results show while fetching)\n timer.current = setTimeout(() => { search(query, limit); }, debounceMs);\n return () => clearTimeout(timer.current);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [query]);\n\n /* Click-outside to close */\n useEffect(() => {\n const h = (e: MouseEvent) => {\n if (wrap.current && !wrap.current.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener('mousedown', h);\n return () => document.removeEventListener('mousedown', h);\n }, []);\n\n const handleSelect = (r: SearchResult) => {\n setOpen(false);\n setQuery(r.product.name);\n onSelect?.(r);\n };\n\n const showDrop = open && query.trim().length > 0;\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <div className={`hsk-sb-wrap ${classNames.root || ''} ${className || ''}`} ref={wrap} style={customStyles}>\n <span className=\"hsk-sb-icon\"><SearchIcon /></span>\n <input\n className={`hsk-sb-input ${classNames.input || ''} ${inputClassName || ''}`}\n type=\"text\"\n value={query}\n placeholder={placeholder}\n onChange={e => setQuery(e.target.value)}\n onFocus={() => results.length > 0 && query.trim() && setOpen(true)}\n autoComplete=\"off\"\n spellCheck={false}\n />\n {showDrop && (\n <div className={`hsk-sb-drop ${classNames.dropdown || ''} ${dropdownClassName || ''}`} style={{ position: 'absolute' }}>\n {loading && <div className=\"hsk-sb-loading-bar\" />}\n\n {results.length === 0 && !loading && (\n <div className=\"hsk-sb-empty\">No results for “{query}”</div>\n )}\n\n {results.map((r, i) => (\n renderResult ? (\n <div\n key={r.id}\n onClick={() => handleSelect(r)}\n className=\"hsk-sb-fade\"\n style={{ animationDelay: `${i * 18}ms` }}\n >\n {renderResult(r)}\n </div>\n ) : (\n <div\n key={r.id}\n className={`hsk-sb-row hsk-sb-fade ${classNames.row || ''}`}\n style={{ animationDelay: `${i * 18}ms` }}\n onClick={() => handleSelect(r)}\n >\n <span className=\"hsk-sb-row-icon\"><SearchIcon /></span>\n <div className=\"hsk-sb-row-body\">\n <div className=\"hsk-sb-row-title\">{r.product.name}</div>\n {(r.product.category || r.product.brand) && (\n <div className=\"hsk-sb-row-sub\">\n {r.product.category ?? r.product.brand}\n </div>\n )}\n </div>\n </div>\n )\n ))}\n </div>\n )}\n </div>\n );\n}\n","import React, { useState, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useSearch } from '../hooks/useSearch';\nimport { SearchResult } from '../types';\n\nexport interface SparkleProps {\n productName: string;\n limit?: number;\n onResult?: (results: SearchResult[]) => void;\n /** Override the backdrop colour (any CSS colour/gradient) */\n backdropColor?: string;\n /** Override backdrop blur — e.g. \"8px\" or 8 */\n backdropBlur?: string | number;\n /** Extra classes on the trigger button */\n className?: string;\n /** Called when user clicks a result — return false to prevent default navigation */\n onNavigate?: (result: SearchResult) => boolean | void;\n theme?: {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n fontFamily?: string;\n };\n classNames?: {\n button?: string;\n backdrop?: string;\n card?: string;\n item?: string;\n };\n}\n\nconst SparkleIcon = ({ className }: { className?: string }) => (\n <svg className={className} width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <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\"/>\n </svg>\n);\n\nconst CloseIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n);\n\n/* ── Modal ────────────────────────────────────────────────────────────────── */\ninterface ModalProps extends Pick<SparkleProps, 'productName' | 'limit' | 'backdropColor' | 'backdropBlur' | 'onNavigate' | 'onResult' | 'theme' | 'classNames'> {\n onClose: () => void;\n}\n\nfunction SparkleModal({ \n productName, \n limit, \n backdropColor, \n backdropBlur, \n onClose, \n onNavigate, \n onResult,\n theme,\n classNames = {},\n}: ModalProps) {\n const { results, loading, search } = useSearch();\n const initiated = useRef(false);\n\n /* auto-search on open */\n useEffect(() => {\n if (!initiated.current) { initiated.current = true; search(productName, limit); }\n }, []);\n\n /* fire callback */\n useEffect(() => { if (results.length > 0) onResult?.(results); }, [results]);\n\n /* Escape key */\n useEffect(() => {\n const h = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };\n document.addEventListener('keydown', h);\n return () => document.removeEventListener('keydown', h);\n }, []);\n\n const blurVal = typeof backdropBlur === 'number' ? `${backdropBlur}px` : (backdropBlur ?? '16px');\n const bg = backdropColor ?? undefined;\n\n const handleNav = (r: SearchResult) => {\n const prevent = onNavigate?.(r);\n if (prevent !== false) {\n onClose();\n if (r.product.url) window.location.href = r.product.url;\n }\n };\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <div\n className={`hsk-sp-backdrop ${classNames.backdrop || ''}`}\n onClick={onClose}\n style={{\n backdropFilter: `blur(${blurVal})`,\n WebkitBackdropFilter: `blur(${blurVal})`,\n background: bg ?? undefined,\n ...customStyles,\n }}\n >\n <div className={`hsk-sp-card ${classNames.card || ''}`} onClick={e => e.stopPropagation()}>\n <div className=\"hsk-sp-header\">\n <span className=\"hsk-sp-header-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </span>\n <div className=\"hsk-sp-header-body\">\n <div className=\"hsk-sp-header-title\">Similar to “{productName}”</div>\n <div className=\"hsk-sp-header-sub\">AI vector similarity · instant results</div>\n </div>\n <button className=\"hsk-sp-close\" onClick={onClose} aria-label=\"Close\">\n <CloseIcon />\n </button>\n </div>\n\n {loading && <div className=\"hsk-sp-bar\" />}\n\n <div className=\"hsk-sp-results\">\n {!loading && results.length === 0 && (\n <div className=\"hsk-sp-empty\">No similar products found.</div>\n )}\n\n {results.map((r, i) => {\n const price = parseFloat(r.product.price?.replace(/[^0-9.]/g, '') || '0');\n const currency = r.product.currency ?? 'KES';\n return (\n <div\n key={r.id}\n className={`hsk-sp-item ${classNames.item || ''}`}\n style={{ animationDelay: `${i * 55}ms` }}\n >\n <div className=\"hsk-sp-img-wrap\">\n {r.product.images?.[0]\n ? <img src={r.product.images[0]} alt={r.product.name} />\n : <span className=\"hsk-sp-img-placeholder\">🛍</span>\n }\n </div>\n\n <div className=\"hsk-sp-item-body\">\n {r.product.category && (\n <div className=\"hsk-sp-item-cat\">{r.product.category}</div>\n )}\n <div className=\"hsk-sp-item-name\">{r.product.name}</div>\n <div className=\"hsk-sp-item-price-row\">\n <span className=\"hsk-sp-item-currency\">{currency}</span>\n <span className=\"hsk-sp-item-price\">{price.toLocaleString()}</span>\n </div>\n <div className=\"hsk-sp-actions\">\n <button\n className=\"hsk-sp-action hsk-sp-action-primary\"\n onClick={() => handleNav(r)}\n >\n View Product\n </button>\n <button\n className=\"hsk-sp-action hsk-sp-action-secondary\"\n onClick={() => onClose()}\n >\n Add to Cart\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n <div className=\"hsk-sp-footer\">\n <span className=\"hsk-sp-badge\" style={{ display: 'inline-flex', alignItems: 'center', gap: '4px' }}>\n <SparkleIcon /> Huskel AI\n </span>\n <span className=\"hsk-sp-esc\">Esc to close</span>\n </div>\n </div>\n </div>\n );\n}\n\n/* ── Exported component ───────────────────────────────────────────────────── */\nexport function Sparkle({ \n productName, \n limit = 8, \n onResult, \n backdropColor, \n backdropBlur, \n className, \n onNavigate,\n theme,\n classNames = {},\n}: SparkleProps) {\n const [open, setOpen] = useState(false);\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => { setMounted(true); }, []);\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <>\n <button\n className={`hsk-sp-btn ${classNames.button || ''} ${className || ''}`}\n onClick={() => setOpen(true)}\n style={customStyles}\n title=\"Find similar products\"\n aria-label=\"Find similar products\"\n >\n <SparkleIcon />\n </button>\n {open && mounted && createPortal(\n <SparkleModal\n productName={productName}\n limit={limit}\n backdropColor={backdropColor}\n backdropBlur={backdropBlur}\n onClose={() => setOpen(false)}\n onResult={onResult}\n onNavigate={onNavigate}\n theme={theme}\n classNames={classNames}\n />,\n document.body\n )}\n </>\n );\n}\n","import React, { useState, useRef, useEffect } from 'react';\nimport { useChat, ChatMessage, ChatSource } from '../hooks/useChat';\nimport { renderMarkdown } from '../utils/markdown';\n\n// Better Prop Interface for SDKs\nexport interface ChatWidgetProps {\n title?: string;\n placeholder?: string;\n emptyStateText?: string;\n emptyStateSuggestions?: string;\n defaultCurrency?: string;\n className?: string;\n \n // Allow overriding styles via standard CSS variables\n theme?: {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n fontFamily?: string;\n };\n \n // Allow targeting specific elements with custom classes (e.g. Tailwind)\n classNames?: {\n root?: string;\n header?: string;\n messageBubble?: string;\n input?: string;\n };\n \n onSelectSource?: (source: ChatSource) => void;\n}\n\n// Simple SVG Icons instead of text characters\nconst SparkleIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <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\"/>\n </svg>\n);\n\nconst ArrowUpIcon = () => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 7-7 7 7\"/>\n <path d=\"M12 19V5\"/>\n </svg>\n);\n\nfunction SourceCard({ source, defaultCurrency, onSelect }: { source: ChatSource; defaultCurrency: string; onSelect?: (s: ChatSource) => void }) {\n return (\n <div className=\"hsk-source-card\" onClick={() => onSelect?.(source)}>\n {source.image && <img src={source.image} alt={source.name} className=\"hsk-source-img\" />}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div className=\"hsk-source-name\">{source.name}</div>\n {source.price && (\n <div className=\"hsk-source-price\">{source.currency ?? defaultCurrency} {source.price}</div>\n )}\n </div>\n </div>\n );\n}\n\nexport function ChatWidget({ \n title = 'AI Shopping Assistant',\n placeholder = 'Ask about anything in our store…', \n emptyStateText = 'Ask me anything about our products',\n emptyStateSuggestions = '\"Find me headphones under KSh 5,000\" · \"Gift ideas\"',\n defaultCurrency = 'KES',\n className,\n theme,\n classNames = {},\n onSelectSource \n}: ChatWidgetProps) {\n const { messages, sources, loading, error, send, reset } = useChat();\n const [input, setInput] = useState('');\n const bottomRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages, loading]);\n\n const handleSend = async () => {\n const q = input.trim();\n if (!q || loading) return;\n setInput('');\n if (textareaRef.current) textareaRef.current.style.height = 'auto';\n await send(q);\n };\n\n const handleKey = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const handleInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setInput(e.target.value);\n const t = e.target;\n t.style.height = 'auto';\n t.style.height = Math.min(t.scrollHeight, 120) + 'px';\n };\n\n // Apply custom CSS variables inline to the root wrapper\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <div \n className={`hsk-chat-widget ${classNames.root || ''} ${className || ''}`} \n style={customStyles}\n >\n <div className={`hsk-chat-header ${classNames.header || ''}`}>\n <span className=\"hsk-chat-header-icon\"><SparkleIcon /></span>\n <span className=\"hsk-chat-title\">{title}</span>\n <span className=\"hsk-chat-badge\">AI</span>\n {messages.length > 0 && (\n <button className=\"hsk-chat-reset\" onClick={reset} style={{ marginLeft: 'auto' }}>Clear</button>\n )}\n </div>\n\n <div className=\"hsk-chat-messages\">\n {messages.length === 0 ? (\n <div className=\"hsk-chat-empty\">\n <div className=\"hsk-chat-empty-icon\"><SparkleIcon /></div>\n <div>{emptyStateText}</div>\n <div className=\"hsk-chat-empty-suggestions\">{emptyStateSuggestions}</div>\n </div>\n ) : (\n messages.map((msg, idx) => (\n <div key={idx}>\n <div className={`hsk-msg-row ${msg.role}`}>\n <div className={`hsk-msg-avatar ${msg.role === 'assistant' ? 'ai' : 'user'}`}>\n {msg.role === 'assistant' ? <SparkleIcon /> : 'U'}\n </div>\n <div className={`hsk-msg-bubble ${msg.role} ${classNames.messageBubble || ''}`}>\n {renderMarkdown(msg.content)}\n </div>\n </div>\n {msg.role === 'assistant' && idx === messages.length - 1 && sources.length > 0 && (\n <div className=\"hsk-sources-container\">\n <div className=\"hsk-sources\">\n {sources.map((src, si) => (\n <SourceCard key={si} source={src} defaultCurrency={defaultCurrency} onSelect={onSelectSource} />\n ))}\n </div>\n </div>\n )}\n </div>\n ))\n )}\n\n {loading && (\n <div className=\"hsk-msg-row\">\n <div className=\"hsk-msg-avatar ai\"><SparkleIcon /></div>\n <div className=\"hsk-typing\">\n <div className=\"hsk-typing-dot\" /><div className=\"hsk-typing-dot\" /><div className=\"hsk-typing-dot\" />\n </div>\n </div>\n )}\n\n {error && <div className=\"hsk-chat-error\">{error}</div>}\n <div ref={bottomRef} />\n </div>\n\n <div className=\"hsk-chat-input-area\">\n <textarea\n ref={textareaRef}\n className={`hsk-chat-input ${classNames.input || ''}`}\n value={input}\n onChange={handleInput}\n onKeyDown={handleKey}\n placeholder={placeholder}\n rows={1}\n disabled={loading}\n />\n <button\n className=\"hsk-chat-send\"\n onClick={handleSend}\n disabled={!input.trim() || loading}\n aria-label=\"Send message\"\n >\n <ArrowUpIcon />\n </button>\n </div>\n </div>\n );\n}\n\n","import React from 'react';\n\n// Helper to parse inline styles (bold, links, and inline code) safely into React nodes\nconst parseInline = (text: string, keyPrefix: string): React.ReactNode => {\n // Regex to match markdown links, bold text, and inline code\n const tokenRegex = /(\\[[^\\]]+\\]\\([^)]+\\)|\\*\\*[^*]+\\*\\*|`[^`]+`)/g;\n const parts = text.split(tokenRegex);\n\n return parts.map((part, index) => {\n if (!part) return null;\n const key = `${keyPrefix}-inline-${index}`;\n\n // Handle Inline Code\n if (part.startsWith('`') && part.endsWith('`')) {\n return (\n <code key={key} className=\"hsk-markdown-code\">\n {part.slice(1, -1)}\n </code>\n );\n }\n\n // Handle Bold\n if (part.startsWith('**') && part.endsWith('**')) {\n return <strong key={key}>{parseInline(part.slice(2, -2), key)}</strong>;\n }\n\n // Handle Links\n const linkMatch = part.match(/^\\[([^\\]]+)\\]\\(([^)]+)\\)$/);\n if (linkMatch) {\n // Basic sanitization: ensure the URL doesn't contain javascript:\n const url = linkMatch[2];\n const isSafeUrl = /^(https?|mailto|tel):/i.test(url) || url.startsWith('/');\n if (isSafeUrl) {\n return (\n <a key={key} href={url} target=\"_blank\" rel=\"noopener noreferrer\" className=\"hsk-markdown-link\">\n {parseInline(linkMatch[1], key)}\n </a>\n );\n }\n return <span key={key}>{parseInline(linkMatch[1], key)}</span>; // Fallback to plain text if unsafe\n }\n\n // Return standard text\n return part;\n });\n};\n\nexport function renderMarkdown(content: string): React.ReactNode {\n const lines = content.split('\\n');\n const elements: React.ReactNode[] = [];\n \n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n const key = `md-line-${i}`;\n\n // 1. Empty lines (spacing)\n if (!line.trim()) {\n i++;\n continue;\n }\n\n // 2. Headers\n const headerMatch = line.match(/^(#{1,3})\\s+(.*)/);\n if (headerMatch) {\n const level = headerMatch[1].length;\n const Tag = `h${level + 3}` as keyof JSX.IntrinsicElements; // Maps # to h4, ## to h5 to avoid messing up host page hierarchy\n elements.push(<Tag key={key} className={`hsk-markdown-h${level}`}>{parseInline(headerMatch[2], key)}</Tag>);\n i++;\n continue;\n }\n\n // 3. Unordered Lists\n if (line.match(/^[-*]\\s+/)) {\n const listItems: React.ReactNode[] = [];\n while (i < lines.length && lines[i].match(/^[-*]\\s+/)) {\n const itemText = lines[i].replace(/^[-*]\\s+/, '');\n listItems.push(<li key={`li-${i}`}>{parseInline(itemText, `li-${i}`)}</li>);\n i++;\n }\n elements.push(<ul key={`ul-${key}`} className=\"hsk-markdown-list\">{listItems}</ul>);\n continue;\n }\n\n // 4. Tables\n if (line.trim().startsWith('|')) {\n const tableRows: React.ReactNode[] = [];\n let isHeader = true;\n\n while (i < lines.length && lines[i].trim().startsWith('|')) {\n const rowLine = lines[i].trim();\n // Skip markdown table separator (e.g., |---|---|)\n if (rowLine.match(/^\\|[-:| ]+\\|$/)) {\n i++;\n isHeader = false;\n continue;\n }\n\n // Slice to remove outer pipes and map trim to handle empty cells properly\n const cells = rowLine.split('|').slice(1, -1).map(c => c.trim());\n const Tag = isHeader ? 'th' : 'td';\n \n tableRows.push(\n <tr key={`tr-${i}`}>\n {cells.map((cell, cIdx) => (\n <Tag key={`td-${i}-${cIdx}`}>{parseInline(cell, `td-${i}-${cIdx}`)}</Tag>\n ))}\n </tr>\n );\n i++;\n }\n \n elements.push(\n <div key={`table-wrapper-${key}`} className=\"hsk-table-wrapper\">\n <table className=\"hsk-markdown-table\">\n <tbody>{tableRows}</tbody>\n </table>\n </div>\n );\n continue;\n }\n\n // 5. Default Paragraph\n elements.push(\n <p key={key} className=\"hsk-markdown-p\">\n {parseInline(line, key)}\n </p>\n );\n i++;\n }\n\n return <>{elements}</>;\n}\n","'use client';\n\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useChat, ChatMessage, ChatSource } from '../hooks/useChat';\nimport { renderMarkdown } from '../utils/markdown';\n\nexport interface AIChatButtonProps {\n label?: string;\n title?: string;\n placeholder?: string;\n backdropColor?: string;\n backdropBlur?: string | number;\n className?: string;\n onSelectSource?: (source: ChatSource) => void;\n defaultCurrency?: string;\n chips?: string[];\n theme?: {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n fontFamily?: string;\n };\n classNames?: {\n button?: string;\n overlay?: string;\n panel?: string;\n input?: string;\n sendButton?: string;\n };\n}\n\nconst SparkleIcon = ({ className }: { className?: string }) => (\n <svg className={className} width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <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\"/>\n </svg>\n);\n\nconst ArrowUpIcon = () => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 7-7 7 7\"/>\n <path d=\"M12 19V5\"/>\n </svg>\n);\n\nconst CloseIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n);\n\nconst ChevronRightIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m9 18 6-6-6-6\"/>\n </svg>\n);\n\nconst DEFAULT_CHIPS = [\n 'Cheapest smartphone',\n 'Smart TV under KSh 20,000',\n 'Noise-cancelling headphones',\n 'Best laptop for students',\n];\n\ninterface SourcesCarouselProps {\n sources: ChatSource[];\n defaultCurrency: string;\n onSelectSource?: (src: ChatSource) => void;\n}\n\nfunction SourcesCarousel({ sources, defaultCurrency, onSelectSource }: SourcesCarouselProps) {\n const railRef = useRef<HTMLDivElement>(null);\n const [showNext, setShowNext] = useState(false);\n\n const measure = useCallback(() => {\n const el = railRef.current;\n if (!el) return;\n const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 8;\n setShowNext(el.scrollWidth > el.clientWidth + 4 && !atEnd);\n }, []);\n\n useEffect(() => {\n measure();\n const el = railRef.current;\n if (!el) return;\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n el.addEventListener('scroll', measure, { passive: true });\n return () => { ro.disconnect(); el.removeEventListener('scroll', measure); };\n }, [measure, sources]);\n\n const scrollNext = () => {\n railRef.current?.scrollBy({ left: 170, behavior: 'smooth' });\n };\n\n return (\n <div className=\"hsk-cb-sources-wrap\">\n <div className=\"hsk-cb-sources\" ref={railRef}>\n {sources.map((src, si) => (\n <div\n key={si}\n className=\"hsk-cb-source\"\n style={{ animationDelay: `${si * 50}ms` }}\n onClick={() => onSelectSource?.(src)}\n >\n {src.image ? (\n <div className=\"hsk-cb-src-imgwrap\">\n <img src={src.image} alt={src.name} loading=\"lazy\" />\n </div>\n ) : (\n <div className=\"hsk-cb-src-imgwrap-empty\">\n <SparkleIcon />\n </div>\n )}\n <div className=\"hsk-cb-src-info\">\n <div className=\"hsk-cb-src-name\">{src.name}</div>\n {src.price && (\n <div className=\"hsk-cb-src-price\">\n {src.currency ?? defaultCurrency}{' '}\n {parseFloat(src.price.replace(/[^0-9.]/g, '') || '0').toLocaleString()}\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n {showNext && (\n <>\n <div\n className=\"hsk-cb-sources-fade\"\n style={{ background: 'linear-gradient(to right, transparent, var(--hsk-fade-bg, #0e0e0f))' }}\n />\n <button className=\"hsk-cb-sources-next\" onClick={scrollNext} aria-label=\"See more\">\n <ChevronRightIcon />\n </button>\n </>\n )}\n </div>\n );\n}\n\ninterface ChatModalProps extends Pick<AIChatButtonProps, 'title' | 'placeholder' | 'backdropColor' | 'backdropBlur' | 'onSelectSource' | 'defaultCurrency' | 'chips' | 'theme' | 'classNames'> {\n onClose: () => void;\n}\n\nfunction ChatModal({\n title = 'AI Shopping Assistant',\n placeholder = 'Ask me anything — gifts, budget, use case…',\n backdropColor,\n backdropBlur,\n onClose,\n onSelectSource,\n defaultCurrency = 'KES',\n chips = DEFAULT_CHIPS,\n theme,\n classNames = {},\n}: ChatModalProps) {\n const { messages, sources, loading, error, send, reset } = useChat();\n const [input, setInput] = useState('');\n const [selectedProduct, setSelectedProduct] = useState<ChatSource | null>(null);\n const bottomRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages, loading, selectedProduct]);\n\n useEffect(() => {\n const h = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };\n document.addEventListener('keydown', h);\n return () => document.removeEventListener('keydown', h);\n }, []);\n\n const handleSourceClick = (src: ChatSource) => {\n setSelectedProduct(src);\n onSelectSource?.(src);\n const q = `Tell me more about the ${src.name}${src.price ? ` (${src.currency ?? defaultCurrency} ${src.price})` : ''} — what are its key specs, who is it best for, and is it worth buying?`;\n send(q);\n };\n\n const handleSend = async (text?: string) => {\n const q = (text ?? input).trim();\n if (!q || loading) return;\n setSelectedProduct(null);\n setInput('');\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto';\n }\n await send(q);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSend(); }\n };\n\n const handleInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setInput(e.target.value);\n const t = e.target;\n t.style.height = 'auto';\n t.style.height = `${Math.min(t.scrollHeight, 140)}px`;\n };\n\n const blurVal = typeof backdropBlur === 'number' ? `${backdropBlur}px` : (backdropBlur ?? '20px');\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <div\n className={`hsk-cb-overlay ${classNames.overlay || ''}`}\n onClick={onClose}\n style={{\n backdropFilter: `blur(${blurVal})`,\n WebkitBackdropFilter: `blur(${blurVal})`,\n ...(backdropColor ? { background: backdropColor } : {}),\n ...customStyles,\n }}\n >\n <div className={`hsk-cb-panel ${classNames.panel || ''}`} onClick={e => e.stopPropagation()}>\n\n {/* Top bar */}\n <div className=\"hsk-cb-topbar\">\n <div className=\"hsk-cb-topbar-left\">\n <span className=\"hsk-cb-topbar-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </span>\n <div>\n <div className=\"hsk-cb-topbar-title\">{title}</div>\n <div className=\"hsk-cb-topbar-sub\">Powered by Huskel AI · searches the whole catalogue</div>\n </div>\n </div>\n <div className=\"hsk-cb-topbar-actions\">\n {messages.length > 0 && (\n <button className=\"hsk-cb-topbar-btn\" onClick={reset}>Clear chat</button>\n )}\n <button className=\"hsk-cb-close\" onClick={onClose} aria-label=\"Close\">\n <CloseIcon />\n </button>\n </div>\n </div>\n\n {/* Messages */}\n <div className=\"hsk-cb-msgs\">\n {messages.length === 0 ? (\n <div className=\"hsk-cb-empty\">\n <div className=\"hsk-cb-empty-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </div>\n <div className=\"hsk-cb-empty-title\">What can I help you find?</div>\n <div className=\"hsk-cb-empty-sub\">\n Ask about products, budgets, gift ideas, specs — I'll search the entire catalogue for you.\n </div>\n <div className=\"hsk-cb-chips\">\n {chips.map(chip => (\n <button\n key={chip}\n className=\"hsk-cb-chip\"\n onClick={() => handleSend(chip)}\n >\n {chip}\n </button>\n ))}\n </div>\n </div>\n ) : (\n messages.map((msg: ChatMessage, idx: number) => {\n const isLast = idx === messages.length - 1;\n const isUser = msg.role === 'user';\n return (\n <div key={idx} className=\"hsk-cb-msg-group\">\n {isUser ? (\n <div className=\"hsk-cb-user-msg\">\n <div className=\"hsk-cb-user-bubble\">{msg.content}</div>\n </div>\n ) : (\n <div className=\"hsk-cb-ai-msg\">\n <div className=\"hsk-cb-ai-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </div>\n <div className=\"hsk-cb-ai-body\">\n <div className=\"hsk-cb-ai-text\">{renderMarkdown(msg.content)}</div>\n\n {/* Sources as horizontal carousel — only after latest assistant reply */}\n {isLast && sources.length > 0 && (\n <SourcesCarousel\n sources={sources}\n defaultCurrency={defaultCurrency}\n onSelectSource={handleSourceClick}\n />\n )}\n </div>\n </div>\n )}\n </div>\n );\n })\n )}\n\n {/* Selected product pinned card — shows while LLM fetches details */}\n {selectedProduct && loading && (\n <div\n className=\"hsk-cb-selected-product\"\n onClick={() => selectedProduct.url && window.open(selectedProduct.url, '_blank')}\n >\n {selectedProduct.image && (\n <img className=\"hsk-cb-selected-img\" src={selectedProduct.image} alt={selectedProduct.name} />\n )}\n <div className=\"hsk-cb-selected-info\">\n <div className=\"hsk-cb-selected-name\">{selectedProduct.name}</div>\n {selectedProduct.price && (\n <div className=\"hsk-cb-selected-price\">\n {selectedProduct.currency ?? defaultCurrency} {parseFloat((selectedProduct.price ?? '').replace(/[^0-9.]/g, '') || '0').toLocaleString()}\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Typing dots */}\n {loading && (\n <div className=\"hsk-cb-typing-row\">\n <div className=\"hsk-cb-ai-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </div>\n <div className=\"hsk-cb-typing\">\n <div className=\"hsk-cb-dot\" />\n <div className=\"hsk-cb-dot\" />\n <div className=\"hsk-cb-dot\" />\n </div>\n </div>\n )}\n\n {error && <div className=\"hsk-cb-error\">{error}</div>}\n <div ref={bottomRef} style={{ height: 1 }} />\n </div>\n\n {/* Input */}\n <div className=\"hsk-cb-input-wrap\">\n <div className=\"hsk-cb-input-box\">\n <textarea\n ref={textareaRef}\n className={`hsk-cb-textarea ${classNames.input || ''}`}\n value={input}\n onChange={handleInput}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n rows={1}\n disabled={loading}\n autoFocus\n />\n <button\n className={`hsk-cb-send ${classNames.sendButton || ''}`}\n onClick={() => handleSend()}\n disabled={!input.trim() || loading}\n aria-label=\"Send message\"\n >\n <ArrowUpIcon />\n </button>\n </div>\n <div className=\"hsk-cb-hint\">Huskel AI · searches the whole catalogue in real time</div>\n </div>\n\n </div>\n </div>\n );\n}\n\nexport function AIChatButton({\n label,\n title,\n placeholder,\n backdropColor,\n backdropBlur,\n className,\n onSelectSource,\n defaultCurrency,\n chips,\n theme,\n classNames = {},\n}: AIChatButtonProps) {\n const [open, setOpen] = useState(false);\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => { setMounted(true); }, []);\n\n const customStyles = {\n ...(theme?.primaryColor && { '--hsk-primary': theme.primaryColor }),\n ...(theme?.backgroundColor && { '--hsk-bg': theme.backgroundColor }),\n ...(theme?.textColor && { '--hsk-text': theme.textColor }),\n ...(theme?.fontFamily && { '--hsk-font': theme.fontFamily }),\n } as React.CSSProperties;\n\n return (\n <>\n <button\n className={`hsk-cb-btn ${classNames.button || ''} ${className || ''}`}\n onClick={() => setOpen(true)}\n style={customStyles}\n aria-label=\"Open AI chat\"\n >\n <span className=\"hsk-cb-btn-icon\" style={{ display: 'flex', alignItems: 'center' }}>\n <SparkleIcon />\n </span>\n {label !== undefined ? label : null}\n </button>\n {open && mounted && createPortal(\n <ChatModal\n title={title}\n placeholder={placeholder}\n backdropColor={backdropColor}\n backdropBlur={backdropBlur}\n onClose={() => setOpen(false)}\n onSelectSource={onSelectSource}\n defaultCurrency={defaultCurrency}\n chips={chips}\n theme={theme}\n classNames={classNames}\n />,\n document.body\n )}\n </>\n );\n}\n"],"mappings":"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","names":["useRef","useRef","useRef","useRef","useCallback","useState","useState","useCallback","useEffect","useRef","useRef","useEffect","useState","useCallback","useRef","useState","useRef","useCallback","useState","useEffect","useRef","jsx","useState","useRef","useEffect","useState","useEffect","useRef","jsx","jsxs","useRef","useEffect","useState","useState","useRef","useEffect","Fragment","jsx","jsx","jsxs","SparkleIcon","useState","useRef","useEffect","useState","useEffect","useRef","useCallback","createPortal","Fragment","jsx","jsxs","SparkleIcon","ArrowUpIcon","CloseIcon","useRef","useState","useCallback","useEffect","_a","createPortal"]}
|