internal audit design complete

design_3.0_internal_audit_module
WaseemAbbasi22 1 week ago
parent b71207538d
commit cbddd807d4

@ -4,8 +4,8 @@ class URLs {
static const String appReleaseBuildNumber = "26";
// static const host1 = "https://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static String _baseUrl = "$_host/mobile";
static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis

@ -133,15 +133,25 @@ class AllRequestsProvider extends ChangeNotifier {
List<int> getStatues(BuildContext context) {
List<int> list = [1, 2, 3, 4];
//TODO need to refactor this code ....
if (context.userProvider.isAssessor) {
list = [9];
return list;
}
if (context.userProvider.isQualityUser) {
//TODO Need to replace with actual number..
// list = [10];
list = [1];
return list;
}
if (!context.userProvider.isNurse) {
list.add(5);
}
if (context.userProvider.isEngineer) {
list.add(10);
}
list.add(6); // task module
if (context.settingProvider.isUserFlowMedical && !context.userProvider.isNurse) {

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

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@ -51,6 +52,9 @@ class RequestCategoryList extends StatelessWidget {
return TaskRequestItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request);
//TODO need to verify this ...
case 10:
return InternalAuditItemView(requestData: request);
default:
return Container(
height: 100,

@ -29,6 +29,10 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart';
import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart';
import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart';
import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart';
import 'package:test_sa/modules/traf_module/create_traf_request_page.dart';
import 'package:test_sa/modules/traf_module/traf_request_provider.dart';
@ -98,6 +102,8 @@ import 'controllers/providers/api/gas_refill_comments.dart';
import 'controllers/providers/api/user_provider.dart';
import 'controllers/providers/settings/setting_provider.dart';
import 'dashboard_latest/dashboard_provider.dart';
import 'modules/internal_audit_module/pages/update_internal_audit_page.dart';
import 'modules/internal_audit_module/provider/internal_audit_checklist_provider.dart';
import 'new_views/pages/gas_refill_request_form.dart';
import 'providers/lookups/classification_lookup_provider.dart';
import 'providers/lookups/department_lookup_provider.dart';
@ -285,6 +291,9 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => PpmServiceProvider()),
ChangeNotifierProvider(create: (_) => CommentsProvider()),
ChangeNotifierProvider(create: (_) => GasRefillCommentsProvider()),
ChangeNotifierProvider(create: (_) => InternalAuditCheckListProvider()),
ChangeNotifierProvider(create: (_) => InternalAuditProvider()),
ChangeNotifierProvider(create: (_) => InternalAuditFindingTypeProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => RequestStatusProvider()),
@ -352,6 +361,9 @@ class MyApp extends StatelessWidget {
ProfilePage.id: (_) => const ProfilePage(),
ReportBugPage.id: (_) => const ReportBugPage(),
HelpCenterPage.id: (_) => const HelpCenterPage(),
CreateEquipmentInternalAuditForm.id: (_) => const CreateEquipmentInternalAuditForm(),
CreateSystemInternalAuditForm.id: (_) => const CreateSystemInternalAuditForm(),
UpdateInternalAuditPage.id: (_) => const UpdateInternalAuditPage(),
// SwipeSuccessView.routeName: (_) => const SwipeSuccessView(),
// SwipeHistoryView.routeName: (_) => const SwipeHistoryView(),
},

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

@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:io';
import 'package:flutter/foundation.dart';
@ -97,6 +98,8 @@ class User {
UsersTypes? get type {
switch (userRoles?.first.value) {
case "R-7": // Head Nurse Role
return UsersTypes.qualityUser;
case "R-6":
return UsersTypes.engineer;
case "R-7": // Nurse Role
@ -107,6 +110,8 @@ class User {
return UsersTypes.assessor;
case "R-19": // Head Nurse Role
return UsersTypes.assessorTl;
//TODO need to replace with actual data when confirm
default:
return null;
}

@ -72,52 +72,44 @@ class _ServiceRequestDetailViewState extends State<ServiceRequestDetailView> {
? const CircularProgressIndicator(color: AppColor.primary10).center
: requestProvider.currentWorkOrder == null
? const NoDataFound()
: Stack(
children: [
Column(
: Column(
children: [
SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider),
initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
12.height,
assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
12.height,
if (context.userProvider.user!.type == UsersTypes.engineer &&
!requestProvider.isReadOnlyRequest &&
requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[
costCard(context, requestProvider),
12.height,
],
contactInfoCard(context, requestProvider.currentWorkOrder!.data!),
20.height,
],
),
).expanded,
SafeArea(
top: false,
right: false,
left: false,
child: FooterActionButton.requestDetailsFooterWidget(
workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!,
status: requestProvider.currentWorkOrder?.data?.status,
isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null,
activities: requestProvider.currentWorkOrder!.data?.activities ?? [],
userProvider: _userProvider,
context: context),
).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0),
workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider),
initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
12.height,
assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
12.height,
if (context.userProvider.user!.type == UsersTypes.engineer &&
!requestProvider.isReadOnlyRequest &&
requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[
costCard(context, requestProvider),
12.height,
],
contactInfoCard(context, requestProvider.currentWorkOrder!.data!),
20.height,
],
),
//no need to show timer as discussed with backend
// if (requestProvider.timer != null && requestProvider.timer!.isActive) ...[
// const TimerWidget(),
// ]
],
);
).expanded,
SafeArea(
top: false,
right: false,
left: false,
child: FooterActionButton.requestDetailsFooterWidget(
workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!,
status: requestProvider.currentWorkOrder?.data?.status,
isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null,
activities: requestProvider.currentWorkOrder!.data?.activities ?? [],
userProvider: _userProvider,
context: context),
).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0),
],
);
});
}

