This commit is contained in:
Sai Naw Wun
2020-10-07 02:33:06 +06:30
parent 01a2798a74
commit 65dda16fe6
475 changed files with 1543 additions and 90780 deletions

View File

@@ -0,0 +1,90 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/data/services/services.dart';
import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/role.dart';
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/helpers/firebase_helper.dart';
import 'package:fcs/pages/main/model/base_model.dart';
import 'package:logging/logging.dart';
class StaffModel extends BaseModel {
final log = Logger('StaffModel');
StreamSubscription<QuerySnapshot> listener;
StreamSubscription<QuerySnapshot> privilegeListener;
List<User> employees = [];
List<Privilege> privileges = [];
@override
void privilegeChanged() {
super.privilegeChanged();
_loadPrivileges();
_loadEmployees();
}
@override
logout() async {
if (listener != null) listener.cancel();
if (privilegeListener != null) privilegeListener.cancel();
employees = [];
privileges = [];
}
Future<void> _loadEmployees() async {
if (user == null || !user.hasStaffs()) return;
try {
if (listener != null) listener.cancel();
listener = 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();
});
} catch (e) {
log.warning("Error!! $e");
}
}
Future<void> _loadPrivileges() async {
if (user == null || !user.hasStaffs()) return;
try {
privilegeListener = 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();
});
} catch (e) {
log.warning("Error!! $e");
}
}
Future<void> updatePrivileges(String userID, List<String> privileges) async {
await request("/employee/privileges", "PUT",
payload: {"id": userID, "privileges": privileges},
token: await getToken());
}
Future<User> findUser(String phoneNumber) {
return Services.instance.userService.findUser(phoneNumber);
}
}

View File

@@ -0,0 +1,280 @@
import 'package:fcs/domain/entities/role.dart';
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/localization/app_translations.dart';
import 'package:fcs/pages/main/model/language_model.dart';
import 'package:fcs/pages/staff/model/staff_model.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/widgets/display_text.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/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, color: primaryColor),
),
Text(p.desc,
style: TextStyle(fontSize: 13, color: Colors.grey[600]))
],
),
],
),
));
}).toList();
}
Widget phoneSearchbox(BuildContext context, FindCallBack findCallBack) {
var languageModel = Provider.of<LanguageModel>(context);
return Container(
padding: EdgeInsets.only(
bottom: 25,
left: 8,
),
child: Stack(
alignment: const Alignment(1, 1.0),
children: <Widget>[
TextFormField(
controller: _phoneInput,
autofocus: false,
cursorColor: primaryColor,
keyboardType: TextInputType.phone,
style: textStyle,
decoration: new InputDecoration(
labelText:
AppTranslations.of(context).text('staff.phone.search'),
labelStyle: languageModel.isEng ? labelStyle : labelStyleMM,
// icon: Icon(
// Icons.search,
// color: primaryColor,
// ),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 1.0)),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 1.0)),
),
),
new IconButton(
onPressed: () {
findCallBack();
},
icon: new Icon(Icons.search, size: 25, color: primaryColor))
],
));
}
@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,
)),
isNew
? Container()
: 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.only(left: 12.0, right: 12),
child: ListView(
children: <Widget>[
isNew
? phoneSearchbox(context, () => _findUser(context))
: Container(),
phoneNumberBox,
namebox,
Padding(
padding: const EdgeInsets.only(top: 18.0),
child: Text("Privileges"),
),
Column(
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);
if (_phoneInput.text == "") return;
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,125 @@
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/localization/app_translations.dart';
import 'package:fcs/pages/staff/model/staff_model.dart';
import 'package:fcs/pages/widgets/bottom_up_page_route.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.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(CupertinoIcons.back),
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: LocalText(context, "staff.new", color: Colors.white),
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),
),
),
],
),
),
],
),
),
),
],
),
),
],
);
}
}