@extends('layouts.app') @section('title', $project->title) @section('content') @php $sv = $project->status instanceof \App\Enums\ProjectStatus ? $project->status->value : $project->status; $statusBadge = match($sv) { 'active' => 'bg-emerald-50 text-emerald-700', 'completed' => 'bg-slate-100 text-slate-600', 'on_hold' => 'bg-amber-50 text-amber-600', 'cancelled' => 'bg-red-50 text-red-600', default => 'bg-slate-100 text-slate-500', }; $statusLabel = match($sv) { 'active' => 'Active', 'completed' => 'Completed', 'on_hold' => 'On Hold', 'cancelled' => 'Cancelled', default => ucfirst($sv), }; $symMap = $financials['symMap']; $hasOutstanding = !empty($financials['outstandingByCurrency']); @endphp
{{-- Flash messages --}} @if (session('success'))
{{ session('success') }}
@endif @if (session('error'))
{{ session('error') }}
@endif {{-- Delete error --}} @if ($errors->has('delete'))
{{ $errors->first('delete') }}
@endif {{-- Page header --}}

{{ $project->title }}

{{ $statusLabel }}

{{ $project->client->name }}

@can('projects.manage') Edit @endcan @can('projects.manage')
@csrf @method('DELETE')
@endcan
{{-- Financial stat cards --}}

Total Proposed

@if (empty($financials['totalProposedByCurrency']))

@else @foreach ($financials['totalProposedByCurrency'] as $cur => $amt)

{{ $symMap[$cur] ?? $cur }} {{ number_format($amt, 2) }}

@endforeach @endif

Total Approved

@if (empty($financials['totalApprovedByCurrency']))

@else @foreach ($financials['totalApprovedByCurrency'] as $cur => $amt)

{{ $symMap[$cur] ?? $cur }} {{ number_format($amt, 2) }}

@endforeach @endif

Total Paid

@if (empty($financials['totalPaidByCurrency']))

@else @foreach ($financials['totalPaidByCurrency'] as $cur => $amt)

{{ $symMap[$cur] ?? $cur }} {{ number_format($amt, 2) }}

@endforeach @endif

Outstanding

@if (!$hasOutstanding)

Settled

@else @foreach ($financials['outstandingByCurrency'] as $cur => $amt)

{{ $symMap[$cur] ?? $cur }} {{ number_format($amt, 2) }}

@endforeach @endif
{{-- Three-column grid --}}
{{-- LEFT: col-span-2 --}}
{{-- Proposals card --}}

Proposals

New Proposal
@if ($project->proposals->isEmpty()) @else @foreach ($project->proposals as $proposal) @php $pSv = $proposal->status instanceof \App\Enums\ProposalStatus ? $proposal->status->value : $proposal->status; $pBadge = match($pSv) { 'draft' => 'bg-slate-100 text-slate-600', 'sent' => 'bg-sky-50 text-sky-700', 'approved' => 'bg-emerald-50 text-emerald-700', 'rejected' => 'bg-red-50 text-red-600', 'expired' => 'bg-amber-50 text-amber-600', default => 'bg-slate-100 text-slate-500', }; $pCur = $proposal->currency instanceof \App\Enums\Currency ? $proposal->currency->value : (string) $proposal->currency; $pSymbol = $symMap[$pCur] ?? $pCur; @endphp @endforeach
Title Amount Status Valid Until
{{ $proposal->title ?? '—' }} {{ $pSymbol }} {{ number_format($proposal->amount, 2) }} {{ ucfirst($pSv) }} {{ $proposal->valid_until ? $proposal->valid_until->format('d M Y') : '—' }} View →
@endif
{{-- Invoices card --}}

Invoices

@if ($project->invoices->isEmpty())

No invoices yet

