import { useState, useRef, useEffect } from "react";
/* ─── CONSTANTS ─── */
const ADMIN_U = "VLAD", ADMIN_P = "smart152527";
const COURSES = ["Програмування","Українська мова"];
const CI = {"Програмування":"💻","Українська мова":"📖"};
const SOCIALS = ["Zoom","Google Meet","Skype","Telegram","Viber","WhatsApp"];
const PKG = [{n:1,p:10},{n:2,p:18},{n:5,p:45},{n:8,p:70},{n:10,p:80},{n:15,p:130},{n:25,p:200},{n:40,p:360}];
const PHONE = "+380 95 891 0937";
const uid = () => Math.random().toString(36).slice(2,9);
const now = () => Date.now();
const fdt = t => t ? new Date(t).toLocaleString("uk-UA",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"}) : "—";
const fd = t => t ? new Date(t).toLocaleDateString("uk-UA",{day:"2-digit",month:"2-digit",year:"numeric"}) : "—";
const ft = t => t ? new Date(t).toLocaleTimeString("uk-UA",{hour:"2-digit",minute:"2-digit"}) : "—";
const nl = n => n===1?"урок":n<5?"уроки":"уроків";
const tod = () => new Date().toISOString().split("T")[0];
const fDT = (d,t) => new Date(`${d}T${t}`).getTime();
const toD = t => { const d=new Date(t); return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,"0")}-${String(d.getDate()).padStart(2,"0")}`; };
const toT = t => { const d=new Date(t); return `${String(d.getHours()).padStart(2,"0")}:${String(d.getMinutes()).padStart(2,"0")}`; };
const fileToB64 = file => new Promise(r=>{ const fr=new FileReader(); fr.onload=e=>r(e.target.result); fr.readAsDataURL(file); });
/* ─── COLORS ─── */
const C = {
bg:"#0d1b2a", primary:"#1d72f5", acc:"#38bdf8",
green:"#10b981", red:"#ef4444", yellow:"#f59e0b", purple:"#8b5cf6",
gray:"#64748b", gL:"#e2e8f0", dark:"#0f1c2e", tD:"#1e3a5f", tM:"#475569"
};
/* ─── STYLE HELPERS ─── */
const Btn = (v="primary",ex={}) => ({
padding:"10px 20px",borderRadius:12,border:"none",cursor:"pointer",
fontWeight:700,fontSize:14,fontFamily:"inherit",transition:"all .15s",
...(v==="primary"&&{background:C.primary,color:"#fff",boxShadow:"0 3px 12px rgba(29,114,245,.3)"}),
...(v==="outline"&&{background:"transparent",color:C.primary,border:`2px solid ${C.primary}`}),
...(v==="ghost" &&{background:"rgba(255,255,255,.1)",color:"#fff",border:"1px solid rgba(255,255,255,.2)"}),
...(v==="danger" &&{background:C.red,color:"#fff"}),
...(v==="gray" &&{background:C.gL,color:C.tD}),
...(v==="green" &&{background:C.green,color:"#fff"}),
...(v==="purple" &&{background:C.purple,color:"#fff"}),
...ex
});
const Inp = (ex={}) => ({
width:"100%",padding:"10px 13px",borderRadius:10,border:`2px solid ${C.gL}`,
fontSize:14,outline:"none",boxSizing:"border-box",fontFamily:"inherit",
color:C.tD,background:"#fff",...ex
});
const Card = (ex={}) => ({
background:"#fff",borderRadius:18,padding:18,
boxShadow:"0 2px 18px rgba(0,0,0,.07)",...ex
});
const Label = ({children,mb=6}) => (
{children}
);
/* ─── STAR RATING ─── */
const Stars = ({value,onChange,size=22}) => (
{[1,2,3,4,5].map(n=>(
onChange&&onChange(n)} style={{fontSize:size,cursor:onChange?"pointer":"default",color:n<=value?C.yellow:"#d1d5db",transition:"color .1s"}}>★
))}
);
/* ════════════════════════════════════════
ROOT APP
════════════════════════════════════════ */
export default function App() {
const [screen,setScreen] = useState("landing");
const [curId,setCurId] = useState(null);
const [isAdmin,setIsAdmin] = useState(false);
const [users,setUsers] = useState([]);
const [lsns,setLsns] = useState({}); // {uid:[lesson,...]}
const [chats,setChats] = useState({}); // {uid:[msg,...]}
const addUser = u => setUsers(p=>[...p,u]);
const updUser = (id,patch) => setUsers(p=>p.map(u=>u.id===id?{...u,...patch}:u));
const delUser = id => setUsers(p=>p.filter(u=>u.id!==id));
const getLsns = id => lsns[id]||[];
const setULsns = (id,ls) => setLsns(p=>({...p,[id]:ls}));
const updLsn = (uid,lid,patch) => setLsns(p=>({...p,[uid]:(p[uid]||[]).map(l=>l.id===lid?{...l,...patch}:l)}));
const getMsgs = id => chats[id]||[];
const addMsg = (id,m) => setChats(p=>({...p,[id]:[...(p[id]||[]),m]}));
const doLogin = (u,admin) => { setCurId(u?u.id:null); setIsAdmin(admin); setScreen(admin?"admin":"student"); };
const doLogout = () => { setCurId(null); setIsAdmin(false); setScreen("landing"); };
const ctx = {users,addUser,updUser,delUser,getLsns,setULsns,updLsn,getMsgs,addMsg,doLogin,doLogout};
const curUser = users.find(u=>u.id===curId);
return (
{screen==="landing" &&
setScreen("register")} onLogin={()=>setScreen("login")}/>}
{screen==="register" && setScreen("landing")} onDone={()=>setScreen("login")}/>}
{screen==="login" && setScreen("landing")}/>}
{screen==="student" && curUser && }
{screen==="admin" && }
);
}
/* ════════════════════════════════════════
LANDING
════════════════════════════════════════ */
function Landing({onStart,onLogin}){
return(
VladSmart
Онлайн репетитор · Програмування та Українська мова
Ласкаво просимо 🎓
Перший урок — безкоштовно!
Домашні завдання, чат, гнучкий розклад
{[["💡","1-й урок безкоштовно"],["📅","Гнучкий розклад"],["💬","Чат з фото"],["⭐","Оцінки та відгуки"]].map(([ic,t])=>(
))}
);
}
/* ════════════════════════════════════════
REGISTER (3 steps + extra info)
════════════════════════════════════════ */
function Register({ctx,onBack,onDone}){
const [step,setStep] = useState(1);
const [course,setCourse] = useState("");
const [date,setDate] = useState(""); const [time,setTime] = useState("");
const [name,setName] = useState(""); const [pass,setPass] = useState(""); const [pass2,setPass2] = useState("");
const [phone,setPhone] = useState("");
const [social,setSocial] = useState("");
const [city,setCity] = useState("");
const [comment,setComment] = useState("");
const [err,setErr] = useState("");
const Wrap=({title,ch})=>(
Реєстрація
Крок {step}/3 — {title}
{ch}
);
if(step===1) return
Який курс вас цікавить?
{COURSES.map(c=>(
))}
>}/>;
if(step===2) return
setName(e.target.value)} style={Inp({marginBottom:12})}/>
setPass(e.target.value)} style={Inp({marginBottom:12})}/>
setPass2(e.target.value)} style={Inp({marginBottom:12})}/>
setPhone(e.target.value)} style={Inp({marginBottom:12})}/>
setCity(e.target.value)} style={Inp({marginBottom:12})}/>