# Story 3.5: Admin Booking Review & Approval ## Epic Reference **Epic 3:** Booking & Consultation System ## User Story As an **admin**, I want **to review, categorize, and approve or reject booking requests**, So that **I can manage my consultation schedule and set appropriate consultation types**. ## Story Context ### Existing System Integration - **Integrates with:** consultations table, notifications, .ics generation - **Technology:** Livewire Volt, Flux UI - **Follows pattern:** Admin action workflow - **Touch points:** Client notifications, calendar file ## Acceptance Criteria ### Pending Bookings List - [ ] View all pending booking requests - [ ] Display: client name, requested date/time, submission date - [ ] Show problem summary preview - [ ] Click to view full details - [ ] Sort by date (oldest first default) - [ ] Filter by date range ### Booking Details View - [ ] Full client information - [ ] Complete problem summary - [ ] Client consultation history - [ ] Requested date and time ### Approval Workflow - [ ] Set consultation type: - Free consultation - Paid consultation - [ ] If paid: set payment amount - [ ] If paid: add payment instructions (optional) - [ ] Approve button with confirmation - [ ] On approval: - Status changes to 'approved' - Client notified via email - .ics calendar file attached to email - Payment instructions included if paid ### Rejection Workflow - [ ] Optional rejection reason field - [ ] Reject button with confirmation - [ ] On rejection: - Status changes to 'rejected' - Client notified via email with reason ### Quick Actions - [ ] Quick approve (free) button on list - [ ] Quick reject button on list - [ ] Bulk actions (optional) ### Quality Requirements - [ ] Audit log for all decisions - [ ] Bilingual notifications - [ ] Tests for approval/rejection flow ## Technical Notes ### Consultation Status Flow ``` pending -> approved (admin approves) pending -> rejected (admin rejects) approved -> completed (after consultation) approved -> no_show (client didn't attend) approved -> cancelled (admin cancels) ``` ### Volt Component for Review ```php consultation = $consultation; } public function approve(): void { $this->validate([ 'consultationType' => ['required', 'in:free,paid'], 'paymentAmount' => ['required_if:consultationType,paid', 'nullable', 'numeric', 'min:0'], 'paymentInstructions' => ['nullable', 'string', 'max:1000'], ]); $this->consultation->update([ 'status' => 'approved', 'type' => $this->consultationType, 'payment_amount' => $this->consultationType === 'paid' ? $this->paymentAmount : null, 'payment_status' => $this->consultationType === 'paid' ? 'pending' : 'not_applicable', ]); // Generate calendar file $calendarService = app(CalendarService::class); $icsContent = $calendarService->generateIcs($this->consultation); // Send notification with .ics attachment $this->consultation->user->notify( new BookingApproved( $this->consultation, $icsContent, $this->paymentInstructions ) ); // Log action AdminLog::create([ 'admin_id' => auth()->id(), 'action_type' => 'approve', 'target_type' => 'consultation', 'target_id' => $this->consultation->id, 'old_values' => ['status' => 'pending'], 'new_values' => [ 'status' => 'approved', 'type' => $this->consultationType, 'payment_amount' => $this->paymentAmount, ], 'ip_address' => request()->ip(), ]); session()->flash('success', __('messages.booking_approved')); $this->redirect(route('admin.bookings.pending')); } public function reject(): void { $this->validate([ 'rejectionReason' => ['nullable', 'string', 'max:1000'], ]); $this->consultation->update([ 'status' => 'rejected', ]); // Send rejection notification $this->consultation->user->notify( new BookingRejected($this->consultation, $this->rejectionReason) ); // Log action AdminLog::create([ 'admin_id' => auth()->id(), 'action_type' => 'reject', 'target_type' => 'consultation', 'target_id' => $this->consultation->id, 'old_values' => ['status' => 'pending'], 'new_values' => [ 'status' => 'rejected', 'reason' => $this->rejectionReason, ], 'ip_address' => request()->ip(), ]); session()->flash('success', __('messages.booking_rejected')); $this->redirect(route('admin.bookings.pending')); } }; ``` ### Blade Template for Approval Modal ```blade {{ __('admin.approve_booking') }}

{{ __('admin.client') }}: {{ $consultation->user->name }}

{{ __('admin.date') }}: {{ $consultation->scheduled_date->translatedFormat('l, d M Y') }}

{{ __('admin.time') }}: {{ Carbon::parse($consultation->scheduled_time)->format('g:i A') }}

{{ __('admin.consultation_type') }} @if($consultationType === 'paid') {{ __('admin.payment_amount') }} * {{ __('admin.payment_instructions') }} @endif
{{ __('common.cancel') }} {{ __('admin.approve') }}
``` ### Pending Bookings List Component ```php Consultation::where('status', 'pending') ->when($this->dateFrom, fn($q) => $q->where('scheduled_date', '>=', $this->dateFrom)) ->when($this->dateTo, fn($q) => $q->where('scheduled_date', '<=', $this->dateTo)) ->with('user') ->orderBy('scheduled_date') ->orderBy('scheduled_time') ->paginate(15), ]; } public function quickApprove(int $id): void { $consultation = Consultation::findOrFail($id); $consultation->update([ 'status' => 'approved', 'type' => 'free', 'payment_status' => 'not_applicable', ]); // Generate and send notification with .ics // ... session()->flash('success', __('messages.booking_approved')); } public function quickReject(int $id): void { $consultation = Consultation::findOrFail($id); $consultation->update(['status' => 'rejected']); // Send rejection notification // ... session()->flash('success', __('messages.booking_rejected')); } }; ``` ## Definition of Done - [ ] Pending bookings list displays correctly - [ ] Can view booking details - [ ] Can approve as free consultation - [ ] Can approve as paid with amount - [ ] Can reject with optional reason - [ ] Approval sends email with .ics file - [ ] Rejection sends email with reason - [ ] Quick actions work from list - [ ] Audit log entries created - [ ] Bilingual support complete - [ ] Tests for approval/rejection - [ ] Code formatted with Pint ## Dependencies - **Story 3.4:** Booking submission (creates pending bookings) - **Story 3.6:** Calendar file generation (.ics) - **Epic 8:** Email notifications ## Risk Assessment - **Primary Risk:** Approving wrong booking - **Mitigation:** Confirmation dialog, clear booking details display - **Rollback:** Admin can cancel approved booking ## Estimation **Complexity:** Medium **Estimated Effort:** 4-5 hours