feat: AfterSales CRM - SOP compliant real-estate customer care system
- Departments + cross-department transfer workflow - Role-based closing (staff→resolved, manager→closed) with proof_of_resolution - Private file storage with collection system + temporary signed URLs - Dashboard: resolved tickets table, stats, handler performance bar chart - Spatie RBAC (admin/manager/staff) - Notifications: TicketTransferred, TicketClosed (database + mail) - Pest tests: 8 tests, 21 assertions - Docker production-ready (Dockerfile + compose + entrypoint)
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<div style="padding: 1rem;">
|
||||
@if(empty($links) || count($links) === 0)
|
||||
<p>No attachments.</p>
|
||||
@else
|
||||
<table style="width: 100%; border-collapse: collapse;">
|
||||
<thead>
|
||||
<tr style="border-bottom: 2px solid #e5e7eb;">
|
||||
<th style="text-align: left; padding: 8px;">File</th>
|
||||
<th style="text-align: left; padding: 8px;">Collection</th>
|
||||
<th style="text-align: left; padding: 8px;">Size</th>
|
||||
<th style="text-align: right; padding: 8px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($links as $link)
|
||||
<tr style="border-bottom: 1px solid #f3f4f6;">
|
||||
<td style="padding: 8px;">{{ $link['name'] }}</td>
|
||||
<td style="padding: 8px;">
|
||||
<span style="
|
||||
display: inline-block; padding: 2px 8px; border-radius: 9999px; font-size: 12px;
|
||||
@if($link['collection'] === 'proof_of_resolution') background: #dcfce7; color: #166534;
|
||||
@elseif($link['collection'] === 'customer_evidence') background: #dbeafe; color: #1e40af;
|
||||
@else background: #f3f4f6; color: #374151;
|
||||
@endif
|
||||
">
|
||||
{{ $link['collection'] }}
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding: 8px;">{{ $link['size'] }}</td>
|
||||
<td style="padding: 8px; text-align: right;">
|
||||
<a href="{{ $link['url'] }}" target="_blank" style="
|
||||
display: inline-block; padding: 4px 12px; border-radius: 6px;
|
||||
background: #3b82f6; color: white; text-decoration: none; font-size: 13px;
|
||||
">Download</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<p style="margin-top: 12px; font-size: 12px; color: #6b7280;">Links expire after 60 minutes.</p>
|
||||
@endif
|
||||
</div>
|
||||
@@ -0,0 +1,68 @@
|
||||
@php
|
||||
use App\Models\Feedback;
|
||||
$record = $this->getRecord();
|
||||
$tagIds = $record->tags->pluck('id')->toArray();
|
||||
$similarCases = collect();
|
||||
|
||||
if (! empty($tagIds)) {
|
||||
$similarCases = Feedback::where('id', '!=', $record->id)
|
||||
->whereHas('tags', fn ($q) => $q->whereIn('feedback_tag_id', $tagIds))
|
||||
->with(['customer', 'tags', 'assignedTo'])
|
||||
->latest()
|
||||
->limit(5)
|
||||
->get();
|
||||
}
|
||||
@endphp
|
||||
|
||||
@if($similarCases->isNotEmpty())
|
||||
<div class="p-6 bg-white rounded-xl shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
||||
<h3 class="text-lg font-semibold text-gray-950 dark:text-white mb-4">
|
||||
Similar Cases (shared tags)
|
||||
</h3>
|
||||
<div class="overflow-hidden rounded-lg border border-gray-200 dark:border-gray-700">
|
||||
<table class="w-full text-sm text-left">
|
||||
<thead class="bg-gray-50 dark:bg-gray-800">
|
||||
<tr>
|
||||
<th class="px-4 py-3 font-medium">Title</th>
|
||||
<th class="px-4 py-3 font-medium">Customer</th>
|
||||
<th class="px-4 py-3 font-medium">Status</th>
|
||||
<th class="px-4 py-3 font-medium">Assigned To</th>
|
||||
<th class="px-4 py-3 font-medium">Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
@foreach($similarCases as $case)
|
||||
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800/50">
|
||||
<td class="px-4 py-3">
|
||||
<a href="{{ \App\Filament\Resources\Feedback\FeedbackResource::getUrl('edit', ['record' => $case]) }}"
|
||||
class="text-blue-600 dark:text-blue-400 hover:underline font-medium">
|
||||
{{ $case->title }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-gray-600 dark:text-gray-400">
|
||||
{{ $case->customer?->name }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<span class="px-2 py-1 text-xs rounded-full font-medium
|
||||
@switch($case->status)
|
||||
@case('pending') bg-yellow-100 text-yellow-800 @break
|
||||
@case('processing') bg-blue-100 text-blue-800 @break
|
||||
@case('resolved') bg-green-100 text-green-800 @break
|
||||
@case('closed') bg-gray-100 text-gray-800 @break
|
||||
@endswitch">
|
||||
{{ ucfirst($case->status) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-gray-600 dark:text-gray-400">
|
||||
{{ $case->assignedTo?->name ?? 'Unassigned' }}
|
||||
</td>
|
||||
<td class="px-4 py-3 text-gray-500 dark:text-gray-400">
|
||||
{{ $case->created_at->format('d/m/Y') }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
Reference in New Issue
Block a user