add customers and staffs

This commit is contained in:
Sai Naw Wun
2020-09-13 21:49:39 +06:30
parent aa8a6765de
commit eccea7ee02
45 changed files with 2094 additions and 1027 deletions

View File

@@ -48,7 +48,9 @@
"language.selection.title":"Please select your language",
"welcome.signin":"Sign In",
"welcome.msg":"Welcome to FCS Logistics!",
"welcome.msg":"Welcome to FCS!",
"home.invitation.request.msg":"We are working on your invitation request!",
"sms.verify.title":"Verify your number",
"sms.six.digit":"Enter 6 digit sms code sent to",
@@ -60,10 +62,44 @@
"invite.request":"Request Invitation",
"invite.request.successful":"Successfully requested!",
"================================================================":"",
"customer.list.title":"Customers",
"customer.name":"Name",
"customer.phone":"Phone Number",
"customer.status":"Status",
"customer.fcs.id":"FCS ID",
"customer.invitation.request.confirm":"Accept Customer",
"invitation.list": "Invitations",
"invitation.edit": "Invitation",
"invitation.new": "New Invitation",
"invitation.confirm.delete": "Delete this invitation?",
"staff.title":"Staffs",
"staff.list.title":"Staffs",
"staff.new":"New Staff",
"staff.form.title":"Staff",
"staff.add":"Add",
"staff.update":"Update",
"profile.title": "My Profile",
"profile.edit_title": "Edit My Profile",
"profile.name": "Name",
"profile.phone": "Phone",
"profile.language": "Languages",
"profile.logout": "logout",
"profile.usa.shipping.address": "USA Shipping Address",
"profile.logout.confirm":"Are you sure want to logout?",
"profile.devices":"Devices",
"profile.email":"Email",
"profile.privilege":"Privilege",
"btn.save": "Save",
"btn.approve":"Approve",
"btn.delete":"Delete",
"================================================================":"",
"product": "Product",
"price": "Price",
@@ -167,16 +203,7 @@
"reg.confirm":"Submit Registration?",
"reg.date":"Registeration Date",
"profile.title": "Profile",
"profile.edit_title": "Edit FCS Profile",
"profile.name": "Name",
"profile.phone": "Phone",
"profile.language": "Languages",
"profile.logout": "logout",
"profile.logout.confirm":"Are you sure want to logout?",
"profile.devices":"Devices",
"profile.email":"Email",
"profile.privilege":"Privilege",
"device.confirm":"Confirm this device?",
"device.logout":"Logout this device?",
@@ -530,12 +557,6 @@
"notifications.title":"Notification",
"staff.title":"Staffs",
"staff.list.title":"STAFFS",
"staff.new":"New Staff",
"staff.form.title":"STAFF",
"staff.add":"Add",
"staff.update":"Update",
"shipment.title":"FCS Shipments",
"shipment.list.title":"FCS SHIPMENTS",
@@ -605,9 +626,6 @@
"invoice.add_package":"Add Package",
"customer.list.title":"CUSTOMERS",
"customer.form.title":"CUSTOMER",
"customer.invite":"Invite",
"fcs.btn": "FCS Profile",
"fcs.profile": "FCS PROFILE",

View File

@@ -48,7 +48,9 @@
"language.selection.title":"ဘာသာစကား ရွေးချယ်ပါ",
"welcome.signin":"ဝင်မည်",
"welcome.msg":"FCS Logistics က ကြိုဆိုပါတယ်!",
"welcome.msg":"FCS က ကြိုဆိုပါတယ်!",
"home.invitation.request.msg":"ဖိတ်ကြားမှု တောင်းဆိုသည်ကို လုပ်ဆောင်နေပါသည်!",
"sms.verify.title":"သင့်နံပါတ်ကိုအတည်ပြုပါ",
"sms.six.digit":"SMS ဂဏန်း ခြောက်လုံး ကိုရိုက်ထဲ့ပါ",
@@ -60,11 +62,43 @@
"invite.request":"ဖိတ်ကြားမှု တောင်းဆိုမည်",
"invite.request.successful":"တောင်းဆိုမှု အောင်မြင်သည်!",
"================================================================":"",
"customer.list.title":"ဝယ်ယူသူများ",
"customer.name":"နာမည်",
"customer.phone":"ဖုန်းနံပါတ်",
"customer.status":"အခြေအနေ",
"customer.fcs.id":"FCS ID",
"customer.invitation.request.confirm":"လက်ခံ လိုက်ပါ",
"invitation.list": "ဖိတ်ကြားမှုများ",
"invitation.edit": "ဖိတ်ကြားမှု",
"invitation.new": "ဖိတ်ကြားမှု အသစ်",
"invitation.confirm.delete": "ဖိတ်ကြားမှု ဖျက်မလား?",
"staff.title":"ဝန်ထမ်းများ",
"staff.list.title":"ဝန်ထမ်းများ",
"staff.new":"ဝန်ထမ်း အသစ်",
"staff.form.title":"ဝန်ထမ်း",
"staff.add":"အသစ်ထည့်မည်",
"staff.update":"ပြုပြင်မည်",
"profile.title":"ကျွန်ုပ် ပရိုဖိုင်",
"profile.edit_title":"ကျွန်ုပ် ပရိုဖိုင်ကိုပြုပြင်ရန်",
"profile.name":"နာမည်",
"profile.phone": "ဖုန်းနံပါတ်",
"profile.language": "ဘာသာစကားများ",
"profile.logout": "အကောင့်ထွက်ရန်",
"profile.usa.shipping.address": "အမေရိကား ပစည်းပို့ရန်လိပ်စာ",
"profile.logout.confirm":"အကောင့်ထွက်ရန်သေချာပြီလား?",
"profile.devices":"ဖုန်းမော်ဒယ်အမျိုးအစားများ",
"profile.email":"အီးမေးလ်",
"profile.privilege":"လုပ်ပိုင်ခွင့်",
"btn.save":"သိမ်းဆည်းရန်",
"btn.approve":"အတည်ပြုရန်",
"btn.delete":"ဖျက်ရန်",
"================================================================":"",
"product": "ကုန်ပစ္စည်း",
"price": "ဈေးနှုန်း",
@@ -166,17 +200,6 @@
"reg.confirm":"မှတ်ပုံတင်သွင်းမည်လား?",
"reg.date":"မှတ်ပုံတင်သည့် နေ့စွဲ",
"profile.title":"ပရိုဖိုင်",
"profile.edit_title":"ပရိုဖိုင်ကိုပြုပြင်ရန်",
"profile.name":"နာမည်",
"profile.phone": "ဖုန်းနံပါတ်",
"profile.language": "ဘာသာစကားများ",
"profile.logout": "အကောင့်ထွက်ရန်",
"profile.logout.confirm":"အကောင့်ထွက်ရန်သေချာပြီလား?",
"profile.devices":"ဖုန်းမော်ဒယ်အမျိုးအစားများ",
"profile.email":"အီးမေးလ်",
"profile.privilege":"လုပ်ပိုင်ခွင့်",
"device.confirm":"ဒီဖုန်းမော်ဒယ်ကိုအတည်ပြုမည်လား?",
"device.logout":"ဒီဖုန်းမော်ဒယ်ကိုထွက်ရန်သေချာပြီလား?",
"device.set_primary":"ဒီဖုန်းမော်ဒယ်ကိုမူလမော်ဒယ်ထည့်ရန်သေချာပြီလား?",
@@ -561,20 +584,12 @@
"notifications.title":"Notifications",
"staff.title":"FCS ဝန်ထမ်းများ",
"staff.list.title":"FCS ဝန်ထမ်းများ",
"staff.new":"New Staff",
"staff.form.title":"FCS STAFF",
"staff.add":"Add",
"staff.update":"Update",
"shipment.title":"FCS တင်ပို့ခြင်းများ",
"shipment.list.title":"FCS တင်ပို့ခြင်းများ",
"shipment.add":"New FCS shipment",
"shipment.form.title":"FCS SHIPMENT",
"shipment.number":"FCS Shipment Number",
"package.name":"Packages",
"package.title":"PACKAGES",
"package.new":"New Package",
@@ -611,7 +626,6 @@
"customers.btn": "ဝယ်ယူသူများ",
"customers.title": "ဝယ်ယူသူများ",
"customer.invite":"Invite",
"invoices.btn": "ငွေတောင်းခံလွှာများ",
"invoices.title": "ငွေတောင်းခံလွှာများ",
@@ -622,8 +636,6 @@
"invoice.add_box":"Add Box",
"customer.list.title":"ဝယ်ယူသူများ",
"customer.form.title":"ဝယ်ယူသူ",
"fcs.profile": "ပရိုဖိုင်",

View File

