records(function (?string $search, ?string $sortColumn, ?string $sortDirection, int|string $page, int|string $recordsPerPage, ?array $filters) use ($service) { $status = Arr::get($filters, 'status.value') ?? Arr::get($filters, 'status'); return $service->paginate( search: $search, sortColumn: $sortColumn, sortDirection: $sortDirection, page: (int) $page, perPage: (int) $recordsPerPage, filters: array_filter(['status' => is_array($status) ? ($status['value'] ?? null) : $status]), ); }) ->columns([ TextColumn::make('complaint_number')->label('No. Komplain')->badge()->sortable(), TextColumn::make('customers.name')->label('Pelanggan'), TextColumn::make('orders.order_number')->label('Order')->placeholder('—'), TextColumn::make('complaint_date')->label('Tgl')->date('d M Y')->sortable(), TextColumn::make('category') ->label('Kategori') ->badge() ->color('info') ->formatStateUsing(fn (string $state): string => ComplaintService::CATEGORIES[$state] ?? $state), TextColumn::make('priority') ->label('Prioritas') ->badge() ->color(fn (string $state): string => match ($state) { 'high' => 'danger', 'medium' => 'warning', default => 'gray', }) ->formatStateUsing(fn (string $state): string => ComplaintService::PRIORITIES[$state] ?? $state) ->sortable(), TextColumn::make('description')->label('Deskripsi')->limit(40), TextColumn::make('status') ->label('Status') ->badge() ->color(fn (string $state): string => $state === ComplaintService::STATUS_OPEN ? 'warning' : 'success') ->formatStateUsing(fn (string $state): string => $state === ComplaintService::STATUS_OPEN ? 'Terbuka' : 'Selesai') ->sortable(), TextColumn::make('resolution')->label('Resolusi')->limit(30)->placeholder('—'), ]) ->filters([ Filter::make('status') ->schema([ Select::make('value')->label('Status')->options([ ComplaintService::STATUS_OPEN => 'Terbuka', ComplaintService::STATUS_RESOLVED => 'Selesai', ]), ]), ]) ->recordActions([ Action::make('tutup') ->label('Tutup') ->color('success') ->icon('heroicon-o-check-badge') ->visible(fn (array $record): bool => $service->canResolve($record, auth()->user())) ->schema(fn (Schema $schema): Schema => $schema->components([ Textarea::make('resolution')->label('Resolusi / Tindak Lanjut')->required(), ])) ->action(function (array $data, array $record) use ($service): void { try { $service->resolve($record['id'], $data['resolution'], auth()->user()); } catch (AuthorizationException) { Notification::make()->title('Akses ditolak')->body('Hanya pembuat komplain atau admin yang dapat menutup.')->danger()->send(); return; } Notification::make()->title('Komplain ditutup.')->success()->send(); }), ]) ->headerActions([ CreateAction::make() ->label('Catat Komplain') ->schema(fn (Schema $schema): Schema => $schema->components([ Select::make('customer_id')->label('Pelanggan')->options(fn (): array => app(CustomerService::class)->optionsForSelect())->required()->searchable(), Select::make('order_id')->label('Order Terkait (opsional)')->options(fn (): array => $service->orderOptions())->searchable(), DatePicker::make('complaint_date')->label('Tanggal')->default(now()->toDateString())->required(), Select::make('category')->label('Kategori')->options(ComplaintService::CATEGORIES)->default('product')->required(), Select::make('priority')->label('Prioritas')->options(ComplaintService::PRIORITIES)->default('medium')->required(), Textarea::make('description')->label('Deskripsi Masalah')->required()->columnSpanFull(), ])) ->using(function (array $data): void { app(ComplaintService::class)->createComplaint($data, auth()->user()); Notification::make()->title('Komplain dicatat.')->success()->send(); }), ]) ->paginated([10, 25, 50]); } public function content(Schema $schema): Schema { return $schema ->components([ EmbeddedTable::make(), ]); } }