This commit is contained in:
2020-09-11 16:14:36 +06:30
parent f65b69aab0
commit 96a095e2e9
29 changed files with 1370 additions and 837 deletions

Binary file not shown.

View File

@@ -41,6 +41,8 @@
"faq.edit.mm":"Myanmar",
"faq.edit.question":"Question",
"faq.edit.answer":"Answer",
"faq.edit.sn":"S/N",
"faq.edit.delete.confirm":"Delete this FAQ?",

View File

@@ -41,7 +41,8 @@
"faq.edit.mm":"မြန်မာ",
"faq.edit.question":"မေးခွန်း",
"faq.edit.answer":"အဖြေ",
"faq.edit.sn":"S/N",
"faq.edit.delete.confirm":"Delete this FAQ?",
"btn.save":"သိမ်းဆည်းရန်",
"btn.approve":"အတည်ပြုရန်",

View File

@@ -4,6 +4,8 @@ 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';
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/model/language_model.dart';
import 'package:fcs/fcs/common/pages/term/model/term_model.dart';
import 'package:fcs/fcs/common/services/services.dart';
@@ -31,7 +33,6 @@ import 'package:fcs/fcs/common/pages/model/main_model.dart' as fcs;
import 'model/announcement_model.dart';
import 'model/chart_model.dart';
import 'model/customer_model.dart';
import 'model/device_model.dart';
import 'model/do_model.dart';
import 'model/employee_model.dart';
@@ -60,6 +61,7 @@ class _AppState extends State<App> {
final ContactModel contactModel =new ContactModel();
final TermModel termModel=new TermModel();
final MainModel mainModel = new MainModel();
final FAQModel faqModel = new FAQModel();
final UserModel userModel = new UserModel();
final ProductModel productModel = new ProductModel();
@@ -130,7 +132,6 @@ class _AppState extends State<App> {
..addModel(messageModel)
..addModel(shipmentRateModel)
..addModel(invoiceModel)
..addModel(customerModel)
..addModel(discountModel);
this.mainModel.init();
@@ -249,6 +250,7 @@ class _AppState extends State<App> {
ChangeNotifierProvider.value(value: mainModel2),
ChangeNotifierProvider.value(value: contactModel),
ChangeNotifierProvider.value(value: termModel),
ChangeNotifierProvider.value(value: faqModel),
],
child: Consumer<LanguageModel>(
builder: (context, value, child) {

View File

@@ -109,6 +109,13 @@ class AuthFb {
user.hasSignup =
idToken.claims.containsKey("signup") && idToken.claims["signup"];
user.phoneNumber = firebaseUser.phoneNumber;
// add privileges
String privileges = idToken.claims["privileges"];
if (privileges != null && privileges != "") {
user.privileges = privileges.split(":").toList();
}
return user;
}

View File

@@ -0,0 +1,36 @@
class Customer {
String id;
String name;
String phoneNumber;
String status;
Customer({
this.id,
this.name,
this.status,
this.phoneNumber,
});
factory Customer.fromMap(Map<String, dynamic> map, String docID) {
return Customer(
id: docID,
name: map['user_name'],
phoneNumber: map['phone_number'],
status: map['status'],
);
}
Map<String, dynamic> toMap() {
return {
'user_name': name,
'phone_number': phoneNumber,
};
}
@override
String toString() {
return 'Customer{name: $name, phoneNumber: $phoneNumber,statis:$status}';
}
}

View File

@@ -1,27 +1,48 @@
class FAQ {
String id;
int sn;
String questionEng;
String questionMm;
String answerEng;
String answerMm;
String question(bool isEng) => isEng?questionEng:questionMm;
String answer(bool isEng) => isEng?answerEng:answerMm;
Map<String, String> images;
FAQ({this.id,this.questionEng,this.questionMm,this.answerEng,this.answerMm,this.images});
String question(bool isEng) => isEng ? questionEng : questionMm;
String answer(bool isEng) => isEng ? answerEng : answerMm;
Map<String, String> imageUrls;
FAQ(
{this.id,
this.sn,
this.questionEng,
this.questionMm,
this.answerEng,
this.answerMm,
this.imageUrls});
Map<String, dynamic> toMap() {
return {
'id': id,
'sn':sn,
'question_eng': questionEng,
'answer_eng': answerEng,
'question_mm': questionMm,
'answer_mm': answerMm,
'images': images,
'images': imageUrls,
};
}
factory FAQ.fromMap(Map<String, dynamic> map, String id) {
return FAQ(
id: id,
sn: map['sn'],
questionEng: map['question_eng'],
answerEng: map['answer_eng'],
questionMm: map['question_mm'],
answerMm: map['answer_mm'],
imageUrls: Map.from(map['images'] ?? Map<String, String>()),
);
}
@override
String toString() {
return 'FAQ{id: $id, questionEng: $questionEng,questionMm:$questionMm}';

View File

@@ -0,0 +1,72 @@
class Role {
String roleID;
String roleName;
String privileges;
Role({this.roleName, this.roleID, this.privileges});
Role.fromJson(Map<String, dynamic> json) {
roleName = json['role_name'];
roleID = json['role_id'];
privileges = json['privileges'];
}
}
class Parser {
String status;
String message;
Role data;
Parser({this.status, this.message, this.data});
Parser.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
if (json['status'] == 'Ok') {
data = Role.fromJson(json['data']);
}
}
}
class StatusParser {
String status;
String message;
StatusParser(this.status, this.message);
StatusParser.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
}
}
class Privilege {
String id;
String name;
String desc;
bool sysAdminOnly = true;
bool isChecked = false;
Privilege({this.id, this.name, this.desc, this.isChecked, this.sysAdminOnly});
factory Privilege.fromMap(Map<String, dynamic> map, String docID) {
return Privilege(
id: docID,
name: map['name'],
desc: map['desc'],
sysAdminOnly: map['sys_admin_only']);
}
}
class UserLevel {
String id;
String name;
int level;
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']
);
}
}

View File

@@ -1,283 +1,70 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class User {
String id;
String name;
String phoneNumber;
bool hasSignup;
List<String> privileges = [];
String fcsID;
String shippingAddress;
String deliveryAddress;
String get phone => phoneNumber != null && phoneNumber.startsWith("959")
? "0${phoneNumber.substring(2)}"
: phoneNumber;
List<String> claimPrivileges = [];
final String dateofBirth;
final String gender;
final String status;
final bool disable;
bool registeredBuyer;
List<String> privilegeIds;
String roleName;
String roleID;
bool agreeTerms;
String bizID;
String accountID;
String email;
bool isBlock;
int userLevel;
String userLevelID;
String frontUrl;
String backUrl;
String selfieUrl;
DateTime lastActiveTime;
String device;
String primaryDeviceID;
String primaryDeviceName;
String pin;
String get getname => this.name;
String get getphonenumber => this.phoneNumber;
String get getdateofBirth => this.dateofBirth;
bool get getdisable => this.disable;
Future<void> setFirebaseUser(FirebaseUser firebaseUser) async {
IdTokenResult idToken = await firebaseUser.getIdToken(refresh: true);
String privileges = idToken.claims["privileges"];
if (privileges == null || privileges == "") return;
this.claimPrivileges = privileges.split(":").toList();
this.accountID = idToken.claims["account_id"];
this.bizID = idToken.claims["biz_id"];
}
User(
{this.id,
this.name,
this.gender,
this.phoneNumber,
this.fcsID,
this.shippingAddress,
this.deliveryAddress,
this.dateofBirth,
this.roleName,
this.roleID,
this.privilegeIds,
this.email,
this.disable,
this.status,
this.frontUrl,
this.backUrl,
this.selfieUrl,
this.registeredBuyer,
this.agreeTerms,
this.lastActiveTime,
this.device,
this.primaryDeviceID,
this.primaryDeviceName,
this.isBlock,
this.userLevel,
this.userLevelID,
this.pin});
User({
this.id,
this.name,
this.phoneNumber,
this.fcsID,
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['user_name'],
phoneNumber: json['phone_number'],
dateofBirth: json['dob'],
gender: json['gender'],
frontUrl: json['front_url'],
backUrl: json['back_url'],
selfieUrl: json['selfie_url'],
status: json['status'],
agreeTerms: json['agree_terms'],
disable: json['disable'],
registeredBuyer: json['registered_buyer'],
privilegeIds: json['privileges'],
email: json['email'],
isBlock: json['black_list'],
userLevel: json['user_level'],
userLevelID: json['user_level_id'],
pin: json['pin']);
}
factory User.fromUserJson(Map<String, dynamic> json) {
DateTime parsedDate = DateTime.parse(json['last_active_time']);
return User(
id: json['id'],
name: json['user_name'],
phoneNumber: json['phone_number'],
dateofBirth: json['dob'],
roleName: json['role_name'],
roleID: json['role_id'],
disable: json['disable'],
gender: json['gender'],
status: json['status'],
lastActiveTime: parsedDate == null ? null : parsedDate,
device: json['last_active_device'],
email: json['email'],
primaryDeviceID: json['primary_device_id'],
primaryDeviceName: json['primary_device_name'],
userLevel: json['user_level'],
userLevelID: json['user_level_id'],
pin: json['pin']);
id: json['id'],
name: json['user_name'],
phoneNumber: json['phone_number'],
);
}
Map<String, dynamic> toJson() => {
'id': id,
'user_name': name,
'gender': gender,
'phone_number': phoneNumber,
'dob': dateofBirth,
'roleName': roleName,
'roleId': roleID,
'disable': disable,
'status': status,
'registered_buyer': registeredBuyer,
'agree_terms': agreeTerms,
'front_url': frontUrl,
'back_url': backUrl,
'selfie_url': selfieUrl,
'email': email,
'black_list': isBlock,
'user_level': userLevel,
'user_level_id': userLevelID,
'pin': pin,
'privileges': privilegeIds,
};
Map<String, dynamic> toMap() {
return {
'user_name': name,
'phone_number': phoneNumber,
'dob': dateofBirth,
'role_name': roleName,
'role_id': roleID,
'disable': disable,
'gender': gender,
'status': status,
'email': email,
'black_list': isBlock,
'user_level': userLevel,
'user_level_id': userLevelID,
'pin': pin
};
}
factory User.fromMap(Map<String, dynamic> map, String docID) {
var activeTime = (map['last_active_time'] as Timestamp);
return User(
id: docID,
name: map['user_name'],
phoneNumber: map['phone_number'],
privilegeIds:
map['privileges'] == null ? [] : map['privileges'].cast<String>(),
dateofBirth: map['dob'],
roleName: map['role_name'],
roleID: map['role_id'],
disable: map['disable'],
gender: map['gender'],
status: map['status'],
registeredBuyer: map['registered_buyer'],
agreeTerms: map['agree_terms'] == null ? false : map['agree_terms'],
lastActiveTime: activeTime == null ? null : activeTime.toDate(),
device: map['last_active_device'],
email: map['email'],
primaryDeviceID: map['primary_device_id'],
primaryDeviceName: map['primary_device_name'],
isBlock: map['black_list'],
userLevel: map['user_level'],
userLevelID: map['user_level_id'],
pin: map['pin']);
id: docID,
name: map['user_name'],
phoneNumber: map['phone_number'],
);
}
bool isBlockUser() {
return this.isBlock == true;
bool isCustomer() {
return privileges == null || privileges.length == 0;
}
bool isPrimaryDevice() {
return this.primaryDeviceID != null && this.primaryDeviceID != '';
}
bool isRegisteredBuyer() {
return this.registeredBuyer != null && this.registeredBuyer;
}
bool isSysAdmin() {
return claimPrivileges != null
? claimPrivileges.contains('sys_admin')
: false;
}
bool isSysSupport() {
return claimPrivileges != null
? claimPrivileges.contains('sys_support')
: false;
}
bool isBizAdmin() {
return claimPrivileges != null ? claimPrivileges.contains('ba') : false;
}
bool isBuyer() {
return claimPrivileges == null || claimPrivileges.length == 0;
}
bool isEmail() {
return email != null;
}
bool hasAccount() {
return isOwner() ||
(claimPrivileges != null ? claimPrivileges.contains('a') : false);
}
bool hasDelivery() {
return isOwner() ||
(claimPrivileges != null ? claimPrivileges.contains('d') : false);
}
bool hasBuyer() {
return isOwner() ||
(claimPrivileges != null ? claimPrivileges.contains('b') : false);
}
bool isOwner() {
return claimPrivileges != null ? claimPrivileges.contains('o') : false;
}
bool isOwnerAndAbove() {
return isOwner() || isBizAdmin() || isSysAdmin();
bool hasSysAdmin() {
return privileges != null ? privileges.contains('sa') : false;
}
bool hasAdmin() {
return isOwner() ||
(claimPrivileges != null ? claimPrivileges.contains('admin') : false);
return privileges != null ? privileges.contains('admin') : false;
}
bool hasDO() {
return isOwner() ||
(claimPrivileges != null ? claimPrivileges.contains('do') : false);
bool hasMaintenance() {
return privileges != null ? privileges.contains('mt') : false;
}
bool hasPO() {
return isOwner() ||
(claimPrivileges != null ? claimPrivileges.contains('po') : false);
}
bool hasInventory() {
return isOwner() ||
(claimPrivileges != null ? claimPrivileges.contains('inv') : false);
bool hasCustomers() {
return privileges != null ? privileges.contains('c') : false;
}
@override

View File

@@ -16,12 +16,13 @@ const TextStyle labelStyleMM = TextStyle(
fontSize: 20,
color: primaryColor,
fontWeight: FontWeight.w500,
fontFamily: "MyanmarUnicode");
height: 1,
fontFamily: "Myanmar3");
const TextStyle subMenuStyle =
TextStyle(fontSize: 14, color: Colors.white, fontWeight: FontWeight.w500);
const TextStyle subMenuStyleMM =
TextStyle(fontSize: 14, color: Colors.white, fontWeight: FontWeight.w500,
fontFamily: "MyanmarUnicode");
fontFamily: "Myanmar3");
const TextStyle welcomeLabelStyle =
TextStyle(fontSize: 23, color: primaryColor, fontWeight: FontWeight.w500);
@@ -53,13 +54,13 @@ TextStyle newLabelStyleMM(
color: color == null ? secondaryColor : color,
fontWeight: fontWeight == null ? FontWeight.w500 : fontWeight,
decoration: underline ? TextDecoration.underline : TextDecoration.none,
fontFamily: "MyanmarUnicode");
fontFamily: "Myanmar3");
}
const TextStyle photoLabelStyle =
TextStyle(color: Colors.black, fontSize: 13.0);
const TextStyle photoLabelStyleMM = TextStyle(
color: Colors.black, fontSize: 13.0, fontFamily: "MyanmarUnicode");
color: Colors.black, fontSize: 13.0, fontFamily: "Myanmar3");
const TextStyle textStyle =
TextStyle(fontSize: 14, color: Colors.black87, fontWeight: FontWeight.w500);
const TextStyle textStyleOdd = TextStyle(

View File

@@ -75,68 +75,64 @@ class _ContactEditorState extends State<ContactEditor> {
return LocalProgress(
inAsyncCall: _isLoading,
child: CupertinoPageScaffold(
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(
AppTranslations.of(context)
.text('contact.edit.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions: [
IconButton(
onPressed: () => _submit(),
icon: Icon(
Icons.save,
color: Colors.white,
))
],
),
];
},
body: Material(
child: Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
children: <Widget>[
itemTitle(context, "contact.callus"),
usaPhoneBox,
mmPhoneBox,
Divider(),
itemTitle(context, "contact.findus"),
usaAddreesBox,
mmAddressBox,
Divider(),
itemTitle(context, "contact.emailus"),
emailBox,
Divider(),
itemTitle(context, "contact.visitus"),
faceBookBox
],
),
child: Scaffold(
body: CustomScrollView(slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title:
Text(AppTranslations.of(context).text('contact.edit.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions: [
IconButton(
onPressed: () => _submit(),
icon: Icon(
Icons.save,
color: Colors.white,
))
],
),
SliverList(
delegate: SliverChildListDelegate([
Padding(
padding: const EdgeInsets.only(left:18.0,right:18),
child: Column(
children: [
itemTitle(context, "contact.callus"),
usaPhoneBox,
mmPhoneBox,
Divider(),
itemTitle(context, "contact.findus"),
usaAddreesBox,
mmAddressBox,
Divider(),
itemTitle(context, "contact.emailus"),
emailBox,
Divider(),
itemTitle(context, "contact.visitus"),
faceBookBox
],
),
))));
),
]),
)
]),
));
}
_submit() async {

View File

@@ -22,93 +22,92 @@ class _ContactPageState extends State<ContactPage> {
@override
Widget build(BuildContext context) {
Setting setting = Provider.of<MainModel>(context).setting;
bool isEditable = context.select((MainModel m) => m.contactEditable());
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(AppTranslations.of(context).text('contact.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions: [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => ContactEditor(
contact: Contact.fromSetting(setting),
),
)),
icon: Icon(
CupertinoIcons.pen,
color: Colors.white,
))
],
body: CustomScrollView(slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
];
},
body: ListView(
children: <Widget>[
itemTitle(context, "contact.callus"),
contactItem(context, setting.usaContactNumber, CupertinoIcons.phone,
onTap: () => _call(setting.usaContactNumber),
labelKey: "contact.usa.phone"),
contactItem(
context,
setting.mmContactNumber,
CupertinoIcons.phone,
onTap: () => _call(
setting.mmContactNumber,
),
labelKey: "contact.mm.phone",
),
itemTitle(context, "contact.findus"),
contactItem(
context,
setting.usaAddress,
CupertinoIcons.location,
labelKey: "contact.usa.address",
),
contactItem(
context,
setting.mmAddress,
CupertinoIcons.location,
labelKey: "contact.mm.address",
),
itemTitle(context, "contact.emailus"),
contactItem(
context,
setting.emailAddress,
CupertinoIcons.mail,
onTap: () => _email(setting.emailAddress),
labelKey: "contact.fcs.email",
),
itemTitle(context, "contact.visitus"),
contactItem(
context,
setting.facebookLink,
FontAwesomeIcons.facebook,
onTap: () => _opencontactItem(setting.facebookLink),
labelKey: "contact.facebook",
),
],
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(AppTranslations.of(context).text('contact.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions: isEditable
? [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => ContactEditor(
contact: Contact.fromSetting(setting),
),
)),
icon: Icon(
CupertinoIcons.pen,
color: Colors.white,
))
]
: [],
),
),
SliverList(
delegate: SliverChildListDelegate([
itemTitle(context, "contact.callus"),
contactItem(context, setting.usaContactNumber, CupertinoIcons.phone,
onTap: () => _call(setting.usaContactNumber),
labelKey: "contact.usa.phone"),
contactItem(
context,
setting.mmContactNumber,
CupertinoIcons.phone,
onTap: () => _call(
setting.mmContactNumber,
),
labelKey: "contact.mm.phone",
),
itemTitle(context, "contact.findus"),
contactItem(
context,
setting.usaAddress,
CupertinoIcons.location,
labelKey: "contact.usa.address",
),
contactItem(
context,
setting.mmAddress,
CupertinoIcons.location,
labelKey: "contact.mm.address",
),
itemTitle(context, "contact.emailus"),
contactItem(
context,
setting.emailAddress,
CupertinoIcons.mail,
onTap: () => _email(setting.emailAddress),
labelKey: "contact.fcs.email",
),
itemTitle(context, "contact.visitus"),
contactItem(
context,
setting.facebookLink,
FontAwesomeIcons.facebook,
onTap: () => _opencontactItem(setting.facebookLink),
labelKey: "contact.facebook",
),
]))
]),
);
}