@@ -1,6 +1,5 @@
import 'dart:io';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/localization/app_translations_delegate.dart';
import 'package:fcs/fcs/common/localization/transalation.dart';
import 'package:fcs/fcs/common/pages/contact/model/contact_model.dart';
@@ -8,7 +7,8 @@ import 'package:fcs/fcs/common/pages/customers/model/customer_model.dart';
import 'package:fcs/fcs/common/pages/faq/model/faq_model.dart';
import 'package:fcs/fcs/common/pages/initial_language_selection.dart';
import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:fcs/fcs/common/pages/signin/model/signin_model.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart' as fcs;
import 'package:fcs/fcs/common/pages/staff/model/staff_model.dart';
import 'package:fcs/fcs/common/pages/term/model/term_model.dart';
import 'package:fcs/fcs/common/services/services.dart';
import 'package:fcs/model/buyer_model.dart';
@@ -31,8 +31,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart' as fcs;
import 'fcs/common/pages/home_page.dart';
import 'fcs/common/pages/splash_page.dart';
import 'fcs/common/pages/welcome_page.dart';
import 'model/announcement_model.dart';
import 'model/chart_model.dart';
import 'model/device_model.dart';
@@ -48,9 +50,6 @@ import 'model/report_user_model.dart';
import 'model/shipment_rate_model.dart';
import 'model/user_model.dart';
import 'model_fcs/box_model.dart';
import 'fcs/common/pages/home_page.dart';
import 'fcs/common/pages/welcome_page.dart';
import 'fcs/common/pages/splash_page.dart';
import 'pages/term.dart';
class App extends StatefulWidget {
@@ -67,7 +66,6 @@ class _AppState extends State<App> {
final UserModel userModel = new UserModel();
final ProductModel productModel = new ProductModel();
final EmployeeModel employeeModel = new EmployeeModel();
final POSubmissionModel poSubmissionModel = new POSubmissionModel();
final DOModel doModel = new DOModel();
final LanguageModel lanuguageModel = new LanguageModel();
@@ -94,7 +92,7 @@ class _AppState extends State<App> {
final InvoiceModel invoiceModel = new InvoiceModel();
final CustomerModel customerModel = new CustomerModel();
final DiscountModel discountModel = new DiscountModel();
final SigninModel signinModel = new SigninModel();
final StaffModel staffModel = new StaffModel();
AppTranslationsDelegate _newLocaleDelegate;
static FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
@@ -103,12 +101,14 @@ class _AppState extends State<App> {
@override
void initState() {
super.initState();
mainModel2..addModel(customerModel);
mainModel2..addModel(staffModel);
mainModel2.init();
_newLocaleDelegate = AppTranslationsDelegate(newLocale: null);
Translation().onLocaleChanged = onLocaleChange;
mainModel
..addModel(userModel)
..addModel(employeeModel)
..addModel(storageModel)
..addModel(regModel)
..addModel(poSubmissionModel)
@@ -225,7 +225,7 @@ class _AppState extends State<App> {
ChangeNotifierProvider.value(value: mainModel),
ChangeNotifierProvider.value(value: userModel),
ChangeNotifierProvider.value(value: productModel),
ChangeNotifierProvider.value(value: employeeModel),
ChangeNotifierProvider.value(value: staffModel),
ChangeNotifierProvider.value(value: poSubmissionModel),
ChangeNotifierProvider.value(value: doModel),
ChangeNotifierProvider.value(value: storageModel),
@@ -255,7 +255,6 @@ class _AppState extends State<App> {
ChangeNotifierProvider.value(value: contactModel),
ChangeNotifierProvider.value(value: termModel),
ChangeNotifierProvider.value(value: faqModel),
ChangeNotifierProvider.value(value: signinModel),
],
child: Consumer<LanguageModel>(
builder: (context, value, child) {

View File

@@ -9,10 +9,13 @@ import 'package:fcs/fcs/common/domain/entities/setting.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/domain/exceiptions/signin_exception.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:logging/logging.dart';
import '../../helpers/api_helper.dart';
class AuthFb {
final log = Logger('AuthFb');
static final AuthFb instance = AuthFb._();
AuthFb._();
@@ -21,13 +24,23 @@ class AuthFb {
Future<fcs.AuthResult> sendSmsCodeToPhoneNumber(String phoneNumber) {
Completer<fcs.AuthResult> completer = Completer();
bool codeSentCompleted = false;
final PhoneVerificationCompleted verificationCompleted =
(AuthCredential credential) async {
AuthResult _authResult = await _fb.signInWithCredential(credential);
AuthResult _authResult;
try {
_authResult = await _fb.signInWithCredential(credential);
print("PhoneVerificationCompleted :$_authResult");
if (_authResult == null) {
throw SigninException("Sigin error!");
}
} catch (e) {
print("Exception:$e");
// throw e;
completer.completeError(SigninException(e.toString()));
return;
}
fcs.AuthResult auth =
fcs.AuthResult(authStatus: AuthStatus.AUTH_VERIFIED);
completer.complete(auth);
@@ -39,25 +52,32 @@ class AuthFb {
(AuthException authException) async {
print(
'Phone number verification failed. Code: ${authException.code}. Message: ${authException.message}');
completer
.completeError(SigninException("Phone number verification failed"));
completer.completeError(SigninException(
"Phone number verification failed:${authException.message}"));
};
final PhoneCodeSent codeSent =
(String verificationId, [int forceResendingToken]) async {
_verificationId = verificationId;
print("code sent to " + phoneNumber);
completer.complete(fcs.AuthResult(authStatus: AuthStatus.SMS_SENT));
print("codeSent " + phoneNumber);
codeSentCompleted = true;
};
final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
(String verificationId) {
print("codeAutoRetrievalTimeout $verificationId ");
_verificationId = verificationId;
if (codeSentCompleted) {
completer.complete(fcs.AuthResult(authStatus: AuthStatus.SMS_SENT));
} else {
completer.completeError(SigninException("SMS code failed"));
}
};
_fb.verifyPhoneNumber(
phoneNumber: phoneNumber,
timeout: const Duration(minutes: 2),
timeout: const Duration(seconds: 0),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
@@ -102,12 +122,12 @@ class AuthFb {
if (firebaseUser == null) return null;
IdTokenResult idToken =
await firebaseUser.getIdToken(refresh: refreshIdToken);
String name = idToken.claims["name"];
log.info("Claims:${idToken.claims}");
User user = User();
user.id = firebaseUser.uid;
user.name = name;
user.hasSignup =
idToken.claims.containsKey("signup") && idToken.claims["signup"];
user.status = idToken.claims["status"];
user.phoneNumber = firebaseUser.phoneNumber;
// add privileges
@@ -115,10 +135,24 @@ class AuthFb {
if (privileges != null && privileges != "") {
user.privileges = privileges.split(":").toList();
}
User _user = await getUserFromFirestore(user.id);
user.fcsID = _user.fcsID;
user.name = _user.name;
return user;
}
Future<User> getUserFromFirestore(String userID) async {
DocumentSnapshot snap = await Firestore.instance
.collection(user_collection)
.document(userID)
.get();
if (snap.exists) {
User user = User.fromMap(snap.data, snap.documentID);
return user;
}
return null;
}
Future<bool> isLogin() async {
final FirebaseUser firebaseUser = await _fb.currentUser();
return Future.value(firebaseUser != null);
@@ -134,6 +168,17 @@ class AuthFb {
return getUser(refreshIdToken: true);
}
Future<bool> hasInvite() async {
var invited =
await requestAPI("/check_invitation", "GET", token: await getToken());
return invited["invited"];
}
Future<void> updateProfile(String newUserName) async {
return await requestAPI("/profile", "PUT",
payload: {"user_name": newUserName}, token: await getToken());
}
Future<String> getToken() async {
FirebaseUser firebaseUser = await _fb.currentUser();
IdTokenResult token = await firebaseUser.getIdToken();

View File

@@ -0,0 +1,38 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/fcs/common/domain/constants.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/helpers/api_helper.dart';
import 'package:fcs/fcs/common/helpers/firebase_helper.dart';
class UserDataProvider {
Future<void> inviteUser(String userName, String phoneNumber) async {
return await requestAPI("/invites", "POST",
payload: {"user_name": userName, "phone_number": phoneNumber},
token: await getToken());
}
Future<void> deleteInvite(String phoneNumber) async {
return await requestAPI("/invites", "DELETE",
payload: {"phone_number": phoneNumber}, token: await getToken());
}
Future<void> acceptRequest(String userID) async {
return await requestAPI("/invites", "PUT",
payload: {"id": userID}, token: await getToken());
}
Future<User> findUser(String phoneNumber) async {
QuerySnapshot querySnap = await Firestore.instance
.collection(user_collection)
.where("phone_number", isEqualTo: phoneNumber)
.limit(1)
.getDocuments();
if (querySnap.documents.length > 0) {
var snap = querySnap.documents.first;
User user = User.fromMap(snap.data, snap.documentID);
return user;
}
return null;
}
}

View File

@@ -1,7 +0,0 @@
import 'package:fcs/fcs/common/domain/entities/user.dart';
class UserFBDataProvider {
Future<User> getUser(String id) {
return null;
}
}

View File

@@ -1,11 +1,13 @@
const ok_doc_id = "ok";
const setting_doc_id = "setting";
const config_collection = "configs";
const user_collection = "users";
const invitations_collection = "invitations";
const setting_doc_id = "setting";
const privilege_collection = "privileges";
const ok_doc_id = "ok";
const biz_collection = "bizs";
const product_collection = "products";
const user_collection = "users";
const privilege_collection = "privileges";
const user_level_collection = "user_levels";
const storage_collection = "storages";
const buyer_collection = "buyers";

View File

@@ -9,7 +9,6 @@ class Role {
roleID = json['role_id'];
privileges = json['privileges'];
}
}
class Parser {
@@ -63,10 +62,6 @@ class UserLevel {
UserLevel({this.id, this.name, this.level});
factory UserLevel.fromMap(Map<String, dynamic> map, String docID) {
return UserLevel(
id: docID,
name: map['name'],
level: map['level']
);
return UserLevel(id: docID, name: map['name'], level: map['level']);
}
}

View File

@@ -22,6 +22,8 @@ class Setting {
String mmContactNumber;
String emailAddress;
String facebookLink;
bool inviteRequired;
String appUrl;
final String okEnergyId;
final String about;
@@ -84,6 +86,8 @@ class Setting {
this.mmContactNumber,
this.emailAddress,
this.facebookLink,
this.inviteRequired,
this.appUrl,
this.about,
this.okEnergyId,
this.terms,
@@ -122,6 +126,8 @@ class Setting {
return Setting(
supportBuildNum: map['support_build_number'],
inviteRequired: map['invite_required'],
appUrl: map['app_url'],
usaAddress: map['usa_address'],
mmAddress: map['mm_address'],
usaContactNumber: map['usa_contact_number'],

View File

@@ -1,22 +1,28 @@
import 'package:fcs/fcs/common/helpers/const.dart';
class User {
String id;
String name;
String phoneNumber;
bool hasSignup;
bool invited;
List<String> privileges = [];
String status;
String fcsID;
List<String> privileges = [];
String get phone => phoneNumber != null && phoneNumber.startsWith("959")
? "0${phoneNumber.substring(2)}"
: phoneNumber;
bool get joined => status != null && status == userStatusJoined;
bool get invited => status != null && status == userStatusInvited;
bool get requested => status != null && status == userStatusRequested;
String get share => "Your phone number:$phoneNumber";
User({
this.id,
this.name,
this.phoneNumber,
this.fcsID,
this.status,
this.privileges,
});
factory User.fromJson(Map<String, dynamic> json) {
@@ -24,6 +30,7 @@ class User {
id: json['id'],
name: json['user_name'],
phoneNumber: json['phone_number'],
status: json['status'],
);
}
@@ -41,11 +48,16 @@ class User {
}
factory User.fromMap(Map<String, dynamic> map, String docID) {
List<String> _privileges =
map['privileges'] == null ? [] : map['privileges'].cast<String>();
return User(
id: docID,
name: map['user_name'],
phoneNumber: map['phone_number'],
);
status: map['status'],
fcsID: map['fcs_id'],
privileges: _privileges);
}
bool isCustomer() {
@@ -60,16 +72,26 @@ class User {
return privileges != null ? privileges.contains('admin') : false;
}
bool hasMaintenance() {
return privileges != null ? privileges.contains('mt') : false;
bool hasCustomers() {
return hasSysAdmin() ||
hasAdmin() ||
(privileges != null ? privileges.contains('c') : false);
}
bool hasCustomers() {
return privileges != null ? privileges.contains('c') : false;
bool hasStaffs() {
return hasSysAdmin() ||
hasAdmin() ||
(privileges != null ? privileges.contains('s') : false);
}
bool hasSupport() {
return hasSysAdmin() ||
hasAdmin() ||
(privileges != null ? privileges.contains('sp') : false);
}
@override
String toString() {
return 'User{name: $name, phoneNumber: $phoneNumber,hasSignup:$hasSignup}';
return 'User{name: $name, phoneNumber: $phoneNumber,status:$status}';
}
}

View File

@@ -0,0 +1,3 @@
const userStatusInvited = "invited";
const userStatusJoined = "joined";
const userStatusRequested = "requested";

View File

@@ -1,363 +1,128 @@
import 'package:fcs/fcs/common/domain/entities/customer.dart';
import 'package:fcs/fcs/common/domain/entities/role.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/pages/customers/model/customer_model.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/fcs/common/pages/widgets/display_text.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
typedef void FindCallBack();
class CustomerEditor extends StatefulWidget {
final Customer customer;
final User customer;
const CustomerEditor({this.customer});
@override
_CustomerEditorState createState() => _CustomerEditorState();
}
class _CustomerEditorState extends State<CustomerEditor> {
TextEditingController _name = new TextEditingController();
TextEditingController _phone = new TextEditingController();
TextEditingController _phoneInput = new TextEditingController();
TextEditingController _status = new TextEditingController();
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
String currentBizId;
bool isSend = false;
User user;
User selectedUser;
List<Privilege> privileges = [
Privilege(name: 'Manage shipment'),
Privilege(name: 'Manage pickups'),
Privilege(name: 'Manage packages'),
Privilege(name: 'Manage deliveries'),
Privilege(name: 'Admin')
];
@override
void initState() {
super.initState();
// privileges = Provider.of<UserModel>(context, listen: false).privileges;
if (widget.customer != null) {
_name.text = widget.customer.name;
_phone.text = widget.customer.phoneNumber;
_status.text = widget.customer.status;
// privileges.forEach((p) => widget.employee.privilegeIds.contains(p.id)
// ? p.isChecked = true
// : p.isChecked = false);
}
}
List<Widget> showprivilegeList(BuildContext context) {
return privileges.map((p) {
return new ListTile(
title: new Row(
children: <Widget>[
new Checkbox(
value: p.isChecked == null ? false : p.isChecked,
activeColor: primaryColor,
onChanged: (bool value) {
setState(() {
p.isChecked = value;
});
}),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
p.name,
style: TextStyle(
fontSize: 15.0,
),
),
// Container(
// width: MediaQuery.of(context).size.width * 0.5,
// child: new Text(
// userModel.getPrivileges[index].desc,
// style:
// TextStyle(fontSize: 12.0, color: Colors.grey[600]),
// ),
// ),
],
),
],
));
}).toList();
}
Widget phoneInputbox(BuildContext context, FindCallBack findCallBack) {
var languageModel = Provider.of<LanguageModel>(context);
return Container(
padding: EdgeInsets.only(top: 10),
child: Stack(
alignment: const Alignment(1.2, 1.0),
children: <Widget>[
TextFormField(
controller: _phoneInput,
autofocus: false,
cursorColor: primaryColor,
keyboardType: TextInputType.phone,
style: textStyle,
decoration: new InputDecoration(
labelText: AppTranslations.of(context).text('employee.phone'),
labelStyle: languageModel.isEng ? labelStyle : labelStyleMM,
icon: Icon(
Icons.phone,
color: primaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 1.0)),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 1.0)),
),
),
new FlatButton(
onPressed: () {
this.isSend = true;
findCallBack();
},
child: new Icon(
Icons.search,
size: 25,
))
],
));
}
@override
Widget build(BuildContext context) {
final namebox = TextFormField(
controller: _name,
autofocus: false,
readOnly: true,
cursorColor: primaryColor,
decoration: new InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
icon: Icon(
Icons.person,
color: primaryColor,
),
),
);
final displayPhoneNo = TextFormField(
controller: _phone,
autofocus: false,
readOnly: true,
cursorColor: primaryColor,
decoration: new InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
icon: Icon(
Icons.phone,
color: primaryColor,
),
),
);
var phoneNumberBox = Row(
children: <Widget>[
Expanded(child: displayPhoneNo),
Expanded(
child: InkWell(
onTap: () => call(context, _phone.text),
child: Icon(
Icons.open_in_new,
color: Colors.grey,
size: 15,
),
),
),
child: DisplayText(
text: widget.customer.phoneNumber,
labelText: getLocalString(context, "customer.phone"),
iconData: Icons.phone,
)),
IconButton(
icon: Icon(Icons.open_in_new, color: primaryColor),
onPressed: () => call(context, widget.customer.phoneNumber)),
],
);
final statusbox = TextFormField(
controller: _status,
autofocus: false,
readOnly: true,
cursorColor: primaryColor,
decoration: new InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
icon: Icon(
Icons.av_timer,
color: primaryColor,
),
),
);
final updateButton = Container(
padding: EdgeInsets.only(top: 40),
child: Container(
height: 45.0,
decoration: BoxDecoration(
color: primaryColor,
shape: BoxShape.rectangle,
),
child: ButtonTheme(
minWidth: 900.0,
height: 100.0,
child: FlatButton(
onPressed: () {},
child: LocalText(
context,
'customer.update',
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
);
final addButton = Container(
padding: EdgeInsets.only(top: 40),
child: Container(
height: 45.0,
decoration: BoxDecoration(
color: primaryColor,
shape: BoxShape.rectangle,
),
child: ButtonTheme(
minWidth: 900.0,
height: 100.0,
child: FlatButton(
onPressed: () {},
child: LocalText(
context,
'customer.add',
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
);
return LocalProgress(
inAsyncCall: _isLoading,
child: SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
shadowColor: Colors.transparent,
centerTitle: true,
leading: new IconButton(
icon: new Icon(Icons.close),
icon: new Icon(
Icons.close,
color: primaryColor,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
title: LocalText(
context,
"customer.form.title",
title: Text(
widget.customer.name,
style: TextStyle(
fontSize: 20,
color: Colors.white,
color: primaryColor,
),
// actions: <Widget>[
// widget.customer == null || !mainModel.showHistoryBtn()
// ? Container()
// : IconButton(
// icon: Icon(Icons.history),
// onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => DocumentLogPage(
// docID: widget.customer.docID)),
// );
// },
// ),
// ],
),
body: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
widget.customer == null
? phoneInputbox(context, () => _findUser(context))
: phoneNumberBox,
widget.customer == null
? this.isSend ? namebox : Container()
: namebox,
statusbox,
// widget.customer == null ? addButton : updateButton,
SizedBox(
height: 20,
)
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 18.0, right: 18),
child: ListView(
children: [
phoneNumberBox,
DisplayText(
text: widget.customer.status,
labelText:
getLocalString(context, "customer.status"),
iconData: Icons.add_alarm,
),
DisplayText(
text: widget.customer.fcsID,
labelText:
getLocalString(context, "customer.fcs.id"),
iconData: Icons.account_circle,
),
],
),
),
),
widget.customer.requested
? fcsButton(
context,
getLocalString(
context, "customer.invitation.request.confirm"),
callack: _add)
: Container()
],
),
),
),
));
}
_add(BuildContext context) async {
if (selectedUser == null) return;
setState(() {
_isLoading = true;
});
// var employeeModel = Provider.of<EmployeeModel>(context);
// try {
// await employeeModel.updatePrivileges(
// this.selectedUser.docID, privilegesIDs());
// Navigator.pop(context);
// } catch (e) {
// showMsgDialog(context, "Error", e.toString());
// } finally {
// setState(() {
// _isLoading = false;
// });
// }
}
List<String> privilegesIDs() {
return this.privileges.where((p) => p.isChecked).map((p) => p.id).toList();
}
_save() async {
_add() async {
showConfirmDialog(context, "customer.invitation.request.confirm", () async {
setState(() {
_isLoading = true;
});
if (widget.customer == null) return;
// var employeeModel = Provider.of<EmployeeModel>(context);
// try {
// await employeeModel.updatePrivileges(
// widget.customer.docID, privilegesIDs());
// Navigator.pop(context);
// } catch (e) {
// showMsgDialog(context, "Error", e.toString());
// } finally {
// setState(() {
// _isLoading = false;
// });
// }
CustomerModel customerModel =
Provider.of<CustomerModel>(context, listen: false);
try {
await customerModel.acceptRequest(widget.customer.id);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
_findUser(BuildContext context) async {
// var userModel = Provider.of<UserModel>(context);
// setState(() {
// _isLoading = true;
// });
// try {
// selectedUser = await userModel.findUser(_phoneInput.text);
// setState(() {
// isSend = true;
// _name.text = selectedUser.name;
// if (selectedUser.privilegeIds != null) {
// privileges.forEach((p) => selectedUser.privilegeIds.contains(p.id)
// ? p.isChecked = true
// : p.isChecked = false);
// }
// });
// } catch (e) {
// showMsgDialog(context, "Error", e.toString());
// } finally {
// setState(() {
// _isLoading = false;
// });
// }
});
}
}

View File

@@ -1,20 +1,18 @@
import 'package:fcs/fcs/common/domain/entities/customer.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/customers/invitation_page.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/pages/customers/customer_editor.dart';
import 'package:fcs/fcs/common/pages/customers/invitation_list.dart';
import 'package:fcs/fcs/common/pages/customers/model/customer_model.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/fcs/common/pages/widgets/bottom_up_page_route.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/widget/progress.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/widget/progress.dart';
import 'customer_editor.dart';
import 'invitation_editor.dart';
class CustomerList extends StatefulWidget {
@override
@@ -40,14 +38,14 @@ class _CustomerListState extends State<CustomerList> {
onPressed: () => Navigator.of(context).pop(),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.search,
color: Colors.white,
),
iconSize: 30,
onPressed: () => {},
),
// IconButton(
// icon: Icon(
// Icons.search,
// color: Colors.white,
// ),
// iconSize: 30,
// onPressed: () => {},
// ),
],
backgroundColor: primaryColor,
title: LocalText(
@@ -57,31 +55,50 @@ class _CustomerListState extends State<CustomerList> {
fontSize: 20,
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context).push(BottomUpPageRoute(InvitationPage()));
},
icon: Icon(Icons.add),
label: Text(AppTranslations.of(context).text("customer.invite")),
backgroundColor: primaryColor,
body: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(top: 3, right: 5),
child: InkWell(
onTap: _invitations,
child: Container(
color: primaryColor,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Text(
"Invitations",
style: TextStyle(color: Colors.white),
),
body: new ListView.separated(
),
),
),
),
Expanded(
child: ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
scrollDirection: Axis.vertical,
padding: EdgeInsets.only(left: 15, right: 15, top: 15),
padding: EdgeInsets.only(left: 15, right: 15),
shrinkWrap: true,
itemCount: customerModel.customers.length,
itemBuilder: (BuildContext context, int index) {
Customer customer = customerModel.customers[index];
User customer = customerModel.customers[index];
return _item(customer);
}),
),
],
),
),
);
}
Widget _item(User customer) {
return Stack(
children: <Widget>[
InkWell(
onTap: () {
Navigator.of(context).push(
BottomUpPageRoute(CustomerEditor(customer: customer)));
},
onTap: () => _select(customer),
child: Row(
children: <Widget>[
Expanded(
@@ -100,23 +117,19 @@ class _CustomerListState extends State<CustomerList> {
),
new Expanded(
child: new Column(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
customer.name,
style: new TextStyle(
fontSize: 15.0,
color: primaryColor),
fontSize: 15.0, color: primaryColor),
),
Padding(
padding:
const EdgeInsets.only(top: 8.0),
padding: const EdgeInsets.only(top: 8.0),
child: new Text(
customer.phoneNumber,
style: new TextStyle(
fontSize: 15.0,
color: Colors.grey),
fontSize: 15.0, color: Colors.grey),
),
),
],
@@ -128,15 +141,28 @@ class _CustomerListState extends State<CustomerList> {
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: getStatus(customer.status),
child: _status(customer.status),
),
],
),
),
],
);
}),
),
);
}
Widget _status(String status) {
return Text(
status == "requested" ? status : "",
style: TextStyle(color: primaryColor, fontSize: 14),
);
}
_select(User customer) {
Navigator.of(context)
.push(BottomUpPageRoute(CustomerEditor(customer: customer)));
}
_invitations() {
Navigator.of(context).push(BottomUpPageRoute(InvitationList()));
}
}

View File

@@ -0,0 +1,159 @@
import 'package:country_code_picker/country_code_picker.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/customers/model/customer_model.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/widget/progress.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class InvitationDetail extends StatefulWidget {
@override
_InvitationDetailState createState() => _InvitationDetailState();
}
class _InvitationDetailState extends State<InvitationDetail> {
TextEditingController _nameController = new TextEditingController();
TextEditingController _phoneController = new TextEditingController();
bool _isLoading = false;
String dialCode;
@override
void initState() {
super.initState();
dialCode = "+95";
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(
Icons.close,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
title: Text(AppTranslations.of(context).text("invitation.new")),
),
body: Container(
padding: EdgeInsets.all(18),
child: Column(
children: <Widget>[
Expanded(
child: ListView(
children: <Widget>[
fcsInput("Name", Icons.person,
controller: _nameController, autoFocus: true),
SizedBox(height: 10),
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.phone,
color: primaryColor,
),
),
Container(
decoration: BoxDecoration(
border:
Border.all(color: Colors.grey[400], width: 1),
borderRadius:
BorderRadius.all(Radius.circular(12.0))),
child: CountryCodePicker(
onChanged: _countryChange,
initialSelection: dialCode,
countryFilter: ['+95', '+1'],
showCountryOnly: false,
showOnlyCountryWhenClosed: false,
alignLeft: false,
textStyle: TextStyle(
fontSize: 16,
),
),
),
SizedBox(
width: 10,
),
Flexible(
child: Container(
padding: EdgeInsets.only(top: 10, bottom: 10),
child: TextFormField(
controller: _phoneController,
cursorColor: primaryColor,
textAlign: TextAlign.left,
keyboardType: TextInputType.phone,
style: TextStyle(
fontSize: 18,
),
decoration: InputDecoration(
fillColor: Colors.white,
labelText: "Phone number",
labelStyle:
TextStyle(fontSize: 16, color: Colors.grey),
filled: true,
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.grey, width: 1.0)),
),
),
),
),
],
),
],
),
),
fcsButton(context, "Invite", callack: _invite),
SizedBox(height: 10)
],
),
),
),
);
}
_countryChange(CountryCode countryCode) {
setState(() {
dialCode = countryCode.dialCode;
});
}
_invite() async {
String userName = _nameController.text;
String phoneNumber = dialCode + _phoneController.text;
if (userName == null ||
userName == "" ||
phoneNumber == null ||
phoneNumber == "") {
showMsgDialog(context, "Error", "Invalid name or phone number");
return;
}
setState(() {
_isLoading = true;
});
try {
CustomerModel customerModel =
Provider.of<CustomerModel>(context, listen: false);
await customerModel.inviteUser(userName, phoneNumber);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
}

View File

@@ -0,0 +1,105 @@
import 'package:fcs/fcs/common/domain/entities/customer.dart';
import 'package:fcs/fcs/common/domain/entities/role.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/customers/model/customer_model.dart';
import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/fcs/common/pages/widgets/display_text.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
typedef void FindCallBack();
class InvitationEditor extends StatefulWidget {
final User customer;
const InvitationEditor({this.customer});
@override
_InvitationEditorState createState() => _InvitationEditorState();
}
class _InvitationEditorState extends State<InvitationEditor> {
bool _isLoading = false;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
var phoneNumberBox = Row(
children: <Widget>[
Expanded(
child: DisplayText(
text: widget.customer.phoneNumber,
labelText: getLocalString(context, "customer.phone"),
iconData: Icons.phone,
)),
IconButton(
icon: Icon(Icons.open_in_new, color: primaryColor),
onPressed: () => call(context, widget.customer.phoneNumber)),
],
);
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
shadowColor: Colors.transparent,
centerTitle: true,
leading: new IconButton(
icon: new Icon(
Icons.close,
color: primaryColor,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
widget.customer.name,
style: TextStyle(fontSize: 20, color: primaryColor),
),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Expanded(
child: ListView(
children: [phoneNumberBox],
),
),
fcsButton(context, getLocalString(context, "btn.delete"),
callack: _delete)
],
),
),
));
}
_delete() async {
showConfirmDialog(context, "invitation.confirm.delete", () async {
setState(() {
_isLoading = true;
});
if (widget.customer == null) return;
CustomerModel customerModel =
Provider.of<CustomerModel>(context, listen: false);
try {
await customerModel.deleteInvite(widget.customer.phoneNumber);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
});
}
}

