@extends('layouts.app')
@section('title', 'Projects | DYSON LATAM')
@section('content')
@php
/*
|--------------------------------------------------------------------------
| DYSON PROJECTS - VIEW LOGIC
|--------------------------------------------------------------------------
*/
$totalProjects = $projects->count();
$completedProjects = $projects
->filter(function ($project) {
$allItems = $project->stages->concat($project->certifications);
if ($allItems->contains(fn($item) => $item->status === 'blocked')) {
return false;
}
if ($allItems->contains(fn($item) => $item->status === 'overdue')) {
return false;
}
return $allItems->isNotEmpty() && $allItems->every(fn($item) => $item->status === 'completed');
})
->count();
$blockedProjects = $projects
->filter(function ($project) {
$allItems = $project->stages->concat($project->certifications);
return $allItems->contains(fn($item) => $item->status === 'blocked');
})
->count();
$overdueProjects = $projects
->filter(function ($project) {
$allItems = $project->stages->concat($project->certifications);
if ($allItems->contains(fn($item) => $item->status === 'blocked')) {
return false;
}
return $allItems->contains(fn($item) => $item->status === 'overdue');
})
->count();
$inProgressProjects = $projects
->filter(function ($project) {
$allItems = $project->stages->concat($project->certifications);
if ($allItems->contains(fn($item) => $item->status === 'blocked')) {
return false;
}
if ($allItems->contains(fn($item) => $item->status === 'overdue')) {
return false;
}
if ($allItems->isNotEmpty() && $allItems->every(fn($item) => $item->status === 'completed')) {
return false;
}
return $allItems->contains(fn($item) => $item->status === 'in_progress');
})
->count();
$countries = $projects->pluck('country')->filter()->unique('id')->sortBy('name');
$categories = $projects->pluck('category')->filter()->unique('id')->sortBy('name');
$globalStatusCounts = [
'completed' => 0,
'in_progress' => 0,
'pending' => 0,
'blocked' => 0,
'overdue' => 0,
];
$projectProgressValues = [];
foreach ($projects as $project) {
$progressItems = $project->stages->concat($project->certifications);
$progressTotal = $progressItems->count();
$progressCompleted = $progressItems->where('status', 'completed')->count();
$projectProgressValues[] = $progressTotal > 0 ? round(($progressCompleted / $progressTotal) * 100) : 0;
}
$averageProgress =
count($projectProgressValues) > 0
? round(array_sum($projectProgressValues) / count($projectProgressValues))
: 0;
foreach ($projects as $project) {
$globalItems = $project->stages->concat($project->certifications);
if ($globalItems->contains(fn($item) => $item->status === 'blocked')) {
$globalStatus = 'blocked';
} elseif ($globalItems->contains(fn($item) => $item->status === 'overdue')) {
$globalStatus = 'overdue';
} elseif ($globalItems->isNotEmpty() && $globalItems->every(fn($item) => $item->status === 'completed')) {
$globalStatus = 'completed';
} elseif ($globalItems->contains(fn($item) => $item->status === 'in_progress')) {
$globalStatus = 'in_progress';
} else {
$globalStatus = 'pending';
}
$globalStatusCounts[$globalStatus]++;
}
$projectProgressValues = [];
foreach ($projects as $project) {
$progressItems = $project->stages->concat($project->certifications);
$progressTotal = $progressItems->count();
$progressCompleted = $progressItems->where('status', 'completed')->count();
$projectProgressValues[] = $progressTotal > 0 ? round(($progressCompleted / $progressTotal) * 100) : 0;
}
$averageProgress =
count($projectProgressValues) > 0
? round(array_sum($projectProgressValues) / count($projectProgressValues))
: 0;
$stageLabels = [
'sample_arrival' => 'Sample Arrival',
'lab_testing' => 'Lab Testing',
'cert_release' => 'Certificate Release',
'country_homologation' => 'Country Homologation',
];
$statusLabels = [
'completed' => 'Completed',
'in_progress' => 'In Progress',
'pending' => 'Pending',
'blocked' => 'Blocked',
'overdue' => 'Overdue',
'na' => 'N/A',
];
$statusClasses = [
'completed' => 'status-green',
'in_progress' => 'status-blue',
'pending' => 'status-slate',
'blocked' => 'status-red',
'overdue' => 'status-red',
'na' => 'status-slate',
];
$countryInitials = [
'Mexico' => 'MX',
'Brazil' => 'BR',
'Colombia' => 'CO',
'Argentina' => 'AR',
'Chile' => 'CL',
'Peru' => 'PE',
'Ecuador' => 'EC',
];
@endphp
{{-- HEADER --}}
{{-- TABS --}}
{{-- KPIs --}}
Total Projects
{{ $totalProjects }}
of total ({{ $totalProjects }})
Certified
{{ $completedProjects }}
of total ({{ $totalProjects }})
In Progress
{{ $inProgressProjects }}
of total ({{ $totalProjects }})
Blocked / Overdue
{{ $blockedProjects + $overdueProjects }}
of total ({{ $totalProjects }})
{{-- OVERVIEW --}}
{{-- OVERVIEW ANALYTICS --}}
{{-- DISTRIBUTION BY STAGE --}}
Distribution by Stage
@foreach ($stageLabels as $stageKey => $stageLabel)
@php
$applicableProjects = $projects->filter(
fn($project) => $project->stages->contains('stage', $stageKey),
);
$activeProjects = $applicableProjects->filter(
fn($project) => $project->stages
->where('stage', $stageKey)
->whereIn('status', ['completed', 'in_progress'])
->isNotEmpty(),
);
$applicableCount = $applicableProjects->count();
$activeCount = $activeProjects->count();
$stageProgress = $applicableCount > 0 ? round(($activeCount / $applicableCount) * 100) : 0;
@endphp
@if ($applicableCount > 0)
{{ $stageLabel }}
{{ $activeCount }}/{{ $applicableCount }}
@endif
@endforeach
{{-- GLOBAL STATUS --}}
Global Status
@foreach ($globalStatusCounts as $statusKey => $statusCount)
@if ($statusCount > 0)
@php
$statusClass = $statusClasses[$statusKey] ?? 'status-slate';
$statusLabel = $statusLabels[$statusKey] ?? ucfirst($statusKey);
@endphp
{{ $statusLabel }}
{{ $statusCount }}
@endif
@endforeach
{{-- GLOBAL AVERAGE PROGRESS --}}
Global Average Progress
{{ $averageProgress }}%
{{-- PROJECTS WITH ALERTS --}}
Projects with Alerts
@php
$alertProjects = $projects->filter(function ($project) {
$alertItems = $project->stages->concat($project->certifications);
return $alertItems->contains(
fn($item) => in_array($item->status, ['blocked', 'overdue'], true),
);
});
@endphp
@if ($alertProjects->isEmpty())
No active alerts.
@else
@foreach ($alertProjects as $project)
@php
$alertItems = $project->stages->concat($project->certifications);
$alertStatus = $alertItems->contains(fn($item) => $item->status === 'blocked')
? 'blocked'
: 'overdue';
$alertStatusClass = $statusClasses[$alertStatus] ?? 'status-red';
$alertStatusLabel = $statusLabels[$alertStatus] ?? ucfirst($alertStatus);
@endphp
NPD-{{ str_pad($project->id, 3, '0', STR_PAD_LEFT) }}
{{ $project->name }}
{{ $project->country->name ?? '—' }}
{{ $alertStatusLabel }}
@endforeach
@endif
{{-- TRACKER --}}
Project Tracker
STAGE STATUS
@foreach ($projects as $project)
@php
$trackerItems = $project->stages->concat($project->certifications);
$trackerHasBlocked = $trackerItems->contains(fn($item) => $item->status === 'blocked');
$trackerHasOverdue = $trackerItems->contains(fn($item) => $item->status === 'overdue');
$trackerHasInProgress = $trackerItems->contains(fn($item) => $item->status === 'in_progress');
$trackerIsCompleted =
$trackerItems->isNotEmpty() &&
$trackerItems->every(fn($item) => $item->status === 'completed');
if ($trackerHasBlocked) {
$trackerStatus = 'blocked';
} elseif ($trackerHasOverdue) {
$trackerStatus = 'overdue';
} elseif ($trackerIsCompleted) {
$trackerStatus = 'completed';
} elseif ($trackerHasInProgress) {
$trackerStatus = 'in_progress';
} else {
$trackerStatus = 'pending';
}
$trackerProgress =
$trackerItems->count() > 0
? round(
($trackerItems->where('status', 'completed')->count() / $trackerItems->count()) *
100,
)
: 0;
@endphp
{{-- LEFT COLUMN --}}
Lifecycle Stages
@foreach ($project->stages as $stage)
@if (\Illuminate\Support\Facades\Auth::user()?->role !== 'viewer')
@else
{{ $stageLabels[$stage->stage] ?? $stage->stage }}
{{ $statusLabels[$stage->status] ?? ucfirst(str_replace('_', ' ', $stage->status)) }}
{{ $stage->completed_at?->format('Y-m-d') ?? '—' }}
{{ $stage->notes ?: '—' }}
@endif
@endforeach
{{ $project->country->name ?? 'Country' }} Certifications
@foreach ($project->certifications as $certification)
@if (\Illuminate\Support\Facades\Auth::user()?->role !== 'viewer')
@else
{{ $certification->certification }}
@if (!$certification->required)
OPTIONAL
@endif
{{ [
'pending' => 'Pending',
'in_progress' => 'In Progress',
'completed' => 'Completed',
'blocked' => 'Blocked',
'overdue' => 'Overdue',
'na' => 'N/A',
][$certification->status] ?? $certification->status }}
{{ $certification->completed_at?->format('Y-m-d') ?? '—' }}
{{ $certification->notes ?: '—' }}
@endif
@endforeach
{{-- RIGHT COLUMN --}}
Comments
@forelse ($project->comments as $comment)
{{ $comment->user->name ?? 'System' }}
{{ $comment->created_at->format('d M Y H:i') }}
{{ $comment->text }}
@empty
No comments have been registered.
@endforelse
@if (\Illuminate\Support\Facades\Auth::user()?->role !== 'viewer')
@endif
@endforeach
{{-- COUNTRY --}}
Projects by Country
{{ $countries->count() }} COUNTRIES
@foreach ($countries as $country)
@php
$countryProjects = $projects->where('country_id', $country->id);
$countryCertRules = [
'Mexico' => [
'required' => ['NOM'],
'optional' => ['CRT'],
],
'Brazil' => [
'required' => ['INMETRO'],
'optional' => ['ANATEL'],
],
'Chile' => [
'required' => ['SEC'],
'optional' => ['SUBTEL'],
],
'Colombia' => [
'required' => ['Homologation'],
'optional' => [],
],
'Argentina' => [
'required' => ['Homologation'],
'optional' => [],
],
'Peru' => [
'required' => ['Homologation'],
'optional' => [],
],
'Ecuador' => [
'required' => ['Homologation'],
'optional' => [],
],
];
$certRules = $countryCertRules[$country->name] ?? [
'required' => ['Homologation'],
'optional' => [],
];
$certifiedProjects = $countryProjects
->filter(function ($project) {
$items = $project->stages->concat($project->certifications);
return $items->isNotEmpty() &&
$items->every(fn($item) => $item->status === 'completed');
})
->count();
$countryProgress =
$countryProjects->count() > 0
? round(($certifiedProjects / $countryProjects->count()) * 100)
: 0;
@endphp
{{ $country->name }}
{{ $countryProjects->count() }}
{{-- COUNTRY CERTIFICATIONS --}}
@foreach ($certRules['required'] as $cert)
✓ {{ $cert }}
REQUIRED
@endforeach
@foreach ($certRules['optional'] as $cert)
○ {{ $cert }}
OPTIONAL
@endforeach
{{-- COUNTRY PROGRESS --}}
{{ $certifiedProjects }} certified /
{{ $countryProjects->count() }} projects
{{-- PROJECTS IN COUNTRY --}}
@foreach ($countryProjects as $project)
@php
$countryItems = $project->stages->concat($project->certifications);
$countryTotalItems = $countryItems->count();
$countryCompletedItems = $countryItems->where('status', 'completed')->count();
$countryProjectProgress =
$countryTotalItems > 0
? round(($countryCompletedItems / $countryTotalItems) * 100)
: 0;
$countryHasBlocked = $countryItems->contains(fn($item) => $item->status === 'blocked');
$countryHasOverdue = $countryItems->contains(fn($item) => $item->status === 'overdue');
$countryHasInProgress = $countryItems->contains(
fn($item) => $item->status === 'in_progress',
);
if ($countryHasBlocked) {
$countryProjectStatus = 'blocked';
} elseif ($countryHasOverdue) {
$countryProjectStatus = 'overdue';
} elseif (
$countryItems->isNotEmpty() &&
$countryItems->every(fn($item) => $item->status === 'completed')
) {
$countryProjectStatus = 'completed';
} elseif ($countryHasInProgress) {
$countryProjectStatus = 'in_progress';
} else {
$countryProjectStatus = 'pending';
}
$countryProjectStatusClass = $statusClasses[$countryProjectStatus] ?? 'status-slate';
@endphp
NPD-{{ str_pad($project->id, 3, '0', STR_PAD_LEFT) }}
·
{{ \Illuminate\Support\Str::limit($project->name, 20) }}
@if ($project->comments->count() > 0)
💬 {{ $project->comments->count() }}
@endif
{{ $countryProjectProgress }}%
{{ $statusLabels[$countryProjectStatus] ?? 'Pending' }}
{{-- PROJECT CERTIFICATIONS --}}
@foreach ($project->certifications as $certification)
{{ $certification->certification }}
@endforeach
@endforeach
@endforeach
@endsection