Fix spec compliance gaps in email and dashboard
- Email subject now follows spec format: PhaseFlow: [STATUS] - Day [cycleDay] ([phase]) - Daily email includes seed switch alert on day 15 (using getSeedSwitchAlert) - Data panel HRV status now color-coded: green=Balanced, red=Unbalanced, gray=Unknown - Data panel shows progress bar for week intensity vs phase limit with color thresholds Adds 13 new tests (990 total). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,11 +55,11 @@ describe("sendDailyEmail", () => {
|
||||
ketoGuidance: "No - exit keto, need carbs for ovulation",
|
||||
};
|
||||
|
||||
it("sends email with correct subject line", async () => {
|
||||
it("sends email with correct subject line per spec", async () => {
|
||||
await sendDailyEmail(sampleData);
|
||||
expect(mockSend).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
subject: "Today's Training: 💪 TRAIN",
|
||||
subject: "PhaseFlow: 💪 TRAIN - Day 15 (OVULATION)",
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -126,6 +126,23 @@ describe("sendDailyEmail", () => {
|
||||
const call = mockSend.mock.calls[0][0];
|
||||
expect(call.text).toContain("Auto-generated by PhaseFlow");
|
||||
});
|
||||
|
||||
it("includes seed switch alert on day 15", async () => {
|
||||
// sampleData already has cycleDay: 15
|
||||
await sendDailyEmail(sampleData);
|
||||
const call = mockSend.mock.calls[0][0];
|
||||
expect(call.text).toContain("🌱 SWITCH TODAY! Start Sesame + Sunflower");
|
||||
});
|
||||
|
||||
it("does not include seed switch alert on other days", async () => {
|
||||
const day10Data: DailyEmailData = {
|
||||
...sampleData,
|
||||
cycleDay: 10,
|
||||
};
|
||||
await sendDailyEmail(day10Data);
|
||||
const call = mockSend.mock.calls[0][0];
|
||||
expect(call.text).not.toContain("SWITCH TODAY");
|
||||
});
|
||||
});
|
||||
|
||||
describe("sendPeriodConfirmationEmail", () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Resend } from "resend";
|
||||
|
||||
import { logger } from "@/lib/logger";
|
||||
import { emailSentTotal } from "@/lib/metrics";
|
||||
import { getSeedSwitchAlert } from "@/lib/nutrition";
|
||||
|
||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||
|
||||
@@ -33,7 +34,12 @@ export async function sendDailyEmail(
|
||||
data: DailyEmailData,
|
||||
userId?: string,
|
||||
): Promise<void> {
|
||||
const subject = `Today's Training: ${data.decision.icon} ${data.decision.status}`;
|
||||
// Subject format per spec: PhaseFlow: [STATUS] - Day [cycleDay] ([phase])
|
||||
const subject = `PhaseFlow: ${data.decision.icon} ${data.decision.status} - Day ${data.cycleDay} (${data.phase})`;
|
||||
|
||||
// Check for seed switch alert on day 15
|
||||
const seedSwitchAlert = getSeedSwitchAlert(data.cycleDay);
|
||||
const seedSwitchSection = seedSwitchAlert ? `\n\n${seedSwitchAlert}` : "";
|
||||
|
||||
const body = `Good morning!
|
||||
|
||||
@@ -52,7 +58,7 @@ ${data.decision.icon} ${data.decision.reason}
|
||||
🌱 SEEDS: ${data.seeds}
|
||||
|
||||
🍽️ MACROS: ${data.carbRange}
|
||||
🥑 KETO: ${data.ketoGuidance}
|
||||
🥑 KETO: ${data.ketoGuidance}${seedSwitchSection}
|
||||
|
||||
---
|
||||
Auto-generated by PhaseFlow`;
|
||||
|
||||
Reference in New Issue
Block a user