diff --git a/app/Livewire/Client/ClientProjects.php b/app/Livewire/Client/ClientProjects.php new file mode 100644 index 0000000..cf2ea96 --- /dev/null +++ b/app/Livewire/Client/ClientProjects.php @@ -0,0 +1,137 @@ +loadProjects(); + } + + public function loadProjects() + { + // Get projects where the user has the 'client' role + $user = auth()->user(); + $this->projects = $user->projects() + ->wherePivot('role_in_project', 'client') + ->with(['phases' => function($query) { + $query->select('id', 'project_id', 'name', 'progress_percent'); + }]) + ->get() + ->toArray(); + } + + public function selectProject($projectId) + { + $this->selectedProject = $projectId; + $this->loadProjectDetails(); + } + + public function loadProjectDetails() + { + if (!$this->selectedProject) { + return; + } + + $project = Project::with([ + 'phases.features', + 'inspections.template' + ])->find($this->selectedProject); + + if (!$project) { + return; + } + + $this->projectDetails = [ + 'id' => $project->id, + 'name' => $project->name, + 'description' => $project->description, + 'start_date' => $project->start_date, + 'end_date' => $project->end_date, + 'status' => $project->status, + 'progress' => $project->phases->avg('progress_percent') ?? 0, + ]; + + // Get recent images (simulated for now) + $this->galleryImages = [ + [ + 'url' => 'https://via.placeholder.com/400x300?text=Avance+1', + 'title' => 'Avance inicial', + 'date' => now()->subDays(30)->format('d/m/Y') + ], + [ + 'url' => 'https://via.placeholder.com/400x300?text=Avance+2', + 'title' => 'Estructura levantada', + 'date' => now()->subDays(15)->format('d/m/Y') + ], + [ + 'url' => 'https://via.placeholder.com/400x300?text=Avance+3', + 'title' => 'Instalaciones', + 'date' => now()->subDays(5)->format('d/m/Y') + ] + ]; + + // Get change orders (simulated for now) + $this->changeOrders = [ + [ + 'id' => 124, + 'title' => 'Ampliación de zona de almacenamiento', + 'description' => 'Solicitud de ampliación de zona de almacenamiento debido a cambios logísticos.', + 'status' => 'pending', + 'requested_at' => now()->subDays(10)->format('d/m/Y'), + 'amount' => 1500.00 + ], + [ + 'id' => 125, + 'title' => 'Cambio de material en acabados interiores', + 'description' => 'Cambio de cerámica estándar a porcelanato en baños y cocinas.', + 'status' => 'pending', + 'requested_at' => now()->subDays(5)->format('d/m/Y'), + 'amount' => 3200.00 + ] + ]; + } + + public function approveChangeOrder($orderId) + { + // In a real app, this would update the database + foreach ($this->changeOrders as &$order) { + if ($order['id'] == $orderId) { + $order['status'] = 'approved'; + break; + } + } + $this->dispatch('changeOrderUpdated', ['id' => $orderId, 'status' => 'approved']); + } + + public function rejectChangeOrder($orderId) + { + // In a real app, this would update the database + foreach ($this->changeOrders as &$order) { + if ($order['id'] == $orderId) { + $order['status'] = 'rejected'; + break; + } + } + $this->dispatch('changeOrderUpdated', ['id' => $orderId, 'status' => 'rejected']); + } + + public function render() + { + return view('livewire.client.client-projects'); + } +} diff --git a/resources/views/client/dashboard.blade.php b/resources/views/client/dashboard.blade.php new file mode 100644 index 0000000..4d35640 --- /dev/null +++ b/resources/views/client/dashboard.blade.php @@ -0,0 +1,128 @@ + +
+

+ Bienvenido, {{ auth()->user()->name }} +

+ +
+
+
+

+ Mis Proyectos Activos +

+ + +
+
+ +
+
+

+ Notificaciones +

+ +
+
+
+ + + +
+
+

+ Proyecto actualizado +

+

+ Se han añadido nuevas fotos al proyecto "Centro Comercial Norte" +

+

+ Hace 2 horas +

+
+
+ +
+
+ + + +
+
+

+ Orden de cambio aprobada +

+

+ La orden de cambio #123 ha sido aprobada +

+

+ Hace 1 día +

+
+
+
+
+
+
+ +
+
+
+

+ Galería de Progreso +

+ + +
+
+ +
+
+

+ Órdenes de Cambio Pendientes +

+ +
+
+

+ Orden de cambio #124 +

+

+ Solicitud de ampliación de zona de almacenamiento +

+
+ + +
+
+ +
+

+ Orden de cambio #125 +

+

+ Cambio de material en acabados interiores +

+
+ + +
+
+
+
+
+
+
+
diff --git a/resources/views/layouts/client.blade.php b/resources/views/layouts/client.blade.php new file mode 100644 index 0000000..9775d07 --- /dev/null +++ b/resources/views/layouts/client.blade.php @@ -0,0 +1,129 @@ + + + + + + + + {{ config('app.name', 'Avante') }} - Portal Cliente + + + + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + @livewireStyles + + + + + + + + + + +
+ +
+
+
+
+
+ Avante +
+ +
+ +
+
+
+ + + + + +
+
+ {{ $slot }} +
+
+
+ + @stack('scripts') + @livewireScripts + + + diff --git a/resources/views/livewire/client/client-projects.blade.php b/resources/views/livewire/client/client-projects.blade.php new file mode 100644 index 0000000..8567f6c --- /dev/null +++ b/resources/views/livewire/client/client-projects.blade.php @@ -0,0 +1,234 @@ +
+ @if(!$selectedProject) + +
+

Seleccione un proyecto para ver detalles

+ +
+ @foreach($projects as $project) +
+
+

{{ $project['name'] }}

+

+ {{ $project['description'] ?? 'Sin descripción disponible' }} +

+
+ + {{ ucfirst($project['pivot']['role_in_project']) }} + + + @php + $progress = collect($project['phases'])->avg('progress_percent') ?? 0; + @endphp + {{ number_format($progress, 1) }}% completado + +
+
+
+ @endforeach +
+
+ @else + +
+
+

{{ $projectDetails['name'] }}

+ +
+ +
+
+

Estado

+

+ @php + $statuses = [ + 'planning' => 'Planificación', + 'in_progress' => 'En progreso', + 'on_hold' => 'En espera', + 'completed' => 'Completado', + 'cancelled' => 'Cancelado' + ]; + echo $statuses[$projectDetails['status']] ?? ucfirst($projectDetails['status']); + @endphp +

+
+ +
+

Fecha de inicio

+

+ {{ $projectDetails['start_date'] ?? 'No definida' }} +

+
+ +
+

Fecha estimada

+

+ {{ $projectDetails['end_date'] ?? 'No definida' }} +

+
+
+ +
+

Descripción

+

+ {{ $projectDetails['description'] ?? 'No hay descripción disponible' }} +

+
+
+ + +
+

Resumen de Progreso

+ +
+
+

Progreso General

+
+ {{ number_format($projectDetails['progress'] ?? 0, 1) }}% +
+
+ +
+
+
+ +
+ {{ $projectDetails['progress'] ?? 0 }}% completado +
+
+
+ + +
+

Progreso por Fase

+ + @php + $project = \App\Models\Project::find($selectedProject); + $phases = $project->phases ?? collect(); + @endphp + + @if($phases->isNotEmpty()) +
+ @foreach($phases as $phase) +
+
+

{{ $phase->name }}

+ + Fase {{ $phase->id }} + +
+ +
+
+
+ +
+ {{ $phase->progress_percent ?? 0 }}% completado +
+ + @if($phase->features->isNotEmpty()) +
+

Características:

+
+ @foreach($phase->features as $feature) +
+ + + {{ $feature->name }}: + {{ $feature->completion_status ?? 'Pendiente' }} + +
+ @endforeach +
+
+ @endif +
+ @endforeach +
+ @else +
+

No hay fases definidas para este proyecto

+
+ @endif +
+ + +
+

Galería de Progreso

+ + +
+ + +
+

Órdenes de Cambio

+ + @if($changeOrders->isNotEmpty()) +
+ @foreach($changeOrders as $order) +
+
+

{{ $order['title'] }}

+ + {{ ucfirst($order['status']) }} + +
+ +

{{ $order['description'] }}

+ +
+ + Solicitado: {{ $order['requested_at'] }} + + + Monto: ${{ number_format($order['amount'], 2) }} + +
+ + @if($order['status'] == 'pending') +
+
+ + +
+
+ @endif +
+ @endforeach +
+ @else +
+

No hay órdenes de cambio pendientes

+
+ @endif +
+ @endif +
diff --git a/routes/web.php b/routes/web.php index 7c22746..26d54d3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -90,6 +90,13 @@ Route::get('/reports/dashboard', ReportsDashboard::class)->name('reports.dashboa // Rutas para el LayerManager: Route::get('/projects/{project}/phases/{phase}/layers/manage', \App\Livewire\LayerManager::class)->name('layers.manage'); + // 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 () { @@ -121,4 +128,4 @@ Route::get('/reports/dashboard', ReportsDashboard::class)->name('reports.dashboa }); // Incluir rutas de autenticación (login, registro, recuperación de contraseña, logout) -require __DIR__ . '/auth.php'; \ No newline at end of file +require __DIR__ . '/auth.php';