Initial commit: Penyerahan final Source code Tugas Akhir

This commit is contained in:
ferdiakhh
2025-07-10 19:15:14 +07:00
commit e1f2206b8a
687 changed files with 80132 additions and 0 deletions

View File

@ -0,0 +1,782 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_order_model.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/screens/checkout/components/bar_batas_bayar.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/components/tab_bar_batas_bayar.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi_pending.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator_pop.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:pusher_client/pusher_client.dart';
import 'package:shimmer/shimmer.dart';
import 'package:initial_folder/screens/checkout/success_paid_course.dart';
import 'package:initial_folder/providers/payments_provider.dart' as payProv;
class BatasBayar extends StatefulWidget {
BatasBayar({
this.historyTransactionModel,
this.isFromHistory,
this.idCart,
});
final HistoryTransactionModel? historyTransactionModel;
final bool? isFromHistory;
final List<String>? idCart;
@override
State<BatasBayar> createState() => _BatasBayarState();
}
class _BatasBayarState extends State<BatasBayar> {
Channel? _channel;
String? statusTransaction;
String? statusMessage;
PusherClient? pusher;
String capitalize(String s) =>
s[0].toUpperCase() + s.substring(1).toLowerCase();
Future<void> deleteCourse() async {
List<String> idCarts = widget.idCart!;
for (var element in idCarts) {
await Provider.of<CartProvider>(context, listen: false)
.deleteCart(element);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
}
}
Future<void> initPusher() async {
int? idUser = await UsersInfo().getIdUser();
PusherClient pusher = PusherClient(
'92060797e94ac7033edb', PusherOptions(cluster: 'ap1'),
autoConnect: false);
pusher.connect();
pusher.onConnectionStateChange((state) {
print(state!.currentState);
});
pusher.onConnectionError((error) {
print(error);
});
_channel = pusher.subscribe('payment-channel');
_channel!.bind(
'paid-event-$idUser',
(event) async {
print("Event? ini apaan dah ${event!.data!}");
if (mounted) {
final status = jsonDecode(event.data!);
final newStatusTransaction = status['status_code'];
final newStatusMessage = status['message'];
if (newStatusMessage.contains("Berhasil !") &&
newStatusTransaction == '200') {
await deleteCourse();
if (mounted) {
setState(() {
statusTransaction = newStatusTransaction;
statusMessage = newStatusMessage;
});
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => SuccessPaidCourse(),
),
(route) => false,
);
}
} else if (newStatusMessage.contains("Dibatalkan") &&
newStatusTransaction == '200') {
await deleteCourse();
if (mounted) {
setState(() {
statusTransaction = newStatusTransaction;
statusMessage = newStatusMessage;
});
Navigator.pop(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor: Theme.of(context).colorScheme.background,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
contentPadding: EdgeInsets.fromLTRB(12, 26, 22, 15),
content: Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(14)),
child: Text(
textAlign: TextAlign.center,
"Transaksi berhasil dibatalkan",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
),
),
),
),
);
}
}
}
},
);
}
@override
void initState() {
initPusher();
super.initState();
}
Widget _buildBatasBayarHistory() {
List<DetailOrderModel> detailOrder =
Provider.of<payProv.PaymentsProvider>(context).detailOrder;
var orders = Provider.of<OrderProvider>(context, listen: false).orders;
var selectedOrder =
Provider.of<payProv.PaymentsProvider>(context, listen: false);
var selected = Provider.of<OrderProvider>(context);
selected.selectedThumbnail = orders[0].imageUrl;
selected.selectedTitle = orders[0].title;
selected.selectedInstructor = orders[0].instructor;
PageProvider pageProviders = Provider.of<PageProvider>(context);
pageProviders.remove();
Widget mandiriPay() {
return detailOrder[0].bankName == 'mandiri'
? Column(
children: [
Row(
children: [
Text(
detailOrder[0].billerCode.toString(),
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: detailOrder[0].billerCode.toString()))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Berhasil Menyalin Kode Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
],
)
: Row();
}
Widget indomartPay() {
return detailOrder[0].bankName == 'indomaret'
? Column(
children: [
Row(
children: [
Text(
detailOrder[0].merchantId!,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(
ClipboardData(text: detailOrder[0].merchantId!))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Berhasil Menyalin Kode Merchant'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
),
],
),
],
)
: Row();
}
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Selesaikan Pembayaran',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: getProportionateScreenWidth(17),
),
onPressed: () {
selectedOrder.selectedIdOrders = '';
Navigator.pop(context);
},
),
),
body: SingleChildScrollView(
child: Consumer<payProv.PaymentsProvider>(
builder: (context, state, _) {
if (state.stateProcess == payProv.Process.loading) {
return Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(20),
bottom: getProportionateScreenHeight(20),
right: getProportionateScreenWidth(20),
),
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: getProportionateScreenWidth(140),
height: getProportionateScreenHeight(7),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Container(
width: getProportionateScreenWidth(110),
height: getProportionateScreenHeight(9),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Container(
width: getProportionateScreenWidth(220),
height: getProportionateScreenHeight(7),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(40)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(250),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(40),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(30)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(170),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
),
],
),
),
);
} else if (state.state == payProv.ResultState.gagal &&
state.stateProcess == payProv.Process.uninitialized) {
return Center(
child: Text('Gagal Mengambil Pesanan'),
);
} else if (state.state == payProv.ResultState.success &&
state.stateProcess == payProv.Process.uninitialized) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: getProportionateScreenHeight(10)),
Center(
child: Column(
children: [
Text(
'Batas akhir pembayaran sampai',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
DateFormat('E, d MMM y (H:m)')
.format(detailOrder[0].transactionTimeLimit),
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Mohon melakukan pembayaran sebelum batas',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'tanggal yang ditetapkan atau pesanan',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'akan otomatis dibatalkan',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(25)),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
detailOrder[0].bankName == 'mandiri'
? 'Mandiri Virtual Account'
: detailOrder[0].bankName == 'permata'
? 'Permata Virtual Account'
: detailOrder[0].bankName == 'bni'
? 'BNI Virtual Account'
: detailOrder[0].bankName == 'bca'
? 'BCA Virtual Account'
: detailOrder[0].bankName ==
'indomaret'
? 'Indomaret'
: 'Alfamart',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.fill,
image: detailOrder[0].bankName ==
'mandiri'
? AssetImage(
"assets/images/mandiri.png")
: detailOrder[0].bankName == 'permata'
? AssetImage(
"assets/images/permata.png")
: detailOrder[0].bankName == 'bni'
? AssetImage(
"assets/images/bni.png")
: detailOrder[0].bankName ==
'bca'
? AssetImage(
"assets/images/bca.png")
: detailOrder[0]
.bankName ==
'alfamart'
? AssetImage(
"assets/images/alfamart.png")
: AssetImage(
"assets/images/indomaret.png"),
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
detailOrder[0].bankName == 'alfamart' ||
detailOrder[0].bankName == 'indomaret'
? 'Nomor Pesanan'
: 'Nomor Virtual Akun',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
detailOrder[0].virtualNumber ?? 'ABCD',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text:
detailOrder[0].virtualNumber!))
.then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(detailOrder[0]
.bankName ==
'alfamart' ||
detailOrder[0].bankName ==
'indomaret'
? 'Berhasil Menyalin Nomor Pesanan'
: 'Berhasil Menyalin Nomor Virtual Akun'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
detailOrder[0].bankName == 'indomaret'
? Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(16),
bottom: getProportionateScreenHeight(8),
),
child: Text(
'Kode Merchant',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
)
: SizedBox.shrink(),
detailOrder[0].bankName == 'mandiri'
? Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(16),
bottom: getProportionateScreenHeight(8),
),
child: Text(
'Kode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
)
: SizedBox.shrink(),
indomartPay(),
mandiriPay(),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (context) {
return BottomSheetDetail();
},
);
},
child: Text(
"Detail Pembayaran",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Status Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Text(
capitalize(
detailOrder[0].transactionStatus!.toString()),
style: thirdTextStyle.copyWith(
color: primaryColor,
letterSpacing: 1,
fontWeight: medium,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
),
),
SizedBox(height: getProportionateScreenHeight(24)),
DefaultButton(
text: 'Belanja kursus lainnya',
weight: semiBold,
press: () {
pageProviders.currentIndex == 0;
Navigator.pushAndRemoveUntil(
context,
CustomNavigatorPop(child: HomeScreen()),
(route) => false,
);
},
),
SizedBox(height: getProportionateScreenHeight(12)),
SizedBox(
width: getProportionateScreenWidth(300),
height: getProportionateScreenHeight(38),
child: TextButton(
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => RiwayatTransaksiPending(),
),
);
},
child: Text(
"Cek Status Transaksi",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: semiBold,
color: primaryColor,
letterSpacing: 0.5,
),
),
style: TextButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.background,
shape: RoundedRectangleBorder(
side: BorderSide(color: primaryColor),
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(10)),
),
backgroundColor: Colors.transparent,
),
),
),
SizedBox(height: getProportionateScreenHeight(32)),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(16)),
child: Text(
'Cara Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 0.5,
),
Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(16)),
child: detailOrder[0].bankName == 'indomaret' ||
detailOrder[0].bankName == 'alfamart'
? BarBatasBayar(detailOrder[0].bankName!)
: TabBarBatasBayar()),
],
),
),
SizedBox(height: getProportionateScreenHeight(30)),
],
),
);
} else {
return Center(
child: Text('Terjadi Kesalahan'),
);
}
},
),
),
);
}
@override
Widget build(BuildContext context) {
return _buildBatasBayarHistory();
}
}

View File

