diff --git a/.claude/napkin.md b/.claude/napkin.md new file mode 100644 index 00000000..7d2370cd --- /dev/null +++ b/.claude/napkin.md @@ -0,0 +1,20 @@ +# Napkin + +## Corrections +| Date | Source | What Went Wrong | What To Do Instead | +|------|--------|----------------|-------------------| + +## User Preferences +- Hide navbar on full-screen flow pages (invite, dashboard, admin) via `ConditionalHeader` patterns + remove `page-with-header` class + +## Patterns That Work +- Convex queries can join related data inline (e.g., activity types + categories in one query) +- `conditional-header.tsx` DASHBOARD_LAYOUT_PATTERNS array controls navbar visibility per route + +## Patterns That Don't Work + +## Domain Notes +- Scoring configs have types: distance, duration, count, variant +- `page-with-header` CSS class = `pt-16` to offset fixed navbar +- Seed data lives in `packages/backend/actions/seed.ts` +- Schema changes auto-deploy locally via `pnpm dev` diff --git a/apps/web/app/challenges/[id]/admin/emails/page.tsx b/apps/web/app/challenges/[id]/admin/emails/page.tsx index 6dfa175a..0b743bbf 100644 --- a/apps/web/app/challenges/[id]/admin/emails/page.tsx +++ b/apps/web/app/challenges/[id]/admin/emails/page.tsx @@ -9,6 +9,8 @@ import { CheckCircle, Clock, Edit2, + Eye, + Layers, Mail, Plus, Save, @@ -95,10 +97,13 @@ const triggerInfo: Record< }, }; +type ViewMode = "sequences" | "template"; + export default function EmailsAdminPage() { const params = useParams(); const challengeId = params.id as string; + const [viewMode, setViewMode] = useState("sequences"); const [selectedEmailId, setSelectedEmailId] = useState(null); const [isCreateOpen, setIsCreateOpen] = useState(false); const [isEditing, setIsEditing] = useState(false); @@ -123,6 +128,8 @@ export default function EmailsAdminPage() { challengeId: challengeId as Id<"challenges">, }); + const templatePreview = useQuery(api.queries.emailSequences.getEmailTemplatePreview); + const selectedEmail = useQuery( api.queries.emailSequences.getById, selectedEmailId ? { emailSequenceId: selectedEmailId as Id<"emailSequences"> } : "skip" @@ -261,7 +268,130 @@ export default function EmailsAdminPage() { } return ( -
+
+ {/* View Mode Toggle */} +
+ + +
+ + {/* Template Preview Mode */} + {viewMode === "template" ? ( +
+ {/* Info Panel */} +
+
+
+
+ +
+
+

Base Email Template

+

Used across all transactional emails

+
+
+

+ This is the shared email template that wraps all transactional emails sent from March Fitness, including invite emails, welcome emails, and weekly recaps. +

+
+ +
+

+ Template Components +

+
+
+
Brand Header
+
Wordmark + indigo-fuchsia gradient divider
+
+
+
Dark Card
+
Title, subtitle, content, callouts, and CTA buttons
+
+
+
Footer
+
Context line + march.fit wordmark link
+
+
+
+ +
+

+ Used In +

+
+ {[ + { name: "Invite Emails", desc: "Sent when users invite friends" }, + { name: "Welcome Email", desc: "Auto-sent on challenge signup" }, + { name: "Weekly Recaps", desc: "Sent after each week" }, + { name: "Challenge Complete", desc: "Sent when challenge ends" }, + ].map((item) => ( +
+ +
+
{item.name}
+
{item.desc}
+
+
+ ))} +
+
+
+ + {/* Template Preview */} +
+
+
+

Template Preview

+ + Active + +
+
+ All emails use this layout +
+
+
+ {templatePreview ? ( +