Merge branch 'refs/heads/design_3.0_TM_Module' into design_3.0_task_module_new_merge

# Conflicts:
#	lib/modules/cm_module/service_request_detail_provider.dart
#	lib/new_views/pages/land_page/land_page.dart
#	lib/views/pages/device_transfer/update_device_transfer.dart
design_3.0_TM_Module_snagsFix
Sikander Saleem 3 months ago
commit ca1ff5892e

@ -19,6 +19,7 @@ class ApiManager {
Map<String, String> get _headers => { Map<String, String> get _headers => {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first,
if (user != null) 'Authorization': 'Bearer ${user!.token}', if (user != null) 'Authorization': 'Bearer ${user!.token}',
if (assetGroup != null) 'AssetGroup': assetGroup!.id.toString(), if (assetGroup != null) 'AssetGroup': assetGroup!.id.toString(),
}; };
@ -156,7 +157,6 @@ class ApiManager {
headers.addAll(_headers); headers.addAll(_headers);
Uri url0 = Uri.parse(url); Uri url0 = Uri.parse(url);
print(url0);
// print(headers); // print(headers);
// log(json.encode(body)); // log(json.encode(body));
var request = http.Request('PUT', url0); var request = http.Request('PUT', url0);

@ -1,7 +1,7 @@
class URLs { class URLs {
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://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV 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 getServiceReportReasonsNew => "$_baseUrl/Lookups/GetLookupReasonNew?lookupEnum=505";
static get getWoFrames => "$_baseUrl/Lookups/GetLookup?lookupEnum=1254";
static get getServiceReportRetirementType => "$_baseUrl/Lookups/GetLookup?lookupEnum=415"; static get getServiceReportRetirementType => "$_baseUrl/Lookups/GetLookup?lookupEnum=415";
static get getVisitReminderTimeValue => "$_baseUrl/Lookups/GetLookup?lookupEnum=1211"; static get getVisitReminderTimeValue => "$_baseUrl/Lookups/GetLookup?lookupEnum=1211";

@ -204,7 +204,6 @@ class FirebaseNotificationManger {
}); });
FirebaseMessaging.onMessage.listen((RemoteMessage message) { FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('notification i got is ${message.toMap()}');
if (Platform.isAndroid) { if (Platform.isAndroid) {
if (message.data["notificationType"] != 'NurseConfirmArrive') { if (message.data["notificationType"] != 'NurseConfirmArrive') {
NotificationManger.showNotification( NotificationManger.showNotification(

@ -31,7 +31,6 @@ class NotificationManger {
} else if (Platform.isAndroid) { } else if (Platform.isAndroid) {
final AndroidFlutterLocalNotificationsPlugin? androidImplementation = localNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>(); final AndroidFlutterLocalNotificationsPlugin? androidImplementation = localNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
final bool granted = await androidImplementation?.requestNotificationsPermission() ?? false; final bool granted = await androidImplementation?.requestNotificationsPermission() ?? false;
print('permission value is $granted');
if (!granted) { if (!granted) {
if (kDebugMode) { if (kDebugMode) {
print("-------------------- Permission Granted ------------------------"); print("-------------------- Permission Granted ------------------------");
@ -43,7 +42,8 @@ class NotificationManger {
await localNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationPressed); await localNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationPressed);
} // push new notification } // push new notification
static const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
static const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
'com.hmg.atoms', 'com.hmg.atoms',
'ATOMS', 'ATOMS',
channelDescription: 'Push notification service for ATOMS', channelDescription: 'Push notification service for ATOMS',
@ -76,7 +76,6 @@ class NotificationManger {
// groupKey: 'com.hmg.atoms', // groupKey: 'com.hmg.atoms',
// ); // );
// const DarwinNotificationDetails iosNotificationDetails = DarwinNotificationDetails( // const DarwinNotificationDetails iosNotificationDetails = DarwinNotificationDetails(
// categoryIdentifier: "atoms", // categoryIdentifier: "atoms",
// ); // );
@ -86,16 +85,9 @@ class NotificationManger {
await localNotificationsPlugin.show(hashcode, title, subtext, platformChannel, payload: payload); await localNotificationsPlugin.show(hashcode, title, subtext, platformChannel, payload: payload);
} }
static Future scheduleNotification( static Future scheduleNotification({int? id, String? title, String? body, String? payLoad, required DateTime scheduledNotificationDateTime}) async {
{int?id,
String? title,
String? body,
String? payLoad,
required DateTime scheduledNotificationDateTime}) async {
print('time i got is ${scheduledNotificationDateTime}');
return localNotificationsPlugin.zonedSchedule( return localNotificationsPlugin.zonedSchedule(
id??0, id ?? 0,
title, title,
body, body,
// tz.TZDateTime.now(tz.local).add(const Duration(seconds: 5)), // tz.TZDateTime.now(tz.local).add(const Duration(seconds: 5)),
@ -103,13 +95,12 @@ class NotificationManger {
scheduledNotificationDateTime, scheduledNotificationDateTime,
tz.local, tz.local,
), ),
const NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails, macOS: iosNotificationDetails), const NotificationDetails(android: androidNotificationDetails, iOS: iosNotificationDetails, macOS: iosNotificationDetails),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation: uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime);
UILocalNotificationDateInterpretation.absoluteTime);
} }
static Future<void> cancelNotificationById(int notificationId) async { static Future<void> cancelNotificationById(int notificationId) async {
await localNotificationsPlugin.cancel(notificationId); await localNotificationsPlugin.cancel(notificationId);
print("Notification with ID $notificationId has been canceled.");
} }
} }

@ -143,7 +143,7 @@ class AllRequestsProvider extends ChangeNotifier {
} }
final type = typeTransaction == null final type = typeTransaction == null
? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false) ? 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 : search!.typeTransaction
: [typeTransaction]; : [typeTransaction];
List<int> status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!; List<int> 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<int> updateRecurrentWo({required int status}) async { Future<bool> updateRecurrentWo({required int status}) async {
isLoading = true; isLoading = true;
Response response; Response response;
try { try {
@ -230,12 +230,15 @@ class AllRequestsProvider extends ChangeNotifier {
stateCode = response.statusCode; stateCode = response.statusCode;
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
return response.statusCode; if (stateCode == 200) {
return true;
}
return false;
} catch (error) { } catch (error) {
isLoading = false; isLoading = false;
stateCode = -1; stateCode = -1;
notifyListeners(); notifyListeners();
return -1; return false;
} }
} }

@ -47,15 +47,12 @@ class GasRefillProvider extends ChangeNotifier {
// failed _loading = false // failed _loading = false
bool isLoading = false; bool isLoading = false;
Future<GasRefillModel?> getGasRefillObjectById(num id) async { Future<GasRefillModel?> getGasRefillObjectById(num id) async {
try { try {
Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gasRefillId=$id"); Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gasRefillId=$id");
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
return GasRefillModel.fromJson(json.decode(response.body)["data"]);
return GasRefillModel.fromJson(json.decode(response.body)["data"]);
} else { } else {
return null; return null;
} }
@ -64,7 +61,6 @@ class GasRefillProvider extends ChangeNotifier {
} }
} }
/// return -2 if request in progress /// return -2 if request in progress
/// return -1 if error happen when sending request /// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
@ -139,6 +135,7 @@ class GasRefillProvider extends ChangeNotifier {
print(error); print(error);
} }
} }
Future<void> updateGasRefillRequestByNurse({ Future<void> updateGasRefillRequestByNurse({
required BuildContext context, required BuildContext context,
required GasRefillModel model, required GasRefillModel model,
@ -167,7 +164,7 @@ class GasRefillProvider extends ChangeNotifier {
} }
} }
Future<int> updateGasRefill({required int status, required GasRefillModel model}) async { Future<bool> updateGasRefill({required int status, required GasRefillModel model}) async {
isLoading = true; isLoading = true;
Response response; Response response;
try { try {
@ -175,12 +172,15 @@ class GasRefillProvider extends ChangeNotifier {
stateCode = response.statusCode; stateCode = response.statusCode;
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
return response.statusCode; if (stateCode == 200) {
return true;
}
return false;
} catch (error) { } catch (error) {
isLoading = false; isLoading = false;
stateCode = -1; stateCode = -1;
notifyListeners(); notifyListeners();
return -1; return false;
} }
} }

@ -52,7 +52,6 @@ class NotificationsProvider extends ChangeNotifier {
response = await ApiManager.instance.post(URLs.getSystemNotifications, body: body); response = await ApiManager.instance.post(URLs.getSystemNotifications, body: body);
stateCode = response.statusCode; stateCode = response.statusCode;
print('notifaction response is ${response.body}');
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // client's request was successfully received
List requestsListJson = json.decode(response.body)["data"]; List requestsListJson = json.decode(response.body)["data"];

@ -182,21 +182,23 @@ class PpmProvider extends ChangeNotifier {
} }
} }
Future<int> updateVisitByEngineer({required int status}) async { Future<bool> updateVisitByEngineer({required int status}) async {
isLoading = true; isLoading = true;
Response response; Response response;
try { try {
response = await ApiManager.instance.post(URLs.updateVisitByEngineer, body: planPreventiveVisit!.toJson(status: status)); response = await ApiManager.instance.post(URLs.updateVisitByEngineer, body: planPreventiveVisit!.toJson(status: status));
print('response i got is ${response.body}');
stateCode = response.statusCode; stateCode = response.statusCode;
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
return response.statusCode; if (stateCode == 200) {
return true;
}
return false;
} catch (error) { } catch (error) {
isLoading = false; isLoading = false;
stateCode = -1; stateCode = -1;
notifyListeners(); notifyListeners();
return -1; return false;
} }
} }

@ -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/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.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/pending_service_request_model.dart';
import 'package:test_sa/models/service_request/service_report.dart'; import 'package:test_sa/models/service_request/service_report.dart';
import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/models/service_request/service_request.dart';
@ -268,7 +267,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
Future<PendingAssetServiceRequest?> checkAssetPendingRequest(int assetId) async { Future<PendingAssetServiceRequest?> checkAssetPendingRequest(int assetId) async {
Response response; Response response;
try { try {
response = await ApiManager.instance.post(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId",body: {}); response = await ApiManager.instance.post(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId", body: {});
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {} if (response.statusCode >= 200 && response.statusCode < 300) {}
return PendingAssetServiceRequest.fromJson(json.decode(response.body)["data"]); return PendingAssetServiceRequest.fromJson(json.decode(response.body)["data"]);
@ -423,7 +422,6 @@ class ServiceRequestsProvider extends ChangeNotifier {
Future<CallRequest?> getCallRequestForWorkOrder({required String callId}) async { Future<CallRequest?> getCallRequestForWorkOrder({required String callId}) async {
Response response; Response response;
print('call id i got is ${callId}');
try { try {
response = await ApiManager.instance.get(URLs.getCallRequestForWorkOrder + "?callId=$callId"); response = await ApiManager.instance.get(URLs.getCallRequestForWorkOrder + "?callId=$callId");
stateCode = response.statusCode; stateCode = response.statusCode;

@ -22,10 +22,7 @@ extension BuildContextExtension on BuildContext {
void showConfirmDialog(String message, {String? title, VoidCallback? onTap}) => showDialog( void showConfirmDialog(String message, {String? title, VoidCallback? onTap}) => showDialog(
context: this, context: this,
builder: (BuildContext cxt) => ConfirmDialog( builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title),
message: message,
onTap: onTap,
),
); );
Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title}) => showModalBottomSheet( Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title}) => showModalBottomSheet(

@ -49,7 +49,19 @@ class Utils {
return null; 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) { static int stringToHex(String colorCode) {
try { try {
return int.parse(colorCode.replaceAll("#", "0xff")); return int.parse(colorCode.replaceAll("#", "0xff"));

@ -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/service_type_provider.dart';
import 'package:test_sa/providers/work_order/supplier_engineer_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/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/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_filter_screen.dart';
import 'package:test_sa/views/pages/device_transfer/device_search_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 /// Loan availability not required
ChangeNotifierProvider(create: (_) => LoanAvailabilityProvider()), ChangeNotifierProvider(create: (_) => LoanAvailabilityProvider()),
ChangeNotifierProvider(create: (_) => ReasonProvider()), ChangeNotifierProvider(create: (_) => ReasonProvider()),
ChangeNotifierProvider(create: (_) => WoFrameProvider()),
ChangeNotifierProvider(create: (_) => RejectReasonProvider()), ChangeNotifierProvider(create: (_) => RejectReasonProvider()),
ChangeNotifierProvider(create: (_) => LastSituationProvider()), ChangeNotifierProvider(create: (_) => LastSituationProvider()),
ChangeNotifierProvider(create: (_) => FaultDescriptionProvider()), ChangeNotifierProvider(create: (_) => FaultDescriptionProvider()),

@ -24,7 +24,7 @@ class AssetByIdModel {
int? testsDay; int? testsDay;
num? purchasingPrice; num? purchasingPrice;
String? nbv; String? nbv;
String? currency; Lookup? currency;
String? poDate; String? poDate;
String? poNo; String? poNo;
String? invoiceNumber; String? invoiceNumber;
@ -153,7 +153,7 @@ class AssetByIdModel {
testsDay = json['testsDay']; testsDay = json['testsDay'];
purchasingPrice = json['purchasingPrice']; purchasingPrice = json['purchasingPrice'];
nbv = json['nbv']; nbv = json['nbv'];
currency = json['currency']; currency = json['currency'] != null ? Lookup.fromJson(json['currency']) : null;
poDate = json['poDate']; poDate = json['poDate'];
poNo = json['poNo']; poNo = json['poNo'];
invoiceNumber = json['invoiceNumber']; invoiceNumber = json['invoiceNumber'];
@ -247,7 +247,9 @@ class AssetByIdModel {
data['testsDay'] = testsDay; data['testsDay'] = testsDay;
data['purchasingPrice'] = purchasingPrice; data['purchasingPrice'] = purchasingPrice;
data['nbv'] = nbv; data['nbv'] = nbv;
data['currency'] = currency; if (currency != null) {
data['currency'] = currency?.toJson();
}
data['poDate'] = poDate; data['poDate'] = poDate;
data['poNo'] = poNo; data['poNo'] = poNo;
data['invoiceNumber'] = invoiceNumber; data['invoiceNumber'] = invoiceNumber;

@ -1,6 +1,7 @@
import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/lookup.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/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/ppm/ppm.dart';
import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/models/timer_model.dart';
@ -89,8 +90,10 @@ class DeviceTransfer {
this.timerModelList, this.timerModelList,
this.assistantEmployees, this.assistantEmployees,
this.modelAssistantEmployees, this.modelAssistantEmployees,
this.assistantEmployList,
this.assetTransferAssistantEmployeesReceiver, this.assetTransferAssistantEmployeesReceiver,
this.assetTransferAssistantEmployeesSender, this.assetTransferAssistantEmployeesSender,
this.statusValue, this.statusValue,
}); });
@ -305,10 +308,11 @@ class DeviceTransfer {
List<VisitTimers>? assetTransferEngineerTimers; List<VisitTimers>? assetTransferEngineerTimers;
List<TimerModel>? timerModelList = []; List<TimerModel>? timerModelList = [];
List<AssistantEmployees>? assistantEmployees; List<AssistantEmployees>? assistantEmployees;
List<AssetTransferAssistantEmployees>? assetTransferAssistantEmployeesSender; List<AssetTransferAssistantEmployees>? assetTransferAssistantEmployeesSender=[];
List<AssetTransferAssistantEmployees>? assetTransferAssistantEmployeesReceiver; List<AssetTransferAssistantEmployees>? assetTransferAssistantEmployeesReceiver=[];
List<AssetTransferContactPerson>? assetTransferContactPersons; List<AssetTransferContactPerson>? assetTransferContactPersons;
AssetTransferAssistantEmployees? modelAssistantEmployees; AssetTransferAssistantEmployees? modelAssistantEmployees;
List<AssetTransferAssistantEmployees>? assistantEmployList=[];
TimerModel? tbsTimer = TimerModel(); TimerModel? tbsTimer = TimerModel();
TimerModel? deviceTimePicker; TimerModel? deviceTimePicker;
@ -384,6 +388,7 @@ class DeviceTransfer {
String? destDepartmentName, String? destDepartmentName,
List<VisitTimers>? senderVisitTimers, List<VisitTimers>? senderVisitTimers,
List<VisitTimers>? receiverVisitTimers, List<VisitTimers>? receiverVisitTimers,
List<AssetTransferAssistantEmployees>? assistantEmployList,
TimerModel? tbsTimer, TimerModel? tbsTimer,
TimerModel? deviceTimePicker}) => TimerModel? deviceTimePicker}) =>
DeviceTransfer( DeviceTransfer(
@ -457,6 +462,7 @@ class DeviceTransfer {
senderVisitTimers: senderVisitTimers ?? this.senderVisitTimers, senderVisitTimers: senderVisitTimers ?? this.senderVisitTimers,
receiverVisitTimers: receiverVisitTimers ?? this.receiverVisitTimers, receiverVisitTimers: receiverVisitTimers ?? this.receiverVisitTimers,
tbsTimer: tbsTimer ?? this.tbsTimer, tbsTimer: tbsTimer ?? this.tbsTimer,
assistantEmployList: assistantEmployList??this.assistantEmployList,
deviceTimePicker: deviceTimePicker ?? this.deviceTimePicker, deviceTimePicker: deviceTimePicker ?? this.deviceTimePicker,
manufacturerName: manufacturerName ?? this.manufacturerName); manufacturerName: manufacturerName ?? this.manufacturerName);
@ -573,13 +579,18 @@ class DeviceTransfer {
if (assetTransferEngineerTimers != null) { if (assetTransferEngineerTimers != null) {
map['assetTransferEngineerTimers'] = assetTransferEngineerTimers!.map((v) => v.toJson()).toList(); map['assetTransferEngineerTimers'] = assetTransferEngineerTimers!.map((v) => v.toJson()).toList();
} }
if (modelAssistantEmployees != null) { if (assistantEmployList != null && assistantEmployList!.isNotEmpty) {
if (modelAssistantEmployees!.employeeId != null) { map['assetTransferAssistantEmployees'] = assistantEmployList;
map['assetTransferAssistantEmployees'] = [modelAssistantEmployees!.toJson()]; } else {
} else { map['assetTransferAssistantEmployees'] = [];
map['assetTransferAssistantEmployees'] = [];
}
} }
// if (modelAssistantEmployees != null) {
// if (modelAssistantEmployees!.employeeId != null) {
// map['assetTransferAssistantEmployees'] = [modelAssistantEmployees!.toJson()];
// } else {
// map['assetTransferAssistantEmployees'] = [];
// }
// }
return map; return map;
} }

@ -35,6 +35,7 @@ class ActivityMaintenanceHelperModel {
List<ActivityMaintenanceTimers>? activityMaintenanceTimers = []; List<ActivityMaintenanceTimers>? activityMaintenanceTimers = [];
TimerModel? activityMaintenanceTimerModel = TimerModel(); TimerModel? activityMaintenanceTimerModel = TimerModel();
TimerModel? activityTimePicker; TimerModel? activityTimePicker;
List<AssistantEmployeesModel>? assistantEmployList=[];
List<TimerModel>? timerModelList = []; List<TimerModel>? timerModelList = [];
ActivityMaintenanceHelperModel( ActivityMaintenanceHelperModel(
@ -63,6 +64,7 @@ class ActivityMaintenanceHelperModel {
this.assignedEmployee, this.assignedEmployee,
this.activityMaintenanceTimers, this.activityMaintenanceTimers,
this.timerModelList, this.timerModelList,
this.assistantEmployList,
this.modelAssistantEmployees}); this.modelAssistantEmployees});
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -85,11 +87,17 @@ class ActivityMaintenanceHelperModel {
data['supplierWorkingHour'] = supplierWorkingHour; data['supplierWorkingHour'] = supplierWorkingHour;
//TODO fix this properly... //TODO fix this properly...
data['activityMaintenanceTimers'] = activityMaintenanceTimers; data['activityMaintenanceTimers'] = activityMaintenanceTimers;
if (assistantEmployees != null && assistantEmployees!.isNotEmpty) { if (assistantEmployList != null && assistantEmployList!.isNotEmpty) {
data['assistantEmployees'] = [modelAssistantEmployees?.toJson()]; data['assistantEmployees'] = assistantEmployList;
} else { } else {
data['assistantEmployees'] = []; 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; return data;
} }
} }

@ -82,16 +82,19 @@ class EngineerUpdateWorkOrderHelperModel {
num? loanAssetId; num? loanAssetId;
WorkOrderAsset? loanAsset; WorkOrderAsset? loanAsset;
Lookup? failureReason; Lookup? failureReason;
Lookup? cmFrameId;
FaultDescription? faultDescription; FaultDescription? faultDescription;
String? solution; String? solution;
String? callResponse; String? callResponse;
String? descriptionOfFinding; String? descriptionOfFinding;
String? actionTaken; String? actionTaken;
String? edd;
EngineerUpdateWorkOrderHelperModel({ EngineerUpdateWorkOrderHelperModel({
this.workOrderId, this.workOrderId,
this.equipmentStatus, this.equipmentStatus,
this.failureReason, this.failureReason,
this.cmFrameId,
this.faultDescription, this.faultDescription,
this.loanAvailability, this.loanAvailability,
this.loanAssetId, this.loanAssetId,
@ -99,6 +102,7 @@ class EngineerUpdateWorkOrderHelperModel {
this.serviceType, this.serviceType,
this.solution, this.solution,
this.returnToService, this.returnToService,
this.edd,
this.callResponse, this.callResponse,
this.descriptionOfFinding, this.descriptionOfFinding,
this.actionTaken, this.actionTaken,
@ -109,9 +113,11 @@ class EngineerUpdateWorkOrderHelperModel {
data['workOrderId'] = workOrderId; data['workOrderId'] = workOrderId;
data['equipmentStatusId'] = equipmentStatus?.id; data['equipmentStatusId'] = equipmentStatus?.id;
data['returnToService'] = returnToService; data['returnToService'] = returnToService;
data['edd'] = edd;
data['loanAvailabilityId'] = loanAvailability?.id; data['loanAvailabilityId'] = loanAvailability?.id;
data['loanAssetId'] = loanAssetId; data['loanAssetId'] = loanAssetId;
data['failureReasonId'] = failureReason?.id; data['failureReasonId'] = failureReason?.id;
data['cmFrameId'] = cmFrameId?.id;
data['faultDescriptionId'] = faultDescription?.id; data['faultDescriptionId'] = faultDescription?.id;
data['callResponse'] = callResponse; data['callResponse'] = callResponse;
data['descriptionOfFinding'] = descriptionOfFinding; data['descriptionOfFinding'] = descriptionOfFinding;

@ -152,7 +152,6 @@ class GasRefillModel {
floor = json['floor'] != null ? Floor.fromJson(json['floor']) : null; floor = json['floor'] != null ? Floor.fromJson(json['floor']) : null;
department = json['department'] != null ? Department.fromJson(json['department']) : null; department = json['department'] != null ? Department.fromJson(json['department']) : null;
mapSite = json['site'] != null ? MappedSite.fromJson(json['site']) : 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()); mappedBuilding = mapSite?.buildings?.firstWhere((element) => element.identifier == building?.identifier, orElse: () => MappedBuilding());
mappedFloor = mappedBuilding?.floors?.firstWhere((element) => element.identifier == floor?.identifier, orElse: () => MappedFloor()); mappedFloor = mappedBuilding?.floors?.firstWhere((element) => element.identifier == floor?.identifier, orElse: () => MappedFloor());
mappedDepartment = mappedFloor?.departments?.firstWhere((element) => element.identifier == department?.identifier, orElse: () => MappedDepartment()); mappedDepartment = mappedFloor?.departments?.firstWhere((element) => element.identifier == department?.identifier, orElse: () => MappedDepartment());

@ -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/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/helper_data_models/workorder/work_order_helper_models.dart';
import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/new_models/assistant_employee.dart';
class WorkOrderDetail { class WorkOrderDetail {
WorkOrderDetail({ WorkOrderDetail({
@ -94,6 +95,7 @@ class WorkOrderData {
this.closedDate, this.closedDate,
this.since, this.since,
this.cmFrame, this.cmFrame,
this.edd,
this.rejectComment, this.rejectComment,
this.callResponse, this.callResponse,
this.descriptionOfFinding, this.descriptionOfFinding,
@ -148,6 +150,7 @@ class WorkOrderData {
Lookup? failureReasone; Lookup? failureReasone;
FaultDescription? faultDescription; FaultDescription? faultDescription;
Lookup? solution; Lookup? solution;
String? edd;
Lookup? cmFrame; Lookup? cmFrame;
//cmComments //cmComments
@ -222,6 +225,7 @@ class WorkOrderData {
problemDescription: json["problemDescription"] == null ? null : Lookup.fromJson(json["problemDescription"]), problemDescription: json["problemDescription"] == null ? null : Lookup.fromJson(json["problemDescription"]),
comments: json["comments"], comments: json["comments"],
voiceNote: json["voiceNote"], voiceNote: json["voiceNote"],
edd: json["edd"],
workOrderAttachments: json["workOrderAttachments"] == null ? [] : List.from(json['workOrderAttachments']).map((e) => WorkOrderAttachments.fromJson(e)).toList(), workOrderAttachments: json["workOrderAttachments"] == null ? [] : List.from(json['workOrderAttachments']).map((e) => WorkOrderAttachments.fromJson(e)).toList(),
returnToService: json["returnToService"], returnToService: json["returnToService"],
serviceType: json["serviceType"] == null ? null : Lookup.fromJson(json["serviceType"]), serviceType: json["serviceType"] == null ? null : Lookup.fromJson(json["serviceType"]),
@ -268,10 +272,12 @@ class WorkOrderData {
"typeofRequest": typeofRequest?.toJson(), "typeofRequest": typeofRequest?.toJson(),
"loanAvailablity": loanAvailablity?.toJson(), "loanAvailablity": loanAvailablity?.toJson(),
"assetLoan": assetLoan?.toJson(), "assetLoan": assetLoan?.toJson(),
"cmFrame": cmFrame?.toJson(),
"safety": safety?.toJson(), "safety": safety?.toJson(),
"problemDescription": problemDescription?.toJson(), "problemDescription": problemDescription?.toJson(),
"comments": comments, "comments": comments,
"voiceNote": voiceNote, "voiceNote": voiceNote,
"edd": edd,
"workOrderAttachments": workOrderAttachments.map((e) => e.toJson()).toList(), "workOrderAttachments": workOrderAttachments.map((e) => e.toJson()).toList(),
"returnToService": returnToService, "returnToService": returnToService,
"serviceType": serviceType?.toJson(), "serviceType": serviceType?.toJson(),
@ -686,7 +692,7 @@ class ActivityMaintenance {
String? supplierEndTime; String? supplierEndTime;
double? supplierWorkingHours; double? supplierWorkingHours;
String? activityType; String? activityType;
List<ActivityMaintenanceAssistantEmployees>? assistantEmployees; List<AssistantEmployeesModel>? assistantEmployees;
List<ActivityMaintenanceTimers>? activityMaintenanceTimers; List<ActivityMaintenanceTimers>? activityMaintenanceTimers;
ActivityMaintenance( ActivityMaintenance(
@ -729,9 +735,9 @@ class ActivityMaintenance {
supplierEndTime = json['supplierEndTime']; supplierEndTime = json['supplierEndTime'];
supplierWorkingHours = json['supplierWorkingHours']; supplierWorkingHours = json['supplierWorkingHours'];
if (json['assistantEmployees'] != null) { if (json['assistantEmployees'] != null) {
assistantEmployees = <ActivityMaintenanceAssistantEmployees>[]; assistantEmployees = <AssistantEmployeesModel>[];
json['assistantEmployees'].forEach((v) { json['assistantEmployees'].forEach((v) {
assistantEmployees!.add(ActivityMaintenanceAssistantEmployees.fromJson(v)); assistantEmployees!.add(AssistantEmployeesModel.fromJson(v));
}); });
} }
if (json['activityMaintenanceTimers'] != null) { if (json['activityMaintenanceTimers'] != null) {
@ -822,15 +828,29 @@ class ActivityMaintenanceAssistantEmployees {
double? workingHours; double? workingHours;
String? technicalComment; String? technicalComment;
AssignedEmployee? user; 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<String, dynamic> json) { ActivityMaintenanceAssistantEmployees.fromJson(Map<String, dynamic> json) {
Map<String,dynamic> assistEmpData={};
startDate = json['startDate'] != null ? DateTime.parse(json['startDate']) : null; startDate = json['startDate'] != null ? DateTime.parse(json['startDate']) : null;
endDate = json['endDate'] != null ? DateTime.parse(json['endDate']) : null; endDate = json['endDate'] != null ? DateTime.parse(json['endDate']) : null;
workingHours = json['workingHours']; workingHours = json['workingHours'];
technicalComment = json['technicalComment']; technicalComment = json['technicalComment'];
user = json['user'] != null ? AssignedEmployee.fromJson(json['user']) : null; 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<String, dynamic> toJson() { Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> toJson() {
// final Map<String, dynamic> data = <String, dynamic>{};
// 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 { class ActivityMaintenanceTimers {
int? id; int? id;
String? startTime; String? startTime;
@ -870,3 +922,48 @@ class ActivityMaintenanceTimers {
return data; 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<String, dynamic> json) {
Map<String,dynamic> 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<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['startDate'] = startDate?.toIso8601String();
data['endDate'] = endDate?.toIso8601String();
data['workingHours'] = workingHours;
data['technicalComment'] = technicalComment;
if (user != null) {
data['userId'] = user?.userId;
}
return data;
}
}

@ -102,7 +102,6 @@ class ServiceRequest {
List list = parsedJson["attachmentsCallRequest"]; List list = parsedJson["attachmentsCallRequest"];
images = list.map((e) => URLs.getFileUrl(e["name"]!) as String).toList(); images = list.map((e) => URLs.getFileUrl(e["name"]!) as String).toList();
} }
// print(parsedJson["requestedDate"]??"");
return ServiceRequest( return ServiceRequest(
id: parsedJson["id"].toString(), id: parsedJson["id"].toString(),
@ -180,7 +179,6 @@ class ServiceRequest {
} }
return true; return true;
} }
} }
class CallCreatedBy { class CallCreatedBy {

@ -611,40 +611,47 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
} }
//engineerUpdateWorkOrder...... //engineerUpdateWorkOrder......
Future<void> engineerUpdateWorkOrder() async { Future<bool> engineerUpdateWorkOrder() async {
isLoading = true;
Response response;
try { try {
isLoading = true; response = await ApiManager.instance.post(URLs.engineerUpdateWorkOrderUrl, body: engineerUpdateWorkOrderHelperModel!.toJson());
notifyListeners();
final response = await ApiManager.instance.post(URLs.engineerUpdateWorkOrderUrl, body: engineerUpdateWorkOrderHelperModel!.toJson());
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body));
}
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
} catch (e) { if (stateCode == 200) {
log("engineer update workorder [error] : $e"); currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body));
notifyListeners();
return true;
}
return false;
} catch (error) {
isLoading = false; isLoading = false;
stateCode = -1;
notifyListeners(); notifyListeners();
return false;
} }
} }
//engineerUpdateWorkOrder...... Future<bool> engineerUpdateCost() async {
Future<void> engineerUpdateCost() async { isLoading = true;
Response response;
try { try {
isLoading = true; response = await ApiManager.instance.post(URLs.engineerUpdateCost, body: workOrderCostModel!.toJson());
notifyListeners();
final response = await ApiManager.instance.post(URLs.engineerUpdateCost, body: workOrderCostModel!.toJson());
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body));
}
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
} catch (e) { if (stateCode == 200) {
log("engineer update workorder [error] : $e"); currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body));
notifyListeners();
return true;
}
return false;
} catch (error) {
isLoading = false; isLoading = false;
stateCode = -1;
notifyListeners(); notifyListeners();
return false;
} }
} }
@ -737,36 +744,43 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
} }
} }
Future<int> updateActivitySparePart() async { Future<bool> updateActivitySparePart() async {
isLoading = true;
Response response;
try { 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; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false;
// request.engineerName = employee.name; notifyListeners();
if (stateCode == 200) {
return true;
} }
return response.statusCode; return false;
} catch (error) { } catch (error) {
return -1; isLoading = false;
stateCode = -1;
notifyListeners();
return false;
} }
} }
Future<int> updateActivityMaintenance() async { Future<bool> updateActivityMaintenance() async {
isLoading = true; isLoading = true;
notifyListeners(); Response response;
try { 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; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// request.engineerName = employee.name;
}
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
return response.statusCode; if (stateCode == 200) {
return true;
}
return false;
} catch (error) { } catch (error) {
isLoading = false; isLoading = false;
stateCode = -1;
notifyListeners(); notifyListeners();
return -1; return false;
} }
} }
@ -798,7 +812,6 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
body: {}, body: {},
); );
print('response i got is ${response.body}');
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
@ -861,41 +874,49 @@ class ServiceRequestDetailProvider extends ChangeNotifier {
} }
} }
Future<int> createActivitySparePart() async { Future<bool> createActivitySparePart() async {
isLoading = true;
Response response;
try { 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; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false;
// currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body)); notifyListeners();
// // updateCurrentWorkOrder(currentWorkOrder); if (stateCode == 200) {
// notifyListeners(); return true;
} }
return response.statusCode; return false;
} catch (error) { } catch (error) {
return -1; isLoading = false;
stateCode = -1;
notifyListeners();
return false;
} }
} }
Future<int> createActivityMaintenanceRequest() async { Future<bool> createActivityMaintenanceRequest() async {
isLoading = true; isLoading = true;
notifyListeners(); Response response;
try { try {
final response = await ApiManager.instance.post( response = await ApiManager.instance.post(
URLs.createActivityMaintenanceUrl, URLs.createActivityMaintenanceUrl,
body: activityMaintenanceHelperModel!.toJson(), body: activityMaintenanceHelperModel!.toJson(),
); );
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// currentWorkOrder = await WorkOrderDetail.fromJson(json.decode(response.body));
// updateCurrentWorkOrder(currentWorkOrder);
}
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
return response.statusCode; if (stateCode == 200) {
return true;
}
return false;
} catch (error) { } catch (error) {
isLoading = false; isLoading = false;
stateCode = -1;
notifyListeners(); notifyListeners();
return -1; return false;
} }
} }

@ -40,7 +40,10 @@ class FooterActionButton {
required UserProvider userProvider, required UserProvider userProvider,
bool isEmpIsAssigned = false}) { bool isEmpIsAssigned = false}) {
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false); ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(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 (userProvider.user?.type == UsersTypes.engineer) {
if (workOrderNextStepStatus == WorkOrderNextStepEnum.assignToMe && isEmpIsAssigned) return const SizedBox(); if (workOrderNextStepStatus == WorkOrderNextStepEnum.assignToMe && isEmpIsAssigned) return const SizedBox();
switch (workOrderNextStepStatus) { switch (workOrderNextStepStatus) {
@ -130,7 +133,7 @@ class FooterActionButton {
maxWidth: true, maxWidth: true,
buttonColor: AppColor.green70, buttonColor: AppColor.green70,
onPressed: () async { onPressed: () async {
requestDetailProvider.engineerAcceptWorkOrder(id: requestDetailProvider.currentWorkOrder!.data!.requestId.toString()).whenComplete(() {}); requestDetailProvider.engineerAcceptWorkOrder(id: requestDetailProvider.currentWorkOrder!.data!.requestId.toString());
}, },
).expanded, ).expanded,
], ],

@ -311,19 +311,19 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
} }
void editMaintenanceRequest({required BuildContext context, required ServiceRequestDetailProvider requestDetailProvider, required Activities activity}) async { void editMaintenanceRequest({required BuildContext context, required ServiceRequestDetailProvider requestDetailProvider, required Activities activity}) async {
Map<String, dynamic> assistEmpData = {}; // Map<String, dynamic> assistEmpData = {};
try { try {
if (activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty) { // if (activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty) {
assistEmpData = { // assistEmpData = {
// 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId != null ? num.tryParse(activity.activityMaintenance!.assistantEmployees![0].user!.userId!) : null, // // 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId != null ? num.tryParse(activity.activityMaintenance!.assistantEmployees![0].user!.userId!) : null,
'id': null, // 'id': null,
'user': { // 'user': {
'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId, // 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId,
// 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId != null ? num.tryParse(activity.activityMaintenance!.assistantEmployees![0].user!.userId!) : null, // // 'id': activity.activityMaintenance?.assistantEmployees?[0].user?.userId != null ? num.tryParse(activity.activityMaintenance!.assistantEmployees![0].user!.userId!) : null,
'name': activity.activityMaintenance?.assistantEmployees?[0].user?.userName, // 'name': activity.activityMaintenance?.assistantEmployees?[0].user?.userName,
}, // },
}; // };
} // }
requestDetailProvider.activityMaintenanceHelperModel = ActivityMaintenanceHelperModel( requestDetailProvider.activityMaintenanceHelperModel = ActivityMaintenanceHelperModel(
id: activity.id, id: activity.id,
@ -337,10 +337,11 @@ class _ActivitiesListViewState extends State<ActivitiesListView> {
// lastSituation: activity.activityMaintenance?.lastSituation, // lastSituation: activity.activityMaintenance?.lastSituation,
assignedEmployee: activity.activityMaintenance?.assignedEmployee != null ? WorkOrderAssignedEmployee.fromJson(activity.activityMaintenance!.assignedEmployee!.toJson()) : null, assignedEmployee: activity.activityMaintenance?.assignedEmployee != null ? WorkOrderAssignedEmployee.fromJson(activity.activityMaintenance!.assignedEmployee!.toJson()) : null,
technicalComment: activity.activityMaintenance?.technicalComment, technicalComment: activity.activityMaintenance?.technicalComment,
assistantEmployees: assistantEmployList:activity.activityMaintenance!.assistantEmployees??[] ,
activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty ? [AssistantEmployees.fromJson(assistEmpData)] : [], // assistantEmployees:
modelAssistantEmployees: // activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty ? [AssistantEmployees.fromJson(assistEmpData)] : [],
activity.activityMaintenance?.assistantEmployees != null && activity.activityMaintenance!.assistantEmployees!.isNotEmpty ? activity.activityMaintenance!.assistantEmployees![0] : null, // 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, supplierStartTime: activity.activityMaintenance?.supplierStartTime != null ? DateTime.parse(activity.activityMaintenance!.supplierStartTime!) : null,
supplierEndTime: activity.activityMaintenance?.supplierEndTime != null ? DateTime.parse(activity.activityMaintenance!.supplierEndTime!) : null, supplierEndTime: activity.activityMaintenance?.supplierEndTime != null ? DateTime.parse(activity.activityMaintenance!.supplierEndTime!) : null,
supplierWorkingHour: activity.activityMaintenance?.supplierWorkingHours, supplierWorkingHour: activity.activityMaintenance?.supplierWorkingHours,

@ -37,7 +37,17 @@ class AssetDetailCard extends StatelessWidget {
textColor: AppColor.white10, textColor: AppColor.white10,
backgroundColor: AppColor.getEquipmentStatusColor(context, requestDetailProvider.engineerUpdateWorkOrderHelperModel!.equipmentStatus!.id ?? 0), 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( StatusLabel(
label: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.serviceType?.name, label: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.serviceType?.name,
id: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.serviceType?.id ?? 0, id: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.serviceType?.id ?? 0,
@ -64,6 +74,10 @@ class AssetDetailCard extends StatelessWidget {
'${context.translation.returnToService}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService?.toAssetDetailsFormat ?? '-'}', '${context.translation.returnToService}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService?.toAssetDetailsFormat ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), 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( Text(
'${context.translation.loanAvailability}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability?.name ?? '-'}', '${context.translation.loanAvailability}: ${requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability?.name ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),

@ -355,8 +355,10 @@ class _ServiceRequestDetailViewState extends State<ServiceRequestDetailView> {
], ],
] else ...[ ] else ...[
8.height, 8.height,
const Divider().defaultStyle(context), if (_attachments.isNotEmpty) ...[
FilesList(images: _attachments.map((toElement) => URLs.getFileUrl(toElement.name!)!).toList()), const Divider().defaultStyle(context),
FilesList(images: _attachments.map((toElement) => URLs.getFileUrl(toElement.name!)!).toList()),
],
//handle nurse case.. //handle nurse case..
], ],
@ -580,6 +582,8 @@ class _ServiceRequestDetailViewState extends State<ServiceRequestDetailView> {
serviceType: currentWorkOrderData.serviceType, serviceType: currentWorkOrderData.serviceType,
descriptionOfFinding: currentWorkOrderData.descriptionOfFinding, descriptionOfFinding: currentWorkOrderData.descriptionOfFinding,
actionTaken: currentWorkOrderData.actionTaken, actionTaken: currentWorkOrderData.actionTaken,
edd: currentWorkOrderData.edd,
cmFrameId: currentWorkOrderData.cmFrame,
); );
return const AssetDetailCard(); return const AssetDetailCard();
} else { } else {

@ -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/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/fault_description_provider.dart';
import 'package:test_sa/providers/work_order/reason_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/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/equipment/pick_asset.dart'; import 'package:test_sa/views/widgets/equipment/pick_asset.dart';
@ -77,6 +78,8 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
callResponse: currentWorkOrderData.callResponse, callResponse: currentWorkOrderData.callResponse,
descriptionOfFinding: currentWorkOrderData.descriptionOfFinding, descriptionOfFinding: currentWorkOrderData.descriptionOfFinding,
actionTaken: currentWorkOrderData.actionTaken, actionTaken: currentWorkOrderData.actionTaken,
edd: currentWorkOrderData.edd,
cmFrameId: currentWorkOrderData.cmFrame,
); );
if (currentWorkOrderData.assetLoan != null) { if (currentWorkOrderData.assetLoan != null) {
loanAvailabilityAsset = Asset( loanAvailabilityAsset = Asset(
@ -101,6 +104,7 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
_loanAvailabilityProvider!.reset(); _loanAvailabilityProvider!.reset();
_equipmentStatusProvider = Provider.of<EquipmentStatusProvider>(context, listen: false); _equipmentStatusProvider = Provider.of<EquipmentStatusProvider>(context, listen: false);
_equipmentStatusProvider!.reset(); _equipmentStatusProvider!.reset();
Provider.of<WoFrameProvider>(context, listen: false).reset();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_equipmentStatusProvider!.getData(); _equipmentStatusProvider!.getData();
}); });
@ -129,7 +133,7 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
hideShadow: true, hideShadow: true,
backgroundColor: AppColor.neutral100, backgroundColor: AppColor.neutral100,
// initialDate: DateTime.tryParse(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService ?? ""), // initialDate: DateTime.tryParse(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService ?? ""),
from:requestDetailProvider.currentWorkOrder?.data?.requestedDate, from: requestDetailProvider.currentWorkOrder?.data?.requestedDate,
date: DateTime.tryParse(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService ?? ""), date: DateTime.tryParse(requestDetailProvider.engineerUpdateWorkOrderHelperModel?.returnToService ?? ""),
formatDateWithTime: true, formatDateWithTime: true,
onDatePicker: (selectedDate) { onDatePicker: (selectedDate) {
@ -158,37 +162,21 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
}); });
}, },
), ),
12.height, 12.height,
SingleItemDropDownMenu<Lookup, LoanAvailabilityProvider>( SingleItemDropDownMenu<Lookup, WoFrameProvider>(
context: context, context: context,
title: context.translation.loanAvailability, title: "WO Frame",
backgroundColor: AppColor.neutral100, backgroundColor: AppColor.neutral100,
height: 56.toScreenHeight, height: 56.toScreenHeight,
showShadow: false, showShadow: false,
initialValue: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability, initialValue: requestDetailProvider.engineerUpdateWorkOrderHelperModel?.cmFrameId,
onSelect: (status) { onSelect: (value) {
if (status != null) { if (value != null) {
requestDetailProvider.engineerUpdateWorkOrderHelperModel?.loanAvailability = status; requestDetailProvider.engineerUpdateWorkOrderHelperModel?.cmFrameId = value;
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, 12.height,
SingleItemDropDownMenu<Lookup, ReasonProvider>( SingleItemDropDownMenu<Lookup, ReasonProvider>(
context: context, context: context,
@ -227,7 +215,73 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
? requestDetailProvider.engineerUpdateWorkOrderHelperModel!.solution!.bodyText2(context).custom(color: AppColor.neutral120, align: TextAlign.justify) ? requestDetailProvider.engineerUpdateWorkOrderHelperModel!.solution!.bodyText2(context).custom(color: AppColor.neutral120, align: TextAlign.justify)
: const SizedBox(), : const SizedBox(),
], ],
8.height, 12.height,
SingleItemDropDownMenu<Lookup, LoanAvailabilityProvider>(
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( AppTextFormField(
labelText: context.translation.callResponse, labelText: context.translation.callResponse,
backgroundColor: AppColor.neutral100, backgroundColor: AppColor.neutral100,
@ -241,7 +295,7 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
if (Provider.of<SettingProvider>(context, listen: false).isUserFMS) ...[ if (Provider.of<SettingProvider>(context, listen: false).isUserFMS) ...[
8.height, 12.height,
AppTextFormField( AppTextFormField(
labelText: "Description of Finding", labelText: "Description of Finding",
backgroundColor: AppColor.neutral100, backgroundColor: AppColor.neutral100,
@ -254,7 +308,7 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
}, },
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
8.height, 12.height,
AppTextFormField( AppTextFormField(
labelText: "Action Taken", labelText: "Action Taken",
backgroundColor: AppColor.neutral100, backgroundColor: AppColor.neutral100,
@ -283,9 +337,13 @@ class _VerifyAssetDetailsState extends State<VerifyAssetDetails> with TickerProv
onPressed: () async { onPressed: () async {
if (validateForm(requestDetailProvider: requestDetailProvider)) { if (validateForm(requestDetailProvider: requestDetailProvider)) {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await requestDetailProvider.engineerUpdateWorkOrder(); await requestDetailProvider.engineerUpdateWorkOrder().then((success){
Navigator.pop(context); Navigator.pop(context);
Navigator.pop(context); if(success){
Navigator.pop(context);
}
});
} }
}, },
), ),

@ -89,7 +89,7 @@ class _CostDetailFormScreenState extends State<CostDetailFormScreen> with Ticker
initialValue: requestDetailProvider.workOrderCostModel?.labourCost?.toString(), initialValue: requestDetailProvider.workOrderCostModel?.labourCost?.toString(),
textAlign: TextAlign.center, textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType:const TextInputType.numberWithOptions(decimal: true), textInputType: const TextInputType.numberWithOptions(decimal: true),
showShadow: false, showShadow: false,
onChange: (value) { onChange: (value) {
requestDetailProvider.workOrderCostModel?.labourCost = num.parse(value); requestDetailProvider.workOrderCostModel?.labourCost = num.parse(value);
@ -131,7 +131,7 @@ class _CostDetailFormScreenState extends State<CostDetailFormScreen> with Ticker
initialValue: requestDetailProvider.workOrderCostModel?.prNo, initialValue: requestDetailProvider.workOrderCostModel?.prNo,
textAlign: TextAlign.center, textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType:const TextInputType.numberWithOptions(decimal: true), textInputType: const TextInputType.numberWithOptions(decimal: true),
showShadow: false, showShadow: false,
onChange: (value) { onChange: (value) {
requestDetailProvider.workOrderCostModel?.prNo = value; requestDetailProvider.workOrderCostModel?.prNo = value;
@ -145,7 +145,7 @@ class _CostDetailFormScreenState extends State<CostDetailFormScreen> with Ticker
initialValue: requestDetailProvider.workOrderCostModel?.poNo, initialValue: requestDetailProvider.workOrderCostModel?.poNo,
textAlign: TextAlign.center, textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType:const TextInputType.numberWithOptions(decimal: true), textInputType: const TextInputType.numberWithOptions(decimal: true),
showShadow: false, showShadow: false,
onChange: (value) { onChange: (value) {
requestDetailProvider.workOrderCostModel?.poNo = value; requestDetailProvider.workOrderCostModel?.poNo = value;
@ -164,9 +164,12 @@ class _CostDetailFormScreenState extends State<CostDetailFormScreen> with Ticker
onPressed: () async { onPressed: () async {
if (validateForm(requestDetailProvider: requestDetailProvider)) { if (validateForm(requestDetailProvider: requestDetailProvider)) {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await requestDetailProvider.engineerUpdateCost(); await requestDetailProvider.engineerUpdateCost().then((success) {
Navigator.pop(context); Navigator.pop(context);
Navigator.pop(context); if (success) {
Navigator.pop(context);
}
});
} }
}, },
), ),

@ -69,7 +69,7 @@ class _AssistantEmployeeCardState extends State<AssistantEmployeeCard> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.black20), 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(() { ).onPress(() {

@ -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<AssistantEmployeesModel>? assistantEmployeeList;
final ValueChanged<List<AssistantEmployeesModel>>? onListChanged;
final double? cardPadding;
final dynamic assetId;
const AssistantEmployeeList({
super.key,
this.assistantEmployeeList,
this.onListChanged,
required this.assetId,
this.cardPadding,
});
@override
State<AssistantEmployeeList> createState() => _AssistantEmployeeListState();
}
class _AssistantEmployeeListState extends State<AssistantEmployeeList> {
late List<AssistantEmployeesModel> _list;
late List<TextEditingController> _controllers;
@override
void initState() {
super.initState();
_list = List<AssistantEmployeesModel>.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<ServiceRequestDetailProvider>(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<ServiceRequestDetailProvider>(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);
}
}

@ -8,14 +8,13 @@ import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/lookup.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/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.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/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/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.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/providers/service_request_providers/last_situation_provider.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'assistant_employee_card.dart';
class InternalMaintenanceRequest extends StatefulWidget { class InternalMaintenanceRequest extends StatefulWidget {
static const String id = "/add-internal-activity"; static const String id = "/add-internal-activity";
@ -119,9 +118,7 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
onPick: (time) { onPick: (time) {
requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker = time; requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker = time;
}, },
timerProgress: (isRunning) { timerProgress: (isRunning) {},
print("timerProgress:$isRunning");
},
onChange: (timer) async { onChange: (timer) async {
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel = timer; requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel = timer;
if (timer.startAt != null && timer.endAt != null) { if (timer.startAt != null && timer.endAt != null) {
@ -298,7 +295,16 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
], ],
), ),
).toShadowContainer(context).paddingOnly(start: 13, end: 14, top: 12), ).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, 100.height,
], ],
), ),

@ -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/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_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/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/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/service_request_detail_provider.dart';
@ -40,8 +41,9 @@ class _MaintenanceRequestFormState extends State<MaintenanceRequestForm> with Si
Future<void> getInitialData() async { Future<void> getInitialData() async {
Provider.of<ServiceReportRepairLocationProvider>(context, listen: false).getTypes(); Provider.of<ServiceReportRepairLocationProvider>(context, listen: false).getTypes();
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false); ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees = // requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees =
requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees ?? ActivityMaintenanceAssistantEmployees(); // requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees ?? ActivityMaintenanceAssistantEmployees();
requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployList = requestDetailProvider.activityMaintenanceHelperModel?.assistantEmployList ?? [];
} }
@override @override
@ -147,19 +149,24 @@ class _MaintenanceRequestFormState extends State<MaintenanceRequestForm> with Si
), ),
); );
}); });
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
int status = -1;
if (requestDetailProvider.activityMaintenanceHelperModel?.id == 0) { if (requestDetailProvider.activityMaintenanceHelperModel?.id == 0) {
status = await requestDetailProvider.createActivityMaintenanceRequest(); await requestDetailProvider.createActivityMaintenanceRequest().then((success) {
} else { Navigator.pop(context);
status = await requestDetailProvider.updateActivityMaintenance(); if (success) {
} requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!);
if (status == 200) { Navigator.pop(context);
requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!); }
Navigator.pop(context); });
Navigator.pop(context);
} else { } 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<MaintenanceRequestForm> with Si
return false; 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) { // if (model.activityMaintenanceTimerModel?.startAt == null) {

@ -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/controllers/validator/validator.dart';
import 'package:test_sa/extensions/context_extension.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/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_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'; import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart';
@ -309,33 +310,8 @@ class _SparePartRequestState extends State<SparePartRequest> with TickerProvider
child: AppFilledButton( child: AppFilledButton(
label: _requestDetailProvider?.sparePartHelperModel?.id == 0 ? context.translation.addSparePartActivity : context.translation.updateSparePartActivity, label: _requestDetailProvider?.sparePartHelperModel?.id == 0 ? context.translation.addSparePartActivity : context.translation.updateSparePartActivity,
buttonColor: AppColor.green70, buttonColor: AppColor.green70,
onPressed: () async { onPressed: () {
requestDetailProvider.sparePartHelperModel?.sparePartAttachments?.clear(); _onSubmit(requestDetailProvider: requestDetailProvider);
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);
}
}, },
)), )),
], ],
@ -344,6 +320,53 @@ class _SparePartRequestState extends State<SparePartRequest> 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 { class PartDetailBottomSheetSheet extends StatelessWidget {

@ -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/text_extensions.dart';
import 'package:test_sa/extensions/widget_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/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/models/service_request/supplier_details.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.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/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/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/providers/work_order/vendor_provider.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'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
class PpmExternalDetailsForm extends StatefulWidget { class PpmExternalDetailsForm extends StatefulWidget {
@ -160,20 +162,53 @@ class _ExternalDetailItemState extends State<ExternalDetailItem> {
}, },
), ),
8.height, 8.height,
SingleItemDropDownMenu<SuppPersons, NullableLoadingProvider>( Row(
context: context, children: [
title: context.translation.supplierEngineer, SingleItemDropDownMenu<SuppPersons, NullableLoadingProvider>(
enabled: widget.model.supplier != null, context: context,
backgroundColor: AppColor.neutral100, title: context.translation.supplierEngineer,
initialValue: widget.model.suppPerson, enabled: widget.model.supplier != null,
staticData: widget.model.supplier?.suppPersons, backgroundColor: AppColor.neutral100,
showAsBottomSheet: true, initialValue: widget.model.suppPerson,
showShadow: false, staticData: widget.model.supplier?.suppPersons,
onSelect: (suppPerson) { showAsBottomSheet: true,
if (suppPerson != null) { showShadow: false,
widget.model.suppPerson = suppPerson; 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, 8.height,
Row( Row(
@ -193,7 +228,8 @@ class _ExternalDetailItemState extends State<ExternalDetailItem> {
).then((selectedTime) { ).then((selectedTime) {
if (selectedTime != null) { if (selectedTime != null) {
DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); 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; "Start time is before the request time.".showToast;
selectedTime = null; selectedTime = null;
return; return;

@ -76,16 +76,15 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
); );
}); });
await ppmProvider.updateVisitByEngineer(status: status).whenComplete(() { await ppmProvider.updateVisitByEngineer(status: status).then((success) {
if (status == 1) { Navigator.pop(context);
if (success) {
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false); AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
allRequestsProvider.reset(); allRequestsProvider.reset();
allRequestsProvider.getAllRequests(context, typeTransaction: 4); allRequestsProvider.getAllRequests(context, typeTransaction: 4);
ppmProvider.ppmPlanAttachments = []; ppmProvider.ppmPlanAttachments = [];
Navigator.pop(context);
} }
// allRequestsProvider.recurrentWoData?.recurrentWoTimerModel=null;
Navigator.pop(context);
Navigator.pop(context);
}); });
} }
} }

@ -145,15 +145,17 @@ void _updateTask({required BuildContext context, required int status}) async {
.updateRecurrentWo( .updateRecurrentWo(
status: status, status: status,
) )
.whenComplete(() { .then((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);
Navigator.pop(context); 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);
}
}); });
} }
} }