@ -0,0 +1,991 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_countdown_timer/current_remaining_time.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_order_model.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/screens/checkout/components/bar_batas_bayar.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/components/tab_bar_batas_bayar.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/services/cancel_payment_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator_pop.dart';
import 'package:initial_folder/widgets/login_regist/default_button_payment.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:pusher_client/pusher_client.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shimmer/shimmer.dart';
import 'package:initial_folder/screens/checkout/success_paid_course.dart';
import 'package:initial_folder/providers/payments_provider.dart' as payProv;
class BatasBayarBank extends StatefulWidget {
BatasBayarBank({
this.historyTransactionModel,
this.isFromHistory,
this.idCart,
});
final HistoryTransactionModel? historyTransactionModel;
final bool? isFromHistory;
final List<String>? idCart;
@override
State<BatasBayarBank> createState() => _BatasBayarBankState();
}
class _BatasBayarBankState extends State<BatasBayarBank> {
Channel? _channel;
String? statusTransaction;
String? statusMessage;
bool isLoading = false;
PusherClient? pusher;
Duration? remainingTime;
String capitalize(String s) =>
s[0].toUpperCase() + s.substring(1).toLowerCase();
Future<void> saveRemainingTime(Duration remainingTime) async {
final prefs = await SharedPreferences.getInstance();
prefs.setInt('remainingTime', remainingTime.inSeconds);
}
Future<void> deleteCourse() async {
List<String> idCarts = widget.idCart!;
for (var element in idCarts) {
await Provider.of<CartProvider>(context, listen: false)
.deleteCart(element);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
}
}
Future<void> initPusher() async {
int? idUser = await UsersInfo().getIdUser();
PusherClient pusher = PusherClient(
'92060797e94ac7033edb', PusherOptions(cluster: 'ap1'),
autoConnect: false);
pusher.connect();
pusher.onConnectionStateChange((state) {
print(state!.currentState);
});
pusher.onConnectionError((error) {
print(error);
});
_channel = pusher.subscribe('payment-channel');
_channel!.bind(
'paid-event-$idUser',
(event) async {
print("Event? ini apaan dah ${event!.data!}");
if (mounted) {
final status = jsonDecode(event.data!);
final newStatusTransaction = status['status_code'];
final newStatusMessage = status['message'];
if (newStatusMessage.contains("Berhasil !") &&
newStatusTransaction == '200') {
await deleteCourse();
if (mounted) {
setState(() {
statusTransaction = newStatusTransaction;
statusMessage = newStatusMessage;
});
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => SuccessPaidCourse(),
),
(route) => false,
);
}
} else if (newStatusMessage.contains("Dibatalkan") &&
newStatusTransaction == '200') {
await deleteCourse();
if (mounted) {
setState(() {
statusTransaction = newStatusTransaction;
statusMessage = newStatusMessage;
});
Navigator.pop(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor: Theme.of(context).colorScheme.background,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
contentPadding: EdgeInsets.fromLTRB(12, 26, 22, 15),
content: Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(14)),
child: Text(
textAlign: TextAlign.center,
"Transaksi berhasil dibatalkan",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
),
),
),
),
);
}
}
}
},
);
}
@override
void initState() {
initPusher();
super.initState();
}
@override
void dispose() {
if (remainingTime != null) {
saveRemainingTime(remainingTime!);
}
super.dispose();
}
Widget _buildBatasBayarHistory() {
List<DetailOrderModel> detailOrder =
Provider.of<payProv.PaymentsProvider>(context).detailOrder;
var orders = Provider.of<OrderProvider>(context, listen: false).orders;
var selected = Provider.of<OrderProvider>(context);
selected.selectedThumbnail = orders[0].imageUrl;
selected.selectedTitle = orders[0].title;
selected.selectedInstructor = orders[0].instructor;
PageProvider pageProvider = Provider.of<PageProvider>(context);
Widget mandiriPay() {
return detailOrder[0].bankName == 'mandiri'
? Column(
children: [
Row(
children: [
Text(
detailOrder[0].billerCode.toString(),
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: detailOrder[0].billerCode.toString()))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Berhasil Menyalin Kode Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
],
)
: Row();
}
Widget indomartPay() {
return detailOrder[0].bankName == 'indomaret'
? Column(
children: [
Row(
children: [
Text(
detailOrder[0].merchantId!,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(
ClipboardData(text: detailOrder[0].merchantId!))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Berhasil Menyalin Kode Merchant'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
),
],
),
],
)
: Row();
}
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
centerTitle: true,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Menunggu Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: Theme.of(context).colorScheme.onBackground,
size: getProportionateScreenWidth(17),
),
onPressed: () {
pageProvider.currentIndex == 0;
Navigator.pushAndRemoveUntil(
context,
CustomNavigatorPop(child: HomeScreen()),
(route) => false,
);
},
),
),
body: SingleChildScrollView(
child: Consumer<payProv.PaymentsProvider>(
builder: (context, state, _) {
if (state.stateProcess == payProv.Process.loading) {
return Padding(
padding: const EdgeInsets.all(20),
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: getProportionateScreenHeight(40)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(250),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(40),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(30)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(170),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
),
],
),
),
);
} else if (state.state == payProv.ResultState.gagal &&
state.stateProcess == payProv.Process.uninitialized) {
return Center(
child: Text('Gagal Mengambil Pesanan'),
);
} else if (state.state == payProv.ResultState.success &&
state.stateProcess == payProv.Process.uninitialized) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(8)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: getProportionateScreenHeight(10)),
Center(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 2,
offset:
Offset(0, getProportionateScreenHeight(4)),
),
],
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(15),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Batas Waktu Pembayaran',
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
DateFormat('E, d MMM y H:m WIB').format(
detailOrder[0].transactionTimeLimit),
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
Container(
decoration: BoxDecoration(
color: sevenColor,
borderRadius: BorderRadius.circular(4),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(3),
vertical: getProportionateScreenHeight(2),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
Icons.access_time,
color: baruTextutih,
size: getProportionateScreenWidth(14),
),
SizedBox(
width:
getProportionateScreenWidth(2)),
CountdownTimer(
endTime: DateTime.now()
.add(Duration(hours: 24))
.millisecondsSinceEpoch,
widgetBuilder:
(_, CurrentRemainingTime? time) {
if (time == null) {
return Text(
'00:00:00',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(
10),
color: baruTextutih,
),
);
} else {
remainingTime = Duration(
hours: time.hours ?? 0,
minutes: time.min ?? 0,
seconds: time.sec ?? 0,
);
return Text(
'${time.hours}:${time.min}:${time.sec}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(
10),
color: baruTextutih,
),
);
}
},
),
],
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Text(
"Kursus",
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: orders.map((e) {
return listCourse(
imageUrl: e.imageUrl,
instructor: e.instructor,
title: e.title,
price: e.price,
discountPrice: e.discountPrice,
);
}).toList(),
),
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
detailOrder[0].bankName == 'mandiri'
? 'Mandiri Virtual Account'
: detailOrder[0].bankName == 'permata'
? 'Permata Virtual Account'
: detailOrder[0].bankName == 'bni'
? 'BNI Virtual Account'
: detailOrder[0].bankName == 'bca'
? 'BCA Virtual Account'
: detailOrder[0].bankName ==
'indomaret'
? 'Indomaret'
: 'Alfamart',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.fill,
image: detailOrder[0].bankName ==
'mandiri'
? AssetImage(
"assets/images/mandiri.png")
: detailOrder[0].bankName == 'permata'
? AssetImage(
"assets/images/permata.png")
: detailOrder[0].bankName == 'bni'
? AssetImage(
"assets/images/bni.png")
: detailOrder[0].bankName ==
'bca'
? AssetImage(
"assets/images/bca.png")
: detailOrder[0]
.bankName ==
'alfamart'
? AssetImage(
"assets/images/alfamart.png")
: AssetImage(
"assets/images/indomaret.png"),
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
detailOrder[0].bankName == 'alfamart' ||
detailOrder[0].bankName == 'indomaret'
? 'Nomor Pesanan'
: 'Nomor Virtual Akun',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
detailOrder[0].virtualNumber ?? 'ABCD',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text:
detailOrder[0].virtualNumber!))
.then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(detailOrder[0]
.bankName ==
'alfamart' ||
detailOrder[0].bankName ==
'indomaret'
? 'Berhasil Menyalin Nomor Pesanan'
: 'Berhasil Menyalin Nomor Virtual Akun'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
detailOrder[0].bankName == 'indomaret'
? Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(16),
bottom: getProportionateScreenHeight(8),
),
child: Text(
'Kode Merchant',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
)
: SizedBox.shrink(),
detailOrder[0].bankName == 'mandiri'
? Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(16),
bottom: getProportionateScreenHeight(8),
),
child: Text(
'Kode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
)
: SizedBox.shrink(),
indomartPay(),
mandiriPay(),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
showModalBottomSheet(
backgroundColor: Theme.of(context)
.colorScheme
.background,
elevation: 0.0,
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (context) {
return BottomSheetDetail();
},
);
},
child: Text(
"Detail Pembayaran",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
SizedBox(
height:
getProportionateScreenHeight(24)),
DefaultButtonPayment(
text: 'Ubah Metode Pembayaran',
weight: semiBold,
press: () {
state.selectedIdOrders = "";
Navigator.pop(context);
},
width: 320,
height: 44,
),
SizedBox(
height:
getProportionateScreenHeight(12)),
SizedBox(
width: getProportionateScreenWidth(320),
height: getProportionateScreenHeight(38),
child: TextButton(
onPressed: () async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
elevation: 0.0,
backgroundColor:
Theme.of(context)
.colorScheme
.background,
contentPadding:
EdgeInsets.symmetric(
vertical:
getProportionateScreenHeight(
20),
horizontal:
getProportionateScreenWidth(
10),
),
actionsPadding: EdgeInsets.only(
right:
getProportionateScreenWidth(
10),
bottom:
getProportionateScreenHeight(
12),
),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
getProportionateScreenWidth(
4)),
),
content: Text(
'Apakah Anda yakin ingin membatalkan transaksi?'),
actions: [
GestureDetector(
child: Text(
'Ya',
style: TextStyle(
color: primaryColor,
fontSize:
getProportionateScreenWidth(
11),
),
),
onTap: () async {
state.selectedIdOrders =
"";
Navigator.of(context)
.pop();
CancelPaymentService
cancelPaymentService =
CancelPaymentService();
setState(() {
isLoading = true;
});
await cancelPaymentService
.cancelPayment(
detailOrder[0]
.idOrder
.toString());
await Future.delayed(
Duration(seconds: 2));
setState(() {
isLoading = false;
});
},
),
SizedBox(
width:
getProportionateScreenWidth(
5)),
GestureDetector(
child: Text(
'Tidak',
style: TextStyle(
color: primaryColor,
fontSize:
getProportionateScreenWidth(
11),
),
),
onTap: () {
Navigator.of(context)
.pop();
},
),
],
);
},
);
},
child: isLoading
? Container(
width:
getProportionateScreenWidth(
15),
height:
getProportionateScreenHeight(
13),
child:
CircularProgressIndicator(
color: primaryColor,
),
)
: Text(
"Batalkan Transaksi",
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
12),
fontWeight: semiBold,
color: primaryColor,
letterSpacing: 0.5,
),
),
style: TextButton.styleFrom(
foregroundColor: Theme.of(context)
.colorScheme
.background,
shape: RoundedRectangleBorder(
side:
BorderSide(color: primaryColor),
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(5),
),
),
backgroundColor: Colors.transparent,
),
),
),
],
),
],
),
],
),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
padding: EdgeInsets.only(
top: getProportionateScreenHeight(15),
bottom: getProportionateScreenHeight(7),
left: getProportionateScreenWidth(18),
),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.2),
spreadRadius: 0,
blurRadius: 2,
offset: Offset(
0, getProportionateScreenHeight(4)),
),
],
),
child: Text(
'Cara Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(5),
),
child: detailOrder[0].bankName == 'indomaret' ||
detailOrder[0].bankName == 'alfamart'
? BarBatasBayar(detailOrder[0].bankName!)
: TabBarBatasBayar(),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(30)),
],
),
);
} else {
return Center(
child: Text('Terjadi Kesalahan'),
);
}
},
),
),
);
}
@override
Widget build(BuildContext context) {
return _buildBatasBayarHistory();
}
Widget listCourse({
String? imageUrl,
String? title,
String? instructor,
String? price,
String? discountPrice,
int? totalPrices,
}) {
return Container(
padding: EdgeInsets.symmetric(vertical: getProportionateScreenHeight(9)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(60),
height: getProportionateScreenHeight(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
image: NetworkImage(imageUrl ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg'),
fit: BoxFit.cover,
),
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,384 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/checkout/components/course_list.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/order_provider.dart' as provOrder;
import '../../providers/payments_provider.dart';
import 'snap_payment_page.dart';
class CheckoutCartCouponPage extends StatefulWidget {
CheckoutCartCouponPage({
Key? key,
required this.idCart,
this.potonganKupon,
this.discountHarga,
this.isKupon,
}) : super(key: key);
final List<String> idCart;
final int? potonganKupon;
final int? discountHarga;
final bool? isKupon;
@override
State<CheckoutCartCouponPage> createState() => _CheckoutCartCouponPageState();
}
class _CheckoutCartCouponPageState extends State<CheckoutCartCouponPage> {
final controller = TextEditingController();
@override
Widget build(BuildContext context) {
final priceCoupon = Provider.of<TotalPriceProvider>(context).priceCoupon;
final totalPrice2 = Provider.of<TotalPriceProvider>(context).totalPrice;
final totalPrice3 = Provider.of<TotalPriceProvider>(context).totalPrices;
final typeCoupon = Provider.of<TotalPriceProvider>(context).typeCoupon;
final finalPriceCoupon =
Provider.of<TotalPriceProvider>(context).finalPriceCoupon;
final potonganKupon2 =
Provider.of<TotalPriceProvider>(context).potonganKupon;
Widget bottomNav(String totalPrice) {
String totalHarga =
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice == '0' ? widget.discountHarga : double.parse(totalPrice))}";
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.onPrimary.withOpacity(0.1),
spreadRadius: 4,
blurRadius: 15,
offset: Offset(0, 4),
),
],
),
child: Row(
children: [
SizedBox(width: 13),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(6)),
Text(
"Total",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
fontWeight: semiBold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon! < 50000 ? finalPriceCoupon + 5000 : finalPriceCoupon)}',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23,
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga)}',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
],
),
Spacer(),
GestureDetector(
onTap: () async {
print("Ini id cart? ${widget.idCart}");
if (totalHarga == 'Rp. 0') {
// Jika harga total adalah 0, arahkan ke halaman zero-payment
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailZeroPayment(idCart: widget.idCart),
),
);
} else {
// harga dan id transaksi untuk Snap Midtrans
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = int.parse(totalHarga.replaceAll('Rp. ', '').replaceAll(',', ''));
// Persiapkan data_invoice berdasarkan pesanan
List<Map<String, dynamic>> dataInvoice = widget.idCart.map((id) {
return {
'id_kursus': id,
'title_kursus': 'Nama Kursus',
'harga': grossAmount.toString(),
'qty': '1',
};
}).toList();
// Panggil Snap melalui provider
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
Map<String, String>? paymentResponse = await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
);
if (paymentResponse != null) {
// Jika Snap berhasil, tampilkan halaman WebView Snap
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: paymentResponse['transactionToken'] ?? '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
print("Pembayaran gagal");
}
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(135),
height: getProportionateScreenHeight(35),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Text(
'Pilih Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.5,
color: baruTextutih,
),
),
),
),
)
],
),
);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Checkout',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Detail Pesanan',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Consumer<provOrder.OrderProvider>(
builder: (context, state, _) {
print(state.orders.map((e) => e.idCourse));
return Column(
children: [
...state.orders.map(
(order) => CourseList(
idCourse: order.idCourse,
title: order.title,
price: widget.isKupon == null
? finalPriceCoupon.toString()
: (potonganKupon2 == 0
? priceCoupon.toString()
: (potonganKupon2! > totalPrice2!
? finalPriceCoupon.toString()
: totalPrice3.toString())),
discountPrice: order.discountPrice,
imageUrl: order.imageUrl,
),
),
],
);
},
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Rincian Harga',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(priceCoupon!)}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon == 0 ? priceCoupon : (potonganKupon2! > totalPrice2! ? finalPriceCoupon : totalPrice3))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Biaya Layanan',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(finalPriceCoupon! < 5000 ? "5000" : "0"))}',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Potongan Kupon',
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(typeCoupon != "3" ? widget.potonganKupon.toString() : (priceCoupon! - widget.potonganKupon!).toString()))}',
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Total Bayar',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon! < 50000 ? finalPriceCoupon + 5000 : finalPriceCoupon)}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga)}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
],
),
Row(
children: [
Text(''),
Spacer(),
if (widget.isKupon == null)
Text(
(int.parse(Provider.of<provOrder.OrderProvider>(context)
.totalPrice!) !=
0 &&
int.parse(
Provider.of<provOrder.OrderProvider>(context).totalPrice!) < 50000) ||
finalPriceCoupon! < 50000
? "+ admin Rp 5000"
: "",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
if (widget.isKupon != null)
Text(
(widget.discountHarga != 0 && widget.discountHarga! < 50000)
? "+ admin Rp 5000"
: "",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(
(int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String)).toString(),
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,296 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/order_provider.dart' as provOrder;
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/components/course_list.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/screens/checkout/snap_payment_page.dart'; // Import SnapPaymentPage
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class CheckoutCartPage extends StatefulWidget {
CheckoutCartPage({
Key? key,
required this.idCart,
this.potonganKupon,
this.discountHarga,
this.isCart,
this.isDetailCourse,
}) : super(key: key);
final List<String> idCart;
final int? potonganKupon;
final int? discountHarga;
final bool? isCart;
final bool? isDetailCourse;
@override
State<CheckoutCartPage> createState() => _CheckoutCartPageState();
}
class _CheckoutCartPageState extends State<CheckoutCartPage> {
final controller = TextEditingController();
@override
Widget build(BuildContext context) {
final subTotal = Provider.of<TotalPriceProvider>(context).subTotal;
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
final themeProvider = Provider.of<ThemeProvider>(context);
Widget bottomNav(String totalPrice) {
String totalHarga =
"Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice == '0' ? widget.discountHarga : double.parse(totalPrice))}";
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.onPrimary.withOpacity(0.1),
spreadRadius: 4,
blurRadius: 15,
offset: Offset(0, 4),
),
],
),
child: Row(
children: [
SizedBox(width: 13),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(6)),
Text(
"Total",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
fontWeight: semiBold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(Provider.of<provOrder.OrderProvider>(context).totalPrice as String == "0" ? (widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga) : (int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice!) == widget.discountHarga ? (int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice!) < 50000 ? int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice!) + 5000 : int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String)) : int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String)))}',
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
fontWeight: bold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
],
),
Spacer(),
GestureDetector(
onTap: () async {
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = Provider.of<provOrder.OrderProvider>(context, listen: false)
.orders
.fold(0, (sum, order) {
// Gunakan harga diskon jika tersedia, jika tidak ada gunakan harga asli
int harga = (order.discountPrice != null && order.discountPrice != "0")
? int.parse(order.discountPrice)
: int.parse(order.price);
// Tambahkan biaya admin jika harga di bawah 50.000
return sum + (harga < 50000 ? harga + 5000 : harga);
});
// Persiapkan data_invoice berdasarkan kursus yang ada di keranjang
List<Map<String, dynamic>> dataInvoice = [];
Provider.of<provOrder.OrderProvider>(context, listen: false).orders.forEach((order) {
dataInvoice.add({
'id_kursus': order.idCourse.toString(),
'title_kursus': order.title,
// Gunakan harga diskon jika tersedia, jika tidak gunakan harga asli
'harga': (order.discountPrice != null && order.discountPrice != "0")
? order.discountPrice.toString()
: order.price.toString(),
'qty': '1',
});
});
// Panggil Snap melalui provider
Map<String, String>? paymentResponse = await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
);
if (paymentResponse != null) {
// Snap berhasil dibuka, navigasi ke SnapPaymentPage untuk menampilkan WebView
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: paymentResponse['transactionToken'] ?? '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
print("Pembayaran gagal");
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(135),
height: getProportionateScreenHeight(35),
decoration: BoxDecoration(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
borderRadius: BorderRadius.circular(10)),
child: Center(
child: Text(
'Pilih Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.5,
color: baruTextutih,
),
),
),
),
)
],
),
);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Checkout',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Detail Pesanan',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Consumer<provOrder.OrderProvider>(
builder: (context, state, _) {
return Column(
children: [
...state.orders.map(
(order) => widget.isDetailCourse != null
? CourseList(
idCourse: order.idCourse,
title: order.title,
price: widget.isCart == null
? order.price
: (order.discountPrice != null
? order.discountPrice
: order.price),
discountPrice: order.discountPrice == null
? order.discountPrice
: order.price,
imageUrl: order.imageUrl,
isDetailCourse: true,
)
: CourseList(
idCourse: order.idCourse,
title: order.title,
price: widget.isCart == null
? order.price
: (order.discountPrice != null
? order.discountPrice
: order.price),
discountPrice: order.discountPrice == null
? order.discountPrice
: order.price,
imageUrl: order.imageUrl,
),
),
],
);
},
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Rincian Harga',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
RichText(
text: TextSpan(
children: [
if (widget.discountHarga.toString() != subTotal)
TextSpan(
text:
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(int.parse(subTotal!))}',
style: thirdTextStyle.copyWith(
decoration: TextDecoration.lineThrough,
color: fourthColor,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.8,
),
),
WidgetSpan(
child: SizedBox(
width: getProportionateScreenWidth(8))),
TextSpan(
text:
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(Provider.of<provOrder.OrderProvider>(context).totalPrice as String == "0" ? (widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga) : int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String))}',
style: thirdTextStyle.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(
(int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String)).toString(),
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,415 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/get_it.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/detail_course_coupon_provider.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import '../../providers/payments_provider.dart';
import 'components/course_list_coupon.dart';
import 'snap_payment_page.dart';
class CheckoutCouponPage extends StatefulWidget {
final idCourse;
final title;
final discountPrice;
final price;
final instructor;
final coupon;
const CheckoutCouponPage(
{Key? key,
required this.idCourse,
required this.instructor,
required this.title,
required this.price,
required this.discountPrice,
required this.coupon})
: super(key: key);
@override
State<CheckoutCouponPage> createState() => _CheckoutCouponPageState();
}
class _CheckoutCouponPageState extends State<CheckoutCouponPage> {
final controller = TextEditingController();
final provider = detailCouponGetIt<DetailCouponProvider>();
Future _showMessage(String text) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(22, 30, 22, 30),
content: Text(
text,
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
),
);
}
@override
Widget build(BuildContext context) {
provider.getDetail(widget.idCourse, widget.coupon);
return StreamBuilder<DataDetailCourseModel>(
stream: provider.detailStream,
builder: (context, AsyncSnapshot<DataDetailCourseModel> snapshot) {
final detail = snapshot.data;
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
case ConnectionState.none:
return Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
case ConnectionState.active:
case ConnectionState.done:
final detail = snapshot.data;
return body(
widget.idCourse,
detail?.title ?? '',
detail?.price ?? '0',
detail?.discountPrice ?? '0',
detail?.thumbnail ?? '',
);
}
}
return Container();
});
}
Widget bottomNav(String discountPrice, String price) {
String total = discountPrice == '0' ? price : discountPrice;
String totalPembayaran =
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price) - (double.parse(price) - double.parse(discountPrice)))}';
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
border: Border(top: BorderSide(color: fourthColor)),
boxShadow: [
BoxShadow(
offset: Offset(0, -2),
blurRadius: 50,
color: fourthColor.withOpacity(0.15))
]),
child: Row(
children: [
SizedBox(
width: 13,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: getProportionateScreenHeight(6),
),
Text(
"Total",
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
letterSpacing: 1),
),
SizedBox(
height: 2,
),
Builder(
builder: (BuildContext context) {
double total = double.parse(price) -
(double.parse(price) - double.parse(discountPrice));
if (total <= 50000) {
total += 5000;
}
return Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(total)}',
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23),
);
},
),
SizedBox(
height: getProportionateScreenHeight(2),
),
],
),
Spacer(),
GestureDetector(
onTap: () async {
if (totalPembayaran == 'Rp. 0') {
// Jika total pembayaran adalah 0, arahkan ke halaman zero-payment
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailZeroPayment(),
),
);
} else {
// Dapatkan total harga dan id transaksi untuk Snap Midtrans
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = int.parse(
totalPembayaran.replaceAll('Rp. ', '').replaceAll(',', '')
);
// Persiapkan data_invoice untuk kursus yang dibeli
List<Map<String, dynamic>> dataInvoice = [
{
'id_kursus': widget.idCourse,
'title_kursus': widget.title,
'harga': grossAmount.toString(),
'qty': '1',
}
];
// Panggil Snap melalui provider
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
Map<String, String>? paymentResponse = await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
);
if (paymentResponse != null) {
// Jika Snap berhasil, tampilkan halaman WebView Snap
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: paymentResponse['transactionToken'] ?? '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
print("Pembayaran gagal");
}
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(188),
height: getProportionateScreenHeight(41),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: Text(
'Lengkapi Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.32,
color: Color(0xff050505),
),
),
),
),
)
],
),
);
}
Widget body(String idCourse, String title, String price, String discountPrice,
String imageUrl) {
return Scaffold(
appBar: AppBar(
title: Text(
'Checkout',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
children: [
Text(
'Detail Pesanan',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
CourseListCoupon(
idCourse: idCourse,
title: title,
price: price,
discountPrice: discountPrice,
imageUrl: imageUrl),
SizedBox(
height: getProportionateScreenHeight(28),
),
Text(
'Rincian Harga',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: primaryTextStyle.copyWith(
letterSpacing: 1,
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
Spacer(),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Row(
children: [
Text(
'Potongan Kupon',
style: primaryTextStyle.copyWith(
letterSpacing: 1,
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
Spacer(),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price) - double.parse(discountPrice))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(5),
),
Divider(
color: tenthColor,
thickness: 0.5,
),
SizedBox(
height: getProportionateScreenHeight(5),
),
Row(
children: [
Text(
'Total',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
Builder(
builder: (BuildContext context) {
double total = double.parse(price) -
(double.parse(price) - double.parse(discountPrice));
if (total <= 50000) {
total += 5000;
} else {
total = total;
}
return Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(total)}',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
);
},
),
],
),
Row(
children: [
Text(''),
Spacer(),
Builder(
builder: (BuildContext context) {
double total = double.parse(price) -
(double.parse(price) - double.parse(discountPrice));
return total <= 50000
? Text(
'+ admin Rp 5000',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
)
: Container();
},
),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(discountPrice, price),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,391 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/checkout/components/course_list.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/order_provider.dart' as provOrder;
import '../../providers/payments_provider.dart';
import 'snap_payment_page.dart';
class CheckoutDetailCoupon extends StatefulWidget {
CheckoutDetailCoupon({
Key? key,
required this.idCart,
this.potonganKupon,
this.discountHarga,
this.isKupon,
}) : super(key: key);
final List<String> idCart;
final int? potonganKupon;
final int? discountHarga;
final bool? isKupon;
@override
State<CheckoutDetailCoupon> createState() => _CheckoutDetailCouponState();
}
class _CheckoutDetailCouponState extends State<CheckoutDetailCoupon> {
final controller = TextEditingController();
@override
Widget build(BuildContext context) {
final priceCoupon = Provider.of<TotalPriceProvider>(context).priceCoupon;
final totalPrice2 = Provider.of<TotalPriceProvider>(context).totalPrice;
final totalPrice3 = Provider.of<TotalPriceProvider>(context).totalPrices;
final typeCoupon = Provider.of<TotalPriceProvider>(context).typeCoupon;
final finalPriceCoupon =
Provider.of<TotalPriceProvider>(context).finalPriceCoupon;
final potonganKupon2 =
Provider.of<TotalPriceProvider>(context).potonganKupon;
Widget bottomNav(String totalPrice) {
String totalHarga =
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice == '0' ? widget.discountHarga : double.parse(totalPrice))}";
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.onPrimary.withOpacity(0.1),
spreadRadius: 4,
blurRadius: 15,
offset: Offset(0, 4),
),
],
),
child: Row(
children: [
SizedBox(width: 13),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(6)),
Text(
"Total",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
fontWeight: semiBold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon! < 50000 ? finalPriceCoupon + 5000 : finalPriceCoupon)}',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23,
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga)}',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
],
),
Spacer(),
GestureDetector(
onTap: () async {
print("Ini id cart? ${widget.idCart}");
if (totalHarga == 'Rp. 0') {
// Jika total harga adalah 0, arahkan ke halaman zero-payment
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailZeroPayment(idCart: widget.idCart),
),
);
} else {
// Dapatkan total harga dan id transaksi untuk Snap Midtrans
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = int.parse(
totalHarga.replaceAll('Rp. ', '').replaceAll(',', '')
);
// Persiapkan data_invoice berdasarkan kursus yang dibeli
List<Map<String, dynamic>> dataInvoice = [];
widget.idCart.forEach((cartId) {
dataInvoice.add({
'id_kursus': cartId, // Sesuaikan dengan data yang relevan
'title_kursus': 'Nama Kursus', // Nama kursus yang sesuai
'harga': grossAmount.toString(),
'qty': '1', // Sesuaikan jumlah jika diperlukan
});
});
// Panggil Snap melalui provider
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
Map<String, String>? paymentResponse = await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
);
if (paymentResponse != null) {
// Snap berhasil dibuka, arahkan ke halaman WebView Snap
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: paymentResponse[''] ?? '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
// Jika Snap gagal dibuka
print("Pembayaran gagal");
}
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(135),
height: getProportionateScreenHeight(35),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Text(
'Pilih Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.5,
color: baruTextutih,
),
),
),
),
)
],
),
);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Checkout',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Detail Pesanan',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Consumer<provOrder.OrderProvider>(
builder: (context, state, _) {
return Column(
children: [
...state.orders.map(
(order) => CourseList(
idCourse: order.idCourse,
title: order.title,
price: widget.isKupon == null
? finalPriceCoupon.toString()
: (potonganKupon2 == 0
? finalPriceCoupon.toString()
: (potonganKupon2! > totalPrice2!
? finalPriceCoupon.toString()
: totalPrice3.toString())),
discountPrice: priceCoupon.toString(),
imageUrl: order.imageUrl,
),
),
],
);
},
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Rincian Harga',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(priceCoupon!)}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon == 0 ? priceCoupon : (potonganKupon2! > totalPrice2! ? finalPriceCoupon : totalPrice3))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Biaya Layanan',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(finalPriceCoupon! < 5000 ? "5000" : "0"))}',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Potongan Kupon',
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(typeCoupon != "3" ? widget.potonganKupon.toString() : (priceCoupon! - finalPriceCoupon).toString()))}',
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Total Bayar',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon! < 50000 ? finalPriceCoupon + 5000 : finalPriceCoupon)}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga)}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
],
),
Row(
children: [
Text(''),
Spacer(),
if (widget.isKupon == null)
Text(
(int.parse(Provider.of<provOrder.OrderProvider>(context)
.totalPrice!) !=
0 &&
int.parse(
Provider.of<provOrder.OrderProvider>(context)
.totalPrice!) < 50000) ||
finalPriceCoupon! < 50000
? "+ admin Rp 5000"
: "",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
if (widget.isKupon != null)
Text(
(widget.discountHarga != 0 &&
widget.discountHarga! < 50000)
? "+ admin Rp 5000"
: "",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(
(int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice
as String))
.toString(),
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,559 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/get_it.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/detail_course_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/checkout/components/course_list.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/screens/login/login_screen.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/screens/my_course/success_free_course.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/payments_provider.dart'
as paymentsProvider;
import 'package:initial_folder/providers/my_course_provider.dart'
as myCourseProvider;
import '../../providers/payments_provider.dart';
import 'snap_payment_page.dart';
class CheckoutPage extends StatefulWidget {
final idCourse;
final title;
final discountPrice;
final price;
final instructor;
final thumbnail;
const CheckoutPage({
Key? key,
required this.idCourse,
required this.instructor,
required this.title,
required this.price,
required this.discountPrice,
required this.thumbnail,
}) : super(key: key);
@override
State<CheckoutPage> createState() => _CheckoutPageState();
}
class _CheckoutPageState extends State<CheckoutPage> {
final controller = TextEditingController();
final provider = detailGetIt<DetailProvider>();
Future _showMessage(String text) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(22, 30, 22, 30),
content: Text(
text,
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
),
);
}
@override
Widget build(BuildContext context) {
provider.getDetail(widget.idCourse);
final selectedTotalPrice = Provider.of<TotalPriceProvider>(context);
// String? discountPrice;
return StreamBuilder<DetailCourseModel>(
stream: provider.detailStream,
builder: (context, AsyncSnapshot<DetailCourseModel> snapshot) {
final detail = snapshot.data?.data[0][0];
// discountPrice = detail?.discountPrice ?? '0';
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
break;
case ConnectionState.none:
Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
break;
case ConnectionState.active:
final detail = snapshot.data?.data[0][0];
// discountPrice = detail?.discountPrice ?? '0';
body(widget.idCourse, detail?.title ?? '', detail?.price ?? '0',
detail?.discountPrice ?? '0', detail?.thumbnail ?? '');
break;
case ConnectionState.done:
final detail = snapshot.data?.data[0][0];
// discountPrice = detail?.discountPrice ?? '0';
body(widget.idCourse, detail?.title ?? '', detail?.price ?? '0',
detail?.discountPrice ?? '0', detail?.thumbnail ?? '');
break;
}
}
return body(widget.idCourse, detail?.title ?? '', detail?.price ?? '0',
detail?.discountPrice ?? '0', detail?.thumbnail ?? '');
},
);
}
Widget bottomNav(String discountPrice, String price) {
String total = discountPrice == '0' ? price : discountPrice;
paymentsProvider.PaymentsProvider pay =
Provider.of<paymentsProvider.PaymentsProvider>(context);
final selectedTotalPrice = Provider.of<TotalPriceProvider>(context);
hargaTotalNavBar() {
String hargaTotal =
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price) - (double.parse(price) - double.parse(discountPrice)))}';
return hargaTotal;
}
showNotifDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Consumer<paymentsProvider.PaymentsProvider>(
builder: (context, state, child) {
if (state.state == paymentsProvider.ResultState.gagal) {
return Container(
height: getProportionateScreenHeight(40),
width: getProportionateScreenWidth(15),
child: Center(
child: Text(
'Anda sudah memiliki kursus ini',
style: primaryTextStyle.copyWith(fontSize: 12),
textAlign: TextAlign.center,
),
),
);
} else {
return Text(
'Erorr lain',
style: thirdTextStyle,
);
}
},
),
);
},
);
}
Future _showDialogNotLogin(String teks) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 1),
content: Text(
'Mohon login terlebih dahulu sebelum $teks',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text('Batal',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
SizedBox(width: getProportionateScreenWidth(5)),
GestureDetector(
onTap: () {
Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false);
},
child: Text(
'Login',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor),
),
),
],
),
);
}
handleNotLoginFree(
String? id,
String? title,
String? thumb,
String? instr,
) async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
print("ini bisa ya");
if (await pay.freeCourse(int.parse(widget.idCourse))) {
await Provider.of<myCourseProvider.MyCourseProvider>(context,
listen: false)
.getMyCourse();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SuccessFreeCourse(
id: id,
thumbnail: thumb,
title: title,
instructor: instr,
),
),
);
} else {
showNotifDialog(context);
}
} else {
String teks = 'memiliki kursus ini';
return _showDialogNotLogin(teks);
}
}
int totalPrice;
if (int.parse(discountPrice) != 0 && int.parse(discountPrice) < 50000) {
totalPrice = int.parse(discountPrice) + 5000;
} else {
if (int.parse(price) < 50000) {
totalPrice = int.parse(price) + 5000;
} else {
totalPrice = int.parse(price);
}
}
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
border: Border(top: BorderSide(color: fourthColor)),
boxShadow: [
BoxShadow(
offset: Offset(0, -2),
blurRadius: 50,
color: fourthColor.withOpacity(0.15),
)
],
),
child: Row(
children: [
SizedBox(width: 13),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(6)),
Text(
"Total",
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
letterSpacing: 1),
),
SizedBox(height: 2),
if (int.parse(price) < 50000 || int.parse(discountPrice) < 50000)
Text(
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice)}",
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23),
)
else
Text(
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(discountPrice == "0" ? double.parse(price) : double.parse(discountPrice))}",
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23),
),
SizedBox(height: getProportionateScreenHeight(2)),
],
),
Spacer(),
GestureDetector(
onTap: () async {
selectedTotalPrice.selectedTotalPrice = totalPrice;
if (price == "0") {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailZeroPayment(
discountPrice: discountPrice,
price: price,
),
),
);
} else {
// Dapatkan total harga dan id transaksi untuk Snap Midtrans
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = int.parse(price);
// Persiapkan data invoice berdasarkan pesanan
List<Map<String, dynamic>> dataInvoice = [
{
'id_kursus': widget.idCourse,
'title_kursus': widget.title,
'harga': price.toString(),
'qty': '1',
}
];
// Panggil Snap melalui provider
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
bool success = (await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
)) as bool;
if (success) {
// Jika Snap berhasil, tampilkan halaman WebView Snap
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
print("Pembayaran gagal");
}
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(188),
height: getProportionateScreenHeight(41),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: Text(
'Lengkapi Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.32,
color: Color(0xff050505),
),
),
),
),
)
],
),
);
}
Widget body(String idCourse, String title, String price, String discountPrice,
String imageUrl) {
int totalPrice;
if (int.parse(discountPrice) != 0 && int.parse(discountPrice) < 50000) {
totalPrice = int.parse(discountPrice) + 5000;
} else {
if (int.parse(price) < 50000) {
totalPrice = int.parse(price) + 5000;
} else {
totalPrice = int.parse(price);
}
}
return Scaffold(
appBar: AppBar(
title: Text(
'Checkout',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
children: [
Text(
'Detail Pesanan',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
CourseList(
idCourse: idCourse,
title: title,
price: price,
discountPrice: discountPrice,
imageUrl: imageUrl),
SizedBox(height: getProportionateScreenHeight(28)),
Text(
'Rincian Harga',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: primaryTextStyle.copyWith(
letterSpacing: 1,
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
Spacer(),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Potongan Kupon',
style: primaryTextStyle.copyWith(
letterSpacing: 1,
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
Spacer(),
discountPrice != "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price) - double.parse(discountPrice))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
)
: Text(
'Rp. 0',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Divider(
color: tenthColor,
thickness: 0.5,
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Total',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
if (int.parse(price) < 50000 ||
int.parse(discountPrice) < 50000)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice)}',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
)
else
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(discountPrice == "0" ? double.parse(price) : double.parse(discountPrice))}',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
],
),
Row(
children: [
Text(''),
Spacer(),
if (int.parse(price) < 50000 ||
int.parse(discountPrice) < 50000 &&
int.parse(discountPrice) != 0)
Text(
'+ admin Rp 5000',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
)
else
SizedBox(),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(discountPrice, price),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,317 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:styled_text/styled_text.dart';
class ATMBNI extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masukkan kartu anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: '2. Pilih Bahasa',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: '3. Masukkan <bold>PIN ATM</bold> Anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih \"Menu Lainnya\"",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text: "5. Pilih \"Transfer\"",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '6. The billing information will appear on the payment validation page',
'6. Pilih Jenis rekening yang akan Anda gunakan',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '7. If the information is correct, enter your password to proceed the payment',
'7. Pilih \"Virtual Account Billing\"',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '8. Your transaction will be processed',
text: '8. Masukkan nomor Virtual Account Anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class ATMBCA extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masukkan kartu anda ATM dan PIN BCA anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pada menu utama, pilih menu \"Transaksi lainnya\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Transfer\" dan kemudian pilih \"BCA Virtual Account\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Masukkan no. BCA Virtual Account & klik \"Lanjutkan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text: "5. Periksa kembali rincian pembayaran anda, lalu pilih Ya",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class AtmMandiri extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masukkan kartu anda ATM dan PIN anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pada menu utama, pilih menu \"Bayar/Beli\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Multi Payment\" (jika di layar belum tersedia tekan menu \"Lainnya\" dan pilih \"Multi Payment\") ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"4. Masukkan nomor Biller Code pada kode perusahaan & klik \"Benar\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"5. Masukkan kode pembayaran (kode pembayaran Mandiri billpayment anda)",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"6. Periksa kembali data transaksi anda dan selesaikan proses pembayaran.",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class AtmPermata extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masukkan kartu ATM dan PIN anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pada menu \"Transaksi Lainnya\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Pembayaran\" kemudian Pilih \"Menu Pembayaran Lainnya\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih menu \"VIRTUAL ACCOUNT\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text: "5. Masukkan nomor \"VIRTUAL ACCOUNT\", dan tekan \"BENAR\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"6. Pilih rekening yang menjadi sumber dana yang akan didebet, lalu tekan YA untuk konfirmasi transaksi",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}

View File

@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:styled_text/styled_text.dart';
class BarBatasBayar extends StatelessWidget {
String storeName;
BarBatasBayar(this.storeName);
final TextStyle baris = thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(13),
);
@override
Widget build(BuildContext context) {
String store = storeName == 'indomaret' ? 'Indomaret' : 'Alfamart';
return Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(12),
vertical: getProportionateScreenHeight(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
text: '1. Datang ke<bold> $store</bold>',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text: '2. Tunjukkan <bold>kode pembayaran</bold> ke kasir',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
'3. Bayar dengan uang tunai sesuai dengan total pembayaran (sudah termasuk biaya layanan)',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text: '4. Transaksi selesai, simpan bukti pembayaran Anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: 4)
],
),
);
}
}

View File

@ -0,0 +1,263 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/order_provider.dart' as orderProvider;
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/providers/user_info_provider.dart'
as userInfoProvider;
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class BottomSheetDetail extends StatelessWidget {
Map<String, String> paymentMethod = {
'echannel': 'Bank Transfer',
'bank_transfer': 'Bank Transfer',
'credit_card': 'Kartu Kredit',
'gopay': 'GoPay',
'cstore': 'Gerai'
};
Widget listCourse({String? title, String? instructor, String? price}) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
// "428 Menit Menjadi Pengusaha Sukses",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
color: tenthColor,
),
),
SizedBox(height: 4),
Text(
'Oleh $instructor',
// 'Oleh Farid Subkhan',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(9.5),
color: secondaryColor,
),
),
],
),
),
Flexible(
flex: 3,
child: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price!))}',
// 'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(50000.0)}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
var dataOrder =
Provider.of<PaymentsProvider>(context, listen: false).detailOrder;
var dataCourse =
Provider.of<orderProvider.OrderProvider>(context, listen: false).orders;
var dataUser =
Provider.of<userInfoProvider.UserInfoProvider>(context, listen: false)
.result;
return Container(
decoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
foregroundDecoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.all(Radius.circular(20))),
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
Row(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.keyboard_arrow_down)),
Text('Detail Pembayaran')
],
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
height: MediaQuery.of(context).size.height * 0.4,
child: ListView(
shrinkWrap: true,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Informasi Pembeli'),
Divider(),
Text(
'Order ID',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataOrder[0].idOrder,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
SizedBox(
height: 15,
),
Text(
'Nama Lengkap',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataUser!.data[0].fullname!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
SizedBox(
height: 15,
),
Text(
'Email',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataUser.data[0].email!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
],
),
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Informasi Pembayaran'),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Metode Pembayaran',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffbfbfbf))),
Text(paymentMethod[dataOrder[0].paymentType]!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Harga',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf))),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(dataOrder[0].totalPayment))}',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Potongan Kupon',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf))),
Text('Rp. 0',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Bayar',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffbfbfbf))),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(dataOrder[0].totalPayment))}',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
],
),
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Kursus Yang Dibeli'),
Divider(),
Column(
children: dataCourse.map((course) {
return listCourse(
title: course.title,
instructor: course.instructor,
price: course.discountPrice == "0"
? course.price
: course.discountPrice,
);
}).toList()),
// listCourse(),
// listCourse(),
// listCourse(),
// Text('Halo'),
// Text('Halo'),
// Text('Halo'),
// Text('Halo')
],
),
)
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,262 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/order_provider.dart' as orderProvider;
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/providers/user_info_provider.dart'
as userInfoProvider;
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class BottomSheetHistory extends StatelessWidget {
Map<String, String> paymentMethod = {
'echannel': 'Bank Transfer',
'bank_transfer': 'Bank Transfer',
'credit_card': 'Kartu Kredit',
'gopay': 'GoPay',
'cstore': 'Gerai'
};
Widget listCourse({String? title, String? instructor, String? price}) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
// "428 Menit Menjadi Pengusaha Sukses",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
color: tenthColor,
),
),
SizedBox(height: 4),
Text(
'Oleh $instructor',
// 'Oleh Farid Subkhan',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(9.5),
color: secondaryColor,
),
),
],
),
),
Flexible(
flex: 3,
child: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price!))}',
// 'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(50000.0)}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
var dataOrder =
Provider.of<PaymentsProvider>(context, listen: false).detailOrder;
var dataCourse =
Provider.of<orderProvider.OrderProvider>(context, listen: false).orders;
var dataUser =
Provider.of<userInfoProvider.UserInfoProvider>(context, listen: false)
.result;
int totalPrices = Provider.of<TotalPriceProvider>(context).totalPrices!;
return Container(
decoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
foregroundDecoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.all(Radius.circular(20))),
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
Row(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.keyboard_arrow_down)),
Text('Detail Pembayaran')
],
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
height: MediaQuery.of(context).size.height * 0.4,
child: ListView(
shrinkWrap: true,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Informasi Pembeli'),
Divider(),
Text(
'Order ID',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataOrder[0].idOrder,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
SizedBox(
height: 15,
),
Text(
'Nama Lengkap',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataUser!.data[0].fullname!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
SizedBox(
height: 15,
),
Text(
'Email',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataUser.data[0].email!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
],
),
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Informasi Pembayaran'),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Metode Pembayaran',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffbfbfbf))),
Text(paymentMethod[dataOrder[0].paymentType]!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Harga',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf))),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(Provider.of<TotalPriceProvider>(context).totalPrices.toString()))}',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Potongan Kupon',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf))),
Text('Rp. 0',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Bayar',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffbfbfbf))),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(Provider.of<TotalPriceProvider>(context).totalPrices.toString()))}',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
],
),
),
Container(
height: 6,
color: Color(0xff181818),
),
// Container(
// padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text('Kursus Yang Dibeli'),
// Divider(),
// Column(
// children: dataCourse.map((course) {
// return listCourse(
// title: course.title,
// instructor: course.instructor,
// price: course.discountPrice);
// }).toList()),
// listCourse(),
// listCourse(),
// listCourse(),
// Text('Halo'),
// Text('Halo'),
// Text('Halo'),
// Text('Halo')
// ],
// ),
// )
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CardMonthInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
var masaController = newValue.text;
if (newValue.selection.baseOffset == 0) {
return newValue;
}
var buffer = new StringBuffer();
for (int i = 0; i < masaController.length; i++) {
buffer.write(masaController[i]);
var nonZeroIndex = i + 1;
if (nonZeroIndex % 2 == 0 && nonZeroIndex != masaController.length) {
buffer.write('/');
}
}
var string = buffer.toString();
return newValue.copyWith(
text: string,
selection: new TextSelection.collapsed(offset: string.length));
}
}

