complete story 4.5 with qa tests and applied pagintation fix
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
use Livewire\Volt\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
new class extends Component
|
||||
{
|
||||
use WithPagination;
|
||||
|
||||
public function with(): array
|
||||
{
|
||||
return [
|
||||
'activeTimelines' => auth()->user()
|
||||
->timelines()
|
||||
->active()
|
||||
->withCount('updates')
|
||||
->with(['updates' => fn ($q) => $q->latest()->limit(1)])
|
||||
->latest('updated_at')
|
||||
->paginate(10, pageName: 'active'),
|
||||
|
||||
'archivedTimelines' => auth()->user()
|
||||
->timelines()
|
||||
->archived()
|
||||
->withCount('updates')
|
||||
->latest('updated_at')
|
||||
->paginate(10, pageName: 'archived'),
|
||||
];
|
||||
}
|
||||
}; ?>
|
||||
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<flux:heading size="xl" class="mb-6">{{ __('client.my_cases') }}</flux:heading>
|
||||
|
||||
{{-- Active Timelines --}}
|
||||
@if($activeTimelines->total() > 0)
|
||||
<div class="mb-8">
|
||||
<h2 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100 mb-4">{{ __('client.active_cases') }}</h2>
|
||||
<div class="space-y-4">
|
||||
@foreach($activeTimelines as $timeline)
|
||||
<div wire:key="timeline-{{ $timeline->id }}" class="bg-white dark:bg-zinc-800 p-4 rounded-lg border-s-4 border-amber-500 shadow-sm">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h3 class="font-medium text-zinc-900 dark:text-zinc-100">{{ $timeline->case_name }}</h3>
|
||||
@if($timeline->case_reference)
|
||||
<p class="text-sm text-zinc-600 dark:text-zinc-400">{{ __('client.reference') }}: {{ $timeline->case_reference }}</p>
|
||||
@endif
|
||||
<p class="text-sm text-zinc-500 dark:text-zinc-500 mt-1">
|
||||
{{ __('client.updates') }}: {{ $timeline->updates_count }}
|
||||
@if($timeline->updates->first())
|
||||
· {{ __('client.last_update') }}: {{ $timeline->updates->first()->created_at->diffForHumans() }}
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<flux:badge variant="success">{{ __('client.active') }}</flux:badge>
|
||||
<flux:button size="sm" href="{{ route('client.timelines.show', $timeline) }}">
|
||||
{{ __('client.view') }}
|
||||
</flux:button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@if($activeTimelines->hasPages())
|
||||
<div class="mt-4">
|
||||
{{ $activeTimelines->links() }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Archived Timelines --}}
|
||||
@if($archivedTimelines->total() > 0)
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold text-zinc-600 dark:text-zinc-400 mb-4">{{ __('client.archived_cases') }}</h2>
|
||||
<div class="space-y-4 opacity-75">
|
||||
@foreach($archivedTimelines as $timeline)
|
||||
<div wire:key="timeline-{{ $timeline->id }}" class="bg-zinc-50 dark:bg-zinc-900 p-4 rounded-lg shadow-sm">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h3 class="font-medium text-zinc-700 dark:text-zinc-300">{{ $timeline->case_name }}</h3>
|
||||
@if($timeline->case_reference)
|
||||
<p class="text-sm text-zinc-500 dark:text-zinc-500">{{ __('client.reference') }}: {{ $timeline->case_reference }}</p>
|
||||
@endif
|
||||
<p class="text-sm text-zinc-400 dark:text-zinc-600 mt-1">
|
||||
{{ __('client.updates') }}: {{ $timeline->updates_count }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<flux:badge>{{ __('client.archived') }}</flux:badge>
|
||||
<flux:button size="sm" variant="ghost" href="{{ route('client.timelines.show', $timeline) }}">
|
||||
{{ __('client.view') }}
|
||||
</flux:button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@if($archivedTimelines->hasPages())
|
||||
<div class="mt-4">
|
||||
{{ $archivedTimelines->links() }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Empty State --}}
|
||||
@if($activeTimelines->total() === 0 && $archivedTimelines->total() === 0)
|
||||
<div class="text-center py-12">
|
||||
<flux:icon name="folder-open" class="w-12 h-12 text-zinc-300 dark:text-zinc-600 mx-auto mb-4" />
|
||||
<p class="text-zinc-500 dark:text-zinc-400">{{ __('client.no_cases_yet') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Timeline;
|
||||
use Livewire\Volt\Component;
|
||||
|
||||
new class extends Component
|
||||
{
|
||||
public Timeline $timeline;
|
||||
|
||||
public function mount(Timeline $timeline): void
|
||||
{
|
||||
// Authorization: Ensure client owns this timeline
|
||||
abort_unless($timeline->user_id === auth()->id(), 403);
|
||||
|
||||
$this->timeline = $timeline->load(['updates' => fn ($q) => $q->oldest()]);
|
||||
}
|
||||
}; ?>
|
||||
|
||||
<div class="max-w-3xl mx-auto">
|
||||
{{-- Header --}}
|
||||
<div class="flex justify-between items-start mb-6">
|
||||
<div>
|
||||
<flux:heading size="xl">{{ $timeline->case_name }}</flux:heading>
|
||||
@if($timeline->case_reference)
|
||||
<p class="text-zinc-600 dark:text-zinc-400">{{ __('client.reference') }}: {{ $timeline->case_reference }}</p>
|
||||
@endif
|
||||
</div>
|
||||
<flux:badge :variant="$timeline->status->value === 'active' ? 'success' : 'default'">
|
||||
{{ __('client.' . $timeline->status->value) }}
|
||||
</flux:badge>
|
||||
</div>
|
||||
|
||||
{{-- Timeline Updates --}}
|
||||
<div class="relative">
|
||||
{{-- Vertical line --}}
|
||||
<div class="absolute {{ app()->getLocale() === 'ar' ? 'right-4' : 'left-4' }} top-0 bottom-0 w-0.5 bg-amber-500/30"></div>
|
||||
|
||||
<div class="space-y-6">
|
||||
@forelse($timeline->updates as $update)
|
||||
<div wire:key="update-{{ $update->id }}" class="relative {{ app()->getLocale() === 'ar' ? 'pr-12' : 'pl-12' }}">
|
||||
{{-- Dot --}}
|
||||
<div class="absolute {{ app()->getLocale() === 'ar' ? 'right-2' : 'left-2' }} top-2 w-4 h-4 rounded-full bg-amber-500 border-4 border-amber-50 dark:border-zinc-900"></div>
|
||||
|
||||
<div class="bg-white dark:bg-zinc-800 p-4 rounded-lg shadow-sm">
|
||||
<div class="text-sm text-zinc-500 dark:text-zinc-400 mb-2">
|
||||
{{ $update->created_at->translatedFormat('l, d M Y - g:i A') }}
|
||||
</div>
|
||||
<div class="prose prose-sm dark:prose-invert max-w-none">
|
||||
{!! $update->update_text !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-center text-zinc-500 dark:text-zinc-400 py-8">
|
||||
{{ __('client.no_updates_yet') }}
|
||||
</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<flux:button href="{{ route('client.timelines.index') }}">
|
||||
{{ __('client.back_to_cases') }}
|
||||
</flux:button>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user