@ -0,0 +1,196 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart';
import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart';
import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart';
import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_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_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart';
import '../../../../../../new_views/common_widgets/default_app_bar.dart';
class CreateSystemInternalAuditForm extends StatefulWidget {
static const String id = "/create-system-audit-view";
const CreateSystemInternalAuditForm({Key? key}) : super(key: key);
@override
_CreateSystemInternalAuditFormState createState() => _CreateSystemInternalAuditFormState();
}
//TODO remove unnecessary code
class _CreateSystemInternalAuditFormState extends State<CreateSystemInternalAuditForm> with TickerProviderStateMixin {
late TextEditingController _commentController;
late InternalAuditProvider _internalAuditProvider;
final InternalAuditModel _internalAuditModel = InternalAuditModel();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final List<GenericAttachmentModel> _deviceImages = [];
bool showLoading = false;
@override
void initState() {
super.initState();
_commentController = TextEditingController();
_internalAuditProvider = Provider.of<InternalAuditProvider>(context, listen: false);
}
@override
void dispose() {
_commentController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(title: 'System Internal Audit Checklist'.addTranslation),
body: Form(
key: _formKey,
child: Column(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AutoCompletePartsField(
assetId: 0,
clearAfterPick: false,
byName: true,
initialValue: _internalAuditModel.woOrderNo ?? "",
onPick: (part) {
_internalAuditModel.woOrderNo = part.name;
setState(() {});
},
),
12.height,
// if(_internalAuditModel.woOrderNo!=null)
_workOrderInfoWidget(context),
12.height,
SingleItemDropDownMenu<Lookup, InternalAuditFindingTypeProvider>(
context: context,
height: 56.toScreenHeight,
title: 'Finding Type'.addTranslation,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: _internalAuditModel.auditCheckList,
onSelect: (status) {
if (status != null) {
_internalAuditModel.auditCheckList = status;
setState(() {});
}
},
),
12.height,
AppTextFormField(
backgroundColor: AppColor.fieldBgColor(context),
labelText: 'Finding Description'.addTranslation,
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
showShadow: false,
onSaved: (text) {},
),
16.height,
AttachmentPicker(
label: context.translation.attachments,
attachment: _deviceImages,
buttonColor: AppColor.primary10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10),
),
],
).toShadowContainer(context),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: context.translation.submitRequest,
onPressed: _submit,
),
),
],
),
),
);
}
Future<void> _submit() async {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
List<WorkOrderAttachments> attachement = [];
for (var item in _deviceImages) {
String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
// attachement.add(WorkOrderAttachments(id: 0, name: fileName));
}
// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
}
}
Widget _workOrderInfoWidget(BuildContext context) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: showLoading ? Colors.white : const Color(0xffF4F6FC),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0xff212936).withOpacity(.03),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
Text(
"WO Type",
style: TextStyle(
fontSize: 14.toScreenWidth,
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
color: Colors.black87,
decoration: TextDecoration.none,
),
).toShimmer(isShow: showLoading, context: context).expanded,
const Icon(
Icons.info,
color: Color(0xff7D859A),
size: 20,
),
],
),
6.height,
"${context.translation.site}: ${'ABC'}".bodyText(context),
"${'Eng. Name'.addTranslation}: ${'ABC'}".bodyText(context),
"${'Asset Name'.addTranslation}: ${'ABC'}".bodyText(context),
"${context.translation.model}: ${'ABC'}".bodyText(context),
"${context.translation.manufacture}: ${'ABC'}".bodyText(context),
"${'SN'.addTranslation}: ${'ABC'}".bodyText(context),
"${context.translation.assetNo}: ${'ABC'}".bodyText(context),
],
),
);
}
}