View File

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CardNumberInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
var text = newValue.text;
if (newValue.selection.baseOffset == 0) {
return newValue;
}
var buffer = new StringBuffer();
for (int i = 0; i < text.length; i++) {
buffer.write(text[i]);
var nonZeroIndex = i + 1;
if (nonZeroIndex % 4 == 0 && nonZeroIndex != text.length) {
buffer.write(' '); // Add double spaces.
}
}
var string = buffer.toString();
return newValue.copyWith(
text: string,
selection: new TextSelection.collapsed(offset: string.length));
}
}

View File

@ -0,0 +1,159 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
class CourseList extends StatelessWidget {
const CourseList({
Key? key,
required this.idCourse,
required this.title,
required this.price,
required this.discountPrice,
required this.imageUrl,
this.isDetailCourse,
}) : super(key: key);
final String idCourse;
final String title;
final String price;
final String discountPrice;
final String imageUrl;
final bool? isDetailCourse;
@override
Widget build(BuildContext context) {
print("Ini price ${price}");
print("Ini discountPrice ${discountPrice}");
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 10,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(70),
height: getProportionateScreenWidth(39),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(imageUrl),
),
),
),
],
)),
SizedBox(width: getProportionateScreenWidth(10)),
Expanded(
flex: 15,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
)),
Spacer(),
Flexible(
flex: 10,
child: Align(
alignment: Alignment.centerRight,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (isDetailCourse == null)
discountPrice == "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
)
: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
)
else
discountPrice == "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
)
: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price == "0" ? discountPrice : price))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
if (isDetailCourse == null)
if (discountPrice != "0" && discountPrice != price)
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(discountPrice))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
decoration: TextDecoration.lineThrough,
color: fourthColor,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.7,
),
)
else
SizedBox.shrink()
else if (price != "0")
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(discountPrice))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
decoration: TextDecoration.lineThrough,
color: fourthColor,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.7,
),
)
else
SizedBox.shrink(),
SizedBox(height: getProportionateScreenHeight(2)),
discountPrice != "0" && discountPrice != price
? SizedBox()
: SizedBox(),
],
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Divider(color: fourthColor),
SizedBox(height: getProportionateScreenHeight(5)),
],
);
}
}

