Merge branch 'zaid-development' into 'master'

Track Service Request DONE

See merge request haroon6138/cloudsolutions-atoms!14
merge-requests/15/merge
Sikander Saleem 2 years ago
commit b2e721a8c5

@ -66,7 +66,7 @@ class ApiClient {
factory ApiClient() => _instance; factory ApiClient() => _instance;
Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject, Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async { {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = true}) async {
var defaultHeaders = {'Accept': 'application/json'}; var defaultHeaders = {'Accept': 'application/json'};
if (headers != null && headers.isNotEmpty) { if (headers != null && headers.isNotEmpty) {
defaultHeaders.addAll(headers); defaultHeaders.addAll(headers);
@ -97,7 +97,7 @@ class ApiClient {
} }
Future<Response> postJsonForResponse<T>(String url, T jsonObject, Future<Response> postJsonForResponse<T>(String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async { {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = true}) async {
int currentRetryTime = retryTimes; int currentRetryTime = retryTimes;
String? requestBody; String? requestBody;
late Map<String, String> stringObj; late Map<String, String> stringObj;

@ -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<Visit> 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<Visit> visitsList = requestsListJson.map((request) => Visit.fromJson(request)).toList();
visits.addAll(visitsList);
}
Future updateGroupOfVisits({required VisitsGroup group}) async {
final user = UserApiClient().user;
Map<String, String> 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();
}
}

@ -2,7 +2,12 @@ import 'dart:convert';
import 'package:test_sa/api/api_client.dart'; import 'package:test_sa/api/api_client.dart';
import 'package:test_sa/api/user_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.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'; import '../controllers/api_routes/urls.dart';
@ -35,7 +40,107 @@ class ServiceRequestApiClient {
"defect_types": (serviceRequest.defectType?.id).toString(), "defect_types": (serviceRequest.defectType?.id).toString(),
"audio": serviceRequest.audio, "audio": serviceRequest.audio,
}, },
isFormData: true,
); );
} }
/// Get Service Requests and Fill [serviceRequests]
Future<List<ServiceRequest>> 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<ServiceRequest> serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList();
serviceRequests.addAll(serviceRequestsPage);
return serviceRequestsPage;
}
Future<ServiceRequest> 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<ServiceRequest> requests = jsonList.map((i) => ServiceRequest.fromJson(i)).toList();
return requests[0];
}
Future createIssueReport(Issue issue) async {
final user = UserApiClient().user;
Map<String, String> 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<String, String> 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<String, String>? 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<String, String> 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<String, String> 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<ServiceReport> 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);
}
} }

@ -25,7 +25,6 @@ class UserApiClient {
}, },
"${URLs.host1}${URLs.login}", "${URLs.host1}${URLs.login}",
await user.toLoginJson(), //body await user.toLoginJson(), //body
isFormData: true,
); );
} }
@ -41,7 +40,6 @@ class UserApiClient {
}, },
"${URLs.host1}${URLs.register}", "${URLs.host1}${URLs.register}",
await newUser.toRegisterJson(), //body await newUser.toRegisterJson(), //body
isFormData: true,
); );
} }
@ -57,7 +55,6 @@ class UserApiClient {
}, },
"${URLs.host1}${URLs.updateProfile}", "${URLs.host1}${URLs.updateProfile}",
updatedUser.toUpdateProfileJson(), //body updatedUser.toUpdateProfileJson(), //body
isFormData: true,
); );
// Map<String, dynamic> jsonObject = {}; // Map<String, dynamic> jsonObject = {};
// jsonObject["uid"] = user.id; // jsonObject["uid"] = user.id;

@ -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<Visit> 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<Visit> visitsList = requestsListJson.map((request) => Visit.fromJson(request)).toList();
visits.addAll(visitsList);
}
Future updateGroupOfVisits({required VisitsGroup group}) async {
final user = UserApiClient().user;
Map<String, String> 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<Pentry> 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<String, String>? 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;
}
}

@ -28,7 +28,7 @@ class DevicesProvider extends LoadingNotifier {
Future getEquipment({required String? hospitalId}) async { Future getEquipment({required String? hospitalId}) async {
if (hospitalId != null) { if (hospitalId != null) {
_searchableList.clear(); _searchableList.clear();
waitApiRequest( await waitApiRequest(
() async { () async {
await DevicesApiClient().getEquipment(hospitalId); await DevicesApiClient().getEquipment(hospitalId);
_searchableList.addAll(DevicesApiClient().devices); _searchableList.addAll(DevicesApiClient().devices);

@ -1,21 +1,22 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart'; 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_group.dart';
import '../../../models/visits/visits_search.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 // number of items call in each request
final pageItemNumber = 50; final pageItemNumber = 50;
//reset provider data //reset provider data
void reset() { void reset() {
visits = null; PreventiveMaintenanceApiClient().visits.clear();
nextPage = true; nextPage = true;
stateCode = null; stateCode = null;
} }
@ -28,98 +29,76 @@ class PreventiveMaintenanceVisitsProvider extends ChangeNotifier {
// true if there is next page in product list and false if not // true if there is next page in product list and false if not
bool? nextPage = true; bool? nextPage = true;
// list of user requests
List<Visit>? visits;
// when requests in-process _loading = true
// done _loading = true
// failed _loading = false
bool? isLoading;
VisitsSearch? visitsSearch = VisitsSearch(); VisitsSearch? visitsSearch = VisitsSearch();
/// return -2 if request in progress Future getVisits() async {
/// return -1 if error happen when sending request await waitApiRequest(
/// return state code if request complete may be 200, 404 or 403 () async {
/// for more details check http state manager await PreventiveMaintenanceApiClient().getVisits(pageItemNumber: pageItemNumber, visitsSearch: visitsSearch);
/// lib\controllers\http_status_manger\http_status_manger.dart },
Future<int> getVisits({ onSuccess: () {
required String host, /// TODO : this is temporary
required User user, stateCode = 200;
// VisitsSearch visitsSearch, if (PreventiveMaintenanceApiClient().visits.length == pageItemNumber) {
}) 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<Visit> visits = requestsListJson.map((request) => Visit.fromJson(request)).toList();
visits.addAll(visits);
if (visits.length == pageItemNumber) {
nextPage = true; nextPage = true;
} else { } else {
nextPage = false; nextPage = false;
} }
} },
isLoading = false; onError: (error) {
notifyListeners(); /// TODO : this is temporary
return response.statusCode; stateCode = error.error?.errorCode;
},
);
} }
/// return -2 if request in progress Future updateGroupOfVisits(BuildContext context) async {
/// return -1 if error happen when sending request final subtitle = AppLocalization.of(context)?.subtitle;
/// return state code if request complete may be 200, 404 or 403 VisitsGroup? group = await showModalBottomSheet(
/// for more details check http state manager isScrollControlled: true,
/// lib\controllers\http_status_manger\http_status_manger.dart context: context,
Future<int> updateGroupOfVisits({ builder: (context) {
required String host, return UpdateVisitsGroupSheet(visits: PreventiveMaintenanceApiClient().visits, title: subtitle?.updatePreventiveMaintenance);
required User user, },
required VisitsGroup group, ) as VisitsGroup?;
}) async { if (context.mounted && group != null) {
Response response; showDialog<void>(
Map<String, String> body = group.toJson(); context: context,
body["token"] = user.token ?? ""; barrierDismissible: false,
body["uid"] = user.id ?? ""; builder: (BuildContext context) {
//userId = 397.toString(); // testing id to view data return CupertinoAlertDialog(
try { title: Text(subtitle?.updatingDots ?? ''),
response = await post( content: const Center(child: CircularProgressIndicator()),
Uri.parse(host + URLs.updatePreventiveMaintenanceVisits),
body: body,
); );
},
stateCode = response.statusCode; );
if (response.statusCode >= 200 && response.statusCode < 300) { await waitApiRequest(
// client's request was successfully received () async {
for (var visit in (group.visits ?? [])) { await PreventiveMaintenanceApiClient().updateGroupOfVisits(group: group);
visit.status = group.status; if (context.mounted) {
visit.actualDate = group.date.toString().split(" ").first; Navigator.of(context).pop();
}
group.visits?.clear();
notifyListeners();
} }
},
return response.statusCode; onSuccess: () {
} catch (error) { /// TODO : this is temporary
isLoading = false; stateCode = 200;
stateCode = -1; Navigator.of(context).pop();
notifyListeners(); Fluttertoast.showToast(
return -1; 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,
);
},
);
} }
} }
} }

@ -1,22 +1,24 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart'; 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/pantry/pentry.dart';
import '../../../models/user.dart';
import '../../../models/visits/visit.dart'; import '../../../models/visits/visit.dart';
import '../../../models/visits/visits_group.dart'; import '../../../models/visits/visits_group.dart';
import '../../../models/visits/visits_search.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 // number of items call in each request
final pageItemNumber = 50; final pageItemNumber = 50;
// reset provider data // reset provider data
void reset() { void reset() {
visits.clear(); VisitsApiClient().visits.clear();
nextPage = true; nextPage = true;
stateCode = null; stateCode = null;
} }
@ -29,145 +31,100 @@ class RegularVisitsProvider extends ChangeNotifier {
// true if there is next page in product list and false if not // true if there is next page in product list and false if not
bool nextPage = true; bool nextPage = true;
// list of user requests
List<Visit> visits = [];
// when requests in-process _loading = true
// done _loading = true
// failed _loading = false
bool? isLoading;
VisitsSearch? visitsSearch = VisitsSearch(); VisitsSearch? visitsSearch = VisitsSearch();
/// return -2 if request in progress Future getVisits() async {
/// return -1 if error happen when sending request await waitApiRequest(
/// return state code if request complete may be 200, 404 or 403 () async {
/// for more details check http state manager await VisitsApiClient().getVisits(pageItemNumber: pageItemNumber, visitsSearch: visitsSearch);
/// lib\controllers\http_status_manger\http_status_manger.dart },
Future<int> getVisits({ onSuccess: () {
required String? host, /// TODO : this is temporary
required User? user, stateCode = 200;
// VisitsSearch visitsSearch, if (VisitsApiClient().visits.length == pageItemNumber) {
}) 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<Visit> visitsList = requestsListJson.map((request) => Visit.fromJson(request)).toList();
visits.addAll(visitsList);
if (visits.length == pageItemNumber) {
nextPage = true; nextPage = true;
} else { } else {
nextPage = false; nextPage = false;
} }
} catch (error) { },
isLoading = false; onError: (error) {
stateCode = -1; /// TODO : this is temporary
notifyListeners(); stateCode = error.error?.errorCode;
return -1; },
} );
}
isLoading = false;
notifyListeners();
return response.statusCode;
} }
/// return -2 if request in progress Future updateGroupOfVisits(BuildContext context) async {
/// return -1 if error happen when sending request final subtitle = AppLocalization.of(context)?.subtitle;
/// return state code if request complete may be 200, 404 or 403 VisitsGroup? group = await showModalBottomSheet(
/// for more details check http state manager isScrollControlled: true,
/// lib\controllers\http_status_manger\http_status_manger.dart context: context,
Future<int> updateGroupOfVisits({ builder: (context) {
required String host, return UpdateVisitsGroupSheet(visits: VisitsApiClient().visits, title: subtitle?.updateRegularVisits);
required User user, },
required VisitsGroup group, ) as VisitsGroup?;
}) async { if (context.mounted && group != null) {
Response response; showDialog<void>(
Map<String, String> body = group.toJson(); context: context,
body["token"] = user.token ?? ""; barrierDismissible: false,
body["uid"] = user.id ?? ""; builder: (BuildContext context) {
//userId = 397.toString(); // testing id to view data return CupertinoAlertDialog(
try { title: Text(subtitle?.updatingDots ?? ''),
response = await post( content: const Center(child: CircularProgressIndicator()),
Uri.parse(host + URLs.updateRegularVisits), );
body: body, },
); );
stateCode = response.statusCode; await waitApiRequest(
if (response.statusCode >= 200 && response.statusCode < 300) { () async {
// client's request was successfully received await VisitsApiClient().updateGroupOfVisits(group: group);
reset(); reset();
notifyListeners(); },
} onSuccess: () {
/// TODO : this is temporary
return response.statusCode; stateCode = 200;
} catch (error) { Navigator.of(context).pop();
isLoading = false; Fluttertoast.showToast(
stateCode = -1; msg: subtitle?.regularVisitsUpdatedSuccessfully ?? '',
notifyListeners(); toastLength: Toast.LENGTH_LONG,
return -1; 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,
);
},
);
} }
} }
Future<Pentry?> getPently({ Future<Pentry?> getPently({required String? id}) async {
required String host, return id == null ? null : await VisitsApiClient().getPentry(id);
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<int> updatePentry({ void updatePentry(BuildContext context, {required Pentry? pentry, required Visit? visit}) async {
required String? host, final subtitle = AppLocalization.of(context)?.subtitle;
required User? user, await waitApiRequest(
required Pentry? pentry, () async {
required Visit? visit, await VisitsApiClient().updatePentry(pentry: pentry, visit: visit);
}) async { },
try { onSuccess: () {
Response response; /// TODO : this is temporary
Map<String, String>? body = pentry?.toMap(); stateCode = 200;
body?["uid"] = user?.id ?? ""; if (subtitle != null) {
body?["token"] = user?.token ?? ""; Fluttertoast.showToast(msg: subtitle.requestCompleteSuccessfully);
response = await post( }
Uri.parse("$host${URLs.updatePentry}/${visit?.id}"), },
body: body, onError: (error) {
/// TODO : this is temporary
stateCode = error.error?.errorCode;
String errorMessage = HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle);
Fluttertoast.showToast(msg: errorMessage);
},
); );
if (response.statusCode >= 200 && response.statusCode < 300) {
visit?.status = pentry?.ppmVisitStatus;
notifyListeners();
}
return response.statusCode;
} catch (error) {
return -1;
}
} }
} }

