import { useState, useEffect } from "react";
// ── CONFIG ────────────────────────────────────────────────────
const API_BASE = "https://yoursite.com";
const DEMO_USERS = [
{ id:1, username:"superadmin", password:"Admin@1234", full_name:"Sheperd Admin", role:"superadmin", email:"admin@sheperd.co.uk" },
{ id:2, username:"admin", password:"Admin@1234", full_name:"License Admin", role:"admin", email:"admin2@sheperd.co.uk" },
{ id:3, username:"viewer", password:"Admin@1234", full_name:"Report Viewer", role:"viewer", email:"viewer@sheperd.co.uk" },
];
const PRODUCTS = ["BI Pro","DataViz","EduTrack","CRM Suite","Analytics Plus"];
const MOCK_LICENSES = [
{ id:1, license_key:"A1B2-C3D4-E5F6-G7H8", client_name:"Acme Corp", email:"admin@acme.com", product:"BI Pro", issued_date:"2025-01-01", expiry_date:"2026-12-01", is_active:1, max_activations:5, current_activations:3 },
{ id:2, license_key:"X9Y8-Z7W6-V5U4-T3S2", client_name:"Gulf Tech LLC", email:"it@gulftech.sa", product:"DataViz", issued_date:"2025-03-15", expiry_date:"2025-12-31", is_active:1, max_activations:2, current_activations:2 },
{ id:3, license_key:"P1Q2-R3S4-T5U6-V7W8", client_name:"Kerala Schools", email:"admin@keralaschools.in", product:"EduTrack", issued_date:"2024-06-01", expiry_date:"2025-06-01", is_active:0, max_activations:10,current_activations:0 },
{ id:4, license_key:"M1N2-O3P4-Q5R6-S7T8", client_name:"NRI Helpdesk", email:"support@nrihelpdesk.com", product:"BI Pro", issued_date:"2025-07-01", expiry_date:"2026-07-01", is_active:1, max_activations:3, current_activations:1 },
{ id:5, license_key:"D4E5-F6G7-H8I9-J0K1", client_name:"TechStart Ltd", email:"cto@techstart.io", product:"CRM Suite", issued_date:"2025-09-01", expiry_date:"2026-09-01", is_active:1, max_activations:1, current_activations:1 },
];
const genKey = () => { const s=()=>Math.random().toString(36).substring(2,6).toUpperCase(); return `${s()}-${s()}-${s()}-${s()}`; };
const isExpired = d => new Date(d) < new Date();
const daysLeft = d => Math.max(0, Math.ceil((new Date(d)-new Date())/86400000));
const roleColor = r => ({superadmin:{bg:"#312e81",color:"#a5b4fc"},admin:{bg:"#052e16",color:"#4ade80"},viewer:{bg:"#422006",color:"#fb923c"}}[r]||{bg:"#1e293b",color:"#94a3b8"});
const roleIcon = r => ({superadmin:"👑",admin:"🛡️",viewer:"👁️"}[r]||"👤");
const can = (user, perm) => {
const perms = { superadmin:["all"], admin:["license.view","license.create","license.edit","license.delete","license.toggle","report.export"], viewer:["license.view","report.export"] };
const p = perms[user?.role]||[];
return p.includes("all") || p.includes(perm);
};
// ── STATUS BADGE ─────────────────────────────────────────────
function Badge({active, expiry}) {
if (!active) return Inactive;
if (isExpired(expiry)) return Expired;
return Active;
}
// ── TOAST ────────────────────────────────────────────────────
function Toast({toast}) {
if (!toast) return null;
const styles = {success:{bg:"#052e16",color:"#4ade80",border:"1px solid #166534"},error:{bg:"#450a0a",color:"#f87171",border:"1px solid #7f1d1d"},info:{bg:"#0c1445",color:"#818cf8",border:"1px solid #312e81"}};
const s = styles[toast.type]||styles.info;
return
{toast.msg}
;
}
// ════════════════════════════════════════════════════════════
export default function App() {
const [user, setUser] = useState(null);
const [page, setPage] = useState("dashboard");
const [licenses, setLicenses] = useState(MOCK_LICENSES);
const [selected, setSelected] = useState(null);
const [toast, setToast] = useState(null);
// login
const [creds, setCreds] = useState({username:"",password:""});
const [showPass, setShowPass] = useState(false);
const [loginErr, setLoginErr] = useState("");
const [loginLoad, setLoginLoad] = useState(false);
// forgot
const [forgotEmail, setForgotEmail] = useState("");
const [forgotMsg, setForgotMsg] = useState({err:"",suc:""});
// list filters
const [search, setSearch] = useState("");
const [fProd, setFProd] = useState("All");
const [fStatus, setFStatus] = useState("All");
// new license form
const [form, setForm] = useState({client_name:"",email:"",product:"BI Pro",expiry_date:"",max_activations:1,license_key:genKey()});
const [formErr, setFormErr] = useState("");
// sidebar collapse on small
const [sideOpen, setSideOpen] = useState(true);
const showToast = (msg, type="success") => { setToast({msg,type}); setTimeout(()=>setToast(null),3200); };
// ── LOGIN ──
const doLogin = async () => {
setLoginErr("");
if (!creds.username||!creds.password) { setLoginErr("Please enter username and password."); return; }
setLoginLoad(true);
await new Promise(r=>setTimeout(r,1000));
const found = DEMO_USERS.find(u=>u.username===creds.username&&u.password===creds.password);
setLoginLoad(false);
if (!found) { setLoginErr("Invalid username or password."); return; }
setUser(found); setPage("dashboard");
};
const doLogout = () => { setUser(null); setCreds({username:"",password:""}); setPage("dashboard"); showToast("Logged out successfully.","info"); };
// ── FORGOT ──
const doForgot = async () => {
setForgotMsg({err:"",suc:""});
if (!forgotEmail) { setForgotMsg({err:"Enter your email address.",suc:""}); return; }
await new Promise(r=>setTimeout(r,800));
setForgotMsg({err:"",suc:`Reset link sent to ${forgotEmail}.`});
};
// ── LICENSE ACTIONS ──
const toggleLicense = id => { setLicenses(p=>p.map(l=>l.id===id?{...l,is_active:l.is_active?0:1}:l)); showToast("License status updated."); };
const deleteLicense = id => { setLicenses(p=>p.filter(l=>l.id!==id)); setSelected(null); showToast("License deleted.","error"); };
const addLicense = () => {
if (!form.client_name||!form.email||!form.expiry_date) { setFormErr("All fields are required."); return; }
setLicenses(p=>[{...form,id:Date.now(),issued_date:new Date().toISOString().split("T")[0],is_active:1,current_activations:0},...p]);
setForm({client_name:"",email:"",product:"BI Pro",expiry_date:"",max_activations:1,license_key:genKey()});
setFormErr(""); showToast("License created successfully!"); setPage("list");
};
const copyKey = k => { navigator.clipboard?.writeText(k); showToast("Key copied to clipboard!"); };
// ── FILTERED LIST ──
const filtered = licenses.filter(l=>{
const q=search.toLowerCase();
const ms=!q||l.license_key.toLowerCase().includes(q)||l.client_name.toLowerCase().includes(q)||l.email.toLowerCase().includes(q);
const mp=fProd==="All"||l.product===fProd;
const mst=fStatus==="All"||(fStatus==="Active"&&l.is_active&&!isExpired(l.expiry_date))||(fStatus==="Expired"&&isExpired(l.expiry_date))||(fStatus==="Inactive"&&!l.is_active);
return ms&&mp&&mst;
});
const stats = { total:licenses.length, active:licenses.filter(l=>l.is_active&&!isExpired(l.expiry_date)).length, expired:licenses.filter(l=>isExpired(l.expiry_date)).length, inactive:licenses.filter(l=>!l.is_active).length };
// ════ STYLES ═══════════════════════════════════════════════
const S = {
app: {fontFamily:"'Segoe UI',sans-serif",background:"#0f172a",minHeight:"100vh",color:"#e2e8f0"},
card: {background:"#1e293b",border:"1px solid #334155",borderRadius:12,padding:20},
inp: {width:"100%",background:"#0f172a",border:"1.5px solid #334155",color:"#e2e8f0",borderRadius:10,padding:"11px 14px",fontSize:13,outline:"none"},
lbl: {fontSize:11,color:"#94a3b8",marginBottom:5,display:"block",fontWeight:700,letterSpacing:.5},
btnP: {padding:"9px 18px",background:"#6366f1",color:"white",border:"none",borderRadius:8,fontSize:13,fontWeight:600,cursor:"pointer"},
btnG: {padding:"9px 18px",background:"#1e293b",color:"#94a3b8",border:"1px solid #334155",borderRadius:8,fontSize:13,fontWeight:600,cursor:"pointer"},
th: {padding:"10px 14px",textAlign:"left",color:"#64748b",fontSize:11,letterSpacing:.8,textTransform:"uppercase",borderBottom:"1px solid #334155"},
td: {padding:"12px 14px",borderBottom:"1px solid #1e293b",verticalAlign:"middle",fontSize:13},
};
// ════ CSS INJECTION ════════════════════════════════════════
useEffect(()=>{
const style=document.createElement("style");
style.innerHTML=`
*{box-sizing:border-box;margin:0;padding:0}
@keyframes si{from{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}
@keyframes sp{to{transform:rotate(360deg)}}
.spin{width:16px;height:16px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:sp .7s linear infinite;display:inline-block;vertical-align:middle;margin-right:6px}
.inp:focus{border-color:#6366f1!important;box-shadow:0 0 0 3px rgba(99,102,241,.15)}
.btn-main{width:100%;padding:13px;background:linear-gradient(135deg,#6366f1,#8b5cf6);color:white;border:none;border-radius:10px;font-size:15px;font-weight:700;cursor:pointer;transition:opacity .2s}
.btn-main:hover:not(:disabled){opacity:.88}
.btn-main:disabled{opacity:.6;cursor:not-allowed}
.nav-item{padding:10px 14px;border-radius:8px;cursor:pointer;font-size:13px;font-weight:600;color:#94a3b8;display:flex;align-items:center;gap:8px;transition:background .15s}
.nav-item:hover{background:#1e293b;color:#fff}
.nav-item.active{background:#312e81;color:#a5b4fc}
.trow:hover td{background:#1e293b}
.chip{background:#1e1b4b;border:1px solid #3730a3;color:#a5b4fc;padding:5px 12px;border-radius:6px;font-size:11px;cursor:pointer;font-weight:600}
.chip:hover{background:#312e81}
.key-chip{font-family:monospace;font-size:11px;background:#0f172a;border:1px solid #334155;padding:4px 8px;border-radius:6px;letter-spacing:1px;cursor:pointer;white-space:nowrap}
.key-chip:hover{border-color:#6366f1}
.pb{background:#0f172a;border-radius:10px;height:5px;overflow:hidden;margin-top:4px}
.pf{height:100%;border-radius:10px;background:linear-gradient(90deg,#6366f1,#8b5cf6)}
.modal-bg{position:fixed;inset:0;background:rgba(0,0,0,.75);display:flex;align-items:center;justify-content:center;z-index:100}
.modal{background:#1e293b;border:1px solid #334155;border-radius:16px;padding:28px;width:500px;max-width:95vw}
.div-line{display:flex;align-items:center;gap:12px;color:#475569;font-size:12px;margin:18px 0 12px}
.div-line::before,.div-line::after{content:'';flex:1;height:1px;background:#334155}
select{background:#0f172a;border:1.5px solid #334155;color:#e2e8f0;border-radius:10px;padding:11px 14px;font-size:13px;width:100%;outline:none}
select:focus{border-color:#6366f1}
input[type=date]{color-scheme:dark}
.sb-btn:hover{background:#991b1b!important}
`;
document.head.appendChild(style);
return ()=>document.head.removeChild(style);
},[]);
// ════ LOGIN SCREEN ════════════════════════════════════════
if (!user) return (
{page==="login"||page==="dashboard" ? (
🔑
LicenseHQ
Sheperd Limited — Admin Portal
Welcome back 👋
Sign in to manage your licenses
{loginErr &&
⚠️ {loginErr}
}
Quick Demo Login
{DEMO_USERS.map(u=>(
setCreds({username:u.username,password:u.password})}>
{roleIcon(u.role)} {u.username}
))}
Click a chip to auto-fill · Password: Admin@1234
© 2026 Sheperd Limited · All rights reserved
) : (
📧
Reset Password
Enter your email to receive a reset link
{forgotMsg.err &&
⚠️ {forgotMsg.err}
}
{forgotMsg.suc &&
✅ {forgotMsg.suc}
}
{setPage("login");setForgotMsg({err:"",suc:""});}}>← Back to Login
)}
);
// ════ MAIN APP ════════════════════════════════════════════
return (
{/* ── SIDEBAR ── */}
🔑 LicenseHQ
Sheperd Limited
{[
["dashboard","📊","Dashboard"],
["list","📋","All Licenses"],
...(can(user,"license.create")?[["add","➕","New License"]]:[]),
...(can(user,"user.manage")?[["users","👥","Users"]]:[]),
].map(([id,ic,lb])=>(
setPage(id)}>{ic} {lb}
))}
{user.full_name[0]}
{user.full_name}
{roleIcon(user.role)} {user.role}
Session Active
{/* ── CONTENT ── */}
{/* ── DASHBOARD PAGE ── */}
{page==="dashboard" && (
Welcome back, {user.full_name.split(" ")[0]}! 👋
{new Date().toLocaleDateString("en-GB",{weekday:"long",year:"numeric",month:"long",day:"numeric"})} · Logged in as {user.username}
{roleIcon(user.role)} {user.role.toUpperCase()}
{/* Stats */}
{[
{label:"Total Licenses",val:stats.total,icon:"🔑",color:"#6366f1"},
{label:"Active",val:stats.active,icon:"✅",color:"#4ade80"},
{label:"Expired",val:stats.expired,icon:"⏰",color:"#fb923c"},
{label:"Inactive",val:stats.inactive,icon:"🚫",color:"#818cf8"},
].map(s=>(
{s.icon}
{s.val}
{s.label}
))}
{/* Recent licenses */}
📋 Recent Licenses
{["Client","Product","Key","Expires","Status"].map(h=>| {h} | )}
{licenses.slice(0,5).map(l=>(
setSelected(l)}>
{l.client_name} {l.email} |
{l.product} |
{e.stopPropagation();copyKey(l.license_key);}}>{l.license_key} |
{l.expiry_date} {daysLeft(l.expiry_date)}d left |
|
))}
)}
{/* ── LIST PAGE ── */}
{page==="list" && (
All Licenses
{filtered.length} of {licenses.length} licenses
{can(user,"license.create") &&
}
{["Client","Product","License Key","Activations","Expires","Status","Actions"].map(h=>| {h} | )}
{filtered.map(l=>(
{l.client_name} {l.email} |
{l.product} |
copyKey(l.license_key)}>{l.license_key} |
{l.current_activations}/{l.max_activations} |
{l.expiry_date} {daysLeft(l.expiry_date)}d left |
|
{can(user,"license.toggle") && (
)}
|
))}
{filtered.length===0 && | No licenses found. |
}
)}
{/* ── ADD LICENSE PAGE ── */}
{page==="add" && can(user,"license.create") && (
Create New License
Fill in the details to generate a license key
EXPIRY DATE *
{setForm(f=>({...f,expiry_date:e.target.value}));setFormErr("");}}/>
{formErr &&
⚠️ {formErr}
}
)}
{/* ── USERS PAGE ── */}
{page==="users" && can(user,"user.manage") && (
User Management
Admin portal accounts and roles
{["User","Email","Role","Status","Actions"].map(h=>| {h} | )}
{DEMO_USERS.map(u=>(
{u.full_name[0]}
{u.full_name}
@{u.username}
|
{u.email} |
{roleIcon(u.role)} {u.role} |
Active |
{u.username!=="superadmin" && }
|
))}
)}
{/* ── DETAIL MODAL ── */}
{selected && (
setSelected(null)}>
e.stopPropagation()}>
License Details
{selected.license_key}
{[["Client",selected.client_name],["Email",selected.email],["Product",selected.product],["Issued",selected.issued_date],["Expires",`${selected.expiry_date} (${daysLeft(selected.expiry_date)} days left)`],["Activations",`${selected.current_activations} / ${selected.max_activations}`]].map(([k,v])=>(
{k}{v}
))}
Status
{can(user,"license.toggle")||can(user,"license.delete") ? (
{can(user,"license.toggle") && (
)}
{can(user,"license.delete") && (
)}
) :
You have view-only access.
}
)}
);
}