View File

@ -0,0 +1,130 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class CourseListCoupon extends StatelessWidget {
final String idCourse;
final String title;
final String price;
final String discountPrice;
final String imageUrl;
const CourseListCoupon({
Key? key,
required this.idCourse,
required this.title,
required this.price,
required this.discountPrice,
required this.imageUrl,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final priceCoupon = Provider.of<TotalPriceProvider>(context).priceCoupon;
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 10,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(70),
height: getProportionateScreenWidth(39),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(imageUrl),
),
),
),
],
)),
SizedBox(width: getProportionateScreenWidth(10)),
Expanded(
flex: 15,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
)),
Spacer(),
Flexible(
flex: 10,
child: Align(
alignment: Alignment.centerRight,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
discountPrice == "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
)
: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(discountPrice))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
// Text(
// 'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: reguler,
// fontSize: getProportionateScreenWidth(12),
// ),
// ),
SizedBox(
height: getProportionateScreenHeight(2),
),
priceCoupon.toString() != "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(priceCoupon.toString()))}',
style: primaryTextStyle.copyWith(
decoration: TextDecoration.lineThrough,
color: secondaryColor,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
)
: SizedBox(),
],
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Divider(color: fourthColor),
SizedBox(height: getProportionateScreenHeight(5)),
],
);
}
}

