feat: notifikasi + push Informasi Sekolah ke semua wali (broadcast, dedupe per hari)

This commit is contained in:
Novy San87
2026-08-06 20:25:24 +07:00
parent c3bda9c0cf
commit d9af7ef45d
2 changed files with 79 additions and 5 deletions
@@ -3,9 +3,14 @@
namespace App\Http\Controllers\Admin; namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\ParentDevice;
use App\Models\ParentStudent;
use App\Models\SchoolInformation; use App\Models\SchoolInformation;
use App\Models\ViolationNotification;
use App\Services\FcmService;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View; use Illuminate\View\View;
class SchoolInformationController extends Controller class SchoolInformationController extends Controller
@@ -27,7 +32,11 @@ class SchoolInformationController extends Controller
SchoolInformation::create($validated + ['created_by' => $request->user()->id]); SchoolInformation::create($validated + ['created_by' => $request->user()->id]);
return back()->with('success', 'Informasi "' . $validated['title'] . '" berhasil dipublikasikan.'); if ($validated['is_published'] ?? false) {
$this->notifyParents($validated['title']);
}
return back()->with('success', 'Informasi "'.$validated['title'].'" berhasil dipublikasikan.');
} }
public function update(Request $request, int $id): RedirectResponse public function update(Request $request, int $id): RedirectResponse
@@ -37,6 +46,10 @@ class SchoolInformationController extends Controller
$info->update($validated); $info->update($validated);
if ($validated['is_published'] ?? false) {
$this->notifyParents($validated['title']);
}
return back()->with('success', 'Informasi berhasil diperbarui.'); return back()->with('success', 'Informasi berhasil diperbarui.');
} }
@@ -58,4 +71,49 @@ class SchoolInformationController extends Controller
'is_published' => ['nullable', 'boolean'], 'is_published' => ['nullable', 'boolean'],
]) + ['is_published' => $request->boolean('is_published')]; ]) + ['is_published' => $request->boolean('is_published')];
} }
/**
* Kirim notifikasi + push informasi sekolah ke semua wali (broadcast).
* Dedupe: satu notifikasi per judul per hari.
*/
protected function notifyParents(string $title): void
{
try {
$message = 'Informasi Sekolah: '.$title;
$already = ViolationNotification::where('channel', 'info')
->where('message', $message)
->whereDate('created_at', today())
->exists();
if ($already) {
return;
}
$parentIds = ParentStudent::where('status', 'active')
->distinct()
->pluck('user_id');
foreach ($parentIds as $userId) {
ViolationNotification::create([
'student_id' => null,
'channel' => 'info',
'recipient' => 'Semua Wali',
'message' => $message,
'status' => 'sent',
'user_id' => $userId,
'created_at' => now(),
]);
$tokens = ParentDevice::where('user_id', $userId)->pluck('fcm_token');
foreach ($tokens as $token) {
app(FcmService::class)->sendToToken($token, [
'title' => '📢 Informasi Sekolah',
'body' => $title,
], ['type' => 'school_info', 'title' => $title]);
}
}
} catch (\Throwable $e) {
Log::error('Notif info sekolah gagal: '.$e->getMessage());
}
}
} }
@@ -29,7 +29,13 @@ class ParentNotificationController extends Controller
} }
$notifications = ViolationNotification::query() $notifications = ViolationNotification::query()
->whereIn('student_id', $studentIds) ->where(function ($q) use ($studentIds) {
$q->whereIn('student_id', $studentIds)
->orWhere(function ($q2) use ($studentIds) {
// Info sekolah (broadcast): student_id null, per user
$q2->whereNull('student_id')->where('user_id', auth()->id());
});
})
->with('student:id,full_name,class_name') ->with('student:id,full_name,class_name')
->orderByDesc('created_at') ->orderByDesc('created_at')
->limit(50) ->limit(50)
@@ -69,8 +75,13 @@ class ParentNotificationController extends Controller
return response()->json(['count' => 0]); return response()->json(['count' => 0]);
} }
$count = ViolationNotification::whereIn('student_id', $studentIds) $count = ViolationNotification::where(function ($q) use ($studentIds) {
->where('channel', 'push') // pelanggaran & SP (bukan kehadiran) $q->whereIn('student_id', $studentIds)
->orWhere(function ($q2) {
$q2->whereNull('student_id')->where('user_id', auth()->id());
});
})
->whereIn('channel', ['push', 'info']) // pelanggaran, SP, info sekolah
->where('is_read', false) ->where('is_read', false)
->count(); ->count();
@@ -89,7 +100,12 @@ class ParentNotificationController extends Controller
$updated = 0; $updated = 0;
if (! empty($studentIds)) { if (! empty($studentIds)) {
$updated = ViolationNotification::whereIn('student_id', $studentIds) $updated = ViolationNotification::where(function ($q) use ($studentIds) {
$q->whereIn('student_id', $studentIds)
->orWhere(function ($q2) {
$q2->whereNull('student_id')->where('user_id', auth()->id());
});
})
->where('is_read', false) ->where('is_read', false)
->update(['is_read' => true, 'read_at' => now()]); ->update(['is_read' => true, 'read_at' => now()]);
} }