feat: realtime notifications, fix broadcasting, add notifications page
- Fix: broadcasting.php config (was missing, broadcast failed) - Fix: Echo class global scope (window.EchoClass) - Fix: Nginx WebSocket proxy for Reverb - Fix: Firewall port 8087 opened - Fix: Duplicate event listener cleanup - Fix: Mark as read functionality - Add: CreateViolationNotification listener - Add: Notifications index page with pagination - Add: Timezone Asia/Jakarta support - Add: Real-time badge across all pages - Remove: toOthers() so recorder also gets notification - Update: .env.example with new variables
This commit is contained in:
@@ -72,6 +72,15 @@ class DashboardController extends Controller
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
public function notificationsIndex(Request $request): View
|
||||
{
|
||||
$notifications = AppNotification::where('user_id', $request->user()->id)
|
||||
->latest()
|
||||
->paginate(20);
|
||||
|
||||
return view('notifications.index', compact('notifications'));
|
||||
}
|
||||
|
||||
public function getUnreadCount(Request $request)
|
||||
{
|
||||
$count = AppNotification::where('user_id', $request->user()->id)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\ViolationRecorded;
|
||||
use App\Models\AppNotification;
|
||||
use App\Models\User;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class CreateViolationNotification implements ShouldQueue
|
||||
{
|
||||
use InteractsWithQueue;
|
||||
|
||||
public function handle(ViolationRecorded $event): void
|
||||
{
|
||||
$violation = $event->violation;
|
||||
$data = $event->data;
|
||||
|
||||
// Kirim notifikasi ke semua user kecuali pencatat
|
||||
$users = User::where('is_active', true)
|
||||
->where('id', '!=', $violation->recorded_by)
|
||||
->get();
|
||||
|
||||
foreach ($users as $user) {
|
||||
AppNotification::create([
|
||||
'user_id' => $user->id,
|
||||
'type' => 'violation',
|
||||
'title' => 'Pelanggaran Baru: ' . ($data['student_name'] ?? ''),
|
||||
'body' => ($data['violation_type'] ?? '') . ' (+' . ($data['points'] ?? 0) . ' poin)',
|
||||
'icon' => 'exclamation-triangle',
|
||||
'color' => $data['category_color'] ?? '#ef4444',
|
||||
'action_url' => $data['url'] ?? null,
|
||||
'is_read' => false,
|
||||
'violation_id' => $violation->id,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
@@ -19,6 +20,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
Paginator::defaultView('vendor.pagination.tailwind');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ class ViolationService
|
||||
}
|
||||
|
||||
// Broadcast via Reverb
|
||||
broadcast(new ViolationRecorded($violation))->toOthers();
|
||||
broadcast(new ViolationRecorded($violation));
|
||||
} catch (\Exception $e) {
|
||||
\Illuminate\Support\Facades\Log::error('Notify realtime failed: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user