f7fc69077b
- Convert static $modelLabel/$pluralModelLabel/$title to getter methods - Wrap ->label()/->placeholder()/->helperText()/->description()/->title()/->body() args - Wrap Section::make()/Fieldset::make()/Notification::make()->title() args - Fix RelationManagers::getTitle() signature to match parent (Model, string) - Fix Pages::getTitle() to instance method (BasePage::getTitle is non-static) - Extend lang/ru.json + lang/en.json with 700+ common terms; identity fallback for the rest - Remove duplicate getters in 5 resources that had manual getModelLabel already All 306 tests pass. Missing translations fall back to the RO key so the UI never breaks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
163 lines
6.0 KiB
PHP
163 lines
6.0 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Tenant\Pages;
|
|
|
|
use App\Tenancy\TenantManager;
|
|
use Filament\Forms;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Pages\Page;
|
|
use Filament\Schemas;
|
|
use Filament\Schemas\Schema;
|
|
|
|
/**
|
|
* 3-step onboarding wizard. Hidden from navigation.
|
|
* Dashboard redirects here on first login when settings.onboarded_at is empty.
|
|
*/
|
|
class Onboarding extends Page
|
|
{
|
|
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-sparkles';
|
|
|
|
protected static bool $shouldRegisterNavigation = false;
|
|
|
|
protected static ?string $title = null;
|
|
|
|
public function getTitle(): string
|
|
{
|
|
return __('Bun venit în AutoCRM!');
|
|
}
|
|
|
|
protected string $view = 'filament.tenant.pages.onboarding';
|
|
|
|
public ?array $data = [];
|
|
|
|
public int $step = 1;
|
|
|
|
public function mount(): void
|
|
{
|
|
$company = app(TenantManager::class)->current();
|
|
if (! $company) abort(404);
|
|
|
|
// Already onboarded → redirect to dashboard
|
|
if (! empty($company->settings['onboarded_at'])) {
|
|
redirect('/app');
|
|
return;
|
|
}
|
|
|
|
$s = (array) ($company->settings ?? []);
|
|
$this->form->fill([
|
|
'display_name' => $company->display_name ?? $company->name,
|
|
'city' => $company->city,
|
|
'phone' => $company->phone,
|
|
'currency' => $s['currency'] ?? 'MDL',
|
|
'language' => $s['language'] ?? 'ro',
|
|
'theme_color' => $s['theme_color'] ?? '#3B82F6',
|
|
'labor_rate' => $s['labor_rate'] ?? 400,
|
|
]);
|
|
}
|
|
|
|
public function form(Schema $schema): Schema
|
|
{
|
|
return $schema
|
|
->components([
|
|
Schemas\Components\Section::make(__('Pas 1 — Datele afacerii'))
|
|
->visible(fn () => $this->step === 1)
|
|
->columns(2)
|
|
->schema([
|
|
Forms\Components\TextInput::make('display_name')
|
|
->label(__('Denumire afișată'))->required()->maxLength(120),
|
|
Forms\Components\TextInput::make('city')
|
|
->label(__('Oraș'))->maxLength(60),
|
|
Forms\Components\TextInput::make('phone')
|
|
->label(__('Telefon principal'))->tel()->maxLength(40),
|
|
Forms\Components\Select::make('currency')
|
|
->label(__('Monedă'))
|
|
->options([
|
|
'MDL' => 'MDL — Leu moldovenesc',
|
|
'EUR' => 'EUR — Euro',
|
|
'USD' => 'USD — US Dollar',
|
|
'RON' => 'RON — Leu românesc',
|
|
'UAH' => 'UAH — Hryvnia',
|
|
'RUB' => 'RUB — Rublă',
|
|
])
|
|
->default('MDL')
|
|
->required()
|
|
->searchable(),
|
|
]),
|
|
Schemas\Components\Section::make(__('Pas 2 — Brand & limbă'))
|
|
->visible(fn () => $this->step === 2)
|
|
->columns(2)
|
|
->schema([
|
|
Forms\Components\Select::make('language')
|
|
->label(__('Limbă'))
|
|
->options(['ro' => 'Română', 'ru' => 'Русский', 'en' => 'English'])
|
|
->required(),
|
|
Forms\Components\ColorPicker::make('theme_color')
|
|
->label(__('Culoare brand')),
|
|
Forms\Components\FileUpload::make('logo')
|
|
->label(__('Logo (opțional)'))
|
|
->image()->imageEditor()->disk('public')
|
|
->directory('tmp-uploads')->visibility('public')
|
|
->maxSize(2048),
|
|
]),
|
|
Schemas\Components\Section::make(__('Pas 3 — Tarif & terminat'))
|
|
->visible(fn () => $this->step === 3)
|
|
->columns(1)
|
|
->schema([
|
|
Forms\Components\TextInput::make('labor_rate')
|
|
->label(__('Tarif normo-oră (poți schimba oricând)'))
|
|
->numeric()->required(),
|
|
]),
|
|
])
|
|
->statePath('data');
|
|
}
|
|
|
|
public function next(): void
|
|
{
|
|
$this->form->getState();
|
|
$this->step = min(3, $this->step + 1);
|
|
}
|
|
|
|
public function prev(): void
|
|
{
|
|
$this->step = max(1, $this->step - 1);
|
|
}
|
|
|
|
public function finish(): void
|
|
{
|
|
$data = $this->form->getState();
|
|
$company = app(TenantManager::class)->current();
|
|
if (! $company) return;
|
|
|
|
$company->update([
|
|
'display_name' => $data['display_name'] ?? $company->display_name,
|
|
'city' => $data['city'] ?? $company->city,
|
|
'phone' => $data['phone'] ?? $company->phone,
|
|
'settings' => array_merge((array) $company->settings, [
|
|
'currency' => $data['currency'] ?? 'MDL',
|
|
'language' => $data['language'] ?? 'ro',
|
|
'theme_color' => $data['theme_color'] ?? '#3B82F6',
|
|
'labor_rate' => (float) ($data['labor_rate'] ?? 400),
|
|
'onboarded_at' => now()->toIso8601String(),
|
|
]),
|
|
]);
|
|
|
|
// Logo upload
|
|
if (! empty($data['logo'])) {
|
|
$abs = \Illuminate\Support\Facades\Storage::disk('public')->path($data['logo']);
|
|
if (file_exists($abs)) {
|
|
$company->clearMediaCollection('logo');
|
|
$company->addMedia($abs)->preservingOriginal()->toMediaCollection('logo');
|
|
@unlink($abs);
|
|
}
|
|
}
|
|
|
|
Notification::make()
|
|
->title(__('🎉 Bun venit în AutoCRM!'))
|
|
->body(__('Setările au fost salvate. Hai să adăugăm primul client.'))
|
|
->success()
|
|
->send();
|
|
|
|
redirect('/app/clients/create');
|
|
}
|
|
}
|