import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'auth_service.dart'; import 'package:flutter/foundation.dart'; class NotificationItem { final String id; final String type; // 'jadwal' | 'laporan_ditolak' final String title; final String message; final String waktu; final bool isRead; final Map? extra; NotificationItem({ required this.id, required this.type, required this.title, required this.message, required this.waktu, this.isRead = false, this.extra, }); NotificationItem copyWith({bool? isRead}) { return NotificationItem( id: id, type: type, title: title, message: message, waktu: waktu, isRead: isRead ?? this.isRead, extra: extra, ); } Map toJson() => { 'id': id, 'type': type, 'title': title, 'message': message, 'waktu': waktu, 'isRead': isRead, 'extra': extra, }; factory NotificationItem.fromJson(Map json) { return NotificationItem( id: json['id'], type: json['type'], title: json['title'], message: json['message'], waktu: json['waktu'], isRead: json['isRead'] ?? false, extra: json['extra'], ); } } class NotificationService { static const String _prefKey = 'user_notifications'; // Ambil semua notifikasi tersimpan lokal static Future> getLocalNotifications() async { final prefs = await SharedPreferences.getInstance(); final raw = prefs.getStringList(_prefKey) ?? []; return raw .map((e) => NotificationItem.fromJson(jsonDecode(e))) .toList() .reversed .toList(); } // Simpan notifikasi baru (hindari duplikat by id) static Future saveNotification(NotificationItem notif) async { final prefs = await SharedPreferences.getInstance(); final raw = prefs.getStringList(_prefKey) ?? []; final existing = raw.map((e) => NotificationItem.fromJson(jsonDecode(e))).toList(); // Skip jika sudah ada ID yang sama if (existing.any((e) => e.id == notif.id)) return; existing.insert(0, notif); // Maksimal simpan 50 notifikasi final trimmed = existing.take(50).toList(); await prefs.setStringList( _prefKey, trimmed.map((e) => jsonEncode(e.toJson())).toList(), ); } // Tandai satu notifikasi sudah dibaca static Future markAsRead(String id) async { final prefs = await SharedPreferences.getInstance(); final raw = prefs.getStringList(_prefKey) ?? []; final list = raw.map((e) => NotificationItem.fromJson(jsonDecode(e))).toList(); final updated = list.map((n) => n.id == id ? n.copyWith(isRead: true) : n).toList(); await prefs.setStringList( _prefKey, updated.map((e) => jsonEncode(e.toJson())).toList(), ); } // Tandai semua sudah dibaca static Future markAllAsRead() async { final prefs = await SharedPreferences.getInstance(); final raw = prefs.getStringList(_prefKey) ?? []; final list = raw.map((e) => NotificationItem.fromJson(jsonDecode(e))).toList(); final updated = list.map((n) => n.copyWith(isRead: true)).toList(); await prefs.setStringList( _prefKey, updated.map((e) => jsonEncode(e.toJson())).toList(), ); } // Hitung notifikasi belum dibaca static Future getUnreadCount() async { final list = await getLocalNotifications(); return list.where((n) => !n.isRead).length; } // Cek jadwal hari ini dan simpan notifikasi jika ada static Future checkJadwalNotification() async { String? token = await AuthService.getToken(); try { final response = await http.get( Uri.parse("${AuthService.baseUrl}/jadwal"), headers: { "Accept": "application/json", "Authorization": "Bearer $token", }, ); if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['jadwal'] != null && data['jadwal'].length > 0) { final now = DateTime.now(); final jadwalList = data['jadwal'] as List; // Ambil tanggal hari ini (format: yyyy-MM-dd) final today = DateTime.now().toIso8601String().substring(0, 10); final jadwal = jadwalList.firstWhere( (j) => j['tanggal'] == today, orElse: () => null, ); if (jadwal != null) { // ID unik berdasarkan tanggal agar tidak duplikat per hari final dateKey = '${now.year}${now.month.toString().padLeft(2, '0')}${now.day.toString().padLeft(2, '0')}'; final notifId = 'jadwal_$dateKey'; await saveNotification( NotificationItem( id: notifId, type: 'jadwal', title: 'Jadwal Shift Hari Ini', message: 'Kamu memiliki shift ${jadwal['nama_shift']} pukul ${jadwal['jam_mulai']} - ${jadwal['jam_selesai']} di ${jadwal['nama_lokasi']}.', waktu: DateTime.now().toIso8601String(), extra: { 'nama_shift': jadwal['nama_shift'], 'jam_mulai': jadwal['jam_mulai'], 'jam_selesai': jadwal['jam_selesai'], 'lokasi': jadwal['nama_lokasi'], }, ), ); } } } } catch (e) { debugPrint("Error check jadwal notif: $e"); } } // Cek laporan yang ditolak dan simpan notifikasi static Future checkLaporanDitolakNotification() async { String? token = await AuthService.getToken(); try { final response = await http.get( Uri.parse("${AuthService.baseUrl}/laporan"), headers: { "Accept": "application/json", "Authorization": "Bearer $token", }, ); if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['data'] != null) { final laporanList = data['data'] as List; for (final laporan in laporanList) { // Sesuaikan key status dengan API kamu, misal: 'ditolak', 'rejected', 2, dll final status = laporan['status']?.toString().toLowerCase(); if (status == 'ditolak' || status == 'rejected' || status == '2') { final notifId = 'laporan_ditolak_${laporan['id']}'; await saveNotification( NotificationItem( id: notifId, type: 'laporan_ditolak', title: 'Laporan Ditolak', message: 'Laporan patroli kamu di ${laporan['lokasi']?['nama_lokasi'] ?? 'lokasi tidak diketahui'} pada ${laporan['waktu_patroli'] ?? '-'} telah ditolak oleh admin.', waktu: laporan['updated_at'] ?? DateTime.now().toIso8601String(), extra: { 'laporan_id': laporan['id'], 'lokasi': laporan['lokasi']?['nama_lokasi'], 'waktu_patroli': laporan['waktu_patroli'], 'keterangan_tolak': laporan['keterangan_tolak'], }, ), ); } } } } } catch (e) { debugPrint("Error check laporan ditolak notif: $e"); } } }