fix: align public schedule page with actual API response schema (#206) #207

Merged
forgejo_admin merged 2 commits from 206-fix-public-schedule-api-schema into main 2026-04-03 23:35:13 +00:00
Contributor

Summary

The public schedule page was built against hardcoded fallback data shapes, not the actual /public/schedule API response. Six field mismatches caused practices and events to silently not render when live API data was returned.

Changes

  • src/routes/(public)/schedule/+page.svelte:
    • Added DAY_NAMES array and dayName() helper to convert integer day_of_week (0-6) to day names
    • Added formatTime() to convert 24h "HH:MM" strings to "H:MM AM/PM" display format
    • Added formatDate() / formatDateRange() for ISO date string formatting
    • Fixed practice filtering: label-based classification (Local in label) instead of nonexistent group field, with fallback compatibility for hardcoded data
    • Fixed event rendering: event.title instead of event.name, formatDateRange(event.start_date, event.end_date) instead of event.date, removed event.teams reference
    • Added Queens practice section with full rendering (previously events-only with "contact director" message)
    • Fixed groupByTeam() to use p.label (API field) with p.team_name fallback

Test Plan

  • Verify npm run build passes (confirmed)
  • Load /schedule page with API running -- Kings and Queens practices and events should render with correct day names, formatted times, and formatted dates
  • Load /schedule page with API down -- fallback data should still render correctly via field fallbacks (event.name, event.date, string day_of_week)

Review Checklist

  • No changes to src/lib/public-api.js or src/lib/api.js
  • Fallback constants preserved unchanged
  • CSS styling untouched
  • npm run build passes
  • Fallback data backward-compatible (field fallbacks for name/date/day_of_week/group)

None.

Closes #206

## Summary The public schedule page was built against hardcoded fallback data shapes, not the actual `/public/schedule` API response. Six field mismatches caused practices and events to silently not render when live API data was returned. ## Changes - `src/routes/(public)/schedule/+page.svelte`: - Added `DAY_NAMES` array and `dayName()` helper to convert integer `day_of_week` (0-6) to day names - Added `formatTime()` to convert 24h `"HH:MM"` strings to `"H:MM AM/PM"` display format - Added `formatDate()` / `formatDateRange()` for ISO date string formatting - Fixed practice filtering: label-based classification (`Local` in label) instead of nonexistent `group` field, with fallback compatibility for hardcoded data - Fixed event rendering: `event.title` instead of `event.name`, `formatDateRange(event.start_date, event.end_date)` instead of `event.date`, removed `event.teams` reference - Added Queens practice section with full rendering (previously events-only with "contact director" message) - Fixed `groupByTeam()` to use `p.label` (API field) with `p.team_name` fallback ## Test Plan - Verify `npm run build` passes (confirmed) - Load `/schedule` page with API running -- Kings and Queens practices and events should render with correct day names, formatted times, and formatted dates - Load `/schedule` page with API down -- fallback data should still render correctly via field fallbacks (`event.name`, `event.date`, string `day_of_week`) ## Review Checklist - [x] No changes to `src/lib/public-api.js` or `src/lib/api.js` - [x] Fallback constants preserved unchanged - [x] CSS styling untouched - [x] `npm run build` passes - [x] Fallback data backward-compatible (field fallbacks for name/date/day_of_week/group) ## Related Notes None. ## Related Closes #206
fix: align public schedule page with actual API response schema (#206)
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
96c11c7d30
The public schedule page was built against hardcoded fallback data shapes
rather than the actual /public/schedule API response. Six field mismatches
caused practices and events to not render from live API data:

- Add DAY_NAMES array and dayName() to convert integer day_of_week to names
- Add formatTime() to convert 24h "HH:MM" strings to "H:MM AM/PM"
- Add formatDate()/formatDateRange() for ISO date string formatting
- Fix practice filtering: use label-based classification (Local vs travel)
  instead of nonexistent group field, with fallback compatibility
- Fix event rendering: title instead of name, start_date/end_date instead
  of date, remove teams field reference
- Add Queens practice section with full rendering (was events-only)
- Fix groupByTeam to use p.label (API) with p.team_name fallback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: handle pre-formatted fallback times in formatTime
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
8d0752ca64
Fallback practice data uses already-formatted strings like "2:00 PM".
formatTime would corrupt these by splitting on ":" and getting NaN.
Add AM/PM guard to return pre-formatted strings as-is.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Contributor

QA Review

Scope: Single file change (src/routes/(public)/schedule/+page.svelte), 1 changed file, +103/-18 lines.

Findings

  1. Bug caught during review (fixed in 8d0752c): formatTime() would corrupt fallback data. Fallback practices use pre-formatted strings like "2:00 PM". Splitting on : and calling Number() on "00 PM" produces NaN. Added an AM/PM guard to return pre-formatted strings as-is.

  2. All six field mismatches addressed:

    • event.name -> event.title || event.name (fallback-safe)
    • event.date -> formatDateRange(event.start_date, event.end_date) with event.date fallback
    • event.teams removed (not in API response)
    • p.group -> label-based classification with p.group fallback
    • practice.day_of_week raw -> dayName() with string passthrough for fallback
    • practice.start_time/end_time raw -> formatTime() with AM/PM guard
  3. Queens practice section added -- renders when API returns girls practices, falls back to "contact director" message when empty.

  4. Build passes -- npm run build confirmed clean.

  5. No prohibited files changed -- public-api.js, api.js, CSS, and fallback constants all untouched.

VERDICT: APPROVED

## QA Review **Scope:** Single file change (`src/routes/(public)/schedule/+page.svelte`), 1 changed file, +103/-18 lines. ### Findings 1. **Bug caught during review (fixed in 8d0752c):** `formatTime()` would corrupt fallback data. Fallback practices use pre-formatted strings like `"2:00 PM"`. Splitting on `:` and calling `Number()` on `"00 PM"` produces `NaN`. Added an AM/PM guard to return pre-formatted strings as-is. 2. **All six field mismatches addressed:** - `event.name` -> `event.title || event.name` (fallback-safe) - `event.date` -> `formatDateRange(event.start_date, event.end_date)` with `event.date` fallback - `event.teams` removed (not in API response) - `p.group` -> label-based classification with `p.group` fallback - `practice.day_of_week` raw -> `dayName()` with string passthrough for fallback - `practice.start_time`/`end_time` raw -> `formatTime()` with AM/PM guard 3. **Queens practice section added** -- renders when API returns girls practices, falls back to "contact director" message when empty. 4. **Build passes** -- `npm run build` confirmed clean. 5. **No prohibited files changed** -- `public-api.js`, `api.js`, CSS, and fallback constants all untouched. ### VERDICT: APPROVED
Author
Contributor

PR #207 Review

DOMAIN REVIEW

Tech stack: SvelteKit (Svelte 5 runes syntax), public-facing schedule page. Single file change: src/routes/(public)/schedule/+page.svelte (+103/-18).

Correctness

  1. DAY_NAMES mapping (0=Monday...6=Sunday): The comment documents "0=Mon...6=Sun" which is an ISO 8601-style zero-indexed convention. This will be correct only if the basketball-api returns day_of_week using this same convention. If the API uses JavaScript's Date.getDay() convention (0=Sunday, 1=Monday...6=Saturday), every day will render shifted by one. Verify the API contract. The fallback handling (typeof day === 'string' passthrough) is correctly implemented for backward compatibility.

  2. formatTime() logic: Correct. Handles null/undefined, passthrough for already-formatted AM/PM strings (fallback data), and proper 24h-to-12h conversion. Edge cases covered: midnight (0:00 -> 12:00 AM), noon (12:00 -> 12:00 PM). The padStart(2,'0') for minutes is correct.

  3. formatDate() with 'T00:00:00' suffix: Good defensive pattern to prevent timezone-offset date shifting when parsing date-only ISO strings.

  4. Practice filtering via label: The ternary p.label ? !p.label.includes('Local') : p.group === 'travel' is a reasonable dual-path filter. Note that any label not containing the substring "Local" is classified as travel -- this is a broad assumption. If the API ever returns labels like "Exhibition" or "Clinic", they would be classified as travel practices.

  5. groupByTeam() key change: Using p.label || p.team_name || 'Practice' means the grouping key changed from team name to label. If multiple practices share the same label but different team names, they will be grouped together. Verify this is the intended behavior.

Accessibility

  • No regressions. The Queens practice section uses the same semantic HTML patterns (section, h2, h3, ul) as the existing Kings sections.

UX

  • Good: Queens practice section now renders real data instead of a static "contact director" message.
  • Good: Fallback message preserved when no Queens practice data exists.
  • The {:else} block for Queens practices renders outside the section-alt div structure differently than the {#if} block -- both wrap in section.section-alt > div.container which is consistent.

BLOCKERS

None.

The "no tests" situation is consistent with the existing codebase (no test infrastructure exists in westside-landing). This is pre-existing technical debt, not a regression introduced by this PR.

NITS

  1. DAY_NAMES convention verification: While not a blocker for the code itself, the day-of-week mapping is the single highest-risk assumption in this PR. If the API uses 0=Sunday convention, all days render wrong. The PR author should confirm the API contract matches 0=Monday.

  2. Label-based filtering fragility: The p.label.includes('Local') check is string-matching on API data. If the API label format ever changes (e.g., "local" lowercase, or "Community/Local"), the filter breaks silently. Consider a case-insensitive check: p.label.toLowerCase().includes('local').

  3. DRY opportunity: The Kings events card template (lines ~172-185) and Queens events card template (lines ~245-258) are nearly identical. A shared EventCard component or Svelte snippet would reduce duplication. Non-blocking since this duplication existed before this PR.

  4. Queens practice section uses grid-2 while Kings local practices use grid-3. This may be intentional (fewer Queens teams) but worth confirming it is a deliberate layout choice.

SOP COMPLIANCE

  • Branch named after issue: 206-fix-public-schedule-api-schema follows {issue-number}-{kebab-case-purpose} convention
  • PR body follows template: Summary, Changes, Test Plan, Review Checklist, Related sections all present
  • Related references plan slug: No plan slug referenced. PR states "None" for Related Notes. Acceptable for a standalone bug fix with no parent plan.
  • No secrets committed: Single .svelte file change, no credentials or env files
  • No scope creep: All changes directly serve the stated goal of aligning with API schema
  • Commit message is descriptive: fix: align public schedule page with actual API response schema (#206)

PROCESS OBSERVATIONS

  • This is a data contract mismatch fix -- the frontend was built against hardcoded data shapes that diverged from the actual API response. This is a common integration failure mode. A shared API type definition or contract test between basketball-api and westside-landing would prevent recurrence.
  • The fallback backward compatibility approach (field fallbacks like event.title || event.name) is pragmatic and reduces deployment risk.
  • Change failure risk is low: single file, template-only changes, no API modifications, fallback paths preserved.

VERDICT: APPROVED

## PR #207 Review ### DOMAIN REVIEW **Tech stack**: SvelteKit (Svelte 5 runes syntax), public-facing schedule page. Single file change: `src/routes/(public)/schedule/+page.svelte` (+103/-18). **Correctness** 1. **`DAY_NAMES` mapping (0=Monday...6=Sunday)**: The comment documents "0=Mon...6=Sun" which is an ISO 8601-style zero-indexed convention. This will be correct *only if* the basketball-api returns `day_of_week` using this same convention. If the API uses JavaScript's `Date.getDay()` convention (0=Sunday, 1=Monday...6=Saturday), every day will render shifted by one. **Verify the API contract.** The fallback handling (`typeof day === 'string'` passthrough) is correctly implemented for backward compatibility. 2. **`formatTime()` logic**: Correct. Handles null/undefined, passthrough for already-formatted AM/PM strings (fallback data), and proper 24h-to-12h conversion. Edge cases covered: midnight (0:00 -> 12:00 AM), noon (12:00 -> 12:00 PM). The `padStart(2,'0')` for minutes is correct. 3. **`formatDate()` with `'T00:00:00'` suffix**: Good defensive pattern to prevent timezone-offset date shifting when parsing date-only ISO strings. 4. **Practice filtering via label**: The ternary `p.label ? !p.label.includes('Local') : p.group === 'travel'` is a reasonable dual-path filter. Note that any label not containing the substring "Local" is classified as travel -- this is a broad assumption. If the API ever returns labels like "Exhibition" or "Clinic", they would be classified as travel practices. 5. **`groupByTeam()` key change**: Using `p.label || p.team_name || 'Practice'` means the grouping key changed from team name to label. If multiple practices share the same label but different team names, they will be grouped together. Verify this is the intended behavior. **Accessibility** - No regressions. The Queens practice section uses the same semantic HTML patterns (section, h2, h3, ul) as the existing Kings sections. **UX** - Good: Queens practice section now renders real data instead of a static "contact director" message. - Good: Fallback message preserved when no Queens practice data exists. - The `{:else}` block for Queens practices renders outside the `section-alt` div structure differently than the `{#if}` block -- both wrap in `section.section-alt > div.container` which is consistent. ### BLOCKERS None. The "no tests" situation is consistent with the existing codebase (no test infrastructure exists in westside-landing). This is pre-existing technical debt, not a regression introduced by this PR. ### NITS 1. **DAY_NAMES convention verification**: While not a blocker for the code itself, the day-of-week mapping is the single highest-risk assumption in this PR. If the API uses 0=Sunday convention, all days render wrong. The PR author should confirm the API contract matches `0=Monday`. 2. **Label-based filtering fragility**: The `p.label.includes('Local')` check is string-matching on API data. If the API label format ever changes (e.g., "local" lowercase, or "Community/Local"), the filter breaks silently. Consider a case-insensitive check: `p.label.toLowerCase().includes('local')`. 3. **DRY opportunity**: The Kings events card template (lines ~172-185) and Queens events card template (lines ~245-258) are nearly identical. A shared `EventCard` component or Svelte snippet would reduce duplication. Non-blocking since this duplication existed before this PR. 4. **Queens practice section uses `grid-2`** while Kings local practices use `grid-3`. This may be intentional (fewer Queens teams) but worth confirming it is a deliberate layout choice. ### SOP COMPLIANCE - [x] Branch named after issue: `206-fix-public-schedule-api-schema` follows `{issue-number}-{kebab-case-purpose}` convention - [x] PR body follows template: Summary, Changes, Test Plan, Review Checklist, Related sections all present - [ ] Related references plan slug: No plan slug referenced. PR states "None" for Related Notes. Acceptable for a standalone bug fix with no parent plan. - [x] No secrets committed: Single `.svelte` file change, no credentials or env files - [x] No scope creep: All changes directly serve the stated goal of aligning with API schema - [x] Commit message is descriptive: `fix: align public schedule page with actual API response schema (#206)` ### PROCESS OBSERVATIONS - This is a data contract mismatch fix -- the frontend was built against hardcoded data shapes that diverged from the actual API response. This is a common integration failure mode. A shared API type definition or contract test between basketball-api and westside-landing would prevent recurrence. - The fallback backward compatibility approach (field fallbacks like `event.title || event.name`) is pragmatic and reduces deployment risk. - Change failure risk is low: single file, template-only changes, no API modifications, fallback paths preserved. ### VERDICT: APPROVED
forgejo_admin deleted branch 206-fix-public-schedule-api-schema 2026-04-03 23:35:13 +00:00
Sign in to join this conversation.
No reviewers
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-app!207
No description provided.