feat: add jersey payment status badges to admin CRM #193

Merged
forgejo_admin merged 1 commit from 183-crm-jersey-badges into main 2026-03-29 22:25:14 +00:00
Contributor

Summary

Adds jersey order status badges to the admin CRM player list. Each player card now shows their jersey payment state as a colored badge, and paid/shipped players display their jersey option and number in the detail line.

Changes

  • src/routes/(app)/admin/players/+page.svelte -- added getJerseyBadgeClass(), getJerseyLabel(), and getJerseyOptionLabel() helper functions following the existing contract badge pattern; added jersey badge to card-row-name-line; added jersey option/number to card-row-detail for paid/shipped players
  • src/app.css -- added four new badge classes: badge-jersey-none (grey), badge-jersey-pending (yellow), badge-jersey-paid (green), badge-jersey-shipped (blue)

Test Plan

  • Visual: admin CRM player list shows jersey badge per player
  • Badge colors: none=grey, pending=yellow, paid=green, shipped=blue
  • Paid/shipped players show jersey option label (Full Kit / Jersey Only / Opt-Out) and jersey number in detail line
  • Mobile: badges wrap naturally within card-row-name-line (uses existing flex-wrap)
  • svelte-check: 0 errors, no new warnings

Review Checklist

  • Follows existing badge pattern (subscription_status, contract_status)
  • New CSS classes use existing design tokens (color vars)
  • No backend changes -- frontend display only
  • svelte-check passes with 0 errors
  • Mobile-compatible (badges use inline-block with natural wrapping)
  • Closes #183
  • Backend dependency: forgejo_admin/basketball-api#248
## Summary Adds jersey order status badges to the admin CRM player list. Each player card now shows their jersey payment state as a colored badge, and paid/shipped players display their jersey option and number in the detail line. ## Changes - `src/routes/(app)/admin/players/+page.svelte` -- added `getJerseyBadgeClass()`, `getJerseyLabel()`, and `getJerseyOptionLabel()` helper functions following the existing contract badge pattern; added jersey badge to card-row-name-line; added jersey option/number to card-row-detail for paid/shipped players - `src/app.css` -- added four new badge classes: `badge-jersey-none` (grey), `badge-jersey-pending` (yellow), `badge-jersey-paid` (green), `badge-jersey-shipped` (blue) ## Test Plan - Visual: admin CRM player list shows jersey badge per player - Badge colors: none=grey, pending=yellow, paid=green, shipped=blue - Paid/shipped players show jersey option label (Full Kit / Jersey Only / Opt-Out) and jersey number in detail line - Mobile: badges wrap naturally within card-row-name-line (uses existing flex-wrap) - `svelte-check`: 0 errors, no new warnings ## Review Checklist - [x] Follows existing badge pattern (subscription_status, contract_status) - [x] New CSS classes use existing design tokens (color vars) - [x] No backend changes -- frontend display only - [x] svelte-check passes with 0 errors - [x] Mobile-compatible (badges use inline-block with natural wrapping) ## Related Notes - Closes #183 - Backend dependency: `forgejo_admin/basketball-api#248`
feat: add jersey payment status badges to admin CRM player list
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
f00ae3cf3d
Show jersey_order_status as a colored badge (none=grey, pending=yellow,
paid=green, shipped=blue) on each player card. For paid/shipped players,
display jersey_option label and jersey_number in the detail line.

Closes #183

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

PR #193 Review

DOMAIN REVIEW

Tech stack: SvelteKit (Svelte 5 runes), vanilla CSS with design tokens.

Pattern compliance: The PR adds three helper functions (getJerseyBadgeClass, getJerseyLabel, getJerseyOptionLabel) that exactly mirror the existing getContractBadgeClass/getContractLabel pattern. Switch/case structure, JSDoc param types, default fallbacks -- all consistent with the established code at lines 41-76 of the players page.

