import { useState, useEffect, useRef, useCallback } from "react";
import { motion, AnimatePresence } from "framer-motion";
import {
Wallet, Users, History, Landmark, Plus, Minus, Send,
ArrowRightLeft, TrendingUp, Zap, ChevronRight, X, Check,
CreditCard, DollarSign, Activity, Shield
} from "lucide-react";
const STARTING_BALANCE = 1500;
const NEON_GREEN = "#00ff9d";
const NEON_CYAN = "#00e5ff";
const GOLD = "#ffd700";
const formatMoney = (amount) =>
new Intl.NumberFormat("de-DE", { style: "currency", currency: "USD", maximumFractionDigits: 0 }).format(amount);
const GlowCard = ({ children, className = "", accent = "green", onClick, hover = true }) => {
const accents = {
green: "border-emerald-500/30 hover:border-emerald-400/60 hover:shadow-emerald-500/20",
cyan: "border-cyan-500/30 hover:border-cyan-400/60 hover:shadow-cyan-500/20",
gold: "border-yellow-500/30 hover:border-yellow-400/60 hover:shadow-yellow-500/20",
red: "border-red-500/30 hover:border-red-400/60 hover:shadow-red-500/20",
};
return (
{children}
);
};
const NeonButton = ({ children, onClick, variant = "green", size = "md", disabled = false, className = "" }) => {
const variants = {
green: "bg-emerald-500/20 border-emerald-400/50 text-emerald-300 hover:bg-emerald-500/40 hover:border-emerald-300 hover:shadow-emerald-500/40",
cyan: "bg-cyan-500/20 border-cyan-400/50 text-cyan-300 hover:bg-cyan-500/40 hover:border-cyan-300 hover:shadow-cyan-500/40",
gold: "bg-yellow-500/20 border-yellow-400/50 text-yellow-300 hover:bg-yellow-500/40 hover:border-yellow-300 hover:shadow-yellow-500/40",
red: "bg-red-500/20 border-red-400/50 text-red-300 hover:bg-red-500/40 hover:border-red-300 hover:shadow-red-500/40",
ghost: "bg-white/5 border-white/10 text-white/70 hover:bg-white/10 hover:border-white/20",
};
const sizes = {
sm: "px-3 py-1.5 text-xs",
md: "px-4 py-2 text-sm",
lg: "px-6 py-3 text-base",
};
return (
{children}
);
};
const NeonInput = ({ value, onChange, placeholder, type = "text", className = "" }) => (
);
const NeonSelect = ({ value, onChange, children, className = "" }) => (
);
const StatCard = ({ icon: Icon, label, value, accent = "green", delay = 0 }) => {
const colors = {
green: { text: "text-emerald-400", bg: "bg-emerald-500/10", glow: "shadow-emerald-500/20" },
cyan: { text: "text-cyan-400", bg: "bg-cyan-500/10", glow: "shadow-cyan-500/20" },
gold: { text: "text-yellow-400", bg: "bg-yellow-500/10", glow: "shadow-yellow-500/20" },
purple: { text: "text-purple-400", bg: "bg-purple-500/10", glow: "shadow-purple-500/20" },
};
const c = colors[accent];
return (
);
};
const PlayerCard = ({ player, onAdjust, onRemove, index }) => {
const isRich = player.balance >= 2000;
const isPoor = player.balance < 500;
const balanceColor = isRich ? "text-emerald-400" : isPoor ? "text-red-400" : "text-cyan-300";
return (
{player.name.charAt(0).toUpperCase()}
{player.name}
ID: #{String(player.id).padStart(4, "0")}
Kontostand
{formatMoney(player.balance)}
onAdjust(player.id, 100)}
className="flex-1 flex items-center justify-center gap-1"
>
$100
onAdjust(player.id, 50)}
className="flex-1 flex items-center justify-center gap-1"
>
$50
onAdjust(player.id, -100)}
className="flex-1 flex items-center justify-center gap-1"
>
$100
);
};
const TransactionItem = ({ tx, index }) => {
const isBank = tx.from === "Bank" || tx.to === "Bank";
return (
{tx.from} → {tx.to}
{formatMoney(tx.amount)}
{tx.time}
);
};
export default function MonopolyBank() {
const [players, setPlayers] = useState([
{ id: 1, name: "Alice", balance: 1500 },
{ id: 2, name: "Bob", balance: 1500 },
]);
const [transactions, setTransactions] = useState([
{ id: 1, from: "Bank", to: "Alice", amount: 1500, time: "Spielstart" },
{ id: 2, from: "Bank", to: "Bob", amount: 1500, time: "Spielstart" },
]);
const [newPlayerName, setNewPlayerName] = useState("");
const [transferFrom, setTransferFrom] = useState("");
const [transferTo, setTransferTo] = useState("");
const [transferAmount, setTransferAmount] = useState("");
const [toast, setToast] = useState(null);
const [activeTab, setActiveTab] = useState("players");
const nextId = useRef(3);
const totalMoney = players.reduce((s, p) => s + p.balance, 0);
const showToast = (msg, type = "success") => {
setToast({ msg, type });
setTimeout(() => setToast(null), 2800);
};
const addPlayer = () => {
const name = newPlayerName.trim();
if (!name) return showToast("Bitte Namen eingeben", "error");
if (players.find(p => p.name.toLowerCase() === name.toLowerCase()))
return showToast("Spieler bereits vorhanden", "error");
const player = { id: nextId.current++, name, balance: STARTING_BALANCE };
setPlayers(prev => [...prev, player]);
setTransactions(prev => [
{ id: Date.now(), from: "Bank", to: name, amount: STARTING_BALANCE, time: new Date().toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit", second: "2-digit" }) },
...prev,
]);
setNewPlayerName("");
showToast(`${name} hat ${formatMoney(STARTING_BALANCE)} erhalten`);
};
const removePlayer = (id) => {
const player = players.find(p => p.id === id);
if (!player) return;
setPlayers(prev => prev.filter(p => p.id !== id));
showToast(`${player.name} wurde entfernt`, "error");
};
const adjustBalance = useCallback((id, delta) => {
const player = players.find(p => p.id === id);
if (!player) return;
if (player.balance + delta < 0) return showToast("Nicht genug Geld!", "error");
setPlayers(prev => prev.map(p => p.id === id ? { ...p, balance: p.balance + delta } : p));
const desc = delta > 0 ? "Bank" : player.name;
const dest = delta > 0 ? player.name : "Bank";
setTransactions(prev => [
{
id: Date.now(),
from: desc,
to: dest,
amount: Math.abs(delta),
time: new Date().toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit", second: "2-digit" })
},
...prev,
]);
}, [players]);
const transfer = useCallback(() => {
const amount = parseInt(transferAmount);
if (!transferFrom || !transferTo) {
return showToast("Bitte Sender und Empfänger auswählen", "error");
}
if (transferFrom === transferTo) {
return showToast("Sender und Empfänger müssen unterschiedlich sein", "error");
}
if (!amount || amount <= 0 || isNaN(amount)) {
return showToast("Bitte einen gültigen Betrag eingeben", "error");
}
const sender = players.find(p => String(p.id) === String(transferFrom));
const receiver = players.find(p => String(p.id) === String(transferTo));
if (!sender || !receiver) {
return showToast("Spieler nicht gefunden", "error");
}
if (sender.balance < amount) {
return showToast(`${sender.name} hat nicht genug Guthaben!`, "error");
}
setPlayers(prev => prev.map(p => {
if (String(p.id) === String(transferFrom)) {
return { ...p, balance: p.balance - amount };
}
if (String(p.id) === String(transferTo)) {
return { ...p, balance: p.balance + amount };
}
return p;
}));
setTransactions(prev => [
{
id: Date.now(),
from: sender.name,
to: receiver.name,
amount: amount,
time: new Date().toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit", second: "2-digit" })
},
...prev,
]);
setTransferAmount("");
showToast(`${formatMoney(amount)} von ${sender.name} an ${receiver.name} transferiert`);
}, [transferFrom, transferTo, transferAmount, players]);
const tabs = [
{ id: "players", label: "Spieler", icon: Users },
{ id: "transfer", label: "Transfer", icon: Send },
{ id: "history", label: "Verlauf", icon: History },
];
return (
{/* Animated background grid */}
{/* Toast */}
{toast && (
{toast.type === "error" ? : }
{toast.msg}
)}
{/* Header */}
MONO
BANK
Digital Banking System
{/* Stats */}
{/* Main Panel */}
{/* Add Player */}
setNewPlayerName(e.target.value)}
placeholder="Spielername eingeben…"
className="flex-1"
onKeyPress={e => e.key === 'Enter' && addPlayer()}
/>
Hinzufügen
+
Startguthaben: {formatMoney(STARTING_BALANCE)} automatisch
{/* Mobile tabs */}
{tabs.map(t => (
))}
{/* Transfer Panel */}
setTransferFrom(e.target.value)}>
{players.map(p => (
))}
setTransferTo(e.target.value)}>
{players.map(p => (
))}
setTransferAmount(e.target.value)}
placeholder="z.B. 200"
onKeyPress={e => e.key === 'Enter' && transfer()}
/>
Transfer senden
{/* Players Grid */}
Kontoübersicht
{players.length} Spieler
{players.length === 0 ? (
Keine Spieler vorhanden
Füge oben einen Spieler hinzu
) : (
{players.map((player, i) => (
))}
)}
{/* Sidebar – Transactions */}
{transactions.length === 0 ? (
) : (
transactions.slice(0, 30).map((tx, i) => (
))
)}
{/* Footer */}
);
}