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'), ]; } }; ?>
{{ __('common.back') }}
{{ __('admin.consultation_detail') }} @if($consultation->status === \App\Enums\ConsultationStatus::Approved)
{{ __('admin.reschedule') }}
@endif
@if(session('success')) {{ session('success') }} @endif @if(session('error')) {{ session('error') }} @endif @if(session('info')) {{ session('info') }} @endif
{{ __('admin.booking_details') }}
{{ __('admin.requested_date') }}
{{ $consultation->booking_date->translatedFormat('l, d M Y') }}
{{ __('admin.requested_time') }}
{{ \Carbon\Carbon::parse($consultation->booking_time)->format('g:i A') }}
{{ __('admin.current_status') }}
@php $statusVariant = match($consultation->status) { \App\Enums\ConsultationStatus::Pending => 'warning', \App\Enums\ConsultationStatus::Approved => 'primary', \App\Enums\ConsultationStatus::Completed => 'success', \App\Enums\ConsultationStatus::Cancelled => 'danger', \App\Enums\ConsultationStatus::NoShow => 'danger', \App\Enums\ConsultationStatus::Rejected => 'danger', }; @endphp {{ $consultation->status->label() }}
{{ __('admin.consultation_type') }}
{{ $consultation->consultation_type->label() }}
@if($consultation->problem_summary)
{{ __('admin.problem_summary') }}
{{ $consultation->problem_summary }}
@endif
@if($consultation->consultation_type === \App\Enums\ConsultationType::Paid)
{{ __('admin.payment_details') }} @if($consultation->payment_status === \App\Enums\PaymentStatus::Pending) {{ __('admin.mark_payment_received') }} @endif
{{ __('admin.payment_amount') }}
{{ number_format($consultation->payment_amount, 2) }} {{ __('common.currency') }}
{{ __('admin.payment_status') }}
@php $paymentVariant = match($consultation->payment_status) { \App\Enums\PaymentStatus::Pending => 'warning', \App\Enums\PaymentStatus::Received => 'success', default => 'outline', }; @endphp {{ $consultation->payment_status->label() }}
@if($consultation->payment_received_at)
{{ __('admin.payment_received_at') }}
{{ $consultation->payment_received_at->translatedFormat('d M Y, g:i A') }}
@endif
@endif
{{ __('admin.admin_notes') }}
@error('newNote') {{ $message }} @enderror
{{ __('admin.add_note') }}
@forelse($consultation->admin_notes ?? [] as $index => $note)
@if($editingNoteIndex === $index) @error('editingNoteText') {{ $message }} @enderror
{{ __('common.cancel') }} {{ __('common.save') }}
@else

{{ $note['text'] }}

{{ __('admin.added_by') }}: {{ $adminUsers[$note['admin_id']] ?? __('common.unknown') }} @if(isset($note['updated_at'])) ({{ __('admin.updated') }}) @endif {{ \Carbon\Carbon::parse($note['created_at'])->translatedFormat('d M Y, g:i A') }}
{{ __('common.edit') }} {{ __('common.delete') }}
@endif
@empty

{{ __('admin.no_notes') }}

@endforelse
{{ __('admin.client_information') }} @if($consultation->user)
{{ __('admin.client_name') }}
{{ $consultation->user->full_name }}
{{ __('admin.client_email') }}
{{ $consultation->user->email }}
@if($consultation->user->phone)
{{ __('admin.client_phone') }}
{{ $consultation->user->phone }}
@endif
{{ __('admin.view_client_history') }}
@else

{{ __('messages.client_account_not_found') }}

@endif
@if($consultation->status === \App\Enums\ConsultationStatus::Approved)
{{ __('common.actions') }}
{{ __('admin.mark_completed') }} {{ __('admin.mark_no_show') }} {{ __('admin.cancel_consultation') }}
@endif @if($consultation->status === \App\Enums\ConsultationStatus::Pending)
{{ __('common.actions') }} {{ __('admin.cancel_consultation') }}
@endif
{{ __('admin.reschedule_consultation') }}

{{ __('admin.current_schedule') }}

{{ $consultation->booking_date->translatedFormat('l, d M Y') }} {{ __('admin.to') }} {{ \Carbon\Carbon::parse($consultation->booking_time)->format('g:i A') }}

{{ __('admin.new_date') }} @error('newDate') {{ $message }} @enderror {{ __('admin.new_time') }} @if(count($availableSlots) > 0) @foreach($availableSlots as $slot) @endforeach @else

{{ __('admin.no_slots_available') }}

@endif @error('newTime') {{ $message }} @enderror
{{ __('common.cancel') }} {{ __('admin.reschedule') }}