diff --git a/app/Filament/Resources/Manage/DataChanges/Actions/AcceptAction.php b/app/Filament/Resources/Manage/DataChanges/Actions/AcceptAction.php
index ffb24f9..e385ccf 100644
--- a/app/Filament/Resources/Manage/DataChanges/Actions/AcceptAction.php
+++ b/app/Filament/Resources/Manage/DataChanges/Actions/AcceptAction.php
@@ -35,7 +35,7 @@ protected function setUp(): void
$entity = $record->entity;
$newData = $record->new_data;
- if (isset($newData['__delete_request__']) && $newData['__delete_request__'] === true) {
+ if (empty($newData)) {
$entity->delete();
$record->update(['status' => DataChangeStatus::APPROVED]);
diff --git a/app/Filament/Resources/Manage/DataChanges/Infolists/DataChangeInfolist.php b/app/Filament/Resources/Manage/DataChanges/Infolists/DataChangeInfolist.php
index 71e2449..054f3dc 100644
--- a/app/Filament/Resources/Manage/DataChanges/Infolists/DataChangeInfolist.php
+++ b/app/Filament/Resources/Manage/DataChanges/Infolists/DataChangeInfolist.php
@@ -4,229 +4,194 @@
use App\Filament\Support\CheerfulNotification;
use App\Models\DataChangeRequest;
+use Filament\Infolists\Components\ImageEntry;
use Filament\Infolists\Components\TextEntry;
+use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Illuminate\Support\Facades\Storage;
+use Joaopaulolndev\FilamentPdfViewer\Infolists\Components\PdfViewerEntry;
class DataChangeInfolist
{
public static function configure(Schema $schema): Schema
{
return $schema
- ->schema([
- Section::make()
- ->schema([
- TextEntry::make('comparison')
+ ->schema(function (DataChangeRequest $record): array {
+ $old = $record->old_data ?? [];
+ $new = $record->new_data ?? [];
+
+ if (! is_array($old) || ! is_array($new)) {
+ return [
+ TextEntry::make('error')
->hiddenLabel()
- ->html()
- ->state(function (DataChangeRequest $record): string {
- $old = $record->old_data ?? [];
- $new = $record->new_data ?? [];
+ ->state('Format data tidak valid.')
+ ->badge()
+ ->color('danger'),
+ ];
+ }
- if (! is_array($old) || ! is_array($new)) {
- return self::alert('Format data tidak valid.', 'warning');
- }
+ if (empty($new)) {
+ return self::buildDeletionView($old);
+ }
- if (isset($new['__delete_request__']) && $new['__delete_request__'] === true) {
- return self::deletionView($old);
- }
+ if (empty($old)) {
+ return self::buildAdditionView($new);
+ }
- if (empty($old)) {
- return self::additionView($new);
- }
-
- return self::updateView($old, $new);
- }),
- ]),
- ])
+ return self::buildUpdateView($old, $new);
+ })
->columns(1);
}
- private static function deletionView(array $old): string
+ private static function buildDeletionView(array $old): array
{
$title = CheerfulNotification::getByKey('data_change.deletion_request_title');
$desc = CheerfulNotification::getByKey('data_change.deletion_request_desc');
- $rows = collect($old)
- ->map(fn ($v, $k) => self::row($k, self::renderValue($v)))
- ->implode('');
-
- return self::card(
- header: self::header('del', $title, $desc, self::badge('Penghapusan', 'del')),
- body: $rows ?: self::emptyRow(),
- );
+ return [
+ Section::make($title)
+ ->description($desc)
+ ->icon('heroicon-o-trash')
+ ->schema([
+ TextEntry::make('badge')->hiddenLabel()->state('Penghapusan')->badge()->color('danger'),
+ ...collect($old)->map(fn ($v, $k) => self::fieldEntry($k, $v, showLabel: true))->flatten()->toArray(),
+ ]),
+ ];
}
- private static function additionView(array $new): string
+ private static function buildAdditionView(array $new): array
{
$title = CheerfulNotification::getByKey('data_change.addition_request_title');
$desc = CheerfulNotification::getByKey('data_change.addition_request_desc');
- $rows = collect($new)
- ->map(fn ($v, $k) => self::row($k, self::renderValue($v)))
- ->implode('');
-
- return self::card(
- header: self::header('add', $title, $desc, self::badge('Penambahan Baru', 'add')),
- body: $rows ?: self::emptyRow(),
- );
+ return [
+ Section::make($title)
+ ->description($desc)
+ ->icon('heroicon-o-plus-circle')
+ ->schema([
+ TextEntry::make('badge')->hiddenLabel()->state('Penambahan Baru')->badge()->color('success'),
+ ...collect($new)->map(fn ($v, $k) => self::fieldEntry($k, $v, showLabel: true))->flatten()->toArray(),
+ ]),
+ ];
}
- private static function updateView(array $old, array $new): string
+ private static function buildUpdateView(array $old, array $new): array
{
- $changed = collect($new)
- ->map(function ($newVal, $key) use ($old) {
- $oldVal = $old[$key] ?? null;
+ $title = CheerfulNotification::getByKey('data_change.comparison_title');
+ $desc = CheerfulNotification::getByKey('data_change.comparison_desc');
- if ($oldVal === $newVal) {
- return null;
- }
+ $changedFields = collect($new)
+ ->filter(fn ($newVal, $key) => ($old[$key] ?? null) !== $newVal);
- return "
-
-
".e($key)."
-
-
".self::renderValue($oldVal)."
-
".self::renderValue($newVal).'
-
-
';
- })
- ->filter();
-
- if ($changed->isEmpty()) {
- return self::alert('Tidak ada perubahan data yang terdeteksi.', 'info');
+ if ($changedFields->isEmpty()) {
+ return [
+ TextEntry::make('info')->hiddenLabel()->state('Tidak ada perubahan data terdeteksi.')->badge()->color('info'),
+ ];
}
- $count = $changed->count();
- $label = $count === 1 ? '1 field diubah' : "{$count} field diubah";
+ $fieldCount = $changedFields->count();
+ $label = $fieldCount === 1 ? '1 field diubah' : "{$fieldCount} field diubah";
- $diffHeader = "
- ";
+ return [
+ Section::make($title)
+ ->description($desc)
+ ->icon('heroicon-o-pencil-square')
+ ->schema([
+ TextEntry::make('badge')->hiddenLabel()->state($label)->badge()->color('primary'),
+ Grid::make(1)
+ ->schema(
+ $changedFields->map(function ($newVal, $key) use ($old) {
+ $oldVal = $old[$key] ?? null;
- return self::card(
- header: self::header('edit', CheerfulNotification::getByKey('data_change.comparison_title'), CheerfulNotification::getByKey('data_change.comparison_desc'), self::badge($label, 'default')),
- body: $diffHeader.$changed->implode(''),
- );
+ return [
+ Section::make($key)
+ ->columnSpanFull()
+ ->compact()
+ ->schema([
+ Grid::make(2)
+ ->schema([
+ Grid::make(1)
+ ->schema([
+ TextEntry::make("{$key}_old_label")
+ ->hiddenLabel()
+ ->state('SEBELUM')
+ ->weight('bold')
+ ->size('xs')
+ ->color('danger'),
+ ...self::fieldEntry("{$key}_old", $oldVal, showLabel: false),
+ ])->columnSpan(1),
+
+ Grid::make(1)
+ ->schema([
+ TextEntry::make("{$key}_new_label")
+ ->hiddenLabel()
+ ->state('SESUDAH')
+ ->weight('bold')
+ ->size('xs')
+ ->color('success'),
+ ...self::fieldEntry("{$key}_new", $newVal, showLabel: false),
+ ])->columnSpan(1),
+ ]),
+ ]),
+ ];
+ })->flatten()->toArray()
+ ),
+ ]),
+ ];
}
- private static function card(string $header, string $body): string
+ private static function fieldEntry(string $label, mixed $value, bool $showLabel = true): array
{
- return "
- ";
- }
+ $id = str($label)->slug('_')->toString();
- private static function header(string $type, string $title, string $desc, string $badge): string
- {
- $icon = self::icon($type);
-
- return "
- ";
- }
-
- private static function row(string $key, string $value): string
- {
- return "
-
-
".e($key)."
-
{$value}
-
";
- }
-
- private static function emptyRow(): string
- {
- return "Tidak ada data tersedia.
";
- }
-
- private static function badge(string $label, string $variant): string
- {
- [$bg, $color, $border] = match ($variant) {
- 'del' => ['var(--dcr-badge-del-bg)', 'var(--dcr-badge-del-color)', 'var(--dcr-badge-del-border)'],
- 'add' => ['var(--dcr-badge-add-bg)', 'var(--dcr-badge-add-color)', 'var(--dcr-badge-add-border)'],
- default => ['var(--dcr-badge-bg)', 'var(--dcr-badge-color)', 'var(--dcr-badge-border)'],
- };
-
- return "{$label}";
- }
-
- private static function alert(string $message, string $type = 'info'): string
- {
- $icon = $type === 'warning' ? '⚠' : 'ℹ';
-
- return "
-
- {$icon}
- {$message}
-
";
- }
-
- private static function icon(string $type): string
- {
- return match ($type) {
- 'del' => "",
- 'add' => "",
- 'edit' => "",
- default => '',
- };
- }
-
- private static function renderValue(mixed $value): string
- {
if ($value === null || $value === '' || (is_array($value) && empty($value))) {
- return "—";
+ return [
+ TextEntry::make($id)
+ ->label($label)
+ ->hiddenLabel(! $showLabel)
+ ->state('—')
+ ->color('gray'),
+ ];
}
$paths = is_array($value) ? $value : [$value];
+ $components = [];
- return collect($paths)->map(function ($item) {
- if (! is_string($item)) {
- return "".e(json_encode($item)).'';
- }
+ foreach ($paths as $index => $item) {
+ $uniqueId = "{$id}_{$index}";
- if (preg_match('/^https?:\/\//i', $item)) {
- return "".e($item).'';
- }
-
- if ((str_contains($item, '/') || str_contains($item, '\\')) && ! str_contains($item, ' ')) {
- $url = Storage::disk(config('filesystems.default'))->url($item);
+ if (is_string($item) && (str_contains($item, '/') || str_contains($item, '\\'))) {
$ext = strtolower(pathinfo($item, PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'])) {
- return "
";
+ $components[] = ImageEntry::make($uniqueId)
+ ->label($index === 0 ? $label : '')
+ ->hiddenLabel(! ($showLabel && $index === 0))
+ ->disk(config('filesystems.default'))
+ ->state($item)
+ ->extraImgAttributes(['style' => 'max-height: 200px; width: auto; border-radius: 0.5rem;']);
+
+ continue;
}
if ($ext === 'pdf') {
- return "
-
-
-
";
+ $components[] = PdfViewerEntry::make($uniqueId)
+ ->label($index === 0 ? $label : '')
+ ->hiddenLabel(! ($showLabel && $index === 0))
+ ->minHeight('500px')
+ ->state(Storage::disk(config('filesystems.default'))->url($item));
+
+ continue;
}
-
- $extUp = $ext ? strtoupper($ext) : 'FILE';
-
- return "
-
- Dokumen {$extUp}
- ";
}
- return "".e($item).'';
- })->implode('
');
+ $components[] = TextEntry::make($uniqueId)
+ ->label($index === 0 ? $label : '')
+ ->hiddenLabel(! ($showLabel && $index === 0))
+ ->state(is_scalar($item) ? $item : json_encode($item));
+ }
+
+ return $components;
}
}
diff --git a/app/Filament/Resources/Manage/Journalists/Actions/DeleteJournalistAction.php b/app/Filament/Resources/Manage/Journalists/Actions/DeleteJournalistAction.php
index 26e3f20..9558538 100644
--- a/app/Filament/Resources/Manage/Journalists/Actions/DeleteJournalistAction.php
+++ b/app/Filament/Resources/Manage/Journalists/Actions/DeleteJournalistAction.php
@@ -28,9 +28,10 @@ protected function setUp(): void
$this->successNotification(null);
- $this->modalHeading(fn () => auth()->user()->company?->verificationRequest?->status === VerificationStatus::APPROVED
- ? CheerfulNotification::getByKey('journalist.request_deletion_title')
- : CheerfulNotification::getByKey('journalist.delete_title')
+ $this->modalHeading(
+ fn () => auth()->user()->company?->verificationRequest?->status === VerificationStatus::APPROVED
+ ? CheerfulNotification::getByKey('journalist.request_deletion_title')
+ : CheerfulNotification::getByKey('journalist.delete_title')
);
$this->schema(fn () => auth()->user()->company?->verificationRequest?->status === VerificationStatus::APPROVED ? [
@@ -58,12 +59,42 @@ protected function setUp(): void
return;
}
+ $fieldLabels = Journalist::dataChangeEntryLabels();
+ $oldFields = [];
+
+ // Standard fields
+ foreach (['name', 'email', 'phone_number', 'press_card', 'ukw_certificate'] as $f) {
+ $label = $fieldLabels[$f] ?? $f;
+ $val = $record->{$f};
+
+ // Resolve enums if necessary
+ if ($val instanceof \BackedEnum) {
+ $val = $val->value;
+ }
+
+ $oldFields[$label] = $val ?? '-';
+ }
+
+ // Document fields
+ $mediaItems = $record->getMedia('journalists');
+ foreach (['press_card_docs', 'ukw_certificate_docs'] as $df) {
+ $label = $fieldLabels[$df] ?? $df;
+ $docType = str($df)->replace('_docs', '')->slug('-');
+
+ $currentMedia = $mediaItems
+ ->where('custom_properties.doc_type', $docType)
+ ->sortByDesc('created_at')
+ ->first();
+
+ $oldFields[$label] = $currentMedia ? [$currentMedia->getPathRelativeToRoot()] : [];
+ }
+
$dataChangeRequest = DataChangeRequest::create([
'user_id' => $user->id,
'entity_type' => Journalist::class,
'entity_id' => $record->id,
- 'old_data' => $record->toArray(),
- 'new_data' => ['__delete_request__' => true],
+ 'old_data' => $oldFields,
+ 'new_data' => [],
'change_reason' => $data['deletion_reason'] ?? 'Penghapusan jurnalis',
]);
diff --git a/lang/id/notif.php b/lang/id/notif.php
index 6b058a4..7f537ea 100644
--- a/lang/id/notif.php
+++ b/lang/id/notif.php
@@ -708,6 +708,14 @@
'cheerful' => 'Maaf ya, pengajuan perubahan data kamu terpaksa ditolak untuk saat ini. Tetap semangat! 💪',
'formal' => 'Pengajuan perubahan data Anda tidak dapat disetujui.',
],
+ 'deletion_approved' => [
+ 'cheerful' => 'Hapus Berhasil! 🗑️🚀',
+ 'formal' => 'Penghapusan Disetujui',
+ ],
+ 'deletion_success_desc' => [
+ 'cheerful' => 'Sip! Data tersebut sudah berhasil dihapus secara permanen dari sistem sebagaimana permintaanmu. ✨🚮',
+ 'formal' => 'Data tersebut telah berhasil dihapus dari sistem sesuai permohonan.',
+ ],
],
'visitor' => [
'empty_state' => [