Files
phaseflow/src/app/api/cycle/current/route.ts
Petru Paler a977934c23 Fix critical bug: cycle phase boundaries now scale with cycle length
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>
2026-01-11 22:39:09 +00:00

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,
});
});