refactor: extract content components from monolithic +page.svelte #35

Closed
opened 2026-04-03 23:51:05 +00:00 by forgejo_admin · 2 comments
Contributor

Type

Feature

Lineage

Sub-ticket of forgejo_admin/westside-contracts#34 — data-driven contract rendering system. Wave 1 (independent). Board note: board-34-data-driven-contracts.

Repo

forgejo_admin/westside-contracts

User Story

As a developer, I want the contract body content extracted into stateless components so that T6 (wire to data) can replace hardcoded HTML with data-driven rendering.

Context

src/routes/contract/[token]/+page.svelte is 725 lines. The file has 5 zones:

  1. Script block (1-163) — all state + logic (signature pad, effects, submit). STAYS IN PAGE.
  2. Header + routing (165-209) — brand header, already-signed check, player card. STAYS IN PAGE.
  3. Contract body (211-632) — three {#if} branches: boys travel (174 lines), girls travel (183 lines), local (58 lines). THIS IS WHAT WE EXTRACT.
  4. Custom notes + signing (636-698) — checkbox, sig pad, submit. STAYS IN PAGE (62 lines, 8 state vars — extraction would add complexity, not reduce it).
  5. Footer + success (703-725) — static. STAYS IN PAGE.

This ticket extracts 6 stateless content components from zone 3. All are props-in, HTML-out. No state management, no lifecycle, no event handling.

File Targets

Create src/lib/components/ directory, then:

  • src/lib/components/FeeSection.svelte — monthly fee display. Props: monthlyFee (number), practiceDescription (string). ~10 lines.
  • src/lib/components/TournamentCard.svelte — single local tournament card. Props: name, dates, cost. ~15 lines.
  • src/lib/components/TournamentTrip.svelte — single travel tournament with cost breakdown table. Props: name, dates, entryFee, travel object (transportation, gas, coaches, lodging, total). ~30 lines.
  • src/lib/components/PracticeSchedule.svelte — practice day/location/time rows. Props: practices array, optional intro text. ~15 lines.
  • src/lib/components/PaymentSchedule.svelte — payment rows + prorated fee calc + Klarna note. Props: payments array, monthlyFee (for prorated calc). ~25 lines.
  • src/lib/components/StaticSection.svelte — generic h3 + paragraph(s) or bullet list. Props: title, content (string or string[]), isList (boolean). ~15 lines.

Modify:

  • src/routes/contract/[token]/+page.svelte — replace inline HTML in the three {#if} branches with component calls. The three branches STAY (boys/girls/local conditional) but each branch uses the extracted components instead of raw HTML.

Do NOT touch:

  • Script block (lines 1-163) — all state/logic unchanged
  • Signing section (lines 645-698) — stays inline
  • Footer + success overlay (lines 703-725) — stays inline
  • src/lib/validation.ts, src/lib/minio.ts, src/lib/db.ts
  • src/routes/contract/[token]/+page.server.ts
  • src/routes/contract/[token]/sign/+server.ts
  • src/app.css

Acceptance Criteria

  • 6 component files exist in src/lib/components/
  • +page.svelte is under 300 lines (163 script + ~130 template using components)
  • The three {#if} branches still exist (boys/girls/local) but dispatch to components
  • Visual output is pixel-identical for all 3 variants
  • Queens pink branding still works
  • Signature pad initialization still works (script block untouched)
  • Contract signing flow works end-to-end
  • Already-signed state renders correctly
  • Custom notes render when present

Test Expectations

  • npm run check passes (TypeScript)
  • npm test passes (validation tests)
  • Manual: visit boys travel, girls travel, local contract pages — visual parity
  • Run command: npm test && npm run check

Constraints

  • Pure refactor — NO behavior changes, NO data model changes
  • Components use Svelte 5 runes ($props only — these are stateless)
  • CSS stays in app.css — components reference existing class names, no scoped styles
  • Do NOT extract the signing section — it has 8 state variables, 3 element bindings, 3 functions. Extraction would increase complexity.
  • Do NOT extract header, footer, or success overlay — they're small and don't benefit from extraction

Checklist

  • PR opened
  • Tests pass (npm test && npm run check)
  • No unrelated changes
  • No visual regression
  • westside-basketball — parent project
  • forgejo_admin/westside-contracts#34 — parent issue
  • Board note: board-34-data-driven-contracts
### Type Feature ### Lineage Sub-ticket of `forgejo_admin/westside-contracts#34` — data-driven contract rendering system. Wave 1 (independent). Board note: `board-34-data-driven-contracts`. ### Repo `forgejo_admin/westside-contracts` ### User Story As a developer, I want the contract body content extracted into stateless components so that T6 (wire to data) can replace hardcoded HTML with data-driven rendering. ### Context `src/routes/contract/[token]/+page.svelte` is 725 lines. The file has 5 zones: 1. **Script block** (1-163) — all state + logic (signature pad, effects, submit). STAYS IN PAGE. 2. **Header + routing** (165-209) — brand header, already-signed check, player card. STAYS IN PAGE. 3. **Contract body** (211-632) — three `{#if}` branches: boys travel (174 lines), girls travel (183 lines), local (58 lines). THIS IS WHAT WE EXTRACT. 4. **Custom notes + signing** (636-698) — checkbox, sig pad, submit. STAYS IN PAGE (62 lines, 8 state vars — extraction would add complexity, not reduce it). 5. **Footer + success** (703-725) — static. STAYS IN PAGE. This ticket extracts 6 stateless content components from zone 3. All are props-in, HTML-out. No state management, no lifecycle, no event handling. ### File Targets Create `src/lib/components/` directory, then: - `src/lib/components/FeeSection.svelte` — monthly fee display. Props: monthlyFee (number), practiceDescription (string). ~10 lines. - `src/lib/components/TournamentCard.svelte` — single local tournament card. Props: name, dates, cost. ~15 lines. - `src/lib/components/TournamentTrip.svelte` — single travel tournament with cost breakdown table. Props: name, dates, entryFee, travel object (transportation, gas, coaches, lodging, total). ~30 lines. - `src/lib/components/PracticeSchedule.svelte` — practice day/location/time rows. Props: practices array, optional intro text. ~15 lines. - `src/lib/components/PaymentSchedule.svelte` — payment rows + prorated fee calc + Klarna note. Props: payments array, monthlyFee (for prorated calc). ~25 lines. - `src/lib/components/StaticSection.svelte` — generic h3 + paragraph(s) or bullet list. Props: title, content (string or string[]), isList (boolean). ~15 lines. Modify: - `src/routes/contract/[token]/+page.svelte` — replace inline HTML in the three `{#if}` branches with component calls. The three branches STAY (boys/girls/local conditional) but each branch uses the extracted components instead of raw HTML. Do NOT touch: - Script block (lines 1-163) — all state/logic unchanged - Signing section (lines 645-698) — stays inline - Footer + success overlay (lines 703-725) — stays inline - `src/lib/validation.ts`, `src/lib/minio.ts`, `src/lib/db.ts` - `src/routes/contract/[token]/+page.server.ts` - `src/routes/contract/[token]/sign/+server.ts` - `src/app.css` ### Acceptance Criteria - [ ] 6 component files exist in `src/lib/components/` - [ ] +page.svelte is under 300 lines (163 script + ~130 template using components) - [ ] The three `{#if}` branches still exist (boys/girls/local) but dispatch to components - [ ] Visual output is pixel-identical for all 3 variants - [ ] Queens pink branding still works - [ ] Signature pad initialization still works (script block untouched) - [ ] Contract signing flow works end-to-end - [ ] Already-signed state renders correctly - [ ] Custom notes render when present ### Test Expectations - [ ] `npm run check` passes (TypeScript) - [ ] `npm test` passes (validation tests) - [ ] Manual: visit boys travel, girls travel, local contract pages — visual parity - Run command: `npm test && npm run check` ### Constraints - Pure refactor — NO behavior changes, NO data model changes - Components use Svelte 5 runes ($props only — these are stateless) - CSS stays in app.css — components reference existing class names, no scoped styles - Do NOT extract the signing section — it has 8 state variables, 3 element bindings, 3 functions. Extraction would increase complexity. - Do NOT extract header, footer, or success overlay — they're small and don't benefit from extraction ### Checklist - [ ] PR opened - [ ] Tests pass (`npm test && npm run check`) - [ ] No unrelated changes - [ ] No visual regression ### Related - `westside-basketball` — parent project - `forgejo_admin/westside-contracts#34` — parent issue - Board note: `board-34-data-driven-contracts`
forgejo_admin changed title from refactor: extract Svelte components from monolithic +page.svelte to refactor: extract content components from monolithic +page.svelte 2026-04-04 21:35:58 +00:00
Author
Contributor

Scope Review: NEEDS_REFINEMENT

Review note: review-775-2026-04-03

Ticket scope is thorough — all template sections present, file targets verified against codebase (725-line file confirmed, zone 3 lines 211-632 confirmed, component directory does not exist yet). Traceability to story:WS-S20 verified. Dependencies documented via wave labels.

One issue:

  • [SCOPE] Architecture note arch-contracts does not exist in pal-e-docs. 10 board items reference arch:contracts but there is no backing note. Create arch-contracts to complete traceability.
## Scope Review: NEEDS_REFINEMENT Review note: `review-775-2026-04-03` Ticket scope is thorough — all template sections present, file targets verified against codebase (725-line file confirmed, zone 3 lines 211-632 confirmed, component directory does not exist yet). Traceability to story:WS-S20 verified. Dependencies documented via wave labels. **One issue:** - `[SCOPE]` Architecture note `arch-contracts` does not exist in pal-e-docs. 10 board items reference `arch:contracts` but there is no backing note. Create `arch-contracts` to complete traceability.
Author
Contributor

Agent picked up this ticket.

Agent picked up this ticket.
Sign in to join this conversation.
No labels
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
ldraney/westside-contracts#35
No description provided.