View File

@@ -0,0 +1,363 @@
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/pages/util.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;
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,
),
),
),
],
);
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: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
title: LocalText(
context,
"customer.form.title",
fontSize: 20,
color: Colors.white,
),
// 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),
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,
)
],
),
));
}
_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 {
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;
// });
// }
}
_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

@@ -0,0 +1,142 @@
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/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: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';
class CustomerList extends StatefulWidget {
@override
_CustomerListState createState() => _CustomerListState();
}
class _CustomerListState extends State<CustomerList> {
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>[
IconButton(
icon: Icon(
Icons.search,
color: Colors.white,
),
iconSize: 30,
onPressed: () => {},
),
],
backgroundColor: primaryColor,
title: LocalText(
context,
'customer.list.title',
color: Colors.white,
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: 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.customers.length,
itemBuilder: (BuildContext context, int index) {
Customer customer = customerModel.customers[index];
return Stack(
children: <Widget>[
InkWell(
onTap: () {
Navigator.of(context).push(
BottomUpPageRoute(CustomerEditor(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),
),
),
],
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: getStatus(customer.status),
),
],
),
),
],
);
}),
),
);
}
}

View File

@@ -0,0 +1,67 @@
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

@@ -0,0 +1,66 @@
import 'package:fcs/fcs/common/domain/entities/customer.dart';
import 'package:fcs/fcs/common/pages/model/base_model.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'),
];
void initUser(user) async {
super.initUser(user);
// _loadCustomer();
}
@override
logout() async {
customers = [];
}
// Future<void> _loadCustomer() async {
// if (!user.isOwnerAndAbove() && !user.hasAccount()) {
// return;
// }
// 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> 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);
// }
// }
}

