You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

400 lines
16 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Phase 1: Slot Definition Management - Wireframes & Form States
**Owner**: Frontend Faye
**Created**: 2025-11-05
**Status**: Draft for review
---
## Overview
Phase 1 enables venue admins to create, edit, and manage recurring slot templates (slot definitions). These templates are materialized into actual slot instances by Cron Carter's materialisation job.
**User Story**: As a venue admin, I want to create recurring time slots for my courts so that customers can book them automatically without manual intervention.
---
## Page Structure
### Route: `/[locale]/admin/clubs/[club_id]/slot-definitions`
**Navigation from Club Detail**:
- Club detail page → "Manage Schedules" button → Slot Definitions page
**Layout**:
```
┌─────────────────────────────────────────────────────────┐
│ [Back to Club] Central Padel Geneva │
├─────────────────────────────────────────────────────────┤
│ │
│ Slot Definitions │
│ Recurring time slots for your courts │
│ │
│ [+ Create New Definition] [Filter ▼] │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Court 1 - Mondays 18:00-19:00 │ │
│ │ Capacity: 4 players | Valid from: 2025-11-01 │ │
│ │ Status: ● Active │ │
│ │ [Edit] [Delete]│ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Court 2 - Tuesdays 19:00-20:00 │ │
│ │ Capacity: 4 players | Valid from: 2025-11-01 │ │
│ │ Status: ● Active │ │
│ │ [Edit] [Delete]│ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
```
---
## Create/Edit Form Modal
### Form Structure
```
┌────────────────────────────────────────────────────┐
│ Create Slot Definition [×] │
├────────────────────────────────────────────────────┤
│ │
│ Court * │
│ [Select court ▼] │
│ │
│ Day of Week * │
│ [Monday ▼] │
│ │
│ Start Time * │
│ [18] : [00] (24-hour format) │
│ │
│ Duration * │
│ [60] minutes │
│ │
│ Capacity * │
│ [4] players │
│ │
│ Valid From * │
│ [2025-11-15] 📅 │
│ │
│ Valid To (optional) │
│ [No end date] 📅 │
│ │
│ ───────────────────────────────────────────── │
│ │
│ [Cancel] [Create Definition] │
│ │
└────────────────────────────────────────────────────┘
```
---
## Form States & Validation
### Field Definitions
#### Court (Required)
- **Type**: Dropdown select
- **Options**: List of active courts for the club
- **Validation**: Must select a court
- **Error**: "Please select a court"
#### Day of Week (Required)
- **Type**: Dropdown select
- **Options**: Monday (1), Tuesday (2), ..., Sunday (0)
- **Validation**: Must select a day
- **Error**: "Please select a day of week"
#### Start Time (Required)
- **Type**: Time input (HH:MM)
- **Format**: 24-hour
- **Validation**:
- Must be valid time (00:00 - 23:59)
- Should align with typical business hours warning (e.g., warning if before 06:00 or after 23:00)
- **Error**: "Please enter a valid start time"
- **Warning**: "⚠️ This time is outside typical business hours (06:00-23:00)"
#### Duration (Required)
- **Type**: Number input
- **Options**: Preset buttons: [30 min] [60 min] [90 min] [120 min] or custom
- **Validation**:
- Must be > 0
- Must be <= 480 minutes (8 hours)
- Recommended: 30, 60, 90, 120 minutes
- **Error**: "Duration must be between 1 and 480 minutes"
- **Warning**: "⚠️ Non-standard duration. Most bookings are 60 or 90 minutes."
#### Capacity (Required)
- **Type**: Number input
- **Default**: 4 (for padel/tennis doubles)
- **Validation**: Must be between 1 and 8
- **Error**: "Capacity must be between 1 and 8 players"
#### Valid From (Required)
- **Type**: Date picker
- **Default**: Tomorrow's date
- **Validation**:
- Must be today or future date
- Cannot be before today
- **Error**: "Valid from date cannot be in the past"
#### Valid To (Optional)
- **Type**: Date picker or "No end date" checkbox
- **Validation**:
- If set, must be after "Valid From"
- Warning if > 1 year in future
- **Error**: "Valid to must be after valid from date"
- **Warning**: "⚠️ Definition valid for more than 1 year. Consider reviewing periodically."
---
## Form Validation States
### 1. Empty / Initial State
- All fields empty or default values
- Submit button disabled
- No error messages shown
### 2. Filling Out (In Progress)
- Fields being completed
- Real-time validation on blur
- Submit button disabled until all required fields valid
- Show field-level errors on blur
### 3. Valid State
- All required fields filled and validated
- No errors shown
- Submit button enabled and highlighted
- Preview of materialization impact shown
### 4. Error State
- One or more validation errors
- Error messages shown under relevant fields
- Submit button disabled
- Focus on first error field
### 5. Conflict State (Backend Error)
- Form submitted but backend returns conflict
- Error banner: "⚠️ A definition already exists for Court 1 on Mondays at 18:00"
- Suggestion: "Edit the existing definition or choose a different time"
- Form fields remain editable
### 6. Submitting State
- Submit button shows loading spinner
- Form fields disabled
- Cannot close modal
- Loading text: "Creating definition..."
### 7. Success State
- Brief success message: "✓ Slot definition created successfully"
- Auto-close modal after 1 second
- Refresh slot definitions list
- Optional: Show materialisation job status
---
## Materialisation Status Indicator
After creating/editing a definition, show materialisation status:
```
┌────────────────────────────────────────────────────┐
│ ✓ Definition created successfully │
│ │
│ Materialisation Status: │
│ ⏳ Slots are being generated... (Job #12345) │
│ │
│ Expected completion: 2 minutes │
│ [View Job Details] │
└────────────────────────────────────────────────────┘
```
**States**:
1. **Queued**: ⏳ Materialisation job queued (position #3)
2. **Running**: ⏳ Generating slots... (45% complete)
3. **Complete**: ✓ 24 new slots created for next 7 days
4. **Error**: ⚠️ Materialisation failed (contact support)
**Link to Cron Carter**: This requires coordination with Cron Carter for job status API.
---
## Delete Confirmation Modal
```
┌────────────────────────────────────────────────────┐
│ Delete Slot Definition? [×] │
├────────────────────────────────────────────────────┤
│ │
│ Are you sure you want to delete: │
│ │
│ 📍 Court 1 - Mondays 18:00-19:00 │
│ Valid from: 2025-11-01 │
│ │
│ ⚠️ This will not delete existing bookings, │
│ but future slots will not be generated. │
│ │
│ [Cancel] [Delete Definition] │
│ │
└────────────────────────────────────────────────────┘
```
---
## Filter & Sort Options
### Filter Dropdown
- All Courts
- By Court (Court 1, Court 2, etc.)
- Active Only
- Inactive Only
- By Day of Week
### Sort Options
- Court (A-Z)
- Day of Week (Mon-Sun)
- Start Time (Early-Late)
- Created Date (Newest-Oldest)
---
## Empty States
### No Definitions Yet
```
┌────────────────────────────────────────────────────┐
│ │
│ 📅 │
│ │
│ No slot definitions yet │
│ │
│ Create recurring time slots so customers can │
│ book your courts automatically. │
│ │
│ [+ Create First Definition] │
│ │
└────────────────────────────────────────────────────┘
```
### No Results (After Filter)
```
┌────────────────────────────────────────────────────┐
│ │
│ 🔍 │
│ │
│ No definitions match your filters │
│ │
│ Try adjusting your filter criteria. │
│ │
│ [Clear Filters] │
│ │
└────────────────────────────────────────────────────┘
```
---
## Mobile Responsive Considerations
### Card Stacking (< 768px)
- Definition cards stack vertically
- Edit/Delete buttons move to card footer
- Form modal takes full screen
- Time picker uses native mobile inputs
### Touch Targets
- Minimum 44px × 44px for all interactive elements
- Larger tap areas for primary actions
- Swipe to delete on mobile (optional)
---
## Accessibility
- All form fields have proper `<label>` associations
- Error messages use `aria-describedby`
- Form validation uses `aria-invalid`
- Focus management: First field on modal open, first error on validation fail
- Keyboard navigation: Tab order follows visual order
- Screen reader announcements for success/error states
---
## API Integration Points
Based on `VENUE_ADMIN_DESIGN.md`:
### GET `/admin/clubs/{club_id}/slot-definitions`
- Load existing definitions for display
- Filter by `court_id` or `active_on` date
### POST `/admin/clubs/{club_id}/slot-definitions`
**Request Body**:
```json
{
"court_id": 12,
"dow": 1,
"starts_at": "18:00:00",
"duration_minutes": 60,
"capacity": 4,
"valid_from": "2025-11-15",
"valid_to": null
}
```
### PATCH `/admin/clubs/{club_id}/slot-definitions/{id}`
**Request Body**: Same as POST (partial updates allowed)
**Headers**: `If-Match: "<etag>"` for optimistic concurrency
### DELETE `/admin/clubs/{club_id}/slot-definitions/{id}`
**Headers**: `If-Match: "<etag>"`
---
## Technical Implementation Notes
### Component Structure
```
/admin/clubs/[club_id]/slot-definitions/
├── page.tsx # Main list page
├── components/
│ ├── DefinitionCard.tsx # Individual definition card
│ ├── DefinitionForm.tsx # Create/edit modal form
│ ├── DeleteConfirm.tsx # Delete confirmation modal
│ ├── FilterBar.tsx # Filter/sort controls
│ └── MaterialisationStatus.tsx # Job status indicator
```
### State Management
- Use React useState for form state
- Consider useReducer for complex form validation
- Optimistic updates for delete (rollback on error)
- Polling or WebSocket for materialisation status updates
### Form Libraries (Recommendation)
- React Hook Form: For form state management
- Zod: For schema validation matching API contracts
- Or plain React state for simplicity (Phase 1 is small)
---
## Open Questions for Cron Carter
1. **Materialisation Job Status API**: What endpoint do we call to check job status?
2. **Real-time Updates**: WebSocket, polling, or manual refresh?
3. **Job Failure Handling**: What UI should we show if materialisation fails?
4. **Manual Trigger**: Should admins be able to manually trigger materialisation?
---
## Next Steps
1. **Review with Chief Cole**: Confirm this matches vision
2. **Share with Cron Carter**: Align on materialisation status display
3. **Implementation**: After Phase 0 integration complete
4. **Design Review**: Share with Ops Omar for pilot feedback
---
**Status**: Ready for review and implementation planning.