Client Dashboard Guide
Last Updated: 2026-01-12 Status: Implemented Plan Reference: 013-client-dashboard.md, 081-client-dashboard-improvement.md
Overview
The Client Dashboard is the landing page for client users after logging into the portal. It provides an overview of their projects, invoices, recent files, and any pending actions or notifications relevant to their account.
Table of Contents
- Accessing the Dashboard
- Dashboard Sections
- Available Information
- Quick Actions
- Technical Architecture
- Related Features
Accessing the Dashboard
Navigation
| Access Point | URL | Role |
|---|---|---|
| Portal Home | /portal | Client User |
| Portal Dashboard | /portal/dashboard | Client User |
Permissions
Only authenticated Client users can access the client dashboard. Admins are redirected to the Admin Dashboard.
Dashboard Sections
Welcome Section
Personalized greeting with:
- User's name
- Client company name
- Quick summary of account status
Active Projects
Overview of current projects:
- Project name and status
- Progress indicator
- Due date (if set)
- Link to project details
Recent Invoices
Summary of billing:
- Latest invoices
- Payment status
- Amount due
- Quick pay link
Recent Files
Latest shared files:
- File name and type
- Upload date
- Quick download link
Notifications
Unread notifications:
- Recent alerts
- Action items
- Mark as read option
Available Information
Project Summary
| Item | Description |
|---|---|
| Active Projects | Count of active projects |
| Total Projects | All projects for client |
| Completed | Finished projects |
| Files Shared | Total visible files |
Invoice Summary
| Item | Description |
|---|---|
| Outstanding | Total unpaid amount |
| Overdue | Past due invoices |
| Last Payment | Date and amount |
| Payment History | Link to full history |
Quick Stats
| Stat | Description |
|---|---|
| Active Projects | Currently in progress |
| Pending Invoices | Awaiting payment |
| Shared Files | Available downloads |
| Unread Notifications | Action needed |
Quick Actions
Available Actions
| Action | Description | Link |
|---|---|---|
| View Projects | See all projects | /portal/projects |
| View Invoices | See all invoices | /portal/invoices |
| View Files | Browse shared files | /portal/files |
| Upload File | Add file to project | Project page |
| Pay Invoice | Make payment | Invoice page |
| Contact Support | Send message | /portal/support |
Action Cards
Prominent action cards for common tasks:
- View Latest Invoice - Direct link to most recent
- Continue Project - Resume last viewed project
- Download Files - Quick access to recent files
Technical Architecture
Controller
Location: app/Http/Controllers/Portal/DashboardController.php
class DashboardController extends Controller
{
public function index(Request $request)
{
$user = $request->user();
$clients = $user->clients;
return view('portal.dashboard', [
'user' => $user,
'clients' => $clients,
'projects' => $this->getProjects($clients),
'invoices' => $this->getInvoices($clients),
'files' => $this->getRecentFiles($clients),
'stats' => $this->getStats($clients),
]);
}
protected function getProjects($clients)
{
return Project::whereIn('client_id', $clients->pluck('id'))
->active()
->latest()
->limit(5)
->get();
}
protected function getInvoices($clients)
{
return Invoice::whereIn('client_id', $clients->pluck('id'))
->whereIn('status', ['sent', 'overdue'])
->latest()
->limit(5)
->get();
}
protected function getStats($clients): array
{
$clientIds = $clients->pluck('id');
return [
'active_projects' => Project::whereIn('client_id', $clientIds)->active()->count(),
'total_projects' => Project::whereIn('client_id', $clientIds)->count(),
'outstanding_amount' => Invoice::whereIn('client_id', $clientIds)->unpaid()->sum('total'),
'shared_files' => ProjectFile::whereHas('project', fn($q) => $q->whereIn('client_id', $clientIds))
->clientVisible()->count(),
];
}
}
Routes
Route::prefix('portal')
->middleware(['auth', 'verified'])
->group(function () {
Route::get('/', fn() => redirect()->route('portal.dashboard'));
Route::get('/dashboard', [Portal\DashboardController::class, 'index'])
->name('portal.dashboard');
});
View
Location: resources/views/portal/dashboard.blade.php
<x-portal-layout>
<x-slot name="header">
Welcome back, {{ $user->name }}!
</x-slot>
{{-- Stats Overview --}}
<div class="grid grid-cols-4 gap-4 mb-6">
<x-stat-card title="Active Projects" :value="$stats['active_projects']" />
<x-stat-card title="Outstanding" :value="money($stats['outstanding_amount'])" />
<x-stat-card title="Shared Files" :value="$stats['shared_files']" />
<x-stat-card title="Notifications" :value="$user->unreadNotifications->count()" />
</div>
<div class="grid grid-cols-2 gap-6">
{{-- Active Projects --}}
<div class="bg-white rounded-lg shadow p-6">
<h2 class="text-lg font-semibold mb-4">Active Projects</h2>
@forelse($projects as $project)
<x-project-card :project="$project" />
@empty
<p class="text-gray-500">No active projects</p>
@endforelse
<a href="{{ route('portal.projects.index') }}" class="text-blue-600">
View all projects →
</a>
</div>
{{-- Recent Invoices --}}
<div class="bg-white rounded-lg shadow p-6">
<h2 class="text-lg font-semibold mb-4">Recent Invoices</h2>
@forelse($invoices as $invoice)
<x-invoice-row :invoice="$invoice" />
@empty
<p class="text-gray-500">No pending invoices</p>
@endforelse
<a href="{{ route('portal.invoices.index') }}" class="text-blue-600">
View all invoices →
</a>
</div>
</div>
{{-- Recent Files --}}
<div class="mt-6 bg-white rounded-lg shadow p-6">
<h2 class="text-lg font-semibold mb-4">Recent Files</h2>
<div class="grid grid-cols-4 gap-4">
@forelse($files as $file)
<x-file-card :file="$file" />
@empty
<p class="text-gray-500 col-span-4">No files shared yet</p>
@endforelse
</div>
</div>
</x-portal-layout>
Components
| Component | Purpose |
|---|---|
stat-card | Display single metric |
project-card | Project summary card |
invoice-row | Invoice list item |
file-card | File preview card |
notification-item | Notification entry |
Multi-Client Support
Users associated with multiple clients see:
- Client selector dropdown
- Combined or per-client views
- Aggregated statistics
// If user has multiple clients
@if($clients->count() > 1)
<x-client-selector :clients="$clients" :selected="$selectedClient" />
@endif
Related Features
Dependencies
| Feature | Relationship |
|---|---|
| Authentication | Login required |
| Authorization | Client role scope |
| Client Management | Client association |
Complementary Features
| Feature | Description |
|---|---|
| Admin Dashboard | Admin view |
| Project Management | Project details |
| Invoicing | Invoice payments |
| File Sharing | File downloads |
| Notifications | Alert system |
Best Practices
For Usability
- Show actionable items first (pending invoices, action needed)
- Limit displayed items to most relevant
- Provide clear navigation to full lists
- Highlight overdue items with visual indicators
For Performance
- Cache client-specific data where appropriate
- Limit query results with pagination
- Eager load relationships to avoid N+1
Troubleshooting
| Issue | Solution |
|---|---|
| No projects shown | Check client association |
| Wrong client data | Verify user-client pivot |
| Missing files | Check file visibility flags |
| Stats incorrect | Verify client ID scoping |
See Also
- Admin Dashboard - Admin view
- Project Management - Projects
- Invoicing - Invoices
- Portal UI - UI customization