feat(ui): localize filament admin panel and refactor settings page

Refactor the IfnexSettingsPage to use a custom Blade view and implement manual property binding for system settings. Additionally, localize navigation labels and groups to Persian for the Filament admin interface.

- Implement `ifnex-settings.blade.php` for custom settings management
- Localize navigation labels for Countries, Shipment Items, Shipments, and Shipping Rates
- Update navigation groups to Persian (تنظیمات, عملیات)
- Refactor `IfnexSettingsPage` to load settings from `SystemSetting` model during `mount`
- Fix type hinting for `ShipmentDirection` enum in `ShipmentResource` table columns
This commit is contained in:
Kazem Alghasi 2026-08-04 04:44:24 +03:30
parent 11845173b6
commit 1c3811b01f
6 changed files with 113 additions and 95 deletions

View File

@ -3,107 +3,75 @@
namespace App\Filament\Pages;
use App\Models\SystemSetting;
use Filament\Forms;
use Filament\Pages\Page;
class IfnexSettingsPage extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-cog-6-tooth';
protected static ?string $navigationLabel = 'Settings';
protected static ?string $navigationGroup = 'Settings';
protected static ?string $navigationLabel = 'تنظیمات سیستم';
protected static ?string $navigationGroup = 'تنظیمات';
protected static ?int $navigationSort = 1;
protected static string $view = 'filament::page';
protected static string $view = 'filament.pages.ifnex-settings';
public float $vat_rate = 0.09;
public float $packing_cost_default = 100000;
public float $profit_margin = 1.25;
public float $aed_to_irr = 455000;
public float $usd_to_irr = 0;
public float $cny_to_irr = 0;
public float $eur_to_irr = 0;
public function mount(): void
{
$this->fillForms();
$settings = SystemSetting::all()->pluck('value', 'key')->toArray();
if (isset($settings['vat_rate'])) $this->vat_rate = (float) $settings['vat_rate'];
if (isset($settings['packing_cost_default'])) $this->packing_cost_default = (float) $settings['packing_cost_default'];
if (isset($settings['profit_margin'])) $this->profit_margin = (float) $settings['profit_margin'];
if (isset($settings['aed_to_irr'])) $this->aed_to_irr = (float) $settings['aed_to_irr'];
if (isset($settings['usd_to_irr'])) $this->usd_to_irr = (float) $settings['usd_to_irr'];
if (isset($settings['cny_to_irr'])) $this->cny_to_irr = (float) $settings['cny_to_irr'];
if (isset($settings['eur_to_irr'])) $this->eur_to_irr = (float) $settings['eur_to_irr'];
}
protected function getFormSchema(): array
{
return [
Forms\Components\TextInput::make('vat_rate')
->label('VAT Rate')
->required()
->numeric()
->step(0.01)
->default(0.09)
->helperText('Example: 0.09 for 9%')
->live(),
Forms\Components\TextInput::make('packing_cost_default')
->label('Default Packing Cost (IRR)')
->required()
->numeric()
->default(100000),
Forms\Components\TextInput::make('profit_margin')
->label('Profit Margin')
->required()
->numeric()
->step(0.01)
->default(1.25)
->helperText('Example: 1.25 for 25% margin'),
Forms\Components\TextInput::make('aed_to_irr')
->label('AED to IRR')
->required()
->numeric()
->default(455000),
Forms\Components\TextInput::make('usd_to_irr')
->label('USD to IRR')
->required()
->numeric()
->default(0),
Forms\Components\TextInput::make('cny_to_irr')
->label('CNY to IRR')
->required()
->numeric()
->default(0),
Forms\Components\TextInput::make('eur_to_irr')
->label('EUR to IRR')
->required()
->numeric()
->default(0),
];
}
protected function mutateFormDataBeforeSave(array $data): array
public function save(): void
{
$userId = auth()->id();
foreach ($data as $key => $value) {
if (is_numeric($value)) {
SystemSetting::updateOrCreate(
['key' => $key],
['value' => $value, 'updated_by' => $userId]
);
}
}
SystemSetting::updateOrCreate(
['key' => 'vat_rate'],
['value' => $this->vat_rate, 'updated_by' => $userId]
);
SystemSetting::updateOrCreate(
['key' => 'packing_cost_default'],
['value' => $this->packing_cost_default, 'updated_by' => $userId]
);
SystemSetting::updateOrCreate(
['key' => 'profit_margin'],
['value' => $this->profit_margin, 'updated_by' => $userId]
);
SystemSetting::updateOrCreate(
['key' => 'aed_to_irr'],
['value' => $this->aed_to_irr, 'updated_by' => $userId]
);
SystemSetting::updateOrCreate(
['key' => 'usd_to_irr'],
['value' => $this->usd_to_irr, 'updated_by' => $userId]
);
SystemSetting::updateOrCreate(
['key' => 'cny_to_irr'],
['value' => $this->cny_to_irr, 'updated_by' => $userId]
);
SystemSetting::updateOrCreate(
['key' => 'eur_to_irr'],
['value' => $this->eur_to_irr, 'updated_by' => $userId]
);
return [];
}
protected function fillForms(): void
{
$settings = SystemSetting::all()->pluck('value', 'key')->toArray();
$defaults = [
'vat_rate' => 0.09,
'packing_cost_default' => 100000,
'profit_margin' => 1.25,
'aed_to_irr' => 455000,
'usd_to_irr' => 0,
'cny_to_irr' => 0,
'eur_to_irr' => 0,
];
$this->data = array_merge($defaults, $settings);
}
protected function getFormStatePath(): string
{
return 'data';
\Filament\Notifications\Notification::make()
->title('Success')
->body('Settings saved successfully.')
->success()
->send();
}
}

