Files
autocrm/resources/views/filament/tenant/pages/excel-import-wizard.blade.php
T
Vasyka 7077fff3b3 feat(i18n): convert 38 hardcoded static labels + safe blade wrap + 226 keys
- Convert all remaining static \$modelLabel/\$pluralModelLabel to getter
  methods with __() (AppointmentResource, WorkOrderResource, MasterResource,
  ServiceTemplateResource, LaborResource, and 33 others)
- Safe blade wrap v2 (37 files, 201 wraps): fixed the regex to not match
  `->`, `=>`, `!<` — previous aggressive pass broke @if directives
- Bulk-translate lowercase model-label keys (programări, fișe lucru,
  tehnicieni, șabloane servicii, norme-ore, etc.) — these were the RO
  strings appearing in page titles/breadcrumbs
- Add human RU/EN for mechanic-kpi (Mecanic/Lucrări/Norma ore/etc.)
  and calendar-board words

Tests 306 green. Blade compiles cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-15 06:17:10 +00:00

229 lines
12 KiB
PHP

<x-filament-panels::page>
<style>
.wiz { max-width: 1000px; margin: 0 auto; }
.wiz-steps { display: flex; gap: 8px; margin-bottom: 24px; align-items: center; }
.wiz-step { display: flex; align-items: center; gap: 8px; padding: 6px 14px; border-radius: 20px; font-size: 13px; font-weight: 500; color: #94a3b8; }
.wiz-step.active { background: #ebf5ff; color: #1d4ed8; }
.wiz-step.done { background: #dcfce7; color: #15803d; }
.wiz-step-sep { width: 24px; height: 2px; background: #e2e8f0; }
.wiz-card { background: white; border: 1px solid #e2e8f0; border-radius: 12px; padding: 24px; }
.dark .wiz-card { background: #1f2937; border-color: #374151; }
.wiz-field { margin-bottom: 16px; }
.wiz-field label { display: block; font-size: 11px; font-weight: 600; color: #718096; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; }
.wiz-field input, .wiz-field select { width: 100%; padding: 10px 12px; border: 1px solid #cbd5e1; border-radius: 6px; font-size: 14px; }
.dark .wiz-field input, .dark .wiz-field select { background: #111827; color: #f1f5f9; border-color: #374151; }
.wiz-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
.wiz-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 24px; }
.wiz-btn { padding: 8px 16px; border-radius: 6px; font-weight: 500; cursor: pointer; border: 1px solid #cbd5e1; background: white; color: #1a202c; }
.wiz-btn:hover { background: #f7fafc; }
.wiz-btn-primary { background: #3b82f6; color: white; border-color: #3b82f6; }
.wiz-btn-primary:hover { background: #2563eb; }
.wiz-preview-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.wiz-preview-table th, .wiz-preview-table td { padding: 6px 8px; border: 1px solid #e2e8f0; text-align: left; }
.wiz-preview-table th { background: #f7fafc; font-weight: 600; font-size: 11px; color: #4a5568; }
.dark .wiz-preview-table th { background: #111827; color: #cbd5e1; }
.wiz-badge { padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 500; }
.wiz-badge.found { background: #dcfce7; color: #15803d; }
.wiz-badge.new { background: #fef3c7; color: #92400e; }
.wiz-badge.no_article { background: #fee2e2; color: #991b1b; }
.wiz-summary { display: flex; gap: 16px; margin-bottom: 16px; padding: 12px; background: #f7fafc; border-radius: 6px; }
.dark .wiz-summary { background: #111827; }
.wiz-summary-item { font-size: 13px; }
.wiz-summary-item strong { font-size: 20px; display: block; font-weight: 700; }
.wiz-upload { border: 2px dashed #cbd5e1; border-radius: 8px; padding: 32px; text-align: center; cursor: pointer; }
.wiz-upload:hover { border-color: #3b82f6; background: #ebf5ff; }
.dark .wiz-upload:hover { background: #1e293b; }
</style>
<div class="wiz">
<div class="wiz-steps">
<div class="wiz-step {{ $step >= 1 ? 'active' : '' }} {{ $step > 1 ? 'done' : '' }}">1. Upload</div>
<div class="wiz-step-sep"></div>
<div class="wiz-step {{ $step == 2 ? 'active' : '' }} {{ $step > 2 ? 'done' : '' }}">2. Mapare coloane</div>
<div class="wiz-step-sep"></div>
<div class="wiz-step {{ $step == 3 ? 'active' : '' }} {{ $step > 3 ? 'done' : '' }}">3. Previzualizare</div>
<div class="wiz-step-sep"></div>
<div class="wiz-step {{ $step == 4 ? 'active' : '' }}">4. Confirmare</div>
</div>
<div class="wiz-card">
{{-- STEP 1: Upload --}}
@if ($step === 1)
<h2 style="font-size:18px;font-weight:600;margin-bottom:16px;">{{ __('Pasul 1: Încarcă fișierul') }}</h2>
<div class="wiz-field">
<label>{{ __('Furnizor *') }}</label>
<select wire:model="supplierId">
<option value="">{{ __('— alege —') }}</option>
@foreach ($this->getSupplierOptions() as $id => $name)
<option value="{{ $id }}">{{ $name }}</option>
@endforeach
</select>
</div>
<div class="wiz-field">
<label>{{ __('Fișier Excel (.xlsx) sau CSV *') }}</label>
<input type="file" wire:model="upload" accept=".xlsx,.xls,.csv" />
@if ($upload)
<div style="margin-top:6px;font-size:12px;color:#4a5568;">Selectat: {{ $upload->getClientOriginalName() }}</div>
@endif
</div>
<div class="wiz-actions">
<button class="wiz-btn wiz-btn-primary" wire:click="goToStep2" wire:loading.attr="disabled">{{ __('Următorul →') }}</button>
</div>
@endif
{{-- STEP 2: Mapping --}}
@if ($step === 2)
<h2 style="font-size:18px;font-weight:600;margin-bottom:16px;">{{ __('Pasul 2: Mapează coloanele') }}</h2>
<p style="color:#4a5568;font-size:13px;margin-bottom:16px;">{{ __('Spune-i sistemului ce reprezintă fiecare coloană din fișier. Vom salva configurația pentru imporțările viitoare.') }}</p>
<div style="overflow-x:auto;margin-bottom:20px;">
<table class="wiz-preview-table">
<thead>
<tr>
@foreach ($headersPreview['columns'] as $col)
<th>{{ $col }}</th>
@endforeach
</tr>
</thead>
<tbody>
@foreach ($headersPreview['rows'] as $row)
<tr>
@foreach ($headersPreview['columns'] as $col)
<td>{{ $row[$col] ?? '' }}</td>
@endforeach
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="wiz-grid">
<div class="wiz-field">
<label>{{ __('Coloana Articol *') }}</label>
<select wire:model="mapping.article_col">
<option value=""></option>
@foreach ($headersPreview['columns'] as $c)<option value="{{ $c }}">{{ $c }}</option>@endforeach
</select>
</div>
<div class="wiz-field">
<label>{{ __('Coloana Denumire *') }}</label>
<select wire:model="mapping.name_col">
<option value=""></option>
@foreach ($headersPreview['columns'] as $c)<option value="{{ $c }}">{{ $c }}</option>@endforeach
</select>
</div>
<div class="wiz-field">
<label>{{ __('Coloana Cantitate *') }}</label>
<select wire:model="mapping.qty_col">
<option value=""></option>
@foreach ($headersPreview['columns'] as $c)<option value="{{ $c }}">{{ $c }}</option>@endforeach
</select>
</div>
<div class="wiz-field">
<label>{{ __('Coloana Preț *') }}</label>
<select wire:model="mapping.price_col">
<option value=""></option>
@foreach ($headersPreview['columns'] as $c)<option value="{{ $c }}">{{ $c }}</option>@endforeach
</select>
</div>
<div class="wiz-field">
<label>{{ __('Coloana Brand (opțional)') }}</label>
<select wire:model="mapping.brand_col">
<option value=""></option>
@foreach ($headersPreview['columns'] as $c)<option value="{{ $c }}">{{ $c }}</option>@endforeach
</select>
</div>
<div class="wiz-field">
<label>{{ __('De la rândul (sărim header) *') }}</label>
<input type="number" min="1" wire:model="mapping.header_row" />
</div>
</div>
<div class="wiz-field">
<label style="display:flex;align-items:center;gap:8px;text-transform:none;">
<input type="checkbox" wire:model="rememberMapping" />
<span>{{ __('Salvează configurația pentru acest furnizor') }}</span>
</label>
</div>
<div class="wiz-actions">
<button class="wiz-btn" wire:click="$set('step', 1)">{{ __('← Înapoi') }}</button>
<button class="wiz-btn wiz-btn-primary" wire:click="goToStep3">{{ __('Previzualizare →') }}</button>
</div>
@endif
{{-- STEP 3: Preview --}}
@if ($step === 3)
<h2 style="font-size:18px;font-weight:600;margin-bottom:16px;">Pasul 3: Previzualizare {{ $previewSummary['total'] }} poziții</h2>
<div class="wiz-summary">
<div class="wiz-summary-item">
<strong style="color:#15803d;">{{ $previewSummary['found'] }}</strong>
{{ __('Găsite (cu articol existent)') }}
</div>
<div class="wiz-summary-item">
<strong style="color:#92400e;">{{ $previewSummary['new'] }}</strong>
Articole noi (se vor crea)
</div>
<div class="wiz-summary-item">
<strong style="color:#991b1b;">{{ $previewSummary['no_article'] }}</strong>
{{ __('Fără articol (manual)') }}
</div>
</div>
<div style="max-height:400px;overflow-y:auto;margin-bottom:16px;">
<table class="wiz-preview-table">
<thead>
<tr>
<th>{{ __('Articol') }}</th><th>{{ __('Denumire') }}</th><th>{{ __('Brand') }}</th><th>{{ __('Cant.') }}</th><th>{{ __('Preț') }}</th><th>{{ __('Status') }}</th>
</tr>
</thead>
<tbody>
@foreach ($previewRows as $row)
<tr>
<td style="font-family:monospace;">{{ $row['article'] }}</td>
<td>{{ $row['name'] }}</td>
<td>{{ $row['brand'] }}</td>
<td>{{ rtrim(rtrim(number_format($row['qty'], 2), '0'), '.') }}</td>
<td>{{ number_format($row['price'], 2) }}</td>
<td><span class="wiz-badge {{ $row['status'] }}">{{ ['found' => '✅ Găsit', 'new' => '⚠️ Nou', 'no_article' => '❓ Nu găsit'][$row['status']] ?? $row['status'] }}</span></td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="wiz-field">
<label style="display:flex;align-items:center;gap:8px;text-transform:none;">
<input type="checkbox" wire:model="createNew" />
<span>{{ __('Creează automat articolele noi în nomenclatură') }}</span>
</label>
</div>
<div class="wiz-actions">
<button class="wiz-btn" wire:click="$set('step', 2)">{{ __('← Înapoi') }}</button>
<button class="wiz-btn wiz-btn-primary" wire:click="confirmImport">{{ __('Confirmă și importă') }}</button>
</div>
@endif
{{-- STEP 4: Done --}}
@if ($step === 4)
<div style="text-align:center;padding:32px;">
<div style="font-size:48px;margin-bottom:16px;"></div>
<h2 style="font-size:20px;font-weight:600;margin-bottom:8px;">{{ __('Import finalizat cu succes') }}</h2>
<p style="color:#4a5568;">{{ $previewSummary['total'] }} poziții importate în Purchase nouă</p>
<div style="margin-top:24px;">
@if (session('purchase_id'))
<a class="wiz-btn wiz-btn-primary" href="{{ route('filament.tenant.resources.purchases.edit', ['record' => session('purchase_id')]) }}">{{ __('↗ Deschide Purchase') }}</a>
@endif
<button class="wiz-btn" wire:click="reset_">{{ __('Import nou') }}</button>
</div>
</div>
@endif
</div>
</div>
</x-filament-panels::page>