@ -0,0 +1,178 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/internal_audit_module/pages/update_internal_audit_page.dart';
import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_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';
class InternalAuditDetailPage extends StatefulWidget {
static const String id = "/details-internal-audit";
final int auditId;
InternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key);
@override
_InternalAuditDetailPageState createState() {
return _InternalAuditDetailPageState();
}
}
class _InternalAuditDetailPageState extends State<InternalAuditDetailPage> {
bool isWoType = true;
@override
void initState() {
super.initState();
//TODO need to get and assign data .
// Provider.of<InternalAuditProvider>(context, listen: false).getInternalAuditById(widget.auditId);
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
//TODO need to check when implementing provider needed or not .
return Scaffold(
appBar: const DefaultAppBar(title: "Request Details"),
body: Selector<InternalAuditProvider, bool>(
selector: (_, provider) => provider.isLoading,
builder: (_, isLoading, __) {
if (isLoading) return const ALoading();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
assetInformation(),
8.height,
isWoType ? workOrderInformation() : requestDetails(),
8.height,
//TODO need to check for comments
// if (model.comment?.isNotEmpty ?? false) ...[
const Divider().defaultStyle(context),
Text(
"Comments".addTranslation,
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
// model.comment!.bodyText(context),
// 8.height,
// ],
//TODO need to check for attachments
// if ( _model.attachment.isNotEmpty) ...[
const Divider().defaultStyle(context),
Text(
"Attachments".addTranslation,
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
// FilesList(images: _model.attachment?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []),
// ],
],
).paddingAll(0).toShadowContainer(context),
).expanded,
if (context.userProvider.isEngineer)
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: "Update",
onPressed: () {
Navigator.pushNamed(context, UpdateInternalAuditPage.id);
}),
),
],
);
},
));
}
Widget workOrderInformation() {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider().defaultStyle(context),
Text(
"WO Info",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
6.height,
'${context.translation.woNumber}: ${'-'}'.bodyText(context),
'${'WO Type'.addTranslation}: ${'-'}'.bodyText(context),
'${context.translation.site}: ${'-'}'.bodyText(context),
'${context.translation.assetName}: ${'-'}'.bodyText(context),
'${context.translation.manufacture}: ${'-'}'.bodyText(context),
'${context.translation.model}: ${'-'}'.bodyText(context),
],
);
}
Widget requestDetails() {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider().defaultStyle(context),
Text(
"Request Details",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
6.height,
checklistWidget(value: 'Asset Tag'.addTranslation),
checklistWidget(value: 'Expired PM Tag'.addTranslation),
],
);
}
Widget assetInformation() {
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,
'${context.translation.assetName}: ${'-'}'.bodyText(context),
'${context.translation.assetNo}: ${'-'}'.bodyText(context),
'${context.translation.manufacture}: ${'-'}'.bodyText(context),
'${context.translation.model}: ${'-'}'.bodyText(context),
],
);
}
Widget checklistWidget({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,113 @@
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/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';
class InternalAuditItemView extends StatelessWidget {
final Data? requestData;
final RequestsDetails? requestDetails;
final bool showShadow;
const InternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key);
@override
Widget build(BuildContext context) {
//TODO need to refactor this code repetation @waseem
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 ?? "Internal Audit Request").heading5(context),
("Internal Audit Request").heading5(context),
// infoWidget(label: context.translation.requestType, value: requestData?.requestTypeName, 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) => InternalAuditDetailPage(auditId: 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 ?? "Internal Audit Request").heading5(context),
("Internal Audit Request").heading5(context),
8.height,
// 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) => InternalAuditDetailPage(auditId: 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,327 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_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/working_time_tile.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
class UpdateInternalAuditPage extends StatefulWidget {
static const String id = "update-internal-audit";
final model;
const UpdateInternalAuditPage({this.model, Key? key}) : super(key: key);
@override
State<UpdateInternalAuditPage> createState() => _UpdateInternalAuditPageState();
}
class _UpdateInternalAuditPageState extends State<UpdateInternalAuditPage> {
final bool _isLoading = false;
double totalWorkingHours = 0.0;
late UserProvider _userProvider;
// GasRefillDetails _currentDetails = GasRefillDetails();
final TextEditingController _commentController = TextEditingController();
final TextEditingController _workingHoursController = TextEditingController();
// final GasRefillModel _formModel = GasRefillModel(gasRefillDetails: []);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
bool _firstTime = true;
List<GenericAttachmentModel> _attachments = [];
List<TimerHistoryModel> timerList = [];
@override
void initState() {
super.initState();
// if (widget.gasRefillModel != null) {
// _formModel.fromGasRefillModel(widget.gasRefillModel!);
// _commentController.text = _formModel.techComment ?? "";
// calculateWorkingTime();
// try {
// _deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty);
// _currentDetails.deliverdQty = _deliveredQuantity!.value;
// } catch (ex) {}
// }
// if (_formModel.gasRefillAttachments != null && _formModel.gasRefillAttachments!.isNotEmpty) {
// _attachments.addAll(_formModel.gasRefillAttachments!.map((e) => GenericAttachmentModel(id:e.id,name:e.attachmentName!)).toList());
// }
}
void calculateWorkingTime() {
// final timers = _formModel.gasRefillTimers ?? [];
// totalWorkingHours = timers.fold<double>(0.0, (sum, item) {
// if (item.startDate == null || item.endDate == null) return sum;
// try {
// final start = DateTime.parse(item.startDate!);
// final end = DateTime.parse(item.endDate!);
// final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours
// return sum + diffInHours;
// } catch (_) {
// return sum;
// }
// });
//
// timerList = timers.map((e) {
// return TimerHistoryModel(
// id: e.id,
// startTime: e.startDate,
// endTime: e.endDate,
// workingHours: e.workingHours,
// );
// }).toList();
}
@override
void setState(VoidCallback fn) {
if (mounted) super.setState(() {});
}
_onSubmit(BuildContext context, int status) async {
bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false;
// if (isTimerPickerEnable) {
// if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) {
// Fluttertoast.showToast(msg: "Working Hours Required");
// return false;
// }
// if (_formModel.gasRefillTimePicker == null) {
// if (_formModel.timer?.startAt == null) {
// Fluttertoast.showToast(msg: "Working Hours Required");
// return false;
// }
// if (_formModel.timer?.endAt == null) {
// Fluttertoast.showToast(msg: "Please Stop The Timer");
// return false;
// }
// }
// } else {
// if (_formModel.timer?.startAt == null) {
// Fluttertoast.showToast(msg: "Working Hours Required");
// return false;
// }
// if (_formModel.timer?.endAt == null) {
// Fluttertoast.showToast(msg: "Please Stop The Timer");
// return false;
// }
// }
//
// if (_currentDetails.deliverdQty == null) {
// await Fluttertoast.showToast(msg: "Delivered Quantity is Required");
// return false;
// }
// _formModel.gasRefillDetails = [];
// _formModel.gasRefillDetails?.add(_currentDetails);
//
// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
// _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? [];
// if (_formModel.gasRefillTimePicker != null) {
// int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds;
// _formModel.gasRefillTimers?.add(
// GasRefillTimer(
// id: 0,
// startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null
// endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null
// workingHours: ((durationInSecond) / 60 / 60),
// ),
// );
// }
// _formModel.timerModelList?.forEach((timer) {
// int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
// _formModel.gasRefillTimers?.add(
// GasRefillTimer(
// id: 0,
// startDate: timer.startAt!.toIso8601String(), // Handle potential null
// endDate: timer.endAt?.toIso8601String(), // Handle potential null
// workingHours: ((durationInSecond) / 60 / 60),
// ),
// );
// });
// _formModel.gasRefillAttachments = [];
// for (var item in _attachments) {
// String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??'';
// _formModel.gasRefillAttachments?.add(GasRefillAttachments(
// id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName));
// }
// await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) {
// Navigator.pop(context);
// if (success) {
// if (status == 1) {
// AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
// // when click complete then this request remove from the list and status changes to closed..
// _gasRefillProvider?.reset();
// allRequestsProvider.getAllRequests(context, typeTransaction: 2);
// }
// Navigator.pop(context);
// }
// });
}
@override
void dispose() {
_commentController.dispose();
_workingHoursController.dispose();
super.dispose();
}
void updateTimer({TimerModel? timer}) {
// _formModel.timer = timer;
// if (timer?.startAt != null && timer?.endAt != null) {
// _formModel.timerModelList = _formModel.timerModelList ?? [];
// _formModel.timerModelList!.add(timer!);
// }
// notifyListeners();
}
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
if (_firstTime) {
String? clientName;
// if (widget.gasRefillModel != null) {
// _gasRefillProvider!.expectedDateTime = DateTime.tryParse(_formModel.expectedDate ?? "");
// _formModel.timer = TimerModel(startAt: DateTime.tryParse(widget.gasRefillModel?.startDate ?? ""), endAt: DateTime.tryParse(widget.gasRefillModel?.endDate ?? ""));
// } else {
// _formModel.timer = null;
// }
}
return Scaffold(
appBar: DefaultAppBar(
title: 'Update Information'.addTranslation,
onWillPopScope: () {
_onSubmit(context, 0);
},
),
key: _scaffoldKey,
body: Form(
key: _formKey,
child: LoadingManager(
isLoading: _isLoading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
8.height,
AppTextFormField(
labelText: 'Debrief'.addTranslation,
textInputType: TextInputType.multiline,
hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
alignLabelWithHint: true,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
controller: _commentController,
onChange: (value) {},
onSaved: (value) {},
),
8.height,
_timerWidget(context, totalWorkingHours),
16.height,
AttachmentPicker(
label: context.translation.attachFiles,
attachment: _attachments,
buttonColor: AppColor.primary10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(
color: AppColor.primary10,
),
),
8.height,
],
).toShadowContainer(context),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
AppFilledButton(
label: context.translation.save,
buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60,
textColor: context.isDark ? AppColor.white10 : AppColor.black10,
onPressed: () => _onSubmit(context, 0),
).expanded,
12.width,
AppFilledButton(
label: context.translation.complete,
buttonColor: AppColor.primary10,
onPressed: () => _onSubmit(context, 1),
).expanded,
],
),
),
],
)),
),
).handlePopScope(
cxt: context,
onSave: () {
_onSubmit(context, 0);
});
}
Widget _timerWidget(BuildContext context, double totalWorkingHours) {
TimerModel? timer = TimerModel();
TimerModel? timerPicker;
List<TimerModel>? timerModelList = [];
return Column(
mainAxisSize: MainAxisSize.min,
children: [
AppTimer(
label: context.translation.workingHours,
timer: timer,
// pickerFromDate: DateTime.tryParse(widget.gasRefillModel?.createdDate ?? ''),
pickerFromDate: DateTime.tryParse(''),
pickerTimer: timerPicker,
onPick: (time) {
//timerPicker = time;
},
width: double.infinity,
decoration: BoxDecoration(
color: AppColor.fieldBgColor(context),
// color: AppColor.neutral100,
borderRadius: BorderRadius.circular(10),
),
timerProgress: (isRunning) {},
onChange: (timer) async {
updateTimer(timer: timer);
return true;
},
),
if (totalWorkingHours > 0.0) ...[
12.height,
WorkingTimeTile(
timerList: timerList,
totalWorkingTime: totalWorkingHours,
),
],
],
);
}
}

