mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 23:51:17 +00:00
feat(availability): per-staff working hours and class/session management
- Working-hours repo accepts nullable staff scope (pgx + memory); staff rules live in availability_rules and drive public slot generation - Protected routes for staff working hours, class templates, and class sessions with tenant-ownership checks and input validation - Sessions derive endsAt/capacity from templates; list resolves location names and live booked counts; template delete cascades sessions, session delete preserves bookings via SET NULL (mirrored in memory) - Zones page: staff-scope selector on working hours, new Classes tab with template/session CRUD, CS+EN strings, mobile tab wrapping - Normalize availability_rules times to HH:MM in the service layer 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
d9aa29dbcb
commit
0405106587
12 files changed
+2069
-58
No files matched your search
@@ -122,13 +122,24 @@ func (r *PGRepository) DeleteBlockedDay(ctx context.Context, blockedDayID string
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *PGRepository) ListWorkingHoursByTenant(ctx context.Context, tenantID string) ([]WorkingHoursRecord, error) {
|
||||
rows, err := r.pool.Query(ctx, `
|
||||
func (r *PGRepository) ListWorkingHoursByTenant(ctx context.Context, tenantID string, staffID *string) ([]WorkingHoursRecord, error) {
|
||||
query := `
|
||||
SELECT tenant_id, staff_id, day_of_week, starts_local::text, ends_local::text
|
||||
FROM availability_rules
|
||||
WHERE tenant_id = $1 AND staff_id IS NULL
|
||||
ORDER BY day_of_week
|
||||
`, tenantID)
|
||||
`
|
||||
args := []any{tenantID}
|
||||
if staffID != nil {
|
||||
query = `
|
||||
SELECT tenant_id, staff_id, day_of_week, starts_local::text, ends_local::text
|
||||
FROM availability_rules
|
||||
WHERE tenant_id = $1 AND staff_id = $2
|
||||
ORDER BY day_of_week
|
||||
`
|
||||
args = append(args, *staffID)
|
||||
}
|
||||
rows, err := r.pool.Query(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -145,12 +156,22 @@ func (r *PGRepository) ListWorkingHoursByTenant(ctx context.Context, tenantID st
|
||||
return records, rows.Err()
|
||||
}
|
||||
|
||||
func (r *PGRepository) UpdateWorkingHours(ctx context.Context, tenantID string, dayOfWeek int, params UpdateWorkingHoursParams) error {
|
||||
if params.IsOpen != nil && !*params.IsOpen {
|
||||
_, err := r.pool.Exec(ctx, `
|
||||
func (r *PGRepository) UpdateWorkingHours(ctx context.Context, tenantID string, staffID *string, dayOfWeek int, params UpdateWorkingHoursParams) error {
|
||||
deleteQuery := `
|
||||
DELETE FROM availability_rules
|
||||
WHERE tenant_id = $1 AND day_of_week = $2 AND staff_id IS NULL
|
||||
`
|
||||
args := []any{tenantID, dayOfWeek}
|
||||
if staffID != nil {
|
||||
deleteQuery = `
|
||||
DELETE FROM availability_rules
|
||||
WHERE tenant_id = $1 AND day_of_week = $2 AND staff_id IS NULL
|
||||
`, tenantID, dayOfWeek)
|
||||
WHERE tenant_id = $1 AND day_of_week = $2 AND staff_id = $3
|
||||
`
|
||||
args = append(args, *staffID)
|
||||
}
|
||||
|
||||
if params.IsOpen != nil && !*params.IsOpen {
|
||||
_, err := r.pool.Exec(ctx, deleteQuery, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -159,17 +180,14 @@ func (r *PGRepository) UpdateWorkingHours(ctx context.Context, tenantID string,
|
||||
}
|
||||
|
||||
// availability_rules has no unique constraint on (tenant, day): replace the
|
||||
// tenant-level row so repeated updates stay idempotent.
|
||||
if _, err := r.pool.Exec(ctx, `
|
||||
DELETE FROM availability_rules
|
||||
WHERE tenant_id = $1 AND day_of_week = $2 AND staff_id IS NULL
|
||||
`, tenantID, dayOfWeek); err != nil {
|
||||
// scoped row so repeated updates stay idempotent.
|
||||
if _, err := r.pool.Exec(ctx, deleteQuery, args...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := r.pool.Exec(ctx, `
|
||||
INSERT INTO availability_rules (id, tenant_id, staff_id, day_of_week, starts_local, ends_local)
|
||||
VALUES (gen_random_uuid(), $1, NULL, $2, $3::time, $4::time)
|
||||
`, tenantID, dayOfWeek, *params.StartsLocal, *params.EndsLocal)
|
||||
VALUES (gen_random_uuid(), $1, $2, $3, $4::time, $5::time)
|
||||
`, tenantID, staffID, dayOfWeek, *params.StartsLocal, *params.EndsLocal)
|
||||
return err
|
||||
}
|
||||
Reference in new issue
Block a user