diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 60e219d..29aba80 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -6,7 +6,7 @@ - diff --git a/lib/data_types/components.dart b/lib/data_types/components.dart index c4a891c..be863c9 100644 --- a/lib/data_types/components.dart +++ b/lib/data_types/components.dart @@ -388,12 +388,15 @@ class Client { String? generalNotes; // General notes about client DateTime? birthday; // Birthday date DateTime creationDate; // Client creation date - DateTime? acceptedDate; // Birthday date int discount; // general discount for client bool isTrusted; // Trusted user String imageURL; // Image URL for quick download List appointments; - bool isApprovedByAdmin; // Admin approved this account + bool? isApprovedByAdmin; // Admin approved this account + String? + lasApprovalEditorId; // last admin id that edited the isApprovedByAdmin + DateTime? lasApprovalEditDate; // last edit date for isApprovedByAdmin + bool isRegistered; // is it a registered user (not created by admin) double get totalRevenue { return appointments.fold(0, (sum, item) => sum + item.totalCost); @@ -428,12 +431,14 @@ class Client { this.generalNotes, this.birthday, required this.creationDate, - this.acceptedDate, this.discount = 0, this.isTrusted = false, this.imageURL = '', this.appointments = const [], this.isApprovedByAdmin = false, + this.lasApprovalEditorId, + this.lasApprovalEditDate, + this.isRegistered = false, }); Map toJson() { @@ -445,11 +450,15 @@ class Client { 'generalNotes': generalNotes, 'birthday': birthday != null ? Timestamp.fromDate(birthday!) : '', 'creationDate': Timestamp.fromDate(creationDate), - 'acceptedDate': Timestamp.fromDate(creationDate), 'discount': discount, 'isTrusted': isTrusted, 'imageURL': imageURL, 'isApprovedByAdmin': isApprovedByAdmin, + 'lasApprovalEditorId': lasApprovalEditorId, + 'lasApprovalEditDate': lasApprovalEditDate != null + ? Timestamp.fromDate(lasApprovalEditDate!) + : null, + 'isRegistered': isRegistered, }; } @@ -479,7 +488,13 @@ class Client { appointments: doc['appointments'] == null ? [] : loadAppointmentsFromDoc(doc['appointments']), - isApprovedByAdmin: doc['isApprovedByAdmin'] ?? false, + isApprovedByAdmin: doc['isApprovedByAdmin'], + lasApprovalEditorId: doc['lasApprovalEditorId'], + lasApprovalEditDate: doc['lasApprovalEditDate'] != null && + doc['lasApprovalEditDate'].toString().isNotEmpty + ? doc['lasApprovalEditDate'].toDate() + : null, + isRegistered: doc['isRegistered'] ?? false, ); } } diff --git a/lib/providers/clients_mgr.dart b/lib/providers/clients_mgr.dart index 6090724..7682bb8 100644 --- a/lib/providers/clients_mgr.dart +++ b/lib/providers/clients_mgr.dart @@ -216,7 +216,7 @@ class ClientsMgr extends ChangeNotifier { } } - Future updateClient(Client updatedClient) async { + Future updateClient(String? adminId, Client updatedClient) async { /// Validate that phone number is not used by another client bool phoneAvailable = await checkPhoneNumberAvailability( updatedClient.phone, updatedClient.id); @@ -231,16 +231,27 @@ class ClientsMgr extends ChangeNotifier { /// Update existing Client - update DB CollectionReference clientsColl = _fs.collection(clientsCollection); + if (initialized) { + var oldClientRes = _clients.where((c) => c.id == updatedClient.id); + if (oldClientRes.isNotEmpty && + oldClientRes.first.isApprovedByAdmin != + updatedClient.isApprovedByAdmin) { + updatedClient.lasApprovalEditorId = adminId; + updatedClient.lasApprovalEditDate = DateTime.now(); + } + } var data = updatedClient.toJson(); clientsColl.doc(updatedClient.id).update(data); updateClientAppointments(updatedClient); } - Future updateClientApproval(String clientId, bool approve) async { - await _fs - .collection(clientsCollection) - .doc(clientId) - .update({'isApprovedByAdmin': approve}); + Future updateClientApproval( + String? adminId, String clientId, bool approve) async { + await _fs.collection(clientsCollection).doc(clientId).update({ + 'isApprovedByAdmin': approve, + 'lasApprovalEditorId': adminId, + 'lasApprovalEditDate': Timestamp.fromDate(DateTime.now()), + }); } /// Client selection diff --git a/lib/screens/home/clients/client.dart b/lib/screens/home/clients/client.dart index 3d1fe54..b3715eb 100644 --- a/lib/screens/home/clients/client.dart +++ b/lib/screens/home/clients/client.dart @@ -25,6 +25,8 @@ import 'package:flutter/services.dart'; import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:provider/provider.dart'; +import '../../../providers/auth_mgr.dart'; + class ClientWidget extends StatefulWidget { final Client? client; const ClientWidget({Key? key, this.client}) : super(key: key); @@ -42,7 +44,7 @@ class _ClientWidgetState extends State { final GlobalKey _formKey = GlobalKey(); int clientDiscount = 0; bool trustedClient = true; - bool blockedClient = false; + bool blockedClient = true; bool autoValidate = false; String imageURL = ''; bool isSaveDisabled = true; @@ -63,7 +65,7 @@ class _ClientWidgetState extends State { _noteController.text = widget.client!.generalNotes!; clientDiscount = widget.client!.discount; trustedClient = widget.client!.isTrusted; - blockedClient = !widget.client!.isApprovedByAdmin; + blockedClient = !(widget.client!.isApprovedByAdmin == true); birthdayDate = widget.client!.birthday; imageURL = widget.client!.imageURL; } @@ -639,6 +641,7 @@ class _ClientWidgetState extends State { if (form!.validate()) { showLoaderDialog(context); final clientMgr = Provider.of(context, listen: false); + final authMgr = Provider.of(context, listen: false); String clientID = widget.client == null ? '' : widget.client!.id; Client client = Client( @@ -647,14 +650,16 @@ class _ClientWidgetState extends State { phone: _phoneController.text, address: _addressController.text, email: _emailController.text, - creationDate: DateTime.now(), + creationDate: widget.client?.creationDate ?? DateTime.now(), birthday: birthdayDate, generalNotes: _noteController.text, discount: clientDiscount, isTrusted: trustedClient, isApprovedByAdmin: !blockedClient, - acceptedDate: DateTime.now(), imageURL: imageURL, + lasApprovalEditorId: widget.client?.lasApprovalEditorId, + lasApprovalEditDate: widget.client?.lasApprovalEditDate, + isRegistered: widget.client?.isRegistered ?? false, ); if (widget.client == null) { @@ -671,7 +676,8 @@ class _ClientWidgetState extends State { } } else { try { - await clientMgr.updateClient(client); + await clientMgr.updateClient( + authMgr.getLoggedInAdminEmail(), client); await clientMgr.setSelectedClient(clientID: client.id); close(); showUpdateClientSuccessMessage(); diff --git a/lib/screens/home/clients/client_details.dart b/lib/screens/home/clients/client_details.dart index aee0915..8e7ddf1 100644 --- a/lib/screens/home/clients/client_details.dart +++ b/lib/screens/home/clients/client_details.dart @@ -160,7 +160,7 @@ class _ClientDetailsState extends State { ), ), Text( - !client.isApprovedByAdmin + !(client.isApprovedByAdmin == true) ? Languages.of(context)!.yesLabel.toTitleCase() : Languages.of(context)!.noLabel.toTitleCase(), maxLines: 1, diff --git a/lib/screens/home/notification/approval_request.dart b/lib/screens/home/notification/approval_request.dart index e45b1e5..d425358 100644 --- a/lib/screens/home/notification/approval_request.dart +++ b/lib/screens/home/notification/approval_request.dart @@ -48,7 +48,8 @@ class _ApprovalRequestState extends State { final notificationsMgr = Provider.of(context, listen: false); final authMgr = Provider.of(context, listen: false); - await clientsMgr.updateClientApproval(client.id, true); + await clientsMgr.updateClientApproval( + authMgr.getLoggedInAdminEmail(), client.id, true); clientUpdatedSuccessfullyMessage(); // delete notification await notificationsMgr.deleteNotification( @@ -62,7 +63,8 @@ class _ApprovalRequestState extends State { final notificationsMgr = Provider.of(context, listen: false); final authMgr = Provider.of(context, listen: false); - await clientsMgr.updateClientApproval(client.id, false); + await clientsMgr.updateClientApproval( + authMgr.getLoggedInAdminEmail(), client.id, false); clientUpdatedSuccessfullyMessage(); // delete notification await notificationsMgr.deleteNotification( diff --git a/lib/widget/client/client_card.dart b/lib/widget/client/client_card.dart index 868f558..239584e 100644 --- a/lib/widget/client/client_card.dart +++ b/lib/widget/client/client_card.dart @@ -54,7 +54,8 @@ class ClientCard extends StatelessWidget { trailing: Row( children: [ Visibility( - visible: !clientCardProps.contactDetails.isApprovedByAdmin, + visible: + !(clientCardProps.contactDetails.isApprovedByAdmin == true), child: Padding( padding: EdgeInsets.only( left: rSize(10), diff --git a/lib/widget/notification_card.dart b/lib/widget/notification_card.dart index 95fc312..3f9b33c 100644 --- a/lib/widget/notification_card.dart +++ b/lib/widget/notification_card.dart @@ -48,7 +48,7 @@ class NotificationCard extends StatelessWidget { final authMgr = Provider.of(context, listen: false); final clientsMgr = Provider.of(context, listen: false); // approve client - await clientsMgr.updateClientApproval( + await clientsMgr.updateClientApproval(authMgr.getLoggedInAdminEmail(), notificationCardProps.notificationDetails.data['client_id'], true); clientUpdatedSuccessfullyMessage(); // delete notification @@ -64,7 +64,7 @@ class NotificationCard extends StatelessWidget { final authMgr = Provider.of(context, listen: false); final clientsMgr = Provider.of(context, listen: false); // deny client - await clientsMgr.updateClientApproval( + await clientsMgr.updateClientApproval(authMgr.getLoggedInAdminEmail(), notificationCardProps.notificationDetails.data['client_id'], false); clientUpdatedSuccessfullyMessage(); // delete notification