Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

CompanyProfile.php 7.8KB

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