mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
6d2dd37414
* feat(dashboard): mobile layout, glass tiles, plain-text countdown, place photos - Rework the mobile dashboard: cover hero, separate boarding-pass card, trimmed atlas (trips + days only), stacked widgets - New floating bottom tab bar with a centred context-aware + button (new trip / place / journey / entry depending on the page) - Move profile + notifications into a small top strip on the dashboard - Desktop: glassmorphic tiles (light + dark), neutral dark palette, plain-text countdown module, real place photos in the boarding pass * i18n(dashboard): translate new dashboard keys across all locales Fill the dashboard-rework keys (hero, atlas, fx, tz, upcoming, copy dialog, aria labels, countdown) that were left as English placeholders, plus the new startsIn/aria keys, for all 19 languages. * feat(oidc): send PKCE (S256) in the OIDC login flow The OIDC client now generates a code_verifier per login, sends the S256 code_challenge on the authorize request and the code_verifier on the token exchange. Works whether the provider has PKCE optional or required (fixes login against providers that require PKCE, e.g. Pocket ID).
83 lines
3.1 KiB
TypeScript
83 lines
3.1 KiB
TypeScript
// FE-COMP-BOTTOMNAV-001 to FE-COMP-BOTTOMNAV-006
|
|
|
|
vi.mock('../../api/websocket', () => ({
|
|
connect: vi.fn(),
|
|
disconnect: vi.fn(),
|
|
getSocketId: vi.fn(() => null),
|
|
setRefetchCallback: vi.fn(),
|
|
setPreReconnectHook: vi.fn(),
|
|
addListener: vi.fn(),
|
|
removeListener: vi.fn(),
|
|
}));
|
|
|
|
const mockNavigate = vi.fn();
|
|
vi.mock('react-router-dom', async () => {
|
|
const actual = await vi.importActual<typeof import('react-router-dom')>('react-router-dom');
|
|
return { ...actual, useNavigate: () => mockNavigate };
|
|
});
|
|
|
|
import { render, screen } from '../../../tests/helpers/render';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { useAuthStore } from '../../store/authStore';
|
|
import { useSettingsStore } from '../../store/settingsStore';
|
|
import { useAddonStore } from '../../store/addonStore';
|
|
import { resetAllStores, seedStore } from '../../../tests/helpers/store';
|
|
import { buildUser, buildSettings } from '../../../tests/helpers/factories';
|
|
import BottomNav from './BottomNav';
|
|
|
|
const currentUser = buildUser({ id: 1, username: 'testuser', email: 'test@example.com' });
|
|
|
|
beforeEach(() => {
|
|
resetAllStores();
|
|
mockNavigate.mockClear();
|
|
seedStore(useAuthStore, { user: currentUser, isAuthenticated: true });
|
|
});
|
|
|
|
describe('BottomNav', () => {
|
|
it('FE-COMP-BOTTOMNAV-001: renders without crashing', () => {
|
|
render(<BottomNav />);
|
|
expect(document.body).toBeInTheDocument();
|
|
});
|
|
|
|
it('FE-COMP-BOTTOMNAV-002: shows the dashboard nav item', () => {
|
|
render(<BottomNav />);
|
|
expect(screen.getByText('My Trips')).toBeInTheDocument();
|
|
});
|
|
|
|
it('FE-COMP-BOTTOMNAV-003: centre create button creates a new trip by default', async () => {
|
|
const user = userEvent.setup();
|
|
render(<BottomNav />);
|
|
await user.click(screen.getByRole('button', { name: 'New Trip' }));
|
|
expect(mockNavigate).toHaveBeenCalledWith('/dashboard?create=1');
|
|
});
|
|
|
|
it('FE-COMP-BOTTOMNAV-004: dashboard label translates when language is fr', async () => {
|
|
seedStore(useSettingsStore, { settings: buildSettings({ language: 'fr' }) });
|
|
render(<BottomNav />);
|
|
expect(await screen.findByText('Mes voyages')).toBeInTheDocument();
|
|
});
|
|
|
|
it('FE-COMP-BOTTOMNAV-005: addon labels translate when language is fr', async () => {
|
|
seedStore(useSettingsStore, { settings: buildSettings({ language: 'fr' }) });
|
|
seedStore(useAddonStore, {
|
|
addons: [
|
|
{ id: 'vacay', name: 'Vacay', type: 'global', icon: 'calendar', enabled: true },
|
|
{ id: 'atlas', name: 'Atlas', type: 'global', icon: 'globe', enabled: true },
|
|
{ id: 'journey', name: 'Journey', type: 'global', icon: 'compass', enabled: true },
|
|
],
|
|
});
|
|
render(<BottomNav />);
|
|
expect(await screen.findByText('Vacances')).toBeInTheDocument();
|
|
expect(await screen.findByText('Atlas')).toBeInTheDocument();
|
|
expect(await screen.findByText('Journal de voyage')).toBeInTheDocument();
|
|
});
|
|
|
|
it('FE-COMP-BOTTOMNAV-006: unknown addon id is not rendered', () => {
|
|
seedStore(useAddonStore, {
|
|
addons: [{ id: 'foo', name: 'Foo Addon', type: 'global', icon: 'star', enabled: true }],
|
|
});
|
|
render(<BottomNav />);
|
|
expect(screen.queryByText('Foo Addon')).not.toBeInTheDocument();
|
|
});
|
|
});
|