@ -223,6 +223,23 @@ class _UpdateTaskRequestState extends State<UpdateTaskRequest> {
); );
}); });
// 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<AllRequestsProvider>(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 { await taskRequestProvider.updateTaskByEngineer().whenComplete(() async {
if (taskRequestProvider.stateCode == 200) { if (taskRequestProvider.stateCode == 200) {
if (status == 1) { if (status == 1) {

@ -77,9 +77,8 @@ class _SingleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier
@override @override
void didUpdateWidget(covariant SingleItemDropDownMenu<T, X> oldWidget) { void didUpdateWidget(covariant SingleItemDropDownMenu<T, X> oldWidget) {
if (widget.initialValue != null) { if (widget.initialValue != null) {
// print("$provider:start3:${DateTime.now()}");
final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier); final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
// print("$provider:start4:${DateTime.now()}");
if (result?.isNotEmpty ?? false) { if (result?.isNotEmpty ?? false) {
_selectedItem = result?.first as T?; _selectedItem = result?.first as T?;
} else { } else {

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinput/pinput.dart'; import 'package:pinput/pinput.dart';
import 'package:provider/provider.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/text_extensions.dart';
import 'package:test_sa/extensions/widget_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/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/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'; import 'package:test_sa/new_views/forget_password_module/reset_password_view.dart';
class ForgetPasswordVerifyOtpView extends StatefulWidget { class ForgetPasswordVerifyOtpView extends StatefulWidget {
Map<String,dynamic> data={}; Map<String, dynamic> data = {};
ForgetPasswordVerifyOtpView({Key ?key,required this.data}) : super(key: key); ForgetPasswordVerifyOtpView({Key? key, required this.data}) : super(key: key);
@override @override
State<ForgetPasswordVerifyOtpView> createState() => _ForgetPasswordVerifyOtpViewState(); State<ForgetPasswordVerifyOtpView> createState() => _ForgetPasswordVerifyOtpViewState();
@ -25,7 +24,7 @@ class ForgetPasswordVerifyOtpView extends StatefulWidget {
class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpView> { class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpView> {
String otp = ''; String otp = '';
Timer? _timer; Timer? _timer;
int _remainingSeconds = 180; // 3 minutes in seconds int _remainingSeconds = 180; // 3 minutes in seconds
@override @override
@ -111,17 +110,16 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
InkWell( InkWell(
onTap: _remainingSeconds == 0 onTap: _remainingSeconds == 0
? () async { ? () async {
UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false); UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);
String employeeId = widget.data['employeeId']; String employeeId = widget.data['employeeId'];
GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp( GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(
context: context, context: context,
employeeId: employeeId, employeeId: employeeId,
); );
print('Response of send OTP: ${response.toJson()}');
// Restart the timer // Restart the timer
_startTimer(); _startTimer();
} }
: null, : null,
child: Text( child: Text(
'Resend', 'Resend',
@ -150,15 +148,16 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
).paddingOnly(start: 20, end: 20, bottom: 16), ).paddingOnly(start: 20, end: 20, bottom: 16),
); );
} }
void verifyOtp() async{
void verifyOtp() async {
if (otp.isNotEmpty) { if (otp.isNotEmpty) {
UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false); UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);
GeneralResponseModel generalResponseModel = await _userProvider.forgetPasswordValidateOtp( GeneralResponseModel generalResponseModel = await _userProvider.forgetPasswordValidateOtp(
context: context, context: context,
employeeId:widget.data['employeeId'], employeeId: widget.data['employeeId'],
otp: otp, otp: otp,
); );
if (generalResponseModel.isSuccess==true) { if (generalResponseModel.isSuccess == true) {
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => ResetPasswordView())); Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => ResetPasswordView()));
} }
} }

@ -1,217 +1,217 @@
import 'dart:convert'; // import 'dart:convert';
//
import 'package:flutter/material.dart'; // import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; // import 'package:provider/provider.dart';
import 'package:test_sa/controllers/notification/firebase_notification_manger.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/notification/notification_manger.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.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/notifications_provider.dart';
import 'package:test_sa/controllers/providers/api/user_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/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.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/extensions/text_extensions.dart'; // import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; // import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/user.dart'; // import 'package:test_sa/models/user.dart';
import 'package:test_sa/new_views/app_style/app_color.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/progress_fragment.dart';
import 'package:test_sa/dashboard_latest/widgets/recent_activites_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/dashboard_latest/widgets/requests_fragment.dart';
import 'package:test_sa/views/pages/user/notifications/notifications_page.dart'; // import 'package:test_sa/views/pages/user/notifications/notifications_page.dart';
//
class DashboardPage extends StatefulWidget { // class DashboardPage extends StatefulWidget {
final VoidCallback onDrawerPress; // final VoidCallback onDrawerPress; //todo @delete
//
const DashboardPage({Key? key,required this.onDrawerPress}) : super(key: key); // const DashboardPage({Key? key,required this.onDrawerPress}) : super(key: key);
//
@override // @override
State<DashboardPage> createState() => _DashboardPageState(); // State<DashboardPage> createState() => _DashboardPageState();
} // }
//
class _DashboardPageState extends State<DashboardPage> { // class _DashboardPageState extends State<DashboardPage> {
int _currentPage = 0; // int _currentPage = 0;
//
@override // @override
void initState() { // void initState() {
super.initState(); // super.initState();
getAllRequests(); // getAllRequests();
} // }
//
void getAllRequests() { // void getAllRequests() {
WidgetsBinding.instance.addPostFrameCallback((_) { // WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<AllRequestsProvider>(context, listen: false).getRequests(); // Provider.of<AllRequestsProvider>(context, listen: false).getRequests();
Provider.of<NotificationsProvider>(context, listen: false).getSystemNotifications(user: Provider.of<UserProvider>(context, listen: false).user!, resetProvider: true); // Provider.of<NotificationsProvider>(context, listen: false).getSystemNotifications(user: Provider.of<UserProvider>(context, listen: false).user!, resetProvider: true);
}); // });
} // }
//
@override // @override
void dispose() { // void dispose() {
super.dispose(); // super.dispose();
} // }
//
bool isFCM = true; // bool isFCM = true;
//
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
if (isFCM) { // if (isFCM) {
FirebaseNotificationManger.initialized(context); // FirebaseNotificationManger.initialized(context);
NotificationManger.initialisation((notificationDetails) { // NotificationManger.initialisation((notificationDetails) {
FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); // FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!));
}, (id, title, body, payload) async {}); // }, (id, title, body, payload) async {});
//
isFCM = false; // isFCM = false;
} // }
final User user = Provider.of<UserProvider>(context, listen: false).user!; // final User user = Provider.of<UserProvider>(context, listen: false).user!;
final setting = Provider.of<SettingProvider>(context, listen: false); // final setting = Provider.of<SettingProvider>(context, listen: false);
return Scaffold( // return Scaffold(
appBar: AppBar( // appBar: AppBar(
automaticallyImplyLeading: false, // automaticallyImplyLeading: false,
backgroundColor: Theme.of(context).scaffoldBackgroundColor, // backgroundColor: Theme.of(context).scaffoldBackgroundColor,
titleSpacing: 0, // titleSpacing: 0,
title: Row( // title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center, // crossAxisAlignment: CrossAxisAlignment.center,
children: [ // children: [
Consumer<UserProvider>(builder: (context, snapshot, _) { // Consumer<UserProvider>(builder: (context, snapshot, _) {
return CircleAvatar( // return CircleAvatar(
radius: 24, // radius: 24,
backgroundColor: context.isDark ? AppColor.neutral50 : AppColor.neutral40, // backgroundColor: context.isDark ? AppColor.neutral50 : AppColor.neutral40,
child: Padding( // child: Padding(
padding: const EdgeInsets.all(1), // Border radius // padding: const EdgeInsets.all(1), // Border radius
child: ClipOval( // child: ClipOval(
child: snapshot.profileImage != null // child: snapshot.profileImage != null
? Image.file(snapshot.profileImage!) // ? Image.file(snapshot.profileImage!)
: (snapshot.user?.profilePhotoName?.isNotEmpty ?? false) // : (snapshot.user?.profilePhotoName?.isNotEmpty ?? false)
? Image.network(snapshot.user!.profilePhotoName!) // ? Image.network(snapshot.user!.profilePhotoName!)
: const Icon(Icons.person, size: 24, color: Colors.white), // : const Icon(Icons.person, size: 24, color: Colors.white),
), // ),
), // ),
); // );
}).onPress(widget.onDrawerPress), // }).onPress(widget.onDrawerPress),
const Spacer(), // const Spacer(),
Container( // Container(
padding: const EdgeInsets.fromLTRB(12, 6, 6, 6), // padding: const EdgeInsets.fromLTRB(12, 6, 6, 6),
decoration: BoxDecoration( // decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), // borderRadius: BorderRadius.circular(8),
color: AppColor.background(context), // color: AppColor.background(context),
boxShadow: const [ // boxShadow: const [
BoxShadow( // BoxShadow(
color: Color(0x07000000), // color: Color(0x07000000),
blurRadius: 14, // blurRadius: 14,
offset: Offset(0, 0), // offset: Offset(0, 0),
spreadRadius: 0, // spreadRadius: 0,
) // )
], // ],
), // ),
child: DropdownButton<AssetGroup>( // child: DropdownButton<AssetGroup>(
value: setting.assetGroup, // value: setting.assetGroup,
//iconSize: 24, // //iconSize: 24,
isDense: true, // isDense: true,
icon: const Icon(Icons.keyboard_arrow_down), // icon: const Icon(Icons.keyboard_arrow_down),
elevation: 8, // elevation: 8,
// dropdownColor: Colors.amber, // // dropdownColor: Colors.amber,
borderRadius: BorderRadius.circular(8), // borderRadius: BorderRadius.circular(8),
style: TextStyle(color: Theme.of(context).primaryColor), // style: TextStyle(color: Theme.of(context).primaryColor),
underline: const SizedBox.shrink(), // underline: const SizedBox.shrink(),
onChanged: (newValue) { // onChanged: (newValue) {
if (setting.assetGroup != newValue) { // if (setting.assetGroup != newValue) {
Provider.of<SettingProvider>(context, listen: false).setAssetGroup(newValue); // Provider.of<SettingProvider>(context, listen: false).setAssetGroup(newValue);
setState(() {}); // setState(() {});
getAllRequests(); // getAllRequests();
} // }
}, // },
items: user.assetGroups!.map<DropdownMenuItem<AssetGroup>>((value) { // items: user.assetGroups!.map<DropdownMenuItem<AssetGroup>>((value) {
return DropdownMenuItem<AssetGroup>( // return DropdownMenuItem<AssetGroup>(
value: value, // value: value,
child: Text( // child: Text(
value.name ?? "", // value.name ?? "",
style: Theme.of(context).textTheme.bodyLarge, // style: Theme.of(context).textTheme.bodyLarge,
), // ),
); // );
}).toList(), // }).toList(),
), // ),
), // ),
16.width, // 16.width,
Stack( // Stack(
alignment: Alignment.topRight, // alignment: Alignment.topRight,
children: [ // children: [
Icon(Icons.notifications, color: context.isDark ? AppColor.neutral30 : AppColor.neutral20, size: 30).paddingOnly(top: 6, end: 0), // 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 // // todo @sikander will add count for unread notifications
// Positioned( // // Positioned(
// top: 0, // // top: 0,
// right: 0, // // right: 0,
// child: Container( // // child: Container(
// padding: const EdgeInsets.all(4), // // padding: const EdgeInsets.all(4),
// decoration: const ShapeDecoration( // // decoration: const ShapeDecoration(
// color: Color(0xFFD02127), // // color: Color(0xFFD02127),
// shape: CircleBorder(), // // shape: CircleBorder(),
// ), // // ),
// child: Text("", style: AppTextStyles.bodyText), // // child: Text("", style: AppTextStyles.bodyText),
// ), // // ),
// ) // // )
], // ],
).onPress(() { // ).onPress(() {
Navigator.of(context).pushNamed(NotificationsPage.id); // Navigator.of(context).pushNamed(NotificationsPage.id);
}), // }),
], // ],
).paddingOnly(start: 16, end: 16), // ).paddingOnly(start: 16, end: 16),
), // ),
body: Column( // body: Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
Column( // Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, // mainAxisSize: MainAxisSize.min,
children: [ // children: [
Text( // Text(
context.translation.welcome, // context.translation.welcome,
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), // style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20),
), // ),
Text( // Text(
user.username ?? "", // user.username ?? "",
style: AppTextStyles.heading2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600), // style: AppTextStyles.heading2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600),
), // ),
24.height, // 24.height,
Row( // Row(
children: [ // children: [
indicatorView(0), // indicatorView(0),
3.width, // 3.width,
indicatorView(1), // indicatorView(1),
3.width, // 3.width,
indicatorView(2), // indicatorView(2),
10.width, // 10.width,
"0${_currentPage + 1}/03".tinyFont(context).custom(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral60), // "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), // ).paddingOnly(start: 16, end: 16, top: 8, bottom: 8),
PageView( // PageView(
onPageChanged: (index) => setState(() => _currentPage = index), // onPageChanged: (index) => setState(() => _currentPage = index),
children: [ // children: [
const RequestsFragment(), // const RequestsFragment(),
ProgressFragment(), // ProgressFragment(),
const RecentActivitiesFragment(), // const RecentActivitiesFragment(),
], // ],
).expanded, // ).expanded,
], // ],
), // ),
); // );
} // }
//
Widget indicatorView(int index) { // Widget indicatorView(int index) {
bool isActive = _currentPage == index; // bool isActive = _currentPage == index;
//
return AnimatedContainer( // return AnimatedContainer(
duration: const Duration(milliseconds: 250), // duration: const Duration(milliseconds: 250),
width: (isActive ? 30 : 12).toScreenWidth, // width: (isActive ? 30 : 12).toScreenWidth,
height: 9.toScreenHeight, // height: 9.toScreenHeight,
decoration: BoxDecoration( // decoration: BoxDecoration(
color: isActive // color: isActive
? AppColor.greenStatus(context) // ? AppColor.greenStatus(context)
: context.isDark // : context.isDark
? AppColor.neutral20 // ? AppColor.neutral20
: AppColor.neutral40, // : AppColor.neutral40,
borderRadius: BorderRadius.circular(8)), // borderRadius: BorderRadius.circular(8)),
); // );
} // }
} // }

@ -106,9 +106,9 @@ class _LandPageState extends State<LandPage> {
if (_userProvider!.user != null && _userProvider!.user!.employeeIsHMG == false) { if (_userProvider!.user != null && _userProvider!.user!.employeeIsHMG == false) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_userProvider!.getSwipeLastTransaction(userId: _userProvider!.user!.userID!); _userProvider!.getSwipeLastTransaction(userId: _userProvider!.user!.userID!);
Provider.of<VendorProvider>(context, listen: false).getDate();
}); });
} }
Provider.of<VendorProvider>(context, listen: false).getData();
_pages = <Widget>[ _pages = <Widget>[
DashboardView(onDrawerPress: (() { DashboardView(onDrawerPress: (() {
_scaffoldKey.currentState!.isDrawerOpen ? _scaffoldKey.currentState!.closeDrawer() : _scaffoldKey.currentState!.openDrawer(); _scaffoldKey.currentState!.isDrawerOpen ? _scaffoldKey.currentState!.closeDrawer() : _scaffoldKey.currentState!.openDrawer();

@ -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/land_page/land_page.dart';
import 'package:test_sa/new_views/pages/login_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/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/new_views/swipe_module/swipe_view.dart';
import 'package:test_sa/views/update_available_screen.dart'; import 'package:test_sa/views/update_available_screen.dart';
@ -84,24 +86,54 @@ class _SplashPageState extends State<SplashPage> {
loading = false; loading = false;
}); });
if (isValid && _settingProvider.isLocalAuthEnable) { if (isValid && _settingProvider.isLocalAuthEnable) {
bool isSuccess = await checkDualAuthentication(); handleLocalAuth();
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);
}
} else { } 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<bool> checkDualAuthentication() async { Future<bool> checkDualAuthentication() async {
return await _settingProvider.auth.authenticate( return await _settingProvider.auth.authenticate(
localizedReason: Platform.isAndroid ? "Scan your fingerprint to authenticate" : "Scan with face id to authenticate", localizedReason: Platform.isAndroid ? "Scan your fingerprint to authenticate" : "Scan with face id to authenticate",
@ -139,7 +171,7 @@ class _SplashPageState extends State<SplashPage> {
animation: "splash", animation: "splash",
callback: (animation) async { callback: (animation) async {
bool isSafe = await checkDeviceSafety(); bool isSafe = await checkDeviceSafety();
print('is safe is ${isSafe}');
if (!isSafe) { if (!isSafe) {
Navigator.pushNamedAndRemoveUntil(context, UnsafeDeviceScreen.routeName, (_) => false); Navigator.pushNamedAndRemoveUntil(context, UnsafeDeviceScreen.routeName, (_) => false);
} else { } else {

@ -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();
},
),
],
),
],
),
),
);
}
}

@ -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,
),
],
),
),
);
}
}

