Chinh sua giao dien phu hop tailwind css va upload
Some checks failed
Tests / PHP 8.3 (push) Has been cancelled
Tests / PHP 8.4 (push) Has been cancelled
Tests / PHP 8.5 (push) Has been cancelled

This commit is contained in:
2026-05-05 09:25:28 +00:00
parent 8c6b71cb8a
commit fb1f82e1a0
12 changed files with 834 additions and 466 deletions

View File

@@ -1,61 +1,50 @@
<div class="p-4">
<div class="p-3" style="max-width: 100%;">
@if(empty($links) || count($links) === 0)
<p class="text-sm text-gray-500 py-8 text-center">{{ __('app.blade_no_attachments') }}</p>
<p class="text-gray-500 text-center" style="font-size: 11px; padding: 16px 0;">{{ __('app.blade_no_attachments') }}</p>
@else
<div class="space-y-3">
<div class="divide-y divide-gray-100 border border-gray-200 rounded-lg overflow-hidden">
@foreach($links as $link)
@php
$isImage = in_array($link['mime_type'] ?? '', ['image/jpeg', 'image/jpg', 'image/png']);
$ext = pathinfo($link['name'] ?? '', PATHINFO_EXTENSION);
$iconColor = match($ext) {
'pdf' => 'text-red-500',
'jpg', 'jpeg', 'png' => 'text-green-500',
default => 'text-gray-400',
};
$bgColor = match($ext) {
'pdf' => 'bg-red-50',
'jpg', 'jpeg', 'png' => 'bg-green-50',
default => 'bg-gray-50',
};
@endphp
<div class="flex items-start gap-4 p-3 border border-gray-200 rounded-lg bg-gray-50/30 hover:border-blue-300 transition-colors group"
onclick="window.open('{{ $link['url'] }}', '_blank')"
style="cursor: pointer;">
{{-- File icon or image preview --}}
<div class="flex-shrink-0">
<a href="{{ $link['url'] }}" target="_blank" class="flex items-center gap-2 px-3 py-1.5 hover:bg-blue-50/50 transition-colors group no-underline" style="text-decoration: none;">
{{-- Icon --}}
<div class="flex-shrink-0 rounded {{ $bgColor }} flex items-center justify-center" style="width: 20px; height: 20px;">
@if($isImage)
<img src="{{ $link['url'] }}" alt="{{ $link['name'] }}"
class="w-16 h-16 rounded object-cover border border-gray-200"
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
<div class="w-16 h-16 rounded border border-gray-200 bg-gray-100 items-center justify-center" style="display: none;">
<svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>
</div>
@elseif(($link['mime_type'] ?? '') === 'application/pdf')
<div class="w-16 h-16 rounded border border-red-200 bg-red-50 flex items-center justify-center">
<svg class="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/></svg>
</div>
<svg width="12" height="12" class="{{ $iconColor }}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>
@elseif($ext === 'pdf')
<svg width="12" height="12" class="{{ $iconColor }}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/></svg>
@else
<div class="w-16 h-16 rounded border border-blue-200 bg-blue-50 flex items-center justify-center">
<svg class="w-8 h-8 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg>
</div>
<svg width="12" height="12" class="{{ $iconColor }}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg>
@endif
</div>
{{-- File info --}}
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-900 truncate group-hover:text-blue-600 transition-colors">
{{ $link['name'] }}
</p>
<div class="flex items-center gap-2 mt-1">
<span class="text-xs text-gray-500">{{ $link['size'] }}</span>
@if(($link['collection'] ?? '') === 'proof_of_resolution')
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-semibold bg-green-100 text-green-700 border border-green-200">{{ __('app.blade_proof_of_resolution') }}</span>
@elseif(($link['collection'] ?? '') === 'customer_evidence')
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-semibold bg-blue-100 text-blue-700 border border-blue-200">{{ __('app.blade_customer_evidence') }}</span>
@else
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-semibold bg-gray-100 text-gray-600 border border-gray-200">{{ $link['collection'] ?? __('app.collection_general') }}</span>
@endif
</div>
</div>
{{-- Tên --}}
<span class="flex-1 text-gray-700 group-hover:text-blue-600 truncate block" style="font-size: 11px; min-width: 0;">{{ $link['name'] }}</span>
{{-- Download button --}}
<a href="{{ $link['url'] }}" target="_blank"
onclick="event.stopPropagation();"
class="flex-shrink-0 inline-flex items-center px-3 py-1.5 rounded text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 transition-colors shadow-sm no-underline">
{{ __('app.blade_open') }}
</a>
</div>
{{-- Badge --}}
@if(($link['collection'] ?? '') === 'proof_of_resolution')
<span class="inline-flex items-center px-1 py-0.5 rounded bg-green-100 text-green-700 flex-shrink-0" style="font-size: 9px;">{{ __('app.blade_proof_of_resolution') }}</span>
@elseif(($link['collection'] ?? '') === 'customer_evidence')
<span class="inline-flex items-center px-1 py-0.5 rounded bg-blue-100 text-blue-700 flex-shrink-0" style="font-size: 9px;">{{ __('app.blade_customer_evidence') }}</span>
@endif
{{-- Size --}}
<span class="text-gray-400 flex-shrink-0" style="font-size: 10px;">{{ $link['size'] }}</span>
</a>
@endforeach
</div>
<p class="mt-4 text-xs text-gray-500">{{ __('app.blade_links_expire') }}</p>
<p class="text-gray-400 text-center" style="font-size: 10px; margin-top: 6px;">{{ __('app.blade_links_expire') }}</p>
@endif
</div>

