Merge branch 'design_3.0_asset_delivery_module' into design_3.0_medical_gas

# Conflicts:
#	lib/controllers/api_routes/urls.dart
#	lib/main.dart
#	lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart
#	lib/new_views/pages/land_page/my_request/my_requests_page.dart
design_3.0_demo_module
Sikander Saleem 4 months ago
commit 178309eb1e

@ -469,8 +469,6 @@
"-framework", "-framework",
"\"nanopb\"", "\"nanopb\"",
"-framework", "-framework",
"\"qr_code_scanner\"",
"-framework",
"\"speech_to_text\"", "\"speech_to_text\"",
"-framework", "-framework",
"\"sqflite\"", "\"sqflite\"",
@ -689,8 +687,6 @@
"-framework", "-framework",
"\"nanopb\"", "\"nanopb\"",
"-framework", "-framework",
"\"qr_code_scanner\"",
"-framework",
"\"speech_to_text\"", "\"speech_to_text\"",
"-framework", "-framework",
"\"sqflite\"", "\"sqflite\"",
@ -795,8 +791,6 @@
"-framework", "-framework",
"\"nanopb\"", "\"nanopb\"",
"-framework", "-framework",
"\"qr_code_scanner\"",
"-framework",
"\"speech_to_text\"", "\"speech_to_text\"",
"-framework", "-framework",
"\"sqflite\"", "\"sqflite\"",

@ -1,12 +1,11 @@
class URLs { class URLs {
URLs._(); URLs._();
static const String appReleaseBuildNumber = "28"; static const String appReleaseBuildNumber = "32";
// 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
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url
// static String _baseUrl = "$_host/mobile"; // static String _baseUrl = "$_host/mobile";
@ -20,6 +19,7 @@ class URLs {
static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis
static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis
static const String resetMessageCount = "$chatHubUrlApi/userChatHistory/AckMessages"; // new V2 apis
static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis
static String _host = host1; static String _host = host1;
@ -67,8 +67,12 @@ class URLs {
//service request new flow urls. //service request new flow urls.
static get nurseDashboardCountUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseCount'; static get nurseDashboardCountUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseCount';
static get qaAuditorCount => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorCount';
static get commissioningEngineerCount => '$_baseUrl/ServiceRequest/GetDashboardCommissioningEngineerCount';
static get nurseDashboardDetailsUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseDetails'; static get nurseDashboardDetailsUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseDetails';
static get qaAuditorDetails => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorDetails';
static get commissioningEngineerDetails => '$_baseUrl/ServiceRequest/GetDashboardCommissioningEngineerDetails';
static get nurseRejectUrl => '$_baseUrl/ServiceRequest/NurseReject'; static get nurseRejectUrl => '$_baseUrl/ServiceRequest/NurseReject';
@ -410,8 +414,10 @@ class URLs {
static get getLineFromExternalPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetLineFromExternalPo'; static get getLineFromExternalPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetLineFromExternalPo';
static get getCostCenterListToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToLineDeliveryInspection'; static get getCostCenterListToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToLineDeliveryInspection';
static get getCostCenterAndSerialNoToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterAndSerialNoToLineDeliveryInspection';
static get getCostCenterToPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToPo'; static get getCostCenterToPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToPo';
static get saveCostCenterToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterToLineDeliveryInspection'; static get saveCostCenterToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterToLineDeliveryInspection';
static get saveCostCenterAndSerialNoToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterAndSerialNoToLineDeliveryInspection';
static get getDeliveryHistories => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveryHistories'; static get getDeliveryHistories => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveryHistories';
//Technical Inscption... //Technical Inscption...
static get getLineFromTechnicalInspection => '$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetLineFromDeliveryInspection'; static get getLineFromTechnicalInspection => '$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetLineFromDeliveryInspection';
@ -422,7 +428,7 @@ class URLs {
static get getAssetFromInternalTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetFromInternal"; static get getAssetFromInternalTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetFromInternal";
static get getAssetDetailsByAssetId => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetByIdFromInternal"; static get getAssetDetailsByAssetId => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetByIdFromInternal";
static get saveTechnicalInspectionAsset => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspectionItem"; static get saveTechnicalInspectionAsset => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspectionItem";
static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachments"; static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachmentsBasedOnType";
static get saveAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/Save"; static get saveAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/Save";
//End user Acceptance... //End user Acceptance...
static get getEndUserAcceptanceCostCenter => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetEndUserAcceptanceCostCenter"; static get getEndUserAcceptanceCostCenter => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetEndUserAcceptanceCostCenter";
@ -430,7 +436,9 @@ class URLs {
static get saveEndUserFormData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveMaster"; static get saveEndUserFormData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveMaster";
static get saveEndUserAssetData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveDetail"; static get saveEndUserAssetData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveDetail";
static get endUserStatusLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=534"; static get endUserStatusLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=534";
static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5007"; // static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5007";
static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=415";
static get attachmentTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5009";
//Medical Gas Request.. //Medical Gas Request..
// 4004 // 4004

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
@ -13,6 +14,7 @@ import 'package:test_sa/modules/cx_module/survey/survey_page.dart';
import 'package:test_sa/modules/pm_module/ppm_wo/ppm_details_page.dart'; import 'package:test_sa/modules/pm_module/ppm_wo/ppm_details_page.dart';
import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart'; import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart';
import 'package:test_sa/modules/tm_module/device_transfer/device_transfer_details.dart'; import 'package:test_sa/modules/tm_module/device_transfer/device_transfer_details.dart';
import 'package:test_sa/modules/tm_module/tasks/task_request_detail_view.dart';
import 'package:test_sa/modules/tm_module/gas_refill/gas_refill_details.dart'; import 'package:test_sa/modules/tm_module/gas_refill/gas_refill_details.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@ -88,6 +90,44 @@ class FirebaseNotificationManger {
String? transactionType = messageData["transactionType"]?.toString(); String? transactionType = messageData["transactionType"]?.toString();
if (transactionType == null) {
return;
} else if (transactionType == "17" && messageData["requestType"] == "chat") {
int moduleId = int.parse(messageData["moduleId"].toString());
int requestNumber = int.parse(messageData["requestNumber"].toString());
switch (moduleId) {
case 1: // cm
serviceClass = CMDetailPage(requestId: requestNumber, moduleId: moduleId);
break;
case 2: // gas refill
serviceClass = GasRefillDetailsPage(
priority: messageData["priority"],
date: messageData["createdOn"],
moduleId: moduleId,
model: GasRefillModel(id: requestNumber),
);
break;
case 3: //transfer
serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: requestNumber), moduleId: moduleId);
break;
case 6: // task
serviceClass = TaskRequestDetailsView(
taskId: requestNumber,
moduleId: moduleId,
// requestDetails: RequestsDetails(nameOfType: requestData?.nameOfType, status: requestData?.statusName, priority: requestData?.priorityName, date: requestData?.transactionDate, ),
);
// ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break;
default:
serviceClass = const Scaffold(body: Center(child: NoDataFound()));
}
Navigator.of(context).push(MaterialPageRoute(builder: (_) => serviceClass!));
return;
}
// PPM=1, // PPM=1,
// ServiceRequestEngineer = 3, // ServiceRequestEngineer = 3,
// AssetTransfer=7, // AssetTransfer=7,
@ -101,21 +141,22 @@ class FirebaseNotificationManger {
break; break;
//these three request are same corrective maintenance.... //these three request are same corrective maintenance....
case "3": case "3":
serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString())); serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break; break;
case "8": case "8":
serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString())); serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break; break;
case "11": case "11":
serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString())); serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break; break;
case "7": case "7":
serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: int.parse(messageData["requestNumber"].toString()))); serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: int.parse(messageData["requestNumber"].toString())), moduleId: 3);
break; break;
case "9": case "9":
serviceClass = GasRefillDetailsPage( serviceClass = GasRefillDetailsPage(
priority: messageData["priority"], priority: messageData["priority"],
date: messageData["createdOn"], date: messageData["createdOn"],
moduleId: 2,
model: GasRefillModel(id: int.parse(messageData["requestNumber"].toString())), model: GasRefillModel(id: int.parse(messageData["requestNumber"].toString())),
); );
break; break;

@ -140,6 +140,7 @@ class AllRequestsProvider extends ChangeNotifier {
} }
if (context.userProvider.isQualityUser) { if (context.userProvider.isQualityUser) {
list = [10, 11]; list = [10, 11];
if (context.settingProvider.isUserFlowMedical) list.insert(0, 7);
return list; return list;
} }
@ -165,7 +166,11 @@ class AllRequestsProvider extends ChangeNotifier {
if (context.userProvider.isNurse) { if (context.userProvider.isNurse) {
list.add(9); // list.add(9); //
} }
list.add(12); // loan module list.add(12);
if (context.userProvider.isCommissioningEngineer) {
list = [13];
}
// loan module
return list; return list;
} }

@ -47,6 +47,7 @@ class UserProvider extends ChangeNotifier {
bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl; bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl;
bool get isQualityUser => user!.type == UsersTypes.qualityUser; bool get isQualityUser => user!.type == UsersTypes.qualityUser;
bool get isCommissioningEngineer => user!.type == UsersTypes.commissioningEngineer;
VerifyOtpModel _verifyOtpModel = VerifyOtpModel(); VerifyOtpModel _verifyOtpModel = VerifyOtpModel();
SwipeTransaction _swipeTransactionModel = SwipeTransaction(); SwipeTransaction _swipeTransactionModel = SwipeTransaction();

@ -106,11 +106,22 @@ class DashBoardProvider extends ChangeNotifier {
isAllCountLoading = true; isAllCountLoading = true;
notifyListeners(); notifyListeners();
String url = ''; String url = '';
if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
url = URLs.engineerDashboardCountUrl; // if (usersType == UsersTypes.qualityUser) {
} else { // url = URLs.qaAuditorCount;
url = URLs.nurseDashboardCountUrl; // } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
} // url = URLs.engineerDashboardCountUrl;
// } else {
// url = URLs.nurseDashboardCountUrl;
// }
final urlMap = {
UsersTypes.qualityUser: URLs.qaAuditorCount,
UsersTypes.commissioningEngineer: URLs.commissioningEngineerCount,
UsersTypes.engineer: URLs.engineerDashboardCountUrl,
UsersTypes.assessor: URLs.engineerDashboardCountUrl,
UsersTypes.assessorTl: URLs.engineerDashboardCountUrl,
};
url = urlMap[usersType] ?? URLs.nurseDashboardCountUrl;
Response response; Response response;
try { try {
response = await ApiManager.instance.post(url, body: {}); response = await ApiManager.instance.post(url, body: {});
@ -233,6 +244,32 @@ class DashBoardProvider extends ChangeNotifier {
} }
} }
String getDashboardUrl({
required UsersTypes usersType,
int? status,
int? tabId,
}) {
switch (usersType) {
case UsersTypes.qualityUser:
return URLs.qaAuditorDetails;
case UsersTypes.commissioningEngineer:
return URLs.commissioningEngineerDetails;
case UsersTypes.engineer:
case UsersTypes.assessor:
case UsersTypes.assessorTl:
if (status == 0) {
return URLs.engineerDashboardUpcoming;
} else if (status == 1 && tabId == 1) {
return URLs.engineerDashboardNotAssignDetails;
} else {
// status == 1 && tabId == 2 OR any other case
return URLs.engineerDashboardDetailsUrl;
}
default:
return URLs.nurseDashboardDetailsUrl;
}
}
Future<int> getRequestDetail({bool showLoader = true, required UsersTypes usersType, int? status, bool isHighPriority = false, bool isOverdue = false, String? date, int? tabId}) async { Future<int> getRequestDetail({bool showLoader = true, required UsersTypes usersType, int? status, bool isHighPriority = false, bool isOverdue = false, String? date, int? tabId}) async {
if (showLoader) { if (showLoader) {
isDetailLoading = showLoader; isDetailLoading = showLoader;
@ -241,22 +278,26 @@ class DashBoardProvider extends ChangeNotifier {
Response response; Response response;
String url = ''; String url = '';
if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { // if (usersType == UsersTypes.qualityUser) {
//need to check pagination for not assigned task @waseem. // url = URLs.qaAuditorDetails;
// } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
//these checks are to call different apis for dashboard for engineer... // //need to check pagination for not assigned task @waseem.
if (status == 0) { //
url = URLs.engineerDashboardUpcoming; // //these checks are to call different apis for dashboard for engineer...
} else if (status == 1 && tabId == 1) { // if (status == 0) {
url = URLs.engineerDashboardNotAssignDetails; // url = URLs.engineerDashboardUpcoming;
} else if (status == 1 && tabId == 2) { // } else if (status == 1 && tabId == 1) {
url = URLs.engineerDashboardDetailsUrl; // url = URLs.engineerDashboardNotAssignDetails;
} else { // } else if (status == 1 && tabId == 2) {
url = URLs.engineerDashboardDetailsUrl; // url = URLs.engineerDashboardDetailsUrl;
} // } else {
} else { // url = URLs.engineerDashboardDetailsUrl;
url = URLs.nurseDashboardDetailsUrl; // }
} // } else {
// url = URLs.nurseDashboardDetailsUrl;
// }
url = getDashboardUrl(usersType: usersType, status: status, tabId: tabId);
try { try {
Map<String, dynamic> body = {"pageNumber": pageNum, "pageSize": pageItemNumber}; Map<String, dynamic> body = {"pageNumber": pageNum, "pageSize": pageItemNumber};
@ -372,6 +413,19 @@ class CategoryTabs {
return tabs; return tabs;
} }
if (userType == UsersTypes.qualityUser) {
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3));
tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4));
return tabs;
}
if (userType == UsersTypes.commissioningEngineer) {
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3));
tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4));
return tabs;
}
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2)); tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3)); tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3));
tabs.add(CategoryTabs(label: 'Pending Acknowledgement', tag: 3, id: 1)); tabs.add(CategoryTabs(label: 'Pending Acknowledgement', tag: 3, id: 1));

@ -73,14 +73,14 @@ class _DashboardViewState extends State<DashboardView> {
// await requestDetailProvider.engineerRejectWorkOrder(id: '3', feedBack: 'Abcdef'); // await requestDetailProvider.engineerRejectWorkOrder(id: '3', feedBack: 'Abcdef');
// await dashBoardProvider.getDashBoardCount(usersType: user.type!); // await dashBoardProvider.getDashBoardCount(usersType: user.type!);
// await getAllRequests(); // await getAllRequests();
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;
} // }
}); });
} }

@ -182,6 +182,13 @@ class ProgressFragment extends StatelessWidget {
ChartData('Open', snapshot.dashboardCount?.data?.countOpen?.toDouble() ?? 0.0, AppColor.blueStatus(context)), ChartData('Open', snapshot.dashboardCount?.data?.countOpen?.toDouble() ?? 0.0, AppColor.blueStatus(context)),
ChartData('In Progress', snapshot.dashboardCount?.data?.countInprogress?.toDouble() ?? 0.0, AppColor.orange70), ChartData('In Progress', snapshot.dashboardCount?.data?.countInprogress?.toDouble() ?? 0.0, AppColor.orange70),
]; ];
} else if (_userProvider.isQualityUser) {
total = (snapshot.dashboardCount?.data?.countComplete ?? 0) + (snapshot.dashboardCount?.data?.countInprogress ?? 0) + (snapshot.dashboardCount?.data?.countOpen ?? 0);
chartData = [
ChartData('Closed', snapshot.dashboardCount?.data?.countComplete?.toDouble() ?? 0.0, AppColor.green70),
ChartData('Open', snapshot.dashboardCount?.data?.countOpen?.toDouble() ?? 0.0, AppColor.blueStatus(context)),
ChartData('In Progress', snapshot.dashboardCount?.data?.countInprogress?.toDouble() ?? 0.0, AppColor.orange70),
];
} else { } else {
total = (snapshot.dashboardCount?.data?.countComplete ?? 0) + (snapshot.dashboardCount?.data?.countInprogress ?? 0) + (snapshot.dashboardCount?.data?.countOpen ?? 0); total = (snapshot.dashboardCount?.data?.countComplete ?? 0) + (snapshot.dashboardCount?.data?.countInprogress ?? 0) + (snapshot.dashboardCount?.data?.countOpen ?? 0);
chartData = [ chartData = [
@ -248,7 +255,7 @@ class ProgressFragment extends StatelessWidget {
showChartValuesOutside: false, showChartValuesOutside: false,
decimalPlaces: 1, decimalPlaces: 1,
), ),
).toShimmer(isShow: snapshot.isAllCountLoading, radius: 250,context: context).paddingAll(0).toShadowContainer(context), ).toShimmer(isShow: snapshot.isAllCountLoading, radius: 250, context: context).paddingAll(0).toShadowContainer(context),
], ],
), ),
), ),

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_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/dashboard_detail.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_item_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks/task_request_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks/task_request_item_view.dart';
@ -62,6 +63,8 @@ class RequestCategoryList extends StatelessWidget {
return EquipmentInternalAuditItemView(requestData: request); return EquipmentInternalAuditItemView(requestData: request);
case 11: case 11:
return EquipmentInternalAuditItemView(requestData: request); return EquipmentInternalAuditItemView(requestData: request);
case 13:
return AssetDeliveryItemView(requestData: request);
default: default:
return Container( return Container(
height: 100, height: 100,

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

@ -121,7 +121,37 @@ extension StringExtensionsRecurrentTaskInpesctionDataType on String {
} }
} }
} }
extension IntExtensionsAssetDeliveryStage on int {
AssetDeliveryStageEnum toAssetDeliveryStageEnum() {
switch (this) {
case 2:
return AssetDeliveryStageEnum.deliveryInspection;
case 3:
return AssetDeliveryStageEnum.technicalInspection;
case 4:
return AssetDeliveryStageEnum.endUserAcceptance;
default:
return AssetDeliveryStageEnum.other;
}
}
}
enum DropDownMatchType { enum DropDownMatchType {
identifier, identifier,
name, name,
} }
enum CostCenterType {
costCenter,
serialNumber,
}
enum AssetDeliveryStageEnum {
deliveryInspection,
technicalInspection,
endUserAcceptance,
other,
}

@ -28,6 +28,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart';
@ -140,6 +141,7 @@ import 'providers/service_request_providers/reject_reason_provider.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
// HttpOverrides.global = MyHttpOverrides(); // for later use. // HttpOverrides.global = MyHttpOverrides(); // for later use.
_configureLocalTimeZone(); _configureLocalTimeZone();
NotificationManger.initialisation((notificationDetails) {}, (id, title, body, payload) async {}); NotificationManger.initialisation((notificationDetails) {}, (id, title, body, payload) async {});
@ -331,6 +333,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => PowerSupplyTypeProvider()), ChangeNotifierProvider(create: (_) => PowerSupplyTypeProvider()),
ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider()), ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider()),
ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider()), ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider()),
ChangeNotifierProvider(create: (_) => AttachmentTypeLookupProvider()),
ChangeNotifierProvider(create: (_) => MedicalGasOrderTypeProvider()), ChangeNotifierProvider(create: (_) => MedicalGasOrderTypeProvider()),
ChangeNotifierProvider(create: (_) => MedicalGasItemTypeProvider()), ChangeNotifierProvider(create: (_) => MedicalGasItemTypeProvider()),
ChangeNotifierProvider(create: (_) => MedicalGasInspectionProvider()), ChangeNotifierProvider(create: (_) => MedicalGasInspectionProvider()),

