您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Localization.php 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. namespace App\Filament\Company\Pages\Setting;
  3. use App\Enums\DateFormat;
  4. use App\Enums\NumberFormat;
  5. use App\Enums\TimeFormat;
  6. use App\Enums\WeekStart;
  7. use App\Models\Setting\CompanyProfile as CompanyProfileModel;
  8. use App\Models\Setting\Localization as LocalizationModel;
  9. use App\Utilities\Localization\Timezone;
  10. use Filament\Actions\Action;
  11. use Filament\Actions\ActionGroup;
  12. use Filament\Facades\Filament;
  13. use Filament\Forms\Components\Component;
  14. use Filament\Forms\Components\Group;
  15. use Filament\Forms\Components\Section;
  16. use Filament\Forms\Components\Select;
  17. use Filament\Forms\Form;
  18. use Filament\Forms\Get;
  19. use Filament\Forms\Set;
  20. use Filament\Notifications\Notification;
  21. use Filament\Pages\Concerns\InteractsWithFormActions;
  22. use Filament\Pages\Page;
  23. use Filament\Support\Exceptions\Halt;
  24. use Guava\FilamentClusters\Forms\Cluster;
  25. use Illuminate\Auth\Access\AuthorizationException;
  26. use Illuminate\Contracts\Support\Htmlable;
  27. use Illuminate\Database\Eloquent\Model;
  28. use Livewire\Attributes\Locked;
  29. use function Filament\authorize;
  30. /**
  31. * @property Form $form
  32. */
  33. class Localization extends Page
  34. {
  35. use InteractsWithFormActions;
  36. protected static ?string $navigationIcon = 'heroicon-o-language';
  37. protected static ?string $title = 'Localization';
  38. protected static ?string $navigationGroup = 'Settings';
  39. protected static ?string $slug = 'settings/localization';
  40. protected static string $view = 'filament.company.pages.setting.localization';
  41. public ?array $data = [];
  42. #[Locked]
  43. public ?LocalizationModel $record = null;
  44. public function getTitle(): string | Htmlable
  45. {
  46. return translate(static::$title);
  47. }
  48. public static function getNavigationLabel(): string
  49. {
  50. return translate(static::$title);
  51. }
  52. public static function getNavigationParentItem(): ?string
  53. {
  54. if (Filament::hasTopNavigation()) {
  55. return translate('Company');
  56. }
  57. return null;
  58. }
  59. public function mount(): void
  60. {
  61. $this->record = LocalizationModel::firstOrNew([
  62. 'company_id' => auth()->user()->currentCompany->id,
  63. ]);
  64. abort_unless(static::canView($this->record), 404);
  65. $this->fillForm();
  66. }
  67. public function fillForm(): void
  68. {
  69. $data = $this->record->attributesToArray();
  70. $this->form->fill($data);
  71. }
  72. public function save(): void
  73. {
  74. try {
  75. $data = $this->form->getState();
  76. $this->handleRecordUpdate($this->record, $data);
  77. } catch (Halt $exception) {
  78. return;
  79. }
  80. $this->getSavedNotification()->send();
  81. }
  82. protected function getSavedNotification(): Notification
  83. {
  84. return Notification::make()
  85. ->success()
  86. ->title(__('filament-panels::resources/pages/edit-record.notifications.saved.title'));
  87. }
  88. public function form(Form $form): Form
  89. {
  90. return $form
  91. ->schema([
  92. $this->getGeneralSection(),
  93. $this->getDateAndTimeSection(),
  94. $this->getFinancialAndFiscalSection(),
  95. ])
  96. ->model($this->record)
  97. ->statePath('data')
  98. ->operation('edit');
  99. }
  100. protected function getGeneralSection(): Component
  101. {
  102. return Section::make('General')
  103. ->schema([
  104. Select::make('language')
  105. ->softRequired()
  106. ->localizeLabel()
  107. ->options(LocalizationModel::getAllLanguages())
  108. ->searchable(),
  109. Select::make('timezone')
  110. ->localizeLabel()
  111. ->options(Timezone::getTimezoneOptions(CompanyProfileModel::first()->country))
  112. ->searchable()
  113. ->nullable(),
  114. ])->columns();
  115. }
  116. protected function getDateAndTimeSection(): Component
  117. {
  118. return Section::make('Date & Time')
  119. ->schema([
  120. Select::make('date_format')
  121. ->softRequired()
  122. ->localizeLabel()
  123. ->options(DateFormat::class)
  124. ->live(),
  125. Select::make('time_format')
  126. ->softRequired()
  127. ->localizeLabel()
  128. ->options(TimeFormat::class),
  129. Select::make('week_start')
  130. ->softRequired()
  131. ->localizeLabel()
  132. ->options(WeekStart::class),
  133. ])->columns();
  134. }
  135. protected function getFinancialAndFiscalSection(): Component
  136. {
  137. $beforeNumber = translate('Before Number');
  138. $afterNumber = translate('After Number');
  139. $selectPosition = translate('Select Position');
  140. return Section::make('Financial & Fiscal')
  141. ->schema([
  142. Select::make('number_format')
  143. ->softRequired()
  144. ->localizeLabel()
  145. ->options(NumberFormat::class),
  146. Select::make('percent_first')
  147. ->softRequired()
  148. ->localizeLabel('Percent Position')
  149. ->boolean($beforeNumber, $afterNumber, $selectPosition),
  150. Group::make()
  151. ->schema([
  152. Cluster::make([
  153. Select::make('fiscal_year_end_month')
  154. ->softRequired()
  155. ->options(array_combine(range(1, 12), array_map(static fn ($month) => now()->month($month)->monthName, range(1, 12))))
  156. ->afterStateUpdated(static fn (Set $set) => $set('fiscal_year_end_day', null))
  157. ->columnSpan(2)
  158. ->live(),
  159. Select::make('fiscal_year_end_day')
  160. ->placeholder('Day')
  161. ->softRequired()
  162. ->columnSpan(1)
  163. ->options(function (Get $get) {
  164. $month = $get('fiscal_year_end_month');
  165. $daysInMonth = now()->month($month)->daysInMonth;
  166. return array_combine(range(1, $daysInMonth), range(1, $daysInMonth));
  167. })
  168. ->live(),
  169. ])
  170. ->columns(3)
  171. ->columnSpan(2)
  172. ->required()
  173. ->markAsRequired(false)
  174. ->label('Fiscal Year End'),
  175. ])->columns(3),
  176. ])->columns();
  177. }
  178. protected function handleRecordUpdate(LocalizationModel $record, array $data): LocalizationModel
  179. {
  180. $record->fill($data);
  181. $keysToWatch = [
  182. 'language',
  183. 'timezone',
  184. 'date_format',
  185. 'week_start',
  186. 'time_format',
  187. ];
  188. if ($record->isDirty($keysToWatch)) {
  189. $this->dispatch('localizationUpdated');
  190. }
  191. $record->save();
  192. return $record;
  193. }
  194. /**
  195. * @return array<Action | ActionGroup>
  196. */
  197. protected function getFormActions(): array
  198. {
  199. return [
  200. $this->getSaveFormAction(),
  201. ];
  202. }
  203. protected function getSaveFormAction(): Action
  204. {
  205. return Action::make('save')
  206. ->label(__('filament-panels::resources/pages/edit-record.form.actions.save.label'))
  207. ->submit('save')
  208. ->keyBindings(['mod+s']);
  209. }
  210. public static function canView(Model $record): bool
  211. {
  212. try {
  213. return authorize('update', $record)->allowed();
  214. } catch (AuthorizationException $exception) {
  215. return $exception->toResponse()->allowed();
  216. }
  217. }
  218. }