@ -1,21 +1,20 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.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/api/service_request_api_client.dart';
import 'package:test_sa/controllers/providers/loading_notifier.dart'; import 'package:test_sa/controllers/providers/loading_notifier.dart';
import 'package:test_sa/exceptions/api_exception.dart';
import '../../../models/issue.dart'; import '../../../models/issue.dart';
import '../../../models/lookup.dart'; import '../../../models/lookup.dart';
import '../../../models/service_report.dart'; import '../../../models/service_report.dart';
import '../../../models/service_request/service_request.dart'; import '../../../models/service_request/service_request.dart';
import '../../../models/service_request/service_request_search.dart'; import '../../../models/service_request/service_request_search.dart';
import '../../../models/subtitle.dart';
import '../../../models/timer_model.dart'; import '../../../models/timer_model.dart';
import '../../../models/user.dart'; import '../../../views/widgets/dialogs/dialog.dart';
import '../../api_routes/urls.dart';
import '../../http_status_manger/http_status_manger.dart'; import '../../http_status_manger/http_status_manger.dart';
import '../../localization/localization.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 // true if there is next page in product list and false if not
bool? nextPage = true; bool? nextPage = true;
// when requests in-process _loading = true
// done _loading = true
// failed _loading = false
bool? isLoading;
ServiceRequestSearch? search = ServiceRequestSearch(); ServiceRequestSearch? search = ServiceRequestSearch();
/// return -2 if request in progress /// Get Service Requests and Fill [ServiceRequestApiClient.serviceRequests]
/// return -1 if error happen when sending request Future getRequests() async {
/// return state code if request complete may be 200, 404 or 403 await waitApiRequest(() async {
/// for more details check http state manager final serviceRequestsPage = await ServiceRequestApiClient().getRequests(pageItemNumber: pageItemNumber, search: search);
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> 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<ServiceRequest> serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList();
ServiceRequestApiClient().serviceRequests.addAll(serviceRequestsPage);
if (serviceRequestsPage.length == pageItemNumber) { if (serviceRequestsPage.length == pageItemNumber) {
nextPage = true; nextPage = true;
} else { } else {
nextPage = false; nextPage = false;
} }
} }, onSuccess: () {
isLoading = false; /// TODO : this is temporary
notifyListeners(); stateCode = 200;
return response.statusCode; }, onError: (error) {
} catch (error) { /// TODO : this is temporary
isLoading = false; stateCode = error.error?.errorCode;
stateCode = -1; });
notifyListeners();
return -1;
}
}
Future<ServiceRequest> 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. Future<ServiceRequest> getSingleServiceRequest({required String? requestId}) async {
if (response.statusCode >= 200 && response.statusCode < 300) { return await ServiceRequestApiClient().getServiceById(requestId);
// If the call to the server was successful, parse the JSON.
List jsonList = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
List<ServiceRequest> requests = jsonList.map((i) => ServiceRequest.fromJson(i)).toList();
return requests[0];
} else {
throw (HttpStatusManger.getStatusMessage(status: response.statusCode, subtitle: subtitle));
}
} }
/// ### Create service request and add the response to [ServiceRequestApiClient.serviceRequests] /// ### Create service request and add the response to [ServiceRequestApiClient.serviceRequests]
@ -145,206 +86,136 @@ class ServiceRequestsProvider extends LoadingNotifier {
}); });
} }
Future<int> createIssueReport({ Future createIssueReport(BuildContext context, {required Issue issue}) async {
required String host, await waitApiRequest(() async {
required User user, await ServiceRequestApiClient().createIssueReport(issue);
required Issue issue, }, onSuccess: () {
}) async { final subtitle = AppLocalization.of(context)?.subtitle;
Response response; Fluttertoast.showToast(msg: subtitle?.requestCompleteSuccessfully ?? '');
Map<String, String> body = issue.toMap();
body["uid"] = user.id ?? "";
body["token"] = user.token ?? "";
try {
response = await post(
Uri.parse(host + URLs.createReport),
body: body,
);
stateCode = response.statusCode; /// TODO : this is temporary
if (response.statusCode >= 200 && response.statusCode < 300) {} stateCode = 200;
return response.statusCode; }, onError: (error) {
} catch (error) { /// TODO : this is temporary
return -1; stateCode = error.error?.errorCode;
} });
} }
Future<int> updateDate({ Future updateDate(BuildContext context, {required String? newDate, required Lookup? employee, required ServiceRequest? request}) async {
required String? host, final subtitle = AppLocalization.of(context)?.subtitle;
required User? user, showDialog<void>(
required String? newDate, context: context,
required Lookup? employee, barrierDismissible: false,
required ServiceRequest? request, builder: (BuildContext context) {
}) async { return CupertinoAlertDialog(title: Text(subtitle?.updatingDots ?? ''), content: const Center(child: CircularProgressIndicator()));
Response response; },
Map<String, String> 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; await waitApiRequest(
if (response.statusCode >= 200 && response.statusCode < 300) { () async {
request?.engineerName = employee?.label; await ServiceRequestApiClient().updateDate(newDate: newDate, employee: employee, request: request);
notifyListeners(); },
} onSuccess: () {
return response.statusCode; Navigator.of(context).pop();
} catch (error) { Fluttertoast.showToast(msg: HttpStatusManger.getStatusMessage(status: 200, subtitle: subtitle));
return -1;
}
}
Future<int> createServiceReport({ /// TODO : this is temporary
required String host, stateCode = 200;
required User user, },
required ServiceReport report, onError: (error) {
required ServiceRequest request, /// TODO : this is temporary
}) async { stateCode = error.error?.errorCode;
Response response; },
Map<String, String> 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; Future createServiceReport(BuildContext context, {required ServiceReport? report, required ServiceRequest? request}) async {
if (response.statusCode >= 200 && response.statusCode < 300) { final subtitle = AppLocalization.of(context)?.subtitle;
await waitApiRequest(
() async {
await ServiceRequestApiClient().createServiceReport(report: report, request: request);
reset(); reset();
notifyListeners(); },
} onSuccess: () {
return response.statusCode; /// TODO : this is temporary
} catch (error) { stateCode = 200;
return -1; 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<int> createDuplicatedReport({ Future createDuplicatedReport(BuildContext context, {required ServiceRequest request}) async {
required String host, final subtitle = AppLocalization.of(context)?.subtitle;
required User user, bool result = await showDialog(context: context, builder: (_) => AAlertDialog(title: subtitle?.duplicateAlert, content: subtitle?.duplicateAlertMessage));
required ServiceRequest request, if (result == true && context.mounted) {
}) async { showDialog(
Response response; context: context,
String userData = ''; builder: (context) {
userData += "&uid=${user.id}"; return const Center(child: CircularProgressIndicator());
userData += "&token=${user.token}"; },
try {
response = await get(
Uri.parse(
"$host${URLs.createDuplicatedReport}?nid=${request.id}$userData",
),
); );
await waitApiRequest(
stateCode = response.statusCode; () async {
await ServiceRequestApiClient().createDuplicatedReport(request: request);
if (response.statusCode >= 200 && response.statusCode < 300) {
reset(); reset();
notifyListeners(); },
} onSuccess: () {
return response.statusCode; Navigator.of(context).pop();
} catch (error) { },
return -1; 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();
},
);
} }
} }
Future<int> updateServiceReport({ Future updateServiceReport(BuildContext context, {required ServiceReport report, required ServiceRequest request}) async {
required String host, final subtitle = AppLocalization.of(context)?.subtitle;
required User user, await waitApiRequest(
required ServiceReport report, () async {
required ServiceRequest request, await ServiceRequestApiClient().updateServiceReport(report: report, request: request);
}) async {
Response response;
Map<String, String> 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) {
reset(); reset();
notifyListeners(); },
} onSuccess: () {
return response.statusCode; Fluttertoast.showToast(msg: subtitle?.requestCompleteSuccessfully ?? '');
} catch (error) { Navigator.of(context).pop();
return -1; Navigator.of(context).pop();
}
}
Future<int> updateServiceReportTimer({ /// TODO : this is temporary
required String host, stateCode = 200;
required User user, },
required TimerModel timer, onError: (error) {
required ServiceRequest request, /// TODO : this is temporary
}) async { stateCode = error.error?.errorCode;
Response response; String errorMessage = HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle);
Map<String, String> body = {}; ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage)));
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 ?? '';
try {
response = await post(
Uri.parse(host + URLs.updateServiceReport),
body: body,
); );
//stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// reset();
// notifyListeners();
} }
return response.statusCode;
} catch (error) {
return -1;
}
}
Future<ServiceReport> 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; Future updateServiceReportTimer({required TimerModel timer, required ServiceRequest request}) async {
try { try {
response = await get(Uri.parse( await ServiceRequestApiClient().updateServiceReportTimer(timer: timer, request: request);
'$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. /// TODO : this is temporary
if (response.statusCode >= 200 && response.statusCode < 300) { stateCode = 200;
// If the call to the server was successful, parse the JSON. } on APIException catch (error) {
return ServiceReport.fromJson(json.decode(utf8.decode(response.bodyBytes)), reportId); /// TODO : this is temporary
} else { stateCode = error.error?.errorCode;
throw (HttpStatusManger.getStatusMessage(
status: response.statusCode,
subtitle: subtitle,
) ??
'');
} }
} }
Future<ServiceReport?> getSingleServiceReport({required String reportId}) async {
return await ServiceRequestApiClient().getSingleServiceReport(reportId: reportId);
}
} }

