CRITICAL BUG FIX: - Phase boundaries were hardcoded for 31-day cycle, breaking correct phase calculations for users with different cycle lengths (28, 35, etc.) - Added getPhaseBoundaries(cycleLength) function in cycle.ts - Updated getPhase() to accept cycleLength parameter (default 31) - Updated all callers (API routes, components) to pass cycleLength - Added 13 new tests for phase boundaries with 28, 31, and 35-day cycles ICS IMPROVEMENTS: - Fixed emojis to match calendar.md spec: 🩸🌱🌸🌙🌑 - Added CATEGORIES field for calendar app colors per spec: MENSTRUAL=Red, FOLLICULAR=Green, OVULATION=Pink, EARLY_LUTEAL=Yellow, LATE_LUTEAL=Orange - Added 5 new tests for CATEGORIES Updated IMPLEMENTATION_PLAN.md with discovered issues and test counts. 825 tests passing (up from 807) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
73 lines
2.2 KiB
TypeScript
73 lines
2.2 KiB
TypeScript
// ABOUTME: API route for current cycle phase information.
|
|
// ABOUTME: Returns current cycle day, phase, and phase limits.
|
|
import { NextResponse } from "next/server";
|
|
|
|
import { withAuth } from "@/lib/auth-middleware";
|
|
import { getCycleDay, getPhase, getPhaseConfig } from "@/lib/cycle";
|
|
|
|
// Phase boundaries per spec: MENSTRUAL 1-3, FOLLICULAR 4-(cl-16), OVULATION (cl-15)-(cl-14),
|
|
// EARLY_LUTEAL (cl-13)-(cl-7), LATE_LUTEAL (cl-6)-cl
|
|
function getNextPhaseStart(currentPhase: string, cycleLength: number): number {
|
|
switch (currentPhase) {
|
|
case "MENSTRUAL":
|
|
return 4; // FOLLICULAR starts at 4
|
|
case "FOLLICULAR":
|
|
return cycleLength - 15; // OVULATION starts at (cycleLength - 15)
|
|
case "OVULATION":
|
|
return cycleLength - 13; // EARLY_LUTEAL starts at (cycleLength - 13)
|
|
case "EARLY_LUTEAL":
|
|
return cycleLength - 6; // LATE_LUTEAL starts at (cycleLength - 6)
|
|
case "LATE_LUTEAL":
|
|
return 1; // New cycle starts
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculates the number of days until the next phase begins.
|
|
* For LATE_LUTEAL, calculates days until new cycle starts (MENSTRUAL).
|
|
*/
|
|
function getDaysUntilNextPhase(cycleDay: number, cycleLength: number): number {
|
|
const currentPhase = getPhase(cycleDay, cycleLength);
|
|
|
|
// For LATE_LUTEAL, calculate days until new cycle
|
|
if (currentPhase === "LATE_LUTEAL") {
|
|
return cycleLength - cycleDay + 1;
|
|
}
|
|
|
|
const nextPhaseStart = getNextPhaseStart(currentPhase, cycleLength);
|
|
return nextPhaseStart - cycleDay;
|
|
}
|
|
|
|
export const GET = withAuth(async (_request, user) => {
|
|
// Validate user has required cycle data
|
|
if (!user.lastPeriodDate) {
|
|
return NextResponse.json(
|
|
{
|
|
error:
|
|
"User has no lastPeriodDate set. Please log your period start date first.",
|
|
},
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
// Calculate current cycle position
|
|
const cycleDay = getCycleDay(
|
|
user.lastPeriodDate,
|
|
user.cycleLength,
|
|
new Date(),
|
|
);
|
|
const phase = getPhase(cycleDay, user.cycleLength);
|
|
const phaseConfig = getPhaseConfig(phase);
|
|
const daysUntilNextPhase = getDaysUntilNextPhase(cycleDay, user.cycleLength);
|
|
|
|
return NextResponse.json({
|
|
cycleDay,
|
|
phase,
|
|
phaseConfig,
|
|
daysUntilNextPhase,
|
|
cycleLength: user.cycleLength,
|
|
});
|
|
});
|