"use client"; import { useState, useEffect, useRef, useCallback } from "react"; import Link from "next/link"; import { useAccount } from "@/contexts/AccountContext"; type Msg = { id: string; sender: string; text: string; time: string; mine: boolean; }; const SEED_MSGS: Omit[] = [ { id: "s1", sender: "void_cartographer", text: "Anyone else notice the latency on the east relay dropped by 40ms this cycle?", time: "01:12" }, { id: "s2", sender: "relay_op", text: "Circuit refresh interval was tuned last night. Should hold for 72h.", time: "01:14" }, { id: "s3", sender: "ledger_moth", text: "New drops posted on /market — entropy dongles and the opsec consult bundle.", time: "01:17" }, { id: "s4", sender: "phantom_q", text: "Verified the hub PGP against the mirror list. All checksums matched.", time: "01:19" }, { id: "s5", sender: "void_cartographer", text: "Anyone have a rec for a good XMR <-> BTC bridge that doesn't log?", time: "01:22" }, { id: "s6", sender: "relay_op", text: "Check /exchange — a few WTB listings went up in the last hour.", time: "01:24" }, ]; const AUTO_REPLIES = [ "Received. Check your vault for any pending receipts.", "Noted. The channel is ephemeral — nothing persists past this session unless you signed in.", "Copy that. See /forum for threaded discussion on that topic.", "Market is up. Check /drops for the latest scheduled releases.", "Circuit healthy. Reply latency nominal.", "Acknowledged. Keep OPSEC tight and verify mirrors before each session.", ]; const CHAT_KEY = "cyberlux-chat-v1"; function now() { return new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); } function uid() { return Math.random().toString(36).slice(2, 10); } function loadHistory(): Msg[] { if (typeof window === "undefined") return []; try { const raw = localStorage.getItem(CHAT_KEY); if (!raw) return []; return JSON.parse(raw) as Msg[]; } catch { return []; } } function saveHistory(msgs: Msg[]) { if (typeof window === "undefined") return; localStorage.setItem(CHAT_KEY, JSON.stringify(msgs.slice(-80))); } export default function ChatWidget() { const { user } = useAccount(); const handle = user?.displayName ?? user?.username ?? "anon"; const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const [hydrated, setHydrated] = useState(false); const endRef = useRef(null); useEffect(() => { const stored = loadHistory(); if (stored.length > 0) { setMessages(stored); } else { const seeded = SEED_MSGS.map((m) => ({ ...m, mine: false })); setMessages(seeded); saveHistory(seeded); } setHydrated(true); }, []); useEffect(() => { if (hydrated && messages.length > 0) { saveHistory(messages); endRef.current?.scrollIntoView({ behavior: "smooth" }); } }, [messages, hydrated]); const send = useCallback(() => { const text = input.trim(); if (!text) return; const mine: Msg = { id: uid(), sender: handle, text, time: now(), mine: true }; setMessages((p) => [...p, mine]); setInput(""); const delay = 900 + Math.random() * 900; setTimeout(() => { const replyText = AUTO_REPLIES[Math.floor(Math.random() * AUTO_REPLIES.length)]!; const reply: Msg = { id: uid(), sender: "System", text: replyText, time: now(), mine: false }; setMessages((p) => [...p, reply]); }, delay); }, [input, handle]); return (

CHANNEL CHAT

Ephemeral hub channel — stored locally.{" "} {user ? ( Posting as @{user.username} ) : ( Sign in to tag your handle )}

channel active local store
{messages.map((msg) => (
{msg.mine ? `@${handle}` : msg.sender === "System" ? "⚡ System" : `@${msg.sender}`} {msg.time}
{msg.text}
))}
setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && send()} maxLength={500} />
{[ { icon: "🔒", label: "Client storage", sub: "Never leaves your browser" }, { icon: "💬", label: "Open channel", sub: "Hub-wide thread" }, { icon: "📬", label: "Forum threads", sub: "/forum for persistence" }, { icon: "📦", label: "Market drops", sub: "/drops for schedule" }, ].map((f) => (
{f.icon}
{f.label}
{f.sub}
))}
); }