UNPKG

@jutech-devs/agent-sdk

Version:

Modern embeddable AI agent chat widget with voice support and payment integration

1,275 lines (1,262 loc) 160 kB
"use client" // src/AgentWidget.tsx import { useState as useState8, useEffect as useEffect4 } from "react"; // src/components/ChatBubble.tsx import { jsx, jsxs } from "react/jsx-runtime"; function ChatBubble({ isOpen, onClick, primaryColor = "#3b82f6", unreadCount = 0, position = "bottom-right" }) { const adjustColor = (color, percent) => { const num = parseInt(color.replace("#", ""), 16); const amt = Math.round(2.55 * percent); const R = (num >> 16) + amt; const G = (num >> 8 & 255) + amt; const B = (num & 255) + amt; return "#" + (16777216 + (R < 255 ? R < 1 ? 0 : R : 255) * 65536 + (G < 255 ? G < 1 ? 0 : G : 255) * 256 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); }; return /* @__PURE__ */ jsxs( "button", { onClick, style: { position: "fixed", bottom: position.includes("bottom") ? "20px" : "auto", top: position.includes("top") ? "20px" : "auto", right: position.includes("right") ? "20px" : "auto", left: position.includes("left") ? "20px" : "auto", width: "60px", height: "60px", borderRadius: "50%", backgroundColor: primaryColor, color: "white", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "24px", boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)", zIndex: 9999, transition: "all 0.2s ease" }, onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = adjustColor(primaryColor, -10); e.currentTarget.style.transform = "scale(1.05)"; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = primaryColor; e.currentTarget.style.transform = "scale(1)"; }, "aria-label": "Open chat", children: [ unreadCount > 0 && /* @__PURE__ */ jsx("span", { style: { position: "absolute", top: "-2px", right: "-2px", background: "linear-gradient(135deg, #ef4444, #dc2626)", color: "white", borderRadius: "50%", minWidth: "20px", height: "20px", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "11px", fontWeight: "600", padding: "0 4px", border: "2px solid white" }, children: unreadCount > 9 ? "9+" : unreadCount }), /* @__PURE__ */ jsx( "svg", { width: "24", height: "24", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx( "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" } ) } ) ] } ); } // src/components/ChatWindow.tsx import { useState as useState4, useRef as useRef2, useEffect } from "react"; // src/components/MessageList.tsx import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime"; function MessageList({ messages, primaryColor, isLoading = false, onEndConversation, onShowProducts, onShowServices, onShowBookingForm, onShowPaymentOptions, onShowInvoice, onRequestFeedback, onShowCart }) { const adjustColor = (color, percent) => { const num = parseInt(color.replace("#", ""), 16); const amt = Math.round(2.55 * percent); const R = (num >> 16) + amt; const G = (num >> 8 & 255) + amt; const B = (num & 255) + amt; return "#" + (16777216 + (R < 255 ? R < 1 ? 0 : R : 255) * 65536 + (G < 255 ? G < 1 ? 0 : G : 255) * 256 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); }; const buttonStyle = { padding: "8px 16px", backgroundColor: primaryColor, color: "white", border: "none", borderRadius: "16px", fontSize: "13px", fontWeight: "500", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: "6px", transition: "all 0.2s ease" }; const ThinkingIndicator = () => /* @__PURE__ */ jsxs2("div", { style: { marginBottom: "16px", display: "flex", gap: "8px", justifyContent: "flex-start", alignItems: "flex-end" }, children: [ /* @__PURE__ */ jsx2("div", { style: { width: "28px", height: "28px", borderRadius: "50%", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "12px", flexShrink: 0, background: `linear-gradient(135deg, ${primaryColor}, ${adjustColor(primaryColor, -10)})`, color: "white", marginBottom: "2px" }, children: /* @__PURE__ */ jsx2("svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }) }), /* @__PURE__ */ jsxs2("div", { style: { maxWidth: "85%", padding: "12px 16px", borderRadius: "16px", borderBottomLeftRadius: "4px", fontSize: "14px", lineHeight: "1.5", backgroundColor: "#f8f9fa", color: "#1f2937", boxShadow: "0 1px 2px rgba(0, 0, 0, 0.1)", display: "flex", alignItems: "center", gap: "8px" }, children: [ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "4px", alignItems: "center" }, children: [ /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out" } }), /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out", animationDelay: "0.2s" } }), /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out", animationDelay: "0.4s" } }) ] }), /* @__PURE__ */ jsx2("span", { style: { color: "#6b7280", fontSize: "13px" }, children: "AI is thinking..." }) ] }) ] }); return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [ messages.map((message) => /* @__PURE__ */ jsxs2( "div", { style: { display: "flex", justifyContent: message.role === "user" ? "flex-end" : "flex-start", marginBottom: "16px", alignItems: "flex-end", gap: "8px" }, children: [ message.role === "assistant" && /* @__PURE__ */ jsx2("div", { style: { width: "28px", height: "28px", borderRadius: "50%", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "12px", flexShrink: 0, background: `linear-gradient(135deg, ${primaryColor}, ${adjustColor(primaryColor, -10)})`, color: "white", marginBottom: "2px" }, children: /* @__PURE__ */ jsx2("svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }) }), /* @__PURE__ */ jsxs2("div", { style: { maxWidth: "85%", padding: "12px 16px", borderRadius: "16px", borderBottomLeftRadius: message.role === "assistant" ? "4px" : "16px", borderBottomRightRadius: message.role === "user" ? "4px" : "16px", fontSize: "14px", lineHeight: "1.5", wordWrap: "break-word", backgroundColor: message.role === "assistant" ? "#f8f9fa" : primaryColor, color: message.role === "assistant" ? "#1f2937" : "white", boxShadow: "0 1px 2px rgba(0, 0, 0, 0.1)", marginLeft: message.role === "user" ? "auto" : "0" }, children: [ /* @__PURE__ */ jsxs2("div", { children: [ message.content || (message.isStreaming ? /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "4px", padding: "8px 0", alignItems: "center" }, children: [ /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out" } }), /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out", animationDelay: "0.2s" } }), /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out", animationDelay: "0.4s" } }) ] }) : /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "4px", padding: "8px 0", alignItems: "center" }, children: [ /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out" } }), /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out", animationDelay: "0.2s" } }), /* @__PURE__ */ jsx2("div", { style: { width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#6b7280", animation: "typing 1.4s infinite ease-in-out", animationDelay: "0.4s" } }) ] })), message.role === "assistant" && message.metadata && /* @__PURE__ */ jsxs2("div", { style: { marginTop: "12px", display: "flex", flexWrap: "wrap", gap: "8px" }, children: [ message.metadata.showProducts && onShowProducts && /* @__PURE__ */ jsx2("button", { onClick: onShowProducts, style: buttonStyle, children: "\u{1F6CD}\uFE0F View Products" }), message.metadata.showServices && onShowServices && /* @__PURE__ */ jsx2("button", { onClick: onShowServices, style: buttonStyle, children: "\u{1F6CE}\uFE0F View Services" }), message.metadata.showBookingForm && onShowBookingForm && /* @__PURE__ */ jsx2("button", { onClick: onShowBookingForm, style: buttonStyle, children: "\u{1F4C5} Book Now" }), message.metadata.showPaymentOptions && onShowPaymentOptions && /* @__PURE__ */ jsx2("button", { onClick: onShowPaymentOptions, style: buttonStyle, children: "\u{1F4B3} Payment Options" }), message.metadata.showInvoice && onShowInvoice && /* @__PURE__ */ jsx2("button", { onClick: onShowInvoice, style: buttonStyle, children: "\u{1F9FE} View Invoice" }), message.metadata.requestFeedback && onRequestFeedback && /* @__PURE__ */ jsx2("button", { onClick: onRequestFeedback, style: buttonStyle, children: "\u2B50 Rate Experience" }), message.metadata.showCart && onShowCart && /* @__PURE__ */ jsx2("button", { onClick: onShowCart, style: buttonStyle, children: "\u{1F6D2} View Cart" }), message.metadata.showEndButton && onEndConversation && /* @__PURE__ */ jsx2("button", { onClick: onEndConversation, style: buttonStyle, children: "\u2705 End Conversation" }) ] }) ] }), message.timestamp && /* @__PURE__ */ jsx2("div", { style: { fontSize: "10px", color: message.role === "assistant" ? "#9ca3af" : "rgba(255,255,255,0.7)", marginTop: "6px", textAlign: message.role === "user" ? "right" : "left" }, children: new Date(message.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) }) ] }), message.role === "user" && /* @__PURE__ */ jsx2("div", { style: { width: "28px", height: "28px", borderRadius: "50%", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "12px", flexShrink: 0, background: "linear-gradient(135deg, #6b7280, #4b5563)", color: "white", marginBottom: "2px" }, children: /* @__PURE__ */ jsx2("svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }) }) ] }, message.id )), isLoading && !messages.some((msg) => msg.isStreaming) && /* @__PURE__ */ jsx2(ThinkingIndicator, {}) ] }); } // src/hooks/useVoice.ts import { useState, useCallback, useRef } from "react"; function useVoice({ onTranscript, enabled = true }) { const [isListening, setIsListening] = useState(false); const [isSupported, setIsSupported] = useState(() => { if (typeof window !== "undefined") { const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; return !!SpeechRecognition && enabled; } return false; }); const recognitionRef = useRef(null); const createRecognition = useCallback(() => { if (typeof window === "undefined") return null; const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (!SpeechRecognition) return null; const recognition = new SpeechRecognition(); recognition.continuous = false; recognition.interimResults = false; recognition.lang = "en-US"; recognition.maxAlternatives = 1; recognition.onstart = () => { console.log("Speech recognition started"); setIsListening(true); }; recognition.onresult = (event) => { console.log("Speech recognition result:", event); console.log("Results length:", event.results.length); for (let i = 0; i < event.results.length; i++) { const result = event.results[i]; console.log(`Result ${i}:`, result); console.log(`Result ${i} transcript:`, result[0]?.transcript); if (result[0]?.transcript) { const transcript = result[0].transcript.trim(); console.log("Final transcript:", transcript); onTranscript(transcript); setIsListening(false); return; } } }; recognition.onend = () => { console.log("Speech recognition ended"); setIsListening(false); }; recognition.onerror = (event) => { console.error("Speech recognition error:", event.error); setIsListening(false); }; return recognition; }, [onTranscript]); const startListening = useCallback(() => { console.log("Starting voice recognition..."); if (recognitionRef.current) { recognitionRef.current.abort(); } const recognition = createRecognition(); if (!recognition) { console.error("Speech recognition not supported"); return; } recognitionRef.current = recognition; try { recognition.start(); } catch (error) { console.error("Failed to start recognition:", error); setIsListening(false); } }, [createRecognition]); const stopListening = useCallback(() => { console.log("Stopping voice recognition..."); if (recognitionRef.current) { recognitionRef.current.stop(); recognitionRef.current = null; } setIsListening(false); }, []); const speak = useCallback((text) => { if (typeof window !== "undefined" && window.speechSynthesis && enabled) { window.speechSynthesis.cancel(); const utterance = new SpeechSynthesisUtterance(text); utterance.rate = 0.9; utterance.pitch = 1; utterance.volume = 0.8; window.speechSynthesis.speak(utterance); } }, [enabled]); return { isListening, isSupported, startListening, stopListening, speak }; } // src/components/MessageInput.tsx import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime"; function MessageInput({ value, onChange, onSend, isLoading, placeholder, primaryColor, voiceEnabled = false }) { const { isListening, isSupported, startListening, stopListening } = useVoice({ onTranscript: (text) => { console.log("MessageInput received transcript:", text); onChange(text); console.log("MessageInput onChange called with:", text); }, enabled: voiceEnabled }); const handleKeyPress = (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); onSend(); } }; const handleVoiceToggle = () => { console.log("Voice toggle clicked, isListening:", isListening); if (isListening) { console.log("Stopping voice recognition"); stopListening(); } else { console.log("Starting voice recognition"); startListening(); } }; const adjustColor = (color, percent) => { const num = parseInt(color.replace("#", ""), 16); const amt = Math.round(2.55 * percent); const R = (num >> 16) + amt; const G = (num >> 8 & 255) + amt; const B = (num & 255) + amt; return "#" + (16777216 + (R < 255 ? R < 1 ? 0 : R : 255) * 65536 + (G < 255 ? G < 1 ? 0 : G : 255) * 256 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); }; return /* @__PURE__ */ jsx3("div", { style: { padding: "16px", borderTop: "1px solid #e5e7eb", backgroundColor: "white" }, children: /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [ /* @__PURE__ */ jsx3( "textarea", { value, onChange: (e) => onChange(e.target.value), onKeyPress: handleKeyPress, placeholder, disabled: isLoading, rows: 1, style: { flex: 1, border: "1px solid #e5e7eb", borderRadius: "20px", padding: "12px 16px", fontSize: "14px", outline: "none", resize: "none", overflow: "hidden", minHeight: "44px", maxHeight: "120px", backgroundColor: "white", color: "#1f2937", fontFamily: "inherit" }, onFocus: (e) => { e.target.style.borderColor = primaryColor; e.target.style.boxShadow = `0 0 0 3px ${primaryColor}20`; }, onBlur: (e) => { e.target.style.borderColor = "#e5e7eb"; e.target.style.boxShadow = "none"; }, onInput: (e) => { const target = e.target; target.style.height = "auto"; target.style.height = Math.min(target.scrollHeight, 120) + "px"; } } ), voiceEnabled && !value.trim() ? /* @__PURE__ */ jsx3( "button", { onClick: handleVoiceToggle, disabled: !isSupported, style: { background: isListening ? `linear-gradient(135deg, #ef4444, #dc2626)` : `linear-gradient(135deg, ${primaryColor}, ${adjustColor(primaryColor, -10)})`, color: "white", border: "none", borderRadius: "50%", width: "44px", height: "44px", display: "flex", alignItems: "center", justifyContent: "center", cursor: !isSupported ? "not-allowed" : "pointer", opacity: !isSupported ? 0.5 : 1, transition: "all 0.2s ease", animation: isListening ? "pulse 1.5s infinite" : "none" }, onMouseEnter: (e) => { if (isSupported) { e.currentTarget.style.transform = "scale(1.05)"; } }, onMouseLeave: (e) => { e.currentTarget.style.transform = "scale(1)"; }, "aria-label": isListening ? "Stop recording" : "Start voice recording", children: /* @__PURE__ */ jsx3("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) }) } ) : /* @__PURE__ */ jsx3( "button", { onClick: onSend, disabled: !value.trim() || isLoading, style: { background: `linear-gradient(135deg, ${primaryColor}, ${adjustColor(primaryColor, -10)})`, color: "white", border: "none", borderRadius: "50%", width: "44px", height: "44px", display: "flex", alignItems: "center", justifyContent: "center", cursor: !value.trim() || isLoading ? "not-allowed" : "pointer", opacity: !value.trim() || isLoading ? 0.5 : 1, transition: "all 0.2s ease" }, onMouseEnter: (e) => { if (!(!value.trim() || isLoading)) { e.currentTarget.style.transform = "scale(1.05)"; } }, onMouseLeave: (e) => { e.currentTarget.style.transform = "scale(1)"; }, "aria-label": "Send message", children: isLoading ? /* @__PURE__ */ jsx3("div", { style: { width: "20px", height: "20px", border: "2px solid transparent", borderTop: "2px solid currentColor", borderRadius: "50%", animation: "spin 1s linear infinite" } }) : /* @__PURE__ */ jsx3("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M12 19l9 2-9-18-9 18 9-2zm0 0v-8" }) }) } ) ] }) }); } // src/components/ProductCard.tsx import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime"; function ProductCard({ product, onBuyNow, primaryColor }) { return /* @__PURE__ */ jsxs4( "div", { style: { border: "1px solid #e5e7eb", borderRadius: "8px", padding: "16px", margin: "8px 0", backgroundColor: "#ffffff" }, children: [ (product.imageUrl || product.images?.[0]) && /* @__PURE__ */ jsx4( "img", { src: product.imageUrl || product.images[0], alt: product.name, style: { width: "100%", height: "120px", objectFit: "cover", borderRadius: "6px", marginBottom: "12px" } } ), /* @__PURE__ */ jsx4( "h3", { style: { fontSize: "16px", fontWeight: "600", margin: "0 0 8px 0", color: "#1f2937" }, children: product.name } ), /* @__PURE__ */ jsx4( "p", { style: { fontSize: "14px", color: "#6b7280", margin: "0 0 12px 0", lineHeight: "1.4" }, children: product.description } ), /* @__PURE__ */ jsxs4( "div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [ /* @__PURE__ */ jsxs4( "span", { style: { fontSize: "18px", fontWeight: "700", color: primaryColor }, children: [ product.currency, " ", product.price ] } ), /* @__PURE__ */ jsx4( "button", { onClick: () => onBuyNow(product), style: { backgroundColor: primaryColor, color: "white", border: "none", borderRadius: "6px", padding: "8px 16px", fontSize: "14px", fontWeight: "500", cursor: "pointer" }, children: "Buy Now" } ) ] } ) ] } ); } // src/components/OrdersView.tsx import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime"; function OrdersView({ orders, onClose, onPayOrder }) { const formatDate = (dateString) => { return new Date(dateString).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }); }; const getStatusColor = (status) => { switch (status) { case "completed": return "#10b981"; case "processing": return "#3b82f6"; case "shipped": return "#8b5cf6"; case "delivered": return "#059669"; case "pending": return "#f59e0b"; case "failed": return "#ef4444"; case "cancelled": return "#6b7280"; default: return "#6b7280"; } }; return /* @__PURE__ */ jsxs5("div", { style: { padding: "20px" }, children: [ /* @__PURE__ */ jsxs5("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }, children: [ /* @__PURE__ */ jsx5("h3", { style: { fontSize: "18px", fontWeight: "600", margin: 0, color: "#1f2937" }, children: "My Orders" }), /* @__PURE__ */ jsx5( "button", { onClick: onClose, style: { background: "none", border: "none", fontSize: "24px", cursor: "pointer", color: "#6b7280", padding: "4px" }, children: "\xD7" } ) ] }), orders.length === 0 ? /* @__PURE__ */ jsx5("div", { style: { textAlign: "center", padding: "40px 20px", color: "#6b7280" }, children: /* @__PURE__ */ jsx5("p", { children: "No orders found" }) }) : /* @__PURE__ */ jsx5("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: orders.map((order) => /* @__PURE__ */ jsx5( "div", { style: { border: "1px solid #e5e7eb", borderRadius: "8px", padding: "16px", backgroundColor: "#ffffff" }, children: /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "12px" }, children: [ order.productId && order.productId.imageUrl && /* @__PURE__ */ jsx5( "img", { src: order.productId.imageUrl, alt: order.productId.name, style: { width: "60px", height: "60px", objectFit: "cover", borderRadius: "6px" } } ), /* @__PURE__ */ jsxs5("div", { style: { flex: 1 }, children: [ /* @__PURE__ */ jsx5("h4", { style: { fontSize: "16px", fontWeight: "600", margin: "0 0 4px 0", color: "#1f2937" }, children: order.productId ? order.productId.name : order.itemName || "Service Order" }), /* @__PURE__ */ jsx5("p", { style: { fontSize: "14px", color: "#6b7280", margin: "0 0 8px 0" }, children: order.productId ? order.productId.description : "Service booking order" }), /* @__PURE__ */ jsxs5("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [ /* @__PURE__ */ jsxs5("span", { style: { fontSize: "16px", fontWeight: "600", color: "#1f2937" }, children: [ order.currency, " ", order.amount ] }), /* @__PURE__ */ jsx5("span", { style: { fontSize: "12px", padding: "4px 8px", borderRadius: "12px", backgroundColor: `${getStatusColor(order.status)}20`, color: getStatusColor(order.status), fontWeight: "500", textTransform: "capitalize" }, children: order.status }) ] }), /* @__PURE__ */ jsx5("p", { style: { fontSize: "12px", color: "#9ca3af", margin: "8px 0 0 0" }, children: formatDate(order.createdAt) }), order.trackingNumber && /* @__PURE__ */ jsxs5("p", { style: { fontSize: "12px", color: "#3b82f6", margin: "4px 0 0 0", fontWeight: "500" }, children: [ "Tracking: ", order.trackingNumber ] }), order.deliveryAddress && /* @__PURE__ */ jsxs5("p", { style: { fontSize: "12px", color: "#6b7280", margin: "4px 0 0 0" }, children: [ order.deliveryAddress.street, ", ", order.deliveryAddress.city, ", ", order.deliveryAddress.state, " ", order.deliveryAddress.zipCode ] }), order.status === "pending" && onPayOrder && /* @__PURE__ */ jsx5( "button", { onClick: () => onPayOrder(order), style: { marginTop: "8px", padding: "6px 12px", backgroundColor: "#3b82f6", color: "white", border: "none", borderRadius: "4px", fontSize: "12px", fontWeight: "500", cursor: "pointer" }, children: "Pay Now" } ) ] }) ] }) }, order._id )) }) ] }); } // src/components/ServiceCard.tsx import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime"; function ServiceCard({ service, onBook }) { return /* @__PURE__ */ jsxs6( "div", { style: { border: "1px solid #e5e7eb", borderRadius: "8px", padding: "16px", backgroundColor: "white", boxShadow: "0 1px 3px rgba(0, 0, 0, 0.1)" }, children: [ service.imageUrl && /* @__PURE__ */ jsx6( "img", { src: service.imageUrl, alt: service.name, style: { width: "100%", height: "120px", objectFit: "cover", borderRadius: "6px", marginBottom: "12px" } } ), /* @__PURE__ */ jsx6("h4", { style: { fontSize: "16px", fontWeight: "600", margin: "0 0 8px 0" }, children: service.name }), /* @__PURE__ */ jsx6("p", { style: { fontSize: "14px", color: "#6b7280", margin: "0 0 12px 0", lineHeight: "1.4" }, children: service.description }), /* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [ /* @__PURE__ */ jsxs6("div", { children: [ /* @__PURE__ */ jsxs6("span", { style: { fontSize: "18px", fontWeight: "700", color: "#1f2937" }, children: [ service.currency, " ", service.price ] }), service.duration && /* @__PURE__ */ jsxs6("div", { style: { fontSize: "12px", color: "#6b7280" }, children: [ service.duration, " minutes" ] }) ] }), /* @__PURE__ */ jsx6( "button", { onClick: () => onBook(service), style: { padding: "8px 16px", backgroundColor: "#3b82f6", color: "white", border: "none", borderRadius: "6px", fontSize: "14px", fontWeight: "500", cursor: "pointer" }, children: "Book Now" } ) ] }) ] } ); } // src/components/BookingsView.tsx import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime"; function BookingsView({ bookings, onClose }) { return /* @__PURE__ */ jsxs7("div", { style: { padding: "16px" }, children: [ /* @__PURE__ */ jsxs7("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "16px" }, children: [ /* @__PURE__ */ jsx7("h3", { style: { fontSize: "18px", fontWeight: "600", margin: 0 }, children: "My Bookings" }), /* @__PURE__ */ jsx7( "button", { onClick: onClose, style: { background: "none", border: "none", fontSize: "20px", cursor: "pointer", color: "#6b7280" }, children: "\xD7" } ) ] }), bookings.length === 0 ? /* @__PURE__ */ jsx7("div", { style: { textAlign: "center", padding: "32px", color: "#6b7280" }, children: /* @__PURE__ */ jsx7("p", { children: "No bookings found" }) }) : /* @__PURE__ */ jsx7("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: bookings.map((booking) => /* @__PURE__ */ jsxs7( "div", { style: { border: "1px solid #e5e7eb", borderRadius: "8px", padding: "12px", backgroundColor: "#f9fafb" }, children: [ /* @__PURE__ */ jsxs7("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: "8px" }, children: [ /* @__PURE__ */ jsx7("h4", { style: { fontSize: "16px", fontWeight: "600", margin: 0 }, children: booking.serviceName }), /* @__PURE__ */ jsx7( "span", { style: { padding: "2px 8px", borderRadius: "12px", fontSize: "12px", backgroundColor: booking.status === "confirmed" ? "#dcfce7" : "#fef3c7", color: booking.status === "confirmed" ? "#166534" : "#92400e" }, children: booking.status } ) ] }), /* @__PURE__ */ jsxs7("div", { style: { fontSize: "14px", color: "#6b7280", marginBottom: "4px" }, children: [ "\u{1F4C5} ", new Date(booking.date).toLocaleDateString(), " at ", booking.time ] }), booking.notes && /* @__PURE__ */ jsxs7("div", { style: { fontSize: "14px", color: "#6b7280" }, children: [ "\u{1F4DD} ", booking.notes ] }) ] }, booking._id )) }) ] }); } // src/components/PaymentOptionsView.tsx import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime"; function PaymentOptionsView({ onClose, primaryColor = "#3b82f6" }) { const paymentMethods = [ { id: "card", name: "Credit/Debit Card", icon: "\u{1F4B3}", description: "Visa, Mastercard, Verve" }, { id: "mobile", name: "Mobile Money", icon: "\u{1F4F1}", description: "MTN, Vodafone, AirtelTigo" }, { id: "bank", name: "Bank Transfer", icon: "\u{1F3E6}", description: "Direct bank transfer" }, { id: "paystack", name: "Paystack", icon: "\u{1F4B0}", description: "Secure online payment" } ]; return /* @__PURE__ */ jsxs8("div", { children: [ /* @__PURE__ */ jsxs8("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "16px" }, children: [ /* @__PURE__ */ jsx8("h4", { style: { fontSize: "18px", fontWeight: "600", margin: 0 }, children: "Payment Methods" }), /* @__PURE__ */ jsx8( "button", { onClick: onClose, style: { background: "none", border: "none", cursor: "pointer", padding: "4px", borderRadius: "4px" }, children: /* @__PURE__ */ jsx8("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx8("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) } ) ] }), /* @__PURE__ */ jsx8("div", { style: { display: "grid", gap: "12px" }, children: paymentMethods.map((method) => /* @__PURE__ */ jsxs8( "div", { style: { padding: "16px", border: "1px solid #e5e7eb", borderRadius: "8px", display: "flex", alignItems: "center", gap: "12px", cursor: "pointer", transition: "all 0.2s" }, onMouseEnter: (e) => { e.currentTarget.style.borderColor = primaryColor; e.currentTarget.style.backgroundColor = `${primaryColor}10`; }, onMouseLeave: (e) => { e.currentTarget.style.borderColor = "#e5e7eb"; e.currentTarget.style.backgroundColor = "transparent"; }, children: [ /* @__PURE__ */ jsx8("div", { style: { fontSize: "24px" }, children: method.icon }), /* @__PURE__ */ jsxs8("div", { style: { flex: 1 }, children: [ /* @__PURE__ */ jsx8("div", { style: { fontWeight: "600", marginBottom: "4px" }, children: method.name }), /* @__PURE__ */ jsx8("div", { style: { fontSize: "14px", color: "#6b7280" }, children: method.description }) ] }), /* @__PURE__ */ jsx8("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx8("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) }) ] }, method.id )) }), /* @__PURE__ */ jsx8("div", { style: { marginTop: "16px", padding: "12px", backgroundColor: "#f3f4f6", borderRadius: "8px", fontSize: "14px", color: "#6b7280" }, children: "\u{1F4A1} All payments are secured with 256-bit SSL encryption" }) ] }); } // src/components/InvoiceView.tsx import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime"; function InvoiceView({ onClose, primaryColor = "#3b82f6", invoice }) { const mockInvoice = invoice || { id: "INV-2024-001", date: (/* @__PURE__ */ new Date()).toLocaleDateString(), amount: 150, currency: "GHS", items: [ { name: "Product/Service", quantity: 1, price: 150 } ], customerName: "Customer", customerEmail: "customer@example.com" }; const handleDownload = () => { alert("Invoice download started..."); }; const handlePrint = () => { window.print(); }; return /* @__PURE__ */ jsxs9("div", { children: [ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }, children: [ /* @__PURE__ */ jsx9("h4", { style: { fontSize: "18px", fontWeight: "600", margin: 0 }, children: "Invoice" }), /* @__PURE__ */ jsx9( "button", { onClick: onClose, style: { background: "none", border: "none", cursor: "pointer", padding: "4px", borderRadius: "4px" }, children: /* @__PURE__ */ jsx9("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) } ) ] }), /* @__PURE__ */ jsxs9("div", { style: { border: "1px solid #e5e7eb", borderRadius: "8px", padding: "20px", backgroundColor: "white" }, children: [ /* @__PURE__ */ jsxs9("div", { style: { marginBottom: "24px", textAlign: "center" }, children: [ /* @__PURE__ */ jsx9("h3", { style: { fontSize: "24px", fontWeight: "bold", color: primaryColor, margin: "0 0 8px 0" }, children: "INVOICE" }), /* @__PURE__ */ jsxs9("p", { style: { margin: 0, color: "#6b7280" }, children: [ "#", mockInvoice.id ] }) ] }), /* @__PURE__ */ jsxs9("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "20px", marginBottom: "24px" }, children: [ /* @__PURE__ */ jsxs9("div", { children: [ /* @__PURE__ */ jsx9("h4", { style: { fontSize: "14px", fontWeight: "600", marginBottom: "8px", color: "#374151" }, children: "Bill To:" }), /* @__PURE__ */ jsx9("p", { style: { margin: "0 0 4px 0", fontWeight: "600" }, children: mockInvoice.customerName }), /* @__PURE__ */ jsx9("p", { style: { margin: 0, color: "#6b7280", fontSize: "14px" }, children: mockInvoice.customerEmail }) ] }), /* @__PURE__ */ jsxs9("div", { style: { textAlign: "right" }, children: [ /* @__PURE__ */ jsx9("h4", { style: { fontSize: "14px", fontWeight: "600", marginBottom: "8px", color: "#374151" }, children: "Invoice Date:" }), /* @__PURE__ */ jsx9("p", { style: { margin: 0, fontSize: "14px" }, children: mockInvoice.date }) ] }) ] }), /* @__PURE__ */ jsx9("div", { style: { marginBottom: "24px" }, children: /* @__PURE__ */ jsxs9("table", { style: { width: "100%", borderCollapse: "collapse" }, children: [ /* @__PURE__ */ jsx9("thead", { children: /* @__PURE__ */ jsxs9("tr", { style: { borderBottom: "2px solid #e5e7eb" }, children: [ /* @__PURE__ */ jsx9("th", { style: { textAlign: "left", padding: "12px 0", fontSize: "14px", fontWeight: "600" }, children: "Item" }), /* @__PURE__ */ jsx9("th", { style: { textAlign: "center", padding: "12px 0", fontSize: "14px", fontWeight: "600" }, children: "Qty" }), /* @__PURE__ */ jsx9("th", { style: { textAlign: "right", padding: "12px 0", fontSize: "14px", fontWeight: "600" }, children: "Price" }) ] }) }), /* @__PURE__ */ jsx9("tbody", { children: mockInvoice.items.map((item, index) => /* @__PURE__ */ jsxs9("tr", { style: { borderBottom: "1px solid #f3f4f6" }, children: [ /* @__PURE__ */ jsx9("td", { style: { padding: "12px 0", fontSize: "14px" }, children: item.name }), /* @__PURE__ */ jsx9("td", { style: { textAlign: "center", padding: "12px 0", fontSize: "14px" }, children: item.quantity }), /* @__PURE__ */ jsxs9("td", { style: { textAlign: "right", padding: "12px 0", fontSize: "14px" }, children: [ mockInvoice.currency, " ", item.price.toFixed(2) ] }) ] }, index)) }) ] }) }), /* @__PURE__ */ jsx9("div", { style: { textAlign: "right", marginBottom: "24px" }, children: /* @__PURE__ */ jsx9("div", { style: { display: "inline-block", padding: "16px", backgroundColor: `${primaryColor}10`, borderRadius: "8px", border: `1px solid ${primaryColor}30` }, children: /* @__PURE__ */ jsxs9("div", { style: { fontSize: "18px", fontWeight: "bold", color: primaryColor }, children: [ "Total: ", mockInvoice.currency, " ", mockInvoice.amount.toFixed(2) ] }) }) }), /* @__PURE__ */ jsxs9("div", { style: { display: "flex", gap: "12px", justifyContent: "center" }, children: [ /* @__PURE__ */ jsxs9( "button", { onClick: handleDownload, style: { padding: "10px 20px", backgroundColor: primaryColor, color: "white", border: "none", borderRadius: "6px", cursor: "pointer", fontSize: "14px", fontWeight: "600", display: "flex", alignItems: "center", gap: "8px" }, children: [ /* @__PURE__ */ jsx9("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }), "Download PDF" ] } ), /* @__PURE__ */ jsxs9( "button", { onClick: handlePrint, style: { padding: "10px 20px", backgroundColor: "white", color: primaryColor, border: `1px solid ${primaryColor}`, borderRadius: "6px", cursor: "pointer", fontSize: "14px", fontWeight: "600", display: "flex", alignItems: "center", gap: "8px" }, children: [ /* @__PURE__ */ jsx9("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z" }) }), "Print" ] } ) ] }) ] }) ] }); } // src/components/FeedbackView.tsx import { useState as useState2 } from "react"; import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime"; function FeedbackView({ onClose, onSubmit, primaryColor = "#3b82f6" }) { const [rating, setRating] = useState2(0); const [hoveredRating, setHoveredRating] = useState2(0); const [comment, setComment] = useState2(""); const [isSubmitting, setIsSubmitting] = useState2(false); const handleSubmit = async () => { if (rating === 0) { alert("Please select a rating"); return; } setIsSubmitting(true); try { await onSubmit({ rating, comment }); alert("Thank you for your feedback!"); onClose(); } catch (error) { alert("Failed to submit feedback. Please try again."); } finally { setIsSubmitting(false); } }; const StarIcon = ({ filled, onHover, onClick }) => /* @__PURE__ */ jsx10( "svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: filled ? primaryColor : "none", stroke: filled ? primaryColor : "#d1d5db", strokeWidth: "2", style: { cursor: "pointer" }, onMouseEnter: onHover, onClick, children: /* @__PURE__ */ jsx10("polygon", { points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26" }) } ); return /* @__PURE__ */ jsxs10("div", { children: [ /* @__PURE__ */ jsxs10("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }, children: [ /* @__PURE__ */ jsx10("h4", { style: { fontSize: "18px", fontWeight: "600", margin: 0 }, children: "Rate Your Experience" }), /* @__PURE__ */ jsx10( "button", { onClick: onClose, style: { background: "none", border: "none", cursor: "pointer", padding: "4px", borderRadius: "4px" }, children: /* @__PURE__ */ jsx10("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) } ) ] }), /* @__PURE__ */ jsxs10("div", { style: { padding: "24px", border: "1px solid #e5e7eb", borderRadius: "12px", backgroundColor: "white", textAlign: "center" }, children: [ /* @__PURE__ */ jsxs10("div", { style: { marginBottom: "24px" }, children: [ /* @__PURE__