View File

@@ -1,4 +1,4 @@
<div>
<div class="max-w-full overflow-hidden">
@include('filament.resources.feedback.feedback-attachments')
@include('filament.resources.feedback.similar-cases')
</div>

View File

@@ -6,56 +6,60 @@
@endphp
@if($attachments->isNotEmpty())
<div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden mt-8">
<div class="px-6 py-4 border-b border-gray-100 bg-gray-50/50 flex justify-between items-center">
<h3 class="font-semibold text-lg text-gray-900 flex items-center gap-2" style="font-family: 'Manrope', sans-serif;">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg>
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden mt-6" style="max-width: 100%;">
<div class="px-4 py-2 border-b border-gray-100 bg-gray-50/50 flex justify-between items-center">
<h3 class="font-semibold text-xs text-gray-900 flex items-center gap-1.5" style="font-family: 'Manrope', sans-serif;">
<svg width="14" height="14" class="text-blue-600 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg>
{{ __('app.attachments') }}
<span class="text-[10px] font-normal text-gray-400">({{ $attachments->count() }})</span>
</h3>
<span class="text-xs text-gray-500">{{ __('app.blade_file_count', ['count' => $attachments->count()]) }}</span>
</div>
<div class="p-4">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
@foreach($attachments as $attachment)
@php
$url = $fileService->getTemporaryUrl($attachment, 60);
$isImage = $fileService->isImage($attachment);
$sizeKb = $attachment->size ? round($attachment->size / 1024, 1) . ' KB' : 'N/A';
@endphp
<div class="border border-gray-200 rounded-lg p-3 flex items-start gap-3 bg-gray-50/30 hover:border-blue-300 transition-colors group cursor-pointer"
onclick="window.open('{{ $url }}', '_blank')">
<div class="divide-y divide-gray-100">
@foreach($attachments as $attachment)
@php
$url = $fileService->getTemporaryUrl($attachment, 60);
$isImage = $fileService->isImage($attachment);
$sizeKb = $attachment->size ? round($attachment->size / 1024, 1) . ' KB' : 'N/A';
$ext = pathinfo($attachment->name, PATHINFO_EXTENSION);
$iconColor = match($ext) {
'pdf' => 'text-red-500',
'jpg', 'jpeg', 'png' => 'text-green-500',
'mp4', 'mov' => 'text-purple-500',
default => 'text-gray-400',
};
$bgColor = match($ext) {
'pdf' => 'bg-red-50',
'jpg', 'jpeg', 'png' => 'bg-green-50',
'mp4', 'mov' => 'bg-purple-50',
default => 'bg-gray-50',
};
@endphp
<a href="{{ $url }}" target="_blank" class="flex items-center gap-2 px-4 py-1.5 hover:bg-blue-50/50 transition-colors group no-underline" style="text-decoration: none;">
{{-- Icon 20x20 --}}
<div class="flex-shrink-0 rounded {{ $bgColor }} flex items-center justify-center" style="width: 20px; height: 20px;">
@if($isImage)
<div class="w-12 h-12 rounded bg-gray-200 overflow-hidden flex-shrink-0">
<img src="{{ $url }}" alt="{{ $attachment->name }}" class="w-full h-full object-cover"
onerror="this.parentElement.innerHTML='<span class=\'flex items-center justify-center h-full text-gray-400\'><svg class=\'w-6 h-6\' fill=\'none\' stroke=\'currentColor\' viewBox=\'0 0 24 24\'><path stroke-linecap=\'round\' stroke-linejoin=\'round\' stroke-width=\'2\' d=\'M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\'/></svg></span>'">
</div>
@elseif($attachment->mime_type === 'application/pdf')
<div class="w-12 h-12 rounded bg-red-100 flex items-center justify-center flex-shrink-0">
<svg class="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/></svg>
</div>
<svg width="12" height="12" class="{{ $iconColor }}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>
@elseif($ext === 'pdf')
<svg width="12" height="12" class="{{ $iconColor }}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/></svg>
@else
<div class="w-12 h-12 rounded bg-blue-100 flex items-center justify-center flex-shrink-0">
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg>
</div>
<svg width="12" height="12" class="{{ $iconColor }}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg>
@endif
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-900 truncate group-hover:text-blue-600 transition-colors">
{{ $attachment->name }}
</p>
<div class="flex items-center gap-2 mt-1">
<span class="text-xs text-gray-500">{{ $sizeKb }}</span>
@if($attachment->collection === 'proof_of_resolution')
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-semibold bg-green-100 text-green-700 border border-green-200">{{ __('app.blade_proof') }}</span>
@elseif($attachment->collection === 'customer_evidence')
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-semibold bg-blue-100 text-blue-700 border border-blue-200">{{ __('app.blade_evidence') }}</span>
@else
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-semibold bg-gray-100 text-gray-600 border border-gray-200">{{ __('app.collection_general') }}</span>
@endif
</div>
</div>
</div>
@endforeach
</div>
{{-- Tên file --}}
<span class="flex-1 text-gray-700 group-hover:text-blue-600 transition-colors truncate" style="font-size: 11px; min-width: 0;">{{ $attachment->name }}</span>
{{-- Badge collection --}}
@if($attachment->collection === 'proof_of_resolution')
<span class="inline-flex items-center px-1 py-0.5 rounded bg-green-100 text-green-700 flex-shrink-0" style="font-size: 9px;">{{ __('app.blade_proof') }}</span>
@elseif($attachment->collection === 'customer_evidence')
<span class="inline-flex items-center px-1 py-0.5 rounded bg-blue-100 text-blue-700 flex-shrink-0" style="font-size: 9px;">{{ __('app.blade_evidence') }}</span>
@endif
{{-- Size --}}
<span class="text-gray-400 flex-shrink-0" style="font-size: 10px;">{{ $sizeKb }}</span>
</a>
@endforeach
</div>
</div>
@endif

