|
|
# 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.
|