import 'dart:async'; 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/models/history_transaction_model.dart'; import 'package:initial_folder/providers/page_provider.dart'; import 'package:initial_folder/providers/theme_provider.dart'; import 'package:initial_folder/screens/checkout/components/bar_batas_bayar.dart'; import 'package:initial_folder/screens/checkout/components/tab_bar_batas_bayar.dart'; import 'package:initial_folder/screens/checkout/gopay/payment_instruction_gopay.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/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:initial_folder/providers/detail_invoice_provider.dart' as detailProv; import 'package:shared_preferences/shared_preferences.dart'; class DetailInvoice extends StatefulWidget { const DetailInvoice({ Key? key, this.orderId, this.dataHistoryTransactionModel, }) : super(key: key); final String? orderId; final HistoryTransactionModel? dataHistoryTransactionModel; @override State createState() => _DetailInvoiceState(); } class _DetailInvoiceState extends State { Duration? remainingTime; final TextStyle baris = primaryTextStyle.copyWith( fontWeight: reguler, color: secondaryColor, fontSize: getProportionateScreenWidth(14), letterSpacing: 0.5, ); Future saveRemainingTime(Duration remainingTime) async { final prefs = await SharedPreferences.getInstance(); prefs.setInt('remainingTime', remainingTime.inSeconds); } Future loadRemainingTime() async { final prefs = await SharedPreferences.getInstance(); final remainingTimeInSeconds = prefs.getInt('remainingTime'); if (remainingTimeInSeconds != null) { remainingTime = Duration(seconds: remainingTimeInSeconds); } } Timer? countdownTimer; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (widget.dataHistoryTransactionModel?.dateExpired != null) { final now = DateTime.now(); final expiryTime = widget.dataHistoryTransactionModel!.dateExpired!; setState(() { remainingTime = expiryTime.isAfter(now) ? expiryTime.difference(now) : Duration.zero; }); // Mulai timer hanya jika ada waktu tersisa if (remainingTime != Duration.zero) { startCountdownTimer(); } } if (widget.orderId?.isNotEmpty ?? false) { Provider.of(context, listen: false) .fetchDetailInvoice(widget.orderId); } }); } void startCountdownTimer() { countdownTimer = Timer.periodic(Duration(seconds: 1), (_) { if (remainingTime == null || remainingTime!.inSeconds <= 0) { countdownTimer?.cancel(); setState(() { remainingTime = Duration.zero; }); } else { setState(() { remainingTime = remainingTime! - Duration(seconds: 1); }); print('Remaining time: $remainingTime'); } }); } @override void dispose() { countdownTimer?.cancel(); if (remainingTime != null) { saveRemainingTime(remainingTime!); } super.dispose(); } Widget buildCountdownTimer() { if (remainingTime == null || remainingTime!.inSeconds <= 0) { return Text( '00:00:00', style: thirdTextStyle.copyWith( fontWeight: semiBold, letterSpacing: 1, fontSize: getProportionateScreenWidth(10), color: baruTextutih, ), ); } final hours = remainingTime!.inHours.toString().padLeft(2, '0'); final minutes = (remainingTime!.inMinutes % 60).toString().padLeft(2, '0'); final seconds = (remainingTime!.inSeconds % 60).toString().padLeft(2, '0'); return Text( '$hours:$minutes:$seconds', style: thirdTextStyle.copyWith( fontWeight: semiBold, letterSpacing: 1, fontSize: getProportionateScreenWidth(10), color: baruTextutih, ), ); } @override Widget build(BuildContext context) { PageProvider pageProvider = Provider.of(context); final themeProvider = Provider.of(context); return Scaffold( appBar: AppBar( centerTitle: true, scrolledUnderElevation: 0.0, backgroundColor: Theme.of(context).colorScheme.background, title: Text( "Cara Pembayaran", style: thirdTextStyle.copyWith( fontWeight: semiBold, fontSize: getProportionateScreenWidth(15), ), ), ), body: SingleChildScrollView( child: Consumer( builder: (context, provider, child) { if (provider.state == detailProv.ResultState.loading) { return Center( child: Column( children: [ Padding( padding: EdgeInsets.only( top: getProportionateScreenHeight(100)), child: CircularProgressIndicator( strokeWidth: 2, color: primaryColor, ), ), ], ), ); } else if (provider.state == detailProv.ResultState.hasData) { Widget buildTextWidget() { String text = ""; if (provider.detailInvoice![0].permataVaNumber != null) { text = "Permata Virtual Account"; } else if (provider.detailInvoice![0].billerCode != null) { text = "Mandiri Virtual Account"; } else if (provider.detailInvoice![0].vaNumbers != null && provider.detailInvoice![0].vaNumbers! .any((va) => va.bank == 'bni')) { text = "BNI Virtual Account"; } else if (provider.detailInvoice![0].vaNumbers != null && provider.detailInvoice![0].vaNumbers! .any((va) => va.bank == 'bca')) { text = "BCA Virtual Account"; } else if (provider.detailInvoice![0].billerCode != null) { text = "Mandiri Virtual Account"; } else if (provider.detailInvoice![0].store == "alfamart") { text = "Alfamart"; } else if (provider.detailInvoice![0].store == "indomaret") { text = "Indomart"; } else if (provider.detailInvoice![0].paymentType == "credit_card") { text = "Credit Card"; } else { text = "QRIS"; } return Text( text, style: thirdTextStyle.copyWith( fontWeight: semiBold, fontSize: getProportionateScreenWidth(13), ), ); } String getVAText() { String text = provider.detailInvoice![0].orderId!; if (provider.detailInvoice != null && provider.detailInvoice!.isNotEmpty) { var invoice = provider.detailInvoice![0]; if (invoice.permataVaNumber != null) { text = invoice.permataVaNumber!; } else if (invoice.billerCode != null) { text = invoice.billKey!; } else if (invoice.vaNumbers != null && invoice.vaNumbers!.any((va) => va.bank == 'bni')) { text = invoice.vaNumbers![0].vaNumber!; } else if (invoice.vaNumbers != null && invoice.vaNumbers!.any((va) => va.bank == 'bca')) { text = invoice.vaNumbers![0].vaNumber!; } else if (invoice.billerCode != null) { text = invoice.billKey!; } else if (invoice.store == "alfamart") { text = provider.detailInvoice![0].paymentCode!; } else if (invoice.store == "indomaret") { text = provider.detailInvoice![0].paymentCode!; } else if (provider.detailInvoice![0].paymentType == "credit_card") { text = provider.detailInvoice![0].maskedCard! .replaceAll('-', ''); } else { text = provider.detailInvoice![0].orderId!; } } return text; } Widget buildVAaWidget() { String text = getVAText(); return Text( text, style: thirdTextStyle.copyWith( fontWeight: semiBold, fontSize: getProportionateScreenWidth(13), ), ); } Widget buildImageWidget() { String imageName = "qris"; if (provider.detailInvoice![0].permataVaNumber != null) { imageName = "permata"; } else if (provider.detailInvoice![0].billerCode != null) { imageName = "mandiri"; } else if (provider.detailInvoice![0].vaNumbers != null && provider.detailInvoice![0].vaNumbers! .any((va) => va.bank == 'bni')) { imageName = "bni"; } else if (provider.detailInvoice![0].vaNumbers != null && provider.detailInvoice![0].vaNumbers! .any((va) => va.bank == 'bca')) { imageName = "bca"; } else if (provider.detailInvoice![0].store == "alfamart") { imageName = "alfamart"; } else if (provider.detailInvoice![0].store == "indomaret") { imageName = "indomaret"; } else if (provider.detailInvoice![0].paymentType == "credit_card") { imageName = "qris"; } return Container( width: getProportionateScreenWidth(50), height: getProportionateScreenWidth(17), decoration: BoxDecoration( boxShadow: [ BoxShadow( color: Theme.of(context).colorScheme.brightness == Brightness.dark ? Colors.transparent : (provider.detailInvoice![0].paymentType == "gopay") ? baruTexthitam.withOpacity(0.3) : Colors.transparent, spreadRadius: 1, blurRadius: 3, offset: Offset(0, 1), ), ], borderRadius: BorderRadius.circular(2), image: DecorationImage( image: AssetImage('assets/images/$imageName.png'), ), ), ); } return Padding( padding: EdgeInsets.symmetric( horizontal: getProportionateScreenWidth(10), vertical: getProportionateScreenHeight(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(4), topRight: Radius.circular(4), ), color: Theme.of(context).colorScheme.primaryContainer, ), padding: EdgeInsets.only( left: getProportionateScreenWidth(10), right: getProportionateScreenWidth(10), top: getProportionateScreenHeight(15), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Batas Waktu Pembayaran', style: thirdTextStyle.copyWith( fontFamily: "Poppins", fontSize: getProportionateScreenWidth(11), ), ), SizedBox(height: getProportionateScreenHeight(2)), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( DateFormat('E, d MMM y HH:mm WIB').format( DateTime.parse(provider .detailInvoice![0].expiryTime!)), 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)), buildCountdownTimer(), ], ), ), ], ), if (provider.detailInvoice![0].paymentType == "gopay") SizedBox(height: getProportionateScreenHeight(5)), if (provider.detailInvoice![0].paymentType == "gopay") Divider( color: secondaryColor, thickness: 1, ), ], ), ), Container( width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.only( bottomLeft: Radius.circular(4), bottomRight: Radius.circular(4), ), color: Theme.of(context).colorScheme.primaryContainer, boxShadow: [ BoxShadow( color: Theme.of(context).brightness == Brightness.dark ? Colors.transparent : secondaryColor.withOpacity(0.2), spreadRadius: 1, blurRadius: 2, offset: Offset(0, getProportionateScreenHeight(4)), ), ], ), padding: EdgeInsets.symmetric( horizontal: getProportionateScreenWidth(10)), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: getProportionateScreenHeight(10)), Text( "Kursus", style: thirdTextStyle.copyWith( fontFamily: "Poppins", fontSize: getProportionateScreenWidth(11), ), ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ listCourse( imageUrl: provider.thumbnail, title: widget.dataHistoryTransactionModel! .courses?[0].title, instructor: widget.dataHistoryTransactionModel! .courses?[0].instructor, price: widget.dataHistoryTransactionModel! .courses?[0].price, discountPrice: widget .dataHistoryTransactionModel! .courses?[0] .price, totalPrices: 0, ), ], ), if (provider.detailInvoice![0].paymentType == "gopay") Divider( color: secondaryColor, thickness: 1, ), Text( 'Metode Pembayaran', style: thirdTextStyle.copyWith( fontWeight: reguler, fontSize: getProportionateScreenWidth(10), ), ), SizedBox(height: getProportionateScreenHeight(5)), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ buildTextWidget(), buildImageWidget(), ], ), SizedBox(height: getProportionateScreenHeight(12)), provider.detailInvoice![0].store == null && provider.detailInvoice![0].paymentType != "credit_card" ? (provider.detailInvoice![0].paymentType != "gopay") ? Text( "Nomor Virtual Akun", style: thirdTextStyle.copyWith( fontWeight: reguler, fontSize: getProportionateScreenWidth(10), ), ) : provider.detailInvoice![0].paymentType != "credit_card" ? (provider.detailInvoice![0] .paymentType != "gopay") ? Text( "Nomor Pesananan", style: thirdTextStyle.copyWith( fontWeight: reguler, fontSize: getProportionateScreenWidth( 10), ), ) : Text( "Order ID", style: thirdTextStyle.copyWith( fontWeight: reguler, fontSize: getProportionateScreenWidth( 10), ), ) : SizedBox.shrink() : Text( "Kode Pembayaran", style: thirdTextStyle.copyWith( fontWeight: reguler, fontSize: getProportionateScreenWidth(10), ), ), if (provider.detailInvoice![0].paymentType == "credit_card") Text( "Nomor Kartu Kredit", style: primaryTextStyle.copyWith( color: Colors.white, letterSpacing: 0.5, fontWeight: reguler, fontSize: getProportionateScreenWidth(10), ), ), SizedBox(height: getProportionateScreenHeight(5)), Row( children: [ buildVAaWidget(), Spacer(), GestureDetector( onTap: () { Clipboard.setData(ClipboardData( text: getVAText().toString())) .then( (_) { ScaffoldMessenger.of(context) .showSnackBar( SnackBar( content: Text( 'Berhasil Menyalin Ke Clipboard'), ), ); }, ); }, child: Text( "Salin", style: thirdTextStyle.copyWith( color: themeProvider.themeData == ThemeClass.darkmode ?primaryColor : primaryColorligtmode, fontSize: getProportionateScreenWidth(10), fontWeight: reguler, ), ), ), ], ), SizedBox(height: getProportionateScreenHeight(10)), if (provider.detailInvoice?[0].billKey != null || provider.detailInvoice?[0].store == "indomaret") Padding( padding: EdgeInsets.only( bottom: getProportionateScreenHeight(5)), child: Text( "Merchant id", style: thirdTextStyle.copyWith( fontWeight: reguler, fontSize: getProportionateScreenWidth(10), ), ), ), if (provider.detailInvoice?[0].billKey != null) Padding( padding: EdgeInsets.only( bottom: getProportionateScreenHeight(16)), child: Row( children: [ Text( provider.detailInvoice![0].billerCode!, style: thirdTextStyle.copyWith( fontWeight: semiBold, fontSize: getProportionateScreenWidth(13), ), ), Spacer(), GestureDetector( onTap: () { Clipboard.setData(ClipboardData( text: provider .detailInvoice![0].billerCode .toString())) .then( (_) { ScaffoldMessenger.of(context) .showSnackBar( SnackBar( content: Text( 'Berhasil Menyalin Kode Pembayaran'), ), ); }, ); }, child: Text( "Salin", style: thirdTextStyle.copyWith( color: primaryColor, fontSize: getProportionateScreenWidth(10), fontWeight: reguler, ), ), ), ], ), ), if (provider.detailInvoice?[0].store == "indomaret") Padding( padding: EdgeInsets.only( bottom: getProportionateScreenHeight(10)), child: Row( children: [ Text( provider.detailInvoice![0].merchantId!, style: primaryTextStyle.copyWith( color: Colors.black, letterSpacing: 1, fontWeight: semiBold, fontSize: getProportionateScreenWidth(13), ), ), Spacer(), GestureDetector( onTap: () { Clipboard.setData(ClipboardData( text: provider .detailInvoice![0].merchantId .toString())) .then( (_) { ScaffoldMessenger.of(context) .showSnackBar( SnackBar( content: Text( 'Berhasil Menyalin Kode Merchant'), ), ); }, ); }, child: Text( "Salin", style: thirdTextStyle.copyWith( color: primaryColor, fontSize: getProportionateScreenWidth(10), fontWeight: reguler, ), ), ), ], ), ), Text( 'Total Pembayaran', style: thirdTextStyle.copyWith( fontWeight: reguler, fontSize: getProportionateScreenWidth(10), ), ), SizedBox(height: getProportionateScreenHeight(8)), Row( children: [ Text( 'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(provider.detailInvoice![0].grossAmount!))}', style: thirdTextStyle.copyWith( fontWeight: semiBold, fontSize: getProportionateScreenWidth(13), ), ), Spacer(), GestureDetector( onTap: () { Clipboard.setData(ClipboardData( text: double.parse(provider .detailInvoice![0] .grossAmount!) .toString())) .then( (_) { ScaffoldMessenger.of(context) .showSnackBar( SnackBar( content: Text( 'Berhasil Menyalin Ke Clipboard'), ), ); }, ); }, child: Text( "Salin", style: thirdTextStyle.copyWith( color: themeProvider.themeData == ThemeClass.darkmode ?primaryColor : primaryColorligtmode, fontSize: getProportionateScreenWidth(10), fontWeight: reguler, ), ), ), ], ), SizedBox(height: getProportionateScreenHeight(10)), ], ), ), SizedBox(height: getProportionateScreenHeight(24)), 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: [ provider.detailInvoice![0].paymentType != "gopay" ? Container( width: double.infinity, padding: EdgeInsets.only( top: getProportionateScreenHeight(15), bottom: getProportionateScreenHeight(7), left: getProportionateScreenWidth(18), ), decoration: BoxDecoration( color: Theme.of(context) .colorScheme .primaryContainer, borderRadius: BorderRadius.only( topLeft: Radius.circular(4), topRight: Radius.circular(4), ), boxShadow: [ BoxShadow( color: secondaryColor.withOpacity(0.2), spreadRadius: 0, blurRadius: 2, offset: Offset( 0, getProportionateScreenHeight(4)), ), ], ), child: Text( 'Cara Pembayaran', style: secondaryTextStyle.copyWith( letterSpacing: 1, fontWeight: semiBold, fontSize: getProportionateScreenWidth(14), ), ), ) : SizedBox.shrink(), Container( padding: EdgeInsets.symmetric( horizontal: getProportionateScreenWidth(5), ), child: provider.detailInvoice![0].store == 'indomaret' || provider.detailInvoice![0].store == 'alfamart' ? BarBatasBayar( provider.detailInvoice![0].store!) : (provider.detailInvoice![0].paymentType != "gopay") ? TabBarBatasBayar( bank: provider.detailInvoice![0] .vaNumbers != null ? provider.detailInvoice![0] .vaNumbers![0].bank : (provider.detailInvoice?[0] .permataVaNumber != null ? "permata" : provider.detailInvoice![0] .paymentType), ) : PaymentInstructionGopay(), ), ], ), ), SizedBox(height: getProportionateScreenHeight(15)), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ DefaultButton( text: 'Belanja kursus lainnya', weight: semiBold, press: () { pageProvider.currentIndex == 0; Navigator.pushAndRemoveUntil( context, CustomNavigatorPop( child: HomeScreen(), ), (route) => false); }, ), ], ), SizedBox(height: getProportionateScreenHeight(10)), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: getProportionateScreenWidth(300), height: getProportionateScreenHeight(38), child: TextButton( onPressed: () { Navigator.pop(context); }, child: Text( "Cek Status Transaksi", style: thirdTextStyle.copyWith( fontSize: getProportionateScreenWidth(12), fontWeight: semiBold, color: themeProvider.themeData == ThemeClass.darkmode ?primaryColor : primaryColorligtmode, letterSpacing: 0.5, ), ), style: TextButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.background, shape: RoundedRectangleBorder( side: BorderSide( color: themeProvider.themeData == ThemeClass.darkmode ?primaryColor : primaryColorligtmode), borderRadius: BorderRadius.circular( getProportionateScreenWidth(10)), ), backgroundColor: Colors.transparent, ), ), ), ], ), ], ), ); } else if (provider.state == detailProv.ResultState.noData) { return Center(child: Text(provider.message ?? '')); } else if (provider.state == detailProv.ResultState.error) { return Center(child: Text(provider.message ?? '')); } else { return Container(); } }, ), ), ); } Widget listCourse({ String? imageUrl, String? title, String? instructor, String? price, String? discountPrice, int? totalPrices, }) { return Container( padding: EdgeInsets.only( top: getProportionateScreenHeight(6), bottom: getProportionateScreenHeight(10), ), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( width: getProportionateScreenWidth(60), height: getProportionateScreenHeight(30), decoration: BoxDecoration( borderRadius: BorderRadius.circular(2), image: DecorationImage( image: NetworkImage(imageUrl == null || imageUrl.isEmpty ? '$baseUrl/images/default-thumbnail.png' : imageUrl.startsWith("http") ? imageUrl : '$baseUrl/uploads/thumbnail/course_thumbnails/$imageUrl'), 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), ), ), ], ), ), ], ), ); } }