import { useState, useEffect, useRef } from "react";
// ─── THEME ───────────────────────────────────────────────────────────────────
const T = {
bg: "#0A0E1A",
surface: "#111827",
card: "#1A2235",
border: "#1E2D45",
gold: "#F0B429",
goldLight: "#F7D070",
goldDark: "#C98D00",
green: "#10B981",
red: "#EF4444",
blue: "#3B82F6",
purple: "#8B5CF6",
cyan: "#06B6D4",
text: "#F1F5F9",
muted: "#64748B",
sub: "#94A3B8",
};
// ─── MOCK DATA ────────────────────────────────────────────────────────────────
const mockUser = {
name: "Alex Tumwine",
username: "alex_t",
phone: "0701234567",
avatar: "AT",
cuBalance: 42500,
ugxBalance: 8500,
notifications: 3,
};
const mockTransactions = [
{ id: 1, type: "deposit", label: "Wallet Deposit", amount: 50000, cu: 42500, date: "Today, 10:32 AM", status: "completed" },
{ id: 2, type: "queue", label: "Queue Commit", amount: -20000, cu: -20000, date: "Yesterday", status: "pending" },
{ id: 3, type: "sacco", label: "SACCO Savings", amount: -20000, cu: -20000, date: "Mon, Apr 21", status: "completed" },
{ id: 4, type: "reward", label: "Blogger Reward", amount: 5000, cu: 5000, date: "Sun, Apr 20", status: "completed" },
];
const mockQueue = [
{ id: 1, username: "james_k", committed: 85000, position: 1, progress: 92 },
{ id: 2, username: "sarah_m", committed: 50000, position: 2, progress: 65 },
{ id: 3, username: "alex_t", committed: 20000, position: 3, progress: 30, isMe: true },
{ id: 4, username: "grace_n", committed: 100000, position: 4, progress: 10 },
];
const mockBusinesses = [
{ id: 1, name: "Kampala Bakers Ltd", category: "Food & Beverage", status: "verified", loan: 500000, repaid: 320000 },
{ id: 2, name: "TechHub Uganda", category: "Technology", status: "pending", loan: 0, repaid: 0 },
];
const mockBloggers = [
{ id: 1, name: "Sarah Mukasa", platform: "Instagram", followers: "12.4K", posts: 8, rewards: 35000, status: "active" },
{ id: 2, name: "David Ojo", platform: "TikTok", followers: "45K", posts: 15, rewards: 82000, status: "active" },
{ id: 3, name: "Faith Apio", platform: "Twitter/X", followers: "8.2K", posts: 5, rewards: 18000, status: "review" },
];
const mockAds = [
{ id: 1, business: "Kampala Bakers", type: "image", expires: "23h 14m", views: 1240 },
{ id: 2, business: "TechHub UG", type: "video", expires: "8h 45m", views: 3870 },
];
const mockSacco = {
joined: true,
savings: 80000,
loanEligible: 240000,
activeLoan: 100000,
loanRepaid: 40000,
weeklyTarget: 20000,
streak: 4,
};
// ─── UTILS ───────────────────────────────────────────────────────────────────
const fmtCU = (n) => n?.toLocaleString() + " CU";
const fmtUGX = (n) => "UGX " + n?.toLocaleString();
const fmtNum = (n) => n?.toLocaleString();
// ─── STYLES ──────────────────────────────────────────────────────────────────
const gbl = `
@import url('https://fonts.googleapis.com/css2?family=Sora:wght@300;400;500;600;700;800&family=Space+Mono:wght@400;700&display=swap');
*{box-sizing:border-box;margin:0;padding:0;}
body{background:${T.bg};color:${T.text};font-family:'Sora',sans-serif;overflow:hidden;}
::-webkit-scrollbar{width:4px;}
::-webkit-scrollbar-track{background:${T.surface};}
::-webkit-scrollbar-thumb{background:${T.border};border-radius:2px;}
.mono{font-family:'Space Mono',monospace;}
@keyframes slideUp{from{transform:translateY(100%);opacity:0;}to{transform:translateY(0);opacity:1;}}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}}
@keyframes pulse{0%,100%{opacity:1;}50%{opacity:.5;}}
@keyframes shimmer{0%{background-position:-200% 0;}100%{background-position:200% 0;}}
@keyframes ringPop{0%{transform:scale(1);}50%{transform:scale(1.2);}100%{transform:scale(1);}}
@keyframes spin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}};
.slide-up{animation:slideUp .35s cubic-bezier(.22,1,.36,1) forwards;}
.fade-in{animation:fadeIn .3s ease forwards;}
.ring-pop{animation:ringPop .4s ease;}
`;
// ─── COMPONENTS ──────────────────────────────────────────────────────────────
function Badge({ color = T.gold, children, small }) {
return (
{children}
);
}
function Card({ children, style, onClick, glow }) {
return (
{children}
);
}
function ProgressBar({ value, color = T.gold, height = 6 }) {
return (
);
}
function Avatar({ initials, size = 38, color = T.gold }) {
return (
{initials}
);
}
function Divider({ style }) {
return
;
}
function Btn({ children, onClick, variant = "primary", small, full, disabled, style }) {
const base = {
border: "none", borderRadius: 12, fontFamily: "Sora, sans-serif",
fontWeight: 600, cursor: disabled ? "not-allowed" : "pointer",
transition: "all .2s", display: "flex", alignItems: "center",
justifyContent: "center", gap: 6, opacity: disabled ? .5 : 1,
padding: small ? "8px 16px" : "12px 20px",
fontSize: small ? 12 : 14, width: full ? "100%" : "auto", ...style,
};
const variants = {
primary: { background: `linear-gradient(135deg, ${T.gold}, ${T.goldDark})`, color: "#0A0E1A" },
ghost: { background: "transparent", color: T.sub, border: `1px solid ${T.border}` },
danger: { background: T.red + "22", color: T.red, border: `1px solid ${T.red}44` },
success: { background: T.green + "22", color: T.green, border: `1px solid ${T.green}44` },
blue: { background: T.blue + "22", color: T.blue, border: `1px solid ${T.blue}44` },
};
return {children} ;
}
function Input({ label, placeholder, type = "text", value, onChange, icon }) {
return (
{label &&
{label}
}
{icon && {icon} }
onChange(e.target.value)}
placeholder={placeholder}
style={{
width: "100%", background: T.surface, border: `1px solid ${T.border}`,
borderRadius: 12, padding: icon ? "12px 14px 12px 40px" : "12px 14px",
color: T.text, fontSize: 14, fontFamily: "Sora, sans-serif",
outline: "none", transition: "border .2s",
}}
/>
);
}
// ─── AUTH SCREENS ─────────────────────────────────────────────────────────────
function LoginScreen({ onLogin }) {
const [tab, setTab] = useState("login");
const [form, setForm] = useState({ identifier: "", password: "", username: "", phone: "", confirm: "" });
const [checking, setChecking] = useState(false);
const [usernameOk, setUsernameOk] = useState(null);
const [loading, setLoading] = useState(false);
const checkUsername = (val) => {
setForm(f => ({ ...f, username: val }));
if (val.length > 2) {
setChecking(true);
setTimeout(() => {
setUsernameOk(!["admin", "awish", "capitallock"].includes(val.toLowerCase()));
setChecking(false);
}, 600);
} else setUsernameOk(null);
};
const handleSubmit = () => {
setLoading(true);
setTimeout(() => { setLoading(false); onLogin(); }, 1200);
};
return (
{/* Logo */}
{/* Tabs */}
{["login", "register"].map(t => (
setTab(t)} style={{
flex: 1, padding: "10px", borderRadius: 10, border: "none", cursor: "pointer",
background: tab === t ? T.gold : "transparent",
color: tab === t ? "#0A0E1A" : T.muted,
fontFamily: "Sora", fontWeight: 600, fontSize: 13,
transition: "all .2s", textTransform: "capitalize",
}}>{t}
))}
{tab === "login" ? (
setForm(f => ({ ...f, identifier: v }))} icon="👤" />
setForm(f => ({ ...f, password: v }))} icon="🔑" />
{loading ? "Signing in…" : "Sign In →"}
) : (
setForm(f => ({ ...f, fullname: v }))} icon="🧑" />
USERNAME
@
checkUsername(e.target.value)}
placeholder="choose a unique username"
style={{
width: "100%", background: T.surface,
border: `1px solid ${usernameOk === false ? T.red : usernameOk ? T.green : T.border}`,
borderRadius: 12, padding: "12px 14px 12px 36px",
color: T.text, fontSize: 14, fontFamily: "Sora", outline: "none",
}} />
{checking && … }
{!checking && usernameOk === true && ✅ }
{!checking && usernameOk === false && ❌ }
{usernameOk === false &&
Username already taken
}
setForm(f => ({ ...f, phone: v }))} icon="📱" />
setForm(f => ({ ...f, password: v }))} icon="🔑" />
setForm(f => ({ ...f, confirm: v }))} icon="🔏" />
{loading ? "Creating account…" : "Create Account →"}
)}
);
}
// ─── NOTIFICATIONS SHEET ──────────────────────────────────────────────────────
function NotifSheet({ onClose }) {
const notifs = [
{ icon: "💰", title: "Queue Progress", body: "Your queue position moved to #3", time: "2 min ago" },
{ icon: "🏦", title: "SACCO Reminder", body: "Weekly savings due in 2 days", time: "1 hr ago" },
{ icon: "🎉", title: "Blogger Reward", body: "You earned 5,000 CU for your post!", time: "Yesterday" },
];
return (
{notifs.map((n, i) => (
{n.icon}
{n.title}
{n.body}
{n.time}
))}
);
}
// ─── BOTTOM SHEET WRAPPER ────────────────────────────────────────────────────
function Sheet({ children, title, onClose }) {
return (
e.stopPropagation()} style={{
background: T.surface, borderRadius: "24px 24px 0 0",
width: "100%", maxHeight: "88vh", overflow: "hidden",
display: "flex", flexDirection: "column",
border: `1px solid ${T.border}`, borderBottom: "none",
}}>
{/* Handle */}
{/* Header */}
{children}
);
}
// ─── WALLET SHEET ─────────────────────────────────────────────────────────────
function WalletSheet({ onClose }) {
const [tab, setTab] = useState("overview");
const [depositAmount, setDepositAmount] = useState("");
const [step, setStep] = useState(1);
const calcCU = (ugx) => Math.floor(ugx * 0.85);
const calcFee = (ugx) => Math.floor(ugx * 0.15);
const handleDeposit = () => {
if (step === 1) setStep(2);
else { setStep(1); setDepositAmount(""); setTab("overview"); }
};
return (
{/* Tabs */}
{["overview", "deposit", "history"].map(t => (
{ setTab(t); setStep(1); }} style={{
padding: "8px 14px", borderRadius: 10, border: "none", cursor: "pointer",
background: tab === t ? T.gold + "22" : T.card,
color: tab === t ? T.gold : T.muted,
fontFamily: "Sora", fontWeight: 600, fontSize: 12,
border: `1px solid ${tab === t ? T.gold + "44" : T.border}`,
}}>{t.charAt(0).toUpperCase() + t.slice(1)}
))}
{tab === "overview" && (
{/* Balances */}
CU BALANCE
{fmtNum(mockUser.cuBalance)}
Capital Units
UGX BALANCE
{fmtNum(mockUser.ugxBalance)}
Ugandan Shilling
{/* CU Explain */}
⚡ HOW CU WORKS
When you deposit UGX, 15% goes to the Reserve Fund and
the remaining 85% becomes CU — your in-app currency used across all services.
setTab("deposit")}>+ Deposit Funds
)}
{tab === "deposit" && (
{step === 1 && (
<>
{depositAmount >= 10000 && (
Deposit Amount
{fmtUGX(+depositAmount)}
Reserve Fund (15%)
-{fmtUGX(calcFee(+depositAmount))}
You Receive (CU)
{fmtNum(calcCU(+depositAmount))} CU
)}
PAYMENT METHOD
{["Mobile Money (MTN)", "Mobile Money (Airtel)", "Bank Transfer"].map((m, i) => (
{m}
))}
Continue →
>
)}
{step === 2 && (
📱
Confirm on your phone
A payment prompt has been sent to 0701234567 .
Enter your Mobile Money PIN to confirm.
{fmtUGX(+depositAmount)}
≈ {fmtNum(calcCU(+depositAmount))} CU after conversion
✓ Payment Confirmed
)}
)}
{tab === "history" && (
{mockTransactions.map(tx => (
0 ? T.green : T.red) + "22",
display: "flex", alignItems: "center", justifyContent: "center", fontSize: 18,
}}>
{tx.type === "deposit" ? "⬇️" : tx.type === "reward" ? "🎁" : "⬆️"}
0 ? T.green : T.red, fontSize: 13 }}>
{tx.amount > 0 ? "+" : ""}{fmtNum(tx.cu)} CU
{tx.status}
))}
)}
);
}
// ─── QUEUE SHEET ──────────────────────────────────────────────────────────────
function QueueSheet({ onClose }) {
const [committing, setCommitting] = useState(false);
const [amount, setAmount] = useState("");
return (
⚙️ HOW THE QUEUE WORKS
Commit your CU to the FIFO queue. Your funds grow through new deposits, business loan repayments, and reserve support. Fully transparent — track your position live.
{/* My Position */}
Progress: 30%
Estimated: ~18 days
{/* Queue List */}
LIVE QUEUE
{mockQueue.map(q => (
#{q.position}
@{q.username}{q.isMe ? " (you)" : ""}
{fmtNum(q.committed)} CU
))}
COMMIT MORE CU
setCommitting(true)} disabled={amount < 10000}>
Lock CU into Queue
);
}
// ─── SACCO SHEET ──────────────────────────────────────────────────────────────
function SaccoSheet({ onClose }) {
const [tab, setTab] = useState("dashboard");
const [loanAmt, setLoanAmt] = useState("");
return (
{["dashboard", "save", "loans"].map(t => (
setTab(t)} style={{
padding: "8px 14px", borderRadius: 10, border: "none", cursor: "pointer", whiteSpace: "nowrap",
background: tab === t ? T.purple + "22" : T.card,
color: tab === t ? T.purple : T.muted,
fontFamily: "Sora", fontWeight: 600, fontSize: 12,
border: `1px solid ${tab === t ? T.purple + "44" : T.border}`,
}}>{t.charAt(0).toUpperCase() + t.slice(1)}
))}
{tab === "dashboard" && (
TOTAL SAVINGS
{fmtUGX(mockSacco.savings)}
LOAN ELIGIBLE
{fmtUGX(mockSacco.loanEligible)}
🔥 Savings Streak
{mockSacco.streak} weeks
Keep saving weekly to increase your loan eligibility!
{mockSacco.activeLoan > 0 && (
Active Loan
{fmtUGX(mockSacco.activeLoan)}
Repaid: {fmtUGX(mockSacco.loanRepaid)}
Remaining: {fmtUGX(mockSacco.activeLoan - mockSacco.loanRepaid)}
)}
)}
{tab === "save" && (
WEEKLY TARGET
{fmtUGX(mockSacco.weeklyTarget)}
{ }} icon="💰" />
Save This Week
SAVINGS HISTORY
{[1, 2, 3, 4].map(w => (
Week {w}
Apr {28 - w * 7}, 2025
))}
)}
{tab === "loans" && (
YOUR LOAN LIMIT
{fmtUGX(mockSacco.loanEligible)}
Based on 3× your total savings
{loanAmt >= 50000 && (
LOAN SUMMARY
{[
["Principal", fmtUGX(+loanAmt)],
["Interest (15%/month)", fmtUGX(Math.floor(+loanAmt * 0.15))],
["Total Repayable", fmtUGX(Math.floor(+loanAmt * 1.15))],
].map(([l, v]) => (
{l}
{v}
))}
)}
mockSacco.loanEligible}>Apply for Loan
)}
);
}
// ─── BUSINESS SHEET ───────────────────────────────────────────────────────────
function BusinessSheet({ onClose }) {
const [tab, setTab] = useState("list");
const [step, setStep] = useState(1);
return (
{["list", "register", "funding"].map(t => (
setTab(t)} style={{
padding: "8px 14px", borderRadius: 10, border: "none", cursor: "pointer",
background: tab === t ? T.cyan + "22" : T.card,
color: tab === t ? T.cyan : T.muted,
fontFamily: "Sora", fontWeight: 600, fontSize: 12,
border: `1px solid ${tab === t ? T.cyan + "44" : T.border}`,
}}>{t.charAt(0).toUpperCase() + t.slice(1)}
))}
{tab === "list" && (
{mockBusinesses.map(b => (
{b.loan > 0 && (
<>
Loan: {fmtUGX(b.loan)}
Repaid: {fmtUGX(b.repaid)}
>
)}
))}
setTab("register")}>
+ Register a Business
)}
{tab === "register" && (
)}
{tab === "funding" && (
)}
);
}
// ─── BLOGGER SHEET ────────────────────────────────────────────────────────────
function BloggerSheet({ onClose }) {
const [tab, setTab] = useState("bloggers");
return (
{["bloggers", "apply", "ads"].map(t => (
setTab(t)} style={{
padding: "8px 14px", borderRadius: 10, border: "none", cursor: "pointer",
background: tab === t ? T.purple + "22" : T.card,
color: tab === t ? T.purple : T.muted,
fontFamily: "Sora", fontWeight: 600, fontSize: 12,
border: `1px solid ${tab === t ? T.purple + "44" : T.border}`,
}}>{t.charAt(0).toUpperCase() + t.slice(1)}
))}
{tab === "bloggers" && (
💡 HOW TO EARN
Apply as a blogger, post about CAPITAL LOCK on your socials, submit post links, and earn CU rewards based on your engagement!
{mockBloggers.map(b => (
x[0]).join("")} color={T.purple} />
{b.name}
{b.platform} • {b.followers}
{b.status}
{fmtNum(b.rewards)} CU
Rewards
))}
)}
{tab === "apply" && (
)}
{tab === "ads" && (
📢 ACTIVE ADS FEED
{mockAds.map(ad => (
{ad.type === "video" ? "🎬" : "🖼️"}
{ad.business}
👁️ {fmtNum(ad.views)} views
⏱️ {ad.expires}
))}
POST YOUR AD
AD FEE
UGX 10,000
Ad visible for 24 hours
📤
Upload image or video
Post Ad (10,000 UGX)
)}
);
}
// ─── ADMIN PANEL ──────────────────────────────────────────────────────────────
function AdminPanel({ onExit }) {
const [section, setSection] = useState("dashboard");
const stats = [
{ label: "Total Users", value: "1,247", icon: "👥", color: T.blue },
{ label: "Total CU in System", value: "8.4M", icon: "💎", color: T.gold },
{ label: "Reserve Fund", value: "UGX 2.1M", icon: "🏛️", color: T.green },
{ label: "Active Queue", value: "89 users", icon: "🔄", color: T.purple },
{ label: "Verified Businesses", value: "23", icon: "🏢", color: T.cyan },
{ label: "Active Bloggers", value: "41", icon: "📣", color: T.red },
];
const sections = ["dashboard", "users", "businesses", "bloggers", "queue", "transactions", "settings"];
return (
{/* Sidebar */}
{sections.map(s => (
setSection(s)} style={{
width: "100%", textAlign: "left", padding: "10px 12px", borderRadius: 10,
border: "none", cursor: "pointer", marginBottom: 4,
background: section === s ? T.gold + "22" : "transparent",
color: section === s ? T.gold : T.sub,
fontFamily: "Sora", fontWeight: 600, fontSize: 13,
textTransform: "capitalize",
}}>
{["📊", "👥", "🏢", "📣", "🔄", "💳", "⚙️"][sections.indexOf(s)]} {s}
))}
← Exit Admin
{/* Content */}
{section === "dashboard" && (
<>
Admin Dashboard
AWISH Capital Lock — System Overview
{stats.map(s => (
{s.icon}
{s.value}
{s.label}
))}
📈 Reserve Fund Flow
{[["Total Deposited", "UGX 12.4M", T.blue], ["Reserve (15%)", "UGX 1.86M", T.gold], ["In Queue", "UGX 8.4M", T.purple], ["Business Loans", "UGX 2.1M", T.cyan]].map(([l, v, c]) => (
{v}
{l}
))}
>
)}
{section === "users" && (
<>
User Management
{[
{ name: "Alex Tumwine", username: "alex_t", phone: "0701234567", cu: 42500, status: "active" },
{ name: "Sarah Mukasa", username: "sarah_m", phone: "0782345678", cu: 128000, status: "active" },
{ name: "James Kato", username: "james_k", phone: "0753456789", cu: 320000, status: "active" },
{ name: "Grace Nakato", username: "grace_n", phone: "0714567890", cu: 85000, status: "suspended" },
].map((u, i) => (
x[0]).join("")} />
{u.name}
@{u.username} • {u.phone}
{u.status}
View
Suspend
))}
>
)}
{section === "businesses" && (
<>
Business Management
{[...mockBusinesses, { id: 3, name: "Nakawa Market Vendors", category: "Retail", status: "pending", loan: 0, repaid: 0 }].map(b => (
{b.status}
{b.status === "pending" && ✓ Verify }
Details
{b.loan > 0 && (
Loan: {fmtUGX(b.loan)} | Repaid: {fmtUGX(b.repaid)}
)}
))}
>
)}
{section === "bloggers" && (
<>
Blogger Management
{mockBloggers.map(b => (
x[0]).join("")} color={T.purple} size={34} />
{b.name}
{b.platform} • {b.followers} followers • {b.posts} posts
{b.status}
{b.status === "review" && Approve }
Reward CU
))}
>
)}
{section === "queue" && (
<>
Queue Management
{mockQueue.map(q => (
#{q.position}
@{q.username}
Progress: {q.progress}%
{fmtNum(q.committed)} CU
))}
>
)}
{section === "transactions" && (
<>
All Transactions
{[
...mockTransactions,
{ id: 5, type: "deposit", label: "Deposit – james_k", amount: 100000, cu: 85000, date: "Yesterday", status: "completed" },
{ id: 6, type: "loan", label: "Business Loan – Kampala Bakers", amount: 500000, cu: 500000, date: "Apr 20", status: "completed" },
].map(tx => (
0 ? T.green : T.red) + "22",
display: "flex", alignItems: "center", justifyContent: "center", fontSize: 16,
}}>
{tx.type === "deposit" ? "⬇️" : tx.type === "loan" ? "🏦" : tx.type === "reward" ? "🎁" : "⬆️"}
0 ? T.green : T.red, fontWeight: 700 }}>
{tx.amount > 0 ? "+" : ""}{fmtUGX(Math.abs(tx.amount))}
{tx.status}
))}
>
)}
{section === "settings" && (
<>
System Settings
⚙️ Economy Parameters
{[
["Reserve Fund Rate", "15%"],
["CU Conversion Rate", "85% of deposit"],
["Minimum Deposit", "UGX 10,000"],
["SACCO Weekly Minimum", "UGX 20,000"],
["Business Verification Fee", "UGX 50,000"],
["Loan Interest Rate", "15% / month"],
["Ad Fee (24h)", "UGX 10,000"],
].map(([k, v]) => (
{k}
{v}
))}
🔑 Admin Accounts
Super Admin
admin@capitallock.ug
SUPER
>
)}
);
}
// ─── MAIN APP ─────────────────────────────────────────────────────────────────
export default function App() {
const [route, setRoute] = useState("login"); // login | app | admin | install
const [activeSheet, setActiveSheet] = useState(null);
const [notifOpen, setNotifOpen] = useState(false);
const [notifRing, setNotifRing] = useState(false);
const [url, setUrl] = useState("/index");
// Simulate URL routing
useEffect(() => {
if (url === "/supperaccount/login") setRoute("admin");
else if (url === "/supperaccount/install") setRoute("install");
else if (url === "/index") setRoute("login");
}, [url]);
const openSheet = (name) => setActiveSheet(name);
const closeSheet = () => setActiveSheet(null);
const ringNotif = () => {
setNotifRing(true);
setTimeout(() => setNotifRing(false), 400);
setNotifOpen(true);
};
if (route === "install") return setRoute("admin")} />;
if (route === "admin") return setRoute("app")} />;
if (route === "login") return setRoute("app")} />;
const tabs = [
{ id: "queue", icon: "🔄", label: "Queue" },
{ id: "sacco", icon: "🏦", label: "SACCO" },
{ id: "wallet", icon: "💼", label: "Wallet", big: true },
{ id: "business", icon: "🏢", label: "Business" },
{ id: "blogger", icon: "📣", label: "Blogger" },
];
return (
{/* TOP BAR */}
{/* Balance */}
ACTIVE BALANCE
{fmtNum(mockUser.cuBalance)}
CU
{/* Right: notif + profile */}
{/* Admin shortcut */}
setRoute("admin")} style={{
background: "none", border: "none", cursor: "pointer",
fontSize: 10, color: T.muted, fontFamily: "Sora",
}}>Admin
{/* Bell */}
🛎️
{mockUser.notifications}
{/* HOME CONTENT */}
{/* Welcome */}
Good morning,
{mockUser.name} 👋
{/* Quick Stats */}
openSheet("queue")} style={{ cursor: "pointer" }}>
QUEUE POSITION
#3
30% funded
openSheet("sacco")} style={{ cursor: "pointer" }}>
SACCO SAVINGS
UGX 80K
🔥 4-week streak
{/* Ads Feed */}
📢 ADS FEED
{mockAds.map(ad => (
{ad.type === "video" ? "🎬" : "🖼️"}
{ad.business}
⏱️ {ad.expires}
))}
{/* Recent Transactions */}
🕐 RECENT ACTIVITY
{mockTransactions.slice(0, 3).map(tx => (
0 ? T.green : T.red) + "22",
display: "flex", alignItems: "center", justifyContent: "center", fontSize: 16,
}}>
{tx.type === "deposit" ? "⬇️" : tx.type === "reward" ? "🎁" : "⬆️"}
0 ? T.green : T.red, fontSize: 13 }}>
{tx.cu > 0 ? "+" : ""}{fmtNum(tx.cu)} CU
))}
{/* BOTTOM NAV */}
{tabs.map(t => (
t.big ? (
openSheet(t.id)} style={{
width: 64, height: 64, borderRadius: "50%", border: "none",
background: `linear-gradient(135deg, ${T.gold}, ${T.goldDark})`,
display: "flex", flexDirection: "column", alignItems: "center",
justifyContent: "center", cursor: "pointer",
boxShadow: `0 0 24px ${T.gold}66`,
transform: "translateY(-16px)", fontSize: 26,
transition: "transform .2s",
}}>
{t.icon}
) : (
openSheet(t.id)} style={{
background: "none", border: "none", cursor: "pointer",
display: "flex", flexDirection: "column", alignItems: "center",
gap: 4, padding: "4px 8px",
}}>
{t.icon}
{t.label}
)
))}
{/* SHEETS */}
{notifOpen &&
setNotifOpen(false)} />}
{activeSheet === "wallet" && }
{activeSheet === "queue" && }
{activeSheet === "sacco" && }
{activeSheet === "business" && }
{activeSheet === "blogger" && }
);
}
// ─── INSTALL SCREEN ───────────────────────────────────────────────────────────
function InstallScreen({ onDone }) {
const [step, setStep] = useState(1);
const [form, setForm] = useState({ dbHost: "localhost", dbPort: "3306", dbName: "", dbUser: "", dbPass: "", adminName: "", adminEmail: "", adminPass: "" });
const [installing, setInstalling] = useState(false);
const runInstall = () => {
setInstalling(true);
setTimeout(() => { setInstalling(false); onDone(); }, 2500);
};
return (
🔒
CAPITAL LOCK
Installation Wizard
{/* Steps */}
{[1, 2, 3].map(s => (
{s < step ? "✓" : s}
{s < 3 &&
}
))}
{step === 1 && (
)}
{step === 2 && (
)}
{step === 3 && (
✅ Review & Install
{[
["Database Host", form.dbHost || "localhost"],
["Database Port", form.dbPort || "3306"],
["Database", form.dbName || "(not set)"],
["Admin Name", form.adminName || "(not set)"],
["Admin Email", form.adminEmail || "(not set)"],
].map(([k, v]) => (
{k}
{v}
))}
{installing ? (
⚙️
Installing Capital Lock…
) : (
setStep(2)}>← Back
🚀 Install Now
)}
)}
);
}