323 lines
18 KiB
PHP
323 lines
18 KiB
PHP
<div class="space-y-6" wire:key="driver-management">
|
|
{{-- Header --}}
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<flux:heading size="lg">Driver Management</flux:heading>
|
|
<flux:subheading>Manage drivers, licenses, and vehicle assignments</flux:subheading>
|
|
</div>
|
|
<flux:button wire:click="openCreateModal" variant="primary" size="sm" icon="plus">
|
|
Add Driver
|
|
</flux:button>
|
|
</div>
|
|
|
|
{{-- Flash Messages --}}
|
|
@if (session()->has('message'))
|
|
<div class="bg-green-100 dark:bg-green-900 border border-green-400 dark:border-green-600 text-green-700 dark:text-green-200 px-4 py-3 rounded relative" role="alert">
|
|
<span class="block sm:inline">{{ session('message') }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
@if (session()->has('error'))
|
|
<div class="bg-red-100 dark:bg-red-900 border border-red-400 dark:border-red-600 text-red-700 dark:text-red-200 px-4 py-3 rounded relative" role="alert">
|
|
<span class="block sm:inline">{{ session('error') }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Stats Cards --}}
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<flux:card>
|
|
<div class="text-center">
|
|
<div class="text-2xl font-bold text-blue-600">{{ $this->stats['total_drivers'] }}</div>
|
|
<div class="text-sm text-gray-600">Total Drivers</div>
|
|
</div>
|
|
</flux:card>
|
|
<flux:card>
|
|
<div class="text-center">
|
|
<div class="text-2xl font-bold text-green-600">{{ $this->stats['active_drivers'] }}</div>
|
|
<div class="text-sm text-gray-600">Active Drivers</div>
|
|
</div>
|
|
</flux:card>
|
|
<flux:card>
|
|
<div class="text-center">
|
|
<div class="text-2xl font-bold text-yellow-600">{{ $this->stats['expiring_licenses'] }}</div>
|
|
<div class="text-sm text-gray-600">Expiring Licenses</div>
|
|
</div>
|
|
</flux:card>
|
|
<flux:card>
|
|
<div class="text-center">
|
|
<div class="text-2xl font-bold text-purple-600">{{ $this->stats['assigned_vehicles'] }}</div>
|
|
<div class="text-sm text-gray-600">Assigned Vehicles</div>
|
|
</div>
|
|
</flux:card>
|
|
</div>
|
|
|
|
{{-- Filters --}}
|
|
<flux:card>
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<flux:input wire:model.live="filters.search" placeholder="Search drivers..." icon="magnifying-glass" />
|
|
|
|
<flux:select wire:model.live="filters.status">
|
|
<option value="">All Status</option>
|
|
<option value="active">Active</option>
|
|
<option value="inactive">Inactive</option>
|
|
<option value="suspended">Suspended</option>
|
|
</flux:select>
|
|
|
|
<flux:select wire:model.live="filters.license_status">
|
|
<option value="">All Licenses</option>
|
|
<option value="valid">Valid License</option>
|
|
<option value="expiring">Expiring Soon</option>
|
|
<option value="expired">Expired</option>
|
|
</flux:select>
|
|
|
|
<flux:select wire:model.live="filters.vehicle_assigned">
|
|
<option value="">All Drivers</option>
|
|
<option value="yes">Vehicle Assigned</option>
|
|
<option value="no">No Vehicle</option>
|
|
</flux:select>
|
|
</div>
|
|
</flux:card>
|
|
|
|
{{-- Drivers Table --}}
|
|
<flux:card>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Driver
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
License
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Status
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Vehicle
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Performance
|
|
</th>
|
|
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Actions
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
@forelse($drivers as $driver)
|
|
<tr>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<div class="flex items-center">
|
|
<div class="flex-shrink-0 h-10 w-10">
|
|
<div class="h-10 w-10 bg-blue-100 rounded-full flex items-center justify-center">
|
|
<span class="text-sm font-medium text-blue-700">
|
|
{{ strtoupper(substr($driver->name, 0, 1)) }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="ml-4">
|
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ $driver->name }}</div>
|
|
<div class="text-sm text-gray-500 dark:text-gray-400">{{ $driver->phone }}</div>
|
|
<div class="text-xs text-gray-400 dark:text-gray-500">ID: {{ $driver->driver_id }}</div>
|
|
@if($driver->user)
|
|
<div class="text-xs text-blue-600 dark:text-blue-400">User: {{ $driver->user->name }}</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<div class="text-sm text-gray-900">{{ $driver->license_number }}</div>
|
|
<div class="text-sm text-gray-500">{{ $driver->license_type }}</div>
|
|
@if($driver->license_expiry_date)
|
|
<div class="text-xs {{ $driver->license_expiry_date->isPast() ? 'text-red-600' : ($driver->license_expiry_date->diffInDays() < 30 ? 'text-yellow-600' : 'text-green-600') }}">
|
|
Expires: {{ $driver->license_expiry_date->format('M j, Y') }}
|
|
</div>
|
|
@endif
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<span class="inline-flex items-center px-2 py-1 text-xs font-semibold rounded-full
|
|
@if($driver->status === 'active') bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200
|
|
@elseif($driver->status === 'inactive') bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200
|
|
@else bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 @endif">
|
|
@if($driver->status === 'suspended')
|
|
<flux:icon.exclamation-triangle class="size-3 mr-1" />
|
|
@endif
|
|
{{ ucfirst($driver->status) }}
|
|
</span>
|
|
@if($driver->status === 'suspended')
|
|
<div class="text-xs text-red-600 dark:text-red-400 mt-1">Access restricted</div>
|
|
@endif
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
@if($driver->assigned_vehicle)
|
|
<div class="text-sm font-medium text-gray-900">{{ $driver->assigned_vehicle }}</div>
|
|
<div class="text-xs text-gray-500">Plate: {{ $driver->vehicle_plate ?? 'N/A' }}</div>
|
|
@else
|
|
<span class="text-sm text-gray-400">No vehicle assigned</span>
|
|
@endif
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
@if($driver->performance_score !== null)
|
|
<div class="flex items-center">
|
|
<div class="text-sm font-medium
|
|
@if($driver->performance_score >= 80) text-green-600
|
|
@elseif($driver->performance_score >= 60) text-yellow-600
|
|
@else text-red-600 @endif">
|
|
{{ $driver->performance_score }}%
|
|
</div>
|
|
<div class="ml-2 w-16 bg-gray-200 rounded-full h-2">
|
|
<div class="h-2 rounded-full
|
|
@if($driver->performance_score >= 80) bg-green-500
|
|
@elseif($driver->performance_score >= 60) bg-yellow-500
|
|
@else bg-red-500 @endif"
|
|
style="width: {{ $driver->performance_score }}%"></div>
|
|
</div>
|
|
</div>
|
|
@else
|
|
<span class="text-sm text-gray-400">No data</span>
|
|
@endif
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium space-x-2">
|
|
<flux:button wire:click="editDriver({{ $driver->id }})" variant="outline" size="xs">
|
|
Edit
|
|
</flux:button>
|
|
<flux:button wire:click="viewPerformance({{ $driver->id }})" variant="ghost" size="xs">
|
|
Performance
|
|
</flux:button>
|
|
@if($driver->status === 'active')
|
|
<flux:button wire:click="suspendDriver({{ $driver->id }})" variant="danger" size="xs">
|
|
Suspend
|
|
</flux:button>
|
|
@else
|
|
<flux:button wire:click="activateDriver({{ $driver->id }})" variant="primary" size="xs">
|
|
Activate
|
|
</flux:button>
|
|
@endif
|
|
<flux:button
|
|
wire:click="deleteDriver({{ $driver->id }})"
|
|
wire:confirm="Are you sure you want to delete this driver?"
|
|
variant="danger"
|
|
size="xs">
|
|
Delete
|
|
</flux:button>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="6" class="px-6 py-4 text-center text-gray-500">
|
|
No drivers found matching your criteria.
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{{-- Pagination --}}
|
|
<div class="mt-4">
|
|
{{ $drivers->links() }}
|
|
</div>
|
|
</flux:card>
|
|
|
|
{{-- Create/Edit Driver Modal --}}
|
|
{{-- Create/Edit Driver Modal --}}
|
|
<flux:modal name="driver-form" class="md:max-w-4xl md:w-full" wire:model.self="showModal">
|
|
<form wire:submit="{{ $editingDriver ? 'updateDriver' : 'createDriver' }}">
|
|
<div class="space-y-6 w-full">
|
|
<div>
|
|
<flux:heading size="lg">{{ $editingDriver ? 'Edit Driver' : 'Add Driver' }}</flux:heading>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<flux:input wire:model="form.name" label="Full Name" required />
|
|
<flux:input wire:model="form.driver_id" label="Driver ID" required />
|
|
|
|
<div>
|
|
<flux:label>Associated User Account</flux:label>
|
|
<flux:select wire:model="form.user_id" placeholder="Select a user (optional)">
|
|
<option value="">No user account</option>
|
|
@foreach($users as $user)
|
|
<option value="{{ $user->id }}">{{ $user->name }} ({{ $user->email }})</option>
|
|
@endforeach
|
|
</flux:select>
|
|
</div>
|
|
|
|
<flux:input wire:model="form.phone" label="Phone Number" />
|
|
<flux:input wire:model="form.email" label="Email Address" type="email" />
|
|
|
|
<flux:input wire:model="form.license_number" label="License Number" required />
|
|
<flux:input wire:model="form.license_type" label="License Type" placeholder="e.g., Commercial, Regular" />
|
|
|
|
<flux:input wire:model="form.license_expiry_date" label="License Expiry Date" type="date" />
|
|
|
|
<div>
|
|
<flux:label>Performance Score (0-100)</flux:label>
|
|
<flux:input wire:model="form.performance_score" type="number" min="0" max="100" placeholder="Optional performance score" />
|
|
</div>
|
|
|
|
<flux:select wire:model="form.status" label="Status">
|
|
<option value="active">Active</option>
|
|
<option value="inactive">Inactive</option>
|
|
<option value="suspended">Suspended</option>
|
|
</flux:select>
|
|
|
|
<div class="flex items-center space-x-2">
|
|
<flux:checkbox wire:model="form.is_active" />
|
|
<flux:label>Driver is active</flux:label>
|
|
</div>
|
|
|
|
<flux:input wire:model="form.assigned_vehicle" label="Assigned Vehicle" />
|
|
<flux:input wire:model="form.vehicle_plate" label="Vehicle Plate Number" />
|
|
</div>
|
|
|
|
<div class="col-span-full">
|
|
<flux:textarea wire:model="form.notes" label="Notes" rows="3" />
|
|
</div>
|
|
|
|
<div class="flex justify-end space-x-2">
|
|
<flux:button type="button" variant="ghost" wire:click="closeModal">Cancel</flux:button>
|
|
<flux:button type="submit" variant="primary">
|
|
{{ $editingDriver ? 'Update Driver' : 'Create Driver' }}
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</flux:modal>
|
|
|
|
{{-- Performance Modal --}}
|
|
<flux:modal name="performance-modal" x-show="$wire.showPerformanceModal" class="md:max-w-2xl">
|
|
@if($selectedDriver)
|
|
<div class="space-y-6">
|
|
<div>
|
|
<flux:heading size="lg">Performance Report: {{ $selectedDriver->name }}</flux:heading>
|
|
<flux:subheading>{{ $performancePeriod }} day analysis</flux:subheading>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div class="text-center">
|
|
<div class="text-xl font-bold text-blue-600">{{ $driverMetrics['total_trips'] ?? 0 }}</div>
|
|
<div class="text-sm text-gray-600">Total Trips</div>
|
|
</div>
|
|
<div class="text-center">
|
|
<div class="text-xl font-bold text-green-600">{{ $driverMetrics['avg_speed'] ?? 0 }} mph</div>
|
|
<div class="text-sm text-gray-600">Avg Speed</div>
|
|
</div>
|
|
<div class="text-center">
|
|
<div class="text-xl font-bold text-yellow-600">{{ $driverMetrics['violations'] ?? 0 }}</div>
|
|
<div class="text-sm text-gray-600">Violations</div>
|
|
</div>
|
|
<div class="text-center">
|
|
<div class="text-xl font-bold text-purple-600">{{ $driverMetrics['fuel_efficiency'] ?? 0 }} mpg</div>
|
|
<div class="text-sm text-gray-600">Fuel Efficiency</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex justify-end">
|
|
<flux:button wire:click="closePerformanceModal" variant="outline">Close</flux:button>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</flux:modal>
|
|
</div>
|