Phase 2: Build 9 presentational components with full test coverage
New components (all with .tsx + .test.tsx, 90%+ coverage): - CalendarDay: day cell with event badges - CalendarEvent: colored event chip with dismiss option - DaysBreakdown: table of days by type - ProgressChart: progress bar toward age-4 deadline - TipCard: optimization tip card with severity badges - VacationDaysInput: number input with min/max validation - ParentProfileInput: dual selects for salary type & employment status - PlanningGoalSelector: radio buttons for planning goal - BreakPeriodsInput: list manager with inline add/edit form All components follow existing patterns from Header/Footer: - Typed props interfaces (exported) - Semantic HTML with data-testid & ARIA attributes - No business logic, purely presentational - Comprehensive test coverage including edge cases npm test: 22 files, 167 tests passing npx tsc --noEmit: clean Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
export interface CalendarDayProps {
|
||||
date: string
|
||||
events?: { type: string; color: string; title?: string }[]
|
||||
isCurrentMonth?: boolean
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
export function CalendarDay({
|
||||
date,
|
||||
events = [],
|
||||
isCurrentMonth = true,
|
||||
onClick,
|
||||
}: CalendarDayProps): ReactNode {
|
||||
const dayNum = new Date(date + 'T00:00:00Z').getUTCDate()
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="calendar-day"
|
||||
onClick={onClick}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={`${date}${events.length > 0 ? ` with ${events.length} event(s)` : ''}`}
|
||||
className={`calendar-day ${!isCurrentMonth ? 'calendar-day--disabled' : ''} ${events.length > 0 ? 'calendar-day--has-events' : ''}`}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
onClick?.()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="calendar-day__number">{dayNum}</div>
|
||||
{events.length > 0 && (
|
||||
<div className="calendar-day__events" data-testid="calendar-day-events">
|
||||
{events.map((event, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="calendar-day__event"
|
||||
style={{ backgroundColor: event.color }}
|
||||
title={event.title ?? event.type}
|
||||
data-testid={`event-${idx}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user