@ -38,6 +38,7 @@ class DeviceTransfer {
this.senderEngSignature, this.senderEngSignature,
this.senderAttachments, this.senderAttachments,
this.receiverAssignedEmployeeId, this.receiverAssignedEmployeeId,
this.receiverAssignedEmployeeNumber,
this.receiverMachineStatusId, this.receiverMachineStatusId,
this.senderMachineStatusValue, this.senderMachineStatusValue,
this.receiverComment, this.receiverComment,
@ -74,6 +75,7 @@ class DeviceTransfer {
this.receiverMachineStatusValue, this.receiverMachineStatusValue,
this.receiverMachineStatusName, this.receiverMachineStatusName,
this.senderAssignedEmployeeName, this.senderAssignedEmployeeName,
this.senderAssignedEmployeeNumber,
this.senderBuildingName, this.senderBuildingName,
this.senderDepartmentName, this.senderDepartmentName,
this.senderEngSignatureUrl, this.senderEngSignatureUrl,
@ -144,6 +146,7 @@ class DeviceTransfer {
}); });
} }
receiverAssignedEmployeeId = json['receiverAssignedEmployeeId']; receiverAssignedEmployeeId = json['receiverAssignedEmployeeId'];
receiverAssignedEmployeeNumber = json['receiverAssignedEmployeeNumber'];
receiverMachineStatusId = json['receiverMachineStatusId']; receiverMachineStatusId = json['receiverMachineStatusId'];
receiverMachineStatusValue = json['receiverMachineStatusValue']; receiverMachineStatusValue = json['receiverMachineStatusValue'];
receiverComment = json['receiverComment']; receiverComment = json['receiverComment'];
@ -220,6 +223,7 @@ class DeviceTransfer {
receiverEngSignatureUrl = json['receiverEngSignatureUrl']; receiverEngSignatureUrl = json['receiverEngSignatureUrl'];
receiverMachineStatusName = json['receiverMachineStatusName']; receiverMachineStatusName = json['receiverMachineStatusName'];
senderAssignedEmployeeName = json['senderAssignedEmployeeName']; senderAssignedEmployeeName = json['senderAssignedEmployeeName'];
senderAssignedEmployeeNumber = json['senderAssignedEmployeeNumber'];
senderBuildingName = json['senderBuildingName']; senderBuildingName = json['senderBuildingName'];
senderDepartmentName = json['senderDepartmentName']; senderDepartmentName = json['senderDepartmentName'];
senderEngSignatureUrl = json['senderEngSignatureUrl']; senderEngSignatureUrl = json['senderEngSignatureUrl'];
@ -270,6 +274,7 @@ class DeviceTransfer {
List<AssetTransferAttachment>? attachments; List<AssetTransferAttachment>? attachments;
List<AssetTransferAttachment>? assetTransferAttachments; List<AssetTransferAttachment>? assetTransferAttachments;
String? receiverAssignedEmployeeId; String? receiverAssignedEmployeeId;
String? receiverAssignedEmployeeNumber;
num? receiverMachineStatusId; num? receiverMachineStatusId;
int? receiverMachineStatusValue; int? receiverMachineStatusValue;
String? receiverComment; String? receiverComment;
@ -290,6 +295,7 @@ class DeviceTransfer {
String? senderFloorName; String? senderFloorName;
String? senderDepartmentName; String? senderDepartmentName;
String? senderAssignedEmployeeName; String? senderAssignedEmployeeName;
String? senderAssignedEmployeeNumber;
String? senderMachineStatusName; String? senderMachineStatusName;
String? senderEngSignatureUrl; String? senderEngSignatureUrl;
String? receiverAssignedEmployeeName; String? receiverAssignedEmployeeName;
@ -345,6 +351,7 @@ class DeviceTransfer {
String? senderEngSignature, String? senderEngSignature,
List<AssetTransferAttachment>? senderAttachments, List<AssetTransferAttachment>? senderAttachments,
String? receiverAssignedEmployeeId, String? receiverAssignedEmployeeId,
String? receiverAssignedEmployeeNumber,
num? receiverMachineStatusId, num? receiverMachineStatusId,
String? receiverComment, String? receiverComment,
String? receiverStartDate, String? receiverStartDate,
@ -364,6 +371,7 @@ class DeviceTransfer {
String? senderFloorName, String? senderFloorName,
String? senderDepartmentName, String? senderDepartmentName,
String? senderAssignedEmployeeName, String? senderAssignedEmployeeName,
String? senderAssignedEmployeeNumber,
String? senderMachineStatusName, String? senderMachineStatusName,
String? senderEngSignatureUrl, String? senderEngSignatureUrl,
String? receiverAssignedEmployeeName, String? receiverAssignedEmployeeName,
@ -420,6 +428,7 @@ class DeviceTransfer {
senderEngSignature: senderEngSignature ?? this.senderEngSignature, senderEngSignature: senderEngSignature ?? this.senderEngSignature,
senderAttachments: senderAttachments ?? this.senderAttachments, senderAttachments: senderAttachments ?? this.senderAttachments,
receiverAssignedEmployeeId: receiverAssignedEmployeeId ?? this.receiverAssignedEmployeeId, receiverAssignedEmployeeId: receiverAssignedEmployeeId ?? this.receiverAssignedEmployeeId,
receiverAssignedEmployeeNumber: receiverAssignedEmployeeNumber ?? this.receiverAssignedEmployeeNumber,
receiverMachineStatusId: receiverMachineStatusId ?? this.receiverMachineStatusId, receiverMachineStatusId: receiverMachineStatusId ?? this.receiverMachineStatusId,
receiverComment: receiverComment ?? this.receiverComment, receiverComment: receiverComment ?? this.receiverComment,
receiverStartDate: receiverStartDate ?? this.receiverStartDate, receiverStartDate: receiverStartDate ?? this.receiverStartDate,
@ -439,6 +448,7 @@ class DeviceTransfer {
senderFloorName: senderFloorName ?? this.senderFloorName, senderFloorName: senderFloorName ?? this.senderFloorName,
senderDepartmentName: senderDepartmentName ?? this.senderDepartmentName, senderDepartmentName: senderDepartmentName ?? this.senderDepartmentName,
senderAssignedEmployeeName: senderAssignedEmployeeName ?? this.senderAssignedEmployeeName, senderAssignedEmployeeName: senderAssignedEmployeeName ?? this.senderAssignedEmployeeName,
senderAssignedEmployeeNumber: senderAssignedEmployeeNumber ?? this.senderAssignedEmployeeNumber,
senderMachineStatusName: senderMachineStatusName ?? this.senderMachineStatusName, senderMachineStatusName: senderMachineStatusName ?? this.senderMachineStatusName,
senderMachineStatusValue: senderMachineStatusValue ?? this.senderMachineStatusValue, senderMachineStatusValue: senderMachineStatusValue ?? this.senderMachineStatusValue,
senderEngSignatureUrl: senderEngSignatureUrl ?? this.senderEngSignatureUrl, senderEngSignatureUrl: senderEngSignatureUrl ?? this.senderEngSignatureUrl,
@ -503,6 +513,7 @@ class DeviceTransfer {
map['senderAttachments'] = senderAttachments!.map((v) => v.toJson()).toList(); map['senderAttachments'] = senderAttachments!.map((v) => v.toJson()).toList();
} }
map['receiverAssignedEmployeeId'] = receiverAssignedEmployeeId; map['receiverAssignedEmployeeId'] = receiverAssignedEmployeeId;
map['receiverAssignedEmployeeNumber'] = receiverAssignedEmployeeNumber;
map['receiverMachineStatusId'] = receiverMachineStatusId; map['receiverMachineStatusId'] = receiverMachineStatusId;
map['receiverComment'] = receiverComment; map['receiverComment'] = receiverComment;
map['receiverStartDate'] = receiverStartDate; map['receiverStartDate'] = receiverStartDate;
@ -524,6 +535,7 @@ class DeviceTransfer {
map["senderFloorName"] = senderFloorName; map["senderFloorName"] = senderFloorName;
map["senderDepartmentName"] = senderDepartmentName; map["senderDepartmentName"] = senderDepartmentName;
map["senderAssignedEmployeeName"] = senderAssignedEmployeeName; map["senderAssignedEmployeeName"] = senderAssignedEmployeeName;
map["senderAssignedEmployeeNumber"] = senderAssignedEmployeeNumber;
map["senderMachineStatusName"] = senderMachineStatusName; map["senderMachineStatusName"] = senderMachineStatusName;
map["senderEngSignatureUrl"] = senderEngSignatureUrl; map["senderEngSignatureUrl"] = senderEngSignatureUrl;
map["receiverAssignedEmployeeName"] = receiverAssignedEmployeeName; map["receiverAssignedEmployeeName"] = receiverAssignedEmployeeName;
@ -631,6 +643,7 @@ class DeviceTransfer {
map['assetTransferReceiverTimers'] = receiverVisitTimers!.map((v) => v.toJson()).toList(); map['assetTransferReceiverTimers'] = receiverVisitTimers!.map((v) => v.toJson()).toList();
} }
map['receiverAssignedEmployeeId'] = receiverAssignedEmployeeId; map['receiverAssignedEmployeeId'] = receiverAssignedEmployeeId;
map['receiverAssignedEmployeeNumber'] = receiverAssignedEmployeeNumber;
map['receiverMachineStatusId'] = receiverMachineStatusId; map['receiverMachineStatusId'] = receiverMachineStatusId;
map['receiverComment'] = receiverComment; map['receiverComment'] = receiverComment;
map['receiverStartDate'] = receiverStartDate; map['receiverStartDate'] = receiverStartDate;
@ -674,6 +687,7 @@ class DeviceTransfer {
senderEngSignature = assetTransfer.senderEngSignature; senderEngSignature = assetTransfer.senderEngSignature;
senderAttachments = assetTransfer.senderAttachments; senderAttachments = assetTransfer.senderAttachments;
receiverAssignedEmployeeId = assetTransfer.receiverAssignedEmployeeId; receiverAssignedEmployeeId = assetTransfer.receiverAssignedEmployeeId;
receiverAssignedEmployeeNumber = assetTransfer.receiverAssignedEmployeeNumber;
receiverMachineStatusId = assetTransfer.receiverMachineStatusId; receiverMachineStatusId = assetTransfer.receiverMachineStatusId;
receiverComment = assetTransfer.receiverComment; receiverComment = assetTransfer.receiverComment;
receiverStartDate = assetTransfer.receiverStartDate; receiverStartDate = assetTransfer.receiverStartDate;
@ -693,6 +707,7 @@ class DeviceTransfer {
senderFloorName = assetTransfer.senderFloorName; senderFloorName = assetTransfer.senderFloorName;
senderDepartmentName = assetTransfer.senderDepartmentName; senderDepartmentName = assetTransfer.senderDepartmentName;
senderAssignedEmployeeName = assetTransfer.senderAssignedEmployeeName; senderAssignedEmployeeName = assetTransfer.senderAssignedEmployeeName;
senderAssignedEmployeeNumber = assetTransfer.senderAssignedEmployeeNumber;
senderMachineStatusName = assetTransfer.senderMachineStatusName; senderMachineStatusName = assetTransfer.senderMachineStatusName;
senderEngSignatureUrl = assetTransfer.senderEngSignatureUrl; senderEngSignatureUrl = assetTransfer.senderEngSignatureUrl;
receiverAssignedEmployeeName = assetTransfer.receiverAssignedEmployeeName; receiverAssignedEmployeeName = assetTransfer.receiverAssignedEmployeeName;

@ -4,5 +4,6 @@ enum UsersTypes {
nurse, // 1 nurse, // 1
assessor, assessor,
assessorTl, assessorTl,
qualityUser qualityUser,
commissioningEngineer
} }

@ -7,9 +7,10 @@ class Lookup extends Base {
int? id; // Now nullable int? id; // Now nullable
int? value; // Now nullable int? value; // Now nullable
WorkOrderNextStepEnum? workOrderNextStepEnum; // Now nullable WorkOrderNextStepEnum? workOrderNextStepEnum; // Now nullable
AssetDeliveryStageEnum? assetDeliveryStageEnum; // Now nullable
String? name; // Now nullable String? name; // Now nullable
Lookup({this.id, this.value, this.name, this.workOrderNextStepEnum}) : super(identifier: id?.toString(), name: name); Lookup({this.id, this.value, this.name, this.workOrderNextStepEnum, this.assetDeliveryStageEnum}) : super(identifier: id?.toString(), name: name);
@override @override
bool operator ==(Object other) => identical(this, other) || other is Lookup && ((value != null && value == other.value) || (id != null && id == other.id)); bool operator ==(Object other) => identical(this, other) || other is Lookup && ((value != null && value == other.value) || (id != null && id == other.id));
@ -38,10 +39,11 @@ class Lookup extends Base {
// } // }
factory Lookup.fromJson(Map<String, dynamic>? parsedJson) { factory Lookup.fromJson(Map<String, dynamic>? parsedJson) {
if(parsedJson==null) return Lookup(); if (parsedJson == null) return Lookup();
return Lookup( return Lookup(
name: parsedJson["name"], name: parsedJson["name"],
workOrderNextStepEnum: parsedJson["value"] == null ? null : (parsedJson["value"] as int).toWorkOrderNextStepEnum(), workOrderNextStepEnum: parsedJson["value"] == null ? null : (parsedJson["value"] as int).toWorkOrderNextStepEnum(),
assetDeliveryStageEnum: parsedJson["value"] == null ? null : (parsedJson["value"] as int).toAssetDeliveryStageEnum(),
id: parsedJson["id"], id: parsedJson["id"],
value: parsedJson["value"], value: parsedJson["value"],
); );

@ -523,3 +523,55 @@ class GasRefillContactPerson {
}; };
} }
} }
class AssignedEmployee {
String? id;
String? name;
String? email;
String? employeeId;
int? languageId;
String? extensionNo;
String? phoneNumber;
String? positionName;
String? position;
bool? isActive;
AssignedEmployee(
{this.id,
this.name,
this.email,
this.employeeId,
this.languageId,
this.extensionNo,
this.phoneNumber,
this.positionName,
this.position,
this.isActive});
AssignedEmployee.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
email = json['email'];
employeeId = json['employeeId'];
languageId = json['languageId'];
extensionNo = json['extensionNo'];
phoneNumber = json['phoneNumber'];
positionName = json['positionName'];
position = json['position'];
isActive = json['isActive'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['email'] = this.email;
data['employeeId'] = this.employeeId;
data['languageId'] = this.languageId;
data['extensionNo'] = this.extensionNo;
data['phoneNumber'] = this.phoneNumber;
data['positionName'] = this.positionName;
data['position'] = this.position;
data['isActive'] = this.isActive;
return data;
}
}

@ -12,6 +12,7 @@ class User {
List<String>? departmentName; List<String>? departmentName;
String? message; String? message;
String? username; String? username;
String? employeeId;
String? userID; String? userID;
String? email; String? email;
String? password; String? password;
@ -53,6 +54,7 @@ class User {
this.departmentName, this.departmentName,
this.message, this.message,
this.username, this.username,
this.employeeId,
this.userID, this.userID,
this.email, this.email,
this.password, this.password,
@ -108,8 +110,13 @@ class User {
return UsersTypes.assessor; return UsersTypes.assessor;
case "R-19": // Head Nurse Role case "R-19": // Head Nurse Role
return UsersTypes.assessorTl; return UsersTypes.assessorTl;
//TODO need to confirm why repeat.
case "R-3": // Quality User case "R-3": // Quality User
return UsersTypes.qualityUser; return UsersTypes.qualityUser;
case "R-58": // Quality User
return UsersTypes.qualityUser;
case "R-201": // Quality User
return UsersTypes.commissioningEngineer;
default: default:
return null; return null;
} }
@ -146,6 +153,7 @@ class User {
map['message'] = message; map['message'] = message;
map['username'] = username; map['username'] = username;
map['userID'] = userID; map['userID'] = userID;
map['employeeId'] = employeeId;
map['email'] = email; map['email'] = email;
map['password'] = password; map['password'] = password;
map['token'] = token; map['token'] = token;
@ -207,6 +215,7 @@ class User {
message = json['message']; message = json['message'];
username = json['username']; username = json['username'];
userID = json['userID']; userID = json['userID'];
employeeId = json['employeeId'];
email = json['email']; email = json['email'];
password = json['password']; password = json['password'];
token = json['token']; token = json['token'];

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
class HelperFunction {
static void attachmentTap({required BuildContext context, bool viewOnly = false, required AssetDeliveryProvider assetDeliveryProvider, required dynamic deliveryTableItemId}) async {
Lookup? result;
result = await showAttachmentTypeBottomSheet(context);
List<GenericAttachmentModel> list = [];
if (result != null) {
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => const AppLazyLoading(),
);
list = await assetDeliveryProvider.getAttachments(tableItemId: deliveryTableItemId, attachmentType: result.value);
Navigator.pop(context);
// if (list.isNotEmpty) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AssetDeliveryAttachmentView(
tableItemId: deliveryTableItemId,
attachmentType: result!.value,
viewOnly: viewOnly,
attachmentList: list,
)));
// }
}
}
static Future<Lookup?> showAttachmentTypeBottomSheet(BuildContext context) {
return showModalBottomSheet<Lookup?>(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (_) {
return SafeArea(
top: false,
child: Padding(
padding: const EdgeInsets.only(
top: 16,
left: 16,
right: 16,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SingleItemDropDownMenu<Lookup, AttachmentTypeLookupProvider>(
context: context,
title: context.translation.reason,
onSelect: (value) {
Navigator.pop(context, value);
},
),
],
),
),
);
},
);
}
}

@ -241,7 +241,7 @@ class AssetDeliveryInternalDetail {
num? qtyCancelled; num? qtyCancelled;
num? unitPrice; num? unitPrice;
num? unitPriceWithTax; num? unitPriceWithTax;
String? itemCategory; Lookup? itemCategory;
num? totalAssets; num? totalAssets;
num? childPerAsset; num? childPerAsset;
@ -259,7 +259,9 @@ class AssetDeliveryInternalDetail {
qtyCancelled = json['qtyCancelled']; qtyCancelled = json['qtyCancelled'];
unitPrice = json['unitPrice']; unitPrice = json['unitPrice'];
unitPriceWithTax = json['unitPriceWithTax']; unitPriceWithTax = json['unitPriceWithTax'];
itemCategory = json['itemCategory']; itemCategory = json['itemCategory'] != null
? Lookup.fromJson(json['itemCategory'])
: null;
totalAssets = json['totalAssets']; totalAssets = json['totalAssets'];
childPerAsset = json['childPerAsset']; childPerAsset = json['childPerAsset'];
} }
@ -303,6 +305,7 @@ class AssetDeliveryTableModel {
status = json['status'] != null status = json['status'] != null
? Lookup.fromJson(json['status']) ? Lookup.fromJson(json['status'])
: null; : null;
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {

@ -40,11 +40,6 @@ class CostCenterModel {
data['id'] = id ?? 0; data['id'] = id ?? 0;
data['qty'] = quantity; data['qty'] = quantity;
// data['costCenter'] = costCenter;
// data['acceptedBy'] = acceptedBy;
// data['acceptanceDate'] = acceptanceDate;
// data['acceptedByEmail'] = acceptedByEmail;
// data['acceptedBySignature'] = acceptedBySignature;
data['costCenter'] = costCenterName; data['costCenter'] = costCenterName;
return data; return data;
} }

@ -0,0 +1,53 @@
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
class CostCenterSerialNoFormModel {
List<CostCenterModel>? costCenters;
List<SerialNoModel>? serialNos;
CostCenterSerialNoFormModel({
this.costCenters,
this.serialNos,
});
// From JSON
CostCenterSerialNoFormModel.fromJson(Map<String, dynamic> json) {
if (json['costCenters'] != null) {
costCenters = List<CostCenterModel>.from((json['costCenters'] as List).map((e) => CostCenterModel.fromJson(e)));
}
if (json['serialNos'] != null) {
serialNos = List<SerialNoModel>.from((json['serialNos'] as List).map((e) => SerialNoModel.fromJson(e)));
}
}
// To JSON
Map<String, dynamic> toJson() {
return {
'costCenters': costCenters?.map((e) => e.toJson()).toList() ?? [],
'serialNos': serialNos?.map((e) => e.toJson()).toList() ?? [],
};
}
}
class SerialNoModel {
int? id;
String? serialNo;
SerialNoModel({
this.id,
this.serialNo,
});
SerialNoModel.fromJson(Map<String, dynamic> json) {
id = json['id'] ?? json['costCenterId'];
serialNo = json['serialNo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['id'] = id ?? 0;
data['serialNo'] = serialNo;
return data;
}
}

@ -1,6 +1,11 @@
import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart';
class DeliveryInspectionFormModel { class DeliveryInspectionFormModel {
int? assetDeliveryExternalDeliveryId; int? assetDeliveryExternalDeliveryId;
String? deliveryInspectionInspectedBy; String? deliveryInspectionInspectedBy;
InspectionPersonModel? inspectedByModel;
InspectionPersonModel? approvedByModel;
InspectionPersonModel? thirdApprovalModel;
DateTime? deliveryInspectionInspectedDateFrom; DateTime? deliveryInspectionInspectedDateFrom;
DateTime? deliveryInspectionInspectedDateTo; DateTime? deliveryInspectionInspectedDateTo;
num? totalTime; num? totalTime;
@ -9,6 +14,9 @@ class DeliveryInspectionFormModel {
DeliveryInspectionFormModel({ DeliveryInspectionFormModel({
this.assetDeliveryExternalDeliveryId, this.assetDeliveryExternalDeliveryId,
this.deliveryInspectionInspectedBy, this.deliveryInspectionInspectedBy,
this.inspectedByModel,
this.approvedByModel,
this.thirdApprovalModel,
this.deliveryInspectionInspectedDateFrom, this.deliveryInspectionInspectedDateFrom,
this.deliveryInspectionInspectedDateTo, this.deliveryInspectionInspectedDateTo,
this.totalTime, this.totalTime,
@ -18,20 +26,32 @@ class DeliveryInspectionFormModel {
DeliveryInspectionFormModel.fromJson(Map<String, dynamic> json) { DeliveryInspectionFormModel.fromJson(Map<String, dynamic> json) {
assetDeliveryExternalDeliveryId = json['assetDeliveryExternalDeliveryId']; assetDeliveryExternalDeliveryId = json['assetDeliveryExternalDeliveryId'];
deliveryInspectionInspectedBy = json['deliveryInspectionInspectedBy']; deliveryInspectionInspectedBy = json['deliveryInspectionInspectedBy'];
deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']):null; inspectedByModel = InspectionPersonModel(name: json['deliveryInspectionInspectedBy'], email: json['deliveryInspectionInspectedByEmail'], signature: json['deliveryInspectionInspectedBySignature']);
deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateTo']):null; approvedByModel = InspectionPersonModel(name: json['deliveryInspectionApprovedBy'], email: json['deliveryInspectionApprovedByEmail'], signature: json['deliveryInspectionApprovedBySignature']);
thirdApprovalModel =
InspectionPersonModel(name: json['deliveryInspectionThirdApproverBy'], email: json['deliveryInspectionThirdApproverByEmail'], signature: json['deliveryInspectionThirdApproverBySignature']);
deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom'] != null ? DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']) : null;
deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo'] != null ? DateTime.tryParse(json['deliveryInspectionInspectedDateTo']) : null;
totalTime = json['totalTime']; totalTime = json['totalTime'];
deliveryInspectionApprovedBy = json['deliveryInspectionApprovedBy']; deliveryInspectionApprovedBy = json['deliveryInspectionApprovedBy'];
} }
//TODO need to set payload..
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'assetDeliveryExternalDeliveryId': assetDeliveryExternalDeliveryId, 'assetDeliveryExternalDeliveryId': assetDeliveryExternalDeliveryId,
'deliveryInspectionInspectedBy': deliveryInspectionInspectedBy, 'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(),
'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(),
'deliveryInspectionInspectedDateTo': deliveryInspectionInspectedDateTo?.toIso8601String(), 'deliveryInspectionInspectedDateTo': deliveryInspectionInspectedDateTo?.toIso8601String(),
'totalTime': totalTime, 'totalTime': totalTime,
'deliveryInspectionApprovedBy': deliveryInspectionApprovedBy, 'deliveryInspectionInspectedBy': inspectedByModel?.name,
"deliveryInspectionInspectedBySignature": inspectedByModel?.signature,
"deliveryInspectionInspectedByEmail": inspectedByModel?.email,
'deliveryInspectionApprovedBy': approvedByModel?.name,
"deliveryInspectionApprovedBySignature": approvedByModel?.signature,
"deliveryInspectionApprovedByEmail": approvedByModel?.email,
"deliveryInspectionThirdApproverBy": thirdApprovalModel?.name,
"deliveryInspectionThirdApproverBySignature": thirdApprovalModel?.signature,
"deliveryInspectionThirdApproverByEmail": thirdApprovalModel?.email,
}; };
} }
} }

@ -0,0 +1,15 @@
import 'package:flutter/services.dart';
class InspectionPersonModel {
String? name;
String? email;
String? signature;
Uint8List? localSignature;
InspectionPersonModel({
this.name,
this.email,
this.signature,
this.localSignature,
});
}

@ -136,7 +136,7 @@ class TechnicalInspectionAssetModel {
Map<String, dynamic> toChildJson() { Map<String, dynamic> toChildJson() {
final Map<String, dynamic> data = {}; final Map<String, dynamic> data = {};
data['id'] = id; data['id'] = id ?? 0;
data['assetDeliveryInternalDetailAssetChildId'] = assetDeliveryInternalDetailAssetChildId; data['assetDeliveryInternalDetailAssetChildId'] = assetDeliveryInternalDetailAssetChildId;
data['assetNumber'] = assetNumber; data['assetNumber'] = assetNumber;
data['assetOriginId'] = assetOrigin?.id; data['assetOriginId'] = assetOrigin?.id;

@ -6,6 +6,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/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/change_status_bottomsheet.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/change_status_bottomsheet.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart';
@ -35,6 +36,7 @@ class AssetDeliveryPage extends StatefulWidget {
class _AssetDeliveryPageState extends State<AssetDeliveryPage> { class _AssetDeliveryPageState extends State<AssetDeliveryPage> {
AssetDeliveryDataModel? dataModel; AssetDeliveryDataModel? dataModel;
AssetDeliveryProvider? assetDeliveryProvider; AssetDeliveryProvider? assetDeliveryProvider;
bool loading = false;
@override @override
void initState() { void initState() {
@ -46,12 +48,18 @@ class _AssetDeliveryPageState extends State<AssetDeliveryPage> {
} }
Future<void> getDetailsById() async { Future<void> getDetailsById() async {
setState(() {
loading = true;
});
final futures = <Future>[ final futures = <Future>[
assetDeliveryProvider!.getAssetDeliveryDetailById(requestId: widget.requestId).then((value) => dataModel = value), assetDeliveryProvider!.getAssetDeliveryDetailById(requestId: widget.requestId).then((value) => dataModel = value),
assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestId), assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestId),
]; ];
await Future.wait(futures); await Future.wait(futures);
setState(() {
loading = false;
});
} }
@override @override
@ -68,66 +76,64 @@ class _AssetDeliveryPageState extends State<AssetDeliveryPage> {
body: Consumer<AssetDeliveryProvider>( body: Consumer<AssetDeliveryProvider>(
builder: (context, provider, child) { builder: (context, provider, child) {
final dataModel = provider.assetDeliveryDataModel; final dataModel = provider.assetDeliveryDataModel;
if (provider.isLoading) { if (loading) {
return const CircularProgressIndicator(color: AppColor.primary10).center; return const CircularProgressIndicator(color: AppColor.primary10).center;
} }
if (dataModel == null) { if (dataModel == null) {
return const NoDataFound().center; return const NoDataFound().center;
} }
return ListView( return SingleChildScrollView(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(16),
children: [ child: Column(
requestDetailCard(context), crossAxisAlignment: CrossAxisAlignment.start,
const Divider().defaultStyle(context), children: [
Row( requestDetailCard(context),
mainAxisAlignment: MainAxisAlignment.spaceBetween, const Divider().defaultStyle(context),
children: [ Row(
Text( mainAxisAlignment: MainAxisAlignment.spaceBetween,
"Asset Delivery Table", children: [
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), Text(
), "Asset Delivery Table",
Row( style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
children: [ ),
Container( Row(
height: 24, children: [
width: 24, Container(
decoration: const BoxDecoration( height: 24,
shape: BoxShape.circle, width: 24,
color: AppColor.primary10, // or AppColor.blueStatus(context) decoration: const BoxDecoration(
), shape: BoxShape.circle,
alignment: Alignment.center, color: AppColor.primary10, // or AppColor.blueStatus(context)
child: const Icon( ),
Icons.add, alignment: Alignment.center,
color: Colors.white, child: const Icon(
size: 16, Icons.add,
color: Colors.white,
size: 16,
),
), ),
), 4.width,
4.width, Text(
Text( "Add more",
"Add more", style: AppTextStyles.bodyText.copyWith(
style: AppTextStyles.bodyText.copyWith( color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, decoration: TextDecoration.underline,
decoration: TextDecoration.underline, ),
), ),
), ],
], ).onPress(() async {
).onPress(() async { await assetDeliveryProvider?.addNewDelivery(requestId: widget.requestId).then((status) async {
await assetDeliveryProvider?.addNewDelivery(requestId: widget.requestId).then((status) async { if (status) {
if (status) { await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestId);
await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestId); }
} });
}); }),
}), ],
], ),
), 8.height,
8.height, assetDeliveryTableList(context: context, assetDeliveryProvider: provider),
assetDeliveryTableList(context: context, assetDeliveryProvider: provider), ],
], ).toShadowContainer(context, borderRadius: 20),
).toShadowContainer(
context,
borderRadius: 20,
padding: 0,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
); );
}, },
), ),
@ -248,16 +254,17 @@ class _AssetDeliveryPageState extends State<AssetDeliveryPage> {
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
), ),
8.height, 8.height,
Text( //Removed as request by Ahmed backend...
'EDD (Estimated Delivery Date)'.addTranslation, // Text(
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), // 'EDD (Estimated Delivery Date)'.addTranslation,
), // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
8.height, // ),
Text( // 8.height,
dataModel?.edd != null ? dataModel!.edd!.toAssetDetailsFormat : '-', // Text(
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), // dataModel?.edd != null ? dataModel!.edd!.toAssetDetailsFormat : '-',
), // style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
8.height, // ),
// 8.height,
Text( Text(
'Total'.addTranslation, 'Total'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
@ -323,10 +330,21 @@ class _AssetDeliveryPageState extends State<AssetDeliveryPage> {
}); });
}); });
} else { } else {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (_) =>
// DeliveryInspectionFormView(
// deliveryTableModel: model,
// requestModel: dataModel,
// ),
// ));
Navigator.of(context).push(MaterialPageRoute( Navigator.of(context).push(MaterialPageRoute(
builder: (_) => DeliveryInspectionFormView( builder: (_) => AssetDeliveryStageTabPage(
deliveryTableModel: model, title: 'Delivery Inspection'.addTranslation,
requestModel: dataModel, detailWidget: DeliveryInspectionFormView(
deliveryTableModel: model,
requestModel: dataModel,
),
tableId: model.id,
), ),
)); ));
} }

@ -0,0 +1,90 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/enum_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/widget_extensions.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/history_log_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
class AssetDeliveryStageTabPage extends StatefulWidget {
String title;
Widget detailWidget;
int? tableId;
AssetDeliveryStageTabPage({
Key? key,
required this.title,
required this.detailWidget,
this.tableId,
}) : super(key: key);
@override
_AssetDeliveryStageTabPageState createState() {
return _AssetDeliveryStageTabPageState();
}
}
class _AssetDeliveryStageTabPageState extends State<AssetDeliveryStageTabPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar(
title: widget.title,
),
body: DefaultTabController(
length: 2,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight),
decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)),
child: TabBar(
padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth),
labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20,
unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20,
unselectedLabelStyle: AppTextStyles.bodyText,
labelStyle: AppTextStyles.bodyText,
indicatorPadding: EdgeInsets.zero,
indicatorSize: TabBarIndicatorSize.tab,
dividerColor: Colors.transparent,
indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)),
tabs: [
Tab(text: context.translation.details, height: 57.toScreenHeight),
Tab(text: context.translation.historyLogs, height: 57.toScreenHeight),
],
),
),
// 12.height,
TabBarView(
children: [
widget.detailWidget,
AssetDeliveryHistoryLogView(
tableItemId: widget.tableId,
),
],
).expanded,
],
),
));
}
String getPageTitle({AssetDeliveryStageEnum? deliveryStage}) {
if (deliveryStage == AssetDeliveryStageEnum.deliveryInspection) {
return 'Delivery Inspection'.addTranslation;
}
if (deliveryStage == AssetDeliveryStageEnum.technicalInspection) {
return 'Technical Inspection'.addTranslation;
}
if (deliveryStage == AssetDeliveryStageEnum.endUserAcceptance) {
return 'End-User Acceptance'.addTranslation;
} else {
return 'Details'.addTranslation;
}
}
}

@ -26,28 +26,33 @@ class AssetDeliveryTableCard extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( StatusLabel(
mainAxisAlignment: MainAxisAlignment.spaceBetween, label: deliveryTableModel.status?.name,
children: [ textColor: AppColor.neutral50,
StatusLabel( backgroundColor: AppColor.orange30,
label: deliveryTableModel.status?.name,
textColor: AppColor.neutral50,
backgroundColor: AppColor.orange30,
),
Row(
children: [
'history_icon'.toSvgAsset(height: 14, width: 14),
8.width,
Text(
'View History'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10),
),
],
).onPress(() {
onViewHistoryTap();
}),
],
), ),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// StatusLabel(
// label: deliveryTableModel.status?.name,
// textColor: AppColor.neutral50,
// backgroundColor: AppColor.orange30,
// ),
// Row(
// children: [
// 'history_icon'.toSvgAsset(height: 14, width: 14),
// 8.width,
// Text(
// 'View History'.addTranslation,
// style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10),
// ),
// ],
// ).onPress(() {
// onViewHistoryTap();
// }),
// ],
// ),
8.height, 8.height,
Text( Text(
'Delivery Number: ${deliveryTableModel.number ?? '-'}', 'Delivery Number: ${deliveryTableModel.number ?? '-'}',

@ -1,8 +1,10 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
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/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/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
@ -15,21 +17,22 @@ 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_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
class AssetDeliveryAttachmentView extends StatefulWidget { class AssetDeliveryAttachmentView extends StatefulWidget {
///Need to check which parm need here.
final int? lineId;
final int? tableItemId; final int? tableItemId;
final int? requestId; final int? attachmentType;
final bool? isHmg; bool viewOnly = false;
final List<GenericAttachmentModel> attachmentList;
const AssetDeliveryAttachmentView({ AssetDeliveryAttachmentView({
super.key, super.key,
this.lineId, required this.attachmentList,
this.requestId, this.viewOnly=false,
this.attachmentType,
this.tableItemId, this.tableItemId,
this.isHmg,
}); });
@override @override
@ -52,15 +55,17 @@ class _AssetDeliveryAttachmentViewState extends State<AssetDeliveryAttachmentVie
void getInitialData() async { void getInitialData() async {
///get previoues Attachment from Apis. ///get previoues Attachment from Apis.
isLoading = true; // isLoading = true;
setState(() {}); setState(() {});
_attachments = await assetDeliveryProvider.getAttachments(tableItemId: widget.tableItemId); _attachments = widget.attachmentList;
isLoading = false; // await assetDeliveryProvider.getAttachments(tableItemId: widget.tableItemId, attachmentType: widget.attachmentType);
// isLoading = false;
setState(() {}); setState(() {});
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
log('value ${widget.attachmentType}');
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar( appBar: DefaultAppBar(
@ -69,58 +74,79 @@ class _AssetDeliveryAttachmentViewState extends State<AssetDeliveryAttachmentVie
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
body: isLoading body: widget.attachmentList.isEmpty
? const CircularProgressIndicator(color: AppColor.primary10).center ? const NoDataFound().center
: Column( : Column(
children: [ children: [
AttachmentPicker( Flexible(
label: context.translation.attachments, fit: FlexFit.loose, // expands only as much as needed
attachment: _attachments, child: Column(
buttonColor: AppColor.primary10, children: [
onlyImages: false, widget.attachmentType == 5 && !widget.viewOnly
// showAsGrid: true, ? AttachmentPicker(
buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10), label: context.translation.attachments,
onChange: (attachment) {}, attachment: _attachments,
) buttonColor: AppColor.primary10,
.toShadowContainer( onlyImages: false,
context, showAsListView: true,
borderRadius: 20, buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10),
padding: 12, onChange: (attachment) {},
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), ).toShadowContainer(
) context,
.expanded, borderRadius: 20,
padding: 12,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
)
: FilesList(images: _attachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []).toShadowContainer(
context,
borderRadius: 20,
padding: 12,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
),
],
),
),
FooterActionButton.footerContainer( FooterActionButton.footerContainer(
context: context, context: context,
child: AppFilledButton( child: AppFilledButton(
buttonColor: AppColor.primary10, buttonColor: AppColor.primary10,
label: 'Save'.addTranslation, label: 'Save'.addTranslation,
maxWidth: true, maxWidth: true,
onPressed: () async { onPressed: _onSavePressed,
List<GenericAttachmentModel> attachement = []; ),
for (var item in _attachments) {
String fileName =
CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
attachement.add(GenericAttachmentModel(id: item.id ?? 0, name: fileName));
}
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
Map<String,dynamic> payLoad ={
'assetDeliveryExternalDeliveryId': widget.tableItemId,
'attachments':attachement,
};
await assetDeliveryProvider.saveAttachment(payload:payLoad).then((status) async {
Navigator.pop(context);
if (status) {
///Need to verify need to stay on this page and refresh or go back..
Navigator.pop(context);
// assetDeliveryProvider.getDeliveryLinesListById(
// itemId: widget.tableItemId,
// );
}
});
}),
), ),
], ],
), ),
); );
} }
Future<void> _onSavePressed() async {
final List<GenericAttachmentModel> attachmentPayload = _attachments.map((item) {
final String name = CMRequestUtils.isLocalUrl(item.name ?? '') ? '${item.name?.split("/").last}|${base64Encode(File(item.name!).readAsBytesSync())}' : item.name ?? '';
return GenericAttachmentModel(
id: item.id ?? 0,
name: name,
);
}).toList();
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => const AppLazyLoading(),
);
final payload = {
'assetDeliveryExternalDeliveryId': widget.tableItemId,
'attachments': attachmentPayload,
};
final status = await assetDeliveryProvider.saveAttachment(payload: payload);
Navigator.pop(context);
if (status) {
Navigator.pop(context);
}
}
} }

