fix: Filament v5 callbacks $r → $record (Plans/Subs/SuperAdmins/Companies)
+ central PWA: real PNG icons, SW registration, scope=/
- All `fn ($r) =>` and `fn (Type $r) =>` replaced with $record (Filament v5
injects callback params by name; $r resolved to nothing)
- /pwa/admin-{192,512}.png — generated on-the-fly with GD + DejaVuSans-Bold
- /pwa/admin-icon.svg — vector favicon
- /admin-sw.js — service worker (cache shell, network-first elsewhere)
with Service-Worker-Allowed: / header
- Manifest scope=/ + start_url=/admin → install prompt fires on Chrome/Edge/Safari
- BODY_END render hook registers SW on central panel
This commit is contained in:
@@ -110,7 +110,7 @@ class CompanyResource extends Resource
|
||||
Tables\Columns\TextColumn::make('slug')
|
||||
->searchable()
|
||||
->copyable()
|
||||
->url(fn (Company $r) => $r->url('/app'))
|
||||
->url(fn (Company $record) => $record->url('/app'))
|
||||
->openUrlInNewTab(),
|
||||
Tables\Columns\TextColumn::make('name')->searchable()->sortable(),
|
||||
Tables\Columns\TextColumn::make('status')
|
||||
@@ -132,30 +132,30 @@ class CompanyResource extends Resource
|
||||
'suspended' => 'Suspendat', 'archived' => 'Arhivat',
|
||||
]),
|
||||
])
|
||||
->recordUrl(fn (Company $r) => CompanyResource::getUrl('view', ['record' => $r]))
|
||||
->recordUrl(fn (Company $record) => CompanyResource::getUrl('view', ['record' => $record]))
|
||||
->actions([
|
||||
Actions\ViewAction::make()
|
||||
->url(fn (Company $r) => CompanyResource::getUrl('view', ['record' => $r])),
|
||||
->url(fn (Company $record) => CompanyResource::getUrl('view', ['record' => $record])),
|
||||
Actions\Action::make('open_tenant')
|
||||
->label('Deschide')
|
||||
->icon('heroicon-m-arrow-top-right-on-square')
|
||||
->color('primary')
|
||||
->url(fn (Company $r) => $r->url('/app'))
|
||||
->url(fn (Company $record) => $record->url('/app'))
|
||||
->openUrlInNewTab(),
|
||||
Actions\Action::make('suspend')
|
||||
->label('Suspendă')
|
||||
->icon('heroicon-m-no-symbol')
|
||||
->color('danger')
|
||||
->visible(fn (Company $r) => in_array($r->status, ['active', 'trial']))
|
||||
->visible(fn (Company $record) => in_array($record->status, ['active', 'trial']))
|
||||
->requiresConfirmation()
|
||||
->action(fn (Company $r) => app(\App\Services\CompanyProvisioner::class)->suspend($r)),
|
||||
->action(fn (Company $record) => app(\App\Services\CompanyProvisioner::class)->suspend($record)),
|
||||
Actions\Action::make('activate')
|
||||
->label('Activează')
|
||||
->icon('heroicon-m-check-circle')
|
||||
->color('success')
|
||||
->visible(fn (Company $r) => in_array($r->status, ['suspended', 'expired']))
|
||||
->visible(fn (Company $record) => in_array($record->status, ['suspended', 'expired']))
|
||||
->requiresConfirmation()
|
||||
->action(fn (Company $r) => app(\App\Services\CompanyProvisioner::class)->reactivate($r)),
|
||||
->action(fn (Company $record) => app(\App\Services\CompanyProvisioner::class)->reactivate($record)),
|
||||
Actions\EditAction::make(),
|
||||
Actions\DeleteAction::make(),
|
||||
])
|
||||
|
||||
@@ -88,11 +88,11 @@ class PlanResource extends Resource
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')->searchable()->sortable(),
|
||||
Tables\Columns\TextColumn::make('price_monthly')
|
||||
->money(fn ($r) => $r->currency)
|
||||
->money(fn ($record) => $record->currency)
|
||||
->label('Lunar')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('price_yearly')
|
||||
->money(fn ($r) => $r->currency)
|
||||
->money(fn ($record) => $record->currency)
|
||||
->label('Anual'),
|
||||
Tables\Columns\TextColumn::make('companies_count')
|
||||
->counts('companies')
|
||||
|
||||
@@ -109,19 +109,19 @@ class SubscriptionResource extends Resource
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('invoice_number')
|
||||
->label('Factură')
|
||||
->placeholder(fn ($r) => '—')
|
||||
->placeholder(fn ($record) => '—')
|
||||
->copyable()
|
||||
->searchable(),
|
||||
Tables\Columns\TextColumn::make('company.name')
|
||||
->label('Companie')
|
||||
->searchable()
|
||||
->url(fn ($r) => \App\Filament\Central\Resources\CompanyResource::getUrl('view', ['record' => $r->company_id])),
|
||||
->url(fn ($record) => \App\Filament\Central\Resources\CompanyResource::getUrl('view', ['record' => $record->company_id])),
|
||||
Tables\Columns\TextColumn::make('plan.name')->label('Plan')->placeholder('—'),
|
||||
Tables\Columns\TextColumn::make('period')
|
||||
->formatStateUsing(fn ($s) => Subscription::PERIODS[$s] ?? $s)
|
||||
->badge(),
|
||||
Tables\Columns\TextColumn::make('amount')
|
||||
->money(fn ($r) => $r->currency)
|
||||
->money(fn ($record) => $record->currency)
|
||||
->sortable()
|
||||
->weight('bold'),
|
||||
Tables\Columns\TextColumn::make('status')
|
||||
@@ -146,16 +146,16 @@ class SubscriptionResource extends Resource
|
||||
->label('Marchează plătit')
|
||||
->icon('heroicon-m-check-circle')
|
||||
->color('success')
|
||||
->visible(fn ($r) => $r->status !== 'paid')
|
||||
->visible(fn ($record) => $record->status !== 'paid')
|
||||
->requiresConfirmation()
|
||||
->action(function (Subscription $r) {
|
||||
$r->update(['status' => 'paid', 'paid_at' => now()]);
|
||||
->action(function (Subscription $record) {
|
||||
$record->update(['status' => 'paid', 'paid_at' => now()]);
|
||||
// Auto-extend company subscription
|
||||
$r->company->update([
|
||||
$record->company->update([
|
||||
'status' => 'active',
|
||||
'active_until' => $r->period_end,
|
||||
'active_until' => $record->period_end,
|
||||
]);
|
||||
Notification::make()->title('Plată confirmată. Abonament extins până la ' . $r->period_end->format('d.m.Y'))->success()->send();
|
||||
Notification::make()->title('Plată confirmată. Abonament extins până la ' . $record->period_end->format('d.m.Y'))->success()->send();
|
||||
}),
|
||||
Actions\EditAction::make(),
|
||||
Actions\DeleteAction::make(),
|
||||
|
||||
@@ -93,7 +93,7 @@ class SuperAdminResource extends Resource
|
||||
Tables\Columns\IconColumn::make('app_authentication_secret')
|
||||
->label('2FA')
|
||||
->boolean()
|
||||
->getStateUsing(fn ($r) => $r->app_authentication_secret !== null)
|
||||
->getStateUsing(fn ($record) => $record?->app_authentication_secret !== null)
|
||||
->trueIcon('heroicon-o-lock-closed')
|
||||
->falseIcon('heroicon-o-lock-open')
|
||||
->trueColor('success')
|
||||
@@ -114,18 +114,18 @@ class SuperAdminResource extends Resource
|
||||
Forms\Components\TextInput::make('new_password')
|
||||
->password()->required()->minLength(8)->revealable(),
|
||||
])
|
||||
->action(function (SuperAdmin $r, array $data) {
|
||||
$r->update(['password' => Hash::make($data['new_password'])]);
|
||||
->action(function (SuperAdmin $record, array $data) {
|
||||
$record->update(['password' => Hash::make($data['new_password'])]);
|
||||
Notification::make()->title('Parolă resetată.')->success()->send();
|
||||
}),
|
||||
Actions\Action::make('toggle_2fa')
|
||||
->label(fn ($r) => $r->app_authentication_secret ? 'Dezactivează 2FA' : 'Forțează re-setare 2FA')
|
||||
->label(fn (SuperAdmin $record) => $record->app_authentication_secret ? 'Dezactivează 2FA' : 'Forțează re-setare 2FA')
|
||||
->icon('heroicon-m-lock-open')
|
||||
->color('danger')
|
||||
->visible(fn ($r) => $r->app_authentication_secret !== null)
|
||||
->visible(fn (SuperAdmin $record) => $record->app_authentication_secret !== null)
|
||||
->requiresConfirmation()
|
||||
->action(function (SuperAdmin $r) {
|
||||
$r->forceFill([
|
||||
->action(function (SuperAdmin $record) {
|
||||
$record->forceFill([
|
||||
'app_authentication_secret' => null,
|
||||
'app_authentication_recovery_codes' => null,
|
||||
'email_authentication_at' => null,
|
||||
@@ -134,8 +134,8 @@ class SuperAdminResource extends Resource
|
||||
}),
|
||||
Actions\EditAction::make(),
|
||||
Actions\DeleteAction::make()
|
||||
->before(function (SuperAdmin $r) {
|
||||
if (auth('central')->id() === $r->id) {
|
||||
->before(function (SuperAdmin $record) {
|
||||
if (auth('central')->id() === $record->id) {
|
||||
Notification::make()->title('Nu te poți șterge pe tine!')->danger()->send();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,10 +29,10 @@ class PendingPayments extends BaseWidget
|
||||
Tables\Columns\TextColumn::make('invoice_number')
|
||||
->label('Factură')
|
||||
->copyable()
|
||||
->url(fn ($r) => SubscriptionResource::getUrl('edit', ['record' => $r])),
|
||||
->url(fn ($record) => SubscriptionResource::getUrl('edit', ['record' => $record])),
|
||||
Tables\Columns\TextColumn::make('company.name')->label('Companie'),
|
||||
Tables\Columns\TextColumn::make('plan.name')->placeholder('—'),
|
||||
Tables\Columns\TextColumn::make('amount')->money(fn ($r) => $r->currency)->weight('bold'),
|
||||
Tables\Columns\TextColumn::make('amount')->money(fn ($record) => $record->currency)->weight('bold'),
|
||||
Tables\Columns\TextColumn::make('status')
|
||||
->badge()
|
||||
->color(fn ($s) => $s === 'overdue' ? 'danger' : 'warning')
|
||||
@@ -40,7 +40,7 @@ class PendingPayments extends BaseWidget
|
||||
Tables\Columns\TextColumn::make('due_at')
|
||||
->label('Scadent')
|
||||
->dateTime()
|
||||
->color(fn ($r) => $r->due_at && $r->due_at->isPast() ? 'danger' : null),
|
||||
->color(fn ($record) => $record->due_at && $record->due_at->isPast() ? 'danger' : null),
|
||||
])
|
||||
->emptyStateHeading('🎉 Toate facturile sunt plătite')
|
||||
->paginated(false);
|
||||
|
||||
@@ -22,7 +22,7 @@ class RecentTenants extends BaseWidget
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('slug')
|
||||
->copyable()
|
||||
->url(fn (Company $r) => CompanyResource::getUrl('view', ['record' => $r])),
|
||||
->url(fn (Company $record) => CompanyResource::getUrl('view', ['record' => $record])),
|
||||
Tables\Columns\TextColumn::make('name')->weight('bold'),
|
||||
Tables\Columns\TextColumn::make('status')
|
||||
->badge()
|
||||
|
||||
Reference in New Issue
Block a user