diff --git a/lib/controllers/api_routes/api_manager.dart b/lib/controllers/api_routes/api_manager.dart index ab6d5808..20c55464 100644 --- a/lib/controllers/api_routes/api_manager.dart +++ b/lib/controllers/api_routes/api_manager.dart @@ -19,6 +19,7 @@ class ApiManager { Map get _headers => { 'Content-Type': 'application/json', + 'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first, if (user != null) 'Authorization': 'Bearer ${user!.token}', if (assetGroup != null) 'AssetGroup': assetGroup!.id.toString(), }; @@ -156,7 +157,6 @@ class ApiManager { headers.addAll(_headers); Uri url0 = Uri.parse(url); - print(url0); // print(headers); // log(json.encode(body)); var request = http.Request('PUT', url0); diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index f584ecd7..ad5c3307 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -1,7 +1,7 @@ class URLs { URLs._(); - static const String appReleaseBuildNumber = "19"; + static const String appReleaseBuildNumber = "21"; // static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url @@ -219,6 +219,8 @@ class URLs { static get getServiceReportReasonsNew => "$_baseUrl/Lookups/GetLookupReasonNew?lookupEnum=505"; + static get getWoFrames => "$_baseUrl/Lookups/GetLookup?lookupEnum=1254"; + static get getServiceReportRetirementType => "$_baseUrl/Lookups/GetLookup?lookupEnum=415"; static get getVisitReminderTimeValue => "$_baseUrl/Lookups/GetLookup?lookupEnum=1211"; diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index 50371c4f..16abd263 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -204,7 +204,6 @@ class FirebaseNotificationManger { }); FirebaseMessaging.onMessage.listen((RemoteMessage message) { - print('notification i got is ${message.toMap()}'); if (Platform.isAndroid) { if (message.data["notificationType"] != 'NurseConfirmArrive') { NotificationManger.showNotification( diff --git a/lib/controllers/notification/notification_manger.dart b/lib/controllers/notification/notification_manger.dart index b101bd3f..ab1df81a 100644 --- a/lib/controllers/notification/notification_manger.dart +++ b/lib/controllers/notification/notification_manger.dart @@ -31,7 +31,6 @@ class NotificationManger { } else if (Platform.isAndroid) { final AndroidFlutterLocalNotificationsPlugin? androidImplementation = localNotificationsPlugin.resolvePlatformSpecificImplementation(); final bool granted = await androidImplementation?.requestNotificationsPermission() ?? false; - print('permission value is $granted'); if (!granted) { if (kDebugMode) { print("-------------------- Permission Granted ------------------------"); @@ -43,7 +42,8 @@ class NotificationManger { await localNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationPressed); } // push new notification - static const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails( + + static const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails( 'com.hmg.atoms', 'ATOMS', channelDescription: 'Push notification service for ATOMS', @@ -76,7 +76,6 @@ class NotificationManger { // groupKey: 'com.hmg.atoms', // ); - // const DarwinNotificationDetails iosNotificationDetails = DarwinNotificationDetails( // categoryIdentifier: "atoms", // ); @@ -86,16 +85,9 @@ class NotificationManger { await localNotificationsPlugin.show(hashcode, title, subtext, platformChannel, payload: payload); } - static Future scheduleNotification( - {int?id, - String? title, - String? body, - String? payLoad, - required DateTime scheduledNotificationDateTime}) async { - - print('time i got is ${scheduledNotificationDateTime}'); + static Future scheduleNotification({int? id, String? title, String? body, String? payLoad, required DateTime scheduledNotificationDateTime}) async { return localNotificationsPlugin.zonedSchedule( - id??0, + id ?? 0, title, body, // tz.TZDateTime.now(tz.local).add(const Duration(seconds: 5)), @@ -103,13 +95,12 @@ class NotificationManger { scheduledNotificationDateTime, tz.local, ), - const NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails, macOS: iosNotificationDetails), + const NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails, macOS: iosNotificationDetails), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, - uiLocalNotificationDateInterpretation: - UILocalNotificationDateInterpretation.absoluteTime); + uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime); } + static Future cancelNotificationById(int notificationId) async { await localNotificationsPlugin.cancel(notificationId); - print("Notification with ID $notificationId has been canceled."); } } diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index f756b9ad..a2e3ec40 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -143,7 +143,7 @@ class AllRequestsProvider extends ChangeNotifier { } final type = typeTransaction == null ? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false) - ? [1, 2, 3, 4, 5,6] //added 6 to get task request ... + ? [1, 2, 3, 4, 5, 6] //added 6 to get task request ... : search!.typeTransaction : [typeTransaction]; List status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!; @@ -222,7 +222,7 @@ class AllRequestsProvider extends ChangeNotifier { } } - Future updateRecurrentWo({required int status}) async { + Future updateRecurrentWo({required int status}) async { isLoading = true; Response response; try { @@ -230,12 +230,15 @@ class AllRequestsProvider extends ChangeNotifier { stateCode = response.statusCode; isLoading = false; notifyListeners(); - return response.statusCode; + if (stateCode == 200) { + return true; + } + return false; } catch (error) { isLoading = false; stateCode = -1; notifyListeners(); - return -1; + return false; } } diff --git a/lib/controllers/providers/api/gas_refill_provider.dart b/lib/controllers/providers/api/gas_refill_provider.dart index 8e6a3b5c..40d6327a 100644 --- a/lib/controllers/providers/api/gas_refill_provider.dart +++ b/lib/controllers/providers/api/gas_refill_provider.dart @@ -47,15 +47,12 @@ class GasRefillProvider extends ChangeNotifier { // failed _loading = false bool isLoading = false; - - Future getGasRefillObjectById(num id) async { try { Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gasRefillId=$id"); if (response.statusCode >= 200 && response.statusCode < 300) { - - return GasRefillModel.fromJson(json.decode(response.body)["data"]); + return GasRefillModel.fromJson(json.decode(response.body)["data"]); } else { return null; } @@ -64,7 +61,6 @@ class GasRefillProvider extends ChangeNotifier { } } - /// 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 @@ -139,6 +135,7 @@ class GasRefillProvider extends ChangeNotifier { print(error); } } + Future updateGasRefillRequestByNurse({ required BuildContext context, required GasRefillModel model, @@ -167,7 +164,7 @@ class GasRefillProvider extends ChangeNotifier { } } - Future updateGasRefill({required int status, required GasRefillModel model}) async { + Future updateGasRefill({required int status, required GasRefillModel model}) async { isLoading = true; Response response; try { @@ -175,12 +172,15 @@ class GasRefillProvider extends ChangeNotifier { stateCode = response.statusCode; isLoading = false; notifyListeners(); - return response.statusCode; + if (stateCode == 200) { + return true; + } + return false; } catch (error) { isLoading = false; stateCode = -1; notifyListeners(); - return -1; + return false; } } diff --git a/lib/controllers/providers/api/notifications_provider.dart b/lib/controllers/providers/api/notifications_provider.dart index 2fc424d3..53d97eaa 100644 --- a/lib/controllers/providers/api/notifications_provider.dart +++ b/lib/controllers/providers/api/notifications_provider.dart @@ -52,7 +52,6 @@ class NotificationsProvider extends ChangeNotifier { response = await ApiManager.instance.post(URLs.getSystemNotifications, body: body); stateCode = response.statusCode; - print('notifaction response is ${response.body}'); if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received List requestsListJson = json.decode(response.body)["data"]; diff --git a/lib/controllers/providers/api/ppm_provider.dart b/lib/controllers/providers/api/ppm_provider.dart index 62ec2d75..900f88bc 100644 --- a/lib/controllers/providers/api/ppm_provider.dart +++ b/lib/controllers/providers/api/ppm_provider.dart @@ -182,21 +182,23 @@ class PpmProvider extends ChangeNotifier { } } - Future updateVisitByEngineer({required int status}) async { + Future updateVisitByEngineer({required int status}) async { isLoading = true; Response response; try { response = await ApiManager.instance.post(URLs.updateVisitByEngineer, body: planPreventiveVisit!.toJson(status: status)); - print('response i got is ${response.body}'); stateCode = response.statusCode; isLoading = false; notifyListeners(); - return response.statusCode; + if (stateCode == 200) { + return true; + } + return false; } catch (error) { isLoading = false; stateCode = -1; notifyListeners(); - return -1; + return false; } } diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index 2ceeacf5..f9d24e20 100644 --- a/lib/controllers/providers/api/service_requests_provider.dart +++ b/lib/controllers/providers/api/service_requests_provider.dart @@ -7,7 +7,6 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/string_extensions.dart'; -import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/pending_service_request_model.dart'; import 'package:test_sa/models/service_request/service_report.dart'; import 'package:test_sa/models/service_request/service_request.dart'; @@ -268,7 +267,7 @@ class ServiceRequestsProvider extends ChangeNotifier { Future checkAssetPendingRequest(int assetId) async { Response response; try { - response = await ApiManager.instance.post(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId",body: {}); + response = await ApiManager.instance.post(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId", body: {}); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) {} return PendingAssetServiceRequest.fromJson(json.decode(response.body)["data"]); @@ -423,7 +422,6 @@ class ServiceRequestsProvider extends ChangeNotifier { Future getCallRequestForWorkOrder({required String callId}) async { Response response; - print('call id i got is ${callId}'); try { response = await ApiManager.instance.get(URLs.getCallRequestForWorkOrder + "?callId=$callId"); stateCode = response.statusCode; diff --git a/lib/extensions/context_extension.dart b/lib/extensions/context_extension.dart index b8ef0520..1f36d4ba 100644 --- a/lib/extensions/context_extension.dart +++ b/lib/extensions/context_extension.dart @@ -22,10 +22,7 @@ extension BuildContextExtension on BuildContext { void showConfirmDialog(String message, {String? title, VoidCallback? onTap}) => showDialog( context: this, - builder: (BuildContext cxt) => ConfirmDialog( - message: message, - onTap: onTap, - ), + builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title), ); Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title}) => showModalBottomSheet( diff --git a/lib/helper/utils.dart b/lib/helper/utils.dart index 9162129d..b56c7474 100644 --- a/lib/helper/utils.dart +++ b/lib/helper/utils.dart @@ -49,7 +49,19 @@ class Utils { return null; } } - +static String getOrdinal(int number) { + if (number >= 11 && number <= 13) return "${number}th"; + switch (number % 10) { + case 1: + return "${number}st"; + case 2: + return "${number}nd"; + case 3: + return "${number}rd"; + default: + return "${number}th"; + } +} static int stringToHex(String colorCode) { try { return int.parse(colorCode.replaceAll("#", "0xff")); diff --git a/lib/main.dart b/lib/main.dart index 4df50e48..88c7bdef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -71,6 +71,7 @@ import 'package:test_sa/providers/work_order/retirement_type_provider.dart'; import 'package:test_sa/providers/work_order/service_type_provider.dart'; import 'package:test_sa/providers/work_order/supplier_engineer_provider.dart'; import 'package:test_sa/providers/work_order/vendor_provider.dart'; +import 'package:test_sa/providers/work_order/wo_frame_provider.dart'; import 'package:test_sa/views/pages/device_transfer/create__device_transfer_request.dart'; import 'package:test_sa/views/pages/device_transfer/device_filter_screen.dart'; import 'package:test_sa/views/pages/device_transfer/device_search_screen.dart'; @@ -239,6 +240,7 @@ class MyApp extends StatelessWidget { /// Loan availability not required ChangeNotifierProvider(create: (_) => LoanAvailabilityProvider()), ChangeNotifierProvider(create: (_) => ReasonProvider()), + ChangeNotifierProvider(create: (_) => WoFrameProvider()), ChangeNotifierProvider(create: (_) => RejectReasonProvider()), ChangeNotifierProvider(create: (_) => LastSituationProvider()), ChangeNotifierProvider(create: (_) => FaultDescriptionProvider()), diff --git a/lib/models/device/asset_by_id_model.dart b/lib/models/device/asset_by_id_model.dart index f83eb4bc..691a916a 100644 --- a/lib/models/device/asset_by_id_model.dart +++ b/lib/models/device/asset_by_id_model.dart @@ -24,7 +24,7 @@ class AssetByIdModel { int? testsDay; num? purchasingPrice; String? nbv; - String? currency; + Lookup? currency; String? poDate; String? poNo; String? invoiceNumber; @@ -153,7 +153,7 @@ class AssetByIdModel { testsDay = json['testsDay']; purchasingPrice = json['purchasingPrice']; nbv = json['nbv']; - currency = json['currency']; + currency = json['currency'] != null ? Lookup.fromJson(json['currency']) : null; poDate = json['poDate']; poNo = json['poNo']; invoiceNumber = json['invoiceNumber']; @@ -247,7 +247,9 @@ class AssetByIdModel { data['testsDay'] = testsDay; data['purchasingPrice'] = purchasingPrice; data['nbv'] = nbv; - data['currency'] = currency; + if (currency != null) { + data['currency'] = currency?.toJson(); + } data['poDate'] = poDate; data['poNo'] = poNo; data['invoiceNumber'] = invoiceNumber; diff --git a/lib/models/device/device_transfer.dart b/lib/models/device/device_transfer.dart index 10393a2e..c8620eaf 100644 --- a/lib/models/device/device_transfer.dart +++ b/lib/models/device/device_transfer.dart @@ -1,6 +1,7 @@ import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/assistant_employee.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; import 'package:test_sa/models/ppm/ppm.dart'; import 'package:test_sa/models/timer_model.dart'; @@ -89,8 +90,10 @@ class DeviceTransfer { this.timerModelList, this.assistantEmployees, this.modelAssistantEmployees, + this.assistantEmployList, this.assetTransferAssistantEmployeesReceiver, this.assetTransferAssistantEmployeesSender, + this.statusValue, }); @@ -305,10 +308,11 @@ class DeviceTransfer { List? assetTransferEngineerTimers; List? timerModelList = []; List? assistantEmployees; - List? assetTransferAssistantEmployeesSender; - List? assetTransferAssistantEmployeesReceiver; + List? assetTransferAssistantEmployeesSender=[]; + List? assetTransferAssistantEmployeesReceiver=[]; List? assetTransferContactPersons; AssetTransferAssistantEmployees? modelAssistantEmployees; + List? assistantEmployList=[]; TimerModel? tbsTimer = TimerModel(); TimerModel? deviceTimePicker; @@ -384,6 +388,7 @@ class DeviceTransfer { String? destDepartmentName, List? senderVisitTimers, List? receiverVisitTimers, + List? assistantEmployList, TimerModel? tbsTimer, TimerModel? deviceTimePicker}) => DeviceTransfer( @@ -457,6 +462,7 @@ class DeviceTransfer { senderVisitTimers: senderVisitTimers ?? this.senderVisitTimers, receiverVisitTimers: receiverVisitTimers ?? this.receiverVisitTimers, tbsTimer: tbsTimer ?? this.tbsTimer, + assistantEmployList: assistantEmployList??this.assistantEmployList, deviceTimePicker: deviceTimePicker ?? this.deviceTimePicker, manufacturerName: manufacturerName ?? this.manufacturerName); @@ -573,13 +579,18 @@ class DeviceTransfer { if (assetTransferEngineerTimers != null) { map['assetTransferEngineerTimers'] = assetTransferEngineerTimers!.map((v) => v.toJson()).toList(); } - if (modelAssistantEmployees != null) { - if (modelAssistantEmployees!.employeeId != null) { - map['assetTransferAssistantEmployees'] = [modelAssistantEmployees!.toJson()]; - } else { - map['assetTransferAssistantEmployees'] = []; - } + if (assistantEmployList != null && assistantEmployList!.isNotEmpty) { + map['assetTransferAssistantEmployees'] = assistantEmployList; + } else { + map['assetTransferAssistantEmployees'] = []; } + // if (modelAssistantEmployees != null) { + // if (modelAssistantEmployees!.employeeId != null) { + // map['assetTransferAssistantEmployees'] = [modelAssistantEmployees!.toJson()]; + // } else { + // map['assetTransferAssistantEmployees'] = []; + // } + // } return map; } diff --git a/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart b/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart index 0089a302..dda5432b 100644 --- a/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart +++ b/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart @@ -35,6 +35,7 @@ class ActivityMaintenanceHelperModel { List? activityMaintenanceTimers = []; TimerModel? activityMaintenanceTimerModel = TimerModel(); TimerModel? activityTimePicker; + List? assistantEmployList=[]; List? timerModelList = []; ActivityMaintenanceHelperModel( @@ -63,6 +64,7 @@ class ActivityMaintenanceHelperModel { this.assignedEmployee, this.activityMaintenanceTimers, this.timerModelList, + this.assistantEmployList, this.modelAssistantEmployees}); Map toJson() { @@ -85,11 +87,17 @@ class ActivityMaintenanceHelperModel { data['supplierWorkingHour'] = supplierWorkingHour; //TODO fix this properly... data['activityMaintenanceTimers'] = activityMaintenanceTimers; - if (assistantEmployees != null && assistantEmployees!.isNotEmpty) { - data['assistantEmployees'] = [modelAssistantEmployees?.toJson()]; + if (assistantEmployList != null && assistantEmployList!.isNotEmpty) { + data['assistantEmployees'] = assistantEmployList; } else { data['assistantEmployees'] = []; } + //TODO need to remove this .. its not required now + // if (assistantEmployees != null && assistantEmployees!.isNotEmpty) { + // data['assistantEmployees'] = [modelAssistantEmployees?.toJson()]; + // } else { + // data['assistantEmployees'] = []; + // } return data; } } diff --git a/lib/models/helper_data_models/workorder/work_order_helper_models.dart b/lib/models/helper_data_models/workorder/work_order_helper_models.dart index 24e2fc20..cd302791 100644 --- a/lib/models/helper_data_models/workorder/work_order_helper_models.dart +++ b/lib/models/helper_data_models/workorder/work_order_helper_models.dart @@ -82,16 +82,19 @@ class EngineerUpdateWorkOrderHelperModel { num? loanAssetId; WorkOrderAsset? loanAsset; Lookup? failureReason; + Lookup? cmFrameId; FaultDescription? faultDescription; String? solution; String? callResponse; String? descriptionOfFinding; String? actionTaken; + String? edd; EngineerUpdateWorkOrderHelperModel({ this.workOrderId, this.equipmentStatus, this.failureReason, + this.cmFrameId, this.faultDescription, this.loanAvailability, this.loanAssetId, @@ -99,6 +102,7 @@ class EngineerUpdateWorkOrderHelperModel { this.serviceType, this.solution, this.returnToService, + this.edd, this.callResponse, this.descriptionOfFinding, this.actionTaken, @@ -109,9 +113,11 @@ class EngineerUpdateWorkOrderHelperModel { data['workOrderId'] = workOrderId; data['equipmentStatusId'] = equipmentStatus?.id; data['returnToService'] = returnToService; + data['edd'] = edd; data['loanAvailabilityId'] = loanAvailability?.id; data['loanAssetId'] = loanAssetId; data['failureReasonId'] = failureReason?.id; + data['cmFrameId'] = cmFrameId?.id; data['faultDescriptionId'] = faultDescription?.id; data['callResponse'] = callResponse; data['descriptionOfFinding'] = descriptionOfFinding; diff --git a/lib/models/new_models/gas_refill_model.dart b/lib/models/new_models/gas_refill_model.dart index cb308215..e9e873f3 100644 --- a/lib/models/new_models/gas_refill_model.dart +++ b/lib/models/new_models/gas_refill_model.dart @@ -152,7 +152,6 @@ class GasRefillModel { floor = json['floor'] != null ? Floor.fromJson(json['floor']) : null; department = json['department'] != null ? Department.fromJson(json['department']) : null; mapSite = json['site'] != null ? MappedSite.fromJson(json['site']) : null; - print('site i got is ::${mapSite?.toJson()}'); mappedBuilding = mapSite?.buildings?.firstWhere((element) => element.identifier == building?.identifier, orElse: () => MappedBuilding()); mappedFloor = mappedBuilding?.floors?.firstWhere((element) => element.identifier == floor?.identifier, orElse: () => MappedFloor()); mappedDepartment = mappedFloor?.departments?.firstWhere((element) => element.identifier == department?.identifier, orElse: () => MappedDepartment()); diff --git a/lib/models/new_models/work_order_detail_model.dart b/lib/models/new_models/work_order_detail_model.dart index 166ed9b6..18041173 100644 --- a/lib/models/new_models/work_order_detail_model.dart +++ b/lib/models/new_models/work_order_detail_model.dart @@ -3,6 +3,7 @@ import 'package:test_sa/models/fault_description.dart'; import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/new_models/assistant_employee.dart'; class WorkOrderDetail { WorkOrderDetail({ @@ -94,6 +95,7 @@ class WorkOrderData { this.closedDate, this.since, this.cmFrame, + this.edd, this.rejectComment, this.callResponse, this.descriptionOfFinding, @@ -148,6 +150,7 @@ class WorkOrderData { Lookup? failureReasone; FaultDescription? faultDescription; Lookup? solution; + String? edd; Lookup? cmFrame; //cmComments @@ -222,6 +225,7 @@ class WorkOrderData { problemDescription: json["problemDescription"] == null ? null : Lookup.fromJson(json["problemDescription"]), comments: json["comments"], voiceNote: json["voiceNote"], + edd: json["edd"], workOrderAttachments: json["workOrderAttachments"] == null ? [] : List.from(json['workOrderAttachments']).map((e) => WorkOrderAttachments.fromJson(e)).toList(), returnToService: json["returnToService"], serviceType: json["serviceType"] == null ? null : Lookup.fromJson(json["serviceType"]), @@ -268,10 +272,12 @@ class WorkOrderData { "typeofRequest": typeofRequest?.toJson(), "loanAvailablity": loanAvailablity?.toJson(), "assetLoan": assetLoan?.toJson(), + "cmFrame": cmFrame?.toJson(), "safety": safety?.toJson(), "problemDescription": problemDescription?.toJson(), "comments": comments, "voiceNote": voiceNote, + "edd": edd, "workOrderAttachments": workOrderAttachments.map((e) => e.toJson()).toList(), "returnToService": returnToService, "serviceType": serviceType?.toJson(), @@ -686,7 +692,7 @@ class ActivityMaintenance { String? supplierEndTime; double? supplierWorkingHours; String? activityType; - List? assistantEmployees; + List? assistantEmployees; List? activityMaintenanceTimers; ActivityMaintenance( @@ -729,9 +735,9 @@ class ActivityMaintenance { supplierEndTime = json['supplierEndTime']; supplierWorkingHours = json['supplierWorkingHours']; if (json['assistantEmployees'] != null) { - assistantEmployees = []; + assistantEmployees = []; json['assistantEmployees'].forEach((v) { - assistantEmployees!.add(ActivityMaintenanceAssistantEmployees.fromJson(v)); + assistantEmployees!.add(AssistantEmployeesModel.fromJson(v)); }); } if (json['activityMaintenanceTimers'] != null) { @@ -822,15 +828,29 @@ class ActivityMaintenanceAssistantEmployees { double? workingHours; String? technicalComment; AssignedEmployee? user; + AssistantEmployees ?employee; - ActivityMaintenanceAssistantEmployees({this.startDate, this.endDate, this.workingHours, this.technicalComment, this.user}); + ActivityMaintenanceAssistantEmployees({this.startDate, this.endDate, this.workingHours, this.technicalComment, this.user,this.employee}); ActivityMaintenanceAssistantEmployees.fromJson(Map json) { + Map assistEmpData={}; + + startDate = json['startDate'] != null ? DateTime.parse(json['startDate']) : null; endDate = json['endDate'] != null ? DateTime.parse(json['endDate']) : null; workingHours = json['workingHours']; technicalComment = json['technicalComment']; user = json['user'] != null ? AssignedEmployee.fromJson(json['user']) : null; + if(json['user']!=null) { + assistEmpData = { + 'id': null, + 'user': { + 'id': user?.userId, + 'name': user?.userName, + }, + }; + } + employee = AssistantEmployees.fromJson(assistEmpData); } Map toJson() { @@ -846,6 +866,38 @@ class ActivityMaintenanceAssistantEmployees { } } + +// class ActivityMaintenanceAssistantEmployees { +// DateTime? startDate; +// DateTime? endDate; +// double? workingHours; +// String? technicalComment; +// AssignedEmployee? user; +// +// +// ActivityMaintenanceAssistantEmployees({this.startDate, this.endDate, this.workingHours, this.technicalComment, this.user}); +// +// ActivityMaintenanceAssistantEmployees.fromJson(Map json) { +// startDate = json['startDate'] != null ? DateTime.parse(json['startDate']) : null; +// endDate = json['endDate'] != null ? DateTime.parse(json['endDate']) : null; +// workingHours = json['workingHours']; +// technicalComment = json['technicalComment']; +// user = json['user'] != null ? AssignedEmployee.fromJson(json['user']) : null; +// } +// +// Map toJson() { +// final Map data = {}; +// data['startDate'] = startDate?.toIso8601String(); +// data['endDate'] = endDate?.toIso8601String(); +// data['workingHours'] = workingHours; +// data['technicalComment'] = technicalComment; +// if (user != null) { +// data['userId'] = user?.userId; +// } +// return data; +// } +// } + class ActivityMaintenanceTimers { int? id; String? startTime; @@ -870,3 +922,48 @@ class ActivityMaintenanceTimers { return data; } } + + +class AssistantEmployeesModel { + DateTime? startDate; + DateTime? endDate; + double? workingHours; + String? technicalComment; + AssignedEmployee? user; + AssistantEmployees ?employee; + + AssistantEmployeesModel({this.startDate, this.endDate, this.workingHours, this.technicalComment, this.user,this.employee}); + + AssistantEmployeesModel.fromJson(Map json) { + Map assistEmpData={}; + + + startDate = json['startDate'] != null ? DateTime.parse(json['startDate']) : null; + endDate = json['endDate'] != null ? DateTime.parse(json['endDate']) : null; + workingHours = json['workingHours']; + technicalComment = json['technicalComment']; + user = json['user'] != null ? AssignedEmployee.fromJson(json['user']) : null; + if(json['user']!=null) { + assistEmpData = { + 'id': null, + 'user': { + 'id': user?.userId, + 'name': user?.userName, + }, + }; + } + employee = AssistantEmployees.fromJson(assistEmpData); + } + + Map toJson() { + final Map data = {}; + data['startDate'] = startDate?.toIso8601String(); + data['endDate'] = endDate?.toIso8601String(); + data['workingHours'] = workingHours; + data['technicalComment'] = technicalComment; + if (user != null) { + data['userId'] = user?.userId; + } + return data; + } +} diff --git a/lib/models/service_request/service_request.dart b/lib/models/service_request/service_request.dart index e2de1b54..f29eb77a 100644 --- a/lib/models/service_request/service_request.dart +++ b/lib/models/service_request/service_request.dart @@ -102,7 +102,6 @@ class ServiceRequest { List list = parsedJson["attachmentsCallRequest"]; images = list.map((e) => URLs.getFileUrl(e["name"]!) as String).toList(); } - // print(parsedJson["requestedDate"]??""); return ServiceRequest( id: parsedJson["id"].toString(), @@ -180,7 +179,6 @@ class ServiceRequest { } return true; } - } class CallCreatedBy { diff --git a/lib/modules/cm_module/service_request_detail_provider.dart b/lib/modules/cm_module/service_request_detail_provider.dart index da6f59c2..743dad6a 100644 --- a/lib/modules/cm_module/service_request_detail_provider.dart +++ b/lib/modules/cm_module/service_request_detail_provider.dart @@ -611,40 +611,47 @@ class ServiceRequestDetailProvider extends ChangeNotifier { } //engineerUpdateWorkOrder...... - Future engineerUpdateWorkOrder() async { + Future engineerUpdateWorkOrder() async { + isLoading = true; + Response response; try { - isLoading = true; - notifyListeners(); - final response = await ApiManager.instance.post(URLs.engineerUpdateWorkOrderUrl, body: engineerUpdateWorkOrderHelperModel!.toJson()); + response = await ApiManager.instance.post(URLs.engineerUpdateWorkOrderUrl, body: engineerUpdateWorkOrderHelperModel!.toJson()); stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body)); - } isLoading = false; notifyListeners(); - } catch (e) { - log("engineer update workorder [error] : $e"); + if (stateCode == 200) { + currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body)); + notifyListeners(); + return true; + } + return false; + } catch (error) { isLoading = false; + stateCode = -1; notifyListeners(); + return false; } } - //engineerUpdateWorkOrder...... - Future engineerUpdateCost() async { + Future engineerUpdateCost() async { + isLoading = true; + Response response; try { - isLoading = true; - notifyListeners(); - final response = await ApiManager.instance.post(URLs.engineerUpdateCost, body: workOrderCostModel!.toJson()); + response = await ApiManager.instance.post(URLs.engineerUpdateCost, body: workOrderCostModel!.toJson()); stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body)); - } isLoading = false; notifyListeners(); - } catch (e) { - log("engineer update workorder [error] : $e"); + if (stateCode == 200) { + currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body)); + notifyListeners(); + return true; + } + return false; + } catch (error) { isLoading = false; + stateCode = -1; notifyListeners(); + return false; } } @@ -737,36 +744,43 @@ class ServiceRequestDetailProvider extends ChangeNotifier { } } - Future updateActivitySparePart() async { + Future updateActivitySparePart() async { + isLoading = true; + Response response; try { - final response = await ApiManager.instance.post(URLs.updateActivitySparePartUrl, body: sparePartHelperModel!.toJson()); + response = await ApiManager.instance.post(URLs.updateActivitySparePartUrl, body: sparePartHelperModel!.toJson()); stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // request.engineerName = employee.name; + isLoading = false; + notifyListeners(); + if (stateCode == 200) { + return true; } - return response.statusCode; + return false; } catch (error) { - return -1; + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; } } - Future updateActivityMaintenance() async { + Future updateActivityMaintenance() async { isLoading = true; - notifyListeners(); + Response response; try { - final response = await ApiManager.instance.put(URLs.updateActivityMaintenanceUrl, body: activityMaintenanceHelperModel!.toJson()); + response = await ApiManager.instance.put(URLs.updateActivityMaintenanceUrl, body: activityMaintenanceHelperModel!.toJson()); stateCode = response.statusCode; - - if (response.statusCode >= 200 && response.statusCode < 300) { - // request.engineerName = employee.name; - } isLoading = false; notifyListeners(); - return response.statusCode; + if (stateCode == 200) { + return true; + } + return false; } catch (error) { isLoading = false; + stateCode = -1; notifyListeners(); - return -1; + return false; } } @@ -798,7 +812,6 @@ class ServiceRequestDetailProvider extends ChangeNotifier { body: {}, ); - print('response i got is ${response.body}'); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { @@ -861,41 +874,49 @@ class ServiceRequestDetailProvider extends ChangeNotifier { } } - Future createActivitySparePart() async { + Future createActivitySparePart() async { + isLoading = true; + Response response; try { - final response = await ApiManager.instance.post(URLs.createActivitySparePartUrl, body: sparePartHelperModel!.toJson()); + response = await ApiManager.instance.post( + URLs.createActivitySparePartUrl, + body: sparePartHelperModel!.toJson(), + ); stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body)); - // // updateCurrentWorkOrder(currentWorkOrder); - // notifyListeners(); + isLoading = false; + notifyListeners(); + if (stateCode == 200) { + return true; } - return response.statusCode; + return false; } catch (error) { - return -1; + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; } } - Future createActivityMaintenanceRequest() async { + Future createActivityMaintenanceRequest() async { isLoading = true; - notifyListeners(); + Response response; try { - final response = await ApiManager.instance.post( + response = await ApiManager.instance.post( URLs.createActivityMaintenanceUrl, body: activityMaintenanceHelperModel!.toJson(), ); stateCode = response.statusCode; - if (response.statusCode >= 200 && response.statusCode < 300) { - // currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body)); - // updateCurrentWorkOrder(currentWorkOrder); - } isLoading = false; notifyListeners(); - return response.statusCode; + if (stateCode == 200) { + return true; + } + return false; } catch (error) { isLoading = false; + stateCode = -1; notifyListeners(); - return -1; + return false; } } diff --git a/lib/modules/cm_module/views/components/action_button/footer_action_button.dart b/lib/modules/cm_module/views/components/action_button/footer_action_button.dart index fe9ccc46..22083d37 100644 --- a/lib/modules/cm_module/views/components/action_button/footer_action_button.dart +++ b/lib/modules/cm_module/views/components/action_button/footer_action_button.dart @@ -40,7 +40,10 @@ class FooterActionButton { required UserProvider userProvider, bool isEmpIsAssigned = false}) { ServiceRequestDetailProvider requestDetailProvider = Provider.of(context, listen: false); - bool showMarkAsFixedButton = activities.isEmpty ? false : activities.any((object) => object.activityStatus!.value == 14 || object.activityStatus!.value == 19); + bool showMarkAsFixedButton = activities.isEmpty + ? false + : activities.any((object) => + object.activityStatus!.value == 14 || object.activityStatus!.value == 19 || object.activityStatus!.value == 11); // value 14,19,20 for fixed,out of scope and duplicate activity status if (userProvider.user?.type == UsersTypes.engineer) { if (workOrderNextStepStatus == WorkOrderNextStepEnum.assignToMe && isEmpIsAssigned) return const SizedBox(); switch (workOrderNextStepStatus) { @@ -130,7 +133,7 @@ class FooterActionButton { maxWidth: true, buttonColor: AppColor.green70, onPressed: () async { - requestDetailProvider.engineerAcceptWorkOrder(id: requestDetailProvider.currentWorkOrder!.data!.requestId.toString()).whenComplete(() {}); + requestDetailProvider.engineerAcceptWorkOrder(id: requestDetailProvider.currentWorkOrder!.data!.requestId.toString()); }, ).expanded, ], diff --git a/lib/modules/cm_module/views/components/activities_list_view.dart b/lib/modules/cm_module/views/components/activities_list_view.dart index 300beeea..c40f5c81 100644 --- a/lib/modules/cm_module/views/components/activities_list_view.dart +++ b/lib/modules/cm_module/views/components/activities_list_view.dart @@ -311,19 +311,19 @@ class _ActivitiesListViewState extends State { } void editMaintenanceRequest({required BuildContext context, required ServiceRequestDetailProvider requestDetailProvider, required Activities activity}) async { - Map assistEmpData = {}; + // Map assistEmpData = {}; try { - if (activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty) { - assistEmpData = { - // 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId != null ? num.tryParse(activity.activityMaintenance!.assistantEmployees![0].user!.userId!) : null, - 'id': null, - 'user': { - 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId, - // 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId != null ? num.tryParse(activity.activityMaintenance!.assistantEmployees![0].user!.userId!) : null, - 'name': activity.activityMaintenance?.assistantEmployees?[0].user?.userName, - }, - }; - } + // if (activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty) { + // assistEmpData = { + // // 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId != null ? num.tryParse(activity.activityMaintenance!.assistantEmployees![0].user!.userId!) : null, + // 'id': null, + // 'user': { + // 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId, + // // 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId != null ? num.tryParse(activity.activityMaintenance!.assistantEmployees![0].user!.userId!) : null, + // 'name': activity.activityMaintenance?.assistantEmployees?[0].user?.userName, + // }, + // }; + // } requestDetailProvider.activityMaintenanceHelperModel = ActivityMaintenanceHelperModel( id: activity.id, @@ -337,10 +337,11 @@ class _ActivitiesListViewState extends State { // lastSituation: activity.activityMaintenance?.lastSituation, assignedEmployee: activity.activityMaintenance?.assignedEmployee != null ? WorkOrderAssignedEmployee.fromJson(activity.activityMaintenance!.assignedEmployee!.toJson()) : null, technicalComment: activity.activityMaintenance?.technicalComment, - assistantEmployees: - activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty ? [AssistantEmployees.fromJson(assistEmpData)] : [], - modelAssistantEmployees: - activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty ? activity.activityMaintenance!.assistantEmployees![0] : null, + assistantEmployList:activity.activityMaintenance!.assistantEmployees??[] , + // assistantEmployees: + // activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty ? [AssistantEmployees.fromJson(assistEmpData)] : [], + // modelAssistantEmployees: + // activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty ? activity.activityMaintenance!.assistantEmployees![0] : null, supplierStartTime: activity.activityMaintenance?.supplierStartTime != null ? DateTime.parse(activity.activityMaintenance!.supplierStartTime!) : null, supplierEndTime: activity.activityMaintenance?.supplierEndTime != null ? DateTime.parse(activity.activityMaintenance!.supplierEndTime!) : null, supplierWorkingHour: activity.activityMaintenance?.supplierWorkingHours, diff --git a/lib/modules/cm_module/views/components/asset_detail_card.dart b/lib/modules/cm_module/views/components/asset_detail_card.dart index 4f377e61..c8ac1c3b 100644 --- a/lib/modules/cm_module/views/components/asset_detail_card.dart +++ b/lib/modules/cm_module/views/components/asset_detail_card.dart @@ -37,7 +37,17 @@ class AssetDetailCard extends StatelessWidget { textColor: AppColor.white10, backgroundColor: AppColor.getEquipmentStatusColor(context, requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.id ?? 0), ), - 5.width, + if(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.cmFrameId!=null)...[ + 6.width, + StatusLabel( + label: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.cmFrameId?.name, + id: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.cmFrameId?.id ?? 0, + radius: 4, + textColor: AppColor.getActivityTypeTextColor(requestDetailProvider.engineerUpdateWorkOrderHelperModel!.cmFrameId?.name ?? ''), + backgroundColor: AppColor.getActivityTypeBgColor(requestDetailProvider.engineerUpdateWorkOrderHelperModel!.cmFrameId?.name ?? ''), + ), + ], + 6.width, StatusLabel( label: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.serviceType?.name, id: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.serviceType?.id ?? 0, @@ -64,6 +74,10 @@ class AssetDetailCard extends StatelessWidget { '${context.translation.returnToService}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService?.toAssetDetailsFormat ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), + Text( + 'EDD: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.edd?.toAssetDetailsFormat ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), Text( '${context.translation.loanAvailability}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability?.name ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), diff --git a/lib/modules/cm_module/views/components/service_request_detail_view.dart b/lib/modules/cm_module/views/components/service_request_detail_view.dart index cc7eef0e..30926f2c 100644 --- a/lib/modules/cm_module/views/components/service_request_detail_view.dart +++ b/lib/modules/cm_module/views/components/service_request_detail_view.dart @@ -355,8 +355,10 @@ class _ServiceRequestDetailViewState extends State { ], ] else ...[ 8.height, - const Divider().defaultStyle(context), - FilesList(images: _attachments.map((toElement) => URLs.getFileUrl(toElement.name!)!).toList()), + if (_attachments.isNotEmpty) ...[ + const Divider().defaultStyle(context), + FilesList(images: _attachments.map((toElement) => URLs.getFileUrl(toElement.name!)!).toList()), + ], //handle nurse case.. ], @@ -580,6 +582,8 @@ class _ServiceRequestDetailViewState extends State { serviceType: currentWorkOrderData.serviceType, descriptionOfFinding: currentWorkOrderData.descriptionOfFinding, actionTaken: currentWorkOrderData.actionTaken, + edd: currentWorkOrderData.edd, + cmFrameId: currentWorkOrderData.cmFrame, ); return const AssetDetailCard(); } else { diff --git a/lib/modules/cm_module/views/forms/asset_retired/verify_asset_detail.dart b/lib/modules/cm_module/views/forms/asset_retired/verify_asset_detail.dart index e773977f..5c69f936 100644 --- a/lib/modules/cm_module/views/forms/asset_retired/verify_asset_detail.dart +++ b/lib/modules/cm_module/views/forms/asset_retired/verify_asset_detail.dart @@ -24,6 +24,7 @@ import 'package:test_sa/providers/service_request_providers/equipment_status_pro import 'package:test_sa/providers/service_request_providers/loan_availability_provider.dart'; import 'package:test_sa/providers/work_order/fault_description_provider.dart'; import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/providers/work_order/wo_frame_provider.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/equipment/pick_asset.dart'; @@ -77,6 +78,8 @@ class _VerifyAssetDetailsState extends State with TickerProv callResponse: currentWorkOrderData.callResponse, descriptionOfFinding: currentWorkOrderData.descriptionOfFinding, actionTaken: currentWorkOrderData.actionTaken, + edd: currentWorkOrderData.edd, + cmFrameId: currentWorkOrderData.cmFrame, ); if (currentWorkOrderData.assetLoan != null) { loanAvailabilityAsset = Asset( @@ -101,6 +104,7 @@ class _VerifyAssetDetailsState extends State with TickerProv _loanAvailabilityProvider!.reset(); _equipmentStatusProvider = Provider.of(context, listen: false); _equipmentStatusProvider!.reset(); + Provider.of(context, listen: false).reset(); WidgetsBinding.instance.addPostFrameCallback((_) { _equipmentStatusProvider!.getData(); }); @@ -129,7 +133,7 @@ class _VerifyAssetDetailsState extends State with TickerProv hideShadow: true, backgroundColor: AppColor.neutral100, // initialDate: DateTime.tryParse(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService ?? ""), - from:requestDetailProvider.currentWorkOrder?.data?.requestedDate, + from: requestDetailProvider.currentWorkOrder?.data?.requestedDate, date: DateTime.tryParse(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService ?? ""), formatDateWithTime: true, onDatePicker: (selectedDate) { @@ -158,37 +162,21 @@ class _VerifyAssetDetailsState extends State with TickerProv }); }, ), + 12.height, - SingleItemDropDownMenu( + SingleItemDropDownMenu( context: context, - title: context.translation.loanAvailability, + title: "WO Frame", backgroundColor: AppColor.neutral100, height: 56.toScreenHeight, showShadow: false, - initialValue: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability, - onSelect: (status) { - if (status != null) { - requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability = status; - if (status.value != 1) { - loanAvailabilityAsset = null; - requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAssetId = null; - } - setState(() {}); + initialValue: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.cmFrameId, + onSelect: (value) { + if (value != null) { + requestDetailProvider.engineerUpdateWorkOrderHelperModel?.cmFrameId = value; } }, ), - if (requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability?.value == 1) 8.height, - if (requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability?.value == 1) - PickAsset( - device: loanAvailabilityAsset, // ?? _serviceReport.device, - cardColor: AppColor.neutral100, - onPickAsset: (asset) { - requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAssetId = asset.id; - setState(() { - loanAvailabilityAsset = asset; - }); - }, - ), 12.height, SingleItemDropDownMenu( context: context, @@ -227,7 +215,73 @@ class _VerifyAssetDetailsState extends State with TickerProv ? requestDetailProvider.engineerUpdateWorkOrderHelperModel!.solution!.bodyText2(context).custom(color: AppColor.neutral120, align: TextAlign.justify) : const SizedBox(), ], - 8.height, + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.loanAvailability, + backgroundColor: AppColor.neutral100, + height: 56.toScreenHeight, + showShadow: false, + initialValue: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability, + onSelect: (status) { + if (status != null) { + requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability = status; + if (status.value != 1) { + loanAvailabilityAsset = null; + requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAssetId = null; + } + setState(() {}); + } + }, + ), + if (requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability?.value == 1) 8.height, + if (requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability?.value == 1) + PickAsset( + device: loanAvailabilityAsset, // ?? _serviceReport.device, + cardColor: AppColor.neutral100, + onPickAsset: (asset) { + requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAssetId = asset.id; + setState(() { + loanAvailabilityAsset = asset; + }); + }, + ), + 12.height, + ADatePicker( + label: "EDD", + hideShadow: true, + backgroundColor: AppColor.neutral100, + // initialDate: DateTime.tryParse(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.edd ?? ""), + from: requestDetailProvider.currentWorkOrder?.data?.requestedDate, + date: DateTime.tryParse(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.edd ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime? selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + // if (requestDetailProvider.engineerUpdateWorkOrderHelperModel?.edd != null && + // selectedDateTime.isBefore(DateTime.parse(requestDetailProvider.engineerUpdateWorkOrderHelperModel!.edd!))) { + // "Return To Service Date time must be greater then previous date".showToast; + // return; + // } + setState(() { + requestDetailProvider.engineerUpdateWorkOrderHelperModel?.edd = selectedDateTime.toIso8601String(); + }); + } + }); + }, + ), + 12.height, AppTextFormField( labelText: context.translation.callResponse, backgroundColor: AppColor.neutral100, @@ -241,7 +295,7 @@ class _VerifyAssetDetailsState extends State with TickerProv style: Theme.of(context).textTheme.titleMedium, ), if (Provider.of(context, listen: false).isUserFMS) ...[ - 8.height, + 12.height, AppTextFormField( labelText: "Description of Finding", backgroundColor: AppColor.neutral100, @@ -254,7 +308,7 @@ class _VerifyAssetDetailsState extends State with TickerProv }, style: Theme.of(context).textTheme.titleMedium, ), - 8.height, + 12.height, AppTextFormField( labelText: "Action Taken", backgroundColor: AppColor.neutral100, @@ -283,9 +337,13 @@ class _VerifyAssetDetailsState extends State with TickerProv onPressed: () async { if (validateForm(requestDetailProvider: requestDetailProvider)) { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - await requestDetailProvider.engineerUpdateWorkOrder(); - Navigator.pop(context); - Navigator.pop(context); + await requestDetailProvider.engineerUpdateWorkOrder().then((success){ + Navigator.pop(context); + if(success){ + Navigator.pop(context); + } + }); + } }, ), diff --git a/lib/modules/cm_module/views/forms/cost/cost_detail_form_screen.dart b/lib/modules/cm_module/views/forms/cost/cost_detail_form_screen.dart index 7e7096b9..c8f99451 100644 --- a/lib/modules/cm_module/views/forms/cost/cost_detail_form_screen.dart +++ b/lib/modules/cm_module/views/forms/cost/cost_detail_form_screen.dart @@ -89,7 +89,7 @@ class _CostDetailFormScreenState extends State with Ticker initialValue: requestDetailProvider.workOrderCostModel?.labourCost?.toString(), textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, - textInputType:const TextInputType.numberWithOptions(decimal: true), + textInputType: const TextInputType.numberWithOptions(decimal: true), showShadow: false, onChange: (value) { requestDetailProvider.workOrderCostModel?.labourCost = num.parse(value); @@ -131,7 +131,7 @@ class _CostDetailFormScreenState extends State with Ticker initialValue: requestDetailProvider.workOrderCostModel?.prNo, textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, - textInputType:const TextInputType.numberWithOptions(decimal: true), + textInputType: const TextInputType.numberWithOptions(decimal: true), showShadow: false, onChange: (value) { requestDetailProvider.workOrderCostModel?.prNo = value; @@ -145,7 +145,7 @@ class _CostDetailFormScreenState extends State with Ticker initialValue: requestDetailProvider.workOrderCostModel?.poNo, textAlign: TextAlign.center, labelStyle: AppTextStyles.textFieldLabelStyle, - textInputType:const TextInputType.numberWithOptions(decimal: true), + textInputType: const TextInputType.numberWithOptions(decimal: true), showShadow: false, onChange: (value) { requestDetailProvider.workOrderCostModel?.poNo = value; @@ -164,9 +164,12 @@ class _CostDetailFormScreenState extends State with Ticker onPressed: () async { if (validateForm(requestDetailProvider: requestDetailProvider)) { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - await requestDetailProvider.engineerUpdateCost(); - Navigator.pop(context); - Navigator.pop(context); + await requestDetailProvider.engineerUpdateCost().then((success) { + Navigator.pop(context); + if (success) { + Navigator.pop(context); + } + }); } }, ), diff --git a/lib/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_card.dart b/lib/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_card.dart index 09a02718..5558287c 100644 --- a/lib/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_card.dart +++ b/lib/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_card.dart @@ -69,7 +69,7 @@ class _AssistantEmployeeCardState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.black20), - Icon(isExpanded ? Icons.arrow_drop_up_outlined : Icons.arrow_drop_down), + Icon(isExpanded ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded), ], ), ).onPress(() { diff --git a/lib/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart b/lib/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart new file mode 100644 index 00000000..3c09f7bd --- /dev/null +++ b/lib/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart @@ -0,0 +1,291 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart'; + +class AssistantEmployeeList extends StatefulWidget { + final List? assistantEmployeeList; + final ValueChanged>? onListChanged; + final double? cardPadding; + final dynamic assetId; + + const AssistantEmployeeList({ + super.key, + this.assistantEmployeeList, + this.onListChanged, + required this.assetId, + this.cardPadding, + }); + + @override + State createState() => _AssistantEmployeeListState(); +} + +class _AssistantEmployeeListState extends State { + late List _list; + late List _controllers; + + @override + void initState() { + super.initState(); + _list = List.from(widget.assistantEmployeeList ?? []); + _controllers = _list.map((e) => TextEditingController(text: e.workingHours?.toString() ?? '')).toList(); + } + + void _addNewEntry() { + setState(() { + _list.add(AssistantEmployeesModel()); + _controllers.add(TextEditingController()); + }); + widget.onListChanged?.call(_list); + } + + void _removeEntry(int index) { + setState(() { + _list.removeAt(index); + _controllers.removeAt(index); + }); + widget.onListChanged?.call(_list); + } + + void _updateModel(int index, void Function(AssistantEmployeesModel model) updateList) { + setState(() { + updateList(_list[index]); + }); + } + + @override + Widget build(BuildContext context) { + final isReadOnly = Provider.of(context, listen: false).isReadOnlyRequest; + return ListView.builder( + itemCount: _list.length + 1, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(widget.cardPadding ?? 16), + itemBuilder: (context, index) { + if (index == _list.length) { + return Visibility( + visible: !isReadOnly, + child: AppFilledButton( + label: "Add Assistant Employee".addTranslation, + maxWidth: true, + textColor: AppColor.black10, + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: _addNewEntry, + ), + ); + } + return EmployeeCard( + model: _list[index], + assetId: widget.assetId, + index: index, + isReadOnly: isReadOnly, + onUpdate: (updateList) => _updateModel(index, updateList), + onRemove: () => _removeEntry(index), + workingHoursController: _controllers[index], + ); + }, + ); + } +} + +class EmployeeCard extends StatelessWidget { + final AssistantEmployeesModel model; + final int index; + final bool isReadOnly; + final dynamic assetId; + + final void Function(void Function(AssistantEmployeesModel model)) onUpdate; + final VoidCallback onRemove; + final TextEditingController workingHoursController; + + const EmployeeCard({ + super.key, + required this.model, + required this.assetId, + required this.index, + required this.isReadOnly, + required this.onUpdate, + required this.onRemove, + required this.workingHoursController, + }); + + @override + Widget build(BuildContext context) { + final requestedDate = Provider.of(context, listen: false).currentWorkOrder?.data?.requestedDate; + + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.black20), + if (!isReadOnly) + Container( + height: 32, + width: 32, + padding: const EdgeInsets.all(6), + child: "trash".toSvgAsset(height: 20, width: 20), + ).onPress(onRemove), + ], + ), + 8.height, + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ServiceReportAssistantEmployeeMenu( + title: context.translation.select, + backgroundColor: AppColor.neutral100, + assetId: assetId, + initialValue: model.employee, + onSelect: (employee) { + if (employee != null) { + onUpdate((model) { + model.employee = employee.copyWith(id: 0); + model.user = AssignedEmployee( + userId: employee.user?.id, + userName: employee.user?.name, + ); + }); + } + }, + ), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + ADatePicker( + label: context.translation.startTime, + hideShadow: true, + backgroundColor: AppColor.neutral100, + date: model.startDate, + formatDateWithTime: true, + from: requestedDate, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + if (selectedTime != null) { + final selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (requestedDate != null && selectedDateTime.isBefore(requestedDate)) { + "Start time is before the request time.".showToast; + return; + } + + if (selectedDateTime.isAfter(DateTime.now())) { + "Start time is after the current time".showToast; + return; + } + + onUpdate((model) { + model.startDate = selectedDateTime; + ServiceRequestUtils.calculateAndAssignWorkingHours( + startTime: model.startDate, + endTime: model.endDate, + workingHoursController: workingHoursController, + updateModel: (hours) => model.workingHours = hours, + ); + }); + } + }); + }, + ).expanded, + 8.width, + ADatePicker( + label: context.translation.endTime, + hideShadow: true, + backgroundColor: AppColor.neutral100, + date: model.endDate, + formatDateWithTime: true, + from: requestedDate, + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + if (selectedTime != null) { + final endDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (!endDateTime.isBefore(DateTime.now())) { + "Please select a time before the current time.".showToast; + return; + } + + if (model.startDate == null || !endDateTime.isAfter(model.startDate!)) { + "End date must be after start date".showToast; + return; + } + + onUpdate((model) { + model.endDate = endDateTime; + ServiceRequestUtils.calculateAndAssignWorkingHours( + startTime: model.startDate, + endTime: model.endDate, + workingHoursController: workingHoursController, + updateModel: (hours) => model.workingHours = hours, + ); + }); + } + }); + }, + ).expanded, + ], + ), + 8.height, + AppTextFormField( + labelText: context.translation.workingHours, + backgroundColor: AppColor.neutral80, + controller: workingHoursController, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + textAlign: TextAlign.center, + enable: false, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + initialValue: model.technicalComment, + labelText: context.translation.technicalComment, + backgroundColor: AppColor.neutral100, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) => onUpdate((model) => model.technicalComment = value), + // onSaved: (value) => onUpdate((model) => model.technicalComment = value), + ), + 8.height, + ], + ) + ], + ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)).paddingOnly(bottom: 12); + } +} diff --git a/lib/modules/cm_module/views/forms/maintenance_request/components/internal_request.dart b/lib/modules/cm_module/views/forms/maintenance_request/components/internal_request.dart index 92d42146..a214591d 100644 --- a/lib/modules/cm_module/views/forms/maintenance_request/components/internal_request.dart +++ b/lib/modules/cm_module/views/forms/maintenance_request/components/internal_request.dart @@ -8,14 +8,13 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/providers/service_request_providers/last_situation_provider.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart'; -import 'assistant_employee_card.dart'; - class InternalMaintenanceRequest extends StatefulWidget { static const String id = "/add-internal-activity"; @@ -119,9 +118,7 @@ class _InternalMaintenanceRequestState extends State onPick: (time) { requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker = time; }, - timerProgress: (isRunning) { - print("timerProgress:$isRunning"); - }, + timerProgress: (isRunning) {}, onChange: (timer) async { requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel = timer; if (timer.startAt != null && timer.endAt != null) { @@ -298,7 +295,16 @@ class _InternalMaintenanceRequestState extends State ], ), ).toShadowContainer(context).paddingOnly(start: 13, end: 14, top: 12), - const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)).paddingOnly(start: 13, end: 14, top: 12), + AssistantEmployeeList( + assetId: requestDetailProvider.currentWorkOrder?.data?.asset?.id, + assistantEmployeeList: requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployList, + onListChanged: (updatedList) { + setState(() { + requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployList = updatedList; + }); + }, + ), + // const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)).paddingOnly(start: 13, end: 14, top: 12), 100.height, ], ), diff --git a/lib/modules/cm_module/views/forms/maintenance_request/maintenance_request_main.dart b/lib/modules/cm_module/views/forms/maintenance_request/maintenance_request_main.dart index 4802f98b..379279bc 100644 --- a/lib/modules/cm_module/views/forms/maintenance_request/maintenance_request_main.dart +++ b/lib/modules/cm_module/views/forms/maintenance_request/maintenance_request_main.dart @@ -7,6 +7,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/helper_data_models/maintenance_request/activity_maintenance_model.dart'; import 'package:test_sa/models/new_models/work_order_detail_model.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; @@ -40,8 +41,9 @@ class _MaintenanceRequestFormState extends State with Si Future getInitialData() async { Provider.of(context, listen: false).getTypes(); ServiceRequestDetailProvider requestDetailProvider = Provider.of(context, listen: false); - requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees = - requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees ?? ActivityMaintenanceAssistantEmployees(); + // requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees = + // requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees ?? ActivityMaintenanceAssistantEmployees(); + requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployList = requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployList ?? []; } @override @@ -147,19 +149,24 @@ class _MaintenanceRequestFormState extends State with Si ), ); }); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - int status = -1; if (requestDetailProvider.activityMaintenanceHelperModel?.id == 0) { - status = await requestDetailProvider.createActivityMaintenanceRequest(); - } else { - status = await requestDetailProvider.updateActivityMaintenance(); - } - if (status == 200) { - requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!); - Navigator.pop(context); - Navigator.pop(context); + await requestDetailProvider.createActivityMaintenanceRequest().then((success) { + Navigator.pop(context); + if (success) { + requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!); + Navigator.pop(context); + } + }); } else { - Navigator.pop(context); + await requestDetailProvider.updateActivityMaintenance().then((success) { + Navigator.pop(context); + if (success) { + requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!); + Navigator.pop(context); + } + }); } } } @@ -197,6 +204,36 @@ class _MaintenanceRequestFormState extends State with Si return false; } } +// assistant employee validation + if (model.assistantEmployList?.isNotEmpty ?? false) { + for (int i = 0; i < model.assistantEmployList!.length; i++) { + final employee = model.assistantEmployList![i]; + final position = Utils.getOrdinal(i + 1); + + if (employee.user == null) { + Fluttertoast.showToast( + msg: "Please select the $position assistant employee", + ); + return false; + } + + if (employee.user?.userId != null) { + if (employee.startDate == null) { + Fluttertoast.showToast( + msg: "Please select start time for assistant employee ${employee.user?.userName}", + ); + return false; + } + + if (employee.endDate == null) { + Fluttertoast.showToast( + msg: "Please select end time for assistant employee ${employee.user?.userName}", + ); + return false; + } + } + } + } // // if (model.activityMaintenanceTimerModel?.startAt == null) { diff --git a/lib/modules/cm_module/views/forms/spare_part/spare_part_request.dart b/lib/modules/cm_module/views/forms/spare_part/spare_part_request.dart index 539dde4f..19726391 100644 --- a/lib/modules/cm_module/views/forms/spare_part/spare_part_request.dart +++ b/lib/modules/cm_module/views/forms/spare_part/spare_part_request.dart @@ -8,6 +8,7 @@ import 'package:test_sa/controllers/providers/api/parts_provider.dart'; import 'package:test_sa/controllers/validator/validator.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; @@ -309,33 +310,8 @@ class _SparePartRequestState extends State with TickerProvider child: AppFilledButton( label: _requestDetailProvider?.sparePartHelperModel?.id == 0 ? context.translation.addSparePartActivity : context.translation.updateSparePartActivity, buttonColor: AppColor.green70, - onPressed: () async { - requestDetailProvider.sparePartHelperModel?.sparePartAttachments?.clear(); - for (var pickerObject in _files) { - String fileData = - _isLocalUrl(pickerObject.file.path) ? ("${pickerObject.file.path.split("/").last}|${base64Encode(File(pickerObject.file.path).readAsBytesSync())}") : pickerObject.file.path; - requestDetailProvider.sparePartHelperModel?.sparePartAttachments?.add(SparePartAttachments(id: pickerObject.id, name: fileData)); - } - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - int status = -1; - if (_requestDetailProvider?.sparePartHelperModel?.id == 0) { - status = await requestDetailProvider.createActivitySparePart(); - } else { - status = await requestDetailProvider.updateActivitySparePart(); - } - if (status == 200) { - await requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!); - //this is for hide the dialoge... - Navigator.pop(context); - Navigator.pop(context); - //show this only for add form.. - if (_requestDetailProvider?.sparePartHelperModel?.id == 0) { - ServiceRequestBottomSheet.addAnotherSpareRequestBottomSheet(context: context); - SizedBox().flushBar(context: context, title: context.translation.sparePartActivitySuccess, message: ''); - } - } else { - Navigator.pop(context); - } + onPressed: () { + _onSubmit(requestDetailProvider: requestDetailProvider); }, )), ], @@ -344,6 +320,53 @@ class _SparePartRequestState extends State with TickerProvider }), ); } + + _onSubmit({required ServiceRequestDetailProvider requestDetailProvider}) async { + if (requestDetailProvider.sparePartHelperModel?.sparePart?.id == null) { + "Please select spare part".showToast; + return; + } else if (requestDetailProvider.sparePartHelperModel?.quantity == null) { + "Please enter quantity".showToast; + return; + } + + requestDetailProvider.sparePartHelperModel?.sparePartAttachments?.clear(); + + for (var pickerObject in _files) { + String fileData = _isLocalUrl(pickerObject.file.path) ? "${pickerObject.file.path.split("/").last}|${base64Encode(File(pickerObject.file.path).readAsBytesSync())}" : pickerObject.file.path; + requestDetailProvider.sparePartHelperModel?.sparePartAttachments?.add( + SparePartAttachments(id: pickerObject.id, name: fileData), + ); + } + + // Show loading dialog + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => const AppLazyLoading(), + ); + bool success = false; + if (_requestDetailProvider?.sparePartHelperModel?.id == 0) { + success = await requestDetailProvider.createActivitySparePart(); + } else { + success = await requestDetailProvider.updateActivitySparePart(); + } + if (mounted) Navigator.pop(context); + if (success) { + requestDetailProvider.getWorkOrderById( + id: requestDetailProvider.currentWorkOrder!.data!.requestId!, + ); + if (mounted) Navigator.pop(context); + if (_requestDetailProvider?.sparePartHelperModel?.id == 0) { + ServiceRequestBottomSheet.addAnotherSpareRequestBottomSheet(context: context); + const SizedBox().flushBar( + context: context, + title: context.translation.sparePartActivitySuccess, + message: '', + ); + } + } + } } class PartDetailBottomSheetSheet extends StatelessWidget { diff --git a/lib/modules/pm_module/ppm_wo/update_ppm/ppm_external_details_form.dart b/lib/modules/pm_module/ppm_wo/update_ppm/ppm_external_details_form.dart index 2ce95ea3..b689b26a 100644 --- a/lib/modules/pm_module/ppm_wo/update_ppm/ppm_external_details_form.dart +++ b/lib/modules/pm_module/ppm_wo/update_ppm/ppm_external_details_form.dart @@ -7,6 +7,7 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/plan_preventive_visit/plan_preventive_visit_model.dart'; +import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; import 'package:test_sa/models/service_request/supplier_details.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -15,6 +16,7 @@ import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/work_order/vendor_provider.dart'; +import 'package:test_sa/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; class PpmExternalDetailsForm extends StatefulWidget { @@ -160,20 +162,53 @@ class _ExternalDetailItemState extends State { }, ), 8.height, - SingleItemDropDownMenu( - context: context, - title: context.translation.supplierEngineer, - enabled: widget.model.supplier != null, - backgroundColor: AppColor.neutral100, - initialValue: widget.model.suppPerson, - staticData: widget.model.supplier?.suppPersons, - showAsBottomSheet: true, - showShadow: false, - onSelect: (suppPerson) { - if (suppPerson != null) { - widget.model.suppPerson = suppPerson; - } - }, + Row( + children: [ + SingleItemDropDownMenu( + context: context, + title: context.translation.supplierEngineer, + enabled: widget.model.supplier != null, + backgroundColor: AppColor.neutral100, + initialValue: widget.model.suppPerson, + staticData: widget.model.supplier?.suppPersons, + showAsBottomSheet: true, + showShadow: false, + onSelect: (suppPerson) { + if (suppPerson != null) { + widget.model.suppPerson = suppPerson; + } + }, + ).expanded, + 8.width, + Container( + height: 56.toScreenHeight, + width: 60.toScreenWidth, + decoration: BoxDecoration( + color: AppColor.neutral100, + borderRadius: BorderRadius.circular(10), + //boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + child: Icon(Icons.add, color: context.isDark ? null : AppColor.neutral60), + ).onPress(() async { + if(widget.model.supplier==null) { + "Please select supplier".showToast; + return; + } + SuppEngineerWorkOrders? suppEngineer = (await showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => AddSupplierEngineerBottomSheet(widget.model.supplier!.id!.toInt()), + )) as SuppEngineerWorkOrders?; + if (suppEngineer == null) return; + widget.model.supplier?.suppPersons ??= []; + widget.model.supplier?.suppPersons!.add(SuppPersons.fromJson(suppEngineer.toJson())); + // requestDetailProvider.activityMaintenanceHelperModel?.supplier?.suppPersons?.add(SuppPersons.fromJson(suppEngineer.toJson())); + widget.model.suppPerson = SuppPersons.fromJson(suppEngineer.toJson()); + setState(() {}); + }), + ], ), 8.height, Row( @@ -193,7 +228,8 @@ class _ExternalDetailItemState extends State { ).then((selectedTime) { if (selectedTime != null) { DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - if (DateTime.tryParse(_ppmProvider?.planPreventiveVisit?.createdDate ?? '') != null && selectedDateTime.isBefore(DateTime.tryParse(_ppmProvider?.planPreventiveVisit?.createdDate ?? '')!)) { + if (DateTime.tryParse(_ppmProvider?.planPreventiveVisit?.createdDate ?? '') != null && + selectedDateTime.isBefore(DateTime.tryParse(_ppmProvider?.planPreventiveVisit?.createdDate ?? '')!)) { "Start time is before the request time.".showToast; selectedTime = null; return; diff --git a/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart b/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart index 4b38f990..9750998d 100644 --- a/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart +++ b/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart @@ -76,16 +76,15 @@ class _UpdatePpmState extends State with TickerProviderStateMixin { ); }); - await ppmProvider.updateVisitByEngineer(status: status).whenComplete(() { - if (status == 1) { + await ppmProvider.updateVisitByEngineer(status: status).then((success) { + Navigator.pop(context); + if (success) { AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); allRequestsProvider.reset(); allRequestsProvider.getAllRequests(context, typeTransaction: 4); ppmProvider.ppmPlanAttachments = []; + Navigator.pop(context); } - // allRequestsProvider.recurrentWoData?.recurrentWoTimerModel=null; - Navigator.pop(context); - Navigator.pop(context); }); } } diff --git a/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart b/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart index 5920fff1..a453473a 100644 --- a/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart +++ b/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart @@ -145,15 +145,17 @@ void _updateTask({required BuildContext context, required int status}) async { .updateRecurrentWo( status: status, ) - .whenComplete(() { - if (status == 1) { - // when click complete then this request remove from the list and status changes to closed.. - allRequestsProvider.reset(); - allRequestsProvider.getAllRequests(context, typeTransaction: 5); - } - allRequestsProvider.recurrentWoData?.recurrentWoTimerModel = null; - Navigator.pop(context); + .then((success) { Navigator.pop(context); + if (success) { + if (status == 1) { + // when click complete then this request remove from the list and status changes to closed.. + allRequestsProvider.reset(); + allRequestsProvider.getAllRequests(context, typeTransaction: 5); + } + allRequestsProvider.recurrentWoData?.recurrentWoTimerModel = null; + Navigator.pop(context); + } }); } } diff --git a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart index 8a203b12..26223427 100644 --- a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart +++ b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart @@ -223,6 +223,23 @@ class _UpdateTaskRequestState extends State { ); }); +// TODO need to test this when task is enabled ... + // await taskRequestProvider.updateTaskByEngineer().then((success) { + // Navigator.pop(context); + // if (success) { + // if (status == 1) { + // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + // allRequestsProvider.reset(); + // allRequestsProvider.getAllRequests(context, typeTransaction: 6); + // } else { + // taskRequestProvider.getTaskById(id: widget.taskId, showLoading: false); + // + // } + // Navigator.pop(context); + // Navigator.pop(context); + // } + // }); + await taskRequestProvider.updateTaskByEngineer().whenComplete(() async { if (taskRequestProvider.stateCode == 200) { if (status == 1) { diff --git a/lib/new_views/common_widgets/single_item_drop_down_menu.dart b/lib/new_views/common_widgets/single_item_drop_down_menu.dart index 3e51e198..8fd75aff 100644 --- a/lib/new_views/common_widgets/single_item_drop_down_menu.dart +++ b/lib/new_views/common_widgets/single_item_drop_down_menu.dart @@ -77,9 +77,8 @@ class _SingleItemDropDownMenuState oldWidget) { if (widget.initialValue != null) { - // print("$provider:start3:${DateTime.now()}"); final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier); - // print("$provider:start4:${DateTime.now()}"); + if (result?.isNotEmpty ?? false) { _selectedItem = result?.first as T?; } else { diff --git a/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart b/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart index e6c81c27..955852a5 100644 --- a/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart +++ b/lib/new_views/forget_password_module/forget_passwod_verify_otp.dart @@ -1,6 +1,5 @@ - - import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:pinput/pinput.dart'; import 'package:provider/provider.dart'; @@ -10,14 +9,14 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/general_response_model.dart'; -import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/forget_password_module/reset_password_view.dart'; class ForgetPasswordVerifyOtpView extends StatefulWidget { - Map data={}; + Map data = {}; - ForgetPasswordVerifyOtpView({Key ?key,required this.data}) : super(key: key); + ForgetPasswordVerifyOtpView({Key? key, required this.data}) : super(key: key); @override State createState() => _ForgetPasswordVerifyOtpViewState(); @@ -25,7 +24,7 @@ class ForgetPasswordVerifyOtpView extends StatefulWidget { class _ForgetPasswordVerifyOtpViewState extends State { String otp = ''; - Timer? _timer; + Timer? _timer; int _remainingSeconds = 180; // 3 minutes in seconds @override @@ -111,17 +110,16 @@ class _ForgetPasswordVerifyOtpViewState extends State(context, listen: false); - String employeeId = widget.data['employeeId']; - GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp( - context: context, - employeeId: employeeId, - ); - print('Response of send OTP: ${response.toJson()}'); + UserProvider _userProvider = Provider.of(context, listen: false); + String employeeId = widget.data['employeeId']; + GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp( + context: context, + employeeId: employeeId, + ); - // Restart the timer - _startTimer(); - } + // Restart the timer + _startTimer(); + } : null, child: Text( 'Resend', @@ -150,15 +148,16 @@ class _ForgetPasswordVerifyOtpViewState extends State(context, listen: false); GeneralResponseModel generalResponseModel = await _userProvider.forgetPasswordValidateOtp( context: context, - employeeId:widget.data['employeeId'], + employeeId: widget.data['employeeId'], otp: otp, ); - if (generalResponseModel.isSuccess==true) { + if (generalResponseModel.isSuccess == true) { Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => ResetPasswordView())); } } diff --git a/lib/new_views/pages/land_page/dashboard_page.dart b/lib/new_views/pages/land_page/dashboard_page.dart index bfa92e7d..44f21ac0 100644 --- a/lib/new_views/pages/land_page/dashboard_page.dart +++ b/lib/new_views/pages/land_page/dashboard_page.dart @@ -1,217 +1,217 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; -import 'package:test_sa/controllers/notification/notification_manger.dart'; -import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; -import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; -import 'package:test_sa/controllers/providers/api/user_provider.dart'; -import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; -import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/text_extensions.dart'; -import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/user.dart'; -import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/dashboard_latest/widgets/progress_fragment.dart'; -import 'package:test_sa/dashboard_latest/widgets/recent_activites_fragment.dart'; -import 'package:test_sa/dashboard_latest/widgets/requests_fragment.dart'; -import 'package:test_sa/views/pages/user/notifications/notifications_page.dart'; - -class DashboardPage extends StatefulWidget { - final VoidCallback onDrawerPress; - - const DashboardPage({Key? key,required this.onDrawerPress}) : super(key: key); - - @override - State createState() => _DashboardPageState(); -} - -class _DashboardPageState extends State { - int _currentPage = 0; - - @override - void initState() { - super.initState(); - getAllRequests(); - } - - void getAllRequests() { - WidgetsBinding.instance.addPostFrameCallback((_) { - Provider.of(context, listen: false).getRequests(); - Provider.of(context, listen: false).getSystemNotifications(user: Provider.of(context, listen: false).user!, resetProvider: true); - }); - } - - @override - void dispose() { - super.dispose(); - } - - bool isFCM = true; - - @override - Widget build(BuildContext context) { - if (isFCM) { - FirebaseNotificationManger.initialized(context); - NotificationManger.initialisation((notificationDetails) { - FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); - }, (id, title, body, payload) async {}); - - isFCM = false; - } - final User user = Provider.of(context, listen: false).user!; - final setting = Provider.of(context, listen: false); - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - titleSpacing: 0, - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Consumer(builder: (context, snapshot, _) { - return CircleAvatar( - radius: 24, - backgroundColor: context.isDark ? AppColor.neutral50 : AppColor.neutral40, - child: Padding( - padding: const EdgeInsets.all(1), // Border radius - child: ClipOval( - child: snapshot.profileImage != null - ? Image.file(snapshot.profileImage!) - : (snapshot.user?.profilePhotoName?.isNotEmpty ?? false) - ? Image.network(snapshot.user!.profilePhotoName!) - : const Icon(Icons.person, size: 24, color: Colors.white), - ), - ), - ); - }).onPress(widget.onDrawerPress), - const Spacer(), - Container( - padding: const EdgeInsets.fromLTRB(12, 6, 6, 6), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: AppColor.background(context), - boxShadow: const [ - BoxShadow( - color: Color(0x07000000), - blurRadius: 14, - offset: Offset(0, 0), - spreadRadius: 0, - ) - ], - ), - child: DropdownButton( - value: setting.assetGroup, - //iconSize: 24, - isDense: true, - icon: const Icon(Icons.keyboard_arrow_down), - elevation: 8, - // dropdownColor: Colors.amber, - borderRadius: BorderRadius.circular(8), - style: TextStyle(color: Theme.of(context).primaryColor), - underline: const SizedBox.shrink(), - onChanged: (newValue) { - if (setting.assetGroup != newValue) { - Provider.of(context, listen: false).setAssetGroup(newValue); - setState(() {}); - getAllRequests(); - } - }, - items: user.assetGroups!.map>((value) { - return DropdownMenuItem( - value: value, - child: Text( - value.name ?? "", - style: Theme.of(context).textTheme.bodyLarge, - ), - ); - }).toList(), - ), - ), - 16.width, - Stack( - alignment: Alignment.topRight, - children: [ - Icon(Icons.notifications, color: context.isDark ? AppColor.neutral30 : AppColor.neutral20, size: 30).paddingOnly(top: 6, end: 0), - // todo @sikander will add count for unread notifications - // Positioned( - // top: 0, - // right: 0, - // child: Container( - // padding: const EdgeInsets.all(4), - // decoration: const ShapeDecoration( - // color: Color(0xFFD02127), - // shape: CircleBorder(), - // ), - // child: Text("", style: AppTextStyles.bodyText), - // ), - // ) - ], - ).onPress(() { - Navigator.of(context).pushNamed(NotificationsPage.id); - }), - ], - ).paddingOnly(start: 16, end: 16), - ), - body: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - context.translation.welcome, - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), - ), - Text( - user.username ?? "", - style: AppTextStyles.heading2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600), - ), - 24.height, - Row( - children: [ - indicatorView(0), - 3.width, - indicatorView(1), - 3.width, - indicatorView(2), - 10.width, - "0${_currentPage + 1}/03".tinyFont(context).custom(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral60), - ], - ), - ], - ).paddingOnly(start: 16, end: 16, top: 8, bottom: 8), - PageView( - onPageChanged: (index) => setState(() => _currentPage = index), - children: [ - const RequestsFragment(), - ProgressFragment(), - const RecentActivitiesFragment(), - ], - ).expanded, - ], - ), - ); - } - - Widget indicatorView(int index) { - bool isActive = _currentPage == index; - - return AnimatedContainer( - duration: const Duration(milliseconds: 250), - width: (isActive ? 30 : 12).toScreenWidth, - height: 9.toScreenHeight, - decoration: BoxDecoration( - color: isActive - ? AppColor.greenStatus(context) - : context.isDark - ? AppColor.neutral20 - : AppColor.neutral40, - borderRadius: BorderRadius.circular(8)), - ); - } -} +// import 'dart:convert'; +// +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; +// import 'package:test_sa/controllers/notification/notification_manger.dart'; +// import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +// import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; +// import 'package:test_sa/controllers/providers/api/user_provider.dart'; +// import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +// import 'package:test_sa/extensions/context_extension.dart'; +// import 'package:test_sa/extensions/int_extensions.dart'; +// import 'package:test_sa/extensions/text_extensions.dart'; +// import 'package:test_sa/extensions/widget_extensions.dart'; +// import 'package:test_sa/models/user.dart'; +// import 'package:test_sa/new_views/app_style/app_color.dart'; +// import 'package:test_sa/dashboard_latest/widgets/progress_fragment.dart'; +// import 'package:test_sa/dashboard_latest/widgets/recent_activites_fragment.dart'; +// import 'package:test_sa/dashboard_latest/widgets/requests_fragment.dart'; +// import 'package:test_sa/views/pages/user/notifications/notifications_page.dart'; +// +// class DashboardPage extends StatefulWidget { +// final VoidCallback onDrawerPress; //todo @delete +// +// const DashboardPage({Key? key,required this.onDrawerPress}) : super(key: key); +// +// @override +// State createState() => _DashboardPageState(); +// } +// +// class _DashboardPageState extends State { +// int _currentPage = 0; +// +// @override +// void initState() { +// super.initState(); +// getAllRequests(); +// } +// +// void getAllRequests() { +// WidgetsBinding.instance.addPostFrameCallback((_) { +// Provider.of(context, listen: false).getRequests(); +// Provider.of(context, listen: false).getSystemNotifications(user: Provider.of(context, listen: false).user!, resetProvider: true); +// }); +// } +// +// @override +// void dispose() { +// super.dispose(); +// } +// +// bool isFCM = true; +// +// @override +// Widget build(BuildContext context) { +// if (isFCM) { +// FirebaseNotificationManger.initialized(context); +// NotificationManger.initialisation((notificationDetails) { +// FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); +// }, (id, title, body, payload) async {}); +// +// isFCM = false; +// } +// final User user = Provider.of(context, listen: false).user!; +// final setting = Provider.of(context, listen: false); +// return Scaffold( +// appBar: AppBar( +// automaticallyImplyLeading: false, +// backgroundColor: Theme.of(context).scaffoldBackgroundColor, +// titleSpacing: 0, +// title: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// crossAxisAlignment: CrossAxisAlignment.center, +// children: [ +// Consumer(builder: (context, snapshot, _) { +// return CircleAvatar( +// radius: 24, +// backgroundColor: context.isDark ? AppColor.neutral50 : AppColor.neutral40, +// child: Padding( +// padding: const EdgeInsets.all(1), // Border radius +// child: ClipOval( +// child: snapshot.profileImage != null +// ? Image.file(snapshot.profileImage!) +// : (snapshot.user?.profilePhotoName?.isNotEmpty ?? false) +// ? Image.network(snapshot.user!.profilePhotoName!) +// : const Icon(Icons.person, size: 24, color: Colors.white), +// ), +// ), +// ); +// }).onPress(widget.onDrawerPress), +// const Spacer(), +// Container( +// padding: const EdgeInsets.fromLTRB(12, 6, 6, 6), +// decoration: BoxDecoration( +// borderRadius: BorderRadius.circular(8), +// color: AppColor.background(context), +// boxShadow: const [ +// BoxShadow( +// color: Color(0x07000000), +// blurRadius: 14, +// offset: Offset(0, 0), +// spreadRadius: 0, +// ) +// ], +// ), +// child: DropdownButton( +// value: setting.assetGroup, +// //iconSize: 24, +// isDense: true, +// icon: const Icon(Icons.keyboard_arrow_down), +// elevation: 8, +// // dropdownColor: Colors.amber, +// borderRadius: BorderRadius.circular(8), +// style: TextStyle(color: Theme.of(context).primaryColor), +// underline: const SizedBox.shrink(), +// onChanged: (newValue) { +// if (setting.assetGroup != newValue) { +// Provider.of(context, listen: false).setAssetGroup(newValue); +// setState(() {}); +// getAllRequests(); +// } +// }, +// items: user.assetGroups!.map>((value) { +// return DropdownMenuItem( +// value: value, +// child: Text( +// value.name ?? "", +// style: Theme.of(context).textTheme.bodyLarge, +// ), +// ); +// }).toList(), +// ), +// ), +// 16.width, +// Stack( +// alignment: Alignment.topRight, +// children: [ +// Icon(Icons.notifications, color: context.isDark ? AppColor.neutral30 : AppColor.neutral20, size: 30).paddingOnly(top: 6, end: 0), +// // todo @sikander will add count for unread notifications +// // Positioned( +// // top: 0, +// // right: 0, +// // child: Container( +// // padding: const EdgeInsets.all(4), +// // decoration: const ShapeDecoration( +// // color: Color(0xFFD02127), +// // shape: CircleBorder(), +// // ), +// // child: Text("", style: AppTextStyles.bodyText), +// // ), +// // ) +// ], +// ).onPress(() { +// Navigator.of(context).pushNamed(NotificationsPage.id); +// }), +// ], +// ).paddingOnly(start: 16, end: 16), +// ), +// body: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisSize: MainAxisSize.min, +// children: [ +// Text( +// context.translation.welcome, +// style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), +// ), +// Text( +// user.username ?? "", +// style: AppTextStyles.heading2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600), +// ), +// 24.height, +// Row( +// children: [ +// indicatorView(0), +// 3.width, +// indicatorView(1), +// 3.width, +// indicatorView(2), +// 10.width, +// "0${_currentPage + 1}/03".tinyFont(context).custom(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral60), +// ], +// ), +// ], +// ).paddingOnly(start: 16, end: 16, top: 8, bottom: 8), +// PageView( +// onPageChanged: (index) => setState(() => _currentPage = index), +// children: [ +// const RequestsFragment(), +// ProgressFragment(), +// const RecentActivitiesFragment(), +// ], +// ).expanded, +// ], +// ), +// ); +// } +// +// Widget indicatorView(int index) { +// bool isActive = _currentPage == index; +// +// return AnimatedContainer( +// duration: const Duration(milliseconds: 250), +// width: (isActive ? 30 : 12).toScreenWidth, +// height: 9.toScreenHeight, +// decoration: BoxDecoration( +// color: isActive +// ? AppColor.greenStatus(context) +// : context.isDark +// ? AppColor.neutral20 +// : AppColor.neutral40, +// borderRadius: BorderRadius.circular(8)), +// ); +// } +// } diff --git a/lib/new_views/pages/land_page/land_page.dart b/lib/new_views/pages/land_page/land_page.dart index 623cb308..fee16b45 100644 --- a/lib/new_views/pages/land_page/land_page.dart +++ b/lib/new_views/pages/land_page/land_page.dart @@ -106,9 +106,9 @@ class _LandPageState extends State { if (_userProvider!.user != null && _userProvider!.user!.employeeIsHMG == false) { WidgetsBinding.instance.addPostFrameCallback((_) { _userProvider!.getSwipeLastTransaction(userId: _userProvider!.user!.userID!); + Provider.of(context, listen: false).getDate(); }); } - Provider.of(context, listen: false).getData(); _pages = [ DashboardView(onDrawerPress: (() { _scaffoldKey.currentState!.isDrawerOpen ? _scaffoldKey.currentState!.closeDrawer() : _scaffoldKey.currentState!.openDrawer(); diff --git a/lib/new_views/pages/splash_page.dart b/lib/new_views/pages/splash_page.dart index b577179e..3e3cbc97 100644 --- a/lib/new_views/pages/splash_page.dart +++ b/lib/new_views/pages/splash_page.dart @@ -15,6 +15,8 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart'; import 'package:test_sa/new_views/pages/login_page.dart'; import 'package:test_sa/new_views/pages/unsafe_device_view.dart'; +import 'package:test_sa/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart'; +import 'package:test_sa/new_views/swipe_module/dialoge/single_btn_dialog.dart'; import 'package:test_sa/new_views/swipe_module/swipe_view.dart'; import 'package:test_sa/views/update_available_screen.dart'; @@ -84,24 +86,54 @@ class _SplashPageState extends State { loading = false; }); if (isValid && _settingProvider.isLocalAuthEnable) { - bool isSuccess = await checkDualAuthentication(); - if (isSuccess) { - _userProvider.setUser(_settingProvider.user!); - - if (_userProvider.user!.onlySwipe!) { - Navigator.of(context).pushNamedAndRemoveUntil(SwipeView.routeName, (routes) => true); - } else { - Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); - } - } else { - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); - } + handleLocalAuth(); } else { - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + showDialog( + context: context, + builder: (BuildContext cxt) => SingleBtnDialog( + title: "Session Expired", + message: "Login session is expired, Please login.", + okTitle: "Login", + onTap: () { + Navigator.pop(context); + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + }), + ); } } } + void handleLocalAuth() async { + bool isSuccess = false; + try { + isSuccess = await checkDualAuthentication(); + } catch (ex) { + // ios exception when scan failed. + } + + if (isSuccess) { + _userProvider.setUser(_settingProvider.user!); + + if (_userProvider.user!.onlySwipe!) { + Navigator.of(context).pushNamedAndRemoveUntil(SwipeView.routeName, (routes) => true); + } else { + Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); + } + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => LocalAuthFailedDialog( + onRetry: () { + handleLocalAuth(); + }, + onLogin: () { + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + }, + ), + ); + } + } + Future checkDualAuthentication() async { return await _settingProvider.auth.authenticate( localizedReason: Platform.isAndroid ? "Scan your fingerprint to authenticate" : "Scan with face id to authenticate", @@ -139,7 +171,7 @@ class _SplashPageState extends State { animation: "splash", callback: (animation) async { bool isSafe = await checkDeviceSafety(); - print('is safe is ${isSafe}'); + if (!isSafe) { Navigator.pushNamedAndRemoveUntil(context, UnsafeDeviceScreen.routeName, (_) => false); } else { diff --git a/lib/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart b/lib/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart new file mode 100644 index 00000000..12715b65 --- /dev/null +++ b/lib/new_views/swipe_module/dialoge/local_auth_failed_dialog.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; + +class LocalAuthFailedDialog extends StatelessWidget { + final String? title; + final String? message; + final String? okTitle; + final String? retryBtnText; + final String? loginBtnText; + final VoidCallback onRetry; + final VoidCallback onLogin; + + const LocalAuthFailedDialog( + {Key? key, this.title, this.message = "Authentication Failed, Please try again or login", this.okTitle, required this.onRetry, required this.onLogin, this.retryBtnText, this.loginBtnText}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Dialog( + backgroundColor: Colors.white, + shape: const RoundedRectangleBorder(), + insetPadding: const EdgeInsets.only(left: 21, right: 21), + child: Padding( + padding: const EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + "Confirm", + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: Colors.black87, height: 35 / 24, letterSpacing: -0.96), + ).paddingOnly(top: 16, bottom: 8), + message != null ? message!.heading5(context).custom(color: AppColor.neutral50) : const SizedBox(), + 28.height, + Column( + children: [ + AppFilledButton( + label: retryBtnText ?? "Retry", + fontSize: 18, + onPressed: () { + Navigator.of(context).pop(); + onRetry(); + }, + buttonColor: AppColor.primary90, + ), + 16.height, + AppFilledButton( + label: loginBtnText ?? "Login", + buttonColor: Colors.white54, + textColor: AppColor.black10, + height: 42, + showBorder: true, + onPressed: () { + Navigator.of(context).pop(); + onLogin(); + }, + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/new_views/swipe_module/dialoge/single_btn_dialog.dart b/lib/new_views/swipe_module/dialoge/single_btn_dialog.dart new file mode 100644 index 00000000..9561f318 --- /dev/null +++ b/lib/new_views/swipe_module/dialoge/single_btn_dialog.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; + +class SingleBtnDialog extends StatelessWidget { + final String? title; + final String? message; + final String? okTitle; + final VoidCallback? onTap; + + const SingleBtnDialog({Key? key, this.title, this.message, this.okTitle, this.onTap}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Dialog( + backgroundColor: Colors.white, + shape: const RoundedRectangleBorder(), + insetPadding: const EdgeInsets.only(left: 21, right: 21), + child: Padding( + padding: const EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title ?? "Confirm", + style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: Colors.black87, height: 35 / 24, letterSpacing: -0.96), + ).paddingOnly(top: 16), + message != null ? message!.heading5(context).custom(color: AppColor.neutral70) : const SizedBox(), + 28.height, + AppFilledButton( + label: okTitle ?? "OK", + height: 46, + onPressed: onTap ?? () => Navigator.pop(context), + textColor: Colors.white, + //color: Ap.green, + ), + ], + ), + ), + ); + } +} diff --git a/lib/providers/task_request_provider/task_request_provider.dart b/lib/providers/task_request_provider/task_request_provider.dart index 5ad0e2f6..590c1bc5 100644 --- a/lib/providers/task_request_provider/task_request_provider.dart +++ b/lib/providers/task_request_provider/task_request_provider.dart @@ -116,15 +116,23 @@ class TaskRequestProvider extends ChangeNotifier { } } - Future updateTaskByEngineer() async { - notifyListeners(); + Future updateTaskByEngineer() async { + isLoading = true; + Response response; try { - final response = await ApiManager.instance.post(URLs.updateTaskByEngineerUrl, body: taskRequestModel!.toEngineerUpdateJson()); + response = await ApiManager.instance.post(URLs.updateTaskByEngineerUrl, body: taskRequestModel!.toEngineerUpdateJson()); stateCode = response.statusCode; + isLoading = false; notifyListeners(); - return response.statusCode; + if (stateCode == 200) { + return true; + } + return false; } catch (error) { - return -1; + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; } } diff --git a/lib/providers/work_order/reason_provider.dart b/lib/providers/work_order/reason_provider.dart index 98945f2a..d077fef2 100644 --- a/lib/providers/work_order/reason_provider.dart +++ b/lib/providers/work_order/reason_provider.dart @@ -8,7 +8,6 @@ import '../../controllers/api_routes/urls.dart'; import '../../models/lookup.dart'; class ReasonProvider extends LoadingListNotifier { - String? serviceRequestId; @override @@ -17,7 +16,7 @@ class ReasonProvider extends LoadingListNotifier { loading = true; notifyListeners(); try { - Response response = await ApiManager.instance.get(URLs.getServiceReportReasonsNew+"&serviceRequestId=$serviceRequestId"); + Response response = await ApiManager.instance.get(URLs.getServiceReportReasonsNew + "&serviceRequestId=$serviceRequestId"); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { List categoriesListJson = json.decode(response.body)["data"]; diff --git a/lib/providers/work_order/wo_frame_provider.dart b/lib/providers/work_order/wo_frame_provider.dart new file mode 100644 index 00000000..2472af1a --- /dev/null +++ b/lib/providers/work_order/wo_frame_provider.dart @@ -0,0 +1,33 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +import '../../controllers/api_routes/api_manager.dart'; +import '../../controllers/api_routes/urls.dart'; +import '../../models/lookup.dart'; + +class WoFrameProvider extends LoadingListNotifier { + @override + Future getDate() async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.getWoFrames); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/views/pages/device_transfer/update_device_transfer.dart b/lib/views/pages/device_transfer/update_device_transfer.dart index 4a35c1f3..3f491f86 100644 --- a/lib/views/pages/device_transfer/update_device_transfer.dart +++ b/lib/views/pages/device_transfer/update_device_transfer.dart @@ -10,6 +10,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/device/asset_transfer_attachment.dart'; import 'package:test_sa/models/device/device_transfer.dart'; import 'package:test_sa/models/new_models/assigned_employee.dart'; @@ -18,6 +19,7 @@ import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; +import 'package:test_sa/modules/cm_module/views/forms/maintenance_request/components/assistant_employee_list.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; @@ -164,15 +166,34 @@ class _UpdateDeviceTransferState extends State { return false; } } +// assistant employee validation + if (_formModel.assistantEmployList?.isNotEmpty ?? false) { + for (int i = 0; i < _formModel.assistantEmployList!.length; i++) { + final employee = _formModel.assistantEmployList![i]; + final position = Utils.getOrdinal(i + 1); + + if (employee.employeeId == null) { + Fluttertoast.showToast( + msg: "Please select the $position assistant employee", + ); + return false; + } - if (_formModel.assistantEmployees != null) { - if (_formModel.modelAssistantEmployees?.startDate == null) { - Fluttertoast.showToast(msg: "Please Select Assistant Employee Start Time"); - return false; - } - if (_formModel.modelAssistantEmployees?.endDate == null) { - Fluttertoast.showToast(msg: "Please Select Assistant Employee End Time"); - return false; + if (employee.employeeId != null) { + if (employee.startDate == null) { + Fluttertoast.showToast( + msg: "Please select start time for assistant employee ${employee.employeeName}", + ); + return false; + } + + if (employee.endDate == null) { + Fluttertoast.showToast( + msg: "Please select end time for assistant employee ${employee.employeeName}", + ); + return false; + } + } } } return true; @@ -210,88 +231,96 @@ class _UpdateDeviceTransferState extends State { ), key: _scaffoldKey, body: LoadingManager( - isLoading: _isLoading, - isFailedLoading: false, - stateCode: 200, - onRefresh: () async {}, - child: Form( - key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)), - child: Column( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _timerWidget(context, totalWorkingHours, isTimerEnable), - 8.height, - AppTextFormField( - initialValue: widget.isSender ? _formModel.senderComment ?? "" : _formModel.receiverComment ?? "", - labelText: context.translation.technicalComment, - labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral20), - textInputType: TextInputType.multiline, - backgroundColor: AppColor.neutral100, - showShadow: false, - alignLabelWithHint: true, - onSaved: (value) { - widget.isSender ? _formModel.senderComment = value : _formModel.receiverComment = value; - }, - ), - 8.height, - MultiFilesPicker( - label: context.translation.attachFiles, - files: _files, - buttonColor: AppColor.black10, - onlyImages: false, - buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), - ), - 8.height, - ], - ).toShadowContainer(context), - 16.height, - AssistantEmployeeCard( - isSender: widget.isSender, - formModel: _formModel, - ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)), - ], - ), - ).expanded, - FooterActionButton.footerContainer( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - AppFilledButton( - label: context.translation.save, - buttonColor: AppColor.white60, - textColor: AppColor.black10, - onPressed: () => _update(status: 0), - ).expanded, - 12.width, - if (!widget.isSender && _formModel.senderMachineStatusValue == 3) ...[ + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _timerWidget(context, totalWorkingHours, isTimerEnable), + 8.height, + AppTextFormField( + initialValue: widget.isSender ? _formModel.senderComment ?? "" : _formModel.receiverComment ?? "", + labelText: context.translation.technicalComment, + labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral20), + textInputType: TextInputType.multiline, + backgroundColor: AppColor.neutral100, + showShadow: false, + alignLabelWithHint: true, + onSaved: (value) { + widget.isSender ? _formModel.senderComment = value : _formModel.receiverComment = value; + }, + ), + 8.height, + MultiFilesPicker( + label: context.translation.attachFiles, + files: _files, + buttonColor: AppColor.black10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), + ), + 8.height, + ], + ).toShadowContainer(context), + 16.height, + DeviceTransferAssistantEmployeeList( + assetId: _formModel.assetId, + createdDate: _formModel.createdDate??'', + assistantEmployeeList: widget.isSender?_formModel.assetTransferAssistantEmployeesSender:_formModel.assetTransferAssistantEmployeesReceiver, + cardPadding: 0, + onListChanged: (updatedList) { + setState(() { + _formModel.assistantEmployList = updatedList; + }); + }, + ), + ], + ), + ).expanded, + FooterActionButton.footerContainer( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ AppFilledButton( + label: context.translation.save, + buttonColor: AppColor.white60, + textColor: AppColor.black10, + onPressed: () => _update(status: 0), + ).expanded, + 12.width, + if (!widget.isSender && _formModel.senderMachineStatusValue == 3) ...[ + AppFilledButton( + label: context.translation.complete, + buttonColor: AppColor.primary10, + onPressed: () { + _update(status: 1); + }).expanded, + ] else if (widget.isSender) ...[ + AppFilledButton( label: context.translation.complete, buttonColor: AppColor.primary10, onPressed: () { _update(status: 1); - }).expanded, - ] else if (widget.isSender) ...[ - AppFilledButton( - label: context.translation.complete, - buttonColor: AppColor.primary10, - onPressed: () { - _update(status: 1); - }, - ).expanded, + }, + ).expanded, + ], ], - ], + ), ), - ), - ], + ], + ), ), ), - ), + ).handlePopScope( cxt: context, onSave: () { @@ -351,224 +380,513 @@ class _UpdateDeviceTransferState extends State { } } -class AssistantEmployeeCard extends StatefulWidget { - bool? isSender = false; - DeviceTransfer? formModel; - AssistantEmployeeCard({super.key, this.isSender, this.formModel}); + + + +class DeviceTransferAssistantEmployeeList extends StatefulWidget { + final List? assistantEmployeeList; + final ValueChanged>? onListChanged; + final double ?cardPadding; + final dynamic assetId; + final String createdDate; + + const DeviceTransferAssistantEmployeeList({ + super.key, + this.assistantEmployeeList, + this.onListChanged, + required this.assetId, + this.cardPadding, + required this.createdDate, + }); @override - State createState() => _AssistantEmployeeCardState(); + State createState() => _DeviceTransferAssistantEmployeeListState(); } -class _AssistantEmployeeCardState extends State { - final TextEditingController _workingHoursController = TextEditingController(text: ''); - bool isCurrentUserIsAssistantEmp = false; - bool isExpanded = false; - List employeeList = []; - AssistantEmployees selectedEmployee = AssistantEmployees(); +class _DeviceTransferAssistantEmployeeListState extends State { + late List _list; + late List _controllers; @override void initState() { - WidgetsBinding.instance.addPostFrameCallback((_) { - getInitialData(); - }); super.initState(); + _list = List.from(widget.assistantEmployeeList ?? []); + _controllers = _list.map((e) => TextEditingController(text: e.workingHours?.toString() ?? '')).toList(); } - Future getInitialData() async { - if (widget.isSender!) { - employeeList = widget.formModel!.assetTransferAssistantEmployeesSender ?? []; - } else { - employeeList = widget.formModel!.assetTransferAssistantEmployeesReceiver ?? []; - } + void _addNewEntry() { + setState(() { + _list.add(AssetTransferAssistantEmployees()); + _controllers.add(TextEditingController()); + }); + widget.onListChanged?.call(_list); + } - widget.formModel?.modelAssistantEmployees = employeeList.isEmpty ? AssetTransferAssistantEmployees() : employeeList[0]; + void _removeEntry(int index) { + setState(() { + _list.removeAt(index); + _controllers.removeAt(index); + }); + widget.onListChanged?.call(_list); + } - AssignedEmployee? assignedUser = AssignedEmployee(); - if (employeeList.isNotEmpty) { - assignedUser = AssignedEmployee( - id: employeeList[0].employeeId, - name: employeeList[0].employeeName, - ); - } - selectedEmployee = AssistantEmployees(userId: assignedUser.id, user: assignedUser); + void _updateModel(int index, void Function(AssetTransferAssistantEmployees model) updateList, {bool updateController = false}) { + setState(() { + updateList(_list[index]); + }); } @override - void dispose() { - _workingHoursController.dispose(); - super.dispose(); + Widget build(BuildContext context) { + return ListView.builder( + itemCount: _list.length + 1, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(widget.cardPadding??16), + itemBuilder: (context, index) { + if (index == _list.length) { + return AppFilledButton( + label: "Add Assistant Employee".addTranslation, + maxWidth: true, + textColor: AppColor.black10, + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: _addNewEntry, + ); + } + AssistantEmployees selectedEmployee = AssistantEmployees(); + AssignedEmployee? assignedUser = AssignedEmployee(); + assignedUser = AssignedEmployee( + id: _list[index].employeeId, + name: _list[index].employeeName, + ); + selectedEmployee = AssistantEmployees( userId: assignedUser.id, user: assignedUser); + return EmployeeCard( + model: _list[index], + assetId: widget.assetId, + index: index, + createdDate: widget.createdDate, + selectedEmployee: selectedEmployee, + onUpdate: (updateList) => _updateModel(index, updateList), + onRemove: () => _removeEntry(index), + workingHoursController: _controllers[index], + ); + }, + ); } +} + +class EmployeeCard extends StatelessWidget { + final AssetTransferAssistantEmployees model; + final int index; + final dynamic assetId ; + final String ? createdDate; + AssistantEmployees? selectedEmployee; + final void Function(void Function(AssetTransferAssistantEmployees model)) onUpdate; + final VoidCallback onRemove; + final TextEditingController workingHoursController; + EmployeeCard({ + super.key, + required this.model, + required this.assetId, + this.selectedEmployee, + required this.index, + required this.onUpdate, + this.createdDate, + required this.onRemove, + required this.workingHoursController, + }); + + // AssistantEmployees selectedEmployee = AssistantEmployees(); @override Widget build(BuildContext context) { + return Column( children: [ - SizedBox( - height: 56.toScreenHeight, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - context.translation.assistantEmployee.heading6(context).custom(color: AppColor.black10), - Icon(isExpanded ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded), - ], - ), - ).onPress(() { - setState(() { - isExpanded = !isExpanded; - }); - }), - isExpanded - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ServiceReportAssistantEmployeeMenu( - title: context.translation.select, - backgroundColor: AppColor.neutral100, - assetId: widget.formModel?.assetId ?? 0, - initialValue: selectedEmployee, - onSelect: (employee) { - if (employee == null) { - widget.formModel?.assistantEmployees = []; - } else { - selectedEmployee = employee; - widget.formModel?.assistantEmployees = [employee.copyWith(id: 0)]; - widget.formModel?.modelAssistantEmployees?.employeeId = employee.user?.id; + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.black20), + Container( + height: 32, + width: 32, + padding: const EdgeInsets.all(6), + child: "trash".toSvgAsset(height: 20, width: 20), + ).onPress(onRemove), + ], + ), + 8.height, + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ServiceReportAssistantEmployeeMenu( + title: context.translation.select, + backgroundColor: AppColor.neutral100, + assetId:assetId, + initialValue: selectedEmployee, + onSelect: (employee) { + if (employee != null) { + onUpdate((model) { + selectedEmployee = employee.copyWith(id: 0); + model.employeeId = employee.user?.id; + model.employeeName = employee.user?.name; + selectedEmployee?.user = AssignedEmployee( + id: employee.user?.id, + name: employee.user?.name, + ); + }); + } + }, + ), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + ADatePicker( + label: context.translation.startTime, + hideShadow: true, + backgroundColor: AppColor.neutral100, + date: model.startDate, + formatDateWithTime: true, + from: DateTime.tryParse(createdDate ?? ''), + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + if (selectedTime != null) { + final selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (createdDate != null && selectedDateTime.isBefore(DateTime.tryParse(createdDate ?? '')!)) { + "Start time is before the request time.".showToast; + return; + } + + if (selectedDateTime.isAfter(DateTime.now())) { + "Start time is after the current time".showToast; + return; + } + + onUpdate((model) { + model.startDate = selectedDateTime; + ServiceRequestUtils.calculateAndAssignWorkingHours( + startTime: model.startDate, + endTime: model.endDate, + workingHoursController: workingHoursController, + updateModel: (hours) => model.workingHours = hours, + ); + }); } - }, - ), - 8.height, - Row( - mainAxisSize: MainAxisSize.min, - children: [ - ADatePicker( - label: context.translation.startTime, - hideShadow: true, - backgroundColor: AppColor.neutral100, - date: widget.formModel?.modelAssistantEmployees?.startDate, - from: DateTime.tryParse(widget.formModel?.createdDate ?? ''), - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ).then((selectedTime) { - // Handle the selected date and time here. - if (selectedTime != null) { - DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - if (DateTime.tryParse(widget.formModel?.createdDate ?? '') != null && selectedDateTime.isBefore(DateTime.tryParse(widget.formModel?.createdDate ?? '')!)) { - "Start time is before the request time.".showToast; - selectedTime = null; - return; - } - if (selectedDateTime.isAfter(DateTime.now())) { - "Start time is after than current time".showToast; - selectedTime = null; - return; - } - widget.formModel?.modelAssistantEmployees?.startDate = selectedDateTime; - ServiceRequestUtils.calculateAndAssignWorkingHours( - startTime: widget.formModel?.modelAssistantEmployees?.startDate, - endTime: widget.formModel?.modelAssistantEmployees?.endDate, - workingHoursController: _workingHoursController, - updateModel: (hours) { - widget.formModel?.modelAssistantEmployees?.workingHours = hours; - }); - setState(() {}); - } - }); - }, - ).expanded, - 8.width, - ADatePicker( - label: context.translation.endTime, - hideShadow: true, - backgroundColor: AppColor.neutral100, - date: widget.formModel?.modelAssistantEmployees?.endDate, - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ).then((selectedTime) { - if (selectedTime != null) { - DateTime selectedDateTime = DateTime( - selectedDate.year, - selectedDate.month, - selectedDate.day, - selectedTime.hour, - selectedTime.minute, - ); - if (widget.formModel?.modelAssistantEmployees?.startDate != null && selectedDateTime.isBefore(widget.formModel!.modelAssistantEmployees!.startDate!)) { - "End Date time must be greater then start date".showToast; - return; - } - - selectedDate = selectedDate.add(Duration(hours: selectedTime.hour, minutes: selectedTime.minute)); - bool isBeforeCurrentTime = selectedDate.isBefore(DateTime.now()); - bool isAfterStartTime = selectedDate.isAfter(widget.formModel!.modelAssistantEmployees!.startDate!); - if (!isBeforeCurrentTime) { - "Please select a time before the current time.".showToast; - return; - } - if (!isAfterStartTime) { - "End Date time must be greater then start date".showToast; - return; - } - - - - - widget.formModel?.modelAssistantEmployees?.endDate = selectedDateTime; - ServiceRequestUtils.calculateAndAssignWorkingHours( - startTime: widget.formModel?.modelAssistantEmployees?.startDate, - endTime: widget.formModel?.modelAssistantEmployees?.endDate, - workingHoursController: _workingHoursController, - updateModel: (hours) { - widget.formModel?.modelAssistantEmployees?.workingHours = hours; - }); - setState(() {}); - } - }); - }, - ).expanded, - ], - ), - 8.height, - AppTextFormField( - labelText: context.translation.workingHours, - backgroundColor: AppColor.neutral80, - controller: _workingHoursController, - suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), - initialValue: widget.formModel?.modelAssistantEmployees?.workingHours != null ? widget.formModel?.modelAssistantEmployees?.workingHours.toString() : '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - enable: false, - showShadow: false, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - initialValue: widget.formModel?.modelAssistantEmployees?.techComment, - labelText: context.translation.technicalComment, - backgroundColor: AppColor.neutral100, - showShadow: false, - labelStyle: AppTextStyles.textFieldLabelStyle, - alignLabelWithHint: true, - textInputType: TextInputType.multiline, - onChange: (value) { - widget.formModel?.modelAssistantEmployees?.techComment = value; - }, - onSaved: (value) { - widget.formModel?.modelAssistantEmployees?.techComment = value; - }, - ), - 16.height, - ], - ) - : const SizedBox(), + }); + }, + ).expanded, + 8.width, + ADatePicker( + label: context.translation.endTime, + hideShadow: true, + backgroundColor: AppColor.neutral100, + date: model.endDate, + formatDateWithTime: true, + from: DateTime.tryParse(createdDate ?? ''), + onDatePicker: (selectedDate) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + if (selectedTime != null) { + final endDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (!endDateTime.isBefore(DateTime.now())) { + "Please select a time before the current time.".showToast; + return; + } + + if (model.startDate == null || !endDateTime.isAfter(model.startDate!)) { + "End date must be after start date".showToast; + return; + } + + onUpdate((model) { + model.endDate = endDateTime; + ServiceRequestUtils.calculateAndAssignWorkingHours( + startTime: model.startDate, + endTime: model.endDate, + workingHoursController: workingHoursController, + updateModel: (hours) => model.workingHours = hours, + ); + }); + } + }); + }, + ).expanded, + ], + ), + 8.height, + AppTextFormField( + labelText: context.translation.workingHours, + backgroundColor: AppColor.neutral80, + controller: workingHoursController, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + textAlign: TextAlign.center, + enable: false, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + initialValue: model.techComment, + labelText: context.translation.technicalComment, + backgroundColor: AppColor.neutral100, + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) => onUpdate((model) => model.techComment = value), + // onSaved: (value) => onUpdate((model) => model.technicalComment = value), + ), + 8.height, + ], + ) ], - ); + ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)) + .paddingOnly(bottom: 12); } } + +// class AssistantEmployeeCard extends StatefulWidget { +// bool? isSender = false; +// DeviceTransfer? formModel; +// +// AssistantEmployeeCard({super.key, this.isSender, this.formModel}); +// +// @override +// State createState() => _AssistantEmployeeCardState(); +// } +// +// class _AssistantEmployeeCardState extends State { +// final TextEditingController _workingHoursController = TextEditingController(text: ''); +// bool isCurrentUserIsAssistantEmp = false; +// bool isExpanded = false; +// List employeeList = []; +// AssistantEmployees selectedEmployee = AssistantEmployees(); + +// @override +// void initState() { +// WidgetsBinding.instance.addPostFrameCallback((_) { +// getInitialData(); +// }); +// super.initState(); +// } +// +// Future getInitialData() async { +// if (widget.isSender!) { +// employeeList = widget.formModel!.assetTransferAssistantEmployeesSender ?? []; +// } else { +// employeeList = widget.formModel!.assetTransferAssistantEmployeesReceiver ?? []; +// } +// +// widget.formModel?.modelAssistantEmployees = employeeList.isEmpty ? AssetTransferAssistantEmployees() : employeeList[0]; +// +// AssignedEmployee? assignedUser = AssignedEmployee(); +// if (employeeList.isNotEmpty) { +// assignedUser = AssignedEmployee( +// id: employeeList[0].employeeId, +// name: employeeList[0].employeeName, +// ); +// } +// selectedEmployee = AssistantEmployees(userId: assignedUser.id, user: assignedUser); +// } +// +// @override +// void dispose() { +// _workingHoursController.dispose(); +// super.dispose(); +// } +// +// @override +// Widget build(BuildContext context) { +// return Column( +// children: [ +// SizedBox( +// height: 56.toScreenHeight, +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// context.translation.assistantEmployee.heading6(context).custom(color: AppColor.black10), +// Icon(isExpanded ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded), +// ], +// ), +// ).onPress(() { +// setState(() { +// isExpanded = !isExpanded; +// }); +// }), +// isExpanded +// ? Column( +// crossAxisAlignment: CrossAxisAlignment.stretch, +// children: [ +// ServiceReportAssistantEmployeeMenu( +// title: context.translation.select, +// backgroundColor: AppColor.neutral100, +// assetId: widget.formModel?.assetId ?? 0, +// initialValue: selectedEmployee, +// onSelect: (employee) { +// if (employee == null) { +// widget.formModel?.assistantEmployees = []; +// } else { +// selectedEmployee = employee; +// widget.formModel?.assistantEmployees = [employee.copyWith(id: 0)]; +// widget.formModel?.modelAssistantEmployees?.employeeId = employee.user?.id; +// } +// }, +// ), +// 8.height, +// Row( +// mainAxisSize: MainAxisSize.min, +// children: [ +// ADatePicker( +// label: context.translation.startTime, +// hideShadow: true, +// backgroundColor: AppColor.neutral100, +// date: widget.formModel?.modelAssistantEmployees?.startDate, +// from: DateTime.tryParse(widget.formModel?.createdDate ?? ''), +// formatDateWithTime: true, +// onDatePicker: (selectedDate) { +// showTimePicker( +// context: context, +// initialTime: TimeOfDay.now(), +// ).then((selectedTime) { +// // Handle the selected date and time here. +// if (selectedTime != null) { +// DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); +// if (DateTime.tryParse(widget.formModel?.createdDate ?? '') != null && selectedDateTime.isBefore(DateTime.tryParse(widget.formModel?.createdDate ?? '')!)) { +// "Start time is before the request time.".showToast; +// selectedTime = null; +// return; +// } +// if (selectedDateTime.isAfter(DateTime.now())) { +// "Start time is after than current time".showToast; +// selectedTime = null; +// return; +// } +// widget.formModel?.modelAssistantEmployees?.startDate = selectedDateTime; +// ServiceRequestUtils.calculateAndAssignWorkingHours( +// startTime: widget.formModel?.modelAssistantEmployees?.startDate, +// endTime: widget.formModel?.modelAssistantEmployees?.endDate, +// workingHoursController: _workingHoursController, +// updateModel: (hours) { +// widget.formModel?.modelAssistantEmployees?.workingHours = hours; +// }); +// setState(() {}); +// } +// }); +// }, +// ).expanded, +// 8.width, +// ADatePicker( +// label: context.translation.endTime, +// hideShadow: true, +// backgroundColor: AppColor.neutral100, +// date: widget.formModel?.modelAssistantEmployees?.endDate, +// formatDateWithTime: true, +// onDatePicker: (selectedDate) { +// showTimePicker( +// context: context, +// initialTime: TimeOfDay.now(), +// ).then((selectedTime) { +// if (selectedTime != null) { +// DateTime selectedDateTime = DateTime( +// selectedDate.year, +// selectedDate.month, +// selectedDate.day, +// selectedTime.hour, +// selectedTime.minute, +// ); +// if (widget.formModel?.modelAssistantEmployees?.startDate != null && selectedDateTime.isBefore(widget.formModel!.modelAssistantEmployees!.startDate!)) { +// "End Date time must be greater then start date".showToast; +// return; +// } +// +// selectedDate = selectedDate.add(Duration(hours: selectedTime.hour, minutes: selectedTime.minute)); +// bool isBeforeCurrentTime = selectedDate.isBefore(DateTime.now()); +// bool isAfterStartTime = selectedDate.isAfter(widget.formModel!.modelAssistantEmployees!.startDate!); +// if (!isBeforeCurrentTime) { +// "Please select a time before the current time.".showToast; +// return; +// } +// if (!isAfterStartTime) { +// "End Date time must be greater then start date".showToast; +// return; +// } +// +// +// +// +// widget.formModel?.modelAssistantEmployees?.endDate = selectedDateTime; +// ServiceRequestUtils.calculateAndAssignWorkingHours( +// startTime: widget.formModel?.modelAssistantEmployees?.startDate, +// endTime: widget.formModel?.modelAssistantEmployees?.endDate, +// workingHoursController: _workingHoursController, +// updateModel: (hours) { +// widget.formModel?.modelAssistantEmployees?.workingHours = hours; +// }); +// setState(() {}); +// } +// }); +// }, +// ).expanded, +// ], +// ), +// 8.height, +// AppTextFormField( +// labelText: context.translation.workingHours, +// backgroundColor: AppColor.neutral80, +// controller: _workingHoursController, +// suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), +// initialValue: widget.formModel?.modelAssistantEmployees?.workingHours != null ? widget.formModel?.modelAssistantEmployees?.workingHours.toString() : '', +// textAlign: TextAlign.center, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// enable: false, +// showShadow: false, +// style: Theme.of(context).textTheme.titleMedium, +// ), +// 8.height, +// AppTextFormField( +// initialValue: widget.formModel?.modelAssistantEmployees?.techComment, +// labelText: context.translation.technicalComment, +// backgroundColor: AppColor.neutral100, +// showShadow: false, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// alignLabelWithHint: true, +// textInputType: TextInputType.multiline, +// onChange: (value) { +// widget.formModel?.modelAssistantEmployees?.techComment = value; +// }, +// onSaved: (value) { +// widget.formModel?.modelAssistantEmployees?.techComment = value; +// }, +// ), +// 16.height, +// ], +// ) +// : const SizedBox(), +// ], +// ); +// } +// } diff --git a/lib/views/pages/user/gas_refill/update_gas_refill_request.dart b/lib/views/pages/user/gas_refill/update_gas_refill_request.dart index 5f5884b0..46bbf265 100644 --- a/lib/views/pages/user/gas_refill/update_gas_refill_request.dart +++ b/lib/views/pages/user/gas_refill/update_gas_refill_request.dart @@ -156,15 +156,18 @@ class _UpdateGasRefillRequestState extends State { _formModel.gasRefillAttachments?.add(GasRefillAttachments( id: 0, gasRefillId: _formModel.id ?? 0, attachmentName: ServiceRequestUtils.isLocalUrl(item.path) ? "${item.path.split("/").last}|${base64Encode(item.readAsBytesSync())}" : item.path)); } - await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).whenComplete(() { - if (status == 1) { - AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); - // when click complete then this request remove from the list and status changes to closed.. - _gasRefillProvider?.reset(); - allRequestsProvider.getAllRequests(context, typeTransaction: 2); - } - Navigator.pop(context); + + await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { Navigator.pop(context); + if (success) { + if (status == 1) { + AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + // when click complete then this request remove from the list and status changes to closed.. + _gasRefillProvider?.reset(); + allRequestsProvider.getAllRequests(context, typeTransaction: 2); + } + Navigator.pop(context); + } }); } diff --git a/lib/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart b/lib/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart index 7f13df6c..fbc606dc 100644 --- a/lib/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart +++ b/lib/views/pages/user/requests/add_supplier_engineer_bottom_sheet.dart @@ -127,8 +127,7 @@ class _AddSupplierEngineerBottomSheetState extends State { _serviceRequest.requestedThrough = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null); _serviceRequest.type = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 1, orElse: null); - // print("_serviceRequest?.requestedThrough:${_serviceRequest?.requestedThrough.toJson()}"); - // print("_serviceRequest?.type:${_serviceRequest?.type.toJson()}"); - // print("_serviceRequest?.priority:${_serviceRequest?.priority.toJson()}"); - // return; - if (_formKey.currentState!.validate() && await _serviceRequest.validateNewRequest(context)) { _formKey.currentState!.save(); diff --git a/lib/views/widgets/images/files_list.dart b/lib/views/widgets/images/files_list.dart index 41679d07..9a24e097 100644 --- a/lib/views/widgets/images/files_list.dart +++ b/lib/views/widgets/images/files_list.dart @@ -60,7 +60,8 @@ class FilesList extends StatelessWidget { body: SafeArea( child: Stack( children: [ - InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, + // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, + InteractiveViewer(child: getImageWidget(itemIndex)).center, const ABackButton(), ], ), @@ -138,6 +139,13 @@ class FilesList extends StatelessWidget { // }); } + Widget getImageWidget(int itemIndex) { + if (_isLocalUrl(images[itemIndex])) { + return Image.file(File(images[itemIndex])); + } + return ImageLoader(url: images[itemIndex]); + } + ImageProvider getImageObject(int itemIndex) { if (_isLocalUrl(images[itemIndex])) { return FileImage(File(images[itemIndex])); diff --git a/lib/views/widgets/parts/auto_complete_parts_field.dart b/lib/views/widgets/parts/auto_complete_parts_field.dart index bf9703cf..649d2d38 100644 --- a/lib/views/widgets/parts/auto_complete_parts_field.dart +++ b/lib/views/widgets/parts/auto_complete_parts_field.dart @@ -32,7 +32,6 @@ class _AutoCompletePartsFieldState extends State { @override void initState() { - print('initial value i got is ${widget.initialValue}'); _controller = TextEditingController(text: widget.initialValue); super.initState(); } @@ -75,7 +74,7 @@ class _AutoCompletePartsFieldState extends State { displayStringForOption: (SparePartsWorkOrders option) => widget.byName ? option.sparePart?.partName ?? "" : option.sparePart?.partNo ?? "", fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { return TextField( - controller: _controller, + controller: _controller, focusNode: fieldFocusNode, style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), textAlign: TextAlign.start, @@ -96,8 +95,8 @@ class _AutoCompletePartsFieldState extends State { labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120), ), textInputAction: TextInputAction.search, - onChanged: (text){ - fieldTextEditingController.text =text; + onChanged: (text) { + fieldTextEditingController.text = text; }, onSubmitted: (String value) { onFieldSubmitted(); diff --git a/lib/views/widgets/sound/sound_player.dart b/lib/views/widgets/sound/sound_player.dart index 055379f9..edf8b377 100644 --- a/lib/views/widgets/sound/sound_player.dart +++ b/lib/views/widgets/sound/sound_player.dart @@ -158,7 +158,6 @@ class _ASoundPlayerState extends State { if (_audio != widget.audio) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { _audio = widget.audio; - print('audio position i got is $_audioPosition'); if (_isLocalFile) { await _audioPlayer.setSourceDeviceFile(_audio); } else { @@ -199,7 +198,8 @@ class _ASoundPlayerState extends State { ).paddingOnly(start: 8, end: 8).expanded, _failedToLoad ? Text("Failed to load", style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60)) - : Text("${format(_audioPosition??Duration.zero)}/${format(_audioTime??Duration.zero)}", style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + : Text("${format(_audioPosition ?? Duration.zero)}/${format(_audioTime ?? Duration.zero)}", + style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), ], ), ], diff --git a/lib/views/widgets/status/single_status_menu.dart b/lib/views/widgets/status/single_status_menu.dart index 52a6fbb8..003d6dac 100644 --- a/lib/views/widgets/status/single_status_menu.dart +++ b/lib/views/widgets/status/single_status_menu.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; -import'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/lookup.dart'; import '../../../new_views/app_style/app_color.dart'; class SingleStatusMenu extends StatefulWidget { - final List? statuses;// Nullable list + final List? statuses; // Nullable list final Lookup? initialStatus; // Nullable final Function(Lookup?)? onSelect; // Nullable function, accepts nullable Lookup final bool enabled; @@ -35,9 +35,7 @@ class _SingleStatusMenuState extends State { @override void didUpdateWidget(covariant SingleStatusMenu oldWidget) { - _selectedStatus = widget.statuses?.firstWhere( - (element) => element == widget.initialStatus, - orElse: null); + _selectedStatus = widget.statuses?.firstWhere((element) => element == widget.initialStatus, orElse: null); if (widget.initialStatus != _selectedStatus) { widget.onSelect?.call(_selectedStatus); // Use null-aware operator @@ -48,10 +46,7 @@ class _SingleStatusMenuState extends State { @override void initState() { - print('status lenght is ${widget.statuses?.length}'); - _selectedStatus = widget.statuses?.firstWhere( - (element) => element == widget.initialStatus, - orElse: () => Lookup()); + _selectedStatus = widget.statuses?.firstWhere((element) => element == widget.initialStatus, orElse: () => Lookup()); if (widget.initialStatus != _selectedStatus) { widget.onSelect?.call(_selectedStatus); // Use null-aware operator @@ -62,25 +57,22 @@ class _SingleStatusMenuState extends State { @override Widget build(BuildContext context) { - return Container(height: 60.toScreenHeight, + return Container( + height: 60.toScreenHeight, padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), decoration: BoxDecoration( color: context.isDark && (!widget.enabled || widget.statuses!.isEmpty) ? AppColor.neutral50 : (!widget.enabled || widget.statuses!.isEmpty) - ? AppColor.neutral40 - : AppColor.background(context), + ? AppColor.neutral40 + : AppColor.background(context), borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10) - ], + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], ), child: Stack( alignment: Alignment.center, children: [ - if (widget.enabled) - const PositionedDirectional( - end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)), + if (widget.enabled) const PositionedDirectional(end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, @@ -88,9 +80,7 @@ class _SingleStatusMenuState extends State { if (widget.title != null) Text( widget.title!, // Use null assertion operator - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: context.isDark ? null : AppColor.neutral20, - fontWeight: FontWeight.w500), + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), ), DropdownButton( value: _selectedStatus, @@ -107,22 +97,22 @@ class _SingleStatusMenuState extends State { underline: const SizedBox.shrink(), onChanged: !widget.enabled ? null - : (Lookup? newValue) { // Nullable Lookup - setState(() { - _selectedStatus = newValue; - }); - widget.onSelect?.call(newValue); // Use null-aware operator - }, - items: widget.statuses - ?.map>((value) { + : (Lookup? newValue) { + // Nullable Lookup + setState(() { + _selectedStatus = newValue; + }); + widget.onSelect?.call(newValue); // Use null-aware operator + }, + items: widget.statuses?.map>((value) { return DropdownMenuItem( value: value, - child: Text(value.name ?? "", // Use null-aware operator + child: Text( + value.name ?? "", // Use null-aware operator style: Theme.of(context).textTheme.bodyLarge, ), ); - }) - .toList(), + }).toList(), ), ], ), @@ -130,4 +120,4 @@ class _SingleStatusMenuState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/views/widgets/total_working_time_detail_bottomsheet.dart b/lib/views/widgets/total_working_time_detail_bottomsheet.dart new file mode 100644 index 00000000..f89c68b9 --- /dev/null +++ b/lib/views/widgets/total_working_time_detail_bottomsheet.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +class TotalWorkingTimeDetailBottomSheet extends StatelessWidget { + final List activityMaintenanceTimers; + + const TotalWorkingTimeDetailBottomSheet({Key? key, this.activityMaintenanceTimers = const []}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: MediaQuery.of(context).size.height * 0.5, + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + 8.height, + Align( + alignment: AlignmentDirectional.centerStart, + child: Text( + "Total Working Time", + style: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w600, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + ), + ListView.separated( + itemCount: activityMaintenanceTimers.length, + separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), + padding: const EdgeInsets.only(top: 16, bottom: 16), + itemBuilder: (cxt, index) { + int totalWorkingHours = DateTime.parse(activityMaintenanceTimers[index].endTime!).difference(DateTime.parse(activityMaintenanceTimers[index].startTime!)).inSeconds; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + text: "From: ", + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), + children: [TextSpan(text: activityMaintenanceTimers[index].startTime!.toServiceRequestDetailsFormat, style: Theme.of(context).textTheme.bodySmall)])), + 4.height, + RichText( + text: TextSpan( + text: "To: ", + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), + children: [TextSpan(text: activityMaintenanceTimers[index].endTime!.toServiceRequestDetailsFormat, style: Theme.of(context).textTheme.bodySmall)])), + 4.height, + RichText( + text: TextSpan( + text: "Duration: ", + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500), + children: [TextSpan(text: " ${ServiceRequestUtils.formatTimerDuration(totalWorkingHours.round())}", style: Theme.of(context).textTheme.bodySmall)])), + ], + ); + }).expanded, + ], + ), + ); + } +} + +class TimerModel { + int? id; + String? startTime; + String? endTime; + dynamic workingHours; + + TimerModel({this.id, this.startTime, this.endTime, this.workingHours}); + + TimerModel.fromJson(Map json) { + id = json['id']; + startTime = json['startTime']; + endTime = json['endTime']; + workingHours = json['workingHours']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['startTime'] = startTime; + data['endTime'] = endTime; + data['workingHours'] = workingHours; + return data; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 455d5d30..47ace654 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.3.3+22 +version: 1.3.5+24 environment: sdk: ">=3.5.0 <4.0.0"