Files
famous-ly4-ev/app-modules/identity/src/Filament/Pages/ManageAppSettings.php
T
Nyan Lin Paing bebcab88fa Generalize per-vehicle-option booking rules to Front Seat too
Front Seat previously had a hardcoded max-per-booking check with no enable
toggle; now every Vehicle Option (front_seat/back_seat/whole_vehicle) gets
the same config-driven pair — an on/off toggle and a max passenger_count —
surfaced via new BOOKING_*_ENABLED/BOOKING_*_MAX_PER_BOOKING env vars,
editable from ManageAppSettings, and exposed on route pricing as
max_per_booking.
2026-08-30 15:45:27 +07:00

213 lines
10 KiB
PHP

<?php
namespace Modules\Identity\Filament\Pages;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Schemas\Components\Actions;
use Filament\Schemas\Components\Form;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\Tabs\Tab;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Illuminate\Support\Facades\Artisan;
use Modules\Shared\Support\EnvFileWriter;
use UnitEnum;
/**
* Edits real env-backed config values (config('app.*'), config('booking.*'))
* in place via EnvFileWriter, rather than introducing a parallel DB-backed
* settings table — so BookingService and everything else that already reads
* config('booking.*') keeps working unchanged (domain.md §2).
*
* Requires the .env file to be writable by the app process; if it isn't
* (e.g. some production containers ship a read-only filesystem), saving
* will throw and the admin needs to edit .env directly on that host instead.
*/
class ManageAppSettings extends Page
{
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCog6Tooth;
protected static string|UnitEnum|null $navigationGroup = 'Access';
protected static ?string $navigationLabel = 'App Settings';
protected static ?string $title = 'App Settings';
protected string $view = 'identity::filament.pages.manage-app-settings';
/**
* @var array<string, mixed>|null
*/
public ?array $data = [];
public static function canAccess(): bool
{
return auth()->user()?->can('manage_settings') ?? false;
}
public function mount(): void
{
$this->form->fill([
'site_name' => config('app.name'),
'support_email' => config('app.support_email'),
'support_phone' => config('app.support_phone'),
'timezone' => config('app.timezone'),
'currency' => config('app.currency'),
'front_seat_enabled' => (bool) config('booking.front_seat_enabled'),
'front_seat_max_per_booking' => config('booking.front_seat_max_per_booking'),
'back_seat_enabled' => (bool) config('booking.back_seat_enabled'),
'back_seat_max_per_booking' => config('booking.back_seat_max_per_booking'),
'whole_vehicle_enabled' => (bool) config('booking.whole_vehicle_enabled'),
'whole_vehicle_max_per_booking' => config('booking.whole_vehicle_max_per_booking'),
'booking_admin_emails' => config('booking.admin_emails'),
'sms_enabled' => (bool) config('services.sms.enabled'),
'sms_server' => config('services.sms.sms_poh.server'),
'sms_token' => config('services.sms.sms_poh.token'),
'sms_sender' => config('services.sms.sms_poh.sender'),
]);
}
public function form(Schema $schema): Schema
{
return $schema
->components([
Form::make([
Tabs::make('Settings')
->tabs([
Tab::make('General')
->schema([
TextInput::make('site_name')
->label('Site Name')
->required()
->maxLength(255),
TextInput::make('support_email')
->label('Support Email')
->email()
->maxLength(255),
TextInput::make('support_phone')
->label('Support Phone')
->tel()
->maxLength(255),
TextInput::make('timezone')
->label('Timezone')
->required()
->maxLength(64)
->helperText('A valid PHP timezone identifier, e.g. Asia/Yangon.'),
TextInput::make('currency')
->label('Currency Code')
->required()
->maxLength(3)
->helperText('ISO 4217 currency code, e.g. MMK.'),
])
->columns(2),
Tab::make('Booking')
->schema([
Toggle::make('front_seat_enabled')
->label('Front Seat Enabled')
->helperText('Whether customers can select Front Seat at all right now.'),
TextInput::make('front_seat_max_per_booking')
->label('Front Seat Max Per Booking')
->numeric()
->minValue(1)
->required()
->helperText('Max Front Seats a single booking may request.'),
Toggle::make('back_seat_enabled')
->label('Back Seat Enabled')
->helperText('Whether customers can select Back Seat at all right now.'),
TextInput::make('back_seat_max_per_booking')
->label('Back Seat Max Per Booking')
->numeric()
->minValue(1)
->required()
->helperText('Max Back Seats a single booking may request.'),
Toggle::make('whole_vehicle_enabled')
->label('Whole Vehicle Enabled')
->helperText('Whether customers can select Whole Vehicle at all right now.'),
TextInput::make('whole_vehicle_max_per_booking')
->label('Whole Vehicle Max Per Booking')
->numeric()
->minValue(1)
->required()
->helperText('Max Whole Vehicle passenger count a single booking may request.'),
TagsInput::make('booking_admin_emails')
->label('Admin Emails')
->required()
->helperText('Notified on booking events. Press enter after each address.'),
])
->columns(2),
Tab::make('SMS')
->schema([
Toggle::make('sms_enabled')
->label('SMS Enabled')
->live()
->helperText('Whether driver/car SMS notifications are sent at all.'),
TextInput::make('sms_server')
->label('SMS Server URL')
->url()
->maxLength(255)
->required(fn (Get $get): bool => (bool) $get('sms_enabled')),
TextInput::make('sms_token')
->label('SMS Token')
->password()
->revealable()
->maxLength(255)
->required(fn (Get $get): bool => (bool) $get('sms_enabled')),
TextInput::make('sms_sender')
->label('SMS Sender')
->maxLength(255)
->helperText('Default sender name/number for outgoing SMS.'),
])
->columns(2),
]),
])
->livewireSubmitHandler('save')
->footer([
Actions::make([
Action::make('save')
->submit('save')
->keyBindings(['mod+s']),
]),
]),
])
->statePath('data');
}
public function save(EnvFileWriter $writer): void
{
$state = $this->form->getState();
$writer->write([
'APP_NAME' => $state['site_name'],
'SUPPORT_EMAIL' => $state['support_email'],
'SUPPORT_PHONE' => $state['support_phone'],
'APP_TIMEZONE' => $state['timezone'],
'APP_CURRENCY' => $state['currency'],
'BOOKING_FRONT_SEAT_ENABLED' => (bool) $state['front_seat_enabled'],
'BOOKING_FRONT_SEAT_MAX_PER_BOOKING' => (int) $state['front_seat_max_per_booking'],
'BOOKING_BACK_SEAT_ENABLED' => (bool) $state['back_seat_enabled'],
'BOOKING_BACK_SEAT_MAX_PER_BOOKING' => (int) $state['back_seat_max_per_booking'],
'BOOKING_WHOLE_VEHICLE_ENABLED' => (bool) $state['whole_vehicle_enabled'],
'BOOKING_WHOLE_VEHICLE_MAX_PER_BOOKING' => (int) $state['whole_vehicle_max_per_booking'],
'BOOKING_ADMIN_EMAILS' => implode(',', $state['booking_admin_emails'] ?? []),
'SMS_ENABLED' => (bool) $state['sms_enabled'],
'SMS_SERVER' => $state['sms_server'],
'SMS_TOKEN' => $state['sms_token'],
'SMS_SENDER' => $state['sms_sender'],
]);
Artisan::call('config:clear');
Notification::make()
->title('Settings saved')
->success()
->send();
}
}