feat(dashboard): show the year on trip dates from other years

Trip dates only showed month + day, so trips from other years were ambiguous
(#1323). Dashboard cards and the boarding-pass hero now include the year, and
so does the shared formatDate (planner day headers etc.) — but only when it
isn't the current year, so this year's trips stay compact. Order and
punctuation follow the locale (EN "Sep 10, 2026", DE "10. Sep 2026").
This commit is contained in:
Maurice
2026-06-29 22:25:02 +02:00
committed by Maurice
parent 9dd9057b7b
commit 42b45dcd82
2 changed files with 27 additions and 7 deletions
+22 -6
View File
@@ -37,17 +37,33 @@ const GRADIENTS = [
]
function tripGradient(id: number): string { return GRADIENTS[id % GRADIENTS.length] }
// Day + short month for the boarding pass / cards, e.g. { d: '10', m: 'Sep' }.
function splitDate(dateStr: string | null | undefined, locale: string): { d: string; m: string } | null {
// Day + short month for the boarding pass / cards, plus the year — but only
// when it isn't the current year (this year's trips stay clutter-free), e.g.
// { d: '10', m: 'Sep', y: '' } now vs { …, y: '2024' } for an older trip.
function splitDate(dateStr: string | null | undefined, locale: string): { d: string; m: string; y: string } | null {
if (!dateStr) return null
const date = new Date(dateStr + 'T00:00:00Z')
if (isNaN(date.getTime())) return null // malformed date — render a dash, never crash
const otherYear = date.getUTCFullYear() !== new Date().getUTCFullYear()
return {
d: date.toLocaleDateString(locale, { day: 'numeric', timeZone: 'UTC' }),
m: date.toLocaleDateString(locale, { month: 'short', timeZone: 'UTC' }),
y: otherYear ? date.toLocaleDateString(locale, { year: 'numeric', timeZone: 'UTC' }) : '',
}
}
// Localized date for the cards. The year is included only when it isn't the
// current year, and order/punctuation follow the locale (EN "Sep 10, 2026",
// DE "10. Sep 2026" — vs a plain "Sep 10" this year), never a hard-coded layout.
function fullDate(dateStr: string | null | undefined, locale: string): string | null {
if (!dateStr) return null
const date = new Date(dateStr + 'T00:00:00Z')
if (isNaN(date.getTime())) return null
const opts: Intl.DateTimeFormatOptions = { day: 'numeric', month: 'short', timeZone: 'UTC' }
if (date.getUTCFullYear() !== new Date().getUTCFullYear()) opts.year = 'numeric'
return date.toLocaleDateString(locale, opts)
}
function buddyColor(seed: number): string {
const pairs = [
['#6366f1', '#8b5cf6'], ['#10b981', '#059669'], ['#f59e0b', '#d97706'],
@@ -322,10 +338,10 @@ function BoardingPassHero({ trip, bundle, locale, onOpen, onEdit, onCopy, onArch
<div className="pass-cell dates-combined">
<div className="pass-label">{t('dashboard.hero.tripDates')}</div>
<div className="dates-row">
{start ? <div className="date-block"><div className="date-num mono">{start.d}</div><div className="date-month">{start.m}</div></div>
{start ? <div className="date-block"><div className="date-num mono">{start.d}</div><div className="date-month">{start.m}{start.y ? ` ${start.y}` : ''}</div></div>
: <div className="date-block"><div className="date-num"></div></div>}
<div className="date-arrow"><ArrowRight /></div>
{end ? <div className="date-block"><div className="date-num mono">{end.d}</div><div className="date-month">{end.m}</div></div>
{end ? <div className="date-block"><div className="date-num mono">{end.d}</div><div className="date-month">{end.m}{end.y ? ` ${end.y}` : ''}</div></div>
: <div className="date-block"><div className="date-num"></div></div>}
</div>
</div>
@@ -530,9 +546,9 @@ function TripCard({ trip, locale, onOpen, onEdit, onCopy, onArchive, onDelete }:
<div className="trip-dates">
{start && end ? (
<>
<span className="date-num">{start.m} {start.d}</span>
<span className="date-num">{fullDate(trip.start_date, locale)}</span>
<span className="date-arrow"><ArrowRight size={11} /></span>
<span className="date-num">{end.m} {end.d}</span>
<span className="date-num">{fullDate(trip.end_date, locale)}</span>
</>
) : <span>{t('dashboard.hero.noDates')}</span>}
</div>
+5 -1
View File
@@ -93,11 +93,15 @@ export function formatMoney(
export function formatDate(dateStr: string | null | undefined, locale: string, timeZone?: string): string | null {
if (!dateStr) return null
const date = new Date(dateStr + 'T00:00:00Z')
const opts: Intl.DateTimeFormatOptions = {
weekday: 'short', day: 'numeric', month: 'short',
timeZone: timeZone || 'UTC',
}
return new Date(dateStr + 'T00:00:00Z').toLocaleDateString(locale, opts)
// Show the year only when it isn't the current year, so this year's dates stay
// compact while older/future ones are unambiguous.
if (date.getUTCFullYear() !== new Date().getUTCFullYear()) opts.year = 'numeric'
return date.toLocaleDateString(locale, opts)
}
export function formatTime(timeStr: string | null | undefined, locale: string, timeFormat: string): string {