libra/docs/stories/story-7.3-my-cases-timeline...

246 lines
8.1 KiB
Markdown

# Story 7.3: My Cases/Timelines View (Dashboard Integration)
## Epic Reference
**Epic 7:** Client Dashboard
## User Story
As a **client**,
I want **to access my case timelines from the dashboard navigation**,
So that **I can easily track the progress of my legal matters from one central location**.
## Story Context
### Relationship to Story 4.5
Story 4.5 (`docs/stories/story-4.5-client-timeline-view.md`) already implements the **complete timeline viewing functionality**:
- Routes: `client.timelines.index` and `client.timelines.show`
- Components: `pages/client/timelines/index.blade.php` and `show.blade.php`
- Active/archived separation with visual distinction
- Individual timeline detail view with chronological updates
- Authorization, tests, and translations
**This story (7.3) focuses solely on dashboard navigation integration** - ensuring clients can access the existing timeline views from the Epic 7 client dashboard structure.
### Prerequisites
- **Story 4.5:** Client Timeline View - MUST be complete (provides all timeline components)
- **Story 7.1:** Client Dashboard Overview - MUST be complete (provides dashboard layout and navigation)
### What This Story Does NOT Do
- Does NOT recreate timeline list or detail views (use Story 4.5's components)
- Does NOT add new timeline functionality
- Does NOT modify existing timeline components
## Acceptance Criteria
### Navigation Integration
- [ ] "My Cases" navigation item added to client dashboard sidebar/nav
- [ ] Navigation links to `route('client.timelines.index')`
- [ ] Active state shown when on timeline routes
- [ ] Icon: folder or briefcase icon for cases
### Dashboard Widget (on Story 7.1's dashboard)
- [ ] "My Cases" widget card displays:
- Count of active cases
- Latest update preview (case name + date)
- "View All" link to timeline index
- [ ] Widget shows empty state if no cases exist
### Layout Consistency
- [ ] Timeline pages use client dashboard layout (consistent header/nav)
- [ ] Breadcrumbs: Dashboard > My Cases (on index)
- [ ] Breadcrumbs: Dashboard > My Cases > [Case Name] (on show)
### Bilingual Support
- [ ] Navigation label translated (AR/EN)
- [ ] Widget content translated (AR/EN)
## Technical Notes
### File Structure
```
Files to Modify:
resources/views/components/layouts/client.blade.php (add nav item)
OR resources/views/livewire/pages/client/dashboard.blade.php (add widget)
Files from Story 4.5 (DO NOT MODIFY - just ensure they exist):
resources/views/livewire/pages/client/timelines/index.blade.php
resources/views/livewire/pages/client/timelines/show.blade.php
Tests to Create:
tests/Feature/Client/DashboardTimelineIntegrationTest.php
```
### Navigation Item Addition
Add to client dashboard navigation (location depends on Story 7.1's implementation):
```php
{{-- In client layout/navigation component --}}
<flux:navbar.item
href="{{ route('client.timelines.index') }}"
:active="request()->routeIs('client.timelines.*')"
icon="folder"
>
{{ __('client.my_cases') }}
</flux:navbar.item>
```
### Dashboard Widget Component
Add to Story 7.1's dashboard view:
```php
{{-- My Cases Widget --}}
<div class="bg-white rounded-lg shadow-sm p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="font-semibold text-charcoal">{{ __('client.my_cases') }}</h3>
<flux:badge>{{ $activeTimelinesCount }} {{ __('client.active') }}</flux:badge>
</div>
@if($latestTimelineUpdate)
<div class="text-sm text-charcoal/70 mb-4">
<p class="font-medium">{{ $latestTimelineUpdate->timeline->case_name }}</p>
<p class="text-xs">{{ __('client.last_update') }}: {{ $latestTimelineUpdate->created_at->diffForHumans() }}</p>
</div>
@else
<p class="text-sm text-charcoal/50 mb-4">{{ __('client.no_cases_yet') }}</p>
@endif
<flux:button size="sm" href="{{ route('client.timelines.index') }}">
{{ __('client.view_all_cases') }}
</flux:button>
</div>
```
### Data for Widget (add to Story 7.1's dashboard component)
```php
// In dashboard component's with() method
'activeTimelinesCount' => auth()->user()->timelines()->active()->count(),
'latestTimelineUpdate' => TimelineUpdate::whereHas('timeline',
fn($q) => $q->where('user_id', auth()->id())->active()
)
->with('timeline:id,case_name')
->latest()
->first(),
```
### Required Translation Keys
```php
// Add to resources/lang/en/client.php (if not already from 4.5)
'view_all_cases' => 'View All Cases',
// Add to resources/lang/ar/client.php
'view_all_cases' => 'عرض جميع القضايا',
```
## Test Scenarios
```php
<?php
// tests/Feature/Client/DashboardTimelineIntegrationTest.php
use App\Models\{User, Timeline, TimelineUpdate};
test('client dashboard has my cases navigation link', function () {
$client = User::factory()->create(['user_type' => 'individual']);
$this->actingAs($client)
->get(route('client.dashboard'))
->assertOk()
->assertSee(__('client.my_cases'))
->assertSee(route('client.timelines.index'));
});
test('client dashboard shows active cases count in widget', function () {
$client = User::factory()->create(['user_type' => 'individual']);
Timeline::factory()->count(3)->create([
'user_id' => $client->id,
'status' => 'active',
]);
Timeline::factory()->create([
'user_id' => $client->id,
'status' => 'archived',
]);
$this->actingAs($client)
->get(route('client.dashboard'))
->assertSee('3'); // Only active cases counted
});
test('client dashboard shows latest timeline update', function () {
$client = User::factory()->create(['user_type' => 'individual']);
$timeline = Timeline::factory()->create([
'user_id' => $client->id,
'case_name' => 'Property Dispute Case',
]);
TimelineUpdate::factory()->create([
'timeline_id' => $timeline->id,
'created_at' => now(),
]);
$this->actingAs($client)
->get(route('client.dashboard'))
->assertSee('Property Dispute Case');
});
test('client dashboard shows empty state when no cases', function () {
$client = User::factory()->create(['user_type' => 'individual']);
$this->actingAs($client)
->get(route('client.dashboard'))
->assertSee(__('client.no_cases_yet'));
});
test('my cases navigation is active on timeline routes', function () {
$client = User::factory()->create(['user_type' => 'individual']);
$timeline = Timeline::factory()->create(['user_id' => $client->id]);
// Test on index
$this->actingAs($client)
->get(route('client.timelines.index'))
->assertOk();
// Test on show
$this->actingAs($client)
->get(route('client.timelines.show', $timeline))
->assertOk();
});
test('timeline pages use client dashboard layout', function () {
$client = User::factory()->create(['user_type' => 'individual']);
$this->actingAs($client)
->get(route('client.timelines.index'))
->assertSee(__('client.my_cases')); // Nav item visible = layout applied
});
```
## Definition of Done
- [ ] "My Cases" navigation item added to client dashboard
- [ ] Navigation links to existing `client.timelines.index` route
- [ ] Active state shows on timeline routes
- [ ] Dashboard widget displays active case count
- [ ] Dashboard widget shows latest update preview
- [ ] Dashboard widget links to timeline index
- [ ] Empty state handled in widget
- [ ] Translation keys added for new strings
- [ ] Timeline pages render within client dashboard layout
- [ ] All tests pass
- [ ] Code formatted with Pint
## Dependencies
- **Story 4.5:** Client Timeline View (REQUIRED - provides timeline components and routes)
- **Story 7.1:** Client Dashboard Overview (REQUIRED - provides dashboard layout)
## Notes
This story is intentionally minimal because the heavy lifting was done in Story 4.5. The developer should:
1. Verify Story 4.5 is complete and routes work
2. Add navigation item to client layout
3. Add widget to dashboard
4. Ensure layout consistency
5. Write integration tests
Do NOT duplicate or recreate the timeline components from Story 4.5.
## Estimation
**Complexity:** Low | **Effort:** 1-2 hours