View File

@@ -0,0 +1,148 @@
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:share/share.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/customers/invitation_detail.dart';
import 'package:fcs/fcs/common/pages/customers/model/customer_model.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/fcs/common/pages/widgets/bottom_up_page_route.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'invitation_editor.dart';
class InvitationList extends StatefulWidget {
@override
_InvitationListState createState() => _InvitationListState();
}
class _InvitationListState extends State<InvitationList> {
var dateFormatter = new DateFormat('dd MMM yyyy - hh:mm:ss a');
final double dotSize = 15.0;
bool _isLoading = false;
@override
Widget build(BuildContext context) {
var customerModel = Provider.of<CustomerModel>(context);
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
),
actions: <Widget>[],
backgroundColor: primaryColor,
title: LocalText(
context,
'invitation.list',
color: Colors.white,
fontSize: 20,
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context).push(BottomUpPageRoute(InvitationDetail()));
},
icon: Icon(Icons.add),
label: Text(AppTranslations.of(context).text("invitation.new")),
backgroundColor: primaryColor,
),
body: new ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
scrollDirection: Axis.vertical,
padding: EdgeInsets.only(left: 15, right: 15, top: 15),
shrinkWrap: true,
itemCount: customerModel.invitations.length,
itemBuilder: (BuildContext context, int index) {
User customer = customerModel.invitations[index];
return _item(customer);
}),
),
);
}
Widget _item(User customer) {
return Stack(
children: <Widget>[
InkWell(
onTap: () {
Navigator.of(context)
.push(BottomUpPageRoute(InvitationEditor(customer: customer)));
},
child: Row(
children: <Widget>[
Expanded(
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.symmetric(
horizontal: 32.0 - dotSize / 2),
child: Icon(
Feather.user,
color: primaryColor,
size: 40,
),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
customer.name,
style: new TextStyle(
fontSize: 15.0, color: primaryColor),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: new Text(
customer.phoneNumber,
style: new TextStyle(
fontSize: 15.0, color: Colors.grey),
),
),
],
),
),
],
),
),
),
FlatButton(
onPressed: () => _share(customer),
child: Row(
children: [
Text("Share"),
Icon(Icons.share),
],
)),
],
),
),
],
);
}
_share(User user) async {
MainModel mainModel = Provider.of<MainModel>(context, listen: false);
String appUrl = mainModel.setting.appUrl;
final RenderBox box = context.findRenderObject();
await Share.share(
user.share + "\n Please join us from this link:\n $appUrl",
subject: "Invitation to FCS App",
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
}
}

