.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(fn () => app(\App\Tenancy\TenantManager::class)->current()?->getLogoUrl() ?: 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') ->globalSearchKeyBindings(['command+k', 'ctrl+k']) ->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