diff --git a/assets/.env b/assets/.env index cb5a20d..a69f659 100644 --- a/assets/.env +++ b/assets/.env @@ -1,5 +1,5 @@ -BASE_URL=https://peakapi.qantra.co.zw/api -; BASE_URL=http://192.168.100.26:6950/api +; BASE_URL=https://peakapi.qantra.co.zw/api +BASE_URL=http://192.168.100.26:6950/api ; BASE_URL=http://10.69.5.204:6950/api ; BASE_URL=http://192.168.1.164:6950/api ; BASE_URL=http://192.168.120.160:6950/api diff --git a/assets/peak-animation.gif b/assets/peak-animation.gif new file mode 100644 index 0000000..f180a90 Binary files /dev/null and b/assets/peak-animation.gif differ diff --git a/lib/main.dart b/lib/main.dart index d4c92be..4218bda 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:provider/provider.dart'; import 'package:go_router/go_router.dart'; import 'package:qpay/screens/confirm/confirm_screen.dart'; import 'package:qpay/screens/gateway/gateway_screen.dart'; +import 'package:qpay/screens/integration/integration_screen.dart'; import 'package:qpay/screens/onboarding/complete_screen.dart'; import 'package:qpay/screens/onboarding/landing/landing_screen.dart'; import 'package:qpay/screens/onboarding/login/login_screen.dart'; @@ -117,6 +118,10 @@ class _MyAppState extends State { path: '/receipt', builder: (context, state) => const ReceiptScreen(), ), + GoRoute( + path: '/integration', + builder: (context, state) => const IntegrationScreen(), + ), GoRoute( path: '/recipients', builder: (context, state) => const RecipientsScreen(), diff --git a/lib/screens/gateway/gateway_screen.dart b/lib/screens/gateway/gateway_screen.dart index b53a6f8..31e98ea 100644 --- a/lib/screens/gateway/gateway_screen.dart +++ b/lib/screens/gateway/gateway_screen.dart @@ -73,7 +73,7 @@ class _GatewayScreenState extends State { builder: (context, child) { if (controller.model.status == 'SUCCESS') { WidgetsBinding.instance.addPostFrameCallback((_) { - context.go('/receipt'); + context.go('/integration'); }); } return controller.model.isLoading diff --git a/lib/screens/home/home_screen.dart b/lib/screens/home/home_screen.dart index 5432d8c..db4642b 100644 --- a/lib/screens/home/home_screen.dart +++ b/lib/screens/home/home_screen.dart @@ -103,7 +103,7 @@ class _HomeScreenState extends State if(prefs.getString("userId") == null) { prefs.setString("userId", Uuid().v4()); - }; + } await homeController.getTransactions(prefs.getString("userId")!); } diff --git a/lib/screens/integration/integration_controller.dart b/lib/screens/integration/integration_controller.dart new file mode 100644 index 0000000..1d338f4 --- /dev/null +++ b/lib/screens/integration/integration_controller.dart @@ -0,0 +1,75 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; +import 'package:qpay/http/http.dart'; +import 'package:qpay/screens/transaction_controller.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class IntegrationModel { + Map? transaction; + String status = ''; + bool isLoading = false; + String? errorMessage; +} + +class IntegrationController extends ChangeNotifier { + final IntegrationModel model = IntegrationModel(); + final Http http = Http(); + late TransactionController transactionController; + late SharedPreferences prefs; + + BuildContext context; + + IntegrationController(this.context) { + transactionController = Provider.of( + context, + listen: false, + ); + } + + void _showErrorSnackBar(String? message) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(message.toString()), + behavior: SnackBarBehavior.floating, + backgroundColor: Colors.deepOrange, + ), + ); + }); + } + + + Future doIntegration() async { + try { + model.isLoading = true; + model.status = ''; + notifyListeners(); + + dynamic workflowResponse = await http.get( + '/public/transaction/integration/' + '${transactionController.model.confirmationData['id']}' + ); + logger.i(workflowResponse.toString()); + + dynamic response = workflowResponse['body']; + + if (response['status'] == 'SUCCESS') { + model.status = response['status']; + transactionController.updateReceiptData(response); + } else { + model.status = response['status']; + model.errorMessage = response['errorMessage']; + _showErrorSnackBar(response['errorMessage']); + } + notifyListeners(); + + } catch (e) { + model.isLoading = false; + model.errorMessage = e.toString(); + notifyListeners(); + } + } +} \ No newline at end of file diff --git a/lib/screens/integration/integration_screen.dart b/lib/screens/integration/integration_screen.dart new file mode 100644 index 0000000..e9b1b17 --- /dev/null +++ b/lib/screens/integration/integration_screen.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +import 'integration_controller.dart'; + +class IntegrationScreen extends StatefulWidget { + const IntegrationScreen({super.key}); + + @override + State createState() => _IntegrationScreenState(); +} + +class _IntegrationScreenState extends State { + late IntegrationController controller; + + @override + void initState() { + super.initState(); + controller = IntegrationController(context); + + controller.doIntegration(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Completing your transaction'), + ), + body: ListenableBuilder( + listenable: controller, + builder: (context, child) { + if (controller.model.status == 'SUCCESS') { + WidgetsBinding.instance.addPostFrameCallback((_) { + context.go('/receipt'); + }); + } + + return Container( + padding: EdgeInsets.all(50), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: 75), + SizedBox(height: 5), + Text( + 'We\'ve successfully collected your funds', + style: TextStyle(fontSize: 22), + textAlign: TextAlign.center, + ), + Image.asset('assets/peak-animation.gif', width: 150), + SizedBox( + width: 50, + child: LinearProgressIndicator(), + ), + SizedBox(height: 50), + Text( + 'We are now updating your billing account', + style: TextStyle(fontSize: 20), + textAlign: TextAlign.center, + ), + Text( + 'This won\'t take long', + style: TextStyle(fontSize: 20), + textAlign: TextAlign.center, + ), + SizedBox(height: 30,), + if(controller.model.status == 'FAILED') + OutlinedButton( + child: Text('Retry'), + onPressed: () { + controller.doIntegration(); + }, + ) + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/lib/screens/onboarding/phone/phone_controller.dart b/lib/screens/onboarding/phone/phone_controller.dart index 3efb701..bbc1cb4 100644 --- a/lib/screens/onboarding/phone/phone_controller.dart +++ b/lib/screens/onboarding/phone/phone_controller.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:qpay/abstracts/AbstractController.dart'; import 'package:qpay/http/http.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import '../onboarding_controller.dart'; @@ -19,6 +20,8 @@ class PhoneController extends AbstractController { BuildContext context; late OnboardingController onboardingController; + late SharedPreferences prefs; + final Http http = Http(); PhoneController(this.context) { @@ -33,7 +36,10 @@ class PhoneController extends AbstractController { notifyListeners(); } + Future register() async { + prefs = await SharedPreferences.getInstance(); + Map user = { "username": onboardingController.model.googleUser?.email, "email": onboardingController.model.googleUser?.email, @@ -41,7 +47,8 @@ class PhoneController extends AbstractController { "lastName": onboardingController.model.googleUser?.displayName?.split(" ").last, "password": onboardingController.model.googleUser?.id, "photoUrl": onboardingController.model.googleUser?.photoUrl, - "phone": onboardingController.model.phone + "phone": onboardingController.model.phone, + "tempUid": prefs.get("userId") }; try { diff --git a/lib/screens/onboarding/verify/verify_controller.dart b/lib/screens/onboarding/verify/verify_controller.dart index 0d5e141..def688c 100644 --- a/lib/screens/onboarding/verify/verify_controller.dart +++ b/lib/screens/onboarding/verify/verify_controller.dart @@ -32,7 +32,7 @@ class VerifyController extends AbstractController { Future verifyOtp () async { Map user = { - "username": onboardingController.model.phone, + "username": onboardingController.model.googleUser?.email, "otpCode": model.code, "otpType": "REGISTRATION", "workflowId": onboardingController.model.workflowId, @@ -64,7 +64,7 @@ class VerifyController extends AbstractController { Future resendOtp () async { Map user = { - "username": onboardingController.model.phone, + "username": onboardingController.model.googleUser?.email, "phone": onboardingController.model.phone, "workflowId": onboardingController.model.workflowId, }; diff --git a/lib/screens/pay/pay_screen.dart b/lib/screens/pay/pay_screen.dart index 7acf0a0..0eb1caa 100644 --- a/lib/screens/pay/pay_screen.dart +++ b/lib/screens/pay/pay_screen.dart @@ -71,6 +71,9 @@ class _PayScreenState extends State with TickerProviderStateMixin { transactionController.model.formData.creditName ?? ''; _emailController.text = transactionController.model.formData.creditEmail ?? ''; + _amountController.text = + transactionController.model.formData.amount; + // Initialize phone number and country code // updatePhoneNumber(transactionController.model.formData.creditPhone ?? '');