diff --git a/server/prisma/dev.db b/server/prisma/dev.db index 043723e..147078e 100644 Binary files a/server/prisma/dev.db and b/server/prisma/dev.db differ diff --git a/server/test.db b/server/test.db index 98b1294..f752d40 100644 Binary files a/server/test.db and b/server/test.db differ diff --git a/specs/gymflow-test-plan.md b/specs/gymflow-test-plan.md index 661d0d7..2d176bc 100644 --- a/specs/gymflow-test-plan.md +++ b/specs/gymflow-test-plan.md @@ -333,6 +333,38 @@ Comprehensive test plan for the GymFlow web application, covering authentication **Expected Results:** - All exercises are created successfully with their respective types. +#### 2.14. A. Workout Plans - Create Plan with AI + +**File:** `tests/workout-management.spec.ts` + +**Steps:** + 1. Log in as a regular user. + 2. Navigate to the 'Plans' section. + 3. Click the '+' FAB button. + 4. Select 'With AI' option. + 5. In the AI Side Sheet, enter a prompt (e.g., 'Create a short leg workout with lunges'). + 6. Click 'Generate'. + 7. Wait for the AI response. + +**Expected Results:** + - A new plan is created and appears in the plans list. + - If 'Lunges' did not exist in the user's exercise library, it is created automatically. + - The plan contains the exercises described in the prompt. + +#### 2.15. B. Tracker - Empty State AI Prompt + +**File:** `tests/workout-management.spec.ts` + +**Steps:** + 1. Log in as a regular user with no existing plans. + 2. Navigate to the 'Tracker' section (Idle View). + 3. Verify the placeholder message "No workout plans yet." is displayed. + 4. Click the "Ask your AI coach to create one" link. + +**Expected Results:** + - User is navigated to the Plans view. + - The AI Side Sheet is automatically opened. + ### 3. III. Workout Tracking **Seed:** `tests/workout-tracking.spec.ts` diff --git a/specs/requirements.md b/specs/requirements.md index 1916058..663d853 100644 --- a/specs/requirements.md +++ b/specs/requirements.md @@ -64,6 +64,23 @@ Users can structure their training via Plans. * **Logic**: Supports reordering capabilities via drag-and-drop in UI. * **3.2.2 Plan Deletion** * Standard soft or hard delete (Cascades to PlanExercises). +* **3.2.3 AI Plan Creation** + * **Trigger**: "Create with AI" option in Plans FAB Menu, or "Ask your AI coach" link from Tracker (when no plans exist). + * **UI Flow**: + * Opens a dedicated Side Sheet in the Plans view. + * User enters a text prompt describing desired workout (e.g., "Create a 20-minute HIIT workout"). + * "Generate" button initiates AI call. + * **AI Logic**: + * System sends prompt to AI service (`geminiService`). + * AI returns a structured JSON object containing: `name`, `description`, and `exercises` array. + * Each exercise object contains: `name`, `isWeighted` (boolean), `restTimeSeconds` (number). + * For **new exercises** (not in user's library), AI also provides: `type` ('reps' or 'time'), `unilateral` (boolean). + * **Auto-Creation of Exercises**: + * System parses AI response. + * For each exercise in the response, checks if it exists in the user's exercise library by name. + * If not found, creates a new `Exercise` record with AI-provided attributes (type, unilateral flag) via `saveExercise`. + * Links the new/existing exercise ID to the plan step. + * **Result**: Saves the generated `WorkoutPlan` to DB and displays it in the Plans list. ### 3.3. Exercise Library * **3.3.1 Exercise Types** diff --git a/src/components/FilledInput.tsx b/src/components/FilledInput.tsx index 76485ba..dab88f1 100644 --- a/src/components/FilledInput.tsx +++ b/src/components/FilledInput.tsx @@ -26,6 +26,7 @@ const FilledInput: React.FC = ({ multiline = false, rows = 3 }) => { const id = useId(); + const inputRef = React.useRef(null); const handleClear = () => { const syntheticEvent = { @@ -33,6 +34,7 @@ const FilledInput: React.FC = ({ } as React.ChangeEvent; onChange(syntheticEvent); if (onClear) onClear(); + inputRef.current?.focus(); }; return ( @@ -43,6 +45,7 @@ const FilledInput: React.FC = ({ {!multiline ? ( } id={id} type={type} step={step} @@ -59,6 +62,7 @@ const FilledInput: React.FC = ({ /> ) : (