From b708c8c1f8788932d5a31ff848b08f6cb84528db Mon Sep 17 00:00:00 2001 From: Harvmaster Date: Mon, 27 Apr 2026 12:46:52 +0000 Subject: [PATCH] Fix invitation import reactivity and focus imported invitation --- .../screens/invitations/InvitationScreen.tsx | 25 +++++++++++++++++-- .../InvitationImportFlow.tsx | 2 +- .../invitations/invitation-import/types.ts | 8 ++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/tui/screens/invitations/InvitationScreen.tsx b/src/tui/screens/invitations/InvitationScreen.tsx index b78fde8..7ebaeca 100644 --- a/src/tui/screens/invitations/InvitationScreen.tsx +++ b/src/tui/screens/invitations/InvitationScreen.tsx @@ -102,6 +102,7 @@ export function InvitationScreen(): React.ReactElement { // Two phases: first the ID input dialog, then the multi-step import flow. const [showIdDialog, setShowIdDialog] = useState(false); const [importingId, setImportingId] = useState(null); + const [pendingImportedInvitationId, setPendingImportedInvitationId] = useState(null); // ── Template cache ─────────────────────────────────────────────────────── const [templateCache, setTemplateCache] = useState>(new Map()); @@ -161,7 +162,7 @@ export function InvitationScreen(): React.ReactElement { }); return [importItem, ...invitationItems]; - }, [invitations, templateCache]); + }, [invitations.length, templateCache]); const selectedItem = listItems[selectedIndex]; const selectedInvitation = selectedItem?.value ?? null; @@ -196,10 +197,30 @@ export function InvitationScreen(): React.ReactElement { /** * Import flow closed (completed or cancelled). */ - const handleImportFlowClose = useCallback(() => { + const handleImportFlowClose = useCallback((importedInvitationId?: string) => { + if (importedInvitationId) { + setPendingImportedInvitationId(importedInvitationId); + } setImportingId(null); }, []); + /** + * Once imported invitation is visible in the list, select and focus it. + */ + useEffect(() => { + if (!pendingImportedInvitationId) return; + + const importedIndex = listItems.findIndex((item) => { + return item.value?.data.invitationIdentifier === pendingImportedInvitationId; + }); + + if (importedIndex >= 0) { + setSelectedIndex(importedIndex); + setFocusedPanel('list'); + setPendingImportedInvitationId(null); + } + }, [pendingImportedInvitationId, listItems]); + // ── Action handlers ──────────────────────────────────────────────────── const acceptInvitation = useCallback(async () => { diff --git a/src/tui/screens/invitations/invitation-import/InvitationImportFlow.tsx b/src/tui/screens/invitations/invitation-import/InvitationImportFlow.tsx index ff87687..b0ac7e5 100644 --- a/src/tui/screens/invitations/invitation-import/InvitationImportFlow.tsx +++ b/src/tui/screens/invitations/invitation-import/InvitationImportFlow.tsx @@ -148,7 +148,7 @@ export function InvitationImportFlow({ `Action: ${invitation?.data.actionIdentifier ?? 'Unknown'}` ); setStatus('Ready'); - onClose(); + onClose(invitation?.data.invitationIdentifier); }, [selectedRole, template, invitation, showInfo, setStatus, onClose]); // ── Keyboard handling ──────────────────────────────────────────────────── diff --git a/src/tui/screens/invitations/invitation-import/types.ts b/src/tui/screens/invitations/invitation-import/types.ts index e14a5f7..626c44e 100644 --- a/src/tui/screens/invitations/invitation-import/types.ts +++ b/src/tui/screens/invitations/invitation-import/types.ts @@ -116,8 +116,12 @@ export interface ImportFlowProps { mode: ImportFlowMode; /** The application service — injected, not pulled from context. */ appService: AppService; - /** Called when the flow completes or is cancelled. */ - onClose: () => void; + /** + * Called when the flow completes or is cancelled. + * When import succeeds, the invitation identifier is provided so callers can + * select/focus the imported invitation in their UI. + */ + onClose: (importedInvitationId?: string) => void; /** Display an error message to the user. */ showError: (message: string) => void; /** Display an info message to the user. */