Redesign the setup flow and consolidate the CSS into one primitives layer

Onboarding asks explicitly for one or two parents and shows one card per
parent for balances; the balance form is per parent with inline
validation; the partner can be filled from the FK deduction or added
from it. Settings and Dashboard reuse the same form.

CSS: bare buttons carry no colour any more; buttons, cards, choice
cards, fields, alerts, badges, eyebrow and modal chrome are defined once
in primitives.css. Media queries live only in responsive.css. A style
guard test blocks hex, !important and stray media queries. Bilingual
fixes: calendar selects size by content, header no longer wraps. Vitest
is capped at four workers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-19 12:27:29 +02:00
parent e4719cb9ae
commit ae6db7e16f
105 changed files with 5683 additions and 3690 deletions
+3
View File
@@ -53,6 +53,8 @@ export function makeWorkspaceContextValue(
personalDataUuid: parent.uuid,
parentName: parent.name,
refreshContext: vi.fn(),
planVersion: 0,
bumpPlanVersion: vi.fn(),
...overrides,
}
}
@@ -127,6 +129,7 @@ export function makeScraperFetchResult(
cancel: vi.fn(),
isRunning: false,
isTerminal: false,
partnerDeduction: null,
...overrides,
}
}
-1
View File
@@ -29,7 +29,6 @@ export function makeWorkspace(overrides: Partial<Workspace> = {}): Workspace {
return {
id: 'ws-1',
name: 'Familjen Testsson',
planningMode: 'solo',
createdAt: '2026-01-01T00:00:00',
...overrides,
}
+29 -1
View File
@@ -10,7 +10,8 @@
*/
import type { startScraperSession } from '@/services/api'
import type { PollResponse } from '@/hooks/useScraperFetch'
import type { PollResponse, RawPartnerDeduction } from '@/hooks/useScraperFetch'
import type { PartnerDeduction } from '@/types'
export type ScraperSessionStartResponse = Awaited<ReturnType<typeof startScraperSession>>
@@ -35,3 +36,30 @@ export function makeScraperSessionStartResponse(
export function makePollResponse(overrides: Partial<PollResponse> = {}): PollResponse {
return { status: 'launching', ...overrides }
}
/** Raw (snake_case) wire shape of `partner_deduction`, as it arrives nested
* inside a poll response — pair with `makePartnerDeduction` for the
* camelCase value `useScraperFetch` derives from it. */
export function makeRawPartnerDeduction(
overrides: Partial<RawPartnerDeduction> = {},
): RawPartnerDeduction {
return {
total_days: 240,
days_left: 140,
sjukpenning_left: 100,
lagsta_niva_left: 40,
dubbeldagar_left: 20,
...overrides,
}
}
export function makePartnerDeduction(overrides: Partial<PartnerDeduction> = {}): PartnerDeduction {
return {
totalDays: 240,
daysLeft: 140,
sjukpenningLeft: 100,
lagstaNivaLeft: 40,
dubbeldagarLeft: 20,
...overrides,
}
}