@extends('layouts.app') @section('title', 'Mon Agenda - Prestataire') @push('styles') @endpush @section('content')
{{-- Header --}}
Vue planning

Mon Agenda 📱 Paysage +

{{-- Stats rapides - toutes sur une ligne --}}
{{ $stats['total'] ?? 0 }} Total
{{ $stats['pending'] ?? 0 }} En attente
{{ $stats['confirmed'] ?? 0 }} Confirmées
{{ $stats['completed'] ?? 0 }} Complétées
{{-- Filtres et Vue --}} @php $currentView = request('view', 'month'); $currentFilter = request('filter', 'all'); $currentStatus = request('status', 'all'); $currentDate = request('date') ? \Carbon\Carbon::parse(request('date')) : now(); $prevMonth = $currentDate->copy()->subMonth()->format('Y-m-d'); $nextMonth = $currentDate->copy()->addMonth()->format('Y-m-d'); $prevWeek = $currentDate->copy()->subWeek()->format('Y-m-d'); $nextWeek = $currentDate->copy()->addWeek()->format('Y-m-d'); $today = now()->format('Y-m-d'); // Appliquer filtre sur les événements $allEvents = collect($calendarEvents ?? []); if($currentFilter !== 'all') { $allEvents = $allEvents->filter(fn($e) => ($e['type'] ?? 'service') === $currentFilter); } if($currentStatus !== 'all') { $allEvents = $allEvents->filter(fn($e) => ($e['status'] ?? 'pending') === $currentStatus); } // Détecter les conflits horaires (même heure, durée 1h par défaut) $eventsWithConflicts = $allEvents->map(function($event) use ($allEvents) { $event['has_conflict'] = false; if(!isset($event['start'])) return $event; $start = \Carbon\Carbon::parse($event['start']); $duration = $event['duration'] ?? 60; // durée en minutes, défaut 1h $end = $start->copy()->addMinutes($duration); $status = $event['status'] ?? 'pending'; // Chercher conflits avec événements acceptés/confirmés $conflicts = $allEvents->filter(function($other) use ($event, $start, $end) { if(($other['id'] ?? null) === ($event['id'] ?? null)) return false; if(!isset($other['start'])) return false; $otherStatus = $other['status'] ?? 'pending'; // Un conflit existe si l'autre est accepté/confirmé if(!in_array($otherStatus, ['accepted', 'confirmed'])) return false; $otherStart = \Carbon\Carbon::parse($other['start']); $otherDuration = $other['duration'] ?? 60; $otherEnd = $otherStart->copy()->addMinutes($otherDuration); // Chevauchement de créneaux return $start < $otherEnd && $end > $otherStart; }); // Marquer comme conflit si en attente et chevauche un accepté if($status === 'pending' && $conflicts->count() > 0) { $event['has_conflict'] = true; } return $event; }); $allEvents = $eventsWithConflicts; @endphp
{{-- Toolbar --}}
@php $mobileFilterLabels = [ 'all' => 'Tous types', 'service' => 'Services', 'equipment' => 'Équipement', 'food' => 'Food', 'manual' => 'Manuel', ]; $mobileStatusLabels = [ 'all' => 'Tous statuts', 'pending' => 'En attente', 'confirmed' => 'Confirmé', 'accepted' => 'Accepté', 'completed' => 'Terminé', 'cancelled' => 'Annulé', ]; @endphp
{{ $currentView === 'week' ? 'Vue semaine' : 'Vue mois' }} • {{ $mobileFilterLabels[$currentFilter] ?? 'Filtre' }} • {{ $mobileStatusLabels[$currentStatus] ?? 'Statut' }}
@if($currentFilter !== 'all' || $currentStatus !== 'all') Réinitialiser @endif
{{-- Filtres Type - Scrollable sur mobile --}} {{-- Filtres Statut --}}

Glissez horizontalement pour afficher tous les filtres.

