mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 07:41:16 +00:00
feat(classes): session roster + manual waitlist promotion
Adds the roster and manual promotion controls deferred from the booking
lifecycle milestones. Businesses can now inspect who holds a seat and who
is queueing on a class session, and promote waitlisted customers by hand
— including a deliberate over-capacity override when the session is full.
Backend:
- GET /v1/catalog/class-sessions/{id}/roster — session metadata plus
confirmed and waitlist entry lists with queue positions
- POST /v1/catalog/bookings/{id}/promote — 409 on a full session unless
allowOverCapacity is set; 400 for non-waitlisted, 404 for missing or
foreign bookings; reuses the shared confirm path so waitlist ledger
rows resolve and reminder jobs re-arm
- ListBookingsBySession repository method (pgx + memory); ClassSession
carries waitlistCount; UpcomingBooking carries classSessionId and
waitlistPosition
- OpenAPI paths + schemas, regenerated client, catalog service tests
Frontend:
- classes tab session rows expand into a two-column roster panel with
per-entry promote buttons and an explicit confirm-anyway step on 409
- booking detail modal shows waitlist position and offers promote for
waitlisted bookings; list badges show #N queue positions
- CS/EN i18n keys and seeded demo roster data; demo mutations surface
the demo notice
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
a82a48e1c8
commit
1cd5b1ba91
18 files changed
+1022
-59
No files matched your search
@@ -18,18 +18,20 @@ type DashboardKPI struct {
|
||||
}
|
||||
|
||||
type UpcomingBooking struct {
|
||||
ID string `json:"id"`
|
||||
Reference string `json:"reference"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerEmail string `json:"customerEmail"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
StaffName string `json:"staffName,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Status string `json:"status"`
|
||||
Label string `json:"label,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Reference string `json:"reference"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerEmail string `json:"customerEmail"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
StaffName string `json:"staffName,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Status string `json:"status"`
|
||||
Label string `json:"label,omitempty"`
|
||||
ClassSessionID *string `json:"classSessionId,omitempty"`
|
||||
WaitlistPosition int `json:"waitlistPosition,omitempty"`
|
||||
}
|
||||
|
||||
type WidgetSnippet struct {
|
||||
@@ -401,6 +403,41 @@ type ClassSession struct {
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Capacity int `json:"capacity"`
|
||||
BookedCount int `json:"bookedCount"`
|
||||
// WaitlistCount is the number of customers queued for a free seat.
|
||||
WaitlistCount int `json:"waitlistCount"`
|
||||
}
|
||||
|
||||
// SessionRosterEntry is one booking on a class session roster. WaitlistPosition
|
||||
// is the 1-based queue spot for waitlisted entries; zero for confirmed ones.
|
||||
type SessionRosterEntry struct {
|
||||
BookingID string `json:"bookingId"`
|
||||
Reference string `json:"reference"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerEmail string `json:"customerEmail"`
|
||||
CustomerPhone string `json:"customerPhone,omitempty"`
|
||||
Status string `json:"status"`
|
||||
WaitlistPosition int `json:"waitlistPosition,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
// SessionRoster is the dashboard attendee view of a class session: confirmed
|
||||
// seats plus the waitlist queue in FIFO order.
|
||||
type SessionRoster struct {
|
||||
SessionID string `json:"sessionId"`
|
||||
TemplateTitle string `json:"templateTitle"`
|
||||
LocationName string `json:"locationName,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Capacity int `json:"capacity"`
|
||||
Confirmed []SessionRosterEntry `json:"confirmed"`
|
||||
Waitlist []SessionRosterEntry `json:"waitlist"`
|
||||
}
|
||||
|
||||
// PromoteBookingRequest controls manual waitlist promotion. AllowOverCapacity
|
||||
// lets a business deliberately overbook a session; without it the request fails
|
||||
// when no free seat remains.
|
||||
type PromoteBookingRequest struct {
|
||||
AllowOverCapacity bool `json:"allowOverCapacity,omitempty"`
|
||||
}
|
||||
|
||||
type CreateClassSessionRequest struct {
|
||||
|
||||
Reference in new issue
Block a user