@ -0,0 +1,34 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
class InternalAuditFindingTypeProvider extends LoadingListNotifier<Lookup> {
@override
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();
Response response;
try {
response = await ApiManager.instance.get(URLs.getPentryTaskStatus);
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List listJson = json.decode(response.body)["data"];
items = listJson.map((department) => Lookup.fromJson(department)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
}
}

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
@ -7,6 +9,8 @@ import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart';
import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart';
import 'package:test_sa/modules/traf_module/create_traf_request_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@ -90,8 +94,11 @@ class CreateRequestModel {
static List<CreateRequestModel> requestsList(BuildContext context) {
List<CreateRequestModel> list = [];
if (context.userProvider.isAssessor) {
log('user type is ${context.userProvider.isQualityUser}');
if (context.userProvider.isQualityUser) {
list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id));
list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id));
} else if (context.userProvider.isAssessor) {
list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id));
} else if (context.userProvider.isEngineer) {
if (Provider.of<SettingProvider>(context, listen: false).engineerCanCreateCM) {

@ -70,6 +70,7 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
if (isEngineer) {
types[context.translation.recurrentWo] = 5;
types["Internal Audit".addTranslation] = 10;
}
if (context.settingProvider.isUserFlowMedical) {
@ -79,8 +80,11 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
if (!isEngineer) {
types['TRAF'] = 9;
}
if (context.userProvider.isAssessor) {
types = {"TRAF": 9};
}if (context.userProvider.isQualityUser) {
types = {"Internal Audit": 10};
}
final statuses = {

@ -1,5 +1,7 @@
//request main page
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
@ -40,9 +42,11 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
Request(2, context.translation.gasRefill),
Request(3, context.translation.transferAsset),
Request(4, context.translation.preventiveMaintenance),
];
if (Provider.of<UserProvider>(context, listen: false).user!.type != UsersTypes.normal_user) {
requestsList.add(Request(5, context.translation.recurrentWo));
}
//TODO unCommit this to enable task
requestsList.add(Request(6, context.translation.taskRequest));
@ -53,6 +57,11 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
if (context.userProvider.user!.type == UsersTypes.normal_user) {
requestsList.add(Request(9, 'TRAF'));
}
if (context.userProvider.isEngineer) {
//TODO need to replace with actual number.
// requestsList.add(Request(10, 'Internal Audit'));
requestsList.add(Request(1, 'Internal Audit'));
}
if (context.userProvider.isAssessor) {
requestsList = [
@ -60,6 +69,15 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
Request(9, 'TRAF'),
];
}
if (context.userProvider.isQualityUser) {
requestsList = [
Request(null, context.translation.allWorkOrder),
//TODO need to replace with actual number.
// Request(10, 'Internal Audit'),
Request(1, 'Internal Audit'),
];
}
_provider = Provider.of<AllRequestsProvider>(context, listen: false);
_provider!.reset();

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@ -46,6 +47,7 @@ class RequestPaginatedListview extends StatelessWidget {
}
Widget _buildRequestItem(Data request) {
//TODO need to replace with switch statement
bool isServiceRequest = request.transactionNo == 1;
bool isGasRefill = request.transactionNo == 2;
bool isAssetTransfer = request.transactionNo == 3;
@ -53,6 +55,7 @@ class RequestPaginatedListview extends StatelessWidget {
bool isRecurrentTask = request.transactionNo == 5;
bool isTask = request.transactionNo == 6;
bool isTRAF = request.transactionNo == 9;
bool isInternalAudit = request.transactionNo == 10;
if (isServiceRequest) {
return ServiceRequestItemView(requestData: request, refreshData: false);
@ -66,9 +69,14 @@ class RequestPaginatedListview extends StatelessWidget {
return RecurrentWoItemView(requestData: request);
} else if (isTask) {
return TaskRequestItemView(requestData: request);
} else if (isTRAF) {
}
else if (isTRAF) {
return TrafRequestItemView(requestData: request);
} else {
}
else if (isInternalAudit) {
return InternalAuditItemView(requestData: request);
}
else {
return Container(
height: 100,
width: double.infinity,

@ -4,6 +4,7 @@ import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_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/modules/internal_audit_module/pages/internal_audit_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart';
@ -29,8 +30,10 @@ class RequestItemViewList extends StatelessWidget {
itemBuilder: (cxt, index) {
if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading);
switch (list[index].transactionType) {
// case 1:
// return ServiceRequestItemView(requestDetails: list[index]);
case 1:
return ServiceRequestItemView(requestDetails: list[index]);
return InternalAuditItemView(requestDetails: list[index]);
case 2:
return GasRefillItemView(requestDetails: list[index]);
case 3:
@ -45,6 +48,9 @@ class RequestItemViewList extends StatelessWidget {
return TaskRequestItemView(requestDetails: list[index]);
case 9:
return TrafRequestItemView(requestDetails: list[index]);
//Need to verify the type No..
case 10:
return InternalAuditItemView(requestDetails: list[index]);
default:
Container(
height: 100,

@ -177,6 +177,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.1"
clipboard:
dependency: "direct main"
description:
name: clipboard
sha256: "1920c0337f8808be4166c5f1b236301ff381ef69633b0757c502d97f1f740102"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
clock:
dependency: transitive
description:

Loading…
Cancel
Save