Files
democratic-money/src/app/casino/page.tsx
2026-05-16 00:47:44 +00:00

98 lines
5.0 KiB
TypeScript

import { redirect } from "next/navigation";
import Link from "next/link";
import { auth } from "@/auth";
import { prisma } from "@/lib/prisma";
import { creditDisplayName, creditTicker } from "@/lib/credits-brand";
import { SiteFooter } from "@/components/SiteFooter";
import { ExchangePanel } from "@/components/casino/ExchangePanel";
import { GameHistory } from "@/components/casino/GameHistory";
const T = creditTicker();
const CREDIT_LONG = creditDisplayName();
const GAMES = [
{ slug: "crash", icon: "📈", name: `${T} Crash`, desc: "Cash out before it crashes", tag: "Solo", color: "from-orange-500 to-red-500" },
{ slug: "dice", icon: "🎲", name: "Dice Roll", desc: "Over/under with custom odds", tag: "Solo", color: "from-blue-500 to-cyan-500" },
{ slug: "mines", icon: "💣", name: "Mines", desc: "Navigate the minefield", tag: "Solo", color: "from-yellow-500 to-orange-500" },
{ slug: "tower", icon: "🏰", name: "Tower Climb", desc: "Climb higher for bigger rewards", tag: "Solo", color: "from-emerald-500 to-teal-500" },
{ slug: "slots", icon: "🎰", name: "Slots", desc: "Classic 3-reel slot machine", tag: "Solo", color: "from-purple-500 to-pink-500" },
{ slug: "blackjack", icon: "🃏", name: "Blackjack", desc: "Beat the dealer to 21", tag: "vs House", color: "from-slate-500 to-gray-600" },
{ slug: "roulette", icon: "🎡", name: "Roulette", desc: "European single-zero", tag: "vs House", color: "from-rose-500 to-red-600" },
{ slug: "coinflip", icon: "🪙", name: "Coin Flip Duel", desc: "Challenge another player", tag: "PvP", color: "from-sky-500 to-blue-600" },
{ slug: "pong", icon: "🏓", name: "PvP Pong", desc: `Pong for real ${T}`, tag: "PvP", color: "from-indigo-500 to-violet-600" },
{ slug: "prediction", icon: "📊", name: "Prediction Market", desc: `Pool ${T} on outcomes`, tag: "Community", color: "from-teal-500 to-cyan-600" },
];
const TAG_COLORS: Record<string, string> = {
Solo: "bg-sky-900/50 text-sky-300",
"vs House": "bg-red-900/50 text-red-300",
PvP: "bg-purple-900/50 text-purple-300",
Community: "bg-emerald-900/50 text-emerald-300",
};
export default async function CasinoLobby() {
const session = await auth();
if (!session?.user?.id) redirect(`/login?callbackUrl=${encodeURIComponent("/casino")}`);
const wallet = await prisma.wallet.findUnique({ where: { userId: session.user.id } });
const balance = wallet?.balanceCredits ?? 0;
return (
<>
<main className="min-h-screen bg-[#030712] px-4 py-8 sm:px-6">
<div className="mx-auto max-w-6xl space-y-8">
{/* Header */}
<div>
<h1 className="text-3xl font-black text-white">
<span className="bg-gradient-to-r from-sky-300 via-indigo-300 to-fuchsia-300 bg-clip-text text-transparent">
{T} · supporter games
</span>
</h1>
<p className="text-slate-400 mt-1">
Wager {CREDIT_LONG} provably fair solo games, house tables, and PvP rooms.
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Exchange Panel + History */}
<div className="space-y-5">
<ExchangePanel initialBalance={balance} />
<div className="rounded-2xl border border-white/10 bg-white/5 p-5 backdrop-blur-sm">
<h2 className="text-sm font-semibold text-white mb-3">Recent Games</h2>
<GameHistory />
</div>
</div>
{/* Game Grid */}
<div className="lg:col-span-2 grid grid-cols-1 sm:grid-cols-2 gap-3">
{GAMES.map(game => (
<Link
key={game.slug}
href={`/casino/${game.slug}`}
className="group relative rounded-2xl border border-white/10 bg-white/5 p-5 hover:bg-white/8 hover:border-white/20 transition-all duration-200 overflow-hidden"
>
<div className={`absolute inset-0 bg-gradient-to-br ${game.color} opacity-0 group-hover:opacity-5 transition-opacity`} />
<div className="relative">
<div className="flex items-start justify-between mb-3">
<span className="text-3xl">{game.icon}</span>
<span className={`text-xs font-medium px-2 py-0.5 rounded-full ${TAG_COLORS[game.tag]}`}>{game.tag}</span>
</div>
<h3 className="text-white font-semibold">{game.name}</h3>
<p className="text-slate-400 text-sm mt-0.5">{game.desc}</p>
</div>
</Link>
))}
</div>
</div>
<p className="text-xs text-slate-600 text-center">
{CREDIT_LONG} ({T}) have no cash redemption value and are not withdrawable. Use is limited to this authorized portal under
committee rules. Solo games employ HMAC-SHA256 provably fair randomness.
</p>
</div>
</main>
<SiteFooter />
</>
);
}