Files
autocrm/resources/views/filament/tenant/pages/work-order-dashboard.blade.php
T
Vasyka fa8704f8b6 feat(work-orders): new Mitchell1-style dashboard view (Phase 1 — layout + tabs)
Custom Filament Page at /app/work-orders/{id}/dashboard renders a
Mitchell1-inspired 3-column layout:
  - Top bar: WO#, status badge, actions (Edit / Tracking link)
  - Meta header row: creation / opened / ETA / responsible / urgency /
    paid amount (6 cells)
  - Left sidebar (300px): Client card (avatar, phone, email, status
    tag, 3-stat grid: visits/total/debt) + Vehicle card (photo, plate,
    VIN, mileage, engine, gearbox) + Repair history (latest 5 for this
    vehicle, links to dashboards)
  - Middle: tab bar (Lucrări/Piese/Diagnostic/Foto/Documente/Note)
    with Alpine-driven switching. Works & Parts show the tables read-
    only; add/edit still goes through existing EditWorkOrder Filament
    resource. Photos tab shows gallery from spatie/media-library.
  - Right (300px): Finance summary card (works cost, parts cost,
    discount, total, paid, balance) + placeholder for Timeline+Chat
    (Phase 2)
  - Responsive: right column collapses <1280px, left <900px.

'Vizualizare dashboard' button added on top of the existing
EditWorkOrder page so users can switch between edit form and info-
dense dashboard.

Fixed getSlug() signature (must match parent with ?Panel $panel).

+14 translations. All 306 tests pass.

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

696 lines
30 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();
$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; }
/* ── RIGHT SIDEBAR (placeholder for phase 2) ── */
.wd-placeholder {
padding: 20px;
text-align: center;
color: var(--wd-text-3);
font-size: 11px;
font-style: italic;
}
</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="{{ route('filament.tenant.pages.work-order-dashboard', ['record' => $h->id]) }}">
<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>
<div class="wd-placeholder">
{{ __('Timeline & Chat — Phase 2') }}
</div>
</div>
</div>
</div>
</x-filament-panels::page>