Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ scripts/ # AWS S3 deployment automation
- localStorage key: `"pedalnotes-sections"`; stored as `{ version: 1, data: Record<SectionId, boolean> }`
- On mount: reads stored state, merges defaults for any missing keys, drops unknown keys
- Version mismatch or malformed data falls back to defaults and overwrites stored value
- Default expansion: Core Metrics=open, Reflection=open, Rest Day=open, Activity=open; Fueling/Performance/Recovery=collapsed
- Default expansion: Daily Notes=open, Core Metrics=open, Reflection=open, Rest Day=open, Activity=open; Fueling/Performance/Recovery=collapsed
- `toggleSection(id)`, `setSection(id, open)`, `resetSections()` — writes persist immediately (no debounce)
- `QuotaExceededError` on write is caught; section states still work in memory
- Section states are independent from form draft; clearing the form does not reset section states
- Section IDs: `core-metrics`, `fueling`, `performance-metrics`, `recovery-metrics`, `reflection`, `rest-day`, `activity`
- Visible sections depend on `entryType` — `expandAllOrCollapseAll` only affects currently visible sections
- Section IDs: `daily-notes`, `core-metrics`, `fueling`, `performance-metrics`, `recovery-metrics`, `reflection`, `rest-day`, `activity`
- Visible sections depend on `entryType` — `expandAllOrCollapseAll` only affects currently visible sections; `daily-notes` is included in all three entry type section lists

### Entry Types
Three entry types supported via `entryType` field (default: `cycling`):
Expand Down
2 changes: 2 additions & 0 deletions client/src/hooks/use-section-state.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState } from "react";

export type SectionId =
| "daily-notes"
| "core-metrics"
| "fueling"
| "performance-metrics"
Expand All @@ -10,6 +11,7 @@ export type SectionId =
| "activity";

const ALL_SECTION_IDS: SectionId[] = [
"daily-notes",
"core-metrics",
"fueling",
"performance-metrics",
Expand Down
64 changes: 34 additions & 30 deletions client/src/pages/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
} from "lucide-react";

const SECTION_DEFAULTS: Record<SectionId, boolean> = {
"daily-notes": true,
"core-metrics": true,
"fueling": false,
"performance-metrics": false,
Expand Down Expand Up @@ -70,6 +71,7 @@ const FIELD_TO_SECTION: Partial<Record<keyof InsertWorkout, SectionId>> = {
whatCouldBeImproved: "reflection",
description: "reflection",
weight: "rest-day",
dailyNotes: "daily-notes",
activityGoal: "activity",
activityNotes: "activity",
};
Expand All @@ -87,9 +89,9 @@ const entryTypeSubtitles: Record<EntryType, string> = {
};

const VISIBLE_SECTIONS_BY_TYPE: Record<EntryType, SectionId[]> = {
cycling: ["core-metrics", "fueling", "performance-metrics", "recovery-metrics", "reflection"],
rest: ["recovery-metrics", "rest-day"],
other: ["activity"],
cycling: ["daily-notes", "core-metrics", "fueling", "performance-metrics", "recovery-metrics", "reflection"],
rest: ["daily-notes", "recovery-metrics", "rest-day"],
other: ["daily-notes", "activity"],
};

const rpeOptions = [
Expand Down Expand Up @@ -705,6 +707,35 @@ export default function Home() {
/>
</div>

{/* Daily Notes — all entry types */}
<CollapsibleSection
id="daily-notes"
title="Daily Notes"
isOpen={sectionStates["daily-notes"]}
onOpenChange={(open) => setSection("daily-notes", open)}
hasData={!!watchedValues.dailyNotes}
>
<FormField
control={form.control}
name="dailyNotes"
render={({ field }) => (
<FormItem>
<FormControl>
<Textarea
rows={4}
placeholder="Life context, mood, decisions, stressors... One thought per line."
className="resize-y"
{...field}
value={field.value ?? ""}
/>
</FormControl>
<p className="text-xs text-gray-500">Each line will be formatted as a bullet point</p>
<FormMessage />
</FormItem>
)}
/>
</CollapsibleSection>

{/* Entry Type Selector */}
<div className="bg-gray-50 dark:bg-gray-700 rounded-lg p-4">
<label className="flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white mb-3">
Expand All @@ -731,33 +762,6 @@ export default function Home() {
</div>
</div>

{/* Daily Notes — all entry types */}
<div className="bg-gray-50 dark:bg-gray-700 rounded-lg p-4">
<FormField
control={form.control}
name="dailyNotes"
render={({ field }) => (
<FormItem>
<FormLabel className="flex items-center gap-2">
<NotebookPen className="w-4 h-4 text-blue-600 dark:text-blue-400" />
Daily Notes
</FormLabel>
<FormControl>
<Textarea
rows={4}
placeholder="Life context, mood, decisions, stressors... One thought per line."
className="resize-y"
{...field}
value={field.value ?? ""}
/>
</FormControl>
<p className="text-xs text-gray-500">Each line will be formatted as a bullet point</p>
<FormMessage />
</FormItem>
)}
/>
</div>

{/* Core Metrics Section — Cycling only */}
{entryType === "cycling" && (
<CollapsibleSection
Expand Down
6 changes: 6 additions & 0 deletions client/src/test/hooks/use-section-state.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import { useSectionState, type SectionId } from "@/hooks/use-section-state";
const SECTIONS_KEY = "pedalnotes-sections-test";

const defaults: Record<SectionId, boolean> = {
"daily-notes": true,
"core-metrics": true,
"fueling": false,
"performance-metrics": false,
"recovery-metrics": false,
"reflection": true,
"rest-day": true,
"activity": true,
};

function makeStored(data: Record<SectionId, boolean>, version = 1) {
Expand Down Expand Up @@ -38,11 +41,14 @@ describe("useSectionState", () => {

it("restores persisted state on mount", () => {
const persisted: Record<SectionId, boolean> = {
"daily-notes": false,
"core-metrics": false,
"fueling": true,
"performance-metrics": true,
"recovery-metrics": false,
"reflection": false,
"rest-day": false,
"activity": false,
};
localStorage.setItem(SECTIONS_KEY, makeStored(persisted));

Expand Down
Loading