- Implemented the customer portal workflow progress component with detailed service progress tracking, including current status, workflow steps, and contact information. - Developed a management workflow analytics dashboard featuring key performance indicators, charts for revenue by branch, labor utilization, and recent quality issues. - Created tests for admin-only middleware to ensure proper access control for admin routes. - Added tests for customer portal view rendering and workflow integration, ensuring the workflow service operates correctly through various stages. - Introduced a .gitignore file for the debugbar storage directory to prevent unnecessary files from being tracked.
184 lines
12 KiB
PHP
184 lines
12 KiB
PHP
<x-layouts.customer-portal :job-card="$jobCard">
|
|
<div class="space-y-8">
|
|
<!-- Flash Messages -->
|
|
@if (session()->has('message'))
|
|
<div class="rounded-md bg-green-50 p-4">
|
|
<div class="flex">
|
|
<div class="flex-shrink-0">
|
|
<svg class="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
|
|
</svg>
|
|
</div>
|
|
<div class="ml-3">
|
|
<p class="text-sm font-medium text-green-800">{{ session('message') }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Progress Timeline -->
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<div class="flex justify-between items-center mb-6">
|
|
<h2 class="text-xl font-semibold text-gray-900">Service Progress</h2>
|
|
<button wire:click="refreshStatus" class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
|
<svg class="h-4 w-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
|
</svg>
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
|
|
<div class="flow-root">
|
|
<ul class="-mb-8">
|
|
@php
|
|
$steps = [
|
|
['key' => 'received', 'title' => 'Vehicle Received', 'description' => 'Your vehicle has been checked in'],
|
|
['key' => 'inspection', 'title' => 'Initial Inspection', 'description' => 'Comprehensive vehicle inspection completed'],
|
|
['key' => 'diagnosis', 'title' => 'Diagnosis', 'description' => 'Issue diagnosis and root cause analysis'],
|
|
['key' => 'estimate', 'title' => 'Estimate Provided', 'description' => 'Repair estimate prepared and sent'],
|
|
['key' => 'approved', 'title' => 'Work Approved', 'description' => 'Estimate approved, work can begin'],
|
|
['key' => 'in_progress', 'title' => 'Work in Progress', 'description' => 'Repairs and services being performed'],
|
|
['key' => 'completed', 'title' => 'Work Completed', 'description' => 'All repairs finished, ready for pickup'],
|
|
];
|
|
$currentStep = $jobCard->status;
|
|
@endphp
|
|
|
|
@foreach($steps as $index => $step)
|
|
@php
|
|
$isCompleted = in_array($currentStep, ['inspection', 'diagnosis', 'estimate_sent', 'estimate_approved', 'in_progress', 'completed']) && $step['key'] === 'received' ||
|
|
in_array($currentStep, ['diagnosis', 'estimate_sent', 'estimate_approved', 'in_progress', 'completed']) && $step['key'] === 'inspection' ||
|
|
in_array($currentStep, ['estimate_sent', 'estimate_approved', 'in_progress', 'completed']) && $step['key'] === 'diagnosis' ||
|
|
in_array($currentStep, ['estimate_sent', 'estimate_approved', 'in_progress', 'completed']) && $step['key'] === 'estimate' ||
|
|
in_array($currentStep, ['estimate_approved', 'in_progress', 'completed']) && $step['key'] === 'approved' ||
|
|
in_array($currentStep, ['in_progress', 'completed']) && $step['key'] === 'in_progress' ||
|
|
$currentStep === 'completed' && $step['key'] === 'completed';
|
|
|
|
$isCurrent = ($currentStep === 'pending' && $step['key'] === 'received') ||
|
|
($currentStep === 'inspection' && $step['key'] === 'inspection') ||
|
|
($currentStep === 'diagnosis' && $step['key'] === 'diagnosis') ||
|
|
($currentStep === 'estimate_sent' && $step['key'] === 'estimate') ||
|
|
($currentStep === 'estimate_approved' && $step['key'] === 'approved') ||
|
|
($currentStep === 'in_progress' && $step['key'] === 'in_progress') ||
|
|
($currentStep === 'completed' && $step['key'] === 'completed');
|
|
@endphp
|
|
|
|
<li>
|
|
<div class="relative pb-8">
|
|
@if($index < count($steps) - 1)
|
|
<span class="absolute top-4 left-4 -ml-px h-full w-0.5 {{ $isCompleted ? 'bg-green-600' : 'bg-gray-200' }}" aria-hidden="true"></span>
|
|
@endif
|
|
<div class="relative flex space-x-3">
|
|
<div>
|
|
<span class="h-8 w-8 rounded-full flex items-center justify-center ring-8 ring-white
|
|
{{ $isCompleted ? 'bg-green-600' : ($isCurrent ? 'bg-blue-600' : 'bg-gray-400') }}">
|
|
@if($isCompleted)
|
|
<svg class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
</svg>
|
|
@else
|
|
<span class="h-2.5 w-2.5 bg-white rounded-full"></span>
|
|
@endif
|
|
</span>
|
|
</div>
|
|
<div class="min-w-0 flex-1 pt-1.5 flex justify-between space-x-4">
|
|
<div>
|
|
<p class="text-sm font-medium text-gray-900">{{ $step['title'] }}</p>
|
|
<p class="text-sm text-gray-500">{{ $step['description'] }}</p>
|
|
</div>
|
|
@if($isCurrent)
|
|
<div class="text-right text-sm">
|
|
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
|
Current
|
|
</span>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Estimates Section -->
|
|
@if($jobCard->estimates && $jobCard->estimates->count() > 0)
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<h2 class="text-xl font-semibold text-gray-900 mb-6">Estimates</h2>
|
|
<div class="space-y-4">
|
|
@foreach($jobCard->estimates as $estimate)
|
|
<div class="border rounded-lg p-4 {{ $estimate->status === 'approved' ? 'border-green-200 bg-green-50' : 'border-gray-200' }}">
|
|
<div class="flex justify-between items-center">
|
|
<div>
|
|
<h3 class="text-lg font-medium text-gray-900">Estimate #{{ $estimate->id }}</h3>
|
|
<p class="text-sm text-gray-600">Created: {{ $estimate->created_at->format('M j, Y g:i A') }}</p>
|
|
<p class="text-lg font-semibold text-gray-900 mt-2">${{ number_format($estimate->total_amount, 2) }}</p>
|
|
</div>
|
|
<div class="text-right">
|
|
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
|
|
@switch($estimate->status)
|
|
@case('approved')
|
|
bg-green-100 text-green-800
|
|
@break
|
|
@case('rejected')
|
|
bg-red-100 text-red-800
|
|
@break
|
|
@case('sent')
|
|
bg-yellow-100 text-yellow-800
|
|
@break
|
|
@default
|
|
bg-gray-100 text-gray-800
|
|
@endswitch
|
|
">
|
|
{{ ucfirst($estimate->status) }}
|
|
</span>
|
|
@if(in_array($estimate->status, ['sent', 'viewed']))
|
|
<a href="{{ route('customer-portal.estimate', [$jobCard, $estimate]) }}"
|
|
class="mt-2 inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-blue-700 bg-blue-100 hover:bg-blue-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
|
Review Estimate
|
|
</a>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Vehicle Information -->
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<h2 class="text-xl font-semibold text-gray-900 mb-6">Vehicle Information</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<h3 class="text-sm font-medium text-gray-500">Vehicle Details</h3>
|
|
<div class="mt-2 space-y-2">
|
|
<p class="text-sm text-gray-900">{{ $jobCard->vehicle->year }} {{ $jobCard->vehicle->make }} {{ $jobCard->vehicle->model }}</p>
|
|
<p class="text-sm text-gray-600">VIN: {{ $jobCard->vehicle->vin ?? 'Not provided' }}</p>
|
|
<p class="text-sm text-gray-600">License: {{ $jobCard->vehicle->license_plate ?? 'Not provided' }}</p>
|
|
<p class="text-sm text-gray-600">Mileage: {{ number_format($jobCard->vehicle->mileage ?? 0) }} miles</p>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-sm font-medium text-gray-500">Service Advisor</h3>
|
|
<div class="mt-2">
|
|
<p class="text-sm text-gray-900">{{ $jobCard->serviceAdvisor->name ?? 'Not assigned' }}</p>
|
|
@if($jobCard->serviceAdvisor)
|
|
<p class="text-sm text-gray-600">{{ $jobCard->serviceAdvisor->email ?? '' }}</p>
|
|
<p class="text-sm text-gray-600">{{ $jobCard->serviceAdvisor->phone ?? '' }}</p>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Service Description -->
|
|
@if($jobCard->description)
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<h2 class="text-xl font-semibold text-gray-900 mb-4">Service Description</h2>
|
|
<p class="text-gray-700">{{ $jobCard->description }}</p>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</x-layouts.customer-portal>
|