import React, { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { Users, User, Plus, Trash2, Edit2, X, Camera, Save } from 'lucide-react' import { useDialog } from './ModalDialog.tsx' import { resizeImageFile } from '../utils/resizeImageFile.js' import type { PersonData, PersonRole } from '../types/person.js' import { MAX_POOL_CREW_MEMBERS } from '../types/person.js' import { loadPersonPool, savePerson, deletePerson, filterSkippers, filterCrew, type DecryptedPerson } from '../services/personPool.js' import { PlausibleEvents, trackPlausibleEvent } from '../services/analytics.js' const emptyPerson = (role: PersonRole): PersonData => ({ name: '', address: '', birthDate: '', phone: '', nationality: '', passportNumber: '', bloodType: '', allergies: '', diseases: '', role, photo: null }) export default function PersonPoolForm() { const { t } = useTranslation() const { showConfirm } = useDialog() const [people, setPeople] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [showForm, setShowForm] = useState(false) const [editingId, setEditingId] = useState(null) const [formRole, setFormRole] = useState('crew') const [form, setForm] = useState(emptyPerson('crew')) const [saving, setSaving] = useState(false) const [photoError, setPhotoError] = useState(null) const fileRef = React.useRef(null) const reload = useCallback(async () => { setLoading(true) setError(null) try { setPeople(await loadPersonPool()) } catch (err: unknown) { setError(err instanceof Error ? err.message : 'Failed to load') } finally { setLoading(false) } }, []) useEffect(() => { void reload() }, [reload]) const openAdd = (role: PersonRole) => { setEditingId(null) setFormRole(role) setForm(emptyPerson(role)) setPhotoError(null) setShowForm(true) } const openEdit = (person: DecryptedPerson) => { setEditingId(person.payloadId) setFormRole(person.data.role) setForm({ ...person.data }) setPhotoError(null) setShowForm(true) } const handleSave = async (e: React.FormEvent) => { e.preventDefault() if (!form.name.trim()) return setSaving(true) setError(null) try { const id = editingId ?? window.crypto.randomUUID() await savePerson(id, { ...form, role: formRole }, !editingId) setShowForm(false) trackPlausibleEvent(PlausibleEvents.CREW_SAVED, { role: formRole, context: 'person_pool' }) await reload() } catch (err: unknown) { if (err instanceof Error && err.message === 'MAX_CREW') { setError(t('crew.max_crew')) } else { setError(err instanceof Error ? err.message : 'Failed to save') } } finally { setSaving(false) } } const handleDelete = async (id: string) => { if ( !(await showConfirm( t('person_pool.delete_confirm'), t('person_pool.title'), t('logs.confirm_yes'), t('logs.confirm_no') )) ) { return } try { await deletePerson(id) await reload() } catch (err: unknown) { setError(err instanceof Error ? err.message : 'Failed to delete') } } const skippers = filterSkippers(people) const crewList = filterCrew(people) if (loading) { return (

{t('person_pool.loading')}

) } const renderCard = (person: DecryptedPerson) => (
{person.data.photo ? ( ) : (
)}

{person.data.name}

{person.data.phone && (

{t('crew.phone')}: {person.data.phone}

)}
) return (

{t('person_pool.title')}

{t('person_pool.subtitle')}

{error &&
{error}
}

{t('person_pool.skippers_section')}

{!showForm && ( )}
{skippers.length === 0 ? (

{t('person_pool.no_skippers')}

) : (
{skippers.map(renderCard)}
)}

{t('person_pool.crew_section')}

{!showForm && crewList.length < MAX_POOL_CREW_MEMBERS && ( )}
{crewList.length === 0 ? (

{t('person_pool.no_crew')}

) : (
{crewList.map(renderCard)}
)} {showForm && (
void handleSave(e)} className="member-editor-card glass mt-6">

{editingId ? formRole === 'skipper' ? t('person_pool.edit_skipper') : t('crew.edit_crew') : formRole === 'skipper' ? t('person_pool.add_skipper') : t('crew.add_crew')}

fileRef.current?.click()}> {form.photo ? ( ) : (
)}
{ const file = e.target.files?.[0] if (!file) return void resizeImageFile(file) .then((photo) => setForm((f) => ({ ...f, photo }))) .catch((err: unknown) => { setPhotoError(err instanceof Error ? err.message : 'Image error') }) }} /> {photoError &&
{photoError}
}
setForm((f) => ({ ...f, name: e.target.value }))} required />
setForm((f) => ({ ...f, address: e.target.value }))} />
setForm((f) => ({ ...f, birthDate: e.target.value }))} />
setForm((f) => ({ ...f, phone: e.target.value }))} />
setForm((f) => ({ ...f, nationality: e.target.value }))} />
setForm((f) => ({ ...f, passportNumber: e.target.value }))} />
)}
) }