Merge branch 'master' into majd_development

merge-requests/16/head
nextwo 2 years ago
commit 32acdb8537

@ -66,7 +66,7 @@ class ApiClient {
factory ApiClient() => _instance;
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'};
if (headers != null && headers.isNotEmpty) {
defaultHeaders.addAll(headers);
@ -97,7 +97,7 @@ class ApiClient {
}
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;
String? requestBody;
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/user_api_client.dart';
import 'package:test_sa/models/issue.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_report.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/service_request/service_request_search.dart';
import 'package:test_sa/models/timer_model.dart';
import '../controllers/api_routes/urls.dart';
@ -35,7 +40,107 @@ class ServiceRequestApiClient {
"defect_types": (serviceRequest.defectType?.id).toString(),
"audio": serviceRequest.audio,
},
isFormData: true,
);
}
/// Get Service Requests and Fill [serviceRequests]
Future<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}",
await user.toLoginJson(), //body
isFormData: true,
);
}
@ -41,7 +40,6 @@ class UserApiClient {
},
"${URLs.host1}${URLs.register}",
await newUser.toRegisterJson(), //body
isFormData: true,
);
}
@ -57,7 +55,6 @@ class UserApiClient {
},
"${URLs.host1}${URLs.updateProfile}",
updatedUser.toUpdateProfileJson(), //body
isFormData: true,
);
// Map<String, dynamic> jsonObject = {};
// 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 {
if (hospitalId != null) {
_searchableList.clear();
waitApiRequest(
await waitApiRequest(
() async {
await DevicesApiClient().getEquipment(hospitalId);
_searchableList.addAll(DevicesApiClient().devices);

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

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

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

@ -20,26 +20,13 @@ class ServiceRequestSearch {
model = newSearch.model;
}
String toSearchString() {
String search = "";
if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) {
search += "&sn_id=$deviceSerialNumber";
}
if (statusValue != null) {
search += "&status=$statusValue";
}
if (deviceName != null && (deviceName?.isNotEmpty ?? false)) {
search += "&equipment_en_name=$deviceName";
}
if (hospital != null && (hospital?.isNotEmpty ?? false)) {
search += "&client=$hospital";
}
if (model != null && (model?.isNotEmpty ?? false)) {
search += "&model=$model";
}
return search;
Map<String, dynamic> queryParameters() {
return <String, dynamic>{
if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) 'sn_id': deviceSerialNumber,
if (statusValue != null) 'status': statusValue?.toString(),
if (deviceName != null && (deviceName?.isNotEmpty ?? false)) 'equipment_en_name': deviceName,
if (hospital != null && (hospital?.isNotEmpty ?? false)) 'client': hospital,
if (model != null && (model?.isNotEmpty ?? false)) 'model': model,
};
}
}

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

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

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

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

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

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

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

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

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

@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../../../api/user_api_client.dart';
import '../../../../../controllers/localization/localization.dart';
import '../../../../../controllers/providers/api/regular_visits_provider.dart';
import '../../../../../controllers/providers/settings/setting_provider.dart';
@ -23,6 +22,7 @@ class FutureEditPentry extends StatefulWidget {
class _FutureEditPentryState extends State<FutureEditPentry> {
late SettingProvider _settingProvider;
@override
Widget build(BuildContext context) {
_settingProvider = Provider.of<SettingProvider>(context);
@ -30,7 +30,7 @@ class _FutureEditPentryState extends State<FutureEditPentry> {
Subtitle subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold(
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) {
if (snapshot.hasError) {
return FailedLoading(

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

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

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

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

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

@ -1,14 +1,9 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../api/user_api_client.dart';
import '../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/service_requests_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../controllers/providers/user_provider.dart';
import '../../../models/lookup.dart';
import '../../../models/service_request/service_request.dart';
import '../../../models/subtitle.dart';
@ -33,45 +28,10 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
DateTime? _dateTime;
Lookup? _employee;
Subtitle? _subtitle;
UserProvider? _userProvider;
SettingProvider? _settingProvider;
ServiceRequestsProvider? _serviceRequestsProvider;
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
void initState() {
super.initState();
@ -80,8 +40,6 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
@override
Widget build(BuildContext context) {
_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);
return Column(
mainAxisSize: MainAxisSize.min,
@ -105,7 +63,13 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
),
ASmallButton(
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(
child: Text(
_subtitle?.date ?? '',
style: Theme.of(context).textTheme.subtitle1,
style: Theme.of(context).textTheme.titleMedium,
textScaleFactor: AppStyle.getScaleFactor(context),
),
),

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

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

Loading…
Cancel
Save