columns([ TextColumn::make('model_type')->label('Tipe') ->formatStateUsing(fn ($state) => match ($state) { 'App\\Models\\CashRecord' => '💰 Transaksi Kas', 'App\\Models\\Activity' => '📅 Kegiatan', default => class_basename($state), }), TextColumn::make('subject') ->label('Deskripsi') ->state(function (Approval $record): string { $subject = $record->approvable; return match (true) { $subject instanceof \App\Models\CashRecord => $subject->description . ' — Rp ' . number_format($subject->amount, 0, ',', '.'), $subject instanceof \App\Models\Activity => $subject->title, default => "#{$record->model_id}", }; }) ->limit(50), TextColumn::make('progress') ->label('Progress') ->state(fn (Approval $record) => $record->items()->where('decision', 'approve')->count() . ' / ' . $record->required_approvals . ' persetujuan') ->badge()->color('info'), TextColumn::make('status')->badge() ->color(fn ($state) => match ($state) { 'approved' => 'success', 'rejected' => 'danger', default => 'warning', }) ->formatStateUsing(fn ($state) => match ($state) { 'approved' => 'Disetujui', 'rejected' => 'Ditolak', default => 'Menunggu', }), TextColumn::make('created_at')->label('Dibuat')->date('d M Y')->sortable(), ]) ->defaultSort('created_at', 'desc') ->filters([ SelectFilter::make('status')->options([ 'pending' => 'Menunggu', 'approved' => 'Disetujui', 'rejected' => 'Ditolak', ]), ]) ->recordActions([ ViewAction::make()->label('Detail'), Action::make('approve') ->label('Setujui') ->icon('heroicon-o-check-circle') ->color('success') ->requiresConfirmation() ->visible(fn (Approval $record) => $record->status === 'pending' && ! $record->items()->where('user_id', auth()->id())->exists()) ->form([Textarea::make('notes')->label('Catatan')->rows(2)]) ->action(function (Approval $record, array $data): void { ApprovalItem::create([ 'approval_id' => $record->id, 'user_id' => auth()->id(), 'decision' => 'approve', 'notes' => $data['notes'] ?? null, ]); $count = $record->items()->where('decision', 'approve')->count(); if ($count >= $record->required_approvals) { $record->update(['status' => 'approved']); } \App\Models\ActivityLog::create([ 'user_id' => auth()->id(), 'action' => 'approved', 'model_type' => Approval::class, 'model_id' => $record->id, 'description' => auth()->user()->name . " menyetujui persetujuan #{$record->id}", ]); }), Action::make('reject') ->label('Tolak') ->icon('heroicon-o-x-circle') ->color('danger') ->visible(fn (Approval $record) => $record->status === 'pending' && ! $record->items()->where('user_id', auth()->id())->exists()) ->form([Textarea::make('notes')->label('Alasan Penolakan')->required()->rows(2)]) ->action(function (Approval $record, array $data): void { ApprovalItem::create([ 'approval_id' => $record->id, 'user_id' => auth()->id(), 'decision' => 'reject', 'notes' => $data['notes'], ]); $record->update(['status' => 'rejected']); \App\Models\ActivityLog::create([ 'user_id' => auth()->id(), 'action' => 'rejected', 'model_type' => Approval::class, 'model_id' => $record->id, 'description' => auth()->user()->name . " menolak persetujuan #{$record->id}", ]); }), ]) ->toolbarActions([BulkActionGroup::make([DeleteBulkAction::make()])]); } }