468 lines
13 KiB
Dart
468 lines
13 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
import '../models/patient_model.dart';
|
|
import '../models/device_model.dart';
|
|
import '../models/room_model.dart';
|
|
import '../models/notification_model.dart';
|
|
import '../models/schedule_model.dart';
|
|
import '../models/history_model.dart';
|
|
import '../models/user_model.dart';
|
|
|
|
class FirestoreService {
|
|
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
|
final FirebaseAuth _auth = FirebaseAuth.instance;
|
|
|
|
// ==================== USER MANAGEMENT ====================
|
|
|
|
Future<bool> userExists(String email) async {
|
|
try {
|
|
final snapshot = await _firestore
|
|
.collection('users')
|
|
.where('email', isEqualTo: email)
|
|
.limit(1)
|
|
.get();
|
|
return snapshot.docs.isNotEmpty;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<String?> createUser({
|
|
required String email,
|
|
required String password,
|
|
required String name,
|
|
required String role,
|
|
String? deviceId,
|
|
}) async {
|
|
final userCredential = await _auth.createUserWithEmailAndPassword(
|
|
email: email,
|
|
password: password,
|
|
);
|
|
|
|
final uid = userCredential.user!.uid;
|
|
|
|
await _firestore.collection('users').doc(uid).set({
|
|
'email': email,
|
|
'name': name,
|
|
'role': role,
|
|
if (deviceId != null) 'device_id': deviceId, // TAMBAH device_id
|
|
'created_at': FieldValue.serverTimestamp(),
|
|
});
|
|
|
|
await _auth.signOut();
|
|
return uid;
|
|
}
|
|
|
|
Future<void> updateUser({
|
|
required String uid,
|
|
required String name,
|
|
String? email,
|
|
String? deviceId,
|
|
}) async {
|
|
final updateData = {'name': name};
|
|
if (email != null) updateData['email'] = email;
|
|
if (deviceId != null)
|
|
updateData['device_id'] = deviceId; // Support update device_id
|
|
await _firestore.collection('users').doc(uid).update(updateData);
|
|
}
|
|
|
|
Future<void> deleteUser(String uid) async {
|
|
await _firestore.collection('users').doc(uid).delete();
|
|
}
|
|
|
|
Future<void> deleteUserFromAuth(String email, String password) async {
|
|
try {
|
|
// Sign in temporary dengan user yang akan dihapus
|
|
final userCredential = await _auth.signInWithEmailAndPassword(
|
|
email: email,
|
|
password: password,
|
|
);
|
|
|
|
// Hapus user dari Authentication
|
|
await userCredential.user?.delete();
|
|
|
|
// Sign out
|
|
await _auth.signOut();
|
|
} catch (e) {
|
|
print('Error deleting user from auth: $e');
|
|
// Jika gagal, ignore error (misalnya user sudah tidak ada)
|
|
}
|
|
}
|
|
|
|
Future<DocumentSnapshot?> getUserByEmail(String email) async {
|
|
try {
|
|
final snapshot = await _firestore
|
|
.collection('users')
|
|
.where('email', isEqualTo: email)
|
|
.limit(1)
|
|
.get();
|
|
return snapshot.docs.isNotEmpty ? snapshot.docs.first : null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<UserModel?> getUserModelByEmail(String email) async {
|
|
try {
|
|
final snapshot = await _firestore
|
|
.collection('users')
|
|
.where('email', isEqualTo: email)
|
|
.limit(1)
|
|
.get();
|
|
return snapshot.docs.isNotEmpty
|
|
? UserModel.fromFirestore(snapshot.docs.first)
|
|
: null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// ==================== DEVICE MANAGEMENT ====================
|
|
|
|
Future<bool> deviceExists(String deviceId) async {
|
|
try {
|
|
final doc = await _firestore.collection('devices').doc(deviceId).get();
|
|
return doc.exists;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<bool> patientExistsByDevice(String deviceId) async {
|
|
try {
|
|
final snapshot = await _firestore
|
|
.collection('patients')
|
|
.where('device_id', isEqualTo: deviceId)
|
|
.limit(1)
|
|
.get();
|
|
return snapshot.docs.isNotEmpty;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Stream<List<DeviceModel>> getDevicesStream() {
|
|
return _firestore
|
|
.collection('devices')
|
|
.snapshots()
|
|
.map(
|
|
(snapshot) => snapshot.docs
|
|
.map((doc) => DeviceModel.fromFirestore(doc))
|
|
.toList(),
|
|
);
|
|
}
|
|
|
|
Future<DeviceModel?> getDeviceById(String deviceId) async {
|
|
try {
|
|
final doc = await _firestore.collection('devices').doc(deviceId).get();
|
|
return doc.exists ? DeviceModel.fromFirestore(doc) : null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<void> createDevice(DeviceModel device) async {
|
|
await _firestore
|
|
.collection('devices')
|
|
.doc(device.idDevices)
|
|
.set(device.toFirestore());
|
|
}
|
|
|
|
Future<void> deleteDevice(String deviceId) async {
|
|
await _firestore.collection('devices').doc(deviceId).delete();
|
|
}
|
|
|
|
// ==================== PATIENT MANAGEMENT ====================
|
|
|
|
Stream<List<PatientModel>> getPatientsStream() {
|
|
return _firestore
|
|
.collection('patients')
|
|
.snapshots()
|
|
.map(
|
|
(snapshot) => snapshot.docs
|
|
.map((doc) => PatientModel.fromFirestore(doc))
|
|
.toList(),
|
|
);
|
|
}
|
|
|
|
Future<PatientModel?> getPatientById(String patientId) async {
|
|
try {
|
|
final doc = await _firestore.collection('patients').doc(patientId).get();
|
|
return doc.exists ? PatientModel.fromFirestore(doc) : null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<PatientModel?> getPatientByDeviceId(String deviceId) async {
|
|
try {
|
|
final snapshot = await _firestore
|
|
.collection('patients')
|
|
.where('device_id', isEqualTo: deviceId)
|
|
.limit(1)
|
|
.get();
|
|
return snapshot.docs.isNotEmpty
|
|
? PatientModel.fromFirestore(snapshot.docs.first)
|
|
: null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<void> createPatient(PatientModel patient) async {
|
|
await _firestore.collection('patients').add(patient.toFirestore());
|
|
}
|
|
|
|
Future<void> updatePatient(String patientId, PatientModel patient) async {
|
|
await _firestore
|
|
.collection('patients')
|
|
.doc(patientId)
|
|
.update(patient.toFirestore());
|
|
}
|
|
|
|
Future<void> deletePatient(String patientId) async {
|
|
await _firestore.collection('patients').doc(patientId).delete();
|
|
}
|
|
|
|
// ==================== ROOM MANAGEMENT ====================
|
|
|
|
Future<bool> roomExists(String roomId) async {
|
|
try {
|
|
final doc = await _firestore.collection('rooms').doc(roomId).get();
|
|
return doc.exists;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Stream<List<RoomModel>> getRoomsStream() {
|
|
return _firestore
|
|
.collection('rooms')
|
|
.snapshots()
|
|
.map(
|
|
(snapshot) =>
|
|
snapshot.docs.map((doc) => RoomModel.fromFirestore(doc)).toList(),
|
|
);
|
|
}
|
|
|
|
Future<RoomModel?> getRoomById(String roomId) async {
|
|
try {
|
|
final doc = await _firestore.collection('rooms').doc(roomId).get();
|
|
return doc.exists ? RoomModel.fromFirestore(doc) : null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<void> createRoom(RoomModel room) async {
|
|
await _firestore.collection('rooms').doc(room.id).set(room.toFirestore());
|
|
}
|
|
|
|
Future<void> deleteRoom(String roomId) async {
|
|
await _firestore.collection('rooms').doc(roomId).delete();
|
|
}
|
|
|
|
// ==================== HISTORY MANAGEMENT ====================
|
|
|
|
Stream<List<HistoryModel>> getDeviceHistoriesStream(String deviceId) {
|
|
return _firestore
|
|
.collection('histories')
|
|
.where('device_id', isEqualTo: deviceId)
|
|
.snapshots()
|
|
.map((snapshot) {
|
|
final histories = snapshot.docs
|
|
.map((doc) => HistoryModel.fromFirestore(doc))
|
|
.toList();
|
|
|
|
histories.sort((a, b) => b.timestamp.compareTo(a.timestamp));
|
|
|
|
return histories;
|
|
});
|
|
}
|
|
|
|
Future<List<HistoryModel>> getDeviceHistories(
|
|
String deviceId, {
|
|
int limit = 100,
|
|
}) async {
|
|
try {
|
|
final snapshot = await _firestore
|
|
.collection('histories')
|
|
.where('device_id', isEqualTo: deviceId)
|
|
.get();
|
|
|
|
final histories = snapshot.docs
|
|
.map((doc) => HistoryModel.fromFirestore(doc))
|
|
.toList();
|
|
|
|
histories.sort((a, b) => b.timestamp.compareTo(a.timestamp));
|
|
|
|
return histories.take(limit).toList();
|
|
} catch (e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
Future<List<HistoryModel>> getDeviceHistoriesInRange(
|
|
String deviceId,
|
|
DateTime startDate,
|
|
DateTime endDate,
|
|
) async {
|
|
try {
|
|
final snapshot = await _firestore
|
|
.collection('histories')
|
|
.where('device_id', isEqualTo: deviceId)
|
|
.where('timestamp', isGreaterThanOrEqualTo: startDate)
|
|
.where('timestamp', isLessThanOrEqualTo: endDate)
|
|
.get();
|
|
|
|
final histories = snapshot.docs
|
|
.map((doc) => HistoryModel.fromFirestore(doc))
|
|
.toList();
|
|
|
|
histories.sort((a, b) => b.timestamp.compareTo(a.timestamp));
|
|
|
|
return histories;
|
|
} catch (e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
Future<List<HistoryModel>> getDeviceHistoriesToday(String deviceId) async {
|
|
final now = DateTime.now();
|
|
final startOfDay = DateTime(now.year, now.month, now.day);
|
|
final endOfDay = DateTime(now.year, now.month, now.day, 23, 59, 59);
|
|
return getDeviceHistoriesInRange(deviceId, startOfDay, endOfDay);
|
|
}
|
|
|
|
Future<void> addHistory(HistoryModel history) async {
|
|
await _firestore.collection('histories').add(history.toFirestore());
|
|
}
|
|
|
|
Future<void> deleteOldHistories({int daysToKeep = 30}) async {
|
|
final cutoffDate = DateTime.now().subtract(Duration(days: daysToKeep));
|
|
final snapshot = await _firestore
|
|
.collection('histories')
|
|
.where('timestamp', isLessThan: cutoffDate)
|
|
.get();
|
|
|
|
final batch = _firestore.batch();
|
|
for (var doc in snapshot.docs) {
|
|
batch.delete(doc.reference);
|
|
}
|
|
await batch.commit();
|
|
}
|
|
|
|
// BARU: Hapus semua histories berdasarkan device_id
|
|
Future<void> deleteHistoriesByDevice(String deviceId) async {
|
|
final snapshot = await _firestore
|
|
.collection('histories')
|
|
.where('device_id', isEqualTo: deviceId)
|
|
.get();
|
|
|
|
final batch = _firestore.batch();
|
|
for (var doc in snapshot.docs) {
|
|
batch.delete(doc.reference);
|
|
}
|
|
await batch.commit();
|
|
}
|
|
|
|
// ==================== NOTIFICATION MANAGEMENT ====================
|
|
|
|
Stream<List<NotificationModel>> getNotificationsStream() {
|
|
return _firestore
|
|
.collection('notifications')
|
|
.orderBy('created_at', descending: true)
|
|
.snapshots()
|
|
.map(
|
|
(snapshot) => snapshot.docs
|
|
.map((doc) => NotificationModel.fromFirestore(doc))
|
|
.toList(),
|
|
);
|
|
}
|
|
|
|
Future<void> addNotification(NotificationModel notification) async {
|
|
await _firestore
|
|
.collection('notifications')
|
|
.add(notification.toFirestore());
|
|
}
|
|
|
|
Future<void> markNotificationAsRead(String notificationId) async {
|
|
await _firestore.collection('notifications').doc(notificationId).update({
|
|
'is_read': true,
|
|
});
|
|
}
|
|
|
|
Future<void> deleteNotification(String notificationId) async {
|
|
await _firestore.collection('notifications').doc(notificationId).delete();
|
|
}
|
|
|
|
// BARU: Hapus semua notifications berdasarkan device_id
|
|
Future<void> deleteNotificationsByDevice(String deviceId) async {
|
|
final snapshot = await _firestore
|
|
.collection('notifications')
|
|
.where('device_id', isEqualTo: deviceId)
|
|
.get();
|
|
|
|
final batch = _firestore.batch();
|
|
for (var doc in snapshot.docs) {
|
|
batch.delete(doc.reference);
|
|
}
|
|
await batch.commit();
|
|
}
|
|
|
|
// ==================== SCHEDULE MANAGEMENT ====================
|
|
|
|
Stream<List<ScheduleModel>> getSchedulesStream({
|
|
DateTime? date,
|
|
String? timeOfDay,
|
|
}) {
|
|
Query query = _firestore.collection('schedules');
|
|
|
|
if (date != null) {
|
|
final startOfDay = DateTime(date.year, date.month, date.day);
|
|
final endOfDay = DateTime(date.year, date.month, date.day, 23, 59, 59);
|
|
query = query
|
|
.where('schedule_date', isGreaterThanOrEqualTo: startOfDay)
|
|
.where('schedule_date', isLessThanOrEqualTo: endOfDay);
|
|
}
|
|
|
|
if (timeOfDay != null) {
|
|
query = query.where('time_of_day', isEqualTo: timeOfDay);
|
|
}
|
|
|
|
return query.snapshots().map(
|
|
(snapshot) =>
|
|
snapshot.docs.map((doc) => ScheduleModel.fromFirestore(doc)).toList(),
|
|
);
|
|
}
|
|
|
|
Future<void> addSchedule(ScheduleModel schedule) async {
|
|
await _firestore.collection('schedules').add(schedule.toFirestore());
|
|
}
|
|
|
|
Future<void> updateSchedule(String scheduleId, ScheduleModel schedule) async {
|
|
await _firestore
|
|
.collection('schedules')
|
|
.doc(scheduleId)
|
|
.update(schedule.toFirestore());
|
|
}
|
|
|
|
Future<void> deleteSchedule(String scheduleId) async {
|
|
await _firestore.collection('schedules').doc(scheduleId).delete();
|
|
}
|
|
|
|
// BARU: Hapus semua schedules berdasarkan device_id
|
|
Future<void> deleteSchedulesByDevice(String deviceId) async {
|
|
final snapshot = await _firestore
|
|
.collection('schedules')
|
|
.where('device_id', isEqualTo: deviceId)
|
|
.get();
|
|
|
|
final batch = _firestore.batch();
|
|
for (var doc in snapshot.docs) {
|
|
batch.delete(doc.reference);
|
|
}
|
|
await batch.commit();
|
|
}
|
|
}
|