@ -1,5 +1,3 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.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';
@ -21,7 +19,7 @@ class AssetDeliveryBottomSheet {
); );
} }
static Future changeStatusBottomSheet({required BuildContext context,required VoidCallback cancelStatusTap,required VoidCallback statusChangeTap}) { static Future changeStatusBottomSheet({required BuildContext context, required VoidCallback cancelStatusTap, required VoidCallback statusChangeTap}) {
return buildBottomSheetParent( return buildBottomSheetParent(
context: context, context: context,
childWidget: Column( childWidget: Column(
@ -31,14 +29,17 @@ class AssetDeliveryBottomSheet {
8.height, 8.height,
Align( Align(
alignment: AlignmentDirectional.centerStart, alignment: AlignmentDirectional.centerStart,
child: Text('Change Status'.addTranslation,style: TextStyle( child: Text(
fontSize: 21.toScreenWidth, 'Change Status'.addTranslation,
fontWeight: FontWeight.w500, style: TextStyle(
fontStyle: FontStyle.normal, fontSize: 21.toScreenWidth,
decoration: TextDecoration.none, fontWeight: FontWeight.w500,
),), fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
),
),
), ),
10.height, 16.height,
Row( Row(
children: [ children: [
AppFilledButton( AppFilledButton(
@ -50,14 +51,16 @@ class AssetDeliveryBottomSheet {
showBorder: true, showBorder: true,
onPressed: () async { onPressed: () async {
cancelStatusTap(); cancelStatusTap();
}, },
).expanded, ).expanded,
12.width, 12.width,
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: () { AppFilledButton(
statusChangeTap(); buttonColor: AppColor.green70,
label: 'Change Status'.addTranslation,
}).expanded, maxWidth: true,
onPressed: () {
statusChangeTap();
}).expanded,
], ],
), ),
], ],

@ -1,6 +1,3 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
@ -11,6 +8,7 @@ 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/lookup.dart'; import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.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';
@ -48,8 +46,9 @@ class CostCenterFormView extends StatefulWidget {
} }
class _CostCenterFormViewState extends State<CostCenterFormView> { class _CostCenterFormViewState extends State<CostCenterFormView> {
List<CostCenterModel> _list = []; CostCenterSerialNoFormModel formModel = CostCenterSerialNoFormModel(costCenters: [], serialNos: []);
late AssetDeliveryProvider assetDeliveryProvider; late AssetDeliveryProvider assetDeliveryProvider;
CostCenterType _selectedType = CostCenterType.costCenter;
@override @override
void initState() { void initState() {
@ -61,15 +60,20 @@ class _CostCenterFormViewState extends State<CostCenterFormView> {
} }
void getInitialData() async { void getInitialData() async {
_list = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines( formModel = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines(
lineId: widget.lineId, lineId: widget.lineId,
tableItemId: widget.tableItemId, tableItemId: widget.tableItemId,
); );
if (_list.isEmpty) { if (formModel.costCenters!.isEmpty) {
_list.add(CostCenterModel( formModel.costCenters!.add(CostCenterModel(
id: 0, id: 0,
)); ));
} }
// if (formModel.serialNos!.isEmpty) {
// formModel.serialNos!.add(SerialNoModel(
// id: 0,
// ));
// }
if (widget.isHmg == true) { if (widget.isHmg == true) {
CostCenterProvider costCenterProvider = Provider.of<CostCenterProvider>(context, listen: false); CostCenterProvider costCenterProvider = Provider.of<CostCenterProvider>(context, listen: false);
if (costCenterProvider.items.isEmpty) { if (costCenterProvider.items.isEmpty) {
@ -79,21 +83,21 @@ class _CostCenterFormViewState extends State<CostCenterFormView> {
setState(() {}); setState(() {});
} }
void _addNewEntry() { void addItem<T>(List<T> list, T Function() creator) {
setState(() { setState(() {
_list.add(CostCenterModel(costCenter: Lookup())); list.add(creator());
}); });
} }
void _removeEntry(int index) { void removeItem<T>(List<T> list, int index) {
setState(() { setState(() {
_list.removeAt(index); list.removeAt(index);
}); });
} }
void _updateModel(int index, void Function(CostCenterModel model) updateList) { void updateItem<T>(List<T> list, int index, void Function(T item) updater) {
setState(() { setState(() {
updateList(_list[index]); updater(list[index]);
}); });
} }
@ -103,102 +107,207 @@ class _CostCenterFormViewState extends State<CostCenterFormView> {
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar( appBar: DefaultAppBar(
title: 'Cost Center for Item'.addTranslation, title: 'Cost Center for Item'.addTranslation,
onBackPress: () { // onBackPress: () {
Navigator.pop(context); // Navigator.pop(context);
}, // },
), ),
body: Consumer<AssetDeliveryProvider>(builder: (context, provider, child) { body: Consumer<AssetDeliveryProvider>(builder: (context, provider, child) {
return Column( return provider.isLoading
children: [ ? const CircularProgressIndicator(color: AppColor.primary10).center
itemDetails(context: context, itemNo: widget.itemNo, itemDescription: widget.itemDescription), : Column(
provider.isLoading children: [
? const CircularProgressIndicator(color: AppColor.primary10).center itemDetails(),
: ListView.builder( selectionButton(),
itemCount: _list.length + 1, _selectedType == CostCenterType.costCenter ? _buildCostCenterList() : _buildSerialNumberList(),
shrinkWrap: true, FooterActionButton.footerContainer(
padding: EdgeInsets.all(widget.cardPadding ?? 16), context: context,
itemBuilder: (context, index) { child: AppFilledButton(
if (index == _list.length) { buttonColor: AppColor.primary10,
return Visibility( label: 'Save'.addTranslation,
child: AppFilledButton( maxWidth: true,
label: "Add Cost Center".addTranslation, onPressed: () async {
maxWidth: true, showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
textColor: AppColor.textColor(context), await assetDeliveryProvider
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, .saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: formModel.costCenters, serialNoList: formModel.serialNos)
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), .then((status) async {
showIcon: true, Navigator.pop(context);
onPressed: _addNewEntry, if (status) {
), Navigator.pop(context);
); assetDeliveryProvider.getDeliveryLinesListById(
} itemId: widget.tableItemId,
return CostCenterItemCard( );
model: _list[index], }
index: index, });
isReadOnly: false, }),
isHmg: widget.isHmg, ),
requestId: widget.requestId, ],
onUpdate: (updateList) => _updateModel(index, updateList), );
onRemove: () => _removeEntry(index),
);
},
).expanded,
8.height,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: 'Save'.addTranslation,
maxWidth: true,
onPressed: () async {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await assetDeliveryProvider.saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: _list).then((status) async {
Navigator.pop(context);
if (status) {
Navigator.pop(context);
assetDeliveryProvider.getDeliveryLinesListById(
itemId: widget.tableItemId,
);
}
});
}),
),
],
);
}), }),
); );
} }
}
Widget itemDetails({required BuildContext context, String? itemNo, String? itemDescription}) { Widget _buildCostCenterList() {
return Column( return ListView.builder(
crossAxisAlignment: CrossAxisAlignment.start, itemCount: formModel.costCenters!.length + 1,
children: [ shrinkWrap: true,
Text( padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
'Item No'.addTranslation, itemBuilder: (context, index) {
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), if (index == formModel.costCenters!.length) {
), return AppFilledButton(
8.height, label: "Add Cost Center".addTranslation,
Text( maxWidth: true,
itemNo ?? '-', textColor: AppColor.textColor(context),
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
), icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
8.height, showIcon: true,
Text( onPressed: () {
'Item Description'.addTranslation, addItem(formModel.costCenters!, () => CostCenterModel(costCenter: Lookup()));
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), },
);
}
return CostCenterItemCard(
model: formModel.costCenters![index],
index: index,
isReadOnly: false,
isHmg: widget.isHmg,
requestId: widget.requestId,
onUpdate: (update) {
updateItem<CostCenterModel>(formModel.costCenters!, index, update);
},
onRemove: () {
removeItem<CostCenterModel>(formModel.costCenters!, index);
},
);
},
).expanded;
}
Widget _buildSerialNumberList() {
return ListView.builder(
itemCount: formModel.serialNos!.length + 1,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
itemBuilder: (context, index) {
if (index == formModel.serialNos!.length) {
return AppFilledButton(
label: "Add Serial Number".addTranslation,
maxWidth: true,
textColor: AppColor.textColor(context),
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: () {
addItem(formModel.serialNos!, () => SerialNoModel());
},
);
}
return SerialNumberItemCard(
model: formModel.serialNos![index],
onUpdate: (update) {
updateItem<SerialNoModel>(formModel.serialNos!, index, update);
},
onRemove: () {
removeItem<SerialNoModel>(formModel.serialNos!, index);
},
);
},
).expanded;
}
Widget selectionButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
children: [
Expanded(
child: _radioItem(
value: CostCenterType.costCenter,
groupValue: _selectedType,
title: 'Cost Center',
onTap: () {
setState(() {
_selectedType = CostCenterType.costCenter;
});
},
),
),
Expanded(
child: _radioItem(
value: CostCenterType.serialNumber,
groupValue: _selectedType,
title: 'Serial Number',
onTap: () {
setState(() {
_selectedType = CostCenterType.serialNumber;
});
},
),
),
],
), ),
8.height, );
Text( }
itemDescription ?? '-',
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), Widget _radioItem({
required CostCenterType value,
required CostCenterType groupValue,
required String title,
required VoidCallback onTap,
}) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap,
child: Row(
children: [
Radio<CostCenterType>(
value: value,
groupValue: groupValue,
onChanged: (_) => onTap(),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact,
),
4.width,
title.addTranslation.bodyText(context),
],
), ),
], );
).toShadowContainer( }
context,
borderRadius: 20, Widget itemDetails() {
padding: 12, return Column(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), crossAxisAlignment: CrossAxisAlignment.start,
); mainAxisSize: MainAxisSize.min,
children: [
Text(
'Item No'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
),
8.height,
Text(
widget.itemNo ?? '-',
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
),
8.height,
Text(
'Item Description'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
),
8.height,
Text(
widget.itemDescription ?? '-',
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
),
],
).toShadowContainer(
context,
borderRadius: 20,
padding: 12,
showShadow: false,
margin: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 8),
);
}
} }
class CostCenterItemCard extends StatelessWidget { class CostCenterItemCard extends StatelessWidget {
@ -293,6 +402,56 @@ class CostCenterItemCard extends StatelessWidget {
], ],
) )
], ],
).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)).paddingOnly(bottom: 12); ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12)).paddingOnly(bottom: 12);
}
}
class SerialNumberItemCard extends StatelessWidget {
final SerialNoModel model;
final VoidCallback onRemove;
final void Function(void Function(SerialNoModel model)) onUpdate;
const SerialNumberItemCard({
super.key,
required this.model,
required this.onRemove,
required this.onUpdate,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
'Serial Number'.addTranslation.bodyText(context),
Container(
height: 28,
width: 28,
padding: const EdgeInsets.all(6),
child: "trash".toSvgAsset(height: 20, width: 20),
).onPress(onRemove),
],
),
8.height,
AppTextFormField(
labelText: 'Serial Number'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.serialNo ?? '',
textAlign: TextAlign.center,
showShadow: false,
onChange: (value) {
model.serialNo = value;
},
style: Theme.of(context).textTheme.titleMedium,
),
],
)
.toShadowContainer(
context,
paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
)
.paddingOnly(bottom: 12);
} }
} }

@ -1,27 +1,33 @@
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/enum_extensions.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/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/lookup.dart';
import 'package:test_sa/modules/asset_delivery_module/helper_function.dart';
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.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/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_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.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/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart';
@ -85,12 +91,12 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar( // appBar: DefaultAppBar(
title: 'Delivery Inspection'.addTranslation, // title: 'Delivery Inspection'.addTranslation,
onBackPress: () { // onBackPress: () {
Navigator.pop(context); // Navigator.pop(context);
}, // },
), // ),
body: isLoading body: isLoading
? const CircularProgressIndicator(color: AppColor.primary10).center ? const CircularProgressIndicator(color: AppColor.primary10).center
: Form( : Form(
@ -110,9 +116,16 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
), ),
8.height, 8.height,
Text( Text(
model.totalTime != null ? '${model.totalTime.toString()} hours' : '-', formatInspectionDuration(model.totalTime),
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), style: AppTextStyles.bodyText2.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral120,
),
), ),
// Text(
// model.totalTime != null ? '${model.totalTime.toString()} hours' : '-',
// style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
// ),
8.height, 8.height,
const Divider().defaultStyle(context), const Divider().defaultStyle(context),
Text( Text(
@ -124,32 +137,50 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
], ],
).toShadowContainer(context, borderRadius: 20, padding: 12)) ).toShadowContainer(context, borderRadius: 20, padding: 12))
.expanded, .expanded,
if (!viewOnly) ...[
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap),
),
8.height,
],
FooterActionButton.footerContainer( FooterActionButton.footerContainer(
context: context, context: context,
child: !viewOnly child: !viewOnly
? Row( ? Column(
children: [ children: [
AppFilledButton( AppFilledButton(
label: 'Cancel'.addTranslation, buttonColor: AppColor.primary10,
maxWidth: true, label: 'Attachments'.addTranslation,
buttonColor: AppColor.background(context), maxWidth: true,
// textColor: context.isDark ? AppColor.neutral30 : Colors.white, onPressed: () {
textColor: AppColor.red30, HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
showBorder: true, }),
onPressed: _cancelTap, 16.height,
).expanded, Row(
12.width, children: [
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, AppFilledButton(
label: 'Cancel'.addTranslation,
maxWidth: true,
buttonColor: AppColor.background(context),
// textColor: context.isDark ? AppColor.neutral30 : Colors.white,
textColor: AppColor.red30,
showBorder: true,
onPressed: _cancelTap,
).expanded,
12.width,
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded,
],
),
], ],
) )
: AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap), : Row(
children: [
AppFilledButton(
buttonColor: AppColor.white60,
label: 'Attachments'.addTranslation,
maxWidth: true,
textColor: AppColor.black10,
onPressed: () {
HelperFunction.attachmentTap(context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
}).expanded,
8.width,
AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded,
],
),
), ),
], ],
), ),
@ -195,69 +226,132 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
} }
void calculateTotalTime() { void calculateTotalTime() {
if (model.deliveryInspectionInspectedDateFrom == null || model.deliveryInspectionInspectedDateTo == null) { final from = model.deliveryInspectionInspectedDateFrom;
final to = model.deliveryInspectionInspectedDateTo;
if (from == null || to == null) {
model.totalTime = null; model.totalTime = null;
return; return;
} }
final fromDate = model.deliveryInspectionInspectedDateFrom!;
final toDate = model.deliveryInspectionInspectedDateTo!; final diffInSeconds = to.difference(from).inSeconds;
final hours = toDate.difference(fromDate).inSeconds / 3600.0;
if (diffInSeconds < 0) {
model.totalTime = null;
return;
}
final hours = diffInSeconds / 3600;
model.totalTime = num.parse(hours.toStringAsFixed(3)); model.totalTime = num.parse(hours.toStringAsFixed(3));
} }
Widget inspectionDetailsForm() { Widget inspectionDetailsForm() {
return Column( return Column(
children: [ children: [
if (widget.requestModel?.isHMG == true) ...[ _inspectionTile(
OracleUserAutoCompleteField( title: 'Inspected by'.addTranslation,
clearAfterPick: false, model: model.inspectedByModel,
initialValue: model.deliveryInspectionInspectedBy ?? '', isHmg: widget.requestModel?.isHMG == true,
label: 'Inspected by'.addTranslation, onTap: () async {
onPick: (value) { final result = await showInspectionBottomSheet(
model.deliveryInspectionInspectedBy = value.fullName; context,
setState(() {}); title: 'Inspected by'.addTranslation,
}, isHmg: widget.requestModel?.isHMG == true,
onChanged: (value) {}, initialModel: model.inspectedByModel ?? InspectionPersonModel(),
), );
8.height, if (result != null) {
OracleUserAutoCompleteField( setState(() => model.inspectedByModel = result);
clearAfterPick: false, }
initialValue: model.deliveryInspectionApprovedBy ?? '', },
label: 'Approved by'.addTranslation, ),
onChanged: (value) {},
onPick: (value) { 8.height,
model.deliveryInspectionApprovedBy = value.fullName; _inspectionTile(
setState(() {}); title: 'Approved by'.addTranslation,
}, model: model.approvedByModel,
), isHmg: widget.requestModel?.isHMG == true,
] //No HMG user free text insted of dropdown ... onTap: () async {
else ...[ final result = await showInspectionBottomSheet(
AppTextFormField( context,
labelText: 'Inspected by'.addTranslation, title: 'Approved by'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context), isHmg: widget.requestModel?.isHMG == true,
initialValue: model.deliveryInspectionInspectedBy ?? '', initialModel: model.approvedByModel ?? InspectionPersonModel(),
textAlign: TextAlign.center, );
labelStyle: AppTextStyles.textFieldLabelStyle, if (result != null) {
showShadow: false, setState(() => model.approvedByModel = result);
onChange: (value) { }
model.deliveryInspectionInspectedBy = value; },
}, ),
style: Theme.of(context).textTheme.titleMedium, if (widget.requestModel?.paymentTerm?.value == 2) ...[
),
8.height, 8.height,
AppTextFormField( _inspectionTile(
labelText: 'Approved by'.addTranslation, title: 'Third Approved by'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context), model: model.thirdApprovalModel,
initialValue: model.deliveryInspectionApprovedBy ?? '', isHmg: widget.requestModel?.isHMG == true,
textAlign: TextAlign.center, onTap: () async {
labelStyle: AppTextStyles.textFieldLabelStyle, final result = await showInspectionBottomSheet(
showShadow: false, context,
onChange: (value) { title: 'Third Approved by'.addTranslation,
model.deliveryInspectionApprovedBy = value; isHmg: widget.requestModel?.isHMG == true,
initialModel: model.thirdApprovalModel ?? InspectionPersonModel(),
);
if (result != null) {
setState(() => model.thirdApprovalModel = result);
}
}, },
style: Theme.of(context).textTheme.titleMedium,
), ),
], ],
// if (widget.requestModel?.isHMG == true) ...[
// OracleUserAutoCompleteField(
// clearAfterPick: false,
// initialValue: model.deliveryInspectionInspectedBy ?? '',
// label: 'Inspected by'.addTranslation,
// onPick: (value) {
// model.deliveryInspectionInspectedBy = value.fullName;
// setState(() {});
// },
// onChanged: (value) {},
// ),
// 8.height,
// OracleUserAutoCompleteField(
// clearAfterPick: false,
// initialValue: model.deliveryInspectionApprovedBy ?? '',
// label: 'Approved by'.addTranslation,
// onChanged: (value) {},
// onPick: (value) {
// model.deliveryInspectionApprovedBy = value.fullName;
// setState(() {});
// },
// ),
// ] //No HMG user free text insted of dropdown ...
// else ...[
// AppTextFormField(
// labelText: 'Inspected by'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: model.deliveryInspectionInspectedBy ?? '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// showShadow: false,
// onChange: (value) {
// model.deliveryInspectionInspectedBy = value;
// },
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// AppTextFormField(
// labelText: 'Approved by'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: model.deliveryInspectionApprovedBy ?? '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// showShadow: false,
// onChange: (value) {
// model.deliveryInspectionApprovedBy = value;
// },
// style: Theme.of(context).textTheme.titleMedium,
// ),
// ],
8.height, 8.height,
ADatePicker( ADatePicker(
label: 'Inspected Date/Time From'.addTranslation, label: 'Inspected Date/Time From'.addTranslation,
@ -267,52 +361,31 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
date: model.deliveryInspectionInspectedDateFrom, date: model.deliveryInspectionInspectedDateFrom,
from: DateTime(DateTime.now().year, 1, 1), from: DateTime(DateTime.now().year, 1, 1),
formatDateWithTime: true, formatDateWithTime: true,
onDatePicker: (selectedDate) { onDatePicker: (selectedDate) async {
showTimePicker( final selectedTime = await showTimePicker(
context: context, context: context,
initialTime: TimeOfDay.now(), initialTime: TimeOfDay.now(),
builder: (BuildContext context, Widget? child) { builder: _timePickerThemeBuilder,
final ThemeData currentTheme = Theme.of(context); );
return Theme( if (selectedTime == null) return;
data: currentTheme.copyWith(
timePickerTheme: TimePickerThemeData( final fromDateTime = DateTime(
dialHandColor: AppColor.primary10, selectedDate.year,
dialBackgroundColor: Colors.grey.withOpacity(0.1), selectedDate.month,
hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), selectedDate.day,
dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), selectedTime.hour,
dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), selectedTime.minute,
dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), );
entryModeIconColor: AppColor.primary10,
), if (!_validateInspectionDates(from: fromDateTime, to: model.deliveryInspectionInspectedDateTo)) {
textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), return; // invalid, do not assign
), }
child: child!,
); model.deliveryInspectionInspectedDateFrom = fromDateTime;
}, setState(() {});
).then((selectedTime) {
if (selectedTime != null) {
model.deliveryInspectionInspectedDateFrom = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
// calculateTotalTime();
///need to check if need validation or not.
// if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) {
// "Start time is before the request time.".showToast;
// _pickerStartAt = null;
// selectedTime = null;
// return;
// }
if (model.deliveryInspectionInspectedDateFrom!.isAfter(DateTime.now())) {
"Start time is after than current time".showToast;
model.deliveryInspectionInspectedDateFrom = null;
selectedTime = null;
return;
}
setState(() {});
}
});
}, },
), ),
8.height, 8.height,
ADatePicker( ADatePicker(
label: 'Inspected Date/Time To'.addTranslation, label: 'Inspected Date/Time To'.addTranslation,
@ -322,55 +395,120 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
date: model.deliveryInspectionInspectedDateTo, date: model.deliveryInspectionInspectedDateTo,
from: model.deliveryInspectionInspectedDateFrom, from: model.deliveryInspectionInspectedDateFrom,
formatDateWithTime: true, formatDateWithTime: true,
onDatePicker: (selectedDate) { onDatePicker: (selectedDate) async {
showTimePicker( if (model.deliveryInspectionInspectedDateFrom == null) {
"Please select time to first".showToast;
return;
}
final selectedTime = await showTimePicker(
context: context, context: context,
initialTime: TimeOfDay.now(), initialTime: TimeOfDay.now(),
builder: (BuildContext context, Widget? child) { builder: _timePickerThemeBuilder,
final ThemeData currentTheme = Theme.of(context); );
return Theme( if (selectedTime == null) return;
data: currentTheme.copyWith(
timePickerTheme: TimePickerThemeData( final toDateTime = DateTime(
dialHandColor: AppColor.primary10, selectedDate.year,
dialBackgroundColor: Colors.grey.withOpacity(0.1), selectedDate.month,
hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), selectedDate.day,
dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), selectedTime.hour,
dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), selectedTime.minute,
dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), );
entryModeIconColor: AppColor.primary10,
), if (!_validateInspectionDates(from: model.deliveryInspectionInspectedDateFrom, to: toDateTime)) {
textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), return; // invalid, do not assign
), }
child: child!,
); model.deliveryInspectionInspectedDateTo = toDateTime;
}, setState(() {});
).then((selectedTime) {
if (selectedTime != null) {
model.deliveryInspectionInspectedDateTo = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
calculateTotalTime();
///Need to check need validation or not..
// if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) {
// "Start time is before the request time.".showToast;
// _pickerStartAt = null;
// selectedTime = null;
// return;
// }
if (model.deliveryInspectionInspectedDateTo!.isAfter(DateTime.now())) {
"End time is after than current time".showToast;
model.deliveryInspectionInspectedDateTo = null;
selectedTime = null;
return;
}
setState(() {});
}
});
}, },
), ),
], ],
); );
} }
bool _validateInspectionDates({DateTime? from, DateTime? to}) {
if (from == null && to == null) return true;
if (from != null) {
if (from.isAfter(DateTime.now())) {
"Time From cannot be in the future".showToast;
return false;
}
if (to != null && from.isAfter(to)) {
"Time To cannot be after Time From".showToast;
return false;
}
}
if (to != null) {
if (to.isAfter(DateTime.now())) {
"Time To cannot be in the future".showToast;
return false;
}
if (from != null && to.isBefore(from)) {
"Timer To cannot be before from time".showToast;
return false;
}
}
if (from != null && to != null) {
final diffInSeconds = to.difference(from).inSeconds;
if (diffInSeconds < 0) {
model.totalTime = null;
return false;
}
final hours = diffInSeconds / 3600.0;
model.totalTime = num.parse(hours.toStringAsFixed(3));
} else {
model.totalTime = null;
}
return true;
}
String formatInspectionDuration(num? hours) {
if (hours == null) return '-';
if (hours < 1) {
final minutes = (hours * 60).round();
return '$minutes minutes';
}
return '${hours.toStringAsFixed(2)} hours';
}
Widget _timePickerThemeBuilder(BuildContext context, Widget? child) {
final ThemeData currentTheme = Theme.of(context);
return Theme(
data: currentTheme.copyWith(
timePickerTheme: TimePickerThemeData(
dialHandColor: AppColor.primary10,
dialBackgroundColor: Colors.grey.withOpacity(0.1),
hourMinuteColor: MaterialStateColor.resolveWith(
(states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1),
),
dayPeriodColor: MaterialStateColor.resolveWith(
(states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent,
),
dayPeriodTextColor: MaterialStateColor.resolveWith(
(states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10,
),
dayPeriodBorderSide: BorderSide(
color: Colors.grey.withOpacity(0.2),
),
entryModeIconColor: AppColor.primary10,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: AppColor.primary10,
),
),
),
child: child!,
);
}
Widget inspectionDetails() { Widget inspectionDetails() {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -418,13 +556,69 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
); );
} }
void _attachmentTap() async { Widget _inspectionTile({
Navigator.push( required String title,
context, InspectionPersonModel? model,
MaterialPageRoute( required bool isHmg,
builder: (context) => AssetDeliveryAttachmentView( required VoidCallback onTap,
tableItemId: widget.deliveryTableModel.id, }) {
))); return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: AppTextStyles.textFieldLabelStyle),
6.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
model?.name?.isNotEmpty == true ? model!.name! : 'Tap to add'.addTranslation,
style: AppTextStyles.bodyText,
),
///Need to display other info as well
// Text(
// model?.email?.isNotEmpty == true
// ? model!.email!
// : '',
// style: AppTextStyles.bodyText,
// ),
],
),
],
),
],
),
),
);
}
Future<Lookup?> showAttachmentTypePicker() {
return showDialog<Lookup>(
context: context,
builder: (_) {
return AlertDialog(
content: SingleItemDropDownMenu<Lookup, AttachmentTypeLookupProvider>(
context: context,
title: context.translation.reason,
showAsFullScreenDialog: false,
onSelect: (value) {
Navigator.pop(context, value);
},
),
);
},
);
} }
void _cancelTap() async { void _cancelTap() async {
@ -440,21 +634,44 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
void _nextTap() { void _nextTap() {
if (widget.deliveryTableModel.isContainsTechnicalInspection == true) { if (widget.deliveryTableModel.isContainsTechnicalInspection == true) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => TechnicalInspectionLinesListView(
// deliveryTableModel: widget.deliveryTableModel,
// requestModel: widget.requestModel,
// ))
// );
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => TechnicalInspectionLinesListView( builder: (context) => AssetDeliveryStageTabPage(
deliveryTableModel: widget.deliveryTableModel, title: 'Technical Inspection'.addTranslation,
requestModel: widget.requestModel, detailWidget: TechnicalInspectionLinesListView(
deliveryTableModel: widget.deliveryTableModel,
requestModel: widget.requestModel,
),
tableId: widget.deliveryTableModel.id,
))); )));
} else { } else {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => EndUserCostCenterLIstView( builder: (context) => AssetDeliveryStageTabPage(
deliveryTableModel: widget.deliveryTableModel, title: 'End-User Acceptance'.addTranslation,
requestModel: widget.requestModel, detailWidget: EndUserCostCenterLIstView(
deliveryTableModel: widget.deliveryTableModel,
requestModel: widget.requestModel,
),
tableId: widget.deliveryTableModel.id,
))); )));
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => EndUserCostCenterLIstView(
// deliveryTableModel: widget.deliveryTableModel,
// requestModel: widget.requestModel,
// )));
} }
} }
@ -470,4 +687,40 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
} }
}); });
} }
Future<InspectionPersonModel?> showInspectionBottomSheet(
BuildContext context, {
required String title,
required bool isHmg,
required InspectionPersonModel initialModel,
}) {
return showModalBottomSheet<InspectionPersonModel>(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (_) {
if (initialModel.localSignature == null && initialModel.signature != null) {
initialModel.localSignature = signatureFromString(initialModel.signature);
}
return InspectionPersonBottomSheet(
title: title,
isHmg: isHmg,
model: InspectionPersonModel(
name: initialModel.name,
email: initialModel.email,
signature: initialModel.signature,
localSignature: initialModel.localSignature,
),
);
},
);
}
Uint8List? signatureFromString(String? value) {
if (value == null || !value.contains('|')) return null;
final base64Part = value.split('|').last;
return base64Decode(base64Part);
}
} }

@ -0,0 +1,152 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.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/modules/asset_delivery_module/models/inspection_person_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.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/e_signature/e_signature.dart';
class InspectionPersonBottomSheet extends StatefulWidget {
final String title;
bool isHmg;
final InspectionPersonModel model;
InspectionPersonBottomSheet({
super.key,
required this.title,
required this.isHmg,
required this.model,
});
@override
State<InspectionPersonBottomSheet> createState() => _InspectionPersonBottomSheetState();
}
class _InspectionPersonBottomSheetState extends State<InspectionPersonBottomSheet> {
late InspectionPersonModel _model;
late TextEditingController nameController;
late TextEditingController emailController;
@override
void initState() {
super.initState();
_model = InspectionPersonModel(name: widget.model.name, email: widget.model.email, signature: widget.model.signature, localSignature: widget.model.localSignature);
nameController = TextEditingController(text: _model.name ?? '');
emailController = TextEditingController(text: _model.email ?? '');
}
@override
void dispose() {
nameController.dispose();
emailController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SafeArea(
top: false,
child: Padding(
padding: EdgeInsets.only(
top: 16,
left: 16,
right: 16,
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(widget.title, style: Theme.of(context).textTheme.titleLarge),
16.height,
if (widget.isHmg)
OracleUserAutoCompleteField(
clearAfterPick: false,
initialValue: _model.name ?? '',
label: 'Name'.addTranslation,
onPick: (value) {
_model.name = value.fullName;
nameController.text = value.fullName ?? '';
emailController.text = value.employeeEmail ?? '';
setState(() {});
},
)
else
AppTextFormField(
labelText: 'Name'.addTranslation,
controller: nameController,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
onChange: (v) {
_model.name = v;
setState(() {});
},
),
12.height,
AppTextFormField(
labelText: 'Email'.addTranslation,
controller: emailController,
textInputType: TextInputType.emailAddress,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
enable: widget.isHmg?false:true,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
onChange: (v) {
setState(() {
_model.email = v;
});
},
),
12.height,
ESignature(
title: '',
oldSignature: _model.localSignature == null ? _model.signature : null,
newSignature: _model.localSignature,
backgroundColor: AppColor.neutral100,
showShadow: false,
onChange: (signature) {
if (signature.isEmpty) return;
setState(() {
_model.localSignature = signature;
_model.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
});
},
onSaved: (signature) {
if (signature == null || signature.isEmpty) return;
setState(() {
_model.localSignature = signature;
_model.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
});
},
),
20.height,
AppFilledButton(
label: context.translation.save,
maxWidth: true,
buttonColor: AppColor.primary10,
onPressed: () async {
_model.name = nameController.text.trim();
_model.email = emailController.text.trim();
Navigator.pop(context, _model);
},
),
],
),
),
);
}
}

@ -26,25 +26,26 @@ class OracleUserAutoCompleteField extends StatefulWidget {
class _AutoCompletePartsFieldState extends State<OracleUserAutoCompleteField> { class _AutoCompletePartsFieldState extends State<OracleUserAutoCompleteField> {
AssetDeliveryProvider? assetDeliveryProvider; AssetDeliveryProvider? assetDeliveryProvider;
late TextEditingController _controller;
// late TextEditingController _controller;
@override @override
void initState() { void initState() {
_controller = TextEditingController(text: widget.initialValue); // _controller = TextEditingController(text: widget.initialValue);
super.initState(); super.initState();
} }
@override @override
void didUpdateWidget(covariant OracleUserAutoCompleteField oldWidget) { void didUpdateWidget(covariant OracleUserAutoCompleteField oldWidget) {
if (widget.initialValue != oldWidget.initialValue) { // if (widget.initialValue != oldWidget.initialValue) {
_controller = TextEditingController(text: widget.initialValue); // _controller = TextEditingController(text: widget.initialValue);
} // }
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
} }
@override @override
void dispose() { void dispose() {
_controller.dispose(); // _controller.dispose();
super.dispose(); super.dispose();
} }
@ -59,16 +60,18 @@ class _AutoCompletePartsFieldState extends State<OracleUserAutoCompleteField> {
// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
), ),
child: Autocomplete<OracleUserModel>( child: Autocomplete<OracleUserModel>(
key: ValueKey(widget.initialValue),
optionsBuilder: (TextEditingValue textEditingValue) async { optionsBuilder: (TextEditingValue textEditingValue) async {
if (textEditingValue.text.isEmpty) { if (textEditingValue.text.isEmpty) {
return const Iterable<OracleUserModel>.empty(); return const Iterable<OracleUserModel>.empty();
} }
return await assetDeliveryProvider!.getOracleUserAutoCompleteDetails(query: textEditingValue.text); return await assetDeliveryProvider!.getOracleUserAutoCompleteDetails(query: textEditingValue.text);
}, },
initialValue: TextEditingValue(text: widget.initialValue),
displayStringForOption: (OracleUserModel option) => option.fullName ?? "", displayStringForOption: (OracleUserModel option) => option.fullName ?? "",
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: fieldTextEditingController,
focusNode: fieldFocusNode, focusNode: fieldFocusNode,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
textAlign: TextAlign.start, textAlign: TextAlign.start,
@ -101,11 +104,11 @@ class _AutoCompletePartsFieldState extends State<OracleUserAutoCompleteField> {
); );
}, },
onSelected: (OracleUserModel selection) { onSelected: (OracleUserModel selection) {
if (widget.clearAfterPick) { // if (widget.clearAfterPick) {
_controller.clear(); // fieldTextEditingController.clear();
} else { // } else {
_controller.text = selection.fullName ?? ''; // _controller.text = selection.fullName ?? '';
} // }
widget.onPick(selection); widget.onPick(selection);
}, },
), ),

