diff --git a/app/Filament/Tenant/Pages/PipelineBoard.php b/app/Filament/Tenant/Pages/PipelineBoard.php index 64bbebb..f4e9026 100644 --- a/app/Filament/Tenant/Pages/PipelineBoard.php +++ b/app/Filament/Tenant/Pages/PipelineBoard.php @@ -42,6 +42,13 @@ class PipelineBoard extends Page public string $activeFilter = 'all'; // all | mine | urgent | today public ?string $openCardKey = null; // "lead:5" / "deal:8" / "wo:12" + public bool $showNewForm = false; // panel in "new request" mode + public string $searchQuery = ''; + public string $newName = ''; + public string $newPhone = ''; + public string $newCar = ''; + public string $newSource = 'call'; + public string $newNotes = ''; public const COLUMNS = [ 'request' => ['Cerere nouă', '#94A3B8'], @@ -124,6 +131,18 @@ class PipelineBoard extends Page $cards['paid'][] = $this->woCard($wo); } + // Apply search query + $q = trim($this->searchQuery); + if ($q !== '') { + $needle = mb_strtolower($q); + foreach ($cards as $col => $list) { + $cards[$col] = array_values(array_filter($list, function ($c) use ($needle) { + $hay = mb_strtolower(($c['subject'] ?? '') . ' ' . ($c['client_name'] ?? '') . ' ' . ($c['plate'] ?? '') . ' ' . ($c['code'] ?? '') . ' ' . ($c['phone'] ?? '')); + return str_contains($hay, $needle); + })); + } + } + // Sort: urgent first, then time foreach ($cards as $col => $list) { usort($list, fn ($a, $b) => ($b['urgent'] ?? false) <=> ($a['urgent'] ?? false)); @@ -188,6 +207,52 @@ class PipelineBoard extends Page $this->activeFilter = in_array($filter, ['all', 'mine', 'urgent', 'today'], true) ? $filter : 'all'; } + public function openNewForm(): void + { + $this->showNewForm = true; + $this->openCardKey = null; + $this->newName = ''; + $this->newPhone = ''; + $this->newCar = ''; + $this->newSource = 'call'; + $this->newNotes = ''; + } + + public function createNewLead(): void + { + $data = ['name' => trim($this->newName), 'phone' => trim($this->newPhone), 'car' => trim($this->newCar) ?: null, 'source' => $this->newSource, 'message' => trim($this->newNotes) ?: null]; + if ($data['name'] === '' || $data['phone'] === '') { + $this->notify('Nume și telefon sunt obligatorii'); + return; + } + Lead::create(array_merge($data, ['status' => 'new'])); + $this->showNewForm = false; + $this->notify('Cerere nouă adăugată'); + } + + public function exportCsv() + { + $columns = $this->getColumns(); + $csv = "Etapă,Cod,Subiect,Client,Telefon,Auto,Sumă,Responsabil,Stare\n"; + foreach ($columns as $col) { + foreach ($col['cards'] as $card) { + $csv .= sprintf( + "%s,%s,%s,%s,%s,%s,%.2f,%s,%s\n", + $col['label'], + $card['code'], + str_replace(',', ' ', $card['subject']), + str_replace(',', ' ', $card['client_name']), + $card['phone'] ?? '', + $card['plate'], + $card['amount'], + $card['assignee']['name'], + str_replace(',', ' ', $card['time_text']), + ); + } + } + return response()->streamDownload(fn () => print $csv, 'pipeline-' . today()->format('Y-m-d') . '.csv', ['Content-Type' => 'text/csv']); + } + public function moveCard(string $key, string $toCol): void { [$kind, $id] = explode(':', $key, 2) + [null, null]; @@ -475,7 +540,9 @@ class PipelineBoard extends Page } if ($wo->status === 'ready') { $tags[] = ['label' => 'Gata', 'color' => 'green']; - if ($wo->pay_status !== 'paid') { + if ($wo->pay_status === 'partial') { + $tags[] = ['label' => 'Avans achitat', 'color' => 'blue']; + } elseif ($wo->pay_status !== 'paid') { $tags[] = ['label' => 'Neachitat', 'color' => 'amber']; } } diff --git a/resources/views/filament/tenant/pages/pipeline-board.blade.php b/resources/views/filament/tenant/pages/pipeline-board.blade.php index ecf3e4d..b7d602b 100644 --- a/resources/views/filament/tenant/pages/pipeline-board.blade.php +++ b/resources/views/filament/tenant/pages/pipeline-board.blade.php @@ -54,7 +54,7 @@ --pb-gray-text: #d1d5db; } -/* Break out of Filament chrome — full-bleed board */ +/* Break out of Filament chrome */ .fi-main-ctn:has(.pb-shell) { padding: 0 !important; } .fi-main:has(.pb-shell) { padding: 0 !important; } .fi-page:has(.pb-shell) > div { padding: 0 !important; gap: 0 !important; } @@ -62,6 +62,20 @@ .fi-page:has(.pb-shell) { gap: 0 !important; } .pb-shell { background:var(--pb-bg); color:var(--pb-text); margin:0; padding:0; min-height:calc(100vh - 64px); font-size:13px; display:flex; flex-direction:column; } + +/* TOPBAR */ +.pb-topbar { height:52px; background:var(--pb-surface); border-bottom:1px solid var(--pb-border); display:flex; align-items:center; padding:0 20px; gap:12px; flex-shrink:0; } +.pb-topbar-title { font-size:15px; font-weight:600; letter-spacing:-.2px; } +.pb-topbar-sep { width:1px; height:18px; background:var(--pb-border-md); } +.pb-search { display:flex; align-items:center; gap:6px; background:var(--pb-bg); border:1px solid var(--pb-border); border-radius:6px; padding:5px 10px; flex:1; max-width:320px; } +.pb-search input { border:none; background:transparent; outline:none; font-size:12px; color:var(--pb-text); width:100%; } +.pb-search-icon { color:var(--pb-text-3); font-size:14px; } +.pb-topbar-right { margin-left:auto; display:flex; align-items:center; gap:8px; } +.pb-btn { display:inline-flex; align-items:center; gap:5px; padding:6px 12px; border-radius:6px; font-size:12px; font-weight:500; cursor:pointer; border:1px solid var(--pb-border-md); background:var(--pb-surface); color:var(--pb-text); white-space:nowrap; text-decoration:none; } +.pb-btn:hover { background:var(--pb-bg); } +.pb-btn-primary { background:var(--pb-blue); color:#fff !important; border-color:var(--pb-blue); } +.pb-btn-primary:hover { background:#1557d4; } + .pb-stat-strip { background:var(--pb-surface); border-bottom:1px solid var(--pb-border); padding:10px 20px; display:flex; gap:20px; flex-wrap:wrap; flex-shrink:0; } .pb-stat-item { display:flex; flex-direction:column; gap:2px; min-width:60px; } .pb-stat-val { font-size:16px; font-weight:600; } @@ -76,6 +90,7 @@ .pb-chip:hover { border-color:var(--pb-border-md); } .pb-chip.active { background:var(--pb-blue-bg); border-color:#93B8F9; color:var(--pb-blue-text); } .pb-filter-sep { width:1px; height:20px; background:var(--pb-border); } +.pb-period { display:flex; align-items:center; gap:5px; padding:4px 10px; border:1px solid var(--pb-border); border-radius:6px; font-size:11px; background:var(--pb-surface); color:var(--pb-text-2); } .pb-total { margin-left:auto; font-size:11px; color:var(--pb-text-2); } .pb-total strong { color:var(--pb-text); } @@ -129,14 +144,18 @@ .pb-act-btn { width:24px; height:24px; border-radius:5px; border:1px solid var(--pb-border); background:var(--pb-surface); cursor:pointer; display:flex; align-items:center; justify-content:center; color:var(--pb-text-2); font-size:13px; text-decoration:none; } .pb-act-btn:hover { background:var(--pb-bg); color:var(--pb-text); border-color:var(--pb-border-md); } +/* Col 6 (Achitat azi): faded, no hover actions */ +.pb-col[data-col="paid"] .pb-deal { opacity:0.65; } +.pb-col[data-col="paid"] .pb-deal-actions { display:none !important; } + .pb-add-card { display:flex; align-items:center; justify-content:center; gap:6px; padding:8px 12px; border-radius:10px; border:1px dashed var(--pb-border-md); color:var(--pb-text-3); font-size:11px; cursor:pointer; background:transparent; text-decoration:none; flex-shrink:0; } .pb-add-card:hover { border-color:var(--pb-blue); color:var(--pb-blue); background:var(--pb-blue-bg); } .pb-overlay { position:fixed; inset:0; background:rgba(0,0,0,0.25); z-index:100; opacity:0; pointer-events:none; transition:opacity .2s; } .pb-overlay.open { opacity:1; pointer-events:all; } -.pb-panel { position:fixed; right:0; top:0; bottom:0; width:440px; max-width:92vw; background:var(--pb-surface); border-left:1px solid var(--pb-border); z-index:101; transform:translateX(100%); transition:transform .25s cubic-bezier(.4,0,.2,1); overflow-y:auto; display:flex; flex-direction:column; } +.pb-panel { position:fixed; right:0; top:0; bottom:0; width:440px; max-width:92vw; background:var(--pb-surface); border-left:1px solid var(--pb-border); z-index:101; transform:translateX(100%); transition:transform .25s cubic-bezier(.4,0,.2,1); overflow:hidden; display:flex; flex-direction:column; } .pb-panel.open { transform:translateX(0); } -.pb-panel-head { padding:16px 20px 12px; border-bottom:1px solid var(--pb-border); display:flex; align-items:flex-start; justify-content:space-between; position:sticky; top:0; background:var(--pb-surface); z-index:10; } +.pb-panel-head { padding:16px 20px 12px; border-bottom:1px solid var(--pb-border); display:flex; align-items:flex-start; justify-content:space-between; background:var(--pb-surface); flex-shrink:0; } .pb-panel-title { font-size:15px; font-weight:600; line-height:1.3; } .pb-panel-id { font-size:11px; color:var(--pb-text-3); margin-top:2px; } .pb-close-btn { width:28px; height:28px; border-radius:6px; border:1px solid var(--pb-border); background:var(--pb-bg); cursor:pointer; display:flex; align-items:center; justify-content:center; } @@ -161,16 +180,38 @@ .pb-quick-grid { display:grid; grid-template-columns:1fr 1fr; gap:6px; } .pb-quick-btn { display:flex; align-items:center; justify-content:center; gap:5px; padding:8px; font-size:11px; border:1px solid var(--pb-border-md); border-radius:6px; background:var(--pb-surface); color:var(--pb-text); cursor:pointer; text-decoration:none; } .pb-quick-btn:hover { background:var(--pb-bg); } -.pb-quick-btn.primary { background:var(--pb-blue); color:#fff; border-color:var(--pb-blue); } +.pb-quick-btn.primary { background:var(--pb-blue); color:#fff !important; border-color:var(--pb-blue); } .pb-quick-btn.primary:hover { background:#1557d4; } -.pb-panel-actions { padding:12px 20px; border-top:1px solid var(--pb-border); display:flex; gap:8px; background:var(--pb-surface); position:sticky; bottom:0; } +.pb-panel-actions { padding:12px 20px; border-top:1px solid var(--pb-border); display:flex; gap:8px; background:var(--pb-surface); flex-shrink:0; } .pb-panel-actions .pb-quick-btn { flex:1; } +/* New-card form */ +.pb-form-field { margin-bottom:12px; } +.pb-form-field label { display:block; font-size:10px; font-weight:600; color:var(--pb-text-3); text-transform:uppercase; letter-spacing:.5px; margin-bottom:4px; } +.pb-form-field input, .pb-form-field textarea, .pb-form-field select { width:100%; padding:8px 10px; font-size:13px; border:1px solid var(--pb-border-md); border-radius:6px; background:var(--pb-surface); color:var(--pb-text); outline:none; font-family:inherit; } +.pb-form-field input:focus, .pb-form-field textarea:focus, .pb-form-field select:focus { border-color:var(--pb-blue); } +.pb-form-field textarea { resize:vertical; min-height:60px; } + .pb-empty-col { display:flex; flex-direction:column; align-items:center; justify-content:center; padding:24px 12px; color:var(--pb-text-3); font-size:11px; text-align:center; }