CSS classes: Four new badge-jersey-* classes added at src/app.css line 1381+, placed directly after the existing contract badge block. All four use existing design token variables (--color-gray-800, --color-yellow-bg, --color-green-bg, --color-blue-bg, etc.), which are all defined in the :root block (lines 32-34 for blue tokens, verified).

Badge color spec verification:

  • badge-jersey-none = grey (gray-800/gray-400/gray-600) -- MATCHES spec
  • badge-jersey-pending = yellow (yellow-bg/yellow/yellow-border) -- MATCHES spec
  • badge-jersey-paid = green (green-bg/green/green-border) -- MATCHES spec
  • badge-jersey-shipped = blue (blue-bg/blue/blue-border) -- MATCHES spec

Mobile handling: The card-row-name-line container (app.css line 1544) uses display: flex; flex-wrap: wrap; gap: 0.5rem, so the third badge will naturally wrap on narrow viewports. No additional responsive CSS needed.

Detail line logic: Jersey option and number only render when jersey_order_status === 'paid' || 'shipped' -- correctly guarded with nested {#if} blocks for both getJerseyOptionLabel() truthiness and player.jersey_number existence.

Scope: Exactly 2 files changed (players page + app.css), 36 additions, 1 deletion (the modified detail line). No unrelated changes detected.

BLOCKERS

None.

This is a frontend-only display change with no user input handling, no auth/security paths, no backend changes, and no new functionality requiring test coverage (display-only badge rendering following an established untested pattern in the same file). The existing badge helpers (getStatusBadgeClass, getContractBadgeClass) are also untested -- adding test requirements here would be scope creep beyond the existing codebase conventions.

NITS

  1. CSS duplication (non-blocking, intentional): The four new badge-jersey-* classes are value-identical to existing classes (badge-jersey-none = badge-no-contract, badge-jersey-pending = badge-offered, badge-jersey-paid = badge-signed, badge-jersey-shipped = badge-division). This follows the established pattern of semantic class naming per domain, which allows independent color changes later. Not a DRY violation -- it is the convention. Noting for awareness only.

  2. Middot character inconsistency (cosmetic): The existing detail line uses \u00B7 in JS template expressions, while the new jersey section uses &middot; HTML entity. Both render identically. The difference is because existing separators are in JS expression context ({player.division ? ' \u00B7 ' + ...}) while the new ones are in Svelte template context ({#if ...} &middot; ...). Functionally correct, just a different encoding of the same character.

  3. Long template line: The card-row-detail div content is now a single very long line (~300+ chars). Readability could be improved by breaking across lines, but this matches the existing style in the file (the original line was already long). Non-blocking.

SOP COMPLIANCE

  • Branch named after issue: 183-crm-jersey-badges follows {issue-number}-{kebab-case-purpose} convention
  • PR body follows template: Summary, Changes, Test Plan, Review Checklist, Related Notes all present
  • Related references issue: Closes #183 and notes backend dependency basketball-api#248
  • No secrets committed: pure frontend display code, no credentials
  • No scope creep: exactly the files and changes expected for this feature
  • Commit message descriptive: PR title feat: add jersey payment status badges to admin CRM follows conventional commits

PROCESS OBSERVATIONS

Clean, minimal PR. 36 lines added across 2 files for a display-only feature. The pattern reuse (copying the contract badge approach) keeps cognitive load low. Backend dependency on basketball-api#248 is noted in the PR body -- the jersey_order_status, jersey_option, and jersey_number fields must exist on the player API response for these badges to render meaningful data (they will gracefully fall back to "No Jersey" / empty if the fields are absent).

VERDICT: APPROVED

## PR #193 Review ### DOMAIN REVIEW **Tech stack**: SvelteKit (Svelte 5 runes), vanilla CSS with design tokens. **Pattern compliance**: The PR adds three helper functions (`getJerseyBadgeClass`, `getJerseyLabel`, `getJerseyOptionLabel`) that exactly mirror the existing `getContractBadgeClass`/`getContractLabel` pattern. Switch/case structure, JSDoc param types, default fallbacks -- all consistent with the established code at lines 41-76 of the players page. **CSS classes**: Four new `badge-jersey-*` classes added at `src/app.css` line 1381+, placed directly after the existing contract badge block. All four use existing design token variables (`--color-gray-800`, `--color-yellow-bg`, `--color-green-bg`, `--color-blue-bg`, etc.), which are all defined in the `:root` block (lines 32-34 for blue tokens, verified). **Badge color spec verification**: - `badge-jersey-none` = grey (gray-800/gray-400/gray-600) -- MATCHES spec - `badge-jersey-pending` = yellow (yellow-bg/yellow/yellow-border) -- MATCHES spec - `badge-jersey-paid` = green (green-bg/green/green-border) -- MATCHES spec - `badge-jersey-shipped` = blue (blue-bg/blue/blue-border) -- MATCHES spec **Mobile handling**: The `card-row-name-line` container (app.css line 1544) uses `display: flex; flex-wrap: wrap; gap: 0.5rem`, so the third badge will naturally wrap on narrow viewports. No additional responsive CSS needed. **Detail line logic**: Jersey option and number only render when `jersey_order_status === 'paid' || 'shipped'` -- correctly guarded with nested `{#if}` blocks for both `getJerseyOptionLabel()` truthiness and `player.jersey_number` existence. **Scope**: Exactly 2 files changed (players page + app.css), 36 additions, 1 deletion (the modified detail line). No unrelated changes detected. ### BLOCKERS None. This is a frontend-only display change with no user input handling, no auth/security paths, no backend changes, and no new functionality requiring test coverage (display-only badge rendering following an established untested pattern in the same file). The existing badge helpers (`getStatusBadgeClass`, `getContractBadgeClass`) are also untested -- adding test requirements here would be scope creep beyond the existing codebase conventions. ### NITS 1. **CSS duplication (non-blocking, intentional)**: The four new `badge-jersey-*` classes are value-identical to existing classes (`badge-jersey-none` = `badge-no-contract`, `badge-jersey-pending` = `badge-offered`, `badge-jersey-paid` = `badge-signed`, `badge-jersey-shipped` = `badge-division`). This follows the established pattern of semantic class naming per domain, which allows independent color changes later. Not a DRY violation -- it is the convention. Noting for awareness only. 2. **Middot character inconsistency (cosmetic)**: The existing detail line uses `\u00B7` in JS template expressions, while the new jersey section uses `&middot;` HTML entity. Both render identically. The difference is because existing separators are in JS expression context (`{player.division ? ' \u00B7 ' + ...}`) while the new ones are in Svelte template context (`{#if ...} &middot; ...`). Functionally correct, just a different encoding of the same character. 3. **Long template line**: The `card-row-detail` div content is now a single very long line (~300+ chars). Readability could be improved by breaking across lines, but this matches the existing style in the file (the original line was already long). Non-blocking. ### SOP COMPLIANCE - [x] Branch named after issue: `183-crm-jersey-badges` follows `{issue-number}-{kebab-case-purpose}` convention - [x] PR body follows template: Summary, Changes, Test Plan, Review Checklist, Related Notes all present - [x] Related references issue: `Closes #183` and notes backend dependency `basketball-api#248` - [x] No secrets committed: pure frontend display code, no credentials - [x] No scope creep: exactly the files and changes expected for this feature - [x] Commit message descriptive: PR title `feat: add jersey payment status badges to admin CRM` follows conventional commits ### PROCESS OBSERVATIONS Clean, minimal PR. 36 lines added across 2 files for a display-only feature. The pattern reuse (copying the contract badge approach) keeps cognitive load low. Backend dependency on `basketball-api#248` is noted in the PR body -- the `jersey_order_status`, `jersey_option`, and `jersey_number` fields must exist on the player API response for these badges to render meaningful data (they will gracefully fall back to "No Jersey" / empty if the fields are absent). ### VERDICT: APPROVED
forgejo_admin deleted branch 183-crm-jersey-badges 2026-03-29 22:25:14 +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!193
No description provided.