From 08331d69ca1a02e3640d08bbee69c2fe4eaed870 Mon Sep 17 00:00:00 2001 From: orangdeso Date: Tue, 29 Apr 2025 11:18:07 +0700 Subject: [PATCH] Feat: completed features porter queue and history transaction porter --- .dart_tool/package_config.json | 2 +- android/build.gradle | 3 +- .../porter_queue_repository_impl.dart | 401 +++++++++++++++++- lib/domain/models/porter_queue_model.dart | 26 +- .../repositories/porter_queue_repository.dart | 24 +- lib/domain/usecases/porter_queue_usecase.dart | 61 ++- .../controllers/porter_queue_controller.dart | 168 +++++++- .../screens/home/pages/home_screen.dart | 13 +- 8 files changed, 669 insertions(+), 29 deletions(-) diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 7395717..bef6318 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -638,7 +638,7 @@ "languageVersion": "3.4" } ], - "generated": "2025-04-23T15:39:37.293764Z", + "generated": "2025-04-27T19:47:24.712851Z", "generator": "pub", "generatorVersion": "3.5.0", "flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0", diff --git a/android/build.gradle b/android/build.gradle index 8256d11..c3422de 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,4 +1,5 @@ buildscript { + ext.kotlin_version = '2.1.0' repositories { google() mavenCentral() @@ -6,7 +7,7 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:8.2.0" + classpath "com.android.tools.build:gradle:8.4.0" classpath 'com.google.gms:google-services:4.4.2' // firebase } } diff --git a/lib/data/repositories/porter_queue_repository_impl.dart b/lib/data/repositories/porter_queue_repository_impl.dart index 8a13625..98454ca 100644 --- a/lib/data/repositories/porter_queue_repository_impl.dart +++ b/lib/data/repositories/porter_queue_repository_impl.dart @@ -1,7 +1,9 @@ +import 'dart:async'; import 'dart:developer'; - +import 'dart:math' hide log; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:e_porter/domain/repositories/porter_queue_repository.dart'; +import 'package:firebase_database/firebase_database.dart'; import '../../domain/models/porter_queue_model.dart'; @@ -12,27 +14,41 @@ class PorterQueueRepositoryImpl implements PorterQueueRepository { FirebaseFirestore? firestore, }) : _firestore = firestore ?? FirebaseFirestore.instance; + String _generateId() { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + final rand = Random(); + return List.generate(7, (index) => chars[rand.nextInt(chars.length)]).join(); + } + @override - Future createPorterQueue(String userId) async { + Future createPorterQueue(String userId, String locationPorter) async { try { log('[PorterRepository] Membuat antrian porter untuk userId: $userId'); - // Periksa apakah porter dengan userId ini sudah ada final existingPorter = await getPorterByUserId(userId); if (existingPorter != null) { log('[PorterRepository] Porter dengan userId: $userId sudah ada di antrian'); + + if (!existingPorter.isAvailable) { + await _firestore.collection('porterOnline').doc(existingPorter.id).update({ + 'isAvailable': true, + 'idUser': null, + 'idTransaction': null, + 'onlineAt': FieldValue.serverTimestamp(), + }); + log('[PorterRepository] Status porter diperbarui menjadi available'); + } + return existingPorter.id!; } - // Buat data porter baru - final now = DateTime.now(); final porterData = PorterQueueModel( userId: userId, - isTaken: true, - onlineAt: now, + isAvailable: true, + onlineAt: DateTime.now(), + locationPorter: locationPorter, ).toJson(); - // Simpan ke Firestore final docRef = await _firestore.collection('porterOnline').add(porterData); log('[PorterRepository] Berhasil membuat antrian porter dengan ID: ${docRef.id}'); @@ -63,6 +79,16 @@ class PorterQueueRepositoryImpl implements PorterQueueRepository { try { log('[PorterRepository] Menghapus antrian porter dengan ID: $porterId'); + // Periksa apakah porter sedang memiliki transaksi aktif + final porterDoc = await _firestore.collection('porterOnline').doc(porterId).get(); + if (porterDoc.exists) { + final data = porterDoc.data(); + if (data != null && data['idTransaction'] != null) { + log('[PorterRepository] Porter memiliki transaksi aktif, tidak dapat dihapus'); + throw Exception('Porter sedang menangani transaksi, selesaikan transaksi terlebih dahulu'); + } + } + await _firestore.collection('porterOnline').doc(porterId).delete(); log('[PorterRepository] Berhasil menghapus antrian porter dengan ID: $porterId'); @@ -71,4 +97,363 @@ class PorterQueueRepositoryImpl implements PorterQueueRepository { throw Exception('Gagal menghapus antrian porter: $e'); } } + + @override + Future getNextAvailablePorter() async { + try { + log('[PorterRepository] Mencari porter yang tersedia...'); + + final snapshot = await _firestore + .collection('porterOnline') + .where('isAvailable', isEqualTo: true) + .orderBy('onlineAt', descending: false) + .limit(1) + .get() + .timeout(Duration(seconds: 10), onTimeout: () { + throw TimeoutException('Waktu pencarian porter habis'); + }); + + log('[PorterRepository] Query result: ${snapshot.docs.length} porters available'); + + if (snapshot.docs.isNotEmpty) { + final porter = PorterQueueModel.fromJson(snapshot.docs.first.data(), docId: snapshot.docs.first.id); + log('[PorterRepository] Porter tersedia: ${porter.id}'); + return porter; + } + log('[PorterRepository] Tidak ada porter yang tersedia'); + return null; + } catch (e) { + log('[PorterRepository] Error mendapatkan porter tersedia: $e'); + return null; + } + } + + @override + Future assignPorterToUser(String porterId, String userId, String transactionId) async { + try { + return await _firestore.runTransaction((transaction) async { + final porterDoc = await transaction.get(_firestore.collection('porterOnline').doc(porterId)); + + if (!porterDoc.exists) { + log('[PorterRepository] Porter tidak ditemukan'); + return false; + } + + final porterData = porterDoc.data(); + if (porterData == null || porterData['isAvailable'] != true) { + log('[PorterRepository] Porter tidak tersedia'); + return false; + } + + transaction.update(_firestore.collection('porterOnline').doc(porterId), { + 'isAvailable': false, + 'idUser': userId, + 'idTransaction': transactionId, + }); + + log('[PorterRepository] Porter berhasil ditugaskan ke user: $userId'); + return true; + }); + } catch (e) { + log('[PorterRepository] Error menugaskan porter: $e'); + return false; + } + } + + @override + Future createPorterTransaction( + {required String porterTransactionId, + required String porterId, + required String passengerId, + required String ticketId, + required String transactionId, + required String locationPassenger, + required String locationPorter}) async { + try { + log('[PorterRepository] Membuat transaksi porter: $porterTransactionId'); + + final now = DateTime.now().millisecondsSinceEpoch; + final kodePorter = _generateId(); + + // Dapatkan userId porter dari dokumen porterOnline + final porterDoc = await _firestore.collection('porterOnline').doc(porterId).get(); + String porterUserId = ''; + + if (porterDoc.exists && porterDoc.data() != null) { + porterUserId = porterDoc.data()!['userId'] ?? ''; + log('[PorterRepository] Mendapatkan userId porter: $porterUserId'); + } + + if (porterUserId.isEmpty) { + log('[PorterRepository] PERINGATAN: userId porter tidak ditemukan, menggunakan porterId: $porterId'); + porterUserId = porterId; // Fallback ke porterId jika userId tidak ditemukan + } + + final data = { + 'kodePorter': kodePorter, + 'porterOnlineId': porterId, + 'porterUserId': porterUserId, // Tambahkan porterUserId dalam data transaksi + 'idPassenger': passengerId, + 'ticketId': ticketId, + 'transactionId': transactionId, + 'status': 'pending', + 'locationPassenger': locationPassenger, + 'locationPorter': locationPorter, + 'createdAt': now, + }; + + // 1. Update Firestore + final batch = _firestore.batch(); + final porterDocId = _firestore.collection('porterOnline').doc(porterId); + final txDoc = _firestore.collection('porterTransactions').doc(porterTransactionId); + + batch.update(porterDocId, { + 'isAvailable': false, + 'idUser': passengerId, + 'idTransaction': porterTransactionId, + 'locationPorter': locationPorter, + }); + batch.set(txDoc, data); + + await batch.commit(); + log('[PorterRepository] Dokumen Firestore berhasil diperbarui'); + + // 2. Simpan transaksi di Realtime Database + final rtdb = FirebaseDatabase.instance.ref(); + + // 2.1 Data transaksi utama + await rtdb.child('porterTransactions/$porterTransactionId').set(data); + log('[PorterRepository] Data transaksi utama disimpan di RTDB'); + + // 2.2 Simpan referensi di porterHistory berdasarkan porterId (untuk kompatibilitas mundur) + await rtdb.child('porterHistory/$porterId/$porterTransactionId').set({ + 'timestamp': now, + 'transactionId': porterTransactionId, + }); + log('[PorterRepository] Referensi disimpan di porterHistory/$porterId'); + + // 2.3 Simpan referensi di porterHistory berdasarkan userId porter (baru) + if (porterUserId != porterId && porterUserId.isNotEmpty) { + await rtdb.child('porterHistory/$porterUserId/$porterTransactionId').set({ + 'timestamp': now, + 'transactionId': porterTransactionId, + }); + log('[PorterRepository] Referensi disimpan di porterHistory/$porterUserId'); + } + + // 2.4 Simpan referensi di passengerHistory + await rtdb.child('passengerHistory/$passengerId/$porterTransactionId').set({ + 'timestamp': now, + 'transactionId': porterTransactionId, + }); + log('[PorterRepository] Referensi disimpan di passengerHistory/$passengerId'); + + log('[PorterRepository] Transaksi porter berhasil dibuat'); + } catch (e) { + log('[PorterRepository] Error membuat transaksi porter: $e'); + throw Exception('Gagal membuat transaksi porter: $e'); + } + } + + // @override + // Future> getPorterTransactionIds(String porterId) async { + // try { + // final rtdb = FirebaseDatabase.instance.ref(); + // final snapshot = await rtdb.child('porterHistory/$porterId').get(); + + // if (snapshot.exists && snapshot.value != null) { + // final Map data = snapshot.value as Map; + // return data.keys.map((key) => key.toString()).toList(); + // } + + // return []; + // } catch (e) { + // log('[PorterRepository] Error getting porter transaction IDs: $e'); + // return []; + // } + // } + + // @override + // Future?> getPorterTransactionById(String transactionId) async { + // try { + // final rtdb = FirebaseDatabase.instance.ref(); + // final snapshot = await rtdb.child('porterTransactions/$transactionId').get(); + + // if (snapshot.exists && snapshot.value != null) { + // return Map.from(snapshot.value as Map); + // } + + // return null; + // } catch (e) { + // log('[PorterRepository] Error getting porter transaction: $e'); + // return null; + // } + // } + + @override + Future completePorterAssignment(String porterId) async { + try { + // Dapatkan dokumen porter + final porterDoc = await _firestore.collection('porterOnline').doc(porterId).get(); + if (porterDoc.exists) { + final porterData = porterDoc.data(); + final transactionId = porterData?['idTransaction']; + + if (transactionId != null) { + // Update status transaksi di Firestore + await _firestore.collection('porterTransactions').doc(transactionId).update({ + 'status': 'selesai', + 'updatedAt': FieldValue.serverTimestamp(), + }); + + // Update status transaksi di Realtime DB + final rtdb = FirebaseDatabase.instance.ref(); + await rtdb.child('porterTransactions/$transactionId').update({ + 'status': 'selesai', + 'updatedAt': DateTime.now().millisecondsSinceEpoch, + }); + } + + // Reset status porter + await _firestore.collection('porterOnline').doc(porterId).update({ + 'isAvailable': true, + 'idUser': null, + 'idTransaction': null, + }); + + log('[PorterRepository] Tugas porter selesai, status diperbarui'); + } + } catch (e) { + log('[PorterRepository] Error menyelesaikan tugas porter: $e'); + throw Exception('Gagal menyelesaikan tugas porter: $e'); + } + } + + // @override + // Future createPorterTransaction( + // {required String porterTransactionId, + // required String porterId, + // required String passengerId, + // required String ticketId, + // required String transactionId, + // required String locationPassenger, + // required String locationPorter}) async { + // final now = FieldValue.serverTimestamp(); + // final kodePorter = _generateId(); + + // final data = { + // 'kodePorter': kodePorter, + // 'porterOnlineId': porterId, + // 'idPassenger': passengerId, + // 'ticketId': ticketId, + // 'transactionId': transactionId, + // 'status': 'pending', + // 'locationPassenger': locationPassenger, + // 'locationPorter': locationPorter, + // 'createdAt': now, + // }; + + // final batch = _firestore.batch(); + // final porterDoc = _firestore.collection('porterOnline').doc(porterId); + // final txDoc = _firestore.collection('porterTransactions').doc(porterTransactionId); + + // batch.update(porterDoc, { + // 'isAvailable': false, + // 'idUser': passengerId, + // 'idTransaction': porterTransactionId, + // 'locationPorter': locationPorter, + // }); + // batch.set(txDoc, data); + + // await batch.commit(); + + // // tulis juga ke Realtime Database agar porter bisa listen secara real-time + // final rtdb = FirebaseDatabase.instance.ref(); + // await rtdb.child('porterTransactions/$porterId/$porterTransactionId').set({ + // ...data, + // 'createdAt': DateTime.now().millisecondsSinceEpoch, + // }); + // } + + // @override + // Future completePorterAssignment(String porterId) async { + // try { + // await _firestore.collection('porterOnline').doc(porterId).update({ + // 'isAvailable': true, + // 'idUser': null, + // 'idTransaction': null, + // }); + + // log('[PorterRepository] Tugas porter selesai, status diperbarui'); + // } catch (e) { + // log('[PorterRepository] Error menyelesaikan tugas porter: $e'); + // throw Exception('Gagal menyelesaikan tugas porter: $e'); + // } + // } + + @override + Future getPorterById(String porterId) async { + try { + log('[PorterRepository] Mendapatkan porter by ID: $porterId'); + + final snapshot = await _firestore.collection('porterOnline').doc(porterId).get(); + + if (snapshot.exists && snapshot.data() != null) { + return PorterQueueModel.fromJson(snapshot.data()!, docId: snapshot.id); + } + + log('[PorterRepository] Porter tidak ditemukan dengan ID: $porterId'); + return null; + } catch (e) { + log('[PorterRepository] Error mendapatkan porter by ID: $e'); + return null; + } + } + + @override + Future checkConditionForPorter(String porterId) async { + try { + // Memeriksa apakah porter ada dan tidak memiliki transaksi aktif + final porterDoc = await _firestore.collection('porterOnline').doc(porterId).get(); + + if (!porterDoc.exists) { + return false; + } + + final data = porterDoc.data(); + if (data != null && data['idTransaction'] != null) { + return false; + } + + return true; + } catch (e) { + throw Exception('Gagal memeriksa kondisi porter: $e'); + } + } + + @override + Stream watchPorterByUserId(String userId) { + try { + log('[PorterRepository] Memulai stream porter dengan userId: $userId'); + + return _firestore + .collection('porterOnline') + .where('userId', isEqualTo: userId) + .limit(1) + .snapshots() + .map((snapshot) { + if (snapshot.docs.isEmpty) { + log('[PorterRepository] Tidak ada porter dengan userId: $userId'); + return null; + } + + final doc = snapshot.docs.first; + log('[PorterRepository] Porter ditemukan dengan ID: ${doc.id}'); + return PorterQueueModel.fromJson(doc.data(), docId: doc.id); + }); + } catch (e) { + log('[PorterRepository] Error watching porter by userId: $e'); + throw Exception('Gagal memantau data porter: $e'); + } + } } diff --git a/lib/domain/models/porter_queue_model.dart b/lib/domain/models/porter_queue_model.dart index 6588a05..06d88b2 100644 --- a/lib/domain/models/porter_queue_model.dart +++ b/lib/domain/models/porter_queue_model.dart @@ -3,32 +3,44 @@ import 'package:cloud_firestore/cloud_firestore.dart'; class PorterQueueModel { final String? id; final String userId; - final bool isTaken; + final bool isAvailable; final DateTime onlineAt; + final String? idUser; + final String? idTransaction; + final String? locationPorter; PorterQueueModel({ this.id, required this.userId, - required this.isTaken, + required this.isAvailable, required this.onlineAt, + this.idUser, + this.idTransaction, + this.locationPorter, }); factory PorterQueueModel.fromJson(Map json, {String? docId}) { return PorterQueueModel( id: docId ?? json['id'], userId: json['userId'] ?? '', - isTaken: json['isTaken'] ?? false, - onlineAt: (json['onlineAt'] is Timestamp) - ? (json['onlineAt'] as Timestamp).toDate() + isAvailable: json['isAvailable'] ?? true, + onlineAt: (json['onlineAt'] is Timestamp) + ? (json['onlineAt'] as Timestamp).toDate() : DateTime.fromMillisecondsSinceEpoch(json['onlineAt'] ?? 0), + idUser: json['idUser'], + idTransaction: json['idTransaction'], + locationPorter: json['locationPorter'], ); } Map toJson() { return { 'userId': userId, - 'isTaken': isTaken, + 'isAvailable': isAvailable, 'onlineAt': onlineAt, + 'idUser': idUser, + 'idTransaction': idTransaction, + 'locationPorter': locationPorter, }; } -} \ No newline at end of file +} diff --git a/lib/domain/repositories/porter_queue_repository.dart b/lib/domain/repositories/porter_queue_repository.dart index 8046772..9778fb6 100644 --- a/lib/domain/repositories/porter_queue_repository.dart +++ b/lib/domain/repositories/porter_queue_repository.dart @@ -1,7 +1,27 @@ import '../models/porter_queue_model.dart'; abstract class PorterQueueRepository { - Future createPorterQueue(String userId); + Future createPorterQueue(String userId, String locationPorter); Future getPorterByUserId(String userId); Future deletePorterQueue(String porterId); -} \ No newline at end of file + + // Sisi Porter + Future getNextAvailablePorter(); + Future assignPorterToUser(String porterId, String userId, String transactionId); + Future createPorterTransaction( + {required String porterTransactionId, + required String porterId, + required String passengerId, + required String transactionId, + required String ticketId, + required String locationPassenger, + required String locationPorter}); + + // Future> getPorterTransactionIds(String porterId); + // Future?> getPorterTransactionById(String transactionId); + + Future completePorterAssignment(String porterId); + Future getPorterById(String porterId); + Future checkConditionForPorter(String porterId); + Stream watchPorterByUserId(String userId); +} diff --git a/lib/domain/usecases/porter_queue_usecase.dart b/lib/domain/usecases/porter_queue_usecase.dart index 46d39c8..8d4d108 100644 --- a/lib/domain/usecases/porter_queue_usecase.dart +++ b/lib/domain/usecases/porter_queue_usecase.dart @@ -6,8 +6,8 @@ class PorterQueueUsecase { PorterQueueUsecase(this._repository); - Future createPorterQueue(String userId) { - return _repository.createPorterQueue(userId); + Future createPorterQueue(String userId, String locationPorter) { + return _repository.createPorterQueue(userId, locationPorter); } Future getPorterByUserId(String userId) { @@ -17,4 +17,61 @@ class PorterQueueUsecase { Future deletePorterQueue(String porterId) { return _repository.deletePorterQueue(porterId); } + + // Sisi Porter + Future getNextAvailablePorter() { + return _repository.getNextAvailablePorter(); + } + + Future assignPorterToUser(String porterId, String userId, String transactionId) { + return _repository.assignPorterToUser(porterId, userId, transactionId); + } + + Future> requestPorter({ + required String passengerId, + required String ticketId, + required String transactionId, + required String locationPassenger, + }) async { + final porter = await _repository.getNextAvailablePorter(); + if (porter == null) throw Exception('Porter tidak tersedia'); + + final porterId = porter.id!; + final txId = DateTime.now().millisecondsSinceEpoch.toString(); + final locPorter = porter.locationPorter!; + + final ok = await _repository.assignPorterToUser(porterId, passengerId, txId); + if (!ok) throw Exception('Gagal menugaskan porter'); + + await _repository.createPorterTransaction( + porterTransactionId: txId, + porterId: porterId, + passengerId: passengerId, + transactionId: transactionId, + ticketId: ticketId, + locationPassenger: locationPassenger, + locationPorter: locPorter, + ); + + return { + 'porterId': porterId, + 'transactionId': txId, + }; + } + + Future completePorterAssignment(String porterId) { + return _repository.completePorterAssignment(porterId); + } + + Future getPorterById(String porterId) { + return _repository.getPorterById(porterId); + } + + Future checkConditionForPorter(String porterId) { + return _repository.checkConditionForPorter(porterId); + } + + Stream watchPorterByUserId(String userId) { + return _repository.watchPorterByUserId(userId); + } } diff --git a/lib/presentation/controllers/porter_queue_controller.dart b/lib/presentation/controllers/porter_queue_controller.dart index cd3d0a1..956fba6 100644 --- a/lib/presentation/controllers/porter_queue_controller.dart +++ b/lib/presentation/controllers/porter_queue_controller.dart @@ -1,3 +1,6 @@ +import 'dart:developer'; + +import 'package:e_porter/_core/utils/snackbar/snackbar_helper.dart'; import 'package:e_porter/domain/models/porter_queue_model.dart'; import 'package:e_porter/domain/usecases/porter_queue_usecase.dart'; import 'package:get/get.dart'; @@ -11,12 +14,12 @@ class PorterQueueController { final RxString error = ''.obs; final Rx currentPorter = Rx(null); - Future createPorterQueue(String userId) async { + Future createPorterQueue(String userId, String locationPorter) async { try { isLoading.value = true; error.value = ''; - final porterId = await _porterQueueUsecase.createPorterQueue(userId); + final porterId = await _porterQueueUsecase.createPorterQueue(userId, locationPorter); final porter = await _porterQueueUsecase.getPorterByUserId(userId); currentPorter.value = porter; @@ -32,7 +35,16 @@ class PorterQueueController { bool validatePorterQueueForDeletion() { final porter = currentPorter.value; - return porter != null && porter.id != null; + if (porter == null || porter.id == null) { + return false; + } + + if (porter.idTransaction != null) { + error.value = 'Porter sedang menangani transaksi, selesaikan transaksi terlebih dahulu'; + return false; + } + + return true; } Future deletePorterQueue(String porterId) async { @@ -40,13 +52,23 @@ class PorterQueueController { isLoading.value = true; error.value = ''; + // Gunakan metode cek kondisi yang telah diperbaiki + final canProceed = await checkConditionForPorter(porterId); + if (!canProceed) { + return false; + } + await _porterQueueUsecase.deletePorterQueue(porterId); - currentPorter.value = null; + currentPorter.value = null; return true; } catch (e) { error.value = 'Gagal menghapus antrian porter: $e'; - return false; + SnackbarHelper.showError( + 'Gagal', + 'Gagal menghapus antrian porter.', + ); + return false; } finally { isLoading.value = false; } @@ -73,4 +95,140 @@ class PorterQueueController { isLoading.value = false; } } + + // Belum + + Future getNextAvailablePorter() async { + try { + isLoading.value = true; + error.value = ''; + + return await _porterQueueUsecase.getNextAvailablePorter(); + } catch (e) { + error.value = 'Gagal mendapatkan porter tersedia: $e'; + return null; + } finally { + isLoading.value = false; + } + } + + Future assignPorterToUser(String porterId, String userId, String transactionId) async { + try { + isLoading.value = true; + error.value = ''; + + return await _porterQueueUsecase.assignPorterToUser(porterId, userId, transactionId); + } catch (e) { + error.value = 'Gagal menugaskan porter: $e'; + return false; + } finally { + isLoading.value = false; + } + } + + Future> requestPorter({ + required String passengerId, + required String ticketId, + required String transactionId, + required String location, + }) async { + try { + isLoading.value = true; + error.value = ''; + + // Panggil usecase dan dapatkan result berupa map + final result = await _porterQueueUsecase.requestPorter( + passengerId: passengerId, + ticketId: ticketId, + transactionId: transactionId, + locationPassenger: location, + ); + + return result; + } catch (e) { + // Simpan pesan error dan lempar ulang + error.value = e.toString(); + rethrow; + } finally { + isLoading.value = false; + } + } + + Future completePorterAssignment(String porterId) async { + try { + isLoading.value = true; + error.value = ''; + + await _porterQueueUsecase.completePorterAssignment(porterId); + + if (currentPorter.value?.id == porterId) { + final userId = currentPorter.value?.userId; + if (userId != null) { + await loadCurrentPorter(userId); + } + } + } catch (e) { + error.value = 'Gagal menyelesaikan tugas porter: $e'; + } finally { + isLoading.value = false; + } + } + + Future checkConditionForPorter(String porterId) async { + try { + isLoading.value = true; + error.value = ''; + + // 1. Dapatkan data terbaru porter langsung dari repository + final freshPorterData = await _porterQueueUsecase.getPorterById(porterId); + + if (freshPorterData == null) { + error.value = 'Data porter tidak ditemukan.'; + SnackbarHelper.showError('Gagal', error.value); + return false; + } + + // 2. Gunakan data terbaru untuk validasi + if (freshPorterData.idTransaction != null) { + error.value = 'Porter sedang menangani transaksi, selesaikan transaksi terlebih dahulu.'; + SnackbarHelper.showError('Gagal', error.value); + return false; + } + + if (freshPorterData.idUser != null) { + error.value = 'Porter masih melayani penumpang, selesaikan tugas terlebih dahulu.'; + SnackbarHelper.showError('Gagal', error.value); + return false; + } + + if (freshPorterData.isAvailable != true) { + error.value = 'Porter belum tersedia untuk keluar antrian.'; + SnackbarHelper.showError('Gagal', error.value); + return false; + } + + return true; + } catch (e) { + error.value = 'Gagal memeriksa kondisi porter: $e'; + SnackbarHelper.showError('Gagal', 'Gagal memeriksa kondisi porter.'); + return false; + } finally { + isLoading.value = false; + } + } + + Stream watchPorter(String userId) { + if (userId.isEmpty) { + log('[PorterQueueController] Error: userId kosong'); + return Stream.value(null); + } + + log('[PorterQueueController] Memulai pemantauan porter dengan userId: $userId'); + return _porterQueueUsecase.watchPorterByUserId(userId); + } + + void setError(String message) { + error.value = message; + log('[PorterQueueController] Error: $message'); + } } diff --git a/lib/presentation/screens/home/pages/home_screen.dart b/lib/presentation/screens/home/pages/home_screen.dart index 3c480b5..f0394f4 100644 --- a/lib/presentation/screens/home/pages/home_screen.dart +++ b/lib/presentation/screens/home/pages/home_screen.dart @@ -120,6 +120,7 @@ class _HomeScreenState extends State { return; } + // Periksa apakah ada porterOnline yang aktif if (_porterQueueController.currentPorter.value == null) { SnackbarHelper.showError( 'Gagal', @@ -127,9 +128,15 @@ class _HomeScreenState extends State { ); return; } - final porterId = _porterQueueController.currentPorter.value!.id!; - final canProceed = await _porterQueueController.checkConditionForPorter(porterId); + // Dapatkan ID porter saat ini + final porterId = _porterQueueController.currentPorter.value!.id!; + + // Muat ulang data porter sebelum melakukan pengecekan (optional) + await _porterQueueController.loadCurrentPorter(validUserId); + + // Gunakan metode cek kondisi yang diperbaiki + final canProceed = await _porterQueueController.checkConditionForPorter(porterId); if (!canProceed) { return; } @@ -158,7 +165,7 @@ class _HomeScreenState extends State { } SnackbarHelper.showError( 'Gagal', - 'Gagal menghentikan antrian porter.', + 'Gagal menghentikan antrian porter: ${e.toString()}', ); } }