10x every page: real interactions, kill fake content, wire everything

- ChatWidget: remove illegal seeds, real localStorage per-handle chat,
  honest bot replies about market/forum/funds
- ForumBoard: wire to real forumState (loadForum/addThread/vote), kill
  fake stats and illegal seed posts
- Home page: privacy features list reflects reality, footer links real
- Links: kill all alert() calls, replace fake onions with real clearnet
  privacy resources + internal route grid
- Support: per-coin copied state, env-driven addresses, real BTC addr
- Inner circle: wire to AccountContext, tier system from LUX balance,
  remove hardcoded admin/shadow credentials and fake trading signals
- Drop box: real sealed-note localStorage system, honest about no
  anonymous upload capability, real file picker with receipt
- Messages: fully functional per-handle localStorage chat, AI-style
  contextual bot replies, clear history, honest about local storage
- Wallets: pivot from fake PayPal accounts to Digital Access Passes,
  wire Buy Now to cart via ShopProduct interface
- Testimonials: wire submit form to localStorage, interactive star
  rating 1-10, display submitted reviews above the fold
- Raffle: use real merchant BTC address, real per-handle entry storage,
  honest LUX-only prize disclaimer, fix 0x address
- Drops/Lotto: real number picker 1-49 with Quick Pick, ticket
  submission, match display against drawn numbers, demo disclaimer
- Sanctuary: real 4-4-6-2 breathing timer, meditation passage with
  timer, candle-lighting with localStorage notes
- Game: full playable Void Pong with canvas physics, CPU AI, scoring,
  rally counter, localStorage high score
- Security analysis: honest architecture breakdown with real grades,
  layer-by-layer analysis, practical OPSEC guide, fiction banner
- Trust: compute real scores from actual localStorage data (LUX,
  USD, forum posts, testimonials), FAQ accordion

Made-with: Cursor
This commit is contained in:
drjones
2026-04-16 00:55:28 -07:00
parent 9da373a190
commit 2f928fbdc4
36 changed files with 3837 additions and 2354 deletions

View File

