# Story 5.2: Post Management Dashboard ## Epic Reference **Epic 5:** Posts/Blog System ## User Story As an **admin**, I want **a dashboard to manage all blog posts**, So that **I can organize, publish, and maintain content efficiently**. ## Story Context ### Existing System Integration - **Integrates with:** posts table - **Technology:** Livewire Volt with pagination - **Follows pattern:** Admin list pattern - **Touch points:** Post CRUD operations ## Acceptance Criteria ### List View - [ ] Display all posts with: - Title (in current admin language) - Status (draft/published) - Created date - Last updated date - [ ] Pagination (10/25/50 per page) ### Filtering & Search - [ ] Filter by status (draft/published/all) - [ ] Search by title or body content - [ ] Sort by date (newest/oldest) ### Quick Actions - [ ] Edit post - [ ] Delete (with confirmation) - [ ] Publish/unpublish toggle - [ ] Bulk delete option (optional) ### Quality Requirements - [ ] Bilingual labels - [ ] Audit log for delete actions - [ ] Tests for list operations ## Technical Notes ### Volt Component ```php resetPage(); } public function sort(string $column): void { if ($this->sortBy === $column) { $this->sortDir = $this->sortDir === 'asc' ? 'desc' : 'asc'; } else { $this->sortBy = $column; $this->sortDir = 'desc'; } } public function togglePublish(int $id): void { $post = Post::findOrFail($id); $newStatus = $post->status === 'published' ? 'draft' : 'published'; $post->update(['status' => $newStatus]); AdminLog::create([ 'admin_id' => auth()->id(), 'action_type' => 'status_change', 'target_type' => 'post', 'target_id' => $post->id, 'old_values' => ['status' => $post->getOriginal('status')], 'new_values' => ['status' => $newStatus], 'ip_address' => request()->ip(), ]); session()->flash('success', __('messages.post_status_updated')); } public function delete(int $id): void { $post = Post::findOrFail($id); AdminLog::create([ 'admin_id' => auth()->id(), 'action_type' => 'delete', 'target_type' => 'post', 'target_id' => $post->id, 'old_values' => $post->toArray(), 'ip_address' => request()->ip(), ]); $post->delete(); session()->flash('success', __('messages.post_deleted')); } public function with(): array { $locale = app()->getLocale(); return [ 'posts' => Post::query() ->when($this->search, fn($q) => $q->where(function($q) use ($locale) { $q->where("title_{$locale}", 'like', "%{$this->search}%") ->orWhere("body_{$locale}", 'like', "%{$this->search}%"); })) ->when($this->statusFilter, fn($q) => $q->where('status', $this->statusFilter)) ->orderBy($this->sortBy, $this->sortDir) ->paginate($this->perPage), ]; } }; ``` ### Template ```blade
{{ __('admin.posts') }} {{ __('admin.create_post') }}
@forelse($posts as $post) @empty @endforelse
{{ __('admin.title') }} {{ __('admin.status') }} {{ __('admin.created') }} {{ __('admin.updated') }} {{ __('admin.actions') }}
{{ $post->title }} {{ __('admin.' . $post->status) }} {{ $post->created_at->format('d/m/Y') }} {{ $post->updated_at->diffForHumans() }}
{{ __('admin.edit') }} {{ $post->status === 'published' ? __('admin.unpublish') : __('admin.publish') }} {{ __('admin.delete') }}
{{ __('admin.no_posts') }}
{{ $posts->links() }}
``` ## Definition of Done - [ ] List displays all posts - [ ] Filter by status works - [ ] Search by title/body works - [ ] Sort by date works - [ ] Quick publish/unpublish toggle works - [ ] Delete with confirmation works - [ ] Pagination works - [ ] Audit log for actions - [ ] Tests pass - [ ] Code formatted with Pint ## Dependencies - **Story 5.1:** Post creation ## Estimation **Complexity:** Medium **Estimated Effort:** 3-4 hours