From 0668f8d3dc99c8f6ce6b8061b6d6628f86dc5b2e Mon Sep 17 00:00:00 2001 From: orangdeso Date: Thu, 24 Apr 2025 18:30:46 +0700 Subject: [PATCH] Feat: fix bug navbar and queue porter --- .dart_tool/package_config.json | 2 +- assets/icons/ic_scroll_filled.svg | 3 + assets/icons/ic_scroll_outline.svg | 3 + .../component/appbar/appbar_component.dart | 18 +-- lib/_core/component/icons/icons_library.dart | 2 + .../controllers/navigation_controller.dart | 14 ++- .../screens/home/pages/home_screen.dart | 97 ++++++++--------- .../screens/navigation/main_navigation.dart | 103 ++++++++++-------- .../screens/routes/app_rountes.dart | 24 ++++ 9 files changed, 156 insertions(+), 110 deletions(-) create mode 100644 assets/icons/ic_scroll_filled.svg create mode 100644 assets/icons/ic_scroll_outline.svg diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index af9f7f5..7395717 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -638,7 +638,7 @@ "languageVersion": "3.4" } ], - "generated": "2025-04-22T06:48:38.993021Z", + "generated": "2025-04-23T15:39:37.293764Z", "generator": "pub", "generatorVersion": "3.5.0", "flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0", diff --git a/assets/icons/ic_scroll_filled.svg b/assets/icons/ic_scroll_filled.svg new file mode 100644 index 0000000..c630a8b --- /dev/null +++ b/assets/icons/ic_scroll_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/ic_scroll_outline.svg b/assets/icons/ic_scroll_outline.svg new file mode 100644 index 0000000..0442b7c --- /dev/null +++ b/assets/icons/ic_scroll_outline.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/_core/component/appbar/appbar_component.dart b/lib/_core/component/appbar/appbar_component.dart index c0699ac..494c016 100644 --- a/lib/_core/component/appbar/appbar_component.dart +++ b/lib/_core/component/appbar/appbar_component.dart @@ -330,14 +330,16 @@ class SimpleAppbarComponent extends StatelessWidget implements PreferredSizeWidg ], ), ), - actions: [ - ZoomTapAnimation( - child: IconButton( - onPressed: onTab, - icon: CustomeIcons.OrderHistoryOutline(), - ), - ) - ], + actions: onTab != null + ? [ + ZoomTapAnimation( + child: IconButton( + onPressed: onTab, + icon: CustomeIcons.OrderHistoryOutline(), + ), + ) + ] + : null, ); } diff --git a/lib/_core/component/icons/icons_library.dart b/lib/_core/component/icons/icons_library.dart index 8079369..cf52e61 100644 --- a/lib/_core/component/icons/icons_library.dart +++ b/lib/_core/component/icons/icons_library.dart @@ -52,7 +52,9 @@ class CustomeIcons { static SvgPicture LogoutOutline({double? size, Color? color}) => getIcon('ic_logout', color: color); static SvgPicture RemoveOutline({double? size, Color? color}) => getIcon('ic_remove', color: color); static SvgPicture UploadOutline({double? size, Color? color}) => getIcon('ic_upload', color: color); + static SvgPicture ScrollOutline({double? size, Color? color}) => getIcon('ic_scroll_outline', color: color); + static SvgPicture ScrollFilled({double? size, Color? color}) => getIcon('ic_scroll_filled', color: color); static SvgPicture FlightSeatFilled({double? size, Color? color}) => getIcon('ic_flight_seat_filled', color: color); static SvgPicture PlaneRightFilled({double? size, Color? color}) => getIcon('ic_plane_filled', color: color); static SvgPicture VIPFilled({double? size, Color? color}) => getIcon('ic_vip', color: color); diff --git a/lib/presentation/controllers/navigation_controller.dart b/lib/presentation/controllers/navigation_controller.dart index 620b90d..677c7b9 100644 --- a/lib/presentation/controllers/navigation_controller.dart +++ b/lib/presentation/controllers/navigation_controller.dart @@ -1,9 +1,19 @@ +import 'dart:developer'; + import 'package:get/get.dart'; class NavigationController extends GetxController { - RxInt currentPage = 0.obs; + final RxInt _currentPage = 0.obs; + + // Property untuk Obx + RxInt get currentPage => _currentPage; void goToTab(int page) { - currentPage.value = page; + log("Changing tab to: $page (type: ${page.runtimeType})"); + + // Langsung gunakan page sebagai int + _currentPage.value = page; + + log("Current page is now: ${_currentPage.value} (type: ${_currentPage.value.runtimeType})"); } } diff --git a/lib/presentation/screens/home/pages/home_screen.dart b/lib/presentation/screens/home/pages/home_screen.dart index 0d7d0dd..3c480b5 100644 --- a/lib/presentation/screens/home/pages/home_screen.dart +++ b/lib/presentation/screens/home/pages/home_screen.dart @@ -120,19 +120,25 @@ class _HomeScreenState extends State { return; } - if (!_porterQueueController.validatePorterQueueForDeletion()) { + if (_porterQueueController.currentPorter.value == null) { SnackbarHelper.showError( 'Gagal', 'Tidak ada antrian porter yang aktif.', ); return; } - final confirm = await _showStopConfirmationDialog(); + final porterId = _porterQueueController.currentPorter.value!.id!; + final canProceed = await _porterQueueController.checkConditionForPorter(porterId); + if (!canProceed) { + return; + } + + final confirm = await _showStopConfirmationDialog(); if (!confirm) return; + _showLoadingDialog(); - final porterId = _porterQueueController.currentPorter.value!.id!; final success = await _porterQueueController.deletePorterQueue(porterId); if (Get.isDialogOpen == true) { @@ -145,20 +151,14 @@ class _HomeScreenState extends State { 'Anda telah berhenti dari antrian porter', ); setState(() {}); - } else { - SnackbarHelper.showError( - 'Gagal', - 'Gagal menghentikan antrian porter: ${_porterQueueController.error.value}', - ); } } catch (e) { if (Get.isDialogOpen == true) { Get.back(); } - SnackbarHelper.showError( 'Gagal', - 'Gagal menghentikan antrian porter: ${e.toString()}', + 'Gagal menghentikan antrian porter.', ); } } @@ -422,49 +422,44 @@ class _HomeScreenState extends State { ), SizedBox(height: 32.w), CustomeShadowCotainner( - child: ZoomTapAnimation( - child: GestureDetector( - onTap: () => _porterQueueController.currentPorter.value != null - ? _handleStopPorterQueue() - : _handlePorterQueueCreation(), - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 6.h), - decoration: BoxDecoration( - color: _porterQueueController.currentPorter.value != null - ? RedColors.red100 - : PrimaryColors.primary200, - borderRadius: BorderRadius.circular(10.r), + child: Obx(() { + final hasPorter = _porterQueueController.currentPorter.value != null; + return ZoomTapAnimation( + child: GestureDetector( + onTap: hasPorter + ? _handleStopPorterQueue // sekarang benar-benar terpilih saat Obx rebuild + : _handlePorterQueueCreation, + child: Column( + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 6.h), + decoration: BoxDecoration( + color: hasPorter ? RedColors.red100 : PrimaryColors.primary200, + borderRadius: BorderRadius.circular(10.r), + ), + child: hasPorter + ? Icon( + Icons.power_settings_new, + color: Colors.red, + size: 32.w, + ) + : SvgPicture.asset( + 'assets/icons/ic_account.svg', + width: 32.w, + height: 32.h, + ), ), - child: Obx(() => _porterQueueController.currentPorter.value != null - ? Icon( - Icons.power_settings_new, - color: Colors.red, - size: 32.w, - ) - : SvgPicture.asset( - 'assets/icons/ic_account.svg', - width: 32.w, - height: 32.h, - )), - ), - SizedBox(height: 10.h), - Obx( - () => _porterQueueController.currentPorter.value != null - ? TypographyStyles.body( - 'Stop', - color: GrayColors.gray800, - ) - : TypographyStyles.body( - 'Mulai Antrian', - ), - ), - ], + SizedBox(height: 10.h), + TypographyStyles.body( + hasPorter ? 'Stop' : 'Mulai Antrian', + color: GrayColors.gray800, + ), + ], + ), ), - ), - ), - ) + ); + }), + ), ], ), ), diff --git a/lib/presentation/screens/navigation/main_navigation.dart b/lib/presentation/screens/navigation/main_navigation.dart index 319cf21..6e4b64d 100644 --- a/lib/presentation/screens/navigation/main_navigation.dart +++ b/lib/presentation/screens/navigation/main_navigation.dart @@ -1,4 +1,5 @@ import 'package:e_porter/_core/constants/colors.dart'; +import 'package:e_porter/presentation/screens/boarding_pass/pages/history_porter_screen.dart'; import 'package:e_porter/presentation/screens/home/pages/home_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -11,7 +12,6 @@ import '../../controllers/navigation_controller.dart'; import '../boarding_pass/pages/boarding_pass_screen.dart'; import '../profile/pages/profile_screen.dart'; - class MainNavigation extends StatefulWidget { final int initialTabIndex; @@ -23,67 +23,77 @@ class MainNavigation extends StatefulWidget { class _MainNavigationState extends State { final NavigationController navigationController = Get.find(); + late final String role; + late final List pages; @override void initState() { super.initState(); + role = Get.arguments as String? ?? 'penumpang'; navigationController.currentPage.value = widget.initialTabIndex; + + pages = [ + HomeScreen(), + if (role == 'penumpang') BoardingPassScreen() else HistoryPorterScreen(), + ProfileScreen(), + ]; } @override Widget build(BuildContext context) { + final bool isPassenger = role == 'penumpang'; + return Scaffold( body: Stack( children: [ Obx(() { - final List pages = [ - HomeScreen(), - BoardingPassScreen(), - ProfileScreen(), - ]; + // Dapatkan nilai dari currentPage + int pageIndex = navigationController.currentPage.value; + + // Pastikan nilai valid + if (pageIndex < 0 || pageIndex >= pages.length) { + pageIndex = 0; + } + return IndexedStack( - index: navigationController.currentPage.value, + index: pageIndex, children: pages, ); - }), + }) ], ), bottomNavigationBar: Obx(() { + // final current = navigationController.currentPage.value; + int current = navigationController.currentPage.value; + return BottomAppBar( color: Colors.white, child: Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - child: _bottomAppBarItem( - context, - iconPath: navigationController.currentPage.value == 0 - ? 'assets/icons/ic_home_filled.svg' - : 'assets/icons/ic_home.svg', - page: 0, - label: 'Home', - ), + _buildNavItem( + iconActive: 'assets/icons/ic_home_filled.svg', + iconInactive: 'assets/icons/ic_home.svg', + label: 'Home', + page: 0, + current: current, ), - Expanded( - child: _bottomAppBarItem( - context, - iconPath: navigationController.currentPage.value == 1 - ? 'assets/icons/ic_boarding_pass_filled.svg' - : 'assets/icons/ic_boarding_pass.svg', - page: 1, - label: 'Boarding Pass', - ), + _buildNavItem( + iconActive: + isPassenger ? 'assets/icons/ic_boarding_pass_filled.svg' : 'assets/icons/ic_scroll_filled.svg', + iconInactive: + isPassenger ? 'assets/icons/ic_boarding_pass.svg' : 'assets/icons/ic_scroll_outline.svg', + label: isPassenger ? 'Boarding Pass' : 'Riwayat', + page: 1, + current: current, ), - Expanded( - child: _bottomAppBarItem( - context, - iconPath: navigationController.currentPage.value == 2 - ? 'assets/icons/ic_profile_filled.svg' - : 'assets/icons/ic_profile.svg', - page: 2, - label: 'Profil', - ), + _buildNavItem( + iconActive: 'assets/icons/ic_profile_filled.svg', + iconInactive: 'assets/icons/ic_profile.svg', + label: 'Profil', + page: 2, + current: current, ), ], ), @@ -93,24 +103,22 @@ class _MainNavigationState extends State { ); } - Widget _bottomAppBarItem( - BuildContext context, { - required String iconPath, - required int page, + Widget _buildNavItem({ + required String iconActive, + required String iconInactive, required String label, + required int page, + required int current, }) { - final controller = Get.find(); - final isActive = controller.currentPage.value == page; - - return ZoomTapAnimation( - onTap: () => controller.goToTab(page), - child: Container( - color: Colors.transparent, + final isActive = current == page; + return Expanded( + child: ZoomTapAnimation( + onTap: () => navigationController.goToTab(page), child: Column( mainAxisSize: MainAxisSize.min, children: [ SvgPicture.asset( - iconPath, + isActive ? iconActive : iconInactive, width: 24.w, height: 24.h, ), @@ -118,7 +126,6 @@ class _MainNavigationState extends State { TypographyStyles.caption( label, color: isActive ? PrimaryColors.primary800 : GrayColors.gray400, - letterSpacing: 0.2, fontWeight: isActive ? FontWeight.w700 : FontWeight.w500, ), ], diff --git a/lib/presentation/screens/routes/app_rountes.dart b/lib/presentation/screens/routes/app_rountes.dart index dd8c16b..49c576d 100644 --- a/lib/presentation/screens/routes/app_rountes.dart +++ b/lib/presentation/screens/routes/app_rountes.dart @@ -7,13 +7,17 @@ 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/domain/bindings/transaction_porter_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'; import 'package:e_porter/presentation/screens/auth/pages/state_succes_screen.dart'; import 'package:e_porter/presentation/screens/boarding_pass/pages/boarding_pass_screen.dart'; import 'package:e_porter/presentation/screens/boarding_pass/pages/detail_ticket_screen.dart'; +import 'package:e_porter/presentation/screens/boarding_pass/pages/history_porter_screen.dart'; import 'package:e_porter/presentation/screens/boarding_pass/pages/print_boarding_pass_screen.dart'; +import 'package:e_porter/presentation/screens/boarding_pass/pages/search_porter_screen.dart'; +import 'package:e_porter/presentation/screens/boarding_pass/pages/scan_qr_screen.dart'; import 'package:e_porter/presentation/screens/boarding_pass/pages/transaction_history.dart'; import 'package:e_porter/presentation/screens/home/pages/booking_tickets_screen.dart'; import 'package:e_porter/presentation/screens/home/pages/choose_seat_screen.dart'; @@ -44,6 +48,7 @@ class AppRoutes { MainNavigationBinding(), HistoryBinding(), PorterQueueBinding(), + TransactionPorterBinding(), ], ), GetPage( @@ -149,6 +154,22 @@ class AppRoutes { name: Routes.PRINTBOARDINGPASS, page: () => PrintBoardingPassScreen(), ), + GetPage( + name: Routes.SCANQR, + page: () => ScanQRScreen(), + bindings: [ + PorterQueueBinding(), + TransactionBinding(), + ], + ), + GetPage( + name: Routes.PROCESSING, + page: () => ProcessingPorterScreen(), + ), + GetPage( + name: Routes.HISTORYPORTER, + page: () => HistoryPorterScreen(), + ), GetPage( name: Routes.ADDPASSENGER, page: () => AddPassengerScreen(), @@ -182,6 +203,9 @@ class Routes { static const TRANSACTIONHISTORY = '/transaction_history'; static const DETAILTICKET = '/detail_ticket'; static const PRINTBOARDINGPASS = '/print_boarding_pass'; + static const SCANQR = '/scan_qr'; + static const PROCESSING = '/processing'; + static const HISTORYPORTER = '/history_porter'; static const ADDPASSENGER = '/add_passenger'; }