Implement GET /api/cycle/current endpoint (P1.3)

Add endpoint returning current cycle day, phase, phase configuration,
and days until next phase. Uses withAuth middleware for authentication.

Response shape:
- cycleDay: current day in menstrual cycle (1-31)
- phase: current phase (MENSTRUAL, FOLLICULAR, OVULATION, EARLY_LUTEAL, LATE_LUTEAL)
- phaseConfig: full configuration including weeklyLimit, trainingType
- daysUntilNextPhase: days remaining in current phase
- cycleLength: user's configured cycle length

Includes 10 tests covering:
- Authentication (401 when not authenticated)
- Validation (400 when no lastPeriodDate)
- All five cycle phases
- Cycle rollover handling
- Custom cycle lengths

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-10 18:58:04 +00:00
parent 62ad2e3d1a
commit b6285e3c01
3 changed files with 304 additions and 8 deletions

View File

@@ -2,7 +2,66 @@
// ABOUTME: Returns current cycle day, phase, and phase limits.
import { NextResponse } from "next/server";
export async function GET() {
// TODO: Implement current cycle info
return NextResponse.json({ message: "Not implemented" }, { status: 501 });
import { withAuth } from "@/lib/auth-middleware";
import {
getCycleDay,
getPhase,
getPhaseConfig,
PHASE_CONFIGS,
} from "@/lib/cycle";
/**
* 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);
const currentConfig = getPhaseConfig(currentPhase);
// For LATE_LUTEAL, calculate days until new cycle
if (currentPhase === "LATE_LUTEAL") {
return cycleLength - cycleDay + 1;
}
// Find next phase start day
const currentIndex = PHASE_CONFIGS.findIndex((c) => c.name === currentPhase);
const nextConfig = PHASE_CONFIGS[currentIndex + 1];
if (nextConfig) {
return nextConfig.days[0] - cycleDay;
}
// Fallback: days until end of current phase + 1
return currentConfig.days[1] - cycleDay + 1;
}
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);
const phaseConfig = getPhaseConfig(phase);
const daysUntilNextPhase = getDaysUntilNextPhase(cycleDay, user.cycleLength);
return NextResponse.json({
cycleDay,
phase,
phaseConfig,
daysUntilNextPhase,
cycleLength: user.cycleLength,
});
});