Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

CompanyProfile.php 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <?php
  2. namespace App\Filament\Company\Pages\Setting;
  3. use App\Enums\EntityType;
  4. use App\Events\CompanyDefaultUpdated;
  5. use App\Models\Setting\CompanyDefault as CompanyDefaultModel;
  6. use Filament\Actions\Action;
  7. use Filament\Actions\ActionGroup;
  8. use Filament\Forms\Components\Component;
  9. use Filament\Forms\Components\DatePicker;
  10. use Filament\Forms\Components\FileUpload;
  11. use Filament\Forms\Components\Group;
  12. use Filament\Forms\Components\Section;
  13. use Filament\Forms\Components\Select;
  14. use Filament\Forms\Components\TextInput;
  15. use Filament\Forms\Form;
  16. use Filament\Forms\Get;
  17. use Filament\Notifications\Notification;
  18. use Filament\Pages\Concerns\InteractsWithFormActions;
  19. use Filament\Pages\Page;
  20. use App\Models\Setting\CompanyProfile as CompanyProfileModel;
  21. use Filament\Support\Exceptions\Halt;
  22. use Illuminate\Auth\Access\AuthorizationException;
  23. use Illuminate\Database\Eloquent\Model;
  24. use Illuminate\Support\Facades\Auth;
  25. use Livewire\Attributes\Locked;
  26. use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
  27. use function Filament\authorize;
  28. /**
  29. * @property Form $form
  30. */
  31. class CompanyProfile extends Page
  32. {
  33. use InteractsWithFormActions;
  34. protected static ?string $navigationIcon = 'heroicon-o-building-office-2';
  35. protected static ?string $navigationLabel = 'Company Profile';
  36. protected static ?string $navigationGroup = 'Settings';
  37. protected static ?string $slug = 'settings/company-profile';
  38. protected ?string $heading = 'Company Profile';
  39. protected static string $view = 'filament.company.pages.setting.company-profile';
  40. public ?array $data = [];
  41. #[Locked]
  42. public ?CompanyProfileModel $record = null;
  43. public function mount(): void
  44. {
  45. $this->record = CompanyProfileModel::firstOrNew([
  46. 'company_id' => auth()->user()->currentCompany->id,
  47. ]);
  48. abort_unless(static::canView($this->record), 404);
  49. $this->fillForm();
  50. }
  51. public function fillForm(): void
  52. {
  53. $data = $this->record->attributesToArray();
  54. $data = $this->mutateFormDataBeforeFill($data);
  55. $data['fiscal_year_start'] = now()->startOfYear()->toDateString();
  56. $data['fiscal_year_end'] = now()->endOfYear()->toDateString();
  57. $this->form->fill($data);
  58. }
  59. protected function mutateFormDataBeforeFill(array $data): array
  60. {
  61. return $data;
  62. }
  63. protected function mutateFormDataBeforeSave(array $data): array
  64. {
  65. return $data;
  66. }
  67. public function save(): void
  68. {
  69. try {
  70. $data = $this->form->getState();
  71. $data = $this->mutateFormDataBeforeSave($data);
  72. $this->handleRecordUpdate($this->record, $data);
  73. } catch (Halt $exception) {
  74. return;
  75. }
  76. $this->getSavedNotification()?->send();
  77. if ($redirectUrl = $this->getRedirectUrl()) {
  78. $this->redirect($redirectUrl);
  79. }
  80. }
  81. protected function getSavedNotification(): ?Notification
  82. {
  83. $title = $this->getSavedNotificationTitle();
  84. if (blank($title)) {
  85. return null;
  86. }
  87. return Notification::make()
  88. ->success()
  89. ->title($this->getSavedNotificationTitle());
  90. }
  91. protected function getSavedNotificationTitle(): ?string
  92. {
  93. return __('filament-panels::pages/tenancy/edit-tenant-profile.notifications.saved.title');
  94. }
  95. protected function getRedirectUrl(): ?string
  96. {
  97. return null;
  98. }
  99. public function form(Form $form): Form
  100. {
  101. return $form
  102. ->schema([
  103. $this->getIdentificationSection(),
  104. $this->getLocationDetailsSection(),
  105. $this->getLegalAndComplianceSection(),
  106. $this->getFiscalYearSection(),
  107. ])
  108. ->model($this->record)
  109. ->statePath('data')
  110. ->operation('edit');
  111. }
  112. protected function getIdentificationSection(): Component
  113. {
  114. return Section::make('Identification')
  115. ->schema([
  116. FileUpload::make('logo')
  117. ->label('Logo')
  118. ->disk('public')
  119. ->directory('logos/company')
  120. ->imageResizeMode('contain')
  121. ->imagePreviewHeight('250')
  122. ->imageCropAspectRatio('2:1')
  123. ->getUploadedFileNameForStorageUsing(
  124. static fn (TemporaryUploadedFile $file): string => (string) str($file->getClientOriginalName())
  125. ->prepend(Auth::user()->currentCompany->id . '_'),
  126. )
  127. ->openable()
  128. ->maxSize(2048)
  129. ->image()
  130. ->visibility('public')
  131. ->acceptedFileTypes(['image/png', 'image/jpeg']),
  132. Group::make()
  133. ->schema([
  134. TextInput::make('email')
  135. ->label('Email')
  136. ->email()
  137. ->maxLength(255)
  138. ->required(),
  139. TextInput::make('phone_number')
  140. ->label('Phone Number')
  141. ->tel()
  142. ->nullable(),
  143. ])->columns(1)
  144. ])->columns();
  145. }
  146. protected function getLocationDetailsSection(): Component
  147. {
  148. return Section::make('Location Details')
  149. ->schema([
  150. Select::make('country')
  151. ->label('Country')
  152. ->native(false)
  153. ->live()
  154. ->searchable()
  155. ->options(CompanyProfileModel::getAvailableCountryOptions())
  156. ->required(),
  157. Select::make('state')
  158. ->label('State / Province')
  159. ->searchable()
  160. ->native(false)
  161. ->options(static fn (Get $get) => CompanyProfileModel::getStateOptions($get('country')))
  162. ->nullable(),
  163. Select::make('timezone')
  164. ->label('Timezone')
  165. ->native(false)
  166. ->options(static fn (Get $get) => CompanyProfileModel::getTimezoneOptions($get('country')))
  167. ->nullable(),
  168. TextInput::make('address')
  169. ->label('Street Address')
  170. ->maxLength(255)
  171. ->nullable(),
  172. TextInput::make('city')
  173. ->label('City / Town')
  174. ->maxLength(255)
  175. ->nullable(),
  176. TextInput::make('zip_code')
  177. ->label('Zip Code')
  178. ->maxLength(20)
  179. ->nullable(),
  180. ])->columns();
  181. }
  182. protected function getLegalAndComplianceSection(): Component
  183. {
  184. return Section::make('Legal & Compliance')
  185. ->schema([
  186. Select::make('entity_type')
  187. ->label('Entity Type')
  188. ->native(false)
  189. ->options(EntityType::class)
  190. ->required(),
  191. TextInput::make('tax_id')
  192. ->label('Tax ID')
  193. ->maxLength(50)
  194. ->nullable(),
  195. ])->columns();
  196. }
  197. protected function getFiscalYearSection(): Component
  198. {
  199. return Section::make('Fiscal Year')
  200. ->schema([
  201. DatePicker::make('fiscal_year_start')
  202. ->label('Start')
  203. ->native(false)
  204. ->seconds(false)
  205. ->rule('required'),
  206. DatePicker::make('fiscal_year_end')
  207. ->label('End')
  208. ->minDate(static fn (Get $get) => $get('fiscal_year_start'))
  209. ->native(false)
  210. ->seconds(false)
  211. ->rule('required'),
  212. ])->columns();
  213. }
  214. protected function handleRecordUpdate(CompanyProfileModel $record, array $data): CompanyProfileModel
  215. {
  216. $record->update($data);
  217. return $record;
  218. }
  219. /**
  220. * @return array<Action | ActionGroup>
  221. */
  222. protected function getFormActions(): array
  223. {
  224. return [
  225. $this->getSaveFormAction(),
  226. ];
  227. }
  228. protected function getSaveFormAction(): Action
  229. {
  230. return Action::make('save')
  231. ->label(__('filament-panels::pages/tenancy/edit-tenant-profile.form.actions.save.label'))
  232. ->submit('save')
  233. ->keyBindings(['mod+s']);
  234. }
  235. public static function canView(Model $record): bool
  236. {
  237. try {
  238. return authorize('update', $record)->allowed();
  239. } catch (AuthorizationException $exception) {
  240. return $exception->toResponse()->allowed();
  241. }
  242. }
  243. }