import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData, } from "@remix-run/react"; import { useEffect, useRef, useState } from "react"; import { json } from "@remix-run/node"; export const loader = async ({ request }) => { try { const { authenticate } = await import("./shopify.server"); const { session } = await authenticate.admin(request); return json({ shop: session?.shop || null }); } catch { return json({ shop: null }); } }; // ── Chat Widget ────────────────────────────────────────────────────────────── function ChatWidget({ shop }) { const [open, setOpen] = useState(false); const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const [unread, setUnread] = useState(0); const [sending, setSending] = useState(false); const msgsRef = useRef(null); const pollRef = useRef(null); const lastTsRef = useRef(""); const BASE = "https://backend.data4autos.com"; const visitorId = (() => { try { let v = localStorage.getItem("d4a_vid"); if (!v) { v = "v" + Math.random().toString(36).slice(2); localStorage.setItem("d4a_vid", v); } return v; } catch { return "anon"; } })(); const loadMessages = async (scrollToBottom = false) => { if (!shop) return; try { const r = await fetch(`${BASE}/chat/${encodeURIComponent(shop)}`); const d = await r.json(); const msgs = d.messages || []; const latest = msgs[msgs.length - 1]?.timestamp || ""; const isNew = latest && latest !== lastTsRef.current; lastTsRef.current = latest; setMessages(msgs); if (!open && isNew && msgs[msgs.length - 1]?.from === "admin") { setUnread(u => u + 1); } if (scrollToBottom || (msgsRef.current && msgsRef.current.scrollHeight - msgsRef.current.scrollTop - msgsRef.current.clientHeight < 80)) { setTimeout(() => { if (msgsRef.current) msgsRef.current.scrollTop = msgsRef.current.scrollHeight; }, 50); } } catch {} }; useEffect(() => { if (!shop) return; loadMessages(false); pollRef.current = setInterval(() => loadMessages(false), 4000); return () => clearInterval(pollRef.current); }, [shop]); useEffect(() => { if (open) { setUnread(0); loadMessages(true); } }, [open]); const sendMessage = async () => { if (!input.trim() || !shop || sending) return; const text = input.trim(); setInput(""); setSending(true); try { await fetch(`${BASE}/chat/${encodeURIComponent(shop)}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text, visitorId }), }); await loadMessages(true); } catch {} setSending(false); }; if (!shop) return null; return ( <> {/* Floating button */} {/* Chat window */} {open && (
💬
Data4Autos Support
We typically reply within a few hours
{messages.length === 0 ? (
Send us a message and we'll get back to you!
) : messages.map(m => (
{m.text}
{new Date(m.timestamp).toLocaleTimeString(undefined,{hour:"2-digit",minute:"2-digit"})}
))}