Feat: fix boarding pass after scan QR

This commit is contained in:
orangdeso 2025-05-19 10:38:59 +07:00
parent 00083b6e75
commit 2e38c7da39
10 changed files with 297 additions and 238 deletions

View File

@ -680,7 +680,7 @@
"languageVersion": "3.4" "languageVersion": "3.4"
} }
], ],
"generated": "2025-05-16T07:28:56.076101Z", "generated": "2025-05-18T15:09:53.002617Z",
"generator": "pub", "generator": "pub",
"generatorVersion": "3.5.0", "generatorVersion": "3.5.0",
"flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0", "flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0",

View File

@ -132,7 +132,6 @@ class HistoryRepositoryImpl implements HistoryRepository {
data['id'] = transactionId; data['id'] = transactionId;
data['ticketId'] = ticketId; data['ticketId'] = ticketId;
// Konversi ke model TransactionModel
final transaction = TransactionModel.fromJson(data); final transaction = TransactionModel.fromJson(data);
log('HistoryRepositoryImpl: berhasil mengambil transaksi dari Firestore'); log('HistoryRepositoryImpl: berhasil mengambil transaksi dari Firestore');
return transaction; return transaction;
@ -141,4 +140,53 @@ class HistoryRepositoryImpl implements HistoryRepository {
return null; return null;
} }
} }
@override
Future<bool> checkIfTicketHasPorter(String ticketId, String transactionId) async {
try {
log('HistoryRepositoryImpl: checking if ticket has porter, ticketId: $ticketId, transactionId: $transactionId');
final querySnapshot = await _firestore
.collection('porterTransactions')
.where('ticketId', isEqualTo: ticketId)
.where('transactionId', isEqualTo: transactionId)
.limit(1)
.get();
final hasPorter = querySnapshot.docs.isNotEmpty;
log('HistoryRepositoryImpl: ticket has porter: $hasPorter');
return hasPorter;
} catch (e) {
log('HistoryRepositoryImpl: error checking if ticket has porter: $e');
return false;
}
}
@override
Future<String?> getPorterTransactionId(String ticketId, String transactionId) async {
try {
log('HistoryRepositoryImpl: getting porter transaction ID, ticketId: $ticketId, transactionId: $transactionId');
final querySnapshot = await _firestore
.collection('porterTransactions')
.where('ticketId', isEqualTo: ticketId)
.where('transactionId', isEqualTo: transactionId)
.limit(1)
.get();
if (querySnapshot.docs.isEmpty) {
log('HistoryRepositoryImpl: no porter transaction found');
return null;
}
final porterTransactionId = querySnapshot.docs.first.id;
log('HistoryRepositoryImpl: found porter transaction ID: $porterTransactionId');
return porterTransactionId;
} catch (e) {
log('HistoryRepositoryImpl: error getting porter transaction ID: $e');
return null;
}
}
} }

View File

@ -1,4 +1,4 @@
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:e_porter/domain/repositories/statistic_repository.dart'; import 'package:e_porter/domain/repositories/statistic_repository.dart';
class StatisticRepositoryImpl implements StatisticRepository { class StatisticRepositoryImpl implements StatisticRepository {

View File

@ -4,4 +4,6 @@ abstract class HistoryRepository {
Stream<List<TransactionModel>> getTransactionsStream(String userId, String status); Stream<List<TransactionModel>> getTransactionsStream(String userId, String status);
Stream<List<TransactionModel>> getHistoryTransactionsStream(String userId); Stream<List<TransactionModel>> getHistoryTransactionsStream(String userId);
Future<TransactionModel?> getTransactionFromFirestore(String ticketId, String transactionId); Future<TransactionModel?> getTransactionFromFirestore(String ticketId, String transactionId);
Future<bool> checkIfTicketHasPorter(String ticketId, String transactionId);
Future<String?> getPorterTransactionId(String ticketId, String transactionId);
} }

View File

@ -22,4 +22,12 @@ class HistoryUseCase {
Future<TransactionModel?> getTransactionFromFirestore(String ticketId, String transactionId) { Future<TransactionModel?> getTransactionFromFirestore(String ticketId, String transactionId) {
return _repository.getTransactionFromFirestore(ticketId, transactionId); return _repository.getTransactionFromFirestore(ticketId, transactionId);
} }
Future<bool> checkIfTicketHasPorter(String ticketId, String transactionId) {
return _repository.checkIfTicketHasPorter(ticketId, transactionId);
}
Future<String?> getPorterTransactionId(String ticketId, String transactionId) {
return _repository.getPorterTransactionId(ticketId, transactionId);
}
} }

