TKK_E32230859/lib/app/modules/profile/controllers/profile_controller.dart

396 lines
11 KiB
Dart

import 'package:get/get.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_database/firebase_database.dart';
import '../../../services/firestore_service.dart';
import '../../../services/realtime_database_service.dart';
import '../../../models/patient_model.dart';
import '../../../models/device_model.dart';
import '../../../models/room_model.dart';
import '../../../widgets/app_snackbar.dart';
class Patient {
final String id;
final String name;
final String room;
final String deviceId;
final String guardian;
final String email;
final String? userId;
final String status;
Patient({
required this.id,
required this.name,
required this.room,
required this.deviceId,
required this.guardian,
required this.email,
this.userId,
this.status = 'Aktif',
});
Map<String, dynamic> toFirestore() {
return {
'name_patient': name,
'name_guardian': guardian,
'device_id': deviceId,
'room_id': room,
'user_id': userId,
};
}
factory Patient.fromFirestore(DocumentSnapshot doc) {
final data = doc.data() as Map<String, dynamic>;
return Patient(
id: doc.id,
name: data['name_patient'] ?? '',
guardian: data['name_guardian'] ?? '',
deviceId: data['device_id'] ?? '',
room: data['room_id'] ?? '',
email: '',
userId: data['user_id'],
);
}
}
class ProfileController extends GetxController {
final FirestoreService _firestoreService = FirestoreService();
final RealtimeDatabaseService _realtimeService = RealtimeDatabaseService();
final patients = <Patient>[].obs;
final isLoading = false.obs;
@override
void onInit() {
super.onInit();
_listenToPatients();
}
void refreshPatients() {
_listenToPatients();
}
void _listenToPatients() {
_firestoreService.getPatientsStream().listen((patientModels) async {
final patientsWithEmail = <Patient>[];
for (var model in patientModels) {
try {
final email = await _getGuardianEmail(model.nameGuardian);
final roomName = await _getRoomName(model.roomId);
patientsWithEmail.add(
Patient(
id: model.id,
name: model.namePatient,
guardian: model.nameGuardian,
deviceId: model.deviceId,
room: roomName,
email: email,
userId: null,
),
);
} catch (e) {
continue;
}
}
patients.value = patientsWithEmail;
}, onError: (error) => AppSnackbar.error('Gagal memuat data'));
}
Future<String> _getGuardianEmail(String guardianName) async {
try {
final userDoc = await FirebaseFirestore.instance
.collection('users')
.where('role', isEqualTo: 'guardian')
.where('name', isEqualTo: guardianName)
.limit(1)
.get();
return userDoc.docs.isNotEmpty
? userDoc.docs.first.data()['email'] ?? ''
: '';
} catch (e) {
return '';
}
}
Future<String> _getRoomName(String roomId) async {
try {
final roomDoc = await FirebaseFirestore.instance
.collection('rooms')
.doc(roomId)
.get();
return roomDoc.data()?['room_name'] ?? roomId;
} catch (e) {
return roomId;
}
}
Future<void> addPatient({
required String patientName,
required String guardianName,
required String roomName,
required String deviceId,
required String email,
required String password,
}) async {
try {
isLoading.value = true;
if (!await _validateNewPatient(email, deviceId)) return;
final roomId = _generateRoomId(roomName);
// PERBAIKAN: Tambahkan device_id saat create user
final userId = await _firestoreService.createUser(
email: email,
password: password,
name: guardianName,
role: 'guardian',
deviceId: deviceId, // ✅ TAMBAHKAN INI
);
if (userId == null) throw Exception('Gagal membuat user');
await _ensureRoomExists(roomId, roomName);
await _createDevice(deviceId, roomId);
await _firestoreService.createPatient(
PatientModel(
id: '',
namePatient: patientName,
nameGuardian: guardianName,
deviceId: deviceId,
roomId: roomId,
),
);
await _realtimeService.updateDeviceStatus(roomId, deviceId, 'connected');
await _createDeviceInRealtimeDB(roomId, deviceId);
Get.back();
AppSnackbar.success('Pasien berhasil ditambahkan');
} catch (e) {
AppSnackbar.error('Gagal menambahkan pasien: $e');
} finally {
isLoading.value = false;
}
}
Future<bool> _validateNewPatient(String email, String deviceId) async {
if (await _firestoreService.userExists(email)) {
AppSnackbar.warning('Email sudah terdaftar');
return false;
}
if (await _firestoreService.deviceExists(deviceId)) {
AppSnackbar.warning('Device ID sudah terdaftar');
return false;
}
if (await _firestoreService.patientExistsByDevice(deviceId)) {
AppSnackbar.warning('Device sudah digunakan');
return false;
}
return true;
}
Future<void> updatePatient({
required String patientId,
required String patientName,
required String guardianName,
required String roomName,
required String deviceId,
required String email,
String? newPassword,
}) async {
try {
isLoading.value = true;
final oldPatient = await _firestoreService.getPatientById(patientId);
if (oldPatient == null) throw Exception('Pasien tidak ditemukan');
final roomId = _generateRoomId(roomName);
if (deviceId != oldPatient.deviceId) {
if (await _firestoreService.deviceExists(deviceId)) {
AppSnackbar.warning('Device ID sudah terdaftar');
return;
}
}
await _firestoreService.updatePatient(
patientId,
PatientModel(
id: patientId,
namePatient: patientName,
nameGuardian: guardianName,
deviceId: deviceId,
roomId: roomId,
),
);
if (deviceId != oldPatient.deviceId || roomId != oldPatient.roomId) {
await _updateDeviceAndRoom(oldPatient, deviceId, roomId);
}
await _ensureRoomExists(roomId, roomName);
// PERBAIKAN: Update device_id di users collection jika device berubah
if (deviceId != oldPatient.deviceId) {
final userDoc = await _firestoreService.getUserByEmail(email);
if (userDoc != null) {
await _firestoreService.updateUser(
uid: userDoc.id,
name: guardianName,
email: email,
deviceId: deviceId, // ✅ UPDATE device_id
);
}
}
Get.back();
AppSnackbar.success('Data berhasil diperbarui');
} catch (e) {
AppSnackbar.error('Gagal memperbarui data: $e');
} finally {
isLoading.value = false;
}
}
Future<void> _updateDeviceAndRoom(
PatientModel oldPatient,
String newDeviceId,
String newRoomId,
) async {
await _firestoreService.deleteDevice(oldPatient.deviceId);
await _deleteDeviceFromRealtimeDB(oldPatient.roomId, oldPatient.deviceId);
await _createDevice(newDeviceId, newRoomId);
await _createDeviceInRealtimeDB(newRoomId, newDeviceId);
}
// PERBAIKAN LENGKAP: Hapus dari semua collection + Authentication
Future<void> deletePatient(String patientId, {String? password}) async {
try {
isLoading.value = true;
final patient = await _firestoreService.getPatientById(patientId);
if (patient == null) throw Exception('Pasien tidak ditemukan');
// 1. Hapus dari Realtime Database
await _deleteDeviceFromRealtimeDB(patient.roomId, patient.deviceId);
// 2. Hapus histories berdasarkan device_id
await _firestoreService.deleteHistoriesByDevice(patient.deviceId);
// 3. Hapus notifications berdasarkan device_id
await _firestoreService.deleteNotificationsByDevice(patient.deviceId);
// 4. Hapus schedules berdasarkan device_id
await _firestoreService.deleteSchedulesByDevice(patient.deviceId);
// 5. Hapus device dari Firestore
await _firestoreService.deleteDevice(patient.deviceId);
// 6. Cari user berdasarkan guardian name dan device_id
final userDoc = await FirebaseFirestore.instance
.collection('users')
.where('role', isEqualTo: 'guardian')
.where('name', isEqualTo: patient.nameGuardian)
.where('device_id', isEqualTo: patient.deviceId)
.limit(1)
.get();
if (userDoc.docs.isNotEmpty) {
final userId = userDoc.docs.first.id;
final userEmail = userDoc.docs.first.data()['email'] as String;
// 7. Hapus dari collection users
await _firestoreService.deleteUser(userId);
// 8. Hapus dari Firebase Authentication
// CATATAN: Memerlukan password untuk delete dari Authentication
if (password != null && password.isNotEmpty) {
await _firestoreService.deleteUserFromAuth(userEmail, password);
} else {
// Jika tidak ada password, tampilkan warning
print(
'⚠️ User tidak terhapus dari Authentication karena password tidak tersedia',
);
AppSnackbar.warning(
'User terhapus dari database, tapi tidak dari Authentication. Hubungi admin untuk menghapus akun sepenuhnya.',
);
}
}
// 9. Hapus patient dari Firestore
await _firestoreService.deletePatient(patientId);
AppSnackbar.success('Pasien berhasil dihapus');
} catch (e) {
AppSnackbar.error('Gagal menghapus pasien: $e');
print('❌ Delete patient error: $e');
} finally {
isLoading.value = false;
}
}
Future<void> _ensureRoomExists(String roomId, String roomName) async {
if (!await _firestoreService.roomExists(roomId)) {
await _firestoreService.createRoom(
RoomModel(
id: roomId,
roomName: roomName,
capacity: 10,
createdAt: DateTime.now(),
),
);
}
}
Future<void> _createDevice(String deviceId, String roomId) async {
await _firestoreService.createDevice(
DeviceModel(
idDevices: deviceId,
roomId: roomId,
devicesName: 'Infusion Device $deviceId',
),
);
}
Future<void> _createDeviceInRealtimeDB(String roomId, String deviceId) async {
final devicePath = 'realtime/rooms/$roomId/devices/$deviceId';
await FirebaseDatabase.instance.ref().child(devicePath).set({
'controlling': {
'servo_open': false,
'last_command': DateTime.now().toIso8601String(),
},
'monitoring': {
'device_status': 'connected',
'drop_rate': 0,
'last_update': DateTime.now().toIso8601String(),
},
'settings': {'servo_angle_open': 90, 'servo_angle_close': 0},
});
}
Future<void> _deleteDeviceFromRealtimeDB(
String roomId,
String deviceId,
) async {
final devicePath = 'realtime/rooms/$roomId/devices/$deviceId';
await FirebaseDatabase.instance.ref().child(devicePath).remove();
}
String _generateRoomId(String roomName) {
return roomName
.trim()
.toLowerCase()
.replaceAll(RegExp(r'[^a-z0-9]+'), '_')
.replaceAll(RegExp(r'_+'), '_')
.replaceAll(RegExp(r'^_|_$'), '');
}
}