/** * FetchInvitationStep — first step in the import flow. * * Receives an invitation ID, fetches the invitation from the sync server, * resolves its template, and auto-advances once loaded. * Shows a loading spinner while fetching and an error state with retry/cancel. */ import React, { useState, useEffect, useCallback } from 'react'; import { Box, Text } from 'ink'; import { colors } from '../../../../theme.js'; import type { FetchStepProps } from '../types.js'; export function FetchInvitationStep({ invitationId, appService, onComplete, isActive, }: FetchStepProps): React.ReactElement { const [status, setStatus] = useState<'loading' | 'error'>('loading'); const [errorMessage, setErrorMessage] = useState(null); /** * Fetch the invitation and its template, then auto-advance. */ const fetchInvitation = useCallback(async () => { setStatus('loading'); setErrorMessage(null); try { // Create/fetch the invitation instance (fetches from sync server if needed) const invitation = await appService.createInvitation(invitationId); // Resolve the template for display in later steps const template = await appService.engine.getTemplate(invitation.data.templateIdentifier); // Auto-advance — hand the loaded data to the flow controller onComplete(invitation, template ?? null); } catch (error) { const message = error instanceof Error ? error.message : String(error); setErrorMessage(message); setStatus('error'); } }, [invitationId, appService, onComplete]); // Kick off the fetch on mount useEffect(() => { if (isActive) { fetchInvitation(); } }, [isActive, fetchInvitation]); return ( {status === 'loading' && ( Fetching invitation... ID: {invitationId} )} {status === 'error' && ( Failed to fetch invitation {errorMessage} Press Enter to retry or Esc to cancel )} ); }