Jersey selection page with Stripe checkout #44

Closed
opened 2026-03-18 20:30:22 +00:00 by forgejo_admin · 0 comments

Type

Feature

Lineage

plan-wkq → Phase 11 → Jersey ordering for second tryout

Repo

forgejo_admin/westside-app

User Story

As a parent
I want to select and pay for my player's jersey option from an email link
So that the jersey is ordered and tracked to my player's account

Context

Parents receive an announcement email with a link to https://westside.tail5b443a.ts.net/jersey?token={registration_token}. This page shows 3 jersey options ($90 reversible, $130 jersey+warmup, opt out). Selecting an option calls the basketball-api to create a Stripe Checkout Session, then redirects to Stripe's hosted checkout page. After payment, Stripe redirects back to a success page.

The token (parent's registration_token) authenticates without requiring Keycloak login — parents click the email link and go straight to the selection page. The basketball-api POST /jersey/checkout endpoint handles the Stripe session creation.

API base URL is in src/lib/api.js (API_BASE). The apiFetch helper handles auth'd requests but jersey checkout uses token auth (query param), not Bearer token.

File Targets

Files the agent should modify or create:

  • src/routes/jersey/+page.svelte — NEW: jersey selection landing page
    • Read token from URL query params
    • Fetch jersey options from GET /jersey/options
    • Display 3 cards: Reversible ($90), Jersey+Warmup ($130), Opt Out (free)
    • Each card has description, price, and "Select" button
    • On select: POST to /jersey/checkout?token={token} with {option: "reversible"} (or "jersey_warmup" or "opt_out")
    • Redirect to the returned Stripe checkout URL
    • Loading states during API calls
    • Error handling if token is invalid or API fails
  • src/routes/jersey/success/+page.svelte — NEW: post-checkout success page
    • "Thank you! Your jersey order has been placed."
    • Link to profile page
    • Westside branding
  • src/routes/jersey/cancel/+page.svelte — NEW: checkout cancelled page
    • "No worries — you can come back and order anytime."
    • Link back to jersey selection
    • Westside branding

Files the agent should NOT touch:

  • src/routes/register/+page.svelte — registration is separate
  • src/routes/players/[id]/billing/+page.svelte — billing is for subscriptions

Acceptance Criteria

  • /jersey?token={valid_token} shows 3 jersey option cards with prices
  • Selecting an option calls the API and redirects to Stripe Checkout
  • /jersey/success shows confirmation message after payment
  • /jersey/cancel shows cancellation message with retry link
  • Invalid or missing token shows an error message
  • Page is mobile-first (most parents will open from phone email)
  • Westside brand colors (red #d42026, black #0a0a0a) used throughout

Test Expectations

  • Manual test: navigate to /jersey?token=test, verify cards render
  • Manual test: verify mobile responsiveness
  • Run command: npm run check (Svelte type check)

Constraints

  • Use existing CSS variables from src/app.css — match the existing card/info-card patterns
  • Do NOT use apiFetch for the jersey checkout call — it adds Bearer token auth. Instead use a plain fetch with the token as a query param (the backend validates the token, not a JWT)
  • For the opt-out option, don't redirect to Stripe — just POST to the API which records the choice, then show the success page directly
  • Mobile-first: cards should stack vertically on small screens
  • The Stripe success/cancel URLs should be: https://westside.tail5b443a.ts.net/jersey/success and https://westside.tail5b443a.ts.net/jersey/cancel

Checklist

  • PR opened
  • npm run check passes
  • No unrelated changes
  • phase-wkq-11-girls-tryout — jersey ordering for second tryout
  • basketball-api issue for jersey checkout endpoints (paired backend work)
### Type Feature ### Lineage `plan-wkq` → Phase 11 → Jersey ordering for second tryout ### Repo `forgejo_admin/westside-app` ### User Story As a parent I want to select and pay for my player's jersey option from an email link So that the jersey is ordered and tracked to my player's account ### Context Parents receive an announcement email with a link to `https://westside.tail5b443a.ts.net/jersey?token={registration_token}`. This page shows 3 jersey options ($90 reversible, $130 jersey+warmup, opt out). Selecting an option calls the basketball-api to create a Stripe Checkout Session, then redirects to Stripe's hosted checkout page. After payment, Stripe redirects back to a success page. The token (parent's `registration_token`) authenticates without requiring Keycloak login — parents click the email link and go straight to the selection page. The basketball-api `POST /jersey/checkout` endpoint handles the Stripe session creation. API base URL is in `src/lib/api.js` (`API_BASE`). The `apiFetch` helper handles auth'd requests but jersey checkout uses token auth (query param), not Bearer token. ### File Targets Files the agent should modify or create: - `src/routes/jersey/+page.svelte` — NEW: jersey selection landing page - Read `token` from URL query params - Fetch jersey options from `GET /jersey/options` - Display 3 cards: Reversible ($90), Jersey+Warmup ($130), Opt Out (free) - Each card has description, price, and "Select" button - On select: POST to `/jersey/checkout?token={token}` with `{option: "reversible"}` (or "jersey_warmup" or "opt_out") - Redirect to the returned Stripe checkout URL - Loading states during API calls - Error handling if token is invalid or API fails - `src/routes/jersey/success/+page.svelte` — NEW: post-checkout success page - "Thank you! Your jersey order has been placed." - Link to profile page - Westside branding - `src/routes/jersey/cancel/+page.svelte` — NEW: checkout cancelled page - "No worries — you can come back and order anytime." - Link back to jersey selection - Westside branding Files the agent should NOT touch: - `src/routes/register/+page.svelte` — registration is separate - `src/routes/players/[id]/billing/+page.svelte` — billing is for subscriptions ### Acceptance Criteria - [ ] `/jersey?token={valid_token}` shows 3 jersey option cards with prices - [ ] Selecting an option calls the API and redirects to Stripe Checkout - [ ] `/jersey/success` shows confirmation message after payment - [ ] `/jersey/cancel` shows cancellation message with retry link - [ ] Invalid or missing token shows an error message - [ ] Page is mobile-first (most parents will open from phone email) - [ ] Westside brand colors (red `#d42026`, black `#0a0a0a`) used throughout ### Test Expectations - [ ] Manual test: navigate to `/jersey?token=test`, verify cards render - [ ] Manual test: verify mobile responsiveness - Run command: `npm run check` (Svelte type check) ### Constraints - Use existing CSS variables from `src/app.css` — match the existing card/info-card patterns - Do NOT use `apiFetch` for the jersey checkout call — it adds Bearer token auth. Instead use a plain `fetch` with the token as a query param (the backend validates the token, not a JWT) - For the opt-out option, don't redirect to Stripe — just POST to the API which records the choice, then show the success page directly - Mobile-first: cards should stack vertically on small screens - The Stripe success/cancel URLs should be: `https://westside.tail5b443a.ts.net/jersey/success` and `https://westside.tail5b443a.ts.net/jersey/cancel` ### Checklist - [ ] PR opened - [ ] `npm run check` passes - [ ] No unrelated changes ### Related - `phase-wkq-11-girls-tryout` — jersey ordering for second tryout - basketball-api issue for jersey checkout endpoints (paired backend work)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/westside-landing#44
No description provided.