- 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
157 lines
6.9 KiB
TypeScript
157 lines
6.9 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useMemo, useState } from "react";
|
|
import ThemedLayout from "@/components/layouts/ThemedLayout";
|
|
import { isMerchantBtcConfigured, getMerchantBtcAddress } from "@/lib/merchantBtc";
|
|
|
|
type Coin = "BTC" | "ETH" | "XMR";
|
|
|
|
function getAddresses() {
|
|
return {
|
|
BTC: (process.env.NEXT_PUBLIC_MERCHANT_BTC_ADDRESS || "").trim() || "bc1q — set NEXT_PUBLIC_MERCHANT_BTC_ADDRESS",
|
|
ETH: (process.env.NEXT_PUBLIC_ETH_ADDRESS || "").trim() || "0x — set NEXT_PUBLIC_ETH_ADDRESS",
|
|
XMR: (process.env.NEXT_PUBLIC_XMR_ADDRESS || "").trim() || "4A — set NEXT_PUBLIC_XMR_ADDRESS",
|
|
};
|
|
}
|
|
|
|
export default function SupportPage() {
|
|
const [copied, setCopied] = useState<Record<Coin, boolean>>({ BTC: false, ETH: false, XMR: false });
|
|
const btcReady = isMerchantBtcConfigured();
|
|
const btcAddr = getMerchantBtcAddress();
|
|
|
|
const addresses = useMemo(() => getAddresses(), []);
|
|
|
|
const copy = async (coin: Coin) => {
|
|
const addr = coin === "BTC" && btcReady ? btcAddr : addresses[coin];
|
|
try {
|
|
await navigator.clipboard.writeText(addr);
|
|
setCopied((p) => ({ ...p, [coin]: true }));
|
|
window.setTimeout(() => setCopied((p) => ({ ...p, [coin]: false })), 1800);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
};
|
|
|
|
const displayAddr = (coin: Coin) =>
|
|
coin === "BTC" && btcReady ? btcAddr : addresses[coin];
|
|
|
|
const configured = {
|
|
BTC: btcReady,
|
|
ETH: Boolean((process.env.NEXT_PUBLIC_ETH_ADDRESS || "").trim()),
|
|
XMR: Boolean((process.env.NEXT_PUBLIC_XMR_ADDRESS || "").trim()),
|
|
};
|
|
|
|
return (
|
|
<ThemedLayout theme="editorial" siteTitle="THE OFFERING" siteSubtitle="Optional support · transparent tip jar">
|
|
<section className="container mx-auto max-w-5xl px-4 py-12">
|
|
<div className="theme-card rounded-3xl p-10 md:p-14">
|
|
<div className="text-center">
|
|
<div className="mb-3 text-[10px] uppercase tracking-widest opacity-70">optional ritual</div>
|
|
<h1 className="text-4xl font-bold md:text-5xl">
|
|
THE <span className="theme-accent">OFFERING</span>
|
|
</h1>
|
|
<p className="mx-auto mt-6 max-w-3xl text-lg opacity-80">
|
|
If this operation kept you online, throw fuel on the fire. Infrastructure and onion mirrors cost time and
|
|
hardware.
|
|
</p>
|
|
<p className="mx-auto mt-3 max-w-3xl text-sm opacity-60">
|
|
Transparent tip jar — choose your asset and amount. No paywalls, no pressure, no analytics. To
|
|
configure addresses, set the corresponding env vars in{" "}
|
|
<code className="rounded bg-white/10 px-1">.env.local</code> and restart Next.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="mt-12 grid grid-cols-1 gap-6 md:grid-cols-3">
|
|
{(["BTC", "ETH", "XMR"] as Coin[]).map((coin) => {
|
|
const addr = displayAddr(coin);
|
|
const isConfigured = configured[coin];
|
|
return (
|
|
<div key={coin} className="theme-card rounded-2xl p-6">
|
|
<div className="mb-1 flex items-center justify-between">
|
|
<div className="text-2xl font-bold theme-accent">{coin}</div>
|
|
{!isConfigured && (
|
|
<span className="rounded-full bg-amber-500/20 px-2 py-0.5 text-[10px] text-amber-300">
|
|
Not configured
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="mt-3 min-h-[3.5rem] rounded-xl bg-black/40 p-3 font-mono text-xs theme-accent break-all">
|
|
{isConfigured ? addr : (
|
|
<span className="opacity-40">
|
|
Set{" "}
|
|
<code>
|
|
NEXT_PUBLIC_{coin === "BTC" ? "MERCHANT_BTC" : coin}_ADDRESS
|
|
</code>{" "}
|
|
in .env.local
|
|
</span>
|
|
)}
|
|
</div>
|
|
<button
|
|
type="button"
|
|
className={`mt-4 w-full rounded-full border-2 border-current px-5 py-3 text-sm font-bold transition-all ${
|
|
isConfigured
|
|
? "theme-accent bg-current text-white hover:opacity-90"
|
|
: "opacity-40 cursor-not-allowed"
|
|
}`}
|
|
onClick={() => void copy(coin)}
|
|
disabled={!isConfigured}
|
|
>
|
|
{copied[coin] ? "✓ COPIED" : `COPY ${coin} ADDRESS`}
|
|
</button>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="mt-12 grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
<div className="theme-card rounded-2xl p-6">
|
|
<div className="mb-3 font-bold">What you're supporting</div>
|
|
<ul className="space-y-2 text-sm text-foreground/70">
|
|
<li className="flex items-start gap-2"><span>—</span> Onion mirror hosting and key backup infrastructure</li>
|
|
<li className="flex items-start gap-2"><span>—</span> More Vault unlocks, drops, and forum rings</li>
|
|
<li className="flex items-start gap-2"><span>—</span> More UI weirdness (the good kind)</li>
|
|
<li className="flex items-start gap-2"><span>—</span> The README staying accurate</li>
|
|
</ul>
|
|
</div>
|
|
<div className="theme-card rounded-2xl p-6">
|
|
<div className="mb-3 font-bold">Where to go next</div>
|
|
<div className="flex flex-wrap gap-3">
|
|
<Link
|
|
href="/account/add-funds"
|
|
className="rounded-full border border-neon-green/40 px-5 py-2 text-sm font-bold text-neon-green hover:bg-neon-green/10"
|
|
>
|
|
Add funds →
|
|
</Link>
|
|
<Link
|
|
href="/market"
|
|
className="rounded-full border border-white/20 px-5 py-2 text-sm font-bold hover:border-neon-cyan/40"
|
|
>
|
|
Market
|
|
</Link>
|
|
<Link
|
|
href="/forum"
|
|
className="rounded-full border border-white/20 px-5 py-2 text-sm font-bold hover:border-neon-cyan/40"
|
|
>
|
|
Forum
|
|
</Link>
|
|
<Link
|
|
href="/"
|
|
className="rounded-full bg-neon-cyan/15 border border-neon-cyan/30 px-5 py-2 text-sm font-bold text-neon-cyan hover:bg-neon-cyan/20"
|
|
>
|
|
Hub →
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-10 rounded-xl bg-white/5 p-4 text-center text-xs text-foreground/50">
|
|
Confirm any BTC address against the signed message on the hub before sending. Same bytes, every time.
|
|
If the address differs from a prior session, treat it as a compromise — do not proceed.
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</ThemedLayout>
|
|
);
|
|
}
|