Files
construprogress/app/Livewire/Reports/ReportsDashboard.php
T
javier da0c8bd134 fix(auth): register Spatie role/permission middleware + add missing #[Layout] (fixes post-login crash)
Login authenticated fine but the landing page crashed (so it looked like
'login doesn't work'):
- bootstrap/app.php didn't register Spatie's middleware aliases -> any route
  with role:/permission: threw 'Target class [role] does not exist'.
  Registered role / permission / role_or_permission.
- config/livewire.php absent -> default layout is the non-existent
  components.layouts.app. ProjectList, PhaseProgress and ReportsDashboard
  lacked #[Layout('layouts.app')] -> MissingLayoutException. Added it (the
  other 10 routed components already had it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 16:12:20 +02:00

105 lines
3.5 KiB
PHP

<?php
namespace App\Livewire\Reports;
use Livewire\Component;
use Livewire\Attributes\Layout;
use App\Models\Project;
use App\Models\Phase;
use App\Models\Inspection;
use Carbon\Carbon;
#[Layout('layouts.app')]
class ReportsDashboard extends Component
{
public $dateRange = 'month'; // week, month, quarter, year
public $chartData = [];
public function mount()
{
$this->loadChartData();
}
public function loadChartData()
{
// Project progress over time (last 6 months)
$projects = Project::with(['phases' => function($query) {
$query->select('project_id', 'progress_percent', 'updated_at');
}])->get();
// Simulate monthly progress data (since we don't have historical stored)
// In a real app, we'd have a progress_history table or similar
$months = [];
$current = Carbon::now();
for ($i = 5; $i >= 0; $i--) {
$month = $current->copy()->subMonths($i);
$months[] = $month->format('M Y');
}
$projectProgress = [];
foreach ($projects as $project) {
$progressData = [];
foreach ($months as $month) {
// For demo, we'll use current progress with some variation
$avgProgress = $project->phases->avg('progress_percent') ?? 0;
// Add some random variation for demo purposes
$variation = rand(-10, 10);
$progress = max(0, min(100, $avgProgress + $variation));
$progressData[] = round($progress);
}
$projectProgress[] = [
'name' => $project->name,
'data' => $progressData
];
}
// Inspections by type (last 6 months)
$inspections = Inspection::with(['template', 'feature'])
->whereDate('created_at', '>=', Carbon::now()->subMonths(6))
->get();
$inspectionTypes = $inspections->groupBy(function($inspection) {
return $inspection->template ? $inspection->template->name : 'Sin plantilla';
})->map(function($group) {
return $group->count();
});
// Projects by status
$projectsByStatus = Project::selectRaw('status, count(*) as count')
->groupBy('status')
->pluck('count', 'status')
->toArray();
// Average phase progress by project
$projectPhaseProgress = Project::with(['phases'])
->get()
->map(function($project) {
return [
'name' => $project->name,
'progress' => $project->phases->avg('progress_percent') ?? 0
];
});
$this->chartData = [
'months' => $months,
'projectProgress' => $projectProgress,
'inspectionTypes' => [
'labels' => $inspectionTypes->keys()->toArray(),
'data' => $inspectionTypes->values()->toArray()
],
'projectsByStatus' => [
'labels' => array_map(function($status) {
return ucfirst(str_replace('_', ' ', $status));
}, array_keys($projectsByStatus)),
'data' => array_values($projectsByStatus)
],
'projectPhaseProgress' => $projectPhaseProgress
];
}
public function render()
{
return view('livewire.reports.reports-dashboard');
}
}