Feat: done post data for transaction
This commit is contained in:
parent
afc667838b
commit
18487e7a2e
|
@ -181,6 +181,24 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "firebase_database",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database-11.3.5",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.2"
|
||||
},
|
||||
{
|
||||
"name": "firebase_database_platform_interface",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database_platform_interface-0.2.6+5",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.2"
|
||||
},
|
||||
{
|
||||
"name": "firebase_database_web",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database_web-0.2.6+11",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "firebase_storage",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage-12.4.5",
|
||||
|
@ -199,6 +217,12 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "fixnum",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fixnum-1.1.1",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.1"
|
||||
},
|
||||
{
|
||||
"name": "flutter",
|
||||
"rootUri": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0/packages/flutter",
|
||||
|
@ -487,6 +511,12 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "2.18"
|
||||
},
|
||||
{
|
||||
"name": "sprintf",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/sprintf-7.0.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "stack_trace",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/stack_trace-1.11.1",
|
||||
|
@ -523,6 +553,12 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "3.5"
|
||||
},
|
||||
{
|
||||
"name": "uuid",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/uuid-4.5.1",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
{
|
||||
"name": "vector_graphics",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/vector_graphics-1.1.18",
|
||||
|
@ -596,7 +632,7 @@
|
|||
"languageVersion": "3.4"
|
||||
}
|
||||
],
|
||||
"generated": "2025-03-31T15:19:30.948302Z",
|
||||
"generated": "2025-04-01T21:50:03.833642Z",
|
||||
"generator": "pub",
|
||||
"generatorVersion": "3.5.0",
|
||||
"flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0",
|
||||
|
|
|
@ -118,6 +118,18 @@ firebase_core_web
|
|||
3.4
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_core_web-2.22.0/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_core_web-2.22.0/lib/
|
||||
firebase_database
|
||||
3.2
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database-11.3.5/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database-11.3.5/lib/
|
||||
firebase_database_platform_interface
|
||||
3.2
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database_platform_interface-0.2.6+5/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database_platform_interface-0.2.6+5/lib/
|
||||
firebase_database_web
|
||||
3.4
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database_web-0.2.6+11/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_database_web-0.2.6+11/lib/
|
||||
firebase_storage
|
||||
3.2
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage-12.4.5/
|
||||
|
@ -130,6 +142,10 @@ firebase_storage_web
|
|||
3.4
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage_web-3.10.12/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage_web-3.10.12/lib/
|
||||
fixnum
|
||||
3.1
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fixnum-1.1.1/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fixnum-1.1.1/lib/
|
||||
flutter_picker
|
||||
2.12
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/flutter_picker-2.1.0/
|
||||
|
@ -306,6 +322,10 @@ source_span
|
|||
2.18
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/source_span-1.10.0/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/source_span-1.10.0/lib/
|
||||
sprintf
|
||||
2.12
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/sprintf-7.0.0/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/sprintf-7.0.0/lib/
|
||||
stack_trace
|
||||
2.18
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/stack_trace-1.11.1/
|
||||
|
@ -330,6 +350,10 @@ typed_data
|
|||
3.5
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/typed_data-1.4.0/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/typed_data-1.4.0/lib/
|
||||
uuid
|
||||
3.0
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/uuid-4.5.1/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/uuid-4.5.1/lib/
|
||||
vector_graphics
|
||||
3.4
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/vector_graphics-1.1.18/
|
||||
|
|
|
@ -0,0 +1,407 @@
|
|||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:firebase_storage/firebase_storage.dart';
|
||||
import 'package:e_porter/domain/models/transaction_model.dart';
|
||||
import 'package:e_porter/domain/repositories/transaction_repository.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
class TransactionRepositoryImpl implements TransactionRepository {
|
||||
final FirebaseFirestore _firestore;
|
||||
final FirebaseStorage _storage;
|
||||
|
||||
TransactionRepositoryImpl({
|
||||
FirebaseFirestore? firestore,
|
||||
FirebaseStorage? storage,
|
||||
}) : _firestore = firestore ?? FirebaseFirestore.instance,
|
||||
_storage = storage ?? FirebaseStorage.instance;
|
||||
|
||||
// Method untuk generate ID unik
|
||||
String _generateUniqueId() {
|
||||
return DateTime.now().millisecondsSinceEpoch.toString() +
|
||||
'_' +
|
||||
(100000 + (DateTime.now().microsecond % 900000)).toString();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> createTransaction({
|
||||
required String ticketId,
|
||||
required String flightId,
|
||||
required double amount,
|
||||
required String method,
|
||||
required DateTime expiryTime,
|
||||
required Map<String, dynamic> flightDetails,
|
||||
required Map<String, dynamic> bandaraDetails,
|
||||
Map<String, dynamic>? porterServiceDetails,
|
||||
required Map<String, dynamic> userDetails,
|
||||
required int passenger,
|
||||
required List<Map<String, dynamic>> passengerDetails,
|
||||
required List<String> numberSeat,
|
||||
}) async {
|
||||
try {
|
||||
final transactionId = _generateUniqueId();
|
||||
final now = DateTime.now();
|
||||
|
||||
final transactionData = {
|
||||
'id': transactionId,
|
||||
'ticketId': ticketId,
|
||||
'flightId': flightId,
|
||||
'amount': amount,
|
||||
'method': method,
|
||||
'status': 'pending',
|
||||
'createdAt': now,
|
||||
'expiryTime': expiryTime,
|
||||
'flightDetails': flightDetails,
|
||||
'bandaraDetails': bandaraDetails,
|
||||
'porterServiceDetails': porterServiceDetails,
|
||||
'userDetails': userDetails,
|
||||
'passenger': passenger,
|
||||
'passengerDetails': passengerDetails,
|
||||
'numberSeat': numberSeat,
|
||||
};
|
||||
|
||||
await _firestore
|
||||
.collection('tickets')
|
||||
.doc(ticketId)
|
||||
.collection('payments')
|
||||
.doc(transactionId)
|
||||
.set(transactionData);
|
||||
|
||||
DocumentSnapshot seatData =
|
||||
await _firestore.collection('tickets').doc(ticketId).collection('flights').doc(flightId).get();
|
||||
|
||||
if (seatData.exists) {
|
||||
Map<String, dynamic>? data = seatData.data() as Map<String, dynamic>?;
|
||||
|
||||
// Fungsi untuk mendapatkan kelas seat dari nomor kursi (misalnya "A2" -> "a")
|
||||
String getSeatClass(String seatNumber) {
|
||||
// Ambil huruf pertama dan ubah ke lowercase
|
||||
if (seatNumber.isNotEmpty) {
|
||||
return seatNumber[0].toLowerCase();
|
||||
}
|
||||
return "a"; // Default ke "a" jika format tidak sesuai
|
||||
}
|
||||
|
||||
// Fungsi untuk mendapatkan indeks seat dari nomor kursi (misalnya "A2" -> 2)
|
||||
int getSeatIndex(String seatNumber) {
|
||||
if (seatNumber.length > 1) {
|
||||
try {
|
||||
return int.parse(seatNumber.substring(1)) - 1; // Konversi ke berbasis-0
|
||||
} catch (e) {
|
||||
log("Error parsing seat index: $e");
|
||||
}
|
||||
}
|
||||
return 0; // Default ke 0 jika format tidak sesuai
|
||||
}
|
||||
|
||||
// Perbarui status kursi untuk setiap seat yang dipilih
|
||||
for (String seatNumber in numberSeat) {
|
||||
String seatClass = getSeatClass(seatNumber);
|
||||
int seatIndex = getSeatIndex(seatNumber);
|
||||
|
||||
log("Processing seat: $seatNumber, class: $seatClass, index: $seatIndex");
|
||||
|
||||
// Pastikan struktur data seat tersedia
|
||||
if (data != null && data.containsKey('seat')) {
|
||||
Map<String, dynamic> seatData = Map<String, dynamic>.from(data['seat']);
|
||||
|
||||
// Pastikan kelas kursi (a-f) tersedia
|
||||
if (seatData.containsKey(seatClass)) {
|
||||
Map<String, dynamic> classSeatData = Map<String, dynamic>.from(seatData[seatClass]);
|
||||
|
||||
// Pastikan array isTaken tersedia
|
||||
if (classSeatData.containsKey('isTaken')) {
|
||||
List<dynamic> isTaken = List<dynamic>.from(classSeatData['isTaken'] ?? []);
|
||||
|
||||
// Perbarui array isTaken
|
||||
while (isTaken.length <= seatIndex) {
|
||||
isTaken.add(false); // Tambahkan seat yang belum ada dengan false
|
||||
}
|
||||
isTaken[seatIndex] = true; // Set kursi yang dipilih sebagai 'taken'
|
||||
|
||||
// Update Firestore untuk kelas kursi tertentu
|
||||
await _firestore
|
||||
.collection('tickets')
|
||||
.doc(ticketId)
|
||||
.collection('flights')
|
||||
.doc(flightId)
|
||||
.update({'seat.$seatClass.isTaken': isTaken});
|
||||
|
||||
log("Successfully updated seat $seatNumber in class $seatClass at index $seatIndex");
|
||||
} else {
|
||||
// Jika 'isTaken' tidak ada, buat array baru
|
||||
List<dynamic> isTaken = List.filled(seatIndex + 1, false);
|
||||
isTaken[seatIndex] = true;
|
||||
|
||||
await _firestore
|
||||
.collection('tickets')
|
||||
.doc(ticketId)
|
||||
.collection('flights')
|
||||
.doc(flightId)
|
||||
.update({'seat.$seatClass.isTaken': isTaken});
|
||||
|
||||
log("Created new isTaken array for seat $seatNumber in class $seatClass");
|
||||
}
|
||||
} else {
|
||||
// Jika kelas kursi tidak ada, buat struktur baru
|
||||
List<dynamic> isTaken = List.filled(seatIndex + 1, false);
|
||||
isTaken[seatIndex] = true;
|
||||
|
||||
await _firestore.collection('tickets').doc(ticketId).collection('flights').doc(flightId).update({
|
||||
'seat.$seatClass': {'isTaken': isTaken}
|
||||
});
|
||||
|
||||
log("Created new seat class $seatClass for seat $seatNumber");
|
||||
}
|
||||
} else {
|
||||
// Jika struktur 'seat' tidak ada, buat struktur lengkap
|
||||
List<dynamic> isTaken = List.filled(seatIndex + 1, false);
|
||||
isTaken[seatIndex] = true;
|
||||
|
||||
Map<String, dynamic> newSeatData = {
|
||||
'seat': {
|
||||
seatClass: {'isTaken': isTaken}
|
||||
}
|
||||
};
|
||||
|
||||
await _firestore
|
||||
.collection('tickets')
|
||||
.doc(ticketId)
|
||||
.collection('flights')
|
||||
.doc(flightId)
|
||||
.set(newSeatData, SetOptions(merge: true));
|
||||
|
||||
log("Created complete new seat structure for seat $seatNumber");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log("Flight document not found");
|
||||
throw Exception("Flight document not found");
|
||||
}
|
||||
|
||||
final databaseRef = FirebaseDatabase.instance.ref();
|
||||
final userId = userDetails['uid'];
|
||||
await databaseRef.child('transactions/$userId/$ticketId/$transactionId').set({
|
||||
'payment': {
|
||||
'id': transactionId,
|
||||
'status': 'pending',
|
||||
'amount': amount,
|
||||
'method': method,
|
||||
'createdAt': now.millisecondsSinceEpoch,
|
||||
'expiryTime': expiryTime.millisecondsSinceEpoch,
|
||||
},
|
||||
'flight': flightDetails,
|
||||
'bandara': bandaraDetails,
|
||||
'porterService': porterServiceDetails,
|
||||
'user': userDetails,
|
||||
'passenger': passenger,
|
||||
'passengerDetails': passengerDetails,
|
||||
'numberSeat': numberSeat,
|
||||
});
|
||||
|
||||
return transactionId;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to create transaction: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateTransactionStatus({
|
||||
required String ticketId,
|
||||
required String transactionId,
|
||||
required String status,
|
||||
required String userId,
|
||||
}) async {
|
||||
try {
|
||||
final now = DateTime.now();
|
||||
|
||||
await _firestore.collection('tickets').doc(ticketId).collection('payments').doc(transactionId).update({
|
||||
'status': status,
|
||||
'updatedAt': now,
|
||||
});
|
||||
|
||||
// Update status dokumen tiket utama
|
||||
await _firestore.collection('tickets').doc(ticketId).update({
|
||||
'status': status == 'paid' ? 'awaiting_verification' : status,
|
||||
'lastUpdated': now,
|
||||
});
|
||||
|
||||
// Update status di Realtime Database
|
||||
final databaseRef = FirebaseDatabase.instance.ref();
|
||||
await databaseRef.child('transactions/$userId/$ticketId/$transactionId/payment').update({
|
||||
'status': status,
|
||||
'updatedAt': now.millisecondsSinceEpoch,
|
||||
});
|
||||
} catch (e) {
|
||||
throw Exception('Failed to update transaction status: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> uploadPaymentProof(
|
||||
{required String ticketId, required String transactionId, required File proofImage}) async {
|
||||
try {
|
||||
final fileName =
|
||||
'payment_proof_${transactionId}_${DateTime.now().millisecondsSinceEpoch}${path.extension(proofImage.path)}';
|
||||
final storageRef = _storage.ref().child('payment/$fileName');
|
||||
|
||||
// Upload file ke Firebase Storage
|
||||
final uploadTask = await storageRef.putFile(proofImage);
|
||||
final downloadUrl = await uploadTask.ref.getDownloadURL();
|
||||
|
||||
// Update di Firestore dengan URL bukti pembayaran
|
||||
await _firestore.collection('tickets').doc(ticketId).collection('payments').doc(transactionId).update({
|
||||
'proofUrl': downloadUrl,
|
||||
'status': 'paid',
|
||||
'paidAt': DateTime.now(),
|
||||
});
|
||||
|
||||
// Update status dokumen tiket utama
|
||||
await _firestore.collection('tickets').doc(ticketId).update({
|
||||
'status': 'awaiting_verification',
|
||||
'lastUpdated': DateTime.now(),
|
||||
});
|
||||
|
||||
// Update di Realtime Database
|
||||
final databaseRef = FirebaseDatabase.instance.ref();
|
||||
await databaseRef.child('transactions/$ticketId/payment').update({
|
||||
'proofUrl': downloadUrl,
|
||||
'status': 'paid',
|
||||
'paidAt': DateTime.now().millisecondsSinceEpoch,
|
||||
});
|
||||
} catch (e) {
|
||||
throw Exception('Failed to upload payment proof: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<TransactionModel>> getTransactionsByUserId(String userId) async {
|
||||
try {
|
||||
// Mencari tiket berdasarkan userId
|
||||
final ticketQuerySnapshot = await _firestore.collection('tickets').where('userId', isEqualTo: userId).get();
|
||||
|
||||
final List<TransactionModel> transactions = [];
|
||||
|
||||
// Untuk setiap tiket, ambil data payment
|
||||
for (var ticketDoc in ticketQuerySnapshot.docs) {
|
||||
final ticketId = ticketDoc.id;
|
||||
final paymentsSnapshot = await _firestore.collection('tickets').doc(ticketId).collection('payments').get();
|
||||
|
||||
for (var paymentDoc in paymentsSnapshot.docs) {
|
||||
final data = paymentDoc.data();
|
||||
data['id'] = paymentDoc.id;
|
||||
transactions.add(TransactionModel.fromJson(data));
|
||||
}
|
||||
}
|
||||
|
||||
return transactions;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to get transactions: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TransactionModel?> getTransactionById({required String ticketId, required String transactionId}) async {
|
||||
try {
|
||||
final docSnapshot =
|
||||
await _firestore.collection('tickets').doc(ticketId).collection('payments').doc(transactionId).get();
|
||||
|
||||
if (docSnapshot.exists) {
|
||||
final data = docSnapshot.data()!;
|
||||
data['id'] = docSnapshot.id;
|
||||
return TransactionModel.fromJson(data);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to get transaction: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> syncTransactionToRealtimeDB({required String ticketId, required String transactionId}) async {
|
||||
try {
|
||||
final transaction = await getTransactionById(ticketId: ticketId, transactionId: transactionId);
|
||||
|
||||
if (transaction != null) {
|
||||
final databaseRef = FirebaseDatabase.instance.ref();
|
||||
await databaseRef.child('transactions/$ticketId').set({
|
||||
'payment': {
|
||||
'id': transaction.id,
|
||||
'status': transaction.status,
|
||||
'amount': transaction.amount,
|
||||
'method': transaction.method,
|
||||
'proofUrl': transaction.proofUrl,
|
||||
'createdAt': transaction.createdAt.millisecondsSinceEpoch,
|
||||
'expiryTime': transaction.expiryTime.millisecondsSinceEpoch,
|
||||
},
|
||||
'flight': transaction.flightDetails,
|
||||
'bandara': transaction.bandaraDetails,
|
||||
'porterService': transaction.porterServiceDetails,
|
||||
'user': transaction.userDetails,
|
||||
'passenger': transaction.passenger,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Failed to sync transaction to Realtime DB: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<TransactionModel?> watchTransaction({required String ticketId, required String transactionId}) {
|
||||
return _firestore
|
||||
.collection('tickets')
|
||||
.doc(ticketId)
|
||||
.collection('payments')
|
||||
.doc(transactionId)
|
||||
.snapshots()
|
||||
.map((snapshot) {
|
||||
if (snapshot.exists) {
|
||||
final data = snapshot.data()!;
|
||||
data['id'] = snapshot.id;
|
||||
return TransactionModel.fromJson(data);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> checkAndCancelExpiredTransactions() async {
|
||||
try {
|
||||
final now = DateTime.now();
|
||||
final pendingTransactionsSnapshot =
|
||||
await _firestore.collectionGroup('payments').where('status', isEqualTo: 'pending').get();
|
||||
|
||||
for (var doc in pendingTransactionsSnapshot.docs) {
|
||||
final data = doc.data();
|
||||
final expiryTime = (data['expiryTime'] as Timestamp).toDate();
|
||||
|
||||
if (expiryTime.isBefore(now)) {
|
||||
final ticketId = data['ticketId'];
|
||||
final transactionId = doc.id;
|
||||
final userId = data['userDetails']['uid'];
|
||||
|
||||
await _firestore.collection('tickets').doc(ticketId).collection('payments').doc(transactionId).update({
|
||||
'status': 'cancelled',
|
||||
'updatedAt': now,
|
||||
});
|
||||
|
||||
await _firestore.collection('tickets').doc(ticketId).update({
|
||||
'status': 'cancelled',
|
||||
'lastUpdated': now,
|
||||
});
|
||||
|
||||
final databaseRef = FirebaseDatabase.instance.ref();
|
||||
await databaseRef.child('transactions/$userId/$ticketId/$transactionId/payment').update({
|
||||
'status': 'cancelled',
|
||||
'updatedAt': now.millisecondsSinceEpoch,
|
||||
});
|
||||
|
||||
log('Transaction $transactionId cancelled due to expiry');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log('Error checking expired transactions: $e');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:e_porter/domain/repositories/transaction_repository.dart';
|
||||
import 'package:e_porter/data/repositories/transaction_repository_impl.dart';
|
||||
import 'package:e_porter/domain/usecases/transaction_usecase.dart';
|
||||
import 'package:e_porter/presentation/controllers/transaction_controller.dart';
|
||||
|
||||
class TransactionBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
// Repository
|
||||
Get.lazyPut<TransactionRepository>(
|
||||
() => TransactionRepositoryImpl(),
|
||||
);
|
||||
|
||||
// UseCase
|
||||
Get.lazyPut<TransactionUseCase>(
|
||||
() => TransactionUseCase(Get.find<TransactionRepository>()),
|
||||
);
|
||||
|
||||
// Controller
|
||||
Get.lazyPut<TransactionController>(
|
||||
() => TransactionController(Get.find<TransactionUseCase>()),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
|
||||
class TransactionModel {
|
||||
final String id;
|
||||
final String ticketId;
|
||||
final String flightId;
|
||||
final double amount;
|
||||
final String method;
|
||||
final String status;
|
||||
final String? proofUrl;
|
||||
final DateTime createdAt;
|
||||
final DateTime expiryTime;
|
||||
final Map<String, dynamic> flightDetails;
|
||||
final Map<String, dynamic> bandaraDetails;
|
||||
final Map<String, dynamic>? porterServiceDetails;
|
||||
final Map<String, dynamic> userDetails;
|
||||
final int passenger;
|
||||
|
||||
TransactionModel({
|
||||
required this.id,
|
||||
required this.ticketId,
|
||||
required this.flightId,
|
||||
required this.amount,
|
||||
required this.method,
|
||||
required this.status,
|
||||
this.proofUrl,
|
||||
required this.createdAt,
|
||||
required this.expiryTime,
|
||||
required this.flightDetails,
|
||||
required this.bandaraDetails,
|
||||
this.porterServiceDetails,
|
||||
required this.userDetails,
|
||||
required this.passenger,
|
||||
});
|
||||
|
||||
factory TransactionModel.fromJson(Map<String, dynamic> json) {
|
||||
return TransactionModel(
|
||||
id: json['id'] ?? '',
|
||||
ticketId: json['ticketId'] ?? '',
|
||||
flightId: json['flightId'] ?? '',
|
||||
amount: (json['amount'] ?? 0.0).toDouble(),
|
||||
method: json['method'] ?? '',
|
||||
status: json['status'] ?? 'pending',
|
||||
proofUrl: json['proofUrl'],
|
||||
createdAt: (json['createdAt'] as Timestamp).toDate(),
|
||||
expiryTime: (json['expiryTime'] as Timestamp).toDate(),
|
||||
flightDetails: json['flightDetails'] ?? {},
|
||||
bandaraDetails: json['bandaraDetails'] ?? {},
|
||||
porterServiceDetails: json['porterServiceDetails'],
|
||||
userDetails: json['userDetails'] ?? {},
|
||||
passenger: json['passenger'] ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'ticketId': ticketId,
|
||||
'flightId': flightId,
|
||||
'amount': amount,
|
||||
'method': method,
|
||||
'status': status,
|
||||
'proofUrl': proofUrl,
|
||||
'createdAt': createdAt,
|
||||
'expiryTime': expiryTime,
|
||||
'flightDetails': flightDetails,
|
||||
'bandaraDetails': bandaraDetails,
|
||||
'porterServiceDetails': porterServiceDetails,
|
||||
'userDetails': userDetails,
|
||||
'passenger': passenger,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
import 'dart:io';
|
||||
import 'package:e_porter/domain/models/transaction_model.dart';
|
||||
|
||||
abstract class TransactionRepository {
|
||||
Future<String> createTransaction({
|
||||
required String ticketId,
|
||||
required String flightId,
|
||||
required double amount,
|
||||
required String method,
|
||||
required DateTime expiryTime,
|
||||
required Map<String, dynamic> flightDetails,
|
||||
required Map<String, dynamic> bandaraDetails,
|
||||
Map<String, dynamic>? porterServiceDetails,
|
||||
required Map<String, dynamic> userDetails,
|
||||
required int passenger,
|
||||
required List<Map<String, dynamic>> passengerDetails,
|
||||
required List<String> numberSeat,
|
||||
});
|
||||
|
||||
Future<void> updateTransactionStatus({
|
||||
required String ticketId,
|
||||
required String transactionId,
|
||||
required String status,
|
||||
required String userId,
|
||||
});
|
||||
|
||||
Future<void> uploadPaymentProof({
|
||||
required String ticketId,
|
||||
required String transactionId,
|
||||
required File proofImage,
|
||||
});
|
||||
|
||||
Future<List<TransactionModel>> getTransactionsByUserId(String userId);
|
||||
|
||||
Future<TransactionModel?> getTransactionById({required String ticketId, required String transactionId});
|
||||
|
||||
Future<void> syncTransactionToRealtimeDB({required String ticketId, required String transactionId});
|
||||
|
||||
Stream<TransactionModel?> watchTransaction({required String ticketId, required String transactionId});
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
import 'dart:io';
|
||||
import 'package:e_porter/domain/models/transaction_model.dart';
|
||||
import 'package:e_porter/domain/repositories/transaction_repository.dart';
|
||||
|
||||
class TransactionUseCase {
|
||||
final TransactionRepository _repository;
|
||||
|
||||
TransactionUseCase(this._repository);
|
||||
|
||||
Future<String> createTransaction({
|
||||
required String ticketId,
|
||||
required String flightId,
|
||||
required double amount,
|
||||
required String method,
|
||||
required DateTime expiryTime,
|
||||
required Map<String, dynamic> flightDetails,
|
||||
required Map<String, dynamic> bandaraDetails,
|
||||
Map<String, dynamic>? porterServiceDetails,
|
||||
required Map<String, dynamic> userDetails,
|
||||
required int passenger,
|
||||
required List<Map<String, dynamic>> passengerDetails, // Tambah parameter ini
|
||||
required List<String> numberSeat, // Tambah parameter ini
|
||||
}) {
|
||||
return _repository.createTransaction(
|
||||
ticketId: ticketId,
|
||||
flightId: flightId,
|
||||
amount: amount,
|
||||
method: method,
|
||||
expiryTime: expiryTime,
|
||||
flightDetails: flightDetails,
|
||||
bandaraDetails: bandaraDetails,
|
||||
porterServiceDetails: porterServiceDetails,
|
||||
userDetails: userDetails,
|
||||
passenger: passenger,
|
||||
passengerDetails: passengerDetails, // Tambahkan parameter ini
|
||||
numberSeat: numberSeat, // Tambahkan parameter ini
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> updateTransactionStatus({
|
||||
required String ticketId,
|
||||
required String transactionId,
|
||||
required String status,
|
||||
required String userId,
|
||||
}) {
|
||||
return _repository.updateTransactionStatus(
|
||||
ticketId: ticketId,
|
||||
transactionId: transactionId,
|
||||
status: status,
|
||||
userId: userId,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> uploadPaymentProof({
|
||||
required String ticketId,
|
||||
required String transactionId,
|
||||
required File proofImage,
|
||||
}) {
|
||||
return _repository.uploadPaymentProof(
|
||||
ticketId: ticketId,
|
||||
transactionId: transactionId,
|
||||
proofImage: proofImage,
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<TransactionModel>> getTransactionsByUserId(String userId) {
|
||||
return _repository.getTransactionsByUserId(userId);
|
||||
}
|
||||
|
||||
Future<TransactionModel?> getTransactionById({required String ticketId, required String transactionId}) {
|
||||
return _repository.getTransactionById(ticketId: ticketId, transactionId: transactionId);
|
||||
}
|
||||
|
||||
Future<void> syncTransactionToRealtimeDB({required String ticketId, required String transactionId}) {
|
||||
return _repository.syncTransactionToRealtimeDB(ticketId: ticketId, transactionId: transactionId);
|
||||
}
|
||||
|
||||
Stream<TransactionModel?> watchTransaction({required String ticketId, required String transactionId}) {
|
||||
return _repository.watchTransaction(ticketId: ticketId, transactionId: transactionId);
|
||||
}
|
||||
}
|
|
@ -1,13 +1,19 @@
|
|||
import 'dart:developer';
|
||||
import 'package:e_porter/data/repositories/transaction_repository_impl.dart';
|
||||
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '_core/service/transaction_expiry_service.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp();
|
||||
|
||||
final transactionRepo = Get.put(TransactionRepositoryImpl());
|
||||
TransactionExpiryService().initialize(transactionRepo);
|
||||
|
||||
log("Firebase Initialized Successfully!");
|
||||
runApp(MyApp(initialRoute: Routes.SPLASH));
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
import 'dart:io';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:e_porter/domain/models/transaction_model.dart';
|
||||
import 'package:e_porter/domain/usecases/transaction_usecase.dart';
|
||||
import 'package:e_porter/_core/service/logger_service.dart';
|
||||
|
||||
class TransactionController extends GetxController {
|
||||
final TransactionUseCase _transactionUseCase;
|
||||
|
||||
TransactionController(this._transactionUseCase);
|
||||
|
||||
final Rx<TransactionModel?> currentTransaction = Rx<TransactionModel?>(null);
|
||||
final RxBool isLoading = false.obs;
|
||||
final RxString error = ''.obs;
|
||||
|
||||
Future<String> createTransaction({
|
||||
required String ticketId,
|
||||
required String flightId,
|
||||
required double amount,
|
||||
required String method,
|
||||
required DateTime expiryTime,
|
||||
required Map<String, dynamic> flightDetails,
|
||||
required Map<String, dynamic> bandaraDetails,
|
||||
Map<String, dynamic>? porterServiceDetails,
|
||||
required Map<String, dynamic> userDetails,
|
||||
required int passenger,
|
||||
required List<Map<String, dynamic>> passengerDetails, // Tambah parameter ini
|
||||
required List<String> numberSeat, // Tambah parameter ini
|
||||
}) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
error.value = '';
|
||||
|
||||
final transactionId = await _transactionUseCase.createTransaction(
|
||||
ticketId: ticketId,
|
||||
flightId: flightId,
|
||||
amount: amount,
|
||||
method: method,
|
||||
expiryTime: expiryTime,
|
||||
flightDetails: flightDetails,
|
||||
bandaraDetails: bandaraDetails,
|
||||
porterServiceDetails: porterServiceDetails,
|
||||
userDetails: userDetails,
|
||||
passenger: passenger,
|
||||
passengerDetails: passengerDetails,
|
||||
numberSeat: numberSeat,
|
||||
);
|
||||
|
||||
// Ambil data transaksi setelah berhasil dibuat
|
||||
final transaction = await _transactionUseCase.getTransactionById(
|
||||
ticketId: ticketId,
|
||||
transactionId: transactionId,
|
||||
);
|
||||
|
||||
currentTransaction.value = transaction;
|
||||
return transactionId;
|
||||
} catch (e) {
|
||||
logger.e('Gagal membuat transaksi: $e');
|
||||
error.value = 'Gagal membuat transaksi: $e';
|
||||
throw Exception('Gagal membuat transaksi: $e');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> uploadPaymentProof(
|
||||
{required String ticketId, required String transactionId, required File proofImage}) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
error.value = '';
|
||||
|
||||
await _transactionUseCase.uploadPaymentProof(
|
||||
ticketId: ticketId, transactionId: transactionId, proofImage: proofImage);
|
||||
|
||||
// Refresh data transaksi setelah bukti pembayaran diunggah
|
||||
final transaction =
|
||||
await _transactionUseCase.getTransactionById(ticketId: ticketId, transactionId: transactionId);
|
||||
|
||||
currentTransaction.value = transaction;
|
||||
} catch (e) {
|
||||
logger.e('Gagal mengunggah bukti pembayaran: $e');
|
||||
error.value = 'Gagal mengunggah bukti pembayaran: $e';
|
||||
throw Exception('Gagal mengunggah bukti pembayaran: $e');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<TransactionModel>> getTransactionsByUserId(String userId) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
error.value = '';
|
||||
|
||||
final transactions = await _transactionUseCase.getTransactionsByUserId(userId);
|
||||
return transactions;
|
||||
} catch (e) {
|
||||
logger.e('Gagal mendapatkan daftar transaksi: $e');
|
||||
error.value = 'Gagal mendapatkan daftar transaksi: $e';
|
||||
throw Exception('Gagal mendapatkan daftar transaksi: $e');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getTransactionById({required String ticketId, required String transactionId}) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
error.value = '';
|
||||
|
||||
final transaction =
|
||||
await _transactionUseCase.getTransactionById(ticketId: ticketId, transactionId: transactionId);
|
||||
|
||||
currentTransaction.value = transaction;
|
||||
} catch (e) {
|
||||
logger.e('Gagal mendapatkan detail transaksi: $e');
|
||||
error.value = 'Gagal mendapatkan detail transaksi: $e';
|
||||
throw Exception('Gagal mendapatkan detail transaksi: $e');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
void watchTransaction({required String ticketId, required String transactionId}) {
|
||||
try {
|
||||
_transactionUseCase.watchTransaction(ticketId: ticketId, transactionId: transactionId).listen(
|
||||
(transaction) {
|
||||
currentTransaction.value = transaction;
|
||||
},
|
||||
onError: (e) {
|
||||
logger.e('Error mendengarkan perubahan transaksi: $e');
|
||||
error.value = 'Error mendengarkan perubahan transaksi: $e';
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
logger.e('Gagal memantau transaksi: $e');
|
||||
error.value = 'Gagal memantau transaksi: $e';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateTransactionStatus({
|
||||
required String ticketId,
|
||||
required String transactionId,
|
||||
required String status,
|
||||
required String userId,
|
||||
}) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
error.value = '';
|
||||
|
||||
await _transactionUseCase.updateTransactionStatus(
|
||||
ticketId: ticketId,
|
||||
transactionId: transactionId,
|
||||
status: status,
|
||||
userId: userId,
|
||||
);
|
||||
|
||||
// Refresh data transaksi setelah status diupdate
|
||||
final transaction = await _transactionUseCase.getTransactionById(
|
||||
ticketId: ticketId,
|
||||
transactionId: transactionId,
|
||||
);
|
||||
|
||||
currentTransaction.value = transaction;
|
||||
} catch (e) {
|
||||
logger.e('Gagal mengupdate status transaksi: $e');
|
||||
error.value = 'Gagal mengupdate status transaksi: $e';
|
||||
throw Exception('Gagal mengupdate status transaksi: $e');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,10 +13,13 @@ import 'package:intl/intl.dart';
|
|||
import '../../../../_core/component/appbar/appbar_component.dart';
|
||||
import '../../../../_core/component/icons/icons_library.dart';
|
||||
import '../../../../_core/service/logger_service.dart';
|
||||
import '../../../../_core/service/preferences_service.dart';
|
||||
import '../../../../_core/utils/snackbar/snackbar_helper.dart';
|
||||
import '../../../../domain/models/porter_service_model.dart';
|
||||
import '../../../../domain/models/ticket_model.dart';
|
||||
import '../../../../domain/models/user_entity.dart';
|
||||
import '../../../controllers/ticket_controller.dart';
|
||||
import '../../../controllers/transaction_controller.dart';
|
||||
import '../component/card_flight_information.dart';
|
||||
|
||||
class TicketBookingStep4Screen extends StatefulWidget {
|
||||
|
@ -41,6 +44,7 @@ class _TicketBookingStep4ScreenState extends State<TicketBookingStep4Screen> {
|
|||
final double serviceCharge = 10000.0;
|
||||
|
||||
final TicketController ticketController = Get.find<TicketController>();
|
||||
final TransactionController transactionController = Get.find<TransactionController>();
|
||||
FlightModel? flightData;
|
||||
String? departureTime;
|
||||
String? arrivalTime;
|
||||
|
@ -218,26 +222,137 @@ class _TicketBookingStep4ScreenState extends State<TicketBookingStep4Screen> {
|
|||
price: "Rp ${NumberFormat.decimalPattern('id_ID').format(totalAll())}",
|
||||
labelButton: "Buat Pesanan",
|
||||
iconButton: CustomeIcons.ProtectOutline(color: Colors.white),
|
||||
onTap: () {
|
||||
final DateTime currentTime = DateTime.now();
|
||||
final DateTime expiryTime = currentTime.add(Duration(hours: 1));
|
||||
final String formattedExpiryTime =
|
||||
"${DateFormat('dd MMMM yyyy', 'en_US').format(expiryTime)}, ${DateFormat.Hm().format(expiryTime)}";
|
||||
final argument = {
|
||||
'ticketId': ticketId,
|
||||
'flightId': flightId,
|
||||
'date': ticketDate,
|
||||
'passenger': passenger,
|
||||
'selectedPassenger': selectedPassengers,
|
||||
'numberSeat': numberSeat,
|
||||
'totalPrice': totalPrice,
|
||||
'grandTotal': grandTotal,
|
||||
'selectedServiceLabels': selectedServiceLabels,
|
||||
'selectedPorterServices': selectedPorterServices,
|
||||
'totalAll': totalAll(),
|
||||
'expiryTime': formattedExpiryTime,
|
||||
};
|
||||
Get.toNamed(Routes.PAYMENT, arguments: argument);
|
||||
onTap: () async {
|
||||
try {
|
||||
Get.dialog(
|
||||
Center(child: CircularProgressIndicator()),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
|
||||
final userData = await PreferencesService.getUserData();
|
||||
if (userData == null) {
|
||||
Get.back(); // close dialog
|
||||
SnackbarHelper.showError('Error', 'Data pengguna tidak ditemukan');
|
||||
return;
|
||||
}
|
||||
|
||||
// Persiapkan data expiry time
|
||||
final DateTime currentTime = DateTime.now();
|
||||
final DateTime expiryTime = currentTime.add(Duration(seconds: 5));
|
||||
|
||||
// Persiapkan data bandara
|
||||
final bandaraData = {
|
||||
'departure': {
|
||||
'code': flightData?.codeDeparture,
|
||||
'city': flightData?.cityDeparture,
|
||||
},
|
||||
'arrival': {
|
||||
'code': flightData?.codeArrival,
|
||||
'city': flightData?.cityArrival,
|
||||
},
|
||||
};
|
||||
|
||||
// Persiapkan data flight
|
||||
final flightDataMap = {
|
||||
'airLines': flightData?.airLines,
|
||||
'code': flightData?.code,
|
||||
'cityDeparture': flightData?.cityDeparture,
|
||||
'cityArrival': flightData?.cityArrival,
|
||||
'codeDeparture': flightData?.codeDeparture,
|
||||
'codeArrival': flightData?.codeArrival,
|
||||
'departureTime': departureTime,
|
||||
'arrivalTime': arrivalTime,
|
||||
'flightClass': flightData?.flightClass,
|
||||
'transitAirplane': flightData?.transitAirplane,
|
||||
'stop': flightData?.stop,
|
||||
'airlineLogo': flightData?.airlineLogo,
|
||||
'price': flightData?.price,
|
||||
};
|
||||
|
||||
// Persiapkan data porter service jika ada
|
||||
Map<String, dynamic>? porterServiceData;
|
||||
if (selectedPorterServices.isNotEmpty) {
|
||||
porterServiceData = {};
|
||||
selectedPorterServices.forEach((key, value) {
|
||||
if (value != null) {
|
||||
porterServiceData![key] = {
|
||||
'name': value.name,
|
||||
'price': value.price,
|
||||
'description': value.description,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Persiapkan data user
|
||||
final userDetailData = {
|
||||
'uid': userData.uid,
|
||||
'name': userData.name,
|
||||
'email': userData.email,
|
||||
'phone': userData.phone,
|
||||
};
|
||||
|
||||
final List<Map<String, dynamic>> passengerDetailsList = [];
|
||||
for (var passenger in selectedPassengers) {
|
||||
if (passenger != null) {
|
||||
passengerDetailsList.add({
|
||||
'name': passenger.name,
|
||||
'typeId': passenger.typeId,
|
||||
'noId': passenger.noId,
|
||||
'gender': passenger.gender,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Buat transaksi
|
||||
final transactionId = await transactionController.createTransaction(
|
||||
ticketId: ticketId,
|
||||
flightId: flightId,
|
||||
amount: totalAll(),
|
||||
method: 'QRIS',
|
||||
expiryTime: expiryTime,
|
||||
flightDetails: flightDataMap,
|
||||
bandaraDetails: bandaraData,
|
||||
porterServiceDetails: porterServiceData,
|
||||
userDetails: userDetailData,
|
||||
passenger: passenger,
|
||||
passengerDetails: passengerDetailsList,
|
||||
numberSeat: numberSeat,
|
||||
);
|
||||
|
||||
// Tutup dialog loading
|
||||
Get.back();
|
||||
|
||||
// Format expiry time untuk tampilan
|
||||
final formattedExpiryTime =
|
||||
"${DateFormat('dd MMMM yyyy', 'en_US').format(expiryTime)}, ${DateFormat.Hm().format(expiryTime)}";
|
||||
|
||||
// Navigasi ke halaman pembayaran
|
||||
final argument = {
|
||||
'ticketId': ticketId,
|
||||
'flightId': flightId,
|
||||
'transactionId': transactionId,
|
||||
'date': ticketDate,
|
||||
'passenger': passenger,
|
||||
'selectedPassenger': selectedPassengers,
|
||||
'numberSeat': numberSeat,
|
||||
'totalPrice': totalPrice,
|
||||
'grandTotal': grandTotal,
|
||||
'selectedServiceLabels': selectedServiceLabels,
|
||||
'selectedPorterServices': selectedPorterServices,
|
||||
'totalAll': totalAll(),
|
||||
'expiryTime': formattedExpiryTime,
|
||||
};
|
||||
|
||||
Get.toNamed(Routes.PAYMENT, arguments: argument);
|
||||
} catch (e) {
|
||||
// Tutup dialog loading jika terjadi error
|
||||
if (Get.isDialogOpen ?? false) {
|
||||
Get.back();
|
||||
}
|
||||
|
||||
SnackbarHelper.showError('Error', 'Gagal membuat pesanan: $e');
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:e_porter/domain/bindings/porter_service_binding.dart';
|
|||
import 'package:e_porter/domain/bindings/profil_binding.dart';
|
||||
import 'package:e_porter/domain/bindings/search_flight_binding.dart';
|
||||
import 'package:e_porter/domain/bindings/ticket_binding.dart';
|
||||
import 'package:e_porter/domain/bindings/transaction_binding.dart';
|
||||
import 'package:e_porter/presentation/screens/auth/pages/forget_password_screen.dart';
|
||||
import 'package:e_porter/presentation/screens/auth/pages/login_screen.dart';
|
||||
import 'package:e_porter/presentation/screens/auth/pages/register_screen.dart';
|
||||
|
@ -112,6 +113,7 @@ class AppRoutes {
|
|||
GetPage(
|
||||
name: Routes.TICKETBOOKINGSTEP4,
|
||||
page: () => TicketBookingStep4Screen(),
|
||||
binding: TransactionBinding(),
|
||||
),
|
||||
GetPage(
|
||||
name: Routes.CHOOSECHAIR,
|
||||
|
|
|
@ -10,6 +10,7 @@ import device_info_plus
|
|||
import file_picker
|
||||
import firebase_auth
|
||||
import firebase_core
|
||||
import firebase_database
|
||||
import firebase_storage
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
|
@ -20,6 +21,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
|
||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||
FLTFirebaseDatabasePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseDatabasePlugin"))
|
||||
FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
|
|
48
pubspec.lock
48
pubspec.lock
|
@ -241,6 +241,30 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.22.0"
|
||||
firebase_database:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_database
|
||||
sha256: "182ce4713d47ffc5f19a5a7b934867d1fae9c33081febcec8c062cb89fc14652"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.3.5"
|
||||
firebase_database_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_database_platform_interface
|
||||
sha256: b65f416dd2c8ac2d5322241e5411a24ed3da43d0f38aaf9ab6c211d72e52261b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.6+5"
|
||||
firebase_database_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_database_web
|
||||
sha256: "5203141fe00a1edfaed5f8e0444b8e4ef807a8ec6eca925621b1cab69b6c06e4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.6+11"
|
||||
firebase_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -265,6 +289,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.10.12"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -637,6 +669,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sprintf
|
||||
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -685,6 +725,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
uuid:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: uuid
|
||||
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.1"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -47,6 +47,8 @@ dependencies:
|
|||
cloud_firestore: ^5.6.4
|
||||
firebase_auth: ^5.5.1
|
||||
firebase_storage: ^12.4.4
|
||||
uuid: ^4.5.1
|
||||
firebase_database: ^11.3.5
|
||||
shared_preferences: ^2.4.6
|
||||
logger: ^2.5.0
|
||||
dropdown_button2: ^2.3.9
|
||||
|
|
Loading…
Reference in New Issue