diff --git a/app/Http/Controllers/Admin/SchoolInformationController.php b/app/Http/Controllers/Admin/SchoolInformationController.php new file mode 100644 index 0000000..c4c59d9 --- /dev/null +++ b/app/Http/Controllers/Admin/SchoolInformationController.php @@ -0,0 +1,61 @@ +with('creator:id,name') + ->orderByDesc('event_date') + ->orderByDesc('created_at') + ->get(); + + return view('settings.school-info', compact('items')); + } + + public function store(Request $request): RedirectResponse + { + $validated = $this->validateData($request); + + SchoolInformation::create($validated + ['created_by' => $request->user()->id]); + + return back()->with('success', 'Informasi "' . $validated['title'] . '" berhasil dipublikasikan.'); + } + + public function update(Request $request, int $id): RedirectResponse + { + $info = SchoolInformation::findOrFail($id); + $validated = $this->validateData($request); + + $info->update($validated); + + return back()->with('success', 'Informasi berhasil diperbarui.'); + } + + public function destroy(Request $request, int $id): RedirectResponse + { + $info = SchoolInformation::findOrFail($id); + $info->delete(); + + return back()->with('success', 'Informasi dihapus.'); + } + + protected function validateData(Request $request): array + { + return $request->validate([ + 'title' => ['required', 'string', 'max:200'], + 'content' => ['nullable', 'string'], + 'category' => ['required', 'string', 'max:50'], + 'event_date' => ['nullable', 'date'], + 'is_published' => ['nullable', 'boolean'], + ]) + ['is_published' => $request->boolean('is_published')]; + } +} diff --git a/app/Http/Controllers/Api/ParentSchoolInformationController.php b/app/Http/Controllers/Api/ParentSchoolInformationController.php new file mode 100644 index 0000000..c4d7a60 --- /dev/null +++ b/app/Http/Controllers/Api/ParentSchoolInformationController.php @@ -0,0 +1,33 @@ +where('is_published', true) + ->orderByDesc('event_date') + ->orderByDesc('created_at') + ->limit(50) + ->get() + ->map(fn (SchoolInformation $i) => [ + 'id' => $i->id, + 'title' => $i->title, + 'content' => $i->content, + 'category' => $i->category, + 'event_date' => $i->event_date?->toDateString(), + 'created_at' => $i->created_at?->toISOString(), + ]); + + return response()->json(['informations' => $items]); + } +} diff --git a/app/Models/SchoolInformation.php b/app/Models/SchoolInformation.php new file mode 100644 index 0000000..4e5c53f --- /dev/null +++ b/app/Models/SchoolInformation.php @@ -0,0 +1,28 @@ + 'date', + 'is_published' => 'boolean', + 'published_at' => 'datetime', + ]; + } + + public function creator() + { + return $this->belongsTo(User::class, 'created_by'); + } +} diff --git a/database/migrations/2026_08_05_210750_create_school_informations_table.php b/database/migrations/2026_08_05_210750_create_school_informations_table.php new file mode 100644 index 0000000..cb46205 --- /dev/null +++ b/database/migrations/2026_08_05_210750_create_school_informations_table.php @@ -0,0 +1,55 @@ +id(); + $table->string('title', 200); + $table->text('content')->nullable(); + $table->string('category', 50)->default('umum')->index(); // umum | akademik | kegiatan | uts | uas | lainnya + $table->date('event_date')->nullable()->index(); // tanggal kegiatan (mis. tanggal UTS) + $table->boolean('is_published')->default(true)->index(); + $table->timestamp('published_at')->nullable(); + $table->unsignedBigInteger('created_by')->nullable(); + $table->timestamps(); + + $table->index(['is_published', 'event_date']); + }); + + // ===== Permission: kelola Informasi Sekolah ===== + $now = now(); + $permId = DB::table('permissions')->insertGetId([ + 'key' => 'manage-school-info', + 'group' => 'sekolah', + 'label' => 'Kelola Informasi Sekolah', + 'description' => 'Tambah/ubah/hapus informasi & pengumuman sekolah (ditampilkan di aplikasi wali murid)', + 'created_at' => $now, + 'updated_at' => $now, + ]); + + foreach (['admin', 'bk', 'waka_kesiswaan', 'kepala_sekolah', 'ketua_tim'] as $role) { + DB::table('role_permissions')->insertOrIgnore([ + 'role' => $role, + 'permission_id' => $permId, + 'created_at' => $now, + 'updated_at' => $now, + ]); + } + } + + public function down(): void + { + Schema::dropIfExists('school_informations'); + + $ids = DB::table('permissions')->where('key', 'manage-school-info')->pluck('id'); + DB::table('role_permissions')->whereIn('permission_id', $ids)->delete(); + DB::table('permissions')->where('key', 'manage-school-info')->delete(); + } +}; diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 90d5687..30fe271 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -200,6 +200,9 @@ @canPermission('parents-verify') Verifikasi Wali @endcanPermission + @canPermission('manage-school-info') + Informasi Sekolah + @endcanPermission @canPermission('sync-data') Sinkronisasi @endcanPermission diff --git a/resources/views/settings/school-info.blade.php b/resources/views/settings/school-info.blade.php new file mode 100644 index 0000000..58c9501 --- /dev/null +++ b/resources/views/settings/school-info.blade.php @@ -0,0 +1,187 @@ +@extends('layouts.app') + +@section('title', 'Informasi Sekolah') + +@section('content') +
+ + {{-- Header --}} +
+
+
+
+
+ +
+

