feat: enriched edit request system with side-by-side snapshots, calendar preloading, and admin review UI

Backend:
- Add enriched response types (EditSnapshot, EnrichedEditRequest) with original vs proposed snapshots
- Add 4 new GET endpoints for viewing edit requests (user and admin scoped)
- Remove github.com/lib/pq dependency — use native PostgreSQL array scanning
- Clean up edit requests, time blockers, and notifications on booking cancellation
- Validate exceptional closed hours on admin approve (409 Conflict)
- Notification upsert on edit request replace (no duplicate admin notifications)

Frontend:
- New user EditRequestModal with time/services/both modes and lunch protection
- New admin EditRequestModal with side-by-side diff (date/time, services, notes)
- Integrate edit requests into PendingApprovals card and notifications page
- Preload 3 months of availability to prevent calendar snap-back
- Apply lunch protection to isDateUnavailable in BookingFlow and BookingCreateModal
- Fix accessibility: card list items use <button> instead of <div>

Dev & Docs:
- Seed edit requests in local-dev-2.sh
- Update all Obsidian manuals with enriched edit request documentation
- 42 new tests (438/441 passing)
This commit is contained in:
2026-05-26 11:59:07 +01:00
parent 3ccc017716
commit 8574bf2221
19 changed files with 5270 additions and 599 deletions
+2 -3
View File
@@ -36,7 +36,6 @@ import (
"github.com/go-chi/chi/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/lib/pq"
)
func resetTestData(t *testing.T) {
@@ -2860,7 +2859,7 @@ func TestAdminApproveEditRequest(t *testing.T) {
t.Fatalf("failed to confirm booking: %v", err)
}
// Create edit request directly in DB (need pq.Array for PostgreSQL array)
// Create edit request directly in DB
var editRequestID string
newTime := time.Now().Add(24 * time.Hour).Truncate(time.Minute)
var emptyServices []string
@@ -2868,7 +2867,7 @@ func TestAdminApproveEditRequest(t *testing.T) {
`INSERT INTO booking_edit_requests (booking_id, requested_by, new_start_time, new_services, notes)
VALUES ($1, $2, $3, $4, 'Please change time')
RETURNING id`,
bookingID, userID, newTime, pq.Array(&emptyServices)).Scan(&editRequestID)
bookingID, userID, newTime, emptyServices).Scan(&editRequestID)
if err != nil {
t.Fatalf("failed to create edit request: %v", err)
}