Feat: add page passenger screen
This commit is contained in:
parent
5f4153fe62
commit
430cce5f10
|
@ -73,6 +73,12 @@
|
||||||
"packageUri": "lib/",
|
"packageUri": "lib/",
|
||||||
"languageVersion": "3.1"
|
"languageVersion": "3.1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "dropdown_button2",
|
||||||
|
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/dropdown_button2-2.3.9",
|
||||||
|
"packageUri": "lib/",
|
||||||
|
"languageVersion": "2.17"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "fake_async",
|
"name": "fake_async",
|
||||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fake_async-1.3.1",
|
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fake_async-1.3.1",
|
||||||
|
@ -440,7 +446,7 @@
|
||||||
"languageVersion": "3.4"
|
"languageVersion": "3.4"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"generated": "2025-03-11T15:01:28.490605Z",
|
"generated": "2025-03-12T12:18:16.494991Z",
|
||||||
"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",
|
||||||
|
|
|
@ -46,6 +46,10 @@ cupertino_icons
|
||||||
3.1
|
3.1
|
||||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/cupertino_icons-1.0.8/
|
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/cupertino_icons-1.0.8/
|
||||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/cupertino_icons-1.0.8/lib/
|
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/cupertino_icons-1.0.8/lib/
|
||||||
|
dropdown_button2
|
||||||
|
2.17
|
||||||
|
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/dropdown_button2-2.3.9/
|
||||||
|
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/dropdown_button2-2.3.9/lib/
|
||||||
fake_async
|
fake_async
|
||||||
2.12
|
2.12
|
||||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fake_async-1.3.1/
|
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fake_async-1.3.1/
|
||||||
|
|
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 @@
|
||||||
#Tue Mar 11 22:03:16 WIB 2025
|
#Wed Mar 12 19:14:57 WIB 2025
|
||||||
base.0=D\:\\Flutter\\Flutter Project\\e_porter\\build\\app\\intermediates\\dex\\debug\\mergeExtDexDebug\\classes.dex
|
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.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
|
base.2=D\:\\Flutter\\Flutter Project\\e_porter\\build\\app\\intermediates\\dex\\debug\\mergeProjectDexDebug\\0\\classes.dex
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:e_porter/_core/constants/colors.dart';
|
import 'package:e_porter/_core/constants/colors.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
||||||
|
|
||||||
import '../../constants/typography.dart';
|
import '../../constants/typography.dart';
|
||||||
|
|
||||||
|
@ -20,27 +21,29 @@ class ButtonFill extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return ZoomTapAnimation(
|
||||||
width: double.infinity,
|
child: SizedBox(
|
||||||
child: ElevatedButton(
|
width: double.infinity,
|
||||||
onPressed: onTap,
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
onPressed: onTap,
|
||||||
backgroundColor:
|
style: ElevatedButton.styleFrom(
|
||||||
isLoading ? GrayColors.gray500 : PrimaryColors.primary800,
|
backgroundColor:
|
||||||
shape: RoundedRectangleBorder(
|
isLoading ? GrayColors.gray500 : PrimaryColors.primary800,
|
||||||
borderRadius: BorderRadius.circular(35.r),
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(35.r),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 14.h),
|
||||||
|
child: isLoading
|
||||||
|
? _rowLoading()
|
||||||
|
: TypographyStyles.h6(
|
||||||
|
text,
|
||||||
|
color: textColor,
|
||||||
|
letterSpacing: 1,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 14.h),
|
|
||||||
child: isLoading
|
|
||||||
? _rowLoading()
|
|
||||||
: TypographyStyles.h6(
|
|
||||||
text,
|
|
||||||
color: textColor,
|
|
||||||
letterSpacing: 1,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
|
import 'package:e_porter/_core/constants/colors.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
|
||||||
|
class DropdownComponent extends StatefulWidget {
|
||||||
|
final String? value;
|
||||||
|
final Function(String?) onChanged;
|
||||||
|
final String hintText;
|
||||||
|
|
||||||
|
const DropdownComponent({
|
||||||
|
Key? key,
|
||||||
|
this.value,
|
||||||
|
required this.onChanged,
|
||||||
|
required this.hintText,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DropdownComponent> createState() => _DropdownComponentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DropdownComponentState extends State<DropdownComponent> {
|
||||||
|
final List<String> items = ["KTP", "Paspor"];
|
||||||
|
String? selectedValue;
|
||||||
|
|
||||||
|
bool _isMenuOpen = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
selectedValue = widget.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: MediaQuery.of(context).size.height * 0.14,
|
||||||
|
child: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton2<String>(
|
||||||
|
isExpanded: true,
|
||||||
|
value: selectedValue,
|
||||||
|
items: items.map((String item) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: item,
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'DMsans',
|
||||||
|
fontSize: 16.sp,
|
||||||
|
color: GrayColors.gray600,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
hint: Text(
|
||||||
|
widget.hintText,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'DMsans',
|
||||||
|
fontSize: 16.sp,
|
||||||
|
color: GrayColors.gray600,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onMenuStateChange: (isOpen) {
|
||||||
|
setState(() {
|
||||||
|
_isMenuOpen = isOpen;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
selectedValue = newValue;
|
||||||
|
});
|
||||||
|
widget.onChanged(newValue);
|
||||||
|
},
|
||||||
|
buttonStyleData: ButtonStyleData(
|
||||||
|
padding: EdgeInsets.only(left: 10.w, right: 16.w, top: 4.h, bottom: 4.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
border: Border.all(width: 1.w, color: _isMenuOpen ? PrimaryColors.primary800 : GrayColors.gray200),
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownStyleData: DropdownStyleData(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
elevation: 1,
|
||||||
|
),
|
||||||
|
menuItemStyleData: MenuItemStyleData(
|
||||||
|
padding: EdgeInsets.only(left: 16.w, top: 8.h, bottom: 8.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ class SearchBarComponent extends StatelessWidget {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10.r)
|
||||||
),
|
),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
|
@ -0,0 +1,44 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
|
||||||
|
import '../../../constants/colors.dart';
|
||||||
|
|
||||||
|
class TextFieldComponent extends StatelessWidget {
|
||||||
|
final TextEditingController? controller;
|
||||||
|
final String hintText;
|
||||||
|
|
||||||
|
const TextFieldComponent({this.controller, required this.hintText});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10.r)),
|
||||||
|
child: TextField(
|
||||||
|
controller: controller,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefix: Padding(padding: EdgeInsets.symmetric(horizontal: 10.w)),
|
||||||
|
hintText: hintText,
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
fontFamily: 'DMsans',
|
||||||
|
fontSize: 16.sp,
|
||||||
|
color: GrayColors.gray600,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
borderSide: BorderSide(width: 1, color: GrayColors.gray200),
|
||||||
|
),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
borderSide: BorderSide(width: 1, color: GrayColors.gray200),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
borderSide: BorderSide(width: 1.5.w, color: PrimaryColors.primary800),
|
||||||
|
),
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 16.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,8 @@ class UserEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserData {
|
class UserData {
|
||||||
|
final String? tipeId;
|
||||||
|
final String? noId;
|
||||||
final String? name;
|
final String? name;
|
||||||
final String? email;
|
final String? email;
|
||||||
final String? phone;
|
final String? phone;
|
||||||
|
@ -22,6 +24,8 @@ class UserData {
|
||||||
final String? role;
|
final String? role;
|
||||||
|
|
||||||
UserData({
|
UserData({
|
||||||
|
required this.tipeId,
|
||||||
|
required this.noId,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.email,
|
required this.email,
|
||||||
required this.phone,
|
required this.phone,
|
||||||
|
@ -46,6 +50,8 @@ class UserData {
|
||||||
}
|
}
|
||||||
|
|
||||||
return UserData(
|
return UserData(
|
||||||
|
tipeId: map['tipeId'] ?? '',
|
||||||
|
noId: map['noId'] ?? '',
|
||||||
name: map['name'] as String?,
|
name: map['name'] as String?,
|
||||||
email: map['email'] as String?,
|
email: map['email'] as String?,
|
||||||
phone: map['phone'] as String?,
|
phone: map['phone'] as String?,
|
||||||
|
@ -60,6 +66,8 @@ class UserData {
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
return {
|
return {
|
||||||
|
'tipeId': tipeId,
|
||||||
|
'noId': noId,
|
||||||
'name': name,
|
'name': name,
|
||||||
'email': email,
|
'email': email,
|
||||||
'phone': phone,
|
'phone': phone,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:e_porter/_core/service/logger_service.dart';
|
||||||
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
|
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -8,7 +9,7 @@ void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await Firebase.initializeApp();
|
await Firebase.initializeApp();
|
||||||
|
|
||||||
print("Firebase Initialized Successfully!");
|
logger.d("Firebase Initialized Successfully!");
|
||||||
runApp(MyApp(initialRoute: Routes.SPLASH));
|
runApp(MyApp(initialRoute: Routes.SPLASH));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,22 +59,17 @@ class CardFlightInformation extends StatelessWidget {
|
||||||
SizedBox(height: 4.h),
|
SizedBox(height: 4.h),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
TypographyStyles.body(departureCity, color: GrayColors.gray800, letterSpacing: 0.2),
|
TypographyStyles.body(departureCity, color: GrayColors.gray800),
|
||||||
SizedBox(width: 10.w),
|
SizedBox(width: 10.w),
|
||||||
CustomeIcons.PlaneRightFilled(color: PrimaryColors.primary800),
|
CustomeIcons.PlaneRightFilled(color: PrimaryColors.primary800),
|
||||||
SizedBox(width: 10.w),
|
SizedBox(width: 10.w),
|
||||||
TypographyStyles.body(arrivalCity, color: GrayColors.gray800, letterSpacing: 0.2)
|
TypographyStyles.body(arrivalCity, color: GrayColors.gray800)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 4.h),
|
SizedBox(height: 4.h),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
TypographyStyles.small(
|
TypographyStyles.small(plane, color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||||
plane,
|
|
||||||
color: GrayColors.gray600,
|
|
||||||
letterSpacing: 0.2,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
_buildText(context, text: seatClass),
|
_buildText(context, text: seatClass),
|
||||||
servicePorter != null ? _buildText(context, text: servicePorter!) : SizedBox.shrink(),
|
servicePorter != null ? _buildText(context, text: servicePorter!) : SizedBox.shrink(),
|
||||||
],
|
],
|
||||||
|
|
|
@ -17,6 +17,8 @@ import 'package:get/get.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
||||||
|
|
||||||
|
import '../../../../_core/service/logger_service.dart';
|
||||||
|
|
||||||
class BookingTickets extends StatefulWidget {
|
class BookingTickets extends StatefulWidget {
|
||||||
const BookingTickets({super.key});
|
const BookingTickets({super.key});
|
||||||
|
|
||||||
|
@ -117,7 +119,7 @@ class _BookingTicketsState extends State<BookingTickets> {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedDate = picked;
|
selectedDate = picked;
|
||||||
selectedDateText = DateFormat('EEE, d MMM yyyy', 'en_US').format(selectedDate);
|
selectedDateText = DateFormat('EEE, d MMM yyyy', 'en_US').format(selectedDate);
|
||||||
print(selectedDate);
|
logger.d(selectedDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -202,25 +204,23 @@ class _BookingTicketsState extends State<BookingTickets> {
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
),
|
),
|
||||||
SizedBox(height: 20.h),
|
SizedBox(height: 20.h),
|
||||||
ZoomTapAnimation(
|
ButtonFill(
|
||||||
child: ButtonFill(
|
text: 'Cari Tiket',
|
||||||
text: 'Cari Tiket',
|
textColor: Colors.white,
|
||||||
textColor: Colors.white,
|
onTap: () {
|
||||||
onTap: () {
|
if (selectedAirportFrom != null && selectedAirportTo != null) {
|
||||||
if (selectedAirportFrom != null && selectedAirportTo != null) {
|
final searchParams = {
|
||||||
final searchParams = {
|
"from": '${selectedAirportFrom!.city}',
|
||||||
"from": '${selectedAirportFrom!.city}',
|
"to": '${selectedAirportTo!.city}',
|
||||||
"to": '${selectedAirportTo!.city}',
|
"leavingDate": selectedDate,
|
||||||
"leavingDate": selectedDate,
|
"flightClass": selectedClass.value,
|
||||||
"flightClass": selectedClass.value,
|
"passengerCount": selectedPassengerCount,
|
||||||
"passengerCount": selectedPassengerCount,
|
};
|
||||||
};
|
Get.toNamed(Routes.SEARCHTICKETS, arguments: searchParams);
|
||||||
Get.toNamed(Routes.SEARCHTICKETS, arguments: searchParams);
|
} else {
|
||||||
} else {
|
Get.snackbar("Error", "Silakan pilih bandara keberangkatan dan tujuan");
|
||||||
Get.snackbar("Error", "Silakan pilih bandara keberangkatan dan tujuan");
|
}
|
||||||
}
|
},
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:e_porter/_core/component/appbar/appbar_component.dart';
|
import 'package:e_porter/_core/component/appbar/appbar_component.dart';
|
||||||
import 'package:e_porter/_core/component/search_bar/search_bar_component.dart';
|
import 'package:e_porter/_core/component/text_field/search_bar/search_bar_component.dart';
|
||||||
import 'package:e_porter/_core/constants/colors.dart';
|
import 'package:e_porter/_core/constants/colors.dart';
|
||||||
import 'package:e_porter/_core/constants/typography.dart';
|
import 'package:e_porter/_core/constants/typography.dart';
|
||||||
import 'package:e_porter/presentation/controllers/search_flight_controller.dart';
|
import 'package:e_porter/presentation/controllers/search_flight_controller.dart';
|
||||||
|
|
|
@ -14,8 +14,10 @@ import 'package:e_porter/presentation/screens/home/component/title_show_modal.da
|
||||||
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
|
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
||||||
|
|
||||||
class TicketBookingStep1Screen extends StatefulWidget {
|
class TicketBookingStep1Screen extends StatefulWidget {
|
||||||
|
@ -34,6 +36,7 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
||||||
late Future<FlightModel> _flightFuture;
|
late Future<FlightModel> _flightFuture;
|
||||||
late final TicketController ticketController;
|
late final TicketController ticketController;
|
||||||
final currencyFormatter = NumberFormat.decimalPattern('id_ID');
|
final currencyFormatter = NumberFormat.decimalPattern('id_ID');
|
||||||
|
dynamic _loggedUser;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -107,14 +110,12 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
||||||
),
|
),
|
||||||
bottomNavigationBar: CustomeShadowCotainner(
|
bottomNavigationBar: CustomeShadowCotainner(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||||
child: ZoomTapAnimation(
|
child: ButtonFill(
|
||||||
child: ButtonFill(
|
text: 'Lanjutkan',
|
||||||
text: 'Lanjutkan',
|
textColor: Colors.white,
|
||||||
textColor: Colors.white,
|
onTap: () {
|
||||||
onTap: () {
|
Get.toNamed(Routes.TICKETBOOKINGSTEP2);
|
||||||
Get.toNamed(Routes.TICKETBOOKINGSTEP2);
|
},
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -124,11 +125,12 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: PreferencesService.getUserData(),
|
future: PreferencesService.getUserData(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.none) {
|
||||||
return CustomeShadowCotainner(child: Center(child: CircularProgressIndicator()));
|
return SizedBox.shrink();
|
||||||
} else if (snapshot.hasData && snapshot.data != null) {
|
} else if (snapshot.hasData && snapshot.data != null) {
|
||||||
final user = snapshot.data!;
|
final user = snapshot.data!;
|
||||||
logger.d('Data user: ${user.email}');
|
_loggedUser = user;
|
||||||
|
logger.d('Data user: ${user.noId}');
|
||||||
return CustomeShadowCotainner(
|
return CustomeShadowCotainner(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -159,7 +161,10 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
||||||
SizedBox(width: 20.w),
|
SizedBox(width: 20.w),
|
||||||
SwitchButton(
|
SwitchButton(
|
||||||
value: isToggled,
|
value: isToggled,
|
||||||
onChanged: (newValue) {
|
onChanged: (newValue) async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setBool('isPassengerAdd', newValue);
|
||||||
|
|
||||||
setState(
|
setState(
|
||||||
() {
|
() {
|
||||||
isToggled = newValue;
|
isToggled = newValue;
|
||||||
|
@ -191,53 +196,116 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
||||||
children: List.generate(
|
children: List.generate(
|
||||||
passenger,
|
passenger,
|
||||||
(index) {
|
(index) {
|
||||||
return Padding(
|
if (isToggled && index == 0 && _loggedUser != null) {
|
||||||
padding: EdgeInsets.only(bottom: 16.h),
|
return Padding(
|
||||||
child: CustomeShadowCotainner(
|
padding: EdgeInsets.only(bottom: 16.h),
|
||||||
child: Row(
|
child: CustomeShadowCotainner(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
child: Row(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
TypographyStyles.body(
|
children: [
|
||||||
'Penumpang 1 (Dewasa)',
|
Column(
|
||||||
color: GrayColors.gray800,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
fontWeight: FontWeight.w500,
|
children: [
|
||||||
),
|
TypographyStyles.body(
|
||||||
ZoomTapAnimation(
|
'${_loggedUser.name}',
|
||||||
child: GestureDetector(
|
color: GrayColors.gray800,
|
||||||
child: CustomeIcons.EditOutline(),
|
fontWeight: FontWeight.w500,
|
||||||
onTap: () {
|
),
|
||||||
showModalBottomSheet(
|
SizedBox(height: 4.h),
|
||||||
context: context,
|
TypographyStyles.caption(
|
||||||
backgroundColor: Colors.white,
|
"${_loggedUser.tipeId} - ${_loggedUser.noId}",
|
||||||
isScrollControlled: true,
|
color: GrayColors.gray800,
|
||||||
shape: RoundedRectangleBorder(
|
fontWeight: FontWeight.w400,
|
||||||
borderRadius: BorderRadius.only(
|
)
|
||||||
topLeft: Radius.circular(10.r),
|
],
|
||||||
topRight: Radius.circular(10.r),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
builder: (context) {
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
||||||
child: Wrap(
|
|
||||||
children: [
|
|
||||||
TitleShowModal(
|
|
||||||
text: 'Informasi Penumpang',
|
|
||||||
onTap: () {},
|
|
||||||
),
|
|
||||||
_buildAddPassenger(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
)
|
ZoomTapAnimation(
|
||||||
],
|
child: GestureDetector(
|
||||||
|
child: CustomeIcons.EditOutline(),
|
||||||
|
onTap: () {
|
||||||
|
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.symmetric(horizontal: 16.w),
|
||||||
|
child: Wrap(
|
||||||
|
children: [
|
||||||
|
TitleShowModal(
|
||||||
|
text: 'Informasi Penumpang',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
_buildAddPassenger(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
} 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(),
|
||||||
|
onTap: () {
|
||||||
|
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.symmetric(horizontal: 16.w),
|
||||||
|
child: Wrap(
|
||||||
|
children: [
|
||||||
|
TitleShowModal(
|
||||||
|
text: 'Informasi Penumpang',
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed(Routes.ADDPASSENGER);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_buildAddPassenger(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -245,6 +313,27 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
||||||
Widget _buildAddPassenger() {
|
Widget _buildAddPassenger() {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 16.h),
|
padding: EdgeInsets.symmetric(vertical: 16.h),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: GrayColors.gray50,
|
||||||
|
border: Border.all(width: 1.w, color: GrayColors.gray200),
|
||||||
|
borderRadius: BorderRadius.circular(10.r)),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TypographyStyles.body("Muhammad Al Kahfi", color: GrayColors.gray800),
|
||||||
|
SizedBox(height: 4.h),
|
||||||
|
TypographyStyles.caption("KTP - 3571", color: GrayColors.gray800, fontWeight: FontWeight.w400)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SvgPicture.asset('assets/icons/ic_more _than.svg')
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
||||||
import '../../../_core/constants/typography.dart';
|
import '../../../_core/constants/typography.dart';
|
||||||
import '../../controllers/navigation_controller.dart';
|
import '../../controllers/navigation_controller.dart';
|
||||||
import '../boarding_pass/pages/boarding_pass_screen.dart';
|
import '../boarding_pass/pages/boarding_pass_screen.dart';
|
||||||
import '../profile/profile_screen.dart';
|
import '../profile/pages/profile_screen.dart';
|
||||||
|
|
||||||
|
|
||||||
class MainNavigation extends StatefulWidget {
|
class MainNavigation extends StatefulWidget {
|
||||||
final int initialTabIndex;
|
final int initialTabIndex;
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
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/card/custome_shadow_cotainner.dart';
|
||||||
|
import 'package:e_porter/_core/component/text_field/dropdown/dropdown_component.dart';
|
||||||
|
import 'package:e_porter/_core/component/text_field/text_input/text_field_component.dart';
|
||||||
|
import 'package:e_porter/_core/constants/colors.dart';
|
||||||
|
import 'package:e_porter/_core/constants/typography.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class AddPassengerScreen extends StatefulWidget {
|
||||||
|
const AddPassengerScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AddPassengerScreen> createState() => _AddPassengerScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AddPassengerScreenState extends State<AddPassengerScreen> {
|
||||||
|
final ValueNotifier<String> selectedGender = ValueNotifier<String>('');
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: GrayColors.gray50,
|
||||||
|
appBar: DefaultAppbarComponent(
|
||||||
|
backgroundColors: PrimaryColors.primary800,
|
||||||
|
title: "Tambah Penumpang",
|
||||||
|
textColor: Colors.white,
|
||||||
|
onTab: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TypographyStyles.body(
|
||||||
|
"Silahkan isi informasi data diri calon penumpang baru",
|
||||||
|
color: GrayColors.gray600,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
maxlines: 2,
|
||||||
|
),
|
||||||
|
SizedBox(height: 32.h),
|
||||||
|
TypographyStyles.body('Nama Lengkap', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||||
|
SizedBox(height: 16.w),
|
||||||
|
TextFieldComponent(hintText: 'Masukkan nama lengkap'),
|
||||||
|
SizedBox(height: 20.h),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TypographyStyles.body('Tipe ID', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
DropdownComponent(
|
||||||
|
hintText: "Pilih jenis dokument",
|
||||||
|
value: "KTP",
|
||||||
|
onChanged: (value) {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(width: 16.w),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TypographyStyles.body('No ID', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
TextFieldComponent(hintText: 'Masukkan ID')
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 20.w),
|
||||||
|
TypographyStyles.body('Jenis Kelamin', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
_buildRadioButton(context, label: 'Laki-laki', value: 'Laki-laki'),
|
||||||
|
SizedBox(width: 40.h),
|
||||||
|
_buildRadioButton(context, label: 'Perempuan', value: 'Perempuan')
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomNavigationBar: CustomeShadowCotainner(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||||
|
borderRadius: BorderRadius.circular(0.r),
|
||||||
|
child: ButtonFill(
|
||||||
|
text: 'Simpan',
|
||||||
|
textColor: Colors.white,
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildRadioButton(
|
||||||
|
BuildContext context, {
|
||||||
|
required String label,
|
||||||
|
required String value,
|
||||||
|
}) {
|
||||||
|
return ValueListenableBuilder<String>(
|
||||||
|
valueListenable: selectedGender,
|
||||||
|
builder: (context, selected, child) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Radio<String>(
|
||||||
|
value: value,
|
||||||
|
groupValue: selected,
|
||||||
|
activeColor: PrimaryColors.primary800,
|
||||||
|
onChanged: (val) {
|
||||||
|
selectedGender.value = val!;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(width: 10.w),
|
||||||
|
TypographyStyles.body(label, color: GrayColors.gray800, fontWeight: FontWeight.w500)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../_core/constants/colors.dart';
|
import '../../../../_core/constants/colors.dart';
|
||||||
import '../../../_core/constants/typography.dart';
|
import '../../../../_core/constants/typography.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileScreen extends StatefulWidget {
|
class ProfileScreen extends StatefulWidget {
|
||||||
const ProfileScreen({super.key});
|
const ProfileScreen({super.key});
|
|
@ -19,7 +19,8 @@ import 'package:e_porter/presentation/screens/home/pages/ticket_booking_step3_sc
|
||||||
import 'package:e_porter/presentation/screens/home/pages/ticket_booking_step4_screen.dart';
|
import 'package:e_porter/presentation/screens/home/pages/ticket_booking_step4_screen.dart';
|
||||||
import 'package:e_porter/presentation/screens/navigation/main_navigation.dart';
|
import 'package:e_porter/presentation/screens/navigation/main_navigation.dart';
|
||||||
import 'package:e_porter/presentation/screens/onboarding/onboarding_screen.dart';
|
import 'package:e_porter/presentation/screens/onboarding/onboarding_screen.dart';
|
||||||
import 'package:e_porter/presentation/screens/profile/profile_screen.dart';
|
import 'package:e_porter/presentation/screens/profile/pages/profile_screen.dart';
|
||||||
|
import 'package:e_porter/presentation/screens/profile/pages/add_passenger_screen.dart';
|
||||||
import 'package:e_porter/presentation/screens/splash/splash_screen.dart';
|
import 'package:e_porter/presentation/screens/splash/splash_screen.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ class AppRoutes {
|
||||||
GetPage(
|
GetPage(
|
||||||
name: Routes.SEARCHTICKETS,
|
name: Routes.SEARCHTICKETS,
|
||||||
page: () => SearchTicketsScreen(),
|
page: () => SearchTicketsScreen(),
|
||||||
binding: TicketBinding()
|
binding: TicketBinding(),
|
||||||
),
|
),
|
||||||
GetPage(
|
GetPage(
|
||||||
name: Routes.TICKETBOOKINGSTEP1,
|
name: Routes.TICKETBOOKINGSTEP1,
|
||||||
|
@ -112,6 +113,10 @@ class AppRoutes {
|
||||||
name: Routes.TRANSACTIONHISTORY,
|
name: Routes.TRANSACTIONHISTORY,
|
||||||
page: () => transactionHistory(),
|
page: () => transactionHistory(),
|
||||||
),
|
),
|
||||||
|
GetPage(
|
||||||
|
name: Routes.ADDPASSENGER,
|
||||||
|
page: () => AddPassengerScreen(),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,4 +141,6 @@ class Routes {
|
||||||
static const CHOOSECHAIR = '/choose_chair';
|
static const CHOOSECHAIR = '/choose_chair';
|
||||||
static const PAYMENT = '/payment';
|
static const PAYMENT = '/payment';
|
||||||
static const TRANSACTIONHISTORY = '/transaction_history';
|
static const TRANSACTIONHISTORY = '/transaction_history';
|
||||||
|
|
||||||
|
static const ADDPASSENGER = '/add_passenger';
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.8"
|
||||||
|
dropdown_button2:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dropdown_button2
|
||||||
|
sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.9"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -49,6 +49,7 @@ dependencies:
|
||||||
firebase_auth: ^5.5.1
|
firebase_auth: ^5.5.1
|
||||||
shared_preferences: ^2.5.2
|
shared_preferences: ^2.5.2
|
||||||
logger: ^2.5.0
|
logger: ^2.5.0
|
||||||
|
dropdown_button2: ^2.3.9
|
||||||
# pin_code_fields: ^8.0.1
|
# pin_code_fields: ^8.0.1
|
||||||
# dio: ^5.8.0+1
|
# dio: ^5.8.0+1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue