consultation = $consultation->load('user'); $this->newDate = $consultation->booking_date->format('Y-m-d'); } // Status Actions public function markCompleted(): void { DB::transaction(function () { $consultation = Consultation::lockForUpdate()->findOrFail($this->consultation->id); $oldStatus = $consultation->status->value; try { $consultation->markAsCompleted(); $this->consultation = $consultation->fresh(); $this->logStatusChange($oldStatus, 'completed'); session()->flash('success', __('messages.marked_completed')); } catch (\InvalidArgumentException $e) { session()->flash('error', $e->getMessage()); } }); } public function markNoShow(): void { DB::transaction(function () { $consultation = Consultation::lockForUpdate()->findOrFail($this->consultation->id); $oldStatus = $consultation->status->value; try { $consultation->markAsNoShow(); $this->consultation = $consultation->fresh(); $this->logStatusChange($oldStatus, 'no_show'); session()->flash('success', __('messages.marked_no_show')); } catch (\InvalidArgumentException $e) { session()->flash('error', $e->getMessage()); } }); } public function cancel(): void { DB::transaction(function () { $consultation = Consultation::lockForUpdate()->with('user')->findOrFail($this->consultation->id); $oldStatus = $consultation->status->value; try { $consultation->cancel(); $this->consultation = $consultation->fresh()->load('user'); if ($consultation->user) { $consultation->user->notify(new ConsultationCancelled($consultation)); } $this->logStatusChange($oldStatus, 'cancelled'); session()->flash('success', __('messages.consultation_cancelled')); } catch (\InvalidArgumentException $e) { session()->flash('error', $e->getMessage()); } }); } public function markPaymentReceived(): void { DB::transaction(function () { $consultation = Consultation::lockForUpdate()->findOrFail($this->consultation->id); try { $consultation->markPaymentReceived(); $this->consultation = $consultation->fresh(); AdminLog::create([ 'admin_id' => auth()->id(), 'action' => 'payment_received', 'target_type' => 'consultation', 'target_id' => $consultation->id, 'old_values' => ['payment_status' => 'pending'], 'new_values' => ['payment_status' => 'received'], 'ip_address' => request()->ip(), 'created_at' => now(), ]); session()->flash('success', __('messages.payment_marked_received')); } catch (\InvalidArgumentException $e) { session()->flash('error', $e->getMessage()); } }); } // Reschedule public function openRescheduleModal(): void { $this->showRescheduleModal = true; $this->newDate = $this->consultation->booking_date->format('Y-m-d'); $this->newTime = ''; $this->loadAvailableSlots(); } public function closeRescheduleModal(): void { $this->showRescheduleModal = false; $this->newDate = ''; $this->newTime = ''; $this->availableSlots = []; } public function updatedNewDate(): void { $this->loadAvailableSlots(); $this->newTime = ''; } private function loadAvailableSlots(): void { if ($this->newDate) { $service = app(AvailabilityService::class); $this->availableSlots = $service->getAvailableSlots(Carbon::parse($this->newDate)); } } public function reschedule(): void { $this->validate([ 'newDate' => ['required', 'date', 'after_or_equal:today'], 'newTime' => ['required'], ]); $oldDate = $this->consultation->booking_date; $oldTime = $this->consultation->booking_time; // Check if same date/time if ($oldDate->format('Y-m-d') === $this->newDate && $oldTime === $this->newTime) { session()->flash('info', __('messages.no_changes_made')); $this->closeRescheduleModal(); return; } // Verify slot available $service = app(AvailabilityService::class); $slots = $service->getAvailableSlots(Carbon::parse($this->newDate)); if (!in_array($this->newTime, $slots)) { $this->addError('newTime', __('booking.slot_not_available')); return; } // Guard against missing user if (!$this->consultation->user) { session()->flash('error', __('messages.client_account_not_found')); return; } DB::transaction(function () use ($oldDate, $oldTime) { $this->consultation->reschedule($this->newDate, $this->newTime); $this->consultation = $this->consultation->fresh()->load('user'); // Generate new .ics $icsContent = ''; try { $calendarService = app(CalendarService::class); $icsContent = $calendarService->generateIcs($this->consultation); } catch (\Exception $e) { Log::error('Failed to generate ICS on reschedule', [ 'consultation_id' => $this->consultation->id, 'error' => $e->getMessage(), ]); } // Notify client try { $this->consultation->user->notify( new ConsultationRescheduled($this->consultation, $oldDate, $oldTime, $icsContent) ); } catch (\Exception $e) { Log::error('Failed to send reschedule notification', [ 'consultation_id' => $this->consultation->id, 'error' => $e->getMessage(), ]); } // Log AdminLog::create([ 'admin_id' => auth()->id(), 'action' => 'reschedule', 'target_type' => 'consultation', 'target_id' => $this->consultation->id, 'old_values' => ['date' => $oldDate->format('Y-m-d'), 'time' => $oldTime], 'new_values' => ['date' => $this->newDate, 'time' => $this->newTime], 'ip_address' => request()->ip(), 'created_at' => now(), ]); }); session()->flash('success', __('messages.consultation_rescheduled')); $this->closeRescheduleModal(); } // Notes public function addNote(): void { $this->validate([ 'newNote' => ['required', 'string', 'max:1000'], ]); $this->consultation->addNote($this->newNote, auth()->id()); $this->consultation = $this->consultation->fresh(); $this->newNote = ''; session()->flash('success', __('messages.note_added')); } public function startEditNote(int $index): void { $notes = $this->consultation->admin_notes ?? []; if (isset($notes[$index])) { $this->editingNoteIndex = $index; $this->editingNoteText = $notes[$index]['text']; } } public function cancelEditNote(): void { $this->editingNoteIndex = null; $this->editingNoteText = ''; } public function updateNote(): void { $this->validate([ 'editingNoteText' => ['required', 'string', 'max:1000'], ]); if ($this->editingNoteIndex !== null) { $this->consultation->updateNote($this->editingNoteIndex, $this->editingNoteText); $this->consultation = $this->consultation->fresh(); $this->cancelEditNote(); session()->flash('success', __('messages.note_updated')); } } public function deleteNote(int $index): void { $this->consultation->deleteNote($index); $this->consultation = $this->consultation->fresh(); session()->flash('success', __('messages.note_deleted')); } private function logStatusChange(string $oldStatus, string $newStatus): void { AdminLog::create([ 'admin_id' => auth()->id(), 'action' => 'status_change', 'target_type' => 'consultation', 'target_id' => $this->consultation->id, 'old_values' => ['status' => $oldStatus], 'new_values' => ['status' => $newStatus], 'ip_address' => request()->ip(), 'created_at' => now(), ]); } public function with(): array { return [ 'adminUsers' => User::query() ->where('user_type', 'admin') ->pluck('full_name', 'id'), ]; } }; ?>
{{ $note['text'] }}
{{ __('admin.no_notes') }}
@endforelse{{ __('messages.client_account_not_found') }}
@endif{{ __('admin.current_schedule') }}
{{ $consultation->booking_date->translatedFormat('l, d M Y') }} {{ __('admin.to') }} {{ \Carbon\Carbon::parse($consultation->booking_time)->format('g:i A') }}
{{ __('admin.no_slots_available') }}
@endif @error('newTime')