86 lines
3.6 KiB
PHP
86 lines
3.6 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
namespace Modules\Core\Privacy\Filament\Extensions;
|
||
|
|
|
||
|
|
use Filament\Actions\Action;
|
||
|
|
use Filament\Forms\Components\Checkbox;
|
||
|
|
use Filament\Notifications\Notification;
|
||
|
|
use Lunar\Admin\Support\Extending\BaseExtension;
|
||
|
|
use Lunar\Models\Customer;
|
||
|
|
use Modules\Core\Auth\Models\Staff;
|
||
|
|
use Modules\Core\Privacy\PrivacyService;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds "Request erasure" / "Request export" header actions to the Customer
|
||
|
|
* resource's edit/view page — the panel entry point for a staff member handling
|
||
|
|
* "a customer emailed asking to be forgotten/for their data" without needing
|
||
|
|
* tinker/code access. Registered centrally in CorePlugin, layered alongside
|
||
|
|
* whatever CustomerResourceExtension a consuming app registers for its own
|
||
|
|
* form/table/relations — LunarPanel::extensions() merges per resource (see
|
||
|
|
* docs/modules.md "Layering Module and App Configuration"), and this extension
|
||
|
|
* deliberately only implements headerActions(), so it never conflicts with an
|
||
|
|
* app's own extension for the same resource.
|
||
|
|
*/
|
||
|
|
class CustomerErasureActionsExtension extends BaseExtension
|
||
|
|
{
|
||
|
|
public function headerActions(array $actions): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
...$actions,
|
||
|
|
Action::make('requestErasure')
|
||
|
|
->label('Request Erasure')
|
||
|
|
->icon('heroicon-o-shield-exclamation')
|
||
|
|
->color('danger')
|
||
|
|
->requiresConfirmation()
|
||
|
|
->modalDescription('Opens a cancellable grace-period erasure request for this Customer account. No linked User\'s login is affected.')
|
||
|
|
->form([
|
||
|
|
Checkbox::make('immediate')
|
||
|
|
->label('Erase immediately (skip the 30-day grace period)')
|
||
|
|
->helperText('Staff-only, for a formal legal request or regulator inquiry that genuinely requires urgency — not a routine deletion. Runs synchronously, cannot be cancelled once submitted.')
|
||
|
|
->default(false),
|
||
|
|
])
|
||
|
|
->action(function (Customer $record, array $data) {
|
||
|
|
$privacyService = app(PrivacyService::class);
|
||
|
|
|
||
|
|
if ($data['immediate']) {
|
||
|
|
$privacyService->requestImmediateErasureForCustomer($record, $this->currentStaff());
|
||
|
|
|
||
|
|
Notification::make()
|
||
|
|
->title('Customer erased')
|
||
|
|
->body('Erasure ran immediately — see the Erasure Requests list for the outcome.')
|
||
|
|
->success()
|
||
|
|
->send();
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$privacyService->requestErasureForCustomer($record, $this->currentStaff());
|
||
|
|
|
||
|
|
Notification::make()
|
||
|
|
->title('Erasure requested')
|
||
|
|
->body('The grace period starts now — see the Erasure Requests list.')
|
||
|
|
->success()
|
||
|
|
->send();
|
||
|
|
}),
|
||
|
|
Action::make('requestExport')
|
||
|
|
->label('Request Export')
|
||
|
|
->icon('heroicon-o-arrow-down-tray')
|
||
|
|
->requiresConfirmation()
|
||
|
|
->action(function (Customer $record) {
|
||
|
|
app(PrivacyService::class)->requestExportForCustomer($record);
|
||
|
|
|
||
|
|
Notification::make()
|
||
|
|
->title('Export requested')
|
||
|
|
->body('Generating in the background — see the Export Requests list once it completes.')
|
||
|
|
->success()
|
||
|
|
->send();
|
||
|
|
}),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
private function currentStaff(): Staff
|
||
|
|
{
|
||
|
|
return auth('staff')->user();
|
||
|
|
}
|
||
|
|
}
|