View File

@ -16,8 +16,8 @@ class CountryResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-globe-alt';
protected static ?string $navigationLabel = 'Countries';
protected static ?string $navigationGroup = 'Settings';
protected static ?string $navigationLabel = 'کشورها';
protected static ?string $navigationGroup = 'تنظیمات';
public static function form(Form $form): Form
{

View File

@ -16,8 +16,8 @@ class ShipmentItemResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-clipboard-document-list';
protected static ?string $navigationLabel = 'Shipment Items';
protected static ?string $navigationGroup = 'Operations';
protected static ?string $navigationLabel = 'اقلام مرسوله';
protected static ?string $navigationGroup = 'عملیات';
public static function form(Form $form): Form
{

View File

@ -16,8 +16,8 @@ class ShipmentResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-truck';
protected static ?string $navigationLabel = 'Shipments';
protected static ?string $navigationGroup = 'Operations';
protected static ?string $navigationLabel = 'مرسولات';
protected static ?string $navigationGroup = 'عملیات';
public static function form(Form $form): Form
{
@ -159,7 +159,7 @@ class ShipmentResource extends Resource
return $table
->columns([
Tables\Columns\TextColumn::make('awb_no')->searchable()->label('AWB No.')->sortable(),
Tables\Columns\TextColumn::make('direction')->badge()->color(fn (string $state): string => match ($state) {
Tables\Columns\TextColumn::make('direction')->badge()->color(fn (\App\Enums\ShipmentDirection $state): string => match ($state->value) {
'import' => 'success',
'export' => 'info',
default => 'gray',

View File

@ -16,8 +16,8 @@ class ShippingRateResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-currency-dollar';
protected static ?string $navigationLabel = 'Shipping Rates';
protected static ?string $navigationGroup = 'Settings';
protected static ?string $navigationLabel = 'نرخ‌های حمل';
protected static ?string $navigationGroup = 'تنظیمات';
public static function form(Form $form): Form
{

View File

@ -0,0 +1,50 @@
<x-filament::page>
<div class="space-y-6">
<x-filament::card>
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
<div>
<label class="block text-sm font-medium text-gray-700">VAT Rate</label>
<input type="number" step="0.01" wire:model="vat_rate" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
<p class="mt-1 text-sm text-gray-500">Example: 0.09 for 9%</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Default Packing Cost (IRR)</label>
<input type="number" wire:model="packing_cost_default" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Profit Margin</label>
<input type="number" step="0.01" wire:model="profit_margin" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
<p class="mt-1 text-sm text-gray-500">Example: 1.25 for 25% margin</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">AED to IRR</label>
<input type="number" wire:model="aed_to_irr" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">USD to IRR</label>
<input type="number" wire:model="usd_to_irr" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">CNY to IRR</label>
<input type="number" wire:model="cny_to_irr" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">EUR to IRR</label>
<input type="number" wire:model="eur_to_irr" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
</div>
</div>
<div class="mt-6">
<button type="button" wire:click="save" class="filament-button filament-button-size-md inline-flex items-center justify-center py-2 px-4 rounded-md text-sm font-medium text-white bg-primary-600 hover:bg-primary-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">
Save Settings
</button>
</div>
</x-filament::card>
</div>
</x-filament::page>