import { useEffect, useRef, useState, type ReactNode } from 'react'; import { opportunityErrorGroup, opportunityMissingGroups, type FillGroup, } from '@/lib/opportunity-fill-flow'; export default function OpportunityFillFlow({ groups, errors, renderField, onOpenResources, missingPaths = [], }: { groups: FillGroup[]; errors: Record; renderField: (field: string) => ReactNode; onOpenResources?: (group: string) => void; missingPaths?: string[]; }) { const [active, setActive] = useState(groups[0]?.id ?? ''); const groupIds = groups.map((group) => group.id).join(','); useEffect(() => { const saved = window.location.hash.replace('#fill-', ''); if (groupIds.split(',').includes(saved)) setActive(saved); }, [groupIds]); const heading = useRef(null); const errorGroup = opportunityErrorGroup(groups, errors); const missing = opportunityMissingGroups(groups, missingPaths); const errorKey = JSON.stringify(errors); useEffect(() => { if (errorGroup) setActive(errorGroup); }, [errorGroup, errorKey]); const index = Math.max( 0, groups.findIndex((group) => group.id === active), ); const current = groups[index]; if (!current) return null; const go = (id: string) => { setActive(id); window.history.replaceState(window.history.state, '', `#fill-${id}`); requestAnimationFrame(() => heading.current?.focus()); }; return (

Pode escolher qualquer grupo, guardar incompleto e retomar. As informações já preenchidas mantêm-se ao avançar e regressar.

{missing.length > 0 && (

Pendências da última gravação:{' '} {missing.map((group) => group.title).join(' · ')}. Guarde para actualizar esta indicação.

)}

{current.title}

{current.hint}

{groups.map((group) => ( ))}
Grupo {index + 1} de {groups.length} · navegação livre
{index > 0 && ( { event.preventDefault(); go(groups[index - 1].id); }} > Anterior )} {index < groups.length - 1 && ( { event.preventDefault(); go(groups[index + 1].id); }} > Continuar: {groups[index + 1].title} )}
); }