{{-- Vues - Compact sur mobile --}}
{{-- Navigation --}}
@if($currentView === 'week')

{{ $currentDate->copy()->startOfWeek()->format('d') }} - {{ $currentDate->copy()->endOfWeek()->format('d M') }}

Aujourd'hui
@else

{{ $currentDate->translatedFormat('F Y') }}

Aujourd'hui
@endif
{{-- Calendrier --}}
@if($currentView === 'week') {{-- Vue Semaine --}} @php $startOfWeek = $currentDate->copy()->startOfWeek(\Carbon\Carbon::MONDAY); $endOfWeek = $currentDate->copy()->endOfWeek(\Carbon\Carbon::SUNDAY); $hours = range(0, 23); // Auto-scroll helper: find earliest event hour in this week $weekEventHours = $allEvents ->filter(function($e) use ($startOfWeek, $endOfWeek) { if (!isset($e['start'])) return false; try { $s = \Carbon\Carbon::parse($e['start']); return $s->betweenIncluded($startOfWeek->copy()->startOfDay(), $endOfWeek->copy()->endOfDay()); } catch (\Exception $ex) { return false; } }) ->map(function($e) { try { return (int) \Carbon\Carbon::parse($e['start'])->hour; } catch (\Exception $ex) { return null; } }) ->filter(fn($h) => $h !== null) ->values(); $scrollToHour = $weekEventHours->count() ? (int) $weekEventHours->min() : null; @endphp
{{-- Header --}}
@for($d = 0; $d < 7; $d++) @php $day = $startOfWeek->copy()->addDays($d); @endphp
{{ $day->translatedFormat('D') }}
{{ $day->day }}
@endfor {{-- Heures --}} @foreach($hours as $hour) @php $hourStr = sprintf('%02d:00', $hour); @endphp
{{ $hourStr }}
@for($d = 0; $d < 7; $d++) @php $day = $startOfWeek->copy()->addDays($d); $dayStr = $day->format('Y-m-d'); $cellStart = \Carbon\Carbon::parse($dayStr . ' ' . $hourStr); $cellEnd = $cellStart->copy()->addHour(); // Show events that overlap this hour cell (so a 3h booking appears on 3 rows) $dayEvents = $allEvents->filter(function($e) use ($dayStr, $cellStart, $cellEnd) { if(!isset($e['start'])) return false; $start = \Carbon\Carbon::parse($e['start']); if ($start->format('Y-m-d') !== $dayStr) return false; $duration = $e['duration'] ?? 60; // minutes if (isset($e['end']) && $e['end']) { try { $endParsed = \Carbon\Carbon::parse($e['end']); $duration = max(1, $start->diffInMinutes($endParsed)); } catch (\Exception $ex) { // ignore parse errors, fallback to duration } } $end = $start->copy()->addMinutes($duration); // overlap with cell [cellStart, cellEnd) return $start->lt($cellEnd) && $end->gt($cellStart); }); @endphp
@foreach($dayEvents->take(2) as $event) @php $eventStatus = $event['status'] ?? 'pending'; $hasConflict = $event['has_conflict'] ?? false; $statusClass = 'event-status-' . $eventStatus; $conflictClass = $hasConflict ? 'event-conflict' : ''; $isContinuation = false; try { $eventStart = isset($event['start']) ? \Carbon\Carbon::parse($event['start']) : null; $isContinuation = $eventStart && $eventStart->hour !== $hour; } catch (\Exception $ex) { $isContinuation = false; } @endphp @if(($event['type'] ?? 'service') === 'manual')
{{ $isContinuation ? '↳ ' : '' }}{{ Str::limit($event['title'] ?? '', 15) }}
@else {{ $isContinuation ? '↳ ' : '' }}{{ Str::limit($event['title'] ?? '', 15) }} @endif @endforeach
@endfor @endforeach
@if($scrollToHour !== null) @endif @else {{-- Vue Mois --}}
{{-- Jours de la semaine - Version courte pour portrait mobile --}} @foreach(['L', 'M', 'M', 'J', 'V', 'S', 'D'] as $index => $dayShort) @php $dayFull = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'][$index]; @endphp
{{ $dayShort }}
@endforeach {{-- Jours du mois --}} @php $startOfMonth = $currentDate->copy()->startOfMonth(); $endOfMonth = $currentDate->copy()->endOfMonth(); $startOfCalendar = $startOfMonth->copy()->startOfWeek(\Carbon\Carbon::MONDAY); $endOfCalendar = $endOfMonth->copy()->endOfWeek(\Carbon\Carbon::SUNDAY); @endphp @for($date = $startOfCalendar->copy(); $date <= $endOfCalendar; $date->addDay()) @php $isToday = $date->isToday(); $isCurrentMonth = $date->month === $currentDate->month; $isWeekend = $date->isWeekend(); $dateStr = $date->format('Y-m-d'); $dayEvents = $allEvents->filter(function($event) use ($dateStr) { $start = isset($event['start']) ? \Carbon\Carbon::parse($event['start'])->format('Y-m-d') : null; return $start === $dateStr; })->take(2); // Limité à 2 pour mobile portrait $totalDayEvents = $allEvents->filter(function($event) use ($dateStr) { $start = isset($event['start']) ? \Carbon\Carbon::parse($event['start'])->format('Y-m-d') : null; return $start === $dateStr; })->count(); @endphp
{{ $date->day }}
@foreach($dayEvents as $event) @php $eventStatus = $event['status'] ?? 'pending'; $hasConflict = $event['has_conflict'] ?? false; $statusClass = 'event-status-' . $eventStatus; $conflictClass = $hasConflict ? 'event-conflict' : ''; // Titre court pour mobile $shortTitle = Str::limit($event['title'] ?? '', 12); $eventTime = isset($event['start']) ? \Carbon\Carbon::parse($event['start'])->format('H:i') : null; @endphp @if(($event['type'] ?? 'service') === 'manual')
@if($eventTime) {{ $eventTime }} @endif {{ $shortTitle }}
@else @if($eventTime) {{ $eventTime }} @endif {{ $shortTitle }} @endif @endforeach @if($totalDayEvents > 2)
+{{ $totalDayEvents - 2 }}
@endif
@endfor
@endif
{{-- Légende - Compacte sur mobile --}}
Serv. Éq. Food Man. Conflit
{{-- Liste des demandes récentes --}}