@else @foreach ($project->invoices as $invoice) @php $iSv = $invoice->status instanceof \App\Enums\InvoiceStatus ? $invoice->status->value : $invoice->status; $iBadge = match($iSv) { 'unpaid' => 'bg-amber-50 text-amber-700', 'partial' => 'bg-sky-50 text-sky-700', 'paid' => 'bg-emerald-50 text-emerald-700', default => 'bg-slate-100 text-slate-600', }; $iLabel = match($iSv) { 'unpaid' => 'Unpaid', 'partial' => 'Partial', 'paid' => 'Paid', default => ucfirst($iSv), }; $iSymbol = $invoice->currency instanceof \App\Enums\Currency ? $invoice->currency->symbol() : (string) $invoice->currency; $totalPaid = $invoice->payments->reduce(fn ($c, $p) => bcadd($c, (string) $p->amount, 2), '0'); $paidPct = bccomp((string) $invoice->amount, '0', 2) > 0 ? min(100, max(0, (int) bcmul(bcdiv($totalPaid, (string) $invoice->amount, 4), '100', 0))) : 0; $progressColor = match($iSv) { 'paid' => 'bg-emerald-500', 'partial' => 'bg-sky-500', default => 'bg-slate-200', }; $iOverdue = $invoice->due_date->isPast() && $iSv === 'unpaid'; @endphp @endforeach
Invoice # Amount Status Due Date Progress
{{ $invoice->invoice_number }} {{ $iSymbol }} {{ number_format($invoice->amount, 2) }} {{ $iLabel }} {{ $invoice->due_date->format('d M Y') }}
{{ $paidPct }}%
View →
@endif
{{-- RIGHT: col-span-1 --}}
{{-- Project Details card --}}

Project Details

Description

{{ $project->description ?? '—' }}

Created

{{ $project->created_at->format('d M Y') }}

Updated

{{ $project->updated_at->format('d M Y') }}

{{-- Client card --}}

Client

{{ $project->client->name }}

@if ($project->client->email) {{ $project->client->email }} @endif @if ($project->client->phone)

{{ $project->client->phone }}

@endif
{{-- Team card --}}

Project Team

@if ($project->assignedUsers->isNotEmpty()) {{ $project->assignedUsers->count() }} @endif
{{-- Member list --}} @if ($project->assignedUsers->isNotEmpty())
@foreach ($project->assignedUsers as $member) @php $initials = collect(explode(' ', $member->name))->map(fn($w) => strtoupper($w[0] ?? ''))->take(2)->implode(''); $memberRole = $member->roles->first()?->name ?? 'Staff'; $avatarColor = match(true) { str_contains($memberRole, 'Admin') => 'bg-slate-700 text-white', str_contains($memberRole, 'Manager') => 'bg-emerald-600 text-white', default => 'bg-sky-600 text-white', }; @endphp
{{ $initials }}

{{ $member->name }}

@if ($member->pivot->role_on_project)

{{ $member->pivot->role_on_project }}

@else

{{ $memberRole }}

@endif
@can('projects.manage')
@csrf @method('DELETE')
@endcan
@endforeach
@else

No team members assigned yet.

@endif {{-- Assign form — managers only --}} @can('projects.manage') @if ($availableUsers->isNotEmpty())
@elseif ($project->assignedUsers->isNotEmpty())

All users are already assigned.

@endif @endcan
{{-- Update Status card --}}

Update Status

{{ $statusLabel }}
@csrf @method('PATCH')
{{-- Timeline card --}}

Timeline

Edit
@if ($project->start_date || $project->end_date || $project->estimated_days)
@if ($project->start_date)

Start

{{ $project->start_date->format('d M Y') }}

@endif @if ($project->end_date)

Deadline

{{ $project->end_date->format('d M Y') }}

@if ($project->isOverdue()) {{ abs($project->daysRemaining()) }}d overdue @elseif ($project->daysRemaining() !== null) {{ $project->daysRemaining() }}d left @endif
@endif @php $duration = $project->durationInDays(); @endphp @if ($duration)

Duration

{{ $project->durationForHumans() }}

@endif {{-- Progress bar (only when both dates set and not yet completed) --}} @if ($project->start_date && $project->end_date && ! in_array($project->status->value, ['completed', 'cancelled'])) @php $total = max(1, $project->start_date->diffInDays($project->end_date)); $elapsed = min($total, max(0, $project->start_date->diffInDays(now()))); $pct = round($elapsed / $total * 100); @endphp
Progress {{ $pct }}%
@endif @if ($project->actual_completion_date)

Completed

{{ $project->actual_completion_date->format('d M Y') }}

@endif
@else

No timeline set. Add dates

@endif

Project age

{{ $project->created_at->diffForHumans() }}

First proposal

{{ $project->proposals->sortBy('created_at')->first()?->created_at?->format('d M Y') ?? '—' }}

Last payment

{{ $project->invoices->flatMap->payments->sortByDesc('paid_at')->first()?->paid_at?->format('d M Y') ?? '—' }}

@endsection