View File

@@ -1,67 +0,0 @@
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:flutter/material.dart';
import 'package:fcs/widget/progress.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class InvitationPage extends StatefulWidget {
@override
_InvitationPageState createState() => _InvitationPageState();
}
class _InvitationPageState extends State<InvitationPage> {
TextEditingController _nameController = new TextEditingController();
TextEditingController _phoneController = new TextEditingController();
bool _isLoading = false;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(
Icons.close,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
title: Text(AppTranslations.of(context).text("customer.form.title")),
),
body: Container(
padding: EdgeInsets.all(18),
child: Column(
children: <Widget>[
Expanded(
child: ListView(
children: <Widget>[
fcsInput("Name", Icons.person, controller: _nameController),
fcsInput("Phone Number", Icons.phone,
controller: _phoneController),
SizedBox(height: 30),
],
),
),
fcsButton(context, "Invite", callack: () {}),
SizedBox(height: 10)
],
),
),
),
);
}
}

View File

@@ -1,26 +1,20 @@
import 'package:fcs/fcs/common/domain/entities/customer.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/fcs/common/domain/constants.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/pages/model/base_model.dart';
import 'package:fcs/fcs/common/services/services.dart';
import 'package:logging/logging.dart';
class CustomerModel extends BaseModel {
final log = Logger('CustomerModel');
List<Customer> customers = [
Customer(
name: 'Ko Nyi',
phoneNumber: '+95 9 717273634',
status: 'Invited'
),
Customer(name: 'Ko Phyu', phoneNumber: '+1 (939) 382-3844',status: 'Signin'),
Customer(name: 'Ko Ye', phoneNumber: '+95 9 983734783', status: 'Invited'),
];
List<User> customers = [];
List<User> invitations = [];
void initUser(user) async {
super.initUser(user);
// _loadCustomer();
_loadCustomer();
_loadInvitations();
}
@override
@@ -28,31 +22,64 @@ class CustomerModel extends BaseModel {
customers = [];
}
// Future<void> _loadCustomer() async {
// if (!user.isOwnerAndAbove() && !user.hasAccount()) {
// return;
// }
Future<void> inviteUser(String userName, String phoneNumber) {
return Services.instance.userService.inviteUser(userName, phoneNumber);
}
// try {
// Firestore.instance
// .collection("/$biz_collection/${setting.okEnergyId}/$user_collection")
// .where("is_employee", isEqualTo: true)
// .snapshots()
// .listen((QuerySnapshot snapshot) {
// customers.clear();
// customers = snapshot.documents.map((documentSnapshot) {
// var user =
// User.fromMap(documentSnapshot.data, documentSnapshot.documentID);
// return user;
// }).toList();
// notifyListeners();
// }).onError((e) {
// log.warning("Error! $e");
// });
// } catch (e) {
// log.warning("Error!! $e");
// }
// }
Future<void> deleteInvite(String phoneNumber) {
return Services.instance.userService.deleteInvite(phoneNumber);
}
Future<void> acceptRequest(String userID) {
return Services.instance.userService.acceptRequest(userID);
}
Future<void> _loadCustomer() async {
if (user == null || !user.hasCustomers()) return;
try {
Firestore.instance
.collection("/$user_collection")
.where("is_sys_admin", isEqualTo: false)
.snapshots()
.listen((QuerySnapshot snapshot) {
customers.clear();
customers = snapshot.documents.map((documentSnapshot) {
var user =
User.fromMap(documentSnapshot.data, documentSnapshot.documentID);
return user;
}).toList();
notifyListeners();
}).onError((e) {
log.warning("Error! $e");
});
} catch (e) {
log.warning("Error!! $e");
}
}
Future<void> _loadInvitations() async {
if (user == null || !user.hasCustomers()) return;
try {
Firestore.instance
.collection("/$invitations_collection")
.snapshots()
.listen((QuerySnapshot snapshot) {
invitations.clear();
invitations = snapshot.documents.map((documentSnapshot) {
var user =
User.fromMap(documentSnapshot.data, documentSnapshot.documentID);
return user;
}).toList();
notifyListeners();
}).onError((e) {
log.warning("Error! $e");
});
} catch (e) {
log.warning("Error!! $e");
}
}
// Future<void> updatePrivileges(String userID, List<String> privileges) async {
// try {

View File

@@ -12,12 +12,12 @@ import 'package:provider/provider.dart';
import 'model/faq_model.dart';
class FAQPage extends StatefulWidget {
class FAQListPage extends StatefulWidget {
@override
_FAQPageState createState() => _FAQPageState();
_FAQListPageState createState() => _FAQListPageState();
}
class _FAQPageState extends State<FAQPage> {
class _FAQListPageState extends State<FAQListPage> {
@override
void initState() {
super.initState();
@@ -51,7 +51,8 @@ class _FAQPageState extends State<FAQPage> {
color: Colors.white,
)),
),
actions:isEditable? [
actions: isEditable
? [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
@@ -62,7 +63,8 @@ class _FAQPageState extends State<FAQPage> {
color: Colors.white,
size: 35,
))
]:[],
]
: [],
),
SliverList(
delegate: SliverChildBuilderDelegate(
@@ -95,12 +97,12 @@ class _FAQPageState extends State<FAQPage> {
child: TextLocalStyle(
context,
faq.question(isEng),
fontSize: 18,
fontSize: 16,
),
),
// Spacer(),
Padding(
padding: const EdgeInsets.only(left:18.0),
padding: const EdgeInsets.only(left: 18.0),
child: Icon(
CupertinoIcons.right_chevron,
color: primaryColor,

View File

@@ -1,8 +1,11 @@
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/localization/transalation.dart';
import 'package:fcs/fcs/common/pages/customers/customer_list.dart';
import 'package:fcs/fcs/common/pages/faq/faq_page.dart';
import 'package:fcs/fcs/common/pages/faq/faq_list_page.dart';
import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/staff/staff_list.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/fcs/common/pages/widgets/action_button.dart';
import 'package:fcs/fcs/common/pages/widgets/bottom_widgets.dart';
import 'package:fcs/pages/discount_list.dart';
@@ -30,9 +33,8 @@ import '../../../pages/fcs_profile_page.dart';
import '../../../pages/invoice/invoce_list.dart';
import '../../../pages/pickup_list.dart';
import '../../../pages/shipment_rates.dart';
import '../../../pages/staff_list.dart';
import '../helpers/theme.dart';
import 'profile_page.dart';
import 'profile/profile_page.dart';
import 'signin/signin_page.dart';
final msgLog = Logger('backgroundMessageHandler');
@@ -70,6 +72,7 @@ class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
User user = Provider.of<MainModel>(context).user;
login = Provider.of<MainModel>(context).isLogin();
// var owner =true;// Provider.of<MainModel>(context).isOwner();
var customer = Provider.of<MainModel>(context).isCustomer();
@@ -78,7 +81,7 @@ class _HomePageState extends State<HomePage> {
final faqBtn = _buildBtn("faq.btn",
icon: MaterialCommunityIcons.frequently_asked_questions,
btnCallback: () => Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => FAQPage(),
builder: (context) => FAQListPage(),
)));
final packagesBtn = _buildBtn("package.name",
@@ -169,22 +172,23 @@ class _HomePageState extends State<HomePage> {
List<Widget> widgets = [];
widgets.add(faqBtn);
if (user != null) {
// customer ? widgets.add(buyingBtn) : "";
// customer || owner ? widgets.add(pickUpBtn) : "";
!customer ? widgets.add(shipmentBtn) : "";
// !customer ? widgets.add(shipmentBtn) : "";
// customer || owner ? widgets.add(notiBtn) : "";
// owner ? widgets.add(staffBtn) : "";
user.hasStaffs() ? widgets.add(staffBtn) : "";
// owner ? widgets.add(fcsProfileBtn) : "";
// widgets.add(shipmentCostBtn);
// customer || owner ? widgets.add(packagesBtn) : "";
// owner ? widgets.add(boxesBtn) : "";
// owner ? widgets.add(deliveryBtn) : "";
widgets.add(customersBtn);
user.hasCustomers() ? widgets.add(customersBtn) : "";
// customer || owner ? widgets.add(invoicesBtn) : "";
// owner ? widgets.add(paymentMethodBtn) : "";
// owner ? widgets.add(discountBtn) : "";
// widgets.add(termBtn);
}
return OfflineRedirect(
child: FlavorBanner(
child: Scaffold(
@@ -295,6 +299,16 @@ class _HomePageState extends State<HomePage> {
),
child: Column(
children: <Widget>[
user.requested
? Container(
padding: const EdgeInsets.all(8.0),
child: Text(
getLocalString(
context, "home.invitation.request.msg"),
style: TextStyle(color: Colors.white70),
),
)
: Container(),
Expanded(
child: ListView(children: [
Wrap(

View File

@@ -5,6 +5,7 @@ import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/signin/signin_page.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
@@ -28,10 +29,12 @@ class _InitialLanguageSelectionPageState
String selectedLanguage;
int selectedIndex;
bool _isLoading;
@override
void initState() {
super.initState();
_isLoading = false;
var languageModel = Provider.of<LanguageModel>(context, listen: false);
this.selectedIndex = languageModel.isEng ? 0 : 1;
loadLaunguage(languageModel);
@@ -48,7 +51,9 @@ class _InitialLanguageSelectionPageState
@override
Widget build(BuildContext context) {
return Material(
return LocalProgress(
inAsyncCall: _isLoading,
child: Material(
type: MaterialType.transparency,
child: Container(
decoration: BoxDecoration(
@@ -165,6 +170,7 @@ class _InitialLanguageSelectionPageState
),
),
),
),
);
}
@@ -179,9 +185,18 @@ class _InitialLanguageSelectionPageState
}
_next() {
setState(() {
_isLoading = true;
});
try {
SharedPref.finishFirstLaunch();
bool isLogin = Provider.of<MainModel>(context, listen: false).isLogin();
String page = isLogin ? "/home" : "/welcome";
Navigator.of(context).pushReplacementNamed(page);
} catch (e) {} finally {
setState(() {
_isLoading = false;
});
}
}
}

View File

@@ -36,20 +36,21 @@ class MainModel extends ChangeNotifier {
});
Services.instance.authService.onAuthStatus().listen((event) {
this.user = event;
_initUser(user);
notifyListeners();
});
}
bool faqEditable() {
return this.user != null && false;
return this.user != null && this.user.hasSupport();
}
bool termEditable() {
return this.user != null && false;
return this.user != null && this.user.hasSupport();
}
bool contactEditable() {
return this.user != null && false;
return this.user != null && this.user.hasSupport();
}
bool isLogin() {
@@ -81,13 +82,13 @@ class MainModel extends ChangeNotifier {
models.add(model);
}
// void _initUser(User user) {
// models.forEach((m) => m.initUser(user));
void _initUser(User user) {
models.forEach((m) => m.initUser(user));
// if (firebaseMessaging != null) {
// firebaseMessaging.subscribeToTopic(user.docID);
// }
// }
}
void _initSetting(Setting setting) {
models.forEach((m) => m.initSetting(setting));
@@ -106,6 +107,7 @@ class MainModel extends ChangeNotifier {
void _loadUser() async {
try {
this.user = await Services.instance.authService.getUser();
_initUser(user);
} finally {
this.isLoaded = true;
notifyListeners();
@@ -143,13 +145,27 @@ class MainModel extends ChangeNotifier {
Future<void> signout() {
this.user = null;
// logout models
models.forEach((m) => m.logout());
notifyListeners();
return Services.instance.authService.signout();
}
Future<bool> hasInvite() async {
return Services.instance.authService.hasInvite();
}
Future<void> signup(String userName) async {
await Services.instance.authService.signup(userName);
this.user = await Services.instance.authService.getUser();
this.user =
await Services.instance.authService.getUser(refreshIdToken: true);
notifyListeners();
}
Future<void> updateProfile(String newUserName) async {
await Services.instance.authService.updateProfile(newUserName);
this.user =
await Services.instance.authService.getUser(refreshIdToken: true);
notifyListeners();
}
}

View File

@@ -0,0 +1,106 @@
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:fcs/fcs/common/pages/util.dart';
typedef void ProfileCallback();
class ProfileEdit extends StatefulWidget {
@override
_ProfileEditState createState() => _ProfileEditState();
}
class _ProfileEditState extends State<ProfileEdit> {
final TextEditingController nameController = new TextEditingController();
bool _loading = false;
@override
void initState() {
super.initState();
MainModel mainModel = Provider.of<MainModel>(context, listen: false);
nameController.text = mainModel.user.name;
}
@override
Widget build(BuildContext context) {
var languageModel = Provider.of<LanguageModel>(context);
final name = Container(
padding: EdgeInsets.only(top: 0, left: 20, right: 15, bottom: 30),
child: TextFormField(
controller: nameController,
autofocus: true,
cursorColor: primaryColor,
style: textStyle,
decoration: new InputDecoration(
labelText: AppTranslations.of(context).text("profile.name"),
labelStyle: languageModel.isEng ? labelStyle : labelStyleMM,
icon: Icon(
Icons.person,
color: primaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 1.0)),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 1.0)),
),
));
final saveBtn =
fcsButton(context, getLocalString(context, "btn.save"), callack: _save);
return LocalProgress(
inAsyncCall: _loading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
AppTranslations.of(context).text("profile.edit_title"),
style: TextStyle(color: primaryColor),
),
backgroundColor: Colors.white,
shadowColor: Colors.transparent,
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 35,
color: primaryColor,
),
onPressed: () => Navigator.of(context).pop(),
),
),
body: Column(
children: <Widget>[
Expanded(child: name),
Padding(
padding: const EdgeInsets.all(18.0),
child: saveBtn,
),
],
),
),
);
}
_save() async {
setState(() {
_loading = true;
});
try {
await Provider.of<MainModel>(context, listen: false)
.updateProfile(nameController.text);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_loading = false;
});
}
}
}

View File

@@ -2,6 +2,8 @@ import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/localization/transalation.dart';
import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/profile/profile_edit.dart';
import 'package:fcs/fcs/common/pages/widgets/display_text.dart';
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:fcs/model/shipment_model.dart';
import 'package:fcs/model/user_model.dart';
@@ -12,10 +14,11 @@ import 'package:fcs/vo/shipping_address.dart';
import 'package:fcs/widget/bottom_up_page_route.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../../../pages/shipping_address_editor.dart';
import '../helpers/theme.dart';
import '../../../../pages/shipping_address_editor.dart';
import '../../helpers/theme.dart';
typedef void ProfileCallback();
@@ -25,6 +28,7 @@ class Profile extends StatefulWidget {
}
class _ProfileState extends State<Profile> {
GlobalKey key = GlobalKey();
bool _isLoading = false;
String selectedLanguage;
TextEditingController bizNameController = new TextEditingController();
@@ -49,173 +53,104 @@ class _ProfileState extends State<Profile> {
@override
Widget build(BuildContext context) {
var languageModel = Provider.of<LanguageModel>(context);
MainModel mainModel = Provider.of<MainModel>(context);
final namebox = Container(
padding: EdgeInsets.only(top: 10, left: 25.0, right: 25.0),
child: Container(
height: 45.0,
child: Row(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(
AppTranslations.of(context).text("profile.name"),
style: languageModel.isEng
? TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.normal)
: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.normal,
fontFamily: "MyanmarUnicode"),
),
),
SizedBox(
width: 30,
),
Container(
child: Center(
child: Text(
mainModel.user == null || mainModel.user.name == null
? ""
: mainModel.user.name,
style:
TextStyle(fontSize: 16.0, fontStyle: FontStyle.normal),
),
),
)
],
),
));
final phonenumberbox = Container(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
height: 45.0,
child: Row(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(
AppTranslations.of(context).text("profile.phone"),
style: languageModel.isEng
? TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.normal)
: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.normal,
fontFamily: "MyanmarUnicode"),
),
),
SizedBox(
width: 27,
),
Container(
child: Center(
child: Text(
mainModel.user == null
? ""
: mainModel.user.phone == null ? '' : mainModel.user.phone,
style: TextStyle(fontSize: 16.0, fontStyle: FontStyle.normal),
),
),
)
],
),
final namebox = DisplayText(
text: mainModel.user.name,
labelText: getLocalString(context, "profile.name"),
iconData: Icons.person,
);
final logoutbutton = Container(
padding: EdgeInsets.only(left: 20.0, right: 24.0),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: Card(
elevation: 23,
child: Container(
height: 45.0,
child: ButtonTheme(
minWidth: 900.0,
height: 100.0,
child: FlatButton.icon(
onPressed: () {
showConfirmDialog(context, "profile.logout.confirm",
() async {
setState(() {
_isLoading = true;
});
await context.read<MainModel>().signout();
Navigator.of(context).pushNamedAndRemoveUntil(
"/welcome", ModalRoute.withName('/welcome'));
Future.delayed(Duration(seconds: 1), () {
if (mounted) {
setState(() {
_isLoading = false;
});
}
});
});
},
label: Text(
AppTranslations.of(context).text("profile.logout"),
style: languageModel.isEng
? TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.normal)
: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.normal,
fontFamily: "MyanmarUnicode")),
icon: Icon(
Icons.exit_to_app,
final phonenumberbox = DisplayText(
text: mainModel.user.phone,
labelText: getLocalString(context, "profile.phone"),
iconData: Icons.phone,
);
final fcsIDBox = Row(
children: [
Expanded(
child: DisplayText(
text: mainModel.user.fcsID,
labelText: getLocalString(context, "customer.fcs.id"),
iconData: Icons.account_circle,
),
),
IconButton(
icon: Icon(Icons.content_copy, color: Colors.grey),
onPressed: () => _copy(
getLocalString(context, "customer.fcs.id"), mainModel.user.fcsID),
)
],
);
final usaShippingAddressBox = Row(
children: [
Expanded(
child: DisplayText(
text: mainModel.setting.usaAddress,
labelText: getLocalString(context, "profile.usa.shipping.address"),
iconData: Icons.location_on,
),
),
)));
IconButton(
icon: Icon(Icons.content_copy, color: Colors.grey),
onPressed: () => _copy(
getLocalString(context, "profile.usa.shipping.address"),
mainModel.setting.usaAddress),
)
],
);
final logoutbutton = fcsButton(
context, getLocalString(context, "profile.logout"),
callack: _logout, iconData: Icons.exit_to_app);
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
key: key,
appBar: AppBar(
centerTitle: true,
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
size: 35,
color: primaryColor,
),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
AppTranslations.of(context).text("profile.title"),
style: TextStyle(color: primaryColor),
),
backgroundColor: primaryColor,
shadowColor: Colors.transparent,
backgroundColor: Colors.white,
actions: <Widget>[],
),
body: Column(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Expanded(
child: ListView(
// padding: EdgeInsets.only(left: 25.0, right: 25.0),
shrinkWrap: true,
children: <Widget>[
Row(
children: <Widget>[
namebox,
Expanded(child: namebox),
Padding(
padding: const EdgeInsets.only(left: 18.0),
child: Icon(Icons.edit, color: primaryColor),
padding: const EdgeInsets.only(right: 0),
child: IconButton(
icon: Icon(Icons.edit, color: Colors.grey),
onPressed: _editName),
)
],
),
mainModel.isCustomer()
? Container()
: getPrivilegeBox(context),
// mainModel.isCustomer()
// ? Container()
// : getPrivilegeBox(context),
phonenumberbox,
fcsIDBox,
usaShippingAddressBox,
// getShippingAddressList(context),
],
),
@@ -225,6 +160,7 @@ class _ProfileState extends State<Profile> {
],
),
),
),
);
}
@@ -347,4 +283,43 @@ class _ProfileState extends State<Profile> {
);
}).toList();
}
_copy(String title, String data) {
Clipboard.setData(ClipboardData(text: data));
_showToast(title);
}
void _showToast(String title) {
final ScaffoldState scaffold = key.currentState;
scaffold.showSnackBar(
SnackBar(
content: Text('copied "$title" data to clipboard'),
backgroundColor: secondaryColor,
duration: Duration(seconds: 1),
),
);
}
_editName() {
Navigator.of(context)
.push<void>(CupertinoPageRoute(builder: (context) => ProfileEdit()));
}
_logout() {
showConfirmDialog(context, "profile.logout.confirm", () async {
setState(() {
_isLoading = true;
});
await context.read<MainModel>().signout();
Navigator.of(context)
.pushNamedAndRemoveUntil("/welcome", ModalRoute.withName('/welcome'));
Future.delayed(Duration(seconds: 1), () {
if (mounted) {
setState(() {
_isLoading = false;
});
}
});
});
}
}