View File

@ -15,6 +15,7 @@ class HistoryController extends GetxController {
final RxBool isLoading = true.obs; final RxBool isLoading = true.obs;
final RxBool isCheckingExpiry = false.obs; final RxBool isCheckingExpiry = false.obs;
final RxBool hasAssignedPorter = false.obs;
final RxString errorMessage = ''.obs; final RxString errorMessage = ''.obs;
StreamSubscription? _pendingSubscription; StreamSubscription? _pendingSubscription;
@ -22,6 +23,7 @@ class HistoryController extends GetxController {
StreamSubscription? _historySubscription; StreamSubscription? _historySubscription;
String _currentUserId = ''; String _currentUserId = '';
String? currentPorterTransactionId;
HistoryController(this._historyUseCase); HistoryController(this._historyUseCase);
@ -44,18 +46,6 @@ class HistoryController extends GetxController {
isLoading.value = false; isLoading.value = false;
}); });
// _activeSubscription = _historyUseCase.getActiveTransactionsStream(userId).listen((transactions) {
// log('HistoryController: active transactions updated, count: ${transactions.length}');
// final sortedTransactions = _sortTransactionsByCreatedAt(transactions);
// activeTransactions.value = sortedTransactions;
// isLoading.value = false;
// }, onError: (error) {
// log('HistoryController: Error mendapatkan transaksi active: $error');
// isLoading.value = false;
// });
_activeSubscription = _historyUseCase.getActiveTransactionsStream(userId).map((list) { _activeSubscription = _historyUseCase.getActiveTransactionsStream(userId).map((list) {
final todayStart = DateTime( final todayStart = DateTime(
DateTime.now().year, DateTime.now().year,
@ -126,6 +116,12 @@ class HistoryController extends GetxController {
if (transaction != null) { if (transaction != null) {
selectedTransaction.value = transaction; selectedTransaction.value = transaction;
hasAssignedPorter.value = await _historyUseCase.checkIfTicketHasPorter(ticketId, transactionId);
if (hasAssignedPorter.value) {
currentPorterTransactionId = await _historyUseCase.getPorterTransactionId(ticketId, transactionId);
}
} else { } else {
errorMessage.value = 'Transaksi tidak ditemukan'; errorMessage.value = 'Transaksi tidak ditemukan';
} }
@ -140,6 +136,26 @@ class HistoryController extends GetxController {
} }
} }
Future<bool> checkIfTicketHasPorter(String ticketId, String transactionId) async {
try {
hasAssignedPorter.value = await _historyUseCase.checkIfTicketHasPorter(ticketId, transactionId);
return hasAssignedPorter.value;
} catch (e) {
log('HistoryController: error checking if ticket has porter: $e');
return false;
}
}
Future<String?> getPorterTransactionId(String ticketId, String transactionId) async {
try {
currentPorterTransactionId = await _historyUseCase.getPorterTransactionId(ticketId, transactionId);
return currentPorterTransactionId;
} catch (e) {
log('HistoryController: error getting porter transaction ID: $e');
return null;
}
}
Future<void> refreshTransactions(String userId) async { Future<void> refreshTransactions(String userId) async {
log('HistoryController: Memperbarui data transaksi untuk userId: $userId'); log('HistoryController: Memperbarui data transaksi untuk userId: $userId');

View File

@ -1,5 +1,4 @@
import 'dart:developer'; import 'dart:developer';
import 'package:e_porter/_core/component/button/button_outline.dart'; import 'package:e_porter/_core/component/button/button_outline.dart';
import 'package:e_porter/_core/component/dotted/dashed_line_component.dart'; import 'package:e_porter/_core/component/dotted/dashed_line_component.dart';
import 'package:e_porter/_core/constants/colors.dart'; import 'package:e_porter/_core/constants/colors.dart';
@ -14,7 +13,6 @@ import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:zoom_tap_animation/zoom_tap_animation.dart'; import 'package:zoom_tap_animation/zoom_tap_animation.dart';
import '../../../../_core/component/appbar/appbar_component.dart'; import '../../../../_core/component/appbar/appbar_component.dart';
import '../../../../_core/component/button/button_fill.dart'; import '../../../../_core/component/button/button_fill.dart';
import '../../../../_core/component/card/custome_shadow_cotainner.dart'; import '../../../../_core/component/card/custome_shadow_cotainner.dart';
@ -41,7 +39,6 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
final args = Get.arguments as Map<String, dynamic>; final args = Get.arguments as Map<String, dynamic>;
id_transaction = args['id_transaction']; id_transaction = args['id_transaction'];
id_ticket = args['id_ticket']; id_ticket = args['id_ticket'];
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_loadTransactionData(); _loadTransactionData();
}); });
@ -100,13 +97,17 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
TypographyStyles.caption( _buildUIHeader(
"Kode Booking Maskapai", value: "${transaction.idBooking}",
color: GrayColors.gray500, onTap: () {
fontWeight: FontWeight.w500, Get.toNamed(
Routes.PROCESSING,
arguments: {
'transactionPorterId': historyController.currentPorterTransactionId,
},
);
},
), ),
SizedBox(height: 6.h),
TypographyStyles.body("${transaction.idBooking}", color: GrayColors.gray800),
Padding( Padding(
padding: EdgeInsets.symmetric(vertical: 20.h), padding: EdgeInsets.symmetric(vertical: 20.h),
child: CustomDashedLine(), child: CustomDashedLine(),
@ -123,15 +124,7 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Row( Row(
children: [ children: _buildServiceInfoItems(transaction),
TypographyStyles.small("Fast Track (FT)",
color: GrayColors.gray600, fontWeight: FontWeight.w400),
SizedBox(width: 10.w),
CircleAvatar(radius: 2.r, backgroundColor: Color(0xFFD9D9D9)),
SizedBox(width: 10.w),
TypographyStyles.small("${transaction.flightDetails['flightClass']}",
color: GrayColors.gray600, fontWeight: FontWeight.w400),
],
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Row( Row(
@ -250,6 +243,7 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
if (!historyController.hasAssignedPorter.value)
ButtonOutline( ButtonOutline(
text: 'Scan QR Code Porter', text: 'Scan QR Code Porter',
textColor: PrimaryColors.primary800, textColor: PrimaryColors.primary800,
@ -271,9 +265,14 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
); );
return; return;
} }
if (result == 'SUCCESS') {
historyController.hasAssignedPorter.value = true;
_loadTransactionData();
}
}, },
), ),
SizedBox(height: 12.h), if (!historyController.hasAssignedPorter.value) SizedBox(height: 12.h),
ButtonFill( ButtonFill(
text: 'Cetak Boarding Pass', text: 'Cetak Boarding Pass',
textColor: Colors.white, textColor: Colors.white,
@ -297,6 +296,45 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
); );
} }
Widget _buildUIHeader({required String value, required VoidCallback? onTap}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.caption(
"Kode Booking Maskapai",
color: GrayColors.gray500,
fontWeight: FontWeight.w500,
),
SizedBox(height: 6.h),
TypographyStyles.body(value, color: GrayColors.gray800),
],
),
Obx(() {
if (historyController.hasAssignedPorter.value) {
return ZoomTapAnimation(
child: GestureDetector(
onTap: onTap,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.orange.shade400,
borderRadius: BorderRadius.circular(20.r),
),
child: TypographyStyles.small("Lihat Status Porter", color: Colors.white),
),
),
);
} else {
return SizedBox();
}
}),
],
);
}
Widget _buildDataBandara({ Widget _buildDataBandara({
required String titleDeparture, required String titleDeparture,
required String planeDeparture, required String planeDeparture,
@ -342,6 +380,48 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
); );
} }
List<Widget> _buildServiceInfoItems(TransactionModel transaction) {
List<Widget> items = [];
if (transaction.porterServiceDetails != null &&
(transaction.porterServiceDetails as Map<String, dynamic>).isNotEmpty) {
if ((transaction.porterServiceDetails as Map<String, dynamic>).containsKey('departure') &&
(transaction.porterServiceDetails as Map<String, dynamic>)['departure'] != null) {
final departureName =
(transaction.porterServiceDetails as Map<String, dynamic>)['departure']['name'] as String? ?? "Fast Track";
items.add(TypographyStyles.small(
departureName,
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
));
items.add(SizedBox(width: 10.w));
items.add(CircleAvatar(radius: 2.r, backgroundColor: Color(0xFFD9D9D9)));
items.add(SizedBox(width: 10.w));
}
if ((transaction.porterServiceDetails as Map<String, dynamic>).containsKey('transit') &&
(transaction.porterServiceDetails as Map<String, dynamic>)['transit'] != null) {
final transitName =
(transaction.porterServiceDetails as Map<String, dynamic>)['transit']['name'] as String? ?? "Transit";
items.add(TypographyStyles.small(
transitName,
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
));
items.add(SizedBox(width: 10.w));
items.add(CircleAvatar(radius: 2.r, backgroundColor: Color(0xFFD9D9D9)));
items.add(SizedBox(width: 10.w));
}
}
items.add(TypographyStyles.small(
"${transaction.flightDetails['flightClass']}",
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
));
return items;
}
void _showCetakBoardingPassBottomSheet(TransactionModel transaction) { void _showCetakBoardingPassBottomSheet(TransactionModel transaction) {
Get.bottomSheet( Get.bottomSheet(
backgroundColor: Colors.white, backgroundColor: Colors.white,

View File

@ -28,6 +28,7 @@ class _ScanQRScreenState extends State<ScanQRScreen> {
torchEnabled: false, torchEnabled: false,
returnImage: true, returnImage: true,
); );
bool isProcessing = false; bool isProcessing = false;
bool _isTorchOn = false; bool _isTorchOn = false;
@ -220,7 +221,7 @@ class _ScanQRScreenState extends State<ScanQRScreen> {
transactionId: transactionId, transactionId: transactionId,
location: rawLocation, location: rawLocation,
); );
await Future.delayed(Duration(seconds: 3)); // await Future.delayed(Duration(seconds: 3));
log('[ScanQRScreen] requestPorter succeeded: $result'); log('[ScanQRScreen] requestPorter succeeded: $result');
@ -245,7 +246,6 @@ class _ScanQRScreenState extends State<ScanQRScreen> {
} on Exception catch (e) { } on Exception catch (e) {
final msg = e.toString(); final msg = e.toString();
if (msg.contains('Porter tidak tersedia')) { if (msg.contains('Porter tidak tersedia')) {
// Porter sibuk langsung pop dengan result
Get.back(result: 'PORTER_BUSY'); Get.back(result: 'PORTER_BUSY');
return; return;
} }

View File

@ -34,12 +34,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// final args = Get.arguments as Map<String, dynamic>;
// final location = args['location'] ?? '';
// final ticketId = args['ticketId'] ?? '';
// final transactionId = args['transactionId'];
// final porterOnlineId = args['porterOnlineId'];
// final transactionPorterId = args['transactionPorterId'] ?? '';
_initializeData(); _initializeData();
} }
@ -59,7 +53,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
log('Memulai pemantauan transaksi porter: $transactionPorterId'); log('Memulai pemantauan transaksi porter: $transactionPorterId');
// Dapatkan detail transaksi dan mulai memantau perubahan
_porterController.getTransactionById(transactionPorterId).then((transaction) { _porterController.getTransactionById(transactionPorterId).then((transaction) {
if (transaction == null) { if (transaction == null) {
log('Transaksi tidak ditemukan: $transactionPorterId'); log('Transaksi tidak ditemukan: $transactionPorterId');
@ -70,7 +63,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
log('Error mendapatkan transaksi: $e'); log('Error mendapatkan transaksi: $e');
}); });
// Mulai memantau transaksi secara real-time
_porterController.watchTransaction(transactionPorterId); _porterController.watchTransaction(transactionPorterId);
} }
@ -86,7 +78,8 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
Get.back(); Get.back();
}, },
), ),
body: SafeArea(child: Obx( body: SafeArea(
child: Obx(
() { () {
final transaction = _porterController.currentTransaction.value; final transaction = _porterController.currentTransaction.value;
final isLoading = _porterController.isLoading.value; final isLoading = _porterController.isLoading.value;
@ -96,34 +89,7 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} }
if (error.isNotEmpty) { if (error.isNotEmpty) {
return Center( return Center(child: TypographyStyles.body('Data transaksi tidak ditemukan', color: GrayColors.gray400));
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error_outline, size: 48.h, color: Colors.red),
SizedBox(height: 16.h),
TypographyStyles.body(
'Terjadi Kesalahan',
color: Colors.red,
),
SizedBox(height: 8.h),
Padding(
padding: EdgeInsets.symmetric(horizontal: 32.w),
child: TypographyStyles.caption(
error,
color: GrayColors.gray600,
textAlign: TextAlign.center,
),
),
SizedBox(height: 16.h),
ButtonFill(
text: 'Kembali',
textColor: Colors.white,
onTap: () => Get.back(),
),
],
),
);
} }
if (transaction == null) { if (transaction == null) {
return Center( return Center(
@ -132,16 +98,7 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
children: [ children: [
Icon(Icons.search_off, size: 48.h, color: GrayColors.gray400), Icon(Icons.search_off, size: 48.h, color: GrayColors.gray400),
SizedBox(height: 16.h), SizedBox(height: 16.h),
TypographyStyles.body( TypographyStyles.body('Transaksi tidak ditemukan', color: GrayColors.gray600),
'Transaksi tidak ditemukan',
color: GrayColors.gray600,
),
SizedBox(height: 16.h),
ButtonFill(
text: 'Kembali',
textColor: Colors.white,
onTap: () => Get.back(),
),
], ],
), ),
); );
@ -153,13 +110,16 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
children: [ children: [
_buildPorterStatusCard(transaction.status), _buildPorterStatusCard(transaction.status),
SizedBox(height: 20.h), SizedBox(height: 20.h),
_buildInfoPorterCard(kodePorter: transaction.kodePorter, namePorter: transaction.porterUserId),
SizedBox(height: 20.h),
_buildPorterDetailsCard(transaction), _buildPorterDetailsCard(transaction),
], ],
), ),
), ),
); );
}, },
)), ),
),
bottomNavigationBar: CustomeShadowCotainner( bottomNavigationBar: CustomeShadowCotainner(
child: ButtonFill( child: ButtonFill(
text: 'Kembali ke menu', text: 'Kembali ke menu',
@ -170,59 +130,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
); );
} }
Widget _buildDesignOld() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
child: SingleChildScrollView(
child: Column(
children: [
TypographyStyles.h1('Ilustrasi'),
SizedBox(height: 32.h),
CustomeShadowCotainner(
child: Column(
children: [
TypographyStyles.h6('Tunggu Portermu', color: GrayColors.gray800),
SizedBox(height: 4.h),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TypographyStyles.caption(
'Tunngu dari pihak Porter merespon',
color: GrayColors.gray500,
fontWeight: FontWeight.w400,
),
SizedBox(width: 4.w),
Icon(Icons.timelapse_outlined)
],
),
],
),
),
SizedBox(height: 20.h),
CustomeShadowCotainner(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.body('Ahmad Choirul Umam', color: GrayColors.gray800),
SizedBox(height: 10.h),
Divider(thickness: 1, color: GrayColors.gray200),
SizedBox(height: 10.h),
TypographyStyles.body('Lokasi', color: GrayColors.gray800),
SizedBox(height: 10.h),
// _buildRowLocation(location: 'Gate Penerbangan', desc: 'Lokasi Anda'),
SizedBox(height: 10.h),
// _buildRowLocation(location: 'Guyangan', desc: 'Lokasi Porter Anda'),
SizedBox(height: 10.h),
// _buildRowLocation(location: 'Porter menuju ke lokasi anda', desc: 'Porter bergerak'),
],
),
),
],
),
),
);
}
Widget _buildPorterStatusCard(String status) { Widget _buildPorterStatusCard(String status) {
String statusText = ''; String statusText = '';
Widget statusIcon = const SizedBox.shrink(); Widget statusIcon = const SizedBox.shrink();
@ -280,6 +187,39 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
} }
} }
Widget _buildInfoPorterCard({required String kodePorter, required String namePorter}) {
return CustomeShadowCotainner(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.h6('Informasi Porter', color: GrayColors.gray800),
SizedBox(height: 10.h),
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.body('Kode Porter', color: GrayColors.gray600, fontWeight: FontWeight.w400),
TypographyStyles.body('Nama Porter', color: GrayColors.gray600, fontWeight: FontWeight.w400),
],
),
SizedBox(width: 20.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.body(kodePorter, color: GrayColors.gray800, maxlines: 1),
TypographyStyles.body(namePorter, color: GrayColors.gray800, maxlines: 1),
],
),
)
],
),
],
),
);
}
Widget _buildPorterDetailsCard(dynamic transaction) { Widget _buildPorterDetailsCard(dynamic transaction) {
final now = DateTime.now(); final now = DateTime.now();
@ -287,11 +227,7 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
TypographyStyles.body('Informasi Porter', color: GrayColors.gray800), TypographyStyles.h6('Lokasi', color: GrayColors.gray800),
SizedBox(height: 10.h),
Divider(thickness: 1, color: GrayColors.gray200),
SizedBox(height: 10.h),
TypographyStyles.body('Lokasi', color: GrayColors.gray800),
SizedBox(height: 10.h), SizedBox(height: 10.h),
_buildRowLocation( _buildRowLocation(
location: location.isNotEmpty ? location : transaction.locationPassenger, location: location.isNotEmpty ? location : transaction.locationPassenger,
@ -310,20 +246,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
desc: 'Status Porter', desc: 'Status Porter',
timestamp: now, timestamp: now,
), ),
SizedBox(height: 10.h),
TypographyStyles.body('Kode Porter', color: GrayColors.gray800),
SizedBox(height: 4.h),
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
decoration: BoxDecoration(
color: PrimaryColors.primary100,
borderRadius: BorderRadius.circular(4.r),
),
child: TypographyStyles.h6(
transaction.kodePorter,
color: PrimaryColors.primary800,
),
),
], ],
), ),
); );
@ -353,12 +275,12 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
TypographyStyles.caption( TypographyStyles.body(
_dateFormat.format(timestamp), _dateFormat.format(timestamp),
color: GrayColors.gray600, color: GrayColors.gray600,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
TypographyStyles.caption( TypographyStyles.body(
_timeFormat.format(timestamp), _timeFormat.format(timestamp),
color: GrayColors.gray600, color: GrayColors.gray600,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -370,16 +292,8 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
TypographyStyles.caption( TypographyStyles.body(location, color: GrayColors.gray800),
location, TypographyStyles.caption(desc, color: GrayColors.gray600, fontWeight: FontWeight.w400)
color: GrayColors.gray800,
fontWeight: FontWeight.w600,
),
TypographyStyles.small(
desc,
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
)
], ],
), ),
), ),