Demandes récentes

{{ count($recentDemands ?? []) }}
@forelse($recentDemands ?? [] as $demand) @php $dType = $demand['type'] ?? 'service'; $dStatus = $demand['status'] ?? 'pending'; $statusColors = [ 'pending' => 'bg-amber-100 text-amber-700', 'confirmed' => 'bg-blue-100 text-blue-700', 'accepted' => 'bg-green-100 text-green-700', 'completed' => 'bg-gray-100 text-gray-700', 'cancelled' => 'bg-red-100 text-red-700', ]; $statusLabels = [ 'pending' => 'En attente', 'confirmed' => 'Confirmée', 'accepted' => 'Acceptée', 'completed' => 'Terminée', 'cancelled' => 'Annulée', ]; $typeIcons = [ 'service' => '🎯', 'equipment' => '🔧', 'food' => '🍽️', 'manual' => '✏️', ]; @endphp
{{ $typeIcons[$dType] ?? '📋' }} {{ $demand['title'] ?? 'Demande' }}
{{ $demand['client_name'] ?? 'Client' }} • {{ isset($demand['start_date']) ? \Carbon\Carbon::parse($demand['start_date'])->format('d/m H:i') : '--' }}
{{ $statusLabels[$dStatus] ?? ucfirst($dStatus) }}
@empty
📭

Aucune demande récente

@endforelse
{{-- Modal Ajouter Événement --}} {{-- Modal Détails Événement Manuel --}} {{-- Modal Détails Journée (tap/clic) --}} @endsection