import 'dart:convert'; import 'dart:io'; import 'package:flutter_svg/svg.dart'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:jwt_decode/jwt_decode.dart'; import 'package:nhance_app_pwa/customAppBar/toastHelper.dart'; import 'package:pinput/pinput.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../customAppBar/responsive.dart'; import '../../models/environment.dart'; import '../postEnrollment/service/svg_service.dart'; import 'authenticationService.dart'; class pinPage extends StatefulWidget { const pinPage({Key? key}) : super(key: key); @override State createState() => _pinPageState(); } class _pinPageState extends State { final AuthService _authService = AuthService(); final TextEditingController _pinController = TextEditingController(); final _formKey = GlobalKey(); late final FocusNode focusNode; String? savedPin; dynamic empMobileNo; dynamic _token; dynamic _postToken; dynamic empCodeString; dynamic empClientBranchId; dynamic empPrimaryId; dynamic gpaEmpName; dynamic client_id; dynamic emp_status; dynamic enrollmentEmpCodeString; dynamic enrollmentEmpClientBranchId; dynamic enrollmentEmpPrimaryId; dynamic enrollmentGpaEmpName; dynamic enrollmentClient_id; dynamic clientName; dynamic clientLogo; dynamic enrollmentEmp_status; dynamic bioMetricMpin; @override void initState() { super.initState(); _checkBiometricAuthentication(); _loadSavedPin(); focusNode = FocusNode(); } @override void dispose() { focusNode.dispose(); super.dispose(); } Future _checkBiometricAuthentication() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); bioMetricMpin = prefs.getString('mpin'); bool authenticated = await _authService.authenticateWithBiometrics(); if (authenticated) { enterPinApi(bioMetricMpin); } else { ToastHelper.showErrorToast(context, 'Biometric authentication failed'); } } Future enterPinApi(mpin) async { try { final SharedPreferences prefs = await SharedPreferences.getInstance(); empMobileNo = prefs.getString('empMobileNo'); // _token = prefs.getString('token'); final response = await http.post( Uri.parse(Environment.apiUrlEnrollment + 'verifyMpin'), body: json.encode({'mobile_number': empMobileNo, 'mpin': mpin}), headers: { HttpHeaders.contentTypeHeader: 'application/json', }, ); if (response.statusCode == 200) { Map data = json.decode(response.body); print('data: $data'); _token = data['data']; String status = data['status']; // Directly access the post_enrollment data Map post = data['post_enrollment']; print('post: $post'); _postToken = post['data']; String postStatus = post['status']; if (postStatus == 'success') { postSuccessData(post, data); } else if (status == 'success') { enrollmentSuccessData(data); } else { ToastHelper.showErrorToast(context, 'Invalid Pin Number'); print('Invalid Pin Number'); } } else { ToastHelper.showErrorToast(context, 'Something went wrong'); throw Exception('Failed to verify pin number'); } } catch (e) { ToastHelper.showErrorToast(context, 'Something went wrong'); print('Error: $e'); } } void postSuccessData(post, data) async { String status = data['status']; String postStatus = post['status']; if (postStatus == 'success') { final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('_postToken', post['data']); // Decode the JWT token received from the API response Map? decodedToken = Jwt.parseJwt(post['data']); print('decodedToken : $decodedToken'); empClientBranchId = decodedToken['client_branch_id']; prefs.setString('empClientBranchId', empClientBranchId); empCodeString = decodedToken['emp_code'].toString(); prefs.setString('empCode', empCodeString); empPrimaryId = decodedToken['id']; prefs.setString('empPrimaryId', empPrimaryId); gpaEmpName = decodedToken['name'].toString(); prefs.setString('gpaEmpName', gpaEmpName); client_id = decodedToken['client_id']; prefs.setString('client_id', client_id); emp_status = decodedToken['emp_status']; prefs.setString('emp_status', emp_status); // getClientLogoAndDetails(); print('Successfully Login'); // Redirect to another page } if (status == 'success') { final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('enrollToken', data['data']); // Decode the JWT token received from the API response Map? decodedToken = Jwt.parseJwt(data['data']); print('decodedToken : $decodedToken'); enrollmentEmpClientBranchId = decodedToken['client_branch_id']; prefs.setString( 'enrollmentEmpClientBranchId', enrollmentEmpClientBranchId); enrollmentEmpCodeString = decodedToken['emp_code'].toString(); prefs.setString('enrollmentEmpCodeString', enrollmentEmpCodeString); enrollmentEmpPrimaryId = decodedToken['id']; prefs.setString('enrollmentEmpPrimaryId', enrollmentEmpPrimaryId); enrollmentGpaEmpName = decodedToken['name'].toString(); prefs.setString('enrollmentGpaEmpName', enrollmentGpaEmpName); enrollmentClient_id = decodedToken['client_id']; prefs.setString('enrollmentClient_id', enrollmentClient_id); enrollmentEmp_status = decodedToken['emp_status']; prefs.setString('enrollmentEmp_status', enrollmentEmp_status); getClientLogoAndDetails(); } final SharedPreferences prefs = await SharedPreferences.getInstance(); final token = prefs.getString('_postToken'); if (token != null && token.isNotEmpty) { ToastHelper.showSuccessToast(context, 'Successfully Login'); // if (enrollmentEmp_status == 'enrolled' || // enrollmentEmp_status == 'active') { Navigator.pushReplacementNamed(context, 'home'); // } else { // Navigator.pushReplacementNamed(context, 'empDetails'); // } } } void enrollmentSuccessData(data) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('enrollToken', data['data']); // Decode the JWT token received from the API response Map? decodedToken = Jwt.parseJwt(data['data']); print('decodedToken : $decodedToken'); enrollmentEmpClientBranchId = decodedToken['client_branch_id']; prefs.setString('enrollmentEmpClientBranchId', enrollmentEmpClientBranchId); enrollmentEmpCodeString = decodedToken['emp_code'].toString(); prefs.setString('enrollmentEmpCodeString', enrollmentEmpCodeString); enrollmentEmpPrimaryId = decodedToken['id']; prefs.setString('enrollmentEmpPrimaryId', enrollmentEmpPrimaryId); enrollmentGpaEmpName = decodedToken['name'].toString(); prefs.setString('enrollmentGpaEmpName', enrollmentGpaEmpName); enrollmentClient_id = decodedToken['client_id']; prefs.setString('enrollmentClient_id', enrollmentClient_id); enrollmentEmp_status = decodedToken['emp_status']; prefs.setString('enrollmentEmp_status', enrollmentEmp_status); getClientLogoAndDetails(); print('Successfully Login'); // Redirect to another page final token = prefs.getString('enrollToken'); if (token != null && token.isNotEmpty) { ToastHelper.showSuccessToast(context, 'Successfully Login'); // if (enrollmentEmp_status == 'enrolled' || // enrollmentEmp_status == 'active') { // Navigator.pushReplacementNamed(context, 'home'); // } else { Navigator.pushReplacementNamed(context, 'empDetails'); // } } } Future enterLoginPin() async { try { if (_formKey.currentState!.validate()) { enterPinApi(_pinController.text); } } catch (e) { ToastHelper.showErrorToast(context, 'Something went wrong'); print('Error: $e'); } } Future _loadSavedPin() async { savedPin = await _authService.getPin(); } String? _validatePin(String? value) { if (value == null || value.isEmpty) { return 'Please enter a pin'; } if (value.length != 4) { return 'Pin must be 4 digits'; } return null; } Future forgotPin() async { final prefs = await SharedPreferences.getInstance(); await prefs.clear(); Navigator.pushNamed(context, 'login'); } Future getClientLogoAndDetails() async { var url = Uri.parse(Environment.apiUrlEnrollment + 'getClientDetails?client_id=$enrollmentClient_id&emp_code=$enrollmentEmpCodeString'); try { var response = await http.get( url, headers: { 'Authorization': 'Bearer $_token', // Add token to the Authorization header }, ); if (response.statusCode == 200) { // print('response.statusCode == 200'); Map data = json.decode(response.body); // print(data); if (data.containsKey('data')) { dynamic clientDetails = data['data']; final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('clientLogo', clientDetails['client']['client_logo']); prefs.setString('clientName', clientDetails['client']['client_name']); setState(() { clientName = clientDetails['client']['client_name']; print(clientName); clientLogo = clientDetails['client']['client_logo']; print(clientLogo); }); } else { print('API request failed with status: ${data['status']}'); } } else { print('Request failed with status: ${response.statusCode}'); } } catch (e) { print('Exception occurred: $e'); } } @override Widget build(BuildContext context) { const focusedBorderColor = Color.fromRGBO(23, 171, 144, 1); const fillColor = Color.fromRGBO(243, 246, 249, 0); const borderColor = Color.fromRGBO(23, 171, 144, 0.4); Size _size = MediaQuery.of(context).size; EdgeInsets marginInsets = EdgeInsets.zero; if (Responsive.isDesktop(context)) { marginInsets = const EdgeInsets.only( left: 0, right: 0, bottom: 0, top: 0, ); } else if (Responsive.isMobile(context)) { marginInsets = const EdgeInsets.only( left: 25, // Example value for mobile right: 25, // Example value for mobile bottom: 0, // Example value for mobile top: 0, // Example value for mobile ); } else if (Responsive.isTablet(context)) { marginInsets = const EdgeInsets.only( left: 25, // Example value for mobile right: 25, // Example value for mobile bottom: 0, // Example value for mobile top: 0, // Example value for mobile ); } final defaultPinTheme = PinTheme( width: 56, height: 56, textStyle: const TextStyle( fontSize: 20, color: Color.fromRGBO(30, 60, 87, 1), ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(19), border: Border.all(color: borderColor), ), ); return WillPopScope( onWillPop: () async { return false; }, child: Scaffold( body: Container( color: Colors.white, // Set the color for the body child: SizedBox.expand( child: Stack(children: [ SingleChildScrollView( child: Container( padding: EdgeInsets.all(0), color: Color(0xFFFFFCE5), child: Column(children: [ Container( decoration: BoxDecoration( color: Color( 0xFFFFFCE5), // Set background color for the container borderRadius: BorderRadius.circular( 10), // Set border radius for the container ), // padding: EdgeInsets.only(top: 0, bottom: 0, left: 10, right: 10), child: Column( // crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded( flex: 12, child: Align( alignment: Alignment.topLeft, child: Padding( padding: const EdgeInsets.only( left: 16.0), // Add left margin child: Image.asset( 'assets/nhance_app_logo.png', width: 150, height: 100, ), ), ), ), ], ), SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( flex: 12, child: Align( alignment: Alignment.center, child: Padding( padding: const EdgeInsets.only( left: 16.0), // Add left margin child: SvgPicture.string( SvgService.getSvg('mpin'), width: 150, height: 150, ), ), ), ), ], ), SizedBox(height: 30), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( flex: 12, child: Text( 'Enter PIN to login', textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 16, color: Color(0xFF404040), fontWeight: FontWeight.w500, ), ), ), ], ), SizedBox(height: 10), ], ), ), Container( decoration: BoxDecoration( color: Colors .white, // Set background color for the container borderRadius: BorderRadius.only( topLeft: Radius.circular(150.0), topRight: Radius.circular(0), ), // Set border radius for the container ), padding: EdgeInsets.only( top: 20, bottom: 10, left: 10, right: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( margin: marginInsets, alignment: Alignment.bottomCenter, child: SingleChildScrollView( child: Form( key: _formKey, child: Column( children: [ Row( children: [ Expanded( flex: 12, child: Column( children: [ SizedBox(height: 40), Container( margin: EdgeInsets.symmetric( horizontal: 30), child: Row( mainAxisAlignment: MainAxisAlignment .start, // Align text to the right children: [ Align( // alignment: Alignment.centerLeft, child: Text( 'Enter the 4 Digit pin', style: GoogleFonts .poppins( fontSize: 16, color: Color( 0xFF909090), fontWeight: FontWeight .w400, ), ), ), ]), ), SizedBox(height: 5), Container( margin: EdgeInsets.symmetric( horizontal: 0), child: Pinput( length: 4, defaultPinTheme: defaultPinTheme, separatorBuilder: (index) => const SizedBox( width: 8), showCursor: true, controller: _pinController, validator: _validatePin, errorPinTheme: defaultPinTheme .copyBorderWith( border: Border.all( color: Colors .redAccent), ), hapticFeedbackType: HapticFeedbackType .lightImpact, onCompleted: (pin) { debugPrint( 'onCompleted: $pin'); }, onChanged: (value) { debugPrint( 'onChanged: $value'); }, cursor: Column( mainAxisAlignment: MainAxisAlignment .end, children: [ Container( margin: const EdgeInsets .only( bottom: 9), width: 22, height: 1, color: focusedBorderColor, ), ], ), focusedPinTheme: defaultPinTheme .copyWith( decoration: defaultPinTheme .decoration! .copyWith( borderRadius: BorderRadius .circular(8), border: Border.all( color: focusedBorderColor), ), ), submittedPinTheme: defaultPinTheme .copyWith( decoration: defaultPinTheme .decoration! .copyWith( color: fillColor, borderRadius: BorderRadius .circular(19), border: Border.all( color: focusedBorderColor), ), ), ), ), SizedBox(height: 15), Container( margin: EdgeInsets.symmetric( horizontal: 30), child: SizedBox( width: double.infinity, height: 45, child: ElevatedButton( style: ElevatedButton .styleFrom( backgroundColor: Color(0xFF00989E), shape: RoundedRectangleBorder( borderRadius: BorderRadius .circular( 10), ), ), onPressed: () async { enterLoginPin(); }, child: Text( "Submit", style: GoogleFonts .poppins( color: Color( 0xFFFFFFFF)), ), ), ), ), SizedBox(height: 15), Container( child: Row( mainAxisAlignment: MainAxisAlignment .center, children: [ GestureDetector( onTap: () { forgotPin(); }, child: Text( 'Forget PIN?', style: GoogleFonts .poppins( fontSize: 12, color: Color( 0xFF929292), fontWeight: FontWeight .w400, ), ), ), ], ), ), ], ), ), ], ), ], ), ), ), ), ], ), ), ]), )), Align( alignment: Alignment.bottomCenter, child: Container( width: double.infinity, // Make the footer full width child: RichText( textAlign: TextAlign.center, text: TextSpan( text: 'By continuing, you agree with our ', style: GoogleFonts.poppins( color: Colors.black, fontSize: 9, ), children: [ TextSpan( text: 'privacy policy ', style: GoogleFonts.poppins( color: Color(0xFF00989E), fontSize: 9, ), ), TextSpan( text: 'and ', style: GoogleFonts.poppins( color: Colors.black, fontSize: 9, ), ), TextSpan( text: 'terms of use', style: GoogleFonts.poppins( color: Color(0xFF00989E), fontSize: 9, ), ), ], ), ), ), ), ]), )))); } }