diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 0c3a1e9..74fa593 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -18,6 +18,7 @@ "back.button_confirm":"Are you sure you want to continue without submitting changes?", "btn.clear":"Clear Filter", "btn.filter":"Filter", + "btn.exit_confirm":"Are you sure you want to exit?", "Buttons End ================================================================":"", "Offline Start ================================================================":"", @@ -104,6 +105,7 @@ "home.invitation.request.msg":"We are working on your invitation request!", "home.search":"Enter tracking number", "home.search.btn":"Search", + "home.pin.logout.confirm":"Are you sure want to logout?", "Home End ================================================================":"", "Invite Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 02666f6..befe69c 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -17,6 +17,7 @@ "back.button_confirm":"Are you sure you want to continue without submitting changes?", "btn.clear":"Clear Filter", "btn.filter":"Filter", + "btn.exit_confirm":"Are you sure you want to exit?", "Buttons End ================================================================":"", "Offline Start ================================================================":"", @@ -104,6 +105,7 @@ "home.invitation.request.msg":"ဖိတ်ကြားမှု တောင်းဆိုသည်ကို လုပ်ဆောင်နေပါသည်!", "home.search":"Tracking number ရိုက်ထည့်ပါ", "home.search.btn":"ရှာမည်", + "home.pin.logout.confirm":"အကောင့်ထွက်ရန်သေချာပြီလား?", "Home End ================================================================":"", "Invite Start ================================================================":"", diff --git a/lib/app.dart b/lib/app.dart index d3243fa..779f703 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -35,6 +35,7 @@ import 'pages/carton/model/package_selection_model.dart'; import 'pages/carton/model/sender_selection_model.dart'; import 'pages/carton/model/shipment_selection_model.dart'; import 'pages/delivery/model/delivery_model.dart'; +import 'pages/signin/pinlogin_page.dart'; class App extends StatefulWidget { final String title; @@ -121,6 +122,7 @@ class _AppState extends State { '/welcome': (_) => WelcomePage(), '/home': (_) => HomePage(), '/language_selection': (context) => InitialLanguageSelectionPage(), + '/pin_login': (_) => PinLoginPage() }; return routes; } diff --git a/lib/constants.dart b/lib/constants.dart index 53f1ba7..5592bcb 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -83,6 +83,7 @@ const privilege_receiving = "rc"; const privilege_pickup = "pku"; const privilege_collect = "col"; const privilege_report = "rpt"; +const privilege_pin ="pin"; // Pickup types const shipment_local_pickup = "Local pickup"; diff --git a/lib/data/provider/auth_fb.dart b/lib/data/provider/auth_fb.dart index cd603e8..c55da89 100644 --- a/lib/data/provider/auth_fb.dart +++ b/lib/data/provider/auth_fb.dart @@ -12,6 +12,7 @@ import 'package:fcs/helpers/firebase_helper.dart'; import 'package:firebase_auth/firebase_auth.dart' as fb; import 'package:logging/logging.dart'; +import '../../helpers/shared_pref.dart'; import '../services/services.dart'; class AuthFb { @@ -108,13 +109,15 @@ class AuthFb { Future signoutStart() async { await userListener?.cancel(); await userAuthListener?.cancel(); + await _pinUserListener?.cancel(); } Future signoutEnd() async { + await SharedPref.setPinLockOn(false); await _fb.signOut(); } - Future _addUserToStream({bool refreshIdToken = false}) async { + Future _addUserToStream({bool refreshIdToken = false}) async { fb.User? firebaseUser = _fb.currentUser; if (firebaseUser == null) return null; Map? claims = @@ -128,15 +131,20 @@ class AuthFb { user = await _getUserFromFirestore(cid); } if (user == null) { - controller.add(null); - return; + _addUser(null); + return null; } loadUserClaim(claims, user); - controller.add(user); + _addUser(user); + return user; } loadUserClaim(Map claims, User user) { + if (pinLoginUser != null) { + user.fcsID = pinLoginUser?.fcsID; + } + // add privileges String? privileges = claims["pr"]; if (privileges != null && privileges != "") { @@ -252,9 +260,9 @@ class AuthFb { // get privilege from claim Map claims = await getClaims(refreshIdToken: true); loadUserClaim(claims, user); - controller.add(user); + _addUser(user); } catch (e) { - controller.add(null); + _addUser(null); } }); } @@ -286,12 +294,23 @@ class AuthFb { log.info("_startAuthListener: $user"); if (_logIn) { - controller.add(user); + _addUser(user); } } }); } + _addUser(User? user) { + if (user == null) { + pinLoginUser = null; + } + if (pinLoginUser != null) { + controller.add(pinLoginUser); + } else { + controller.add(user); + } + } + Stream user() { // ignore: close_sinks StreamSubscription? authListener; @@ -301,7 +320,7 @@ class AuthFb { authListener = _fb.authStateChanges().listen((firebaseUser) async { _logIn = firebaseUser != null; if (firebaseUser == null) { - controller.add(null); + _addUser(null); } else { _addUserToStream(refreshIdToken: true); _startUserListener(); @@ -319,4 +338,51 @@ class AuthFb { return controller.stream; } + + User? pinLoginUser; + + StreamSubscription? _pinUserListener; + + Future pinLogin( + {required String currentUserId, + required String fcsID, + required String pin}) async { + var data = await requestAPI("/pin/login", "POST", + token: await getToken(), payload: {'fcs_id': fcsID, 'pin': pin}); + + var userId = data['user_id'] ?? ''; + if (userId == currentUserId) { + //logout + logoutPinAccount(); + await SharedPref.setPinLockOn(false); + } + + var pinToken = data['pin_token'] ?? ''; + + // Get user for pin login + _listenPinUser(userId: userId, pinToken: pinToken); + } + + Future _listenPinUser( + {required String userId, required String pinToken}) async { + Stream snapshot = FirebaseFirestore.instance + .collection(user_collection) + .doc(userId) + .snapshots(); + _pinUserListener?.cancel(); + _pinUserListener = snapshot.listen((snap) async { + User user = User.fromMap(snap.data() as Map, snap.id); + pinLoginUser = user; + if (pinLoginUser != null) { + pinLoginUser!.pinToken = pinToken; + } + await _addUserToStream(refreshIdToken: true); + }); + } + + Future logoutPinAccount() async { + _pinUserListener?.cancel(); + pinLoginUser = null; + await _addUserToStream(refreshIdToken: true); + } } diff --git a/lib/data/services/auth_imp.dart b/lib/data/services/auth_imp.dart index def1606..a923101 100644 --- a/lib/data/services/auth_imp.dart +++ b/lib/data/services/auth_imp.dart @@ -74,4 +74,23 @@ class AuthServiceImp implements AuthService { Future deleteAccount() { return authFb.deleteAccount(); } + + @override + Future pinLogin( + {required String currentUserId, + required String fcsID, + required String pin}) { + return authFb.pinLogin( + currentUserId: currentUserId, fcsID: fcsID, pin: pin); + } + + @override + User? getPinLoginUser() { + return authFb.pinLoginUser; + } + + @override + Future logoutPinAccount() { + return authFb.logoutPinAccount(); + } } diff --git a/lib/data/services/auth_service.dart b/lib/data/services/auth_service.dart index 4a6c6ad..90017a3 100644 --- a/lib/data/services/auth_service.dart +++ b/lib/data/services/auth_service.dart @@ -15,4 +15,10 @@ abstract class AuthService { Stream getUserStream(); Stream getSetting(); Future deleteAccount(); + Future pinLogin( + {required String currentUserId, + required String fcsID, + required String pin}); + User? getPinLoginUser(); + Future logoutPinAccount(); } diff --git a/lib/domain/entities/user.dart b/lib/domain/entities/user.dart index bef8dec..6751e72 100644 --- a/lib/domain/entities/user.dart +++ b/lib/domain/entities/user.dart @@ -21,6 +21,7 @@ class User { String? preferCurrency; bool enablePinLogin; String? pinDigit; + List privileges = []; String get initial => name != null && name != "" ? name!.substring(0, 1) : "?"; @@ -48,7 +49,9 @@ class User { String get getFcsUnseenCount => fcsUnseenCount > 100 ? "99+" : fcsUnseenCount.toString(); - List privileges = []; + // for pin login + String? pinToken; + bool get isPinLogin => pinToken!=null; String get phone => phoneNumber != null && phoneNumber!.startsWith("959") ? "0${phoneNumber!.substring(2)}" @@ -117,7 +120,9 @@ class User { userUnseenCount: map['user_unseen_count'] ?? 0, fcsUnseenCount: map['fcs_unseen_count'] ?? 0, preferCurrency: map['preferred_currency'], - lastMessageTime: _date == null ? null : _date.toDate()); + lastMessageTime: _date == null ? null : _date.toDate(), + enablePinLogin: map['enable_pin_login'] ?? false, + pinDigit: map['pin'] ?? ''); } bool diffPrivileges(User another) { diff --git a/lib/domain/vo/privilege.dart b/lib/domain/vo/privilege.dart index afec5fb..f170f57 100644 --- a/lib/domain/vo/privilege.dart +++ b/lib/domain/vo/privilege.dart @@ -3,6 +3,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart' as vector; class Privilege { String id; @@ -49,6 +50,8 @@ class Privilege { iconData = MaterialCommunityIcons.layers; } else if (this.id == privilege_report) { iconData = Feather.file_text; + } else if (this.id == privilege_pin) { + iconData = vector.MaterialCommunityIcons.account_lock_outline; } else { iconData = MaterialCommunityIcons.account_question; } diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 240a9df..81fa7e5 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -4,6 +4,8 @@ import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:dio/dio.dart'; +import 'package:fcs/data/services/services.dart'; +import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/domain/vo/status.dart'; import 'package:logging/logging.dart'; import 'package:path_provider/path_provider.dart'; @@ -28,6 +30,10 @@ Future requestAPI(String path, method, if (token != null) { headers["Token"] = token; } + User? pinLoginUser = Services.instance.authService.getPinLoginUser(); + if (pinLoginUser != null) { + headers["pin_token"] = pinLoginUser.pinToken; + } if (devInfo.deviceID != null) { headers["Device"] = devInfo.deviceID ?? "" + ":" + deviceName; } diff --git a/lib/helpers/shared_pref.dart b/lib/helpers/shared_pref.dart index 68d1921..3ba06bd 100644 --- a/lib/helpers/shared_pref.dart +++ b/lib/helpers/shared_pref.dart @@ -108,4 +108,14 @@ class SharedPref { static Future clearRecentSearch(String key) async { return await _remove(key); } + + static Future getPinLockOn() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getBool('pin_lock'); + } + + static Future setPinLockOn(bool isLockOn) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.setBool('pin_lock', isLockOn); + } } diff --git a/lib/pages/main/home_page.dart b/lib/pages/main/home_page.dart index c1ad000..f04d77d 100644 --- a/lib/pages/main/home_page.dart +++ b/lib/pages/main/home_page.dart @@ -203,9 +203,27 @@ class _HomePageState extends State { super.dispose(); } + _logoutPinAccount() async { + setState(() { + _isLoading = true; + }); + + try { + await context.read().logoutPinAccount(); + Navigator.pushNamedAndRemoveUntil(context, "/pin_login", (r) => false); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } + @override Widget build(BuildContext context) { - User? user = Provider.of(context).user; + var mainModel = context.watch(); + User? user = mainModel.user; if (user == null) { Future.microtask( @@ -213,7 +231,7 @@ class _HomePageState extends State { return Container(); } - login = Provider.of(context).isLogin(); + login = mainModel.isLogin(); LanguageModel languageModel = Provider.of(context); final faqBtn = TaskButton("faq.btn", @@ -357,7 +375,7 @@ class _HomePageState extends State { selectedColor: Colors.white, color: Colors.blue, children: [ - Icon(MaterialCommunityIcons.account_tie,size: 25), + Icon(MaterialCommunityIcons.account_tie, size: 25), ], onPressed: (i) => this.setState(() { isFcs[0] = !isFcs[0]; @@ -387,11 +405,14 @@ class _HomePageState extends State { color: buttonColor, ), ); - + final pinLoginBtn = IconButton( onPressed: () { - Navigator.of(context) - .push(CupertinoPageRoute(builder: (context) => PinLoginPage())); + Navigator.pushAndRemoveUntil( + context, + CupertinoPageRoute( + builder: (BuildContext context) => PinLoginPage()), + (r) => false); }, iconSize: 25, icon: Icon( @@ -400,6 +421,19 @@ class _HomePageState extends State { ), ); + final pinLogoutBtn = IconButton( + onPressed: () { + showConfirmDialog(context, "home.pin.logout.confirm", () async { + await _logoutPinAccount(); + }); + }, + iconSize: 25, + icon: Icon( + MaterialCommunityIcons.lock_open_variant_outline, + color: buttonColor, + ), + ); + var searchInput = Row(children: [ Expanded( child: Padding( @@ -478,7 +512,7 @@ class _HomePageState extends State { profileBtn, ] : [ - pinLoginBtn, + mainModel.isPinLogin ? pinLogoutBtn : pinLoginBtn, fcsToggle, profileBtn, ] diff --git a/lib/pages/main/model/main_model.dart b/lib/pages/main/model/main_model.dart index b541704..781241f 100644 --- a/lib/pages/main/model/main_model.dart +++ b/lib/pages/main/model/main_model.dart @@ -17,6 +17,7 @@ class MainModel extends ChangeNotifier { String? messagingToken; User? user; + User? _fbUser; PackageInfo? packageInfo; set setMessaginToken(token) { @@ -29,6 +30,9 @@ class MainModel extends ChangeNotifier { bool isLoaded = false; bool isOnline = false; bool isFirstLaunch = false; + bool isLockOn = false; + + bool get isPinLogin => user?.isPinLogin ?? false; MainModel() { NetworkConnectivity.instance.statusStream.listen((data) { @@ -83,6 +87,7 @@ class MainModel extends ChangeNotifier { await _listenSetting(); this.isFirstLaunch = await SharedPref.isFirstLaunch() ?? true; this.packageInfo = await PackageInfo.fromPlatform(); + this.isLockOn = await SharedPref.getPinLockOn() ?? false; userListener?.cancel(); userListener = @@ -91,6 +96,17 @@ class MainModel extends ChangeNotifier { bool diffPrivilege = _user != null && (user == null || user!.diffPrivileges(_user)); bool loggingOut = user != null && _user == null; + + if (_user != null) { + if (!_user.isPinLogin) { + _fbUser = _user; + } + } + + if ((_fbUser?.id == _user?.id)) { + _user?.pinToken = null; + } + user = _user; if (_user != null) { @@ -101,6 +117,7 @@ class MainModel extends ChangeNotifier { } } } + if (loggingOut) { for (final m in models) { m.logout(); @@ -196,4 +213,13 @@ class MainModel extends ChangeNotifier { Future deleteAccount() async { return await Services.instance.authService.deleteAccount(); } + + Future pinLogin({required String fcsID, required String pin}) async { + await Services.instance.authService + .pinLogin(fcsID: fcsID, pin: pin, currentUserId: _fbUser?.id ?? ''); + } + + Future logoutPinAccount() async { + await Services.instance.authService.logoutPinAccount(); + } } diff --git a/lib/pages/main/splash_page.dart b/lib/pages/main/splash_page.dart index e719e5b..4b4e410 100644 --- a/lib/pages/main/splash_page.dart +++ b/lib/pages/main/splash_page.dart @@ -53,7 +53,11 @@ class _SplashScreenState extends State { if (mainModel.isFirstLaunch) { page = "/language_selection"; } else if (mainModel.isLogin()) { - page = "/home"; + if (mainModel.isLockOn) { + page = "/pin_login"; + } else { + page = "/home"; + } } else { page = "/welcome"; } diff --git a/lib/pages/profile/profile_page.dart b/lib/pages/profile/profile_page.dart index 4a9811b..6c9eb07 100644 --- a/lib/pages/profile/profile_page.dart +++ b/lib/pages/profile/profile_page.dart @@ -129,12 +129,17 @@ class _ProfileState extends State { ], ); - final logoutbutton = fcsButton( - context, getLocalString(context, "profile.logout"), callack: () { - showConfirmDialog(context, "profile.logout.confirm", () async { - await _logout(); - }); - }, iconData: Icons.exit_to_app); + final logoutbutton = + fcsButton(context, getLocalString(context, "profile.logout"), + callack: mainModel.isPinLogin + ? null + : () { + showConfirmDialog(context, "profile.logout.confirm", + () async { + await _logout(); + }); + }, + iconData: Icons.exit_to_app); return LocalProgress( inAsyncCall: _isLoading, @@ -355,8 +360,12 @@ class _ProfileState extends State { } _showToast(String title) { - final ScaffoldMessengerState scaffold = - key.currentState as ScaffoldMessengerState; + ScaffoldMessengerState? scaffold = key.currentState; + + if (scaffold == null) { + scaffold = ScaffoldMessenger.of(context); + } + scaffold.showSnackBar( SnackBar( content: Text('copied "$title" data to clipboard'), diff --git a/lib/pages/signin/pinlogin_page.dart b/lib/pages/signin/pinlogin_page.dart index 14d9eb6..31b11c7 100644 --- a/lib/pages/signin/pinlogin_page.dart +++ b/lib/pages/signin/pinlogin_page.dart @@ -1,13 +1,18 @@ import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/main/model/language_model.dart'; +import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/local_button.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/material.dart'; import 'package:pin_input_text_field/pin_input_text_field.dart'; +import 'package:provider/provider.dart'; + +import '../../helpers/shared_pref.dart'; +import '../../localization/app_translations.dart'; class PinLoginPage extends StatefulWidget { - //final User user; const PinLoginPage({super.key}); @override @@ -18,10 +23,77 @@ class _PinLoginPageState extends State { bool _isLoading = false; String pin = ""; String prefixText = "FCS-"; - //late User _user; + final _formKey = GlobalKey(); TextEditingController _fcsIdCtl = new TextEditingController(); + @override + void initState() { + _init(); + super.initState(); + } + + _init() async { + await SharedPref.setPinLockOn(true); + } + + Future _onWillPop() async { + // Show the confirmation dialog + return (await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Center( + child: + LocalText(context, 'btn.exit_confirm', color: primaryColor), + ), + content: Container( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TextButton( + style: TextButton.styleFrom( + backgroundColor: Colors.grey[300], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0))), + child: Text( + AppTranslations.of(context)!.text('btn.cancel'), + style: Provider.of(context).isEng + ? TextStyle(color: primaryColor) + : TextStyle( + fontFamily: 'Myanmar3', color: primaryColor), + ), + onPressed: () { + Navigator.of(context).pop(false); + }), + SizedBox( + width: 0, + ), + TextButton( + style: TextButton.styleFrom( + backgroundColor: primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0))), + child: Text(AppTranslations.of(context)!.text('btn.ok'), + style: Provider.of(context).isEng + ? TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold) + : TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontFamily: 'Myanmar3')), + onPressed: () { + Navigator.of(context).pop(true); + }) + ], + ), + ), + ), + )) ?? + false; + } + Widget build(BuildContext context) { final fcsIdBox = TextFormField( controller: _fcsIdCtl, @@ -48,7 +120,7 @@ class _PinLoginPageState extends State { prefixText, style: TextStyle(color: Colors.black), ), - prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0), + prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0), contentPadding: EdgeInsets.all(0), labelStyle: newLabelStyle(color: Colors.black54, fontSize: 17), enabledBorder: UnderlineInputBorder( @@ -121,42 +193,47 @@ class _PinLoginPageState extends State { callBack: _login, ), ); - return LocalProgress( - inAsyncCall: _isLoading, - child: new Scaffold( - body: Form( - key: _formKey, - child: ListView( - padding: EdgeInsets.only(top: 80, left: 15, right: 15, bottom: 20), - children: [ - pinLoginLogo, - Padding( - padding: EdgeInsets.only(top: 20, bottom: 20), - child: Center( - child: LocalText(context, "welcome.pinlogin", - color: Colors.black, fontSize: 18), + + // ignore: deprecated_member_use + return WillPopScope( + onWillPop: _onWillPop, + child: LocalProgress( + inAsyncCall: _isLoading, + child: new Scaffold( + body: Form( + key: _formKey, + child: ListView( + padding: EdgeInsets.only(top: 80, left: 15, right: 15, bottom: 20), + children: [ + pinLoginLogo, + Padding( + padding: EdgeInsets.only(top: 20, bottom: 20), + child: Center( + child: LocalText(context, "welcome.pinlogin", + color: Colors.black, fontSize: 18), + ), ), - ), - LocalText( - context, - "welcome.pinlogin.fcsid", - color: Colors.black54, - fontSize: 15, - ), - fcsIdBox, - Padding( - padding: EdgeInsets.only(top: 25, bottom: 20), - child: LocalText( - context, - "welcome.pinlogin.pin", - color: Colors.black54, - fontSize: 15, - )), - pinInputBox, - loginBtn, - ], - ), - )), + LocalText( + context, + "welcome.pinlogin.fcsid", + color: Colors.black54, + fontSize: 15, + ), + fcsIdBox, + Padding( + padding: EdgeInsets.only(top: 25, bottom: 20), + child: LocalText( + context, + "welcome.pinlogin.pin", + color: Colors.black54, + fontSize: 15, + )), + pinInputBox, + loginBtn, + ], + ), + )), + ), ); } @@ -171,14 +248,14 @@ class _PinLoginPageState extends State { return; } String fcsId = "$prefixText${_fcsIdCtl.text}"; - print(fcsId); setState(() { _isLoading = true; }); try { - Navigator.pop(context, true); + await context.read().pinLogin(fcsID: fcsId, pin: pin); + Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false); } catch (e) { showMsgDialog(context, "Error", e.toString()); } finally { diff --git a/lib/pages/staff/model/staff_model.dart b/lib/pages/staff/model/staff_model.dart index 3f7a615..6603cfc 100644 --- a/lib/pages/staff/model/staff_model.dart +++ b/lib/pages/staff/model/staff_model.dart @@ -81,7 +81,7 @@ class StaffModel extends BaseModel { Future updatePin( {required String userID, required bool enablePin, - required int? pin}) async { + required String? pin}) async { await request("/employee/pin", "PUT", payload: {"id": userID, "enable_pin_login": enablePin, "pin": pin}, token: await getToken()); diff --git a/lib/pages/staff/staff_pin_editor.dart b/lib/pages/staff/staff_pin_editor.dart index 7b686e7..e13f2bd 100644 --- a/lib/pages/staff/staff_pin_editor.dart +++ b/lib/pages/staff/staff_pin_editor.dart @@ -310,7 +310,7 @@ class _StaffPinEditorState extends State { await context.read().updatePin( userID: _staff.id!, enablePin: _enablePinLogin, - pin: _enablePinLogin ? int.parse(_confirmPin) : null); + pin: _enablePinLogin ? _confirmPin : null); Navigator.pop(context, true); } catch (e) { showMsgDialog(context, "Error", e.toString());