From c7f0013e57c4117eebe9fd327e5664634b381cc7 Mon Sep 17 00:00:00 2001 From: Davide Scaini Date: Wed, 13 May 2026 01:03:34 +0200 Subject: [PATCH] SegmentCreate: prompt after save instead of immediate redirect; update plan After saving, show "Saved! Add another from this activity?" with two buttons: "Add another" (resets name/handles, keeps map loaded) and "Done" (navigates to /segments/). --- segments-plan.md | 43 +++++++++++++++++ site/src/components/SegmentCreate.svelte | 60 +++++++++++++++++++----- 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/segments-plan.md b/segments-plan.md index 1925094..fc323af 100644 --- a/segments-plan.md +++ b/segments-plan.md @@ -187,3 +187,46 @@ UI-first, so users can start populating the segment collection immediately. Dete 11. `/segments/{id}/` page — segment detail + effort history table 12. Activity detail — show matched segment efforts below stats 13. Athlete page — segments section + +--- + +## Phase 4 Detail + +### New API endpoints + +| Endpoint | Notes | +|---|---| +| `GET /api/segments/{id}` | Single segment metadata | +| `GET /api/activities/{activity_id}/segment_efforts` | Scans user's effort files; returns `[{segment_id, segment_name, elapsed_s, started_at, ...}]` for hits on this activity. Auth required. | +| `GET /api/users/{handle}/segment_summary` | Public. Returns `[{segment: {...}, best_elapsed_s, effort_count}]` — all segments where this user has efforts, best time + count each. | + +### SegmentDetail page (`/segments/{id}/`) + +- Map with segment polyline (reuse MapLibre, same style as `SegmentsView`) +- Metadata row: name, sport, distance, created by +- Effort history table sorted newest-first; columns: Date, Time, Avg speed, Avg HR, Avg power, NP, Δ vs PR + - PR row highlighted; Δ column shows `+N s` / `-N s` in red/green vs best effort +- "Retrigger detection" button with loading state (blocks, shows count when done) +- Auth-gated: effort table only rendered if logged in + +### Activity detail additions + +Below the laps table: if the user is logged in and this activity has any segment effort hits, show a compact block — segment name (linked to `/segments/{id}/`) + elapsed time + Δ vs PR. + +Fetch: `GET /api/activities/{activity_id}/segment_efforts` (gracefully hidden if 401 or empty). + +### Athlete page additions + +New "Segments" tab in `AthleteView.svelte`. Fetches `GET /api/users/{handle}/segment_summary` (public, no auth needed). Shows a table: Segment name (linked), Sport, Distance, Best time, # efforts. Empty state if no efforts yet. + +### Effort time display + +Use compact `m:ss` format (e.g. "5:23") for segment effort tables — add `formatElapsed(s: number): string` to `format.ts`. + +### Post-save UX in SegmentCreate (updated) + +After a successful save, instead of immediately redirecting to `/segments/`, show an inline prompt: +> Segment saved! Add another from this activity? [Yes, add another] [Done] + +- **"Yes, add another"** — clears `segName`, `segSport`; resets handles to full range; keeps the map and activity loaded +- **"Done"** — navigates to `/segments/` diff --git a/site/src/components/SegmentCreate.svelte b/site/src/components/SegmentCreate.svelte index a1edb03..f2040b3 100644 --- a/site/src/components/SegmentCreate.svelte +++ b/site/src/components/SegmentCreate.svelte @@ -29,6 +29,8 @@ let segSport = ''; let saving = false; let saveError = ''; + let justSaved = false; + let lastSavedName = ''; // ── Map ─────────────────────────────────────────────────────────────────── let mapEl: HTMLDivElement; @@ -251,14 +253,29 @@ }), }); const d = await r.json(); - if (r.ok) { window.location.href = `${base}segments/`; } - else { saveError = d.detail ?? 'Failed to save segment'; saving = false; } + if (r.ok) { + lastSavedName = segName.trim(); + justSaved = true; + saving = false; + } else { + saveError = d.detail ?? 'Failed to save segment'; + saving = false; + } } catch { saveError = 'Could not reach server'; saving = false; } } + function addAnother() { + justSaved = false; + segName = ''; + segSport = selectedActivity?.sport ?? ''; + startIdx = 0; + endIdx = maxIdx; + saveError = ''; + } + // ── Helpers ─────────────────────────────────────────────────────────────── function polylineDistance(pts: [number, number][]): number { let d = 0; @@ -406,17 +423,36 @@ - {#if saveError} -

{saveError}

- {/if} + {#if justSaved} +
+

+ ✓ "{lastSavedName}" saved. + Add another segment from this activity? +

+
+ + Done +
+
+ {:else} + {#if saveError} +

{saveError}

+ {/if} - + + {/if} {/if} {/if}