293 lines
14 KiB
PHP
293 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Resources\Manage\DataChanges;
|
|
|
|
use App\Enums\DataChangeStatus;
|
|
use App\Enums\RoleEnum;
|
|
use App\Filament\Actions\DefaultBulkActions;
|
|
use App\Filament\Columns\RowIndexColumn;
|
|
use App\Filament\Resources\Manage\DataChanges\Actions\DataChangeRequest\AcceptAction;
|
|
use App\Filament\Resources\Manage\DataChanges\Actions\DataChangeRequest\RejectAction;
|
|
use App\Filament\Resources\Manage\DataChanges\Pages\ManageDataChanges;
|
|
use App\Filament\Resources\Manage\DataChanges\Pages\ViewDataChange;
|
|
use App\Models\Company;
|
|
use App\Models\DataChangeRequest;
|
|
use App\Models\Journalist;
|
|
use App\Models\PartnerMedia;
|
|
use BackedEnum;
|
|
use Filament\Actions\BulkActionGroup;
|
|
use Filament\Actions\ViewAction;
|
|
use Filament\Infolists\Components\TextEntry;
|
|
use Filament\Resources\Resource;
|
|
use Filament\Schemas\Schema;
|
|
use Filament\Support\Icons\Heroicon;
|
|
use Filament\Tables\Columns\TextColumn;
|
|
use Filament\Tables\Filters\SelectFilter;
|
|
use Filament\Tables\Filters\TrashedFilter;
|
|
use Filament\Tables\Table;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use UnitEnum;
|
|
|
|
class DataChangesResource extends Resource
|
|
{
|
|
protected static ?string $model = DataChangeRequest::class;
|
|
|
|
protected static string|UnitEnum|null $navigationGroup = 'Kelola';
|
|
|
|
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDocumentText;
|
|
|
|
protected static ?string $navigationLabel = 'Permohonan Perubahan Data';
|
|
|
|
protected static ?int $navigationSort = 8;
|
|
|
|
protected static ?string $recordTitleAttribute = 'change_reason';
|
|
|
|
protected static ?string $slug = 'manage/data-changes';
|
|
|
|
public static function getNavigationBadge(): ?string
|
|
{
|
|
if (auth()->user()->hasRole(RoleEnum::PERUSAHAAN)) {
|
|
return null;
|
|
}
|
|
|
|
return static::getModel()::pending()->count();
|
|
}
|
|
|
|
public static function infolist(Schema $schema): Schema
|
|
{
|
|
return $schema
|
|
->schema([
|
|
TextEntry::make('comparison')
|
|
->hiddenLabel()
|
|
->html()
|
|
->state(function (DataChangeRequest $record): string {
|
|
$old = $record->old_data ?? [];
|
|
$new = $record->new_data ?? [];
|
|
|
|
if (! is_array($old) || ! is_array($new)) {
|
|
return '<em>Format data tidak valid.</em>';
|
|
}
|
|
|
|
$renderValue = function ($value) {
|
|
if (empty($value)) {
|
|
return '<em>Kosong</em>';
|
|
}
|
|
|
|
$paths = is_array($value) ? $value : [$value];
|
|
$isProbablyPath = false;
|
|
|
|
foreach ($paths as $path) {
|
|
if (is_string($path) && (str_contains($path, '/') || str_contains($path, '\\'))) {
|
|
$isProbablyPath = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($isProbablyPath) {
|
|
return collect($paths)
|
|
->map(function ($path) {
|
|
if (! is_string($path)) {
|
|
return e(json_encode($path));
|
|
}
|
|
|
|
$url = Storage::disk(config('filesystems.default'))->url($path);
|
|
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
|
|
|
|
if (in_array($extension, ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'])) {
|
|
return "<a href='{$url}' target='_blank'><img src='{$url}' style='max-height:100px; border-radius:8px; margin-top:4px; border:1px solid #e5e7eb;'></a>";
|
|
}
|
|
|
|
if ($extension === 'pdf') {
|
|
return "
|
|
<div style='margin-top:4px;'>
|
|
<iframe src='{$url}' style='width:100%; height:300px; border:1px solid #e5e7eb; border-radius:8px;'></iframe>
|
|
<a href='{$url}' target='_blank' style='display:block; margin-top:4px; color:#3b82f6; text-decoration:underline; font-size:0.75rem;'>↗️ Buka PDF di Tab Baru</a>
|
|
</div>
|
|
";
|
|
}
|
|
|
|
return "<a href='{$url}' target='_blank' style='color:#3b82f6; text-decoration:underline; font-size:0.875rem;'>📎 Buka Dokumen (".strtoupper($extension).')</a>';
|
|
})
|
|
->implode('<br>');
|
|
}
|
|
|
|
return e(is_scalar($value) ? $value : json_encode($value));
|
|
};
|
|
|
|
// 1. Deletion Request
|
|
if (isset($new['__delete_request__']) && $new['__delete_request__'] === true) {
|
|
return "
|
|
<div style='background-color:#fee2e2; border:1px solid #f87171; color:#991b1b; padding:16px; border-radius:8px; margin-bottom:16px;'>
|
|
<div style='font-weight:700; font-size:1.125rem; margin-bottom:4px;'>🚮 Permohonan Penghapusan Data</div>
|
|
<p style='font-size:0.875rem;'>User mengajukan penghapusan permanen untuk data ini. Semua informasi terkait akan dihapus setelah disetujui.</p>
|
|
</div>
|
|
";
|
|
}
|
|
|
|
// 2. New Addition Request
|
|
if (empty($old)) {
|
|
$rows = collect($new)
|
|
->map(function ($value, $key) use ($renderValue) {
|
|
return sprintf(
|
|
"<div style='margin-bottom:12px; border-bottom:1px solid #f3f4f6; padding-bottom:8px'>
|
|
<div style='font-weight:600; color:#374151; margin-bottom:4px'>%s</div>
|
|
<div style='color:#16a34a; font-weight:500;'>[BARU]</div>
|
|
<div style='margin-top:4px'>%s</div>
|
|
</div>",
|
|
e($key),
|
|
$renderValue($value)
|
|
);
|
|
})
|
|
->implode('');
|
|
|
|
return "
|
|
<div style='background-color:#f0fdf4; border:1px solid #bbf7d0; color:#166534; padding:16px; border-radius:8px; margin-bottom:16px;'>
|
|
<div style='font-weight:700; font-size:1.125rem; margin-bottom:4px;'>✨ Permohonan Penambahan Data</div>
|
|
<p style='font-size:0.875rem;'>Berikut adalah data baru yang akan dibuat.</p>
|
|
</div>
|
|
{$rows}
|
|
";
|
|
}
|
|
|
|
// 3. Standard Comparison (Update)
|
|
return collect($new)
|
|
->map(function ($newValue, $key) use ($old, $renderValue) {
|
|
$oldValue = $old[$key] ?? null;
|
|
|
|
if ($oldValue === $newValue) {
|
|
return null;
|
|
}
|
|
|
|
return sprintf(
|
|
"<div style='margin-bottom:16px; border-bottom:1px solid #f3f4f6; padding-bottom:12px'>
|
|
<div style='font-weight:600; color:#374151; margin-bottom:4px'>%s</div>
|
|
<div style='display:grid; grid-template-columns: 1fr 1fr; gap:16px'>
|
|
<div>
|
|
<span style='font-size:0.75rem; font-weight:700; color:#dc2626; text-transform:uppercase'>LAMA</span>
|
|
<div style='margin-top:2px'>%s</div>
|
|
</div>
|
|
<div>
|
|
<span style='font-size:0.75rem; font-weight:700; color:#16a34a; text-transform:uppercase'>BARU</span>
|
|
<div style='margin-top:2px'>%s</div>
|
|
</div>
|
|
</div>
|
|
</div>",
|
|
e($key),
|
|
$renderValue($oldValue),
|
|
$renderValue($newValue)
|
|
);
|
|
})
|
|
->filter()
|
|
->implode('');
|
|
})
|
|
->columnSpanFull(),
|
|
])
|
|
->columns(1);
|
|
}
|
|
|
|
public static function table(Table $table): Table
|
|
{
|
|
return $table
|
|
->columns([
|
|
...RowIndexColumn::make(),
|
|
|
|
TextColumn::make('user.name')
|
|
->label('Pemohon')
|
|
->searchable()
|
|
->sortable()
|
|
->description(fn (DataChangeRequest $record): ?string => $record?->entity?->name)
|
|
->visible(! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)),
|
|
|
|
TextColumn::make('entity_type')
|
|
->label('Jenis Data')
|
|
->searchable()
|
|
->sortable()
|
|
->description(fn (DataChangeRequest $record): ?string => match (true) {
|
|
isset($record->new_data['__delete_request__']) => '🗑️ Penghapusan',
|
|
empty($record->old_data) => '✨ Penambahan',
|
|
default => '📝 Perubahan',
|
|
})
|
|
->formatStateUsing(fn (DataChangeRequest $record): ?string => match ($record->entity_type) {
|
|
Company::class => 'Perusahaan',
|
|
PartnerMedia::class => 'Media',
|
|
Journalist::class => 'Jurnalis',
|
|
default => 'Lainnya',
|
|
})
|
|
->color(fn (DataChangeRequest $record): ?string => match ($record->entity_type) {
|
|
Company::class => 'success',
|
|
PartnerMedia::class => 'info',
|
|
Journalist::class => 'warning',
|
|
default => 'secondary',
|
|
})
|
|
->badge(),
|
|
|
|
TextColumn::make('status')
|
|
->label('Status')
|
|
->searchable()
|
|
->sortable()
|
|
->badge()
|
|
->formatStateUsing(fn (DataChangeStatus $state): string => $state->getLabel())
|
|
->color(fn (DataChangeStatus $state): string => $state->getColor())
|
|
->description(fn (DataChangeRequest $record): ?string => $record?->review ? 'Oleh: '.$record->review?->reviewer?->name : ''),
|
|
|
|
TextColumn::make('change_reason')
|
|
->label('Alasan Perubahan')
|
|
->limit(50),
|
|
|
|
TextColumn::make('review.note')
|
|
->label('Alasan Penolakan')
|
|
->limit(50),
|
|
|
|
TextColumn::make('created_at')
|
|
->label('Tgl Permohonan')
|
|
->date()
|
|
->sortable()
|
|
->dateTime('l, d F Y H:i:s')
|
|
->wrap(),
|
|
])
|
|
->filters([
|
|
SelectFilter::make('status')
|
|
->label('Status')
|
|
->options(DataChangeStatus::class)
|
|
->native(false),
|
|
|
|
TrashedFilter::make()
|
|
->native(false)
|
|
->visible(fn () => auth()->user()?->hasRole(RoleEnum::DEVELOPER->value)),
|
|
])
|
|
->recordActions([
|
|
ViewAction::make(),
|
|
AcceptAction::make('accept'),
|
|
RejectAction::make('reject'),
|
|
])
|
|
->toolbarActions([
|
|
BulkActionGroup::make([
|
|
...DefaultBulkActions::make('permohonan perubahan data'),
|
|
]),
|
|
])
|
|
->emptyStateIcon(Heroicon::OutlinedDocumentText)
|
|
->emptyStateDescription('Belum ada permohonan perubahan data.')
|
|
->defaultSort('created_at', 'desc')
|
|
->deferFilters(false)
|
|
->paginated([25, 50, 100, 'all'])
|
|
->deferLoading();
|
|
}
|
|
|
|
public static function getEloquentQuery(): Builder
|
|
{
|
|
return parent::getEloquentQuery()
|
|
->when(auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value), function (Builder $q): Builder {
|
|
return $q->where('user_id', auth()->id());
|
|
});
|
|
}
|
|
|
|
public static function getPages(): array
|
|
{
|
|
return [
|
|
'index' => ManageDataChanges::route('/'),
|
|
'view' => ViewDataChange::route('/{record}'),
|
|
];
|
|
}
|
|
}
|