View File

@@ -15,55 +15,57 @@
@endphp
@if($similarCases->isNotEmpty())
<div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden mt-8">
<div class="px-6 py-4 border-b border-gray-100 bg-gray-50/50 flex justify-between items-center">
<h3 class="font-semibold text-lg text-gray-900 flex items-center gap-2" style="font-family: 'Manrope', sans-serif;">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden mt-6" style="max-width: 100%;">
<div class="px-4 py-2 border-b border-gray-100 bg-gray-50/50 flex justify-between items-center">
<h3 class="font-semibold text-xs text-gray-900 flex items-center gap-1.5" style="font-family: 'Manrope', sans-serif;">
<svg width="14" height="14" class="text-blue-600 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
{{ __('app.blade_similar_cases') }}
</h3>
<span class="text-xs text-gray-500">{{ __('app.blade_matching_tags') }} {{ $record->tags->pluck('name')->implode(', ') }}</span>
<span class="text-[10px] text-gray-400">{{ __('app.blade_matching_tags') }} {{ $record->tags->pluck('name')->implode(', ') }}</span>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-gray-50 border-b border-gray-200">
<th class="px-6 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_title') }}</th>
<th class="px-6 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_customer') }}</th>
<th class="px-6 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_status') }}</th>
<th class="px-6 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_handler') }}</th>
<th class="px-6 py-3 text-xs font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_date') }}</th>
<tr class="bg-gray-50/50 border-b border-gray-100">
<th class="px-4 py-2 text-[10px] font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_title') }}</th>
<th class="px-4 py-2 text-[10px] font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_customer') }}</th>
<th class="px-4 py-2 text-[10px] font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_status') }}</th>
<th class="px-4 py-2 text-[10px] font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_handler') }}</th>
<th class="px-4 py-2 text-[10px] font-semibold text-gray-500 uppercase tracking-wider">{{ __('app.blade_date') }}</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach($similarCases as $case)
<tr class="hover:bg-gray-50/50 transition-colors cursor-pointer"
<tr class="hover:bg-blue-50/30 transition-colors cursor-pointer"
onclick="window.location='{{ \App\Filament\Resources\Feedback\FeedbackResource::getUrl('edit', ['record' => $case]) }}'">
<td class="px-6 py-4 text-sm text-gray-900 hover:text-blue-600 transition-colors font-medium">
{{ $case->title }}
<td class="px-4 py-2">
<span class="text-blue-600 hover:text-blue-800 hover:underline transition-colors font-medium" style="font-size: 12px;">
{{ $case->title }}
</span>
</td>
<td class="px-6 py-4 text-sm text-gray-600">
<td class="px-4 py-2 text-gray-600" style="font-size: 12px;">
{{ $case->customer?->name }}
</td>
<td class="px-6 py-4">
<td class="px-4 py-2">
@switch($case->status)
@case('pending')
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-semibold bg-amber-50 text-amber-700 border border-amber-200">{{ __('app.status_pending') }}</span>
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[9px] font-medium bg-amber-50 text-amber-700 border border-amber-200">{{ __('app.status_pending') }}</span>
@break
@case('processing')
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-semibold bg-blue-50 text-blue-700 border border-blue-200">{{ __('app.status_processing') }}</span>
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[9px] font-medium bg-blue-50 text-blue-700 border border-blue-200">{{ __('app.status_processing') }}</span>
@break
@case('resolved')
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-semibold bg-green-50 text-green-700 border border-green-200">{{ __('app.status_resolved') }}</span>
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[9px] font-medium bg-green-50 text-green-700 border border-green-200">{{ __('app.status_resolved') }}</span>
@break
@case('closed')
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-semibold bg-gray-100 text-gray-600 border border-gray-200">{{ __('app.status_closed') }}</span>
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[9px] font-medium bg-gray-100 text-gray-600 border border-gray-200">{{ __('app.status_closed') }}</span>
@break
@endswitch
</td>
<td class="px-6 py-4 text-sm text-gray-600">
<td class="px-4 py-2 text-gray-600" style="font-size: 12px;">
{{ $case->assignedTo?->name ?? __('app.unassigned') }}
</td>
<td class="px-6 py-4 text-sm text-gray-500">
<td class="px-4 py-2 text-gray-500" style="font-size: 12px;">
{{ $case->created_at->format('d/m/Y') }}
</td>
</tr>