@ -116,15 +116,23 @@ class TaskRequestProvider extends ChangeNotifier {
} }
} }
Future<int> updateTaskByEngineer() async { Future<bool> updateTaskByEngineer() async {
notifyListeners(); isLoading = true;
Response response;
try { 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; stateCode = response.statusCode;
isLoading = false;
notifyListeners(); notifyListeners();
return response.statusCode; if (stateCode == 200) {
return true;
}
return false;
} catch (error) { } catch (error) {
return -1; isLoading = false;
stateCode = -1;
notifyListeners();
return false;
} }
} }

@ -8,7 +8,6 @@ import '../../controllers/api_routes/urls.dart';
import '../../models/lookup.dart'; import '../../models/lookup.dart';
class ReasonProvider extends LoadingListNotifier<Lookup> { class ReasonProvider extends LoadingListNotifier<Lookup> {
String? serviceRequestId; String? serviceRequestId;
@override @override
@ -17,7 +16,7 @@ class ReasonProvider extends LoadingListNotifier<Lookup> {
loading = true; loading = true;
notifyListeners(); notifyListeners();
try { try {
Response response = await ApiManager.instance.get(URLs.getServiceReportReasonsNew+"&serviceRequestId=$serviceRequestId"); Response response = await ApiManager.instance.get(URLs.getServiceReportReasonsNew + "&serviceRequestId=$serviceRequestId");
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
List categoriesListJson = json.decode(response.body)["data"]; List categoriesListJson = json.decode(response.body)["data"];

@ -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<Lookup> {
@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;
}
}
}

@ -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/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/widget_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/asset_transfer_attachment.dart';
import 'package:test_sa/models/device/device_transfer.dart'; import 'package:test_sa/models/device/device_transfer.dart';
import 'package:test_sa/models/new_models/assigned_employee.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/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/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/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/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
@ -164,15 +166,34 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
return false; 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 (employee.employeeId != null) {
if (_formModel.modelAssistantEmployees?.startDate == null) { if (employee.startDate == null) {
Fluttertoast.showToast(msg: "Please Select Assistant Employee Start Time"); Fluttertoast.showToast(
return false; msg: "Please select start time for assistant employee ${employee.employeeName}",
} );
if (_formModel.modelAssistantEmployees?.endDate == null) { return false;
Fluttertoast.showToast(msg: "Please Select Assistant Employee End Time"); }
return false;
if (employee.endDate == null) {
Fluttertoast.showToast(
msg: "Please select end time for assistant employee ${employee.employeeName}",
);
return false;
}
}
} }
} }
return true; return true;
@ -210,88 +231,96 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
), ),
key: _scaffoldKey, key: _scaffoldKey,
body: LoadingManager( body: LoadingManager(
isLoading: _isLoading, isLoading: _isLoading,
isFailedLoading: false, isFailedLoading: false,
stateCode: 200, stateCode: 200,
onRefresh: () async {}, onRefresh: () async {},
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)), padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)),
child: Column( child: Column(
children: [ children: [
Column( Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
_timerWidget(context, totalWorkingHours, isTimerEnable), _timerWidget(context, totalWorkingHours, isTimerEnable),
8.height, 8.height,
AppTextFormField( AppTextFormField(
initialValue: widget.isSender ? _formModel.senderComment ?? "" : _formModel.receiverComment ?? "", initialValue: widget.isSender ? _formModel.senderComment ?? "" : _formModel.receiverComment ?? "",
labelText: context.translation.technicalComment, labelText: context.translation.technicalComment,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral20), labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral20),
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
backgroundColor: AppColor.neutral100, backgroundColor: AppColor.neutral100,
showShadow: false, showShadow: false,
alignLabelWithHint: true, alignLabelWithHint: true,
onSaved: (value) { onSaved: (value) {
widget.isSender ? _formModel.senderComment = value : _formModel.receiverComment = value; widget.isSender ? _formModel.senderComment = value : _formModel.receiverComment = value;
}, },
), ),
8.height, 8.height,
MultiFilesPicker( MultiFilesPicker(
label: context.translation.attachFiles, label: context.translation.attachFiles,
files: _files, files: _files,
buttonColor: AppColor.black10, buttonColor: AppColor.black10,
onlyImages: false, onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
), ),
8.height, 8.height,
], ],
).toShadowContainer(context), ).toShadowContainer(context),
16.height, 16.height,
AssistantEmployeeCard( DeviceTransferAssistantEmployeeList(
isSender: widget.isSender, assetId: _formModel.assetId,
formModel: _formModel, createdDate: _formModel.createdDate??'',
).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)), assistantEmployeeList: widget.isSender?_formModel.assetTransferAssistantEmployeesSender:_formModel.assetTransferAssistantEmployeesReceiver,
], cardPadding: 0,
), onListChanged: (updatedList) {
).expanded, setState(() {
FooterActionButton.footerContainer( _formModel.assistantEmployList = updatedList;
child: Row( });
mainAxisAlignment: MainAxisAlignment.spaceAround, },
children: [ ),
AppFilledButton( ],
label: context.translation.save, ),
buttonColor: AppColor.white60, ).expanded,
textColor: AppColor.black10, FooterActionButton.footerContainer(
onPressed: () => _update(status: 0), child: Row(
).expanded, mainAxisAlignment: MainAxisAlignment.spaceAround,
12.width, children: [
if (!widget.isSender && _formModel.senderMachineStatusValue == 3) ...[
AppFilledButton( 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, label: context.translation.complete,
buttonColor: AppColor.primary10, buttonColor: AppColor.primary10,
onPressed: () { onPressed: () {
_update(status: 1); _update(status: 1);
}).expanded, },
] else if (widget.isSender) ...[ ).expanded,
AppFilledButton( ],
label: context.translation.complete,
buttonColor: AppColor.primary10,
onPressed: () {
_update(status: 1);
},
).expanded,
], ],
], ),
), ),
), ],
], ),
), ),
), ),
),
).handlePopScope( ).handlePopScope(
cxt: context, cxt: context,
onSave: () { onSave: () {
@ -351,224 +380,513 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
} }
} }
class AssistantEmployeeCard extends StatefulWidget {
bool? isSender = false;
DeviceTransfer? formModel;
AssistantEmployeeCard({super.key, this.isSender, this.formModel});
class DeviceTransferAssistantEmployeeList extends StatefulWidget {
final List<AssetTransferAssistantEmployees>? assistantEmployeeList;
final ValueChanged<List<AssetTransferAssistantEmployees>>? 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 @override
State<AssistantEmployeeCard> createState() => _AssistantEmployeeCardState(); State<DeviceTransferAssistantEmployeeList> createState() => _DeviceTransferAssistantEmployeeListState();
} }
class _AssistantEmployeeCardState extends State<AssistantEmployeeCard> { class _DeviceTransferAssistantEmployeeListState extends State<DeviceTransferAssistantEmployeeList> {
final TextEditingController _workingHoursController = TextEditingController(text: ''); late List<AssetTransferAssistantEmployees> _list;
bool isCurrentUserIsAssistantEmp = false; late List<TextEditingController> _controllers;
bool isExpanded = false;
List<AssetTransferAssistantEmployees> employeeList = [];
AssistantEmployees selectedEmployee = AssistantEmployees();
@override @override
void initState() { void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData();
});
super.initState(); super.initState();
_list = List<AssetTransferAssistantEmployees>.from(widget.assistantEmployeeList ?? []);
_controllers = _list.map((e) => TextEditingController(text: e.workingHours?.toString() ?? '')).toList();
} }
Future<void> getInitialData() async { void _addNewEntry() {
if (widget.isSender!) { setState(() {
employeeList = widget.formModel!.assetTransferAssistantEmployeesSender ?? []; _list.add(AssetTransferAssistantEmployees());
} else { _controllers.add(TextEditingController());
employeeList = widget.formModel!.assetTransferAssistantEmployeesReceiver ?? []; });
} 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(); void _updateModel(int index, void Function(AssetTransferAssistantEmployees model) updateList, {bool updateController = false}) {
if (employeeList.isNotEmpty) { setState(() {
assignedUser = AssignedEmployee( updateList(_list[index]);
id: employeeList[0].employeeId, });
name: employeeList[0].employeeName,
);
}
selectedEmployee = AssistantEmployees(userId: assignedUser.id, user: assignedUser);
} }
@override @override
void dispose() { Widget build(BuildContext context) {
_workingHoursController.dispose(); return ListView.builder(
super.dispose(); 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
children: [ children: [
SizedBox( Row(
height: 56.toScreenHeight, mainAxisAlignment: MainAxisAlignment.spaceBetween,
child: Row( children: [
mainAxisAlignment: MainAxisAlignment.spaceBetween, context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.black20),
children: [ Container(
context.translation.assistantEmployee.heading6(context).custom(color: AppColor.black10), height: 32,
Icon(isExpanded ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded), width: 32,
], padding: const EdgeInsets.all(6),
), child: "trash".toSvgAsset(height: 20, width: 20),
).onPress(() { ).onPress(onRemove),
setState(() { ],
isExpanded = !isExpanded; ),
}); 8.height,
}), Column(
isExpanded crossAxisAlignment: CrossAxisAlignment.stretch,
? Column( children: [
crossAxisAlignment: CrossAxisAlignment.stretch, ServiceReportAssistantEmployeeMenu(
children: [ title: context.translation.select,
ServiceReportAssistantEmployeeMenu( backgroundColor: AppColor.neutral100,
title: context.translation.select, assetId:assetId,
backgroundColor: AppColor.neutral100, initialValue: selectedEmployee,
assetId: widget.formModel?.assetId ?? 0, onSelect: (employee) {
initialValue: selectedEmployee, if (employee != null) {
onSelect: (employee) { onUpdate((model) {
if (employee == null) { selectedEmployee = employee.copyWith(id: 0);
widget.formModel?.assistantEmployees = []; model.employeeId = employee.user?.id;
} else { model.employeeName = employee.user?.name;
selectedEmployee = employee; selectedEmployee?.user = AssignedEmployee(
widget.formModel?.assistantEmployees = [employee.copyWith(id: 0)]; id: employee.user?.id,
widget.formModel?.modelAssistantEmployees?.employeeId = 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, ).expanded,
Row( 8.width,
mainAxisSize: MainAxisSize.min, ADatePicker(
children: [ label: context.translation.endTime,
ADatePicker( hideShadow: true,
label: context.translation.startTime, backgroundColor: AppColor.neutral100,
hideShadow: true, date: model.endDate,
backgroundColor: AppColor.neutral100, formatDateWithTime: true,
date: widget.formModel?.modelAssistantEmployees?.startDate, from: DateTime.tryParse(createdDate ?? ''),
from: DateTime.tryParse(widget.formModel?.createdDate ?? ''), onDatePicker: (selectedDate) {
formatDateWithTime: true, showTimePicker(
onDatePicker: (selectedDate) { context: context,
showTimePicker( initialTime: TimeOfDay.now(),
context: context, ).then((selectedTime) {
initialTime: TimeOfDay.now(), if (selectedTime != null) {
).then((selectedTime) { final endDateTime = DateTime(
// Handle the selected date and time here. selectedDate.year,
if (selectedTime != null) { selectedDate.month,
DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); selectedDate.day,
if (DateTime.tryParse(widget.formModel?.createdDate ?? '') != null && selectedDateTime.isBefore(DateTime.tryParse(widget.formModel?.createdDate ?? '')!)) { selectedTime.hour,
"Start time is before the request time.".showToast; selectedTime.minute,
selectedTime = null; );
return;
} if (!endDateTime.isBefore(DateTime.now())) {
if (selectedDateTime.isAfter(DateTime.now())) { "Please select a time before the current time.".showToast;
"Start time is after than current time".showToast; return;
selectedTime = null; }
return;
} if (model.startDate == null || !endDateTime.isAfter(model.startDate!)) {
widget.formModel?.modelAssistantEmployees?.startDate = selectedDateTime; "End date must be after start date".showToast;
ServiceRequestUtils.calculateAndAssignWorkingHours( return;
startTime: widget.formModel?.modelAssistantEmployees?.startDate, }
endTime: widget.formModel?.modelAssistantEmployees?.endDate,
workingHoursController: _workingHoursController, onUpdate((model) {
updateModel: (hours) { model.endDate = endDateTime;
widget.formModel?.modelAssistantEmployees?.workingHours = hours; ServiceRequestUtils.calculateAndAssignWorkingHours(
}); startTime: model.startDate,
setState(() {}); endTime: model.endDate,
} workingHoursController: workingHoursController,
}); updateModel: (hours) => model.workingHours = hours,
}, );
).expanded, });
8.width, }
ADatePicker( });
label: context.translation.endTime, },
hideShadow: true, ).expanded,
backgroundColor: AppColor.neutral100, ],
date: widget.formModel?.modelAssistantEmployees?.endDate, ),
formatDateWithTime: true, 8.height,
onDatePicker: (selectedDate) { AppTextFormField(
showTimePicker( labelText: context.translation.workingHours,
context: context, backgroundColor: AppColor.neutral80,
initialTime: TimeOfDay.now(), controller: workingHoursController,
).then((selectedTime) { suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
if (selectedTime != null) { textAlign: TextAlign.center,
DateTime selectedDateTime = DateTime( enable: false,
selectedDate.year, showShadow: false,
selectedDate.month, labelStyle: AppTextStyles.textFieldLabelStyle,
selectedDate.day, style: Theme.of(context).textTheme.titleMedium,
selectedTime.hour, ),
selectedTime.minute, 8.height,
); AppTextFormField(
if (widget.formModel?.modelAssistantEmployees?.startDate != null && selectedDateTime.isBefore(widget.formModel!.modelAssistantEmployees!.startDate!)) { initialValue: model.techComment,
"End Date time must be greater then start date".showToast; labelText: context.translation.technicalComment,
return; backgroundColor: AppColor.neutral100,
} showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
selectedDate = selectedDate.add(Duration(hours: selectedTime.hour, minutes: selectedTime.minute)); alignLabelWithHint: true,
bool isBeforeCurrentTime = selectedDate.isBefore(DateTime.now()); textInputType: TextInputType.multiline,
bool isAfterStartTime = selectedDate.isAfter(widget.formModel!.modelAssistantEmployees!.startDate!); onChange: (value) => onUpdate((model) => model.techComment = value),
if (!isBeforeCurrentTime) { // onSaved: (value) => onUpdate((model) => model.technicalComment = value),
"Please select a time before the current time.".showToast; ),
return; 8.height,
} ],
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(),
], ],
); ).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<AssistantEmployeeCard> createState() => _AssistantEmployeeCardState();
// }
//
// class _AssistantEmployeeCardState extends State<AssistantEmployeeCard> {
// final TextEditingController _workingHoursController = TextEditingController(text: '');
// bool isCurrentUserIsAssistantEmp = false;
// bool isExpanded = false;
// List<AssetTransferAssistantEmployees> employeeList = [];
// AssistantEmployees selectedEmployee = AssistantEmployees();
// @override
// void initState() {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// getInitialData();
// });
// super.initState();
// }
//
// Future<void> 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(),
// ],
// );
// }
// }

@ -156,15 +156,18 @@ class _UpdateGasRefillRequestState extends State<UpdateGasRefillRequest> {
_formModel.gasRefillAttachments?.add(GasRefillAttachments( _formModel.gasRefillAttachments?.add(GasRefillAttachments(
id: 0, gasRefillId: _formModel.id ?? 0, attachmentName: ServiceRequestUtils.isLocalUrl(item.path) ? "${item.path.split("/").last}|${base64Encode(item.readAsBytesSync())}" : item.path)); 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) { await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) {
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(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);
Navigator.pop(context); Navigator.pop(context);
if (success) {
if (status == 1) {
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(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);
}
}); });
} }

@ -127,8 +127,7 @@ class _AddSupplierEngineerBottomSheetState extends State<AddSupplierEngineerBott
} }
engineer.personRoleId = suppEngRole?.id; engineer.personRoleId = suppEngRole?.id;
// print(engineer.toJson());
// return;
SuppEngineerWorkOrders? suppEngineer = await snapshot.addSupplierEngineer(engineer); SuppEngineerWorkOrders? suppEngineer = await snapshot.addSupplierEngineer(engineer);
if (suppEngineer == null) { if (suppEngineer == null) {
Fluttertoast.showToast(msg: context.translation.failedToCompleteRequest); Fluttertoast.showToast(msg: context.translation.failedToCompleteRequest);

@ -378,11 +378,6 @@ class CreateServiceRequestPageState extends State<CreateServiceRequestPage> {
_serviceRequest.requestedThrough = Provider.of<RequestedThroughProvider>(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null); _serviceRequest.requestedThrough = Provider.of<RequestedThroughProvider>(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null);
_serviceRequest.type = Provider.of<TypeOfRequestProvider>(context, listen: false).items.firstWhere((element) => element.value == 1, orElse: null); _serviceRequest.type = Provider.of<TypeOfRequestProvider>(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)) { if (_formKey.currentState!.validate() && await _serviceRequest.validateNewRequest(context)) {
_formKey.currentState!.save(); _formKey.currentState!.save();

@ -60,7 +60,8 @@ class FilesList extends StatelessWidget {
body: SafeArea( body: SafeArea(
child: Stack( child: Stack(
children: [ children: [
InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center,
InteractiveViewer(child: getImageWidget(itemIndex)).center,
const ABackButton(), 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) { ImageProvider getImageObject(int itemIndex) {
if (_isLocalUrl(images[itemIndex])) { if (_isLocalUrl(images[itemIndex])) {
return FileImage(File(images[itemIndex])); return FileImage(File(images[itemIndex]));

@ -32,7 +32,6 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
@override @override
void initState() { void initState() {
print('initial value i got is ${widget.initialValue}');
_controller = TextEditingController(text: widget.initialValue); _controller = TextEditingController(text: widget.initialValue);
super.initState(); super.initState();
} }
@ -75,7 +74,7 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
displayStringForOption: (SparePartsWorkOrders option) => widget.byName ? option.sparePart?.partName ?? "" : option.sparePart?.partNo ?? "", displayStringForOption: (SparePartsWorkOrders option) => widget.byName ? option.sparePart?.partName ?? "" : option.sparePart?.partNo ?? "",
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
return TextField( return TextField(
controller: _controller, controller: _controller,
focusNode: fieldFocusNode, focusNode: fieldFocusNode,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
textAlign: TextAlign.start, textAlign: TextAlign.start,
@ -96,8 +95,8 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120), labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120),
), ),
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onChanged: (text){ onChanged: (text) {
fieldTextEditingController.text =text; fieldTextEditingController.text = text;
}, },
onSubmitted: (String value) { onSubmitted: (String value) {
onFieldSubmitted(); onFieldSubmitted();

@ -158,7 +158,6 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
if (_audio != widget.audio) { if (_audio != widget.audio) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
_audio = widget.audio; _audio = widget.audio;
print('audio position i got is $_audioPosition');
if (_isLocalFile) { if (_isLocalFile) {
await _audioPlayer.setSourceDeviceFile(_audio); await _audioPlayer.setSourceDeviceFile(_audio);
} else { } else {
@ -199,7 +198,8 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
).paddingOnly(start: 8, end: 8).expanded, ).paddingOnly(start: 8, end: 8).expanded,
_failedToLoad _failedToLoad
? Text("Failed to load", style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60)) ? 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)),
], ],
), ),
], ],

@ -1,12 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.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 'package:test_sa/models/lookup.dart';
import '../../../new_views/app_style/app_color.dart'; import '../../../new_views/app_style/app_color.dart';
class SingleStatusMenu extends StatefulWidget { class SingleStatusMenu extends StatefulWidget {
final List<Lookup>? statuses;// Nullable list final List<Lookup>? statuses; // Nullable list
final Lookup? initialStatus; // Nullable final Lookup? initialStatus; // Nullable
final Function(Lookup?)? onSelect; // Nullable function, accepts nullable Lookup final Function(Lookup?)? onSelect; // Nullable function, accepts nullable Lookup
final bool enabled; final bool enabled;
@ -35,9 +35,7 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
@override @override
void didUpdateWidget(covariant SingleStatusMenu oldWidget) { void didUpdateWidget(covariant SingleStatusMenu oldWidget) {
_selectedStatus = widget.statuses?.firstWhere( _selectedStatus = widget.statuses?.firstWhere((element) => element == widget.initialStatus, orElse: null);
(element) => element == widget.initialStatus,
orElse: null);
if (widget.initialStatus != _selectedStatus) { if (widget.initialStatus != _selectedStatus) {
widget.onSelect?.call(_selectedStatus); // Use null-aware operator widget.onSelect?.call(_selectedStatus); // Use null-aware operator
@ -48,10 +46,7 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
@override @override
void initState() { 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) { if (widget.initialStatus != _selectedStatus) {
widget.onSelect?.call(_selectedStatus); // Use null-aware operator widget.onSelect?.call(_selectedStatus); // Use null-aware operator
@ -62,25 +57,22 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container(height: 60.toScreenHeight, return Container(
height: 60.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.isDark && (!widget.enabled || widget.statuses!.isEmpty) color: context.isDark && (!widget.enabled || widget.statuses!.isEmpty)
? AppColor.neutral50 ? AppColor.neutral50
: (!widget.enabled || widget.statuses!.isEmpty) : (!widget.enabled || widget.statuses!.isEmpty)
? AppColor.neutral40 ? AppColor.neutral40
: AppColor.background(context), : AppColor.background(context),
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
boxShadow: [ boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)
],
), ),
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
if (widget.enabled) if (widget.enabled) const PositionedDirectional(end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)),
const PositionedDirectional(
end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -88,9 +80,7 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
if (widget.title != null) if (widget.title != null)
Text( Text(
widget.title!, // Use null assertion operator widget.title!, // Use null assertion operator
style: Theme.of(context).textTheme.bodySmall?.copyWith( style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
color: context.isDark ? null : AppColor.neutral20,
fontWeight: FontWeight.w500),
), ),
DropdownButton<Lookup>( DropdownButton<Lookup>(
value: _selectedStatus, value: _selectedStatus,
@ -107,22 +97,22 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
underline: const SizedBox.shrink(), underline: const SizedBox.shrink(),
onChanged: !widget.enabled onChanged: !widget.enabled
? null ? null
: (Lookup? newValue) { // Nullable Lookup : (Lookup? newValue) {
setState(() { // Nullable Lookup
_selectedStatus = newValue; setState(() {
}); _selectedStatus = newValue;
widget.onSelect?.call(newValue); // Use null-aware operator });
}, widget.onSelect?.call(newValue); // Use null-aware operator
items: widget.statuses },
?.map<DropdownMenuItem<Lookup>>((value) { items: widget.statuses?.map<DropdownMenuItem<Lookup>>((value) {
return DropdownMenuItem<Lookup>( return DropdownMenuItem<Lookup>(
value: value, value: value,
child: Text(value.name ?? "", // Use null-aware operator child: Text(
value.name ?? "", // Use null-aware operator
style: Theme.of(context).textTheme.bodyLarge, style: Theme.of(context).textTheme.bodyLarge,
), ),
); );
}) }).toList(),
.toList(),
), ),
], ],
), ),
@ -130,4 +120,4 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
), ),
); );
} }
} }

@ -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> 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<String, dynamic> json) {
id = json['id'];
startTime = json['startTime'];
endTime = json['endTime'];
workingHours = json['workingHours'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['startTime'] = startTime;
data['endTime'] = endTime;
data['workingHours'] = workingHours;
return data;
}
}

@ -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. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.3.3+22 version: 1.3.5+24
environment: environment:
sdk: ">=3.5.0 <4.0.0" sdk: ">=3.5.0 <4.0.0"

Loading…
Cancel
Save