@@ -1,156 +1,195 @@
"use client";
import { useState, useEffect, useRef } from "react";
import { useState, useEffect, useRef, useCallback } from "react";
import Link from "next/link";
import { useAccount } from "@/contexts/AccountContext";
const ChatWidget = () => {
const [messages, setMessages] = useState([
{ id: 1, sender: "System", text: "Welcome to the encrypted channel. All messages are endtoend encrypted.", time: "12:00" },
{ id: 2, sender: "Ghost", text: "Has anyone tested the new stimulant batch?", time: "12:05" },
{ id: 3, sender: "Vendor_X", text: "Batch #8 passes all purity tests. Available for bulk.", time: "12:07" },
{ id: 4, sender: "Anonymous", text: "Need a EU passport within 48 hours. DM if you can deliver.", time: "12:10" },
]);
type Msg = {
id: string;
sender: string;
text: string;
time: string;
mine: boolean;
};
const SEED_MSGS: Omit<Msg, "mine">[] = [
{ 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<Msg[]>([]);
const [input, setInput] = useState("");
/** Set after mount so SSR HTML matches first client paint (no Math.random in initial state). */
const [encryptionKey, setEncryptionKey] = useState("");
const chatContainerRef = useRef<HTMLDivElement>(null);
const [hydrated, setHydrated] = useState(false);
const endRef = useRef<HTMLDivElement>(null);
useEffect(() => {
setEncryptionKey("session_" + Math.random().toString(36).substring(2, 9));
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 (chatContainerRef.current) {
chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
if (hydrated && messages.length > 0) {
saveHistory(messages);
endRef.current?.scrollIntoView({ behavior: "smooth" });
}
}, [messages]);
}, [messages, hydrated]);
const handleSend = () => {
if (!input.trim()) return;
const newMessage = {
id: messages.length + 1,
sender: "You",
text: input,
time: new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
};
setMessages([...messages, newMessage]);
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("");
// Simulate a reply after a delay
const delay = 900 + Math.random() * 900;
setTimeout(() => {
const replies = [
"Received. Encryption verified.",
"I can help with that. Check your vault.",
"New drop incoming in 24 hours.",
"Your request has been logged.",
];
const randomReply = replies[Math.floor(Math.random() * replies.length)];
const replyMessage = {
id: messages.length + 2,
sender: "System",
text: randomReply,
time: new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
};
setMessages(prev => [...prev, replyMessage]);
}, 1000);
};
const handleEncrypt = () => {
alert(`Session key: ${encryptionKey}\nAll messages are encrypted with this key.`);
};
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 (
<div className="glass rounded-3xl border border-white/10 p-8">
<div className="mb-8 flex items-center justify-between">
<div className="mb-6 flex flex-wrap items-start justify-between gap-4">
<div>
<h2 className="font-orbitron text-3xl font-bold">ENCRYPTED CHAT</h2>
<p className="text-foreground/60">Endtoend encrypted messaging. No logs, no traces.</p>
<h2 className="font-orbitron text-3xl font-bold">CHANNEL CHAT</h2>
<p className="mt-1 text-sm text-foreground/60">
Ephemeral hub channel stored locally.{" "}
{user ? (
<span className="text-neon-cyan">Posting as @{user.username}</span>
) : (
<Link href="/sign-in" className="text-neon-cyan underline">
Sign in to tag your handle
</Link>
)}
</p>
</div>
<div className="flex gap-3 text-[10px] font-mono uppercase tracking-wider text-foreground/40">
<span className="flex items-center gap-1">
<span className="inline-block h-2 w-2 animate-pulse rounded-full bg-neon-green" />
channel active
</span>
<span>local store</span>
</div>
<button
onClick={handleEncrypt}
className="rounded-full bg-gradient-to-r from-neon-cyan to-neon-purple px-6 py-3 font-bold text-background"
>
🔐 SHOW SESSION KEY
</button>
</div>
{/* Chat messages */}
<div
ref={chatContainerRef}
className="glass mb-6 h-96 overflow-y-auto rounded-2xl border border-white/10 p-6"
>
<div className="mb-4 h-72 overflow-y-auto rounded-2xl border border-white/10 bg-black/30 p-4 space-y-3">
{messages.map((msg) => (
<div
key={msg.id}
className={`mb-4 ${msg.sender === "You" ? "text-right" : ""}`}
>
<div className="mb-1 flex items-center gap-2">
<span className={`inline-block rounded-full px-3 py-1 text-xs font-medium ${msg.sender === "You"
? "bg-neon-cyan/20 text-neon-cyan"
: msg.sender === "System"
? "bg-neon-purple/20 text-neon-purple"
: "bg-white/10"
}`}>
{msg.sender}
<div key={msg.id} className={`flex flex-col ${msg.mine ? "items-end" : "items-start"}`}>
<div className="mb-0.5 flex items-center gap-2">
<span
className={`text-xs font-medium ${
msg.mine
? "text-neon-cyan"
: msg.sender === "System"
? "text-neon-purple"
: "text-foreground/70"
}`}
>
{msg.mine ? `@${handle}` : msg.sender === "System" ? "⚡ System" : `@${msg.sender}`}
</span>
<span className="text-xs text-foreground/40">{msg.time}</span>
<span className="text-[10px] text-foreground/30">{msg.time}</span>
</div>
<div className={`glass inline-block max-w-[80%] rounded-2xl px-4 py-3 ${msg.sender === "You"
? "bg-gradient-to-r from-neon-cyan/20 to-neon-cyan/10"
: "bg-white/5"
}`}>
<div
className={`max-w-[80%] rounded-2xl px-4 py-2 text-sm ${
msg.mine
? "bg-neon-cyan/15 text-neon-cyan"
: msg.sender === "System"
? "bg-neon-purple/10 text-neon-purple/90"
: "bg-white/5 text-foreground/90"
}`}
>
{msg.text}
</div>
</div>
))}
<div ref={endRef} />
</div>
{/* Input area */}
<div className="flex gap-4">
<div className="flex gap-3">
<input
type="text"
className="glass flex-1 rounded-2xl border border-white/10 bg-transparent px-6 py-4"
placeholder="Type your encrypted message..."
className="flex-1 rounded-2xl border border-white/10 bg-black/40 px-5 py-3 text-sm focus:border-neon-cyan/40 focus:outline-none"
placeholder={user ? `Message as @${user.username}` : "Message the channel…"}
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && handleSend()}
onKeyDown={(e) => e.key === "Enter" && send()}
maxLength={500}
/>
<button
onClick={handleSend}
className="rounded-full bg-gradient-to-r from-neon-cyan to-neon-purple px-8 py-4 font-bold text-background"
type="button"
onClick={send}
disabled={!input.trim()}
className="rounded-2xl bg-gradient-to-r from-neon-cyan to-neon-purple px-6 py-3 text-sm font-bold text-background disabled:opacity-40"
>
SEND
Send
</button>
</div>
{/* Chat features */}
<div className="mt-8 grid grid-cols-2 gap-6 md:grid-cols-4">
<div className="glass rounded-2xl border border-white/10 p-4 text-center">
<div className="text-2xl">🔒</div>
<div className="mt-2 text-sm font-bold">AES256GCM</div>
<div className="text-xs text-foreground/60">Encryption</div>
</div>
<div className="glass rounded-2xl border border-white/10 p-4 text-center">
<div className="text-2xl"></div>
<div className="mt-2 text-sm font-bold">ZeroKnowledge</div>
<div className="text-xs text-foreground/60">No server storage</div>
</div>
<div className="glass rounded-2xl border border-white/10 p-4 text-center">
<div className="text-2xl">🌐</div>
<div className="mt-2 text-sm font-bold">WebRTC</div>
<div className="text-xs text-foreground/60">P2P possible</div>
</div>
<div className="glass rounded-2xl border border-white/10 p-4 text-center">
<div className="text-2xl">🕶</div>
<div className="mt-2 text-sm font-bold">SelfDestruct</div>
<div className="text-xs text-foreground/60">Messages expire</div>
</div>
</div>
<div className="mt-8 text-center text-xs text-foreground/40">
<p>Ephemeral client-side queue nothing leaves this browser profile until a real transport is configured.</p>
<div className="mt-6 grid grid-cols-2 gap-4 md:grid-cols-4">
{[
{ 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) => (
<div key={f.label} className="glass rounded-2xl border border-white/10 p-4 text-center">
<div className="text-2xl">{f.icon}</div>
<div className="mt-2 text-sm font-bold">{f.label}</div>
<div className="text-xs text-foreground/50">{f.sub}</div>
</div>
))}
</div>
</div>
);
};
export default ChatWidget;
}