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(), ]); } }