View File

@ -409,7 +409,7 @@ class _HomeScreenState extends State<HomeScreen> {
icon: Icon(Icons.calendar_today, size: 20.r, color: PrimaryColors.primary800)), icon: Icon(Icons.calendar_today, size: 20.r, color: PrimaryColors.primary800)),
SizedBox(width: 8.w), SizedBox(width: 8.w),
DateSetting( DateSetting(
onTap: () => _statisticController.previousMonth(), onTap: () => _statisticController.nextMonth(),
icon: Icon(Icons.chevron_right, size: 20.r, color: GrayColors.gray800), icon: Icon(Icons.chevron_right, size: 20.r, color: GrayColors.gray800),
), ),
], ],
@ -489,9 +489,7 @@ class _HomeScreenState extends State<HomeScreen> {
final hasPorter = _porterQueueController.currentPorter.value != null; final hasPorter = _porterQueueController.currentPorter.value != null;
return ZoomTapAnimation( return ZoomTapAnimation(
child: GestureDetector( child: GestureDetector(
onTap: hasPorter onTap: hasPorter ? _handleStopPorterQueue : _handlePorterQueueCreation,
? _handleStopPorterQueue // sekarang benar-benar terpilih saat Obx rebuild
: _handlePorterQueueCreation,
child: Column( child: Column(
children: [ children: [
Container( Container(
@ -538,6 +536,7 @@ class _HomeScreenState extends State<HomeScreen> {
Future<bool> _showStopConfirmationDialog() async { Future<bool> _showStopConfirmationDialog() async {
return await Get.dialog<bool>( return await Get.dialog<bool>(
Dialog( Dialog(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.r), borderRadius: BorderRadius.circular(10.r),
), ),
@ -551,13 +550,12 @@ class _HomeScreenState extends State<HomeScreen> {
color: GrayColors.gray800, color: GrayColors.gray800,
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Text( TypographyStyles.caption(
'Apakah Anda yakin ingin menghentikan layanan porter?', 'Apakah Anda yakin ingin menghentikan layanan porter?',
fontWeight: FontWeight.w400,
color: GrayColors.gray500,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( maxlines: 3,
fontSize: 14.sp,
color: GrayColors.gray600,
),
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
Row( Row(
@ -569,7 +567,7 @@ class _HomeScreenState extends State<HomeScreen> {
style: TextButton.styleFrom( style: TextButton.styleFrom(
foregroundColor: GrayColors.gray600, foregroundColor: GrayColors.gray600,
), ),
child: Text('Batal'), child: TypographyStyles.body('Batal', color: GrayColors.gray600),
), ),
), ),
SizedBox(width: 8.w), SizedBox(width: 8.w),
@ -580,7 +578,7 @@ class _HomeScreenState extends State<HomeScreen> {
backgroundColor: RedColors.red500, backgroundColor: RedColors.red500,
foregroundColor: Colors.white, foregroundColor: Colors.white,
), ),
child: Text('Berhenti'), child: TypographyStyles.body('Berhenti', color: Colors.white),
), ),
), ),
], ],
@ -681,7 +679,6 @@ class _HomeScreenState extends State<HomeScreen> {
required String nameAvatar, required String nameAvatar,
required String nameUser, required String nameUser,
required String subTitle, required String subTitle,
// VoidCallback? onTap,
}) { }) {
return CustomeShadowCotainner( return CustomeShadowCotainner(
sizeRadius: 0.r, sizeRadius: 0.r,
@ -703,12 +700,6 @@ class _HomeScreenState extends State<HomeScreen> {
], ],
), ),
), ),
// ZoomTapAnimation(
// child: IconButton(
// onPressed: onTap,
// icon: CustomeIcons.NotificationOutline(),
// ),
// )
], ],
), ),
); );