View File

@@ -1,9 +1,7 @@
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/signin/model/signin_model.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import '../../../../widget/local_text.dart';
@@ -107,16 +105,17 @@ class _RequestInvitationPageState extends State<RequestInvitationPage> {
_isLoading = true;
});
try {
await context.read<SigninModel>().requestInvitation(nameCtl.text);
// just signup to request for invitation
await context.read<MainModel>().signup(nameCtl.text);
await showMsgDialog(context, "Successful",
getLocalString(context, "invite.request.successful"));
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
} catch (e) {
await showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
Navigator.pushNamedAndRemoveUntil(context, "/welcome", (r) => false);
}
}
}

View File

@@ -1,22 +0,0 @@
import 'dart:async';
import 'package:fcs/fcs/common/pages/model/base_model.dart';
import 'package:fcs/fcs/common/services/services.dart';
import 'package:logging/logging.dart';
class SigninModel extends BaseModel {
final log = Logger('SigninModel');
Future<bool> checkInvatation() async {
var invited = await request("/check_invitation", "GET",
token: await Services.instance.authService.getToken());
return invited["invited"];
}
Future<void> requestInvitation(String name) async {
await request("/request_invitation", "POST",
payload: {"user_name": name},
token: await Services.instance.authService.getToken());
await Services.instance.authService.signout();
}
}

