- Implemented dashboard view with vehicle stats, active services, recent activity, and upcoming appointments. - Created estimates view with filtering options and a list of service estimates. - Developed invoices view to manage service invoices and payment history with filtering. - Added vehicles view to display registered vehicles and their details. - Built work orders view to track the progress of vehicle services with filtering and detailed information.
222 lines
13 KiB
PHP
222 lines
13 KiB
PHP
<x-layouts.customer-portal>
|
|
<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
|
|
|
|
<!-- Back to Status -->
|
|
<div>
|
|
<a href="{{ route('customer-portal.status', $jobCard) }}" class="inline-flex items-center text-blue-600 hover:text-blue-800">
|
|
<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="M15 19l-7-7 7-7"></path>
|
|
</svg>
|
|
Back to Job Status
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Estimate Header -->
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<div class="flex justify-between items-start">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-900">Estimate #{{ $estimate->id }}</h1>
|
|
<p class="text-sm text-gray-600 mt-1">Created: {{ $estimate->created_at->format('M j, Y g:i A') }}</p>
|
|
@if($estimate->diagnosis)
|
|
<p class="text-sm text-gray-600">Diagnosis: {{ $estimate->diagnosis->summary ?? 'No summary provided' }}</p>
|
|
@endif
|
|
</div>
|
|
<div class="text-right">
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm 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')
|
|
@case('viewed')
|
|
bg-yellow-100 text-yellow-800
|
|
@break
|
|
@default
|
|
bg-gray-100 text-gray-800
|
|
@endswitch
|
|
">
|
|
{{ ucfirst($estimate->status) }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Estimate Details -->
|
|
<div class="bg-white rounded-lg shadow overflow-hidden">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h2 class="text-lg font-semibold text-gray-900">Estimate Details</h2>
|
|
</div>
|
|
|
|
@if($estimate->lineItems && $estimate->lineItems->count() > 0)
|
|
<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">Description</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Quantity</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Unit Price</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
@foreach($estimate->lineItems as $item)
|
|
<tr>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<div class="text-sm font-medium text-gray-900">{{ $item->description }}</div>
|
|
@if($item->notes)
|
|
<div class="text-sm text-gray-500">{{ $item->notes }}</div>
|
|
@endif
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
|
|
{{ $item->type === 'labor' ? 'bg-blue-100 text-blue-800' : 'bg-green-100 text-green-800' }}">
|
|
{{ ucfirst($item->type) }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
{{ $item->quantity }}
|
|
@if($item->type === 'labor')
|
|
{{ $item->quantity == 1 ? 'hour' : 'hours' }}
|
|
@endif
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
${{ number_format($item->unit_price, 2) }}
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
|
${{ number_format($item->total_price, 2) }}
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
<tfoot class="bg-gray-50">
|
|
<tr>
|
|
<td colspan="4" class="px-6 py-4 text-right text-sm font-medium text-gray-900">Subtotal:</td>
|
|
<td class="px-6 py-4 text-sm font-medium text-gray-900">${{ number_format($estimate->subtotal_amount, 2) }}</td>
|
|
</tr>
|
|
@if($estimate->tax_amount > 0)
|
|
<tr>
|
|
<td colspan="4" class="px-6 py-4 text-right text-sm font-medium text-gray-900">Tax:</td>
|
|
<td class="px-6 py-4 text-sm font-medium text-gray-900">${{ number_format($estimate->tax_amount, 2) }}</td>
|
|
</tr>
|
|
@endif
|
|
<tr>
|
|
<td colspan="4" class="px-6 py-4 text-right text-lg font-bold text-gray-900">Total:</td>
|
|
<td class="px-6 py-4 text-lg font-bold text-gray-900">${{ number_format($estimate->total_amount, 2) }}</td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
@else
|
|
<div class="px-6 py-8 text-center">
|
|
<p class="text-gray-500">No line items found for this estimate.</p>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Estimate Notes -->
|
|
@if($estimate->notes)
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<h2 class="text-lg font-semibold text-gray-900 mb-4">Additional Notes</h2>
|
|
<p class="text-gray-700 whitespace-pre-line">{{ $estimate->notes }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Customer Actions -->
|
|
@if(in_array($estimate->status, ['sent', 'viewed']))
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<h2 class="text-lg font-semibold text-gray-900 mb-4">Your Response Required</h2>
|
|
<p class="text-gray-600 mb-6">Please review the estimate above and choose your response:</p>
|
|
|
|
<div class="flex flex-col sm:flex-row gap-4">
|
|
<button wire:click="approveEstimate"
|
|
wire:confirm="Are you sure you want to approve this estimate? This will authorize us to begin work on your vehicle."
|
|
class="inline-flex justify-center items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
|
|
<svg class="h-5 w-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
|
</svg>
|
|
Approve Estimate
|
|
</button>
|
|
|
|
<button onclick="document.getElementById('reject-modal').classList.remove('hidden')"
|
|
class="inline-flex justify-center items-center px-6 py-3 border border-gray-300 text-base 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-5 w-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
</svg>
|
|
Decline Estimate
|
|
</button>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Already Responded -->
|
|
@if(in_array($estimate->status, ['approved', 'rejected']))
|
|
<div class="bg-white rounded-lg shadow p-6">
|
|
<h2 class="text-lg font-semibold text-gray-900 mb-4">Your Response</h2>
|
|
<div class="flex items-center">
|
|
@if($estimate->status === 'approved')
|
|
<svg class="h-5 w-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
|
</svg>
|
|
<span class="text-green-800 font-medium">You approved this estimate on {{ $estimate->customer_approved_at->format('M j, Y g:i A') }}</span>
|
|
@else
|
|
<svg class="h-5 w-5 text-red-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
</svg>
|
|
<span class="text-red-800 font-medium">You declined this estimate on {{ $estimate->customer_approved_at->format('M j, Y g:i A') }}</span>
|
|
@endif
|
|
</div>
|
|
@if($estimate->status === 'rejected' && $estimate->notes)
|
|
<div class="mt-4 p-4 bg-gray-50 rounded-md">
|
|
<p class="text-sm text-gray-700"><strong>Your comments:</strong> {{ $estimate->notes }}</p>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Rejection Modal -->
|
|
<div id="reject-modal" class="hidden fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
|
|
<div class="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
|
|
<div class="mt-3">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-4">Decline Estimate</h3>
|
|
<p class="text-sm text-gray-600 mb-4">Please let us know why you're declining this estimate so we can better assist you:</p>
|
|
|
|
<textarea wire:model="customerComments"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
rows="4"
|
|
placeholder="Your comments or concerns..."></textarea>
|
|
|
|
<div class="flex justify-end space-x-3 mt-6">
|
|
<button onclick="document.getElementById('reject-modal').classList.add('hidden')"
|
|
class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">
|
|
Cancel
|
|
</button>
|
|
<button wire:click="rejectEstimate"
|
|
class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700">
|
|
Decline Estimate
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</x-layouts.customer-portal>
|