Feat: done page ticket_booking_step1
This commit is contained in:
parent
7b4506a256
commit
7c79dfab1e
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
|||
#Fri Mar 14 19:50:32 WIB 2025
|
||||
#Sat Mar 15 19:23:50 WIB 2025
|
||||
base.0=D\:\\Flutter\\Flutter Project\\e_porter\\build\\app\\intermediates\\dex\\debug\\mergeExtDexDebug\\classes.dex
|
||||
base.1=D\:\\Flutter\\Flutter Project\\e_porter\\build\\app\\intermediates\\dex\\debug\\mergeLibDexDebug\\0\\classes.dex
|
||||
base.2=D\:\\Flutter\\Flutter Project\\e_porter\\build\\app\\intermediates\\dex\\debug\\mergeProjectDexDebug\\0\\classes.dex
|
||||
|
|
|
@ -10,6 +10,7 @@ class ButtonFill extends StatelessWidget {
|
|||
final Color? textColor;
|
||||
final VoidCallback? onTap;
|
||||
final bool isLoading;
|
||||
final Color? backgroundColor;
|
||||
|
||||
const ButtonFill({
|
||||
Key? key,
|
||||
|
@ -17,6 +18,7 @@ class ButtonFill extends StatelessWidget {
|
|||
required this.textColor,
|
||||
this.onTap,
|
||||
this.isLoading = false,
|
||||
this.backgroundColor,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -27,8 +29,7 @@ class ButtonFill extends StatelessWidget {
|
|||
child: ElevatedButton(
|
||||
onPressed: onTap,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
isLoading ? GrayColors.gray500 : PrimaryColors.primary800,
|
||||
backgroundColor: isLoading ? GrayColors.gray400 : (backgroundColor ?? PrimaryColors.primary800),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(35.r),
|
||||
),
|
||||
|
|
|
@ -16,6 +16,8 @@ class CardFlightInformation extends StatelessWidget {
|
|||
final String seatClass;
|
||||
final String? servicePorter;
|
||||
final String passenger;
|
||||
final String? transiAirplane;
|
||||
final String? stop;
|
||||
|
||||
const CardFlightInformation({
|
||||
Key? key,
|
||||
|
@ -27,6 +29,8 @@ class CardFlightInformation extends StatelessWidget {
|
|||
required this.seatClass,
|
||||
this.servicePorter,
|
||||
required this.passenger,
|
||||
this.transiAirplane,
|
||||
this.stop,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -39,12 +43,13 @@ class CardFlightInformation extends StatelessWidget {
|
|||
SizedBox(height: 10.h),
|
||||
Row(
|
||||
children: [
|
||||
TypographyStyles.small(
|
||||
date,
|
||||
color: GrayColors.gray600,
|
||||
letterSpacing: 0.2,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
if (stop != null && stop!.isNotEmpty) ...[
|
||||
TypographyStyles.small('${stop}', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
SizedBox(width: 10.w),
|
||||
CircleAvatar(radius: 2.r, backgroundColor: Color(0xFFD9D9D9)),
|
||||
SizedBox(width: 10.w),
|
||||
],
|
||||
TypographyStyles.small(date, color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
SizedBox(width: 10.w),
|
||||
CircleAvatar(radius: 2.r, backgroundColor: Color(0xFFD9D9D9)),
|
||||
SizedBox(width: 10.w),
|
||||
|
@ -63,7 +68,13 @@ class CardFlightInformation extends StatelessWidget {
|
|||
SizedBox(width: 10.w),
|
||||
CustomeIcons.PlaneRightFilled(color: PrimaryColors.primary800),
|
||||
SizedBox(width: 10.w),
|
||||
TypographyStyles.body(arrivalCity, color: GrayColors.gray800)
|
||||
if (transiAirplane != null && transiAirplane!.isNotEmpty) ...[
|
||||
TypographyStyles.body('${transiAirplane}', color: GrayColors.gray800),
|
||||
SizedBox(width: 10.w),
|
||||
CustomeIcons.PlaneRightFilled(color: PrimaryColors.primary800),
|
||||
SizedBox(width: 10.w),
|
||||
],
|
||||
TypographyStyles.body(arrivalCity, color: GrayColors.gray800),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4.h),
|
||||
|
|
|
@ -203,6 +203,8 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||
color: GrayColors.gray600,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
|
||||
],
|
||||
),
|
||||
)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'package:e_porter/_core/component/appbar/appbar_component.dart';
|
||||
import 'package:e_porter/_core/component/button/button_fill.dart';
|
||||
import 'package:e_porter/_core/component/button/switch_button.dart';
|
||||
|
@ -9,6 +11,7 @@ import 'package:e_porter/_core/service/logger_service.dart';
|
|||
import 'package:e_porter/_core/service/preferences_service.dart';
|
||||
import 'package:e_porter/_core/utils/snackbar/snackbar_helper.dart';
|
||||
import 'package:e_porter/domain/models/ticket_model.dart';
|
||||
import 'package:e_porter/domain/models/user_entity.dart';
|
||||
import 'package:e_porter/presentation/controllers/profil_controller.dart';
|
||||
import 'package:e_porter/presentation/controllers/ticket_controller.dart';
|
||||
import 'package:e_porter/presentation/screens/home/component/card_flight_information.dart';
|
||||
|
@ -40,6 +43,7 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
final ProfilController profilController = Get.find<ProfilController>();
|
||||
final currencyFormatter = NumberFormat.decimalPattern('id_ID');
|
||||
dynamic _loggedUser;
|
||||
List<PassengerModel?> selectedPassengers = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -53,6 +57,8 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
|
||||
ticketController = Get.find<TicketController>();
|
||||
_flightFuture = ticketController.getFlightById(ticketId: ticketId, flightId: flightId);
|
||||
|
||||
selectedPassengers = List.filled(passenger, null, growable: false);
|
||||
}
|
||||
|
||||
Future<void> _loadPassengers() async {
|
||||
|
@ -66,6 +72,14 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
logger.d('User ID: $userId');
|
||||
}
|
||||
|
||||
bool isAllPassengersFilled() {
|
||||
if (isToggled && _loggedUser != null) {
|
||||
return selectedPassengers.skip(1).every((p) => p != null);
|
||||
} else {
|
||||
return selectedPassengers.every((p) => p != null);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -100,13 +114,15 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CardFlightInformation(
|
||||
date: '${ticketDate}',
|
||||
date: ticketDate,
|
||||
time: '$departureTime - $arrivalTime',
|
||||
departureCity: '${flight.cityDeparture}',
|
||||
arrivalCity: '${flight.cityArrival}',
|
||||
departureCity: flight.cityDeparture,
|
||||
arrivalCity: flight.cityArrival,
|
||||
plane: '${flight.airLines} (${flight.code})',
|
||||
seatClass: '${flight.flightClass}',
|
||||
seatClass: flight.flightClass,
|
||||
passenger: '$passenger',
|
||||
transiAirplane: flight.transitAirplane,
|
||||
stop: flight.stop,
|
||||
),
|
||||
SizedBox(height: 32.h),
|
||||
TypographyStyles.h6('Detail Pemesanan', color: GrayColors.gray800),
|
||||
|
@ -128,8 +144,13 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
child: ButtonFill(
|
||||
text: 'Lanjutkan',
|
||||
textColor: Colors.white,
|
||||
backgroundColor: isAllPassengersFilled() ? PrimaryColors.primary800 : GrayColors.gray400,
|
||||
onTap: () {
|
||||
if (!isAllPassengersFilled()) {
|
||||
SnackbarHelper.showError('Error', 'Harap lengkapi slot penumpang');
|
||||
} else {
|
||||
Get.toNamed(Routes.TICKETBOOKINGSTEP2);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -212,6 +233,21 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
passenger,
|
||||
(index) {
|
||||
if (isToggled && index == 0 && _loggedUser != null) {
|
||||
return _buildUserPassengerCard(_loggedUser);
|
||||
} else {
|
||||
final p = selectedPassengers[index];
|
||||
if (p != null) {
|
||||
return _buildSelectedPassengerCard(p, index);
|
||||
} else {
|
||||
return _buildEmptyPassengerCard(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUserPassengerCard(dynamic user) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 16.h),
|
||||
child: CustomeShadowCotainner(
|
||||
|
@ -234,22 +270,6 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 16.h),
|
||||
child: CustomeShadowCotainner(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TypographyStyles.body(
|
||||
'Penumpang ${index + 1} (Dewasa)',
|
||||
color: GrayColors.gray800,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
ZoomTapAnimation(
|
||||
child: GestureDetector(
|
||||
child: CustomeIcons.EditOutline(),
|
||||
|
@ -269,7 +289,6 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
var result = await Get.toNamed(Routes.ADDPASSENGER);
|
||||
if (result == true) {
|
||||
_loadPassengers().then((_) => setState(() {}));
|
||||
// SnackbarHelper.showSuccess('Berhasil', 'Penumpang berhasil ditambahkan');
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -295,7 +314,12 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
child: _buildAddPassenger(
|
||||
context,
|
||||
title: "${passenger.name}",
|
||||
subTitle: "${passenger.noId}",
|
||||
subTitle: "${passenger.typeId} - ${passenger.noId}",
|
||||
onTap: () {
|
||||
selectedPassengers[index] = passenger;
|
||||
Get.back();
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -314,70 +338,6 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
),
|
||||
),
|
||||
);
|
||||
// showModalBottomSheet(
|
||||
// context: context,
|
||||
// backgroundColor: Colors.white,
|
||||
// isScrollControlled: true,
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.only(
|
||||
// topLeft: Radius.circular(10.r),
|
||||
// topRight: Radius.circular(10.r),
|
||||
// ),
|
||||
// ),
|
||||
// builder: (context) {
|
||||
// return Padding(
|
||||
// padding: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 16.h),
|
||||
// child: Wrap(
|
||||
// children: [
|
||||
// TitleShowModal(
|
||||
// text: 'Informasi Penumpang',
|
||||
// onTap: () {
|
||||
// Navigator.pop(context);
|
||||
// Future.delayed(Duration(milliseconds: 300), () {
|
||||
// Get.toNamed(Routes.ADDPASSENGER)?.then((result) {
|
||||
// if (result == true) {
|
||||
// _loadPassengers().then((_) => setState(() {}));
|
||||
// SnackbarHelper.showSuccess('Berhasil', 'Penumpang berhasil ditambahkan');
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// SizedBox(height: 16.h),
|
||||
// Obx(
|
||||
// () {
|
||||
// if (profilController.passengerList.isEmpty) {
|
||||
// return Center(
|
||||
// child: TypographyStyles.body(
|
||||
// "Belum ada penumpang",
|
||||
// color: GrayColors.gray400,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// return ListView.builder(
|
||||
// itemCount: profilController.passengerList.length,
|
||||
// shrinkWrap: true,
|
||||
// itemBuilder: (context, index) {
|
||||
// final passenger = profilController.passengerList[index];
|
||||
// logger.d("Passenger Models : ${passenger.noId}");
|
||||
// return Padding(
|
||||
// padding: EdgeInsets.only(top: 16.h),
|
||||
// child: _buildAddPassenger(
|
||||
// context,
|
||||
// title: "${passenger.name}",
|
||||
// subTitle: "${passenger.noId}",
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
},
|
||||
),
|
||||
)
|
||||
|
@ -386,8 +346,68 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSelectedPassengerCard(PassengerModel p, int slotIndex) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 16.h),
|
||||
child: CustomeShadowCotainner(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TypographyStyles.body(
|
||||
'${p.name}',
|
||||
color: GrayColors.gray800,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
SizedBox(height: 4.h),
|
||||
TypographyStyles.caption(
|
||||
"${p.typeId} - ${p.noId}",
|
||||
color: GrayColors.gray800,
|
||||
fontWeight: FontWeight.w400,
|
||||
)
|
||||
],
|
||||
),
|
||||
ZoomTapAnimation(
|
||||
child: GestureDetector(
|
||||
child: CustomeIcons.EditOutline(),
|
||||
onTap: () {
|
||||
_onEditPassenger(slotIndex);
|
||||
},
|
||||
));
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEmptyPassengerCard(int slotIndex) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 16.h),
|
||||
child: CustomeShadowCotainner(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TypographyStyles.body(
|
||||
'Penumpang ${slotIndex + 1} (Dewasa)',
|
||||
color: GrayColors.gray800,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
ZoomTapAnimation(
|
||||
child: GestureDetector(
|
||||
child: CustomeIcons.EditOutline(),
|
||||
onTap: () {
|
||||
_onEditPassenger(slotIndex);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAddPassenger(
|
||||
|
@ -395,10 +415,11 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
required String title,
|
||||
required String subTitle,
|
||||
VoidCallback? onTap,
|
||||
bool enabled = true,
|
||||
}) {
|
||||
return ZoomTapAnimation(
|
||||
child: GestureDetector(
|
||||
onTap: onTap,
|
||||
onTap: enabled ? onTap : null,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.h),
|
||||
decoration: BoxDecoration(
|
||||
|
@ -412,16 +433,95 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TypographyStyles.body(title, color: GrayColors.gray800),
|
||||
TypographyStyles.body(title, color: enabled ? GrayColors.gray800 : GrayColors.gray300),
|
||||
SizedBox(height: 4.h),
|
||||
TypographyStyles.caption("KTP - ${subTitle}", color: GrayColors.gray800, fontWeight: FontWeight.w400)
|
||||
TypographyStyles.caption(
|
||||
"${subTitle}",
|
||||
color: enabled ? GrayColors.gray800 : GrayColors.gray300,
|
||||
fontWeight: FontWeight.w400,
|
||||
)
|
||||
],
|
||||
),
|
||||
SvgPicture.asset('assets/icons/ic_more _than.svg')
|
||||
SvgPicture.asset(
|
||||
'assets/icons/ic_more _than.svg',
|
||||
color: enabled ? PrimaryColors.primary800 : GrayColors.gray300,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onEditPassenger(int slotIndex) {
|
||||
Get.bottomSheet(
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 16.h),
|
||||
child: Wrap(
|
||||
children: [
|
||||
TitleShowModal(
|
||||
text: 'Informasi Penumpang',
|
||||
onTap: () async {
|
||||
if (Get.isBottomSheetOpen ?? false) {
|
||||
Get.back();
|
||||
}
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
var result = await Get.toNamed(Routes.ADDPASSENGER);
|
||||
if (result == true) {
|
||||
_loadPassengers().then((_) => setState(() {}));
|
||||
}
|
||||
},
|
||||
),
|
||||
Obx(
|
||||
() {
|
||||
final usedNoIds = selectedPassengers.where((p) => p != null).map((p) => p!.noId).toSet();
|
||||
if (profilController.passengerList.isEmpty) {
|
||||
return Center(
|
||||
child: TypographyStyles.body(
|
||||
"Belum ada penumpang",
|
||||
color: GrayColors.gray400,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}
|
||||
return ListView.builder(
|
||||
itemCount: profilController.passengerList.length,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, pIndex) {
|
||||
final passenger = profilController.passengerList[pIndex];
|
||||
final isUsed = usedNoIds.contains(passenger.noId);
|
||||
logger.d("Passenger Models : ${passenger.noId}");
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: 16.h),
|
||||
child: _buildAddPassenger(
|
||||
context,
|
||||
title: "${passenger.name}",
|
||||
subTitle: "${passenger.typeId} - ${passenger.noId}",
|
||||
enabled: !isUsed,
|
||||
onTap: isUsed
|
||||
? null
|
||||
: () {
|
||||
selectedPassengers[slotIndex] = passenger;
|
||||
Get.back();
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.white,
|
||||
isScrollControlled: true,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.r),
|
||||
topRight: Radius.circular(10.r),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue