Merge branch 'refs/heads/design_3.0_loan_module' into design_3.0_asset_delivery_module

# Conflicts:
#	lib/controllers/api_routes/urls.dart
design_3.0_asset_delivery_module
Sikander Saleem 2 months ago
commit 9f670d4a0b

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

@ -1,7 +1,7 @@
class URLs {
URLs._();
static const String appReleaseBuildNumber = "28";
static const String appReleaseBuildNumber = "31";
// static const host1 = "https://atomsm.hmg.com"; // production url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
@ -67,8 +67,10 @@ class URLs {
//service request new flow urls.
static get nurseDashboardCountUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseCount';
static get qaAuditorCount => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorCount';
static get nurseDashboardDetailsUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseDetails';
static get qaAuditorDetails => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorDetails';
static get nurseRejectUrl => '$_baseUrl/ServiceRequest/NurseReject';

@ -110,12 +110,13 @@ class FirebaseNotificationManger {
serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()));
break;
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;
case "9":
serviceClass = GasRefillDetailsPage(
priority: messageData["priority"],
date: messageData["createdOn"],
moduleId: 2,
model: GasRefillModel(id: int.parse(messageData["requestNumber"].toString())),
);
break;

@ -140,6 +140,7 @@ class AllRequestsProvider extends ChangeNotifier {
}
if (context.userProvider.isQualityUser) {
list = [10, 11];
if (context.settingProvider.isUserFlowMedical) list.insert(0, 7);
return list;
}

@ -106,7 +106,9 @@ class DashBoardProvider extends ChangeNotifier {
isAllCountLoading = true;
notifyListeners();
String url = '';
if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
if (usersType == UsersTypes.qualityUser) {
url = URLs.qaAuditorCount;
} else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
url = URLs.engineerDashboardCountUrl;
} else {
url = URLs.nurseDashboardCountUrl;
@ -241,7 +243,10 @@ class DashBoardProvider extends ChangeNotifier {
Response response;
String url = '';
if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
if (usersType == UsersTypes.qualityUser) {
url = URLs.qaAuditorDetails;
} else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
//need to check pagination for not assigned task @waseem.
//these checks are to call different apis for dashboard for engineer...
@ -372,6 +377,13 @@ class CategoryTabs {
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;
}
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3));
tabs.add(CategoryTabs(label: 'Pending Acknowledgement', tag: 3, id: 1));

@ -182,6 +182,13 @@ class ProgressFragment extends StatelessWidget {
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 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 {
total = (snapshot.dashboardCount?.data?.countComplete ?? 0) + (snapshot.dashboardCount?.data?.countInprogress ?? 0) + (snapshot.dashboardCount?.data?.countOpen ?? 0);
chartData = [
@ -248,7 +255,7 @@ class ProgressFragment extends StatelessWidget {
showChartValuesOutside: false,
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),
],
),
),

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

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

@ -110,6 +110,8 @@ class User {
return UsersTypes.assessorTl;
case "R-3": // Quality User
return UsersTypes.qualityUser;
case "R-58": // Quality User
return UsersTypes.qualityUser;
default:
return null;
}

@ -153,7 +153,8 @@ class _CMDetailPageState extends State<CMDetailPage> {
],
),
).onPress(() {
Navigator.push(context, MaterialPageRoute(builder: (context) => CreateLoanRequestPage(workOrderId: widget.requestId)));
CMDetailProvider provider = Provider.of<CMDetailProvider>(context, listen: false);
Navigator.push(context, MaterialPageRoute(builder: (context) => CreateLoanRequestPage(workOrderId: widget.requestId, workOrder: provider.currentWorkOrder!.data)));
});
}
return const SizedBox();

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

