78ff8d4b43
User screenshots showed the tenant admin panel (Filament) had sidebar
labels stuck in Romanian even when switching to Russian: 'Cereri',
'Calendar vizual', 'Atelierul meu', 'KPI mecanici', 'Fișe lucru',
'Norme-ore', 'Tehnicieni', 'Șabloane servicii', 'Depozite', 'Scaner',
'Depozit', 'VIN-căutare', 'Furnizori', 'Achiziții', 'Procentaj',
'Coeficienți preț', plus all group headers.
Root cause: every Filament Resource and Page had static properties
'protected static ?string $navigationLabel = "Fișe lucru"' — string
literals baked into class definitions. Static properties don't run
through the translation layer.
Fix in two parts:
1. New translation files with 52 label keys + 12 group keys:
- lang/ro/nav.php — Romanian (identity)
- lang/ru/nav.php — full Russian translations (Заказ-наряды,
Автомобили, Клиенты, Календарь, Моя мастерская, Механики KPI,
Настройки, etc.)
- lang/en/nav.php — English translations (Work orders, Vehicles,
Clients, Calendar, My workshop, Mechanic KPI, Settings, etc.)
Keyed by the Romanian original so lookups map 1:1 —
'nav.label.Fișe lucru' returns 'Заказ-наряды' in RU, 'Work orders'
in EN, 'Fișe lucru' in RO.
2. Python transformer converted 54 files:
- 33 Filament Tenant Resources
- 15 Filament Tenant Pages
- 4 Filament Central Resources
- 1 Filament Central Page
- 1 Widget
Each 'protected static ?string $navigationLabel = "X";' became
'public static function getNavigationLabel(): string { return
__("nav.label.X"); }'. Same treatment for $navigationGroup.
Cleanup: 6 resources already had manually-added getNavigationLabel
methods from an earlier partial effort — those used flat JSON keys
(__("Cereri")) that never resolved. Deduped so only the nav.label.*
version remains.
Untouched (intentional):
- $modelLabel / $pluralModelLabel (used in breadcrumbs and headings —
still hardcoded, next tier of work)
- Section titles, column headers, form field labels (medium priority)
- $navigationSort (numeric, no translation needed)
- $navigationIcon (icon reference)
Suite: 306 passed (853 assertions). Unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
149 lines
4.5 KiB
PHP
149 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Tenant\Pages;
|
|
|
|
use App\Models\Tenant\WorkOrder;
|
|
use App\Models\Tenant\WorkOrderWork;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Pages\Page;
|
|
|
|
/**
|
|
* Mobile-first dashboard for a single mechanic — shows ONLY work orders
|
|
* assigned to the currently logged-in user (master_id = auth()->id()).
|
|
* Kanban-style grouped by status.
|
|
*/
|
|
class MechanicBoard extends Page
|
|
{
|
|
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-wrench';
|
|
|
|
public static function getNavigationLabel(): string
|
|
{
|
|
return __('nav.label.Atelierul meu');
|
|
}
|
|
|
|
public static function getNavigationGroup(): ?string
|
|
{
|
|
return __('nav.group.Service');
|
|
}
|
|
|
|
protected static ?int $navigationSort = 25;
|
|
|
|
protected static ?string $title = 'Atelierul meu';
|
|
|
|
protected string $view = 'filament.tenant.pages.mechanic-board';
|
|
|
|
public function getColumns(): array
|
|
{
|
|
$userId = auth()->id();
|
|
if (! $userId) return [];
|
|
|
|
$all = WorkOrder::with(['client', 'vehicle'])
|
|
->where('master_id', $userId)
|
|
->whereIn('status', ['in_work', 'awaiting_parts', 'ready', 'done', 'approved', 'diagnosis'])
|
|
->orderBy('opened_at', 'desc')
|
|
->get();
|
|
|
|
return [
|
|
[
|
|
'key' => 'in_work',
|
|
'label' => 'În lucru',
|
|
'color' => '#f59e0b',
|
|
'items' => $all->where('status', 'in_work')->values(),
|
|
],
|
|
[
|
|
'key' => 'awaiting_parts',
|
|
'label' => 'Așteaptă piese',
|
|
'color' => '#8b5cf6',
|
|
'items' => $all->whereIn('status', ['awaiting_parts'])->values(),
|
|
],
|
|
[
|
|
'key' => 'ready',
|
|
'label' => 'Gata',
|
|
'color' => '#10b981',
|
|
'items' => $all->where('status', 'ready')->values(),
|
|
],
|
|
[
|
|
'key' => 'recent',
|
|
'label' => 'Recente / restul',
|
|
'color' => '#64748b',
|
|
'items' => $all->whereIn('status', ['done', 'approved', 'diagnosis'])
|
|
->take(20)
|
|
->values(),
|
|
],
|
|
];
|
|
}
|
|
|
|
public ?int $blockingWorkId = null;
|
|
public string $blockReason = 'missing_part';
|
|
public string $blockNote = '';
|
|
|
|
public function startWork(int $id): void
|
|
{
|
|
$w = WorkOrderWork::find($id);
|
|
if ($w && $w->workOrder?->master_id === auth()->id()) $w->start();
|
|
}
|
|
|
|
public function pauseWork(int $id): void
|
|
{
|
|
$w = WorkOrderWork::find($id);
|
|
if ($w && $w->workOrder?->master_id === auth()->id()) $w->pause();
|
|
}
|
|
|
|
public function resumeWork(int $id): void
|
|
{
|
|
$w = WorkOrderWork::find($id);
|
|
if ($w && $w->workOrder?->master_id === auth()->id()) $w->resume();
|
|
}
|
|
|
|
public function doneWork(int $id): void
|
|
{
|
|
$w = WorkOrderWork::find($id);
|
|
if ($w && $w->workOrder?->master_id === auth()->id()) $w->markDone();
|
|
}
|
|
|
|
public function openBlockModal(int $id): void
|
|
{
|
|
$this->blockingWorkId = $id;
|
|
$this->blockReason = 'missing_part';
|
|
$this->blockNote = '';
|
|
}
|
|
|
|
public function confirmBlock(): void
|
|
{
|
|
if (! $this->blockingWorkId) return;
|
|
$work = WorkOrderWork::find($this->blockingWorkId);
|
|
if (! $work) return;
|
|
// Only own work
|
|
if ($work->workOrder?->master_id !== auth()->id()) {
|
|
$this->blockingWorkId = null;
|
|
return;
|
|
}
|
|
$work->block($this->blockReason, trim($this->blockNote) ?: null);
|
|
Notification::make()->title('Lucrare blocată')->body($work->name . ' · ' . WorkOrderWork::BLOCK_REASONS[$this->blockReason])->warning()->send();
|
|
$this->blockingWorkId = null;
|
|
}
|
|
|
|
public function getWorksFor(int $woId): array
|
|
{
|
|
return WorkOrderWork::where('work_order_id', $woId)->orderBy('id')->get()->all();
|
|
}
|
|
|
|
public function getCounts(): array
|
|
{
|
|
$userId = auth()->id();
|
|
return [
|
|
'active' => $userId
|
|
? WorkOrder::where('master_id', $userId)
|
|
->whereIn('status', ['in_work', 'awaiting_parts', 'ready'])
|
|
->count()
|
|
: 0,
|
|
'closed_today' => $userId
|
|
? WorkOrder::where('master_id', $userId)
|
|
->where('status', 'done')
|
|
->whereDate('closed_at', today())
|
|
->count()
|
|
: 0,
|
|
];
|
|
}
|
|
}
|