route('dashboard'); })->middleware(['auth']); // Grupo de rutas protegidas por autenticación Route::middleware(['auth'])->group(function () { // Dashboard principal (vista con estadísticas y lista de proyectos) Route::get('/dashboard', function () { $user = \Illuminate\Support\Facades\Auth::user(); $projectIds = \App\Models\Project::accessibleBy($user)->pluck('id'); $projects = \App\Models\Project::accessibleBy($user) ->withCount('phases') ->with(['phases' => fn($q) => $q->orderBy('order')]) ->latest()->take(6)->get(); $activeProjects = \App\Models\Project::accessibleBy($user)->where('status', 'in_progress')->count(); $totalProjects = \App\Models\Project::accessibleBy($user)->count(); $totalPhases = \App\Models\Phase::whereIn('project_id', $projectIds)->count(); $totalFeatures = \App\Models\Feature::whereHas('layer.phase', fn($q) => $q->whereIn('project_id', $projectIds))->count(); $globalProgress = \App\Models\Phase::whereIn('project_id', $projectIds)->avg('progress_percent') ?? 0; $openIssues = \App\Models\Issue::whereIn('project_id', $projectIds)->where('status', 'open')->count(); $criticalIssues = \App\Models\Issue::whereIn('project_id', $projectIds)->where('status', 'open')->where('priority', 'critical')->count(); $pendingInspections = \App\Models\Inspection::whereIn('project_id', $projectIds)->where('status', 'pending')->count(); $completedInspections = \App\Models\Inspection::whereIn('project_id', $projectIds)->where('status', 'completed')->count(); $rejectedInspections = \App\Models\Inspection::whereIn('project_id', $projectIds)->where('status', 'rejected')->count(); $recentInspections = \App\Models\Inspection::whereIn('project_id', $projectIds) ->with(['template', 'feature', 'project']) ->latest()->take(5)->get(); $recentIssues = \App\Models\Issue::whereIn('project_id', $projectIds) ->with(['feature', 'reporter', 'project']) ->where('status', '!=', 'closed') ->orderByRaw("FIELD(priority,'critical','high','medium','low')") ->take(5)->get(); // Projects with delay (planned_end exceeded and not completed) $delayedPhases = \App\Models\Phase::whereIn('project_id', $projectIds) ->whereNotNull('planned_end') ->where('planned_end', '<', now()) ->where('progress_percent', '<', 100) ->with('project') ->count(); return view('dashboard', [ 'stats' => [ 'active_projects' => $activeProjects, 'total_projects' => $totalProjects, 'total_phases' => $totalPhases, 'total_features' => $totalFeatures, 'global_progress' => round($globalProgress), 'open_issues' => $openIssues, 'critical_issues' => $criticalIssues, 'pending_inspections' => $pendingInspections, 'completed_inspections'=> $completedInspections, 'rejected_inspections' => $rejectedInspections, 'delayed_phases' => $delayedPhases, ], 'recentProjects' => $projects, 'recentInspections' => $recentInspections, 'recentIssues' => $recentIssues, ]); })->name('dashboard'); // Reports — Admin only Route::middleware(['can:manage all'])->prefix('reports')->name('reports.')->group(function () { Route::get('/dashboard', ReportsDashboard::class)->name('dashboard'); Route::get('export/projects', [App\Http\Controllers\Reports\ExportController::class, 'exportProjects'])->name('export.projects'); Route::get('export/phases', [App\Http\Controllers\Reports\ExportController::class, 'exportPhases'])->name('export.phases'); Route::get('export/inspections', [App\Http\Controllers\Reports\ExportController::class, 'exportInspections'])->name('export.inspections'); }); // ------------------------------------------------------------ // Gestión de proyectos // ------------------------------------------------------------ // Create/Edit handled by unified Livewire component Route::get('/projects/create', \App\Livewire\ProjectForm::class)->name('projects.create'); Route::get('/projects/{project}/edit', \App\Livewire\ProjectForm::class)->name('projects.edit'); Route::resource('projects', ProjectController::class)->except(['create', 'edit']); // Ruta personalizada para ver el mapa de un proyecto específico Route::get('/projects/{project}/map', [ProjectController::class, 'map'])->name('projects.map'); // Ruta para que el componente Livewire muestre/gestione el progreso de una fase Route::get('/phases/{phase}/progress', PhaseProgress::class)->name('phases.progress'); Route::get('/projects-list', ProjectList::class)->name('projects.list'); // Ruta para templates Route::get('/projects/{project}/templates', function ($project) { return view('projects.templates', ['project' => \App\Models\Project::findOrFail($project)]); })->name('projects.templates')->middleware('can:edit projects'); // Rutas para el LayerManager: Route::get('/projects/{project}/phases/{phase}/layers/manage', \App\Livewire\LayerManager::class)->name('layers.manage'); // Cronograma Gantt y reporte del proyecto Route::get('/projects/{project}/gantt', PhaseGantt::class)->name('projects.gantt'); Route::get('/projects/{project}/report', [ProjectReportController::class, 'show'])->name('projects.report'); // Issues del proyecto Route::get('/projects/{project}/issues', \App\Livewire\IssueManager::class)->name('projects.issues'); // Dashboard por proyecto Route::get('/projects/{project}/dashboard', \App\Livewire\ProjectDashboard::class)->name('projects.dashboard'); // Cliente: portal cliente Route::middleware(['auth', 'role:client'])->prefix('client')->name('client.')->group(function () { Route::get('/', function () { return view('client.dashboard'); })->name('dashboard'); }); // Admin: gestión de usuarios y roles Route::middleware(['can:manage all'])->prefix('admin')->name('admin.')->group(function () { Route::get('/users', function () { return view('admin.users'); })->name('users'); Route::get('/users/create', \App\Livewire\UserForm::class)->name('users.create'); Route::get('/users/{user}', \App\Livewire\UserView::class)->name('users.show'); Route::get('/users/{user}/edit', \App\Livewire\UserForm::class)->name('users.edit'); }); // Gestor de medios Route::get('/projects/{project}/media', function (\App\Models\Project $project) { return view('projects.media', compact('project')); })->name('projects.media'); Route::get('/companies', \App\Livewire\CompanyManagement::class)->name('companies.manage'); Route::get('/companies/create', \App\Livewire\CompanyForm::class)->name('companies.create'); Route::get('/companies/{company}', \App\Livewire\CompanyView::class)->name('companies.show'); Route::get('/companies/{company}/edit', \App\Livewire\CompanyForm::class)->name('companies.edit'); // ------------------------------------------------------------ // Sincronización offline (para trabajadores en campo) // ------------------------------------------------------------ Route::post('/offline/pending', [OfflineSyncController::class, 'storePending'])->name('offline.store'); Route::post('/offline/sync', [OfflineSyncController::class, 'sync'])->name('offline.sync'); // ------------------------------------------------------------ // Perfil de usuario (proporcionado por Laravel Breeze) // ------------------------------------------------------------ Route::get('/profile', [ProfileController::class, 'edit'])->name('profile'); //Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); Route::post('/logout', [AuthenticatedSessionController::class, 'destroy']) ->name('logout'); }); // Incluir rutas de autenticación (login, registro, recuperación de contraseña, logout) require __DIR__ . '/auth.php';