@ -13,7 +13,7 @@ class LoadingNotifier with ChangeNotifier {
/// - [fun] : Callback function that contains the API request. /// - [fun] : Callback function that contains the API request.
/// - [onError] : Optional callback function to handle the request on failure with [APIException] parameter. /// - [onError] : Optional callback function to handle the request on failure with [APIException] parameter.
/// - [onSuccess] : Optional callback function to handle the request on succeed. /// - [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) { if (_loading == true) {
debugPrint('loading_notifier.dart : another action already started'); debugPrint('loading_notifier.dart : another action already started');
return; return;

@ -20,26 +20,13 @@ class ServiceRequestSearch {
model = newSearch.model; model = newSearch.model;
} }
String toSearchString() { Map<String, dynamic> queryParameters() {
String search = ""; return <String, dynamic>{
if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) { if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) 'sn_id': deviceSerialNumber,
search += "&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 (statusValue != null) { if (model != null && (model?.isNotEmpty ?? false)) 'model': model,
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;
} }
} }

@ -36,47 +36,18 @@ class VisitsSearch {
statusValue = newSearch.statusValue; statusValue = newSearch.statusValue;
} }
String toSearchString() { Map<String, dynamic> queryParameters() {
String _search = ""; return <String, dynamic>{
if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) { if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) 'sn_id': deviceSerialNumber,
_search += "&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 (hospitalName != null && (hospitalName?.isNotEmpty ?? false)) { if (model != null && (model?.isNotEmpty ?? false)) 'model': model,
_search += "&client=$hospitalName"; 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 (brand != null && (brand?.isNotEmpty ?? false)) { if (actualDateTo != null) 'actual_date_to': (actualDateTo?.millisecondsSinceEpoch ?? 0) ~/ 1000,
_search += "&brand=$brand"; if (contactStatus != null) 'assigned_to': contactStatus,
} };
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;
} }
} }

@ -1,17 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../../api/user_api_client.dart';
import '../../../controllers/localization/localization.dart'; import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/service_requests_provider.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 '../../../controllers/validator/validator.dart';
import '../../../models/issue.dart'; import '../../../models/issue.dart';
import '../../../models/service_request/service_request.dart'; import '../../../models/service_request/service_request.dart';
import '../../../models/subtitle.dart';
import '../../../models/user.dart';
import '../../app_style/colors.dart'; import '../../app_style/colors.dart';
import '../../app_style/sizing.dart'; import '../../app_style/sizing.dart';
import '../../widgets/app_text_form_field.dart'; import '../../widgets/app_text_form_field.dart';
@ -25,27 +19,24 @@ class ReportIssuesPage extends StatefulWidget {
final ServiceRequest? serviceRequest; final ServiceRequest? serviceRequest;
const ReportIssuesPage({Key? key, this.serviceRequest}) : super(key: key); const ReportIssuesPage({Key? key, this.serviceRequest}) : super(key: key);
@override @override
_ReportIssuesPageState createState() => _ReportIssuesPageState(); ReportIssuesPageState createState() => ReportIssuesPageState();
} }
class _ReportIssuesPageState extends State<ReportIssuesPage> { class ReportIssuesPageState extends State<ReportIssuesPage> {
List<String> _issues = []; final List<String> _issues = [];
Issue _issue = Issue(reports: []); final Issue _issue = Issue(reports: []);
late double _height; late double _height;
bool _isLoading = false;
late ServiceRequestsProvider _serviceRequestsProvider; late ServiceRequestsProvider _serviceRequestsProvider;
late UserProvider _userProvider;
late SettingProvider _settingProvider;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!; final subtitle = AppLocalization.of(context)?.subtitle;
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context); _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_height = MediaQuery.of(context).size.height; _height = MediaQuery.of(context).size.height;
_subtitle.setIssues(_issues); subtitle?.setIssues(_issues);
return Scaffold( return Scaffold(
body: SafeArea( body: SafeArea(
child: Form( child: Form(
@ -54,7 +45,7 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
onRefresh: () async {}, onRefresh: () async {},
stateCode: 200, stateCode: 200,
isFailedLoading: false, isFailedLoading: false,
isLoading: _isLoading, isLoading: _serviceRequestsProvider.loading,
child: Stack( child: Stack(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
@ -67,27 +58,21 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
vertical: 24 * AppStyle.getScaleFactor(context), vertical: 24 * AppStyle.getScaleFactor(context),
), ),
child: Text( child: Text(
_subtitle.reportIssue, subtitle?.reportIssue ?? '',
style: Theme.of(context).textTheme.headline5?.copyWith(color: AColors.cyan, fontWeight: FontWeight.bold), style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: AColors.cyan, fontWeight: FontWeight.bold),
), ),
), ),
), ),
Image( Image(height: _height / 8, image: const AssetImage("assets/images/logo.png")),
height: _height / 8,
image: AssetImage("assets/images/logo.png"),
),
Container( Container(
padding: EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
horizontal: 16,
vertical: 16,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AColors.grey, color: AColors.grey,
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(AppStyle.getBorderRadius(context)), topLeft: Radius.circular(AppStyle.getBorderRadius(context)),
topRight: Radius.circular(AppStyle.getBorderRadius(context)), topRight: Radius.circular(AppStyle.getBorderRadius(context)),
), ),
boxShadow: [ boxShadow: const [
BoxShadow( BoxShadow(
color: AColors.grey, color: AColors.grey,
offset: Offset(0, -1), offset: Offset(0, -1),
@ -97,19 +82,17 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ATextFormField( ATextFormField(
initialValue: _issue?.title, initialValue: _issue.title,
hintText: _subtitle.title, hintText: subtitle?.title,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.titleValidateMessage, validator: (value) => Validator.hasValue(value) ? null : subtitle?.titleValidateMessage,
textInputType: TextInputType.name, textInputType: TextInputType.name,
onSaved: (value) { onSaved: (value) {
_issue.title = value; _issue.title = value;
}, },
), ),
SizedBox( const SizedBox(height: 8),
height: 8,
),
Column( Column(
children: List.generate( children: List.generate(
_issues.length, _issues.length,
@ -128,13 +111,13 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: Text(
"${_subtitle.shareAntherIssue} :", "${subtitle?.shareAntherIssue} :",
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
), ),
), ),
ATextFormField( ATextFormField(
hintText: _subtitle.description, hintText: subtitle?.description,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
onSaved: (value) { onSaved: (value) {
_issue.description = value; _issue.description = value;
@ -143,28 +126,13 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: AButton( child: AButton(
text: _subtitle.submit, text: subtitle?.submit ?? '',
onPressed: () async { onPressed: () async {
if (!(_formKey.currentState?.validate() ?? false)) return; if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save();
_issue.serviceRequestId = widget.serviceRequest?.id; _issue.serviceRequestId = widget.serviceRequest?.id;
_isLoading = true; _formKey.currentState?.save();
setState(() {}); await _serviceRequestsProvider.createIssueReport(context, issue: _issue);
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();
} }
_isLoading = false;
setState(() {});
}, },
), ),
), ),
@ -174,7 +142,7 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
], ],
), ),
), ),
ABackButton(), const ABackButton(),
], ],
), ),
), ),

