Share one date formatter, and stop describing files that are gone

Two components each carried the same four lines turning a date into an ISO
string from local parts. They now share one helper, deliberately separate
from the one that formats in UTC: substituting one for the other shifts the
day by one anywhere east of Greenwich, Sweden included, so a test pins the
difference rather than a comment asking nicely.

Creating a period ran its own copy of the sync-and-report sequence purely so
it could name a wish the lookup could not yet see; it now passes that wish to
the ordinary path instead.

Two comments still explained their relationship to components deleted some
time ago, which would send the next reader looking for files that are not
there, and some styling outlived the markup it described.
This commit is contained in:
2026-09-18 01:12:58 +02:00
parent 9ac67933d4
commit f2b3920cbc
8 changed files with 112 additions and 99 deletions
@@ -13,9 +13,9 @@ export interface SeasonPreset {
}
/**
* The four season quick-picks, copied from `SEASON_PRESETS` in
* `WishEditor.tsx` (PLANNING_ENGINE_SPEC.md §10.7) — deliberately NOT
* imported from there since that component is owned by another task.
* The four season quick-picks (PLANNING_ENGINE_SPEC.md §10.7). This is the
* sole copy of `SEASON_PRESETS` — the `WishEditor.tsx` component it was
* originally copied from has since been deleted.
* Every one of these is a `flexible` wish: the dates below are the bounding
* range the allocator searches within for the best-costing placement, not
* the final dates. A fixed (exact-dates) period is what dragging on the
@@ -1,7 +1,7 @@
import { ReactNode, useMemo } from 'react'
import type { PlannedLeaveDay, CalendarDayEntry } from '@/types'
import { getColorForType, getLabelForType } from '@/utils/leaveTypes'
import { getISOWeekNumber } from '@/utils/dates'
import { getISOWeekNumber, formatDateLocalISO } from '@/utils/dates'
import { useTranslation } from '@/i18n'
import { CalendarDay } from './CalendarDay'
import { CalendarEvent } from './CalendarEvent'
@@ -290,7 +290,7 @@ export function CalendarWeek({
<CalendarDay
date={date}
isCurrentMonth={isCurrentMonth && dayIsCurrentMonth}
isToday={date === getTodayString()}
isToday={date === formatDateLocalISO(new Date())}
isSelected={selectedDates.has(date)}
dayType={calendarInfo?.dayType}
holidayName={calendarInfo?.name ?? null}
@@ -392,11 +392,3 @@ export function CalendarWeek({
</div>
)
}
function getTodayString(): string {
const today = new Date()
const year = today.getFullYear()
const month = String(today.getMonth() + 1).padStart(2, '0')
const day = String(today.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
+14 -16
View File
@@ -1,10 +1,8 @@
/**
* Folds the wished-vs-funded/surplus/balance content that used to live only
* on the Plan tab's `PlanResults.tsx` into Översikt, collapsed below the
* fold. Read `PlanResults.tsx` for the reference implementation; this is a
* separate, trimmed-down component (not a shared import) because
* `PlanResults.tsx` is scheduled for deletion by another task and must not
* be edited here.
* on the Plan tab's `PlanResults.tsx` (since deleted) into Översikt,
* collapsed below the fold. This is now the sole implementation of that
* content — a trimmed-down component, not a shared import.
*
* Read-only. The calendar's `POST /api/plan/sync` (see `Calendar.tsx`) is
* now the only way a plan is written — it proposes and persists in one
@@ -16,14 +14,14 @@
* like a proposal, and `/api/plan/propose` is documented read-only —
* "persists nothing, safe to spam" (`backend/app/routers/plan.py`).
*
* Dropped relative to `PlanResults.tsx` (kept there / on the Plan tab
* instead, to avoid duplicating content the Hero and `Age4Bars` already
* cover): the warnings section, the age4Projections table, and the
* per-window explanation/remedy detail cards. Also dropped, as of the move
* to `/api/plan/sync`: the apply button, collision-confirmation UI, and
* rejection rendering — applying is no longer a thing this fold does (see
* `frontend/src/utils/rejectionMessages.ts` for where rejection rendering
* now lives, for the sync toast in `Calendar.tsx`).
* Dropped relative to the old `PlanResults.tsx` (content not duplicated here
* since the Hero and `Age4Bars` already cover it): the warnings section, the
* age4Projections table, and the per-window explanation/remedy detail cards.
* Also dropped, as of the move to `/api/plan/sync`: the apply button,
* collision-confirmation UI, and rejection rendering — applying is no
* longer a thing this fold does (see `frontend/src/utils/rejectionMessages.ts`
* for where rejection rendering now lives, for the sync toast in
* `Calendar.tsx`).
*/
import { ReactNode, useEffect } from 'react'
import type { PersonalData, SurplusAdvice, WindowOutcome } from '@/types'
@@ -34,9 +32,9 @@ import { resolveWishName } from '@/utils/wishName'
type Translate = (key: TranslationKey, params?: TranslationParams) => string
// §9.2 surplus-advice kinds — mirrors `PlanResults.tsx`'s `SURPLUS_ADVICE_KEYS`/
// `SURPLUS_ADVICE_BODY_KEYS` (the two catalogues are independent copies, not
// a shared import — see the file banner above).
// §9.2 surplus-advice kinds — originally mirrored the deleted `PlanResults.tsx`'s
// `SURPLUS_ADVICE_KEYS`/`SURPLUS_ADVICE_BODY_KEYS`; this is now the sole copy
// (see the file banner above).
const SURPLUS_ADVICE_KEYS: Record<string, TranslationKey> = {
wish_more_leave: 'planResults.surplusAdviceWishMoreLeave',
shift_mix_to_fp: 'planResults.surplusAdviceShiftMixToFp',