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>
This commit is contained in:
@@ -5,12 +5,22 @@ import { createEvents, type EventAttributes } from "ics";
|
||||
import type { PeriodLog } from "@/types";
|
||||
import { getCycleDay, getPhase, PHASE_CONFIGS } from "./cycle";
|
||||
|
||||
// Phase emojis per calendar.md spec
|
||||
const PHASE_EMOJIS: Record<string, string> = {
|
||||
MENSTRUAL: "🔵",
|
||||
FOLLICULAR: "🟢",
|
||||
OVULATION: "🟣",
|
||||
EARLY_LUTEAL: "🟡",
|
||||
LATE_LUTEAL: "🔴",
|
||||
MENSTRUAL: "🩸",
|
||||
FOLLICULAR: "🌱",
|
||||
OVULATION: "🌸",
|
||||
EARLY_LUTEAL: "🌙",
|
||||
LATE_LUTEAL: "🌑",
|
||||
};
|
||||
|
||||
// Phase color categories per calendar.md spec for calendar app color coding
|
||||
const PHASE_CATEGORIES: Record<string, string> = {
|
||||
MENSTRUAL: "Red",
|
||||
FOLLICULAR: "Green",
|
||||
OVULATION: "Pink",
|
||||
EARLY_LUTEAL: "Yellow",
|
||||
LATE_LUTEAL: "Orange",
|
||||
};
|
||||
|
||||
interface IcsGeneratorOptions {
|
||||
@@ -35,12 +45,13 @@ export function generateIcsFeed(options: IcsGeneratorOptions): string {
|
||||
const currentDate = new Date(lastPeriodDate);
|
||||
let currentPhase = getPhase(
|
||||
getCycleDay(lastPeriodDate, cycleLength, currentDate),
|
||||
cycleLength,
|
||||
);
|
||||
let phaseStartDate = new Date(currentDate);
|
||||
|
||||
while (currentDate <= endDate) {
|
||||
const cycleDay = getCycleDay(lastPeriodDate, cycleLength, currentDate);
|
||||
const phase = getPhase(cycleDay);
|
||||
const phase = getPhase(cycleDay, cycleLength);
|
||||
|
||||
// Add warning events
|
||||
if (cycleDay === 22) {
|
||||
@@ -107,7 +118,7 @@ export function generateIcsFeed(options: IcsGeneratorOptions): string {
|
||||
events.push({
|
||||
start: dateToArray(predicted),
|
||||
end: dateToArray(predictedEnd),
|
||||
title: "🔵 MENSTRUAL (Predicted)",
|
||||
title: "🩸 MENSTRUAL (Predicted)",
|
||||
description,
|
||||
});
|
||||
}
|
||||
@@ -127,12 +138,14 @@ function createPhaseEvent(
|
||||
): EventAttributes {
|
||||
const config = PHASE_CONFIGS.find((c) => c.name === phase);
|
||||
const emoji = PHASE_EMOJIS[phase] || "📅";
|
||||
const category = PHASE_CATEGORIES[phase];
|
||||
|
||||
return {
|
||||
start: dateToArray(startDate),
|
||||
end: dateToArray(endDate),
|
||||
title: `${emoji} ${phase.replace("_", " ")}`,
|
||||
description: config?.trainingType || "",
|
||||
categories: category ? [category] : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user