234 lines
7.3 KiB
Dart
234 lines
7.3 KiB
Dart
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<String, dynamic>? 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<String, dynamic> toJson() => {
|
|
'id': id,
|
|
'type': type,
|
|
'title': title,
|
|
'message': message,
|
|
'waktu': waktu,
|
|
'isRead': isRead,
|
|
'extra': extra,
|
|
};
|
|
|
|
factory NotificationItem.fromJson(Map<String, dynamic> 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<List<NotificationItem>> 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<void> 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<void> 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<void> 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<int> getUnreadCount() async {
|
|
final list = await getLocalNotifications();
|
|
return list.where((n) => !n.isRead).length;
|
|
}
|
|
|
|
// Cek jadwal hari ini dan simpan notifikasi jika ada
|
|
static Future<void> 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<void> 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");
|
|
}
|
|
}
|
|
}
|