@ -90,10 +90,12 @@ class EndUserAssetDetailCard extends StatelessWidget {
'Replaced Asset No: ${assetModel.replacedAssetNo ?? '-'}', 'Replaced Asset No: ${assetModel.replacedAssetNo ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
), ),
Text( //TODO Need to confirm with @Ahmed need to hide this or not
'Rejection Reason: ${assetModel.rejectionReason?.name ?? '-'}', if (assetModel.status?.value == 2)
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), Text(
), 'Rejection Reason: ${assetModel.rejectionReason?.name ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text( Text(
'Description: ${assetModel.description ?? '-'}', 'Description: ${assetModel.description ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),

@ -5,6 +5,7 @@ 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/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/modules/asset_delivery_module/helper_function.dart';
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart';
@ -71,10 +72,10 @@ class _EndUserCostCenterLIstViewState extends State<EndUserCostCenterLIstView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
appBar: DefaultAppBar( // appBar: DefaultAppBar(
title: 'End-User Acceptance'.addTranslation, // title: 'End-User Acceptance'.addTranslation,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), // titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
), // ),
body: Form( body: Form(
key: _formKey, key: _formKey,
child: isLoading child: isLoading
@ -83,31 +84,41 @@ class _EndUserCostCenterLIstViewState extends State<EndUserCostCenterLIstView> {
children: [ children: [
//Refactor this //Refactor this
SingleChildScrollView(padding: const EdgeInsets.all(16), child: linesList(context).toShadowContainer(context, borderRadius: 20, padding: 12)).expanded, SingleChildScrollView(padding: const EdgeInsets.all(16), child: linesList(context).toShadowContainer(context, borderRadius: 20, padding: 12)).expanded,
if (!viewOnly) ...[
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap),
),
8.height,
],
!viewOnly !viewOnly
? FooterActionButton.footerContainer( ? FooterActionButton.footerContainer(
context: context, context: context,
child: Row( child: Column(
children: [ children: [
AppFilledButton( AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap),
label: 'Cancel'.addTranslation, 16.height,
maxWidth: true, Row(
buttonColor: AppColor.background(context), children: [
textColor: AppColor.red30, AppFilledButton(
showBorder: true, label: 'Cancel'.addTranslation,
onPressed: _cancelTap, maxWidth: true,
).expanded, buttonColor: AppColor.background(context),
12.width, textColor: AppColor.red30,
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, showBorder: true,
onPressed: _cancelTap,
).expanded,
12.width,
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded,
],
),
], ],
)) ))
: const SizedBox(), : FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.white60,
label: 'Attachments'.addTranslation,
maxWidth: true,
textColor: AppColor.black10,
onPressed: () {
HelperFunction.attachmentTap(context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
}),
),
], ],
), ),
), ),
@ -156,12 +167,7 @@ class _EndUserCostCenterLIstViewState extends State<EndUserCostCenterLIstView> {
} }
void _attachmentTap() async { void _attachmentTap() async {
Navigator.push( HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
context,
MaterialPageRoute(
builder: (context) => AssetDeliveryAttachmentView(
tableItemId: widget.deliveryTableModel.id,
)));
} }
void _cancelTap() async { void _cancelTap() async {

@ -1,6 +1,229 @@
// import 'dart:developer';
//
// import 'package:flutter/foundation.dart';
// 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/lookup.dart';
// import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart';
// import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
// import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart';
// import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart';
// import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
// import 'package:test_sa/new_views/app_style/app_color.dart';
// import 'package:test_sa/new_views/common_widgets/app_lazy_loading.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 '../../../../new_views/common_widgets/app_filled_button.dart';
// import '../../../../new_views/common_widgets/default_app_bar.dart';
//
// class UpdateEndUserAssetDetailsView extends StatefulWidget {
// EndUserAssetDetailsModel? assetDetailsModel;
// String? costCenterName;
// int? tableId;
//
// UpdateEndUserAssetDetailsView({Key? key, this.assetDetailsModel, this.costCenterName, this.tableId}) : super(key: key);
//
// @override
// State<UpdateEndUserAssetDetailsView> createState() => _UpdateEndUserAssetDetailsViewState();
// }
//
// class _UpdateEndUserAssetDetailsViewState extends State<UpdateEndUserAssetDetailsView> {
// final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
// final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
// bool viewOnly = false;
// late AssetDeliveryProvider assetDeliveryProvider;
// EndUserAssetDetailsModel model = EndUserAssetDetailsModel();
// late TextEditingController quantityController;
// late TextEditingController descriptionController;
//
// @override
// void initState() {
// quantityController = TextEditingController();
// descriptionController = TextEditingController();
// WidgetsBinding.instance.addPostFrameCallback((_) {
// getInitialData();
// });
// super.initState();
// }
//
// @override
// void dispose() {
// super.dispose();
// }
//
// void getInitialData() async {
// assetDeliveryProvider = Provider.of<AssetDeliveryProvider>(context, listen: false);
// if (widget.assetDetailsModel != null) {
// model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson());
// model.costCenterName = widget.costCenterName;
// model.assetDeliveryExternalDeliveryId = widget.tableId;
// model.status = widget.assetDetailsModel?.status;
// model.rejectionReason = widget.assetDetailsModel?.rejectionReason;
// }
// quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : '';
// descriptionController.text = model.description ?? '';
// model.type = 'Accessory';
// setState(() {});
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// key: _scaffoldKey,
// appBar: DefaultAppBar(
// title: 'Item Details'.addTranslation,
// titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
// ),
// body: Form(
// key: _formKey,
// child: Column(
// children: [
// SingleChildScrollView(
// padding: const EdgeInsets.all(16),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// SingleItemDropDownMenu<Lookup, EndUserStatusLookupProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: 'Status'.addTranslation,
// titleTextColor: AppColor.neutral120,
// showShadow: false,
// validator: (value) {
// if (value == null) return "Please select status";
// return null;
// },
// backgroundColor: AppColor.fieldBgColor(context),
// showAsBottomSheet: true,
// initialValue: model.status,
// onSelect: (status) {
// if (status != null) {
// model.status = status;
// setState(() {});
// }
// },
// ),
// 8.height,
// if (model.type == 'Accessory') ...[
// AppTextFormField(
// labelText: 'Rejected Quantity'.addTranslation,
// controller: quantityController,
// backgroundColor: AppColor.fieldBgColor(context),
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// textInputType: TextInputType.number,
// showShadow: false,
// validator: (value) {
// if ((value ?? "").isEmpty) return "Mandatory";
// return null;
// },
// onChange: (value) {
// if (value.isNotEmpty) {
// model.rejectedQty = model.rejectedQty = num.tryParse(value);
// setState(() {});
// }
// },
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// if (model.status?.value == 1 && (model.rejectedQty != null && quantityController.text.isNotEmpty && model.rejectedQty! > 0))
// SingleItemDropDownMenu<Lookup, EndUserRejectionReasonLookupProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: 'Rejection Reason '.addTranslation,
// validator: (value) {
// if (value == null) return "Please select rejection reason";
// return null;
// },
// titleTextColor: AppColor.neutral120,
// showShadow: false,
// backgroundColor: AppColor.fieldBgColor(context),
// showAsBottomSheet: true,
// initialValue: model.rejectionReason,
// onSelect: (reason) {
// if (reason != null) {
// model.rejectionReason = reason;
// setState(() {});
// }
// },
// ),
// 8.height,
// ],
// if (model.status != null && model.status!.value == 2) ...[
// SingleItemDropDownMenu<Lookup, EndUserRejectionReasonLookupProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: 'Rejection Reason '.addTranslation,
// validator: (value) {
// if (value == null) return "Please select rejection reason";
// return null;
// },
// titleTextColor: AppColor.neutral120,
// showShadow: false,
// backgroundColor: AppColor.fieldBgColor(context),
// showAsBottomSheet: true,
// initialValue: model.rejectionReason,
// onSelect: (reason) {
// if (reason != null) {
// model.rejectionReason = reason;
// setState(() {});
// }
// },
// ),
// 8.height,
// ],
// AppTextFormField(
// controller: descriptionController,
// labelText: 'Description'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// showShadow: false,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// alignLabelWithHint: true,
// textInputType: TextInputType.multiline,
// onChange: (value) {
// model.description = value;
// },
// onSaved: (value) {
// model.description = value;
// },
// ),
// 8.height,
// ],
// ).toShadowContainer(context, borderRadius: 20, padding: 12))
// .expanded,
// FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
// ],
// ),
// ),
// );
// }
//
// ///Need to check which details show here...
//
// void _saveTap() async {
// if (!_formKey.currentState!.validate()) {
// return;
// }
// _formKey.currentState!.save();
// log('payload ${model.toJson()}');
// return;
// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
// await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async {
// Navigator.pop(context);
// if (status) {
// Navigator.pop(context, true);
// }
// });
// }
// }
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
@ -22,11 +245,16 @@ import '../../../../new_views/common_widgets/app_filled_button.dart';
import '../../../../new_views/common_widgets/default_app_bar.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart';
class UpdateEndUserAssetDetailsView extends StatefulWidget { class UpdateEndUserAssetDetailsView extends StatefulWidget {
EndUserAssetDetailsModel? assetDetailsModel; final EndUserAssetDetailsModel? assetDetailsModel;
String? costCenterName; final String? costCenterName;
int? tableId; final int? tableId;
UpdateEndUserAssetDetailsView({Key? key, this.assetDetailsModel, this.costCenterName, this.tableId}) : super(key: key); const UpdateEndUserAssetDetailsView({
Key? key,
this.assetDetailsModel,
this.costCenterName,
this.tableId,
}) : super(key: key);
@override @override
State<UpdateEndUserAssetDetailsView> createState() => _UpdateEndUserAssetDetailsViewState(); State<UpdateEndUserAssetDetailsView> createState() => _UpdateEndUserAssetDetailsViewState();
@ -34,147 +262,259 @@ class UpdateEndUserAssetDetailsView extends StatefulWidget {
class _UpdateEndUserAssetDetailsViewState extends State<UpdateEndUserAssetDetailsView> { class _UpdateEndUserAssetDetailsViewState extends State<UpdateEndUserAssetDetailsView> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
bool viewOnly = false;
late AssetDeliveryProvider assetDeliveryProvider; late AssetDeliveryProvider assetDeliveryProvider;
EndUserAssetDetailsModel model = EndUserAssetDetailsModel(); EndUserAssetDetailsModel model = EndUserAssetDetailsModel();
late TextEditingController quantityController; late TextEditingController quantityController;
late TextEditingController descriptionController; late TextEditingController descriptionController;
@override @override
void initState() { void initState() {
super.initState();
quantityController = TextEditingController(); quantityController = TextEditingController();
descriptionController = TextEditingController(); descriptionController = TextEditingController();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData(); _loadInitialData();
}); });
super.initState();
} }
@override void _loadInitialData() {
void dispose() {
super.dispose();
}
void getInitialData() async {
assetDeliveryProvider = Provider.of<AssetDeliveryProvider>(context, listen: false); assetDeliveryProvider = Provider.of<AssetDeliveryProvider>(context, listen: false);
if (widget.assetDetailsModel != null) { if (widget.assetDetailsModel != null) {
model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson()); model = EndUserAssetDetailsModel.fromJson(
widget.assetDetailsModel!.toJson(),
);
model.costCenterName = widget.costCenterName; model.costCenterName = widget.costCenterName;
model.assetDeliveryExternalDeliveryId = widget.tableId; model.assetDeliveryExternalDeliveryId = widget.tableId;
model.status = widget.assetDetailsModel?.status; model.status = widget.assetDetailsModel?.status;
model.rejectionReason = widget.assetDetailsModel?.rejectionReason; model.rejectionReason = widget.assetDetailsModel?.rejectionReason;
model.receivedQty = widget.assetDetailsModel?.receivedQty;
} }
quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : ''; quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : '';
descriptionController.text = model.description ?? ''; descriptionController.text = model.description ?? '';
setState(() {}); setState(() {});
} }
bool get _isAccessory => model.type == 'Accessory';
bool get _isAccepted => model.status?.value == 1;
bool get _isRejected => model.status?.value == 2;
bool get _showRejectedQty {
if (_isAccessory) return true;
return false;
}
bool get _showReceivedQty {
if (_isAccessory && model.receivedQty != null) return true;
return false;
}
bool get _showRejectionReason {
if (_isAccessory) {
if (_isRejected) return true;
if (_isAccepted && (model.rejectedQty ?? 0) > 0) return true;
return false;
}
if (_isRejected) return true;
return false;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar( appBar: DefaultAppBar(
title: 'Item Details'.addTranslation, title: 'Item Details'.addTranslation,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), titleStyle: AppTextStyles.heading3.copyWith(
fontWeight: FontWeight.w500,
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
),
), ),
body: Form( body: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Column( child: _formBody(context),
crossAxisAlignment: CrossAxisAlignment.start, ).expanded,
children: [ FooterActionButton.footerContainer(
SingleItemDropDownMenu<Lookup, EndUserStatusLookupProvider>( context: context,
context: context, child: AppFilledButton(
height: 56.toScreenHeight, buttonColor: AppColor.primary10,
title: 'Status'.addTranslation, label: 'Save'.addTranslation,
titleTextColor: AppColor.neutral120, maxWidth: true,
showShadow: false, onPressed: _saveTap,
backgroundColor: AppColor.fieldBgColor(context), ),
showAsBottomSheet: true, ),
initialValue: model.status,
onSelect: (status) {
if (status != null) {
model.status = status;
setState(() {});
}
},
),
8.height,
SingleItemDropDownMenu<Lookup, EndUserRejectionReasonLookupProvider>(
context: context,
height: 56.toScreenHeight,
title: 'Rejection Reason '.addTranslation,
titleTextColor: AppColor.neutral120,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: model.rejectionReason,
onSelect: (reason) {
if (reason != null) {
model.rejectionReason = reason;
setState(() {});
}
},
),
8.height,
if (model.type == 'Accessory') ...[
AppTextFormField(
labelText: 'Rejected Quantity'.addTranslation,
controller: quantityController,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number,
showShadow: false,
onChange: (value) {
if (value.isNotEmpty) {
model.rejectedQty = model.rejectedQty = num.tryParse(value);
}
},
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
],
AppTextFormField(
controller: descriptionController,
labelText: 'Description'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) {
model.description = value;
},
onSaved: (value) {
model.description = value;
},
),
8.height,
],
).toShadowContainer(context, borderRadius: 20, padding: 12))
.expanded,
FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
], ],
), ),
), ),
); );
} }
///Need to check which details show here... Widget _formBody(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_statusDropdown(),
8.height,
if (_showReceivedQty) ...[
_receivedQtyField(),
8.height,
],
if (_showRejectedQty) ...[
_rejectedQtyField(),
8.height,
],
if (_showRejectionReason) ...[
_rejectionReasonDropdown(),
8.height,
],
_descriptionField(),
8.height,
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
Widget _statusDropdown() {
return SingleItemDropDownMenu<Lookup, EndUserStatusLookupProvider>(
context: context,
height: 56.toScreenHeight,
title: 'Status'.addTranslation,
titleTextColor: AppColor.neutral120,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: model.status,
validator: (value) {
if (value == null) return 'Please select status';
return null;
},
onSelect: (status) {
if (status != null) {
model.status = status;
model.rejectionReason = null;
setState(() {});
}
},
);
}
Widget _rejectedQtyField() {
return AppTextFormField(
labelText: 'Rejected Quantity'.addTranslation,
controller: quantityController,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
validator: (value) {
if (!_showRejectedQty) return null;
if ((value ?? '').isEmpty) return 'Mandatory';
final qty = num.tryParse(value!);
if (qty == null || qty <= 0) return 'Enter valid quantity';
return null;
},
onChange: (value) {
model.rejectedQty = value.isNotEmpty ? num.tryParse(value) : null;
setState(() {});
},
);
}
Widget _receivedQtyField() {
return Container(
padding: const EdgeInsets.all(12),
width: double.infinity,
decoration: BoxDecoration(
color: AppColor.neutral40,
// color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Received Qty', style: AppTextStyles.textFieldLabelStyle),
4.height,
Text(model.receivedQty.toString(), style: AppTextStyles.textFieldLabelStyle),
],
),
);
AppTextFormField(
labelText: 'Received Quantity'.addTranslation,
initialValue: model.receivedQty.toString(),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
enable: false,
style: Theme.of(context).textTheme.titleMedium,
);
}
Widget _rejectionReasonDropdown() {
return SingleItemDropDownMenu<Lookup, EndUserRejectionReasonLookupProvider>(
context: context,
height: 56.toScreenHeight,
title: 'Rejection Reason'.addTranslation,
titleTextColor: AppColor.neutral120,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: model.rejectionReason,
validator: (value) {
if (!_showRejectionReason) return null;
if (value == null) return 'Please select rejection reason';
return null;
},
onSelect: (reason) {
if (reason != null) {
model.rejectionReason = reason;
setState(() {});
}
},
);
}
Widget _descriptionField() {
return AppTextFormField(
controller: descriptionController,
labelText: 'Description'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) => model.description = value,
onSaved: (value) => model.description = value,
);
}
void _saveTap() async { void _saveTap() async {
if (!_formKey.currentState!.validate()) return;
_formKey.currentState!.save(); _formKey.currentState!.save();
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); log('payload ${model.toJson()}');
await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async {
Navigator.pop(context); showDialog(
if (status) { context: context,
Navigator.pop(context, true); barrierDismissible: false,
} builder: (_) => const AppLazyLoading(),
}); );
final status = await assetDeliveryProvider.saveEndUserAssetDataData(model: model);
Navigator.pop(context);
if (status) {
Navigator.pop(context, true);
}
} }
} }

@ -235,16 +235,6 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
onChanged: (value) {}, onChanged: (value) {},
), ),
8.height, 8.height,
AppTextFormField(
labelText: 'Accepted By Email'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
controller: acceptedByEmailController,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
enable: false,
style: Theme.of(context).textTheme.titleMedium,
),
] else ...[ ] else ...[
AppTextFormField( AppTextFormField(
labelText: 'Accepted By'.addTranslation, labelText: 'Accepted By'.addTranslation,
@ -253,25 +243,34 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
textAlign: TextAlign.center, textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false, showShadow: false,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onChange: (value) { onChange: (value) {
model.acceptedBy = value; model.acceptedBy = value;
}, },
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
8.height, 8.height,
AppTextFormField(
labelText: 'Accepted By Email'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
controller: acceptedByEmailController,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
onChange: (value) {
model.acceptedByEmail = value;
},
style: Theme.of(context).textTheme.titleMedium,
),
], ],
AppTextFormField(
labelText: 'Accepted By Email'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
controller: acceptedByEmailController,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onChange: (value) {
model.acceptedByEmail = value;
},
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
enable: widget.isHmg == true ? false : true,
style: Theme.of(context).textTheme.titleMedium,
),
8.height, 8.height,
ESignature( ESignature(
title: 'End User Signature', title: 'End User Signature',
@ -280,11 +279,6 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
backgroundColor: AppColor.neutral100, backgroundColor: AppColor.neutral100,
showShadow: false, showShadow: false,
onChange: (signature) { onChange: (signature) {
log('onChange called.');
updateSignature(signature: signature);
},
onSaved: (signature) {
log('onSaved called.');
updateSignature(signature: signature); updateSignature(signature: signature);
}, },
) )
@ -294,7 +288,10 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
void updateSignature({Uint8List? signature}) { void updateSignature({Uint8List? signature}) {
if (signature == null || signature.isEmpty) { if (signature == null || signature.isEmpty) {
model.acceptedBySignature = ''; setState(() {
newSignature = null;
model.acceptedBySignature = null;
});
return; return;
} }
setState(() { setState(() {
@ -304,6 +301,23 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
} }
void _saveTap() async { void _saveTap() async {
if (!_formKey.currentState!.validate()) {
return;
}
if (model.acceptanceDate == null) {
"Select Accepted date".showToast;
return;
}
if (widget.isHmg == true) {
if ((model.acceptedBy ?? '').isEmpty || (model.acceptedByEmail ?? '').isEmpty) {
'Accepted By and Email are required'.addTranslation.showToast;
return;
}
}
if (model.acceptedBySignature == null || model.acceptedBySignature!.isEmpty) {
'Signature is required'.addTranslation.showToast;
return;
}
_formKey.currentState!.save(); _formKey.currentState!.save();
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
model.assetDeliveryExternalDetailId = widget.tableItemId; model.assetDeliveryExternalDetailId = widget.tableItemId;

@ -41,12 +41,12 @@ class _AssetDeliveryHistoryLogViewState extends State<AssetDeliveryHistoryLogVie
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar( // appBar: DefaultAppBar(
title: 'History Log'.addTranslation, // title: 'History Log'.addTranslation,
onBackPress: () { // onBackPress: () {
Navigator.pop(context); // Navigator.pop(context);
}, // },
), // ),
body: Consumer<AssetDeliveryProvider>(builder: (context, provider, _) { body: Consumer<AssetDeliveryProvider>(builder: (context, provider, _) {
return provider.isLoading return provider.isLoading
? const CircularProgressIndicator(color: AppColor.primary10).center ? const CircularProgressIndicator(color: AppColor.primary10).center

@ -7,40 +7,33 @@ 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/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_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/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/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
class InspectionChecklistBottomSheet extends StatefulWidget { class InspectionCheckListView extends StatefulWidget {
final List<InspectionChecklistItem>? initialValues; final List<InspectionChecklistItem>? initialValues;
const InspectionChecklistBottomSheet({super.key, this.initialValues}); const InspectionCheckListView({super.key, this.initialValues});
@override @override
State<InspectionChecklistBottomSheet> createState() => State<InspectionCheckListView> createState() => _InspectionCheckListViewState();
_InspectionChecklistBottomSheetState();
} }
class _InspectionChecklistBottomSheetState class _InspectionCheckListViewState extends State<InspectionCheckListView> {
extends State<InspectionChecklistBottomSheet> {
late List<InspectionChecklistItem> checklist; late List<InspectionChecklistItem> checklist;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
checklist = AssetDeliveryUtils.inspectionChecklist.map((e) => InspectionChecklistItem(title: e.title)).toList();
/// Create local copy (no shared mutation)
checklist = AssetDeliveryUtils.inspectionChecklist
.map((e) => InspectionChecklistItem(title: e.title))
.toList();
/// Apply initial values only if provided
if (widget.initialValues != null && widget.initialValues!.isNotEmpty) { if (widget.initialValues != null && widget.initialValues!.isNotEmpty) {
for (final item in checklist) { for (final item in checklist) {
final matched = widget.initialValues!.firstWhere( final matched = widget.initialValues!.firstWhere(
(e) => e.title == item.title, (e) => e.title == item.title,
orElse: () => InspectionChecklistItem(), orElse: () => InspectionChecklistItem(),
); );
item.status = matched.status; // null-safe item.status = matched.status; // null-safe
@ -54,70 +47,36 @@ class _InspectionChecklistBottomSheetState
}); });
} }
List<InspectionChecklistItem> get selectedValues => List<InspectionChecklistItem> get selectedValues => checklist.where((e) => e.status != null).toList();
checklist.where((e) => e.status != null).toList();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: AppColor.white10,
appBar: DefaultAppBar( appBar: DefaultAppBar(
title: 'Asset Check List'.addTranslation, title: 'Asset Check List'.addTranslation,
showBackButton: false,
titleStyle: AppTextStyles.heading3.copyWith(
fontWeight: FontWeight.w500,
color: context.isDark
? AppColor.neutral30
: AppColor.neutral50,
),
), ),
body: Column( body: Column(
children: [ children: [
12.height, Column(
ListView.builder( crossAxisAlignment: CrossAxisAlignment.start,
shrinkWrap: true, mainAxisSize: MainAxisSize.min,
physics: const NeverScrollableScrollPhysics(), children: List.generate(
itemCount: checklist.length, checklist.length,
padding: const EdgeInsets.symmetric(horizontal: 12), (index) {
itemBuilder: (context, index) { final model = checklist[index];
final item = checklist[index]; return inspectionStatusRadioWidget(
return Column( model: model,
crossAxisAlignment: CrossAxisAlignment.start, index: index,
children: [ context: context,
Text( );
item.title ?? '', },
style: AppTextStyles.heading6.copyWith( ),
color: context.isDark ).toShadowContainer(
? AppColor.neutral30 context,
: AppColor.black10, borderRadius: 20,
), margin: const EdgeInsets.only(top: 12, left: 12, right: 12),
), ),
Row( const Spacer(),
children: [
Expanded(
child: RadioListTile<String>(
title: const Text('Pass'),
value: 'PASS',
groupValue: item.status,
onChanged: (v) =>
updateStatus(index, v!),
),
),
Expanded(
child: RadioListTile<String>(
title: const Text('Fail'),
value: 'FAIL',
groupValue: item.status,
onChanged: (v) =>
updateStatus(index, v!),
),
),
],
),
],
);
},
).expanded,
FooterActionButton.footerContainer( FooterActionButton.footerContainer(
context: context, context: context,
child: AppFilledButton( child: AppFilledButton(
@ -133,5 +92,124 @@ class _InspectionChecklistBottomSheetState
), ),
); );
} }
}
Widget inspectionStatusRadioWidget({required int index, required InspectionChecklistItem model, required BuildContext context}) {
bool status = (model.status == null || model.status == null) ? true : (model.status != null ? (model.status == 'true' ? true : false) : false);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
model.title ?? '',
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? Colors.white : AppColor.white936),
),
14.height,
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
//
// (status ? 'Pass' : 'Fail').bodyText2(context).custom(color: AppColor.neutral120, fontWeight: FontWeight.w500),
// ],
// ).expanded,
GestureDetector(
onTap: () {
setState(() {
status = !status;
model.status = status.toString();
});
},
child: Container(
width: 99.toScreenWidth,
height: 40.toScreenHeight,
padding: EdgeInsetsDirectional.all(4.toScreenHeight),
decoration: BoxDecoration(
color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildToggleOption(
label: "PASS",
isActive: status,
activeColor: AppColor.green20,
inactiveColor: Colors.transparent,
textColor: status
? AppColor.green50
: context.isDark
? Colors.white
: AppColor.black20,
),
buildToggleOption(
label: "FAIL",
isActive: !status,
activeColor: AppColor.red20,
inactiveColor: Colors.transparent,
textColor: status
? context.isDark
? Colors.white
: AppColor.black20
: AppColor.red30,
),
],
),
),
),
],
).paddingOnly(top: 4, bottom: 4);
}
Widget buildToggleOption({
required String label,
required bool isActive,
required Color activeColor,
required Color inactiveColor,
required Color textColor,
}) {
return Container(
width: 44.toScreenWidth,
height: 30.toScreenHeight,
alignment: Alignment.center,
decoration: BoxDecoration(
color: isActive ? activeColor : inactiveColor,
borderRadius: BorderRadius.circular(3),
),
child: label.bodyText2(context).custom(color: textColor),
);
}
//older widget ...
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// item.title ?? '',
// style: AppTextStyles.heading6.copyWith(
// color: context.isDark ? AppColor.neutral30 : AppColor.black10,
// ),
// ),
// Row(
// children: [
// Expanded(
// child: RadioListTile<String>(
// title: const Text('Pass'),
// value: 'PASS',
// groupValue: item.status,
// onChanged: (v) => updateStatus(index, v!),
// ),
// ),
// Expanded(
// child: RadioListTile<String>(
// title: const Text('Fail'),
// value: 'FAIL',
// groupValue: item.status,
// onChanged: (v) => updateStatus(index, v!),
// ),
// ),
// ],
// ),
// ],
// );
}

@ -75,6 +75,14 @@ class TechnicalInspectionAssetCard extends StatelessWidget {
'Asset Number: ${assetModel.assetNumber ?? '-'}', 'Asset Number: ${assetModel.assetNumber ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
), ),
Text(
'Model: ${assetModel.modelDefinition?.model ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Manufacturer: ${assetModel.modelDefinition?.manufacturer ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text( Text(
'Serial Number: ${assetModel.serialNo ?? '-'}', 'Serial Number: ${assetModel.serialNo ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),

@ -8,9 +8,11 @@ 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/lookup.dart'; import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/asset_delivery_module/helper_function.dart';
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart';
@ -78,95 +80,106 @@ class _TechnicalInspectionLinesListViewState extends State<TechnicalInspectionLi
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
appBar: DefaultAppBar( // appBar: DefaultAppBar(
title: 'Technical Inspection'.addTranslation, // title: 'Technical Inspection'.addTranslation,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), // titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
), // ),
body: Form( body: Form(
key: _formKey, key: _formKey,
child: Column( child: (isLoading)
children: [ ? const CircularProgressIndicator(color: AppColor.primary10).center
Expanded( : (technicalInspectionLinesList.isEmpty)
child: linesList(context).toShadowContainer(context, borderRadius: 20, padding: 12), ? const NoDataFound().center
), : Column(
if (!viewOnly) ...[ children: [
FooterActionButton.footerContainer( SingleChildScrollView(
context: context, padding: const EdgeInsets.all(16),
child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), child: Column(
), children: [
8.height, ListView.separated(
], padding: const EdgeInsets.all(0),
FooterActionButton.footerContainer( shrinkWrap: true,
context: context, physics: const NeverScrollableScrollPhysics(),
child: !viewOnly itemCount: technicalInspectionLinesList.length + 1,
? Row( // +1 for the header
children: [ separatorBuilder: (_, __) => 8.height,
AppFilledButton( itemBuilder: (context, index) {
label: 'Cancel'.addTranslation, if (index == 0) {
maxWidth: true, return Text(
buttonColor: AppColor.background(context), "Lines",
// textColor: context.isDark ? AppColor.neutral30 : Colors.white, style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
textColor: AppColor.red30, );
showBorder: true, }
onPressed: _cancelTap,
).expanded, final DeliveryLineModel model = technicalInspectionLinesList[index - 1];
12.width, return AssetDeliveryLineCard(
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded, deliveryLineModel: model,
], isViewOnly: viewOnly,
) isTechnical: true,
: AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap), editPress: () {
), Navigator.push(
], context,
), MaterialPageRoute(
builder: (context) => UpdateTechnicalInspectionLinesView(
requestModel: widget.requestModel,
deliveryTableModel: widget.deliveryTableModel,
deliveryLineModel: model,
),
),
);
},
);
},
).toShadowContainer(context, borderRadius: 20, padding: 12),
],
),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: !viewOnly
? Column(
children: [
AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap),
16.height,
Row(
children: [
AppFilledButton(
label: 'Cancel'.addTranslation,
maxWidth: true,
buttonColor: AppColor.background(context),
// textColor: context.isDark ? AppColor.neutral30 : Colors.white,
textColor: AppColor.red30,
showBorder: true,
onPressed: _cancelTap,
).expanded,
12.width,
AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded,
],
),
],
)
: Row(
children: [
AppFilledButton(
buttonColor: AppColor.white60,
label: 'Attachments'.addTranslation,
maxWidth: true,
textColor: AppColor.black10,
onPressed: () {
HelperFunction.attachmentTap(
context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
}).expanded,
8.width,
AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded,
],
),
),
],
),
), ),
); );
} }
Widget linesList(BuildContext context) {
if (isLoading) {
return SizedBox.expand(
child: const CircularProgressIndicator(color: AppColor.primary10).center,
);
}
if (technicalInspectionLinesList.isEmpty) {
return const NoDataFound().center;
}
return ListView.separated(
padding: const EdgeInsets.all(16),
itemCount: technicalInspectionLinesList.length + 1, // +1 for the header
separatorBuilder: (_, __) => 8.height,
itemBuilder: (context, index) {
if (index == 0) {
return Text(
"Lines",
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
);
}
final DeliveryLineModel model = technicalInspectionLinesList[index - 1];
return AssetDeliveryLineCard(
deliveryLineModel: model,
isViewOnly: viewOnly,
isTechnical: true,
editPress: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UpdateTechnicalInspectionLinesView(
requestModel: widget.requestModel,
deliveryTableModel: widget.deliveryTableModel,
deliveryLineModel: model,
),
),
);
},
);
},
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
//May be need to show data. //May be need to show data.
Widget inspectionDetails() { Widget inspectionDetails() {
return Column( return Column(
@ -227,12 +240,13 @@ class _TechnicalInspectionLinesListViewState extends State<TechnicalInspectionLi
} }
void _attachmentTap() async { void _attachmentTap() async {
Navigator.push( HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
context, // Navigator.push(
MaterialPageRoute( // context,
builder: (context) => AssetDeliveryAttachmentView( // MaterialPageRoute(
tableItemId: widget.deliveryTableModel.id, // builder: (context) => AssetDeliveryAttachmentView(
))); // tableItemId: widget.deliveryTableModel.id,
// )));
} }
void _cancelTap() async { void _cancelTap() async {
@ -247,12 +261,24 @@ class _TechnicalInspectionLinesListViewState extends State<TechnicalInspectionLi
} }
void _nextTap() async { void _nextTap() async {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => EndUserCostCenterLIstView(
// requestModel: widget.requestModel,
// deliveryTableModel: widget.deliveryTableModel,
// )));
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => EndUserCostCenterLIstView( builder: (context) => AssetDeliveryStageTabPage(
requestModel: widget.requestModel, title: 'End-User Acceptance'.addTranslation,
deliveryTableModel: widget.deliveryTableModel, detailWidget: EndUserCostCenterLIstView(
deliveryTableModel: widget.deliveryTableModel,
requestModel: widget.requestModel,
),
tableId: widget.deliveryTableModel.id,
))); )));
} }
} }

