import { useState, useEffect } from 'react'; import { useToast } from '../contexts/ToastContext.jsx'; import { useAuth } from '../contexts/AuthContext.jsx'; import { api } from '../utils/api.js'; export default function AddChildAliasModal({ features = {}, onClose }) { const toast = useToast(); const { user: currentUser } = useAuth(); const loginType = features.loginType || 'guardian_only'; const isMixedAge = loginType === 'mixed_age'; // ── Guardian-only state (alias form) ────────────────────────────────────── const [aliases, setAliases] = useState([]); const [editingAlias, setEditingAlias] = useState(null); const [form, setForm] = useState({ firstName: '', lastName: '', dob: '', phone: '', email: '' }); const [avatarFile, setAvatarFile] = useState(null); const [saving, setSaving] = useState(false); // ── Mixed-age state (real minor users) ──────────────────────────────────── const [minorPlayers, setMinorPlayers] = useState([]); // available + already-mine const [selectedMinorId, setSelectedMinorId] = useState(''); const [addingMinor, setAddingMinor] = useState(false); // ── Partner state (shared) ──────────────────────────────────────────────── const [partner, setPartner] = useState(null); const [selectedPartnerId, setSelectedPartnerId] = useState(''); const [respondSeparately, setRespondSeparately] = useState(false); const [allUsers, setAllUsers] = useState([]); const [savingPartner, setSavingPartner] = useState(false); useEffect(() => { const loads = [api.getPartner(), api.searchUsers('')]; if (isMixedAge) { loads.push(api.getMinorPlayers()); } else { loads.push(api.getAliases()); } Promise.all(loads).then(([partnerRes, usersRes, thirdRes]) => { const p = partnerRes.partner || null; setPartner(p); setSelectedPartnerId(p?.id?.toString() || ''); setRespondSeparately(p?.respond_separately || false); setAllUsers((usersRes.users || []).filter(u => u.id !== currentUser?.id && !u.is_default_admin)); if (isMixedAge) { setMinorPlayers(thirdRes.users || []); } else { setAliases(thirdRes.aliases || []); } }).catch(() => {}); }, [isMixedAge]); // ── Helpers ─────────────────────────────────────────────────────────────── const set = k => e => setForm(p => ({ ...p, [k]: e.target.value })); const resetForm = () => { setEditingAlias(null); setForm({ firstName: '', lastName: '', dob: '', phone: '', email: '' }); setAvatarFile(null); }; const lbl = (text, required) => ( ); // ── Partner handlers ────────────────────────────────────────────────────── const handleSavePartner = async () => { setSavingPartner(true); try { if (!selectedPartnerId) { await api.removePartner(); setPartner(null); setRespondSeparately(false); if (!isMixedAge) { const { aliases: fresh } = await api.getAliases(); setAliases(fresh || []); resetForm(); } else { const { users: fresh } = await api.getMinorPlayers(); setMinorPlayers(fresh || []); } toast('Spouse/Partner/Co-Parent removed', 'success'); } else { const { partner: p } = await api.setPartner(parseInt(selectedPartnerId), respondSeparately); setPartner(p); setRespondSeparately(p?.respond_separately || false); if (!isMixedAge) { const { aliases: fresh } = await api.getAliases(); setAliases(fresh || []); } toast('Spouse/Partner/Co-Parent saved', 'success'); } } catch (e) { toast(e.message, 'error'); } finally { setSavingPartner(false); } }; // ── Guardian-only alias handlers ────────────────────────────────────────── const handleSelectAlias = (a) => { if (editingAlias?.id === a.id) { resetForm(); return; } setEditingAlias(a); setForm({ firstName: a.first_name || '', lastName: a.last_name || '', dob: a.date_of_birth ? a.date_of_birth.slice(0, 10) : '', phone: a.phone || '', email: a.email || '', }); setAvatarFile(null); }; const handleSaveAlias = async () => { if (!form.firstName.trim() || !form.lastName.trim()) return toast('First and last name required', 'error'); setSaving(true); try { if (editingAlias) { await api.updateAlias(editingAlias.id, { firstName: form.firstName.trim(), lastName: form.lastName.trim(), dateOfBirth: form.dob || null, phone: form.phone || null, email: form.email || null, }); if (avatarFile) await api.uploadAliasAvatar(editingAlias.id, avatarFile); toast('Child alias updated', 'success'); } else { const { alias } = await api.createAlias({ firstName: form.firstName.trim(), lastName: form.lastName.trim(), dateOfBirth: form.dob || null, phone: form.phone || null, email: form.email || null, }); if (avatarFile) await api.uploadAliasAvatar(alias.id, avatarFile); toast('Child alias added', 'success'); } const { aliases: fresh } = await api.getAliases(); setAliases(fresh || []); resetForm(); } catch (e) { toast(e.message, 'error'); } finally { setSaving(false); } }; const handleDeleteAlias = async (e, aliasId) => { e.stopPropagation(); try { await api.deleteAlias(aliasId); setAliases(prev => prev.filter(a => a.id !== aliasId)); if (editingAlias?.id === aliasId) resetForm(); toast('Child alias removed', 'success'); } catch (err) { toast(err.message, 'error'); } }; // ── Mixed-age minor handlers ────────────────────────────────────────────── const myMinors = minorPlayers.filter(u => u.guardian_user_id === currentUser?.id); const availableMinors = minorPlayers.filter(u => !u.guardian_user_id); const handleAddMinor = async () => { if (!selectedMinorId) return; setAddingMinor(true); try { await api.addGuardianChild(parseInt(selectedMinorId)); const { users: fresh } = await api.getMinorPlayers(); setMinorPlayers(fresh || []); setSelectedMinorId(''); toast('Child added and account activated', 'success'); } catch (e) { toast(e.message, 'error'); } finally { setAddingMinor(false); } }; const handleRemoveMinor = async (e, minorId) => { e.stopPropagation(); try { await api.removeGuardianChild(minorId); const { users: fresh } = await api.getMinorPlayers(); setMinorPlayers(fresh || []); toast('Child removed', 'success'); } catch (err) { toast(err.message, 'error'); } }; return (
e.target === e.currentTarget && onClose()}>
{/* Header */}

