/* ============================================================
ZENITH — Authentication surfaces
· LoginMain : students & teachers (segmented toggle), root path
· LoginAdmin : separate admin console, reached via #admin
Pure front-end POC — any credentials sign you in.
============================================================ */
function BrandPanel({ lang }) {
const t = (en, si) => tx(lang, en, si);
const ticks = [
t("Sit full A/L papers in a real exam-hall environment", "සැබෑ විභාග ශාලා පරිසරයක පත්ර ලියන්න"),
t("Get a predicted Z-Score with island & district rank", "දිවයින් හා දිස්ත්රික් ශ්රේණිය සමඟ පුරෝකථන Z අගයක්"),
t("Teacher-marked papers, released every Saturday", "ගුරු ලකුණු කළ පත්ර, සෑම සෙනසුරාදාම නිකුත් වේ"),
];
return (
{t("Open Ai Pvt Ltd · institute administrators only", "Open Ai Pvt Ltd · ආයතන පරිපාලකයින්ට පමණි")}
{t("Restricted access. All activity is logged.", "සීමිත ප්රවේශය. සියලු ක්රියාකාරකම් සටහන් වේ.")}
);
}
function AdminField({ label, type = "text", value, onChange, placeholder, icon }) {
return (
);
}
/* ---------- Student signup ----------
Catalog-driven: streams/subjects/provinces/schools come from GET /api/catalog
(admin-enabled entries only). Subjects unlock after a stream is picked and
exactly 3 must be chosen. Creates a REAL student via POST /api/signup. */
function SignupStudent({ lang, setLang, onCreate, onBack, onboarding }) {
const t = (en, si) => tx(lang, en, si);
const [cat, setCat] = useState(null); // catalog payload
const [catErr, setCatErr] = useState(false);
const [busy, setBusy] = useState(false);
const [err, setErr] = useState(null); // bilingual submit error text
const [f, setF] = useState({
name: "", email: "", school: "", schoolOther: "", province: "western",
stream: "", subjects: [], medium: "English", pw: "", confirm: "", terms: true,
});
const set = (k, v) => setF(prev => ({ ...prev, [k]: v }));
const loadCatalog = () => {
setCatErr(false);
window.ZAPI.getCatalog()
.then(c => setCat(c))
.catch(e => { console.error("[islandrank] catalog load failed", e); setCatErr(true); });
};
useEffect(loadCatalog, []);
const streamObj = cat && cat.streams.find(s => s.code === f.stream);
const toggleSubject = code => {
setErr(null);
setF(prev => {
const has = prev.subjects.includes(code);
if (!has && prev.subjects.length >= 3) return prev; // hard cap at 3
return { ...prev, subjects: has ? prev.subjects.filter(c => c !== code) : [...prev.subjects, code] };
});
};
const DETAIL_MSG = {
email_exists: ["This email is already registered.", "මෙම විද්යුත් තැපෑල දැනටමත් ලියාපදිංචියි."],
valid_email_required: ["Enter a valid email address.", "වලංගු විද්යුත් තැපෑලක් ඇතුළත් කරන්න."],
full_name_required: ["Enter your full name.", "ඔබේ සම්පූර්ණ නම ඇතුළත් කරන්න."],
school_required: ["Enter your school name.", "ඔබේ පාසලේ නම ඇතුළත් කරන්න."],
province_unknown: ["Select your province.", "ඔබේ පළාත තෝරන්න."],
stream_disabled_or_unknown: ["This stream is not available.", "මෙම විෂය ධාරාව ලබාගත නොහැක."],
exactly_3_subjects_required: ["Pick exactly 3 subjects.", "විෂයයන් 3ක්ම තෝරන්න."],
subjects_not_available_in_stream: ["One of the subjects is not available in this stream.", "තෝරාගත් විෂයයක් මෙම ධාරාවේ නොමැත."],
};
const submit = async e => {
e.preventDefault();
setErr(null);
if (f.subjects.length !== 3) { setErr(t("Pick exactly 3 subjects.", "විෂයයන් 3ක්ම තෝරන්න.")); return; }
if (!onboarding) {
if (f.pw !== f.confirm) { setErr(t("Passwords do not match.", "මුරපද නොගැලපේ.")); return; }
if (!f.terms) { setErr(t("Please agree to the terms to continue.", "ඉදිරියට යාමට නියමයන්ට එකඟ වන්න.")); return; }
}
setBusy(true);
try {
const profile = { school: f.school, schoolOther: f.schoolOther || null,
province: f.province, stream: f.stream, subjects: f.subjects, medium: f.medium };
if (onboarding) {
await window.ZAPI.completeProfile(profile); // account already exists (via Google)
onCreate();
} else {
const res = await window.ZAPI.signup({ fullName: f.name, email: f.email, password: f.pw, ...profile });
onCreate(res.systemId);
}
} catch (ex) {
const m = DETAIL_MSG[ex.detail];
setErr(m ? t(m[0], m[1]) : t("Registration failed — please try again.", "ලියාපදිංචිය අසාර්ථකයි — නැවත උත්සාහ කරන්න."));
setBusy(false);
}
};
const canSubmit = cat && f.school && (f.school !== "Other" || f.schoolOther.trim()) &&
f.stream && f.subjects.length === 3 && !busy &&
(onboarding || (f.name.trim() && f.email.trim() && f.pw && f.pw === f.confirm && f.terms));
return (
{onboarding ? t("Complete your profile", "ඔබේ පැතිකඩ සම්පූර්ණ කරන්න") : t("Create your account", "ඔබේ ගිණුම සාදන්න")}
{onboarding ? t("Pick your stream and subjects to see the right papers.", "නිවැරදි පත්ර දැකීමට ඔබේ විෂය ධාරාව හා විෂයයන් තෝරන්න.") : t("Register as an A/L student to start sitting papers.", "පත්ර ලිවීම ඇරඹීමට උ.පෙ සිසුවෙකු ලෙස ලියාපදිංචි වන්න.")}