import { useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { Users, User, Save, Check } from 'lucide-react' import type { LogbookCrewSelectionData, PersonSnapshot } from '../types/person.js' import type { DecryptedPerson } from '../services/personPool.js' import { loadPersonPool, filterSkippers, filterCrew } from '../services/personPool.js' import { loadLogbookCrewSelection, saveLogbookCrewSelectionFromIds } from '../services/logbookCrewSelection.js' import { PlausibleEvents, trackPlausibleEvent } from '../services/analytics.js' export interface LogbookCrewPickerProps { logbookId: string readOnly?: boolean /** Demo / share: in-memory pool */ preloadedPool?: Array<{ payloadId: string; data: DecryptedPerson['data'] }> preloadedSelection?: LogbookCrewSelectionData /** Shared logbook: only people from selection snapshots */ selectionOnly?: boolean } function snapshotsToPoolList( selection: LogbookCrewSelectionData ): Array<{ payloadId: string; data: DecryptedPerson['data'] }> { return Object.values(selection.snapshotsById).map((snap) => ({ payloadId: snap.id, data: { name: snap.name, address: snap.address, birthDate: snap.birthDate, phone: snap.phone, nationality: snap.nationality, passportNumber: snap.passportNumber, bloodType: snap.bloodType, allergies: snap.allergies, diseases: snap.diseases, role: snap.role, photo: snap.photo } })) } export default function LogbookCrewPicker({ logbookId, readOnly = false, preloadedPool, preloadedSelection, selectionOnly = false }: LogbookCrewPickerProps) { const { t } = useTranslation() const [loading, setLoading] = useState(!preloadedSelection) const [saving, setSaving] = useState(false) const [saved, setSaved] = useState(false) const [error, setError] = useState(null) const [pool, setPool] = useState([]) const [activeSkipperId, setActiveSkipperId] = useState(null) const [activeCrewIds, setActiveCrewIds] = useState([]) const loadData = useCallback(async () => { setLoading(true) setError(null) try { const selection = preloadedSelection ?? (logbookId === 'demo' ? null : await loadLogbookCrewSelection(logbookId)) if (selection) { setActiveSkipperId(selection.activeSkipperId) setActiveCrewIds([...selection.activeCrewIds]) } if (preloadedPool) { setPool( preloadedPool.map((p) => ({ payloadId: p.payloadId, data: p.data })) ) } else if (selectionOnly && selection) { setPool(snapshotsToPoolList(selection)) } else { setPool(await loadPersonPool()) } } catch (err: unknown) { setError(err instanceof Error ? err.message : 'Failed to load crew selection') } finally { setLoading(false) } }, [logbookId, preloadedPool, preloadedSelection, selectionOnly]) useEffect(() => { void loadData() }, [loadData]) const skippers = useMemo(() => filterSkippers(pool), [pool]) const crewMembers = useMemo(() => filterCrew(pool), [pool]) const toggleCrew = (id: string) => { if (readOnly) return setActiveCrewIds((prev) => prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id] ) } const handleSave = async () => { if (readOnly || logbookId === 'demo') return setSaving(true) setError(null) setSaved(false) try { await saveLogbookCrewSelectionFromIds(logbookId, activeSkipperId, activeCrewIds) setSaved(true) trackPlausibleEvent(PlausibleEvents.CREW_SAVED, { context: 'logbook_selection' }) setTimeout(() => setSaved(false), 3000) } catch (err: unknown) { setError(err instanceof Error ? err.message : 'Failed to save') } finally { setSaving(false) } } if (loading) { return (

{t('person_pool.loading')}

) } return (

{t('logbook_crew.title')}

{t('logbook_crew.subtitle')}

{selectionOnly &&

{t('logbook_crew.selection_only_hint')}

} {error &&
{error}
}
{skippers.length === 0 ? (

{t('logbook_crew.no_skippers_in_pool')}

) : (
{skippers.map((s) => ( ))} {!readOnly && ( )}
)}
{crewMembers.length === 0 ? (

{t('logbook_crew.no_crew_in_pool')}

) : (
{crewMembers.map((c) => ( ))}
)}
{!readOnly && logbookId !== 'demo' && (
{saved && (
{t('logbook_crew.saved')}
)}
)}
) } export function selectionFromSnapshots( snapshotsById: Record ): LogbookCrewSelectionData { const snapshots = Object.values(snapshotsById) const skipper = snapshots.find((s) => s.role === 'skipper') return { activeSkipperId: skipper?.id ?? null, activeCrewIds: snapshots.filter((s) => s.role === 'crew').map((s) => s.id), snapshotsById } }