View File

@@ -0,0 +1,31 @@
import 'package:fcs/fcs/common/domain/entities/setting.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/signin/invitation_request_page.dart';
import 'package:fcs/fcs/common/pages/signin/signup_page.dart';
import 'package:fcs/fcs/common/pages/widgets/bottom_up_page_route.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
navigateAfterAuthVerified(BuildContext context) async {
User user = Provider.of<MainModel>(context, listen: false).user;
Setting setting = Provider.of<MainModel>(context, listen: false).setting;
if (user == null || setting == null) return;
if (user.joined || user.requested) {
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
} else {
if (setting.inviteRequired) {
bool invited =
await Provider.of<MainModel>(context, listen: false).hasInvite();
if (!invited) {
await Navigator.of(context).pushAndRemoveUntil(
BottomUpPageRoute(RequestInvitationPage()), (r) => false);
return;
}
}
await Navigator.of(context)
.pushAndRemoveUntil(BottomUpPageRoute(SignupPage()), (r) => false);
}
}

View File

@@ -1,8 +1,10 @@
import 'package:country_code_picker/country_code_picker.dart';
import 'package:fcs/fcs/common/domain/entities/auth_result.dart';
import 'package:fcs/fcs/common/domain/entities/auth_status.dart';
import 'package:fcs/fcs/common/domain/entities/setting.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/signin/signin_logic.dart';
import 'package:fcs/fcs/common/pages/signin/signup_page.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/widget/bottom_up_page_route.dart';
@@ -179,12 +181,7 @@ class _SigninPageState extends State<SigninPage> {
.push(BottomUpPageRoute(SmsCodePage(phoneNumber: phoneNumber)));
Navigator.pop(context);
} else if (auth.authStatus == AuthStatus.AUTH_VERIFIED) {
User user = context.read<MainModel>().user;
if (user != null && !user.hasSignup) {
await Navigator.of(context).push(BottomUpPageRoute(SignupPage()));
} else {
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
}
await navigateAfterAuthVerified(context);
}
if (auth.authStatus == AuthStatus.ERROR) {
showMsgDialog(context, "Error", auth.authErrorMsg);

View File

@@ -1,4 +1,5 @@
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
@@ -108,7 +109,18 @@ class _SignupPageState extends State<SignupPage> {
}
_submit() async {
setState(() {
_isLoading = true;
});
try {
await context.read<MainModel>().signup(nameCtl.text);
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
}

View File

@@ -2,20 +2,16 @@ import 'dart:async';
import 'package:fcs/fcs/common/domain/entities/auth_result.dart';
import 'package:fcs/fcs/common/domain/entities/auth_status.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart';
import 'package:fcs/fcs/common/pages/signin/model/signin_model.dart';
import 'package:fcs/fcs/common/pages/signin/invitation_request_page.dart';
import 'package:fcs/fcs/common/pages/signin/signin_logic.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/widget/bottom_up_page_route.dart';
import 'package:flutter/material.dart';
import 'package:pin_input_text_field/pin_input_text_field.dart';
import 'package:provider/provider.dart';
import 'signup_page.dart';
import '../../helpers/theme.dart';
import '../../../../widget/progress.dart';
import '../../helpers/theme.dart';
const resend_count_sec = 30;
@@ -202,18 +198,7 @@ class _SmsCodePageState extends State<SmsCodePage> {
AuthResult auth = await context.read<MainModel>().signin(this.pin);
if (auth.authStatus == AuthStatus.AUTH_VERIFIED) {
User user = context.read<MainModel>().user;
if (user != null && !user.hasSignup) {
bool invited = await context.read<SigninModel>().checkInvatation();
if (invited) {
await Navigator.of(context).push(BottomUpPageRoute(SignupPage()));
} else {
await Navigator.of(context)
.push(BottomUpPageRoute(RequestInvitationPage()));
}
} else {
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
}
await navigateAfterAuthVerified(context);
}
} catch (e) {
showMsgDialog(context, "Error", e.toString());

View File

@@ -52,7 +52,7 @@ class _SplashScreenState extends State<SplashScreen> {
if (mainModel.isLoaded) {
if (mainModel.isFirstLaunch) {
page = "/language_selection";
} else if (mainModel.isLogin() && mainModel.user.hasSignup) {
} else if (mainModel.isLogin()) {
page = "/home";
} else {
page = "/welcome";

View File

@@ -0,0 +1,88 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/fcs/common/domain/constants.dart';
import 'package:fcs/fcs/common/domain/entities/role.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/helpers/firebase_helper.dart';
import 'package:fcs/fcs/common/pages/model/base_model.dart';
import 'package:fcs/fcs/common/services/services.dart';
import 'package:logging/logging.dart';
class StaffModel extends BaseModel {
final log = Logger('StaffModel');
List<User> employees = [];
List<Privilege> privileges = [];
void initUser(user) async {
super.initUser(user);
_loadPrivileges();
_loadEmployees();
}
@override
logout() async {
employees = [];
}
Future<void> _loadEmployees() async {
if (user == null || !user.hasStaffs()) return;
try {
Firestore.instance
.collection("/$user_collection")
.where("is_employee", isEqualTo: true)
.where("is_sys_admin", isEqualTo: false)
.snapshots()
.listen((QuerySnapshot snapshot) {
employees.clear();
employees = snapshot.documents.map((documentSnapshot) {
var user =
User.fromMap(documentSnapshot.data, documentSnapshot.documentID);
return user;
}).toList();
notifyListeners();
}).onError((e) {
log.warning("Error! $e");
});
} catch (e) {
log.warning("Error!! $e");
}
}
Future<void> _loadPrivileges() async {
if (user == null || !user.hasStaffs()) return;
try {
Firestore.instance
.collection("/$privilege_collection")
.snapshots()
.listen((QuerySnapshot snapshot) {
privileges.clear();
privileges = snapshot.documents.map((documentSnapshot) {
var privilege = Privilege.fromMap(
documentSnapshot.data, documentSnapshot.documentID);
return privilege;
}).toList();
notifyListeners();
}).onError((e) {
log.warning("Error! $e");
});
} catch (e) {
log.warning("Error!! $e");
}
}
Future<void> updatePrivileges(String userID, List<String> privileges) async {
try {
await request("/employee/privileges", "PUT",
payload: {"id": userID, "privileges": privileges},
token: await getToken());
} catch (e) {
throw Exception(e);
}
}
Future<User> findUser(String phoneNumber) {
return Services.instance.userService.findUser(phoneNumber);
}
}

View File

@@ -0,0 +1,276 @@
import 'package:fcs/fcs/common/domain/entities/role.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:fcs/fcs/common/pages/staff/model/staff_model.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/fcs/common/pages/widgets/display_text.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
typedef void FindCallBack();
class StaffEditor extends StatefulWidget {
final User staff;
const StaffEditor({this.staff});
@override
_StaffEditorState createState() => _StaffEditorState();
}
class _StaffEditorState extends State<StaffEditor> {
TextEditingController _phoneInput = new TextEditingController();
bool _isLoading = false;
User user;
User selectedUser;
List<Privilege> privileges = [];
bool isNew = true;
@override
void initState() {
super.initState();
privileges = Provider.of<StaffModel>(context, listen: false).privileges;
isNew = widget.staff == null;
user = User();
if (!isNew) {
user =
User(name: widget.staff.name, phoneNumber: widget.staff.phoneNumber);
user.privileges = widget.staff.privileges;
privileges.forEach((p) => user.privileges.contains(p.id)
? p.isChecked = true
: p.isChecked = false);
} else {
user.name = "";
user.phoneNumber = "";
privileges.forEach((p) => p.isChecked = false);
}
}
List<Widget> showprivilegeList(BuildContext context) {
return privileges.map((p) {
return new ListTile(
title: InkWell(
onTap: () {
setState(() {
p.isChecked = p.isChecked == null ? true : !p.isChecked;
});
},
child: new Row(
children: <Widget>[
new Checkbox(
value: p.isChecked == null ? false : p.isChecked,
activeColor: primaryColor,
onChanged: (bool value) {
setState(() {
p.isChecked = value;
});
}),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
p.name,
style: TextStyle(
fontSize: 15.0,
),
),
],
),
],
),
));
}).toList();
}
Widget phoneSearchbox(BuildContext context, FindCallBack findCallBack) {
var languageModel = Provider.of<LanguageModel>(context);
return Container(
padding: EdgeInsets.only(bottom: 15, left: 8),
child: Stack(
alignment: const Alignment(1.2, 1.0),
children: <Widget>[
TextFormField(
controller: _phoneInput,
autofocus: false,
cursorColor: primaryColor,
keyboardType: TextInputType.phone,
style: textStyle,
decoration: new InputDecoration(
labelText: AppTranslations.of(context).text('employee.phone'),
labelStyle: languageModel.isEng ? labelStyle : labelStyleMM,
icon: Icon(
Icons.phone,
color: primaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 1.0)),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 1.0)),
),
),
new FlatButton(
onPressed: () {
findCallBack();
},
child: new Icon(
Icons.search,
size: 25,
))
],
));
}
@override
Widget build(BuildContext context) {
final namebox = DisplayText(
text: user.name,
labelText: getLocalString(context, "customer.name"),
iconData: Icons.person,
);
var phoneNumberBox = Row(
children: <Widget>[
Expanded(
child: DisplayText(
text: user.phoneNumber,
labelText: getLocalString(context, "customer.phone"),
iconData: Icons.phone,
)),
IconButton(
icon: Icon(Icons.open_in_new, color: primaryColor),
onPressed: () => call(context, user.phoneNumber)),
],
);
final updateButton = fcsButton(
context,
getLocalString(context, 'staff.update'),
callack: _save,
);
final addButton = fcsButton(
context,
getLocalString(context, 'staff.add'),
callack: _add,
);
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(Icons.close, color: primaryColor, size: 30),
onPressed: () => Navigator.of(context).pop(),
),
shadowColor: Colors.transparent,
backgroundColor: Colors.white,
title: LocalText(
context,
"staff.form.title",
fontSize: 20,
color: primaryColor,
),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
isNew
? phoneSearchbox(context, () => _findUser(context))
: Container(),
phoneNumberBox,
namebox,
Expanded(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
children: showprivilegeList(context),
),
),
Container(
child: isNew ? addButton : updateButton,
),
SizedBox(
height: 10,
)
],
),
),
));
}
_add() async {
if (isNew && selectedUser == null) {
showMsgDialog(context, "Error", "Invalid user!");
return;
}
setState(() {
_isLoading = true;
});
StaffModel staffModel = Provider.of<StaffModel>(context, listen: false);
try {
await staffModel.updatePrivileges(this.selectedUser.id, privilegesIDs());
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
List<String> privilegesIDs() {
return this.privileges.where((p) => p.isChecked).map((p) => p.id).toList();
}
_save() async {
setState(() {
_isLoading = true;
});
if (widget.staff == null) return;
StaffModel staffModel = Provider.of<StaffModel>(context, listen: false);
try {
await staffModel.updatePrivileges(widget.staff.id, privilegesIDs());
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
_findUser(BuildContext context) async {
StaffModel staffModel = Provider.of<StaffModel>(context, listen: false);
setState(() {
_isLoading = true;
});
try {
User _user = await staffModel.findUser(_phoneInput.text);
if (_user == null) {
showMsgDialog(context, "Error", _phoneInput.text + " not found!");
return;
}
this.selectedUser = _user;
this.user = _user;
setState(() {
if (user.privileges != null) {
privileges.forEach((p) => user.privileges.contains(p.id)
? p.isChecked = true
: p.isChecked = false);
}
});
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
}

View File

@@ -0,0 +1,124 @@
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/staff/model/staff_model.dart';
import 'package:fcs/fcs/common/pages/widgets/bottom_up_page_route.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'staff_editor.dart';
class StaffList extends StatefulWidget {
@override
_StaffListState createState() => _StaffListState();
}
class _StaffListState extends State<StaffList> {
var dateFormatter = new DateFormat('dd MMM yyyy - hh:mm:ss a');
final double dotSize = 15.0;
bool _isLoading = false;
@override
Widget build(BuildContext context) {
StaffModel staffModel = Provider.of<StaffModel>(context);
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
title: LocalText(
context,
'staff.list.title',
color: Colors.white,
fontSize: 20,
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context).push(BottomUpPageRoute(StaffEditor()));
},
icon: Icon(Icons.add),
label: Text(AppTranslations.of(context).text("staff.new")),
backgroundColor: primaryColor,
),
body: new ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
scrollDirection: Axis.vertical,
padding: EdgeInsets.only(left: 5, right: 5, top: 5),
shrinkWrap: true,
itemCount: staffModel.employees.length,
itemBuilder: (BuildContext context, int index) {
User user = staffModel.employees[index];
return _item(user);
}),
),
);
}
Widget _item(User user) {
return Stack(
children: <Widget>[
InkWell(
onTap: () {
Navigator.of(context)
.push(BottomUpPageRoute(StaffEditor(staff: user)));
},
child: Row(
children: <Widget>[
Expanded(
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.symmetric(
horizontal: 32.0 - dotSize / 2),
child: Icon(
MaterialCommunityIcons.worker,
color: primaryColor,
size: 40,
),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
user.name,
style: new TextStyle(fontSize: 15.0),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: new Text(
user.phoneNumber,
style: new TextStyle(
fontSize: 15.0, color: Colors.grey),
),
),
],
),
),
],
),
),
),
],
),
),
],
);
}
}