@ -73,25 +73,26 @@ class _ChatWidgetState extends State<ChatWidget> {
@override
Widget build(BuildContext context) {
return Consumer<ChatProvider>(builder: (pContext, requestProvider, _) {
return IconButton(
icon: const Icon(Icons.chat_bubble),
onPressed: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => ChatPage(
moduleId: widget.moduleId,
requestId: widget.requestId,
title: widget.title,
readOnly: widget.isReadOnly,
assigneeEmployeeNumber: widget.assigneeEmployeeNumber,
contactEmployeeINumber: widget.contactEmployeeINumber,
myLoginUserID: widget.myLoginUserID,
)));
},
).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30);
});
;
return widget.isShow
? Consumer<ChatProvider>(builder: (pContext, requestProvider, _) {
return IconButton(
icon: const Icon(Icons.chat_bubble),
onPressed: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => ChatPage(
moduleId: widget.moduleId,
requestId: widget.requestId,
title: widget.title,
readOnly: widget.isReadOnly,
assigneeEmployeeNumber: widget.assigneeEmployeeNumber,
contactEmployeeINumber: widget.contactEmployeeINumber,
myLoginUserID: widget.myLoginUserID,
)));
},
).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30);
})
: const SizedBox();
}
}

@ -127,8 +127,9 @@ class ChatFileViewer extends StatelessWidget {
Future<File?> downloadFile() async {
try {
// print("downloadUrl:$downloadUrl");
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) {
print("downloadFile:$ex");
return null;

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

@ -42,6 +42,8 @@ class _CreateEquipmentInternalAuditFormState extends State<CreateEquipmentIntern
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
FocusNode auditCheckListNode = FocusNode();
int noFindingValue = 4;
@override
void initState() {
super.initState();
@ -78,7 +80,6 @@ class _CreateEquipmentInternalAuditFormState extends State<CreateEquipmentIntern
},
),
16.height,
//TODO need to check layout issue...
MultipleItemDropDownMenu<Lookup, InternalAuditCheckListProvider>(
context: context,
showAsBottomSheet: true,
@ -89,6 +90,15 @@ class _CreateEquipmentInternalAuditFormState extends State<CreateEquipmentIntern
title: 'Internal Audit Checklist'.addTranslation,
initialValue: _equipmentinternalAuditModel.findings,
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 ?? [];
},
),
@ -137,9 +147,9 @@ class _CreateEquipmentInternalAuditFormState extends State<CreateEquipmentIntern
}
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
_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);
if(status){
if (status) {
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/loaders/app_loading.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 {
static const String id = "/details-internal-audit";
@ -51,12 +52,10 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
Future<void> getAuditData() async {
model = await _internalAuditProvider.getEquipmentInternalAuditById(widget.auditId);
allAttachments.clear();
allAttachments = [
allAttachments = [
...(model?.attachments ?? []),
...(model?.engineerData?.attachments ?? []),
];
}
@override
@ -82,12 +81,43 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
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(),
8.height,
requestDetails(),
8.height,
if (model?.remarks?.isNotEmpty ?? false) ...[
const Divider().defaultStyle(context),
Text(
"Remarks",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
model!.remarks!.bodyText(context),
8.height,
],
@ -103,7 +133,7 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
],
).paddingAll(0).toShadowContainer(context),
).expanded,
if (context.userProvider.isEngineer&&model?.status?.value!=3)
if (context.userProvider.isEngineer && model?.status?.value != 3)
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
@ -160,6 +190,7 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
6.height,
'${context.translation.requestNo}: ${model?.requestNo ?? '-'}'.bodyText(context),
if (model != null && model!.equipmentsFindings != null && model!.equipmentsFindings!.isNotEmpty)
...model!.equipmentsFindings!.map((item) {
final findingName = item.finding?.name ?? 'Unknown';
@ -177,14 +208,17 @@ class _EquipmentInternalAuditDetailPageState extends State<EquipmentInternalAudi
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Asset Details",
"Asset Information",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
6.height,
'${context.translation.assetName}: ${model?.asset?.assetName ?? '-'}'.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.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
Widget build(BuildContext context) {
//TODO need to refactor this code repetation @waseem
if (requestData != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -44,8 +43,8 @@ class EquipmentInternalAuditItemView extends StatelessWidget {
),
8.height,
(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,
Row(
mainAxisSize: MainAxisSize.min,
@ -60,7 +59,7 @@ class EquipmentInternalAuditItemView extends StatelessWidget {
),
],
).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(
@ -85,9 +84,11 @@ class EquipmentInternalAuditItemView extends StatelessWidget {
8.height,
(requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context),
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.assetSN, value: requestDetails!.assetSN, context: context),
infoWidget(label: context.translation.model, value: requestDetails!.model, context: context),
infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
8.height,
Row(
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/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
class SystemInternalAuditDetailPage extends StatefulWidget {
static const String id = "/details-system-internal-audit";
@ -79,17 +80,45 @@ class _SystemInternalAuditDetailPageState extends State<SystemInternalAuditDetai
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
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,
workOrderInformation(),
workOrderInfo(),
const Divider().defaultStyle(context),
8.height,
assetInfo(),
//TODO need to check for comments
if (model?.findingDescription?.isNotEmpty ?? false) ...[
const Divider().defaultStyle(context),
// Text(
// "Comments".addTranslation,
// style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
// ),
Text(
"Remarks",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
model!.findingDescription!.bodyText(context),
],
//TODO need to check for attachments
@ -143,10 +172,33 @@ class _SystemInternalAuditDetailPageState extends State<SystemInternalAuditDetai
6.height,
labelValueText(context, context.translation.woNumber, details?.workOrderNo),
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.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 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) {
if (value == null || value.isEmpty) return const SizedBox.shrink();

@ -44,9 +44,9 @@ class SystemInternalAuditItemView extends StatelessWidget {
],
),
8.height,
(requestData?.typeTransaction ?? "Internal Audit Request").heading5(context),
infoWidget(label: context.translation.assetNo, value: requestData?.assetNumber, context: context),
(requestData?.typeTransaction ?? "System Audit Request").heading5(context),
infoWidget(label: context.translation.requestNo, value: requestData!.requestNo, context: context),
infoWidget(label: context.translation.assetNumber, value: requestData?.assetNumber, context: context),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
@ -61,7 +61,7 @@ class SystemInternalAuditItemView extends StatelessWidget {
),
],
).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(
@ -85,9 +85,12 @@ class SystemInternalAuditItemView extends StatelessWidget {
),
8.height,
(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.assetSN, value: requestDetails!.assetSN, context: context),
infoWidget(label: context.translation.model, value: requestDetails!.model, context: context),
infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
8.height,
// infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
8.height,

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

@ -16,14 +16,9 @@ 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/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/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/service_request/pending_service_request_model.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/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/loan_module/models/loan_form_model.dart';
@ -39,20 +34,15 @@ 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/loading_list_notifier.dart';
import 'package:test_sa/providers/task_request_provider/task_job_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 '../../../../../../new_views/common_widgets/default_app_bar.dart';
import '../../../models/new_models/department.dart';
class CreateLoanRequestPage extends StatefulWidget {
static const String id = "/create-loan";
int? workOrderId;
WorkOrderData? workOrder;
CreateLoanRequestPage({Key? key, this.workOrderId}) : super(key: key);
CreateLoanRequestPage({Key? key, this.workOrderId, this.workOrder}) : super(key: key);
@override
_CreateLoanRequestPageState createState() => _CreateLoanRequestPageState();
@ -62,7 +52,6 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
final List<GenericAttachmentModel> attachments = [];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
Asset? device;
TaskType? selectedType;
final LoanFormModel _loanFormModel = LoanFormModel();
@ -70,11 +59,14 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
bool get isBackUpRequest => widget.workOrderId != null;
List<Lookup> loanTypes = [];
@override
void initState() {
super.initState();
Provider.of<MedicalDepartmentProvider>(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
@ -92,23 +84,55 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
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) ...[
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,
],
...doctorInfoSection(),
// ...contactInfoSection(),
// 16.height,
...itemDetailsSection(),
16.height,
...doctorInfoSection(),
...itemDetailsSection(),
16.height,
...vendorDetailsSection(),
16.height,
AttachmentPicker(
label: context.translation.attachments,
attachment: attachments,
buttonColor: AppColor.black10,
onlyImages: false,
showAsListView: true,
buttonIcon: 'image-plus'.toSvgAsset(color: context.isDark ? AppColor.primary10 : AppColor.neutral120),
onChange: (attachments) {
attachments = attachments;
@ -473,24 +497,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 {
FocusScope.of(context).unfocus();
if (isBackUpRequest && device == null) {
"Please scan or pick asset".showToast;
return;
}
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
@ -507,7 +515,12 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
body["requestorUserID"] = context.userProvider.user!.userID;
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;
}
bool isSuccess = await loanProvider.addLoanRequest(body);

@ -1,4 +1,5 @@
import 'package:flutter/cupertino.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
@ -8,9 +9,10 @@ import 'dart:convert';
class LoanProvider extends ChangeNotifier {
Future<bool> addLoanRequest(Map<String, dynamic> body) async {
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) {
// 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 false;

@ -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/widget_extensions.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/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
@ -22,8 +23,9 @@ import 'update_device_transfer.dart';
class DeviceTransferDetails extends StatefulWidget {
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
State<DeviceTransferDetails> createState() => _DeviceTransferDetailsState();
@ -131,6 +133,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
] else ...[
// sender card
_buildCard(
_model!,
isSender: true,
site: _model?.senderSiteName?.cleanupWhitespace.capitalizeFirstOfEach ?? "",
dept: _model?.senderDepartmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "",
@ -150,6 +153,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
8.height,
// receiver card
_buildCard(
_model!,
isSender: false,
site: _model?.destSiteName?.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: _model!.senderMachineStatusValue! != 4,
isReadOnly: _model!.senderMachineStatusValue! != 1,
requestId: widget.model.id!.toInt(),
assigneeEmployeeNumber: _model!.senderAssignedEmployeeNumber,
myLoginUserID: context.userProvider.user!.username!,
contactEmployeeINumber: _model!.assetTransferContactPersons!.first.employeeNumber,
),
if ((_userProvider!.user?.type == UsersTypes.engineer))
if (isCurrentEngineerEligibleForEdit && isCurrentRequestEditAble)
"edit".toSvgAsset(height: 40, width: 40).onPress(() async {
@ -248,7 +262,8 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
).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 isCurrentRequestClosed = isSender ? ((_model?.senderMachineStatusValue == 3)) : ((_model?.receiverMachineStatusValue == 3));
@ -265,7 +280,17 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
if (statusLabel != null) 8.height,
isSender ? context.translation.senderDetails.heading5(context) : context.translation.receiverDetails.heading5(context),
],
),
).expanded,
if (context.userProvider.isEngineer || context.userProvider.isNurse)
ChatWidget(
moduleId: widget.moduleId,
isShow: (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!.username!,
contactEmployeeINumber: _deviceTransfer.assetTransferContactPersons!.first.employeeNumber,
),
if ((_userProvider!.user?.type == UsersTypes.engineer))
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?.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;
if (isReload ?? false) {
setState(() {});

@ -28,8 +28,9 @@ import 'update_gas_refill_request.dart';
class GasRefillDetailsPage extends StatefulWidget {
GasRefillModel model;
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
State<GasRefillDetailsPage> createState() => _GasRefillDetailsPageState();
@ -59,21 +60,22 @@ class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
appBar: DefaultAppBar(
title: context.translation.gasRefillDetails,
actions: [
// if (context.userProvider.isEngineer || context.userProvider.isNurse)
// Selector<GasRefillProvider, GasRefillModel?>(
// selector: (_, myModel) => myModel.gasRefillModel, // Selects only the userName
// builder: (_, _gasRefillModel, __) {
// if (_gasRefillModel == null) return const SizedBox();
// return ChatWidget(
// moduleId: 2,
// isShow: _gasRefillModel.status!.value! == 1,
// // isReadOnly: _gasRefillModel.status!.value! == 1,
// requestId: widget.model.id!.toInt(),
// assigneeEmployeeNumber: _gasRefillModel.assignedEmployee!.name!,
// myLoginUserID: context.userProvider.user!.username!,
// contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!,
// );
// })
if (context.userProvider.isEngineer || context.userProvider.isNurse)
Selector<GasRefillProvider, GasRefillModel?>(
selector: (_, myModel) => myModel.gasRefillModel, // Selects only the userName
builder: (_, _gasRefillModel, __) {
if (_gasRefillModel == null) return const SizedBox();
return ChatWidget(
moduleId: widget.moduleId,
isShow: _gasRefillModel.status!.value! != 0,
isReadOnly: _gasRefillModel.status!.value! != 1,
requestId: widget.model.id!.toInt(),
assigneeEmployeeNumber: _gasRefillModel.assignedEmployee?.employeeId!,
myLoginUserID: context.userProvider.user!.username!,
contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!,
);
})
],
),
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/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/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/working_time_tile.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";
final int taskId;
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
_TaskRequestDetailsViewState createState() {
@ -65,7 +67,27 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
Widget build(BuildContext context) {
userProvider ??= Provider.of<UserProvider>(context, listen: false);
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();
return ChatWidget(
moduleId: widget.moduleId,
isShow: _taskReqModel.taskJobStatus!.value! != 1,
isReadOnly: _taskReqModel.taskJobStatus!.value! != 2,
requestId: widget.taskId.toInt(),
assigneeEmployeeNumber: _taskReqModel.assignedEngineer?.employeeId!,
myLoginUserID: context.userProvider.user!.username!,
contactEmployeeINumber: _taskReqModel.taskJobContactPersons!.first.user?.employeeId,
);
})
],
),
body: Consumer<TaskRequestProvider>(builder: (context, taskProvider, child) {
TaskData? taskModel = taskProvider.taskRequestModel;
return taskProvider.isLoading

@ -68,7 +68,8 @@ class TaskRequestItemView extends StatelessWidget {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => TaskRequestDetailsView(
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(
builder: (_) => TaskRequestDetailsView(
taskId: requestDetails!.id!,
moduleId: requestDetails!.transactionType!,
requestDetails: requestDetails,
)));
});

@ -102,7 +102,9 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
types = {"TRAF": 9};
}
if (context.userProvider.isQualityUser) {
types = {'Equipment Internal Audit': 10, 'System Internal Audit': 11};
if (context.settingProvider.isUserFlowMedical) types = {'Recall and Alert': 7};
types['Equipment Internal Audit'] = 10;
types['System Internal Audit'] = 11;
}
final statuses = {

@ -83,6 +83,7 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
if (context.userProvider.isQualityUser) {
requestsList = [
Request(null, context.translation.allWorkOrder),
if (context.settingProvider.isUserFlowMedical) Request(7, 'Recall and Alert'),
Request(10, 'Equipment Internal Audit'),
Request(11, 'System Internal Audit'),
];

@ -77,7 +77,7 @@ class DeviceItemView extends StatelessWidget {
),
],
).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(() {
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(
priority: requestData!.priorityName,
date: requestData!.transactionDate!,
moduleId: requestData!.transactionNo!,
model: GasRefillModel(id: requestData!.id),
),
),
@ -135,6 +136,7 @@ class GasRefillItemView extends StatelessWidget {
builder: (_) => GasRefillDetailsPage(
priority: requestDetails!.priority!,
date: requestDetails!.date,
moduleId: requestDetails!.transactionType!,
model: GasRefillModel(id: requestDetails!.id),
),
),

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

@ -1,10 +1,15 @@
import 'dart:io';
import 'package:ellipsized_text/ellipsized_text.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:open_file/open_file.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/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/loaders/image_loader.dart';
import 'package:url_launcher/url_launcher.dart';
@ -12,78 +17,180 @@ import 'package:url_launcher/url_launcher.dart';
class FilesList extends StatelessWidget {
final List<String> images;
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
Widget build(BuildContext context) {
return 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");
}
var isImage = 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 showAsListView
? ListView.separated(
shrinkWrap: true,
padding: const EdgeInsets.only(top: 8),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, itemIndex) {
if (!images[itemIndex].contains(".")) {
return const Text("Bad\nFile");
}
var isImage =
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(),
],
return Row(
children: [
Container(
width: 48.toScreenWidth,
height: 48.toScreenWidth,
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")),
),
),
),
),
);
} 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 ');
8.width,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
EllipsizedText(
images[itemIndex].split("/").last,
style: AppTextStyles.heading6.copyWith(color: AppColor.black10),
type: EllipsisType.start, // or EllipsisType.middle
),
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) {
Fluttertoast.showToast(msg: "No Viewer found.");
}
}
});
},
);
var isImage =
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(
// padding: padding ?? EdgeInsets.symmetric(horizontal: 32 * AppStyle.getScaleFactor(context)),

@ -320,6 +320,7 @@ class AttachmentPicker extends StatefulWidget {
Color? buttonColor;
final Function(List<GenericAttachmentModel>)? onChange;
final bool showAsGrid;
final bool showAsListView;
AttachmentPicker(
{Key? key,
@ -332,6 +333,7 @@ class AttachmentPicker extends StatefulWidget {
this.onlyImages = false,
this.onChange,
this.showAsGrid = false,
this.showAsListView = false,
this.buttonColor})
: super(key: key);
@ -357,29 +359,54 @@ class _AttachmentPickerState extends State<AttachmentPicker> {
: onFilePicker),
16.height,
if (widget.attachment.isNotEmpty)
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(() {});
widget.showAsListView
? ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) {
File image = File(widget.attachment[index].name!);
return MultiFilesPickerItem(
file: image,
showAsListView: widget.showAsListView,
enabled: widget.enabled,
onRemoveTap: (image) {
if (!widget.enabled) {
return;
}
widget.attachment.removeAt(index);
if (widget.onChange != null) {
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 {
// if (widget.attachment.length >= 5) {
// Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5);
// return;
// }
ImageSource source = (await showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
@ -475,11 +497,6 @@ class _AttachmentPickerState extends State<AttachmentPicker> {
}
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>(
context: context,
builder: (BuildContext context) {

@ -1,5 +1,7 @@
import 'dart:io';
import 'package:ellipsized_text/ellipsized_text.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:open_file/open_file.dart';
@ -18,8 +20,16 @@ class MultiFilesPickerItem extends StatelessWidget {
final bool enabled;
final Function(File) onRemoveTap;
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
Widget build(BuildContext context) {
@ -27,6 +37,96 @@ class MultiFilesPickerItem extends StatelessWidget {
bool isPdf = file.path.split(".").last.toLowerCase() == "pdf";
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(
width: 60.toScreenWidth,
height: 60.toScreenWidth,

@ -265,6 +265,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
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.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.3.11+30
version: 1.4.0+31
environment:
sdk: ">=3.5.0 <4.0.0"
@ -98,6 +98,7 @@ dependencies:
tree_view_flutter: ^1.0.2
audio_waveforms: ^1.3.0
signalr_netcore: ^1.4.4
ellipsized_text: ^1.2.0
local_auth_darwin: any
dev_dependencies:

Loading…
Cancel
Save