5.8 KiB
5.8 KiB
Story 4.4: Admin Timeline Dashboard
Epic Reference
Epic 4: Case Timeline System
User Story
As an admin, I want a central view to manage all timelines across all clients, So that I can efficiently track and update case progress.
Story Context
Existing System Integration
- Integrates with: timelines table, users table
- Technology: Livewire Volt with pagination
- Follows pattern: Admin list/dashboard pattern
- Touch points: All timeline operations
Acceptance Criteria
List View
- Display all timelines with:
- Case name
- Client name
- Status (active/archived)
- Last update date
- Update count
- Pagination (15/25/50 per page)
Filtering
- Filter by client (search/select)
- Filter by status (active/archived/all)
- Filter by date range (created/updated)
- Search by case name or reference
Sorting
- Sort by client name
- Sort by case name
- Sort by last updated
- Sort by created date
Quick Actions
- View timeline details
- Add update (inline or link)
- Archive/unarchive toggle
Quality Requirements
- Fast loading with eager loading
- Bilingual support
- Tests for filtering/sorting
Technical Notes
Volt Component
<?php
use App\Models\Timeline;
use Livewire\Volt\Component;
use Livewire\WithPagination;
new class extends Component {
use WithPagination;
public string $search = '';
public string $clientFilter = '';
public string $statusFilter = '';
public string $dateFrom = '';
public string $dateTo = '';
public string $sortBy = 'updated_at';
public string $sortDir = 'desc';
public int $perPage = 15;
public function updatedSearch()
{
$this->resetPage();
}
public function sort(string $column): void
{
if ($this->sortBy === $column) {
$this->sortDir = $this->sortDir === 'asc' ? 'desc' : 'asc';
} else {
$this->sortBy = $column;
$this->sortDir = 'asc';
}
}
public function with(): array
{
return [
'timelines' => Timeline::query()
->with(['user', 'updates' => fn($q) => $q->latest()->limit(1)])
->withCount('updates')
->when($this->search, fn($q) => $q->where(function($q) {
$q->where('case_name', 'like', "%{$this->search}%")
->orWhere('case_reference', 'like', "%{$this->search}%");
}))
->when($this->clientFilter, fn($q) => $q->where('user_id', $this->clientFilter))
->when($this->statusFilter, fn($q) => $q->where('status', $this->statusFilter))
->when($this->dateFrom, fn($q) => $q->where('created_at', '>=', $this->dateFrom))
->when($this->dateTo, fn($q) => $q->where('created_at', '<=', $this->dateTo))
->orderBy($this->sortBy, $this->sortDir)
->paginate($this->perPage),
];
}
};
Template Structure
<div>
<!-- Filters Row -->
<div class="flex flex-wrap gap-4 mb-6">
<flux:input wire:model.live.debounce="search" placeholder="{{ __('admin.search_cases') }}" />
<flux:select wire:model.live="statusFilter">
<option value="">{{ __('admin.all_statuses') }}</option>
<option value="active">{{ __('admin.active') }}</option>
<option value="archived">{{ __('admin.archived') }}</option>
</flux:select>
<!-- More filters... -->
</div>
<!-- Table -->
<table class="w-full">
<thead>
<tr>
<th wire:click="sort('case_name')">{{ __('admin.case_name') }}</th>
<th wire:click="sort('user_id')">{{ __('admin.client') }}</th>
<th>{{ __('admin.status') }}</th>
<th wire:click="sort('updated_at')">{{ __('admin.last_update') }}</th>
<th>{{ __('admin.actions') }}</th>
</tr>
</thead>
<tbody>
@foreach($timelines as $timeline)
<tr>
<td>{{ $timeline->case_name }}</td>
<td>{{ $timeline->user->name }}</td>
<td>
<flux:badge :variant="$timeline->status === 'active' ? 'success' : 'secondary'">
{{ __('admin.' . $timeline->status) }}
</flux:badge>
</td>
<td>{{ $timeline->updated_at->diffForHumans() }}</td>
<td>
<flux:dropdown>
<flux:button size="sm">{{ __('admin.actions') }}</flux:button>
<flux:menu>
<flux:menu.item href="{{ route('admin.timelines.show', $timeline) }}">
{{ __('admin.view') }}
</flux:menu.item>
<flux:menu.item wire:click="toggleArchive({{ $timeline->id }})">
{{ $timeline->status === 'active' ? __('admin.archive') : __('admin.unarchive') }}
</flux:menu.item>
</flux:menu>
</flux:dropdown>
</td>
</tr>
@endforeach
</tbody>
</table>
{{ $timelines->links() }}
</div>
Definition of Done
- List displays all timelines
- All filters working
- All sorts working
- Quick actions functional
- Pagination working
- No N+1 queries
- Bilingual support
- Tests pass
- Code formatted with Pint
Dependencies
- Story 4.1: Timeline creation
- Story 4.3: Archive functionality
Estimation
Complexity: Medium Estimated Effort: 3-4 hours