@ -10,7 +10,7 @@ import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/floor.dart'; import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
@ -25,8 +25,6 @@ import '../../../../models/new_models/department.dart';
import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart';
import '../../../../new_views/common_widgets/default_app_bar.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart';
//TODO need to refactor this screen when done ...
class UpdateChildAssetView extends StatefulWidget { class UpdateChildAssetView extends StatefulWidget {
final TechnicalInspectionAssetModel assetModel; final TechnicalInspectionAssetModel assetModel;
final int? lineId; final int? lineId;
@ -183,17 +181,53 @@ class _UpdateChildAssetViewState extends State<UpdateChildAssetView> {
await provider.getSiteData(siteId: assetModel.site?.id, model: provider.childFormModel); await provider.getSiteData(siteId: assetModel.site?.id, model: provider.childFormModel);
} }
provider.setParentModel(assetModel); provider.setParentModel(assetModel);
log('child list length ${assetModel.childAssetList?.length}');
populateTextFields(model: provider.childFormModel); populateTextFields(model: provider.childFormModel);
} }
} }
}), }),
8.height, 8.height,
AppTextFormField(
labelText: 'Asset Name'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.assetName,
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Model'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.model,
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Manufacturer'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.manufacturer ?? '',
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField( AppTextFormField(
labelText: 'Serial Number'.addTranslation, labelText: 'Serial Number'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
controller: serialNoCtrl, controller: serialNoCtrl,
initialValue: model.serialNo ?? '', initialValue: model.serialNo ?? '',
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
textAlign: TextAlign.center, textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number, textInputType: TextInputType.number,
@ -346,7 +380,13 @@ class _UpdateChildAssetViewState extends State<UpdateChildAssetView> {
///Need to check which details show here... ///Need to check which details show here...
void _saveTap() async { void _saveTap() async {
if (!_formKey.currentState!.validate()) return;
if (assetDeliveryProvider.childFormModel.installationDate == null) {
"Installation Date is Required".showToast;
return;
}
_formKey.currentState!.save(); _formKey.currentState!.save();
//Need to check if not auto update. //Need to check if not auto update.
// assetDeliveryProvider.parentFormModel.childAssetList?[widget.index]= assetDeliveryProvider.childFormModel; // assetDeliveryProvider.parentFormModel.childAssetList?[widget.index]= assetDeliveryProvider.childFormModel;
Navigator.pop(context); Navigator.pop(context);
@ -358,7 +398,7 @@ class _UpdateChildAssetViewState extends State<UpdateChildAssetView> {
final result = await Navigator.push( final result = await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => InspectionChecklistBottomSheet( builder: (context) => InspectionCheckListView(
initialValues: checkList, initialValues: checkList,
))); )));
if (result != null) { if (result != null) {
@ -423,6 +463,10 @@ class _UpdateChildAssetViewState extends State<UpdateChildAssetView> {
} }
String _statusFromBool(bool? value) { String _statusFromBool(bool? value) {
return value == true ? 'PASS' :value==false? 'FAIL':''; return value == true
? 'PASS'
: value == false
? 'FAIL'
: '';
} }
} }

@ -10,7 +10,7 @@ import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/floor.dart'; import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart';
@ -28,8 +28,6 @@ import '../../../../models/new_models/department.dart';
import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart';
import '../../../../new_views/common_widgets/default_app_bar.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart';
//TODO need to refactor this screen also add loaders when done ...
class UpdateParentAssetView extends StatefulWidget { class UpdateParentAssetView extends StatefulWidget {
final TechnicalInspectionAssetModel assetModel; final TechnicalInspectionAssetModel assetModel;
final int? lineId; final int? lineId;
@ -216,20 +214,64 @@ class _UpdateParentAssetViewState extends State<UpdateParentAssetView> {
if (assetModel.site != null) { if (assetModel.site != null) {
await provider.getSiteData(siteId: assetModel.site?.id, model: provider.parentFormModel); await provider.getSiteData(siteId: assetModel.site?.id, model: provider.parentFormModel);
} }
assetModel.assetDeliveryInternalDetailAssetId = assetModel.id; assetModel.assetDeliveryInternalDetailAssetId = assetModel.id;
assetModel.id = 0; assetModel.id = 0;
if (assetModel.childAssetList != null && assetModel.childAssetList!.isNotEmpty) {
for (var asset in assetModel.childAssetList!) {
asset.assetDeliveryInternalDetailAssetChildId = asset.id;
asset.id = 0;
}
}
provider.setParentModel(assetModel); provider.setParentModel(assetModel);
log('child list length ${assetModel.childAssetList?.length}'); log('child list length ${assetModel.childAssetList?.length}');
populateTextFields(model: provider.parentFormModel); populateTextFields(model: provider.parentFormModel);
} }
} }
}), }),
8.height, 8.height,
AppTextFormField(
labelText: 'Asset Name'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.assetName,
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Model'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.model,
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Manufacturer'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.manufacturer ?? '',
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField( AppTextFormField(
labelText: 'Serial Number'.addTranslation, labelText: 'Serial Number'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
controller: serialNoCtrl, controller: serialNoCtrl,
initialValue: model.serialNo ?? '', initialValue: model.serialNo ?? '',
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
textAlign: TextAlign.center, textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number, textInputType: TextInputType.number,
@ -384,12 +426,16 @@ class _UpdateParentAssetViewState extends State<UpdateParentAssetView> {
///Need to check which details show here... ///Need to check which details show here...
void _saveTap() async { void _saveTap() async {
if (!_formKey.currentState!.validate()) return;
if (assetDeliveryProvider.parentFormModel.installationDate == null) {
"Installation Date is Required".showToast;
return;
}
_formKey.currentState!.save(); _formKey.currentState!.save();
assetDeliveryProvider.parentFormModel.lineId = widget.lineId; assetDeliveryProvider.parentFormModel.lineId = widget.lineId;
assetDeliveryProvider.parentFormModel.tableItemId = widget.tableItemId; assetDeliveryProvider.parentFormModel.tableItemId = widget.tableItemId;
assetDeliveryProvider.parentFormModel.costCenterId = widget.costCenterItemId; assetDeliveryProvider.parentFormModel.costCenterId = widget.costCenterItemId;
log('model data ${assetDeliveryProvider.parentFormModel.toJson()}');
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await assetDeliveryProvider.saveTechnicalInspectionAssetData(model: assetDeliveryProvider.parentFormModel).then((status) async { await assetDeliveryProvider.saveTechnicalInspectionAssetData(model: assetDeliveryProvider.parentFormModel).then((status) async {
Navigator.pop(context); Navigator.pop(context);
@ -404,7 +450,7 @@ class _UpdateParentAssetViewState extends State<UpdateParentAssetView> {
final result = await Navigator.push( final result = await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => InspectionChecklistBottomSheet( builder: (context) => InspectionCheckListView(
initialValues: checkList, initialValues: checkList,
))); )));
@ -413,18 +459,6 @@ class _UpdateParentAssetViewState extends State<UpdateParentAssetView> {
setState(() {}); setState(() {});
} }
buildInspectionPayload(checkList); buildInspectionPayload(checkList);
if (checkList.isNotEmpty) {
final isPass = checkList.every((e) => e.status == 'PASS');
log('Final Status: ${isPass ? 'PASS' : 'FAIL'}');
}
// call this as bottomsheet.
// final result = await showModalBottomSheet<List<Map<String, dynamic>>>(
// context: context,
// isScrollControlled: true,
// backgroundColor: Colors.transparent,
// builder: (_) => const InspectionChecklistBottomSheet(),
// );
} }
bool _isPass(List<InspectionChecklistItem> list, String title) { bool _isPass(List<InspectionChecklistItem> list, String title) {
@ -479,446 +513,9 @@ class _UpdateParentAssetViewState extends State<UpdateParentAssetView> {
break; break;
} }
} }
checkList.forEach((item) {
log('items ${item.toJson()}');
});
} }
String _statusFromBool(bool? value) { String _statusFromBool(bool? value) {
return value == true ? 'PASS' : 'FAIL'; return value == true ? 'PASS' : 'FAIL';
} }
} }
// import 'dart:developer';
// 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/building.dart';
// import 'package:test_sa/models/new_models/floor.dart';
// import 'package:test_sa/models/new_models/site.dart';
// import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart';
// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart';
// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart';
// import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart';
// import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
// import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
// import 'package:test_sa/new_views/app_style/app_color.dart';
// import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
// import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
// import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
// import 'package:test_sa/providers/loading_list_notifier.dart';
// import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
// import '../../../../models/new_models/department.dart';
// import '../../../../new_views/common_widgets/app_filled_button.dart';
// import '../../../../new_views/common_widgets/default_app_bar.dart';
//
// //TODO need to refactor this screen when done ...
//
// class UpdateParentAssetView extends StatefulWidget {
// final TechnicalInspectionParentAssetModel assetModel;
// final int? lineId;
//
// UpdateParentAssetView({
// Key? key,
// required this.assetModel,
// this.lineId,
// }) : super(key: key);
//
// @override
// State<UpdateParentAssetView> createState() => _UpdateParentAssetViewState();
// }
//
// class _UpdateParentAssetViewState extends State<UpdateParentAssetView> {
// final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
// final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
// List<InspectionChecklistItem> checkList = [];
// late SiteProvider siteProvider;
// late AssetDeliveryProvider assetDeliveryProvider;
//
// @override
// void initState() {
// siteProvider = Provider.of<SiteProvider>(context, listen: false);
// assetDeliveryProvider = Provider.of<AssetDeliveryProvider>(context, listen: false);
// // WidgetsBinding.instance.addPostFrameCallback((_) {
// populateForm();
// // });
// super.initState();
// }
//
// void populateForm() async {
// // _model = widget.assetModel;
// assetDeliveryProvider.setModel(widget.assetModel);
// applyInspectionFlagsToChecklist(model: widget.assetModel,checklist: checkList);
// if (widget.assetModel.site != null) {
// await assetDeliveryProvider.getSiteData(siteId: widget.assetModel.site?.id, model: _model);
// }
// setState(() {});
// }
//
// @override
// void dispose() {
// super.dispose();
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// key: _scaffoldKey,
// appBar: DefaultAppBar(
// title: 'Parent Details'.addTranslation,
// titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
// ),
// body: Form(
// key: _formKey,
// child: Column(
// children: [
// SingleChildScrollView(
// padding: const EdgeInsets.all(16),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// inspectionDetailsForm(lineId: widget.lineId),
// 8.height,
// const Divider().defaultStyle(context),
// 8.height,
// childList(context),
// ],
// ).toShadowContainer(context, borderRadius: 20, padding: 12))
// .expanded,
// FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
// ],
// ),
// ),
// );
// }
//
// Widget childList(BuildContext context) {
// final assetDeliveryTableList = ['abc', 'def', 'ghi', 'fhg', 'hjhh'];
// return Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// children: [
// Text(
// "Test List",
// style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
// ),
// 8.width,
// 'web_link_icon'.toSvgAsset().onPress(() {
// openInspectionChecklist(context);
// }),
// ],
// ),
// 8.height,
// ListView.separated(
// itemCount: assetDeliveryTableList.length,
// separatorBuilder: (_, __) => 8.height,
// padding: EdgeInsets.zero,
// shrinkWrap: true,
// physics: const NeverScrollableScrollPhysics(),
// itemBuilder: (listContext, itemIndex) {
// return TechnicalInspectionAssetCard(
// assetModel: TechnicalInspectionParentAssetModel(),
// ischild: true,
// editPress: () {
// Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateChildAssetView()));
// },
// isViewOnly: false,
// );
// },
// ),
// ],
// );
// }
//
// Widget inspectionDetailsForm({int? lineId}) {
// return Column(
// children: [
// //Replace with simple container...
// AppTextFormField(
// labelText: 'Asset Number'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: _model.assetNumber,
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// textInputType: TextInputType.number,
// showShadow: false,
// enable: false,
// style: Theme.of(context).textTheme.titleMedium,
// ).onPress(() async {
// var data = await Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => TechnicalInspectionSearchAssetView(
// lineId: lineId,
// )));
// if (data != null) {
// TechnicalInspectionParentAssetModel? assetModel = await assetDeliveryProvider.getAssetDetails(assetId: data?.id);
//
// if (assetModel != null) {
// _model =TechnicalInspectionParentAssetModel();
// setState(() {
//
// });
// setState(() {
// _model = assetModel;
// });
// if (assetModel.site != null) {
// await assetDeliveryProvider.getSiteData(siteId: assetModel.site?.id, model: _model);
// }
// setState(() {});
// }
// }
// }),
// 8.height,
// AppTextFormField(
// labelText: 'Serial Number'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: _model.serialNo ?? '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// textInputType: TextInputType.number,
// showShadow: false,
// onSaved: (value) {
// _model.serialNo = value;
// },
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// AppTextFormField(
// labelText: 'System ID'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: _model.systemId ?? '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// showShadow: false,
// onSaved: (value) {
// _model.systemId = value;
// },
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// SingleItemDropDownMenu<Site, SiteProvider>(
// context: context,
// title: 'Site',
// initialValue: _model.site,
// loading: assetDeliveryProvider.isSiteLoading,
// showAsBottomSheet: true,
// backgroundColor: AppColor.fieldBgColor(context),
// showShadow: false,
// // enabled: false,
// onSelect: (value) {
// if (value == null) {
// return;
// }
// _model.site = value;
// _model.building = null;
// _model.floor = null;
// _model.department = null;
// setState(() {});
// },
// ),
// 8.height,
// SingleItemDropDownMenu<Building, NullableLoadingProvider>(
// context: context,
// title: 'Building',
// backgroundColor: AppColor.fieldBgColor(context),
// showAsBottomSheet: true,
// loading: assetDeliveryProvider.isSiteLoading,
// showShadow: false,
// initialValue: _model.building,
// enabled: _model.site?.buildings?.isNotEmpty ?? false,
// staticData: _model.site?.buildings ?? [],
// onSelect: (value) {
// if (value == null) {
// return;
// }
// _model.building = value;
// _model.floor = null;
// _model.department = null;
// setState(() {});
// },
// ),
// 8.height,
// SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
// context: context,
// showAsBottomSheet: true,
// backgroundColor: AppColor.fieldBgColor(context),
// loading: assetDeliveryProvider.isSiteLoading,
// showShadow: false,
// title: 'Floor',
// initialValue: _model.floor,
// enabled: _model.building?.floors?.isNotEmpty ?? false,
// staticData: _model.building?.floors ?? [],
// onSelect: (value) {
// if (value == null) {
// return;
// }
// _model.floor = value;
// _model.department = null;
// setState(() {});
// },
// ),
// 8.height,
// SingleItemDropDownMenu<Department, NullableLoadingProvider>(
// context: context,
// title: 'Department',
// backgroundColor: AppColor.fieldBgColor(context),
// loading: assetDeliveryProvider.isSiteLoading,
// showAsBottomSheet: true,
// showShadow: false,
// initialValue: _model.department,
// enabled: _model.floor?.departments?.isNotEmpty ?? false,
// staticData: _model.floor?.departments ?? [],
// onSelect: (value) {
// if (value == null) {
// return;
// }
// _model.department = value;
// _model.room = null;
// setState(() {});
// },
// ),
//
// 8.height,
// ADatePicker(
// label: 'Installation Date'.addTranslation,
// hideShadow: true,
// height: 56.toScreenHeight,
// backgroundColor: AppColor.fieldBgColor(context),
// date: _model.installationDate,
// // from: widget.pickerFromDate,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// builder: (BuildContext context, Widget? child) {
// final ThemeData currentTheme = Theme.of(context);
// return Theme(
// data: currentTheme.copyWith(
// timePickerTheme: TimePickerThemeData(
// dialHandColor: AppColor.primary10,
// dialBackgroundColor: Colors.grey.withOpacity(0.1),
// hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)),
// dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent),
// dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10),
// dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)),
// entryModeIconColor: AppColor.primary10,
// ),
// textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)),
// ),
// child: child!,
// );
// },
// ).then((selectedTime) {
// if (selectedTime != null) {
// _model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
// setState(() {});
// }
// });
// },
// ),
// 8.height,
// ],
// );
// }
//
// ///Need to check which details show here...
//
// void _saveTap() async {
// _formKey.currentState!.save();
// }
//
// Future<void> openInspectionChecklist(BuildContext context) async {
// final result = await Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => InspectionChecklistBottomSheet(
// initialValues: checkList,
// )));
//
// log('result i got is $result');
// if(result!=null){
// checkList = result;
// setState(() {});
// }
// if (checkList.isNotEmpty) {
// final isPass = checkList.every((e) => e.status == 'PASS');
// log('Final Status: ${isPass ? 'PASS' : 'FAIL'}');
// }
// final payload = buildInspectionPayload(checkList);
//
// log('API Payload: $payload');
// // call this as bottomsheet.
// // final result = await showModalBottomSheet<List<Map<String, dynamic>>>(
// // context: context,
// // isScrollControlled: true,
// // backgroundColor: Colors.transparent,
// // builder: (_) => const InspectionChecklistBottomSheet(),
// // );
// }
//
// bool _isPass(List<InspectionChecklistItem> list, String title) {
// return list
// .firstWhere(
// (e) => e.title == title,
// orElse: () => InspectionChecklistItem(status: 'FAIL'),
// )
// .status ==
// 'PASS';
// }
//
// Map<String, bool> buildInspectionPayload(List<InspectionChecklistItem> checklist) {
// return {
// 'flagphysicalInspection': _isPass(checklist, 'Physical Inspection As Per Manufacturer Instructions'),
// 'flagFunctionPerformance': _isPass(checklist, 'Functional Performance As Per Results Of Manufacturer Recommended Check List'),
// 'flagGroundingResistance': _isPass(checklist, 'Grounding Resistance: Ω'),
// 'flagChassiss': _isPass(checklist, 'Chassis Leakage Current: µA'),
// 'flagLeadsLeakage': _isPass(checklist, 'Leads Leakage Current: µA'),
// 'flagAlert': _isPass(checklist, 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form'),
// };
// }
//
// void applyInspectionFlagsToChecklist({
// required List<InspectionChecklistItem> checklist,
// required TechnicalInspectionParentAssetModel model,
// }) {
// for (final item in checklist) {
// switch (item.title) {
// case 'Physical Inspection As Per Manufacturer Instructions':
// item.status = _statusFromBool(model.flagphysicalInspection);
// break;
//
// case 'Functional Performance As Per Results Of Manufacturer Recommended Check List':
// item.status = _statusFromBool(model.flagFunctionPerformance);
// break;
//
// case 'Grounding Resistance: Ω':
// item.status = _statusFromBool(model.flagGroundingResistance);
// break;
//
// case 'Chassis Leakage Current: µA':
// item.status = _statusFromBool(model.flagChassiss);
// break;
//
// case 'Leads Leakage Current: µA':
// item.status = _statusFromBool(model.flagLeadsLeakage);
// break;
//
// case 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form':
// item.status = _statusFromBool(model.flagAlert);
// break;
// }
// }
// }
// String _statusFromBool(bool? value) {
// return value == true ? 'PASS' : 'FAIL';
// }
// }

