user()->hasRole(RoleEnum::PERUSAHAAN->value) && ! auth()->user()->company) { $this->restricted = true; return; } $company = auth()->user()->company; if (! $company) { $this->restricted = true; return; } $this->company = $company; $verificationRequest = $this->company->verificationRequest() ->latest() ->first(); $this->verificationRequest = $verificationRequest; $media = $company->partnerMedia; if (! $media) { return; } $this->media = $media; $this->form->fill($media->toArray()); $documents = [ 'journalism_organization', 'press_council_certificate', ]; $mediaItems = $media->getMedia('partnerMedia'); foreach ($documents as $docType) { $mediaItem = $mediaItems ->where('custom_properties.doc_type', str($docType)->replace('_docs', '')->slug('-')) ->sortByDesc('created_at') ->first(); if ($mediaItem) { $path = $mediaItem->getPathRelativeToRoot(); $this->data["{$docType}_docs"] = [$path]; $this->originalDocuments["{$docType}_docs"] = [$path]; } } } public static function form(Schema $schema): Schema { $documents = [ [ 'title' => 'Organisasi Kewartawanan', 'text_name' => 'journalism_organization', 'placeholder' => '*****', 'max' => 100, 'max_size' => 1024 * 10, 'file_name' => 'journalism_organization_docs', 'accept' => ['application/pdf'], 'folder' => 'media/journalism-organization/', ], [ 'title' => 'Sertifikat Dewan Pers', 'text_name' => 'press_council_certificate', 'placeholder' => '*****', 'max' => 100, 'max_size' => 1024 * 10, 'file_name' => 'press_council_certificate_docs', 'accept' => ['application/pdf'], 'folder' => 'media/press-council-certificate/', ], ]; return $schema ->components([ Section::make('Informasi') ->schema([ TextInput::make('name') ->label('Nama') ->placeholder('PWK News') ->autocomplete(false) ->autofocus() ->required() ->maxLength(100), TextInput::make('link') ->label('Tautan') ->placeholder('https://www.pwknews.com') ->autocomplete(false) ->nullable() ->maxLength(50) ->url(), Textarea::make('address') ->label('Alamat') ->placeholder('Jl. Kebontoro, Jakarta Pusat') ->autocomplete(false) ->required() ->columnSpanFull(), Radio::make('type') ->label('Jenis') ->options(MediaType::options()) ->inline() ->required() ->in(implode(',', array_column(MediaType::cases(), 'value'))), Radio::make('classification') ->label('Klasifikasi') ->options(MediaClassification::options()) ->inline() ->required() ->in(implode(',', array_column(MediaClassification::cases(), 'value'))), ]) ->columns(2) ->columnSpan(2), Group::make() ->schema( collect($documents) ->map(function (array $doc): Section { return Section::make($doc['title']) ->schema([ TextInput::make($doc['text_name']) ->hiddenLabel() ->placeholder($doc['placeholder']) ->autocomplete(false) ->required() ->maxLength($doc['max']), AdvancedFileUpload::make($doc['file_name']) ->hiddenLabel() ->disk(config('filesystems.default')) ->acceptedFileTypes($doc['accept']) ->maxSize($doc['max_size']) ->directory($doc['folder'].now()->toDateString()), ]); })->toArray() ) ->columns(2), ]) ->statePath('data'); } public function save(): void { $this->mountAction('save'); } public function saveAction(): Action { $needsReview = $this->media?->company?->verificationRequest?->status !== null; return Action::make('save') ->label('Simpan') ->modalHeading('Ajukan Perubahan') ->modal($needsReview) ->schema( $needsReview ? [ Textarea::make('change_reason') ->label('Alasan') ->required() ->placeholder('Jelaskan alasan perubahan data ini...') ->autocomplete(false) ->autofocus(), ] : [] ) ->action(function (array $data = []) use ($needsReview) { $this->performSave($data, $needsReview); }) ->modalWidth(Width::Large); } public function performSave(array $data = [], bool $needsReview = false): void { if ($needsReview) { $existingRequest = DataChangeRequest::where('entity_type', PartnerMedia::class) ->where('entity_id', $this->media->id) ->where('status', DataChangeStatus::PENDING) ->exists(); if ($existingRequest) { CheerfulNotification::warning( 'Pengajuan Sudah Ada ⏳', 'Masih ada pengajuan perubahan data yang sedang menunggu verifikasi. Silakan tunggu hingga selesai diproses.' ) ->send(); return; } $state = $this->form->getState(); $data = array_merge($state, $data); $fieldLabels = PartnerMedia::dataChangeEntryLabels(); $editableFields = [ 'name', 'link', 'address', 'type', 'classification', 'journalism_organization', 'press_council_certificate', ]; $changedFields = []; $oldDataArr = []; $casts = $this->media->getCasts(); foreach ($editableFields as $field) { $val = $data[$field]; $oldVal = $this->media->{$field}; // If value is a raw scalar but should be an enum, resolve it for display if (isset($casts[$field]) && ! ($val instanceof BackedEnum) && enum_exists($casts[$field])) { $enumClass = $casts[$field]; $val = $enumClass::tryFrom($val) ?? $val; } // Use labels for Enums if they implement HasLabel $displayVal = ($val instanceof HasLabel) ? $val->getLabel() : ($val instanceof BackedEnum ? $val->value : $val); $displayOldVal = ($oldVal instanceof HasLabel) ? $oldVal->getLabel() : ($oldVal instanceof BackedEnum ? $oldVal->value : $oldVal); if ($displayOldVal !== $displayVal) { $label = $fieldLabels[$field] ?? $field; $changedFields[$label] = $displayVal; $oldDataArr[$label] = $displayOldVal; } } $documents = [ 'journalism_organization_docs', 'press_council_certificate_docs', ]; foreach ($documents as $field) { $newValue = $this->data[$field] ?? []; $oldValue = $this->originalDocuments[$field] ?? []; if (json_encode($newValue) !== json_encode($oldValue)) { $label = $fieldLabels[$field] ?? $field; $changedFields[$label] = $newValue; $oldDataArr[$label] = $oldValue; } } if (empty($changedFields)) { CheerfulNotification::info( 'Belum ada yang berubah ✨', 'Ubah data terlebih dulu lalu simpan kembali 💪' ) ->send(); return; } $dataChangeRequest = DataChangeRequest::create([ 'user_id' => auth()->id(), 'entity_type' => PartnerMedia::class, 'entity_id' => $this->media->id, 'old_data' => $oldDataArr, 'new_data' => $changedFields, 'change_reason' => $data['change_reason'], ]); CheerfulNotification::success( 'Permohonan Berhasil 🎉', 'Data sudah dikirim dan sedang menunggu verifikasi admin ⏳' ) ->send(); User::superAdmin() ->get() ->each(function ($admin) use ($dataChangeRequest): void { $admin->notify(new BroadcastNotification([ 'title' => 'Ada Pengajuan Perubahan Data Media ✨', 'body' => 'Halooo Admin! 👋 '.auth()->user()->name.' baru saja mengajukan perubahan data media. Yuk, cek detailnya! 🚀', 'action' => [ Action::make('view') ->label('Lihat') ->url(DataChangesResource::getUrl('view', ['record' => $dataChangeRequest->id])), ], ])); }); } else { $state = $this->form->getState(); $media = PartnerMedia::updateOrCreate([ 'id' => $this->media?->id, ], [ 'company_id' => $this->company->id, 'name' => $state['name'], 'link' => $state['link'], 'address' => $state['address'], 'type' => $state['type'], 'classification' => $state['classification'], 'journalism_organization' => $state['journalism_organization'], 'press_council_certificate' => $state['press_council_certificate'], ]); $this->media = $media; $documents = [ 'journalism_organization_docs', 'press_council_certificate_docs', ]; foreach ($documents as $field) { if (empty($this->data[$field])) { continue; } foreach ((array) $this->data[$field] as $filePath) { $fullPath = Storage::disk(config('filesystems.default'))->path($filePath); if (! file_exists($fullPath)) { continue; } $media ->addMediaFromDisk($filePath, config('filesystems.default')) ->preservingOriginal() ->withCustomProperties([ 'feature' => 'media', 'date' => now()->toDateString(), 'doc_type' => str($field) ->replace('_docs', '') ->slug('-'), ]) ->toMediaCollection('partnerMedia'); } } CheerfulNotification::create()->send(); } } }