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

283 lines
9.3 KiB
PHP

<?php
namespace App\Livewire\Appointments;
use Livewire\Component;
use App\Models\Appointment;
use App\Models\Technician;
use Carbon\Carbon;
class Calendar extends Component
{
public $currentDate;
public $currentMonth;
public $currentYear;
public $selectedDate;
public $selectedTechnician = '';
public $viewType = 'month'; // month, week, day
public $calendarDays = [];
public $appointments = [];
public $technicians = [];
public $showAppointmentModal = false;
public $selectedAppointment = null;
public function mount()
{
$this->currentDate = now();
$this->currentMonth = $this->currentDate->month;
$this->currentYear = $this->currentDate->year;
$this->selectedDate = $this->currentDate->format('Y-m-d');
$this->technicians = Technician::where('status', 'active')->orderBy('first_name')->get();
$this->generateCalendar();
$this->loadAppointments();
}
public function updatedSelectedTechnician()
{
$this->loadAppointments();
}
public function setViewType($type)
{
$this->viewType = $type;
$this->generateCalendar();
$this->loadAppointments();
}
public function previousPeriod()
{
switch ($this->viewType) {
case 'month':
$this->currentDate = $this->currentDate->subMonth();
break;
case 'week':
$this->currentDate = $this->currentDate->subWeek();
break;
case 'day':
$this->currentDate = $this->currentDate->subDay();
break;
}
$this->currentMonth = $this->currentDate->month;
$this->currentYear = $this->currentDate->year;
$this->generateCalendar();
$this->loadAppointments();
}
public function nextPeriod()
{
switch ($this->viewType) {
case 'month':
$this->currentDate = $this->currentDate->addMonth();
break;
case 'week':
$this->currentDate = $this->currentDate->addWeek();
break;
case 'day':
$this->currentDate = $this->currentDate->addDay();
break;
}
$this->currentMonth = $this->currentDate->month;
$this->currentYear = $this->currentDate->year;
$this->generateCalendar();
$this->loadAppointments();
}
public function today()
{
$this->currentDate = now();
$this->currentMonth = $this->currentDate->month;
$this->currentYear = $this->currentDate->year;
$this->selectedDate = $this->currentDate->format('Y-m-d');
$this->generateCalendar();
$this->loadAppointments();
}
public function selectDate($date)
{
$this->selectedDate = $date;
$this->currentDate = Carbon::parse($date);
$this->dispatch('date-selected', date: $date);
}
public function showAppointmentDetails($appointmentId)
{
$this->selectedAppointment = Appointment::with(['customer', 'vehicle', 'assignedTechnician'])
->find($appointmentId);
$this->showAppointmentModal = true;
}
public function closeAppointmentModal()
{
$this->showAppointmentModal = false;
$this->selectedAppointment = null;
}
private function generateCalendar()
{
$this->calendarDays = [];
switch ($this->viewType) {
case 'month':
$this->generateMonthCalendar();
break;
case 'week':
$this->generateWeekCalendar();
break;
case 'day':
$this->generateDayCalendar();
break;
}
}
private function generateMonthCalendar()
{
$startOfMonth = $this->currentDate->copy()->startOfMonth();
$endOfMonth = $this->currentDate->copy()->endOfMonth();
$startOfCalendar = $startOfMonth->copy()->startOfWeek();
$endOfCalendar = $endOfMonth->copy()->endOfWeek();
$current = $startOfCalendar->copy();
$this->calendarDays = [];
while ($current <= $endOfCalendar) {
$this->calendarDays[] = [
'date' => $current->format('Y-m-d'),
'day' => $current->day,
'isCurrentMonth' => $current->month === $this->currentMonth,
'isToday' => $current->isToday(),
'isSelected' => $current->format('Y-m-d') === $this->selectedDate,
'dayName' => $current->format('D'),
];
$current->addDay();
}
}
private function generateWeekCalendar()
{
$startOfWeek = $this->currentDate->copy()->startOfWeek();
$this->calendarDays = [];
for ($i = 0; $i < 7; $i++) {
$date = $startOfWeek->copy()->addDays($i);
$this->calendarDays[] = [
'date' => $date->format('Y-m-d'),
'day' => $date->day,
'isCurrentMonth' => true,
'isToday' => $date->isToday(),
'isSelected' => $date->format('Y-m-d') === $this->selectedDate,
'dayName' => $date->format('l'),
'fullDate' => $date->format('M j'),
];
}
}
private function generateDayCalendar()
{
$this->calendarDays = [[
'date' => $this->currentDate->format('Y-m-d'),
'day' => $this->currentDate->day,
'isCurrentMonth' => true,
'isToday' => $this->currentDate->isToday(),
'isSelected' => true,
'dayName' => $this->currentDate->format('l'),
'fullDate' => $this->currentDate->format('F j, Y'),
]];
}
private function loadAppointments()
{
$query = Appointment::with(['customer', 'vehicle', 'assignedTechnician']);
switch ($this->viewType) {
case 'month':
$startDate = $this->currentDate->copy()->startOfMonth();
$endDate = $this->currentDate->copy()->endOfMonth();
break;
case 'week':
$startDate = $this->currentDate->copy()->startOfWeek();
$endDate = $this->currentDate->copy()->endOfWeek();
break;
case 'day':
$startDate = $this->currentDate->copy()->startOfDay();
$endDate = $this->currentDate->copy()->endOfDay();
break;
}
$query->whereBetween('scheduled_datetime', [$startDate, $endDate]);
if ($this->selectedTechnician) {
$query->where('assigned_technician_id', $this->selectedTechnician);
}
$appointments = $query->orderBy('scheduled_datetime')->get();
// Group appointments by date and convert to array for blade template
$this->appointments = $appointments->groupBy(function ($appointment) {
return $appointment->scheduled_datetime->format('Y-m-d');
})->map(function ($dayAppointments) {
return $dayAppointments->map(function ($appointment) {
return [
'id' => $appointment->id,
'scheduled_datetime' => $appointment->scheduled_datetime->toISOString(),
'service_requested' => $appointment->service_requested,
'status' => $appointment->status,
'status_color' => $appointment->status_color,
'customer' => [
'first_name' => $appointment->customer->first_name ?? '',
'last_name' => $appointment->customer->last_name ?? '',
],
'assigned_technician' => [
'first_name' => $appointment->assignedTechnician->first_name ?? '',
'last_name' => $appointment->assignedTechnician->last_name ?? '',
],
];
})->toArray();
})->toArray();
}
public function getTimeSlots()
{
$slots = [];
$start = 8; // 8 AM
$end = 18; // 6 PM
for ($hour = $start; $hour < $end; $hour++) {
$slots[] = [
'time' => sprintf('%02d:00', $hour),
'label' => Carbon::createFromTime($hour, 0)->format('g:i A'),
];
$slots[] = [
'time' => sprintf('%02d:30', $hour),
'label' => Carbon::createFromTime($hour, 30)->format('g:i A'),
];
}
return $slots;
}
public function getCurrentPeriodLabel()
{
switch ($this->viewType) {
case 'month':
return $this->currentDate->format('F Y');
case 'week':
$start = $this->currentDate->copy()->startOfWeek();
$end = $this->currentDate->copy()->endOfWeek();
return $start->format('M j') . ' - ' . $end->format('M j, Y');
case 'day':
return $this->currentDate->format('l, F j, Y');
}
}
public function render()
{
return view('livewire.appointments.calendar', [
'currentPeriodLabel' => $this->getCurrentPeriodLabel(),
'timeSlots' => $this->getTimeSlots(),
'appointmentCount' => collect($this->appointments)->flatten(1)->count(),
]);
}
}