diff --git a/lib/data/provider/auth_fb.dart b/lib/data/provider/auth_fb.dart index 49b5dbb..7e79a04 100644 --- a/lib/data/provider/auth_fb.dart +++ b/lib/data/provider/auth_fb.dart @@ -12,6 +12,8 @@ import 'package:fcs/helpers/firebase_helper.dart'; import 'package:firebase_auth/firebase_auth.dart' as fb; import 'package:logging/logging.dart'; +import '../services/services.dart'; + class AuthFb { final log = Logger('AuthFb'); @@ -21,6 +23,10 @@ class AuthFb { late StreamController controller; static final fb.FirebaseAuth _fb = fb.FirebaseAuth.instance; static String _verificationId = ''; + static bool _logIn = false; + + StreamSubscription? userListener; + StreamSubscription? userAuthListener; Future sendSmsCodeToPhoneNumber(String phoneNumber) { Completer completer = Completer(); @@ -99,9 +105,13 @@ class AuthFb { return Future.value(fcs.AuthResult(authStatus: AuthStatus.AUTH_VERIFIED)); } - Future signout() async { - if (userListener != null) await userListener!.cancel(); - return _fb.signOut(); + Future signoutStart() async { + await userListener?.cancel(); + await userAuthListener?.cancel(); + } + + Future signoutEnd() async { + await _fb.signOut(); } Future _addUserToStream({bool refreshIdToken = false}) async { @@ -111,7 +121,6 @@ class AuthFb { await getClaims(refreshIdToken: refreshIdToken); log.info("Claims:$claims"); - if (claims == null) return; String? cid = claims["cid"]; User? user; @@ -123,6 +132,11 @@ class AuthFb { return; } + loadUserClaim(claims, user); + controller.add(user); + } + + loadUserClaim(Map claims, User user) { // add privileges String? privileges = claims["pr"]; if (privileges != null && privileges != "") { @@ -130,7 +144,6 @@ class AuthFb { } else { user.privileges = []; } - controller.add(user); } Future _getUserFromFirestore(String userID) async { @@ -205,13 +218,12 @@ class AuthFb { fb.User? firebaseUser = _fb.currentUser; if (firebaseUser == null) return null; Map? claims = await getClaims(); - if (claims == null) return null; String cid = claims["cid"]; return cid; } Future _startUserListener() async { - if (userListener != null) userListener!.cancel(); + _startAuthListener(); String? _userID = await _getCurrentUserID(); if (_userID == null) { return; @@ -221,6 +233,7 @@ class AuthFb { .collection(user_collection) .doc(_userID) .snapshots(); + userListener?.cancel(); userListener = snapshot.listen((snap) async { User user = User.fromMap(snap.data() as Map, snap.id); @@ -229,14 +242,12 @@ class AuthFb { userListener?.cancel(); return; } + + if (!_logIn) return; try { // get privilege from claim - fb.IdTokenResult idToken = await firebaseUser.getIdTokenResult(true); - - String? privileges = idToken.claims?["pr"] ?? ''; - if (privileges != null && privileges != "") { - user.privileges = privileges.split(":").toList(); - } + Map claims = await getClaims(refreshIdToken: true); + loadUserClaim(claims, user); controller.add(user); } catch (e) { controller.add(null); @@ -244,14 +255,47 @@ class AuthFb { }); } - StreamSubscription? userListener; + Future _startAuthListener() async { + String? authId = _fb.currentUser?.uid; + if (authId == null) return; + + Stream snapshot = FirebaseFirestore.instance + .collection(authCollection) + .doc(authId) + .snapshots(); + userAuthListener?.cancel(); + userAuthListener = snapshot.listen((snap) async { + if (snap.exists) { + Map map = snap.data() as Map; + String userID = map['user_id'] ?? ""; + + User? user = await Services.instance.userService.getUser(userID); + if (user == null) return; + + if (_fb.currentUser == null) { + userAuthListener?.cancel(); + return; + } + + Map claims = await getClaims(refreshIdToken: true); + loadUserClaim(claims, user); + + log.info("_startAuthListener: $user"); + if (_logIn) { + controller.add(user); + } + } + }); + } + Stream user() { // ignore: close_sinks StreamSubscription? authListener; Future _start() async { await authListener?.cancel(); - authListener = _fb.authStateChanges().listen((firebaseUser) { + authListener = _fb.authStateChanges().listen((firebaseUser) async { + _logIn = firebaseUser != null; if (firebaseUser == null) { controller.add(null); } else { diff --git a/lib/data/provider/user_data_provider.dart b/lib/data/provider/user_data_provider.dart index 3a606de..1756eab 100644 --- a/lib/data/provider/user_data_provider.dart +++ b/lib/data/provider/user_data_provider.dart @@ -85,4 +85,29 @@ class UserDataProvider { return await requestAPI("/enable_user", "PUT", payload: {"id": userID, "enabled": enabled}, token: await getToken()); } + + Future getUser(String userID) async { + if (userID == "") return null; + + String path = "/$user_collection"; + try { + var snap = await FirebaseFirestore.instance + .collection(path) + .doc(userID) + .get(const GetOptions(source: Source.server)); + + if (snap.data() == null) return null; + Map? data = snap.data() as Map; + + if (data['delete_time'] == 0) { + User user = User.fromMap(data, snap.id); + return user; + } else { + return null; + } + } catch (e) { + log.warning("Error!! $e"); + } + return null; + } } diff --git a/lib/data/services/auth_imp.dart b/lib/data/services/auth_imp.dart index 056907f..e3d1b11 100644 --- a/lib/data/services/auth_imp.dart +++ b/lib/data/services/auth_imp.dart @@ -25,11 +25,6 @@ class AuthServiceImp implements AuthService { return authFb.signInWithPhoneNumber(smsCode); } - @override - Future signout() { - return authFb.signout(); - } - @override Stream getUserStream() { return authFb.user(); @@ -64,4 +59,14 @@ class AuthServiceImp implements AuthService { Future updatePreferredCurrency(String currency) { return authFb.updatePreferredCurrency(currency); } + + @override + Future signoutEnd() { + return authFb.signoutEnd(); + } + + @override + Future signoutStart() { + return authFb.signoutStart(); + } } diff --git a/lib/data/services/auth_service.dart b/lib/data/services/auth_service.dart index a276495..ceba0bf 100644 --- a/lib/data/services/auth_service.dart +++ b/lib/data/services/auth_service.dart @@ -5,7 +5,8 @@ import 'package:fcs/domain/entities/user.dart'; abstract class AuthService { Future sendSmsCodeToPhoneNumber(String phoneNumber); Future signInWithSmsCode(String smsCode); - Future signout(); + Future signoutStart(); + Future signoutEnd(); Future signup(String userName); Future joinInvite(String userName); Future updateProfileName(String newUserName); diff --git a/lib/data/services/user_imp.dart b/lib/data/services/user_imp.dart index 9b5305a..f6e2baa 100644 --- a/lib/data/services/user_imp.dart +++ b/lib/data/services/user_imp.dart @@ -52,4 +52,9 @@ class UserServiceImp implements UserService { Future enableUser(String userID, bool enabled) { return userDataProvider.enableUser(userID, enabled); } + + @override + Future getUser(String userID) { + return userDataProvider.getUser(userID); + } } diff --git a/lib/data/services/user_service.dart b/lib/data/services/user_service.dart index 0dd4297..1e929a9 100644 --- a/lib/data/services/user_service.dart +++ b/lib/data/services/user_service.dart @@ -9,4 +9,5 @@ abstract class UserService { Future uploadMsgToken(String token); Future removeMsgToken(String token); Future enableUser(String userID, bool enabled); + Future getUser(String userID); } diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index 1bf7bc6..52f6bfb 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -2,6 +2,7 @@ const uploadPhotoLimit = 10; const config_collection = "configs"; const user_collection = "users"; +const authCollection = "auths"; const invitations_collection = "invitations"; const privilege_collection = "privileges"; const markets_collection = "markets"; @@ -113,8 +114,8 @@ const carton_processing_status = "processing"; const carton_arrived_status = "arrived"; const carton_invoiced_status = "invoiced"; const carton_canceled_status = "canceled"; -const all_status= "All stauts"; -const all ="All"; +const all_status = "All stauts"; +const all = "All"; // shipment status const shipment_pending_status = "pending"; @@ -141,6 +142,6 @@ const payment_canceled_status = "canceled"; const delivery_caton = "Delivery carton"; const pickup_carton = "Pick-up carton"; -// bill -const billToSender ="Bill to sender"; -const billToConsignee="Bill to consignee"; +// bill +const billToSender = "Bill to sender"; +const billToConsignee = "Bill to consignee"; diff --git a/lib/domain/entities/user.dart b/lib/domain/entities/user.dart index e0c7826..8e1a73f 100644 --- a/lib/domain/entities/user.dart +++ b/lib/domain/entities/user.dart @@ -21,7 +21,6 @@ class User { String? preferCurrency; bool enablePinLogin; String? pinDigit; - String? confirmPinDigit; String get initial => name != null && name != "" ? name!.substring(0, 1) : "?"; @@ -60,21 +59,21 @@ class User { bool get disabled => status != null && status == user_disabled_status; String get share => "Your phone number:$phoneNumber"; - User( - {this.id, - this.name, - this.phoneNumber, - this.fcsID, - this.status, - this.privileges = const [], - this.lastMessage, - this.lastMessageTime, - this.userUnseenCount = 0, - this.fcsUnseenCount = 0, - this.preferCurrency, - this.enablePinLogin = false, - this.pinDigit, - this.confirmPinDigit}); + User({ + this.id, + this.name, + this.phoneNumber, + this.fcsID, + this.status, + this.privileges = const [], + this.lastMessage, + this.lastMessageTime, + this.userUnseenCount = 0, + this.fcsUnseenCount = 0, + this.preferCurrency, + this.enablePinLogin = false, + this.pinDigit, + }); factory User.fromJson(Map json) { return User( diff --git a/lib/helpers/firebase_helper.dart b/lib/helpers/firebase_helper.dart index 4efa642..3c8b1c8 100644 --- a/lib/helpers/firebase_helper.dart +++ b/lib/helpers/firebase_helper.dart @@ -15,12 +15,12 @@ Future getToken() async { return token; } -Future getClaims({bool refreshIdToken = false}) async { +Future getClaims({bool refreshIdToken = false}) async { fb.User? firebaseUser = auth.currentUser; - if (firebaseUser == null) return null; + if (firebaseUser == null) return {}; fb.IdTokenResult idToken = await firebaseUser.getIdTokenResult(refreshIdToken); - return idToken.claims; + return idToken.claims ?? {}; } // returns list of url diff --git a/lib/localization/app_translations.dart b/lib/localization/app_translations.dart index 73242b2..ade1cc8 100644 --- a/lib/localization/app_translations.dart +++ b/lib/localization/app_translations.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart' show rootBundle; diff --git a/lib/pages/buying_instruction/buying_online.dart b/lib/pages/buying_instruction/buying_online.dart index ceb8b74..3cba994 100644 --- a/lib/pages/buying_instruction/buying_online.dart +++ b/lib/pages/buying_instruction/buying_online.dart @@ -4,7 +4,6 @@ import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_text.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/pages/customer/customer_list.dart b/lib/pages/customer/customer_list.dart index 6225afc..eef9255 100644 --- a/lib/pages/customer/customer_list.dart +++ b/lib/pages/customer/customer_list.dart @@ -77,7 +77,7 @@ class _CustomerListState extends State { children: [ Expanded( child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 5.0), + padding: const EdgeInsets.symmetric(vertical: 8.0), child: new Row( children: [ InkWell( diff --git a/lib/pages/customer/invitation_create.dart b/lib/pages/customer/invitation_create.dart index ac40275..a148e81 100644 --- a/lib/pages/customer/invitation_create.dart +++ b/lib/pages/customer/invitation_create.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:country_code_picker/country_code_picker.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/customer/model/customer_model.dart'; diff --git a/lib/pages/invoice/editor/invoice_handling_fee_list.dart b/lib/pages/invoice/editor/invoice_handling_fee_list.dart index e2fbd41..269c57a 100644 --- a/lib/pages/invoice/editor/invoice_handling_fee_list.dart +++ b/lib/pages/invoice/editor/invoice_handling_fee_list.dart @@ -2,7 +2,6 @@ import 'package:fcs/domain/entities/shipment.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_text.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; typedef OnAdd(Shipment shipment); diff --git a/lib/pages/main/model/base_model.dart b/lib/pages/main/model/base_model.dart index a5cbc4f..77d94fc 100644 --- a/lib/pages/main/model/base_model.dart +++ b/lib/pages/main/model/base_model.dart @@ -10,7 +10,7 @@ abstract class BaseModel extends ChangeNotifier { Setting? setting; MainModel? mainModel; - void initUser(User user) async { + void initUser(User? user) async { this.user = user; } diff --git a/lib/pages/main/model/main_model.dart b/lib/pages/main/model/main_model.dart index 0c2a5bd..c76dc0f 100644 --- a/lib/pages/main/model/main_model.dart +++ b/lib/pages/main/model/main_model.dart @@ -87,23 +87,6 @@ class MainModel extends ChangeNotifier { userListener?.cancel(); userListener = Services.instance.authService.getUserStream().listen((_user) { - // if (_user != null) { - // models.forEach((m) => m.initUser(_user)); - // // call diffPrivileges if privilege changed or first time login - // if (this.user == null || _user.diffPrivileges(this.user!)) { - // models.forEach((m) => m.privilegeChanged()); - // } - // if (this.user == null) { - // uploadMsgToken(); - // } - // } else { - // if (this.user != null) { - // models.forEach((m) => m.logout()); - // } - // } - // this.user = _user; - // isLoaded = true; - bool isFirstTime = user == null && _user != null; bool diffPrivilege = _user != null && (user == null || user!.diffPrivileges(_user)); @@ -163,24 +146,28 @@ class MainModel extends ChangeNotifier { } Future _uploadMsgToken() { - log.info("messagingToken:$messagingToken::user:$user"); - if (messagingToken == null || user == null) return Future.value(); + if (messagingToken == null || user == null) return Future.value(); return Services.instance.userService.uploadMsgToken(messagingToken!); } Future _removeMsgToken() { - if (messagingToken == null || user == null) return Future.value(); + if (messagingToken == null || user == null) return Future.value(); return Services.instance.userService.removeMsgToken(messagingToken!); } Future signout() async { try { + await Services.instance.authService.signoutStart(); await _removeMsgToken(); + for (var i = 0; i < models.length; i++) { + models[i].initUser(null); + models[i].logout(); + } + + await Services.instance.authService.signoutEnd(); } catch (e) { - log.info(e.toString()); + log.info("signout:${e.toString()}"); } - await Services.instance.authService.signout(); - models.forEach((m) => m.logout()); } Future hasInvite() async { diff --git a/lib/pages/rates/shipment_rates_calculate.dart b/lib/pages/rates/shipment_rates_calculate.dart index 949a2cc..9fea9ce 100644 --- a/lib/pages/rates/shipment_rates_calculate.dart +++ b/lib/pages/rates/shipment_rates_calculate.dart @@ -10,7 +10,6 @@ import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_dropdown.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart'; import 'package:provider/provider.dart'; diff --git a/lib/pages/staff/model/staff_model.dart b/lib/pages/staff/model/staff_model.dart index 0db5bfe..58fdb6f 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 int? pin}) async { // await request("/employee/pin", "PUT", // payload: { // "id": userID, diff --git a/lib/pages/staff/staff_pin_editor.dart b/lib/pages/staff/staff_pin_editor.dart index ab2ceef..7b686e7 100644 --- a/lib/pages/staff/staff_pin_editor.dart +++ b/lib/pages/staff/staff_pin_editor.dart @@ -39,7 +39,7 @@ class _StaffPinEditorState extends State { _staff = widget.staff; _enablePinLogin = _staff.enablePinLogin; _newPin = _staff.pinDigit ?? ""; - _confirmPin = _staff.confirmPinDigit ?? ""; + _confirmPin = _staff.pinDigit ?? ""; _newPinCtl.text = _newPin; _confirmPinCtl.text = _confirmPin; _checkFocusNode(); @@ -298,7 +298,9 @@ class _StaffPinEditorState extends State { } _save() async { - if (!_formKey.currentState!.validate()) return; + if (_enablePinLogin) { + if (!_formKey.currentState!.validate()) return; + } setState(() { _isLoading = true; @@ -308,7 +310,7 @@ class _StaffPinEditorState extends State { await context.read().updatePin( userID: _staff.id!, enablePin: _enablePinLogin, - pin: int.parse(_confirmPin)); + pin: _enablePinLogin ? int.parse(_confirmPin) : null); Navigator.pop(context, true); } catch (e) { showMsgDialog(context, "Error", e.toString()); diff --git a/lib/pages/widgets/fcs_expansion_tile.dart b/lib/pages/widgets/fcs_expansion_tile.dart index 633e305..e38e65c 100644 --- a/lib/pages/widgets/fcs_expansion_tile.dart +++ b/lib/pages/widgets/fcs_expansion_tile.dart @@ -1,5 +1,4 @@ import 'package:fcs/helpers/theme.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'callbacks.dart'; diff --git a/lib/pages/widgets/img_url.dart b/lib/pages/widgets/img_url.dart index 6cdb69e..68f4fc8 100644 --- a/lib/pages/widgets/img_url.dart +++ b/lib/pages/widgets/img_url.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'show_img.dart'; diff --git a/lib/pages/widgets/input_time.dart b/lib/pages/widgets/input_time.dart index 8c283a1..6f69ff6 100644 --- a/lib/pages/widgets/input_time.dart +++ b/lib/pages/widgets/input_time.dart @@ -1,7 +1,6 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/main/model/language_model.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; diff --git a/lib/pages/widgets/show_img.dart b/lib/pages/widgets/show_img.dart index 191096a..a3bdb21 100644 --- a/lib/pages/widgets/show_img.dart +++ b/lib/pages/widgets/show_img.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:fcs/helpers/theme.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:photo_view/photo_view.dart';