View File

@ -0,0 +1,105 @@
import 'package:flutter/material.dart';
import '../../../../theme.dart';
import '../../../../size_config.dart';
class FieldKupon extends StatelessWidget {
final TextEditingController controler;
final IconButton? prefix;
const FieldKupon({Key? key, required this.controler, this.prefix})
: super(key: key);
@override
Widget build(BuildContext context) {
OutlineInputBorder outlineInputBorder = OutlineInputBorder(
borderSide: BorderSide(color: Colors.transparent),
gapPadding: 10,
);
// width: SizeConfig.screenWidth * 0.9,
// height: 33,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(15),
// border: Border.all(
// color: kSecondaryColor.withOpacity(0.5),
// width: 2,
// return Scaffold(
// body: Container(
// height: 36,
// //padding: EdgeInsets.only(top: getProportionateScreenWidth(20)),
// child: TextField(
// controller: controler,
// cursorColor: secondaryColor,
// enabled: true,
// //obscureText: true,
// textAlignVertical: TextAlignVertical.center,
// style: TextStyle(fontSize: 12, color: Colors.white),
// onChanged: (value) => print(value),
// decoration: InputDecoration(
// //isDense: true,
// contentPadding: EdgeInsets.only(top: 10, left: 15),
// filled: true,
// fillColor: Colors.transparent,
// enabledBorder: outlineInputBorder,
// focusedBorder: outlineInputBorder,
// border: outlineInputBorder,
// hintText: "Masukkan kode kupon",
// hintStyle: primaryTextStyle.copyWith(
// fontSize: 12,
// color: fourthColor,
// fontWeight: reguler,
// letterSpacing: 0.5),
// ),
// ),
// ),
// // SizedBox(height: getProportionateScreenHeight(16)),
// );
return Column(
children: [
Container(
height: getProportionateScreenHeight(32),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).brightness == Brightness.dark
? seventeenColor.withOpacity(0.9)
: secondaryColor.withOpacity(0.2),
),
child: TextField(
controller: controler,
cursorColor: Theme.of(context).colorScheme.onPrimary,
enabled: true,
textAlignVertical: TextAlignVertical.center,
style: TextStyle(
fontSize: 14,
color: Theme.of(context).colorScheme.onPrimary,
),
onChanged: (value) => print(value),
decoration: InputDecoration(
prefix: prefix,
contentPadding: EdgeInsets.only(
top: getProportionateScreenHeight(10),
left: getProportionateScreenWidth(15),
),
filled: true,
fillColor: Colors.transparent,
enabledBorder: outlineInputBorder,
focusedBorder: outlineInputBorder,
border: outlineInputBorder,
hintText: "Masukkan kode kupon",
hintStyle: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih.withOpacity(0.5)
: Colors.grey,
fontWeight: reguler,
letterSpacing: 0.5,
),
),
),
),
SizedBox(height: getProportionateScreenHeight(16)),
],
);
}
}

View File

