Fix SSE listeners type cast, replace Blade tab component with Alpine.js tabs in DjModeration, use wire:confirm instead of onclick

This commit is contained in:
root
2026-05-24 14:15:44 +02:00
parent 0c6c558a59
commit 261a5e63c6
27 changed files with 142 additions and 136 deletions
File diff suppressed because one or more lines are too long
View File
View File
View File
View File
View File
View File
View File
View File
View File
+1 -1
View File
@@ -134,7 +134,7 @@ class SseController extends Controller
private function getListeners(): int
{
return Cache::remember('radio_listeners', 30, function () {
return (int) Cache::remember('radio_listeners', 30, function () {
$apiUrl = $this->getSetting(RadioSettings::ListenersEnabled)
? ($this->getSetting(RadioSettings::ListenersApiUrl) ?: $this->getAzureCastApiUrl())
: null;
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
View File
View File
+136 -130
View File
@@ -7,145 +7,151 @@ use App\Models\RadioSongRequest;
?>
<x-filament-panels::page>
<x-filament::tabs>
<div x-data="{ tab: 'shouts' }">
<div class="flex gap-1 mb-6 border-b border-gray-200 dark:border-gray-700">
<button @click="tab = 'shouts'" :class="{ 'border-primary-600 text-primary-600': tab === 'shouts', 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300': tab !== 'shouts' }" class="px-4 py-2 text-sm font-medium border-b-2 transition flex items-center gap-2">
<x-filament::icon name="heroicon-o-chat-bubble-oval-left" class="w-4 h-4" />
Shouts
<span class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-medium rounded-full bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400">{{ RadioShout::where('approved', false)->count() }}</span>
</button>
<button @click="tab = 'requests'" :class="{ 'border-primary-600 text-primary-600': tab === 'requests', 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300': tab !== 'requests' }" class="px-4 py-2 text-sm font-medium border-b-2 transition flex items-center gap-2">
<x-filament::icon name="heroicon-o-musical-note" class="w-4 h-4" />
Verzoeken
<span class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-medium rounded-full bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400">{{ RadioSongRequest::where('is_approved', false)->where('is_played', false)->count() }}</span>
</button>
<button @click="tab = 'applications'" :class="{ 'border-primary-600 text-primary-600': tab === 'applications', 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300': tab !== 'applications' }" class="px-4 py-2 text-sm font-medium border-b-2 transition flex items-center gap-2">
<x-filament::icon name="heroicon-o-user-group" class="w-4 h-4" />
Aanmeldingen
<span class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-medium rounded-full bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400">{{ RadioApplication::where('status', 'pending')->count() }}</span>
</button>
</div>
{{-- Shouts Tab --}}
<x-filament::tabs.tab
icon="heroicon-o-chat-bubble-oval-left"
label="Shouts ({{ RadioShout::where('approved', false)->count() }} wachtend, {{ RadioShout::where('reported', true)->count() }} gerapporteerd)"
>
<div class="space-y-4">
@php $pendingShouts = $this->getPendingShouts(); @endphp
@if($pendingShouts->count() > 0)
<h3 class="text-lg font-semibold">Wachtend op goedkeuring</h3>
<div class="space-y-2">
@foreach($pendingShouts as $shout)
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<p class="font-medium text-sm">{{ $shout->user?->username ?? 'Onbekend' }}</p>
<p class="text-sm text-gray-600 dark:text-gray-400 truncate">{{ $shout->message }}</p>
<p class="text-xs text-gray-400 mt-1">{{ $shout->created_at->diffForHumans() }}</p>
</div>
<div class="flex gap-2 shrink-0">
<x-filament::button wire:click="approveShout({{ $shout->id }})" color="success" size="xs" icon="heroicon-o-check">
Goedkeuren
</x-filament::button>
<x-filament::button wire:click="deleteShout({{ $shout->id }})" color="danger" size="xs" icon="heroicon-o-trash" onclick="return confirm('Zeker weten?')">
Verwijderen
</x-filament::button>
</div>
</div>
@endforeach
{{ $pendingShouts->links() }}
</div>
@endif
<div x-show="tab === 'shouts'">
@php $pendingShouts = $this->getPendingShouts(); @endphp
@php $reportedShouts = $this->getReportedShouts(); @endphp
@php $reportedShouts = $this->getReportedShouts(); @endphp
@if($reportedShouts->count() > 0)
<h3 class="text-lg font-semibold mt-6">Gerapporteerde shouts</h3>
<div class="space-y-2">
@foreach($reportedShouts as $shout)
<div class="bg-red-50 dark:bg-red-950 rounded-lg p-4 flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<p class="font-medium text-sm">{{ $shout->user?->username ?? 'Onbekend' }}</p>
<p class="text-sm text-gray-600 dark:text-gray-400 truncate">{{ $shout->message }}</p>
<p class="text-xs text-gray-400 mt-1">{{ $shout->created_at->diffForHumans() }}</p>
</div>
<div class="flex gap-2 shrink-0">
<x-filament::button wire:click="dismissShoutReport({{ $shout->id }})" color="info" size="xs" icon="heroicon-o-flag">
Negeren
</x-filament::button>
<x-filament::button wire:click="deleteShout({{ $shout->id }})" color="danger" size="xs" icon="heroicon-o-trash" onclick="return confirm('Zeker weten?')">
Verwijderen
</x-filament::button>
</div>
@if($pendingShouts->count() > 0)
<h3 class="text-lg font-semibold mb-3">Wachtend op goedkeuring</h3>
<div class="space-y-2 mb-6">
@foreach($pendingShouts as $shout)
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<p class="font-medium text-sm">{{ $shout->user?->username ?? 'Onbekend' }}</p>
<p class="text-sm text-gray-600 dark:text-gray-400 truncate">{{ $shout->message }}</p>
<p class="text-xs text-gray-400 mt-1">{{ $shout->created_at->diffForHumans() }}</p>
</div>
@endforeach
{{ $reportedShouts->links() }}
</div>
@endif
<div class="flex gap-2 shrink-0">
<x-filament::button wire:click="approveShout({{ $shout->id }})" color="success" size="xs" icon="heroicon-o-check">
Goedkeuren
</x-filament::button>
<x-filament::button wire:click="deleteShout({{ $shout->id }})" color="danger" size="xs" icon="heroicon-o-trash" wire:confirm="Zeker weten?">
Verwijderen
</x-filament::button>
</div>
</div>
@endforeach
{{ $pendingShouts->links() }}
</div>
@endif
@if($pendingShouts->count() === 0 && $reportedShouts->count() === 0)
<p class="text-gray-500 text-center py-8">Geen shouts wachtend op moderatie</p>
@endif
</div>
</x-filament::tabs.tab>
@if($reportedShouts->count() > 0)
<h3 class="text-lg font-semibold mb-3">Gerapporteerde shouts</h3>
<div class="space-y-2">
@foreach($reportedShouts as $shout)
<div class="bg-red-50 dark:bg-red-950 rounded-lg p-4 flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<p class="font-medium text-sm">{{ $shout->user?->username ?? 'Onbekend' }}</p>
<p class="text-sm text-gray-600 dark:text-gray-400 truncate">{{ $shout->message }}</p>
<p class="text-xs text-gray-400 mt-1">{{ $shout->created_at->diffForHumans() }}</p>
</div>
<div class="flex gap-2 shrink-0">
<x-filament::button wire:click="dismissShoutReport({{ $shout->id }})" color="info" size="xs" icon="heroicon-o-flag">
Negeren
</x-filament::button>
<x-filament::button wire:click="deleteShout({{ $shout->id }})" color="danger" size="xs" icon="heroicon-o-trash" wire:confirm="Zeker weten?">
Verwijderen
</x-filament::button>
</div>
</div>
@endforeach
{{ $reportedShouts->links() }}
</div>
@endif
@if($pendingShouts->count() === 0 && $reportedShouts->count() === 0)
<p class="text-gray-500 text-center py-8">Geen shouts wachtend op moderatie</p>
@endif
</div>
{{-- Song Requests Tab --}}
<x-filament::tabs.tab
icon="heroicon-o-musical-note"
label="Verzoeken ({{ RadioSongRequest::where('is_approved', false)->where('is_played', false)->count() }} wachtend)"
>
<div class="space-y-4">
@php $requests = $this->getPendingRequests(); @endphp
@if($requests->count() > 0)
<div class="space-y-2">
@foreach($requests as $request)
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<p class="font-medium text-sm">{{ $request->user?->username ?? 'Onbekend' }}</p>
<p class="text-sm font-semibold">{{ $request->song_title }}</p>
<p class="text-sm text-gray-500" x-show="{{ $request->song_artist }}">{{ $request->song_artist }}</p>
<div class="flex items-center gap-3 mt-1">
<span class="text-xs text-gray-400">{{ $request->submitted_at->diffForHumans() }}</span>
<span class="text-xs text-amber-500">{{ $request->votes }} stemmen</span>
</div>
</div>
<div class="flex gap-2 shrink-0">
<x-filament::button wire:click="approveRequest({{ $request->id }})" color="success" size="xs" icon="heroicon-o-check">
Goedkeuren
</x-filament::button>
<x-filament::button wire:click="rejectRequest({{ $request->id }})" color="danger" size="xs" icon="heroicon-o-x-mark" onclick="return confirm('Zeker weten?')">
Afwijzen
</x-filament::button>
<div x-show="tab === 'requests'">
@php $requests = $this->getPendingRequests(); @endphp
@if($requests->count() > 0)
<div class="space-y-2">
@foreach($requests as $request)
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<p class="font-medium text-sm">{{ $request->user?->username ?? 'Onbekend' }}</p>
<p class="text-sm font-semibold">{{ $request->song_title }}</p>
@if($request->song_artist)
<p class="text-sm text-gray-500">{{ $request->song_artist }}</p>
@endif
<div class="flex items-center gap-3 mt-1">
<span class="text-xs text-gray-400">{{ $request->submitted_at->diffForHumans() }}</span>
<span class="text-xs text-amber-500">{{ $request->votes }} stemmen</span>
</div>
</div>
@endforeach
{{ $requests->links() }}
</div>
@else
<p class="text-gray-500 text-center py-8">Geen verzoeken wachtend op goedkeuring</p>
@endif
</div>
</x-filament::tabs.tab>
<div class="flex gap-2 shrink-0">
<x-filament::button wire:click="approveRequest({{ $request->id }})" color="success" size="xs" icon="heroicon-o-check">
Goedkeuren
</x-filament::button>
<x-filament::button wire:click="rejectRequest({{ $request->id }})" color="danger" size="xs" icon="heroicon-o-x-mark" wire:confirm="Zeker weten?">
Afwijzen
</x-filament::button>
</div>
</div>
@endforeach
{{ $requests->links() }}
</div>
@else
<p class="text-gray-500 text-center py-8">Geen verzoeken wachtend op goedkeuring</p>
@endif
</div>
{{-- Applications Tab --}}
<x-filament::tabs.tab
icon="heroicon-o-user-group"
label="Aanmeldingen ({{ RadioApplication::where('status', 'pending')->count() }} wachtend)"
>
<div class="space-y-4">
@php $applications = $this->getPendingApplications(); @endphp
@if($applications->count() > 0)
<div class="space-y-2">
@foreach($applications as $app)
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<p class="font-medium">{{ $app->user?->username ?? 'Onbekend' }}</p>
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ $app->rank?->name ?? 'Geen functie' }} &middot; {{ $app->age }} jaar
</p>
<p class="text-sm mt-2">{{ $app->motivation }}</p>
@if($app->experience)
<p class="text-xs text-gray-400 mt-1">Ervaring: {{ $app->experience }}</p>
@endif
<p class="text-xs text-gray-400 mt-1">{{ $app->created_at->diffForHumans() }}</p>
</div>
<div class="flex gap-2 shrink-0">
<x-filament::button wire:click="approveApplication({{ $app->id }})" color="success" size="xs" icon="heroicon-o-check" onclick="return confirm('Aanmelding goedkeuren?')">
Goedkeuren
</x-filament::button>
<x-filament::button wire:click="rejectApplication({{ $app->id }})" color="danger" size="xs" icon="heroicon-o-x-mark" onclick="return confirm('Aanmelding afwijzen?')">
Afwijzen
</x-filament::button>
</div>
<div x-show="tab === 'applications'">
@php $applications = $this->getPendingApplications(); @endphp
@if($applications->count() > 0)
<div class="space-y-2">
@foreach($applications as $app)
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<p class="font-medium">{{ $app->user?->username ?? 'Onbekend' }}</p>
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ $app->rank?->name ?? 'Geen functie' }} &middot; {{ $app->age }} jaar
</p>
<p class="text-sm mt-2">{{ $app->motivation }}</p>
@if($app->experience)
<p class="text-xs text-gray-400 mt-1">Ervaring: {{ $app->experience }}</p>
@endif
<p class="text-xs text-gray-400 mt-1">{{ $app->created_at->diffForHumans() }}</p>
</div>
@endforeach
{{ $applications->links() }}
</div>
@else
<p class="text-gray-500 text-center py-8">Geen aanmeldingen wachtend</p>
@endif
</div>
</x-filament::tabs.tab>
</x-filament::tabs>
<div class="flex gap-2 shrink-0">
<x-filament::button wire:click="approveApplication({{ $app->id }})" color="success" size="xs" icon="heroicon-o-check" wire:confirm="Aanmelding goedkeuren?">
Goedkeuren
</x-filament::button>
<x-filament::button wire:click="rejectApplication({{ $app->id }})" color="danger" size="xs" icon="heroicon-o-x-mark" wire:confirm="Aanmelding afwijzen?">
Afwijzen
</x-filament::button>
</div>
</div>
@endforeach
{{ $applications->links() }}
</div>
@else
<p class="text-gray-500 text-center py-8">Geen aanmeldingen wachtend</p>
@endif
</div>
</div>
</x-filament-panels::page>
View File
View File
+4 -4
View File
@@ -1,5 +1,5 @@
{
"exported_at": "2026-05-22 18:56:37",
"exported_at": "2026-05-23 17:57:11",
"settings": {
"preset": "atom_original",
"color_primary": "#eeb425",
@@ -102,15 +102,15 @@
"card_border_width": "1",
"card_border_radius": "12",
"page_transition": true,
"login_effect_enabled": true,
"login_effect_enabled": false,
"login_effect_animation": "fire",
"login_effect_background": "#0088ff",
"login_effect_icon_color": "#eeb425",
"login_effect_text_color": "#ffffff",
"login_effect_bar_color": "#eeb425",
"login_effect_bar_style": "dots",
"login_effect_show_logo": true,
"login_effect_show_name": true,
"login_effect_show_logo": false,
"login_effect_show_name": false,
"login_effect_icon_size": "120",
"login_effect_custom_text": "",
"header_background": "#2d2d44",