@ -1,13 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.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/api/service_requests_provider.dart';
import '../../../../controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../controllers/providers/user_provider.dart'; import '../../../../controllers/providers/user_provider.dart';
import '../../../../models/service_request/service_request.dart'; import '../../../../models/service_request/service_request.dart';
import '../../../../models/subtitle.dart';
import '../../../widgets/loaders/app_loading.dart'; import '../../../widgets/loaders/app_loading.dart';
import '../../../widgets/loaders/failed_loading.dart'; import '../../../widgets/loaders/failed_loading.dart';
import 'request_details.dart'; import 'request_details.dart';
@ -29,10 +26,9 @@ class _FutureRequestServiceDetailsState extends State<FutureRequestServiceDetail
_userProvider = Provider.of<UserProvider>(context); _userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context); _settingProvider = Provider.of<SettingProvider>(context);
String? requestId = ModalRoute.of(context)?.settings.arguments as String?; String? requestId = ModalRoute.of(context)?.settings.arguments as String?;
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold( return Scaffold(
body: FutureBuilder<ServiceRequest>( body: FutureBuilder<ServiceRequest>(
future: ServiceRequestsProvider().getSingleServiceRequest(requestId: requestId ?? '', user: UserApiClient().user!, host: _settingProvider.host ?? "", subtitle: _subtitle), future: ServiceRequestsProvider().getSingleServiceRequest(requestId: requestId),
builder: (BuildContext context, AsyncSnapshot<ServiceRequest> snapshot) { builder: (BuildContext context, AsyncSnapshot<ServiceRequest> snapshot) {
if (snapshot.hasError) { if (snapshot.hasError) {
return FailedLoading( return FailedLoading(

@ -2,15 +2,11 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.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/localization/localization.dart';
import '../../../../../controllers/providers/api/service_requests_provider.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/api/status_drop_down/report/service_report_last_calls_provider.dart';
import '../../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../../controllers/validator/validator.dart'; import '../../../../../controllers/validator/validator.dart';
import '../../../../../models/device/device.dart'; import '../../../../../models/device/device.dart';
import '../../../../../models/lookup.dart'; import '../../../../../models/lookup.dart';
@ -48,12 +44,10 @@ class CreateServiceReport extends StatefulWidget {
} }
class CreateServiceReportState extends State<CreateServiceReport> with TickerProviderStateMixin { class CreateServiceReportState extends State<CreateServiceReport> with TickerProviderStateMixin {
SettingProvider? _settingProvider;
ServiceRequestsProvider? _serviceRequestsProvider; ServiceRequestsProvider? _serviceRequestsProvider;
bool _validate = false; bool _validate = false;
ServiceReport? _serviceReport; ServiceReport? _serviceReport;
bool _isLoading = false;
Subtitle? _subtitle; Subtitle? _subtitle;
File? _image; File? _image;
@ -84,14 +78,13 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_settingProvider = Provider.of<SettingProvider>(context);
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context); _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_subtitle = AppLocalization.of(context)?.subtitle; _subtitle = AppLocalization.of(context)?.subtitle;
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
body: SafeArea( body: SafeArea(
child: LoadingManager( child: LoadingManager(
isLoading: _isLoading, isLoading: _serviceRequestsProvider?.loading,
isFailedLoading: false, isFailedLoading: false,
stateCode: 200, stateCode: 200,
onRefresh: () async {}, onRefresh: () async {},
@ -110,15 +103,15 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: Text(
_subtitle?.newServiceReport ?? "", _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( Container(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 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 [
const BoxShadow( BoxShadow(
color: AColors.grey, color: AColors.grey,
offset: Offset(0, -1), offset: Offset(0, -1),
) )
@ -144,7 +137,7 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
), ),
Text( Text(
"${_subtitle?.customer}: ${widget.request?.hospitalName}", "${_subtitle?.customer}: ${widget.request?.hospitalName}",
style: Theme.of(context).textTheme.subtitle1?.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 12, fontSize: 12,
), ),
@ -343,7 +336,7 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
ATextFormField( ATextFormField(
initialValue: _serviceReport?.invoiceNumber ?? "", initialValue: _serviceReport?.invoiceNumber ?? "",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "", validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "",
textInputType: TextInputType.number, textInputType: TextInputType.number,
onSaved: (value) { onSaved: (value) {
@ -367,7 +360,7 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
ATextFormField( ATextFormField(
initialValue: _serviceReport?.invoiceCode ?? "", initialValue: _serviceReport?.invoiceCode ?? "",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "", validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "",
textInputType: TextInputType.text, textInputType: TextInputType.text,
onSaved: (value) { onSaved: (value) {
@ -389,10 +382,7 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
Expanded( Expanded(
child: SizedBox( child: SizedBox(
height: 32 * AppStyle.getScaleFactor(context), height: 32 * AppStyle.getScaleFactor(context),
child: SpeechToTextButton( child: SpeechToTextButton(controller: _faultController, mini: true),
controller: _faultController,
mini: true,
),
), ),
), ),
], ],
@ -404,7 +394,7 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
initialValue: _serviceReport?.faultDescription ?? "", initialValue: _serviceReport?.faultDescription ?? "",
textAlign: TextAlign.center, textAlign: TextAlign.center,
controller: _faultController, controller: _faultController,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "", validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "",
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
onSaved: (value) { onSaved: (value) {
@ -435,7 +425,7 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
initialValue: _serviceReport?.workPreformed ?? "", initialValue: _serviceReport?.workPreformed ?? "",
textAlign: TextAlign.center, textAlign: TextAlign.center,
controller: _workPreformedController, controller: _workPreformedController,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "", validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "",
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
onSaved: (value) { onSaved: (value) {
@ -542,7 +532,7 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
initialValue: _serviceReport?.travelingHours, initialValue: _serviceReport?.travelingHours,
textAlign: TextAlign.center, textAlign: TextAlign.center,
hintText: "i.e 3, 3.5, 4", hintText: "i.e 3, 3.5, 4",
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
// validator: (value) => // validator: (value) =>
// Validator.isNumeric(value) // Validator.isNumeric(value)
// ? null : _subtitle.requiredWord, // ? null : _subtitle.requiredWord,
@ -596,7 +586,7 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
ATextFormField( ATextFormField(
initialValue: _serviceReport?.jobSheetNumber, initialValue: _serviceReport?.jobSheetNumber,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.name, textInputType: TextInputType.name,
onSaved: (value) { onSaved: (value) {
_serviceReport?.jobSheetNumber = value; _serviceReport?.jobSheetNumber = value;
@ -649,9 +639,9 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
), ),
Column( Column(
children: List.generate(_serviceReport!.parts!.length, (index) { children: List.generate(_serviceReport!.parts!.length, (index) {
Part _part = _serviceReport!.parts![index]; Part part = _serviceReport!.parts![index];
return PartItem( return PartItem(
part: _part, part: part,
onDelete: (part) { onDelete: (part) {
_serviceReport!.parts!.remove(part); _serviceReport!.parts!.remove(part);
setState(() {}); setState(() {});
@ -672,31 +662,9 @@ class CreateServiceReportState extends State<CreateServiceReport> with TickerPro
text: _subtitle?.submit ?? "", text: _subtitle?.submit ?? "",
onPressed: () async { onPressed: () async {
_validate = true; _validate = true;
if (!(_formKey.currentState?.validate() ?? false)) { if (_formKey.currentState?.validate() ?? false) {
setState(() {});
return;
}
if (!(_serviceReport?.validate() ?? false)) return;
_formKey.currentState?.save(); _formKey.currentState?.save();
await _serviceRequestsProvider?.createServiceReport(context, report: _serviceReport, request: widget.request);
_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),
));
} }
}, },
), ),

@ -2,16 +2,11 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.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/localization/localization.dart';
import '../../../../../controllers/providers/api/service_requests_provider.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/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 '../../../../../controllers/validator/validator.dart';
import '../../../../../models/part.dart'; import '../../../../../models/part.dart';
import '../../../../../models/service_report.dart'; import '../../../../../models/service_report.dart';
@ -38,30 +33,27 @@ import '../../../../widgets/timer/app_timer.dart';
import '../../../../widgets/titles/app_sub_title.dart'; import '../../../../widgets/titles/app_sub_title.dart';
class EditServiceReport extends StatefulWidget { class EditServiceReport extends StatefulWidget {
static final String id = "/edit-service-report"; static const String id = "/edit-service-report";
final ServiceRequest request; final ServiceRequest request;
final ServiceReport report; final ServiceReport report;
const EditServiceReport({Key? key, required this.request, required this.report}) : super(key: key); const EditServiceReport({Key? key, required this.request, required this.report}) : super(key: key);
@override @override
_EditServiceReportState createState() => _EditServiceReportState(); EditServiceReportState createState() => EditServiceReportState();
} }
class _EditServiceReportState extends State<EditServiceReport> with TickerProviderStateMixin { class EditServiceReportState extends State<EditServiceReport> with TickerProviderStateMixin {
late UserProvider _userProvider;
late SettingProvider _settingProvider;
late ServiceRequestsProvider _serviceRequestsProvider; late ServiceRequestsProvider _serviceRequestsProvider;
bool _validate = false; bool _validate = false;
late ServiceReport _serviceReport; late ServiceReport _serviceReport;
bool _isLoading = false;
late Subtitle _subtitle; late Subtitle _subtitle;
late File _image; late File _image;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
TextEditingController _faultController = TextEditingController(); final TextEditingController _faultController = TextEditingController();
TextEditingController _workPreformedController = TextEditingController(); final TextEditingController _workPreformedController = TextEditingController();
@override @override
void initState() { void initState() {
@ -78,15 +70,13 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context); _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_subtitle = AppLocalization.of(context)!.subtitle!; _subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
body: SafeArea( body: SafeArea(
child: LoadingManager( child: LoadingManager(
isLoading: _isLoading, isLoading: _serviceRequestsProvider.loading,
isFailedLoading: false, isFailedLoading: false,
stateCode: 200, stateCode: 200,
onRefresh: () async {}, onRefresh: () async {},
@ -105,14 +95,14 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: Text(
_subtitle.editServiceReport, _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( Container(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 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( BoxShadow(
color: AColors.grey, color: AColors.grey,
offset: Offset(0, -1), offset: Offset(0, -1),
@ -121,28 +111,15 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox( const SizedBox(height: 8),
height: 8,
),
Wrap( Wrap(
spacing: 10, spacing: 10,
children: [ children: [
ASubTitle( ASubTitle("${_subtitle.callId}: ${widget.request.requestCode}", font: 14),
"${_subtitle.callId}: ${widget.request.requestCode}", widget.request.deviceSerialNumber == null ? const SizedBox() : ASubTitle("${_subtitle.deviceSN}: ${widget.request.deviceSerialNumber}", font: 14),
font: 14,
),
widget.request.deviceSerialNumber == null
? const SizedBox()
: ASubTitle(
"${_subtitle.deviceSN}: ${widget.request.deviceSerialNumber}",
font: 14,
),
Text( Text(
"${_subtitle.customer}: ${widget.request.hospitalName}", "${_subtitle.customer}: ${widget.request.hospitalName}",
style: Theme.of(context).textTheme.subtitle1?.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold, fontSize: 12),
fontWeight: FontWeight.bold,
fontSize: 12,
),
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
) )
], ],
@ -158,15 +135,8 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.reportType), ASubTitle(_subtitle.reportType),
_validate && _serviceReport.type == null _validate && _serviceReport.type == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(),
? ASubTitle( const SizedBox(height: 4),
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceReportTypeMenu( ServiceReportTypeMenu(
initialValue: _serviceReport.type, initialValue: _serviceReport.type,
onSelect: (status) { onSelect: (status) {
@ -176,21 +146,14 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
], ],
), ),
), ),
const SizedBox( const SizedBox(width: 8),
width: 8,
),
// visit date // visit date
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.visitDate), ASubTitle(_subtitle.visitDate),
_validate && _serviceReport.visitDate == null _validate && _serviceReport.visitDate == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(),
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
Row( Row(
children: [ children: [
Expanded( Expanded(
@ -211,9 +174,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
), ),
], ],
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
// device sn // device sn
Visibility( Visibility(
visible: true, //widget.report.device == null, visible: true, //widget.report.device == null,
@ -221,12 +182,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.deviceSN), ASubTitle(_subtitle.deviceSN),
_validate && _serviceReport.device?.id == null _validate && _serviceReport.device?.id == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(),
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
AutoCompleteDeviceField( AutoCompleteDeviceField(
hospitalId: widget.request.hospitalId, hospitalId: widget.request.hospitalId,
initialValue: _serviceReport.device!, initialValue: _serviceReport.device!,
@ -234,34 +190,21 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
_serviceReport.device?.id = id; _serviceReport.device?.id = id;
}, },
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
], ],
), ),
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
ASubTitle(_subtitle.serviceType), ASubTitle(_subtitle.serviceType),
_validate && _serviceReport.serviceType == null _validate && _serviceReport.serviceType == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(),
? ASubTitle( const SizedBox(height: 4),
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceStatusMenu( ServiceStatusMenu(
initialValue: _serviceReport.serviceType, initialValue: _serviceReport.serviceType,
onSelect: (status) { onSelect: (status) {
_serviceReport.serviceType = status; _serviceReport.serviceType = status;
}, },
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
// Report status and Service Type // Report status and Service Type
Row( Row(
children: [ children: [
@ -271,15 +214,8 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.reportStatus), ASubTitle(_subtitle.reportStatus),
_validate && _serviceReport.status == null _validate && _serviceReport.status == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(),
? ASubTitle( const SizedBox(height: 4),
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceReportStatusMenu( ServiceReportStatusMenu(
report: _serviceReport, report: _serviceReport,
onSelect: (status) { onSelect: (status) {
@ -289,9 +225,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
], ],
), ),
), ),
const SizedBox( const SizedBox(width: 8),
width: 8,
),
Provider.of<ServiceReportLastCallsProvider>(context).isLoading == null Provider.of<ServiceReportLastCallsProvider>(context).isLoading == null
? const SizedBox.shrink() ? const SizedBox.shrink()
: :
@ -301,15 +235,8 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.callLastSituation), ASubTitle(_subtitle.callLastSituation),
_validate && _serviceReport.callLastSituation == null _validate && _serviceReport.callLastSituation == null ? ASubTitle(_subtitle.requiredWord, color: Colors.red) : const SizedBox.shrink(),
? ASubTitle( const SizedBox(height: 4),
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceReportLastCallsMenu( ServiceReportLastCallsMenu(
report: _serviceReport, report: _serviceReport,
onSelect: (status) { onSelect: (status) {
@ -326,9 +253,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
), ),
], ],
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
// invoice number & code // invoice number & code
_serviceReport.callLastSituation?.id != 12 _serviceReport.callLastSituation?.id != 12
? const SizedBox.shrink() ? const SizedBox.shrink()
@ -339,13 +264,11 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.invoiceNumber), ASubTitle(_subtitle.invoiceNumber),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
ATextFormField( ATextFormField(
initialValue: _serviceReport?.invoiceNumber, initialValue: _serviceReport.invoiceNumber,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.number, textInputType: TextInputType.number,
onSaved: (value) { onSaved: (value) {
@ -355,21 +278,17 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
], ],
), ),
), ),
const SizedBox( const SizedBox(width: 8),
width: 8,
),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.invoiceCode), ASubTitle(_subtitle.invoiceCode),
const SizedBox( const SizedBox(height: 4),
height: 4,
),
ATextFormField( ATextFormField(
initialValue: _serviceReport?.invoiceCode, initialValue: _serviceReport.invoiceCode,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.text, textInputType: TextInputType.text,
onSaved: (value) { onSaved: (value) {
@ -382,19 +301,14 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
], ],
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
Row( Row(
children: [ children: [
ASubTitle(_subtitle.faultDescription), ASubTitle(_subtitle.faultDescription),
Expanded( Expanded(
child: SizedBox( child: SizedBox(
height: 32 * AppStyle.getScaleFactor(context), height: 32 * AppStyle.getScaleFactor(context),
child: SpeechToTextButton( child: SpeechToTextButton(controller: _faultController, mini: true),
controller: _faultController,
mini: true,
),
), ),
), ),
], ],
@ -403,29 +317,24 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
height: 4, height: 4,
), ),
ATextFormField( ATextFormField(
initialValue: _serviceReport?.faultDescription, initialValue: _serviceReport.faultDescription,
textAlign: TextAlign.center, textAlign: TextAlign.center,
controller: _faultController, controller: _faultController,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
onSaved: (value) { onSaved: (value) {
_serviceReport.faultDescription = value; _serviceReport.faultDescription = value;
}, },
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
Row( Row(
children: [ children: [
ASubTitle(_subtitle.workPreformed), ASubTitle(_subtitle.workPreformed),
Expanded( Expanded(
child: SizedBox( child: SizedBox(
height: 32 * AppStyle.getScaleFactor(context), height: 32 * AppStyle.getScaleFactor(context),
child: SpeechToTextButton( child: SpeechToTextButton(controller: _workPreformedController, mini: true),
controller: _workPreformedController,
mini: true,
),
), ),
), ),
], ],
@ -434,10 +343,10 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
height: 4, height: 4,
), ),
ATextFormField( ATextFormField(
initialValue: _serviceReport?.workPreformed, initialValue: _serviceReport.workPreformed,
textAlign: TextAlign.center, textAlign: TextAlign.center,
controller: _workPreformedController, controller: _workPreformedController,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord, validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
onSaved: (value) { onSaved: (value) {
@ -503,9 +412,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.workingHours), ASubTitle(_subtitle.workingHours),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
AppTimer( AppTimer(
timer: _serviceReport.timer, timer: _serviceReport.timer,
onChange: (timer) async { onChange: (timer) async {
@ -529,22 +436,18 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
], ],
), ),
), ),
const SizedBox( const SizedBox(width: 8),
width: 8,
),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ASubTitle(_subtitle.travelingHours), ASubTitle(_subtitle.travelingHours),
const SizedBox( const SizedBox(height: 4),
height: 4,
),
ATextFormField( ATextFormField(
initialValue: _serviceReport?.travelingHours, initialValue: _serviceReport.travelingHours,
textAlign: TextAlign.center, textAlign: TextAlign.center,
hintText: "i.e 3, 3.5, 4", 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, validator: (value) => Validator.isNumeric(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.number, textInputType: TextInputType.number,
onSaved: (value) { onSaved: (value) {
@ -556,9 +459,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
), ),
], ],
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
// Operating Hours and Job Sheet Number // Operating Hours and Job Sheet Number
Row( Row(
children: [ children: [
@ -571,10 +472,10 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
height: 4, height: 4,
), ),
ATextFormField( ATextFormField(
initialValue: _serviceReport?.operatingHours, initialValue: _serviceReport.operatingHours,
textAlign: TextAlign.center, textAlign: TextAlign.center,
hintText: "i.e 3, 3.5, 4", 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, validator: (value) => Validator.isNumeric(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.number, textInputType: TextInputType.number,
onSaved: (value) { onSaved: (value) {
@ -596,9 +497,9 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
height: 4, height: 4,
), ),
ATextFormField( ATextFormField(
initialValue: _serviceReport?.jobSheetNumber, initialValue: _serviceReport.jobSheetNumber,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.name, textInputType: TextInputType.name,
onSaved: (value) { onSaved: (value) {
_serviceReport.jobSheetNumber = value; _serviceReport.jobSheetNumber = value;
@ -609,9 +510,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
), ),
], ],
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
// Part Number and Quantity // Part Number and Quantity
Row( Row(
children: [ children: [
@ -652,9 +551,9 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
), ),
Column( Column(
children: List.generate(_serviceReport.parts!.length, (index) { children: List.generate(_serviceReport.parts!.length, (index) {
Part _part = _serviceReport.parts![index]; Part part = _serviceReport.parts![index];
return PartItem( return PartItem(
part: _part, part: part,
onDelete: (part) { onDelete: (part) {
_serviceReport.parts?.remove(part); _serviceReport.parts?.remove(part);
setState(() {}); setState(() {});
@ -663,9 +562,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
}), }),
), ),
const SizedBox( const SizedBox(height: 16),
height: 16,
),
], ],
), ),
), ),
@ -675,34 +572,9 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
text: _subtitle.update, text: _subtitle.update,
onPressed: () async { onPressed: () async {
_validate = true; _validate = true;
if (!(_formKey.currentState?.validate() ?? false)) { if (_formKey.currentState?.validate() ?? false) {
setState(() {});
return;
}
if (!_serviceReport.validate()) {
setState(() {});
return;
}
_formKey.currentState?.save(); _formKey.currentState?.save();
await _serviceRequestsProvider.updateServiceReport(context, report: _serviceReport, request: widget.request);
_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),
));
} }
}, },
), ),

@ -1,14 +1,8 @@
import 'package:flutter/material.dart'; 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/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_report.dart';
import '../../../../../models/service_request/service_request.dart'; import '../../../../../models/service_request/service_request.dart';
import '../../../../../models/subtitle.dart';
import '../../../../widgets/loaders/app_loading.dart'; import '../../../../widgets/loaders/app_loading.dart';
import '../../../../widgets/loaders/failed_loading.dart'; import '../../../../widgets/loaders/failed_loading.dart';
import 'edit_service_report.dart'; import 'edit_service_report.dart';
@ -19,35 +13,28 @@ class FutureServiceReport extends StatefulWidget {
const FutureServiceReport({Key? key, required this.request}) : super(key: key); const FutureServiceReport({Key? key, required this.request}) : super(key: key);
@override @override
_FutureServiceReportState createState() => _FutureServiceReportState(); FutureServiceReportState createState() => FutureServiceReportState();
} }
class _FutureServiceReportState extends State<FutureServiceReport> { class FutureServiceReportState extends State<FutureServiceReport> {
late UserProvider _userProvider;
late SettingProvider _settingProvider;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold( return Scaffold(
body: FutureBuilder<ServiceReport>( body: FutureBuilder<ServiceReport?>(
future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.request.reportID ?? "", user: UserApiClient().user!, host: _settingProvider.host ?? "", subtitle: _subtitle), future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.request.reportID ?? ""),
builder: (BuildContext context, AsyncSnapshot<ServiceReport> snapshot) { builder: (BuildContext context, snapshot) {
if (snapshot.hasError) if (snapshot.hasError) {
return FailedLoading( return FailedLoading(
message: snapshot.error.toString(), message: snapshot.error.toString(),
onReload: () { onReload: () {
setState(() {}); setState(() {});
}, },
); );
}
if (snapshot.hasData) { if (snapshot.hasData) {
return EditServiceReport( return EditServiceReport(report: snapshot.data!, request: widget.request);
report: snapshot.data!,
request: widget.request,
);
} }
return Center(child: ALoading()); return const Center(child: ALoading());
}, },
), ),
); );

@ -3,20 +3,15 @@ import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../../../api/user_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/localization/localization.dart';
import '../../../../controllers/providers/api/service_requests_provider.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/enums/user_types.dart';
import '../../../../models/service_request/service_request.dart'; import '../../../../models/service_request/service_request.dart';
import '../../../../models/subtitle.dart';
import '../../../app_style/colors.dart'; import '../../../app_style/colors.dart';
import '../../../app_style/sizing.dart'; import '../../../app_style/sizing.dart';
import '../../../widgets/buttons/app_back_button.dart'; import '../../../widgets/buttons/app_back_button.dart';
import '../../../widgets/buttons/app_button.dart'; import '../../../widgets/buttons/app_button.dart';
import '../../../widgets/buttons/app_icon_button.dart'; import '../../../widgets/buttons/app_icon_button.dart';
import '../../../widgets/dialogs/dialog.dart';
import '../../../widgets/images/images_list.dart'; import '../../../widgets/images/images_list.dart';
import '../../../widgets/loaders/image_loader.dart'; import '../../../widgets/loaders/image_loader.dart';
import '../../../widgets/requests/info_row.dart'; import '../../../widgets/requests/info_row.dart';
@ -29,16 +24,15 @@ import 'report/create_service_report.dart';
import 'report/future_service_report.dart'; import 'report/future_service_report.dart';
class RequestDetailsPage extends StatelessWidget { class RequestDetailsPage extends StatelessWidget {
static final String id = "/call-details"; static const String id = "/call-details";
final ServiceRequest serviceRequest; final ServiceRequest serviceRequest;
const RequestDetailsPage({Key? key, required this.serviceRequest}) : super(key: key); const RequestDetailsPage({Key? key, required this.serviceRequest}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!; final subtitle = AppLocalization.of(context)?.subtitle;
UserProvider _userProvider = Provider.of<UserProvider>(context); ServiceRequestsProvider serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
SettingProvider _settingProvider = Provider.of<SettingProvider>(context);
ServiceRequestsProvider _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
return DefaultTabController( return DefaultTabController(
length: 2, length: 2,
child: Scaffold( child: Scaffold(
@ -50,12 +44,12 @@ class RequestDetailsPage extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row( child: Row(
children: [ children: [
ABackButton(), const ABackButton(),
Expanded( Expanded(
child: Center( child: Center(
child: Text( child: Text(
_subtitle.details, subtitle?.details ?? '',
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), style: Theme.of(context).textTheme.titleLarge?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
), ),
), ),
), ),
@ -70,9 +64,7 @@ class RequestDetailsPage extends StatelessWidget {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
builder: (context) { builder: (context) {
return ServiceRequestsUpdateDialog( return ServiceRequestsUpdateDialog(request: serviceRequest);
request: serviceRequest,
);
}); });
// DateTime picked = await showDatePicker( // DateTime picked = await showDatePicker(
// context: context, // context: context,
@ -109,173 +101,98 @@ class RequestDetailsPage extends StatelessWidget {
buttonSize: 42, buttonSize: 42,
backgroundColor: AColors.deepOrange, backgroundColor: AColors.deepOrange,
onPressed: () { onPressed: () {
Navigator.of(context).push(MaterialPageRoute( Navigator.of(context).push(MaterialPageRoute(builder: (_) => ReportIssuesPage(serviceRequest: serviceRequest)));
builder: (_) => ReportIssuesPage(
serviceRequest: serviceRequest,
)));
}, },
), ),
), ),
SizedBox( const SizedBox(width: 16)
width: 16,
)
], ],
), ),
), ),
(serviceRequest.devicePhotos?.isEmpty ?? false) (serviceRequest.devicePhotos?.isEmpty ?? false)
? SizedBox.shrink() ? const SizedBox.shrink()
: Column( : Column(
children: [ children: [
SizedBox( const SizedBox(height: 8),
height: 8,
),
MaterialButton( MaterialButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
onPressed: () { onPressed: () {
Navigator.of(context).push(MaterialPageRoute( Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Scaffold( builder: (_) => Scaffold(
body: InteractiveViewer( body: InteractiveViewer(
child: Center( child: Center(child: ImageLoader(url: serviceRequest.devicePhotos?.first, boxFit: BoxFit.contain)),
child: ImageLoader(
url: serviceRequest.devicePhotos?.first,
boxFit: BoxFit.contain,
), ),
), ),
), ),
))); );
}, },
child: SizedBox( child: SizedBox(
height: 140 * AppStyle.getScaleFactor(context), height: 140 * AppStyle.getScaleFactor(context),
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
child: ImageLoader( child: ImageLoader(url: serviceRequest.devicePhotos?.first, boxFit: BoxFit.cover),
url: serviceRequest.devicePhotos?.first,
boxFit: BoxFit.cover,
),
), ),
), ),
SizedBox( const SizedBox(height: 8),
height: 8,
),
SizedBox( SizedBox(
height: 60 * AppStyle.getScaleFactor(context), height: 60 * AppStyle.getScaleFactor(context),
child: ImagesList( child: ImagesList(images: serviceRequest.devicePhotos!),
images: serviceRequest.devicePhotos!,
),
), ),
], ],
), ),
TabBar(labelColor: AColors.primaryColor, tabs: [ TabBar(
Tab( labelColor: AColors.primaryColor,
text: _subtitle.general, tabs: [
), Tab(text: subtitle?.general),
Tab( Tab(text: subtitle?.serviceRequestInformation),
text: _subtitle.serviceRequestInformation, ],
),
]),
SizedBox(
height: 8,
), ),
const SizedBox(height: 8),
Expanded( Expanded(
child: TabBarView( child: TabBarView(
children: [ children: [
ListView( ListView(
padding: EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
children: [ children: [
RequestInfoRow( RequestInfoRow(title: subtitle?.code, info: serviceRequest.requestCode),
title: _subtitle.code, RequestInfoRow(title: "Asset Number", info: serviceRequest.deviceNumber),
info: serviceRequest.requestCode, RequestInfoRow(title: subtitle?.deviceSN, info: serviceRequest.deviceSerialNumber),
), RequestInfoRow(title: subtitle?.deviceModel, info: serviceRequest.deviceModel),
RequestInfoRow( RequestInfoRow(title: subtitle?.engineerName, info: serviceRequest.engineerName),
title: "Asset Number", RequestInfoRow(title: subtitle?.engineerPhone, info: serviceRequest.engineerMobile),
info: serviceRequest.deviceNumber, RequestInfoRow(title: subtitle?.date, info: serviceRequest.date),
),
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 serviceRequest.nextVisitDate == null
? SizedBox.shrink() ? const SizedBox.shrink()
: RequestInfoRow( : RequestInfoRow(title: subtitle?.nextVisitDate, info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate!)),
title: _subtitle.nextVisitDate,
info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate!),
),
Row( Row(
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"${_subtitle.status} : ", "${subtitle?.status} : ",
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
), ),
StatusLabel(label: serviceRequest.statusLabel, color: AColors.getRequestStatusColor(serviceRequest.statusValue!)), StatusLabel(label: serviceRequest.statusLabel, color: AColors.getRequestStatusColor(serviceRequest.statusValue!)),
], ],
), ),
Divider( Divider(color: Theme.of(context).primaryColor),
color: Theme.of(context).primaryColor, RequestInfoRow(title: subtitle?.hospital, info: serviceRequest.hospitalName),
), RequestInfoRow(title: subtitle?.unite, info: serviceRequest.departmentName),
RequestInfoRow(
title: _subtitle.hospital,
info: serviceRequest.hospitalName,
),
RequestInfoRow(
title: _subtitle.unite,
info: serviceRequest.departmentName,
),
// RequestInfoRow( // RequestInfoRow(
// title: _subtitle.deviceArName, // title: _subtitle.deviceArName,
// content: serviceRequest.deviceArName, // content: serviceRequest.deviceArName,
// ), // ),
RequestInfoRow( RequestInfoRow(title: subtitle?.deviceEnName, content: serviceRequest.deviceEnName),
title: _subtitle.deviceEnName, RequestInfoRow(title: subtitle?.maintenanceIssue, content: serviceRequest.maintenanceIssue),
content: serviceRequest.deviceEnName, if (serviceRequest.audio?.isNotEmpty == true) ASoundPlayer(audio: serviceRequest.audio),
),
RequestInfoRow(
title: _subtitle.maintenanceIssue,
content: serviceRequest.maintenanceIssue,
),
if (serviceRequest.audio?.isNotEmpty == true)
ASoundPlayer(
audio: serviceRequest.audio,
),
Center( Center(
child: Padding( child: Padding(
padding: EdgeInsets.all(32), padding: const EdgeInsets.all(32),
child: AButton( child: AButton(
text: _subtitle.duplicateRequest, text: subtitle?.duplicateRequest ?? '',
onPressed: () async { onPressed: () async {
bool result = await showDialog( await serviceRequestsProvider.createDuplicatedReport(context, request: serviceRequest);
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))));
}
}, },
), ),
), ),
@ -284,62 +201,42 @@ class RequestDetailsPage extends StatelessWidget {
), ),
serviceRequest.viewReport ?? false serviceRequest.viewReport ?? false
? ListView( ? ListView(
padding: EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
children: [ children: [
RequestInfoRow( RequestInfoRow(title: subtitle?.faultDescription, content: serviceRequest.faultDescription),
title: _subtitle.faultDescription, RequestInfoRow(title: subtitle?.workPerformed, content: serviceRequest.workPerformed),
content: serviceRequest.faultDescription, RequestInfoRow(title: subtitle?.visitDate, info: serviceRequest.visitDate),
), RequestInfoRow(title: subtitle?.jobSheetNumber, info: serviceRequest.jobSheetNumber),
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 UserApiClient().user?.type == UsersTypes.engineer
? Padding( ? Padding(
padding: EdgeInsets.all(32), padding: const EdgeInsets.all(32),
child: AButton( child: AButton(
text: _subtitle.editServiceReport, text: subtitle?.editServiceReport ?? '',
onPressed: () { onPressed: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(builder: (_) => FutureServiceReport(request: serviceRequest)),
builder: (_) => FutureServiceReport(
request: serviceRequest,
)),
); );
}, },
), ),
) )
: SizedBox.shrink(), : const SizedBox.shrink(),
], ],
) )
: UserApiClient().user?.type == UsersTypes.engineer : UserApiClient().user?.type == UsersTypes.engineer
? Center( ? Center(
child: Padding( child: Padding(
padding: EdgeInsets.all(32), padding: const EdgeInsets.all(32),
child: AButton( child: AButton(
text: "Create Report", text: "Create Report",
onPressed: () { onPressed: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)),
builder: (_) => CreateServiceReport(
request: serviceRequest,
)),
); );
}, },
), ),
), ),
) )
: Center( : Center(child: ASubTitle(subtitle?.noDateFound ?? '')),
child: ASubTitle(_subtitle.noDateFound),
),
], ],
), ),
), ),

@ -2,10 +2,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/api/service_request_api_client.dart'; import 'package:test_sa/api/service_request_api_client.dart';
import '../../../../api/user_api_client.dart';
import '../../../../controllers/localization/localization.dart'; import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/service_requests_provider.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/service_request/service_request_search.dart';
import '../../../../models/subtitle.dart'; import '../../../../models/subtitle.dart';
import '../../../app_style/colors.dart'; import '../../../app_style/colors.dart';
@ -26,14 +24,12 @@ class ServiceRequestsPage extends StatefulWidget {
class ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerProviderStateMixin { class ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerProviderStateMixin {
late ServiceRequestsProvider _serviceRequestsProvider; late ServiceRequestsProvider _serviceRequestsProvider;
late SettingProvider _settingProvider;
final bool _expandedSearch = false; final bool _expandedSearch = false;
bool _firstTime = true; bool _firstTime = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context); _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
Subtitle? subtitle = AppLocalization.of(context)?.subtitle; Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
if (_firstTime) { if (_firstTime) {
_serviceRequestsProvider.reset(); _serviceRequestsProvider.reset();
@ -43,15 +39,11 @@ class ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerPro
return Scaffold( return Scaffold(
body: SafeArea( body: SafeArea(
child: LoadingManager( child: LoadingManager(
isLoading: _serviceRequestsProvider.isLoading, isLoading: _serviceRequestsProvider.loading,
stateCode: _serviceRequestsProvider.stateCode, stateCode: _serviceRequestsProvider.stateCode,
onRefresh: () async { onRefresh: () async {
_serviceRequestsProvider.reset(); _serviceRequestsProvider.reset();
await _serviceRequestsProvider.getRequests( await _serviceRequestsProvider.getRequests();
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
hospitalId: UserApiClient().user!.hospital!.id,
);
}, },
child: Stack( child: Stack(
children: [ children: [
@ -87,9 +79,7 @@ class ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerPro
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (context) { builder: (context) {
return ServiceRequestsSearchDialog( return ServiceRequestsSearchDialog(initialSearchValue: _serviceRequestsProvider.search!);
initialSearchValue: _serviceRequestsProvider.search!,
);
}, },
); );
if (temp != null) { if (temp != null) {
@ -107,13 +97,9 @@ class ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerPro
), ),
Expanded( Expanded(
child: ServiceRequestsList( child: ServiceRequestsList(
nextPage: _serviceRequestsProvider.nextPage!, nextPage: _serviceRequestsProvider.nextPage ?? false,
onLazyLoad: () async { onLazyLoad: () async {
await _serviceRequestsProvider.getRequests( await _serviceRequestsProvider.getRequests();
user: UserApiClient().user,
host: _settingProvider.host ?? "",
hospitalId: UserApiClient().user?.hospital?.id,
);
}, },
requests: ServiceRequestApiClient().serviceRequests, requests: ServiceRequestApiClient().serviceRequests,
), ),

@ -1,12 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.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/localization/localization.dart';
import '../../../../../controllers/providers/api/regular_visits_provider.dart'; import '../../../../../controllers/providers/api/regular_visits_provider.dart';
import '../../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../../models/pantry/pentry.dart'; import '../../../../../models/pantry/pentry.dart';
import '../../../../../models/subtitle.dart'; import '../../../../../models/subtitle.dart';
import '../../../../../models/visits/visit.dart'; import '../../../../../models/visits/visit.dart';
@ -28,45 +24,14 @@ class EditPentry extends StatefulWidget {
} }
class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateMixin { class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateMixin {
bool _isLoading = false;
bool _validate = false; bool _validate = false;
Subtitle? _subtitle; Subtitle? _subtitle;
late SettingProvider _settingProvider;
late RegularVisitsProvider _regularVisitsProvider; late RegularVisitsProvider _regularVisitsProvider;
Pentry? _pentry; Pentry? _pentry;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
late final TabController _tabController; 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 @override
void initState() { void initState() {
_pentry = widget.pentry; _pentry = widget.pentry;
@ -83,13 +48,12 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context)?.subtitle; _subtitle = AppLocalization.of(context)?.subtitle;
_settingProvider = Provider.of<SettingProvider>(context);
_regularVisitsProvider = Provider.of<RegularVisitsProvider>(context); _regularVisitsProvider = Provider.of<RegularVisitsProvider>(context);
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
body: SafeArea( body: SafeArea(
child: LoadingManager( child: LoadingManager(
isLoading: _isLoading, isLoading: _regularVisitsProvider.loading,
isFailedLoading: false, isFailedLoading: false,
stateCode: 200, stateCode: 200,
onRefresh: () async {}, onRefresh: () async {},
@ -176,7 +140,12 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
if (_tabController.index == _tabController.length - 1) if (_tabController.index == _tabController.length - 1)
ASmallButton( ASmallButton(
text: _subtitle?.update, text: _subtitle?.update,
onPressed: _onSubmit, onPressed: () async {
_validate = true;
if (_pentry?.validate() ?? false) {
_regularVisitsProvider.updatePentry(context, pentry: _pentry, visit: widget.visit);
}
},
), ),
], ],
), ),

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../../../../api/user_api_client.dart';
import '../../../../../controllers/localization/localization.dart'; import '../../../../../controllers/localization/localization.dart';
import '../../../../../controllers/providers/api/regular_visits_provider.dart'; import '../../../../../controllers/providers/api/regular_visits_provider.dart';
import '../../../../../controllers/providers/settings/setting_provider.dart'; import '../../../../../controllers/providers/settings/setting_provider.dart';
@ -23,6 +22,7 @@ class FutureEditPentry extends StatefulWidget {
class _FutureEditPentryState extends State<FutureEditPentry> { class _FutureEditPentryState extends State<FutureEditPentry> {
late SettingProvider _settingProvider; late SettingProvider _settingProvider;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_settingProvider = Provider.of<SettingProvider>(context); _settingProvider = Provider.of<SettingProvider>(context);
@ -30,7 +30,7 @@ class _FutureEditPentryState extends State<FutureEditPentry> {
Subtitle subtitle = AppLocalization.of(context)!.subtitle!; Subtitle subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold( return Scaffold(
body: FutureBuilder<Pentry?>( body: FutureBuilder<Pentry?>(
future: RegularVisitsProvider().getPently(user: UserApiClient().user!, host: _settingProvider.host ?? "", id: widget.visit.id!), future: RegularVisitsProvider().getPently(id: widget.visit.id),
builder: (BuildContext context, AsyncSnapshot<Pentry?> snapshot) { builder: (BuildContext context, AsyncSnapshot<Pentry?> snapshot) {
if (snapshot.hasError) { if (snapshot.hasError) {
return FailedLoading( return FailedLoading(

@ -1,16 +1,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.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/localization/localization.dart';
import '../../../../controllers/providers/api/preventive_maintenance_visits_provider.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/subtitle.dart';
import '../../../../models/visits/visits_group.dart';
import '../../../../models/visits/visits_search.dart'; import '../../../../models/visits/visits_search.dart';
import '../../../app_style/colors.dart'; import '../../../app_style/colors.dart';
import '../../../widgets/buttons/app_back_button.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/loaders/loading_manager.dart';
import '../../../widgets/search/visits_search_bar.dart'; import '../../../widgets/search/visits_search_bar.dart';
import '../../../widgets/visits/visits_list.dart'; import '../../../widgets/visits/visits_list.dart';
import 'update_visits_group_sheet.dart';
class PreventiveMaintenanceVisitsPage extends StatefulWidget { class PreventiveMaintenanceVisitsPage extends StatefulWidget {
static final String id = "/preventive-maintenance-visits"; static const String id = "/preventive-maintenance-visits";
const PreventiveMaintenanceVisitsPage({super.key});
@override @override
_PreventiveMaintenanceVisitsPageState createState() => _PreventiveMaintenanceVisitsPageState(); PreventiveMaintenanceVisitsPageState createState() => PreventiveMaintenanceVisitsPageState();
} }
class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceVisitsPage> with TickerProviderStateMixin { class PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceVisitsPage> with TickerProviderStateMixin {
late PreventiveMaintenanceVisitsProvider _visitsProvider; late PreventiveMaintenanceVisitsProvider _visitsProvider;
late UserProvider _userProvider; Subtitle? _subtitle;
late SettingProvider _settingProvider;
late Subtitle _subtitle;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_visitsProvider = Provider.of<PreventiveMaintenanceVisitsProvider>(context); _visitsProvider = Provider.of<PreventiveMaintenanceVisitsProvider>(context);
_userProvider = Provider.of<UserProvider>(context); _subtitle = AppLocalization.of(context)?.subtitle;
_settingProvider = Provider.of<SettingProvider>(context);
_subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold( return Scaffold(
body: SafeArea( body: SafeArea(
child: LoadingManager( child: LoadingManager(
isLoading: _visitsProvider.isLoading, isLoading: _visitsProvider.loading,
isFailedLoading: _visitsProvider.visits == null,
stateCode: _visitsProvider.stateCode, stateCode: _visitsProvider.stateCode,
onRefresh: () async { onRefresh: () async {
//_visitsProvider.visitsSearch = VisitsSearch(); //_visitsProvider.visitsSearch = VisitsSearch();
_visitsProvider.reset(); _visitsProvider.reset();
await _visitsProvider.getVisits( await _visitsProvider.getVisits();
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
//visitsSearch: _visitsSearch
);
}, },
child: Stack( child: Stack(
children: [ children: [
@ -65,12 +52,12 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
children: [ children: [
Row( Row(
children: [ children: [
ABackButton(), const ABackButton(),
Expanded( Expanded(
child: Center( child: Center(
child: Text( child: Text(
_subtitle.preventiveMaintenance, _subtitle?.preventiveMaintenance ?? '',
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), style: Theme.of(context).textTheme.titleLarge?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
), ),
), ),
), ),
@ -80,41 +67,35 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
buttonSize: 42, buttonSize: 42,
backgroundColor: AColors.white, backgroundColor: AColors.white,
onPressed: () async { onPressed: () async {
VisitsSearch? _temp = await showModalBottomSheet( VisitsSearch? temp = await showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (context) { builder: (context) {
return VisitsSearchDialog( return VisitsSearchDialog(
initialSearchValue: _visitsProvider.visitsSearch!, initialSearchValue: _visitsProvider.visitsSearch!,
onSearch: (VisitsSearch) {}, onSearch: (visitsSearch) {},
); );
}); },
if (_temp != null) {
_visitsProvider.visitsSearch = _temp;
_visitsProvider.reset();
setState(() {});
await _visitsProvider.getVisits(
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
//visitsSearch: _visitsSearch
); );
if (temp != null) {
_visitsProvider.visitsSearch = temp;
_visitsProvider.reset();
await _visitsProvider.getVisits();
} }
}, },
), ),
SizedBox( const SizedBox(width: 16)
width: 16,
)
], ],
), ),
], ],
), ),
), ),
Visibility( Visibility(
visible: _visitsProvider.visitsSearch?.toSearchString().isNotEmpty ?? false, visible: _visitsProvider.visitsSearch?.queryParameters().isNotEmpty ?? false,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: AButton( child: AButton(
text: _subtitle.clearSearch, text: _subtitle?.clearSearch ?? '',
onPressed: () { onPressed: () {
_visitsProvider.visitsSearch = VisitsSearch(); _visitsProvider.visitsSearch = VisitsSearch();
_visitsProvider.reset(); _visitsProvider.reset();
@ -127,52 +108,12 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
child: VisitsList( child: VisitsList(
nextPage: _visitsProvider.nextPage!, nextPage: _visitsProvider.nextPage!,
onLazyLoad: () async { onLazyLoad: () async {
await _visitsProvider.getVisits( await _visitsProvider.getVisits();
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
//visitsSearch: _visitsSearch
);
}, },
onEditGroup: (visits) async { onEditGroup: (visits) async {
VisitsGroup _group = await showModalBottomSheet( _visitsProvider.updateGroupOfVisits(context);
isScrollControlled: true,
context: context,
builder: (context) {
return UpdateVisitsGroupSheet(
visits: visits,
title: _subtitle.updatePreventiveMaintenance,
);
},
) as VisitsGroup;
if (_group != null) {
showDialog<void>(
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,
);
}
}
}, },
visits: _visitsProvider.visits!, visits: PreventiveMaintenanceApiClient().visits,
), ),
), ),
], ],

@ -1,16 +1,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.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/localization/localization.dart';
import '../../../../controllers/providers/api/regular_visits_provider.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/subtitle.dart';
import '../../../../models/visits/visits_group.dart';
import '../../../../models/visits/visits_search.dart'; import '../../../../models/visits/visits_search.dart';
import '../../../app_style/colors.dart'; import '../../../app_style/colors.dart';
import '../../../widgets/buttons/app_back_button.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/loaders/loading_manager.dart';
import '../../../widgets/search/visits_search_bar.dart'; import '../../../widgets/search/visits_search_bar.dart';
import '../../../widgets/visits/visits_list.dart'; import '../../../widgets/visits/visits_list.dart';
import 'update_visits_group_sheet.dart';
class RegularVisitsPage extends StatefulWidget { class RegularVisitsPage extends StatefulWidget {
static const String id = "/Regular-visits"; static const String id = "/Regular-visits";
const RegularVisitsPage({super.key}); const RegularVisitsPage({super.key});
@override @override
_RegularVisitsPageState createState() => _RegularVisitsPageState(); RegularVisitsPageState createState() => RegularVisitsPageState();
} }
class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProviderStateMixin { class RegularVisitsPageState extends State<RegularVisitsPage> with TickerProviderStateMixin {
late RegularVisitsProvider _visitsProvider; late RegularVisitsProvider _visitsProvider;
late UserProvider _userProvider; final bool _expandedSearch = false;
late SettingProvider _settingProvider; late Subtitle? _subtitle;
bool _expandedSearch = false;
late Subtitle _subtitle;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_visitsProvider = Provider.of<RegularVisitsProvider>(context); _visitsProvider = Provider.of<RegularVisitsProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context); _subtitle = AppLocalization.of(context)?.subtitle;
_userProvider = Provider.of<UserProvider>(context);
_subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold( return Scaffold(
body: SafeArea( body: SafeArea(
child: LoadingManager( child: LoadingManager(
isLoading: _visitsProvider.isLoading, isLoading: _visitsProvider.loading,
stateCode: _visitsProvider.stateCode, stateCode: _visitsProvider.stateCode,
onRefresh: () async { onRefresh: () async {
_visitsProvider.reset(); _visitsProvider.reset();
//_visitsProvider.visitsSearch = VisitsSearch(); //_visitsProvider.visitsSearch = VisitsSearch();
await _visitsProvider.getVisits( await _visitsProvider.getVisits();
user: UserApiClient().user,
host: _settingProvider.host,
);
}, },
child: Stack( child: Stack(
children: [ children: [
@ -65,17 +53,17 @@ class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProvid
children: [ children: [
Row( Row(
children: [ children: [
ABackButton(), const ABackButton(),
Expanded( Expanded(
child: Center( child: Center(
child: Text( child: Text(
_subtitle.preventiveMaintenance, _subtitle?.preventiveMaintenance ?? '',
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), style: Theme.of(context).textTheme.titleLarge?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
), ),
), ),
), ),
AnimatedSwitcher( AnimatedSwitcher(
duration: Duration(milliseconds: 400), duration: const Duration(milliseconds: 400),
child: AIconButton( child: AIconButton(
key: ValueKey(_expandedSearch), key: ValueKey(_expandedSearch),
iconData: _expandedSearch ? Icons.keyboard_arrow_up : Icons.search, iconData: _expandedSearch ? Icons.keyboard_arrow_up : Icons.search,
@ -83,35 +71,33 @@ class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProvid
buttonSize: 42, buttonSize: 42,
backgroundColor: AColors.white, backgroundColor: AColors.white,
onPressed: () async { onPressed: () async {
VisitsSearch _temp = await showModalBottomSheet( VisitsSearch temp = await showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (context) { builder: (context) {
return VisitsSearchDialog( return VisitsSearchDialog(
initialSearchValue: _visitsProvider.visitsSearch!, initialSearchValue: _visitsProvider.visitsSearch!,
onSearch: (VisitsSearch) {}, onSearch: (visitsSearch) {},
); );
}); });
_visitsProvider.visitsSearch?.fromSearch(_temp); _visitsProvider.visitsSearch?.fromSearch(temp);
_visitsProvider.reset(); _visitsProvider.reset();
setState(() {}); setState(() {});
}, },
), ),
), ),
SizedBox( const SizedBox(width: 16)
width: 16,
)
], ],
), ),
], ],
), ),
), ),
Visibility( Visibility(
visible: _visitsProvider.visitsSearch?.toSearchString().isNotEmpty ?? false, visible: _visitsProvider.visitsSearch?.queryParameters().isNotEmpty ?? false,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: AButton( child: AButton(
text: _subtitle.clearSearch, text: _subtitle?.clearSearch ?? '',
onPressed: () { onPressed: () {
_visitsProvider.visitsSearch = VisitsSearch(); _visitsProvider.visitsSearch = VisitsSearch();
_visitsProvider.reset(); _visitsProvider.reset();
@ -124,51 +110,12 @@ class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProvid
child: VisitsList( child: VisitsList(
nextPage: _visitsProvider.nextPage, nextPage: _visitsProvider.nextPage,
onLazyLoad: () async { onLazyLoad: () async {
await _visitsProvider.getVisits( await _visitsProvider.getVisits();
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
);
}, },
onEditGroup: (visits) async { onEditGroup: (visits) async {
VisitsGroup? group = await showModalBottomSheet( await _visitsProvider.updateGroupOfVisits(context);
isScrollControlled: true,
context: context,
builder: (context) {
return UpdateVisitsGroupSheet(
visits: visits,
title: _subtitle.updateRegularVisits,
);
},
) as VisitsGroup?;
if (group != null) {
showDialog<void>(
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,
);
}
}
}, },
visits: _visitsProvider.visits, visits: VisitsApiClient().visits,
), ),
), ),
], ],

@ -16,13 +16,13 @@ import '../../../widgets/visits/visit_status.dart';
import 'pantry/future_edit_pently.dart'; import 'pantry/future_edit_pently.dart';
class VisitDetailsPage extends StatelessWidget { class VisitDetailsPage extends StatelessWidget {
static final String id = "/visit-details"; static const String id = "/visit-details";
final Visit visit; final Visit visit;
const VisitDetailsPage({Key? key, required this.visit}) : super(key: key); const VisitDetailsPage({Key? key, required this.visit}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!; Subtitle subtitle = AppLocalization.of(context)!.subtitle!;
final regularVisitsProvider = Provider.of<RegularVisitsProvider>(context); final regularVisitsProvider = Provider.of<RegularVisitsProvider>(context);
return Scaffold( return Scaffold(
@ -38,7 +38,7 @@ class VisitDetailsPage extends StatelessWidget {
Expanded( Expanded(
child: Center( child: Center(
child: Text( child: Text(
_subtitle.visitInformation, subtitle.visitInformation,
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic), style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
), ),
), ),
@ -105,7 +105,7 @@ class VisitDetailsPage extends StatelessWidget {
height: 8, height: 8,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.code, title: subtitle.code,
info: visit.serialNumber, info: visit.serialNumber,
), ),
RequestInfoRow( RequestInfoRow(
@ -113,22 +113,22 @@ class VisitDetailsPage extends StatelessWidget {
info: visit.deviceNumber, info: visit.deviceNumber,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.deviceSN, title: subtitle.deviceSN,
info: visit.deviceSerialNumber, info: visit.deviceSerialNumber,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.expectDate, title: subtitle.expectDate,
info: visit.expectDate, info: visit.expectDate,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.actualDate, title: subtitle.actualDate,
info: visit.actualDate, info: visit.actualDate,
), ),
Row( Row(
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"${_subtitle.status} : ", "${subtitle.status} : ",
style: Theme.of(context).textTheme.subtitle1?.copyWith(fontWeight: FontWeight.bold), style: Theme.of(context).textTheme.subtitle1?.copyWith(fontWeight: FontWeight.bold),
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
@ -142,23 +142,23 @@ class VisitDetailsPage extends StatelessWidget {
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.contactStatus, title: subtitle.contactStatus,
info: visit.assignTo, info: visit.assignTo,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.engineerName, title: subtitle.engineerName,
info: visit.employName, info: visit.employName,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.hospital, title: subtitle.hospital,
content: visit.hospitalName, content: visit.hospitalName,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.deviceArName, title: subtitle.deviceArName,
content: visit.deviceArabicName, content: visit.deviceArabicName,
), ),
RequestInfoRow( RequestInfoRow(
title: _subtitle.deviceEnName, title: subtitle.deviceEnName,
content: visit.deviceEnglishName, content: visit.deviceEnglishName,
), ),
], ],

@ -18,21 +18,21 @@ class LazyLoading extends StatefulWidget {
}) : super(key: key); }) : super(key: key);
@override @override
_LazyLoadingState createState() => _LazyLoadingState(); LazyLoadingState createState() => LazyLoadingState();
} }
class _LazyLoadingState extends State<LazyLoading> with TickerProviderStateMixin { class LazyLoadingState extends State<LazyLoading> with TickerProviderStateMixin {
late AnimationController _animationController; late AnimationController _animationController;
late Animation<Offset> _offsetAnimation; late Animation<Offset> _offsetAnimation;
_scrollListener() async { _scrollListener() async {
if (!_animationController.isAnimating && !_animationController.isCompleted && widget.nextPage) { if (!_animationController.isAnimating && !_animationController.isCompleted && widget.nextPage) {
_animationController?.forward(); _animationController.forward();
setState(() {}); setState(() {});
await widget.onLazyLoad(); await widget.onLazyLoad();
await Future.delayed(Duration(milliseconds: 600)); await Future.delayed(const Duration(milliseconds: 600));
setState(() {}); setState(() {});
_animationController?.reverse(); _animationController.reverse();
} }
} }
@ -56,7 +56,7 @@ class _LazyLoadingState extends State<LazyLoading> with TickerProviderStateMixin
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
_animationController?.dispose(); _animationController.dispose();
} }
@override @override
@ -75,13 +75,13 @@ class _LazyLoadingState extends State<LazyLoading> with TickerProviderStateMixin
position: _offsetAnimation, position: _offsetAnimation,
child: Center( child: Center(
child: Visibility( child: Visibility(
visible: (_animationController?.isAnimating ?? false) || (_animationController?.isCompleted ?? false), visible: (_animationController.isAnimating) || (_animationController.isCompleted),
child: Container( child: Container(
height: 36 * AppStyle.getScaleFactor(context), height: 36 * AppStyle.getScaleFactor(context),
width: 36 * AppStyle.getScaleFactor(context), width: 36 * AppStyle.getScaleFactor(context),
padding: EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle, boxShadow: [AppStyle.boxShadow]), decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle, boxShadow: [AppStyle.boxShadow]),
child: ALoading(), child: const ALoading(),
), ),
), ),
), ),

@ -49,7 +49,7 @@ class _LoadingManagerState extends State<LoadingManager> {
Subtitle? subtitle = AppLocalization.of(context)?.subtitle; Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
Widget? placeHolder; Widget? placeHolder;
// to load data if load not start // 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) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
widget.onRefresh!(); widget.onRefresh!();
}); });
@ -70,7 +70,7 @@ class _LoadingManagerState extends State<LoadingManager> {
// if load end successfully return loaded widget // if load end successfully return loaded widget
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
await widget.onRefresh!(); if (widget.onRefresh != null) await widget.onRefresh!();
}, },
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: const Duration(milliseconds: 400), duration: const Duration(milliseconds: 400),

@ -1,14 +1,9 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.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/localization/localization.dart';
import '../../../controllers/providers/api/service_requests_provider.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/lookup.dart';
import '../../../models/service_request/service_request.dart'; import '../../../models/service_request/service_request.dart';
import '../../../models/subtitle.dart'; import '../../../models/subtitle.dart';
@ -33,45 +28,10 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
DateTime? _dateTime; DateTime? _dateTime;
Lookup? _employee; Lookup? _employee;
Subtitle? _subtitle; Subtitle? _subtitle;
UserProvider? _userProvider;
SettingProvider? _settingProvider;
ServiceRequestsProvider? _serviceRequestsProvider; ServiceRequestsProvider? _serviceRequestsProvider;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
_update() async {
if (_dateTime == null && _employee == null) {
Fluttertoast.showToast(msg: _subtitle?.noDateFound ?? '');
return;
}
showDialog<void>(
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 @override
void initState() { void initState() {
super.initState(); super.initState();
@ -80,8 +40,6 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context)?.subtitle; _subtitle = AppLocalization.of(context)?.subtitle;
_userProvider = Provider.of<UserProvider>(context, listen: false);
_settingProvider = Provider.of<SettingProvider>(context, listen: false);
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context, listen: false); _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context, listen: false);
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -105,7 +63,13 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
), ),
ASmallButton( ASmallButton(
text: _subtitle?.update, text: _subtitle?.update,
onPressed: _update, onPressed: () async {
if (_dateTime == null && _employee == null) {
Fluttertoast.showToast(msg: _subtitle?.noDateFound ?? '');
return;
}
await _serviceRequestsProvider?.updateDate(context, request: widget.request, newDate: _dateTime?.toString().split(" ").first, employee: _employee);
},
) )
], ],
), ),
@ -115,7 +79,7 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
Expanded( Expanded(
child: Text( child: Text(
_subtitle?.date ?? '', _subtitle?.date ?? '',
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
), ),

@ -69,9 +69,10 @@ class ServiceRequestsSearchDialogState extends State<ServiceRequestsSearchDialog
ASmallButton( ASmallButton(
text: subtitle?.search, text: subtitle?.search,
onPressed: () { onPressed: () {
if (!(_formKey.currentState?.validate() ?? true)) return; if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save(); _formKey.currentState?.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}
}, },
) )
], ],
@ -83,9 +84,10 @@ class ServiceRequestsSearchDialogState extends State<ServiceRequestsSearchDialog
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: () { onAction: () {
if (!(_formKey.currentState?.validate() ?? true)) return; if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save(); _formKey.currentState?.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}
}, },
onSaved: (value) { onSaved: (value) {
_search.deviceSerialNumber = value; _search.deviceSerialNumber = value;
@ -113,9 +115,10 @@ class ServiceRequestsSearchDialogState extends State<ServiceRequestsSearchDialog
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: () { onAction: () {
if (!(_formKey.currentState?.validate() ?? true)) return; if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save(); _formKey.currentState?.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}
}, },
onSaved: (value) { onSaved: (value) {
_search.deviceName = value; _search.deviceName = value;
@ -128,9 +131,10 @@ class ServiceRequestsSearchDialogState extends State<ServiceRequestsSearchDialog
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: () { onAction: () {
if (!(_formKey.currentState?.validate() ?? true)) return; if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save(); _formKey.currentState?.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}
}, },
onSaved: (value) { onSaved: (value) {
_search.model = value; _search.model = value;
@ -145,7 +149,9 @@ class ServiceRequestsSearchDialogState extends State<ServiceRequestsSearchDialog
spacing: 10, spacing: 10,
runSpacing: 10, runSpacing: 10,
alignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly,
children: List.generate(status.length, (index) { children: List.generate(
status.length,
(index) {
bool isSelected = _search.statusValue == status[index].id; bool isSelected = _search.statusValue == status[index].id;
return FilterItem( return FilterItem(
isSelected: isSelected, isSelected: isSelected,
@ -159,11 +165,12 @@ class ServiceRequestsSearchDialogState extends State<ServiceRequestsSearchDialog
}, },
status: status[index], status: status[index],
); );
}), },
),
), ),
), ),
Visibility( Visibility(
visible: widget.initialSearchValue.toSearchString().isNotEmpty, visible: widget.initialSearchValue.queryParameters().isNotEmpty,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 8, vertical: 8,

@ -245,7 +245,7 @@ class VisitsSearchDialogState extends State<VisitsSearchDialog> with TickerProvi
}, },
), ),
Visibility( Visibility(
visible: _search?.toSearchString().isNotEmpty ?? false, visible: _search?.queryParameters().isNotEmpty ?? false,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: AButton( child: AButton(

Loading…
Cancel
Save