@ -179,6 +179,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
title: 'Power Supply Type'.addTranslation, title: 'Power Supply Type'.addTranslation,
titleTextColor: AppColor.neutral120, titleTextColor: AppColor.neutral120,
showShadow: false, showShadow: false,
validator: (value) {
if (value == null) return 'Please select power supply type';
return null;
},
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true, showAsBottomSheet: true,
initialValue: model.powerSupplyType, initialValue: model.powerSupplyType,
@ -198,6 +202,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number, textInputType: TextInputType.number,
showShadow: false, showShadow: false,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onSaved: (value) { onSaved: (value) {
model.powerReading = int.tryParse(value); model.powerReading = int.tryParse(value);
}, },
@ -212,6 +220,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number, textInputType: TextInputType.number,
showShadow: false, showShadow: false,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onSaved: (value) { onSaved: (value) {
model.maxCurrent = int.tryParse(value); model.maxCurrent = int.tryParse(value);
}, },
@ -224,6 +236,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
textInputType: TextInputType.number, textInputType: TextInputType.number,
initialValue: model.voltage != null ? model.voltage.toString() : '', initialValue: model.voltage != null ? model.voltage.toString() : '',
textAlign: TextAlign.center, textAlign: TextAlign.center,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onSaved: (value) { onSaved: (value) {
model.voltage = int.tryParse(value); model.voltage = int.tryParse(value);
}, },
@ -238,6 +254,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
initialValue: model.frequency != null ? model.frequency.toString() : '', initialValue: model.frequency != null ? model.frequency.toString() : '',
textInputType: TextInputType.number, textInputType: TextInputType.number,
textAlign: TextAlign.center, textAlign: TextAlign.center,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onSaved: (value) { onSaved: (value) {
model.frequency = int.tryParse(value); model.frequency = int.tryParse(value);
}, },
@ -250,6 +270,7 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
} }
void _saveTap() async { void _saveTap() async {
if (!_formKey.currentState!.validate()) return;
_formKey.currentState!.save(); _formKey.currentState!.save();
model.tableItemId = widget.deliveryTableModel.id; model.tableItemId = widget.deliveryTableModel.id;
model.lineId = widget.deliveryLineModel?.id; model.lineId = widget.deliveryLineModel?.id;

@ -11,6 +11,7 @@ import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/room_model.dart'; import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart';
@ -171,33 +172,38 @@ class AssetDeliveryProvider extends ChangeNotifier {
} }
} }
Future<List<CostCenterModel>> getAssetDeliveryCostCenterListForLines({int? lineId, int? tableItemId}) async { Future<CostCenterSerialNoFormModel> getAssetDeliveryCostCenterListForLines({
List<CostCenterModel> costCenterList = []; int? lineId,
int? tableItemId,
}) async {
CostCenterSerialNoFormModel costCenterSerialNoFormModel = CostCenterSerialNoFormModel();
try { try {
isLoading = true; isLoading = true;
notifyListeners(); notifyListeners();
final response = await ApiManager.instance.get( final response = await ApiManager.instance.get(
"${URLs.getCostCenterListToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId", "${URLs.getCostCenterAndSerialNoToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId",
); );
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
final jsonData = json.decode(response.body)["data"]; final jsonData = json.decode(response.body)["data"];
if (jsonData is List) { costCenterSerialNoFormModel = CostCenterSerialNoFormModel.fromJson(jsonData);
costCenterList = jsonData.map((e) => CostCenterModel.fromJson(e)).toList();
}
} else { } else {
costCenterList = []; costCenterSerialNoFormModel.costCenters = [];
costCenterSerialNoFormModel.serialNos = [];
} }
isLoading = false;
notifyListeners();
return costCenterList;
} catch (e) { } catch (e) {
log("get Delivery Lines List [error] : $e"); log("get Delivery Lines List [error] : $e");
costCenterSerialNoFormModel.costCenters = [];
costCenterSerialNoFormModel.serialNos = [];
} finally {
isLoading = false; isLoading = false;
costCenterList = [];
notifyListeners(); notifyListeners();
return costCenterList;
} }
return costCenterSerialNoFormModel;
} }
Future<bool> addNewDelivery({ Future<bool> addNewDelivery({
@ -253,15 +259,17 @@ class AssetDeliveryProvider extends ChangeNotifier {
int? tableItemId, int? tableItemId,
int? lineId, int? lineId,
List<CostCenterModel>? list, List<CostCenterModel>? list,
List<SerialNoModel>? serialNoList,
}) async { }) async {
isLoading = true; isLoading = true;
Map<String, dynamic> payload = { Map<String, dynamic> payload = {
"assetDeliveryExternalDeliveryId": tableItemId, "assetDeliveryExternalDeliveryId": tableItemId,
"assetDeliveryExternalDetailId": lineId, "assetDeliveryExternalDetailId": lineId,
"costCenters": list?.map((x) => x.toJson()).toList(), "costCenters": list?.map((x) => x.toJson()).toList(),
if (serialNoList != null && serialNoList.isNotEmpty) "serialNos": serialNoList.map((x) => x.toJson()).toList(),
}; };
try { try {
final response = await ApiManager.instance.post(URLs.saveCostCenterToLineDeliveryInspection, body: payload); final response = await ApiManager.instance.post(URLs.saveCostCenterAndSerialNoToLineDeliveryInspection, body: payload);
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false; isLoading = false;
@ -421,10 +429,11 @@ class AssetDeliveryProvider extends ChangeNotifier {
Future<List<GenericAttachmentModel>> getAttachments({ Future<List<GenericAttachmentModel>> getAttachments({
num? tableItemId, num? tableItemId,
num? attachmentType,
}) async { }) async {
try { try {
isLoading = true; isLoading = true;
final response = await ApiManager.instance.get("${URLs.getAttachments}?assetDeliveryExternalDeliveryId=$tableItemId"); final response = await ApiManager.instance.get("${URLs.getAttachments}?attachmentDocTypeValue=$attachmentType&assetDeliveryExternalDeliveryId=$tableItemId");
List<GenericAttachmentModel> list = []; List<GenericAttachmentModel> list = [];
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false; isLoading = false;

@ -0,0 +1,33 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
class AttachmentTypeLookupProvider extends LoadingListNotifier<Lookup> {
@override
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.attachmentTypeLookup);
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;
}
}
}

@ -13,6 +13,7 @@ import 'package:test_sa/modules/cm_module/cm_detail_provider.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/cx_module/chat/chat_page.dart'; import 'package:test_sa/modules/cx_module/chat/chat_page.dart';
import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; import 'package:test_sa/modules/cx_module/chat/chat_provider.dart';
import 'package:test_sa/modules/cx_module/chat/chat_widget.dart';
import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/modules/cx_module/survey/survey_page.dart';
import 'package:test_sa/modules/loan_module/pages/create_loan_request_page.dart'; import 'package:test_sa/modules/loan_module/pages/create_loan_request_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
@ -23,8 +24,9 @@ import 'views/components/service_request_detail_view.dart';
class CMDetailPage extends StatefulWidget { class CMDetailPage extends StatefulWidget {
final int requestId; final int requestId;
final int moduleId;
CMDetailPage({Key? key, required this.requestId}) : super(key: key); CMDetailPage({Key? key, required this.requestId, required this.moduleId}) : super(key: key);
@override @override
_CMDetailPageState createState() { _CMDetailPageState createState() {
@ -40,6 +42,7 @@ class _CMDetailPageState extends State<CMDetailPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_requestProvider = Provider.of<CMDetailProvider>(context, listen: false);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<ChatProvider>(context, listen: false).reset(); Provider.of<ChatProvider>(context, listen: false).reset();
getInitialData(); getInitialData();
@ -89,84 +92,46 @@ class _CMDetailPageState extends State<CMDetailPage> {
Navigator.pop(context); Navigator.pop(context);
}, },
actions: [ actions: [
if (context.userProvider.isEngineer || context.userProvider.isNurse) Selector<CMDetailProvider, bool>(
Selector<CMDetailProvider, bool>( selector: (_, myModel) => myModel.isLoading, // Selects only the userName
selector: (_, myModel) => myModel.isLoading, // Selects only the userName builder: (_, isLoading, __) {
builder: (_, isLoading, __) { if (isLoading) {
if (isLoading) { return const SizedBox();
return const SizedBox(); } else {
} else { CMDetailProvider provider = Provider.of<CMDetailProvider>(context, listen: false);
CMDetailProvider provider = Provider.of<CMDetailProvider>(context, listen: false); if ((context.userProvider.isEngineer || context.userProvider.isNurse) &&
int? statusValue = provider.currentWorkOrder?.data?.status?.value; provider.currentWorkOrder?.data?.assignedEmployee != null &&
if (statusValue == 2 || statusValue == 3 || statusValue == 5 || statusValue == 6) { (provider.currentWorkOrder?.data?.workOrderContactPerson?.isNotEmpty ?? false)) {
getChatToken(moduleId, provider.currentWorkOrder?.data?.workOrderNo ?? ""); return ChatWidget(
return Consumer<ChatProvider>(builder: (pContext, requestProvider, _) { moduleId: widget.moduleId,
return IconButton( isShow: context.settingProvider.isUserFlowMedical && (context.userProvider.isEngineer || context.userProvider.isNurse) && provider.currentWorkOrder?.data?.assignedEmployee != null,
icon: const Icon(Icons.chat_bubble), isReadOnly: _requestProvider.isReadOnlyRequest,
onPressed: () { requestId: widget.requestId.toInt(),
Navigator.push( assigneeEmployeeNumber: provider.currentWorkOrder?.data?.assignedEmployee!.employeeId!,
context, myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
CupertinoPageRoute( contactEmployeeINumber: provider.currentWorkOrder?.data?.workOrderContactPerson.first.employeeId,
builder: (context) => ChatPage( );
moduleId: moduleId,
requestId: widget.requestId,
title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? "",
readOnly: _requestProvider.isReadOnlyRequest,
)));
},
).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30);
});
}
return const SizedBox();
}
}),
if (isNurse)
IconButton(
icon: 'qr'.toSvgAsset(height: 24, width: 24),
onPressed: () {
ServiceRequestBottomSheet.getQRCodeBottomSheet(context: context);
},
)
else ...[
Selector<CMDetailProvider, bool>(
selector: (_, myModel) => myModel.isLoading, // Selects only the userName
builder: (_, isLoading, __) {
if (isLoading) {
return const SizedBox();
} else {
CMDetailProvider provider = Provider.of<CMDetailProvider>(context, listen: false);
int? statusValue = provider.currentWorkOrder?.data?.status?.value;
if (statusValue == 2) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
margin: const EdgeInsets.only(left: 2),
decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, borderRadius: BorderRadius.circular(16)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.add, size: 20, color: AppColor.black1E),
Text(
"Loan",
style: AppTextStyles.bodyText2.copyWith(color: AppColor.black1E),
),
4.width,
],
),
).onPress(() {
Navigator.push(context, MaterialPageRoute(builder: (context) => CreateLoanRequestPage(workOrderId: widget.requestId)));
});
}
return const SizedBox();
} }
}), return const SizedBox();
IconButton( }
icon: const Icon(Icons.home), }),
onPressed: () { isNurse
// stopTimer(); ? IconButton(
Navigator.pop(context); icon: 'qr'.toSvgAsset(
}, height: 24,
) width: 24,
], ),
onPressed: () {
ServiceRequestBottomSheet.getQRCodeBottomSheet(context: context);
},
)
: IconButton(
icon: const Icon(Icons.home),
onPressed: () {
// stopTimer();
Navigator.pop(context);
},
),
], ],
), ),
body: DefaultTabController( body: DefaultTabController(

@ -300,7 +300,7 @@ class _CreateCMRequestState extends State<CreateCMRequest> with TickerProviderSt
bool checkPendingRequest = false; bool checkPendingRequest = false;
void showPendingRequests() { void showPendingRequests() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!))); Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!, 1)));
} }
void showPendingRequestBottomSheet() async { void showPendingRequestBottomSheet() async {

@ -199,8 +199,6 @@ class _ServiceRequestDetailViewState extends State<ServiceRequestDetailView> {
'${context.translation.assetName}: ${workOrder.assetNdModel!.name?.cleanupWhitespace?.capitalizeFirstOfEach}', '${context.translation.assetName}: ${workOrder.assetNdModel!.name?.cleanupWhitespace?.capitalizeFirstOfEach}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
), ),
// 8.height,
Text( Text(
'${context.translation.assetNumber}: ${workOrder.asset!.assetNumber}', '${context.translation.assetNumber}: ${workOrder.asset!.assetNumber}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),

@ -35,6 +35,7 @@ import 'model/user_chat_history_model.dart';
// import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user; // import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user;
// import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; // import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav;
//Need to refector this remove unused code.
class ChatApiClient { class ChatApiClient {
static final ChatApiClient _instance = ChatApiClient._internal(); static final ChatApiClient _instance = ChatApiClient._internal();
@ -81,8 +82,9 @@ class ChatApiClient {
} }
Future<ChatParticipantModel?> loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async { Future<ChatParticipantModel?> loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async {
Response response = Response response = await ApiClient().getJsonForResponse(
await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token); "${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber&requestType=chat&transactionType=17",
token: chatLoginResponse!.token);
if (!kReleaseMode) { if (!kReleaseMode) {
// logger.i("login-res: " + response.body); // logger.i("login-res: " + response.body);
@ -94,6 +96,20 @@ class ChatApiClient {
} }
} }
Future<bool> resetCountApi(int moduleCode, int referenceNumber, String? employeeNumber) async {
final Map<String, dynamic> payload = {
'moduleCode': "$moduleCode",
'ReferenceNumber': "$referenceNumber",
};
final Response response = await ApiClient().postJsonForResponse(
URLs.resetMessageCount,
payload,
token: chatLoginResponse!.token,
);
return response.statusCode == 200;
}
Future<List<ChatAttachment>> viewAllDocuments(int moduleId, int referenceId) async { Future<List<ChatAttachment>> viewAllDocuments(int moduleId, int referenceId) async {
Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/attachments/conversation?referenceId=$referenceId&moduleCode=$moduleId", token: chatLoginResponse!.token); Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/attachments/conversation?referenceId=$referenceId&moduleCode=$moduleId", token: chatLoginResponse!.token);

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
@ -29,6 +30,7 @@ import 'helper/chat_file_viewer.dart';
import 'model/get_single_user_chat_list_model.dart'; import 'model/get_single_user_chat_list_model.dart';
import 'model/user_chat_history_model.dart'; import 'model/user_chat_history_model.dart';
//Need to refactor this ...
enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted }
class ChatPage extends StatefulWidget { class ChatPage extends StatefulWidget {
@ -66,7 +68,10 @@ class _ChatPageState extends State<ChatPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
loadChatHistory(); WidgetsBinding.instance.addPostFrameCallback((_) {
loadChatHistory();
});
playerController.addListener(() async { playerController.addListener(() async {
// if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) { // if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) {
// await playerController.stopPlayer(); // await playerController.stopPlayer();
@ -75,7 +80,7 @@ class _ChatPageState extends State<ChatPage> {
}); });
} }
void loadChatHistory() { void loadChatHistory() async {
// // String assigneeEmployeeNumber = Provider.of<ServiceRequestDetailProvider>(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; // // String assigneeEmployeeNumber = Provider.of<ServiceRequestDetailProvider>(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? "";
// // String myEmployeeId = context.userProvider.user!.username!; // // String myEmployeeId = context.userProvider.user!.username!;
// // // //
@ -99,7 +104,14 @@ class _ChatPageState extends State<ChatPage> {
? Provider.of<CMDetailProvider>(context, listen: false).currentWorkOrder!.data!.workOrderCreatedBy!.employeeId! ? Provider.of<CMDetailProvider>(context, listen: false).currentWorkOrder!.data!.workOrderCreatedBy!.employeeId!
: Provider.of<CMDetailProvider>(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!)) : Provider.of<CMDetailProvider>(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!))
: ""); : "");
Provider.of<ChatProvider>(context, listen: false).connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted); final chatProvider = context.read<ChatProvider>();
// final chatProvider = Provider.of<C;
chatProvider.connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted);
bool readStatus = await chatProvider.resetCount(moduleId: widget.moduleId, referenceNo: widget.requestId, userId: context.userProvider.user?.id);
if (readStatus) {
chatProvider.chatParticipantModel?.unreadCount = 0;
}
} }
@override @override
@ -231,7 +243,9 @@ class _ChatPageState extends State<ChatPage> {
} }
return Column(mainAxisSize: MainAxisSize.min, children: [ return Column(mainAxisSize: MainAxisSize.min, children: [
if (showDateHeader) dateCard(currentMessage.createdDate?.toString().chatMsgDateWithYear ?? ""), if (showDateHeader) dateCard(currentMessage.createdDate?.toString().chatMsgDateWithYear ?? ""),
isSender ? senderMsgCard(showSenderName, chatProvider.chatResponseList[index]) : recipientMsgCard(showSenderName, chatProvider.chatResponseList[index]) isSender
? senderMsgCard(showSenderName, chatProvider.chatResponseList[index], index: index)
: recipientMsgCard(showSenderName, chatProvider.chatResponseList[index])
]); ]);
}, },
itemCount: chatProvider.chatResponseList.length)) itemCount: chatProvider.chatResponseList.length))
@ -607,7 +621,7 @@ class _ChatPageState extends State<ChatPage> {
.center; .center;
} }
Widget senderMsgCard(bool showHeader, SingleUserChatModel? chatResponse, {bool loading = false, String msg = ""}) { Widget senderMsgCard(bool showHeader, SingleUserChatModel? chatResponse, {bool loading = false, String msg = "", int index = 0}) {
Widget senderHeader = Row( Widget senderHeader = Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
@ -40,6 +41,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:signalr_netcore/hub_connection.dart'; import 'package:signalr_netcore/hub_connection.dart';
import 'package:signalr_netcore/signalr_client.dart'; import 'package:signalr_netcore/signalr_client.dart';
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/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/modules/cx_module/chat/model/chat_login_response_model.dart'; import 'package:test_sa/modules/cx_module/chat/model/chat_login_response_model.dart';
@ -54,6 +56,8 @@ import 'model/get_single_user_chat_list_model.dart';
import 'model/user_chat_history_model.dart'; import 'model/user_chat_history_model.dart';
// import 'get_single_user_chat_list_model.dart'; // import 'get_single_user_chat_list_model.dart';
//Need to refactor this remove unused code.
HubConnection? chatHubConnection; HubConnection? chatHubConnection;
class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
@ -248,6 +252,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
chatHubConnection!.on("OnSubmitChatAsync", OnSubmitChatAsync); chatHubConnection!.on("OnSubmitChatAsync", OnSubmitChatAsync);
chatHubConnection!.on("OnTypingAsync", OnTypingAsync); chatHubConnection!.on("OnTypingAsync", OnTypingAsync);
chatHubConnection!.on("OnStopTypingAsync", OnStopTypingAsync); chatHubConnection!.on("OnStopTypingAsync", OnStopTypingAsync);
//Need by Chat Backend for seen and un seen.
chatHubConnection!.on("OnSeenChatUserAsync", onSeenUserChatAsync);
chatHubConnection!.on("OnAckSeenAsync", onAckSeenAsync);
//group On message //group On message
@ -370,7 +377,19 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
// } // }
} }
} }
// notifyListeners(); }
Future<bool> resetCount({
required int moduleId,
required int referenceNo,
String? userId,
}) async {
try {
return await ChatApiClient().resetCountApi(moduleId, referenceNo, userId);
} catch (e, stack) {
debugPrint('resetCount error: $e');
rethrow;
}
} }
void updateUserChatHistoryStatusAsync(List data) { void updateUserChatHistoryStatusAsync(List data) {
@ -453,6 +472,15 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
print(args); print(args);
} }
Future<void> markMessageAsRead(int messageId) async {
final senderId = sender?.userId;
if (senderId == null) return;
chatHubConnection?.invoke(
"SendMessageReadAsync",
args: [messageId, senderId],
);
}
void onChatSeen(List<Object?>? args) { void onChatSeen(List<Object?>? args) {
dynamic items = args!.toList(); dynamic items = args!.toList();
// for (var user in searchedChats!) { // for (var user in searchedChats!) {
@ -559,6 +587,57 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
notifyListeners(); notifyListeners();
} }
Future<void> onSeenUserChatAsync(List<Object?>? parameters) async {
try {
if (parameters == null || parameters.isEmpty) {
log('onSeenUserChatAsync: parameters are null or empty');
return;
}
final parm = parameters.first;
if (parm is! List || parm.isEmpty) {
log('onSeenUserChatAsync: parm is not a valid list');
return;
}
final firstItem = parm.first;
if (firstItem is! Map<String, dynamic>) {
log('onSeenUserChatAsync: firstItem is not a Map');
return;
}
await chatHubConnection!.invoke(
"AckSeenAsync",
args: [
firstItem['currentUserId'],
[firstItem['userChatHistoryId']],
],
);
} catch (e, stackTrace) {
log('onSeenUserChatAsync error: $e');
log('StackTrace: $stackTrace');
}
}
Future<void> onAckSeenAsync(List<Object?>? parameters) async {
try {
if (parameters == null || parameters.isEmpty) {
log('onAckSeenAsync: parameters are null or empty');
return;
}
final parm = parameters.first;
log('parm onAckSeenAsync $parm');
if (chatResponseList.isEmpty) {
log('onAckSeenAsync: chatResponseList is empty');
return;
}
log('last list item id ${chatResponseList.first.toJson()}');
chatResponseList.first.isSeen = true;
notifyListeners();
} catch (e, stackTrace) {
log('onAckSeenAsync error: $e');
log('StackTrace: $stackTrace');
}
}
// Future<void> OnSubmitChatAsync(List<Object?>? parameters) async { // Future<void> OnSubmitChatAsync(List<Object?>? parameters) async {
// // List data = jsonDecode(parameters!.first!.toString()); // // List data = jsonDecode(parameters!.first!.toString());
// //

@ -1,9 +1,12 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; import 'package:test_sa/modules/cm_module/cm_detail_provider.dart';
import 'package:test_sa/new_views/common_widgets/custom_badge.dart';
import 'chat_page.dart'; import 'chat_page.dart';
import 'chat_provider.dart'; import 'chat_provider.dart';
@ -40,8 +43,10 @@ class _ChatWidgetState extends State<ChatWidget> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
Provider.of<ChatProvider>(context, listen: false).reset(); WidgetsBinding.instance.addPostFrameCallback((_) {
getChatToken(); Provider.of<ChatProvider>(context, listen: false).reset();
getChatToken();
});
} }
void getChatToken() { void getChatToken() {
@ -73,25 +78,33 @@ class _ChatWidgetState extends State<ChatWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<ChatProvider>(builder: (pContext, requestProvider, _) { return widget.isShow
return IconButton( ? Consumer<ChatProvider>(builder: (pContext, chatProvider, _) {
icon: const Icon(Icons.chat_bubble), final int unreadCount = (!chatProvider.chatLoginTokenLoading && (chatProvider.chatParticipantModel?.unreadCount ?? 0) > 0) ? chatProvider.chatParticipantModel!.unreadCount! : 0;
onPressed: () { return CustomBadge2(
Navigator.push( value: unreadCount,
context, top: 2,
CupertinoPageRoute( right: 2,
builder: (context) => ChatPage( minSize: 18,
moduleId: widget.moduleId, child: IconButton(
requestId: widget.requestId, icon: const Icon(Icons.chat_bubble),
title: widget.title, onPressed: () {
readOnly: widget.isReadOnly, Navigator.push(
assigneeEmployeeNumber: widget.assigneeEmployeeNumber, context,
contactEmployeeINumber: widget.contactEmployeeINumber, CupertinoPageRoute(
myLoginUserID: widget.myLoginUserID, builder: (context) => ChatPage(
))); moduleId: widget.moduleId,
}, requestId: widget.requestId,
).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); title: widget.title,
}); readOnly: widget.isReadOnly,
; assigneeEmployeeNumber: widget.assigneeEmployeeNumber,
contactEmployeeINumber: widget.contactEmployeeINumber,
myLoginUserID: widget.myLoginUserID,
)));
},
).toShimmer(context: context, isShow: chatProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30),
);
})
: const SizedBox();
} }
} }

@ -46,6 +46,7 @@ class ChatFilePicker extends StatelessWidget {
fromMediaPicker(BuildContext context, ImageSource imageSource) async { fromMediaPicker(BuildContext context, ImageSource imageSource) async {
XFile? pickedFile = await ImagePicker().pickImage(source: imageSource, imageQuality: 70, maxWidth: 800, maxHeight: 800); XFile? pickedFile = await ImagePicker().pickImage(source: imageSource, imageQuality: 70, maxWidth: 800, maxHeight: 800);
if (pickedFile != null) { if (pickedFile != null) {
//Has UI issues here top buttons not clickable smoothly
CroppedFile? croppedFile = await ImageCropper().cropImage( CroppedFile? croppedFile = await ImageCropper().cropImage(
sourcePath: pickedFile.path, sourcePath: pickedFile.path,
// aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1), // aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1),

@ -24,6 +24,7 @@ class ChatFileViewer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FutureBuilder<File?>( return FutureBuilder<File?>(
future: checkFileInLocalStorage(), future: checkFileInLocalStorage(),
builder: (BuildContext context, AsyncSnapshot<File?> snapshot) { builder: (BuildContext context, AsyncSnapshot<File?> snapshot) {
@ -127,8 +128,9 @@ class ChatFileViewer extends StatelessWidget {
Future<File?> downloadFile() async { Future<File?> downloadFile() async {
try { try {
// print("downloadUrl:$downloadUrl");
return await ChatApiClient() return await ChatApiClient()
.downloadFileWithHttp(downloadUrl, fileName: fileTypeResponse.fileName, fileTypeDescription: fileTypeResponse.fileTypeDescription, fileSource: fileTypeResponse.fileTypeId!); .downloadFileWithHttp(downloadUrl, fileName: fileTypeResponse.fileName, fileTypeDescription: fileTypeResponse.fileTypeDescription ?? "", fileSource: fileTypeResponse.fileTypeId!);
} catch (ex) { } catch (ex) {
print("downloadFile:$ex"); print("downloadFile:$ex");
return null; return null;

@ -1,12 +1,15 @@
import 'dart:developer';
class ChatParticipantModel { class ChatParticipantModel {
int? id; int? id;
String? title; String? title;
String? conversationType; String? conversationType;
List<Participants>? participants; List<Participants>? participants;
String? lastMessage; dynamic lastMessage;
String? createdAt; String? createdAt;
int? unreadCount;
ChatParticipantModel({this.id, this.title, this.conversationType, this.participants, this.lastMessage, this.createdAt}); ChatParticipantModel({this.id, this.title, this.conversationType, this.participants, this.createdAt, this.unreadCount});
ChatParticipantModel.fromJson(Map<String, dynamic> json) { ChatParticipantModel.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
@ -20,18 +23,20 @@ class ChatParticipantModel {
} }
lastMessage = json['lastMessage']; lastMessage = json['lastMessage'];
createdAt = json['createdAt']; createdAt = json['createdAt'];
unreadCount = json['unreadCount'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>(); final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = this.id; data['id'] = id;
data['title'] = this.title; data['title'] = title;
data['conversationType'] = this.conversationType; data['conversationType'] = conversationType;
if (this.participants != null) { if (participants != null) {
data['participants'] = this.participants!.map((v) => v.toJson()).toList(); data['participants'] = participants!.map((v) => v.toJson()).toList();
} }
data['lastMessage'] = this.lastMessage; data['lastMessage'] = lastMessage;
data['createdAt'] = this.createdAt; data['createdAt'] = createdAt;
data['unreadCount'] = unreadCount;
return data; return data;
} }
} }
@ -54,12 +59,12 @@ class Participants {
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>(); final Map<String, dynamic> data = <String, dynamic>{};
data['userId'] = this.userId; data['userId'] = userId;
data['userName'] = this.userName; data['userName'] = userName;
data['employeeNumber'] = this.employeeNumber; data['employeeNumber'] = employeeNumber;
data['role'] = this.role; data['role'] = role;
data['userStatus'] = this.userStatus; data['userStatus'] = userStatus;
return data; return data;
} }
} }

@ -170,6 +170,8 @@ class Asset {
String? siteName; String? siteName;
int? siteId; int? siteId;
String? modelDefinition; String? modelDefinition;
int? departmentId;
String? departmentName;
Asset({ Asset({
this.id, this.id,
@ -181,6 +183,8 @@ class Asset {
this.siteName, this.siteName,
this.siteId, this.siteId,
this.modelDefinition, this.modelDefinition,
this.departmentId,
this.departmentName,
}); });
Asset.fromJson(Map<String, dynamic> json) { Asset.fromJson(Map<String, dynamic> json) {
@ -193,6 +197,8 @@ class Asset {
siteName = json['siteName']; siteName = json['siteName'];
siteId = json['siteId']; siteId = json['siteId'];
modelDefinition = json['modelDefinition']; modelDefinition = json['modelDefinition'];
departmentId = json['departmentId'];
departmentName = json['departmentName'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -206,6 +212,8 @@ class Asset {
data['siteName'] = siteName; data['siteName'] = siteName;
data['siteId'] = siteId; data['siteId'] = siteId;
data['modelDefinition'] = modelDefinition; data['modelDefinition'] = modelDefinition;
data['departmentId'] = departmentId;
data['departmentName'] = departmentName;
return data; return data;
} }
} }

@ -42,6 +42,8 @@ class _CreateEquipmentInternalAuditFormState extends State<CreateEquipmentIntern
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
FocusNode auditCheckListNode = FocusNode(); FocusNode auditCheckListNode = FocusNode();
int noFindingValue = 4;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -78,7 +80,6 @@ class _CreateEquipmentInternalAuditFormState extends State<CreateEquipmentIntern
}, },
), ),
16.height, 16.height,
//TODO need to check layout issue...
MultipleItemDropDownMenu<Lookup, InternalAuditCheckListProvider>( MultipleItemDropDownMenu<Lookup, InternalAuditCheckListProvider>(
context: context, context: context,
showAsBottomSheet: true, showAsBottomSheet: true,
@ -89,6 +90,15 @@ class _CreateEquipmentInternalAuditFormState extends State<CreateEquipmentIntern
title: 'Internal Audit Checklist'.addTranslation, title: 'Internal Audit Checklist'.addTranslation,
initialValue: _equipmentinternalAuditModel.findings, initialValue: _equipmentinternalAuditModel.findings,
onSelect: (value) { onSelect: (value) {
if ((value ?? []).isNotEmpty) {
Lookup? noFindingElement;
try {
noFindingElement = value!.singleWhere((element) => element.value == noFindingValue);
} catch (ex) {}
if (noFindingElement != null) {
value!.removeWhere((element) => element.value != noFindingElement!.value);
}
}
_equipmentinternalAuditModel.findings = value ?? []; _equipmentinternalAuditModel.findings = value ?? [];
}, },
), ),
@ -137,9 +147,9 @@ class _CreateEquipmentInternalAuditFormState extends State<CreateEquipmentIntern
} }
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
_equipmentinternalAuditModel.auditorId = context.userProvider.user?.userID; _equipmentinternalAuditModel.auditorId = context.userProvider.user?.userID;
bool status = await internalAuditProvider.addEquipmentInternalAudit(context: context, request: _equipmentinternalAuditModel); bool status = await internalAuditProvider.addEquipmentInternalAudit(context: context, request: _equipmentinternalAuditModel);
Navigator.pop(context); Navigator.pop(context);
if(status){ if (status) {
Navigator.pop(context); Navigator.pop(context);
} }
} }

@ -19,6 +19,7 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
class EquipmentInternalAuditDetailPage extends StatefulWidget { class EquipmentInternalAuditDetailPage extends StatefulWidget {
static const String id = "/details-internal-audit"; static const String id = "/details-internal-audit";
@ -51,12 +52,10 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
Future<void> getAuditData() async { Future<void> getAuditData() async {
model = await _internalAuditProvider.getEquipmentInternalAuditById(widget.auditId); model = await _internalAuditProvider.getEquipmentInternalAuditById(widget.auditId);
allAttachments.clear(); allAttachments.clear();
allAttachments = [ allAttachments = [
...(model?.attachments ?? []), ...(model?.attachments ?? []),
...(model?.engineerData?.attachments ?? []), ...(model?.engineerData?.attachments ?? []),
]; ];
} }
@override @override
@ -82,12 +81,43 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
StatusLabel(
label: model!.status!.name,
id: model!.status!.value,
radius: 4,
textColor: AppColor.getRequestStatusTextColorByName(
context,
model!.status!.name,
),
backgroundColor: AppColor.getRequestStatusColorByName(
context,
model!.status!.name,
),
// textColor: AppColor.green15,
// backgroundColor: AppColor.greenStatus(context),
),
Text(
model!.createdDate!.toString().toServiceRequestCardFormat,
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
)
],
),
8.height,
assetDetails(), assetDetails(),
8.height, 8.height,
requestDetails(), requestDetails(),
8.height, 8.height,
if (model?.remarks?.isNotEmpty ?? false) ...[ if (model?.remarks?.isNotEmpty ?? false) ...[
const Divider().defaultStyle(context), const Divider().defaultStyle(context),
Text(
"Remarks",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
model!.remarks!.bodyText(context), model!.remarks!.bodyText(context),
8.height, 8.height,
], ],
@ -103,7 +133,7 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
], ],
).paddingAll(0).toShadowContainer(context), ).paddingAll(0).toShadowContainer(context),
).expanded, ).expanded,
if (context.userProvider.isEngineer&&model?.status?.value!=3) if (context.userProvider.isEngineer && model?.status?.value != 3)
FooterActionButton.footerContainer( FooterActionButton.footerContainer(
context: context, context: context,
child: AppFilledButton( child: AppFilledButton(
@ -160,6 +190,7 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
), ),
6.height, 6.height,
'${context.translation.requestNo}: ${model?.requestNo ?? '-'}'.bodyText(context),
if (model != null && model!.equipmentsFindings != null && model!.equipmentsFindings!.isNotEmpty) if (model != null && model!.equipmentsFindings != null && model!.equipmentsFindings!.isNotEmpty)
...model!.equipmentsFindings!.map((item) { ...model!.equipmentsFindings!.map((item) {
final findingName = item.finding?.name ?? 'Unknown'; final findingName = item.finding?.name ?? 'Unknown';
@ -177,14 +208,17 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Asset Details", "Asset Information",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
), ),
6.height, 6.height,
'${context.translation.assetName}: ${model?.asset?.assetName ?? '-'}'.bodyText(context), '${context.translation.assetName}: ${model?.asset?.assetName ?? '-'}'.bodyText(context),
'${context.translation.assetNo}: ${model?.asset?.assetNumber ?? '-'}'.bodyText(context), '${context.translation.assetNo}: ${model?.asset?.assetNumber ?? '-'}'.bodyText(context),
'${context.translation.serialNumber}: ${model?.asset?.assetNumber ?? '-'}'.bodyText(context),
'${context.translation.manufacture}: ${model?.asset?.manufacturerName ?? '-'}'.bodyText(context), '${context.translation.manufacture}: ${model?.asset?.manufacturerName ?? '-'}'.bodyText(context),
'${context.translation.model}: ${model?.asset?.modelName ?? '-'}'.bodyText(context), '${context.translation.model}: ${model?.asset?.modelName ?? '-'}'.bodyText(context),
'${context.translation.site}: ${model?.asset?.siteName ?? '-'}'.bodyText(context),
'${context.translation.department}: ${model?.asset?.departmentName ?? '-'}'.bodyText(context),
], ],
); );
} }

@ -21,7 +21,6 @@ class EquipmentInternalAuditItemView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
//TODO need to refactor this code repetation @waseem
if (requestData != null) { if (requestData != null) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -44,8 +43,8 @@ class EquipmentInternalAuditItemView extends StatelessWidget {
), ),
8.height, 8.height,
(requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context),
infoWidget(label: context.translation.assetNumber, value: requestData?.assetNumber, context: context), infoWidget(label: context.translation.requestNo, value: requestData!.requestNo, context: context),
infoWidget(label: context.translation.assetNumber, value: requestData!.assetNumber, context: context),
8.height, 8.height,
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -60,7 +59,7 @@ class EquipmentInternalAuditItemView extends StatelessWidget {
), ),
], ],
).toShadowContainer(context, withShadow: showShadow).onPress(() async { ).toShadowContainer(context, withShadow: showShadow).onPress(() async {
Navigator.push(context, MaterialPageRoute(builder: (context) => EquipmentInternalAuditDetailPage(auditId: requestDetails!.id!))); Navigator.push(context, MaterialPageRoute(builder: (context) => EquipmentInternalAuditDetailPage(auditId: requestData!.id!)));
}); });
} }
return Column( return Column(
@ -85,9 +84,11 @@ class EquipmentInternalAuditItemView extends StatelessWidget {
8.height, 8.height,
(requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context),
8.height, 8.height,
infoWidget(label: context.translation.requestNo, value: requestDetails!.requestNo, context: context),
infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context), infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context),
infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context), infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context),
infoWidget(label: context.translation.model, value: requestDetails!.model, context: context), infoWidget(label: context.translation.model, value: requestDetails!.model, context: context),
infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
8.height, 8.height,
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

