TenantAtlas/apps/platform/resources/views/filament/partials/context-bar.blade.php
Ahmed Darrazi d51df2800b
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 56s
feat: implement platform localization v1
2026-04-28 21:27:22 +02:00

229 lines
13 KiB
PHP

@php
use App\Filament\Pages\ChooseTenant;
use App\Filament\Pages\ChooseWorkspace;
use App\Models\Tenant;
use App\Models\User;
use App\Support\OperateHub\OperateHubShell;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
/** @var WorkspaceContext $workspaceContext */
$workspaceContext = app(WorkspaceContext::class);
$resolvedContext = app(OperateHubShell::class)->resolvedContext(request());
$workspace = $resolvedContext->workspace;
$user = auth()->user();
$tenants = collect();
if ($user instanceof User && $workspace) {
$tenants = collect($user->getTenants(Filament::getCurrentOrDefaultPanel()))
->filter(fn ($tenant): bool => $tenant instanceof Tenant && (int) $tenant->workspace_id === (int) $workspace->getKey())
->values();
}
$currentTenant = $resolvedContext->tenant;
$currentTenantId = $currentTenant instanceof Tenant ? (int) $currentTenant->getKey() : null;
$currentTenantName = $currentTenant instanceof Tenant ? $currentTenant->getFilamentName() : null;
$lastTenantId = $workspaceContext->lastTenantId(request());
$canClearTenantContext = $currentTenant instanceof Tenant || $lastTenantId !== null;
@endphp
@php
$tenantLabel = $currentTenantName ?? __('localization.shell.no_tenant_selected');
$workspaceLabel = $workspace?->name ?? __('localization.shell.choose_workspace');
$hasActiveTenant = $currentTenantName !== null;
$managedTenantsUrl = $workspace
? route('admin.workspace.managed-tenants.index', ['workspace' => $workspace])
: route('admin.onboarding');
$workspaceUrl = $workspace
? route('admin.home')
: ChooseWorkspace::getUrl(panel: 'admin');
$tenantTriggerLabel = $workspace ? $tenantLabel : __('localization.shell.choose_workspace');
$localePlane = Filament::getCurrentPanel()?->getId() === 'tenant' ? 'tenant' : 'admin';
@endphp
<div class="inline-flex items-center gap-0 rounded-lg border border-gray-200 bg-white text-sm dark:border-white/10 dark:bg-white/5">
{{-- Workspace label: standalone link --}}
<a
href="{{ $workspaceUrl }}"
wire:navigate
class="inline-flex items-center gap-1.5 rounded-l-lg px-2.5 py-1.5 font-medium text-gray-700 transition hover:bg-gray-50 hover:text-primary-600 dark:text-gray-200 dark:hover:bg-white/10 dark:hover:text-primary-400"
>
<x-filament::icon icon="heroicon-o-squares-2x2" class="h-4 w-4 text-gray-400 dark:text-gray-500" />
{{ $workspaceLabel }}
</a>
@if ($workspace)
<x-filament::icon icon="heroicon-m-chevron-right" class="h-3 w-3 shrink-0 text-gray-300 dark:text-gray-600" />
@endif
{{-- Dropdown trigger: tenant label + chevron --}}
<x-filament::dropdown placement="bottom-start" teleport width="xs">
<x-slot name="trigger">
<button
type="button"
aria-label="{{ $workspace ? __('localization.shell.tenant_scope') : __('localization.shell.select_tenant') }}"
class="inline-flex items-center gap-1.5 rounded-r-lg px-2 py-1.5 transition hover:bg-gray-50 dark:hover:bg-white/10"
>
<span class="{{ $workspace && $hasActiveTenant ? 'font-medium text-primary-600 dark:text-primary-400' : 'text-gray-500 dark:text-gray-400' }}">
{{ $tenantTriggerLabel }}
</span>
<x-filament::icon icon="heroicon-m-chevron-down" class="h-3.5 w-3.5 text-gray-400 dark:text-gray-500" />
</button>
</x-slot>
<x-filament::dropdown.list>
<div class="space-y-3 px-3 py-2" x-data="{ query: '' }">
@if ($resolvedContext->showsRecoveryNotice())
<div class="rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200">
<div class="font-semibold">{{ __('localization.shell.context_unavailable') }}</div>
@if ($workspace)
<div>{{ __('localization.shell.context_unavailable_workspace') }}</div>
@else
<div>{{ __('localization.shell.context_unavailable_no_workspace') }}</div>
@endif
</div>
@endif
{{-- Workspace section --}}
<div class="space-y-1">
<div class="text-xs font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
{{ __('localization.shell.workspace') }}
</div>
<div class="flex items-center justify-between rounded-lg bg-gray-50 px-3 py-2 dark:bg-white/5">
<div class="flex items-center gap-2">
<x-filament::icon icon="heroicon-o-squares-2x2" class="h-4 w-4 text-gray-500 dark:text-gray-400" />
<span class="text-sm font-medium text-gray-950 dark:text-white">{{ $workspaceLabel }}</span>
</div>
<a
href="{{ ChooseWorkspace::getUrl(panel: 'admin').'?choose=1' }}"
class="text-xs font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300"
>
{{ __('localization.shell.switch_workspace') }}
</a>
</div>
<a
href="{{ route('admin.home') }}"
class="flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-gray-700 transition hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-white/5"
>
<x-filament::icon icon="heroicon-o-home" class="h-4 w-4 text-gray-400 dark:text-gray-500" />
{{ __('localization.shell.workspace_home') }}
</a>
</div>
@if ($workspace)
<div class="border-t border-gray-200 dark:border-white/10"></div>
{{-- Tenant section --}}
<div class="space-y-2">
<div class="flex items-center justify-between">
<div class="text-xs font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
{{ __('localization.shell.selected_tenant') }}
</div>
</div>
@if ($resolvedContext->pageCategory->requiresExplicitTenant() && $hasActiveTenant)
<div class="space-y-2">
<div class="flex items-center gap-2 rounded-lg bg-primary-50 px-3 py-2 dark:bg-primary-950/30">
<x-filament::icon icon="heroicon-o-building-office-2" class="h-4 w-4 text-primary-600 dark:text-primary-400" />
<span class="text-sm font-medium text-primary-700 dark:text-primary-300">{{ $currentTenantName }}</span>
<a
href="{{ ChooseTenant::getUrl(panel: 'admin') }}"
class="ml-auto text-xs font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300"
>
{{ __('localization.shell.switch_tenant') }}
</a>
</div>
@if ($canClearTenantContext)
<form method="POST" action="{{ route('admin.clear-tenant-context') }}">
@csrf
<button type="submit" class="w-full rounded-lg px-3 py-1.5 text-left text-xs font-medium text-gray-500 transition hover:bg-gray-50 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-200">
{{ __('localization.shell.clear_tenant_scope') }}
</button>
</form>
@endif
</div>
@else
@if ($tenants->isEmpty())
<div class="space-y-2 rounded-lg border border-dashed border-gray-300 px-3 py-3 text-center text-xs text-gray-500 dark:border-gray-600 dark:text-gray-400">
<div>{{ __('localization.shell.no_active_tenants') }}</div>
<a href="{{ $managedTenantsUrl }}" class="inline-flex items-center gap-1 text-primary-600 hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300">
<x-filament::icon icon="heroicon-o-arrow-top-right-on-square" class="h-3.5 w-3.5" />
{{ __('localization.shell.view_managed_tenants') }}
</a>
</div>
@else
@if (! $hasActiveTenant)
<div class="rounded-lg bg-gray-50 px-3 py-2 text-xs text-gray-600 dark:bg-white/5 dark:text-gray-400">
{{ __('localization.shell.workspace_wide_available') }}
</div>
@endif
<input
type="text"
class="fi-input fi-text-input w-full"
placeholder="{{ __('localization.shell.search_tenants') }}"
x-model="query"
/>
<div class="max-h-48 overflow-auto rounded-lg border border-gray-200 dark:border-gray-700">
@foreach ($tenants as $tenant)
@php
$isActive = $currentTenantId !== null && (int) $tenant->getKey() === $currentTenantId;
@endphp
<form method="POST" action="{{ route('admin.select-tenant') }}">
@csrf
<input type="hidden" name="tenant_id" value="{{ (int) $tenant->getKey() }}" />
<button
type="submit"
class="flex w-full items-center gap-2 px-3 py-2 text-left text-sm transition {{ $isActive ? 'bg-primary-50 font-medium text-primary-700 dark:bg-primary-950/30 dark:text-primary-300' : 'text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-white/5' }}"
data-search="{{ (string) str($tenant->getFilamentName())->lower() }}"
x-show="query === '' || ($el.dataset.search ?? '').includes(query.toLowerCase())"
>
@if ($isActive)
<x-filament::icon icon="heroicon-s-check-circle" class="h-4 w-4 shrink-0 text-primary-600 dark:text-primary-400" />
@else
<x-filament::icon icon="heroicon-o-building-office-2" class="h-4 w-4 shrink-0 text-gray-400 dark:text-gray-500" />
@endif
{{ $tenant->getFilamentName() }}
</button>
</form>
@endforeach
</div>
@if ($canClearTenantContext)
<form method="POST" action="{{ route('admin.clear-tenant-context') }}">
@csrf
<button type="submit" class="w-full rounded-lg px-3 py-1.5 text-left text-xs font-medium text-gray-500 transition hover:bg-gray-50 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-200">
{{ __('localization.shell.clear_tenant_scope') }}
</button>
</form>
@endif
@endif
@endif
</div>
@else
<div class="rounded-lg border border-dashed border-gray-300 px-3 py-3 text-center text-xs text-gray-500 dark:border-gray-600 dark:text-gray-400">
{{ __('localization.shell.choose_workspace_first') }}
</div>
@endif
</div>
</x-filament::dropdown.list>
</x-filament::dropdown>
@include('filament.partials.locale-switcher', ['plane' => $localePlane, 'showPreference' => true, 'embedded' => true])
</div>