diff --git a/frontend/src/hooks/useConversationRouter.ts b/frontend/src/hooks/useConversationRouter.ts index 5a59c94..b8a4372 100644 --- a/frontend/src/hooks/useConversationRouter.ts +++ b/frontend/src/hooks/useConversationRouter.ts @@ -99,17 +99,10 @@ export function useConversationRouter({ // No hash: optionally restore last-viewed conversation if enabled on this device. if (!hashConv && getReopenLastConversationEnabled()) { const lastViewed = getLastViewedConversation(); - if (lastViewed?.type === 'raw') { - setActiveConversationState(lastViewed); - hasSetDefaultConversation.current = true; - return; - } - if (lastViewed?.type === 'map') { - setActiveConversationState(lastViewed); - hasSetDefaultConversation.current = true; - return; - } - if (lastViewed?.type === 'visualizer') { + if ( + lastViewed && + (lastViewed.type === 'raw' || lastViewed.type === 'map' || lastViewed.type === 'visualizer') + ) { setActiveConversationState(lastViewed); hasSetDefaultConversation.current = true; return; @@ -174,9 +167,9 @@ export function useConversationRouter({ if (lastViewed?.type !== 'contact') return; if (!contactsLoaded) return; - const contact = contacts.find( - (item) => item.public_key.toLowerCase() === lastViewed.id.toLowerCase() - ); + const contact = + contacts.find((item) => item.public_key.toLowerCase() === lastViewed.id.toLowerCase()) || + resolveContactFromHashToken(lastViewed.id, contacts); if (contact) { setActiveConversationState({ type: 'contact', diff --git a/frontend/src/test/appStartupHash.test.tsx b/frontend/src/test/appStartupHash.test.tsx index 51dceba..31863c1 100644 --- a/frontend/src/test/appStartupHash.test.tsx +++ b/frontend/src/test/appStartupHash.test.tsx @@ -256,4 +256,43 @@ describe('App startup hash resolution', () => { }); expect(window.location.hash).toBe(''); }); + + it('restores last viewed contact from legacy name token when hash is empty and reopen is enabled', async () => { + const aliceContact = { + public_key: 'b'.repeat(64), + name: 'Alice', + type: 1, + flags: 0, + last_path: null, + last_path_len: -1, + last_advert: null, + lat: null, + lon: null, + last_seen: null, + on_radio: false, + last_contacted: null, + last_read_at: null, + }; + + window.location.hash = ''; + localStorage.setItem(REOPEN_LAST_CONVERSATION_KEY, '1'); + localStorage.setItem( + LAST_VIEWED_CONVERSATION_KEY, + JSON.stringify({ + type: 'contact', + id: 'Alice', + name: 'Alice', + }) + ); + mocks.api.getContacts.mockResolvedValue([aliceContact]); + + render(); + + await waitFor(() => { + for (const node of screen.getAllByTestId('active-conversation')) { + expect(node).toHaveTextContent(`contact:${aliceContact.public_key}:Alice`); + } + }); + expect(window.location.hash).toBe(''); + }); });