.service.mir.md.
* ResolveTenant middleware loads the current Company before any auth check.
*/
class TenantPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->id('tenant')
->path('app')
->login()
->brandName(fn () => app(\App\Tenancy\TenantManager::class)->current()?->display_name
?? app(\App\Tenancy\TenantManager::class)->current()?->name
?? 'AutoCRM')
->brandLogo(function () {
$t = app(\App\Tenancy\TenantManager::class)->current();
if (! $t) return null;
$logo = $t->getLogoUrl();
$name = e($t->display_name ?? $t->name ?? 'AutoCRM');
if ($logo) {
return new \Illuminate\Support\HtmlString(
'
'
. '
 . ')
'
. '
' . $name . ''
. '
'
);
}
return null;
})
->brandLogoHeight('2.5rem')
->favicon(fn () => app(\App\Tenancy\TenantManager::class)->current()?->getFaviconUrl()
?: app(\App\Tenancy\TenantManager::class)->current()?->getLogoUrl()
?: null)
->colors([
'primary' => Color::Blue,
])
->authGuard('web')
->databaseNotifications()
->databaseNotificationsPolling('30s')
->globalSearch()
->globalSearchKeyBindings(['mod+k'])
->globalSearchFieldKeyBindingSuffix()
->globalSearchDebounce('500ms')
->multiFactorAuthentication([
\Filament\Auth\MultiFactor\App\AppAuthentication::make(),
\Filament\Auth\MultiFactor\Email\EmailAuthentication::make(),
])
->profile()
->discoverResources(in: app_path('Filament/Tenant/Resources'), for: 'App\\Filament\\Tenant\\Resources')
->discoverPages(in: app_path('Filament/Tenant/Pages'), for: 'App\\Filament\\Tenant\\Pages')
->pages([
Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Tenant/Widgets'), for: 'App\\Filament\\Tenant\\Widgets')
->widgets([
\App\Filament\Tenant\Widgets\StatsOverview::class,
\App\Filament\Tenant\Widgets\FinanceOverview::class,
\App\Filament\Tenant\Widgets\LowStockTable::class,
])
->middleware([
// CRITICAL: tenant resolution must run BEFORE Filament's
// Authenticate middleware (which is inserted by authMiddleware
// between ShareErrorsFromSession and AuthenticateSession).
// Otherwise User::find() during auth check has no tenant
// context → TenantScope returns 0 rows → user appears
// unauthenticated → endless redirect to /app/login.
ResolveTenant::class,
CheckTenantStatus::class,
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
\App\Http\Middleware\SetLocale::class,
\App\Http\Middleware\RequireOnboarding::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
])
// PWA + theming injection
->renderHook(
PanelsRenderHook::HEAD_END,
fn (): string => Blade::render(<<<'BLADE'
@php
$t = app(\App\Tenancy\TenantManager::class)->current();
$themeColor = $t?->settings['theme_color'] ?? '#3B82F6';
$name = $t?->display_name ?? $t?->name ?? 'AutoCRM';
// Generate primary color shades from theme_color hex.
$hex = ltrim($themeColor, '#');
if (strlen($hex) === 6) {
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
} else { $r = 59; $g = 130; $b = 246; }
@endphp
BLADE)
)
->userMenuItems([
'billing' => \Filament\Navigation\MenuItem::make()
->label('Facturile mele')
->icon('heroicon-o-credit-card')
->url('/billing')
->openUrlInNewTab(false),
])
->renderHook(
PanelsRenderHook::USER_MENU_BEFORE,
fn (): string => Blade::render(<<<'BLADE'
@php
$locale = app()->getLocale();
$langs = ['ro' => 'RO', 'ru' => 'RU', 'en' => 'EN'];
$csrf = csrf_token();
@endphp
BLADE)
)
->renderHook(
PanelsRenderHook::BODY_END,
fn (): string => Blade::render(<<<'BLADE'
@php
$tenant = app(\App\Tenancy\TenantManager::class)->current();
$reverbKey = config('broadcasting.connections.reverb.key');
$reverbHost = config('broadcasting.connections.reverb.options.host');
$reverbPort = config('broadcasting.connections.reverb.options.port');
$reverbScheme = config('broadcasting.connections.reverb.options.scheme', 'https');
$broadcastEnabled = config('broadcasting.default') === 'reverb' && $reverbKey && $reverbHost;
$vapidPublic = config('webpush.vapid.public_key');
$csrf = csrf_token();
@endphp
@if ($broadcastEnabled && $tenant)
@endif
BLADE)
);
}
}