View File

@@ -1,84 +1,95 @@
import 'package:fcs/fcs/common/domain/entities/faq.dart';
import 'package:fcs/fcs/common/domain/entities/setting.dart';
import 'package:fcs/fcs/common/domain/vo/contact.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/contact/contact_editor.dart';
import 'package:fcs/fcs/common/pages/faq/faq_edit_page.dart';
import 'package:fcs/fcs/common/pages/faq/model/faq_model.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/util.dart';
import 'package:fcs/fcs/common/pages/widgets/local_text.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';
class FAQDetailPage extends StatelessWidget {
class FAQDetailPage extends StatefulWidget {
final FAQ faq;
const FAQDetailPage({this.faq});
@override
_FAQDetailPageState createState() => _FAQDetailPageState();
}
const FAQDetailPage({Key key, this.faq}) : super(key: key);
class _FAQDetailPageState extends State<FAQDetailPage> {
bool _isLoading = false;
@override
Widget build(BuildContext context) {
Setting setting = Provider.of<MainModel>(context).setting;
return Scaffold(
body: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(AppTranslations.of(context).text('faq.btn'),
style: TextStyle(
color: Colors.white,
)),
),
actions: [
bool isEditable = context.select((MainModel m) => m.faqEditable());
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
body: CustomScrollView(slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
color: primaryColor,
size: 50,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: Colors.white,
expandedHeight: 100.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
),
actions: isEditable
? [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => ContactEditor(
contact: Contact.fromSetting(setting),
),
)),
onPressed: () {
showConfirmDialog(context, "faq.edit.delete.confirm",
() {
_delete();
});
},
icon: Icon(
CupertinoIcons.delete,
color: Colors.white,
color: primaryColor,
size: 30,
)),
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => ContactEditor(
contact: Contact.fromSetting(setting),
),
builder: (context) => FAQEditor(faq: widget.faq),
)),
icon: Icon(
CupertinoIcons.pen,
color: Colors.white,
color: primaryColor,
))
],
),
];
},
body: Padding(
padding: const EdgeInsets.only(left:20.0,right:20),
child: ListView(
children: [getQuestion(context, faq),
SizedBox(height: 30,),
getAnwser(context, faq)],
]
: [],
),
SliverList(
delegate: SliverChildListDelegate([
Padding(
padding: const EdgeInsets.all(28.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
getQuestion(context, widget.faq),
SizedBox(
height: 50,
),
getAnwser(context, widget.faq)
],
),
)));
),
]))
]),
),
);
}
Widget getQuestion(BuildContext context, FAQ faq) {
@@ -91,7 +102,6 @@ class FAQDetailPage extends StatelessWidget {
);
}
Widget getAnwser(BuildContext context, FAQ faq) {
bool isEng = Provider.of<LanguageModel>(context).isEng;
return TextLocalStyle(
@@ -102,4 +112,20 @@ class FAQDetailPage extends StatelessWidget {
);
}
_delete() async {
setState(() {
_isLoading = true;
});
try {
FAQModel faqModel = Provider.of<FAQModel>(context, listen: false);
await faqModel.deleteFAQ(widget.faq);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
}

View File

@@ -1,6 +1,7 @@
import 'package:fcs/fcs/common/domain/entities/faq.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/faq/model/faq_model.dart';
import 'package:fcs/fcs/common/pages/faq/widgets.dart';
import 'package:fcs/fcs/common/pages/util.dart';
import 'package:fcs/fcs/common/pages/widgets/input_text.dart';
@@ -8,6 +9,7 @@ import 'package:fcs/fcs/common/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:provider/provider.dart';
class FAQEditor extends StatefulWidget {
final FAQ faq;
@@ -17,6 +19,7 @@ class FAQEditor extends StatefulWidget {
}
class _FAQEditorState extends State<FAQEditor> {
TextEditingController _sn = new TextEditingController();
TextEditingController _engQ = new TextEditingController();
TextEditingController _mmQ = new TextEditingController();
TextEditingController _engA = new TextEditingController();
@@ -25,12 +28,12 @@ class _FAQEditorState extends State<FAQEditor> {
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
bool _isNew = false;
@override
void initState() {
super.initState();
_isNew = widget.faq == null;
if (widget.faq != null) {
_sn.text = widget.faq.sn.toString();
_engQ.text = widget.faq.questionEng;
_mmQ.text = widget.faq.questionMm;
_engA.text = widget.faq.answerEng;
@@ -40,22 +43,29 @@ class _FAQEditorState extends State<FAQEditor> {
@override
Widget build(BuildContext context) {
final usaPhoneBox = InputText(
final snBox = InputText(
controller: _sn,
maxLines: 1,
withBorder: true,
textInputType: TextInputType.number,
);
final questionEngBox = InputText(
controller: _engQ,
maxLines: 2,
withBorder: true,
);
final mmPhoneBox = InputText(
controller: _mmQ,
final answerEngBox = InputText(
controller: _engA,
maxLines: 5,
withBorder: true,
);
final usaAddreesBox = InputText(
controller: _engA,
final questionMmBox = InputText(
controller: _mmQ,
maxLines: 2,
withBorder: true,
);
final mmAddressBox = InputText(
final answerMmBox = InputText(
controller: _mmA,
maxLines: 5,
withBorder: true,
@@ -63,76 +73,101 @@ class _FAQEditorState extends State<FAQEditor> {
return LocalProgress(
inAsyncCall: _isLoading,
child: CupertinoPageScaffold(
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
child: Scaffold(
body: CustomScrollView(slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(
AppTranslations.of(context)
.text(_isNew ? 'faq.add.title' : 'faq.edit.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions: [
IconButton(
onPressed: () => _save(),
icon: Icon(
Icons.save,
color: Colors.white,
))
],
),
SliverList(
delegate: SliverChildListDelegate([
Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
children: <Widget>[
Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 18.0, left: 0),
child: subItemTitle(context, "faq.edit.sn"),
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(
AppTranslations.of(context)
.text(_isNew?'faq.add.title':'faq.edit.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions: [
IconButton(
onPressed: () => _submit(),
icon: Icon(
Icons.save,
color: Colors.white,
))
Expanded(child: snBox),
],
),
];
},
body: Material(
child: Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
children: <Widget>[
Center(child: itemTitle(context, "faq.edit.eng")),
subItemTitle(context, "faq.edit.question",iconData: SimpleLineIcons.question),
usaPhoneBox,
subItemTitle(context, "faq.edit.answer",iconData: MaterialCommunityIcons.message_reply_text),
mmPhoneBox,
Divider(),
Center(child: itemTitle(context, "faq.edit.mm")),
subItemTitle(context, "faq.edit.question",iconData: SimpleLineIcons.question),
usaAddreesBox,
subItemTitle(context, "faq.edit.answer",iconData: MaterialCommunityIcons.message_reply_text),
mmAddressBox,
],
),
),
))));
Center(child: itemTitle(context, "faq.edit.eng")),
subItemTitle(context, "faq.edit.question",
iconData: SimpleLineIcons.question),
questionEngBox,
subItemTitle(context, "faq.edit.answer",
iconData: MaterialCommunityIcons.message_reply_text),
answerEngBox,
Divider(),
Center(child: itemTitle(context, "faq.edit.mm")),
subItemTitle(context, "faq.edit.question",
iconData: SimpleLineIcons.question),
questionMmBox,
subItemTitle(context, "faq.edit.answer",
iconData: MaterialCommunityIcons.message_reply_text),
answerMmBox,
],
),
),
),
]))
])));
}
_submit() async {
_save() async {
setState(() {
_isLoading = true;
});
try {
widget.faq.questionEng = _engQ.text;
// var contactModel = Provider.of<ContactModel>(context, listen: false);
// await contactModel.saveContact(widget.contact);
int sn = int.parse(
_sn.text,
onError: (source) => throw Exception("Invalid number"),
);
FAQModel faqModel = Provider.of<FAQModel>(context, listen: false);
FAQ _faq = FAQ(
sn: sn,
questionEng: _engQ.text,
answerEng: _engA.text,
questionMm: _mmQ.text,
answerMm: _mmA.text);
if (_isNew) {
await faqModel.addFAQ(_faq);
} else {
_faq.id = widget.faq.id;
await faqModel.updateFAQ(_faq);
}
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());

View File

@@ -1,22 +1,16 @@
import 'package:fcs/fcs/common/domain/entities/faq.dart';
import 'package:fcs/fcs/common/domain/entities/setting.dart';
import 'package:fcs/fcs/common/domain/vo/contact.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/fcs/common/localization/app_translations.dart';
import 'package:fcs/fcs/common/pages/contact/contact_editor.dart';
import 'package:fcs/fcs/common/pages/contact/widgets.dart';
import 'package:fcs/fcs/common/pages/faq/faq_detail_page.dart';
import 'package:fcs/fcs/common/pages/faq/faq_edit_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/widgets/local_text.dart';
import 'package:fcs/widget/local_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:package_info/package_info.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'model/faq_model.dart';
class FAQPage extends StatefulWidget {
@override
@@ -24,132 +18,62 @@ class FAQPage extends StatefulWidget {
}
class _FAQPageState extends State<FAQPage> {
List<FAQ> faqs = [];
@override
void initState() {
super.initState();
faqs = [
FAQ(questionEng: "Question 1?", answerEng: "Answer 1."),
FAQ(questionEng: "Question 2?", answerEng: "Answer 2."),
FAQ(questionEng: "Question 3?", answerEng: "Answer 3."),
FAQ(questionEng: "Question 4?", answerEng: "Answer 4."),
FAQ(questionEng: "Question 5?", answerEng: "Answer 5.")
];
}
@override
Widget build(BuildContext context) {
FAQModel faqModel = Provider.of<FAQModel>(context);
bool isEditable = context.select((MainModel m) => m.faqEditable());
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(AppTranslations.of(context).text('faq.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions: [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => FAQEditor(),
)),
icon: Icon(
CupertinoIcons.add,
color: Colors.white,
size: 35,
))
],
),
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(AppTranslations.of(context).text('faq.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions:isEditable? [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => FAQEditor(),
)),
icon: Icon(
CupertinoIcons.add,
color: Colors.white,
size: 35,
))
]:[],
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => _faqItem(context, faqs[index]),
childCount: faqs.length,
),
)
// SliverFillRemaining(
// child: Padding(
// padding: const EdgeInsets.only(left: 18.0, right: 18),
// child: ListView.separated (
// separatorBuilder: (_, i) => Divider(),
// itemCount: faqs.length,
// itemBuilder: (BuildContext ctxt, int index) {
// return _faqItem(context, faqs[index]);
// }),
// )),
delegate: SliverChildBuilderDelegate(
(context, index) => _faqItem(context, faqModel.faqs[index]),
childCount: faqModel.faqs.length,
),
)
],
));
}
@override
Widget build1(BuildContext context) {
Setting setting = Provider.of<MainModel>(context).setting;
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
leading: IconButton(
icon: Icon(
CupertinoIcons.back,
size: 30,
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
titlePadding: EdgeInsets.symmetric(vertical: 10),
title: Text(AppTranslations.of(context).text('faq.title'),
style: TextStyle(
color: Colors.white,
)),
),
actions: [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => FAQEditor(),
)),
icon: Icon(
CupertinoIcons.add,
color: Colors.white,
size: 35,
))
],
),
];
},
body: Padding(
padding: const EdgeInsets.only(left: 18.0, right: 18),
child: ListView.separated(
separatorBuilder: (_, i) => Divider(),
itemCount: faqs.length,
itemBuilder: (BuildContext ctxt, int index) {
return _faqItem(context, faqs[index]);
}),
)),
);
}
Widget _faqItem(BuildContext context, FAQ faq) {
bool isEng = Provider.of<LanguageModel>(context).isEng;
return Column(
@@ -167,16 +91,21 @@ class _FAQPageState extends State<FAQPage> {
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextLocalStyle(
context,
faq.question(isEng),
fontSize: 16,
Flexible(
child: TextLocalStyle(
context,
faq.question(isEng),
fontSize: 18,
),
),
Spacer(),
Icon(
CupertinoIcons.right_chevron,
color: primaryColor,
size: 22,
// Spacer(),
Padding(
padding: const EdgeInsets.only(left:18.0),
child: Icon(
CupertinoIcons.right_chevron,
color: primaryColor,
size: 22,
),
)
],
)),

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/fcs/common/domain/entities/faq.dart';
import 'package:fcs/fcs/common/pages/model/base_model.dart';
import 'package:fcs/fcs/common/services/services.dart';
@@ -8,10 +9,45 @@ import 'package:logging/logging.dart';
class FAQModel extends BaseModel {
final log = Logger('FAQModel');
List<FAQ> faqs = [];
StreamSubscription<QuerySnapshot> listener;
FAQModel() {
Stream<QuerySnapshot> query = Firestore.instance
.collection("/faqs")
.orderBy("sn", descending: false)
.snapshots();
if (listener != null) {
listener.cancel();
}
listener = query.listen((snaps) {
faqs.clear();
snaps.documents.forEach((d) {
faqs.add(FAQ.fromMap(d.data, d.documentID));
});
notifyListeners();
});
}
Future<void> addFAQ(FAQ faq) async {
await request("/faq", "POST",
payload: faq.toMap(), token: await Services.instance.authService.getToken());
await request("/faqs", "POST",
payload: faq.toMap(),
token: await Services.instance.authService.getToken());
notifyListeners();
}
Future<void> updateFAQ(FAQ faq) async {
await request("/faqs", "PUT",
payload: faq.toMap(),
token: await Services.instance.authService.getToken());
notifyListeners();
}
Future<void> deleteFAQ(FAQ faq) async {
await request("/faqs", "DELETE",
payload: faq.toMap(),
token: await Services.instance.authService.getToken());
notifyListeners();
}
}

View File

@@ -1,4 +1,5 @@
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/model/language_model.dart';
import 'package:fcs/fcs/common/pages/model/main_model.dart';
@@ -25,7 +26,6 @@ import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import '../../../pages/buying_online.dart';
import '../../../pages/customer_list.dart';
import '../../../pages/fcs_profile_page.dart';
import '../../../pages/invoice/invoce_list.dart';
import '../../../pages/pickup_list.dart';
@@ -71,7 +71,7 @@ class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
login = Provider.of<MainModel>(context).isLogin();
var owner = Provider.of<MainModel>(context).isOwner();
// var owner =true;// Provider.of<MainModel>(context).isOwner();
var customer = Provider.of<MainModel>(context).isCustomer();
LanguageModel languageModel = Provider.of<LanguageModel>(context);
@@ -169,20 +169,20 @@ class _HomePageState extends State<HomePage> {
List<Widget> widgets = [];
widgets.add(faqBtn);
customer ? widgets.add(buyingBtn) : "";
customer || owner ? widgets.add(pickUpBtn) : "";
owner ? widgets.add(shipmentBtn) : "";
customer || owner ? widgets.add(notiBtn) : "";
owner ? widgets.add(staffBtn) : "";
owner ? widgets.add(fcsProfileBtn) : "";
widgets.add(shipmentCostBtn);
customer || owner ? widgets.add(packagesBtn) : "";
owner ? widgets.add(boxesBtn) : "";
owner ? widgets.add(deliveryBtn) : "";
owner ? widgets.add(customersBtn) : "";
customer || owner ? widgets.add(invoicesBtn) : "";
owner ? widgets.add(paymentMethodBtn) : "";
owner ? widgets.add(discountBtn) : "";
// customer ? widgets.add(buyingBtn) : "";
// customer || owner ? widgets.add(pickUpBtn) : "";
!customer ? widgets.add(shipmentBtn) : "";
// customer || owner ? widgets.add(notiBtn) : "";
// owner ? 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) ;
// customer || owner ? widgets.add(invoicesBtn) : "";
// owner ? widgets.add(paymentMethodBtn) : "";
// owner ? widgets.add(discountBtn) : "";
// widgets.add(termBtn);
return OfflineRedirect(

View File

@@ -9,6 +9,7 @@ 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/helpers/network_connectivity.dart';
import 'package:fcs/fcs/common/pages/model/base_model.dart';
import 'package:fcs/fcs/common/services/services.dart';
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
@@ -16,6 +17,7 @@ import 'package:package_info/package_info.dart';
class MainModel extends ChangeNotifier {
final log = Logger('MainModel');
List<BaseModel> models = [];
User user;
PackageInfo packageInfo;
@@ -37,67 +39,50 @@ class MainModel extends ChangeNotifier {
notifyListeners();
});
Services.instance.authService.onAuthStatus().listen((event) {
this.user=event;
notifyListeners();
print("main event-->$event");
});
}
bool faqEditable(){
return this.user != null && false;
}
bool termEditable(){
return this.user != null && false;
}
bool contactEditable(){
return this.user != null && false;
}
bool isLogin() {
return this.user != null;
}
bool isCustomer() {
return user != null && user.name != "Owner";
}
bool isOwner() {
return user != null && user.name == "Owner";
}
bool hasEmail() {
return this.user != null && this.user.isEmail();
}
bool agreedTerm() {
return this.user != null && this.user.agreeTerms;
}
bool isBuyer() {
return this.user == null || this.user.isBuyer();
return user != null && user.isCustomer();
}
bool isSysAdmin() {
return this.user != null && this.user.isSysAdmin();
return this.user != null && this.user.hasSysAdmin();
}
bool isSysSupport() {
return this.user != null && this.user.isSysSupport();
}
bool isBizAdmin() {
return this.user != null && this.user.isBizAdmin();
}
bool isOwnerAndAbove() {
return this.user != null && this.user.isOwnerAndAbove();
}
bool isAdmin() {
return this.user != null && this.user.hasAdmin();
}
bool showHistoryBtn() {
return isSysAdmin() || isSysSupport() || isBizAdmin();
}
init() async {
await _loadSetting();
_loadUser();
this.packageInfo = await PackageInfo.fromPlatform();
}
// void addModel(BaseModel model) {
// models.add(model);
// }
void addModel(BaseModel model) {
models.add(model);
}
// void _initUser(User user) {
// models.forEach((m) => m.initUser(user));
@@ -107,18 +92,18 @@ class MainModel extends ChangeNotifier {
// }
// }
// void _initSetting(Setting setting) {
// models.forEach((m) => m.initSetting(setting));
// }
void _initSetting(Setting setting) {
models.forEach((m) => m.initSetting(setting));
}
Future<void> _loadSetting() async {
try {
Services.instance.authService.getSetting().listen((event) {
this.setting = event;
_initSetting(setting);
notifyListeners();
});
} finally {}
// _initSetting(setting);
}
void _loadUser() async {

View File

@@ -51,16 +51,7 @@ class _ProfileState extends State<Profile> {
var languageModel = Provider.of<LanguageModel>(context);
MainModel mainModel = Provider.of<MainModel>(context);
// buildLanguage(languageModel);
_selectedDropdown(String selected) {
setState(() {
selectedLanguage = selected;
languageModel.saveLanguage(selectedLanguage);
});
}
final namebox = Container(
// padding: EdgeInsets.only(left: 25.0, right: 25.0),
padding: EdgeInsets.only(top: 10, left: 25.0, right: 25.0),
child: Container(
height: 45.0,
@@ -137,80 +128,7 @@ class _ProfileState extends State<Profile> {
],
),
);
final emailBox = Container(
padding: EdgeInsets.only(top: 10, left: 25.0, right: 25.0),
child: Row(
children: <Widget>[
Text(
AppTranslations.of(context).text("profile.email"),
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: 35,
),
Text(
mainModel.user == null
? ""
: mainModel.user.email == null || mainModel.user.email == ''
? ''
: mainModel.user.email,
style: TextStyle(fontSize: 16.0, fontStyle: FontStyle.normal),
),
],
),
);
final languageBox = Container(
padding: EdgeInsets.only(bottom: 0, top: 7, left: 25.0, right: 25.0),
child: Container(
height: 45.0,
child: Row(
children: <Widget>[
Text(
AppTranslations.of(context).text("profile.language"),
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"),
),
Container(
width: 140,
padding: EdgeInsets.only(left: 30),
child: Theme(
data: new ThemeData(
canvasColor: Colors.white,
),
child: DropdownButton(
hint: Text("English"),
value: selectedLanguage,
isExpanded: true,
iconSize: 40,
items: languagesList
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: _selectedDropdown),
)),
],
),
));
final logoutbutton = Container(
padding: EdgeInsets.only(left: 20.0, right: 24.0),
@@ -283,20 +201,15 @@ class _ProfileState extends State<Profile> {
namebox,
Padding(
padding: const EdgeInsets.only(left: 18.0),
child: Icon(Icons.edit),
child: Icon(Icons.edit, color: primaryColor),
)
],
),
mainModel.isBuyer() ? Container() : getPrivilegeBox(context),
phonenumberbox,
mainModel.user == null
mainModel.isCustomer()
? Container()
: mainModel.user.email == null ||
mainModel.user.email == ''
? Container()
: emailBox,
languageBox,
getShippingAddressList(context),
: getPrivilegeBox(context),
phonenumberbox,
// getShippingAddressList(context),
],
),
),

View File

@@ -193,6 +193,9 @@ class _CodePageState extends State<CodePage> {
_resend() async {}
_verify() async {
setState(() {
_isLoading = true;
});
try {
AuthResult auth = await context.read<MainModel>().signin(this.pin);
if (auth.authStatus == AuthStatus.AUTH_VERIFIED) {
@@ -202,12 +205,13 @@ class _CodePageState extends State<CodePage> {
} else {
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
}
// Provider.of<MainModel>(context, listen: false)
// .saveUser(pin, widget.phoneNumber);
}
} catch (e) {
showMsgDialog(context, "Error", e.toString());
}
setState(() {
_isLoading = false;
});
}
_completeResend() {

View File

@@ -1,7 +1,9 @@
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/user.dart';
import 'package:fcs/fcs/common/pages/model/main_model.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';
import 'package:flutter/material.dart';
@@ -176,6 +178,13 @@ class _SigninPageState extends State<SigninPage> {
await Navigator.of(context)
.push(BottomUpPageRoute(CodePage(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);
}
}
if (auth.authStatus == AuthStatus.ERROR) {
showMsgDialog(context, "Error", auth.authErrorMsg);

View File

@@ -49,8 +49,10 @@ class _TermPageState extends State<TermPage> {
@override
Widget build(BuildContext context) {
Setting setting = Provider.of<MainModel>(context).setting;
return CupertinoPageScaffold(
child: CustomScrollView(slivers: [
bool isEditable = context.select((MainModel m) => m.termEditable());
return Scaffold(
body: CustomScrollView(slivers: [
SliverAppBar(
leading: IconButton(
icon: Icon(
@@ -60,8 +62,8 @@ class _TermPageState extends State<TermPage> {
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
expandedHeight: 150.0,
floating: true,
expandedHeight: 100.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
@@ -72,34 +74,35 @@ class _TermPageState extends State<TermPage> {
color: Colors.white,
),
),
actions: [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) =>
TermEdit(term: Term.fromSetting(setting)),
)),
icon: Icon(
CupertinoIcons.pen,
color: Colors.white,
))
],
actions: isEditable
? [
IconButton(
onPressed: () =>
Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) =>
TermEdit(term: Term.fromSetting(setting)),
)),
icon: Icon(
CupertinoIcons.pen,
color: Colors.white,
))
]
: [],
),
SliverFillRemaining(child: ZefyrTheme(
data: ZefyrThemeData().copyWith(
defaultLineTheme: LineTheme(
textStyle: TextStyle(color: Colors.black),
padding: EdgeInsets.all(0))),
child: ZefyrScaffold(
child: ZefyrEditor(
mode: ZefyrMode.view,
padding: EdgeInsets.all(16),
controller: ZefyrController(_loadDocument(setting)),
focusNode: _focusNode,
),
))
),
SliverFillRemaining(
child: ZefyrTheme(
data: ZefyrThemeData().copyWith(
defaultLineTheme: LineTheme(
textStyle: TextStyle(color: Colors.black),
padding: EdgeInsets.all(0))),
child: ZefyrScaffold(
child: ZefyrEditor(
mode: ZefyrMode.view,
padding: EdgeInsets.all(16),
controller: ZefyrController(_loadDocument(setting)),
focusNode: _focusNode,
),
))),
]));
}

View File

@@ -0,0 +1,23 @@
import 'package:flutter/cupertino.dart';
class BottomUpPageRoute extends PageRouteBuilder {
final Widget child;
BottomUpPageRoute(this.child)
: super(
pageBuilder: (context, animation, secondaryAnimation) => child,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
var begin = Offset(0.0, 1.0);
var end = Offset.zero;
var curve = Curves.ease;
var tween =
Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}

View File

@@ -13,6 +13,7 @@ class InputText extends StatelessWidget {
final int maxLines;
final bool withBorder;
final Color borderColor;
final TextInputType textInputType;
const InputText(
{Key key,
@@ -22,7 +23,8 @@ class InputText extends StatelessWidget {
this.validator,
this.maxLines = 1,
this.withBorder = false,
this.borderColor})
this.borderColor,
this.textInputType})
: super(key: key);
@override
Widget build(BuildContext context) {
@@ -36,10 +38,11 @@ class InputText extends StatelessWidget {
cursorColor: primaryColor,
style: textStyle,
maxLines: maxLines,
keyboardType: textInputType,
decoration: new InputDecoration(
hintText: '',
// hintText: '',
hintStyle: TextStyle(
height: 2.5,
height: 3.5,
),
labelText: labelTextKey == null
? null

View File

@@ -115,3 +115,8 @@ flutter:
- family: MyanmarUnicode
fonts:
- asset: assets/fonts/MyMMUnicodeUniversal.ttf
- family: Myanmar3
fonts:
- asset: assets/fonts/Myanmar3_2018.ttf