208 lines
5.7 KiB
Dart
208 lines
5.7 KiB
Dart
// lib/app/modules/notification/controllers/notification_controller.dart
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'dart:async';
|
|
import '../../../services/firestore_service.dart';
|
|
import '../../../models/notification_model.dart';
|
|
import '../../../models/patient_model.dart';
|
|
import '../../../models/room_model.dart';
|
|
|
|
class NotificationItem {
|
|
final String id;
|
|
final String title;
|
|
final String message;
|
|
final String room;
|
|
final String patientName;
|
|
final DateTime time;
|
|
final String deviceId;
|
|
final bool isRead;
|
|
|
|
NotificationItem({
|
|
required this.id,
|
|
required this.title,
|
|
required this.message,
|
|
required this.room,
|
|
required this.deviceId,
|
|
required this.patientName,
|
|
required this.time,
|
|
this.isRead = false,
|
|
});
|
|
|
|
NotificationItem copyWith({
|
|
String? id,
|
|
String? title,
|
|
String? message,
|
|
String? room,
|
|
String? patientName,
|
|
DateTime? time,
|
|
String? deviceId,
|
|
bool? isRead,
|
|
}) {
|
|
return NotificationItem(
|
|
id: id ?? this.id,
|
|
title: title ?? this.title,
|
|
message: message ?? this.message,
|
|
room: room ?? this.room,
|
|
deviceId: deviceId ?? this.deviceId,
|
|
patientName: patientName ?? this.patientName,
|
|
time: time ?? this.time,
|
|
isRead: isRead ?? this.isRead,
|
|
);
|
|
}
|
|
}
|
|
|
|
class NotificationController extends GetxController {
|
|
final FirestoreService _firestoreService = FirestoreService();
|
|
|
|
final selectedTab = 0.obs;
|
|
final _allNotifications = <NotificationItem>[].obs;
|
|
final isLoading = true.obs;
|
|
|
|
StreamSubscription? _notificationsSubscription;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_initializeNotifications();
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_notificationsSubscription?.cancel();
|
|
super.onClose();
|
|
}
|
|
|
|
/// Initialize notifications dari Firestore
|
|
void _initializeNotifications() {
|
|
isLoading.value = true;
|
|
|
|
_notificationsSubscription = _firestoreService
|
|
.getNotificationsStream()
|
|
.listen((notificationModels) async {
|
|
final List<NotificationItem> items = [];
|
|
|
|
for (var notifModel in notificationModels) {
|
|
// Get patient info
|
|
final patient = await _firestoreService.getPatientById(
|
|
notifModel.patientId,
|
|
);
|
|
|
|
// Get room name from patient's roomId
|
|
String roomName = 'Unknown Room';
|
|
if (patient != null && patient.roomId.isNotEmpty) {
|
|
final rooms = await _firestoreService.getRoomsStream().first;
|
|
final room = rooms.firstWhereOrNull(
|
|
(r) => r.roomName.toLowerCase() == patient.roomId.toLowerCase(),
|
|
);
|
|
roomName = room?.roomName ?? patient.roomId;
|
|
}
|
|
|
|
items.add(
|
|
NotificationItem(
|
|
id: notifModel.id,
|
|
title: notifModel.title,
|
|
message: notifModel.message,
|
|
room: roomName,
|
|
deviceId: notifModel.deviceId,
|
|
patientName: patient?.namePatient ?? 'Unknown Patient',
|
|
time: notifModel.createdAt,
|
|
isRead: notifModel.isRead,
|
|
),
|
|
);
|
|
}
|
|
|
|
_allNotifications.value = items;
|
|
isLoading.value = false;
|
|
}, onError: (error) {
|
|
print('Error listening to notifications: $error');
|
|
isLoading.value = false;
|
|
});
|
|
}
|
|
|
|
// Computed property untuk notifikasi yang difilter
|
|
List<NotificationItem> get notifications {
|
|
if (selectedTab.value == 0) {
|
|
// Tab "Baru" - notifikasi yang belum dibaca
|
|
return _allNotifications.where((notif) => !notif.isRead).toList();
|
|
} else {
|
|
// Tab "Sudah dibaca" - notifikasi yang sudah dibaca
|
|
return _allNotifications.where((notif) => notif.isRead).toList();
|
|
}
|
|
}
|
|
|
|
void changeTab(int index) {
|
|
selectedTab.value = index;
|
|
}
|
|
|
|
Future<void> deleteNotification(String id) async {
|
|
try {
|
|
await _firestoreService.deleteNotification(id);
|
|
// Local update akan dilakukan otomatis oleh stream
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'Error',
|
|
'Gagal menghapus notifikasi: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.redAccent,
|
|
colorText: Colors.white,
|
|
margin: const EdgeInsets.all(16),
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> markAsRead(String id) async {
|
|
try {
|
|
await _firestoreService.markNotificationAsRead(id);
|
|
// Local update akan dilakukan otomatis oleh stream
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'Error',
|
|
'Gagal menandai notifikasi: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.redAccent,
|
|
colorText: Colors.white,
|
|
margin: const EdgeInsets.all(16),
|
|
);
|
|
}
|
|
}
|
|
|
|
String getTimeAgo(DateTime time) {
|
|
final difference = DateTime.now().difference(time);
|
|
if (difference.inMinutes < 60) {
|
|
return '${difference.inMinutes}min ago';
|
|
} else if (difference.inHours < 24) {
|
|
return '${difference.inHours}h ago';
|
|
} else {
|
|
return '${difference.inDays}d ago';
|
|
}
|
|
}
|
|
|
|
// Method untuk menghitung jumlah notifikasi baru
|
|
int get unreadCount {
|
|
return _allNotifications.where((notif) => !notif.isRead).length;
|
|
}
|
|
|
|
/// Method untuk menambahkan notifikasi baru (bisa dipanggil dari monitoring)
|
|
Future<void> addNotification({
|
|
required String patientId,
|
|
required String deviceId,
|
|
required String title,
|
|
required String message,
|
|
}) async {
|
|
try {
|
|
final notification = NotificationModel(
|
|
id: '', // Will be auto-generated by Firestore
|
|
patientId: patientId,
|
|
deviceId: deviceId,
|
|
title: title,
|
|
message: message,
|
|
isRead: false,
|
|
createdAt: DateTime.now(),
|
|
);
|
|
|
|
await _firestoreService.addNotification(notification);
|
|
} catch (e) {
|
|
print('Error adding notification: $e');
|
|
}
|
|
}
|
|
} |