@ -20,6 +20,7 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
class SystemInternalAuditDetailPage extends StatefulWidget { class SystemInternalAuditDetailPage extends StatefulWidget {
static const String id = "/details-system-internal-audit"; static const String id = "/details-system-internal-audit";
@ -79,17 +80,45 @@ class _SystemInternalAuditDetailPageState extends State<SystemInternalAuditDetai
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
assetInformation(), Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
StatusLabel(
label: model!.status!.name,
id: model!.status!.value,
radius: 4,
textColor: AppColor.getRequestStatusTextColorByName(
context,
model!.status!.name,
),
backgroundColor: AppColor.getRequestStatusColorByName(
context,
model!.status!.name,
),
// textColor: AppColor.green15,
// backgroundColor: AppColor.greenStatus(context),
),
Text(
model!.createdDate!.toString().toServiceRequestCardFormat,
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
)
],
),
8.height, 8.height,
workOrderInformation(), workOrderInfo(),
const Divider().defaultStyle(context),
8.height, 8.height,
assetInfo(),
//TODO need to check for comments //TODO need to check for comments
if (model?.findingDescription?.isNotEmpty ?? false) ...[ if (model?.findingDescription?.isNotEmpty ?? false) ...[
const Divider().defaultStyle(context), const Divider().defaultStyle(context),
// Text( Text(
// "Comments".addTranslation, "Remarks",
// style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
// ), ),
model!.findingDescription!.bodyText(context), model!.findingDescription!.bodyText(context),
], ],
//TODO need to check for attachments //TODO need to check for attachments
@ -143,10 +172,33 @@ class _SystemInternalAuditDetailPageState extends State<SystemInternalAuditDetai
6.height, 6.height,
labelValueText(context, context.translation.woNumber, details?.workOrderNo), labelValueText(context, context.translation.woNumber, details?.workOrderNo),
labelValueText(context, 'WO Type'.addTranslation, model?.workOrderType?.name), labelValueText(context, 'WO Type'.addTranslation, model?.workOrderType?.name),
labelValueText(context, context.translation.site, details?.woSite),
labelValueText(context, context.translation.assetName, details?.woAssetName), labelValueText(context, context.translation.assetName, details?.woAssetName),
labelValueText(context, context.translation.assetNo, details?.woAssetNo),
labelValueText(context, context.translation.manufacture, details?.woManufacturer), labelValueText(context, context.translation.manufacture, details?.woManufacturer),
labelValueText(context, context.translation.serialNumber, details?.wosn),
labelValueText(context, context.translation.model, details?.woModel), labelValueText(context, context.translation.model, details?.woModel),
labelValueText(context, context.translation.site, details?.woSite),
labelValueText(context, context.translation.department, details?.woDepartment),
],
);
}
Widget workOrderInfo() {
final details = model?.workOrderDetails;
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"WO Info",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
6.height,
labelValueText(context, context.translation.requestNo, model?.requestNo),
labelValueText(context, 'WO Type'.addTranslation, model?.workOrderType?.name),
labelValueText(context, context.translation.woNumber, details?.workOrderNo),
labelValueText(context, "Finding Type", model?.findingType?.name),
labelValueText(context, "Assigned Engineer", model?.workOrderDetails?.woAssignedEngineer),
], ],
); );
} }
@ -187,6 +239,28 @@ class _SystemInternalAuditDetailPageState extends State<SystemInternalAuditDetai
); );
} }
Widget assetInfo() {
final details = model?.workOrderDetails;
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Asset Details",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
6.height,
labelValueText(context, context.translation.assetName, details?.woAssetName),
labelValueText(context, context.translation.assetNo, details?.woAssetNo),
labelValueText(context, context.translation.manufacture, details?.woManufacturer),
labelValueText(context, context.translation.serialNumber, details?.wosn),
labelValueText(context, context.translation.model, details?.woModel),
labelValueText(context, context.translation.site, details?.woSite),
labelValueText(context, context.translation.department, details?.woDepartment),
],
);
}
Widget labelValueText(BuildContext context, String label, String? value) { Widget labelValueText(BuildContext context, String label, String? value) {
if (value == null || value.isEmpty) return const SizedBox.shrink(); if (value == null || value.isEmpty) return const SizedBox.shrink();

@ -44,9 +44,9 @@ class SystemInternalAuditItemView extends StatelessWidget {
], ],
), ),
8.height, 8.height,
(requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), (requestData?.typeTransaction ?? "System Audit Request").heading5(context),
infoWidget(label: context.translation.assetNo, value: requestData?.assetNumber, context: context), infoWidget(label: context.translation.requestNo, value: requestData!.requestNo, context: context),
infoWidget(label: context.translation.assetNumber, value: requestData?.assetNumber, context: context),
8.height, 8.height,
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -61,7 +61,7 @@ class SystemInternalAuditItemView extends StatelessWidget {
), ),
], ],
).toShadowContainer(context, withShadow: showShadow).onPress(() async { ).toShadowContainer(context, withShadow: showShadow).onPress(() async {
Navigator.push(context, MaterialPageRoute(builder: (context) => SystemInternalAuditDetailPage(auditId: requestDetails!.id!))); Navigator.push(context, MaterialPageRoute(builder: (context) => SystemInternalAuditDetailPage(auditId: requestData!.id!)));
}); });
} }
return Column( return Column(
@ -85,9 +85,12 @@ class SystemInternalAuditItemView extends StatelessWidget {
), ),
8.height, 8.height,
(requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context),
infoWidget(label: context.translation.requestNo, value: requestDetails!.requestNo, context: context),
infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context), infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context),
infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context), infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context),
infoWidget(label: context.translation.model, value: requestDetails!.model, context: context), infoWidget(label: context.translation.model, value: requestDetails!.model, context: context),
infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
8.height, 8.height,
// infoWidget(label: context.translation.site, value: requestDetails!.site, context: context), // infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
8.height, 8.height,

@ -1,8 +1,7 @@
import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/new_models/building.dart'; import 'package:test_sa/models/new_models/mapped_sites.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/models/new_models/traf_department.dart';
import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; import 'package:test_sa/modules/loan_module/models/medical_department_model.dart';
class LoanFormModel { class LoanFormModel {
@ -21,6 +20,8 @@ class LoanFormModel {
Site? site; Site? site;
MedicalDepartmentModel? department; MedicalDepartmentModel? department;
List<LoanAttachments>? loanAttachment; List<LoanAttachments>? loanAttachment;
MappedSite? mappedSite;
TrafDepartment? mappedDepartment;
LoanFormModel({ LoanFormModel({
this.docName, this.docName,
@ -38,6 +39,8 @@ class LoanFormModel {
this.loanAttachment, this.loanAttachment,
this.site, this.site,
this.department, this.department,
this.mappedSite,
this.mappedDepartment,
}); });
//{ //{
@ -91,8 +94,10 @@ class LoanFormModel {
"vendorNumber": vendorNumber, "vendorNumber": vendorNumber,
"vendorContact": vendorNumber, "vendorContact": vendorNumber,
"vendorEmail": vendorEmail, "vendorEmail": vendorEmail,
'siteId': site?.id, // 'siteId': site?.id,
'departmentId': department?.id, 'siteId': mappedSite?.id,
// 'departmentId': department?.id,
'departmentId': mappedDepartment?.id,
"loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [],
}; };
} }

@ -1,18 +1,20 @@
import 'package:test_sa/models/base.dart'; import 'package:test_sa/models/base.dart';
class MedicalDepartmentModel extends Base { class MedicalDepartmentModel extends Base {
MedicalDepartmentModel({ MedicalDepartmentModel(
this.departmentName, this.departmentCode, this.ntCode, this.costCenterNumber, this.costCenterName, this.name, this.id, this.createdBy, this.createdDate, this.modifiedBy, this.modifiedDate {this.departmentName, this.departmentCode, this.ntCode, this.costCenterNumber, this.costCenterName, this.name, this.id, this.createdBy, this.createdDate, this.modifiedBy, this.modifiedDate})
}) : super(identifier: id?.toString() ?? '', name: departmentName); // Handle potential null id : super(identifier: id?.toString() ?? '', name: departmentName); // Handle potential null id
MedicalDepartmentModel.fromJson(Map<String, dynamic> json) { MedicalDepartmentModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
identifier = id?.toString() ?? '';
name = json['departmentName'] ?? json['name'];
departmentName = json['departmentName'] ?? json['name']; departmentName = json['departmentName'] ?? json['name'];
departmentCode = json['departmentCode']; departmentCode = json['departmentCode'];
ntCode = json['ntCode']; ntCode = json['ntCode'];
costCenterNumber = json['costCenterNumber']; costCenterNumber = json['costCenterNumber'];
costCenterName = json['costCenterName']; costCenterName = json['costCenterName'];
name = json['name']; name = json['name'];
id = json['id'];
createdBy = json['createdBy']; createdBy = json['createdBy'];
createdDate = json['createdDate']; createdDate = json['createdDate'];
modifiedBy = json['modifiedBy']; modifiedBy = json['modifiedBy'];
@ -30,6 +32,4 @@ class MedicalDepartmentModel extends Base {
String? createdDate; String? createdDate;
String? modifiedBy; String? modifiedBy;
String? modifiedDate; String? modifiedDate;
} }

@ -1,58 +1,42 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
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/providers/api/device_transfer_provider.dart';
import 'package:test_sa/controllers/validator/validator.dart'; import 'package:test_sa/controllers/validator/validator.dart';
import 'package:test_sa/dashboard_latest/dashboard_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/string_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/helper/utils.dart'; import 'package:test_sa/helper/utils.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/mapped_sites.dart'; import 'package:test_sa/models/new_models/mapped_sites.dart';
import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/models/new_models/task_request/task_request_model.dart';
import 'package:test_sa/models/new_models/task_request/task_type_model.dart'; import 'package:test_sa/models/new_models/task_request/task_type_model.dart';
import 'package:test_sa/models/service_request/pending_service_request_model.dart'; import 'package:test_sa/models/new_models/traf_department.dart';
import 'package:test_sa/models/new_models/work_order_detail_model.dart';
import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; import 'package:test_sa/modules/cm_module/cm_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/loan_module/models/loan_form_model.dart'; import 'package:test_sa/modules/loan_module/models/loan_form_model.dart';
import 'package:test_sa/modules/loan_module/models/medical_department_model.dart';
import 'package:test_sa/modules/loan_module/provider/loan_period_provider.dart'; import 'package:test_sa/modules/loan_module/provider/loan_period_provider.dart';
import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; import 'package:test_sa/modules/loan_module/provider/loan_provider.dart';
import 'package:test_sa/modules/loan_module/provider/loan_provider.dart';
import 'package:test_sa/modules/loan_module/provider/medical_department_provider.dart'; import 'package:test_sa/modules/loan_module/provider/medical_department_provider.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/common_widgets/app_filled_button.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/department_provider.dart';
import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/providers/task_request_provider/task_job_provider.dart'; import 'package:test_sa/providers/lookups/department_lookup_provider.dart';
import 'package:test_sa/providers/task_request_provider/task_request_provider.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import '../../../../../../new_views/common_widgets/default_app_bar.dart'; import '../../../../../../new_views/common_widgets/default_app_bar.dart';
import '../../../models/new_models/department.dart';
class CreateLoanRequestPage extends StatefulWidget { class CreateLoanRequestPage extends StatefulWidget {
static const String id = "/create-loan"; static const String id = "/create-loan";
int? workOrderId; int? workOrderId;
WorkOrderData? workOrder;
CreateLoanRequestPage({Key? key, this.workOrderId}) : super(key: key); CreateLoanRequestPage({Key? key, this.workOrderId, this.workOrder}) : super(key: key);
@override @override
_CreateLoanRequestPageState createState() => _CreateLoanRequestPageState(); _CreateLoanRequestPageState createState() => _CreateLoanRequestPageState();
@ -62,7 +46,6 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
final List<GenericAttachmentModel> attachments = []; final List<GenericAttachmentModel> attachments = [];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
Asset? device;
TaskType? selectedType; TaskType? selectedType;
final LoanFormModel _loanFormModel = LoanFormModel(); final LoanFormModel _loanFormModel = LoanFormModel();
@ -70,11 +53,14 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
bool get isBackUpRequest => widget.workOrderId != null; bool get isBackUpRequest => widget.workOrderId != null;
List<Lookup> loanTypes = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
Provider.of<MedicalDepartmentProvider>(context, listen: false).reset(); Provider.of<MedicalDepartmentProvider>(context, listen: false).reset();
Provider.of<LoanPeriodProvider>(context, listen: false).reset(); Provider.of<LoanPeriodProvider>(context, listen: false).reset();
loanTypes = [Lookup(id: 0, name: "Standard", value: 1), Lookup(id: 1, name: "Backup", value: 2)];
} }
@override @override
@ -92,23 +78,55 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SingleItemDropDownMenu<Lookup, NullableLoadingProvider>(
context: context,
title: "Loan Type",
enabled: false,
staticData: loanTypes,
initialValue: isBackUpRequest ? loanTypes[1] : loanTypes[0],
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
onSelect: (value) {},
),
16.height,
if (isBackUpRequest) ...[ if (isBackUpRequest) ...[
scanAssetButton(), 'Asset Information'.addTranslation.bodyText(context).custom(color: AppColor.black10),
8.height,
Text(
'${context.translation.assetName}: ${widget.workOrder!.assetNdModel!.name?.cleanupWhitespace?.capitalizeFirstOfEach}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.assetNumber}: ${widget.workOrder!.asset!.assetNumber}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.serialNo}: ${widget.workOrder!.asset!.assetSerialNo}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.model}: ${widget.workOrder!.model?.name!.cleanupWhitespace?.capitalizeFirstOfEach}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.manufacture}: ${widget.workOrder!.manufacturer?.name?.cleanupWhitespace?.capitalizeFirstOfEach}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
16.height, 16.height,
], ],
...doctorInfoSection(),
// ...contactInfoSection(), // ...contactInfoSection(),
// 16.height,
...itemDetailsSection(),
16.height, 16.height,
...doctorInfoSection(), ...itemDetailsSection(),
16.height, 16.height,
...vendorDetailsSection(), ...vendorDetailsSection(),
16.height, 16.height,
AttachmentPicker( AttachmentPicker(
label: context.translation.attachments, label: context.translation.attachments,
attachment: attachments, attachment: attachments,
buttonColor: AppColor.black10,
onlyImages: false, onlyImages: false,
showAsListView: true,
buttonIcon: 'image-plus'.toSvgAsset(color: context.isDark ? AppColor.primary10 : AppColor.neutral120), buttonIcon: 'image-plus'.toSvgAsset(color: context.isDark ? AppColor.primary10 : AppColor.neutral120),
onChange: (attachments) { onChange: (attachments) {
attachments = attachments; attachments = attachments;
@ -251,10 +269,10 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
return [ return [
'Item Details'.addTranslation.bodyText(context).custom(color: AppColor.black10), 'Item Details'.addTranslation.bodyText(context).custom(color: AppColor.black10),
8.height, 8.height,
SingleItemDropDownMenu<Site, SiteProvider>( SingleItemDropDownMenu<MappedSite, MappedSiteProvider>(
context: context, context: context,
title: context.translation.site, title: context.translation.site,
initialValue: _loanFormModel.site, initialValue: _loanFormModel.mappedSite,
showShadow: false, showShadow: false,
validator: (value) { validator: (value) {
if (value == null) return "Please select a site"; if (value == null) return "Please select a site";
@ -263,12 +281,17 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true, showAsBottomSheet: true,
onSelect: (value) { onSelect: (value) {
_loanFormModel.site = value; if(value!=null){
setState(() {}); _loanFormModel.mappedSite = value;
_loanFormModel.mappedDepartment = null;
Provider.of<DepartmentLookupProvider>(context,listen:false).getData(id:_loanFormModel.mappedSite?.id);
setState(() {});
}
}, },
), ),
8.height, 8.height,
SingleItemDropDownMenu<MedicalDepartmentModel, MedicalDepartmentProvider>( SingleItemDropDownMenu<TrafDepartment, DepartmentLookupProvider>(
context: context, context: context,
title: context.translation.department, title: context.translation.department,
showShadow: false, showShadow: false,
@ -277,11 +300,11 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
return null; return null;
}, },
showAsBottomSheet: true, showAsBottomSheet: true,
initialValue: _loanFormModel.department, initialValue: _loanFormModel.mappedDepartment,
requestById: context.userProvider.user?.clientId, requestById: context.userProvider.user?.clientId,
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
onSelect: (value) { onSelect: (value) {
_loanFormModel.department = value; _loanFormModel.mappedDepartment = value;
setState(() {}); setState(() {});
}, },
), ),
@ -473,24 +496,8 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
]; ];
} }
Widget scanAssetButton() {
return AssetPicker(
device: device,
showLoading: false,
borderColor: AppColor.black20,
onPick: (asset) async {
device = asset;
setState(() {});
},
);
}
Future<void> _submit() async { Future<void> _submit() async {
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
if (isBackUpRequest && device == null) {
"Please scan or pick asset".showToast;
return;
}
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
_formKey.currentState!.save(); _formKey.currentState!.save();
@ -507,7 +514,12 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
body["requestorUserID"] = context.userProvider.user!.userID; body["requestorUserID"] = context.userProvider.user!.userID;
if (isBackUpRequest) { if (isBackUpRequest) {
body["assetId"] = device!.id; body["assetId"] = widget.workOrder!.asset!.id;
body["assetName"] = widget.workOrder!.assetNdModel!.name;
body["assetNumber"] = widget.workOrder!.asset!.assetNumber;
body["assetSerialNumber"] = widget.workOrder!.asset!.assetSerialNo;
body["model"] = widget.workOrder!.model?.name;
body["manufacturer"] = widget.workOrder!.manufacturer?.name;
body["cMWOItemId"] = widget.workOrderId; body["cMWOItemId"] = widget.workOrderId;
} }
bool isSuccess = await loanProvider.addLoanRequest(body); bool isSuccess = await loanProvider.addLoanRequest(body);

@ -1,4 +1,5 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart'; 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';
@ -8,9 +9,10 @@ import 'dart:convert';
class LoanProvider extends ChangeNotifier { class LoanProvider extends ChangeNotifier {
Future<bool> addLoanRequest(Map<String, dynamic> body) async { Future<bool> addLoanRequest(Map<String, dynamic> body) async {
try { try {
Response response = await ApiManager.instance.post(URLs.addLoan, body: body); Response response = await ApiManager.instance.post(URLs.addLoan, body: body, showToast: false);
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]); String message = (jsonDecode(response.body)["data"] ?? "") + " " + (jsonDecode(response.body)["message"] ?? "");
Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG);
return true; return true;
} }
return false; return false;

@ -62,10 +62,6 @@ class _CreateDeviceTransferRequestState extends State<CreateDeviceTransferReques
bool checkPendingRequest = false; bool checkPendingRequest = false;
void showPendingRequests() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!)));
}
void _onSubmit() async { void _onSubmit() async {
_transferModel.assetId = _pickedAsset?.id; _transferModel.assetId = _pickedAsset?.id;
_transferModel.destSiteId = _assetDestination.site?.id; _transferModel.destSiteId = _assetDestination.site?.id;

@ -9,6 +9,7 @@ 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/models/device/device_transfer.dart'; import 'package:test_sa/models/device/device_transfer.dart';
import 'package:test_sa/modules/cx_module/chat/chat_widget.dart';
import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
@ -22,8 +23,9 @@ import 'update_device_transfer.dart';
class DeviceTransferDetails extends StatefulWidget { class DeviceTransferDetails extends StatefulWidget {
final DeviceTransfer model; final DeviceTransfer model;
final int moduleId;
const DeviceTransferDetails({Key? key, required this.model}) : super(key: key); const DeviceTransferDetails({Key? key, required this.model, required this.moduleId}) : super(key: key);
@override @override
State<DeviceTransferDetails> createState() => _DeviceTransferDetailsState(); State<DeviceTransferDetails> createState() => _DeviceTransferDetailsState();
@ -131,6 +133,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
] else ...[ ] else ...[
// sender card // sender card
_buildCard( _buildCard(
_model!,
isSender: true, isSender: true,
site: _model?.senderSiteName?.cleanupWhitespace.capitalizeFirstOfEach ?? "", site: _model?.senderSiteName?.cleanupWhitespace.capitalizeFirstOfEach ?? "",
dept: _model?.senderDepartmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "", dept: _model?.senderDepartmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "",
@ -150,6 +153,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
8.height, 8.height,
// receiver card // receiver card
_buildCard( _buildCard(
_model!,
isSender: false, isSender: false,
site: _model?.destSiteName?.cleanupWhitespace.capitalizeFirstOfEach ?? "", site: _model?.destSiteName?.cleanupWhitespace.capitalizeFirstOfEach ?? "",
dept: _model?.destDepartmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "", dept: _model?.destDepartmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "",
@ -215,7 +219,17 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
], ],
), ),
], ],
), ).expanded,
if (context.userProvider.isEngineer || context.userProvider.isNurse)
ChatWidget(
moduleId: widget.moduleId,
isShow: context.settingProvider.isUserFlowMedical && _model!.senderMachineStatusValue! != 4,
isReadOnly: _model!.senderMachineStatusValue! != 1,
requestId: widget.model.id!.toInt(),
assigneeEmployeeNumber: _model!.senderAssignedEmployeeNumber,
myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
contactEmployeeINumber: _model!.assetTransferContactPersons!.first.employeeNumber,
),
if ((_userProvider!.user?.type == UsersTypes.engineer)) if ((_userProvider!.user?.type == UsersTypes.engineer))
if (isCurrentEngineerEligibleForEdit && isCurrentRequestEditAble) if (isCurrentEngineerEligibleForEdit && isCurrentRequestEditAble)
"edit".toSvgAsset(height: 40, width: 40).onPress(() async { "edit".toSvgAsset(height: 40, width: 40).onPress(() async {
@ -248,7 +262,8 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
).toShadowContainer(context); ).toShadowContainer(context);
} }
_buildCard({required String site, String? building, String? dept, String? floor, required String comment, required bool isSender, StatusLabel? statusLabel, String? assignTo}) { _buildCard(DeviceTransfer _deviceTransfer,
{required String site, String? building, String? dept, String? floor, required String comment, required bool isSender, StatusLabel? statusLabel, String? assignTo}) {
bool isCurrentEngineerEligibleForEdit = isSender ? _model?.senderAssignedEmployeeId == _userProvider!.user?.userID : _model?.receiverAssignedEmployeeId == _userProvider!.user?.userID; bool isCurrentEngineerEligibleForEdit = isSender ? _model?.senderAssignedEmployeeId == _userProvider!.user?.userID : _model?.receiverAssignedEmployeeId == _userProvider!.user?.userID;
bool isCurrentRequestClosed = isSender ? ((_model?.senderMachineStatusValue == 3)) : ((_model?.receiverMachineStatusValue == 3)); bool isCurrentRequestClosed = isSender ? ((_model?.senderMachineStatusValue == 3)) : ((_model?.receiverMachineStatusValue == 3));
@ -265,7 +280,17 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
if (statusLabel != null) 8.height, if (statusLabel != null) 8.height,
isSender ? context.translation.senderDetails.heading5(context) : context.translation.receiverDetails.heading5(context), isSender ? context.translation.senderDetails.heading5(context) : context.translation.receiverDetails.heading5(context),
], ],
), ).expanded,
if (context.userProvider.isEngineer || context.userProvider.isNurse)
ChatWidget(
moduleId: widget.moduleId,
isShow: context.settingProvider.isUserFlowMedical && (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue!) != 0,
isReadOnly: (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue) != 1,
requestId: widget.model.id!.toInt(),
assigneeEmployeeNumber: isSender ? _deviceTransfer.senderAssignedEmployeeNumber! : _deviceTransfer.receiverAssignedEmployeeNumber!,
myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
contactEmployeeINumber: _deviceTransfer.assetTransferContactPersons!.first.employeeNumber,
),
if ((_userProvider!.user?.type == UsersTypes.engineer)) if ((_userProvider!.user?.type == UsersTypes.engineer))
if (isCurrentEngineerEligibleForEdit && !isCurrentRequestClosed) if (isCurrentEngineerEligibleForEdit && !isCurrentRequestClosed)
@ -273,7 +298,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
// ? (!(_model?.senderMachineStatusName?.toLowerCase()?.contains("close") ?? false) && !(_model?.senderMachineStatusName?.toLowerCase()?.contains("complete") ?? false)) // ? (!(_model?.senderMachineStatusName?.toLowerCase()?.contains("close") ?? false) && !(_model?.senderMachineStatusName?.toLowerCase()?.contains("complete") ?? false))
// : (!(_model?.receiverMachineStatusName?.toLowerCase()?.contains("close") ?? false) && !(_model?.receiverMachineStatusName?.toLowerCase()?.contains("complete") ?? false))) // : (!(_model?.receiverMachineStatusName?.toLowerCase()?.contains("close") ?? false) && !(_model?.receiverMachineStatusName?.toLowerCase()?.contains("complete") ?? false)))
// //
"edit".toSvgAsset(height: 48, width: 48).onPress(() async { "edit".toSvgAsset(height: 48, width: 48).onPress(() async {
bool isReload = (await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateDeviceTransfer(model: _model!, isSender: isSender)))) as bool; bool isReload = (await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateDeviceTransfer(model: _model!, isSender: isSender)))) as bool;
if (isReload ?? false) { if (isReload ?? false) {
setState(() {}); setState(() {});

@ -28,8 +28,9 @@ import 'update_gas_refill_request.dart';
class GasRefillDetailsPage extends StatefulWidget { class GasRefillDetailsPage extends StatefulWidget {
GasRefillModel model; GasRefillModel model;
String? priority, date; String? priority, date;
final int moduleId;
GasRefillDetailsPage({Key? key, this.priority, this.date, required this.model}) : super(key: key); GasRefillDetailsPage({Key? key, this.priority, this.date, required this.model, required this.moduleId}) : super(key: key);
@override @override
State<GasRefillDetailsPage> createState() => _GasRefillDetailsPageState(); State<GasRefillDetailsPage> createState() => _GasRefillDetailsPageState();
@ -59,21 +60,22 @@ class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
appBar: DefaultAppBar( appBar: DefaultAppBar(
title: context.translation.gasRefillDetails, title: context.translation.gasRefillDetails,
actions: [ actions: [
// if (context.userProvider.isEngineer || context.userProvider.isNurse) if (context.userProvider.isEngineer || context.userProvider.isNurse)
// Selector<GasRefillProvider, GasRefillModel?>( Selector<GasRefillProvider, GasRefillModel?>(
// selector: (_, myModel) => myModel.gasRefillModel, // Selects only the userName selector: (_, myModel) => myModel.gasRefillModel, // Selects only the userName
// builder: (_, _gasRefillModel, __) { builder: (_, _gasRefillModel, __) {
// if (_gasRefillModel == null) return const SizedBox(); if (_gasRefillModel == null) return const SizedBox();
// return ChatWidget(
// moduleId: 2, return ChatWidget(
// isShow: _gasRefillModel.status!.value! == 1, moduleId: widget.moduleId,
// // isReadOnly: _gasRefillModel.status!.value! == 1, isShow: context.settingProvider.isUserFlowMedical && _gasRefillModel.status!.value! != 0,
// requestId: widget.model.id!.toInt(), isReadOnly: _gasRefillModel.status!.value! != 1,
// assigneeEmployeeNumber: _gasRefillModel.assignedEmployee!.name!, requestId: widget.model.id!.toInt(),
// myLoginUserID: context.userProvider.user!.username!, assigneeEmployeeNumber: _gasRefillModel.assignedEmployee?.employeeId!,
// contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!, myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
// ); contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!,
// }) );
})
], ],
), ),
key: _scaffoldKey, key: _scaffoldKey,

@ -11,6 +11,7 @@ import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/new_models/task_request/task_request_model.dart'; import 'package:test_sa/models/new_models/task_request/task_request_model.dart';
import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; import 'package:test_sa/modules/cm_module/cm_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/cx_module/chat/chat_widget.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
import 'package:test_sa/providers/task_request_provider/task_request_provider.dart'; import 'package:test_sa/providers/task_request_provider/task_request_provider.dart';
@ -29,8 +30,9 @@ class TaskRequestDetailsView extends StatefulWidget {
static const String id = "/task-request-detail"; static const String id = "/task-request-detail";
final int taskId; final int taskId;
final RequestsDetails? requestDetails; final RequestsDetails? requestDetails;
final int moduleId;
const TaskRequestDetailsView({Key? key, required this.taskId, this.requestDetails}) : super(key: key); const TaskRequestDetailsView({Key? key, required this.taskId, this.requestDetails, required this.moduleId}) : super(key: key);
@override @override
_TaskRequestDetailsViewState createState() { _TaskRequestDetailsViewState createState() {
@ -65,7 +67,31 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
userProvider ??= Provider.of<UserProvider>(context, listen: false); userProvider ??= Provider.of<UserProvider>(context, listen: false);
return Scaffold( return Scaffold(
appBar: DefaultAppBar(title: context.translation.taskRequest), appBar: DefaultAppBar(
title: context.translation.taskRequest,
actions: [
if (context.userProvider.isEngineer || context.userProvider.isNurse)
Selector<TaskRequestProvider, TaskData?>(
selector: (_, myModel) => myModel.taskRequestModel, // Selects only the userName
builder: (_, _taskReqModel, __) {
if (_taskReqModel == null) return const SizedBox();
if ((context.userProvider.isEngineer || context.userProvider.isNurse) &&
_taskReqModel.assignedEngineer?.employeeId != null &&
(_taskReqModel.taskJobContactPersons?.isNotEmpty ?? false)) {
return ChatWidget(
moduleId: widget.moduleId,
isShow: context.settingProvider.isUserFlowMedical && _taskReqModel.taskJobStatus!.value! != 1,
isReadOnly: _taskReqModel.taskJobStatus!.value! != 2,
requestId: widget.taskId.toInt(),
assigneeEmployeeNumber: _taskReqModel.assignedEngineer?.employeeId!,
myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
contactEmployeeINumber: _taskReqModel.taskJobContactPersons!.first.user?.employeeId,
);
} else
return const SizedBox();
})
],
),
body: Consumer<TaskRequestProvider>(builder: (context, taskProvider, child) { body: Consumer<TaskRequestProvider>(builder: (context, taskProvider, child) {
TaskData? taskModel = taskProvider.taskRequestModel; TaskData? taskModel = taskProvider.taskRequestModel;
return taskProvider.isLoading return taskProvider.isLoading

@ -68,7 +68,8 @@ class TaskRequestItemView extends StatelessWidget {
Navigator.of(context).push(MaterialPageRoute( Navigator.of(context).push(MaterialPageRoute(
builder: (_) => TaskRequestDetailsView( builder: (_) => TaskRequestDetailsView(
taskId: requestData!.id!, taskId: requestData!.id!,
requestDetails: RequestsDetails(nameOfType: requestData?.nameOfType, status: requestData?.statusName, priority: requestData?.priorityName, date: requestData?.transactionDate), moduleId: requestData!.transactionNo!,
requestDetails: RequestsDetails(nameOfType: requestData?.nameOfType, status: requestData?.statusName, priority: requestData?.priorityName, date: requestData?.transactionDate, ),
))); )));
}); });
} }
@ -122,6 +123,7 @@ class TaskRequestItemView extends StatelessWidget {
Navigator.of(context).push(MaterialPageRoute( Navigator.of(context).push(MaterialPageRoute(
builder: (_) => TaskRequestDetailsView( builder: (_) => TaskRequestDetailsView(
taskId: requestDetails!.id!, taskId: requestDetails!.id!,
moduleId: requestDetails!.transactionType!,
requestDetails: requestDetails, requestDetails: requestDetails,
))); )));
}); });

@ -18,13 +18,12 @@ class AppBottomNavigationBar extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
bool isEngineer = (Provider.of<UserProvider>(context, listen: false).user?.type) == UsersTypes.engineer; bool isEngineer = (Provider.of<UserProvider>(context, listen: false).user?.type) == UsersTypes.engineer;
bool isUserFMS = Provider.of<SettingProvider>(context, listen: false).isUserFMS; bool isUserFMS = Provider.of<SettingProvider>(context, listen: false).isUserFMS;
bool commissioningEng = context.userProvider.isCommissioningEngineer;
List<NavItemModel> navItems = [ List<NavItemModel> navItems = [
NavItemModel(0, "overview", context.translation.overview), NavItemModel(0, "overview", context.translation.overview),
NavItemModel(1, "request_icon", context.translation.workOrder), NavItemModel(1, "request_icon", context.translation.workOrder),
//TODO unCommit this to disable task if (!commissioningEng) NavItemModel(2, "add_icon", context.translation.calendar, showLabel: false),
// if (!isEngineer||isUserFMS)
NavItemModel(2, "add_icon", context.translation.calendar, showLabel: false),
NavItemModel(3, "assets", context.translation.assets), NavItemModel(3, "assets", context.translation.assets),
NavItemModel(4, "contact", context.translation.contact), NavItemModel(4, "contact", context.translation.contact),
]; ];

@ -5,12 +5,20 @@ import 'package:test_sa/new_views/app_style/app_color.dart';
class CustomBadge extends StatelessWidget { class CustomBadge extends StatelessWidget {
final Widget child; // The widget that the badge will be overlaid on. final Widget child; // The widget that the badge will be overlaid on.
final int value; // The value or text to be displayed in the badge. final int value; // The value or text to be displayed in the badge.
final Color color; // The background color of the badge. final Color color;
final double? positionR;
final double? positionT;
final double? height;
final double? width;
const CustomBadge({ CustomBadge({
Key? key, Key? key,
required this.child, required this.child,
required this.value, required this.value,
this.height,
this.width,
this.positionR,
this.positionT,
this.color = AppColor.red30, // Default color is red this.color = AppColor.red30, // Default color is red
}) : super(key: key); }) : super(key: key);
@ -22,13 +30,14 @@ class CustomBadge extends StatelessWidget {
child, // The main widget child, // The main widget
// if (value > 0) // if (value > 0)
Positioned( Positioned(
right: -6, right: positionR ?? -6,
top: -6, top: positionT ?? -6,
//Need to check why opacity he used here this is not correct need to make this total dynamic and responsive
child: Opacity( child: Opacity(
opacity: value > 0 ? 1 : 0, opacity: value > 0 ? 1 : 0,
child: Container( child: Container(
height: 23, height: height ?? 23,
constraints: const BoxConstraints(minWidth: 23), constraints: BoxConstraints(minWidth: width ?? 23),
padding: const EdgeInsets.all(3), padding: const EdgeInsets.all(3),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(30)), decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(30)),
@ -43,3 +52,139 @@ class CustomBadge extends StatelessWidget {
); );
} }
} }
//Need to use this badge every where..
class CustomBadge2 extends StatelessWidget {
final Widget child;
final int value;
final double top;
final double right;
final double left;
final double bottom;
final double minSize;
final Color backgroundColor;
final Color textColor;
final TextStyle? textStyle;
final int maxValue;
final Duration animationDuration;
const CustomBadge2({
super.key,
required this.child,
required this.value,
this.top = -6,
this.right = -6,
this.left = double.nan,
this.bottom = double.nan,
this.minSize = 18,
this.backgroundColor = AppColor.red30,
this.textColor = AppColor.white10,
this.textStyle,
this.maxValue = 99,
this.animationDuration = const Duration(milliseconds: 200),
});
bool get _isVisible => value > 0;
@override
Widget build(BuildContext context) {
return Stack(
clipBehavior: Clip.none,
children: [
child,
if (_isVisible)
Positioned(
top: top.isNaN ? null : top,
right: right.isNaN ? null : right,
left: left.isNaN ? null : left,
bottom: bottom.isNaN ? null : bottom,
child: AnimatedScale(
scale: _isVisible ? 1 : 0,
duration: animationDuration,
curve: Curves.easeOutBack,
child: AnimatedOpacity(
opacity: _isVisible ? 1 : 0,
duration: animationDuration,
child: _Badge(
value: value,
maxValue: maxValue,
minSize: minSize,
backgroundColor: backgroundColor,
textColor: textColor,
textStyle: textStyle ??
Theme.of(context).textTheme.labelSmall?.copyWith(
fontWeight: FontWeight.w700,
),
),
),
),
),
],
);
}
}
class _Badge extends StatelessWidget {
final int value;
final int maxValue;
final double minSize;
final Color backgroundColor;
final Color textColor;
final TextStyle? textStyle;
const _Badge({
required this.value,
required this.maxValue,
required this.minSize,
required this.backgroundColor,
required this.textColor,
this.textStyle,
});
bool get _isOverflow => value > maxValue;
@override
Widget build(BuildContext context) {
final TextStyle baseStyle = (textStyle ?? Theme.of(context).textTheme.labelMedium)!.copyWith(
color: textColor,
fontWeight: FontWeight.w700,
);
final double badgeSize = minSize;
return IgnorePointer(
child: SizedBox(
width: badgeSize,
height: badgeSize,
child: DecoratedBox(
decoration: const BoxDecoration(
shape: BoxShape.circle,
),
child: DecoratedBox(
decoration: BoxDecoration(
color: backgroundColor,
shape: BoxShape.circle,
),
child: Center(
child: _isOverflow
? FittedBox(
child: Text(
'$maxValue+',
style: baseStyle.copyWith(
fontSize: badgeSize * 0.45,
),
),
)
: CounterAnimatedText(
value: value,
style: baseStyle.copyWith(
fontSize: badgeSize * 0.6,
),
),
),
),
),
),
);
}
}

@ -113,12 +113,14 @@ class CreateRequestModel {
// list.add(CreateRequestModel(module.module!.name!, "add_icon", CreateTaskView.id)); // list.add(CreateRequestModel(module.module!.name!, "add_icon", CreateTaskView.id));
// } // }
// }); // });
if (context.userProvider.isQualityUser) { if (context.userProvider.isQualityUser && context.settingProvider.isUserFlowMedical) {
list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id)); list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id));
list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id)); list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id));
} else if (context.userProvider.isAssessor) { }
list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); // else if (context.userProvider.isAssessor) {
} else if (context.userProvider.isEngineer) { // list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id));
// }
else if (context.userProvider.isEngineer) {
if (Provider.of<SettingProvider>(context, listen: false).engineerCanCreateCM) { if (Provider.of<SettingProvider>(context, listen: false).engineerCanCreateCM) {
list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateCMRequest.id)); list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateCMRequest.id));
} }
@ -135,7 +137,7 @@ class CreateRequestModel {
list.add(CreateRequestModel(context.translation.transferAsset, "add_icon", CreateDeviceTransferRequest.id)); list.add(CreateRequestModel(context.translation.transferAsset, "add_icon", CreateDeviceTransferRequest.id));
//TODO uncommit this to enable task. //TODO uncommit this to enable task.
list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id)); list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id));
list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); // list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id));
list.add(CreateRequestModel('Loan Equipment Request'.addTranslation, "add_icon", CreateLoanRequestPage.id)); list.add(CreateRequestModel('Loan Equipment Request'.addTranslation, "add_icon", CreateLoanRequestPage.id));
} }
return list; return list;

