TenantAtlas/apps/platform/resources/views/filament/widgets/tenant/tenant-review-pack-card.blade.php
ahmido 7ee4909212
Some checks failed
Main Confidence / confidence (push) Failing after 1m45s
feat: commercial lifecycle overlay for workspace entitlements (#292)
## Summary
- add the bounded workspace commercial lifecycle overlay from spec 251 on top of the existing entitlement substrate
- expose audited commercial state inspection and mutation on the system workspace detail surface
- gate onboarding activation and review-pack start actions through the shared lifecycle decision while preserving suspended read-only access to existing review, evidence, and generated-pack history
- add focused Pest coverage plus the spec/plan/tasks/data-model/contract artifacts for the feature

## Validation
- targeted Pest unit and feature lanes for lifecycle resolution, system-plane mutation, onboarding gating, review-pack enforcement, download preservation, customer review workspace access, and evidence snapshot access
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- integrated browser smoke on the system workspace detail and the preserved read-only review/evidence/review-pack surfaces

## Notes
- branch: `251-commercial-entitlements-billing-state`
- base: `dev`
- commit: `606e9760`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #292
2026-04-28 13:39:33 +00:00

241 lines
9.3 KiB
PHP

@php
use App\Support\Badges\BadgeCatalog;
use App\Support\Badges\BadgeDomain;
use App\Support\ReviewPackStatus;
/** @var ?\App\Models\Tenant $tenant */
/** @var ?\App\Models\ReviewPack $pack */
/** @var ?ReviewPackStatus $statusEnum */
/** @var ?string $pollingInterval */
/** @var bool $canView */
/** @var bool $canManage */
/** @var bool $generationBlocked */
/** @var ?string $generationBlockReason */
/** @var ?string $generationWarningReason */
/** @var ?string $customerWorkspaceUrl */
/** @var ?string $downloadUrl */
/** @var ?string $failedReason */
/** @var ?string $failedReasonDetail */
/** @var ?array<string, mixed> $failedReasonSemantics */
/** @var ?string $reviewUrl */
$badgeSpec = $statusEnum ? BadgeCatalog::spec(BadgeDomain::ReviewPackStatus, $statusEnum->value) : null;
@endphp
<div
@if ($pollingInterval)
wire:poll.{{ $pollingInterval }}
@endif
>
<x-filament::section heading="Review Pack">
@if ($canManage && $generationBlocked && $generationBlockReason)
<div class="mb-3 rounded-lg border border-warning-200 bg-warning-50 px-3 py-2 text-sm text-warning-800 dark:border-warning-500/30 dark:bg-warning-500/10 dark:text-warning-200">
{{ $generationBlockReason }}
</div>
@endif
@if ($canManage && ! $generationBlocked && $generationWarningReason)
<div class="mb-3 rounded-lg border border-warning-200 bg-warning-50 px-3 py-2 text-sm text-warning-800 dark:border-warning-500/30 dark:bg-warning-500/10 dark:text-warning-200">
{{ $generationWarningReason }}
</div>
@endif
@if (! $pack)
{{-- State 1: No pack --}}
<div class="flex flex-col items-center gap-3 py-4 text-center">
<x-heroicon-o-document-arrow-down class="h-8 w-8 text-gray-400 dark:text-gray-500" />
<div class="text-sm text-gray-500 dark:text-gray-400">
No review pack generated yet.
</div>
@if ($canManage)
<x-filament::button
size="sm"
wire:click="generatePack"
wire:loading.attr="disabled"
:disabled="$generationBlocked"
>
Generate pack
</x-filament::button>
@endif
</div>
@endif
@if ($pack && ($statusEnum === ReviewPackStatus::Queued || $statusEnum === ReviewPackStatus::Generating))
{{-- State 2: Queued / Generating --}}
<div class="flex flex-col gap-3">
<div class="flex items-center gap-2">
<x-filament::badge
:color="$badgeSpec?->color"
:icon="$badgeSpec?->icon"
>
{{ $badgeSpec?->label ?? '—' }}
</x-filament::badge>
</div>
<div class="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
<x-filament::loading-indicator class="h-4 w-4" />
Generation in progress&hellip;
</div>
<div class="text-xs text-gray-400 dark:text-gray-500">
Started {{ $pack->created_at?->diffForHumans() ?? '—' }}
</div>
</div>
@endif
@if ($pack && $statusEnum === ReviewPackStatus::Ready)
{{-- State 3: Ready --}}
<div class="flex flex-col gap-3">
<div class="flex items-center gap-2">
<x-filament::badge
:color="$badgeSpec?->color"
:icon="$badgeSpec?->icon"
>
{{ $badgeSpec?->label ?? '—' }}
</x-filament::badge>
</div>
<dl class="grid grid-cols-2 gap-x-4 gap-y-1 text-sm">
<dt class="text-gray-500 dark:text-gray-400">Generated</dt>
<dd>{{ $pack->generated_at?->format('M j, Y H:i') ?? '—' }}</dd>
<dt class="text-gray-500 dark:text-gray-400">Expires</dt>
<dd>{{ $pack->expires_at?->format('M j, Y') ?? '—' }}</dd>
<dt class="text-gray-500 dark:text-gray-400">Size</dt>
<dd>{{ $pack->file_size ? Number::fileSize($pack->file_size) : '—' }}</dd>
</dl>
<div class="flex items-center gap-2">
@if ($canView && $downloadUrl)
<x-filament::button
size="sm"
tag="a"
:href="$downloadUrl"
target="_blank"
icon="heroicon-o-arrow-down-tray"
>
Download
</x-filament::button>
@endif
@if ($canView && $reviewUrl)
<x-filament::button
size="sm"
color="gray"
tag="a"
:href="$reviewUrl"
>
View review
</x-filament::button>
@endif
@if ($canManage)
<x-filament::button
size="sm"
color="gray"
wire:click="generatePack"
wire:loading.attr="disabled"
:disabled="$generationBlocked"
>
Generate new
</x-filament::button>
@endif
</div>
</div>
@endif
@if ($pack && $statusEnum === ReviewPackStatus::Failed)
{{-- State 4: Failed --}}
<div class="flex flex-col gap-3">
<div class="flex items-center gap-2">
<x-filament::badge
:color="$badgeSpec?->color"
:icon="$badgeSpec?->icon"
>
{{ $badgeSpec?->label ?? '—' }}
</x-filament::badge>
</div>
@if ($failedReason)
<div class="text-sm font-medium text-danger-600 dark:text-danger-400">
{{ $failedReason }}
</div>
@endif
@if ($failedReasonDetail)
<div class="text-xs text-gray-500 dark:text-gray-400">
{{ $failedReasonDetail }}
</div>
@endif
@if (is_array($failedReasonSemantics ?? null))
<div class="text-xs text-gray-500 dark:text-gray-400">
Reason owner: {{ $failedReasonSemantics['owner_label'] ?? 'Platform core' }}
&middot;
Platform reason family: {{ $failedReasonSemantics['family_label'] ?? 'Compatibility' }}
</div>
@endif
<div class="text-xs text-gray-400 dark:text-gray-500">
{{ $pack->updated_at?->diffForHumans() ?? '—' }}
</div>
@if ($canManage)
<x-filament::button
size="sm"
wire:click="generatePack"
wire:loading.attr="disabled"
:disabled="$generationBlocked"
>
Retry
</x-filament::button>
@endif
</div>
@endif
@if ($pack && $statusEnum === ReviewPackStatus::Expired)
{{-- State 5: Expired --}}
<div class="flex flex-col gap-3">
<div class="flex items-center gap-2">
<x-filament::badge
:color="$badgeSpec?->color"
:icon="$badgeSpec?->icon"
>
{{ $badgeSpec?->label ?? '—' }}
</x-filament::badge>
</div>
<div class="text-sm text-gray-500 dark:text-gray-400">
Expired {{ $pack->expires_at?->diffForHumans() ?? '—' }}
</div>
@if ($canManage)
<x-filament::button
size="sm"
wire:click="generatePack"
wire:loading.attr="disabled"
:disabled="$generationBlocked"
>
Generate new
</x-filament::button>
@endif
</div>
@endif
@if ($canView && $customerWorkspaceUrl)
<div class="mt-3 flex items-center gap-2">
<x-filament::button
size="sm"
color="gray"
tag="a"
:href="$customerWorkspaceUrl"
>
Customer workspace
</x-filament::button>
</div>
@endif
</x-filament::section>
</div>