getRecord(); $user = auth()->user(); if (! $user instanceof User || ! $tenant instanceof Tenant || ! $record instanceof TenantReview) { abort(404); } if ((int) $record->tenant_id !== (int) $tenant->getKey()) { abort(404); } if (! $user->canAccessTenant($tenant)) { abort(404); } if (! $user->can('view', $record)) { abort(403); } } protected function getHeaderActions(): array { $secondaryActions = $this->secondaryLifecycleActions(); return array_values(array_filter([ $this->primaryLifecycleAction(), Actions\ActionGroup::make($secondaryActions) ->label('More') ->icon('heroicon-m-ellipsis-vertical') ->color('gray') ->visible(fn (): bool => $secondaryActions !== []), Actions\ActionGroup::make([ $this->archiveReviewAction(), ]) ->label('Danger') ->icon('heroicon-o-archive-box') ->color('danger') ->visible(fn (): bool => ! $this->record->statusEnum()->isTerminal()), ])); } private function primaryLifecycleAction(): ?Actions\Action { return match ($this->primaryLifecycleActionName()) { 'refresh_review' => $this->refreshReviewAction(), 'publish_review' => $this->publishReviewAction(), 'export_executive_pack' => $this->exportExecutivePackAction(), default => null, }; } private function primaryLifecycleActionName(): ?string { if ((string) $this->record->status === TenantReviewStatus::Published->value) { return 'export_executive_pack'; } if ((string) $this->record->status === TenantReviewStatus::Ready->value) { return 'publish_review'; } if ($this->record->isMutable()) { return 'refresh_review'; } return null; } /** * @return list */ private function secondaryLifecycleActions(): array { return array_values(array_filter(array_map( fn (string $name): ?Actions\Action => match ($name) { 'refresh_review' => $this->refreshReviewAction(), 'publish_review' => $this->publishReviewAction(), 'export_executive_pack' => $this->exportExecutivePackAction(), 'create_next_review' => $this->createNextReviewAction(), default => null, }, $this->secondaryLifecycleActionNames(), ))); } /** * @return array */ private function secondaryLifecycleActionNames(): array { $names = []; if ($this->record->isMutable()) { $names[] = 'refresh_review'; $names[] = 'publish_review'; } if (in_array((string) $this->record->status, [ TenantReviewStatus::Ready->value, TenantReviewStatus::Published->value, ], true)) { $names[] = 'export_executive_pack'; } if ($this->record->isPublished()) { $names[] = 'create_next_review'; } return array_values(array_filter( $names, fn (string $name): bool => $name !== $this->primaryLifecycleActionName(), )); } private function refreshReviewAction(): Actions\Action { return UiEnforcement::forAction( Actions\Action::make('refresh_review') ->label('Refresh review') ->icon('heroicon-o-arrow-path') ->color('primary') ->hidden(fn (): bool => ! $this->record->isMutable()) ->requiresConfirmation() ->action(function (): void { $user = auth()->user(); if (! $user instanceof User) { abort(403); } try { app(TenantReviewService::class)->refresh($this->record, $user); } catch (\Throwable $throwable) { Notification::make()->danger()->title('Unable to refresh review')->body($throwable->getMessage())->send(); return; } Notification::make()->success()->title('Refresh review queued')->send(); }), ) ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) ->preserveVisibility() ->apply(); } private function publishReviewAction(): Actions\Action { return UiEnforcement::forAction( Actions\Action::make('publish_review') ->label('Publish review') ->icon('heroicon-o-check-badge') ->color('primary') ->hidden(fn (): bool => ! $this->record->isMutable()) ->requiresConfirmation() ->action(function (): void { $user = auth()->user(); if (! $user instanceof User) { abort(403); } try { app(TenantReviewLifecycleService::class)->publish($this->record, $user); } catch (\Throwable $throwable) { Notification::make()->danger()->title('Unable to publish review')->body($throwable->getMessage())->send(); return; } $this->refreshFormData(['status', 'published_at', 'published_by_user_id', 'summary']); Notification::make()->success()->title('Review published')->send(); }), ) ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) ->preserveVisibility() ->apply(); } private function exportExecutivePackAction(): Actions\Action { return UiEnforcement::forAction( Actions\Action::make('export_executive_pack') ->label('Export executive pack') ->icon('heroicon-o-arrow-down-tray') ->color('primary') ->hidden(fn (): bool => ! in_array((string) $this->record->status, [ TenantReviewStatus::Ready->value, TenantReviewStatus::Published->value, ], true)) ->action(fn (): mixed => TenantReviewResource::executeExport($this->record)), ) ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) ->preserveVisibility() ->apply(); } private function createNextReviewAction(): Actions\Action { return UiEnforcement::forAction( Actions\Action::make('create_next_review') ->label('Create next review') ->icon('heroicon-o-document-duplicate') ->hidden(fn (): bool => ! $this->record->isPublished()) ->action(function (): void { $user = auth()->user(); if (! $user instanceof User) { abort(403); } try { $nextReview = app(TenantReviewLifecycleService::class)->createNextReview($this->record, $user); } catch (\Throwable $throwable) { Notification::make()->danger()->title('Unable to create next review')->body($throwable->getMessage())->send(); return; } $this->redirect(TenantReviewResource::tenantScopedUrl('view', ['record' => $nextReview], $nextReview->tenant)); }), ) ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) ->preserveVisibility() ->apply(); } private function archiveReviewAction(): Actions\Action { return UiEnforcement::forAction( Actions\Action::make('archive_review') ->label('Archive review') ->icon('heroicon-o-archive-box') ->color('danger') ->hidden(fn (): bool => $this->record->statusEnum()->isTerminal()) ->requiresConfirmation() ->action(function (): void { $user = auth()->user(); if (! $user instanceof User) { abort(403); } app(TenantReviewLifecycleService::class)->archive($this->record, $user); $this->refreshFormData(['status', 'archived_at']); Notification::make()->success()->title('Review archived')->send(); }), ) ->requireCapability(Capabilities::TENANT_REVIEW_MANAGE) ->preserveVisibility() ->apply(); } }