Informasi Sekolah

+

Pengumuman kegiatan sekolah yang tampil di aplikasi Wali Murid (S1WON DIGI)

+
+
+ + {{ $items->count() }} informasi + +
+
+ + @if(session('success')) +
+ {{ session('success') }} +
+ @endif + +
+ + {{-- ===== Form ===== --}} +
+
+
+

Tambah Informasi

+ +
+
+ @csrf + + +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ + + + +
+
+
+ + {{-- ===== Daftar ===== --}} +
+ @forelse($items as $info) +
+
+
+ + {{ ucfirst($info->category) }} + + @if($info->event_date) + + {{ $info->event_date->format('d M Y') }} + + @endif + @if(!$info->is_published) + + Draft + + @endif +
+
+ +
+ @csrf @method('DELETE') + +
+
+
+

{{ $info->title }}

+ @if($info->content) +

{{ $info->content }}

+ @endif +

+ Diposting oleh {{ $info->creator?->name ?? '-' }} ยท {{ $info->created_at->diffForHumans() }} +

+
+ @empty +
+
+ +
+

Belum ada informasi

+

Tambahkan informasi pertama (UTS, Class Meet, kegiatan, dll) lewat form di samping.

+
+ @endforelse +
+
+
+ + +@endsection diff --git a/routes/api.php b/routes/api.php index 3ade119..20dd0a5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,6 +2,7 @@ use App\Http\Controllers\Api\ParentAuthController; use App\Http\Controllers\Api\ParentNotificationController; +use App\Http\Controllers\Api\ParentSchoolInformationController; use App\Http\Controllers\Api\ParentStudentController; use Illuminate\Support\Facades\Route; @@ -37,5 +38,6 @@ Route::middleware('auth:sanctum')->prefix('parent')->group(function () { // Notifikasi & perangkat Route::get('/notifications', [ParentNotificationController::class, 'index'])->name('api.parent.notifications'); + Route::get('/school-informations', [ParentSchoolInformationController::class, 'index'])->name('api.parent.school-informations'); Route::post('/devices', [ParentNotificationController::class, 'registerDevice'])->name('api.parent.devices'); }); diff --git a/routes/web.php b/routes/web.php index b3574fe..50892bf 100644 --- a/routes/web.php +++ b/routes/web.php @@ -146,6 +146,13 @@ Route::middleware('auth')->group(function () { Route::post('/parents/verification/{link}/reject', [\App\Http\Controllers\Admin\ParentVerificationController::class, 'reject'])->name('parents.verification.reject'); }); + Route::middleware('permission:manage-school-info')->group(function () { + Route::get('/settings/school-info', [\App\Http\Controllers\Admin\SchoolInformationController::class, 'index'])->name('settings.school-info'); + Route::post('/settings/school-info', [\App\Http\Controllers\Admin\SchoolInformationController::class, 'store'])->name('settings.school-info.store'); + Route::put('/settings/school-info/{info}', [\App\Http\Controllers\Admin\SchoolInformationController::class, 'update'])->name('settings.school-info.update'); + Route::delete('/settings/school-info/{info}', [\App\Http\Controllers\Admin\SchoolInformationController::class, 'destroy'])->name('settings.school-info.destroy'); + }); + // ===== Administrasi (permission-based) ===== Route::middleware('permission:settings-manage')->group(function () { Route::get('/settings', [SettingsController::class, 'index'])->name('settings.index');