Give a new account a first run, and drop to three tabs

Registering used to land you on a bare form asking for a child, with no hint
what came next. A short wizard now walks through the child, whether you are
planning alone or together, and where the day balances come from: fetched from
Försäkringskassan, entered by hand, or skipped — and if skipped, the figures
carry a badge saying they are estimates until real ones arrive.

Fetching is the first option rather than a hidden one, so the scraper is on by
default and the script that used to force it on no longer needs to.

Planning and Tips lose their tabs. Authoring moved to the calendar and the
figures moved to the overview, so both pages were only a second way to reach
what is already on screen; their routes now redirect rather than dead-end. The
dead translations went with them.

Dates also follow the chosen language now instead of always formatting as
Swedish.
This commit is contained in:
2026-09-17 22:05:54 +02:00
parent 064bcc2b3a
commit a4fce16dd1
40 changed files with 1060 additions and 4986 deletions
+23 -130
View File
@@ -38,6 +38,13 @@ vi.mock('@/components/layout/Layout', () => ({
Layout: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}))
// Dashboard hands off to Onboarding entirely when there are no children yet —
// stub it out so this file only asserts the hand-off happens, not
// Onboarding's own behaviour (covered by Onboarding.test.tsx).
vi.mock('@/pages/Onboarding', () => ({
Onboarding: () => <div data-testid="onboarding-page">Onboarding</div>,
}))
const renderWithRouter = (component: React.ReactElement) => {
return render(<BrowserRouter>{component}</BrowserRouter>)
}
@@ -136,7 +143,7 @@ describe('Dashboard', () => {
expect(screen.getByText(/Laddar/)).toBeInTheDocument()
})
it('shows add child form when no children', () => {
it('hands off to Onboarding when there are no children yet', () => {
vi.mocked(useWorkspace).mockReturnValue(
makeWorkspaceContextValue({
workspace: { id: 'ws-1', name: 'Test Workspace', planningMode: 'solo', createdAt: '2026-01-01' },
@@ -148,8 +155,21 @@ describe('Dashboard', () => {
})
)
renderWithRouter(<Dashboard />)
expect(screen.getByText(/Du har inga barn registrerade ännu/)).toBeInTheDocument()
expect(screen.getByLabelText(/Barnets namn/)).toBeInTheDocument()
expect(screen.getByTestId('onboarding-page')).toBeInTheDocument()
expect(screen.queryByTestId('dashboard')).not.toBeInTheDocument()
})
describe('estimated-figures badge', () => {
it('is hidden once real parental-leave balances have been fetched (the default mock)', () => {
renderWithRouter(<Dashboard />)
expect(screen.queryByTestId('dashboard-estimate-badge')).not.toBeInTheDocument()
})
it('is shown when no parental-leave balance has ever been fetched, labelling the figures as estimates', () => {
vi.mocked(hooks.useParentalLeave).mockReturnValue(makeParentalLeaveResult({ data: null }))
renderWithRouter(<Dashboard />)
expect(screen.getByTestId('dashboard-estimate-badge')).toHaveTextContent('Uppskattat')
})
})
describe('Hero', () => {
@@ -396,133 +416,6 @@ describe('Dashboard', () => {
expect(button).not.toBeDisabled()
})
it('submits add child form with valid data', async () => {
const user = userEvent.setup()
const mockCreateChild = vi.fn().mockResolvedValue({ id: 'c-2', name: 'New Child', birth_date: '2024-01-15' })
const mockRefreshContext = vi.fn().mockResolvedValue(undefined)
vi.mocked(useWorkspace).mockReturnValue(
makeWorkspaceContextValue({
workspace: { id: 'ws-1', name: 'Test Workspace', planningMode: 'solo', createdAt: '2026-01-01' },
workspaceId: 'ws-1',
children: [],
selectedChildId: null,
personalDataUuid: 'pd-1',
parentName: 'Test Parent',
refreshContext: mockRefreshContext,
})
)
const mockApi = await import('@/services/api')
vi.mocked(mockApi.createChild).mockImplementation(mockCreateChild)
renderWithRouter(<Dashboard />)
const nameInput = screen.getByLabelText(/Barnets namn/)
const birthDateInput = screen.getByTestId('birth-date-input')
const submitButton = screen.getByRole('button', { name: /Lägg till barn/ })
await user.type(nameInput, 'Test Child')
await user.type(birthDateInput, '2024-01-15')
await user.click(submitButton)
expect(mockCreateChild).toHaveBeenCalledWith({
workspace_id: 'ws-1',
name: 'Test Child',
birth_date: '2024-01-15',
})
expect(mockRefreshContext).toHaveBeenCalled()
})
it('shows error when add child form submission fails', async () => {
const user = userEvent.setup()
const mockCreateChild = vi.fn().mockRejectedValue(new Error('API error'))
vi.mocked(useWorkspace).mockReturnValue(
makeWorkspaceContextValue({
workspace: { id: 'ws-1', name: 'Test Workspace', planningMode: 'solo', createdAt: '2026-01-01' },
workspaceId: 'ws-1',
children: [],
selectedChildId: null,
personalDataUuid: 'pd-1',
parentName: 'Test Parent',
})
)
const mockApi = await import('@/services/api')
vi.mocked(mockApi.createChild).mockImplementation(mockCreateChild)
renderWithRouter(<Dashboard />)
const nameInput = screen.getByLabelText(/Barnets namn/)
const birthDateInput = screen.getByTestId('birth-date-input')
const submitButton = screen.getByRole('button', { name: /Lägg till barn/ })
await user.type(nameInput, 'Test Child')
await user.type(birthDateInput, '2024-01-15')
await user.click(submitButton)
expect(screen.getByText(/API error/)).toBeInTheDocument()
})
it('disables submit button during form submission', async () => {
const user = userEvent.setup()
const mockCreateChild = vi.fn().mockImplementation(
() => new Promise(resolve => setTimeout(() => resolve({ id: 'c-2' }), 100))
)
vi.mocked(useWorkspace).mockReturnValue(
makeWorkspaceContextValue({
workspace: { id: 'ws-1', name: 'Test Workspace', planningMode: 'solo', createdAt: '2026-01-01' },
workspaceId: 'ws-1',
children: [],
selectedChildId: null,
personalDataUuid: 'pd-1',
parentName: 'Test Parent',
refreshContext: vi.fn().mockResolvedValue(undefined),
})
)
const mockApi = await import('@/services/api')
vi.mocked(mockApi.createChild).mockImplementation(mockCreateChild)
renderWithRouter(<Dashboard />)
const nameInput = screen.getByLabelText(/Barnets namn/)
const birthDateInput = screen.getByTestId('birth-date-input')
const submitButton = screen.getByRole('button', { name: /Lägg till barn/ })
await user.type(nameInput, 'Test Child')
await user.type(birthDateInput, '2024-01-15')
await user.click(submitButton)
expect(submitButton).toBeDisabled()
})
it('validates add child form with workspace check', async () => {
vi.mocked(useWorkspace).mockReturnValue(
makeWorkspaceContextValue({
workspace: null,
children: [],
selectedChildId: null,
})
)
renderWithRouter(<Dashboard />)
const nameInput = screen.getByLabelText(/Barnets namn/)
const birthDateInput = screen.getByTestId('birth-date-input')
const user = userEvent.setup()
await user.type(nameInput, 'Test Child')
await user.type(birthDateInput, '2024-01-15')
const submitButton = screen.getByRole('button', { name: /Lägg till barn/ })
await user.click(submitButton)
expect(screen.getByText(/Fyll i alla fält/)).toBeInTheDocument()
})
it('has manual fetch button enabled when child selected', () => {
renderWithRouter(<Dashboard />)