continuous-integration/drone/push Build is passingDetails
- Add PlanEntitlementsEditor component for Pay-Per-Court settings
- Add EntitlementsConfigModal for editing plan entitlements
- Update PlanCard with entitlements badges and configure button
- Update MembershipPlansComponent to fetch/display entitlements
- Create credits management page with balance list and adjustment modal
- Create transfers management page with filtering and stats
- Add Credits and Transfers tabs to ClubDetailTabs navigation
- Add API client functions for credits and transfers endpoints
- Update facility-admin types with credit and transfer interfaces
continuous-integration/drone/push Build is passingDetails
- Add PlanTemplate type and listPlanTemplates API function
- Create TemplateCard and TemplatePicker components
- Modify PlanFormModal to accept initialValues from template
- Update MembershipPlansComponent to show template picker first
- Add missing translations (Venue Management, Club Management, etc.)
continuous-integration/drone/push Build is passingDetails
Backend only accepts: 'monthly', 'annual', or null
Frontend was offering: daily, weekly, monthly, quarterly, yearly, lifetime
Changes:
- Update BillingPeriod type to 'monthly' | 'annual' | null
- Update PlanFormModal dropdown to only show valid options
- Update PlanCard formatBillingPeriod to handle new values
- Display 'Annual (Yearly)' in UI but send 'annual' to API
Fixes validation error: 'Must be monthly, annual, or null'
continuous-integration/drone/push Build is passingDetails
Add admin context API client:
- Create /admin/context types (ManagedFacility, AdminSettings)
- Add getAdminContext() API client function
- Separate admin context from player context
Fix API response type mismatches:
- UserSettings: API uses 'origin' terminology, map to internal 'remote'
- Fix transformApiSettings to use default_origin_sport/default_origin_member_id
- Update UserSettingsContext to read origin_members from API
- Fix getPolicy to handle direct object response (not wrapped)
- Fix listPlans/listMembers to extract nested arrays from API responses
These fixes ensure TypeScript types match actual API responses.
continuous-integration/drone/push Build is passingDetails
Implements Phase B1-B4 of the admin portal frontend:
Phase B1 - Setup & Types:
- Add TypeScript type definitions for all admin APIs
- Add complete API client with all 15 endpoint integrations
Phase B2 - Membership Plans UI:
- Add plans listing page with create/edit/delete functionality
- Add PlanCard, PlanFormModal, and PlanListSkeleton components
- Support billing periods, pricing, and activation status
Phase B3 - Member Management UI:
- Add members listing page with search and filters
- Add member CRUD modals with role/plan assignment
- Add RoleBadge, StatusBadge, and MemberCard components
- Support filtering by role and status
Phase B4 - Policy Configuration UI:
- Add facility settings page for policy management
- Add AccessModelSelector for membership/payg/open models
- Add GuestPricingInput and BookingLimitsForm components
- Support configuring booking limits and access control
All components follow existing design patterns with purple/indigo
gradients, responsive layouts, and loading states.
continuous-integration/drone/push Build is passingDetails
The API now returns address at facility.address instead of facility.settings.address, and uses field names like address_line_1 and zip instead of line_1 and postal_code. Updated the ClubProfile type and form to match.
continuous-integration/drone/push Build is passingDetails
The API now returns 'facility' with expanded address/settings fields instead of 'club', and slot types have been restructured to use flat properties instead of nested booking/meta objects.
continuous-integration/drone/push Build is passingDetails
Complete migration of all admin API endpoints from clubs to facilities nomenclature:
**Admin Endpoint Changes:**
- GET /admin/clubs → GET /admin/facilities
- GET /admin/clubs/{id} → GET /admin/facilities/{id}
- All 30+ admin routes migrated from /clubs/ to /facilities/
**API Client Files Updated:**
- admin-clubs.ts: List and detail endpoints (2 endpoints)
- materialisation.ts: Materialization status and trigger (2 endpoints)
- slot-definitions.ts: All CRUD operations (6 endpoints)
- courts.ts: Court management and profile (7 endpoints)
- admin-api.ts: TypeScript documentation comments (7 updates)
**Total Changes:**
- 28 endpoint path replacements across 5 files
- All /admin/clubs references removed
- Comments and documentation updated
**Verification:**
- TypeScript compilation: ✓ No errors
- All admin endpoints now use /admin/facilities
- Fixes 404 errors on admin panel endpoints
BREAKING CHANGES: Requires backend Build 363+ with /admin/facilities endpoints
continuous-integration/drone/push Build is passingDetails
- Add MaterialisationJobInfo interface with job status, timing, and results
- Add last_job field to MaterialisationStatus (BUILD 353 support)
- Add calculateElapsedTime and formatElapsedTime helper functions
- Implement job status polling (every 2s while queued/running)
- Add elapsed time counter for running jobs with live updates
- Display job progress states:
- Queued: 'Job queued, waiting to start...'
- Running: 'Generating slots... (45s)' with policy and horizon info
- Completed: '✅ Generated X slots (Y cancelled, Z errors)' with detailed metrics
- Failed: '❌ Job failed' with error message
- Update rate limit display logic (only show when can_trigger=false AND no active job)
- Disable trigger button when job is active (queued/running)
- Resolves UX confusion where users saw rate limits while jobs were actually running
- Implements Backend Brooke BUILD 353 job tracking feature
continuous-integration/drone/push Build was killedDetails
Backend Brooke confirmed the actual API response structure uses "definitions"
not "created_definitions". Also added missing preset and pattern fields to
GenerateSlotDefinitionsResponse.
Changes:
- GenerateSlotDefinitionsResponse: added preset and pattern fields
- GenerateSlotDefinitionsResponse: renamed created_definitions → definitions
- CloneSlotDefinitionResponse: renamed created_definitions → definitions
This matches the confirmed API contract from BUILD 348.
continuous-integration/drone/push Build is passingDetails
Backend Brooke reverted the breaking change from BUILD:347. The generate
endpoint continues to use "preset" field name, not "pattern_type".
This reverts commit 834e1a8 and restores the original API contract.
Changes:
- Reverted GenerateSlotDefinitionsRequest: pattern_type → preset
- Reverted GenerateSlotDefinitionsModal to send preset in request body
Backend BUILD:348 has restored the original "preset" field.
continuous-integration/drone/push Build is passingDetails
Backend API changed field name from "preset" to "pattern_type" in the
generate slot definitions endpoint (BUILD:347).
Changes:
- Updated GenerateSlotDefinitionsRequest interface: preset → pattern_type
- Updated GenerateSlotDefinitionsModal to send pattern_type in request body
This fixes compatibility with the updated backend API contract.
continuous-integration/drone/push Build is passingDetails
Migrated all admin API clients to automatically send X-Locale and X-Timezone headers
with every request for proper internationalization and timezone-aware operations.
Changes:
- Migrated slot-definitions.ts, materialisation.ts, courts.ts, booking-admin.ts to use apiFetch utility
- Added getLocaleHeaders() helper to admin-clubs.ts for SSR compatibility
- Added getSlotDefinitionPresets() endpoint to fetch localized preset metadata
- Updated slot-definitions types to support API-based preset loading
- Refactored GenerateSlotDefinitionsModal to fetch presets from API with localized titles/descriptions
Benefits:
- All API requests now include user's locale (e.g., en-US, fr-CH) for i18n
- Timezone-aware operations use browser's Intl.DateTimeFormat timezone
- Preset titles and descriptions are localized per user language
- Consistent header management across all admin endpoints
Technical Details:
- apiFetch extracts locale from URL pathname via getPathnameLocale()
- apiFetch automatically adds credentials: 'include' for session auth
- admin-clubs.ts uses manual headers for SSR cookie forwarding compatibility
- GenerateSlotDefinitionsModal shows loading state while fetching presets
continuous-integration/drone/push Build is passingDetails
Fixes from tsc type checking:
- Re-added useEffect import to ClubCourtsTab (used in CourtFormModal)
- Updated mock courts data to include created_at/updated_at timestamps
- Fixed CourtError dependencies type to match CourtDependencies structure
(slot_instances_future/booked instead of upcoming_bookings)
All court-related TypeScript errors resolved. Build succeeds.
continuous-integration/drone/push Build is passingDetails
Root cause: GET /admin/clubs/{id}/courts endpoint doesn't include
sport_variation nested structure, but GET /admin/clubs/{id} does.
Changes:
- Updated AdminClubDetail.courts to use Court[] type (includes sport_variation)
- ClubDetailTabs now passes courts + onUpdate callback to ClubCourtsTab
- ClubCourtsTab accepts courts as props instead of fetching separately
- Removed redundant getCourts() API call
- Removed debug logging
This fixes the court edit dropdown issue where sport variation wasn't
displaying because the data wasn't available from the courts endpoint.
continuous-integration/drone/push Build is passingDetails
Fixed two issues reported by user:
1. Slot definition duration validation error:
- Changed step from "15" to "1" on duration input
- HTML5 validation was failing because with min="1" and step="15",
valid values were 1, 16, 31, 46, 61, 76, 91... (not 90!)
- Now accepts any integer duration >= 1 minute
- Error "nearest 76 or 91" resolved
2. Sport variation not showing in court edit form:
- Updated Court type to include nested sport_variation structure
- Backend now returns full sport_variation object with sport details
- Updated CourtFormModal to extract sport_variation_id from nested
structure: court.sport_variation.sport_variation_id
- Added sport variation display in court list (e.g., "Padel - Indoor")
- Maintains backward compatibility with deprecated flat field
Changes:
- SlotDefinitionForm: step="1" instead of step="15"
- Court interface: added optional sport_variation nested object
- ClubCourtsTab: reads sport_variation_id from nested structure
- ClubCourtsTab: displays "Sport - Variation" in court list
Related: Backend Brooke nested sport_variation response structure
continuous-integration/drone/push Build is passingDetails
Court Sport Variation (BUILD:296-297 requirement):
- Added Sport and SportVariation types to courts.ts
- Created getSports() API client for GET /admin/sports
- Updated Court and CourtRequest types with sport_variation_id field
- Added sport variation dropdown to court creation modal
- Auto-selects first variation for new courts
- Sport type locked after creation (disabled in edit mode)
- Mock data updated with sport_variation_id values
Profile Bug Fix:
- Fixed click-to-edit crash when field values are empty/undefined
- Added null checks before calling .trim() in hasFieldValue() and EditableField
- Error: "Cannot read properties of undefined (reading 'trim')"
- Now safely handles empty string values
UI Details:
- Sport dropdown shows "Padel - Indoor", "Padel - Outdoor", etc.
- Loading spinner while fetching sports
- Validation error if no sport variation selected
- Form includes both name and sport_variation_id in POST request
Backend Brooke message: Court creation now requires sport_variation_id parameter
continuous-integration/drone/push Build is passingDetails
Add TypeScript types, API client, and table view for slot definitions.
Uses mock data until backend endpoints are ready.
Components:
- SlotDefinitionsComponent: table with create/edit/delete actions
- TypeScript types matching API contract specs
- API client with CRUD operations (POST/GET/PATCH/DELETE)
- Mock data for local development
Features:
- Professional slate theme throughout
- Empty state with CTA
- Table showing: day, time range, duration, capacity, valid period, description
- Edit/delete action buttons (TODOs for modals)
- Loading and error states with proper UX
- Breadcrumb navigation back to club
Contract alignment:
- Day format: 0=Monday, 6=Sunday
- Time format: HH:MM:SS with display helpers
- Date range: valid_from required, valid_to optional
- RFC-7807 error handling ready
Next: Create/edit form modal with validation