View File

@@ -410,13 +410,18 @@ Widget phoneWidget(BuildContext context, String phone) {
}
Widget fcsInput(String label, IconData iconData,
{TextEditingController controller, String value}) {
{TextEditingController controller,
String value,
bool autoFocus = false,
TextInputType textInputType}) {
return TextFormField(
initialValue: value,
controller: controller,
cursorColor: primaryColor,
maxLines: null,
minLines: 1,
autofocus: autoFocus,
keyboardType: textInputType,
decoration: InputDecoration(
fillColor: Colors.white,
labelText: label,
@@ -553,7 +558,19 @@ Widget _dropDown() {
);
}
Widget fcsButton(BuildContext context, String text, {Function callack}) {
Widget fcsButton(BuildContext context, String text,
{Function callack, IconData iconData}) {
var languageModel = Provider.of<LanguageModel>(context);
var style = languageModel.isEng
? TextStyle(
fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.bold)
: TextStyle(
fontSize: 16.0,
color: Colors.white,
fontWeight: FontWeight.bold,
fontFamily: "Myanmar3");
return Container(
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
child: Container(
@@ -567,12 +584,21 @@ Widget fcsButton(BuildContext context, String text, {Function callack}) {
height: 100.0,
child: FlatButton(
onPressed: callack,
child: Text(text,
style: TextStyle(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
iconData == null
? Container()
: Icon(
iconData,
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
)),
),
SizedBox(
width: 15,
),
Text(text, style: style),
],
),
),
),
),

View File

@@ -13,7 +13,7 @@ import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import '../helpers/theme.dart';
import 'profile_page.dart';
import 'profile/profile_page.dart';
import 'signin/signin_page.dart';
final msgLog = Logger('backgroundMessageHandler');

View File

@@ -0,0 +1,69 @@
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/pages/model/language_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class DisplayText extends StatelessWidget {
final String text;
final String labelText;
final IconData iconData;
final int maxLines;
final bool withBorder;
final Color borderColor;
const DisplayText({
Key key,
this.text,
this.labelText,
this.iconData,
this.maxLines = 1,
this.withBorder = false,
this.borderColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
var languageModel = Provider.of<LanguageModel>(context);
var labelStyle = languageModel.isEng
? TextStyle(
color: Colors.black54,
)
: TextStyle(color: Colors.black54, fontFamily: "Myanmar3");
var textStyle = languageModel.isEng
? TextStyle(
color: primaryColor,
)
: TextStyle(color: primaryColor, fontFamily: "Myanmar3");
return Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
iconData,
color: primaryColor,
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
labelText,
style: labelStyle,
),
Text(
text,
style: textStyle,
),
],
),
),
],
),
);
}
}

