Files
letter/src/utils/letterTemplate.ts
T
nmemmertandClaude Sonnet 4.6 c446546964 Initial build: personal annual letter + podcast year-end email generator
- Monthly journal: 6 prompts per month, saved to localStorage
- Year-end reflections: 6 closing prompts compiled into a letter
- Podcast module: 9 prompts → ready-to-send listener email with preview tab
- Home dashboard: month grid, progress bar, year-end task checklist
- Letter view: formatted narrative with Copy and Download
- Dockerfile + nginx.conf for containerized deployment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-17 13:06:14 -04:00

81 lines
2.8 KiB
TypeScript

import { MONTH_NAMES } from "../types";
import type { AppData } from "../types";
export function generateLetter(data: AppData, year: number): string {
const name = data.name || "Friend";
const entries = data.monthlyEntries
.filter((e) => e.year === year)
.sort((a, b) => a.month - b.month);
const yearEnd = data.yearEndEntries.find((e) => e.year === year);
const today = new Date();
const dateStr = today.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
let letter = `${year} Annual Letter\n`;
letter += `Written ${dateStr}\n\n`;
letter += `Dear ${name},\n\n`;
if (yearEnd?.answers.word) {
letter += `If ${year} had a single word, it would be: *${yearEnd.answers.word}*.\n\n`;
}
if (entries.length === 0 && !yearEnd) {
letter +=
"This letter is still being written. Return here at the end of the year to read it.\n";
return letter;
}
// Monthly narrative
if (entries.length > 0) {
letter += `Here is what the months held:\n\n`;
for (const entry of entries) {
const monthName = MONTH_NAMES[entry.month];
letter += `**${monthName}**\n`;
const parts: string[] = [];
if (entry.answers.win)
parts.push(`The month's bright spot: ${entry.answers.win}.`);
if (entry.answers.challenge)
parts.push(`You were tested by: ${entry.answers.challenge}.`);
if (entry.answers.learned)
parts.push(`You learned: ${entry.answers.learned}.`);
if (entry.answers.memory)
parts.push(`The moment to hold onto: ${entry.answers.memory}.`);
if (entry.answers.people)
parts.push(`The people in the picture: ${entry.answers.people}.`);
if (entry.answers.forward)
parts.push(`Carrying forward: ${entry.answers.forward}.`);
letter += parts.join("\n") + "\n\n";
}
}
// Year-end reflections
if (yearEnd) {
letter += `**Looking back at the full year:**\n\n`;
if (yearEnd.answers.change)
letter += `The most important thing that changed: ${yearEnd.answers.change}\n\n`;
if (yearEnd.answers.identity)
letter += `What the year taught you about yourself: ${yearEnd.answers.identity}\n\n`;
if (yearEnd.answers.gratitude)
letter += `What you were most grateful for: ${yearEnd.answers.gratitude}\n\n`;
if (yearEnd.answers.release)
letter += `What you're ready to leave behind: ${yearEnd.answers.release}\n\n`;
if (yearEnd.answers.carry)
letter += `What you're carrying forward: ${yearEnd.answers.carry}\n\n`;
}
const completedMonths = entries.length;
if (completedMonths < 12) {
const remaining = 12 - completedMonths;
letter += `*${remaining} month${remaining !== 1 ? "s" : ""} of this year are still being written.*\n\n`;
}
letter += `With love,\n${name} — ${year}`;
return letter;
}