@ -0,0 +1,337 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:styled_text/styled_text.dart';
class InternetBankBNI extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masuk ke https://ibank.bni.co.id',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: '2. Masukkan User ID dan Password',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Transfer\", lalu pilih \"Tambah Rekening Favorit\". Jika menggunakan Desktop. tambah rekening pada menu \"Transaksi\" kemudian \"Atur Rekening Tujuan\" lalu pilih \"Tambah Rekening Tujuan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Masukkan nomor Virtual Account",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"5. Masukkan Kode Otentikasi dan Nomor Rekening berhasil ditambahkan",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '6. The billing information will appear on the payment validation page',
"6. Pilih menu \"Transfer\", lalu pilih \"Transfer Antar Rekening BNI\", pilih \"Rekening Tujuan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '7. If the information is correct, enter your password to proceed the payment',
"7. Pilih Rekening Debit",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '8. Your transaction will be processed',
text: "8. Masukkan jumlah pembayaran sesuai tagihan",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '8. Your transaction will be processed',
text: "9. Masukkan Kode Otentikasi",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class InternetBankBCA extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Login pada aplikasi KlikBCA, masukkan user ID & PIN.',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text:
"2. Pilih \"Transfer Dana\", kemudian pilih \"Transfer ke BCA Virtual Account\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Masukkan no. BCA Virtual Account & klik \"Lanjutkan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"4. Pastikan data yang dimasukkan sudah benar, dan Input \"Respon KeyBCA\", lalu klik \"Kirim\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class InternetBankMandiri extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Lakukan Login ke Internet Banking Mandiri kamu.',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text:
"2. Pada menu utama, pilih menu \"Bayar\" lalu pilih menu \"Multi Payment\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih akun anda di bagian Dari Rekening, kemudian di Penyedia Jasa ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"4. Masukkan kode pembayaran (kode pembayaran Mandiri billpayment kamu), dan klik \"Lanjutkan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"5. Periksa kembali nama perusahaan, nomor pesanan, dan jumlah pembayaran anda ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "6. Selesaikan pembayaran dengan menggunakan Token Mandiri ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class InternetBankPermata extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Buka Website PermataNet',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Masukan User ID dan Password ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Pilih Pembayaran Tagihan ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih Virtual Account ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "5. Masukkan 16 digit kode bayar ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "6. Masukkan nominal pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "7. Muncul konfirmasi pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "8. Masukan Mobile PIN",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}

View File

@ -0,0 +1,351 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:styled_text/styled_text.dart';
class MobileBankBNI extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: "1. Akses BNI Mobile Banking melalui handphone",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Masukkan User ID dan Password",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Transfer\", lalu pilih \"Antar Rekening BNI\", pilih \"Input Rekening Baru\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Masukkan nomor Virtual Account",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"5.Di halaman konfirmasi, pastikan data transaksi sudah benar kemudian pilih \"Ya\"",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '6. The billing information will appear on the payment validation page',
"6. Masukkan password anda ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class MobileBankBCA extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Lakukan log in pada aplikasi BCA mobile.',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pilih \"m-BCA\" masukan kode akses m-BCA. ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Pilih \"m-Transfer\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih \"BCA Virtual Account\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "5. Masukkan nomor BCA Virtual Account dan klik \"OK\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "6. Konfirmasi no virtual account dan rekening pendebetan ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"7. Periksa kembalian rincian pembayaran kamu, lalu klik \"Ya\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "8. Masukan pin m-BCA ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class MobileBankMandiri extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Lakukan Login ke Mandiri Online kamu',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pada menu utama, pilih menu \"Bayar\"",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Lalu pilih menu \"Multi Payment\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. kemudian pilih Penyedia Jasa ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"5. Masukkan kode pembayaran [Kode pembayaran Mandiri billpayment], dan klik \"Lanjutkan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"6. Periksa kembali data transaksi kamu dan selesaikan proses pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class MobileBankPermata extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Buka aplikasi PermataMobile X',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Masukan Password ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Pilih Pembayaran Tagihan ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih Virtual Account ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "5. Masukan Nomor Virtual Account ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "6. Pilih Rekening",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "7. Masukkan nominal pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "8. Muncul konfirmasi pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "9. Masukan Mobile PIN",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}

View File

@ -0,0 +1,145 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/detail_order_model.dart';
import 'package:initial_folder/providers/payments_provider.dart' as payProv;
import 'package:initial_folder/providers/tab_provider.dart';
import 'package:initial_folder/screens/checkout/components/atm.dart';
import 'package:initial_folder/screens/checkout/components/internet_banking.dart';
import 'package:initial_folder/screens/checkout/components/mobile_banking.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
class TabBarBatasBayar extends StatelessWidget {
TabBarBatasBayar({
Key? key,
this.bank,
}) : super(key: key);
final String? bank;
@override
Widget build(BuildContext context) {
print("Apa hayoo ${bank}");
List<DetailOrderModel> detailOrder =
Provider.of<payProv.PaymentsProvider>(context).detailOrder;
String? bankName = detailOrder.isNotEmpty ? detailOrder[0].bankName : null;
print("Apa hayoo2 ${bankName}");
TabProvider tab = Provider.of<TabProvider>(context);
Widget buildContent(int currentIndex) {
switch (currentIndex) {
case 0:
switch (bank ?? bankName) {
case 'bni':
return ATMBNI();
case 'bca':
return ATMBCA();
case 'mandiri':
case 'echannel':
return AtmMandiri();
case 'permata':
return AtmPermata();
default:
return SizedBox();
}
case 1:
switch (bank ?? bankName) {
case 'bni':
return InternetBankBNI();
case 'bca':
return InternetBankBCA();
case 'mandiri':
case 'echannel':
return InternetBankMandiri();
case 'permata':
return InternetBankPermata();
default:
return SizedBox();
}
case 2:
switch (bank ?? bankName) {
case 'bni':
return MobileBankBNI();
case 'bca':
return MobileBankBCA();
case 'mandiri':
case 'echannel':
return MobileBankMandiri();
case 'permata':
return MobileBankPermata();
default:
return SizedBox();
}
default:
return SizedBox();
}
}
return Column(
children: [
ExpansionTile(
title: Text(
'ATM',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13)),
),
children: [
buildContent(0),
],
),
Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(8)),
height: getProportionateScreenHeight(3),
decoration: BoxDecoration(
color: secondaryColor.withOpacity(0.1),
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 1,
offset: Offset(0, 1),
),
],
),
),
ExpansionTile(
title: Text(
'Internet Banking',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13)),
),
children: [
buildContent(1),
],
),
Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(8)),
height: getProportionateScreenHeight(3),
decoration: BoxDecoration(
color: secondaryColor.withOpacity(0.1),
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 1,
offset: Offset(0, 1),
),
],
),
),
ExpansionTile(
title: Text(
'Mobile Banking',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13)),
),
children: [
buildContent(2),
],
),
],
);
}
}

View File

@ -0,0 +1,435 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/zero_price_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/my_course_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/providers/user_info_provider.dart' as userInfo;
import 'package:initial_folder/screens/checkout/batas_bayar.dart';
import 'package:initial_folder/screens/checkout/success_paid_course.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class DetailZeroPayment extends StatelessWidget {
final String? discountPrice;
final String? price;
final List<String>? idCart;
const DetailZeroPayment(
{Key? key, this.idCart, this.discountPrice, this.price})
: super(key: key);
@override
Widget build(BuildContext context) {
Future<void> deleteCourse() async {
List<String> idCarts = idCart!;
idCarts.forEach((element) async {
await Provider.of<CartProvider>(context, listen: false)
.deleteCart(element);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
});
}
var invoice = Provider.of<OrderProvider>(context, listen: false).invoice;
var totalPrice =
Provider.of<OrderProvider>(context, listen: false).totalPrice!;
var orders = Provider.of<OrderProvider>(context, listen: false).orders;
print(orders);
var zero = Provider.of<PaymentsProvider>(context).zeroPrice;
Widget bottomNav() {
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(90),
vertical: getProportionateScreenHeight(10)),
child: DefaultButton(
text: 'Lanjutkan',
press: () {
Provider.of<PaymentsProvider>(context, listen: false)
.zeroPayment(invoice, totalPrice.toString());
deleteCourse();
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SuccessPaidCourse()));
},
),
);
}
Widget listCourse({String? title, String? instructor, String? price}) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
color: tenthColor,
),
),
SizedBox(height: 4),
Text(
'Oleh $instructor',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(9.5),
color: secondaryColor,
),
),
],
),
),
Flexible(
flex: 3,
child: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price!))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
),
],
),
);
}
var user = Provider.of<userInfo.UserInfoProvider>(context).result;
// var zero = Provider.of<PaymentsProvider>(context).zeroPrice;
return Scaffold(
//backgroundColor: Colors.black,
appBar: AppBar(
title: Text(
'Checkout',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Text(
'Informasi Pembeli',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: tenthColor,
),
),
),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 1),
Container(
padding: EdgeInsets.symmetric(
vertical: 10,
horizontal: getProportionateScreenWidth(15)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Text(
// 'Order ID',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: reguler,
// fontSize: getProportionateScreenWidth(10),
// color: secondaryColor,
// ),
// ),
// Text(
// // state.detailOrder[0].idOrder,
// // zero!.data![0].orderId as String,
// '123',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: reguler,
// fontSize: getProportionateScreenWidth(12),
// color: tenthColor,
// ),
// ),
// SizedBox(height: 16),
Text(
'Nama Lengkap',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
color: secondaryColor,
),
),
Text(
user!.data[0].fullname as String,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
SizedBox(height: 16),
Text(
'Email',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
color: secondaryColor,
),
),
Text(
user.data[0].email as String,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
SizedBox(height: 12),
],
),
),
],
),
),
],
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Text(
'Informasi Pembeli',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: tenthColor,
),
),
),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 1),
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Harga',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
color: secondaryColor,
),
),
discountPrice != "0"
? Text(
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(discountPrice!))}",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
12),
color: tenthColor,
),
)
: Text(
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price!))}",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
12),
color: tenthColor,
),
),
],
),
SizedBox(height: 16),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 1),
SizedBox(height: 16),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Bayar',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(12),
color: secondaryColor,
),
),
Text(
'Rp. 0',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize:
getProportionateScreenWidth(14),
color: tenthColor,
),
),
],
),
],
),
),
],
),
),
],
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Text(
'Kursus yang dibeli',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: tenthColor,
),
),
),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 1),
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: orders.map((e) {
return listCourse(
instructor: e.instructor,
title: e.title,
price: e.discountPrice);
}).toList(),
),
)
],
),
),
],
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
bottomNav(),
SizedBox(
height: getProportionateScreenHeight(15),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,377 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/gopay/payment_instruction_gopay.dart';
import 'package:initial_folder/screens/checkout/gopay/qr_code_gopay.dart';
import 'package:initial_folder/screens/checkout/success_paid_course.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:pusher_client/pusher_client.dart';
class BatasBayarGopay extends StatefulWidget {
final List<String>? idCart;
BatasBayarGopay({this.idCart});
@override
State<BatasBayarGopay> createState() => _BatasBayarGopayState();
}
class _BatasBayarGopayState extends State<BatasBayarGopay> {
Channel? _channel;
String? statusTransaction;
Future<void> deleteCourse() async {
List<String> idCarts = widget.idCart ?? [];
idCarts.forEach((element) async {
await Provider.of<CartProvider>(context, listen: false)
.deleteCart(element);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
});
}
Future<void> initPusher() async {
int? idUser = await UsersInfo().getIdUser();
PusherClient pusher = PusherClient(
'92060797e94ac7033edb', PusherOptions(cluster: 'ap1'),
autoConnect: false);
pusher.connect();
// pusher.onConnectionStateChange((state) {
// print(state!.currentState);
// });
// pusher.onConnectionError((error) {
// print(error);
// });
_channel = pusher.subscribe('payment-channel');
_channel!.bind('paid-event-$idUser', (event) {
if (mounted) {
final status = jsonDecode(event!.data!);
setState(() {
statusTransaction = status['status_code'];
if (statusTransaction == "201") {
print(status['message']);
print(widget.idCart);
deleteCourse();
// Navigator.of(context).pushAndRemoveUntil(
// MaterialPageRoute(
// builder: (context) => SuccessPaidCourse(),
// ),
// (route) => false,
// );
}
});
}
});
}
@override
void initState() {
initPusher();
super.initState();
}
@override
Widget build(BuildContext context) {
var detailOrder = Provider.of<PaymentsProvider>(context).detailOrder;
return Scaffold(
appBar: AppBar(
title: Text(
'Selesaikan Pembayaran',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: getProportionateScreenHeight(10)),
Center(
child: Column(
children: [
Text(
'Batas akhir pembayaran sampai',
style: primaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
// 'Rabu, 13 Oktober 2021 (Pukul 19:32)',
DateFormat('E, d MMM y (H:m)')
.format(detailOrder[0].transactionTimeLimit),
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
color: tenthColor,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Segera selesaikan pembayaran atau pesananmu',
style: primaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'akan dibatalkan secara otomatis',
style: primaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
],
),
),
SizedBox(
height: getProportionateScreenHeight(30),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Metode Pembayaran',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'GoPay',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.scaleDown,
image: AssetImage('assets/images/gopay2.png'),
),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(16),
),
Text(
'Kode QR',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Row(
children: [
Icon(Icons.qr_code),
Spacer(),
GestureDetector(
onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => QRCodeGopay()));
Navigator.pop(context);
},
child: Text(
"Scan Kode QR",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(16),
),
Text(
'Total Pembayaran',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(detailOrder[0].totalPayment))}',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20))),
builder: (context) {
return BottomSheetDetail();
});
},
child: Text(
"Detail Pembayaran",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(16),
),
Text(
'Status Pembayaran',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Text(
statusTransaction == '201' || statusTransaction == null
? 'Pending'
: 'Success',
style: primaryTextStyle.copyWith(
color: Color(0xffEDA923),
letterSpacing: 1,
fontWeight: medium,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
),
),
SizedBox(
height: getProportionateScreenHeight(24),
),
DefaultButton(
text: 'Belanja kursus lainnya',
weight: reguler,
press: () {
Navigator.pushNamedAndRemoveUntil(
context, "/home", (r) => false);
},
),
SizedBox(
height: getProportionateScreenHeight(32),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(16)),
child: Text(
'Cara Pembayaran',
style: secondaryTextStyle.copyWith(
color: tenthColor,
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Divider(
color: Color(0xff2D2D2D), thickness: 0.5, height: 0.5),
PaymentInstructionGopay()
],
),
),
SizedBox(
height: getProportionateScreenHeight(30),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,249 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/gopay/payment_instruction_gopay.dart';
import 'package:initial_folder/screens/checkout/gopay/qr_code_gopay.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class BayarGopay extends StatelessWidget {
BayarGopay({this.idCart});
final List<String>? idCart;
static String routeName = "/bayarGopay";
@override
Widget build(BuildContext context) {
Widget bottomNav() {
return DefaultButton(
text: 'Bayar dengan QRIS',
press: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => GopaySplashScreen(idCart: idCart),
),
);
},
);
}
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Bayar Dengan QRIS',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
body: Consumer<PaymentsProvider>(
builder: (context, state, _) {
if (state.stateProcess == Process.loading) {
return SizedBox(
height: MediaQuery.of(context).size.height,
child: Center(child: CircularProgressIndicator()));
} else if (state.state == ResultState.gagal) {
return Center(child: Text('Terjadi Kesalahan'));
} else {
return SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 10),
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal:
getProportionateScreenWidth(15)),
child: Text(
'Informasi Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: Theme.of(context)
.colorScheme
.onBackground,
),
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal:
getProportionateScreenWidth(15)),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'Order ID',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
fontFamily: "Poppins",
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
state.detailOrder[0].idOrder,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
12),
),
),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: state
.detailOrder[0].idOrder,
)).then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Berhasil Menyalin Kode Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(
10),
fontWeight: reguler),
),
),
],
),
SizedBox(
height:
getProportionateScreenHeight(10)),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
fontFamily: "Poppins",
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '').format(double.parse(state.detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize:
getProportionateScreenWidth(
12),
),
),
GestureDetector(
onTap: () {
showModalBottomSheet(
backgroundColor:
Theme.of(context)
.colorScheme
.background,
elevation: 0.0,
context: context,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (context) {
return BottomSheetDetail();
},
);
},
child: Text(
"Detail Pembayaran",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(
10),
fontWeight: reguler),
),
),
],
),
SizedBox(
height:
getProportionateScreenHeight(12)),
],
),
),
],
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(30)),
PaymentInstructionGopay(),
SizedBox(height: getProportionateScreenHeight(15)),
bottomNav(),
SizedBox(height: getProportionateScreenHeight(15)),
],
),
),
);
}
},
),
);
}
}

