You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
19 KiB
Dart
379 lines
19 KiB
Dart
import 'package:flutter/gestures.dart';
|
|
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/models/all_requests_and_count_model.dart';
|
|
import 'package:test_sa/models/new_models/task_request/task_request_model.dart';
|
|
import 'package:test_sa/modules/cm_module/cm_request_utils.dart';
|
|
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
|
|
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
|
|
import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
|
|
import 'package:test_sa/providers/task_request_provider/task_request_provider.dart';
|
|
import 'package:test_sa/views/widgets/images/files_list.dart';
|
|
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
|
|
import 'package:test_sa/views/widgets/requests/request_status.dart';
|
|
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
|
|
|
|
import '../../../../controllers/providers/api/user_provider.dart';
|
|
import '../../../../models/enums/user_types.dart';
|
|
import '../../../../new_views/app_style/app_color.dart';
|
|
import '../../../../new_views/common_widgets/app_filled_button.dart';
|
|
import 'update_task_request_view.dart';
|
|
|
|
class TaskRequestDetailsView extends StatefulWidget {
|
|
static const String id = "/task-request-detail";
|
|
final int taskId;
|
|
final RequestsDetails? requestDetails;
|
|
|
|
const TaskRequestDetailsView({Key? key, required this.taskId, this.requestDetails}) : super(key: key);
|
|
|
|
@override
|
|
_TaskRequestDetailsViewState createState() {
|
|
return _TaskRequestDetailsViewState();
|
|
}
|
|
}
|
|
|
|
class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
|
|
UserProvider? userProvider;
|
|
|
|
TaskRequestProvider? taskProvider;
|
|
|
|
@override
|
|
void initState() {
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
getTaskData();
|
|
});
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> getTaskData() async {
|
|
taskProvider = Provider.of<TaskRequestProvider>(context, listen: false);
|
|
await taskProvider?.getTaskById(id: widget.taskId);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
userProvider ??= Provider.of<UserProvider>(context, listen: false);
|
|
return Scaffold(
|
|
appBar: DefaultAppBar(title: context.translation.taskRequest),
|
|
body: Consumer<TaskRequestProvider>(builder: (context, taskProvider, child) {
|
|
TaskData? taskModel = taskProvider.taskRequestModel;
|
|
return taskProvider.isLoading
|
|
? const ALoading()
|
|
: Column(children: [
|
|
SingleChildScrollView(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
StatusLabel(
|
|
label: widget.requestDetails?.priority!,
|
|
textColor: AppColor.getRequestStatusTextColorByName(context, widget.requestDetails?.priority!),
|
|
backgroundColor: AppColor.getRequestStatusColorByName(context, widget.requestDetails?.priority!),
|
|
),
|
|
8.width,
|
|
StatusLabel(
|
|
label: widget.requestDetails?.status!,
|
|
textColor: AppColor.getRequestStatusTextColorByName(context, widget.requestDetails?.status!),
|
|
backgroundColor: AppColor.getRequestStatusColorByName(context, widget.requestDetails?.status!),
|
|
),
|
|
1.width.expanded,
|
|
Text(
|
|
widget.requestDetails?.date?.toServiceRequestCardFormat ?? "-",
|
|
textAlign: TextAlign.end,
|
|
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
|
|
),
|
|
],
|
|
),
|
|
8.height,
|
|
if (taskProvider.taskRequestModel?.taskType?.relatedTo?.value == 1) ...[
|
|
assetDetails(taskModel: taskProvider.taskRequestModel!),
|
|
],
|
|
if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) ...[installationWidget(taskModel: taskProvider.taskRequestModel!)],
|
|
if (taskProvider.taskRequestModel?.taskType?.relatedTo?.value == 2) ...[
|
|
linkWithLocationWidget(taskModel: taskProvider.taskRequestModel!),
|
|
],
|
|
const Divider().defaultStyle(context),
|
|
Text(
|
|
"Task Details".addTranslation,
|
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
|
),
|
|
'${context.translation.taskType}: ${taskModel?.taskType?.typeName ?? "-"}'.bodyText(context),
|
|
'${context.translation.taskNo}: ${taskModel?.taskJobNo ?? "-"}'.bodyText(context),
|
|
'${context.translation.createdBy}: ${taskModel?.userCreated?.userName ?? "-"}'.bodyText(context),
|
|
if (taskProvider.taskRequestModel?.taskType?.isRecallAndAlert == true) ...[
|
|
recallAlertTypeWidget(taskModel: taskProvider.taskRequestModel!),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
'Type of alert: ${taskProvider.taskRequestModel?.typeOfAlert?.name ?? '-'}'.bodyText(context),
|
|
'Risk Level: ${taskProvider.taskRequestModel?.riskLevel?.name ?? '-'}'.bodyText(context),
|
|
'Resource: ${taskProvider.taskRequestModel?.resource?.name ?? '-'}'.bodyText(context),
|
|
'Evaluator User: ${taskProvider.taskRequestModel?.evaluatorUser?.userName ?? '-'}'.bodyText(context)
|
|
],
|
|
),
|
|
],
|
|
showWorkingTime(taskModel?.taskJobActivityEngineerTimers ?? []),
|
|
if ((taskProvider.taskRequestModel?.taskJobContactPersons ?? []).isNotEmpty) ...[contactInfoCard(context, taskProvider.taskRequestModel!)],
|
|
if (taskProvider.taskRequestModel?.callComment != null) ...[
|
|
const Divider().defaultStyle(context),
|
|
Text(
|
|
context.translation.comment,
|
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
|
),
|
|
2.height,
|
|
taskProvider.taskRequestModel!.callComment!.bodyText(context),
|
|
],
|
|
if (taskProvider.taskRequestModel?.taskJobAttachments?.isNotEmpty ?? false) ...[
|
|
8.height,
|
|
const Divider().defaultStyle(context),
|
|
Text(
|
|
"Attachments".addTranslation,
|
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
|
),
|
|
FilesList(images: taskProvider.taskRequestModel!.taskJobAttachments!.map((toElement) => URLs.getFileUrl(toElement.name ?? '') ?? '').toList()),
|
|
],
|
|
buildTechnicalComments(taskModel: taskModel),
|
|
],
|
|
).toShadowContainer(context).paddingAll(16),
|
|
).expanded,
|
|
if (userProvider!.user!.type == UsersTypes.engineer && (taskModel?.taskJobStatus?.value != 4 && taskModel?.taskJobStatus?.value != 3))
|
|
FooterActionButton.footerContainer(
|
|
context: context,
|
|
child: AppFilledButton(
|
|
onPressed: () async {
|
|
if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) {
|
|
taskProvider.getSiteData(siteId: taskProvider.taskRequestModel?.asset?.siteId);
|
|
}
|
|
Navigator.of(context).push(MaterialPageRoute(
|
|
builder: (_) => UpdateTaskRequest(
|
|
taskId: widget.taskId,
|
|
createdDate: widget.requestDetails?.date,
|
|
)));
|
|
},
|
|
label: context.translation.updateRequest,
|
|
),
|
|
)
|
|
]);
|
|
}),
|
|
);
|
|
}
|
|
|
|
Widget showWorkingTime(List<TaskJobActivityEngineerTimer> timer) {
|
|
if (context.userProvider.user!.type == UsersTypes.normal_user) return const SizedBox();
|
|
|
|
double totalWorkingHours = timer.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;
|
|
}
|
|
});
|
|
String totalHourString = (totalWorkingHours > 0.0) ? CMRequestUtils.formatTotalWorkingHours(totalWorkingHours) : totalWorkingHours.toString();
|
|
|
|
return RichText(
|
|
text: TextSpan(
|
|
text: "${context.translation.totalWorkingTime}: ",
|
|
style: TextStyle(
|
|
fontSize: 14.toScreenWidth, fontWeight: FontWeight.w500, fontStyle: FontStyle.normal, decoration: TextDecoration.none, color: context.isDark ? AppColor.neutral10 : AppColor.neutral20),
|
|
children: [
|
|
TextSpan(text: "$totalHourString ", style: AppTextStyles.bodyText),
|
|
const WidgetSpan(
|
|
child: Icon(Icons.info_outline_rounded, color: AppColor.primary10, size: 14),
|
|
),
|
|
],
|
|
),
|
|
).onPress(() => showModalBottomSheet(
|
|
context: context,
|
|
isDismissible: true,
|
|
shape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
|
),
|
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
|
builder: (BuildContext context) => TotalWorkingTimeDetailBottomSheet(
|
|
timerList: timer.map((e) {
|
|
return TimerHistoryModel(
|
|
id: e.id,
|
|
startTime: e.startDate,
|
|
endTime: e.endDate,
|
|
workingHours: e.totalWorkingHour,
|
|
);
|
|
}).toList()),
|
|
));
|
|
}
|
|
|
|
Widget contactInfoCard(BuildContext context, TaskData? taskModel) {
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
8.height,
|
|
const Divider().defaultStyle(context),
|
|
Text(
|
|
"Contact Info",
|
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
|
),
|
|
// 8.height,
|
|
ListView.separated(
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
shrinkWrap: true,
|
|
padding: EdgeInsets.zero,
|
|
itemBuilder: (cxt, index) => Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
'${context.translation.name}: ${taskModel.taskJobContactPersons?[index].user?.userName ?? '-'}'.bodyText(context),
|
|
'${context.translation.employeeId}: ${taskModel.taskJobContactPersons?[index].user?.employeeId ?? '-'}'.bodyText(context),
|
|
'${context.translation.telephone}: ${taskModel.taskJobContactPersons?[index].user?.phoneNumber ?? '-'}'.bodyText(context),
|
|
'${context.translation.email}: ${taskModel.taskJobContactPersons?[index].user?.email ?? '-'}'.bodyText(context),
|
|
'Extension: ${taskModel.taskJobContactPersons?[index].user?.extensionNo ?? '-'}'.bodyText(context),
|
|
],
|
|
),
|
|
separatorBuilder: (cxt, index) => const Divider().defaultStyle(context),
|
|
itemCount: taskModel!.taskJobContactPersons!.length),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget installationWidget({required TaskData taskModel}) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Divider().defaultStyle(context),
|
|
Text(
|
|
"Site Details".addTranslation,
|
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
|
),
|
|
'${context.translation.installationSite}: ${taskModel.asset?.siteName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}'.bodyText(context),
|
|
'${context.translation.installationBuilding}: ${taskModel.installationBuilding?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? '-'}'.bodyText(context),
|
|
'${context.translation.installationFloor}: ${taskModel.installationFloor?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? '-'}'.bodyText(context),
|
|
'${context.translation.installationDepartment}: ${taskModel.installationDepartment?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? '-'}'.bodyText(context),
|
|
'${context.translation.installationDate}: ${taskModel.installationDate?.toAssetDetailsFormat ?? "-"}'.bodyText(context),
|
|
'${context.translation.serialNo}: ${taskModel.serialNo ?? '-'}'.bodyText(context),
|
|
// const Divider().defaultStyle(context),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget buildTechnicalComments({TaskData? taskModel}) {
|
|
String previousComments = taskModel?.taskJobActivityEngineerTimers?.map((e) => e.comment?.trim()).where((comment) => comment != null && comment.isNotEmpty).join('\n') ?? '';
|
|
if (previousComments.isNotEmpty) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Divider().defaultStyle(context),
|
|
Text(
|
|
"Technical Comments".addTranslation,
|
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
|
),
|
|
previousComments.bodyText2(context).custom(color: AppColor.neutral50),
|
|
8.height,
|
|
],
|
|
);
|
|
}
|
|
return const SizedBox();
|
|
}
|
|
|
|
Widget linkWithLocationWidget({required TaskData taskModel}) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
"Location Details".addTranslation,
|
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
|
),
|
|
'${context.translation.site}: ${taskModel.site?.name ?? "-"}'.bodyText(context),
|
|
'${context.translation.building}: ${taskModel.building?.name ?? "-"}'.bodyText(context),
|
|
'${context.translation.floor}: ${taskModel.floor?.name ?? "-"}'.bodyText(context),
|
|
'${context.translation.department}: ${taskModel.department?.name ?? "-"}'.bodyText(context),
|
|
'${context.translation.room}: ${taskModel.room?.name ?? "-"}'.bodyText(context),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget assetDetails({required TaskData taskModel}) {
|
|
return taskModel.asset != null
|
|
? Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
context.translation.assetDetails,
|
|
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
|
|
),
|
|
'${context.translation.assetName}: ${taskModel.asset?.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}'.bodyText(context),
|
|
'${context.translation.assetNo}: ${taskModel.asset?.assetNumber ?? "-"}'.bodyText(context),
|
|
'${context.translation.manufacture}: ${taskModel.asset?.manufacturer ?? "-"}'.bodyText(context),
|
|
'${context.translation.model}: ${taskModel.asset?.model ?? "-"}'.bodyText(context),
|
|
'${context.translation.serialNo}: ${taskModel.asset?.serialNo ?? "-"}'.bodyText(context),
|
|
'${context.translation.assetType}: ${taskModel.asset?.assetTypeName ?? "-"}'.bodyText(context),
|
|
'${context.translation.site}: ${taskModel.asset?.siteName ?? "-"}'.bodyText(context),
|
|
'${context.translation.building}: ${taskModel.asset?.buildingName ?? "-"}'.bodyText(context),
|
|
'${context.translation.floor}: ${taskModel.asset?.floorName ?? "-"}'.bodyText(context),
|
|
'${context.translation.department}: ${taskModel.asset?.departmentName ?? "-"}'.bodyText(context),
|
|
'${context.translation.room}: ${taskModel.asset?.roomName ?? "-"}'.bodyText(context),
|
|
'${context.translation.supplier}: ${taskModel.asset?.supplierName ?? "-"}'.bodyText(context),
|
|
'PO Number: ${taskModel.asset?.poNumber ?? "-"}'.bodyText(context),
|
|
'${context.translation.installationDate}: ${taskModel.asset?.installationDate?.toAssetDetailsFormat ?? "-"}'.bodyText(context),
|
|
],
|
|
)
|
|
: const SizedBox();
|
|
}
|
|
|
|
Widget recallAlertTypeWidget({required TaskData taskModel}) {
|
|
if (taskModel.typeOfAlert != null) {
|
|
switch (taskModel.typeOfAlert!.value) {
|
|
case 1:
|
|
return '${context.translation.acknowledge}: ${taskModel.isUserAcknowledge ?? "-"}'.bodyText(context);
|
|
case 2:
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// assetDetails(taskModel: taskModel),
|
|
'${context.translation.completedActions}: ${taskModel.actionNeeded?.name ?? "-"}'.bodyText(context),
|
|
if (taskModel.actionNeeded?.value == 1) ...[
|
|
'${context.translation.impactStatus}: ${taskModel.impactStatus?.name ?? "-"}'.bodyText(context),
|
|
],
|
|
],
|
|
);
|
|
|
|
case 3:
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// assetDetails(taskModel: taskModel),
|
|
'${context.translation.acknowledge}: ${taskModel.isUserAcknowledge ?? "-"}'.bodyText(context),
|
|
'${context.translation.completedActions}: ${taskModel.actionNeeded?.name ?? "-"}'.bodyText(context),
|
|
if (taskModel.actionNeeded?.value == 1) ...[
|
|
'${context.translation.impactStatus}: ${taskModel.impactStatus?.name ?? "-"}'.bodyText(context),
|
|
],
|
|
],
|
|
);
|
|
default:
|
|
return const SizedBox();
|
|
}
|
|
}
|
|
return const SizedBox();
|
|
}
|
|
}
|