Remember last used channel when selected

This commit is contained in:
Jack Kingsman
2026-02-20 17:03:13 -08:00
parent 41bf4eb73a
commit f9eb46f2ab
7 changed files with 409 additions and 20 deletions
+65
View File
@@ -137,6 +137,10 @@ vi.mock('../components/ui/sonner', () => ({
}));
import { App } from '../App';
import {
LAST_VIEWED_CONVERSATION_KEY,
REOPEN_LAST_CONVERSATION_KEY,
} from '../utils/lastViewedConversation';
const publicChannel = {
key: '8B3387E9C5CDEA6AC9E5EDBAA115CD72',
@@ -149,6 +153,7 @@ const publicChannel = {
describe('App startup hash resolution', () => {
beforeEach(() => {
vi.clearAllMocks();
localStorage.clear();
window.location.hash = `#contact/${'a'.repeat(64)}/Alice`;
mocks.api.getRadioConfig.mockResolvedValue({
@@ -178,6 +183,7 @@ describe('App startup hash resolution', () => {
afterEach(() => {
window.location.hash = '';
localStorage.clear();
});
it('falls back to Public when contact hash is unresolvable and contacts are empty', async () => {
@@ -189,4 +195,63 @@ describe('App startup hash resolution', () => {
}
});
});
it('restores last viewed channel when hash is empty and reopen preference is enabled', async () => {
const chatChannel = {
key: '11111111111111111111111111111111',
name: 'Ops',
is_hashtag: false,
on_radio: false,
last_read_at: null,
};
window.location.hash = '';
localStorage.setItem(REOPEN_LAST_CONVERSATION_KEY, '1');
localStorage.setItem(
LAST_VIEWED_CONVERSATION_KEY,
JSON.stringify({
type: 'channel',
id: chatChannel.key,
name: chatChannel.name,
})
);
mocks.api.getChannels.mockResolvedValue([publicChannel, chatChannel]);
render(<App />);
await waitFor(() => {
for (const node of screen.getAllByTestId('active-conversation')) {
expect(node).toHaveTextContent(`channel:${chatChannel.key}:${chatChannel.name}`);
}
});
});
it('uses Public channel when hash is empty and reopen preference is disabled', async () => {
const chatChannel = {
key: '11111111111111111111111111111111',
name: 'Ops',
is_hashtag: false,
on_radio: false,
last_read_at: null,
};
window.location.hash = '';
localStorage.setItem(
LAST_VIEWED_CONVERSATION_KEY,
JSON.stringify({
type: 'channel',
id: chatChannel.key,
name: chatChannel.name,
})
);
mocks.api.getChannels.mockResolvedValue([publicChannel, chatChannel]);
render(<App />);
await waitFor(() => {
for (const node of screen.getAllByTestId('active-conversation')) {
expect(node).toHaveTextContent(`channel:${publicChannel.key}:Public`);
}
});
});
});
+30
View File
@@ -11,6 +11,10 @@ import type {
StatisticsResponse,
} from '../types';
import type { SettingsSection } from '../components/SettingsModal';
import {
LAST_VIEWED_CONVERSATION_KEY,
REOPEN_LAST_CONVERSATION_KEY,
} from '../utils/lastViewedConversation';
const baseConfig: RadioConfig = {
public_key: 'aa'.repeat(32),
@@ -128,9 +132,16 @@ function openConnectivitySection() {
fireEvent.click(connectivityToggle);
}
function openDatabaseSection() {
const databaseToggle = screen.getByRole('button', { name: /Database/i });
fireEvent.click(databaseToggle);
}
describe('SettingsModal', () => {
afterEach(() => {
vi.restoreAllMocks();
localStorage.clear();
window.location.hash = '';
});
it('refreshes app settings when opened', async () => {
@@ -291,6 +302,25 @@ describe('SettingsModal', () => {
expect(onClose).not.toHaveBeenCalled();
});
it('stores and clears reopen-last-conversation preference locally', () => {
window.location.hash = '#raw';
renderModal();
openDatabaseSection();
const checkbox = screen.getByLabelText('Reopen to last viewed channel/conversation');
expect(checkbox).not.toBeChecked();
fireEvent.click(checkbox);
expect(localStorage.getItem(REOPEN_LAST_CONVERSATION_KEY)).toBe('1');
expect(localStorage.getItem(LAST_VIEWED_CONVERSATION_KEY)).toContain('"type":"raw"');
fireEvent.click(checkbox);
expect(localStorage.getItem(REOPEN_LAST_CONVERSATION_KEY)).toBeNull();
expect(localStorage.getItem(LAST_VIEWED_CONVERSATION_KEY)).toBeNull();
});
it('renders statistics section with fetched data', async () => {
const mockStats: StatisticsResponse = {
busiest_channels_24h: [