Family Manager

{/* Spouse/Partner/Co-Parent section */}
{lbl('Spouse/Partner/Co-Parent')}
{partner && (
Linked with {partner.display_name || partner.name}
)}
{/* ── Mixed Age: link real minor users ── */} {isMixedAge && ( <> {/* Current children list */} {myMinors.length > 0 && (
Your Children
{myMinors.map((u, i) => (
{u.first_name} {u.last_name} {u.date_of_birth && ( {u.date_of_birth.slice(0, 10)} )}
))}
)} {/* Add minor from players group */}
Add Child
{availableMinors.length === 0 && myMinors.length === 0 && (

No minor players available to link.

)} )} {/* ── Guardian Only: alias form ── */} {!isMixedAge && ( <> {/* Existing aliases list */} {aliases.length > 0 && (
Your Children — click to edit
{aliases.map((a, i) => (
handleSelectAlias(a)} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 12px', cursor: 'pointer', borderBottom: i < aliases.length - 1 ? '1px solid var(--border)' : 'none', background: editingAlias?.id === a.id ? 'var(--primary-light)' : 'transparent', }} > {a.first_name} {a.last_name} {a.date_of_birth && ( {a.date_of_birth.slice(0, 10)} )}
))}
)} {/* Form section label */}
{editingAlias ? `Editing: ${editingAlias.first_name} ${editingAlias.last_name}` : 'Add Child'}
{/* Form */}
{lbl('First Name', true)}
{lbl('Last Name', true)}
{lbl('Date of Birth')}
{lbl('Phone')}
{lbl('Email (optional)')}
{lbl('Avatar (optional)')} setAvatarFile(e.target.files?.[0] || null)} />
{editingAlias && ( )}
)}
); }