Remove public upload links, sort photos by capture time, cut stale marketing - #36
Conversation
…rketing Three fixes: 1. Remove the last 3 public buttons that linked to /photos (the unauthenticated crew upload page): FollowSection's "Share a photo" button, and PhotoStreamTile's "View all" (now points to #follow instead) and "Share a photo" link. /photos itself is untouched - crews still reach it via their direct link. 2. Sort photos/videos by capturedAt (when taken) instead of upload order everywhere: useMediaPosts sorts once at the source, MediaMarkers' sortNewestFirst() and mediaClusterRenderer's pickThumbnailPost() updated to match. Crews upload with a lag; followers should see trip-timeline order. Every post already has a capturedAt value, so this reorders all previously-uploaded photos too with no backend change or migration. 3. Remove stale pre-trip recruiting content now that the trip is almost over: delete ConceptSection and SignupSection entirely, drop Hero's "Join the Rallye" CTA, remove #concept/#join from Nav and Footer. Strip the "sign up" copy/link from CrewsSection, keep the crew list. Reorder App.tsx so the live map and photo stream lead (Hero -> Route -> Follow -> Itinerary -> Crews -> Last Year). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the public-facing rallye site to remove links to the unauthenticated crew upload page, reorder media consistently by capture time (trip timeline), and remove/reorder “join/concept” marketing sections to prioritize live-follow content.
Changes:
- Removed remaining public UI links to
/photos(upload page), replacing “View all” with an in-page#followanchor. - Changed media ordering logic to sort newest-captured-first at the
useMediaPostssource and aligned map marker/cluster ordering accordingly. - Deleted
ConceptSection/SignupSectionand simplified navigation/hero/footer to remove#join/#concept, plus reordered the main page sections.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/sections/SignupSection.tsx | Deleted legacy signup CTA section. |
| src/sections/ConceptSection.tsx | Deleted legacy “The Idea / What to bring” marketing section. |
| src/sections/Hero.tsx | Removed “Join” CTA, kept route CTA styling consistent. |
| src/components/Nav.tsx | Removed join/concept items; updated nav order to include Follow. |
| src/sections/Footer.tsx | Removed join/concept links; added Follow link. |
| src/sections/CrewsSection.tsx | Removed signup prompt copy; updated headings. |
| src/sections/FollowSection.tsx | Removed public “Share a photo” button linking to /photos. |
| src/App.tsx | Reordered sections to surface Route + Follow earlier; removed deleted sections. |
| src/hooks/useMediaPosts.ts | Re-sorted posts by capturedAt descending at the hook source. |
| src/components/RouteMap/MediaMarkers.tsx | Updated map lightbox ordering to match captured-time ordering. |
| src/components/RouteMap/mediaClusterRenderer.ts | Updated cluster thumbnail selection ordering to match captured-time ordering. |
| src/components/RouteMap/PhotoStreamTile.tsx | Repointed “View all” to #follow; removed “Share a photo” link. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** | ||
| * Sorts posts newest-*captured*-first (not newest-uploaded). Crews upload | ||
| * with a time lag, but followers should see photos in the trip's actual | ||
| * timeline order regardless of when they landed in Blob/Table Storage. | ||
| * `capturedAt` is an ISO date string, so lexicographic comparison sorts | ||
| * correctly without parsing. | ||
| */ | ||
| function sortByCapturedAtDesc(posts: MediaPost[]): MediaPost[] { | ||
| return [...posts].sort((a, b) => (a.capturedAt < b.capturedAt ? 1 : a.capturedAt > b.capturedAt ? -1 : 0)); | ||
| } |
There was a problem hiding this comment.
Fixed in 6aa1615: extracted a shared compareCapturedAtDesc() that parses capturedAt via Date.parse (epoch ms) instead of comparing raw strings, with an id tie-breaker for equal/unparseable timestamps.
| * `useMediaPosts` sorts. Crews upload with a time lag, so sorting by | ||
| * `capturedAt` (an ISO string, sorts correctly lexicographically) keeps | ||
| * lightbox ordering on trip-timeline order everywhere it's opened from. */ | ||
| function sortNewestFirst(posts: readonly MediaPost[]): MediaPost[] { | ||
| return [...posts].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)); | ||
| return [...posts].sort((a, b) => (a.capturedAt < b.capturedAt ? 1 : a.capturedAt > b.capturedAt ? -1 : 0)); |
There was a problem hiding this comment.
Fixed in 6aa1615: now imports and uses the shared compareCapturedAtDesc() from useMediaPosts.ts instead of the local string-based sort.
| // no photos at all. Pick deterministically (newest *captured* first, by | ||
| // `capturedAt` - an ISO string, sorts correctly lexicographically) | ||
| // rather than randomly, so the same cluster doesn't flicker between | ||
| // different thumbnails on every pan/zoom re-render. | ||
| const photos = posts.filter((p) => p.mediaType === 'photo'); |
There was a problem hiding this comment.
Fixed in 6aa1615: pickThumbnailPost() now imports and uses the shared compareCapturedAtDesc() instead of comparing capturedAt as raw strings.
| * Compact preview of the live photo stream, shown next to the map so | ||
| * visitors don't have to scroll all the way down to `/photos` / the | ||
| * `FollowSection` grid to see what's just been uploaded. Shows the most | ||
| * recent thumbnails; tapping one opens the same shared `MediaLightbox` | ||
| * used everywhere else, seeded with the *full* posts list (not just this | ||
| * visitors don't have to scroll all the way down to the `FollowSection` | ||
| * grid to see what's just been uploaded. Shows the most recent | ||
| * thumbnails; tapping one opens the same shared `MediaLightbox` used |
There was a problem hiding this comment.
Fixed in 6aa1615: reworded the doc comment to describe capture-time ordering instead of the stale "just been uploaded" phrasing.
- Extract shared compareCapturedAtDesc() in useMediaPosts.ts: parses
capturedAt to epoch ms (Date.parse) instead of comparing raw strings,
and falls back to an id tie-breaker when timestamps are equal or
unparseable. Fixes fragile lexicographic comparison flagged across
three call sites.
- MediaMarkers.tsx and mediaClusterRenderer.ts now import and reuse the
shared comparator instead of duplicating string-based sort logic.
- PhotoStreamTile.tsx: reworded stale doc comment that referenced
upload-time ordering ("just been uploaded") to reflect the
capturedAt-based capture-time ordering shipped in this PR.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
main had independently added multi-photo browsing/navigation and a download button to MediaLightbox (#35), plus client-side capturedAt sorting in useMediaPosts (#36), overlapping with this branch's own displayUrl-fetching and download-button work. Resolved by keeping main's posts/initialIndex-based MediaLightbox (portal rendering, prev/next nav, single download button) and layering this branch's displayUrl fetch-on-open logic on top, keyed to the currently navigated post - so browsing between photos in the lightbox still uses the compressed display copy per-post, not just on initial open. PhotoStream.tsx: kept main's selectedIndex-based version, re-applied the 12-post preview cap on top. useMediaPosts.ts: both branches sort by capturedAt (main client-side, this branch server-side in media.ts) - harmless redundancy, kept both and corrected a comment that had gone stale. Verified with npm run build (frontend) and cd api && npm run build - both clean.
Why
Three follow-up issues after the map/media polish PR (#35) merged:
/photos, the unauthenticated crew upload page (shared token embedded server-side, no real auth) —FollowSection's "Share a photo from your phone" button, andPhotoStreamTile's "View all" and "Share a photo" links.rowKey/id), not capture order. Crews upload with a lag, so followers weren't seeing photos in the trip's actual timeline.What changed
/photoslinks.PhotoStreamTile's "View all" now points to#follow(the fuller in-page grid) instead of leaking the crew upload page; the bottom "Share a photo" link is gone with no replacement./photositself and its rewrite rule are untouched — crews still have their direct link.useMediaPostsnow sorts bycapturedAtdescending once at the source;MediaMarkers'sortNewestFirst()andmediaClusterRenderer'spickThumbnailPost()updated to match (previously sorted byid/rowKey, i.e. upload order). Every post already has acapturedAtvalue, so this reorders everything already uploaded — no backend change or backfill needed.ConceptSection.tsxandSignupSection.tsxentirely, dropped Hero's "Join the Rallye" CTA, removed#concept/#joinfromNav.tsxandFooter.tsx. Stripped the "sign up" copy/link fromCrewsSection(kept the crew list itself). ReorderedApp.tsx:Hero → RouteSection (map) → FollowSection (stream) → Itinerary → Crews → LastYear.Verification
npm run buildandnpm run lintclean./api/media: confirmed nav/hero have no dangling#join/#conceptlinks, no remaining/photoshrefs anywhere in the rendered DOM, "View all" correctly points to#follow, and the photo grid renders newest-captured-first (verified against a fixture where capture order differs from upload order).Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com