Untitled
unknown
dart
a year ago
16 kB
16
Indexable
import 'dart:async'; import 'package:BlinkDocs/app_state.dart'; import 'package:BlinkDocs/backend/stripe/StripeAddress.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:dio/dio.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:flutter_stripe/flutter_stripe.dart'; import 'StripeCustomer.dart'; import 'StripeResponse.dart'; const _isProd = false; // Stripe Credentials const _kProdStripePublishableKey = 'pk_live_51LNt0dSJESo9WpI9EK7gV4gR2ziZP41Y91sLIpnRc4mCOKQxLCzq88fBhVUYtVstk6FXOOpUiwIje94OAdOccRxU005cOw8IdW'; const _kTestStripePublishableKey = 'pk_test_51LNt0dSJESo9WpI9zXhDLotxJ8FA1n2p4Q5h9tcpmfAQWwmAE1TWMO6xQtaUPFvNQLpLl3wsMSKPi4oniiirFCyd008XdMg6vv'; const _kAppleMerchantId = 'BLINKVIS'; const _kProdStripeSecretKey = "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" ; const _kTestStripeSecretKey = "sk_test_51LNt0dSJESo9WpI9kZxaIS4eUd14FtO2i8tB8MNvbPIhEnC874Hn5DM8sTK9skqmK8KvluvOEXNM5mrIUzVJfwdu00XTYt4rm4"; String stripePublishableKey() => _isProd ? _kProdStripePublishableKey : _kTestStripePublishableKey; // check if the user is android or ios Future initializeStripe() async { Stripe.publishableKey = stripePublishableKey(); await Stripe.instance.applySettings(); } class StripePaymentResponse { const StripePaymentResponse({this.paymentId, this.errorMessage}); final String? paymentId; final String? errorMessage; } // call Stripe Create Customer Api. This will return a customer id. Future createCustomer( StripeAddressData address, String customerName , String customerEmail, String description) async { var customerData = StripeCustomer( name: customerName, email: customerEmail, description: description, address: address ); Response response = await Dio().post('https://api.stripe.com/v1/customers', data: customerData.toJson(), options: Options(contentType:Headers.formUrlEncodedContentType, headers: { 'Authorization': "Bearer ${_isProd ? _kProdStripeSecretKey : _kTestStripeSecretKey}" } ), ); // convert response to StripeResponse model var stripeResponseObj = StripeResponse.fromJson(response.data); return stripeResponseObj; } Future<StripePaymentResponse> showWebPaymentSheet( BuildContext context, { required String name, required String paymentId, required String paymentIntentSecret, required num amount, required String currency, required String description, Color? buttonColor, Color? buttonTextColor, ThemeMode? themeStyle, }) async { final isDarkMode = themeStyle == null ? Theme.of(context).brightness == Brightness.dark : themeStyle == ThemeMode.dark; buttonColor = buttonColor ?? Theme.of(context).primaryColor; final screenWidth = MediaQuery.of(context).size.width; // ignore: prefer_function_declarations_over_variables final buildPaymentSheet = (BuildContext context, double width) => WebStripePayment( paymentId: paymentId, paymentIntentSecret: paymentIntentSecret, amount: amount, currency: currency, description: description, buttonColor: buttonColor, buttonTextColor: buttonTextColor, themeStyle: themeStyle, darkMode: isDarkMode, width: width, ); StripePaymentResponse? response; // If on mobile for web, display the payment sheet as a bottom sheet. if (screenWidth < 429) { response = await showModalBottomSheet<StripePaymentResponse>( context: context, builder: (context) => buildPaymentSheet(context, screenWidth), ); } // Otherwise, show a dialog, which is better for Tablet and Web/Desktop. else { response = await showDialog<StripePaymentResponse>( context: context, builder: (context) => AlertDialog( backgroundColor: Colors.transparent, contentPadding: EdgeInsets.zero, content: buildPaymentSheet(context, 420), ), ); } // Return the payment response, or an empty response if the user canceled. return response ?? StripePaymentResponse(); } // create Stateful widget for StripePaymentResponse class WebStripePayment extends StatefulWidget { final String paymentId; final String paymentIntentSecret; final num amount; final String currency; final String description; final Color? buttonColor; final Color? buttonTextColor; final ThemeMode? themeStyle; final bool darkMode; final double width; const WebStripePayment({ Key? key, required this.paymentId, required this.paymentIntentSecret, required this.amount, required this.currency, required this.description, this.buttonColor, this.buttonTextColor, this.themeStyle, required this.darkMode, required this.width, }) : super(key: key); @override WebStripePaymentState createState() => WebStripePaymentState(); } class WebStripePaymentState extends State<WebStripePayment> { ThemeMode themeStyle = ThemeMode.system; bool isLoading = false; @override void initState() { // TODO: implement initState super.initState(); } @override Widget build(BuildContext context) { return Container( width: 600, child: Column( mainAxisSize: MainAxisSize.max, children: [ ClipRRect( borderRadius: BorderRadius.circular(8.0), child: Material( color: Colors.transparent, child: Container( padding: const EdgeInsets.fromLTRB(24.0, 14.0, 24.0, 24.0), color: widget.darkMode ? Color(0xFF101213) : Colors.white, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Expanded( child: Text( 'Payment Information', ), ), InkWell( onTap: () => Navigator.pop(context), child: Padding( padding: EdgeInsets.all(4.0), child: Icon( Icons.close_rounded, size: 22, color: widget.darkMode ? const Color(0xFF95A1AC) : const Color(0xFF57636C), ), ), ), ], ), if (widget.description.isNotEmpty) ...[ const SizedBox(height: 8.0), Text( widget.description, ), ], ], ), const SizedBox(height: 16.0), CardField( decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: widget.buttonColor!, width: 2.0, ), borderRadius: BorderRadius.circular(8.0), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: widget.darkMode ? const Color(0xFF22282F) : const Color(0xFFE0E3E7), width: 2.0, ), borderRadius: BorderRadius.circular(8.0), ), fillColor: const Color(0xFFF1F4F8), filled: widget.darkMode, ), // enablePostalCode: true, ), const SizedBox(height: 20.0), GestureDetector( onTap: () async { setState(() { isLoading = true; }); try { final response = await Stripe.instance.confirmPayment( paymentIntentClientSecret: widget.paymentIntentSecret, data: const PaymentMethodParams.card( paymentMethodData: PaymentMethodData(), ), ); if (response.status == PaymentIntentsStatus.Succeeded) { setState(() { isLoading = false; }); Navigator.pop( context, StripePaymentResponse(paymentId: widget.paymentId), ); } }catch ( error){ setState(() { isLoading = false; }); if (error is StripeError && error.message != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: Colors.blue, content: SizedBox( height: 40, child: Text(error.message! ,style: TextStyle(color: Colors.white, fontWeight: FontWeight.w600, fontSize: 16,fontFamily: 'Gilroy' ) ), ), ), ); } } }, child: Container( width: kIsWeb ?203:103, height: 56, decoration: BoxDecoration( color: const Color(0xff1F75EC), borderRadius: BorderRadius.circular(14), ), alignment: Alignment.center, child: isLoading ? const CircularProgressIndicator( color: Colors.white, ) : Text( 'Pay ${widget.currency} ${(widget.amount/100).toString()}', style: const TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600, ), ), ), ), ], ), ), ), ), ], ), ); } } // call Stripe Create Payment Method Api. This will return a payment method id. Future<StripePaymentResponse> processStripePayment( BuildContext context, { required num amount, required String currency, required String customerEmail, required StripeAddressData address, required customerName, required description, bool allowGooglePay = false, bool allowApplePay = false, ThemeMode themeStyle = ThemeMode.system, Color? buttonColor, Color? buttonTextColor, }) async { var paymentID = ''; try { if ( FFAppState().stripeCustomerId.isEmpty){ StripeResponse stripeResponseObj = await createCustomer(address, customerName, customerEmail, description); FFAppState().stripeCustomerId = stripeResponseObj.id; FirebaseFirestore.instance.collection("customerData"). doc(FirebaseAuth.instance.currentUser?.uid).update({"stripeCustID":FFAppState().stripeCustomerId}); } var paymentItentData = { "currency": currency, "amount": amount.round(), "description": description, "customer": FFAppState().stripeCustomerId, }; Response response = await Dio().post( 'https://api.stripe.com/v1/payment_intents', data: paymentItentData, options: Options(contentType: Headers.formUrlEncodedContentType, headers: { 'Authorization': "Bearer ${_isProd ? _kProdStripeSecretKey : _kTestStripeSecretKey}", "HttpHeaders.contentTypeHeader": "application/x-www-form-urlencoded" } ), ).onError((error, stackTrace) { print(error); print(stackTrace); throw stackTrace.toString(); } ); /// For web, display a payment sheet with a credit card form. if (kIsWeb) { StripePaymentResponse resp = await showWebPaymentSheet( context, paymentId: response.data['id'], paymentIntentSecret: response.data['client_secret'], amount: amount, currency: currency, description: description, buttonColor: buttonColor, buttonTextColor: buttonTextColor, themeStyle: themeStyle, name: customerName, ); paymentID = resp.paymentId ?? ''; return resp; } await Stripe.instance.initPaymentSheet( paymentSheetParameters: SetupPaymentSheetParameters( customFlow: false, paymentIntentClientSecret: response.data['client_secret'], customerId: response.data['customer'], merchantDisplayName: 'BLINKVISA', style: themeStyle, appearance: PaymentSheetAppearance( primaryButton: PaymentSheetPrimaryButtonAppearance( colors: PaymentSheetPrimaryButtonTheme( light: PaymentSheetPrimaryButtonThemeColors( background: buttonColor, text: buttonTextColor, ), dark: PaymentSheetPrimaryButtonThemeColors( background: buttonColor, text: buttonTextColor ), ), ), ), ), ); /// Then show the payment sheet and confirm payment. try { await Stripe.instance.presentPaymentSheet().then((value) { Stripe.instance.confirmPaymentSheetPayment(); }); } catch (e) { // Show snackbar if the payment was cancelled ScaffoldMessenger.of(context).showSnackBar( const SnackBar( backgroundColor: Colors.blue, content: Text('Payment Failed. Please try again to continue' ,style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold , fontSize: 16 ) ), ), ); return StripePaymentResponse(paymentId: "", errorMessage: e.toString()); } paymentID = response.data['id']; return StripePaymentResponse(paymentId: paymentID); } catch (e) { if (e is StripeException && e.error.code == FailureCode.Canceled) { return StripePaymentResponse(); } return StripePaymentResponse(errorMessage: '$e'); } }
Editor is loading...