Implement MiniCalendar dashboard widget (P2.14)

Complete the MiniCalendar component with:
- Full calendar grid showing all days of the month
- Phase colors applied to each day
- Today highlighting with ring indicator
- Navigation buttons (prev/next month, Today)
- Compact phase legend
- Integration into dashboard page (shows when lastPeriodDate exists)

Adds 23 new tests for the MiniCalendar component covering:
- Calendar grid rendering
- Phase color application
- Navigation functionality
- Cycle rollover handling
- Custom year/month props

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 08:47:28 +00:00
parent 5a0cdf7450
commit b2915bca9c
5 changed files with 513 additions and 34 deletions

View File

@@ -564,7 +564,8 @@ describe("Dashboard", () => {
render(<Dashboard />);
await waitFor(() => {
expect(screen.getByText(/follicular/i)).toBeInTheDocument();
// Check for phase in the cycle info header (uppercase, with Day X prefix)
expect(screen.getByText(/Day 12 · FOLLICULAR/)).toBeInTheDocument();
});
});
});

View File

@@ -6,6 +6,7 @@ import { useCallback, useEffect, useState } from "react";
import { DataPanel } from "@/components/dashboard/data-panel";
import { DecisionCard } from "@/components/dashboard/decision-card";
import { MiniCalendar } from "@/components/dashboard/mini-calendar";
import { NutritionPanel } from "@/components/dashboard/nutrition-panel";
import { OverrideToggles } from "@/components/dashboard/override-toggles";
import type {
@@ -37,6 +38,8 @@ interface UserData {
id: string;
email: string;
activeOverrides: OverrideType[];
lastPeriodDate: string | null;
cycleLength: number;
}
export default function Dashboard() {
@@ -44,6 +47,16 @@ export default function Dashboard() {
const [userData, setUserData] = useState<UserData | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [calendarYear, setCalendarYear] = useState(new Date().getFullYear());
const [calendarMonth, setCalendarMonth] = useState(new Date().getMonth());
const handleCalendarMonthChange = useCallback(
(year: number, month: number) => {
setCalendarYear(year);
setCalendarMonth(month);
},
[],
);
const fetchTodayData = useCallback(async () => {
const response = await fetch("/api/today");
@@ -194,6 +207,17 @@ export default function Dashboard() {
activeOverrides={userData.activeOverrides}
onToggle={handleOverrideToggle}
/>
{/* Mini Calendar */}
{userData.lastPeriodDate && (
<MiniCalendar
lastPeriodDate={new Date(userData.lastPeriodDate)}
cycleLength={userData.cycleLength}
year={calendarYear}
month={calendarMonth}
onMonthChange={handleCalendarMonthChange}
/>
)}
</div>
)}
</main>