diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 49c3e2d4..d9ffd0ce 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -66,7 +66,7 @@ class ApiClient { factory ApiClient() => _instance; Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, - {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = true}) async { var defaultHeaders = {'Accept': 'application/json'}; if (headers != null && headers.isNotEmpty) { defaultHeaders.addAll(headers); @@ -97,7 +97,7 @@ class ApiClient { } Future postJsonForResponse(String url, T jsonObject, - {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = true}) async { int currentRetryTime = retryTimes; String? requestBody; late Map stringObj; diff --git a/lib/api/preventive_maintenance_api_client.dart b/lib/api/preventive_maintenance_api_client.dart new file mode 100644 index 00000000..00814d77 --- /dev/null +++ b/lib/api/preventive_maintenance_api_client.dart @@ -0,0 +1,54 @@ +import 'dart:convert'; + +import 'package:test_sa/api/api_client.dart'; +import 'package:test_sa/api/user_api_client.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/visits/visits_group.dart'; +import 'package:test_sa/models/visits/visits_search.dart'; + +import '../models/visits/visit.dart'; + +class PreventiveMaintenanceApiClient { + static final PreventiveMaintenanceApiClient _instance = PreventiveMaintenanceApiClient._internal(); + + /// ## list of user requests + final List visits = []; + + PreventiveMaintenanceApiClient._internal(); + + factory PreventiveMaintenanceApiClient() => _instance; + + Future getVisits({required int pageItemNumber, VisitsSearch? visitsSearch}) async { + final response = await ApiClient().getJsonForResponse( + '${URLs.host1}${URLs.getPreventiveMaintenanceVisits}', + headers: {"Content-Type": "application/json; charset=utf-8"}, + queryParameters: { + 'uid': UserApiClient().user?.id, + 'token': UserApiClient().user?.token, + 'page': '${(visits.length) ~/ pageItemNumber}', + if (visitsSearch != null) ...visitsSearch.queryParameters(), + }, + ); + List requestsListJson = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", "")); + List visitsList = requestsListJson.map((request) => Visit.fromJson(request)).toList(); + visits.addAll(visitsList); + } + + Future updateGroupOfVisits({required VisitsGroup group}) async { + final user = UserApiClient().user; + Map body = group.toJson(); + body["token"] = user?.token ?? ""; + body["uid"] = user?.id ?? ""; + //userId = 397.toString(); // testing id to view data + await ApiClient().postJsonForResponse( + '${URLs.host1}${URLs.updatePreventiveMaintenanceVisits}', + body, + ); + // client's request was successfully received + for (var visit in (group.visits ?? [])) { + visit.status = group.status; + visit.actualDate = group.date.toString().split(" ").first; + } + group.visits?.clear(); + } +} diff --git a/lib/api/service_request_api_client.dart b/lib/api/service_request_api_client.dart index ca5f5be5..2e35eef9 100644 --- a/lib/api/service_request_api_client.dart +++ b/lib/api/service_request_api_client.dart @@ -2,7 +2,12 @@ import 'dart:convert'; import 'package:test_sa/api/api_client.dart'; import 'package:test_sa/api/user_api_client.dart'; +import 'package:test_sa/models/issue.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/service_report.dart'; import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/models/service_request/service_request_search.dart'; +import 'package:test_sa/models/timer_model.dart'; import '../controllers/api_routes/urls.dart'; @@ -35,7 +40,107 @@ class ServiceRequestApiClient { "defect_types": (serviceRequest.defectType?.id).toString(), "audio": serviceRequest.audio, }, - isFormData: true, ); } + + /// Get Service Requests and Fill [serviceRequests] + Future> getRequests({pageItemNumber, ServiceRequestSearch? search}) async { + final user = UserApiClient().user; + final response = await ApiClient().getJsonForResponse( + '${URLs.host1}${URLs.getServiceRequests}', + headers: {"Content-Type": "application/json; charset=utf-8"}, + queryParameters: { + 'uid': user?.id, + if (user?.hospital?.id != null) 'client_nid': user?.hospital?.id, + 'token': user?.token, + 'page': '${(serviceRequests.length) ~/ pageItemNumber}', + if (search != null) ...search.queryParameters(), + }, + ); + List requestsListJson = json.decode(utf8.decode(response.bodyBytes)); + List serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList(); + serviceRequests.addAll(serviceRequestsPage); + return serviceRequestsPage; + } + + Future getServiceById(String? requestId) async { + final user = UserApiClient().user; + final response = await ApiClient().getJsonForResponse( + '${URLs.host1}${URLs.getSingleServiceRequest}', + queryParameters: {'call_nid': requestId, 'uid': user?.id, 'token': user?.token}, + ); + // If the call to the server was successful, parse the JSON. + List jsonList = json.decode(utf8.decode(response.bodyBytes)); + List requests = jsonList.map((i) => ServiceRequest.fromJson(i)).toList(); + return requests[0]; + } + + Future createIssueReport(Issue issue) async { + final user = UserApiClient().user; + Map body = issue.toMap(); + body["uid"] = user?.id ?? ""; + body["token"] = user?.token ?? ""; + await ApiClient().postJsonForResponse('${URLs.host1}${URLs.createReport}', body); + } + + Future updateDate({String? newDate, Lookup? employee, ServiceRequest? request}) async { + final user = UserApiClient().user; + Map body = {}; + body["uid"] = user?.id ?? ''; + body["token"] = user?.token ?? ''; + body["nid"] = request?.id ?? ''; + body["date"] = newDate ?? ''; + body["ass_emp"] = employee?.id?.toString() ?? ''; + await ApiClient().postJsonForResponse('${URLs.host1}${URLs.updateRequestDate}', body); + request?.engineerName = employee?.label; + } + + Future createServiceReport({required ServiceReport? report, required ServiceRequest? request}) async { + final user = UserApiClient().user; + Map? body = report?.toMap(); + body?["uid"] = user?.id ?? ""; + body?["token"] = user?.token ?? ""; + body?["job_id"] = request?.id ?? ''; + await ApiClient().postJsonForResponse('${URLs.host1}${URLs.createServiceReport}', body); + } + + Future createDuplicatedReport({required ServiceRequest request}) async { + final user = UserApiClient().user; + await ApiClient().getJsonForResponse( + '${URLs.host1}${URLs.createDuplicatedReport}', + queryParameters: {'nid': request.id, 'uid': user?.id, 'token': user?.token}, + ); + } + + Future updateServiceReport({required ServiceReport report, required ServiceRequest request}) async { + final user = UserApiClient().user; + Map body = report.toMap(); + body["uid"] = user?.id ?? ""; + body["token"] = user?.token ?? ""; + body["job_id"] = request.id ?? ''; + body["report_id"] = request.reportID ?? ''; + await ApiClient().postJsonForResponse('${URLs.host1}${URLs.updateServiceReport}', body); + } + + Future updateServiceReportTimer({required TimerModel timer, required ServiceRequest request}) async { + final user = UserApiClient().user; + Map body = {}; + body["uid"] = user?.id ?? ""; + body["token"] = user?.token ?? ""; + body["job_id"] = request.id ?? ''; + body["start_time"] = ((timer.startAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0); + body["end_time"] = ((timer.endAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0); + body["working_hours"] = ((timer.durationInSecond ?? 0) / 60 / 60).toStringAsFixed(5); + body["report_id"] = request.reportID ?? ''; + await ApiClient().postJsonForResponse('${URLs.host1}${URLs.updateServiceReport}', body); + } + + Future getSingleServiceReport({required String reportId}) async { + final user = UserApiClient().user; + final response = await ApiClient().getJsonForResponse( + '${URLs.host1}${URLs.getServiceReport}', + queryParameters: {'report_id': reportId, 'uid': user?.id, 'token': user?.token}, + ); + return ServiceReport.fromJson(json.decode(utf8.decode(response.bodyBytes)), reportId); + } } diff --git a/lib/api/user_api_client.dart b/lib/api/user_api_client.dart index 370d7052..b11b8887 100644 --- a/lib/api/user_api_client.dart +++ b/lib/api/user_api_client.dart @@ -25,7 +25,6 @@ class UserApiClient { }, "${URLs.host1}${URLs.login}", await user.toLoginJson(), //body - isFormData: true, ); } @@ -41,7 +40,6 @@ class UserApiClient { }, "${URLs.host1}${URLs.register}", await newUser.toRegisterJson(), //body - isFormData: true, ); } @@ -57,7 +55,6 @@ class UserApiClient { }, "${URLs.host1}${URLs.updateProfile}", updatedUser.toUpdateProfileJson(), //body - isFormData: true, ); // Map jsonObject = {}; // jsonObject["uid"] = user.id; diff --git a/lib/api/visits_api_client.dart b/lib/api/visits_api_client.dart new file mode 100644 index 00000000..8bbfa309 --- /dev/null +++ b/lib/api/visits_api_client.dart @@ -0,0 +1,64 @@ +import 'dart:convert'; + +import 'package:test_sa/api/api_client.dart'; +import 'package:test_sa/api/user_api_client.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/pantry/pentry.dart'; +import 'package:test_sa/models/visits/visits_group.dart'; +import 'package:test_sa/models/visits/visits_search.dart'; + +import '../models/visits/visit.dart'; + +class VisitsApiClient { + static final VisitsApiClient _instance = VisitsApiClient._internal(); + + /// ## list of user requests + final List visits = []; + + VisitsApiClient._internal(); + + factory VisitsApiClient() => _instance; + + Future getVisits({required int pageItemNumber, VisitsSearch? visitsSearch}) async { + final response = await ApiClient().getJsonForResponse( + '${URLs.host1}${URLs.getRegularVisits}', + headers: {"Content-Type": "application/json; charset=utf-8"}, + queryParameters: { + 'uid': UserApiClient().user?.id, + 'token': UserApiClient().user?.token, + 'page': '${(visits.length) ~/ pageItemNumber}', + if (visitsSearch != null) ...visitsSearch.queryParameters(), + }, + ); + List requestsListJson = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", "")); + List visitsList = requestsListJson.map((request) => Visit.fromJson(request)).toList(); + visits.addAll(visitsList); + } + + Future updateGroupOfVisits({required VisitsGroup group}) async { + final user = UserApiClient().user; + Map body = group.toJson(); + body["token"] = user?.token ?? ""; + body["uid"] = user?.id ?? ""; + //userId = 397.toString(); // testing id to view data + await ApiClient().postJsonForResponse('${URLs.host1}${URLs.updateRegularVisits}', body); + } + + Future getPentry(String id) async { + final response = await ApiClient().getJsonForResponse( + '${URLs.host1}${URLs.getPentry}/$id', + headers: {"Content-Type": "application/json; charset=utf-8"}, + ); + + return Pentry.fromMap(json.decode(utf8.decode(response.bodyBytes))); + } + + Future updatePentry({Pentry? pentry, Visit? visit}) async { + final user = UserApiClient().user; + Map? body = pentry?.toMap(); + body?["uid"] = user?.id ?? ""; + body?["token"] = user?.token ?? ""; + await ApiClient().postJsonForResponse('${URLs.host1}${URLs.updatePentry}/${visit?.id}', body); + visit?.status = pentry?.ppmVisitStatus; + } +} diff --git a/lib/controllers/providers/api/devices_provider.dart b/lib/controllers/providers/api/devices_provider.dart index 14f88cae..ed1f7c4b 100644 --- a/lib/controllers/providers/api/devices_provider.dart +++ b/lib/controllers/providers/api/devices_provider.dart @@ -28,7 +28,7 @@ class DevicesProvider extends LoadingNotifier { Future getEquipment({required String? hospitalId}) async { if (hospitalId != null) { _searchableList.clear(); - waitApiRequest( + await waitApiRequest( () async { await DevicesApiClient().getEquipment(hospitalId); _searchableList.addAll(DevicesApiClient().devices); diff --git a/lib/controllers/providers/api/preventive_maintenance_visits_provider.dart b/lib/controllers/providers/api/preventive_maintenance_visits_provider.dart index b943f3f3..6cfe2171 100644 --- a/lib/controllers/providers/api/preventive_maintenance_visits_provider.dart +++ b/lib/controllers/providers/api/preventive_maintenance_visits_provider.dart @@ -1,21 +1,22 @@ -import 'dart:convert'; - import 'package:flutter/cupertino.dart'; -import 'package:http/http.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:test_sa/api/preventive_maintenance_api_client.dart'; +import 'package:test_sa/controllers/providers/loading_notifier.dart'; -import '../../../models/user.dart'; -import '../../../models/visits/visit.dart'; import '../../../models/visits/visits_group.dart'; import '../../../models/visits/visits_search.dart'; -import '../../api_routes/urls.dart'; +import '../../../views/pages/user/visits/update_visits_group_sheet.dart'; +import '../../http_status_manger/http_status_manger.dart'; +import '../../localization/localization.dart'; -class PreventiveMaintenanceVisitsProvider extends ChangeNotifier { +class PreventiveMaintenanceVisitsProvider extends LoadingNotifier { // number of items call in each request final pageItemNumber = 50; //reset provider data void reset() { - visits = null; + PreventiveMaintenanceApiClient().visits.clear(); nextPage = true; stateCode = null; } @@ -28,98 +29,76 @@ class PreventiveMaintenanceVisitsProvider extends ChangeNotifier { // true if there is next page in product list and false if not bool? nextPage = true; - // list of user requests - List? visits; - - // when requests in-process _loading = true - // done _loading = true - // failed _loading = false - bool? isLoading; - VisitsSearch? visitsSearch = VisitsSearch(); - /// return -2 if request in progress - /// return -1 if error happen when sending request - /// return state code if request complete may be 200, 404 or 403 - /// for more details check http state manager - /// lib\controllers\http_status_manger\http_status_manger.dart - Future getVisits({ - required String host, - required User user, - // VisitsSearch visitsSearch, - }) async { - if (isLoading == true) return -2; - isLoading = true; - Response response; - //userId = 397.toString(); // testing id to view data - try { - response = await get( - Uri.parse( - "${host + URLs.getPreventiveMaintenanceVisits}?uid=${user.id}&token=${user.token}&page=${(visits?.length ?? 0) ~/ pageItemNumber}${visitsSearch?.toSearchString()}", - ), - headers: {"Content-Type": "application/json; charset=utf-8"}, - ); - } catch (error) { - isLoading = false; - stateCode = -1; - notifyListeners(); - return -1; - } - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // client's request was successfully received - List requestsListJson = json.decode(utf8.decode(response.bodyBytes)); - List visits = requestsListJson.map((request) => Visit.fromJson(request)).toList(); - visits.addAll(visits); - if (visits.length == pageItemNumber) { - nextPage = true; - } else { - nextPage = false; - } - } - isLoading = false; - notifyListeners(); - return response.statusCode; + Future getVisits() async { + await waitApiRequest( + () async { + await PreventiveMaintenanceApiClient().getVisits(pageItemNumber: pageItemNumber, visitsSearch: visitsSearch); + }, + onSuccess: () { + /// TODO : this is temporary + stateCode = 200; + if (PreventiveMaintenanceApiClient().visits.length == pageItemNumber) { + nextPage = true; + } else { + nextPage = false; + } + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + }, + ); } - /// return -2 if request in progress - /// return -1 if error happen when sending request - /// return state code if request complete may be 200, 404 or 403 - /// for more details check http state manager - /// lib\controllers\http_status_manger\http_status_manger.dart - Future updateGroupOfVisits({ - required String host, - required User user, - required VisitsGroup group, - }) async { - Response response; - Map body = group.toJson(); - body["token"] = user.token ?? ""; - body["uid"] = user.id ?? ""; - //userId = 397.toString(); // testing id to view data - try { - response = await post( - Uri.parse(host + URLs.updatePreventiveMaintenanceVisits), - body: body, + Future updateGroupOfVisits(BuildContext context) async { + final subtitle = AppLocalization.of(context)?.subtitle; + VisitsGroup? group = await showModalBottomSheet( + isScrollControlled: true, + context: context, + builder: (context) { + return UpdateVisitsGroupSheet(visits: PreventiveMaintenanceApiClient().visits, title: subtitle?.updatePreventiveMaintenance); + }, + ) as VisitsGroup?; + if (context.mounted && group != null) { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(subtitle?.updatingDots ?? ''), + content: const Center(child: CircularProgressIndicator()), + ); + }, + ); + await waitApiRequest( + () async { + await PreventiveMaintenanceApiClient().updateGroupOfVisits(group: group); + if (context.mounted) { + Navigator.of(context).pop(); + } + }, + onSuccess: () { + /// TODO : this is temporary + stateCode = 200; + Navigator.of(context).pop(); + Fluttertoast.showToast( + msg: subtitle?.regularVisitsUpdatedSuccessfully ?? '', + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.BOTTOM, + ); + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + Fluttertoast.showToast( + msg: HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle), + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.BOTTOM, + ); + }, ); - - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // client's request was successfully received - for (var visit in (group.visits ?? [])) { - visit.status = group.status; - visit.actualDate = group.date.toString().split(" ").first; - } - group.visits?.clear(); - notifyListeners(); - } - - return response.statusCode; - } catch (error) { - isLoading = false; - stateCode = -1; - notifyListeners(); - return -1; } } } diff --git a/lib/controllers/providers/api/regular_visits_provider.dart b/lib/controllers/providers/api/regular_visits_provider.dart index 0d66fb34..447bcddd 100644 --- a/lib/controllers/providers/api/regular_visits_provider.dart +++ b/lib/controllers/providers/api/regular_visits_provider.dart @@ -1,22 +1,24 @@ -import 'dart:convert'; - import 'package:flutter/cupertino.dart'; -import 'package:http/http.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:test_sa/api/visits_api_client.dart'; +import 'package:test_sa/controllers/providers/loading_notifier.dart'; import '../../../models/pantry/pentry.dart'; -import '../../../models/user.dart'; import '../../../models/visits/visit.dart'; import '../../../models/visits/visits_group.dart'; import '../../../models/visits/visits_search.dart'; -import '../../api_routes/urls.dart'; +import '../../../views/pages/user/visits/update_visits_group_sheet.dart'; +import '../../http_status_manger/http_status_manger.dart'; +import '../../localization/localization.dart'; -class RegularVisitsProvider extends ChangeNotifier { +class RegularVisitsProvider extends LoadingNotifier { // number of items call in each request final pageItemNumber = 50; - //reset provider data + // reset provider data void reset() { - visits.clear(); + VisitsApiClient().visits.clear(); nextPage = true; stateCode = null; } @@ -29,145 +31,100 @@ class RegularVisitsProvider extends ChangeNotifier { // true if there is next page in product list and false if not bool nextPage = true; - // list of user requests - List visits = []; - - // when requests in-process _loading = true - // done _loading = true - // failed _loading = false - bool? isLoading; - VisitsSearch? visitsSearch = VisitsSearch(); - /// return -2 if request in progress - /// return -1 if error happen when sending request - /// return state code if request complete may be 200, 404 or 403 - /// for more details check http state manager - /// lib\controllers\http_status_manger\http_status_manger.dart - Future getVisits({ - required String? host, - required User? user, - // VisitsSearch visitsSearch, - }) async { - if (isLoading == true) { - return -2; - } - isLoading = true; - Response response; - //userId = 397.toString(); // testing id to view data - try { - response = await get( - Uri.parse( - "$host${URLs.getRegularVisits}?uid=${user?.id}&token=${user?.token}&page=${(visits.length) ~/ pageItemNumber}${visitsSearch?.toSearchString()}", - ), - headers: {"Content-Type": "application/json; charset=utf-8"}, - ); - } catch (error) { - isLoading = false; - stateCode = -1; - notifyListeners(); - return -1; - } - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // client's request was successfully received - try { - List requestsListJson = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", "")); - List visitsList = requestsListJson.map((request) => Visit.fromJson(request)).toList(); - visits.addAll(visitsList); - if (visits.length == pageItemNumber) { + Future getVisits() async { + await waitApiRequest( + () async { + await VisitsApiClient().getVisits(pageItemNumber: pageItemNumber, visitsSearch: visitsSearch); + }, + onSuccess: () { + /// TODO : this is temporary + stateCode = 200; + if (VisitsApiClient().visits.length == pageItemNumber) { nextPage = true; } else { nextPage = false; } - } catch (error) { - isLoading = false; - stateCode = -1; - notifyListeners(); - return -1; - } - } - isLoading = false; - notifyListeners(); - return response.statusCode; + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + }, + ); } - /// return -2 if request in progress - /// return -1 if error happen when sending request - /// return state code if request complete may be 200, 404 or 403 - /// for more details check http state manager - /// lib\controllers\http_status_manger\http_status_manger.dart - Future updateGroupOfVisits({ - required String host, - required User user, - required VisitsGroup group, - }) async { - Response response; - Map body = group.toJson(); - body["token"] = user.token ?? ""; - body["uid"] = user.id ?? ""; - //userId = 397.toString(); // testing id to view data - try { - response = await post( - Uri.parse(host + URLs.updateRegularVisits), - body: body, + Future updateGroupOfVisits(BuildContext context) async { + final subtitle = AppLocalization.of(context)?.subtitle; + VisitsGroup? group = await showModalBottomSheet( + isScrollControlled: true, + context: context, + builder: (context) { + return UpdateVisitsGroupSheet(visits: VisitsApiClient().visits, title: subtitle?.updateRegularVisits); + }, + ) as VisitsGroup?; + if (context.mounted && group != null) { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(subtitle?.updatingDots ?? ''), + content: const Center(child: CircularProgressIndicator()), + ); + }, + ); + await waitApiRequest( + () async { + await VisitsApiClient().updateGroupOfVisits(group: group); + reset(); + }, + onSuccess: () { + /// TODO : this is temporary + stateCode = 200; + Navigator.of(context).pop(); + Fluttertoast.showToast( + msg: subtitle?.regularVisitsUpdatedSuccessfully ?? '', + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.BOTTOM, + ); + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + Fluttertoast.showToast( + msg: HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle), + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.BOTTOM, + ); + }, ); - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // client's request was successfully received - reset(); - notifyListeners(); - } - - return response.statusCode; - } catch (error) { - isLoading = false; - stateCode = -1; - notifyListeners(); - return -1; } } - Future getPently({ - required String host, - required User user, - required String id, - }) async { - Response response; - response = await get( - Uri.parse("$host${URLs.getPentry}/$id"), - headers: {"Content-Type": "application/json; charset=utf-8"}, - ); - - Pentry? pantry; - if (response.statusCode >= 200 && response.statusCode < 300) { - pantry = Pentry.fromMap(json.decode(utf8.decode(response.bodyBytes))); - } - return pantry; + Future getPently({required String? id}) async { + return id == null ? null : await VisitsApiClient().getPentry(id); } - Future updatePentry({ - required String? host, - required User? user, - required Pentry? pentry, - required Visit? visit, - }) async { - try { - Response response; - Map? body = pentry?.toMap(); - body?["uid"] = user?.id ?? ""; - body?["token"] = user?.token ?? ""; - response = await post( - Uri.parse("$host${URLs.updatePentry}/${visit?.id}"), - body: body, - ); - if (response.statusCode >= 200 && response.statusCode < 300) { - visit?.status = pentry?.ppmVisitStatus; - notifyListeners(); - } - return response.statusCode; - } catch (error) { - return -1; - } + void updatePentry(BuildContext context, {required Pentry? pentry, required Visit? visit}) async { + final subtitle = AppLocalization.of(context)?.subtitle; + await waitApiRequest( + () async { + await VisitsApiClient().updatePentry(pentry: pentry, visit: visit); + }, + onSuccess: () { + /// TODO : this is temporary + stateCode = 200; + if (subtitle != null) { + Fluttertoast.showToast(msg: subtitle.requestCompleteSuccessfully); + } + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + String errorMessage = HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle); + Fluttertoast.showToast(msg: errorMessage); + }, + ); } } diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index 0fe16f5d..ddb7623d 100644 --- a/lib/controllers/providers/api/service_requests_provider.dart +++ b/lib/controllers/providers/api/service_requests_provider.dart @@ -1,21 +1,20 @@ import 'dart:convert'; import 'dart:io'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; -import 'package:http/http.dart'; import 'package:test_sa/api/service_request_api_client.dart'; import 'package:test_sa/controllers/providers/loading_notifier.dart'; +import 'package:test_sa/exceptions/api_exception.dart'; import '../../../models/issue.dart'; import '../../../models/lookup.dart'; import '../../../models/service_report.dart'; import '../../../models/service_request/service_request.dart'; import '../../../models/service_request/service_request_search.dart'; -import '../../../models/subtitle.dart'; import '../../../models/timer_model.dart'; -import '../../../models/user.dart'; -import '../../api_routes/urls.dart'; +import '../../../views/widgets/dialogs/dialog.dart'; import '../../http_status_manger/http_status_manger.dart'; import '../../localization/localization.dart'; @@ -38,86 +37,28 @@ class ServiceRequestsProvider extends LoadingNotifier { // true if there is next page in product list and false if not bool? nextPage = true; - // when requests in-process _loading = true - // done _loading = true - // failed _loading = false - bool? isLoading; - ServiceRequestSearch? search = ServiceRequestSearch(); - /// return -2 if request in progress - /// return -1 if error happen when sending request - /// return state code if request complete may be 200, 404 or 403 - /// for more details check http state manager - /// lib\controllers\http_status_manger\http_status_manger.dart - Future getRequests({ - required String host, - required User? user, - required String? hospitalId, - }) async { - if (isLoading == true) { - return -2; - } - isLoading = true; - Response response; - try { - response = await get( - Uri.parse( - "$host${URLs.getServiceRequests}?uid=${user?.id}${hospitalId == null ? "" : "&client_nid=$hospitalId"}&token=${user?.token}&page=${(ServiceRequestApiClient().serviceRequests.length) ~/ pageItemNumber}${search?.toSearchString()}", - ), - headers: {"Content-Type": "application/json; charset=utf-8"}, - ); - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // client's request was successfully received - List requestsListJson = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", "")); - List serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList(); - ServiceRequestApiClient().serviceRequests.addAll(serviceRequestsPage); - if (serviceRequestsPage.length == pageItemNumber) { - nextPage = true; - } else { - nextPage = false; - } + /// Get Service Requests and Fill [ServiceRequestApiClient.serviceRequests] + Future getRequests() async { + await waitApiRequest(() async { + final serviceRequestsPage = await ServiceRequestApiClient().getRequests(pageItemNumber: pageItemNumber, search: search); + if (serviceRequestsPage.length == pageItemNumber) { + nextPage = true; + } else { + nextPage = false; } - isLoading = false; - notifyListeners(); - return response.statusCode; - } catch (error) { - isLoading = false; - stateCode = -1; - notifyListeners(); - return -1; - } + }, onSuccess: () { + /// TODO : this is temporary + stateCode = 200; + }, onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + }); } - Future getSingleServiceRequest({ - required String requestId, - required String host, - required User user, - required Subtitle subtitle, - }) async { - String userData = ''; - userData += "&uid=${user.id}"; - userData += "&token=${user.token}"; - - Response response; - try { - response = await get(Uri.parse( - '$host${URLs.getSingleServiceRequest}?call_nid=$requestId$userData', - )); - } catch (error) { - throw (HttpStatusManger.getStatusMessage(status: -1, subtitle: subtitle) ?? ''); - } - - // If the call to the server was successful, parse the JSON. - if (response.statusCode >= 200 && response.statusCode < 300) { - // If the call to the server was successful, parse the JSON. - List jsonList = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", "")); - List requests = jsonList.map((i) => ServiceRequest.fromJson(i)).toList(); - return requests[0]; - } else { - throw (HttpStatusManger.getStatusMessage(status: response.statusCode, subtitle: subtitle)); - } + Future getSingleServiceRequest({required String? requestId}) async { + return await ServiceRequestApiClient().getServiceById(requestId); } /// ### Create service request and add the response to [ServiceRequestApiClient.serviceRequests] @@ -145,206 +86,136 @@ class ServiceRequestsProvider extends LoadingNotifier { }); } - Future createIssueReport({ - required String host, - required User user, - required Issue issue, - }) async { - Response response; - Map body = issue.toMap(); - body["uid"] = user.id ?? ""; - body["token"] = user.token ?? ""; - try { - response = await post( - Uri.parse(host + URLs.createReport), - body: body, - ); + Future createIssueReport(BuildContext context, {required Issue issue}) async { + await waitApiRequest(() async { + await ServiceRequestApiClient().createIssueReport(issue); + }, onSuccess: () { + final subtitle = AppLocalization.of(context)?.subtitle; + Fluttertoast.showToast(msg: subtitle?.requestCompleteSuccessfully ?? ''); - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) {} - return response.statusCode; - } catch (error) { - return -1; - } + /// TODO : this is temporary + stateCode = 200; + }, onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + }); } - Future updateDate({ - required String? host, - required User? user, - required String? newDate, - required Lookup? employee, - required ServiceRequest? request, - }) async { - Response response; - Map body = {}; - body["uid"] = user?.id ?? ''; - body["token"] = user?.token ?? ''; - body["nid"] = request?.id ?? ''; - body["date"] = newDate ?? ''; - body["ass_emp"] = employee?.id.toString() ?? ''; - try { - response = await post( - Uri.parse((host ?? '') + URLs.updateRequestDate), - body: body, - ); - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - request?.engineerName = employee?.label; - notifyListeners(); - } - return response.statusCode; - } catch (error) { - return -1; - } + Future updateDate(BuildContext context, {required String? newDate, required Lookup? employee, required ServiceRequest? request}) async { + final subtitle = AppLocalization.of(context)?.subtitle; + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return CupertinoAlertDialog(title: Text(subtitle?.updatingDots ?? ''), content: const Center(child: CircularProgressIndicator())); + }, + ); + await waitApiRequest( + () async { + await ServiceRequestApiClient().updateDate(newDate: newDate, employee: employee, request: request); + }, + onSuccess: () { + Navigator.of(context).pop(); + Fluttertoast.showToast(msg: HttpStatusManger.getStatusMessage(status: 200, subtitle: subtitle)); + + /// TODO : this is temporary + stateCode = 200; + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + }, + ); } - Future createServiceReport({ - required String host, - required User user, - required ServiceReport report, - required ServiceRequest request, - }) async { - Response response; - Map body = report.toMap(); - body["uid"] = user.id ?? ""; - body["token"] = user.token ?? ""; - body["job_id"] = request.id ?? ''; - try { - response = await post( - Uri.parse(host + URLs.createServiceReport), - body: body, - ); - - stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { + Future createServiceReport(BuildContext context, {required ServiceReport? report, required ServiceRequest? request}) async { + final subtitle = AppLocalization.of(context)?.subtitle; + await waitApiRequest( + () async { + await ServiceRequestApiClient().createServiceReport(report: report, request: request); reset(); - notifyListeners(); - } - return response.statusCode; - } catch (error) { - return -1; - } + }, + onSuccess: () { + /// TODO : this is temporary + stateCode = 200; + Fluttertoast.showToast(msg: subtitle?.requestCompleteSuccessfully ?? ""); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + String errorMessage = HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle); + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage))); + }, + ); } - Future createDuplicatedReport({ - required String host, - required User user, - required ServiceRequest request, - }) async { - Response response; - String userData = ''; - userData += "&uid=${user.id}"; - userData += "&token=${user.token}"; - - try { - response = await get( - Uri.parse( - "$host${URLs.createDuplicatedReport}?nid=${request.id}$userData", - ), + Future createDuplicatedReport(BuildContext context, {required ServiceRequest request}) async { + final subtitle = AppLocalization.of(context)?.subtitle; + bool result = await showDialog(context: context, builder: (_) => AAlertDialog(title: subtitle?.duplicateAlert, content: subtitle?.duplicateAlertMessage)); + if (result == true && context.mounted) { + showDialog( + context: context, + builder: (context) { + return const Center(child: CircularProgressIndicator()); + }, + ); + await waitApiRequest( + () async { + await ServiceRequestApiClient().createDuplicatedReport(request: request); + reset(); + }, + onSuccess: () { + Navigator.of(context).pop(); + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle)))); + Navigator.of(context).pop(); + }, ); - - stateCode = response.statusCode; - - if (response.statusCode >= 200 && response.statusCode < 300) { - reset(); - notifyListeners(); - } - return response.statusCode; - } catch (error) { - return -1; } } - Future updateServiceReport({ - required String host, - required User user, - required ServiceReport report, - required ServiceRequest request, - }) async { - Response response; - Map body = report.toMap(); - body["uid"] = user.id ?? ""; - body["token"] = user.token ?? ""; - body["job_id"] = request.id ?? ''; - body["report_id"] = request.reportID ?? ''; - try { - response = await post( - Uri.parse(host + URLs.updateServiceReport), - body: body, - ); - stateCode = response.statusCode; - - if (response.statusCode >= 200 && response.statusCode < 300) { + Future updateServiceReport(BuildContext context, {required ServiceReport report, required ServiceRequest request}) async { + final subtitle = AppLocalization.of(context)?.subtitle; + await waitApiRequest( + () async { + await ServiceRequestApiClient().updateServiceReport(report: report, request: request); reset(); - notifyListeners(); - } - return response.statusCode; - } catch (error) { - return -1; - } + }, + onSuccess: () { + Fluttertoast.showToast(msg: subtitle?.requestCompleteSuccessfully ?? ''); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + + /// TODO : this is temporary + stateCode = 200; + }, + onError: (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; + String errorMessage = HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle); + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage))); + }, + ); } - Future updateServiceReportTimer({ - required String host, - required User user, - required TimerModel timer, - required ServiceRequest request, - }) async { - Response response; - Map body = {}; - body["uid"] = user.id ?? ""; - body["token"] = user.token ?? ""; - body["job_id"] = request.id ?? ''; - body["start_time"] = ((timer.startAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0); - body["end_time"] = ((timer.endAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0); - body["working_hours"] = ((timer.durationInSecond ?? 0) / 60 / 60).toStringAsFixed(5); - body["report_id"] = request.reportID ?? ''; + Future updateServiceReportTimer({required TimerModel timer, required ServiceRequest request}) async { try { - response = await post( - Uri.parse(host + URLs.updateServiceReport), - body: body, - ); - //stateCode = response.statusCode; + await ServiceRequestApiClient().updateServiceReportTimer(timer: timer, request: request); - if (response.statusCode >= 200 && response.statusCode < 300) { - // reset(); - // notifyListeners(); - } - return response.statusCode; - } catch (error) { - return -1; + /// TODO : this is temporary + stateCode = 200; + } on APIException catch (error) { + /// TODO : this is temporary + stateCode = error.error?.errorCode; } } - Future getSingleServiceReport({ - required String reportId, - required String host, - required User user, - required Subtitle subtitle, - }) async { - String userData = ''; - userData += "&uid=${user.id}"; - userData += "&token=${user.token}"; - - Response response; - try { - response = await get(Uri.parse( - '$host${URLs.getServiceReport}?report_id=$reportId$userData', - )); - } catch (error) { - throw (HttpStatusManger.getStatusMessage(status: -1, subtitle: subtitle) ?? ''); - } - - // If the call to the server was successful, parse the JSON. - if (response.statusCode >= 200 && response.statusCode < 300) { - // If the call to the server was successful, parse the JSON. - return ServiceReport.fromJson(json.decode(utf8.decode(response.bodyBytes)), reportId); - } else { - throw (HttpStatusManger.getStatusMessage( - status: response.statusCode, - subtitle: subtitle, - ) ?? - ''); - } + Future getSingleServiceReport({required String reportId}) async { + return await ServiceRequestApiClient().getSingleServiceReport(reportId: reportId); } } diff --git a/lib/controllers/providers/loading_notifier.dart b/lib/controllers/providers/loading_notifier.dart index 5d800b2d..b849956d 100644 --- a/lib/controllers/providers/loading_notifier.dart +++ b/lib/controllers/providers/loading_notifier.dart @@ -13,7 +13,7 @@ class LoadingNotifier with ChangeNotifier { /// - [fun] : Callback function that contains the API request. /// - [onError] : Optional callback function to handle the request on failure with [APIException] parameter. /// - [onSuccess] : Optional callback function to handle the request on succeed. - void waitApiRequest(Function fun, {Function(APIException)? onError, Function? onSuccess}) async { + Future waitApiRequest(Function fun, {Function(APIException)? onError, Function? onSuccess}) async { if (_loading == true) { debugPrint('loading_notifier.dart : another action already started'); return; diff --git a/lib/models/service_request/service_request_search.dart b/lib/models/service_request/service_request_search.dart index 5f381d20..bd617b58 100644 --- a/lib/models/service_request/service_request_search.dart +++ b/lib/models/service_request/service_request_search.dart @@ -20,26 +20,13 @@ class ServiceRequestSearch { model = newSearch.model; } - String toSearchString() { - String search = ""; - if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) { - search += "&sn_id=$deviceSerialNumber"; - } - - if (statusValue != null) { - search += "&status=$statusValue"; - } - - if (deviceName != null && (deviceName?.isNotEmpty ?? false)) { - search += "&equipment_en_name=$deviceName"; - } - - if (hospital != null && (hospital?.isNotEmpty ?? false)) { - search += "&client=$hospital"; - } - if (model != null && (model?.isNotEmpty ?? false)) { - search += "&model=$model"; - } - return search; + Map queryParameters() { + return { + if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) 'sn_id': deviceSerialNumber, + if (statusValue != null) 'status': statusValue?.toString(), + if (deviceName != null && (deviceName?.isNotEmpty ?? false)) 'equipment_en_name': deviceName, + if (hospital != null && (hospital?.isNotEmpty ?? false)) 'client': hospital, + if (model != null && (model?.isNotEmpty ?? false)) 'model': model, + }; } } diff --git a/lib/models/visits/visits_search.dart b/lib/models/visits/visits_search.dart index 9620c3e7..f4d2b9e2 100644 --- a/lib/models/visits/visits_search.dart +++ b/lib/models/visits/visits_search.dart @@ -36,47 +36,18 @@ class VisitsSearch { statusValue = newSearch.statusValue; } - String toSearchString() { - String _search = ""; - if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) { - _search += "&sn_id=$deviceSerialNumber"; - } - - if (hospitalName != null && (hospitalName?.isNotEmpty ?? false)) { - _search += "&client=$hospitalName"; - } - - if (brand != null && (brand?.isNotEmpty ?? false)) { - _search += "&brand=$brand"; - } - - if (model != null && (model?.isNotEmpty ?? false)) { - _search += "&model=$model"; - } - - if (expectedDateFrom != null) { - _search += "&expected_date_from=${(expectedDateFrom?.millisecondsSinceEpoch ?? 0) ~/ 1000}"; - } - - if (expectedDateTo != null) { - _search += "&expected_date_to=${(expectedDateTo?.millisecondsSinceEpoch ?? 0) ~/ 1000}"; - } - - if (actualDateFrom != null) { - _search += "&actual_date_from=${(actualDateFrom?.millisecondsSinceEpoch ?? 0) ~/ 1000}"; - } - - if (actualDateTo != null) { - _search += "&actual_date_to=${(actualDateTo?.millisecondsSinceEpoch ?? 0) ~/ 1000}"; - } - - if (statusValue != null) { - _search += "&status=$statusValue"; - } - - if (contactStatus != null) { - _search += "&assigned_to=$contactStatus"; - } - return _search; + Map queryParameters() { + return { + if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) 'sn_id': deviceSerialNumber, + if (statusValue != null) 'status': statusValue?.toString(), + if (hospitalName != null && (hospitalName?.isNotEmpty ?? false)) 'client': hospitalName, + if (brand != null && (brand?.isNotEmpty ?? false)) 'brand': brand, + if (model != null && (model?.isNotEmpty ?? false)) 'model': model, + if (expectedDateFrom != null) 'expected_date_from': (expectedDateFrom?.millisecondsSinceEpoch ?? 0) ~/ 1000, + if (expectedDateTo != null) 'expected_date_to': (expectedDateTo?.millisecondsSinceEpoch ?? 0) ~/ 1000, + if (actualDateFrom != null) 'actual_date_from': (actualDateFrom?.millisecondsSinceEpoch ?? 0) ~/ 1000, + if (actualDateTo != null) 'actual_date_to': (actualDateTo?.millisecondsSinceEpoch ?? 0) ~/ 1000, + if (contactStatus != null) 'assigned_to': contactStatus, + }; } } diff --git a/lib/views/pages/user/report_issues_page.dart b/lib/views/pages/user/report_issues_page.dart index 4728561f..f027f915 100644 --- a/lib/views/pages/user/report_issues_page.dart +++ b/lib/views/pages/user/report_issues_page.dart @@ -1,17 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; -import '../../../api/user_api_client.dart'; import '../../../controllers/localization/localization.dart'; import '../../../controllers/providers/api/service_requests_provider.dart'; -import '../../../controllers/providers/settings/setting_provider.dart'; -import '../../../controllers/providers/user_provider.dart'; import '../../../controllers/validator/validator.dart'; import '../../../models/issue.dart'; import '../../../models/service_request/service_request.dart'; -import '../../../models/subtitle.dart'; -import '../../../models/user.dart'; import '../../app_style/colors.dart'; import '../../app_style/sizing.dart'; import '../../widgets/app_text_form_field.dart'; @@ -25,27 +19,24 @@ class ReportIssuesPage extends StatefulWidget { final ServiceRequest? serviceRequest; const ReportIssuesPage({Key? key, this.serviceRequest}) : super(key: key); + @override - _ReportIssuesPageState createState() => _ReportIssuesPageState(); + ReportIssuesPageState createState() => ReportIssuesPageState(); } -class _ReportIssuesPageState extends State { - List _issues = []; - Issue _issue = Issue(reports: []); +class ReportIssuesPageState extends State { + final List _issues = []; + final Issue _issue = Issue(reports: []); late double _height; - bool _isLoading = false; late ServiceRequestsProvider _serviceRequestsProvider; - late UserProvider _userProvider; - late SettingProvider _settingProvider; final GlobalKey _formKey = GlobalKey(); + @override Widget build(BuildContext context) { - Subtitle _subtitle = AppLocalization.of(context)!.subtitle!; + final subtitle = AppLocalization.of(context)?.subtitle; _serviceRequestsProvider = Provider.of(context); - _userProvider = Provider.of(context); - _settingProvider = Provider.of(context); _height = MediaQuery.of(context).size.height; - _subtitle.setIssues(_issues); + subtitle?.setIssues(_issues); return Scaffold( body: SafeArea( child: Form( @@ -54,7 +45,7 @@ class _ReportIssuesPageState extends State { onRefresh: () async {}, stateCode: 200, isFailedLoading: false, - isLoading: _isLoading, + isLoading: _serviceRequestsProvider.loading, child: Stack( children: [ SingleChildScrollView( @@ -67,27 +58,21 @@ class _ReportIssuesPageState extends State { vertical: 24 * AppStyle.getScaleFactor(context), ), child: Text( - _subtitle.reportIssue, - style: Theme.of(context).textTheme.headline5?.copyWith(color: AColors.cyan, fontWeight: FontWeight.bold), + subtitle?.reportIssue ?? '', + style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: AColors.cyan, fontWeight: FontWeight.bold), ), ), ), - Image( - height: _height / 8, - image: AssetImage("assets/images/logo.png"), - ), + Image(height: _height / 8, image: const AssetImage("assets/images/logo.png")), Container( - padding: EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), decoration: BoxDecoration( color: AColors.grey, borderRadius: BorderRadius.only( topLeft: Radius.circular(AppStyle.getBorderRadius(context)), topRight: Radius.circular(AppStyle.getBorderRadius(context)), ), - boxShadow: [ + boxShadow: const [ BoxShadow( color: AColors.grey, offset: Offset(0, -1), @@ -97,19 +82,17 @@ class _ReportIssuesPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ ATextFormField( - initialValue: _issue?.title, - hintText: _subtitle.title, + initialValue: _issue.title, + hintText: subtitle?.title, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.headline6, - validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.titleValidateMessage, + style: Theme.of(context).textTheme.titleLarge, + validator: (value) => Validator.hasValue(value) ? null : subtitle?.titleValidateMessage, textInputType: TextInputType.name, onSaved: (value) { _issue.title = value; }, ), - SizedBox( - height: 8, - ), + const SizedBox(height: 8), Column( children: List.generate( _issues.length, @@ -128,13 +111,13 @@ class _ReportIssuesPageState extends State { Padding( padding: const EdgeInsets.all(8.0), child: Text( - "${_subtitle.shareAntherIssue} :", - style: Theme.of(context).textTheme.headline6, + "${subtitle?.shareAntherIssue} :", + style: Theme.of(context).textTheme.titleLarge, ), ), ATextFormField( - hintText: _subtitle.description, - style: Theme.of(context).textTheme.subtitle1, + hintText: subtitle?.description, + style: Theme.of(context).textTheme.titleMedium, textInputType: TextInputType.multiline, onSaved: (value) { _issue.description = value; @@ -143,28 +126,13 @@ class _ReportIssuesPageState extends State { Padding( padding: const EdgeInsets.all(8.0), child: AButton( - text: _subtitle.submit, + text: subtitle?.submit ?? '', onPressed: () async { - if (!(_formKey.currentState?.validate() ?? false)) return; - _formKey.currentState?.save(); - _issue.serviceRequestId = widget.serviceRequest?.id; - _isLoading = true; - setState(() {}); - int status = await _serviceRequestsProvider.createIssueReport( - user: UserApiClient().user ?? User(), - host: _settingProvider.host ?? "", - issue: _issue, - ); - _isLoading = false; - setState(() {}); - if (status >= 200 && status < 300) { - Fluttertoast.showToast( - msg: _subtitle.requestCompleteSuccessfully, - ); - Navigator.of(context).pop(); + if (_formKey.currentState?.validate() ?? false) { + _issue.serviceRequestId = widget.serviceRequest?.id; + _formKey.currentState?.save(); + await _serviceRequestsProvider.createIssueReport(context, issue: _issue); } - _isLoading = false; - setState(() {}); }, ), ), @@ -174,7 +142,7 @@ class _ReportIssuesPageState extends State { ], ), ), - ABackButton(), + const ABackButton(), ], ), ), diff --git a/lib/views/pages/user/requests/future_request_service_details.dart b/lib/views/pages/user/requests/future_request_service_details.dart index 73d24154..5eb9531b 100644 --- a/lib/views/pages/user/requests/future_request_service_details.dart +++ b/lib/views/pages/user/requests/future_request_service_details.dart @@ -1,13 +1,10 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import '../../../../api/user_api_client.dart'; -import '../../../../controllers/localization/localization.dart'; import '../../../../controllers/providers/api/service_requests_provider.dart'; import '../../../../controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/user_provider.dart'; import '../../../../models/service_request/service_request.dart'; -import '../../../../models/subtitle.dart'; import '../../../widgets/loaders/app_loading.dart'; import '../../../widgets/loaders/failed_loading.dart'; import 'request_details.dart'; @@ -29,10 +26,9 @@ class _FutureRequestServiceDetailsState extends State(context); _settingProvider = Provider.of(context); String? requestId = ModalRoute.of(context)?.settings.arguments as String?; - Subtitle _subtitle = AppLocalization.of(context)!.subtitle!; return Scaffold( body: FutureBuilder( - future: ServiceRequestsProvider().getSingleServiceRequest(requestId: requestId ?? '', user: UserApiClient().user!, host: _settingProvider.host ?? "", subtitle: _subtitle), + future: ServiceRequestsProvider().getSingleServiceRequest(requestId: requestId), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasError) { return FailedLoading( diff --git a/lib/views/pages/user/requests/report/create_service_report.dart b/lib/views/pages/user/requests/report/create_service_report.dart index 27370cbc..e37a8f95 100644 --- a/lib/views/pages/user/requests/report/create_service_report.dart +++ b/lib/views/pages/user/requests/report/create_service_report.dart @@ -2,15 +2,11 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; -import '../../../../../api/user_api_client.dart'; -import '../../../../../controllers/http_status_manger/http_status_manger.dart'; import '../../../../../controllers/localization/localization.dart'; import '../../../../../controllers/providers/api/service_requests_provider.dart'; import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; -import '../../../../../controllers/providers/settings/setting_provider.dart'; import '../../../../../controllers/validator/validator.dart'; import '../../../../../models/device/device.dart'; import '../../../../../models/lookup.dart'; @@ -48,12 +44,10 @@ class CreateServiceReport extends StatefulWidget { } class CreateServiceReportState extends State with TickerProviderStateMixin { - SettingProvider? _settingProvider; ServiceRequestsProvider? _serviceRequestsProvider; bool _validate = false; ServiceReport? _serviceReport; - bool _isLoading = false; Subtitle? _subtitle; File? _image; @@ -84,14 +78,13 @@ class CreateServiceReportState extends State with TickerPro @override Widget build(BuildContext context) { - _settingProvider = Provider.of(context); _serviceRequestsProvider = Provider.of(context); _subtitle = AppLocalization.of(context)?.subtitle; return Scaffold( key: _scaffoldKey, body: SafeArea( child: LoadingManager( - isLoading: _isLoading, + isLoading: _serviceRequestsProvider?.loading, isFailedLoading: false, stateCode: 200, onRefresh: () async {}, @@ -110,15 +103,15 @@ class CreateServiceReportState extends State with TickerPro padding: const EdgeInsets.all(8.0), child: Text( _subtitle?.newServiceReport ?? "", - style: Theme.of(context).textTheme.headline5?.copyWith(color: AColors.cyan, fontSize: 28, fontWeight: FontWeight.bold), + style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: AColors.cyan, fontSize: 28, fontWeight: FontWeight.bold), ), ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 16), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), - decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: [ - const BoxShadow( + decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: const [ + BoxShadow( color: AColors.grey, offset: Offset(0, -1), ) @@ -144,7 +137,7 @@ class CreateServiceReportState extends State with TickerPro ), Text( "${_subtitle?.customer}: ${widget.request?.hospitalName}", - style: Theme.of(context).textTheme.subtitle1?.copyWith( + style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, fontSize: 12, ), @@ -343,7 +336,7 @@ class CreateServiceReportState extends State with TickerPro ATextFormField( initialValue: _serviceReport?.invoiceNumber ?? "", textAlign: TextAlign.center, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "", textInputType: TextInputType.number, onSaved: (value) { @@ -367,7 +360,7 @@ class CreateServiceReportState extends State with TickerPro ATextFormField( initialValue: _serviceReport?.invoiceCode ?? "", textAlign: TextAlign.center, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "", textInputType: TextInputType.text, onSaved: (value) { @@ -389,10 +382,7 @@ class CreateServiceReportState extends State with TickerPro Expanded( child: SizedBox( height: 32 * AppStyle.getScaleFactor(context), - child: SpeechToTextButton( - controller: _faultController, - mini: true, - ), + child: SpeechToTextButton(controller: _faultController, mini: true), ), ), ], @@ -404,7 +394,7 @@ class CreateServiceReportState extends State with TickerPro initialValue: _serviceReport?.faultDescription ?? "", textAlign: TextAlign.center, controller: _faultController, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "", textInputType: TextInputType.multiline, onSaved: (value) { @@ -435,7 +425,7 @@ class CreateServiceReportState extends State with TickerPro initialValue: _serviceReport?.workPreformed ?? "", textAlign: TextAlign.center, controller: _workPreformedController, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "", textInputType: TextInputType.multiline, onSaved: (value) { @@ -542,7 +532,7 @@ class CreateServiceReportState extends State with TickerPro initialValue: _serviceReport?.travelingHours, textAlign: TextAlign.center, hintText: "i.e 3, 3.5, 4", - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, // validator: (value) => // Validator.isNumeric(value) // ? null : _subtitle.requiredWord, @@ -596,7 +586,7 @@ class CreateServiceReportState extends State with TickerPro ATextFormField( initialValue: _serviceReport?.jobSheetNumber, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, textInputType: TextInputType.name, onSaved: (value) { _serviceReport?.jobSheetNumber = value; @@ -649,9 +639,9 @@ class CreateServiceReportState extends State with TickerPro ), Column( children: List.generate(_serviceReport!.parts!.length, (index) { - Part _part = _serviceReport!.parts![index]; + Part part = _serviceReport!.parts![index]; return PartItem( - part: _part, + part: part, onDelete: (part) { _serviceReport!.parts!.remove(part); setState(() {}); @@ -672,31 +662,9 @@ class CreateServiceReportState extends State with TickerPro text: _subtitle?.submit ?? "", onPressed: () async { _validate = true; - if (!(_formKey.currentState?.validate() ?? false)) { - setState(() {}); - return; - } - if (!(_serviceReport?.validate() ?? false)) return; - _formKey.currentState?.save(); - - _isLoading = true; - setState(() {}); - - int? status = - await _serviceRequestsProvider?.createServiceReport(user: UserApiClient().user!, host: _settingProvider?.host ?? "", report: _serviceReport!, request: widget.request!); - _isLoading = false; - setState(() {}); - if (status != null && status >= 200 && status < 300) { - Fluttertoast.showToast( - msg: _subtitle?.requestCompleteSuccessfully ?? "", - ); - Navigator.of(context).pop(); - Navigator.of(context).pop(); - } else { - String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle); - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(errorMessage), - )); + if (_formKey.currentState?.validate() ?? false) { + _formKey.currentState?.save(); + await _serviceRequestsProvider?.createServiceReport(context, report: _serviceReport, request: widget.request); } }, ), diff --git a/lib/views/pages/user/requests/report/edit_service_report.dart b/lib/views/pages/user/requests/report/edit_service_report.dart index 36a72cb2..90a7113a 100644 --- a/lib/views/pages/user/requests/report/edit_service_report.dart +++ b/lib/views/pages/user/requests/report/edit_service_report.dart @@ -2,16 +2,11 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; -import '../../../../../api/user_api_client.dart'; -import '../../../../../controllers/http_status_manger/http_status_manger.dart'; import '../../../../../controllers/localization/localization.dart'; import '../../../../../controllers/providers/api/service_requests_provider.dart'; import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; -import '../../../../../controllers/providers/settings/setting_provider.dart'; -import '../../../../../controllers/providers/user_provider.dart'; import '../../../../../controllers/validator/validator.dart'; import '../../../../../models/part.dart'; import '../../../../../models/service_report.dart'; @@ -38,30 +33,27 @@ import '../../../../widgets/timer/app_timer.dart'; import '../../../../widgets/titles/app_sub_title.dart'; class EditServiceReport extends StatefulWidget { - static final String id = "/edit-service-report"; + static const String id = "/edit-service-report"; final ServiceRequest request; final ServiceReport report; const EditServiceReport({Key? key, required this.request, required this.report}) : super(key: key); + @override - _EditServiceReportState createState() => _EditServiceReportState(); + EditServiceReportState createState() => EditServiceReportState(); } -class _EditServiceReportState extends State with TickerProviderStateMixin { - late UserProvider _userProvider; - late SettingProvider _settingProvider; +class EditServiceReportState extends State with TickerProviderStateMixin { late ServiceRequestsProvider _serviceRequestsProvider; bool _validate = false; late ServiceReport _serviceReport; - bool _isLoading = false; - late Subtitle _subtitle; late File _image; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - TextEditingController _faultController = TextEditingController(); - TextEditingController _workPreformedController = TextEditingController(); + final TextEditingController _faultController = TextEditingController(); + final TextEditingController _workPreformedController = TextEditingController(); @override void initState() { @@ -78,15 +70,13 @@ class _EditServiceReportState extends State with TickerProvid @override Widget build(BuildContext context) { - _userProvider = Provider.of(context); - _settingProvider = Provider.of(context); _serviceRequestsProvider = Provider.of(context); _subtitle = AppLocalization.of(context)!.subtitle!; return Scaffold( key: _scaffoldKey, body: SafeArea( child: LoadingManager( - isLoading: _isLoading, + isLoading: _serviceRequestsProvider.loading, isFailedLoading: false, stateCode: 200, onRefresh: () async {}, @@ -105,14 +95,14 @@ class _EditServiceReportState extends State with TickerProvid padding: const EdgeInsets.all(8.0), child: Text( _subtitle.editServiceReport, - style: Theme.of(context).textTheme.headline5?.copyWith(color: AColors.cyan, fontSize: 28, fontWeight: FontWeight.bold), + style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: AColors.cyan, fontSize: 28, fontWeight: FontWeight.bold), ), ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 16), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), - decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: [ + decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: const [ BoxShadow( color: AColors.grey, offset: Offset(0, -1), @@ -121,28 +111,15 @@ class _EditServiceReportState extends State with TickerProvid child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), Wrap( spacing: 10, children: [ - ASubTitle( - "${_subtitle.callId}: ${widget.request.requestCode}", - font: 14, - ), - widget.request.deviceSerialNumber == null - ? const SizedBox() - : ASubTitle( - "${_subtitle.deviceSN}: ${widget.request.deviceSerialNumber}", - font: 14, - ), + ASubTitle("${_subtitle.callId}: ${widget.request.requestCode}", font: 14), + widget.request.deviceSerialNumber == null ? const SizedBox() : ASubTitle("${_subtitle.deviceSN}: ${widget.request.deviceSerialNumber}", font: 14), Text( "${_subtitle.customer}: ${widget.request.hospitalName}", - style: Theme.of(context).textTheme.subtitle1?.copyWith( - fontWeight: FontWeight.bold, - fontSize: 12, - ), + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold, fontSize: 12), textScaleFactor: AppStyle.getScaleFactor(context), ) ], @@ -158,15 +135,8 @@ class _EditServiceReportState extends State with TickerProvid crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.reportType), - _validate && _serviceReport.type == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), - const SizedBox( - height: 4, - ), + _validate && _serviceReport.type == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(), + const SizedBox(height: 4), ServiceReportTypeMenu( initialValue: _serviceReport.type, onSelect: (status) { @@ -176,21 +146,14 @@ class _EditServiceReportState extends State with TickerProvid ], ), ), - const SizedBox( - width: 8, - ), + const SizedBox(width: 8), // visit date Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.visitDate), - _validate && _serviceReport.visitDate == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), + _validate && _serviceReport.visitDate == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(), Row( children: [ Expanded( @@ -211,9 +174,7 @@ class _EditServiceReportState extends State with TickerProvid ), ], ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), // device sn Visibility( visible: true, //widget.report.device == null, @@ -221,12 +182,7 @@ class _EditServiceReportState extends State with TickerProvid crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.deviceSN), - _validate && _serviceReport.device?.id == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), + _validate && _serviceReport.device?.id == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(), AutoCompleteDeviceField( hospitalId: widget.request.hospitalId, initialValue: _serviceReport.device!, @@ -234,34 +190,21 @@ class _EditServiceReportState extends State with TickerProvid _serviceReport.device?.id = id; }, ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), ], ), ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), ASubTitle(_subtitle.serviceType), - _validate && _serviceReport.serviceType == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), - const SizedBox( - height: 4, - ), + _validate && _serviceReport.serviceType == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(), + const SizedBox(height: 4), ServiceStatusMenu( initialValue: _serviceReport.serviceType, onSelect: (status) { _serviceReport.serviceType = status; }, ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), // Report status and Service Type Row( children: [ @@ -271,15 +214,8 @@ class _EditServiceReportState extends State with TickerProvid crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.reportStatus), - _validate && _serviceReport.status == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), - const SizedBox( - height: 4, - ), + _validate && _serviceReport.status == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(), + const SizedBox(height: 4), ServiceReportStatusMenu( report: _serviceReport, onSelect: (status) { @@ -289,9 +225,7 @@ class _EditServiceReportState extends State with TickerProvid ], ), ), - const SizedBox( - width: 8, - ), + const SizedBox(width: 8), Provider.of(context).isLoading == null ? const SizedBox.shrink() : @@ -301,15 +235,8 @@ class _EditServiceReportState extends State with TickerProvid crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.callLastSituation), - _validate && _serviceReport.callLastSituation == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), - const SizedBox( - height: 4, - ), + _validate && _serviceReport.callLastSituation == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(), + const SizedBox(height: 4), ServiceReportLastCallsMenu( report: _serviceReport, onSelect: (status) { @@ -326,9 +253,7 @@ class _EditServiceReportState extends State with TickerProvid ), ], ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), // invoice number & code _serviceReport.callLastSituation?.id != 12 ? const SizedBox.shrink() @@ -339,13 +264,11 @@ class _EditServiceReportState extends State with TickerProvid crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.invoiceNumber), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), ATextFormField( - initialValue: _serviceReport?.invoiceNumber, + initialValue: _serviceReport.invoiceNumber, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord, textInputType: TextInputType.number, onSaved: (value) { @@ -355,21 +278,17 @@ class _EditServiceReportState extends State with TickerProvid ], ), ), - const SizedBox( - width: 8, - ), + const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.invoiceCode), - const SizedBox( - height: 4, - ), + const SizedBox(height: 4), ATextFormField( - initialValue: _serviceReport?.invoiceCode, + initialValue: _serviceReport.invoiceCode, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord, textInputType: TextInputType.text, onSaved: (value) { @@ -382,19 +301,14 @@ class _EditServiceReportState extends State with TickerProvid ], ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), Row( children: [ ASubTitle(_subtitle.faultDescription), Expanded( child: SizedBox( height: 32 * AppStyle.getScaleFactor(context), - child: SpeechToTextButton( - controller: _faultController, - mini: true, - ), + child: SpeechToTextButton(controller: _faultController, mini: true), ), ), ], @@ -403,29 +317,24 @@ class _EditServiceReportState extends State with TickerProvid height: 4, ), ATextFormField( - initialValue: _serviceReport?.faultDescription, + initialValue: _serviceReport.faultDescription, textAlign: TextAlign.center, controller: _faultController, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord, textInputType: TextInputType.multiline, onSaved: (value) { _serviceReport.faultDescription = value; }, ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), Row( children: [ ASubTitle(_subtitle.workPreformed), Expanded( child: SizedBox( height: 32 * AppStyle.getScaleFactor(context), - child: SpeechToTextButton( - controller: _workPreformedController, - mini: true, - ), + child: SpeechToTextButton(controller: _workPreformedController, mini: true), ), ), ], @@ -434,10 +343,10 @@ class _EditServiceReportState extends State with TickerProvid height: 4, ), ATextFormField( - initialValue: _serviceReport?.workPreformed, + initialValue: _serviceReport.workPreformed, textAlign: TextAlign.center, controller: _workPreformedController, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord, textInputType: TextInputType.multiline, onSaved: (value) { @@ -503,9 +412,7 @@ class _EditServiceReportState extends State with TickerProvid crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.workingHours), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), AppTimer( timer: _serviceReport.timer, onChange: (timer) async { @@ -529,22 +436,18 @@ class _EditServiceReportState extends State with TickerProvid ], ), ), - const SizedBox( - width: 8, - ), + const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ASubTitle(_subtitle.travelingHours), - const SizedBox( - height: 4, - ), + const SizedBox(height: 4), ATextFormField( - initialValue: _serviceReport?.travelingHours, + initialValue: _serviceReport.travelingHours, textAlign: TextAlign.center, hintText: "i.e 3, 3.5, 4", - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.isNumeric(value!) ? '' : _subtitle.requiredWord, textInputType: TextInputType.number, onSaved: (value) { @@ -556,9 +459,7 @@ class _EditServiceReportState extends State with TickerProvid ), ], ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), // Operating Hours and Job Sheet Number Row( children: [ @@ -571,10 +472,10 @@ class _EditServiceReportState extends State with TickerProvid height: 4, ), ATextFormField( - initialValue: _serviceReport?.operatingHours, + initialValue: _serviceReport.operatingHours, textAlign: TextAlign.center, hintText: "i.e 3, 3.5, 4", - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, validator: (value) => Validator.isNumeric(value!) ? '' : _subtitle.requiredWord, textInputType: TextInputType.number, onSaved: (value) { @@ -596,9 +497,9 @@ class _EditServiceReportState extends State with TickerProvid height: 4, ), ATextFormField( - initialValue: _serviceReport?.jobSheetNumber, + initialValue: _serviceReport.jobSheetNumber, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, textInputType: TextInputType.name, onSaved: (value) { _serviceReport.jobSheetNumber = value; @@ -609,9 +510,7 @@ class _EditServiceReportState extends State with TickerProvid ), ], ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), // Part Number and Quantity Row( children: [ @@ -652,9 +551,9 @@ class _EditServiceReportState extends State with TickerProvid ), Column( children: List.generate(_serviceReport.parts!.length, (index) { - Part _part = _serviceReport.parts![index]; + Part part = _serviceReport.parts![index]; return PartItem( - part: _part, + part: part, onDelete: (part) { _serviceReport.parts?.remove(part); setState(() {}); @@ -663,9 +562,7 @@ class _EditServiceReportState extends State with TickerProvid }), ), - const SizedBox( - height: 16, - ), + const SizedBox(height: 16), ], ), ), @@ -675,34 +572,9 @@ class _EditServiceReportState extends State with TickerProvid text: _subtitle.update, onPressed: () async { _validate = true; - if (!(_formKey.currentState?.validate() ?? false)) { - setState(() {}); - return; - } - if (!_serviceReport.validate()) { - setState(() {}); - return; - } - _formKey.currentState?.save(); - - _isLoading = true; - setState(() {}); - - int status = - await _serviceRequestsProvider.updateServiceReport(user: UserApiClient().user!, host: _settingProvider.host ?? "", report: _serviceReport, request: widget.request); - _isLoading = false; - setState(() {}); - if (status >= 200 && status < 300) { - Fluttertoast.showToast( - msg: _subtitle.requestCompleteSuccessfully, - ); - Navigator.of(context).pop(); - Navigator.of(context).pop(); - } else { - String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle); - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(errorMessage), - )); + if (_formKey.currentState?.validate() ?? false) { + _formKey.currentState?.save(); + await _serviceRequestsProvider.updateServiceReport(context, report: _serviceReport, request: widget.request); } }, ), diff --git a/lib/views/pages/user/requests/report/future_service_report.dart b/lib/views/pages/user/requests/report/future_service_report.dart index 38e8ac77..9cb2253e 100644 --- a/lib/views/pages/user/requests/report/future_service_report.dart +++ b/lib/views/pages/user/requests/report/future_service_report.dart @@ -1,14 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import '../../../../../api/user_api_client.dart'; -import '../../../../../controllers/localization/localization.dart'; import '../../../../../controllers/providers/api/service_requests_provider.dart'; -import '../../../../../controllers/providers/settings/setting_provider.dart'; -import '../../../../../controllers/providers/user_provider.dart'; import '../../../../../models/service_report.dart'; import '../../../../../models/service_request/service_request.dart'; -import '../../../../../models/subtitle.dart'; import '../../../../widgets/loaders/app_loading.dart'; import '../../../../widgets/loaders/failed_loading.dart'; import 'edit_service_report.dart'; @@ -19,35 +13,28 @@ class FutureServiceReport extends StatefulWidget { const FutureServiceReport({Key? key, required this.request}) : super(key: key); @override - _FutureServiceReportState createState() => _FutureServiceReportState(); + FutureServiceReportState createState() => FutureServiceReportState(); } -class _FutureServiceReportState extends State { - late UserProvider _userProvider; - late SettingProvider _settingProvider; +class FutureServiceReportState extends State { @override Widget build(BuildContext context) { - _userProvider = Provider.of(context); - _settingProvider = Provider.of(context); - Subtitle _subtitle = AppLocalization.of(context)!.subtitle!; return Scaffold( - body: FutureBuilder( - future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.request.reportID ?? "", user: UserApiClient().user!, host: _settingProvider.host ?? "", subtitle: _subtitle), - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasError) + body: FutureBuilder( + future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.request.reportID ?? ""), + builder: (BuildContext context, snapshot) { + if (snapshot.hasError) { return FailedLoading( message: snapshot.error.toString(), onReload: () { setState(() {}); }, ); + } if (snapshot.hasData) { - return EditServiceReport( - report: snapshot.data!, - request: widget.request, - ); + return EditServiceReport(report: snapshot.data!, request: widget.request); } - return Center(child: ALoading()); + return const Center(child: ALoading()); }, ), ); diff --git a/lib/views/pages/user/requests/request_details.dart b/lib/views/pages/user/requests/request_details.dart index 46074004..8c783354 100644 --- a/lib/views/pages/user/requests/request_details.dart +++ b/lib/views/pages/user/requests/request_details.dart @@ -3,20 +3,15 @@ import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import '../../../../api/user_api_client.dart'; -import '../../../../controllers/http_status_manger/http_status_manger.dart'; import '../../../../controllers/localization/localization.dart'; import '../../../../controllers/providers/api/service_requests_provider.dart'; -import '../../../../controllers/providers/settings/setting_provider.dart'; -import '../../../../controllers/providers/user_provider.dart'; import '../../../../models/enums/user_types.dart'; import '../../../../models/service_request/service_request.dart'; -import '../../../../models/subtitle.dart'; import '../../../app_style/colors.dart'; import '../../../app_style/sizing.dart'; import '../../../widgets/buttons/app_back_button.dart'; import '../../../widgets/buttons/app_button.dart'; import '../../../widgets/buttons/app_icon_button.dart'; -import '../../../widgets/dialogs/dialog.dart'; import '../../../widgets/images/images_list.dart'; import '../../../widgets/loaders/image_loader.dart'; import '../../../widgets/requests/info_row.dart'; @@ -29,16 +24,15 @@ import 'report/create_service_report.dart'; import 'report/future_service_report.dart'; class RequestDetailsPage extends StatelessWidget { - static final String id = "/call-details"; + static const String id = "/call-details"; final ServiceRequest serviceRequest; const RequestDetailsPage({Key? key, required this.serviceRequest}) : super(key: key); + @override Widget build(BuildContext context) { - Subtitle _subtitle = AppLocalization.of(context)!.subtitle!; - UserProvider _userProvider = Provider.of(context); - SettingProvider _settingProvider = Provider.of(context); - ServiceRequestsProvider _serviceRequestsProvider = Provider.of(context); + final subtitle = AppLocalization.of(context)?.subtitle; + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context); return DefaultTabController( length: 2, child: Scaffold( @@ -50,12 +44,12 @@ class RequestDetailsPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), child: Row( children: [ - ABackButton(), + const ABackButton(), Expanded( child: Center( child: Text( - _subtitle.details, - style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), + subtitle?.details ?? '', + style: Theme.of(context).textTheme.titleLarge?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), ), ), ), @@ -70,9 +64,7 @@ class RequestDetailsPage extends StatelessWidget { showModalBottomSheet( context: context, builder: (context) { - return ServiceRequestsUpdateDialog( - request: serviceRequest, - ); + return ServiceRequestsUpdateDialog(request: serviceRequest); }); // DateTime picked = await showDatePicker( // context: context, @@ -109,173 +101,98 @@ class RequestDetailsPage extends StatelessWidget { buttonSize: 42, backgroundColor: AColors.deepOrange, onPressed: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => ReportIssuesPage( - serviceRequest: serviceRequest, - ))); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => ReportIssuesPage(serviceRequest: serviceRequest))); }, ), ), - SizedBox( - width: 16, - ) + const SizedBox(width: 16) ], ), ), (serviceRequest.devicePhotos?.isEmpty ?? false) - ? SizedBox.shrink() + ? const SizedBox.shrink() : Column( children: [ - SizedBox( - height: 8, - ), + const SizedBox(height: 8), MaterialButton( padding: EdgeInsets.zero, onPressed: () { - Navigator.of(context).push(MaterialPageRoute( + Navigator.of(context).push( + MaterialPageRoute( builder: (_) => Scaffold( - body: InteractiveViewer( - child: Center( - child: ImageLoader( - url: serviceRequest.devicePhotos?.first, - boxFit: BoxFit.contain, - ), - ), - ), - ))); + body: InteractiveViewer( + child: Center(child: ImageLoader(url: serviceRequest.devicePhotos?.first, boxFit: BoxFit.contain)), + ), + ), + ), + ); }, child: SizedBox( height: 140 * AppStyle.getScaleFactor(context), width: MediaQuery.of(context).size.width, - child: ImageLoader( - url: serviceRequest.devicePhotos?.first, - boxFit: BoxFit.cover, - ), + child: ImageLoader(url: serviceRequest.devicePhotos?.first, boxFit: BoxFit.cover), ), ), - SizedBox( - height: 8, - ), + const SizedBox(height: 8), SizedBox( height: 60 * AppStyle.getScaleFactor(context), - child: ImagesList( - images: serviceRequest.devicePhotos!, - ), + child: ImagesList(images: serviceRequest.devicePhotos!), ), ], ), - TabBar(labelColor: AColors.primaryColor, tabs: [ - Tab( - text: _subtitle.general, - ), - Tab( - text: _subtitle.serviceRequestInformation, - ), - ]), - SizedBox( - height: 8, + TabBar( + labelColor: AColors.primaryColor, + tabs: [ + Tab(text: subtitle?.general), + Tab(text: subtitle?.serviceRequestInformation), + ], ), + const SizedBox(height: 8), Expanded( child: TabBarView( children: [ ListView( - padding: EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.symmetric(horizontal: 16), children: [ - RequestInfoRow( - title: _subtitle.code, - info: serviceRequest.requestCode, - ), - RequestInfoRow( - title: "Asset Number", - info: serviceRequest.deviceNumber, - ), - RequestInfoRow( - title: _subtitle.deviceSN, - info: serviceRequest.deviceSerialNumber, - ), - RequestInfoRow( - title: _subtitle.deviceModel, - info: serviceRequest.deviceModel, - ), - RequestInfoRow( - title: _subtitle.engineerName, - info: serviceRequest.engineerName, - ), - RequestInfoRow( - title: _subtitle.engineerPhone, - info: serviceRequest.engineerMobile, - ), - RequestInfoRow( - title: _subtitle.date, - info: serviceRequest.date, - ), + RequestInfoRow(title: subtitle?.code, info: serviceRequest.requestCode), + RequestInfoRow(title: "Asset Number", info: serviceRequest.deviceNumber), + RequestInfoRow(title: subtitle?.deviceSN, info: serviceRequest.deviceSerialNumber), + RequestInfoRow(title: subtitle?.deviceModel, info: serviceRequest.deviceModel), + RequestInfoRow(title: subtitle?.engineerName, info: serviceRequest.engineerName), + RequestInfoRow(title: subtitle?.engineerPhone, info: serviceRequest.engineerMobile), + RequestInfoRow(title: subtitle?.date, info: serviceRequest.date), serviceRequest.nextVisitDate == null - ? SizedBox.shrink() - : RequestInfoRow( - title: _subtitle.nextVisitDate, - info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate!), - ), + ? const SizedBox.shrink() + : RequestInfoRow(title: subtitle?.nextVisitDate, info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate!)), Row( children: [ Expanded( child: Text( - "${_subtitle.status} : ", - style: Theme.of(context).textTheme.subtitle1, + "${subtitle?.status} : ", + style: Theme.of(context).textTheme.titleMedium, textScaleFactor: AppStyle.getScaleFactor(context), ), ), StatusLabel(label: serviceRequest.statusLabel, color: AColors.getRequestStatusColor(serviceRequest.statusValue!)), ], ), - Divider( - color: Theme.of(context).primaryColor, - ), - RequestInfoRow( - title: _subtitle.hospital, - info: serviceRequest.hospitalName, - ), - RequestInfoRow( - title: _subtitle.unite, - info: serviceRequest.departmentName, - ), + Divider(color: Theme.of(context).primaryColor), + RequestInfoRow(title: subtitle?.hospital, info: serviceRequest.hospitalName), + RequestInfoRow(title: subtitle?.unite, info: serviceRequest.departmentName), // RequestInfoRow( // title: _subtitle.deviceArName, // content: serviceRequest.deviceArName, // ), - RequestInfoRow( - title: _subtitle.deviceEnName, - content: serviceRequest.deviceEnName, - ), - RequestInfoRow( - title: _subtitle.maintenanceIssue, - content: serviceRequest.maintenanceIssue, - ), - if (serviceRequest.audio?.isNotEmpty == true) - ASoundPlayer( - audio: serviceRequest.audio, - ), + RequestInfoRow(title: subtitle?.deviceEnName, content: serviceRequest.deviceEnName), + RequestInfoRow(title: subtitle?.maintenanceIssue, content: serviceRequest.maintenanceIssue), + if (serviceRequest.audio?.isNotEmpty == true) ASoundPlayer(audio: serviceRequest.audio), Center( child: Padding( - padding: EdgeInsets.all(32), + padding: const EdgeInsets.all(32), child: AButton( - text: _subtitle.duplicateRequest, + text: subtitle?.duplicateRequest ?? '', onPressed: () async { - bool result = await showDialog( - context: context, - builder: (_) => AAlertDialog( - title: _subtitle.duplicateAlert, - content: _subtitle.duplicateAlertMessage, - )); - if (result == true) { - showDialog( - context: context, - builder: (context) { - return Center(child: CircularProgressIndicator()); - }); - int status = await _serviceRequestsProvider.createDuplicatedReport(host: _settingProvider.host ?? "", user: UserApiClient().user!, request: serviceRequest); - Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle)))); - } + await serviceRequestsProvider.createDuplicatedReport(context, request: serviceRequest); }, ), ), @@ -284,62 +201,42 @@ class RequestDetailsPage extends StatelessWidget { ), serviceRequest.viewReport ?? false ? ListView( - padding: EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.symmetric(horizontal: 16), children: [ - RequestInfoRow( - title: _subtitle.faultDescription, - content: serviceRequest.faultDescription, - ), - RequestInfoRow( - title: _subtitle.workPerformed, - content: serviceRequest.workPerformed, - ), - RequestInfoRow( - title: _subtitle.visitDate, - info: serviceRequest.visitDate, - ), - RequestInfoRow( - title: _subtitle.jobSheetNumber, - info: serviceRequest.jobSheetNumber, - ), + RequestInfoRow(title: subtitle?.faultDescription, content: serviceRequest.faultDescription), + RequestInfoRow(title: subtitle?.workPerformed, content: serviceRequest.workPerformed), + RequestInfoRow(title: subtitle?.visitDate, info: serviceRequest.visitDate), + RequestInfoRow(title: subtitle?.jobSheetNumber, info: serviceRequest.jobSheetNumber), UserApiClient().user?.type == UsersTypes.engineer ? Padding( - padding: EdgeInsets.all(32), + padding: const EdgeInsets.all(32), child: AButton( - text: _subtitle.editServiceReport, + text: subtitle?.editServiceReport ?? '', onPressed: () { Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => FutureServiceReport( - request: serviceRequest, - )), + MaterialPageRoute(builder: (_) => FutureServiceReport(request: serviceRequest)), ); }, ), ) - : SizedBox.shrink(), + : const SizedBox.shrink(), ], ) : UserApiClient().user?.type == UsersTypes.engineer ? Center( child: Padding( - padding: EdgeInsets.all(32), + padding: const EdgeInsets.all(32), child: AButton( text: "Create Report", onPressed: () { Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => CreateServiceReport( - request: serviceRequest, - )), + MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)), ); }, ), ), ) - : Center( - child: ASubTitle(_subtitle.noDateFound), - ), + : Center(child: ASubTitle(subtitle?.noDateFound ?? '')), ], ), ), diff --git a/lib/views/pages/user/requests/requests_page.dart b/lib/views/pages/user/requests/requests_page.dart index ab0eba6b..30731d4e 100644 --- a/lib/views/pages/user/requests/requests_page.dart +++ b/lib/views/pages/user/requests/requests_page.dart @@ -2,10 +2,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/api/service_request_api_client.dart'; -import '../../../../api/user_api_client.dart'; import '../../../../controllers/localization/localization.dart'; import '../../../../controllers/providers/api/service_requests_provider.dart'; -import '../../../../controllers/providers/settings/setting_provider.dart'; import '../../../../models/service_request/service_request_search.dart'; import '../../../../models/subtitle.dart'; import '../../../app_style/colors.dart'; @@ -26,14 +24,12 @@ class ServiceRequestsPage extends StatefulWidget { class ServiceRequestsPageState extends State with TickerProviderStateMixin { late ServiceRequestsProvider _serviceRequestsProvider; - late SettingProvider _settingProvider; final bool _expandedSearch = false; bool _firstTime = true; @override Widget build(BuildContext context) { _serviceRequestsProvider = Provider.of(context); - _settingProvider = Provider.of(context); Subtitle? subtitle = AppLocalization.of(context)?.subtitle; if (_firstTime) { _serviceRequestsProvider.reset(); @@ -43,15 +39,11 @@ class ServiceRequestsPageState extends State with TickerPro return Scaffold( body: SafeArea( child: LoadingManager( - isLoading: _serviceRequestsProvider.isLoading, + isLoading: _serviceRequestsProvider.loading, stateCode: _serviceRequestsProvider.stateCode, onRefresh: () async { _serviceRequestsProvider.reset(); - await _serviceRequestsProvider.getRequests( - user: UserApiClient().user!, - host: _settingProvider.host ?? "", - hospitalId: UserApiClient().user!.hospital!.id, - ); + await _serviceRequestsProvider.getRequests(); }, child: Stack( children: [ @@ -87,9 +79,7 @@ class ServiceRequestsPageState extends State with TickerPro context: context, isScrollControlled: true, builder: (context) { - return ServiceRequestsSearchDialog( - initialSearchValue: _serviceRequestsProvider.search!, - ); + return ServiceRequestsSearchDialog(initialSearchValue: _serviceRequestsProvider.search!); }, ); if (temp != null) { @@ -107,13 +97,9 @@ class ServiceRequestsPageState extends State with TickerPro ), Expanded( child: ServiceRequestsList( - nextPage: _serviceRequestsProvider.nextPage!, + nextPage: _serviceRequestsProvider.nextPage ?? false, onLazyLoad: () async { - await _serviceRequestsProvider.getRequests( - user: UserApiClient().user, - host: _settingProvider.host ?? "", - hospitalId: UserApiClient().user?.hospital?.id, - ); + await _serviceRequestsProvider.getRequests(); }, requests: ServiceRequestApiClient().serviceRequests, ), diff --git a/lib/views/pages/user/visits/pantry/edit_pentry.dart b/lib/views/pages/user/visits/pantry/edit_pentry.dart index e3cf1ca4..7d35f375 100644 --- a/lib/views/pages/user/visits/pantry/edit_pentry.dart +++ b/lib/views/pages/user/visits/pantry/edit_pentry.dart @@ -1,12 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; -import '../../../../../api/user_api_client.dart'; -import '../../../../../controllers/http_status_manger/http_status_manger.dart'; import '../../../../../controllers/localization/localization.dart'; import '../../../../../controllers/providers/api/regular_visits_provider.dart'; -import '../../../../../controllers/providers/settings/setting_provider.dart'; import '../../../../../models/pantry/pentry.dart'; import '../../../../../models/subtitle.dart'; import '../../../../../models/visits/visit.dart'; @@ -28,45 +24,14 @@ class EditPentry extends StatefulWidget { } class _EditPentryState extends State with SingleTickerProviderStateMixin { - bool _isLoading = false; bool _validate = false; Subtitle? _subtitle; - late SettingProvider _settingProvider; late RegularVisitsProvider _regularVisitsProvider; Pentry? _pentry; final GlobalKey _scaffoldKey = GlobalKey(); late final TabController _tabController; - _onSubmit() async { - _validate = true; - - if (!(_pentry?.validate() ?? false)) { - setState(() {}); - return; - } - - _isLoading = true; - setState(() {}); - - int status = await _regularVisitsProvider.updatePentry(user: UserApiClient().user, host: _settingProvider.host, pentry: _pentry, visit: widget.visit); - _isLoading = false; - setState(() {}); - if (status >= 200 && status < 300) { - if (_subtitle != null) { - Fluttertoast.showToast( - msg: _subtitle!.requestCompleteSuccessfully, - ); - } - // Navigator.of(context).pop(); - } else { - String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle); - Fluttertoast.showToast( - msg: errorMessage, - ); - } - } - @override void initState() { _pentry = widget.pentry; @@ -83,13 +48,12 @@ class _EditPentryState extends State with SingleTickerProviderStateM @override Widget build(BuildContext context) { _subtitle = AppLocalization.of(context)?.subtitle; - _settingProvider = Provider.of(context); _regularVisitsProvider = Provider.of(context); return Scaffold( key: _scaffoldKey, body: SafeArea( child: LoadingManager( - isLoading: _isLoading, + isLoading: _regularVisitsProvider.loading, isFailedLoading: false, stateCode: 200, onRefresh: () async {}, @@ -176,7 +140,12 @@ class _EditPentryState extends State with SingleTickerProviderStateM if (_tabController.index == _tabController.length - 1) ASmallButton( text: _subtitle?.update, - onPressed: _onSubmit, + onPressed: () async { + _validate = true; + if (_pentry?.validate() ?? false) { + _regularVisitsProvider.updatePentry(context, pentry: _pentry, visit: widget.visit); + } + }, ), ], ), diff --git a/lib/views/pages/user/visits/pantry/future_edit_pently.dart b/lib/views/pages/user/visits/pantry/future_edit_pently.dart index f37ebf57..63dd6526 100644 --- a/lib/views/pages/user/visits/pantry/future_edit_pently.dart +++ b/lib/views/pages/user/visits/pantry/future_edit_pently.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import '../../../../../api/user_api_client.dart'; import '../../../../../controllers/localization/localization.dart'; import '../../../../../controllers/providers/api/regular_visits_provider.dart'; import '../../../../../controllers/providers/settings/setting_provider.dart'; @@ -23,6 +22,7 @@ class FutureEditPentry extends StatefulWidget { class _FutureEditPentryState extends State { late SettingProvider _settingProvider; + @override Widget build(BuildContext context) { _settingProvider = Provider.of(context); @@ -30,7 +30,7 @@ class _FutureEditPentryState extends State { Subtitle subtitle = AppLocalization.of(context)!.subtitle!; return Scaffold( body: FutureBuilder( - future: RegularVisitsProvider().getPently(user: UserApiClient().user!, host: _settingProvider.host ?? "", id: widget.visit.id!), + future: RegularVisitsProvider().getPently(id: widget.visit.id), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasError) { return FailedLoading( diff --git a/lib/views/pages/user/visits/preventive_maintenance_visits_page.dart b/lib/views/pages/user/visits/preventive_maintenance_visits_page.dart index f34c37dd..06cfcd52 100644 --- a/lib/views/pages/user/visits/preventive_maintenance_visits_page.dart +++ b/lib/views/pages/user/visits/preventive_maintenance_visits_page.dart @@ -1,16 +1,10 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/api/preventive_maintenance_api_client.dart'; -import '../../../../api/user_api_client.dart'; -import '../../../../controllers/http_status_manger/http_status_manger.dart'; import '../../../../controllers/localization/localization.dart'; import '../../../../controllers/providers/api/preventive_maintenance_visits_provider.dart'; -import '../../../../controllers/providers/settings/setting_provider.dart'; -import '../../../../controllers/providers/user_provider.dart'; import '../../../../models/subtitle.dart'; -import '../../../../models/visits/visits_group.dart'; import '../../../../models/visits/visits_search.dart'; import '../../../app_style/colors.dart'; import '../../../widgets/buttons/app_back_button.dart'; @@ -19,40 +13,33 @@ import '../../../widgets/buttons/app_icon_button.dart'; import '../../../widgets/loaders/loading_manager.dart'; import '../../../widgets/search/visits_search_bar.dart'; import '../../../widgets/visits/visits_list.dart'; -import 'update_visits_group_sheet.dart'; class PreventiveMaintenanceVisitsPage extends StatefulWidget { - static final String id = "/preventive-maintenance-visits"; + static const String id = "/preventive-maintenance-visits"; + + const PreventiveMaintenanceVisitsPage({super.key}); + @override - _PreventiveMaintenanceVisitsPageState createState() => _PreventiveMaintenanceVisitsPageState(); + PreventiveMaintenanceVisitsPageState createState() => PreventiveMaintenanceVisitsPageState(); } -class _PreventiveMaintenanceVisitsPageState extends State with TickerProviderStateMixin { +class PreventiveMaintenanceVisitsPageState extends State with TickerProviderStateMixin { late PreventiveMaintenanceVisitsProvider _visitsProvider; - late UserProvider _userProvider; - late SettingProvider _settingProvider; - late Subtitle _subtitle; + Subtitle? _subtitle; @override Widget build(BuildContext context) { _visitsProvider = Provider.of(context); - _userProvider = Provider.of(context); - _settingProvider = Provider.of(context); - _subtitle = AppLocalization.of(context)!.subtitle!; + _subtitle = AppLocalization.of(context)?.subtitle; return Scaffold( body: SafeArea( child: LoadingManager( - isLoading: _visitsProvider.isLoading, - isFailedLoading: _visitsProvider.visits == null, + isLoading: _visitsProvider.loading, stateCode: _visitsProvider.stateCode, onRefresh: () async { //_visitsProvider.visitsSearch = VisitsSearch(); _visitsProvider.reset(); - await _visitsProvider.getVisits( - user: UserApiClient().user!, - host: _settingProvider.host ?? "", - //visitsSearch: _visitsSearch - ); + await _visitsProvider.getVisits(); }, child: Stack( children: [ @@ -65,12 +52,12 @@ class _PreventiveMaintenanceVisitsPageState extends State( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text(_subtitle.updatingDots), - content: Center(child: CircularProgressIndicator()), - ); - }, - ); - int status = await _visitsProvider.updateGroupOfVisits(user: UserApiClient().user!, host: _settingProvider.host ?? "", group: _group); - Navigator.of(context).pop(); - if (status >= 200 && status < 300) { - Fluttertoast.showToast( - msg: _subtitle.preventiveMaintenanceUpdatedSuccessfully, - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.BOTTOM, - ); - } else { - Fluttertoast.showToast( - msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle), - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.BOTTOM, - ); - } - } + _visitsProvider.updateGroupOfVisits(context); }, - visits: _visitsProvider.visits!, + visits: PreventiveMaintenanceApiClient().visits, ), ), ], diff --git a/lib/views/pages/user/visits/regular_visits_page.dart b/lib/views/pages/user/visits/regular_visits_page.dart index 3eb96124..319931e4 100644 --- a/lib/views/pages/user/visits/regular_visits_page.dart +++ b/lib/views/pages/user/visits/regular_visits_page.dart @@ -1,16 +1,10 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/api/visits_api_client.dart'; -import '../../../../api/user_api_client.dart'; -import '../../../../controllers/http_status_manger/http_status_manger.dart'; import '../../../../controllers/localization/localization.dart'; import '../../../../controllers/providers/api/regular_visits_provider.dart'; -import '../../../../controllers/providers/settings/setting_provider.dart'; -import '../../../../controllers/providers/user_provider.dart'; import '../../../../models/subtitle.dart'; -import '../../../../models/visits/visits_group.dart'; import '../../../../models/visits/visits_search.dart'; import '../../../app_style/colors.dart'; import '../../../widgets/buttons/app_back_button.dart'; @@ -19,40 +13,34 @@ import '../../../widgets/buttons/app_icon_button.dart'; import '../../../widgets/loaders/loading_manager.dart'; import '../../../widgets/search/visits_search_bar.dart'; import '../../../widgets/visits/visits_list.dart'; -import 'update_visits_group_sheet.dart'; class RegularVisitsPage extends StatefulWidget { static const String id = "/Regular-visits"; const RegularVisitsPage({super.key}); + @override - _RegularVisitsPageState createState() => _RegularVisitsPageState(); + RegularVisitsPageState createState() => RegularVisitsPageState(); } -class _RegularVisitsPageState extends State with TickerProviderStateMixin { +class RegularVisitsPageState extends State with TickerProviderStateMixin { late RegularVisitsProvider _visitsProvider; - late UserProvider _userProvider; - late SettingProvider _settingProvider; - bool _expandedSearch = false; - late Subtitle _subtitle; + final bool _expandedSearch = false; + late Subtitle? _subtitle; + @override Widget build(BuildContext context) { _visitsProvider = Provider.of(context); - _settingProvider = Provider.of(context); - _userProvider = Provider.of(context); - _subtitle = AppLocalization.of(context)!.subtitle!; + _subtitle = AppLocalization.of(context)?.subtitle; return Scaffold( body: SafeArea( child: LoadingManager( - isLoading: _visitsProvider.isLoading, + isLoading: _visitsProvider.loading, stateCode: _visitsProvider.stateCode, onRefresh: () async { _visitsProvider.reset(); //_visitsProvider.visitsSearch = VisitsSearch(); - await _visitsProvider.getVisits( - user: UserApiClient().user, - host: _settingProvider.host, - ); + await _visitsProvider.getVisits(); }, child: Stack( children: [ @@ -65,17 +53,17 @@ class _RegularVisitsPageState extends State with TickerProvid children: [ Row( children: [ - ABackButton(), + const ABackButton(), Expanded( child: Center( child: Text( - _subtitle.preventiveMaintenance, - style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), + _subtitle?.preventiveMaintenance ?? '', + style: Theme.of(context).textTheme.titleLarge?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), ), ), ), AnimatedSwitcher( - duration: Duration(milliseconds: 400), + duration: const Duration(milliseconds: 400), child: AIconButton( key: ValueKey(_expandedSearch), iconData: _expandedSearch ? Icons.keyboard_arrow_up : Icons.search, @@ -83,35 +71,33 @@ class _RegularVisitsPageState extends State with TickerProvid buttonSize: 42, backgroundColor: AColors.white, onPressed: () async { - VisitsSearch _temp = await showModalBottomSheet( + VisitsSearch temp = await showModalBottomSheet( context: context, isScrollControlled: true, builder: (context) { return VisitsSearchDialog( initialSearchValue: _visitsProvider.visitsSearch!, - onSearch: (VisitsSearch) {}, + onSearch: (visitsSearch) {}, ); }); - _visitsProvider.visitsSearch?.fromSearch(_temp); + _visitsProvider.visitsSearch?.fromSearch(temp); _visitsProvider.reset(); setState(() {}); }, ), ), - SizedBox( - width: 16, - ) + const SizedBox(width: 16) ], ), ], ), ), Visibility( - visible: _visitsProvider.visitsSearch?.toSearchString().isNotEmpty ?? false, + visible: _visitsProvider.visitsSearch?.queryParameters().isNotEmpty ?? false, child: Padding( padding: const EdgeInsets.all(8.0), child: AButton( - text: _subtitle.clearSearch, + text: _subtitle?.clearSearch ?? '', onPressed: () { _visitsProvider.visitsSearch = VisitsSearch(); _visitsProvider.reset(); @@ -124,51 +110,12 @@ class _RegularVisitsPageState extends State with TickerProvid child: VisitsList( nextPage: _visitsProvider.nextPage, onLazyLoad: () async { - await _visitsProvider.getVisits( - user: UserApiClient().user!, - host: _settingProvider.host ?? "", - ); + await _visitsProvider.getVisits(); }, onEditGroup: (visits) async { - VisitsGroup? group = await showModalBottomSheet( - isScrollControlled: true, - context: context, - builder: (context) { - return UpdateVisitsGroupSheet( - visits: visits, - title: _subtitle.updateRegularVisits, - ); - }, - ) as VisitsGroup?; - if (group != null) { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text(_subtitle.updatingDots), - content: Center(child: CircularProgressIndicator()), - ); - }, - ); - int status = await _visitsProvider.updateGroupOfVisits(user: UserApiClient().user!, host: _settingProvider.host ?? "", group: group); - Navigator.of(context).pop(); - if (status >= 200 && status < 300) { - Fluttertoast.showToast( - msg: _subtitle.regularVisitsUpdatedSuccessfully, - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.BOTTOM, - ); - } else { - Fluttertoast.showToast( - msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle), - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.BOTTOM, - ); - } - } + await _visitsProvider.updateGroupOfVisits(context); }, - visits: _visitsProvider.visits, + visits: VisitsApiClient().visits, ), ), ], diff --git a/lib/views/pages/user/visits/visit_details.dart b/lib/views/pages/user/visits/visit_details.dart index 360dcfad..156b7e8a 100644 --- a/lib/views/pages/user/visits/visit_details.dart +++ b/lib/views/pages/user/visits/visit_details.dart @@ -16,13 +16,13 @@ import '../../../widgets/visits/visit_status.dart'; import 'pantry/future_edit_pently.dart'; class VisitDetailsPage extends StatelessWidget { - static final String id = "/visit-details"; + static const String id = "/visit-details"; final Visit visit; const VisitDetailsPage({Key? key, required this.visit}) : super(key: key); @override Widget build(BuildContext context) { - Subtitle _subtitle = AppLocalization.of(context)!.subtitle!; + Subtitle subtitle = AppLocalization.of(context)!.subtitle!; final regularVisitsProvider = Provider.of(context); return Scaffold( @@ -38,7 +38,7 @@ class VisitDetailsPage extends StatelessWidget { Expanded( child: Center( child: Text( - _subtitle.visitInformation, + subtitle.visitInformation, style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), ), ), @@ -105,7 +105,7 @@ class VisitDetailsPage extends StatelessWidget { height: 8, ), RequestInfoRow( - title: _subtitle.code, + title: subtitle.code, info: visit.serialNumber, ), RequestInfoRow( @@ -113,22 +113,22 @@ class VisitDetailsPage extends StatelessWidget { info: visit.deviceNumber, ), RequestInfoRow( - title: _subtitle.deviceSN, + title: subtitle.deviceSN, info: visit.deviceSerialNumber, ), RequestInfoRow( - title: _subtitle.expectDate, + title: subtitle.expectDate, info: visit.expectDate, ), RequestInfoRow( - title: _subtitle.actualDate, + title: subtitle.actualDate, info: visit.actualDate, ), Row( children: [ Expanded( child: Text( - "${_subtitle.status} : ", + "${subtitle.status} : ", style: Theme.of(context).textTheme.subtitle1?.copyWith(fontWeight: FontWeight.bold), textScaleFactor: AppStyle.getScaleFactor(context), ), @@ -142,23 +142,23 @@ class VisitDetailsPage extends StatelessWidget { color: Theme.of(context).primaryColor, ), RequestInfoRow( - title: _subtitle.contactStatus, + title: subtitle.contactStatus, info: visit.assignTo, ), RequestInfoRow( - title: _subtitle.engineerName, + title: subtitle.engineerName, info: visit.employName, ), RequestInfoRow( - title: _subtitle.hospital, + title: subtitle.hospital, content: visit.hospitalName, ), RequestInfoRow( - title: _subtitle.deviceArName, + title: subtitle.deviceArName, content: visit.deviceArabicName, ), RequestInfoRow( - title: _subtitle.deviceEnName, + title: subtitle.deviceEnName, content: visit.deviceEnglishName, ), ], diff --git a/lib/views/widgets/loaders/lazy_loading.dart b/lib/views/widgets/loaders/lazy_loading.dart index d91b7af9..d3f692b1 100644 --- a/lib/views/widgets/loaders/lazy_loading.dart +++ b/lib/views/widgets/loaders/lazy_loading.dart @@ -18,21 +18,21 @@ class LazyLoading extends StatefulWidget { }) : super(key: key); @override - _LazyLoadingState createState() => _LazyLoadingState(); + LazyLoadingState createState() => LazyLoadingState(); } -class _LazyLoadingState extends State with TickerProviderStateMixin { +class LazyLoadingState extends State with TickerProviderStateMixin { late AnimationController _animationController; late Animation _offsetAnimation; _scrollListener() async { if (!_animationController.isAnimating && !_animationController.isCompleted && widget.nextPage) { - _animationController?.forward(); + _animationController.forward(); setState(() {}); await widget.onLazyLoad(); - await Future.delayed(Duration(milliseconds: 600)); + await Future.delayed(const Duration(milliseconds: 600)); setState(() {}); - _animationController?.reverse(); + _animationController.reverse(); } } @@ -56,7 +56,7 @@ class _LazyLoadingState extends State with TickerProviderStateMixin @override void dispose() { super.dispose(); - _animationController?.dispose(); + _animationController.dispose(); } @override @@ -75,13 +75,13 @@ class _LazyLoadingState extends State with TickerProviderStateMixin position: _offsetAnimation, child: Center( child: Visibility( - visible: (_animationController?.isAnimating ?? false) || (_animationController?.isCompleted ?? false), + visible: (_animationController.isAnimating) || (_animationController.isCompleted), child: Container( height: 36 * AppStyle.getScaleFactor(context), width: 36 * AppStyle.getScaleFactor(context), - padding: EdgeInsets.all(8), - decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle, boxShadow: [AppStyle.boxShadow]), - child: ALoading(), + padding: const EdgeInsets.all(8), + decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle, boxShadow: [AppStyle.boxShadow]), + child: const ALoading(), ), ), ), diff --git a/lib/views/widgets/loaders/loading_manager.dart b/lib/views/widgets/loaders/loading_manager.dart index 67c1c01f..b88ca5ac 100644 --- a/lib/views/widgets/loaders/loading_manager.dart +++ b/lib/views/widgets/loaders/loading_manager.dart @@ -49,7 +49,7 @@ class _LoadingManagerState extends State { Subtitle? subtitle = AppLocalization.of(context)?.subtitle; Widget? placeHolder; // to load data if load not start - if (widget.isLoading == false && widget.stateCode == null) { + if (widget.onRefresh != null && widget.isLoading == false && widget.stateCode == null) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { widget.onRefresh!(); }); @@ -70,7 +70,7 @@ class _LoadingManagerState extends State { // if load end successfully return loaded widget return RefreshIndicator( onRefresh: () async { - await widget.onRefresh!(); + if (widget.onRefresh != null) await widget.onRefresh!(); }, child: AnimatedSwitcher( duration: const Duration(milliseconds: 400), diff --git a/lib/views/widgets/requests/service_request_update_dialog.dart b/lib/views/widgets/requests/service_request_update_dialog.dart index c42d6333..7e65f1a0 100644 --- a/lib/views/widgets/requests/service_request_update_dialog.dart +++ b/lib/views/widgets/requests/service_request_update_dialog.dart @@ -1,14 +1,9 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; -import '../../../api/user_api_client.dart'; -import '../../../controllers/http_status_manger/http_status_manger.dart'; import '../../../controllers/localization/localization.dart'; import '../../../controllers/providers/api/service_requests_provider.dart'; -import '../../../controllers/providers/settings/setting_provider.dart'; -import '../../../controllers/providers/user_provider.dart'; import '../../../models/lookup.dart'; import '../../../models/service_request/service_request.dart'; import '../../../models/subtitle.dart'; @@ -33,45 +28,10 @@ class _ServiceRequestsUpdateDialogState extends State _formKey = GlobalKey(); - _update() async { - if (_dateTime == null && _employee == null) { - Fluttertoast.showToast(msg: _subtitle?.noDateFound ?? ''); - return; - } - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text(_subtitle?.updatingDots ?? ''), - content: const Center(child: CircularProgressIndicator()), - ); - }, - ); - int? status = await _serviceRequestsProvider?.updateDate( - user: UserApiClient().user, - host: _settingProvider?.host, - request: widget.request, - newDate: _dateTime?.toString().split(" ").first, - employee: _employee, - ); - if (status == 200) Navigator.of(context).pop(); - Navigator.of(context).pop(); - Fluttertoast.showToast( - msg: HttpStatusManger.getStatusMessage( - status: status, - subtitle: _subtitle, - ) ?? - '', - ); - } - @override void initState() { super.initState(); @@ -80,8 +40,6 @@ class _ServiceRequestsUpdateDialogState extends State(context, listen: false); - _settingProvider = Provider.of(context, listen: false); _serviceRequestsProvider = Provider.of(context, listen: false); return Column( mainAxisSize: MainAxisSize.min, @@ -105,7 +63,13 @@ class _ServiceRequestsUpdateDialogState extends State with TickerProvi }, ), Visibility( - visible: _search?.toSearchString().isNotEmpty ?? false, + visible: _search?.queryParameters().isNotEmpty ?? false, child: Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: AButton(