4.8 KiB
4.8 KiB
Story 4.5: Client Timeline View
Epic Reference
Epic 4: Case Timeline System
User Story
As a client, I want to view my case timelines and updates, So that I can track the progress of my legal matters.
Story Context
Existing System Integration
- Integrates with: timelines, timeline_updates tables
- Technology: Livewire Volt (read-only)
- Follows pattern: Client dashboard pattern
- Touch points: Client portal navigation
Acceptance Criteria
Timeline List
- Display all client's timelines
- Active timelines prominently displayed
- Archived timelines clearly separated
- Visual distinction (color/icon) for status
- Show for each:
- Case name and reference
- Status indicator
- Last update date
- Update count
Individual Timeline View
- Case name and reference
- Status indicator
- All updates in chronological order
- Each update shows:
- Date and time
- Update content (formatted)
Restrictions
- Read-only (no edit/comment)
- No ability to archive/delete
- Only see own timelines
UX Features
- Recent updates indicator (new since last view, optional)
- Responsive design for mobile
- Bilingual labels and dates
Technical Notes
Volt Component for List
<?php
use Livewire\Volt\Component;
new class extends Component {
public function with(): array
{
return [
'activeTimelines' => auth()->user()
->timelines()
->active()
->withCount('updates')
->with(['updates' => fn($q) => $q->latest()->limit(1)])
->latest('updated_at')
->get(),
'archivedTimelines' => auth()->user()
->timelines()
->archived()
->withCount('updates')
->latest('updated_at')
->get(),
];
}
};
Timeline Detail View
<?php
use App\Models\Timeline;
use Livewire\Volt\Component;
new class extends Component {
public Timeline $timeline;
public function mount(Timeline $timeline): void
{
// Ensure client owns this timeline
abort_unless($timeline->user_id === auth()->id(), 403);
$this->timeline = $timeline->load(['updates' => fn($q) => $q->oldest()]);
}
};
Template
<div class="max-w-3xl mx-auto">
<!-- Header -->
<div class="flex justify-between items-start mb-6">
<div>
<flux:heading>{{ $timeline->case_name }}</flux:heading>
@if($timeline->case_reference)
<p class="text-charcoal/70">{{ __('client.reference') }}: {{ $timeline->case_reference }}</p>
@endif
</div>
<flux:badge :variant="$timeline->status === 'active' ? 'success' : 'secondary'">
{{ __('client.' . $timeline->status) }}
</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-gold/30"></div>
<div class="space-y-6">
@forelse($timeline->updates as $update)
<div 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-gold border-4 border-cream"></div>
<div class="bg-white p-4 rounded-lg shadow-sm">
<div class="text-sm text-charcoal/70 mb-2">
{{ $update->created_at->translatedFormat('l, d M Y - g:i A') }}
</div>
<div class="prose prose-sm">
{!! $update->update_text !!}
</div>
</div>
</div>
@empty
<p class="text-center text-charcoal/70 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>
Definition of Done
- Client can view list of their timelines
- Active/archived clearly separated
- Can view individual timeline details
- All updates displayed chronologically
- Read-only (no edit capabilities)
- Cannot view other clients' timelines
- Mobile responsive
- RTL support
- Tests pass
- Code formatted with Pint
Dependencies
- Story 4.1-4.3: Timeline management
- Epic 7: Client dashboard structure
Estimation
Complexity: Medium Estimated Effort: 3-4 hours