Absolutely! Here’s a step-by-step solution for implementing a Company Switcher for super admins in Filament v3, including all the code you need.
1. Livewire Component: CompanySwitcher
Create a Livewire component to handle the dropdown and session logic.
Generate the component:
php artisan make:livewire CompanySwitcher
app/Http/Livewire/CompanySwitcher.php
namespace App\Http\Livewire;
use Livewire\Component;
use Illuminate\Support\Facades\Session;
use App\Models\Company;
class CompanySwitcher extends Component
{
public $selectedCompany;
public function mount()
{
$this->selectedCompany = session('filament_company_id', 'all');
}
public function updatedSelectedCompany($value)
{
if ($value === 'all') {
session()->forget('filament_company_id');
} else {
session(['filament_company_id' => $value]);
}
// Optionally, you can emit an event or just reload the page
return redirect(request()->header('Referer') ?? '/admin');
}
public function render()
{
return view('livewire.company-switcher', [
'companies' => Company::orderBy('name')->get(),
]);
}
}
2. Blade View for the Component
resources/views/livewire/company-switcher.blade.php
<div>
<form wire:submit.prevent>
<select wire:model="selectedCompany" wire:change="updatedSelectedCompany($event.target.value)" class="filament-dropdown">
<option value="all">All Companies</option>
@foreach($companies as $company)
<option value="{{ $company->id }}">{{ $company->name }}</option>
@endforeach
</select>
</form>
</div>
Style the select as you wish, or use Filament's classes.
3. Add the Switcher to Filament’s Topbar
Use Filament’s Render Hook to inject the component into the navigation bar.
In your Filament Panel Provider (e.g., app/Providers/Filament/AdminPanelProvider.php):
use Filament\Panel;
use Filament\Navigation\NavigationBuilder;
public function panel(Panel $panel): Panel
{
return $panel
// ... other config
->renderHook(
'panels::topbar.start',
fn () => auth()->user()?->is_super_admin
? view('filament.components.company-switcher')
: ''
);
}
Create the Blade file to render the Livewire component:
resources/views/filament/components/company-switcher.blade.php
@livewire('company-switcher')
4. Update the CompanyScope
app/Scopes/CompanyScope.php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class CompanyScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$user = auth()->user();
if (!$user) {
return;
}
// Regular users: always filter by their company_id
if (! $user->is_super_admin) {
$builder->where($model->qualifyColumn('company_id'), $user->company_id);
return;
}
// Super admin: check for session filter
$companyId = session('filament_company_id');
if ($companyId) {
$builder->where($model->qualifyColumn('company_id'), $companyId);
}
// else: no filter, see all companies
}
}
5. Apply the Scope to Your Models
In each model (e.g., Product, Invoice, etc.):
protected static function booted()
{
static::addGlobalScope(new \App\Scopes\CompanyScope);
}
6. (Optional) Clear Session on Logout
To avoid session leaks, clear the filter on logout. In your Logout logic:
session()->forget('filament_company_id');
Summary
- Livewire component handles the dropdown and session.
- Render hook injects the switcher for super admins.
- CompanyScope checks the session for the filter.
- Dropdown lists all companies and "All Companies".
- Session persists the filter across navigation.
This approach is clean, leverages Filament’s extensibility, and keeps your authorization logic centralized.
Let me know if you need further clarification!