Files
autocrm/resources/views/filament/tenant/pages/work-order-dashboard.blade.php
T
Vasyka 5fff3d1a70 fix(dashboard): replace route() with url() — Filament auto-name has literal {record}
Filament auto-generates route names from the URL slug, so my custom
Page with slug 'work-orders/{record}/dashboard' got the ugly name
'filament.tenant.pages.work-orders.{record}.dashboard' — where
'{record}' is treated as a literal segment in the name, breaking
route() lookups.

Switch all links + the header-action URL to url('/app/work-orders/'
. \$id . '/dashboard') so they resolve correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-05 19:05:42 +00:00

819 lines
36 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<x-filament-panels::page>
@php
/** @var \App\Models\Tenant\WorkOrder $wo */
$wo = $this->record;
$finance = $this->getFinance();
$history = $this->getRepairHistory();
$timeline = $this->getTimeline();
$messages = $this->getNotifications();
$prev = $this->getPrevWo();
$next = $this->getNextWo();
$tabs = [
'works' => ['label' => __('Lucrări'), 'count' => $wo->works->count()],
'parts' => ['label' => __('Piese'), 'count' => $wo->parts->count()],
'diag' => ['label' => __('Diagnostic'), 'count' => null],
'photos' => ['label' => __('Foto'), 'count' => $wo->getMedia('photos')->count() ?? 0],
'docs' => ['label' => __('Documente'), 'count' => null],
'notes' => ['label' => __('Note'), 'count' => null],
];
$statusClass = match ($wo->status) {
'in_work' => 'wd-status-active',
'awaiting_parts' => 'wd-status-warn',
'ready' => 'wd-status-ready',
'done' => 'wd-status-done',
'cancelled' => 'wd-status-cancel',
default => 'wd-status-new',
};
@endphp
<style>
/* ══ WORK-ORDER DASHBOARD (Mitchell1-style) ══ */
:root {
--wd-bg: #F7F7F5;
--wd-surface: #FFFFFF;
--wd-border: #E5E7EB;
--wd-border-md: #D1D5DB;
--wd-text: #111827;
--wd-text-2: #4B5563;
--wd-text-3: #9CA3AF;
--wd-blue: #2563EB;
--wd-blue-bg: #EFF6FF;
--wd-green: #16A34A;
--wd-green-bg: #DCFCE7;
--wd-amber: #D97706;
--wd-amber-bg: #FEF3C7;
--wd-red: #DC2626;
--wd-red-bg: #FEE2E2;
--wd-slate: #64748B;
}
.dark {
--wd-bg: #0F172A;
--wd-surface: #1E293B;
--wd-border: #334155;
--wd-border-md: #475569;
--wd-text: #F1F5F9;
--wd-text-2: #CBD5E1;
--wd-text-3: #94A3B8;
}
/* Break out of Filament content wrapper */
.fi-main-ctn:has(.wd-shell) { padding: 0 !important; }
.fi-main:has(.wd-shell) { padding: 0 !important; }
.fi-page:has(.wd-shell) > div { padding: 0 !important; gap: 0 !important; }
.fi-page:has(.wd-shell) .fi-header { display: none !important; }
.wd-shell {
background: var(--wd-bg);
color: var(--wd-text);
min-height: calc(100vh - 64px);
display: flex;
flex-direction: column;
font-size: 13px;
}
/* ── TOP BAR ── */
.wd-topbar {
background: var(--wd-surface);
border-bottom: 1px solid var(--wd-border);
padding: 10px 20px;
display: flex;
align-items: center;
gap: 12px;
flex-shrink: 0;
}
.wd-wo-title { font-size: 15px; font-weight: 700; letter-spacing: -.2px; }
.wd-status {
padding: 4px 10px;
border-radius: 6px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .3px;
cursor: pointer;
display: inline-flex; align-items: center; gap: 4px;
}
.wd-status-active { background: #DBEAFE; color: #1E40AF; }
.wd-status-warn { background: var(--wd-amber-bg); color: var(--wd-amber); }
.wd-status-ready { background: var(--wd-green-bg); color: #166534; }
.wd-status-done { background: #F3F4F6; color: #6B7280; }
.wd-status-cancel { background: var(--wd-red-bg); color: var(--wd-red); }
.wd-status-new { background: #EDE9FE; color: #6D28D9; }
.wd-btn {
padding: 7px 12px;
border: 1px solid var(--wd-border-md);
border-radius: 6px;
font-size: 12px;
font-weight: 500;
background: var(--wd-surface);
color: var(--wd-text);
cursor: pointer;
display: inline-flex; align-items: center; gap: 5px;
text-decoration: none;
}
.wd-btn:hover { background: var(--wd-bg); }
.wd-btn-primary { background: var(--wd-green); color: #fff; border-color: var(--wd-green); }
.wd-btn-primary:hover { background: #15803d; }
.wd-btn-secondary { background: var(--wd-text); color: #fff; border-color: var(--wd-text); }
.wd-btn-secondary:hover { background: #000; }
.wd-topbar-actions { margin-left: auto; display: flex; gap: 6px; }
/* ── META HEADER ROW ── */
.wd-meta {
background: var(--wd-surface);
border-bottom: 1px solid var(--wd-border);
padding: 10px 20px;
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 16px;
flex-shrink: 0;
}
.wd-meta-item { display: flex; flex-direction: column; gap: 3px; }
.wd-meta-lbl { font-size: 10px; color: var(--wd-text-3); text-transform: uppercase; letter-spacing: .4px; font-weight: 600; }
.wd-meta-val { font-size: 13px; color: var(--wd-text); }
.wd-meta-val.person { display: flex; align-items: center; gap: 6px; }
.wd-avatar {
width: 22px; height: 22px; border-radius: 50%;
background: var(--wd-blue-bg); color: var(--wd-blue);
display: inline-flex; align-items: center; justify-content: center;
font-size: 10px; font-weight: 700;
}
.wd-priority-dot {
display: inline-block; width: 8px; height: 8px; border-radius: 50%;
margin-right: 5px;
}
.wd-priority-normal { background: var(--wd-amber); }
.wd-priority-urgent, .wd-priority-express { background: var(--wd-red); }
/* ── 3-COLUMN GRID ── */
.wd-body {
flex: 1;
display: grid;
grid-template-columns: 300px 1fr 300px;
gap: 12px;
padding: 12px;
min-height: 0;
overflow: hidden;
}
@media (max-width: 1280px) {
.wd-body { grid-template-columns: 260px 1fr; }
.wd-col-right { display: none; }
}
@media (max-width: 900px) {
.wd-body { grid-template-columns: 1fr; }
.wd-col-left { display: none; }
}
.wd-col-left, .wd-col-mid, .wd-col-right {
display: flex; flex-direction: column; gap: 12px;
overflow-y: auto;
min-height: 0;
}
/* ── CARDS (common) ── */
.wd-card {
background: var(--wd-surface);
border: 1px solid var(--wd-border);
border-radius: 10px;
padding: 14px;
}
.wd-card-hd {
display: flex; align-items: center; justify-content: space-between;
margin-bottom: 10px;
}
.wd-card-hd h3 { font-size: 13px; font-weight: 600; margin: 0; }
.wd-card-hd a { font-size: 11px; color: var(--wd-blue); text-decoration: none; }
.wd-card-hd a:hover { text-decoration: underline; }
/* ── LEFT SIDEBAR ── */
.wd-person-row {
display: flex; align-items: center; gap: 10px;
margin-bottom: 8px;
}
.wd-person-avatar {
width: 40px; height: 40px; border-radius: 50%;
background: var(--wd-bg); border: 1px solid var(--wd-border);
display: inline-flex; align-items: center; justify-content: center;
font-size: 15px; font-weight: 700; color: var(--wd-text-2);
flex-shrink: 0;
}
.wd-person-name { font-size: 13px; font-weight: 600; line-height: 1.2; }
.wd-person-phone { font-size: 11px; color: var(--wd-blue); display: block; margin-top: 2px; }
.wd-person-email { font-size: 11px; color: var(--wd-text-2); display: block; margin-top: 1px; }
.wd-tag {
display: inline-block;
background: var(--wd-blue-bg); color: var(--wd-blue);
padding: 2px 8px; border-radius: 4px;
font-size: 10px; font-weight: 600;
margin-top: 6px;
}
.wd-stat-grid {
display: grid; grid-template-columns: repeat(3, 1fr);
gap: 6px; margin-top: 10px;
}
.wd-stat-cell {
text-align: center;
background: var(--wd-bg);
border-radius: 6px;
padding: 6px 4px;
}
.wd-stat-cell .l { font-size: 9px; color: var(--wd-text-3); text-transform: uppercase; }
.wd-stat-cell .v { font-size: 12px; font-weight: 700; margin-top: 2px; }
.wd-stat-cell .v.money { color: var(--wd-green); }
.wd-stat-cell .v.debt { color: var(--wd-red); }
.wd-vehicle-photo {
width: 100%; aspect-ratio: 16/10; object-fit: cover;
background: var(--wd-bg);
border-radius: 6px;
margin-bottom: 8px;
}
.wd-veh-title { font-size: 13px; font-weight: 700; line-height: 1.2; }
.wd-veh-facts {
display: grid; grid-template-columns: auto 1fr;
gap: 4px 10px; font-size: 11px;
margin-top: 6px;
}
.wd-veh-facts dt { color: var(--wd-text-3); }
.wd-veh-facts dd { color: var(--wd-text); font-weight: 500; margin: 0; }
.wd-history-item {
padding: 6px 0;
border-bottom: 1px solid var(--wd-border);
font-size: 11px;
display: flex; justify-content: space-between; gap: 8px;
}
.wd-history-item:last-child { border-bottom: 0; }
.wd-history-item .h-date { color: var(--wd-text-3); }
.wd-history-item .h-total { font-weight: 600; }
.wd-history-item a { color: var(--wd-text); text-decoration: none; }
.wd-history-item a:hover { color: var(--wd-blue); }
/* ── MIDDLE: TABS ── */
.wd-tabs-bar {
background: var(--wd-surface);
border: 1px solid var(--wd-border);
border-radius: 10px 10px 0 0;
border-bottom: 0;
display: flex;
padding: 0 8px;
overflow-x: auto;
flex-shrink: 0;
}
.wd-tab {
padding: 12px 16px;
border-bottom: 2px solid transparent;
color: var(--wd-text-2);
cursor: pointer;
font-size: 13px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: .3px;
background: none;
border-left: 0; border-right: 0; border-top: 0;
white-space: nowrap;
display: inline-flex; align-items: center; gap: 5px;
}
.wd-tab.active { color: var(--wd-blue); border-bottom-color: var(--wd-blue); font-weight: 600; }
.wd-tab-count {
background: var(--wd-bg); color: var(--wd-text-2);
padding: 1px 6px; border-radius: 8px;
font-size: 10px; font-weight: 600;
}
.wd-tab-content {
background: var(--wd-surface);
border: 1px solid var(--wd-border);
border-top: 0;
border-radius: 0 0 10px 10px;
padding: 16px;
flex: 1;
overflow: auto;
min-height: 0;
}
/* Tables inside tabs */
.wd-tbl { width: 100%; border-collapse: collapse; font-size: 12px; }
.wd-tbl th, .wd-tbl td {
padding: 8px 10px;
text-align: left;
border-bottom: 1px solid var(--wd-border);
}
.wd-tbl th {
font-size: 10px; color: var(--wd-text-3);
text-transform: uppercase; letter-spacing: .3px;
font-weight: 600; background: var(--wd-bg);
}
.wd-tbl td.right, .wd-tbl th.right { text-align: right; font-variant-numeric: tabular-nums; }
.wd-tbl tr:last-child td { border-bottom: 0; }
.wd-tbl tr:hover td { background: rgba(37,99,235,.03); }
.wd-mini-badge {
display: inline-block;
padding: 2px 7px; border-radius: 4px;
font-size: 10px; font-weight: 600;
text-transform: uppercase;
}
.wd-mini-todo { background: #F3F4F6; color: #6B7280; }
.wd-mini-progress { background: var(--wd-blue-bg); color: var(--wd-blue); }
.wd-mini-done { background: var(--wd-green-bg); color: #166534; }
.wd-empty { padding: 40px 20px; text-align: center; color: var(--wd-text-3); font-size: 12px; }
.wd-empty-add { margin-top: 8px; }
.wd-footer-row {
display: flex; justify-content: space-between; align-items: center;
padding: 10px 4px; margin-top: 8px;
font-size: 12px;
border-top: 1px solid var(--wd-border);
}
.wd-footer-total { font-weight: 700; font-size: 13px; }
/* ── TIMELINE ── */
.wd-timeline { display: flex; flex-direction: column; gap: 10px; max-height: 240px; overflow-y: auto; }
.wd-tl-item { display: flex; gap: 8px; font-size: 11px; }
.wd-tl-icon {
width: 24px; height: 24px; border-radius: 50%;
background: var(--wd-bg); border: 1px solid var(--wd-border);
display: flex; align-items: center; justify-content: center;
flex-shrink: 0; font-size: 11px;
}
.wd-tl-body { flex: 1; min-width: 0; }
.wd-tl-body .lbl { font-weight: 600; color: var(--wd-text); line-height: 1.3; }
.wd-tl-body .meta { color: var(--wd-text-3); font-size: 10px; margin-top: 2px; }
/* ── CHAT ── */
.wd-chat { display: flex; flex-direction: column; height: 260px; }
.wd-chat-list { flex: 1; overflow-y: auto; padding-right: 4px; }
.wd-msg { margin-bottom: 8px; }
.wd-msg-meta { font-size: 10px; color: var(--wd-text-3); margin-bottom: 2px; display: flex; gap: 6px; }
.wd-msg-body {
background: var(--wd-blue-bg); color: var(--wd-text);
padding: 6px 10px; border-radius: 8px 8px 8px 2px;
font-size: 11px; line-height: 1.4;
white-space: pre-wrap;
}
.wd-msg.failed .wd-msg-body { background: var(--wd-red-bg); color: var(--wd-red); }
.wd-chat-input { display: flex; gap: 6px; margin-top: 8px; }
.wd-chat-input input {
flex: 1; padding: 7px 10px; font-size: 12px;
border: 1px solid var(--wd-border-md); border-radius: 6px;
background: var(--wd-surface); color: var(--wd-text);
}
/* ── BOTTOM ACTION BAR ── */
.wd-bottom {
background: var(--wd-surface);
border-top: 1px solid var(--wd-border);
padding: 10px 20px;
display: flex; gap: 8px; align-items: center;
flex-shrink: 0;
}
.wd-bottom-nav { display: flex; gap: 4px; }
.wd-bottom-actions { margin-left: auto; display: flex; gap: 6px; }
.wd-btn-danger { background: var(--wd-red); color: #fff; border-color: var(--wd-red); }
.wd-btn-danger:hover { background: #991b1b; }
</style>
<div class="wd-shell" x-data="{ tab: @entangle('activeTab').live }">
{{-- ── TOP BAR ── --}}
<div class="wd-topbar">
<span class="wd-wo-title">{{ __('Fișă') }} {{ $wo->number }}</span>
<span class="wd-status {{ $statusClass }}">
{{ __(\App\Models\Tenant\WorkOrder::STATUSES[$wo->status] ?? $wo->status) }}
<span style="opacity:.6;"></span>
</span>
<div class="wd-topbar-actions">
<a class="wd-btn" href="{{ route('filament.tenant.resources.work-orders.edit', ['record' => $wo->id]) }}">
{{ __('Editează') }}
</a>
@if ($wo->tracking_token)
<a class="wd-btn" target="_blank" href="{{ $wo->trackingUrl() }}">
🔗 {{ __('Link tracking') }}
</a>
@endif
<button type="button" class="wd-btn wd-btn-primary">{{ __('Salvează') }}</button>
</div>
</div>
{{-- ── META HEADER ── --}}
<div class="wd-meta">
<div class="wd-meta-item">
<span class="wd-meta-lbl">{{ __('Data creării') }}</span>
<span class="wd-meta-val">{{ $wo->created_at?->format('d.m.Y H:i') ?? '—' }}</span>
</div>
<div class="wd-meta-item">
<span class="wd-meta-lbl">{{ __('Deschis') }}</span>
<span class="wd-meta-val">{{ $wo->opened_at?->format('d.m.Y H:i') ?? '—' }}</span>
</div>
<div class="wd-meta-item">
<span class="wd-meta-lbl">{{ __('ETA') }}</span>
<span class="wd-meta-val">{{ $wo->eta_at?->format('d.m.Y H:i') ?? '—' }}</span>
</div>
<div class="wd-meta-item">
<span class="wd-meta-lbl">{{ __('Responsabil') }}</span>
<span class="wd-meta-val person">
@if ($wo->master)
<span class="wd-avatar">{{ mb_strtoupper(mb_substr($wo->master->name, 0, 2)) }}</span>
{{ $wo->master->name }}
@else @endif
</span>
</div>
<div class="wd-meta-item">
<span class="wd-meta-lbl">{{ __('Urgență') }}</span>
<span class="wd-meta-val">
<span class="wd-priority-dot wd-priority-{{ $wo->urgency ?? 'normal' }}"></span>
{{ __(\App\Models\Tenant\PricingCoefficient::URGENCY[$wo->urgency ?? 'normal'] ?? 'Normal') }}
</span>
</div>
<div class="wd-meta-item">
<span class="wd-meta-lbl">{{ __('Data plății') }}</span>
<span class="wd-meta-val">{{ $wo->paidAmount() > 0 ? number_format($wo->paidAmount(), 2, '.', ' ') . ' MDL' : '—' }}</span>
</div>
</div>
{{-- ── 3-COLUMN BODY ── --}}
<div class="wd-body">
{{-- ═══ LEFT SIDEBAR ═══ --}}
<div class="wd-col-left">
{{-- CLIENT CARD --}}
<div class="wd-card">
<div class="wd-card-hd">
<h3>{{ __('Client') }}</h3>
@if ($wo->client)
<a href="{{ route('filament.tenant.resources.clients.edit', ['record' => $wo->client_id]) }}">{{ __('Editează') }}</a>
@endif
</div>
@if ($wo->client)
<div class="wd-person-row">
<div class="wd-person-avatar">{{ mb_strtoupper(mb_substr($wo->client->name, 0, 1)) }}</div>
<div style="flex:1;min-width:0;">
<div class="wd-person-name">{{ $wo->client->name }}</div>
@if ($wo->client->phone)
<a href="tel:{{ $wo->client->phone }}" class="wd-person-phone">📞 {{ $wo->client->phone }}</a>
@endif
@if ($wo->client->email)
<span class="wd-person-email">{{ $wo->client->email }}</span>
@endif
</div>
</div>
@if (! empty($wo->client->status))
<span class="wd-tag">{{ __(ucfirst($wo->client->status)) }}</span>
@endif
@php
$totalOrders = \App\Models\Tenant\WorkOrder::where('client_id', $wo->client_id)->count();
$totalSpent = (float) \App\Models\Tenant\WorkOrder::where('client_id', $wo->client_id)->sum('total');
$debt = (float) $wo->client->balance;
@endphp
<div class="wd-stat-grid">
<div class="wd-stat-cell">
<div class="l">{{ __('Vizite') }}</div>
<div class="v">{{ $totalOrders }}</div>
</div>
<div class="wd-stat-cell">
<div class="l">{{ __('Total') }}</div>
<div class="v money">{{ number_format($totalSpent, 0, '.', ' ') }}</div>
</div>
<div class="wd-stat-cell">
<div class="l">{{ __('Datorie') }}</div>
<div class="v {{ $debt > 0 ? 'debt' : '' }}">{{ number_format($debt, 0, '.', ' ') }}</div>
</div>
</div>
@else
<div class="wd-empty">{{ __('Fără client') }}</div>
@endif
</div>
{{-- VEHICLE CARD --}}
<div class="wd-card">
<div class="wd-card-hd">
<h3>{{ __('Automobil') }}</h3>
@if ($wo->vehicle)
<a href="{{ route('filament.tenant.resources.vehicles.edit', ['record' => $wo->vehicle_id]) }}">{{ __('Editează') }}</a>
@endif
</div>
@if ($wo->vehicle)
@php
$photoUrl = $wo->vehicle->getFirstMediaUrl('photos') ?? null;
@endphp
@if ($photoUrl)
<img class="wd-vehicle-photo" src="{{ $photoUrl }}" alt="{{ $wo->vehicle->make }}">
@else
<div class="wd-vehicle-photo" style="display:flex;align-items:center;justify-content:center;color:var(--wd-text-3);font-size:24px;">🚗</div>
@endif
<div class="wd-veh-title">{{ $wo->vehicle->make }} {{ $wo->vehicle->model }} {{ $wo->vehicle->year }}</div>
<dl class="wd-veh-facts">
@if ($wo->vehicle->plate)
<dt>{{ __('Nr.') }}</dt><dd>{{ $wo->vehicle->plate }}</dd>
@endif
@if ($wo->vehicle->vin)
<dt>VIN</dt><dd style="font-family:monospace;font-size:10px;">{{ $wo->vehicle->vin }}</dd>
@endif
@if ($wo->vehicle->mileage)
<dt>{{ __('Km') }}</dt><dd>{{ number_format($wo->vehicle->mileage, 0, '.', ' ') }}</dd>
@endif
@if ($wo->vehicle->engine)
<dt>{{ __('Motor') }}</dt><dd>{{ $wo->vehicle->engine }}</dd>
@endif
@if ($wo->vehicle->gearbox)
<dt>{{ __('Cutie') }}</dt><dd>{{ $wo->vehicle->gearbox }}</dd>
@endif
</dl>
@else
<div class="wd-empty">{{ __('Fără mașină') }}</div>
@endif
</div>
{{-- REPAIR HISTORY --}}
<div class="wd-card">
<div class="wd-card-hd">
<h3>{{ __('Istoric reparații') }}</h3>
</div>
@forelse ($history as $h)
<div class="wd-history-item">
<a href="{{ url('/app/work-orders/' . $h->id . '/dashboard') }}">
<span class="h-date">{{ $h->opened_at?->format('d.m.Y') }}</span>
<span>{{ $h->number }}</span>
</a>
<span class="h-total">{{ number_format($h->total, 0, '.', ' ') }} MDL</span>
</div>
@empty
<div class="wd-empty" style="padding:16px 0;">{{ __('Prima vizită') }}</div>
@endforelse
</div>
</div>
{{-- ═══ MIDDLE: TABS ═══ --}}
<div class="wd-col-mid">
<div class="wd-tabs-bar">
@foreach ($tabs as $key => $t)
<button type="button" class="wd-tab" :class="tab === '{{ $key }}' && 'active'" @click="tab = '{{ $key }}'">
{{ $t['label'] }}
@if (! is_null($t['count']))
<span class="wd-tab-count">{{ $t['count'] }}</span>
@endif
</button>
@endforeach
</div>
<div class="wd-tab-content">
{{-- ── WORKS TAB ── --}}
<div x-show="tab === 'works'" x-cloak>
@if ($wo->works->isNotEmpty())
<table class="wd-tbl">
<thead>
<tr>
<th>#</th>
<th>{{ __('Manoperă') }}</th>
<th class="right">{{ __('Ore') }}</th>
<th>{{ __('Mecanic') }}</th>
<th class="right">{{ __('Preț/h') }}</th>
<th class="right">{{ __('Total') }}</th>
<th>{{ __('Status') }}</th>
</tr>
</thead>
<tbody>
@foreach ($wo->works as $i => $w)
<tr>
<td>{{ $i + 1 }}</td>
<td>{{ $w->labor?->label() ?: $w->name }}</td>
<td class="right">{{ rtrim(rtrim(number_format($w->hours, 2), '0'), '.') }}</td>
<td>{{ $w->master?->name ?? '—' }}</td>
<td class="right">{{ number_format($w->price_per_hour, 2, '.', ' ') }}</td>
<td class="right">{{ number_format($w->total, 2, '.', ' ') }}</td>
<td>
<span class="wd-mini-badge wd-mini-{{ $w->status === 'done' ? 'done' : ($w->status === 'in_progress' ? 'progress' : 'todo') }}">
{{ __(\App\Models\Tenant\WorkOrderWork::STATUSES[$w->status] ?? $w->status) }}
</span>
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="wd-footer-row">
<a class="wd-btn" href="{{ route('filament.tenant.resources.work-orders.edit', ['record' => $wo->id, 'relation' => 0]) }}">+ {{ __('Adaugă manoperă') }}</a>
<span class="wd-footer-total">{{ __('Total manopere:') }} {{ number_format($finance['works_sum'], 2, '.', ' ') }} MDL</span>
</div>
@else
<div class="wd-empty">
{{ __('Nicio manoperă efectuată.') }}
<div class="wd-empty-add"><a class="wd-btn" href="{{ route('filament.tenant.resources.work-orders.edit', ['record' => $wo->id, 'relation' => 0]) }}">+ {{ __('Adaugă manoperă') }}</a></div>
</div>
@endif
</div>
{{-- ── PARTS TAB ── --}}
<div x-show="tab === 'parts'" x-cloak>
@if ($wo->parts->isNotEmpty())
<table class="wd-tbl">
<thead>
<tr>
<th>{{ __('Cod') }}</th>
<th>{{ __('Denumire') }}</th>
<th>{{ __('Brand') }}</th>
<th class="right">{{ __('Cant.') }}</th>
<th class="right">{{ __('Preț') }}</th>
<th class="right">{{ __('Total') }}</th>
<th>{{ __('Status') }}</th>
</tr>
</thead>
<tbody>
@foreach ($wo->parts as $p)
<tr>
<td style="font-family:monospace;font-size:11px;">{{ $p->article ?? '—' }}</td>
<td>{{ $p->name }}</td>
<td>{{ $p->brand ?? '—' }}</td>
<td class="right">{{ rtrim(rtrim(number_format($p->qty, 2), '0'), '.') }} {{ $p->unitLabel() ?: '' }}</td>
<td class="right">{{ number_format($p->sell_price, 2, '.', ' ') }}</td>
<td class="right">{{ number_format($p->total, 2, '.', ' ') }}</td>
<td>
<span class="wd-mini-badge wd-mini-{{ $p->status === 'installed' ? 'done' : ($p->status === 'delivered' ? 'progress' : 'todo') }}">
{{ __(\App\Models\Tenant\WorkOrderPart::STATUSES[$p->status] ?? $p->status) }}
</span>
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="wd-footer-row">
<a class="wd-btn" href="{{ route('filament.tenant.resources.work-orders.edit', ['record' => $wo->id, 'relation' => 1]) }}">+ {{ __('Adaugă piesă') }}</a>
<span class="wd-footer-total">{{ __('Total piese:') }} {{ number_format($finance['parts_sum'], 2, '.', ' ') }} MDL</span>
</div>
@else
<div class="wd-empty">
{{ __('Nicio piesă montată.') }}
<div class="wd-empty-add"><a class="wd-btn" href="{{ route('filament.tenant.resources.work-orders.edit', ['record' => $wo->id, 'relation' => 1]) }}">+ {{ __('Adaugă piesă') }}</a></div>
</div>
@endif
</div>
{{-- ── DIAGNOSTIC TAB ── --}}
<div x-show="tab === 'diag'" x-cloak>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">
<div>
<h4 style="font-size:11px;color:var(--wd-text-3);text-transform:uppercase;margin:0 0 8px;">{{ __('Plângere client') }}</h4>
<div style="background:var(--wd-bg);padding:10px 12px;border-radius:6px;font-size:12px;white-space:pre-wrap;min-height:60px;">{{ $wo->complaint ?: '—' }}</div>
</div>
<div>
<h4 style="font-size:11px;color:var(--wd-text-3);text-transform:uppercase;margin:0 0 8px;">{{ __('Diagnostic') }}</h4>
<div style="background:var(--wd-bg);padding:10px 12px;border-radius:6px;font-size:12px;white-space:pre-wrap;min-height:60px;">{{ $wo->diagnosis ?: '—' }}</div>
</div>
</div>
</div>
{{-- ── PHOTOS TAB ── --}}
<div x-show="tab === 'photos'" x-cloak>
@php $photos = $wo->getMedia('photos'); @endphp
@if ($photos->isNotEmpty())
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px;">
@foreach ($photos as $ph)
<a href="{{ $ph->getFullUrl() }}" target="_blank">
<img src="{{ $ph->getFullUrl() }}" style="width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:6px;border:1px solid var(--wd-border);">
</a>
@endforeach
</div>
@else
<div class="wd-empty">{{ __('Nicio fotografie') }}</div>
@endif
</div>
{{-- ── DOCUMENTS TAB ── --}}
<div x-show="tab === 'docs'" x-cloak>
<div class="wd-empty">{{ __('Nicio factură emisă încă') }}</div>
</div>
{{-- ── NOTES TAB ── --}}
<div x-show="tab === 'notes'" x-cloak>
<div style="background:var(--wd-bg);padding:10px 12px;border-radius:6px;font-size:12px;white-space:pre-wrap;min-height:80px;">{{ $wo->notes ?: __('Nicio notă internă.') }}</div>
</div>
</div>
</div>
{{-- ═══ RIGHT COLUMN (placeholder Phase 2) ═══ --}}
<div class="wd-col-right">
<div class="wd-card">
<div class="wd-card-hd">
<h3>{{ __('Finanțe') }}</h3>
</div>
<div style="display:flex;flex-direction:column;gap:6px;font-size:12px;">
<div style="display:flex;justify-content:space-between;">
<span style="color:var(--wd-text-2);">{{ __('Cost manopere') }}</span>
<b>{{ number_format($finance['works_sum'], 2, '.', ' ') }}</b>
</div>
<div style="display:flex;justify-content:space-between;">
<span style="color:var(--wd-text-2);">{{ __('Cost piese') }}</span>
<b>{{ number_format($finance['parts_sum'], 2, '.', ' ') }}</b>
</div>
@if ($finance['discount'] > 0)
<div style="display:flex;justify-content:space-between;">
<span style="color:var(--wd-text-2);">{{ __('Discount') }}</span>
<b style="color:var(--wd-red);">{{ number_format($finance['discount'], 2, '.', ' ') }}</b>
</div>
@endif
<div style="border-top:1px solid var(--wd-border);padding-top:8px;display:flex;justify-content:space-between;font-size:15px;">
<span>{{ __('Total') }}</span>
<b>{{ number_format($finance['total'], 2, '.', ' ') }} MDL</b>
</div>
<div style="display:flex;justify-content:space-between;color:var(--wd-green);">
<span>{{ __('Achitat') }}</span>
<b>{{ number_format($finance['paid'], 2, '.', ' ') }}</b>
</div>
@if ($finance['balance'] > 0)
<div style="display:flex;justify-content:space-between;color:var(--wd-red);font-weight:700;">
<span>{{ __('Rest de plată') }}</span>
<b>{{ number_format($finance['balance'], 2, '.', ' ') }} MDL</b>
</div>
@endif
</div>
</div>
{{-- TIMELINE --}}
<div class="wd-card">
<div class="wd-card-hd">
<h3>{{ __('Timeline') }}</h3>
</div>
@if (! empty($timeline))
<div class="wd-timeline">
@foreach ($timeline as $ev)
<div class="wd-tl-item">
<div class="wd-tl-icon">{{ $ev['icon'] }}</div>
<div class="wd-tl-body">
<div class="lbl">{{ $ev['label'] }}</div>
<div class="meta">
{{ $ev['at']->format('d.m.Y H:i') }}
@if ($ev['meta']) · {{ $ev['meta'] }} @endif
</div>
</div>
</div>
@endforeach
</div>
@else
<div class="wd-empty" style="padding:16px 0;">{{ __('Fără evenimente') }}</div>
@endif
</div>
{{-- CHAT CLIENT --}}
<div class="wd-card">
<div class="wd-card-hd">
<h3>{{ __('Chat client') }}</h3>
@if ($wo->client?->telegram_chat_id)
<span style="font-size:10px;color:var(--wd-blue);"> Telegram</span>
@elseif ($wo->client?->phone)
<span style="font-size:10px;color:var(--wd-text-3);">SMS/WhatsApp</span>
@endif
</div>
@if ($wo->client)
<div class="wd-chat">
<div class="wd-chat-list">
@forelse ($messages as $m)
<div class="wd-msg {{ $m->status === 'failed' ? 'failed' : '' }}">
<div class="wd-msg-meta">
<span>{{ strtoupper($m->channel) }}</span>
<span>{{ $m->sent_at?->format('d.m H:i') }}</span>
@if ($m->status === 'failed')<span style="color:var(--wd-red);"> {{ __('Eșuat') }}</span>@endif
</div>
<div class="wd-msg-body">{{ $m->message_text }}</div>
</div>
@empty
<div class="wd-empty" style="padding:16px 0;">{{ __('Nicio conversație') }}</div>
@endforelse
</div>
<form class="wd-chat-input" wire:submit.prevent="sendMessage">
<input type="text" placeholder="{{ __('Scrie mesajul tău...') }}" wire:model="newMessage" maxlength="1000">
<button type="submit" class="wd-btn wd-btn-primary"></button>
</form>
</div>
@else
<div class="wd-empty" style="padding:16px 0;">{{ __('Fără client — nu se poate trimite mesaj.') }}</div>
@endif
</div>
</div>
</div>
{{-- ── BOTTOM ACTION BAR ── --}}
<div class="wd-bottom">
<div class="wd-bottom-nav">
@if ($prev)
<a class="wd-btn" href="{{ url('/app/work-orders/' . $prev->id . '/dashboard') }}">
{{ __('Precedent') }} <span style="color:var(--wd-text-3);">({{ $prev->number }})</span>
</a>
@endif
@if ($next)
<a class="wd-btn" href="{{ url('/app/work-orders/' . $next->id . '/dashboard') }}">
{{ __('Următor') }} <span style="color:var(--wd-text-3);">({{ $next->number }})</span>
</a>
@endif
</div>
<div class="wd-bottom-actions">
<a class="wd-btn" href="{{ route('filament.tenant.resources.work-orders.create') }}?client_id={{ $wo->client_id }}&vehicle_id={{ $wo->vehicle_id }}">
📄 {{ __('Comandă repetată') }}
</a>
@if ($wo->status !== 'done')
<button type="button" class="wd-btn wd-btn-danger" wire:click="closeWorkOrder" wire:confirm="{{ __('Închide fișa?') }}">
🔒 {{ __('Închide fișă') }}
</button>
@endif
</div>
</div>
</div>
</x-filament-panels::page>