View File

@ -0,0 +1,395 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_countdown_timer/current_remaining_time.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/gopay/payment_instruction_gopay.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import '../../../size_config.dart';
import '../../../theme.dart';
class GopayPaymentConfirmation extends StatelessWidget {
@override
Widget build(BuildContext context) {
var detailOrder =
Provider.of<PaymentsProvider>(context, listen: false).detailOrder;
var orders = Provider.of<OrderProvider>(context, listen: false).orders;
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
scrolledUnderElevation: 0.0,
title: Text(
'Cara Pembayaran',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
body: Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(10)),
child: SingleChildScrollView(
child: Column(
children: [
Container(
height: getProportionateScreenHeight(290),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
margin: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(9),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(15),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Batas Waktu Pembayaran',
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
DateFormat('E, d MMM y H:m WIB')
.format(detailOrder[0].transactionTimeLimit),
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
Container(
decoration: BoxDecoration(
color: sevenColor,
borderRadius: BorderRadius.circular(4),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(3),
vertical: getProportionateScreenHeight(2),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
Icons.access_time,
color: baruTextutih,
size: getProportionateScreenWidth(14),
),
SizedBox(width: getProportionateScreenWidth(2)),
CountdownTimer(
endTime: DateTime.now()
.add(Duration(hours: 24))
.millisecondsSinceEpoch,
widgetBuilder: (_, CurrentRemainingTime? time) {
if (time == null) {
return Text(
'00:00:00',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(10),
color: baruTextutih,
),
);
} else {
return Text(
'${time.hours}:${time.min}:${time.sec}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(10),
color: baruTextutih,
),
);
}
},
),
],
),
),
],
),
SizedBox(height: getProportionateScreenHeight(4)),
Divider(
color: secondaryColor,
thickness: 1,
),
Text(
"Kursus",
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: orders.map((e) {
return listCourse(
imageUrl: e.imageUrl,
instructor: e.instructor,
title: e.title,
price: e.price,
discountPrice: e.discountPrice,
);
}).toList(),
),
SizedBox(height: getProportionateScreenHeight(10)),
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"QRIS",
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color:
Theme.of(context).colorScheme.brightness ==
Brightness.dark
? Colors.transparent
: baruTexthitam.withOpacity(0.3),
spreadRadius: 1,
blurRadius: 3,
offset: Offset(0, 1),
),
],
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage("assets/images/qris.png"),
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(15)),
Text(
"Order ID",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
detailOrder[0].idOrder,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(
ClipboardData(text: detailOrder[0].idOrder))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Berhasil Menyalin Order ID'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(15)),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(6)),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: detailOrder[0].totalPayment))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Berhasil Menyalin Total Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
],
),
),
SizedBox(height: getProportionateScreenHeight(13)),
PaymentInstructionGopay(),
SizedBox(height: getProportionateScreenHeight(17)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
width: double.infinity,
height: getProportionateScreenHeight(42),
decoration: BoxDecoration(
color: primaryColor,
border: Border.all(
color: primaryColor,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
child: Center(
child: Text(
'Lihat QRIS',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
fontWeight: semiBold,
color: baruTextutih,
),
),
),
),
onTap: () {
Navigator.pop(context);
},
),
),
SizedBox(height: getProportionateScreenHeight(21)),
],
),
),
),
);
}
Widget listCourse({
String? imageUrl,
String? title,
String? instructor,
String? price,
String? discountPrice,
int? totalPrices,
}) {
return Container(
padding: EdgeInsets.symmetric(vertical: getProportionateScreenHeight(9)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(60),
height: getProportionateScreenHeight(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
image: NetworkImage(imageUrl ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg'),
fit: BoxFit.cover,
),
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,102 @@
import 'package:flutter/material.dart';
import 'package:styled_text/styled_text.dart';
import '../../../size_config.dart';
import '../../../theme.dart';
class PaymentInstructionGopay extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(14),
);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(15),
horizontal: getProportionateScreenWidth(16),
),
child: Text(
'Cara Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
text:
'1. Buka aplikasi <bold>Gojek</bold> atau <bold>e-Wallet</bold> apapun milik anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
StyledText(
text:
'2. Scan <bold>QR Code</bold> yang tertera dan masukkan nominal sesuai tagihan transaksi',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
StyledText(
text:
'3. Periksa detail transaksi Anda pada aplikasi, lalu tap tombol Bayar.',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
StyledText(
text: '4. Masukkan pin Anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
StyledText(
text: '5. Transaksi Anda telah selesai',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,345 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/batas_bayar.dart';
import 'package:initial_folder/screens/checkout/gopay/batas_bayar_gopay.dart';
import 'package:initial_folder/screens/checkout/gopay/gopay_payment_confirmation.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi_pending.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
class QRCodeGopay extends StatelessWidget {
final List<String>? idCart;
QRCodeGopay({this.idCart});
@override
Widget build(BuildContext context) {
var detailOrder =
Provider.of<PaymentsProvider>(context, listen: false).detailOrder;
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
scrolledUnderElevation: 0.0,
leading: IconButton(
icon: Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
},
),
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(10),
),
child: Column(
children: [
Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(
"assets/images/qris_background.png",
width: getProportionateScreenWidth(328),
height: getProportionateScreenHeight(470),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: getProportionateScreenHeight(45)),
Text(
"VOCASIA",
style: secondaryTextStyle.copyWith(
fontWeight: bold,
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(40)),
child: Text(
"Lakukan pembayaran dengan cara scan code dibawah ini dan lakukan pembayaran sesuai dengan tagihan yang diterima.",
textAlign: TextAlign.center,
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(9),
color: baruTexthitam,
),
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Center(
child: Container(
height: getProportionateScreenHeight(150),
width: getProportionateScreenWidth(150),
child: Image.network(detailOrder[0].qrCodeUrl!
// 'https://api.sandbox.midtrans.com/v2/gopay/916c417c-dd69-455f-9f8d-997b31d38c21/qr-code'
),
),
),
// Image.network(),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Order ID',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
Text(
detailOrder[0].idOrder,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
fontWeight: semiBold,
letterSpacing: 1,
),
),
SizedBox(height: getProportionateScreenHeight(6)),
Text(
'Total',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '').format(double.parse(detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
fontWeight: semiBold,
letterSpacing: 2,
),
),
// Center(
// child: Text(
// detailOrder[0].qrCodeUrl!.toString(),
// style: thirdTextStyle.copyWith(
// fontWeight: semiBold,
// fontSize: 14,
// color: Color(0xff181818)),
// ),
// ),
// GestureDetector(
// child: Container(
// padding: EdgeInsets.all(16),
// width: double.infinity,
// height: getProportionateScreenHeight(44),
// decoration: BoxDecoration(
// color: Color(0xff25D366),
// border: Border.all(color: Color(0xff25D366), width: 1),
// borderRadius: BorderRadius.circular(10)),
// child: Center(
// child: Text(
// 'Pembayaran Gojek',
// style: thirdTextStyle.copyWith(
// fontSize: 14, color: Color(0xfff4f4f4)),
// ),
// ),
// ),
// onTap: () async {
// await openUrl(detailOrder[0].urlGopay!.toString());
// },
// ),
],
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
width: double.infinity,
height: getProportionateScreenHeight(40),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Cara Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
fontWeight: semiBold,
),
),
Icon(
Icons.keyboard_arrow_down_outlined,
size: getProportionateScreenWidth(22),
color: Theme.of(context).colorScheme.onBackground,
),
],
),
),
onTap: () {
Navigator.push(
context,
CustomNavigator(
child: GopayPaymentConfirmation(),
),
);
},
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
width: double.infinity,
height: getProportionateScreenHeight(43),
decoration: BoxDecoration(
color: primaryColor,
border: Border.all(
color: primaryColor,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
child: Center(
child: Text(
'Unduh QRIS',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
fontWeight: semiBold,
color: baruTextutih,
),
),
),
),
onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => GopayPaymentConfirmation()));
},
),
),
SizedBox(height: 16),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
width: double.infinity,
height: getProportionateScreenHeight(43),
decoration: BoxDecoration(
border: Border.all(
color: primaryColor,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
child: Center(
child: Text(
'Cek Status Transaksi',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: primaryColor,
fontWeight: semiBold,
),
),
),
),
onTap: () {
print(idCart);
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => BatasBayarGopay(idCart: idCart),
// ),
// );
Navigator.pushReplacement(
context,
CustomNavigator(
child: RiwayatTransaksiPending(),
),
);
},
),
),
SizedBox(height: getProportionateScreenHeight(20)),
],
),
),
),
);
}
}
class GopaySplashScreen extends StatefulWidget {
final List<String>? idCart;
GopaySplashScreen({this.idCart});
@override
State<GopaySplashScreen> createState() => _GopaySplashScreenState();
}
class _GopaySplashScreenState extends State<GopaySplashScreen> {
@override
void initState() {
super.initState();
Timer(
Duration(seconds: 2),
() => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => QRCodeGopay(idCart: widget.idCart),
),
),
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: SafeArea(
child: Container(
color: Color(0xff4DC256),
alignment: Alignment.center,
child: Image(
image: AssetImage('assets/images/gopay1.png'),
height: 50,
),
)),
);
}
}
Future<void> openUrl(String url,
{bool forceWebView = false, enableJavaScript = false}) async {
await launchUrl(Uri.parse(url));
}

View File

