// Member login + Federation admin password reset / forgot-password flow. function LoginPage() { const { go } = CTSCShell.useNav(); const { data, actions } = CTSCStore.useStore(); const [role, setRole] = React.useState('federation'); const [fedId, setFedId] = React.useState(data.federations[0].id); // mode: signin | forgot | sent | reset | done const [mode, setMode] = React.useState('signin'); const [resetFedId, setResetFedId] = React.useState(data.federations[0].id); const [email, setEmail] = React.useState(''); const [pw, setPw] = React.useState(''); const [pw2, setPw2] = React.useState(''); const [signinPw, setSigninPw] = React.useState('demo1234'); const [err, setErr] = React.useState(''); const fedEmail = (f) => f.secretaryEmail || f.presidentEmail || ('admin@' + (f.abbr || 'fed').toLowerCase().replace(/[^a-z0-9]/g, '') + '.org.za'); const submit = () => { if (role === 'council') actions.login({ role: 'council', name: 'Council Administrator', fedId: null }); else { const f = data.federations.find(x => x.id === fedId); const contact = f.president || f.secretary || 'Administrator'; actions.login({ role: 'federation', name: contact + ' · ' + f.name, fedId }); } go('admin'); }; // start forgot flow — prefill the federation currently selected on the sign-in form const startForgot = () => { const f = data.federations.find(x => x.id === fedId) || data.federations[0]; setResetFedId(f.id); setEmail(fedEmail(f)); setErr(''); setMode('forgot'); }; const sendLink = () => { if (!email.trim() || !/^\S+@\S+\.\S+$/.test(email.trim())) { setErr('Enter a valid email address.'); return; } setErr(''); setMode('sent'); }; const savePassword = () => { if (pw.length < 8) { setErr('Password must be at least 8 characters.'); return; } if (pw !== pw2) { setErr('Passwords do not match.'); return; } actions.setPassword(resetFedId, pw); setSigninPw(pw); setErr(''); setMode('done'); }; const backToSignin = () => { setRole('federation'); setFedId(resetFedId); setPw(''); setPw2(''); setErr(''); setMode('signin'); }; const resetFed = data.federations.find(x => x.id === resetFedId) || data.federations[0]; const errBox = err ?
{err}
: null; const backLink = ( ); // ---- right-panel content by mode ---- let panel; if (mode === 'signin') { panel = ( <>
{role === 'federation' && (
)}
{role === 'federation' && }
setSigninPw(e.target.value)} />

{role === 'council' ? 'Council admins approve submissions from all federations.' : 'Federation admins manage their own content; submissions go to the council for approval.'}

); } else if (mode === 'forgot') { panel = ( <>

Reset your password

Choose your federation and confirm the email on file — we'll send a secure password-reset link.

{errBox}
setEmail(e.target.value)} placeholder="you@federation.org.za" />
{backLink} ); } else if (mode === 'sent') { panel = ( <>

Check your email

We've sent a password-reset link to {email} for {resetFed.name}. The link expires in 60 minutes.

Didn't get it? Check spam, or resend from the previous step.

Prototype — the emailed link opens the reset form below.

{backLink} ); } else if (mode === 'reset') { const strength = pw.length === 0 ? null : pw.length < 8 ? 'weak' : pw.length < 12 ? 'good' : 'strong'; panel = ( <>

Set a new password

Create a new password for {resetFed.name} ({email}).

{errBox}
setPw(e.target.value)} placeholder="At least 8 characters" />
{strength &&
{strength}
}
setPw2(e.target.value)} placeholder="Re-enter password" />
{backLink} ); } else { // done panel = ( <>

Password updated

The password for {resetFed.name} has been changed. You can now sign in with your new password.

); } return (

Member Portal

Manage your federation's heroes, events, coaching, fundraising, transformation reporting and news — with a council approval workflow.

Prototype — no real password needed.
{panel}
); } window.LoginPage = LoginPage;