Files
F-r-ldraledigplannerare/frontend/src/utils/constants.ts
T
jacobh2 d5f33e8c7f Tell parents how to save the days expiring at age 4
The dashboard stated the loss and stopped there. With Jacob at 48/48 savable
and 24 days over the cap, and Amelie at 3/48 with 45 days of headroom, those
24 days are not lost at all — transferring them before the 4th birthday saves
every one. The app never said so.

`_rule_age4_pooling_loss` already computed exactly that advice, bounded by the
FK-reported `transferable_days_left`, in finished Swedish and English. It never
ran: `age4_pooling_tip_min_child_age_years` held it back until the child turned
2. The calendar IS the plan, so gate on the plan instead — the noise case is a
newborn with nothing planned, not a young child whose parents have planned in
detail. `age4_pooling_tip_min_planned_days` (20) replaces the age gate.

Both variants drop to `info`. A projection four years out should not read as a
verdict on the user's planning; the hero carries the alarm, this card carries
the advice. The copy now leads with "plans change, this is only a projection"
and closes by pointing at keeping balances up to date, since parents will come
back and record what they actually took.

- Suppress `preserve_for_age_4` whenever `age4_pooling_loss` fires for the same
  child. The pooling tip states the same loss plus the remedy and the correct
  per-parent cap, so emitting both gave two contradictory "you're losing N
  days" figures.
- `preserve_for_age_4` now sends `parent_cap` and its copy interpolates it. It
  claimed "only 96 days can be saved" — false for a two-parent family, where
  the cap is 48 each, as the Age4Bars card two rows below already showed.
- The hero grows a "How to save them" line derived from the tip itself, so the
  two can never disagree on the number. Dismissing the tip retires both.
- "Försäkringskassan" in that line links to FK's BankID login carrying a `goto`
  to Min föräldrapenning — the e-service showing "Dagar ni kan föra över" —
  so the transfer is one click away. `translate()` returns a plain string and
  word order differs between locales, so the anchor's position travels inside
  the template as `{fk}` and the rendered string is split around it.

Verified in the browser: hero, link target, tip severity and the absence of
`preserve_for_age_4`, in both languages and at 390px. Note the demo seed cannot
reach this shape — it gives the surplus parent no FK snapshot at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DXPBfr1v7F71t6QcbHCaaT
2026-09-20 09:51:10 +02:00

63 lines
2.4 KiB
TypeScript

/**
* Swedish parental leave rule constants.
*
* These values mirror backend/app/config.py::LeaveRules and must be kept in sync.
* They are the authoritative source for the domain rules governing föräldrapenning,
* dubbeldagar, age-4 restrictions, and SGI protection.
*
* NOTE: These figures are common-case defaults. Children born before 2014, multiples
* (tvillingtillägg), and single-custody arrangements differ and should become
* configurable when tackled. Update both frontend and backend together.
*
* @see backend/app/config.py#LeaveRules
* @see ARCHITECTURE.md#1
*/
export const LEAVE_RULES = {
// Total föräldrapenning entitlement and tier breakdown
totalDaysPerChild: 480,
sjukpenningDays: 390, // income-based tier
lagstaNivaDays: 90, // flat low-rate tier
// Default joint-custody split (per parent)
daysPerParent: 240,
reservedDaysPerParent: 90, // non-transferable ("reserverade dagar")
// Derived: transferable days per parent (240 - 90)
get transferableDaysPerParent(): number {
return this.daysPerParent - this.reservedDaysPerParent;
},
// Dubbeldagar: both parents taking leave for the same child on the same day
maxDubbeldagar: 60,
dubbeldagarMonthsLimit: 15, // only within the child's first 15 months
// Age-4 rule: max 96 days may be saved after the child's 4th birthday
maxSavableDaysAtAge4: 96,
hardExpiryAgeYears: 12,
// SGI protection and minimum work intensity
sgiProtectedFirstMonths: 12, // protected regardless of days taken
sgiMinDaysPerWeekAfterAge1: 5, // minimum to maintain SGI after age 1
// Default reserve for preschool planning days ("studiedagar") closures
preschoolPlanningDaysPerYear: 6,
// Statutory Swedish vacation days
vacationDaysPerYear: 25,
} as const;
/**
* Försäkringskassan's BankID login page, carrying a `goto` fragment so the
* user lands on the "Min föräldrapenning" e-service after authenticating —
* the page that shows "Dagar ni kan föra över" and where a transfer between
* parents is actually made. Mirrors the URL shapes in
* `backend/app/scrapers/fk_scraper.py` (`LOGIN_URL` / `MIN_FP_URL`); keep in
* sync if FK moves the e-service.
*
* @see backend/app/scrapers/fk_scraper.py#LOGIN_URL
*/
export const FK_TRANSFER_LOGIN_URL =
'https://www.forsakringskassan.se/privatperson/logga-in' +
'#/?goto=%2Fprivatperson%2Fmina-sidor%2Falla-e-tjanster%2Fmin-foraldrapenning';