@ -1,8 +1,11 @@
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:test_sa/controllers/notification/firebase_notification_manger.dart';
import 'package:test_sa/controllers/notification/notification_manger.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/app_settings.dart'; import 'package:test_sa/controllers/providers/settings/app_settings.dart';
import 'package:test_sa/dashboard_latest/dashboard_view.dart'; import 'package:test_sa/dashboard_latest/dashboard_view.dart';
@ -42,7 +45,7 @@ class _LandPageState extends State<LandPage> {
bool showAppbar = true; bool showAppbar = true;
late List<Widget> _pages; late List<Widget> _pages;
UserProvider? _userProvider; UserProvider? _userProvider;
bool isFCM = true;
@override @override
void initState() { void initState() {
_pages = <Widget>[]; _pages = <Widget>[];
@ -123,7 +126,14 @@ class _LandPageState extends State<LandPage> {
// if (_userProvider!.user!.type != UsersTypes.engineer) const CalendarPage(), // if (_userProvider!.user!.type != UsersTypes.engineer) const CalendarPage(),
const MyAssetsPage(fromBottomBar: true), const MyAssetsPage(fromBottomBar: true),
]; ];
if (isFCM) {
FirebaseNotificationManger.initialized(context);
NotificationManger.initialisation((notificationDetails) {
FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!));
}, (id, title, body, payload) async {});
isFCM = false;
}
checkLocalAuth(); checkLocalAuth();
} }

@ -79,9 +79,9 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
if (isEngineer) { if (isEngineer) {
types[context.translation.recurrentWo] = 5; types[context.translation.recurrentWo] = 5;
types["Equipment Internal Audit".addTranslation] = 10; if (context.settingProvider.isUserFlowMedical) types["Equipment Internal Audit".addTranslation] = 10;
types["System Internal Audit".addTranslation] = 11; if (context.settingProvider.isUserFlowMedical) types["System Internal Audit".addTranslation] = 11;
types["Medical Gas Inspection".addTranslation] = 14; if (context.settingProvider.isUserFlowMedical) types["Medical Gas Inspection".addTranslation] = 11;
} }
if (context.settingProvider.isUserFlowMedical && isEngineer) { if (context.settingProvider.isUserFlowMedical && isEngineer) {
@ -94,16 +94,24 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
types[module.module!.name!] = module.module!.value!; types[module.module!.name!] = module.module!.value!;
} }
}); });
//Hide traf
// if (!isEngineer) {
// types['TRAF'] = 9;
// }
if (!isEngineer) { // if (context.userProvider.isAssessor) {
types['TRAF'] = 9; // types = {"TRAF": 9};
} // }
if (context.userProvider.isAssessor) {
types = {"TRAF": 9};
}
if (context.userProvider.isQualityUser) { if (context.userProvider.isQualityUser) {
types = {'Equipment Internal Audit': 10, 'System Internal Audit': 11}; if (context.settingProvider.isUserFlowMedical) types = {'Recall and Alert': 7};
if (context.settingProvider.isUserFlowMedical) types['Equipment Internal Audit'] = 10;
if (context.settingProvider.isUserFlowMedical) types['System Internal Audit'] = 11;
}
if (context.userProvider.isCommissioningEngineer) {
///TODO need to check what other requests type needed here.
types = {
'Asset Delivery': 13,
};
} }
final statuses = { final statuses = {

@ -62,14 +62,15 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
requestsList.add(Request(module.module!.value!, module.module!.name!.addTranslation)); requestsList.add(Request(module.module!.value!, module.module!.name!.addTranslation));
} }
}); });
if (context.userProvider.user!.type == UsersTypes.normal_user) { //Hide TRAF.
requestsList.add(Request(9, 'TRAF')); // if (context.userProvider.user!.type == UsersTypes.normal_user) {
} // requestsList.add(Request(9, 'TRAF'));
if (context.userProvider.isEngineer) { // }
if (context.userProvider.isEngineer &&context.settingProvider.isUserFlowMedical) {
requestsList.add(Request(10, 'Equipment Internal Audit')); requestsList.add(Request(10, 'Equipment Internal Audit'));
requestsList.add(Request(11, 'System Internal Audit')); requestsList.add(Request(11, 'System Internal Audit'));
//Need to be added for new user role commissioning engineer //Need to be added for new user role commissioning engineer
requestsList.add(Request(13, "Asset Delivery")); // requestsList.add(Request(13, "Asset Delivery"));
requestsList.add(Request(14, "Medical Gas Inspection")); requestsList.add(Request(14, "Medical Gas Inspection"));
} }
@ -78,14 +79,22 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
if (context.userProvider.isAssessor) { if (context.userProvider.isAssessor) {
requestsList = [ requestsList = [
Request(null, context.translation.allWorkOrder), Request(null, context.translation.allWorkOrder),
Request(9, 'TRAF'), // Request(9, 'TRAF'),
];
}
if (context.userProvider.isCommissioningEngineer) {
///TODO need to show only allowed ids for all workOrder
requestsList = [
Request(null, context.translation.allWorkOrder),
Request(13, "Asset Delivery"),
]; ];
} }
if (context.userProvider.isQualityUser) { if (context.userProvider.isQualityUser) {
requestsList = [ requestsList = [
Request(null, context.translation.allWorkOrder), Request(null, context.translation.allWorkOrder),
Request(10, 'Equipment Internal Audit'), if (context.settingProvider.isUserFlowMedical) Request(7, 'Recall and Alert'),
Request(11, 'System Internal Audit'), if (context.settingProvider.isUserFlowMedical) Request(10, 'Equipment Internal Audit'),
if (context.settingProvider.isUserFlowMedical) Request(11, 'System Internal Audit'),
]; ];
} }

@ -77,7 +77,7 @@ class DeviceItemView extends StatelessWidget {
), ),
], ],
).toShadowContainer(context, withShadow: showShadow).onPress(() { ).toShadowContainer(context, withShadow: showShadow).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => DeviceTransferDetails(model: DeviceTransfer(id: requestData!.id!)))); Navigator.of(context).push(MaterialPageRoute(builder: (_) => DeviceTransferDetails(model: DeviceTransfer(id: requestData!.id!), moduleId: requestData!.transactionNo!)));
}); });
} }
@ -138,7 +138,11 @@ class DeviceItemView extends StatelessWidget {
), ),
], ],
).toShadowContainer(context, withShadow: showShadow).onPress(() { ).toShadowContainer(context, withShadow: showShadow).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => DeviceTransferDetails(model: DeviceTransfer(id: requestDetails!.id!)))); Navigator.of(context).push(MaterialPageRoute(
builder: (_) => DeviceTransferDetails(
model: DeviceTransfer(id: requestDetails!.id!),
moduleId: requestDetails!.transactionType!,
)));
}); });
} }

@ -74,6 +74,7 @@ class GasRefillItemView extends StatelessWidget {
builder: (_) => GasRefillDetailsPage( builder: (_) => GasRefillDetailsPage(
priority: requestData!.priorityName, priority: requestData!.priorityName,
date: requestData!.transactionDate!, date: requestData!.transactionDate!,
moduleId: requestData!.transactionNo!,
model: GasRefillModel(id: requestData!.id), model: GasRefillModel(id: requestData!.id),
), ),
), ),
@ -135,6 +136,7 @@ class GasRefillItemView extends StatelessWidget {
builder: (_) => GasRefillDetailsPage( builder: (_) => GasRefillDetailsPage(
priority: requestDetails!.priority!, priority: requestDetails!.priority!,
date: requestDetails!.date, date: requestDetails!.date,
moduleId: requestDetails!.transactionType!,
model: GasRefillModel(id: requestDetails!.id), model: GasRefillModel(id: requestDetails!.id),
), ),
), ),

@ -81,7 +81,7 @@ class ServiceRequestItemView extends StatelessWidget {
), ),
], ],
).toShadowContainer(context, withShadow: showShadow).onPress(() async { ).toShadowContainer(context, withShadow: showShadow).onPress(() async {
await Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: requestData!.id!))); await Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: requestData!.id!, moduleId: requestData!.transactionNo!)));
if (refreshData) { if (refreshData) {
Provider.of<DashBoardProvider>(context, listen: false).refreshDashboard(userType: Provider.of<SettingProvider>(context, listen: false).user!.type!, context: context); Provider.of<DashBoardProvider>(context, listen: false).refreshDashboard(userType: Provider.of<SettingProvider>(context, listen: false).user!.type!, context: context);
} }
@ -140,7 +140,7 @@ class ServiceRequestItemView extends StatelessWidget {
), ),
], ],
).toShadowContainer(context, withShadow: showShadow).onPress(() { ).toShadowContainer(context, withShadow: showShadow).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: requestDetails!.id!))); Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: requestDetails!.id!, moduleId: requestDetails!.transactionType!)));
}); });
} }

@ -77,6 +77,7 @@ class TaskRequestProvider extends ChangeNotifier {
Future getTaskById({required int id, bool? showLoading = true}) async { Future getTaskById({required int id, bool? showLoading = true}) async {
try { try {
isLoading = showLoading ?? true; isLoading = showLoading ?? true;
taskRequestModel = null;
notifyListeners(); notifyListeners();
final response = await ApiManager.instance.get(URLs.getTaskByIdUrl + "?taskJobId=$id"); final response = await ApiManager.instance.get(URLs.getTaskByIdUrl + "?taskJobId=$id");
stateCode = response.statusCode; stateCode = response.statusCode;
@ -129,7 +130,6 @@ class TaskRequestProvider extends ChangeNotifier {
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
if (stateCode == 200) { if (stateCode == 200) {
return true; return true;
} }
return false; return false;

@ -9,9 +9,10 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart';
class PendingServiceRequestScreen extends StatelessWidget { class PendingServiceRequestScreen extends StatelessWidget {
final int moduleId;
final PendingAssetServiceRequest pendingAssetServiceRequest; final PendingAssetServiceRequest pendingAssetServiceRequest;
const PendingServiceRequestScreen(this.pendingAssetServiceRequest, {Key? key}) : super(key: key); const PendingServiceRequestScreen(this.pendingAssetServiceRequest, this.moduleId, {Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -63,7 +64,7 @@ class PendingServiceRequestScreen extends StatelessWidget {
], ],
), ),
).onPress(() { ).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: pendingAssetServiceRequest.details![index].id ?? 0))); Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: pendingAssetServiceRequest.details![index].id ?? 0, moduleId: moduleId)));
}))); })));
} }
} }

@ -122,7 +122,7 @@ class _AssetDetailPageState extends State<AssetDetailPage> {
"${context.translation.building}: ${assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), "${context.translation.building}: ${assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
"${context.translation.floor}: ${assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), "${context.translation.floor}: ${assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
"${context.translation.md}: ${assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), "${context.translation.md}: ${assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
"${context.translation.room}: ${assetModel.room?.value ?? "-"}".bodyText(context), "${context.translation.room}: ${assetModel.room?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
], ],
).expanded, ).expanded,
], ],

@ -1,10 +1,15 @@
import 'dart:io'; import 'dart:io';
import 'package:ellipsized_text/ellipsized_text.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:open_file/open_file.dart'; import 'package:open_file/open_file.dart';
import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/api_routes/urls.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/extensions/widget_extensions.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/loaders/image_loader.dart'; import 'package:test_sa/views/widgets/loaders/image_loader.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -12,78 +17,180 @@ import 'package:url_launcher/url_launcher.dart';
class FilesList extends StatelessWidget { class FilesList extends StatelessWidget {
final List<String> images; final List<String> images;
final EdgeInsets? padding; final EdgeInsets? padding;
final bool showAsListView;
const FilesList({Key? key, this.images = const <String>[], this.padding}) : super(key: key); const FilesList({Key? key, this.images = const <String>[], this.padding, this.showAsListView = false}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GridView.builder( return showAsListView
padding: const EdgeInsets.only(top: 8, bottom: 8), ? ListView.separated(
physics: const NeverScrollableScrollPhysics(), shrinkWrap: true,
shrinkWrap: true, padding: const EdgeInsets.only(top: 8),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 6, mainAxisSpacing: 8, crossAxisSpacing: 8), physics: const NeverScrollableScrollPhysics(),
itemCount: images.length, itemBuilder: (cxt, itemIndex) {
itemBuilder: (context, itemIndex) { if (!images[itemIndex].contains(".")) {
if (!images[itemIndex].contains(".")) { return const Text("Bad\nFile");
return const Text("Bad\nFile"); }
} var isImage =
var isImage = images[itemIndex].split(".").last.toLowerCase() == "png" || images[itemIndex].split(".").last.toLowerCase() == "jpg" || images[itemIndex].split(".").last.toLowerCase() == "jpeg"; images[itemIndex].split(".").last.toLowerCase() == "png" || images[itemIndex].split(".").last.toLowerCase() == "jpg" || images[itemIndex].split(".").last.toLowerCase() == "jpeg";
var isPdf = images[itemIndex].split(".").last.toLowerCase() == "pdf"; var isPdf = images[itemIndex].split(".").last.toLowerCase() == "pdf";
var isExcel = images[itemIndex].split(".").last.toLowerCase() == "xlsx"; var isExcel = images[itemIndex].split(".").last.toLowerCase() == "xlsx";
return Container( return Row(
decoration: ShapeDecoration( children: [
color: Colors.white, Container(
shape: RoundedRectangleBorder( width: 48.toScreenWidth,
side: const BorderSide(width: 1, color: Color(0xFFEAF1F4)), height: 48.toScreenWidth,
borderRadius: BorderRadius.circular(8), decoration: ShapeDecoration(
), color: Colors.white,
), shape: RoundedRectangleBorder(
child: ClipRRect( side: const BorderSide(width: 1, color: Color(0xFFEAF1F4)),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: (isImage ),
? (_isLocalUrl(images[itemIndex]) ),
? Image.file(File(images[itemIndex])) child: ClipRRect(
: ImageLoader( borderRadius: BorderRadius.circular(8),
url: images[itemIndex], child: (isImage
boxFit: BoxFit.cover, ? (_isLocalUrl(images[itemIndex])
height: 48, ? Image.file(File(images[itemIndex]))
width: 48, : ImageLoader(
)) url: images[itemIndex],
: Image.asset("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png")), boxFit: BoxFit.cover,
), height: 48,
).onPress(() async { width: 48,
if (isImage) { ))
Navigator.of(context).push( : Image.asset("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png")),
MaterialPageRoute(
builder: (_) => Scaffold(
body: SafeArea(
child: Stack(
children: [
// InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center,
InteractiveViewer(child: getImageWidget(itemIndex)).center,
const ABackButton(),
],
), ),
), ),
), 8.width,
), Column(
); crossAxisAlignment: CrossAxisAlignment.start,
} else if (_isLocalUrl(images[itemIndex])) { children: [
OpenFile.open(images[itemIndex]); EllipsizedText(
} else { images[itemIndex].split("/").last,
try { style: AppTextStyles.heading6.copyWith(color: AppColor.black10),
if (!await launchUrl(Uri.parse(images[itemIndex]), mode: LaunchMode.externalApplication)) { type: EllipsisType.start, // or EllipsisType.middle
Fluttertoast.showToast(msg: "UnExpected Error with file."); ),
throw Exception('Could not launch '); 4.height,
RichText(
text: TextSpan(
text: 'Asset Guide | ',
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral120),
children: <TextSpan>[
TextSpan(
text: 'View',
recognizer: TapGestureRecognizer()
..onTap = () async {
if (isImage) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Scaffold(
body: SafeArea(
child: Stack(
children: [
// InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center,
InteractiveViewer(child: getImageWidget(itemIndex)).center,
const ABackButton(),
],
),
),
),
),
);
} else if (_isLocalUrl(images[itemIndex])) {
OpenFile.open(images[itemIndex]);
} else {
try {
if (!await launchUrl(Uri.parse(images[itemIndex]), mode: LaunchMode.externalApplication)) {
Fluttertoast.showToast(msg: "UnExpected Error with file.");
throw Exception('Could not launch ');
}
} catch (ex) {
Fluttertoast.showToast(msg: "No Viewer found.");
}
}
},
style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10, decoration: TextDecoration.underline),
),
],
),
),
],
).expanded
],
);
},
separatorBuilder: (cxt, index) => 8.height,
itemCount: images.length)
: GridView.builder(
padding: const EdgeInsets.only(top: 8, bottom: 8),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 6, mainAxisSpacing: 8, crossAxisSpacing: 8),
itemCount: images.length,
itemBuilder: (context, itemIndex) {
if (!images[itemIndex].contains(".")) {
return const Text("Bad\nFile");
} }
} catch (ex) { var isImage =
Fluttertoast.showToast(msg: "No Viewer found."); images[itemIndex].split(".").last.toLowerCase() == "png" || images[itemIndex].split(".").last.toLowerCase() == "jpg" || images[itemIndex].split(".").last.toLowerCase() == "jpeg";
} var isPdf = images[itemIndex].split(".").last.toLowerCase() == "pdf";
} var isExcel = images[itemIndex].split(".").last.toLowerCase() == "xlsx";
});
}, return Container(
); decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
side: const BorderSide(width: 1, color: Color(0xFFEAF1F4)),
borderRadius: BorderRadius.circular(8),
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: (isImage
? (_isLocalUrl(images[itemIndex])
? Image.file(File(images[itemIndex]))
: ImageLoader(
url: images[itemIndex],
boxFit: BoxFit.cover,
height: 48,
width: 48,
))
: Image.asset("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png")),
),
).onPress(() async {
if (isImage) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Scaffold(
body: SafeArea(
child: Stack(
children: [
// InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center,
InteractiveViewer(child: getImageWidget(itemIndex)).center,
const ABackButton(),
],
),
),
),
),
);
} else if (_isLocalUrl(images[itemIndex])) {
OpenFile.open(images[itemIndex]);
} else {
try {
if (!await launchUrl(Uri.parse(images[itemIndex]), mode: LaunchMode.externalApplication)) {
Fluttertoast.showToast(msg: "UnExpected Error with file.");
throw Exception('Could not launch ');
}
} catch (ex) {
Fluttertoast.showToast(msg: "No Viewer found.");
}
}
});
},
);
// return ListView.separated( // return ListView.separated(
// padding: padding ?? EdgeInsets.symmetric(horizontal: 32 * AppStyle.getScaleFactor(context)), // padding: padding ?? EdgeInsets.symmetric(horizontal: 32 * AppStyle.getScaleFactor(context)),

@ -320,6 +320,7 @@ class AttachmentPicker extends StatefulWidget {
Color? buttonColor; Color? buttonColor;
final Function(List<GenericAttachmentModel>)? onChange; final Function(List<GenericAttachmentModel>)? onChange;
final bool showAsGrid; final bool showAsGrid;
final bool showAsListView;
AttachmentPicker( AttachmentPicker(
{Key? key, {Key? key,
@ -332,6 +333,7 @@ class AttachmentPicker extends StatefulWidget {
this.onlyImages = false, this.onlyImages = false,
this.onChange, this.onChange,
this.showAsGrid = false, this.showAsGrid = false,
this.showAsListView = false,
this.buttonColor}) this.buttonColor})
: super(key: key); : super(key: key);
@ -357,29 +359,54 @@ class _AttachmentPickerState extends State<AttachmentPicker> {
: onFilePicker), : onFilePicker),
16.height, 16.height,
if (widget.attachment.isNotEmpty) if (widget.attachment.isNotEmpty)
Wrap( widget.showAsListView
spacing: 8.toScreenWidth, ? ListView.separated(
children: List.generate( shrinkWrap: true,
widget.attachment.length, physics: const NeverScrollableScrollPhysics(),
(index) { padding: EdgeInsets.zero,
File image = File(widget.attachment[index].name!); itemBuilder: (cxt, index) {
return MultiFilesPickerItem( File image = File(widget.attachment[index].name!);
file: image, return MultiFilesPickerItem(
enabled: widget.enabled, file: image,
onRemoveTap: (image) { showAsListView: widget.showAsListView,
if (!widget.enabled) { enabled: widget.enabled,
return; onRemoveTap: (image) {
} if (!widget.enabled) {
widget.attachment.removeAt(index); return;
if (widget.onChange != null) { }
widget.onChange!(widget.attachment); widget.attachment.removeAt(index);
} if (widget.onChange != null) {
setState(() {}); widget.onChange!(widget.attachment);
}
setState(() {});
},
);
}, },
); separatorBuilder: (cxt, index) => 8.height,
}, itemCount: widget.attachment.length)
), : Wrap(
), spacing: 8.toScreenWidth,
children: List.generate(
widget.attachment.length,
(index) {
File image = File(widget.attachment[index].name!);
return MultiFilesPickerItem(
file: image,
enabled: widget.enabled,
onRemoveTap: (image) {
if (!widget.enabled) {
return;
}
widget.attachment.removeAt(index);
if (widget.onChange != null) {
widget.onChange!(widget.attachment);
}
setState(() {});
},
);
},
),
),
], ],
); );
} }
@ -402,11 +429,6 @@ class _AttachmentPickerState extends State<AttachmentPicker> {
} }
void showFileSourceSheet() async { void showFileSourceSheet() async {
// if (widget.attachment.length >= 5) {
// Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5);
// return;
// }
ImageSource source = (await showModalBottomSheet( ImageSource source = (await showModalBottomSheet(
context: context, context: context,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
@ -475,11 +497,6 @@ class _AttachmentPickerState extends State<AttachmentPicker> {
} }
onFilePicker() async { onFilePicker() async {
//TODO removed on request by Backend as they don't have anyissue with large number of files
// if (widget.attachment.length >= 5) {
// Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5);
// return;
// }
ImageSource? source = await showModalBottomSheet<ImageSource>( ImageSource? source = await showModalBottomSheet<ImageSource>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {

@ -1,5 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:ellipsized_text/ellipsized_text.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:open_file/open_file.dart'; import 'package:open_file/open_file.dart';
@ -18,8 +20,16 @@ class MultiFilesPickerItem extends StatelessWidget {
final bool enabled; final bool enabled;
final Function(File) onRemoveTap; final Function(File) onRemoveTap;
final VoidCallback? onRemove; final VoidCallback? onRemove;
final bool showAsListView;
const MultiFilesPickerItem({Key? key, required this.file, required this.enabled, required this.onRemoveTap, this.onRemove}) : super(key: key); const MultiFilesPickerItem({
Key? key,
required this.file,
required this.enabled,
required this.onRemoveTap,
this.onRemove,
this.showAsListView = false,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -27,6 +37,96 @@ class MultiFilesPickerItem extends StatelessWidget {
bool isPdf = file.path.split(".").last.toLowerCase() == "pdf"; bool isPdf = file.path.split(".").last.toLowerCase() == "pdf";
bool isExcel = file.path.split(".").last.toLowerCase() == "xlsx"; bool isExcel = file.path.split(".").last.toLowerCase() == "xlsx";
if (showAsListView) {
return Row(
children: [
Container(
width: 48.toScreenWidth,
height: 48.toScreenWidth,
decoration: BoxDecoration(
color: AppColor.neutral90,
border: Border.all(width: 1, color: context.isDark ? AppColor.neutral30 : AppColor.neutral30),
image: DecorationImage(
image: getImage(isImage, isPdf, isExcel, file),
fit: BoxFit.cover,
),
borderRadius: BorderRadius.circular(8),
),
),
8.width,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Flexible(
child: EllipsizedText(
file.path.split("/").last,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
type: EllipsisType.start, // or EllipsisType.middle
),
),
8.width,
if (enabled)
InkWell(
child: "remove".toSvgAsset(width: 16),
onTap: () {
onRemoveTap(file);
if (onRemove != null) {
onRemove!();
}
},
)
],
),
4.height,
RichText(
text: TextSpan(
text: 'Asset Guide | ',
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral120),
children: <TextSpan>[
TextSpan(
text: 'View',
recognizer: TapGestureRecognizer()
..onTap = () async {
if (isImage) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Scaffold(
appBar: const DefaultAppBar(),
body: SafeArea(
child: InteractiveViewer(
child: _isLocalUrl(file.path)
? Image.file(file)
: ImageLoader(
url: URLs.getFileUrl(file.path),
boxFit: BoxFit.cover,
),
).center,
),
),
),
);
} else if (_isLocalUrl(file.path)) {
OpenFile.open(file.path);
} else {
if (!await launchUrl(Uri.parse(URLs.getFileUrl(file.path)!), mode: LaunchMode.externalApplication)) {
Fluttertoast.showToast(msg: "UnExpected Error with file.");
throw Exception('Could not launch');
}
}
},
style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10, decoration: TextDecoration.underline),
),
],
),
),
],
).expanded
],
);
}
return SizedBox( return SizedBox(
width: 60.toScreenWidth, width: 60.toScreenWidth,
height: 60.toScreenWidth, height: 60.toScreenWidth,

@ -265,6 +265,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
ellipsized_text:
dependency: "direct main"
description:
name: ellipsized_text
sha256: d4d372c2baf8d4adfb2ca3728c1e5955d1683e75fae774b311d557ad13317105
url: "https://pub.dev"
source: hosted
version: "1.2.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:

@ -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.11+30 version: 1.5.0+32
environment: environment:
sdk: ">=3.5.0 <4.0.0" sdk: ">=3.5.0 <4.0.0"
@ -98,6 +98,7 @@ dependencies:
tree_view_flutter: ^1.0.2 tree_view_flutter: ^1.0.2
audio_waveforms: ^1.3.0 audio_waveforms: ^1.3.0
signalr_netcore: ^1.4.4 signalr_netcore: ^1.4.4
ellipsized_text: ^1.2.0
local_auth_darwin: any local_auth_darwin: any
dev_dependencies: dev_dependencies:

Loading…
Cancel
Save