@ -0,0 +1,151 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/my_course_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/home/components/body_comp/latest_course.dart';
import 'package:initial_folder/screens/home/components/home_page.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
// import 'package:initial_folder/models/course_model.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:provider/provider.dart';
class NotSuccessPaidCourse extends StatelessWidget {
const NotSuccessPaidCourse({
Key? key,
this.title,
this.id,
this.thumbnail,
this.instructor,
}) : super(key: key);
final String? instructor, id, thumbnail, title;
@override
Widget build(BuildContext context) {
PageProvider pageProvider = Provider.of<PageProvider>(context);
var orders = Provider.of<OrderProvider>(context).orders;
return Scaffold(
appBar: AppBar(
leadingWidth: 14,
),
body: ListView(
children: [
SizedBox(height: getProportionateScreenHeight(8)),
Text(
'TRANSAKSI DIBATALKAN',
style: secondaryTextStyle.copyWith(
fontWeight: bold,
color: primaryColor,
fontSize: getProportionateScreenWidth(20),
letterSpacing: 1),
textAlign: TextAlign.center,
),
SizedBox(
height: getProportionateScreenHeight(16),
),
// Column(
// children: [
// Text(
// 'Order ID',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: bold,
// fontSize: getProportionateScreenWidth(10),
// color: secondaryColor,
// ),
// ),
// Text(
// '123',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: reguler,
// fontSize: getProportionateScreenWidth(12),
// color: tenthColor,
// ),
// ),
// ],
// ),
// SizedBox(
// height: getProportionateScreenHeight(16),
// ),
Container(
margin: EdgeInsets.only(left: 16, right: 16),
width: SizeConfig.screenWidth,
height: getProportionateScreenHeight(180),
child: Column(
children: [
Container(
width: getProportionateScreenWidth(278),
height: getProportionateScreenHeight(156),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
image: NetworkImage(thumbnail ??
// '$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg'
orders[0].imageUrl),
fit: BoxFit.fill)),
),
],
),
),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
bottom: getProportionateScreenHeight(8),
),
child: Center(
child: Text(
title ?? '',
style: secondaryTextStyle.copyWith(
fontSize: 20, letterSpacing: 0.2),
textAlign: TextAlign.center,
),
),
),
Container(
child: Center(
child: Text(
instructor == null
? 'Oleh ${orders[0].instructor}'
: 'Oleh $instructor ',
style:
primaryTextStyle.copyWith(fontSize: 14, letterSpacing: 0.5),
textAlign: TextAlign.center,
),
),
),
Container(
child: Text(
orders.length == 1 ? '' : '(${orders.length} kursus lainnya)'),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Container(
margin: EdgeInsets.only(left: 16, right: 16),
child: DefaultButton(
text: 'Kembali Ke Home',
press: () async {
await Provider.of<MyCourseProvider>(context, listen: false)
.getMyCourse();
pageProvider.currentIndex = 0;
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => HomePage()),
(route) => false);
},
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
LatestCourse(text: "Kursus Terbaru")
],
),
);
}
}

View File

@ -0,0 +1,361 @@
import 'dart:convert';
import 'dart:io';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi_pending.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:initial_folder/theme.dart';
import 'package:url_launcher/url_launcher.dart'; // Import url_launcher
import 'success_paid_course.dart';
class SnapPaymentPage extends StatefulWidget {
final String transactionToken;
final String orderId;
final int grossAmount;
final String courseTitle;
final String courseThumbnail;
final String courseInstructor;
final String courseId;
SnapPaymentPage({
required this.transactionToken,
required this.orderId,
required this.grossAmount,
required this.courseTitle,
required this.courseThumbnail,
required this.courseInstructor,
required this.courseId,
});
@override
_SnapPaymentPageState createState() => _SnapPaymentPageState();
}
class _SnapPaymentPageState extends State<SnapPaymentPage> {
// Controller untuk WebView
late WebViewController _controller;
double _progress = 0; // Menyimpan progress loading WebView
bool _isLoading = true; // Status loading halaman
String? baseUrlmidtrans = dotenv.env['BASE_URL_MIDTRANS']; // Base URL Midtrans
@override
void initState() {
super.initState();
// Inisialisasi WebViewController dan pengaturan event handler
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onProgress: _onProgress, // Handler progress loading
onPageStarted: _onPageStarted, // Handler saat halaman mulai dimuat
onPageFinished: _onPageFinished, // Handler saat halaman selesai dimuat
onWebResourceError: _onWebResourceError, // Handler error resource
onNavigationRequest: _onNavigationRequest, // Handler navigasi
),
)
..addJavaScriptChannel(
'BlobDataChannel',
// Handler pesan dari JavaScript untuk download QRIS
onMessageReceived: (JavaScriptMessage message) async {
if (message.message.startsWith('error:')) {
// Jika error saat fetch blob
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Download Sedang Tidak Tersedia'),
content: Text(
'Silahkan screenshot Qris tersebut untuk menyimpan ke perangkat kamu.'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
),
);
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text('Gagal mengunduh QRIS. Silakan coba lagi.')),
// );
} else {
// Jika berhasil, proses data blob
await _handleBlobData(message.message);
}
},
)
// Memuat halaman pembayaran Midtrans
..loadRequest(Uri.parse(
"$baseUrlmidtrans/snap/v2/vtweb/${widget.transactionToken}",
));
}
// Handler progress loading WebView
void _onProgress(int progressValue) {
setState(() {
_progress = progressValue / 100;
});
}
// Handler saat halaman mulai dimuat
void _onPageStarted(String url) {
setState(() {
_isLoading = true;
});
}
// Handler saat halaman selesai dimuat
void _onPageFinished(String url) {
setState(() {
_isLoading = false;
_progress = 0;
});
}
// Handler jika terjadi error pada resource WebView
void _onWebResourceError(WebResourceError error) {
setState(() {
_isLoading = false;
});
_showErrorDialog(error.description ?? 'Unknown Error');
}
// Handler navigasi pada WebView
NavigationDecision _onNavigationRequest(NavigationRequest request) {
// Redirect ke aplikasi pembayaran jika diperlukan
if (request.url.startsWith('https://gopay.co.id/') ||
request.url.startsWith('https://app.shopeepay.co.id/')) {
print('Redirecting to GoPay/GoJek app');
_launchURL(request.url);
return NavigationDecision.prevent;
}
// Jika link blob (download QRIS), jalankan fetch blob
if (request.url.startsWith('blob:')) {
print('Redirecting download qris');
_fetchBlobData(baseUrlmidtrans ?? "https://app.sandbox.midtrans.com",
widget.transactionToken);
return NavigationDecision.prevent;
}
// Redirect ke halaman riwayat transaksi jika status pending
if (request.url.contains('transaction_status=pending') ||
request.url.contains('https://vocasia.id/')) {
Navigator.of(context)
.pushReplacementNamed(RiwayatTransaksiPending.routeName);
return NavigationDecision.prevent;
}
// Jika pembayaran sukses, tambahkan order dan redirect ke halaman sukses
if (request.url.contains('transaction_status=settlement') ||
request.url.contains('transaction_status=capture')) {
var orderProvider = Provider.of<OrderProvider>(context, listen: false);
orderProvider.addOrder(
id: widget.courseId,
title: widget.courseTitle,
price: widget.grossAmount.toString(),
imageUrl: widget.courseThumbnail,
instructor: widget.courseInstructor,
discountPrice: '',
);
Navigator.of(context).pushReplacementNamed(
SuccessPaidCourse.routeName,
);
return NavigationDecision.prevent;
}
// Jika user menekan tombol kembali di halaman pembayaran
if (request.url.contains('action=back')) {
Navigator.of(context).pop();
return NavigationDecision.prevent;
}
// Default: lanjutkan navigasi
return NavigationDecision.navigate;
}
// Menjalankan JavaScript untuk mengambil data blob QRIS dari WebView
Future<void> _fetchBlobData(String baseUrl, String transactionId) async {
print('Fetching transaction URL: $transactionId');
final realUrl =
baseUrl + "/snap/v1/transactions/" + transactionId + "/qr-code";
final script = '''
(async function() {
try {
const response = await fetch('$baseUrl')
const blob = await response.blob();
const reader = new FileReader();
reader.onloadend = function() {
const base64data = reader.result.split(',')[1];
BlobDataChannel.postMessage(base64data);
};
reader.readAsDataURL(blob);
} catch (error) {
console.error('Failed to fetch blob:', error);
BlobDataChannel.postMessage('error: ' + error.message);
}
})();
''';
_controller.runJavaScript(script);
}
// Menyimpan data QRIS hasil download ke file lokal
Future<void> _handleBlobData(String base64Data) async {
try {
final decodedBytes = base64Decode(base64Data);
final directory = await getApplicationDocumentsDirectory();
final path = directory.path;
final file = File('$path/qris_download.png');
await file.writeAsBytes(decodedBytes);
await FileSaver.instance.saveAs(
name: 'qris_download',
ext: 'png',
mimeType: MimeType.png,
file: file,
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('QRIS berhasil diunduh')),
);
} catch (e) {
_showErrorDialog('Gagal mengunduh QRIS: $e');
}
}
// Menampilkan dialog error
void _showErrorDialog(String errorMessage) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Error'),
content: Text(errorMessage),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
),
);
}
// Membuka aplikasi eksternal (misal: GoPay/ShopeePay)
Future<void> _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
_showErrorDialog('Could not open the app');
}
}
// Handler ketika user menekan tombol back (hardware/software)
Future<bool> _onWillPop() async {
return (await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Pembayaran Belum Selesai'),
content: Text('Apakah Anda yakin ingin keluar dari halaman ini?'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text('Batal'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
Navigator.of(context)
.pushReplacementNamed(RiwayatTransaksi.routeName);
},
child: Text('Keluar'),
),
],
),
)) ??
false;
}
// Melakukan reload halaman pembayaran
void _refreshPage() {
_controller.reload();
}
@override
Widget build(BuildContext context) {
// Widget utama halaman pembayaran
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: AppBar(
elevation: 5,
title: Center(
child: Text(
'Pembayaran',
style: primaryTextStyle.copyWith(
color: Colors.white,
),
),
),
backgroundColor: primaryColor,
iconTheme: IconThemeData(color: Colors.white),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () async {
bool shouldExit = await _onWillPop();
if (shouldExit) {
Navigator.of(context)
.pushReplacementNamed(RiwayatTransaksi.routeName);
}
},
),
actions: [
IconButton(
icon: Icon(Icons.refresh),
onPressed: _refreshPage,
),
],
),
),
body: Stack(
children: [
// Widget WebView untuk menampilkan halaman pembayaran
RefreshIndicator(
onRefresh: () async {
_refreshPage();
},
child: WebViewWidget(controller: _controller),
),
// Progress bar saat loading
if (_isLoading)
LinearProgressIndicator(
value: _progress,
color: sevenColor,
backgroundColor: secondaryColor,
),
// Spinner loading di tengah layar
if (_isLoading)
Center(
child: CircularProgressIndicator(),
),
],
),
),
);
}
}

View File

@ -0,0 +1,130 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/default_button_payment.dart';
import 'package:provider/provider.dart';
import '../../providers/my_course_provider.dart';
class SuccessPaidCourse extends StatefulWidget {
static const String routeName = "/success-paid-course";
@override
State<SuccessPaidCourse> createState() => _SuccessPaidCourseState();
}
class _SuccessPaidCourseState extends State<SuccessPaidCourse> {
@override
Widget build(BuildContext context) {
var orders = Provider.of<OrderProvider>(context).orders;
var pageProvider = Provider.of<PageProvider>(context);
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
leadingWidth: 14,
),
body: ListView(
children: [
Image.asset(
"assets/images/success_pay.png",
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(100),
),
SizedBox(height: getProportionateScreenHeight(15)),
Text(
'Pembayaran Berhasil',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
textAlign: TextAlign.center,
),
SizedBox(height: getProportionateScreenHeight(15)),
Container(
margin: EdgeInsets.symmetric(horizontal: 16),
width: SizeConfig.screenWidth,
height: getProportionateScreenHeight(169),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
),
child: Column(
children: [
Container(
width: getProportionateScreenWidth(278),
height: getProportionateScreenHeight(145),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
image: NetworkImage(
orders[0].imageUrl, // Ambil dari OrderProvider
),
fit: BoxFit.cover,
),
),
),
],
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(15)),
child: Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(8),
),
child: Center(
child: Text(
orders[0].title ?? '', // Ambil dari OrderProvider
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.2,
),
textAlign: TextAlign.center,
),
),
),
),
Container(
child: Center(
child: Text(
'Oleh ${orders[0].instructor}', // Ambil dari OrderProvider
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
letterSpacing: 0.5,
fontFamily: "Poppins",
),
textAlign: TextAlign.center,
),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Container(
margin: EdgeInsets.symmetric(horizontal: 16),
child: DefaultButtonPayment(
width: double.infinity,
height: getProportionateScreenHeight(34),
text: 'Lihat Kursus',
press: () async {
await Provider.of<MyCourseProvider>(context, listen: false)
.getMyCourse();
pageProvider.currentIndex = 2;
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),
),
(route) => false,
);
},
),
),
],
),
);
}
}