View File

@@ -1,5 +1,5 @@
import 'package:fcs/fcs/common/data/providers/auth_fb.dart';
import 'package:fcs/fcs/common/data/providers/user_fb_data_provider.dart';
import 'package:fcs/fcs/common/data/providers/user_data_provider.dart';
import 'package:fcs/fcs/common/data/providers/user_local_data_provider.dart';
import 'package:fcs/fcs/common/domain/entities/auth_result.dart';
import 'package:fcs/fcs/common/domain/entities/connectivity.dart';
@@ -13,12 +13,10 @@ class AuthServiceImp implements AuthService {
AuthServiceImp({
@required this.authFb,
@required this.connectivity,
@required this.userFBDataProvider,
@required this.userLocalDataProvider,
});
final Connectivity connectivity;
final UserFBDataProvider userFBDataProvider;
final UserLocalDataProvider userLocalDataProvider;
final AuthFb authFb;
@@ -61,4 +59,14 @@ class AuthServiceImp implements AuthService {
Future<String> getToken() {
return authFb.getToken();
}
@override
Future<bool> hasInvite() {
return authFb.hasInvite();
}
@override
Future<void> updateProfile(String newUserName) {
return authFb.updateProfile(newUserName);
}
}

View File

@@ -8,6 +8,8 @@ abstract class AuthService {
Future<void> signout();
Future<User> getUser({bool refreshIdToken = false});
Future<User> signup(String userName);
Future<void> updateProfile(String newUserName);
Future<bool> hasInvite();
Stream<Setting> getSetting();
Stream<User> onAuthStatus();
Future<String> getToken();

View File

@@ -1,7 +1,10 @@
import 'package:fcs/fcs/common/data/providers/auth_fb.dart';
import 'package:fcs/fcs/common/data/providers/user_data_provider.dart';
import 'package:fcs/fcs/common/services/auth_imp.dart';
import 'package:fcs/fcs/common/services/messaging_imp.dart';
import 'package:fcs/fcs/common/services/messaging_service.dart';
import 'package:fcs/fcs/common/services/user_imp.dart';
import 'package:fcs/fcs/common/services/user_service.dart';
import 'auth_service.dart';
@@ -9,16 +12,19 @@ class Services {
static final Services instance = Services._();
AuthService _authService;
UserService _userService;
MessagingService _messagingService;
Services._() {
_authService = AuthServiceImp(
authFb: AuthFb.instance,
connectivity: null,
userFBDataProvider: null,
userLocalDataProvider: null);
_userService = UserServiceImp(
connectivity: null, userDataProvider: UserDataProvider());
_messagingService = MessagingServiceImp();
}
AuthService get authService => _authService;
UserService get userService => _userService;
MessagingService get messagingService => _messagingService;
}

View File

@@ -1,33 +1,36 @@
import 'package:fcs/fcs/common/data/providers/user_data_provider.dart';
import 'package:fcs/fcs/common/domain/entities/connectivity.dart';
import 'package:fcs/fcs/common/domain/entities/user.dart';
import 'package:fcs/fcs/common/domain/exceiptions/server_exceptions.dart';
import 'package:flutter/material.dart';
import 'user_interface.dart';
import 'user_service.dart';
class UserImp implements UserInterface {
UserImp({
class UserServiceImp implements UserService {
UserServiceImp({
@required this.connectivity,
@required this.userDataProvider,
});
final Connectivity connectivity;
final UserDataProvider userDataProvider;
@override
Future<User> getUser(String id) async {
if (connectivity.isConnected) {
try {
final User user = User();
// await userFBDataProvider.getUser(id);
// cache product
// productLocalDataProvider.cacheProduct(product);
return user;
} catch (e) {
print(e);
return ServerException()();
Future<void> inviteUser(String userName, String phoneNumber) {
return userDataProvider.inviteUser(userName, phoneNumber);
}
} else {
return Future.value(User());
// return userLocalDataProvider.getUser(id);
@override
Future<void> deleteInvite(String phoneNumber) {
return userDataProvider.deleteInvite(phoneNumber);
}
@override
Future<void> acceptRequest(String userID) {
return userDataProvider.acceptRequest(userID);
}
@override
Future<User> findUser(String phoneNumber) {
return userDataProvider.findUser(phoneNumber);
}
}

View File

@@ -1,5 +0,0 @@
import 'package:fcs/fcs/common/domain/entities/user.dart';
abstract class UserInterface {
Future<User> getUser(String id);
}

View File

@@ -0,0 +1,8 @@
import 'package:fcs/fcs/common/domain/entities/user.dart';
abstract class UserService {
Future<void> inviteUser(String userName, String phoneNumber);
Future<void> deleteInvite(String phoneNumber);
Future<void> acceptRequest(String userID);
Future<User> findUser(String phoneNumber);
}

View File

@@ -245,7 +245,21 @@ packages:
name: firebase_auth
url: "https://pub.dartlang.org"
source: hosted
version: "0.14.0+9"
version: "0.16.1"
firebase_auth_platform_interface:
dependency: transitive
description:
name: firebase_auth_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.8"
firebase_auth_web:
dependency: transitive
description:
name: firebase_auth_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3+1"
firebase_core:
dependency: "direct main"
description:
@@ -328,6 +342,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.5"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.4+4"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
flutter_localizations:
dependency: "direct main"
description: flutter
@@ -709,6 +737,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
share:
dependency: "direct main"
description:
name: share
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.5"
shared_preferences:
dependency: "direct main"
description:

View File

@@ -75,6 +75,7 @@ dependencies:
barcode_scan: ^3.0.1
flutter_pdfview: ^1.0.3
flutter_local_notifications: ^1.4.4+4
share: ^0.6.5