Merge branch 'design_3.0_incident_module' into design_3.0_demo_module
# Conflicts: # lib/controllers/api_routes/urls.dart # lib/main.dart # lib/new_views/common_widgets/single_item_drop_down_menu.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 # lib/new_views/pages/land_page/requests/request_paginated_listview.dart # lib/new_views/pages/land_page/widgets/request_item_view_list.dartdesign_3.0_demo_module
commit
65c0566eef
@ -0,0 +1,710 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:test_sa/controllers/validator/validator.dart';
|
||||||
|
import 'package:test_sa/extensions/context_extension.dart';
|
||||||
|
import 'package:test_sa/extensions/int_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/string_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/text_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/widget_extensions.dart';
|
||||||
|
import 'package:test_sa/helper/utils.dart';
|
||||||
|
import 'package:test_sa/models/device/asset.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/site.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/incident_module/incident_lookup_provider.dart';
|
||||||
|
import 'package:test_sa/modules/incident_module/incident_provider.dart';
|
||||||
|
import 'package:test_sa/modules/loan_module/models/medical_department_model.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/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/default_app_bar.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/providers/lookups/yes_no_lookup_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 '../../models/new_models/department.dart';
|
||||||
|
import '../../new_views/swipe_module/dialoge/info_dialog.dart';
|
||||||
|
import 'flow_medical_department_provider.dart';
|
||||||
|
import 'incident_attachment_model.dart';
|
||||||
|
|
||||||
|
class CreateIncidentRequestPage extends StatefulWidget {
|
||||||
|
static const String id = "/create-incident";
|
||||||
|
|
||||||
|
CreateIncidentRequestPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CreateIncidentRequestPageState createState() {
|
||||||
|
return _CreateIncidentRequestPageState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateIncidentRequestPageState extends State<CreateIncidentRequestPage> {
|
||||||
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
List<GenericAttachmentModel> attachments = [];
|
||||||
|
|
||||||
|
MedicalDepartmentModel? _medicalDepartmentModel;
|
||||||
|
Site? _empSite;
|
||||||
|
Site? _selectedSite;
|
||||||
|
Building? _selectedBuilding;
|
||||||
|
Floor? _selectedFloor;
|
||||||
|
Department? _selectedDepartment;
|
||||||
|
|
||||||
|
Asset? device;
|
||||||
|
|
||||||
|
Lookup? incidentType;
|
||||||
|
Lookup? ovrSystem;
|
||||||
|
Lookup? rootCause;
|
||||||
|
Lookup? involvedPerson;
|
||||||
|
Lookup? gender;
|
||||||
|
DateTime? occurrenceDate;
|
||||||
|
|
||||||
|
Map<String, dynamic> payload = {};
|
||||||
|
|
||||||
|
Map<String, dynamic>? ovrDetails;
|
||||||
|
|
||||||
|
bool get isOvrVerified => ovrDetails != null;
|
||||||
|
|
||||||
|
bool ovrVerifying = false;
|
||||||
|
String ovrTicketNumber = "";
|
||||||
|
|
||||||
|
TextEditingController ovrTicketController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
ovrSystem = Lookup(id: 81, name: "No", value: 0);
|
||||||
|
payload["id"] = 0;
|
||||||
|
payload["isFromMobile"] = true;
|
||||||
|
payload["requestorUserId"] = context.userProvider.user!.userID;
|
||||||
|
payload["requestorSiteId"] = context.userProvider.user!.clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
key: _scaffoldKey,
|
||||||
|
appBar: DefaultAppBar(title: 'Incident'.addTranslation),
|
||||||
|
body: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
...empSiteSection(),
|
||||||
|
16.height,
|
||||||
|
...incidentInfoSection(),
|
||||||
|
if (incidentType?.value == 1) ...[
|
||||||
|
16.height,
|
||||||
|
"Asset Details".bodyText(context).custom(color: AppColor.black10),
|
||||||
|
8.height,
|
||||||
|
AssetPicker(
|
||||||
|
device: device,
|
||||||
|
showLoading: false,
|
||||||
|
borderColor: AppColor.black20,
|
||||||
|
onPick: (asset) async {
|
||||||
|
device = asset;
|
||||||
|
payload["assetId"] = asset.modelDefinition?.id;
|
||||||
|
payload["oracleCode"] = asset.modelDefinition?.oracleCodes?.first.codeValue;
|
||||||
|
payload["model"] = asset.modelDefinition?.modelName;
|
||||||
|
payload["manufacturer"] = asset.modelDefinition?.manufacturerId;
|
||||||
|
payload["assetOrigin"] = asset.modelDefinition?.assetName;
|
||||||
|
payload["siteId"] = asset.site?.id;
|
||||||
|
payload["buildingId"] = asset.building?.id;
|
||||||
|
payload["floorId"] = asset.floor?.id;
|
||||||
|
payload["departmentId"] = asset.department?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
if (incidentType?.value != null && incidentType?.value != 1) ...[
|
||||||
|
16.height,
|
||||||
|
...siteSection(),
|
||||||
|
],
|
||||||
|
16.height,
|
||||||
|
...detailsSection(),
|
||||||
|
16.height,
|
||||||
|
...optionQuestions(),
|
||||||
|
16.height,
|
||||||
|
"Attachments".bodyText(context).custom(color: AppColor.black10),
|
||||||
|
8.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;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).toShadowContainer(context, borderRadius: 20),
|
||||||
|
).expanded,
|
||||||
|
FooterActionButton.footerContainer(
|
||||||
|
context: context,
|
||||||
|
child: AppFilledButton(
|
||||||
|
buttonColor: AppColor.primary10,
|
||||||
|
label: context.translation.submitRequest,
|
||||||
|
onPressed: _submit,
|
||||||
|
// buttonColor: AppColor.primary10,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> optionQuestions() {
|
||||||
|
return [
|
||||||
|
'Additional Information & Comments'.addTranslation.bodyText(context).custom(color: AppColor.black10),
|
||||||
|
8.height,
|
||||||
|
AppTextFormField(
|
||||||
|
initialValue: "",
|
||||||
|
labelText: "Some Comments",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
|
||||||
|
labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)),
|
||||||
|
floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
showShadow: false,
|
||||||
|
textInputType: TextInputType.multiline,
|
||||||
|
makeMultiLinesNull: false,
|
||||||
|
onChange: (value) {
|
||||||
|
payload["comments"] = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> siteSection() {
|
||||||
|
return [
|
||||||
|
'Site Details'.addTranslation.bodyText(context).custom(color: AppColor.black10),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Site, SiteProvider>(
|
||||||
|
context: context,
|
||||||
|
title: context.translation.site,
|
||||||
|
initialValue: _selectedSite,
|
||||||
|
showShadow: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Please select a site";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
_selectedSite = value;
|
||||||
|
payload["siteId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
|
||||||
|
context: context,
|
||||||
|
title: context.translation.building,
|
||||||
|
initialValue: _selectedBuilding,
|
||||||
|
showShadow: false,
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Please select a building";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
enabled: _selectedSite?.buildings?.isNotEmpty ?? false,
|
||||||
|
staticData: _selectedSite?.buildings ?? [],
|
||||||
|
onSelect: (value) {
|
||||||
|
_selectedBuilding = value;
|
||||||
|
_selectedFloor = null;
|
||||||
|
_selectedDepartment = null;
|
||||||
|
payload["buildingId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
|
||||||
|
context: context,
|
||||||
|
title: context.translation.floor,
|
||||||
|
showShadow: false,
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
initialValue: _selectedFloor,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
enabled: _selectedBuilding?.floors?.isNotEmpty ?? false,
|
||||||
|
staticData: _selectedBuilding?.floors ?? [],
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Please select a floor";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onSelect: (value) {
|
||||||
|
_selectedFloor = value;
|
||||||
|
_selectedDepartment = null;
|
||||||
|
payload["floorId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
|
||||||
|
context: context,
|
||||||
|
title: context.translation.department,
|
||||||
|
showShadow: false,
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
initialValue: _selectedDepartment,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
enabled: _selectedFloor?.departments?.isNotEmpty ?? false,
|
||||||
|
staticData: _selectedFloor?.departments ?? [],
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Please select a department";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onSelect: (value) {
|
||||||
|
_selectedDepartment = value;
|
||||||
|
payload["departmentId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> empSiteSection() {
|
||||||
|
return [
|
||||||
|
SingleItemDropDownMenu<Site, SiteProvider>(
|
||||||
|
context: context,
|
||||||
|
title: "Employee Site",
|
||||||
|
initialValue: _empSite,
|
||||||
|
showShadow: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Please select a site";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
_empSite = value;
|
||||||
|
payload["requestorSiteId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<MedicalDepartmentModel, FlowMedicalDepartmentProvider>(
|
||||||
|
context: context,
|
||||||
|
title: "Employee Department",
|
||||||
|
showShadow: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Please select a department";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
initialValue: _medicalDepartmentModel,
|
||||||
|
requestById: context.userProvider.user?.clientId,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
onSelect: (value) {
|
||||||
|
_medicalDepartmentModel = value;
|
||||||
|
payload["requestorFlowDepartmentId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> incidentInfoSection() {
|
||||||
|
return [
|
||||||
|
"Incident Details".bodyText(context).custom(color: AppColor.black10),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Lookup, IncidentTypeLookupProvider>(
|
||||||
|
context: context,
|
||||||
|
height: 56.toScreenHeight,
|
||||||
|
title: "Incident Type",
|
||||||
|
initialValue: incidentType,
|
||||||
|
showShadow: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
infoCallback: () {
|
||||||
|
context.showInfoDialog("Select the category that best describes the incident:", content: [
|
||||||
|
InfoContent(title: "Medical Equipment", message: "Malfunction, failure, or issue involving a device."),
|
||||||
|
InfoContent(title: "EHS (Environment, Health, Safety)", message: "Incidents related to safety hazards, spills, injuries."),
|
||||||
|
InfoContent(title: "Late Delivery", message: "Delayed receipt of medical equipment, materials, or supplies."),
|
||||||
|
InfoContent(title: "Mis-conduct", message: "FLOW staff behavior that violates rules, ethics, or procedures."),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
incidentType = value;
|
||||||
|
payload["incidentClassificationId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Lookup, YesNoLookupProvider>(
|
||||||
|
context: context,
|
||||||
|
height: 56.toScreenHeight,
|
||||||
|
title: "Is there any existing OVR System?",
|
||||||
|
initialValue: ovrSystem,
|
||||||
|
showShadow: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
ovrSystem = value;
|
||||||
|
payload["existingOvrTicketId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (ovrSystem?.value == 1) ...[
|
||||||
|
8.height,
|
||||||
|
AppTextFormField(
|
||||||
|
initialValue: "",
|
||||||
|
controller: ovrTicketController,
|
||||||
|
labelText: "OVR Ticket Number",
|
||||||
|
validator: (value) {
|
||||||
|
if ((value ?? "").isEmpty) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
|
||||||
|
showShadow: false,
|
||||||
|
suffixIcon: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (ovrVerifying || isOvrVerified) return;
|
||||||
|
if (ovrTicketNumber.isEmpty) {
|
||||||
|
"Please enter OVR ticket number".showToast;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ovrVerifying = true;
|
||||||
|
setState(() {});
|
||||||
|
context.read<IncidentProvider>().getOvrTicketDetails(ovrTicketNumber).then((details) {
|
||||||
|
ovrDetails = details;
|
||||||
|
if (ovrDetails != null) {
|
||||||
|
payload["ovrTicketNumber"] = ovrTicketNumber;
|
||||||
|
"OVR Ticket verified successfully".showToast;
|
||||||
|
}
|
||||||
|
}).whenComplete(() {
|
||||||
|
ovrVerifying = false;
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: ovrVerifying
|
||||||
|
? SizedBox(
|
||||||
|
width: 16.toScreenHeight,
|
||||||
|
height: 16.toScreenHeight,
|
||||||
|
child: const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2),
|
||||||
|
)
|
||||||
|
: isOvrVerified
|
||||||
|
? const Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [Icon(Icons.done), Text("Verified")],
|
||||||
|
)
|
||||||
|
: const Text("Verify"),
|
||||||
|
),
|
||||||
|
if (isOvrVerified)
|
||||||
|
const Icon(Icons.clear, color: AppColor.red30).paddingOnly(end: 8).onPress(() {
|
||||||
|
ovrDetails = null;
|
||||||
|
ovrTicketNumber = "";
|
||||||
|
ovrTicketController.clear();
|
||||||
|
payload.remove("ovrTicketNumber");
|
||||||
|
setState(() {});
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
textInputType: TextInputType.name,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChange: (value) {
|
||||||
|
ovrTicketNumber = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
8.height,
|
||||||
|
AppTextFormField(
|
||||||
|
initialValue: "",
|
||||||
|
labelText: "Incident Title",
|
||||||
|
validator: (value) {
|
||||||
|
if ((value ?? "").isEmpty) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
suffixIcon: const Icon(Icons.info_outline_rounded, color: AppColor.neutral120).paddingOnly(end: 8).onPress(() {
|
||||||
|
context.showInfoDialog("Brief explanation of the incident, e.g., “Damaged patient monitor screen“");
|
||||||
|
}),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
|
||||||
|
showShadow: false,
|
||||||
|
textInputType: TextInputType.name,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChange: (value) {
|
||||||
|
payload["incidentTitle"] = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
AppTextFormField(
|
||||||
|
initialValue: "",
|
||||||
|
labelText: "Incident Description",
|
||||||
|
validator: (value) {
|
||||||
|
if ((value ?? "").isEmpty) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
suffixIcon: const Icon(Icons.info_outline_rounded, color: AppColor.neutral120).paddingOnly(end: 8).onPress(() {
|
||||||
|
context.showInfoDialog(
|
||||||
|
"Provide a clear and factual description of the incident, including how the issue was identified. Ex. “The ECG cable connector was damaged due to continuos forcfull disconnetionnby end-users. Multiple bent pins were noted during inspection after repeated complains of poor signal quality“");
|
||||||
|
}),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
|
||||||
|
showShadow: false,
|
||||||
|
textInputType: TextInputType.name,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChange: (value) {
|
||||||
|
payload["incidentDescription"] = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> detailsSection() {
|
||||||
|
return [
|
||||||
|
'Details'.addTranslation.bodyText(context).custom(color: AppColor.black10),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Lookup, IncidentRootCauseLookupProvider>(
|
||||||
|
context: context,
|
||||||
|
height: 56.toScreenHeight,
|
||||||
|
title: "Root Cause",
|
||||||
|
initialValue: rootCause,
|
||||||
|
showShadow: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
infoCallback: () {
|
||||||
|
context.showInfoDialog("Select the primary cause that best explains why the incident occurred. If “Other“ is selected, specify the details in the text box provided.", content: [
|
||||||
|
InfoContent(
|
||||||
|
title: "Misuse",
|
||||||
|
message: "Clear, improper use of the device by the end-user despite available knowledge or instructions. Misuse implies that correct handling was possible but not followed."),
|
||||||
|
InfoContent(title: "Lack of Awareness", message: "End-user was unaware of proper handling or procedures due to missing information or communication."),
|
||||||
|
InfoContent(title: "Insufficient Training", message: "Formal training on the device was not provided, incomplete, or outdated, leading to misuse."),
|
||||||
|
InfoContent(
|
||||||
|
title: "Utility Failure",
|
||||||
|
message: "A utility issue that disrupted the medical device operation, degrade, performance, or create unsafe conditions. such as (power outage, HVAC, or environment)."),
|
||||||
|
InfoContent(title: "Other", message: "Any cause that does not fit into the categories above (please specify)."),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
rootCause = value;
|
||||||
|
payload["rootCauseId"] = value?.id;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (rootCause?.value == 5) ...[
|
||||||
|
8.height,
|
||||||
|
AppTextFormField(
|
||||||
|
initialValue: "",
|
||||||
|
labelText: "Root Cause (Other)",
|
||||||
|
validator: (value) {
|
||||||
|
if ((value ?? "").isEmpty) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
|
||||||
|
showShadow: false,
|
||||||
|
textInputType: TextInputType.name,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChange: (value) {
|
||||||
|
payload["otherRootCause"] = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Lookup, IncidentPersonInvolvedLookupProvider>(
|
||||||
|
context: context,
|
||||||
|
height: 56.toScreenHeight,
|
||||||
|
title: "Person Involved",
|
||||||
|
initialValue: involvedPerson,
|
||||||
|
showShadow: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
infoCallback: () {
|
||||||
|
context.showInfoDialog("Ensure to provide information of person in Charge (e.g., Charge Nurse, Unit Team Leader), not a general staff member.", content: []);
|
||||||
|
},
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
involvedPerson = value;
|
||||||
|
payload["personInvolvedId"] = value?.id;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
SingleItemDropDownMenu<Lookup, GenderLookupProvider>(
|
||||||
|
context: context,
|
||||||
|
height: 56.toScreenHeight,
|
||||||
|
title: "Gender",
|
||||||
|
initialValue: gender,
|
||||||
|
showShadow: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
gender = value;
|
||||||
|
payload["genderId"] = value?.id;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
AppTextFormField(
|
||||||
|
initialValue: "",
|
||||||
|
labelText: "Person Involved ID",
|
||||||
|
validator: (value) {
|
||||||
|
if (involvedPerson?.value == 3 && (value ?? "").isEmpty) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
suffixIcon: const Icon(Icons.info_outline_rounded, color: AppColor.neutral120).paddingOnly(end: 8).onPress(() {
|
||||||
|
context.showInfoDialog(
|
||||||
|
"Required if the person is an Employee. Ensure the correct Employee ID of the Person in Charge (e.g., Charge Nurse, Unit Team Leader) is provided, not a general staff member. (Ex. 34567)");
|
||||||
|
}),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
|
||||||
|
showShadow: false,
|
||||||
|
textInputType: TextInputType.number,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChange: (value) {
|
||||||
|
payload["personInvolvedEmployeeId"] = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
AppTextFormField(
|
||||||
|
initialValue: "",
|
||||||
|
labelText: "Person Involved Name",
|
||||||
|
validator: (value) {
|
||||||
|
if (involvedPerson?.value == 3 && (value ?? "").isEmpty) return "Mandatory";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
suffixIcon: const Icon(Icons.info_outline_rounded, color: AppColor.neutral120).paddingOnly(end: 8).onPress(() {
|
||||||
|
context.showInfoDialog("State the end-user Employee/Patient Full name. Required if the person is an Employee. (Ex. Mary-Anne Joseph)");
|
||||||
|
}),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
backgroundColor: AppColor.fieldBgColor(context),
|
||||||
|
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
|
||||||
|
showShadow: false,
|
||||||
|
textInputType: TextInputType.name,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChange: (value) {
|
||||||
|
payload["personInvolvedEmployeeName"] = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
ADatePicker(
|
||||||
|
label: "Occurrence Date & Time",
|
||||||
|
hideShadow: true,
|
||||||
|
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90,
|
||||||
|
date: occurrenceDate,
|
||||||
|
from: DateTime.now().subtract(const Duration(days: 365)),
|
||||||
|
// enable: widget.enabled ? _tempPickerTimer == null : false,
|
||||||
|
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) {
|
||||||
|
occurrenceDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _submit() async {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
if (incidentType?.value == 1 && device == null) {
|
||||||
|
"Please scan or pick asset".showToast;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ovrSystem?.value == 1 && isOvrVerified == false) {
|
||||||
|
"Please verify OVR Ticket Number".showToast;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (occurrenceDate == null) {
|
||||||
|
"Please select occurrence Data".showToast;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
payload["occurrenceDate"] = occurrenceDate!.toIso8601String();
|
||||||
|
_formKey.currentState!.save();
|
||||||
|
|
||||||
|
List<IncidentAttachments> attachmentList = [];
|
||||||
|
|
||||||
|
for (var item in attachments) {
|
||||||
|
String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
|
||||||
|
attachmentList.add(IncidentAttachments(id: 0, attachmentName: fileName, incidentId: 0));
|
||||||
|
}
|
||||||
|
Utils.showLoading(context);
|
||||||
|
IncidentProvider incidentProvider = Provider.of<IncidentProvider>(context, listen: false);
|
||||||
|
|
||||||
|
payload["incidentAttachments"] = attachmentList.map((v) => v.toJson()).toList();
|
||||||
|
bool isSuccess = await incidentProvider.addIncidentRequest(payload);
|
||||||
|
Utils.hideLoading(context);
|
||||||
|
if (isSuccess) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
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/modules/loan_module/models/medical_department_model.dart';
|
||||||
|
import 'package:test_sa/providers/loading_list_notifier.dart';
|
||||||
|
|
||||||
|
class FlowMedicalDepartmentProvider extends LoadingListNotifier<MedicalDepartmentModel> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading == true) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.getFlowMedicalDepartments);
|
||||||
|
stateCode = response.statusCode;
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
|
List categoriesListJson = json.decode(response.body)["data"];
|
||||||
|
items = categoriesListJson.map((item) => MedicalDepartmentModel.fromJson(item)).toList();
|
||||||
|
}
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return response.statusCode;
|
||||||
|
} catch (error) {
|
||||||
|
loading = false;
|
||||||
|
stateCode = -1;
|
||||||
|
notifyListeners();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
class IncidentAttachments {
|
||||||
|
num? id;
|
||||||
|
num? incidentId;
|
||||||
|
String? attachmentName;
|
||||||
|
String? attachmentDescription;
|
||||||
|
|
||||||
|
IncidentAttachments({this.id, this.attachmentName, this.incidentId, this.attachmentDescription});
|
||||||
|
|
||||||
|
IncidentAttachments.fromJson(dynamic json) {
|
||||||
|
id = json['id'];
|
||||||
|
incidentId = json['incidentId'];
|
||||||
|
attachmentName = json['attachmentName'];
|
||||||
|
attachmentDescription = json['attachmentDescription'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final map = <String, dynamic>{};
|
||||||
|
map['id'] = id;
|
||||||
|
map['attachmentName'] = attachmentName;
|
||||||
|
map['incidentId'] = incidentId;
|
||||||
|
map['attachmentDescription'] = attachmentDescription;
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,313 @@
|
|||||||
|
import 'package:test_sa/modules/incident_module/incident_attachment_model.dart';
|
||||||
|
|
||||||
|
class IncidentDataModel {
|
||||||
|
int? id;
|
||||||
|
int? reqNo;
|
||||||
|
String? reqCode;
|
||||||
|
int? incidentStatusId;
|
||||||
|
String? incidentStatusName;
|
||||||
|
int? incidentStatusValue;
|
||||||
|
int? incidentClassificationId;
|
||||||
|
String? incidentClassificationName;
|
||||||
|
int? incidentClassificationValue;
|
||||||
|
int? existingOvrTicketId;
|
||||||
|
String? existingOvrTicketName;
|
||||||
|
int? existingOvrTicketValue;
|
||||||
|
String? ovrTicketNumber;
|
||||||
|
String? incidentTitle;
|
||||||
|
String? incidentDescription;
|
||||||
|
int? assetId;
|
||||||
|
String? assetNumber;
|
||||||
|
String? oracleCode;
|
||||||
|
String? model;
|
||||||
|
String? manufacturer;
|
||||||
|
String? assetOrigin;
|
||||||
|
int? siteId;
|
||||||
|
String? siteName;
|
||||||
|
int? buildingId;
|
||||||
|
String? buildingName;
|
||||||
|
int? departmentId;
|
||||||
|
String? departmentName;
|
||||||
|
int? floorId;
|
||||||
|
String? floorName;
|
||||||
|
int? rootCauseId;
|
||||||
|
String? rootCauseName;
|
||||||
|
int? rootCauseValue;
|
||||||
|
String? otherRootCause;
|
||||||
|
String? comments;
|
||||||
|
int? personInvolvedId;
|
||||||
|
String? personInvolvedName;
|
||||||
|
int? personInvolvedValue;
|
||||||
|
int? genderId;
|
||||||
|
String? genderName;
|
||||||
|
int? personInvolvedEmployeeId;
|
||||||
|
String? personInvolvedEmployeeName;
|
||||||
|
String? assignedQAId;
|
||||||
|
String? assignedQAName;
|
||||||
|
String? assignedSecondaryQAId;
|
||||||
|
String? assignedSecondaryQAName;
|
||||||
|
String? qaLeaderId;
|
||||||
|
String? qaLeaderName;
|
||||||
|
String? correctiveAction;
|
||||||
|
int? escalateToOvrId;
|
||||||
|
String? escalateToOvrName;
|
||||||
|
int? immediateActionId;
|
||||||
|
String? immediateActionName;
|
||||||
|
int? clinicalOrNonClinicalId;
|
||||||
|
String? clinicalOrNonClinicalName;
|
||||||
|
String? recommendation;
|
||||||
|
String? requestorUserId;
|
||||||
|
String? requesterEmployeeId;
|
||||||
|
String? requesterEmployeeName;
|
||||||
|
String? requesterEmployeeEmail;
|
||||||
|
String? requesterPosition;
|
||||||
|
String? requesterContactNo;
|
||||||
|
String? requesterExtensionNo;
|
||||||
|
int? requestorSiteId;
|
||||||
|
String? requestorSiteName;
|
||||||
|
int? requestorDepartmentId;
|
||||||
|
String? requestorDepartmentName;
|
||||||
|
int? requestorFlowDepartmentId;
|
||||||
|
String? requestorFlowDepartmentName;
|
||||||
|
String? requestorFlowDepartmentShortCode;
|
||||||
|
String? approvalSignature;
|
||||||
|
String? occurrenceDate;
|
||||||
|
String? createdDate;
|
||||||
|
List<IncidentAttachments>? incidentAttachments;
|
||||||
|
|
||||||
|
IncidentDataModel(
|
||||||
|
{this.id,
|
||||||
|
this.reqNo,
|
||||||
|
this.reqCode,
|
||||||
|
this.incidentStatusId,
|
||||||
|
this.incidentStatusName,
|
||||||
|
this.incidentStatusValue,
|
||||||
|
this.incidentClassificationId,
|
||||||
|
this.incidentClassificationName,
|
||||||
|
this.incidentClassificationValue,
|
||||||
|
this.existingOvrTicketId,
|
||||||
|
this.existingOvrTicketName,
|
||||||
|
this.existingOvrTicketValue,
|
||||||
|
this.ovrTicketNumber,
|
||||||
|
this.incidentTitle,
|
||||||
|
this.incidentDescription,
|
||||||
|
this.assetId,
|
||||||
|
this.assetNumber,
|
||||||
|
this.oracleCode,
|
||||||
|
this.model,
|
||||||
|
this.manufacturer,
|
||||||
|
this.assetOrigin,
|
||||||
|
this.siteId,
|
||||||
|
this.siteName,
|
||||||
|
this.buildingId,
|
||||||
|
this.buildingName,
|
||||||
|
this.departmentId,
|
||||||
|
this.departmentName,
|
||||||
|
this.floorId,
|
||||||
|
this.floorName,
|
||||||
|
this.rootCauseId,
|
||||||
|
this.rootCauseName,
|
||||||
|
this.rootCauseValue,
|
||||||
|
this.otherRootCause,
|
||||||
|
this.comments,
|
||||||
|
this.personInvolvedId,
|
||||||
|
this.personInvolvedName,
|
||||||
|
this.personInvolvedValue,
|
||||||
|
this.genderId,
|
||||||
|
this.genderName,
|
||||||
|
this.personInvolvedEmployeeId,
|
||||||
|
this.personInvolvedEmployeeName,
|
||||||
|
this.assignedQAId,
|
||||||
|
this.assignedQAName,
|
||||||
|
this.assignedSecondaryQAId,
|
||||||
|
this.assignedSecondaryQAName,
|
||||||
|
this.qaLeaderId,
|
||||||
|
this.qaLeaderName,
|
||||||
|
this.correctiveAction,
|
||||||
|
this.escalateToOvrId,
|
||||||
|
this.escalateToOvrName,
|
||||||
|
this.immediateActionId,
|
||||||
|
this.immediateActionName,
|
||||||
|
this.clinicalOrNonClinicalId,
|
||||||
|
this.clinicalOrNonClinicalName,
|
||||||
|
this.recommendation,
|
||||||
|
this.requestorUserId,
|
||||||
|
this.requesterEmployeeId,
|
||||||
|
this.requesterEmployeeName,
|
||||||
|
this.requesterEmployeeEmail,
|
||||||
|
this.requesterPosition,
|
||||||
|
this.requesterContactNo,
|
||||||
|
this.requesterExtensionNo,
|
||||||
|
this.requestorSiteId,
|
||||||
|
this.requestorSiteName,
|
||||||
|
this.requestorDepartmentId,
|
||||||
|
this.requestorDepartmentName,
|
||||||
|
this.requestorFlowDepartmentId,
|
||||||
|
this.requestorFlowDepartmentName,
|
||||||
|
this.requestorFlowDepartmentShortCode,
|
||||||
|
this.approvalSignature,
|
||||||
|
this.occurrenceDate,
|
||||||
|
this.createdDate,
|
||||||
|
this.incidentAttachments});
|
||||||
|
|
||||||
|
IncidentDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
id = json['id'];
|
||||||
|
reqNo = json['reqNo'];
|
||||||
|
reqCode = json['reqCode'];
|
||||||
|
incidentStatusId = json['incidentStatusId'];
|
||||||
|
incidentStatusName = json['incidentStatusName'];
|
||||||
|
incidentStatusValue = json['incidentStatusValue'];
|
||||||
|
incidentClassificationId = json['incidentClassificationId'];
|
||||||
|
incidentClassificationName = json['incidentClassificationName'];
|
||||||
|
incidentClassificationValue = json['incidentClassificationValue'];
|
||||||
|
existingOvrTicketId = json['existingOvrTicketId'];
|
||||||
|
existingOvrTicketName = json['existingOvrTicketName'];
|
||||||
|
existingOvrTicketValue = json['existingOvrTicketValue'];
|
||||||
|
ovrTicketNumber = json['ovrTicketNumber'];
|
||||||
|
incidentTitle = json['incidentTitle'];
|
||||||
|
incidentDescription = json['incidentDescription'];
|
||||||
|
assetId = json['assetId'];
|
||||||
|
assetNumber = json['assetNumber'];
|
||||||
|
oracleCode = json['oracleCode'];
|
||||||
|
model = json['model'];
|
||||||
|
manufacturer = json['manufacturer'];
|
||||||
|
assetOrigin = json['assetOrigin'];
|
||||||
|
siteId = json['siteId'];
|
||||||
|
siteName = json['siteName'];
|
||||||
|
buildingId = json['buildingId'];
|
||||||
|
buildingName = json['buildingName'];
|
||||||
|
departmentId = json['departmentId'];
|
||||||
|
departmentName = json['departmentName'];
|
||||||
|
floorId = json['floorId'];
|
||||||
|
floorName = json['floorName'];
|
||||||
|
rootCauseId = json['rootCauseId'];
|
||||||
|
rootCauseName = json['rootCauseName'];
|
||||||
|
rootCauseValue = json['rootCauseValue'];
|
||||||
|
otherRootCause = json['otherRootCause'];
|
||||||
|
comments = json['comments'];
|
||||||
|
personInvolvedId = json['personInvolvedId'];
|
||||||
|
personInvolvedName = json['personInvolvedName'];
|
||||||
|
personInvolvedValue = json['personInvolvedValue'];
|
||||||
|
genderId = json['genderId'];
|
||||||
|
genderName = json['genderName'];
|
||||||
|
personInvolvedEmployeeId = json['personInvolvedEmployeeId'];
|
||||||
|
personInvolvedEmployeeName = json['personInvolvedEmployeeName'];
|
||||||
|
assignedQAId = json['assignedQAId'];
|
||||||
|
assignedQAName = json['assignedQAName'];
|
||||||
|
assignedSecondaryQAId = json['assignedSecondaryQAId'];
|
||||||
|
assignedSecondaryQAName = json['assignedSecondaryQAName'];
|
||||||
|
qaLeaderId = json['qaLeaderId'];
|
||||||
|
qaLeaderName = json['qaLeaderName'];
|
||||||
|
correctiveAction = json['correctiveAction'];
|
||||||
|
escalateToOvrId = json['escalateToOvrId'];
|
||||||
|
escalateToOvrName = json['escalateToOvrName'];
|
||||||
|
immediateActionId = json['immediateActionId'];
|
||||||
|
immediateActionName = json['immediateActionName'];
|
||||||
|
clinicalOrNonClinicalId = json['clinicalOrNonClinicalId'];
|
||||||
|
clinicalOrNonClinicalName = json['clinicalOrNonClinicalName'];
|
||||||
|
recommendation = json['recommendation'];
|
||||||
|
requestorUserId = json['requestorUserId'];
|
||||||
|
requesterEmployeeId = json['requesterEmployeeId'];
|
||||||
|
requesterEmployeeName = json['requesterEmployeeName'];
|
||||||
|
requesterEmployeeEmail = json['requesterEmployeeEmail'];
|
||||||
|
requesterPosition = json['requesterPosition'];
|
||||||
|
requesterContactNo = json['requesterContactNo'];
|
||||||
|
requesterExtensionNo = json['requesterExtensionNo'];
|
||||||
|
requestorSiteId = json['requestorSiteId'];
|
||||||
|
requestorSiteName = json['requestorSiteName'];
|
||||||
|
requestorDepartmentId = json['requestorDepartmentId'];
|
||||||
|
requestorDepartmentName = json['requestorDepartmentName'];
|
||||||
|
requestorFlowDepartmentId = json['requestorFlowDepartmentId'];
|
||||||
|
requestorFlowDepartmentName = json['requestorFlowDepartmentName'];
|
||||||
|
requestorFlowDepartmentShortCode = json['requestorFlowDepartmentShortCode'];
|
||||||
|
approvalSignature = json['approvalSignature'];
|
||||||
|
occurrenceDate = json['occurrenceDate'];
|
||||||
|
createdDate = json['createdDate'];
|
||||||
|
if (json['incidentAttachments'] != null) {
|
||||||
|
incidentAttachments = <IncidentAttachments>[];
|
||||||
|
json['incidentAttachments'].forEach((v) {
|
||||||
|
incidentAttachments!.add(IncidentAttachments.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['id'] = this.id;
|
||||||
|
data['reqNo'] = this.reqNo;
|
||||||
|
data['reqCode'] = this.reqCode;
|
||||||
|
data['incidentStatusId'] = this.incidentStatusId;
|
||||||
|
data['incidentStatusName'] = this.incidentStatusName;
|
||||||
|
data['incidentStatusValue'] = this.incidentStatusValue;
|
||||||
|
data['incidentClassificationId'] = this.incidentClassificationId;
|
||||||
|
data['incidentClassificationName'] = this.incidentClassificationName;
|
||||||
|
data['incidentClassificationValue'] = this.incidentClassificationValue;
|
||||||
|
data['existingOvrTicketId'] = this.existingOvrTicketId;
|
||||||
|
data['existingOvrTicketName'] = this.existingOvrTicketName;
|
||||||
|
data['existingOvrTicketValue'] = this.existingOvrTicketValue;
|
||||||
|
data['ovrTicketNumber'] = this.ovrTicketNumber;
|
||||||
|
data['incidentTitle'] = this.incidentTitle;
|
||||||
|
data['incidentDescription'] = this.incidentDescription;
|
||||||
|
data['assetId'] = this.assetId;
|
||||||
|
data['assetNumber'] = this.assetNumber;
|
||||||
|
data['oracleCode'] = this.oracleCode;
|
||||||
|
data['model'] = this.model;
|
||||||
|
data['manufacturer'] = this.manufacturer;
|
||||||
|
data['assetOrigin'] = this.assetOrigin;
|
||||||
|
data['siteId'] = this.siteId;
|
||||||
|
data['siteName'] = this.siteName;
|
||||||
|
data['buildingId'] = this.buildingId;
|
||||||
|
data['buildingName'] = this.buildingName;
|
||||||
|
data['departmentId'] = this.departmentId;
|
||||||
|
data['departmentName'] = this.departmentName;
|
||||||
|
data['floorId'] = this.floorId;
|
||||||
|
data['floorName'] = this.floorName;
|
||||||
|
data['rootCauseId'] = this.rootCauseId;
|
||||||
|
data['rootCauseName'] = this.rootCauseName;
|
||||||
|
data['rootCauseValue'] = this.rootCauseValue;
|
||||||
|
data['otherRootCause'] = this.otherRootCause;
|
||||||
|
data['comments'] = this.comments;
|
||||||
|
data['personInvolvedId'] = this.personInvolvedId;
|
||||||
|
data['personInvolvedName'] = this.personInvolvedName;
|
||||||
|
data['personInvolvedValue'] = this.personInvolvedValue;
|
||||||
|
data['genderId'] = this.genderId;
|
||||||
|
data['genderName'] = this.genderName;
|
||||||
|
data['personInvolvedEmployeeId'] = this.personInvolvedEmployeeId;
|
||||||
|
data['personInvolvedEmployeeName'] = this.personInvolvedEmployeeName;
|
||||||
|
data['assignedQAId'] = this.assignedQAId;
|
||||||
|
data['assignedQAName'] = this.assignedQAName;
|
||||||
|
data['assignedSecondaryQAId'] = this.assignedSecondaryQAId;
|
||||||
|
data['assignedSecondaryQAName'] = this.assignedSecondaryQAName;
|
||||||
|
data['qaLeaderId'] = this.qaLeaderId;
|
||||||
|
data['qaLeaderName'] = this.qaLeaderName;
|
||||||
|
data['correctiveAction'] = this.correctiveAction;
|
||||||
|
data['escalateToOvrId'] = this.escalateToOvrId;
|
||||||
|
data['escalateToOvrName'] = this.escalateToOvrName;
|
||||||
|
data['immediateActionId'] = this.immediateActionId;
|
||||||
|
data['immediateActionName'] = this.immediateActionName;
|
||||||
|
data['clinicalOrNonClinicalId'] = this.clinicalOrNonClinicalId;
|
||||||
|
data['clinicalOrNonClinicalName'] = this.clinicalOrNonClinicalName;
|
||||||
|
data['recommendation'] = this.recommendation;
|
||||||
|
data['requestorUserId'] = this.requestorUserId;
|
||||||
|
data['requesterEmployeeId'] = this.requesterEmployeeId;
|
||||||
|
data['requesterEmployeeName'] = this.requesterEmployeeName;
|
||||||
|
data['requesterEmployeeEmail'] = this.requesterEmployeeEmail;
|
||||||
|
data['requesterPosition'] = this.requesterPosition;
|
||||||
|
data['requesterContactNo'] = this.requesterContactNo;
|
||||||
|
data['requesterExtensionNo'] = this.requesterExtensionNo;
|
||||||
|
data['requestorSiteId'] = this.requestorSiteId;
|
||||||
|
data['requestorSiteName'] = this.requestorSiteName;
|
||||||
|
data['requestorDepartmentId'] = this.requestorDepartmentId;
|
||||||
|
data['requestorDepartmentName'] = this.requestorDepartmentName;
|
||||||
|
data['requestorFlowDepartmentId'] = this.requestorFlowDepartmentId;
|
||||||
|
data['requestorFlowDepartmentName'] = this.requestorFlowDepartmentName;
|
||||||
|
data['requestorFlowDepartmentShortCode'] = this.requestorFlowDepartmentShortCode;
|
||||||
|
data['approvalSignature'] = this.approvalSignature;
|
||||||
|
data['occurrenceDate'] = this.occurrenceDate;
|
||||||
|
data['createdDate'] = this.createdDate;
|
||||||
|
if (this.incidentAttachments != null) {
|
||||||
|
data['incidentAttachments'] = this.incidentAttachments!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,200 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:flutter/material.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/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/cm_module/views/components/action_button/footer_action_button.dart';
|
||||||
|
import 'package:test_sa/modules/incident_module/incident_attachment_model.dart';
|
||||||
|
import 'package:test_sa/modules/incident_module/incident_data_model.dart';
|
||||||
|
import 'package:test_sa/modules/incident_module/incident_provider.dart';
|
||||||
|
import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
|
||||||
|
import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart';
|
||||||
|
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart';
|
||||||
|
import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart';
|
||||||
|
import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
|
||||||
|
import 'package:test_sa/modules/loan_module/models/loan_attachment_model.dart';
|
||||||
|
import 'package:test_sa/modules/loan_module/models/loan_request_model.dart';
|
||||||
|
import 'package:test_sa/modules/loan_module/provider/loan_provider.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/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 IncidentDetailPage extends StatelessWidget {
|
||||||
|
static const String id = "/incident-detail-page";
|
||||||
|
final int incidentId;
|
||||||
|
|
||||||
|
IncidentDetailPage({Key? key, required this.incidentId}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: const DefaultAppBar(title: "Request Details"),
|
||||||
|
body: FutureBuilder<IncidentDataModel?>(
|
||||||
|
future: Provider.of<IncidentProvider>(context, listen: false).getIncidentById(incidentId),
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<IncidentDataModel?> snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center;
|
||||||
|
if (snapshot.data == null) return const NoDataFound().center;
|
||||||
|
|
||||||
|
List<IncidentAttachments> allAttachments = snapshot.data!.incidentAttachments!;
|
||||||
|
|
||||||
|
return ListView(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
StatusLabel(
|
||||||
|
label: snapshot.data!.incidentStatusName!,
|
||||||
|
textColor: AppColor.getRequestStatusTextColorByName(context, snapshot.data!.incidentStatusName!),
|
||||||
|
backgroundColor: AppColor.getRequestStatusColorByName(context, snapshot.data!.incidentStatusName!),
|
||||||
|
),
|
||||||
|
1.width.expanded,
|
||||||
|
Text(
|
||||||
|
snapshot.data!.createdDate?.toServiceRequestCardFormat ?? "-",
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
12.height,
|
||||||
|
...requesterDetails(context, snapshot.data!),
|
||||||
|
const Divider().defaultStyle(context),
|
||||||
|
...requestDetails(context, snapshot.data!),
|
||||||
|
if (snapshot.data!.ovrTicketNumber?.isNotEmpty ?? false) ovrInformation(context, snapshot.data!.ovrTicketNumber!),
|
||||||
|
const Divider().defaultStyle(context),
|
||||||
|
...assetDetails(context, snapshot.data!),
|
||||||
|
const Divider().defaultStyle(context),
|
||||||
|
...personInvolvedDetails(context, snapshot.data!),
|
||||||
|
if (allAttachments.isNotEmpty) ...[
|
||||||
|
const Divider().defaultStyle(context),
|
||||||
|
Text(
|
||||||
|
"Attachments".addTranslation,
|
||||||
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
||||||
|
),
|
||||||
|
FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
).toShadowContainer(context, padding: 12),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> requestDetails(BuildContext context, IncidentDataModel incidentData) {
|
||||||
|
return [
|
||||||
|
Text("Request Details", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
|
||||||
|
'Incident No: ${incidentData.reqCode ?? "-"}'.bodyText(context),
|
||||||
|
'Incident Type: ${incidentData.incidentClassificationName ?? "-"}'.bodyText(context),
|
||||||
|
'Incident Title: ${incidentData.incidentTitle ?? "-"}'.bodyText(context),
|
||||||
|
'Incident Description: ${incidentData.incidentDescription ?? "-"}'.bodyText(context),
|
||||||
|
'Exist OVR: ${incidentData.existingOvrTicketName ?? "-"}'.bodyText(context),
|
||||||
|
'Site: ${incidentData.siteName ?? "-"}'.bodyText(context),
|
||||||
|
'Building: ${incidentData.buildingName ?? "-"}'.bodyText(context),
|
||||||
|
'Floor: ${incidentData.floorName ?? "-"}'.bodyText(context),
|
||||||
|
'Department: ${incidentData.departmentName ?? "-"}'.bodyText(context),
|
||||||
|
'Occurrence Date: ${incidentData.occurrenceDate?.toServiceRequestDetailsFormat ?? "-"}'.bodyText(context),
|
||||||
|
'Root Cause: ${incidentData.rootCauseName ?? "-"}'.bodyText(context),
|
||||||
|
if (incidentData.rootCauseValue == 5) 'Root reason: ${incidentData.otherRootCause ?? "-"}'.bodyText(context),
|
||||||
|
'Comments: ${incidentData.comments ?? "-"}'.bodyText(context),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget ovrInformation(BuildContext context, String ovrNumber) {
|
||||||
|
return FutureBuilder<Map<String, dynamic>?>(
|
||||||
|
future: Provider.of<IncidentProvider>(context, listen: false).getOvrTicketDetails(ovrNumber),
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<Map<String, dynamic>?> snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center;
|
||||||
|
if (snapshot.data == null) return const NoDataFound().center;
|
||||||
|
|
||||||
|
Map<String, dynamic>? data = snapshot.data;
|
||||||
|
if (data == null) return const SizedBox();
|
||||||
|
List<String> keysList = data.keys.toList();
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Divider().defaultStyle(context),
|
||||||
|
Text("OVR Ticket Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
|
||||||
|
'OVR Ticket Number: $ovrNumber'.bodyText(context),
|
||||||
|
for (int i = 0; i < keysList.length; i++) '${keysList[i]}: ${data[keysList[i]] ?? "-"}'.bodyText(context),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> personInvolvedDetails(BuildContext context, IncidentDataModel incidentData) {
|
||||||
|
return [
|
||||||
|
Text("Person Involved Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
|
||||||
|
'Person Involved: ${incidentData.personInvolvedName ?? "-"}'.bodyText(context),
|
||||||
|
'Gender: ${incidentData.genderName ?? "-"}'.bodyText(context),
|
||||||
|
'Person Involved ID: ${incidentData.personInvolvedEmployeeId ?? "-"}'.bodyText(context),
|
||||||
|
'Person Involved Name: ${incidentData.personInvolvedEmployeeName ?? "-"}'.bodyText(context),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> assetDetails(BuildContext context, IncidentDataModel loanData) {
|
||||||
|
return [
|
||||||
|
Text("Asset Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
|
||||||
|
'${context.translation.assetName}: ${loanData.assetOrigin ?? "-"}'.bodyText(context),
|
||||||
|
'${context.translation.assetNo}: ${loanData.assetNumber ?? "-"}'.bodyText(context),
|
||||||
|
// '${context.translation.serialNumber}: ${loanData.assetSerialNumber ?? "-"}'.bodyText(context),
|
||||||
|
'${context.translation.manufacture}: ${loanData.manufacturer ?? "-"}'.bodyText(context),
|
||||||
|
'${context.translation.model}: ${loanData.model ?? "-"}'.bodyText(context),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> requesterDetails(BuildContext context, IncidentDataModel incidentData) {
|
||||||
|
return [
|
||||||
|
Text("Requester Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
|
||||||
|
'Name: ${incidentData.requesterEmployeeName ?? "-"}'.bodyText(context),
|
||||||
|
'Email: ${incidentData.requesterEmployeeEmail ?? "-"}'.bodyText(context),
|
||||||
|
'Contact: ${incidentData.requesterContactNo ?? "-"}'.bodyText(context),
|
||||||
|
'Extension: ${incidentData.requesterExtensionNo ?? "-"}'.bodyText(context),
|
||||||
|
'Site: ${incidentData.requestorSiteName ?? "-"}'.bodyText(context),
|
||||||
|
'Department: ${incidentData.requestorFlowDepartmentName ?? "-"}'.bodyText(context),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget labelValueText(BuildContext context, String label, String? value) {
|
||||||
|
if (value == null || value.isEmpty) return const SizedBox.shrink();
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 4),
|
||||||
|
child: Text(
|
||||||
|
'$label: $value',
|
||||||
|
style: AppTextStyles.bodyText.copyWith(
|
||||||
|
color: context.isDark ? AppColor.neutral30 : AppColor.neutral120,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget checklistWidget(BuildContext context, {required String value}) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Checkbox(
|
||||||
|
value: true,
|
||||||
|
activeColor: AppColor.neutral120,
|
||||||
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
visualDensity: const VisualDensity(horizontal: -4, vertical: -3),
|
||||||
|
onChanged: (value) {},
|
||||||
|
),
|
||||||
|
value.bodyText(context),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:test_sa/extensions/context_extension.dart';
|
||||||
|
import 'package:test_sa/extensions/int_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/string_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/text_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/widget_extensions.dart';
|
||||||
|
import 'package:test_sa/models/all_requests_and_count_model.dart';
|
||||||
|
import 'package:test_sa/models/new_models/dashboard_detail.dart';
|
||||||
|
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart';
|
||||||
|
import 'package:test_sa/new_views/app_style/app_color.dart';
|
||||||
|
import 'package:test_sa/views/widgets/requests/request_status.dart';
|
||||||
|
|
||||||
|
import 'incident_detail_page.dart';
|
||||||
|
|
||||||
|
class IncidentItemView extends StatelessWidget {
|
||||||
|
final Data? requestData;
|
||||||
|
final RequestsDetails? requestDetails;
|
||||||
|
final bool showShadow;
|
||||||
|
|
||||||
|
const IncidentItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (requestData != null) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
StatusLabel(
|
||||||
|
label: requestData!.statusName!,
|
||||||
|
textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!),
|
||||||
|
backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!),
|
||||||
|
),
|
||||||
|
1.width.expanded,
|
||||||
|
Text(
|
||||||
|
requestData!.transactionDate?.toServiceRequestCardFormat ?? "",
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
(requestData?.typeTransaction ?? "Loan Request").heading5(context),
|
||||||
|
infoWidget(label: context.translation.requestType, value: requestData?.requestTypeName, context: context),
|
||||||
|
infoWidget(label: "Incident No", value: requestData?.requestNo, context: context),
|
||||||
|
// infoWidget(label: context.translation.site, value: requestData?., context: context),
|
||||||
|
8.height,
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
context.translation.viewDetails,
|
||||||
|
style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
|
||||||
|
),
|
||||||
|
4.width,
|
||||||
|
Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).toShadowContainer(context, withShadow: showShadow).onPress(() async {
|
||||||
|
Navigator.push(context, MaterialPageRoute(builder: (context) => IncidentDetailPage(incidentId: requestDetails!.id!)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
StatusLabel(
|
||||||
|
label: requestDetails!.status!,
|
||||||
|
textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!),
|
||||||
|
backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!),
|
||||||
|
),
|
||||||
|
1.width.expanded,
|
||||||
|
Text(
|
||||||
|
requestDetails!.date?.toServiceRequestCardFormat ?? "",
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
(requestDetails?.nameOfType ?? "Loan Request").heading5(context),
|
||||||
|
8.height,
|
||||||
|
infoWidget(label: context.translation.requestType, value: requestDetails!.requestType, context: context),
|
||||||
|
infoWidget(label: "Incident No", value: requestDetails!.requestNo, context: context),
|
||||||
|
infoWidget(label: context.translation.assetName, value: requestDetails!.assetName, context: context),
|
||||||
|
infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
|
||||||
|
8.height,
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
context.translation.viewDetails,
|
||||||
|
style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
|
||||||
|
),
|
||||||
|
4.width,
|
||||||
|
Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).toShadowContainer(context, withShadow: showShadow).onPress(() async {
|
||||||
|
Navigator.push(context, MaterialPageRoute(builder: (context) => IncidentDetailPage(incidentId: requestDetails!.id!)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget infoWidget({required String label, String? value, required BuildContext context}) {
|
||||||
|
if (value != null && value.isNotEmpty) {
|
||||||
|
return '$label: $value'.bodyText(context);
|
||||||
|
}
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,158 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
import 'package:test_sa/providers/loading_list_notifier.dart';
|
||||||
|
|
||||||
|
import '../../controllers/api_routes/api_manager.dart';
|
||||||
|
import '../../controllers/api_routes/urls.dart';
|
||||||
|
import '../../models/lookup.dart';
|
||||||
|
|
||||||
|
class IncidentStatusLookupProvider extends LoadingListNotifier<Lookup> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading == true) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.incidentStatusLookup);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IncidentTypeLookupProvider extends LoadingListNotifier<Lookup> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading == true) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.incidentTypeLookup);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IncidentRootCauseLookupProvider extends LoadingListNotifier<Lookup> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading == true) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.incidentRootCauseLookup);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IncidentPersonInvolvedLookupProvider extends LoadingListNotifier<Lookup> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading == true) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.incidentPersonInvolvedLookup);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClinicalNonClinicalLookupProvider extends LoadingListNotifier<Lookup> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading == true) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.clinicalNonClinicalLookup);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GenderLookupProvider extends LoadingListNotifier<Lookup> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading == true) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.genderLookup);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
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';
|
||||||
|
import 'package:test_sa/modules/loan_module/models/loan_request_model.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'incident_data_model.dart';
|
||||||
|
|
||||||
|
class IncidentProvider extends ChangeNotifier {
|
||||||
|
Future<bool> addIncidentRequest(Map<String, dynamic> body) async {
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.post(URLs.addIncident, body: body);
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
|
String message = (jsonDecode(response.body)["data"] ?? "") + " " + (jsonDecode(response.body)["message"] ?? "");
|
||||||
|
Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLoading = false;
|
||||||
|
|
||||||
|
Future<IncidentDataModel?> getIncidentById(int id) async {
|
||||||
|
IncidentDataModel? loanData;
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.getIncidentById + "?incidentId=$id");
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
|
loanData = IncidentDataModel.fromJson(json.decode(response.body)["data"]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
print(error);
|
||||||
|
}
|
||||||
|
return loanData;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>?> getOvrTicketDetails(String ticketNumber) async {
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.post(URLs.getOvrTicketDetails, body: {"ticketNumber": ticketNumber}, showToast: false);
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
|
if (json.decode(response.body)["statusCode"] == 404) {
|
||||||
|
Fluttertoast.showToast(msg: json.decode(response.body)["message"] ?? "OVR Ticket not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return json.decode(response.body)["data"];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
print(error);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
import 'package:test_sa/providers/loading_list_notifier.dart';
|
||||||
|
|
||||||
|
import '../../controllers/api_routes/api_manager.dart';
|
||||||
|
import '../../controllers/api_routes/urls.dart';
|
||||||
|
import '../../models/lookup.dart';
|
||||||
|
|
||||||
|
class DemoPeriodLookupProvider extends LoadingListNotifier<Lookup> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading == true) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.get(URLs.incidentTypeLookup);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:test_sa/extensions/context_extension.dart';
|
||||||
|
import 'package:test_sa/extensions/int_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/text_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/widget_extensions.dart';
|
||||||
|
import 'package:test_sa/new_views/app_style/app_color.dart';
|
||||||
|
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
|
||||||
|
|
||||||
|
class InfoContent {
|
||||||
|
final String? title;
|
||||||
|
final String? message;
|
||||||
|
|
||||||
|
InfoContent({this.title, this.message});
|
||||||
|
}
|
||||||
|
|
||||||
|
class InfoDialog extends StatelessWidget {
|
||||||
|
final String? title;
|
||||||
|
final String? message;
|
||||||
|
final List<InfoContent> content;
|
||||||
|
|
||||||
|
final String? okTitle;
|
||||||
|
final VoidCallback? onTap;
|
||||||
|
final VoidCallback? onCloseTap;
|
||||||
|
|
||||||
|
const InfoDialog({Key? key, this.title, this.message, this.content = const [], this.okTitle, this.onTap, this.onCloseTap}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Dialog(
|
||||||
|
backgroundColor: AppColor.background(context),
|
||||||
|
shape: const RoundedRectangleBorder(),
|
||||||
|
insetPadding: const EdgeInsets.only(left: 21, right: 21),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
title ?? "Information",
|
||||||
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: AppColor.headingTextColor(context), height: 35 / 24, letterSpacing: -0.96),
|
||||||
|
).paddingOnly(top: 16),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
color: AppColor.iconColor(context),
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
onPressed: () => onCloseTap ?? Navigator.pop(context),
|
||||||
|
// onPressed: () => Navigator.pop(context),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
message != null ? message!.bodyText(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20) : const SizedBox(),
|
||||||
|
8.height,
|
||||||
|
ListView.separated(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (cxt, index) => RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: "${content[index].title}: ",
|
||||||
|
style: AppTextStyles.heading6.copyWith(fontWeight: FontWeight.w600, color: AppColor.textColor(context)),
|
||||||
|
children: [
|
||||||
|
TextSpan(text: content[index].message, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
separatorBuilder: (cxt, index) => 6.height,
|
||||||
|
itemCount: content.length),
|
||||||
|
24.height,
|
||||||
|
AppFilledButton(
|
||||||
|
label: okTitle ?? "OK",
|
||||||
|
onPressed: onTap ?? () => Navigator.pop(context),
|
||||||
|
textColor: Colors.white,
|
||||||
|
//color: Ap.green,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue