You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CompanyProfile.php 8.7KB

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