sackey e839d40a99
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
Initial commit
2025-07-30 17:15:50 +00:00

205 lines
6.8 KiB
PHP

<?php
namespace App\Livewire\Appointments;
use Livewire\Component;
use Livewire\Attributes\On;
use App\Models\Appointment;
use App\Models\Customer;
use App\Models\Vehicle;
use App\Models\Technician;
use Carbon\Carbon;
class Form extends Component
{
public $showModal = true;
public $appointment = null;
public $editing = false;
// Form fields
public $customer_id = '';
public $vehicle_id = '';
public $assigned_technician_id = '';
public $scheduled_date = '';
public $scheduled_time = '';
public $estimated_duration_minutes = 60;
public $appointment_type = 'maintenance';
public $service_requested = '';
public $customer_notes = '';
public $internal_notes = '';
// Options
public $customers = [];
public $vehicles = [];
public $technicians = [];
public $availableTimeSlots = [];
public $appointmentTypes = [
'maintenance' => 'Maintenance',
'repair' => 'Repair',
'inspection' => 'Inspection',
'estimate' => 'Estimate',
'pickup' => 'Pickup',
'delivery' => 'Delivery'
];
public $durationOptions = [
30 => '30 minutes',
60 => '1 hour',
90 => '1.5 hours',
120 => '2 hours',
180 => '3 hours',
240 => '4 hours',
300 => '5 hours',
360 => '6 hours',
480 => '8 hours'
];
protected $rules = [
'customer_id' => 'required|exists:customers,id',
'vehicle_id' => 'required|exists:vehicles,id',
'assigned_technician_id' => 'nullable|exists:technicians,id',
'scheduled_date' => 'required|date|after_or_equal:today',
'scheduled_time' => 'required|date_format:H:i',
'estimated_duration_minutes' => 'required|integer|min:15|max:480',
'appointment_type' => 'required|in:maintenance,repair,inspection,estimate,pickup,delivery',
'service_requested' => 'required|string|max:1000',
'customer_notes' => 'nullable|string|max:1000',
'internal_notes' => 'nullable|string|max:1000'
];
public function mount($appointment = null)
{
$this->customers = Customer::orderBy('first_name')->get();
$this->technicians = Technician::where('status', 'active')->orderBy('first_name')->get();
if ($appointment) {
$this->appointment = $appointment;
$this->editing = true;
$this->loadAppointmentData();
} else {
$this->scheduled_date = now()->addDay()->format('Y-m-d');
$this->scheduled_time = '09:00';
}
}
public function loadAppointmentData()
{
$this->customer_id = $this->appointment->customer_id;
$this->vehicle_id = $this->appointment->vehicle_id;
$this->assigned_technician_id = $this->appointment->assigned_technician_id;
$this->scheduled_date = $this->appointment->scheduled_datetime->format('Y-m-d');
$this->scheduled_time = $this->appointment->scheduled_datetime->format('H:i');
$this->estimated_duration_minutes = $this->appointment->estimated_duration_minutes;
$this->appointment_type = $this->appointment->appointment_type;
$this->service_requested = $this->appointment->service_requested;
$this->customer_notes = $this->appointment->customer_notes;
$this->internal_notes = $this->appointment->internal_notes;
$this->loadVehicles();
}
public function updatedCustomerId()
{
$this->vehicle_id = '';
$this->loadVehicles();
}
public function updatedScheduledDate()
{
$this->checkTimeSlotAvailability();
}
public function updatedScheduledTime()
{
$this->checkTimeSlotAvailability();
}
public function updatedAssignedTechnicianId()
{
$this->checkTimeSlotAvailability();
}
public function loadVehicles()
{
if ($this->customer_id) {
$this->vehicles = Vehicle::where('customer_id', $this->customer_id)->get();
} else {
$this->vehicles = [];
}
}
public function checkTimeSlotAvailability()
{
if (!$this->scheduled_date || !$this->scheduled_time || !$this->assigned_technician_id) {
return;
}
$scheduledDateTime = Carbon::parse($this->scheduled_date . ' ' . $this->scheduled_time);
$endDateTime = $scheduledDateTime->copy()->addMinutes($this->estimated_duration_minutes);
// Check for conflicts
$conflicts = Appointment::where('assigned_technician_id', $this->assigned_technician_id)
->where('status', '!=', 'cancelled')
->where(function ($query) use ($scheduledDateTime, $endDateTime) {
$query->whereBetween('scheduled_datetime', [$scheduledDateTime, $endDateTime])
->orWhere(function ($q) use ($scheduledDateTime, $endDateTime) {
$q->where('scheduled_datetime', '<=', $scheduledDateTime)
->whereRaw('DATE_ADD(scheduled_datetime, INTERVAL estimated_duration_minutes MINUTE) > ?', [$scheduledDateTime]);
});
});
if ($this->editing && $this->appointment) {
$conflicts->where('id', '!=', $this->appointment->id);
}
if ($conflicts->exists()) {
$this->addError('scheduled_time', 'This time slot conflicts with another appointment for the selected technician.');
} else {
$this->resetErrorBag('scheduled_time');
}
}
public function save()
{
$this->validate();
$scheduledDateTime = Carbon::parse($this->scheduled_date . ' ' . $this->scheduled_time);
$data = [
'customer_id' => $this->customer_id,
'vehicle_id' => $this->vehicle_id,
'assigned_technician_id' => $this->assigned_technician_id ?: null,
'scheduled_datetime' => $scheduledDateTime,
'estimated_duration_minutes' => $this->estimated_duration_minutes,
'appointment_type' => $this->appointment_type,
'service_requested' => $this->service_requested,
'customer_notes' => $this->customer_notes,
'internal_notes' => $this->internal_notes,
'status' => 'scheduled'
];
if ($this->editing && $this->appointment) {
$this->appointment->update($data);
session()->flash('message', 'Appointment updated successfully!');
} else {
Appointment::create($data);
session()->flash('message', 'Appointment scheduled successfully!');
}
$this->dispatch('appointment-saved');
$this->closeModal();
}
public function closeModal()
{
$this->showModal = false;
$this->dispatch('close-appointment-form');
}
public function render()
{
return view('livewire.appointments.form');
}
}