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.
cloudsolutions-atoms/lib/modules/tm_module/tasks/update_task_request_view.dart

937 lines
36 KiB
Dart

import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.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/helper/utils.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/department.dart';
import 'package:test_sa/models/new_models/floor.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/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/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/providers/task_request_provider/task_job_provider.dart';
import 'package:test_sa/providers/task_request_provider/task_request_provider.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.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/status/report/service_report_assistant_employee_menu.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
import '../../../../models/new_models/site.dart';
import '../../../models/new_models/work_order_detail_model.dart';
class UpdateTaskRequest extends StatefulWidget {
final int taskId;
final String? createdDate;
const UpdateTaskRequest({Key? key, required this.taskId, this.createdDate}) : super(key: key);
@override
State<UpdateTaskRequest> createState() => _UpdateTaskRequestState();
}
class _UpdateTaskRequestState extends State<UpdateTaskRequest> {
TaskRequestProvider? _taskProvider;
final TextEditingController _requestedQuantityController = TextEditingController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
List<GenericAttachmentModel> attachments = [];
List<TaskJobAttachment> otherAttachments = [];
bool installationType = true;
String comments = '';
List<TimerHistoryModel> timerList = [];
double totalWorkingHours = 0;
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
assignData();
});
super.initState();
}
Future<void> assignData() async {
//may need to pass model in class parameters.
_taskProvider = Provider.of<TaskRequestProvider>(context, listen: false);
UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);
TaskData? taskModel = _taskProvider?.taskRequestModel;
_taskProvider?.refresh();
calculateWorkingTime(helperModel: taskModel!);
if (taskModel.taskJobAttachments != null) {
attachments = taskModel.taskJobAttachments!.where((e) => e.createdBy == _userProvider.user?.userID).map((e) => GenericAttachmentModel(id: e.id, name: e.name ?? '')).toList();
otherAttachments = taskModel.taskJobAttachments?.where((e) => e.createdBy != _userProvider.user?.userID).toList() ?? [];
}
}
void calculateWorkingTime({required TaskData helperModel}) {
//we can make a single timer model for all type of request ....
// final helperModel = _taskProvider?.taskRequestModel;
final timers = helperModel.taskJobActivityEngineerTimers ?? [];
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.totalWorkingHour,
);
}).toList();
}
@override
void dispose() {
_requestedQuantityController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<TaskRequestProvider>(builder: (context, taskProvider, child) {
return Scaffold(
appBar: DefaultAppBar(
title: context.translation.taskRequest,
onWillPopScope: () {
_updateTask(context: context, status: 0);
},
),
key: _scaffoldKey,
body: taskProvider.isLoading
? const ALoading()
: taskProvider.taskRequestModel != null
? Form(
key: _formKey,
child: Column(
children: [
SingleChildScrollView(
padding: EdgeInsets.all(12 * AppStyle.getScaleFactor(context)),
child: Column(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_timerWidget(context, true, taskProvider),
8.height,
if (taskProvider.taskRequestModel?.taskType?.isInstallation == true) ...[installationWidget(taskModel: taskProvider.taskRequestModel!)],
if (taskProvider.taskRequestModel?.taskType?.isRecallAndAlert == true) ...[
recallAlertTypeWidget(taskModel: taskProvider.taskRequestModel!),
],
// if (previousComments.isNotEmpty) ...[
// 'Previous Comments'.bodyText2(context).custom(color: AppColor.neutral50),
// 8.height,
buildPreviousComments(taskProvider: taskProvider),
// 8.height,
// ],
AppTextFormField(
initialValue: "",
labelText: context.translation.technicalComment,
textInputType: TextInputType.multiline,
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: TextStyle(color: AppColor.textColor(context)),
showShadow: false,
alignLabelWithHint: true,
onChange: (value) {
comments = value;
setState(() {});
},
onSaved: (value) {},
),
20.height,
AttachmentPicker(
label: context.translation.attachFiles,
attachment: attachments,
buttonColor: AppColor.black10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
),
],
).toShadowContainer(context),
16.height,
TaskRequestAssistantEmployeeList(
assetId: taskProvider.taskRequestModel?.asset?.id,
createdDate: widget.createdDate ?? '',
//widget.requestDetails?.date
assistantEmployeeList: taskProvider.taskRequestModel?.taskJobAssistantEmployees,
cardPadding: 0,
onListChanged: (updatedList) {
setState(() {
taskProvider.taskRequestModel?.taskJobAssistantEmployees = updatedList;
});
},
),
// const AssistantEmployeeCard().toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16)),
],
),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
AppFilledButton(
label: context.translation.save,
buttonColor: AppColor.white60,
textColor: AppColor.black10,
onPressed: () => _updateTask(context: context, status: 0),
).expanded,
12.width,
AppFilledButton(
label: context.translation.complete,
buttonColor: AppColor.primary10,
onPressed: () => _updateTask(context: context, status: 1),
).expanded,
],
),
),
],
),
)
: NoDataFound(message: context.translation.noDataFound).center,
).handlePopScope(
cxt: context,
onSave: () {
_updateTask(context: context, status: 0);
});
});
}
void _updateTask({required BuildContext context, required int status}) async {
TaskRequestProvider taskRequestProvider = Provider.of<TaskRequestProvider>(context, listen: false);
TaskData? taskModel = TaskData.copyWith(taskRequestProvider.taskRequestModel!);
taskModel?.statusValue = status;
// taskModel.taskTimePicker = taskRequestProvider.taskRequestModel?.taskTimePicker;
// taskModel.totalWorkingHours = taskRequestProvider.taskRequestModel?.totalWorkingHours;
// taskModel.taskTimerModel = taskRequestProvider.taskRequestModel?.taskTimerModel;
// taskModel.timerModelList = taskRequestProvider.taskRequestModel?.timerModelList;
if (validate(model: taskModel)) {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
List<TaskJobAttachment> taskAttachment = [];
if (otherAttachments.isNotEmpty) {
taskAttachment.addAll(otherAttachments);
}
for (var item in attachments) {
String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
taskAttachment.add(TaskJobAttachment(id: item.id, name: fileName));
}
taskModel?.taskJobAttachments = taskAttachment;
if (taskModel?.taskTimePicker != null) {
int durationInSecond = taskModel!.taskTimePicker!.endAt!.difference(taskModel.taskTimePicker!.startAt!).inSeconds;
taskModel.taskJobActivityEngineerTimers?.add(
TaskJobActivityEngineerTimer(
id: 0,
startDate: taskModel.taskTimePicker!.startAt!.toIso8601String(),
endDate: taskModel.taskTimePicker!.endAt?.toIso8601String(),
totalWorkingHour: ((durationInSecond) / 60 / 60),
comment: comments,
),
);
}
taskModel?.timerModelList?.forEach((timer) {
int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
taskModel.taskJobActivityEngineerTimers?.add(
TaskJobActivityEngineerTimer (
id: 0, startDate: timer.startAt!.toIso8601String(), endDate: timer.endAt?.toIso8601String(), totalWorkingHour: ((durationInSecond) / 60 / 60), comment: timer.comments ?? comments),
);
});
await taskRequestProvider.updateTaskByEngineer(taskModel).then((success) async {
if (success) {
if (status == 1) {
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
allRequestsProvider.reset();
await allRequestsProvider.getAllRequests(context, typeTransaction: taskRequestProvider.taskRequestModel?.taskType?.id);
Navigator.pop(context);
Navigator.pop(context);
Navigator.pop(context);
} else {
await taskRequestProvider.getTaskById(id: widget.taskId, showLoading: false);
Navigator.pop(context);
Navigator.pop(context);
}
} else {
Navigator.pop(context);
}
});
}
}
Widget installationWidget({required TaskData taskModel}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ADatePicker(
label: context.translation.installationDate,
hideShadow: true,
backgroundColor: AppColor.fieldBgColor(context),
date: DateTime.tryParse(taskModel.installationDate ?? ""),
formatDateWithTime: false,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
// Handle the selected date and time here.
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
taskModel.installationDate = selectedDateTime.toIso8601String();
setState(() {});
}
});
},
),
8.height,
AppTextFormField(
labelText: context.translation.serialNo,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
initialValue: taskModel.serialNo ?? '',
textInputType: TextInputType.text,
onChange: (value) {
taskModel.serialNo = value;
},
),
8.height,
SingleItemDropDownMenu<Site, SiteProvider>(
context: context,
title: 'Installation Site',
initialValue: taskModel.site,
loading: _taskProvider?.isSiteLoading,
showAsBottomSheet: true,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
enabled: false,
onSelect: (value) {
if (value == null) {
return;
}
taskModel.site = value;
taskModel.building = null;
taskModel.floor = null;
taskModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: 'Installation Building',
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
loading: _taskProvider?.isSiteLoading,
showShadow: false,
initialValue: taskModel.building,
enabled: taskModel.site?.buildings?.isNotEmpty ?? false,
staticData: taskModel.site?.buildings ?? [],
onSelect: (value) {
if (value == null) {
return;
}
taskModel.building = value;
taskModel.floor = null;
taskModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.fieldBgColor(context),
loading: _taskProvider?.isSiteLoading,
showShadow: false,
title: 'Installation Floor',
initialValue: taskModel.floor,
enabled: taskModel.building?.floors?.isNotEmpty ?? false,
staticData: taskModel.building?.floors ?? [],
onSelect: (value) {
if (value == null) {
return;
}
taskModel.floor = value;
taskModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: 'Installation Department',
backgroundColor: AppColor.fieldBgColor(context),
loading: _taskProvider?.isSiteLoading,
showAsBottomSheet: true,
showShadow: false,
initialValue: taskModel.department,
enabled: taskModel.floor?.departments?.isNotEmpty ?? false,
staticData: taskModel.floor?.departments ?? [],
onSelect: (value) {
if (value == null) {
return;
}
taskModel.department = value;
taskModel.room = null;
setState(() {});
},
),
8.height,
],
);
}
Widget recallAlertTypeWidget({required TaskData taskModel}) {
Widget userAcknowledgeWidget() {
return Row(
children: [
InkWell(
child: taskModel.isUserAcknowledge == true
? const Icon(
Icons.check_box,
color: AppColor.primary10,
)
: const Icon(
Icons.check_box_outline_blank,
color: AppColor.neutral120,
),
onTap: () {
setState(() {
taskModel.isUserAcknowledge = !taskModel.isUserAcknowledge!;
});
},
),
6.width,
Flexible(
child: context.translation.acknowledge.bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral120),
),
],
);
}
if (taskModel.typeOfAlert != null) {
switch (taskModel.typeOfAlert!.value) {
case 1:
return userAcknowledgeWidget();
case 2:
return Column(
children: [
SingleItemDropDownMenu<Lookup, TaskJobActionNeededProvider>(
context: context,
height: 56.toScreenHeight,
title: context.translation.completedActions,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
enabled: false,
showAsBottomSheet: true,
initialValue: taskModel.actionNeeded,
onSelect: (status) {
//read only ...
},
),
if (taskModel.actionNeeded?.value == 1) ...[
8.height,
SingleItemDropDownMenu<Lookup, TaskJobImpactStatusProvider>(
context: context,
height: 56.toScreenHeight,
title: context.translation.impactStatus,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: taskModel.impactStatus,
onSelect: (status) {
if (status != null) {
taskModel.impactStatus = status;
setState(() {});
}
},
),
8.height,
],
],
);
case 3:
return Column(
children: [
userAcknowledgeWidget(),
8.height,
SingleItemDropDownMenu<Lookup, TaskJobActionNeededProvider>(
context: context,
height: 56.toScreenHeight,
title: context.translation.completedActions,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
enabled: false,
showAsBottomSheet: true,
initialValue: taskModel.actionNeeded,
onSelect: (status) {
//this is read only ...
},
),
8.height,
if (taskModel.actionNeeded?.value == 1) ...[
SingleItemDropDownMenu<Lookup, TaskJobImpactStatusProvider>(
context: context,
height: 56.toScreenHeight,
title: context.translation.impactStatus,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: taskModel.impactStatus,
onSelect: (status) {
if (status != null) {
taskModel.impactStatus = status;
setState(() {});
}
},
)
],
],
);
default:
return const SizedBox();
}
}
return const SizedBox();
}
Widget _timerWidget(BuildContext context, bool isTimerEnable, TaskRequestProvider taskProvider) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppTimer(
label: context.translation.timer,
timer: taskProvider.taskRequestModel?.taskTimerModel,
pickerFromDate: DateTime.tryParse(widget.createdDate ?? ''),
width: double.infinity,
enabled: isTimerEnable,
decoration: BoxDecoration(
color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(10),
),
pickerTimer: taskProvider.taskRequestModel?.taskTimePicker,
onPick: (time) {
taskProvider.taskRequestModel?.taskTimePicker = time;
},
onChange: (timer) async {
taskProvider.updateTaskTimer(timer: timer);
return true;
},
),
if (totalWorkingHours > 0.0) ...[
8.height,
WorkingTimeTile(
timerList: timerList,
totalWorkingTime: totalWorkingHours,
),
],
8.height,
],
);
}
Widget buildPreviousComments({required TaskRequestProvider taskProvider}) {
String previousComments = taskProvider.taskRequestModel?.taskJobActivityEngineerTimers?.map((e) => e.comment?.trim()).where((comment) => comment != null && comment!.isNotEmpty).join('\n') ?? '';
if (previousComments.isNotEmpty) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
8.height,
'Previous Comments'.bodyText2(context).custom(color: AppColor.neutral50),
8.height,
Container(
constraints: BoxConstraints(
maxHeight: 200.toScreenHeight,
),
child: SingleChildScrollView(
child: previousComments.bodyText2(context).custom(color: AppColor.neutral50),
),
).toShadowContainer(showShadow: false, context, backgroundColor: AppColor.neutral90, paddingObject: const EdgeInsets.only(left: 10, right: 20, bottom: 20, top: 10)),
8.height,
],
);
}
return const SizedBox();
}
}
bool validate({TaskData? model}) {
bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false;
if (isTimerPickerEnable) {
if (model?.taskTimerModel?.startAt == null && model?.taskTimePicker == null) {
Fluttertoast.showToast(msg: "Working Hours Required");
return false;
}
if (model?.taskTimePicker == null) {
if (model?.taskTimerModel?.startAt == null) {
Fluttertoast.showToast(msg: "Working Hours Required");
return false;
}
if (model?.taskTimerModel?.endAt == null) {
Fluttertoast.showToast(msg: "Please Stop The Timer");
return false;
}
}
} else {
if (model?.taskTimerModel?.startAt == null) {
Fluttertoast.showToast(msg: "Working Hours Required");
return false;
}
if (model?.taskTimerModel?.endAt == null) {
Fluttertoast.showToast(msg: "Please Stop The Timer");
return false;
}
}
if (model!.taskJobAssistantEmployees?.isNotEmpty ?? false) {
for (int i = 0; i < model.taskJobAssistantEmployees!.length; i++) {
final employee = model.taskJobAssistantEmployees![i];
final position = Utils.getOrdinal(i + 1);
if (employee.user == null) {
Fluttertoast.showToast(
msg: "Please select the $position assistant employee",
);
return false;
}
if (employee.user?.userId != null) {
if (employee.startDate == null) {
Fluttertoast.showToast(
msg: "Please select start time for assistant employee ${employee.user?.userName}",
);
return false;
}
if (employee.endDate == null) {
Fluttertoast.showToast(
msg: "Please select end time for assistant employee ${employee.user?.userName}",
);
return false;
}
}
}
}
return true;
}
class TaskRequestAssistantEmployeeList extends StatefulWidget {
final List<TaskJobAssistantEmployees>? assistantEmployeeList;
final ValueChanged<List<TaskJobAssistantEmployees>>? onListChanged;
final double? cardPadding;
final dynamic assetId;
final String createdDate;
const TaskRequestAssistantEmployeeList({
super.key,
this.assistantEmployeeList,
this.onListChanged,
required this.assetId,
this.cardPadding,
required this.createdDate,
});
@override
State<TaskRequestAssistantEmployeeList> createState() => _TaskRequestAssistantEmployeeListState();
}
class _TaskRequestAssistantEmployeeListState extends State<TaskRequestAssistantEmployeeList> {
late List<TaskJobAssistantEmployees> _list;
late List<TextEditingController> _controllers;
@override
void initState() {
super.initState();
_list = List<TaskJobAssistantEmployees>.from(widget.assistantEmployeeList ?? []);
_controllers = _list.map((e) => TextEditingController(text: e.workingHours?.toString() ?? '')).toList();
}
void _addNewEntry() {
setState(() {
_list.add(TaskJobAssistantEmployees());
_controllers.add(TextEditingController());
});
widget.onListChanged?.call(_list);
}
void _removeEntry(int index) {
setState(() {
_list.removeAt(index);
_controllers.removeAt(index);
});
widget.onListChanged?.call(_list);
}
void _updateModel(int index, void Function(TaskJobAssistantEmployees model) updateList, {bool updateController = false}) {
setState(() {
updateList(_list[index]);
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _list.length + 1,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(widget.cardPadding ?? 16),
itemBuilder: (context, index) {
if (index == _list.length) {
return AppFilledButton(
label: "Add Assistant Employee".addTranslation,
maxWidth: true,
textColor: AppColor.textColor(context),
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: _addNewEntry,
);
}
return EmployeeCard(
model: _list[index],
assetId: widget.assetId,
index: index,
createdDate: widget.createdDate,
// selectedEmployee: selectedEmployee,
onUpdate: (updateList) => _updateModel(index, updateList),
onRemove: () => _removeEntry(index),
workingHoursController: _controllers[index],
);
},
);
}
}
class EmployeeCard extends StatelessWidget {
final TaskJobAssistantEmployees model;
final int index;
final dynamic assetId;
final String? createdDate;
final void Function(void Function(TaskJobAssistantEmployees model)) onUpdate;
final VoidCallback onRemove;
final TextEditingController workingHoursController;
EmployeeCard({
super.key,
required this.model,
required this.assetId,
required this.index,
required this.onUpdate,
this.createdDate,
required this.onRemove,
required this.workingHoursController,
});
// AssistantEmployees selectedEmployee = AssistantEmployees();
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.textColor(context)),
Container(
height: 32,
width: 32,
padding: const EdgeInsets.all(6),
child: "trash".toSvgAsset(height: 20, width: 20),
).onPress(onRemove),
],
),
8.height,
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ServiceReportAssistantEmployeeMenu(
title: context.translation.select,
backgroundColor: AppColor.fieldBgColor(context),
assetId: assetId,
initialValue: model.employee,
onSelect: (employee) {
if (employee != null) {
onUpdate((model) {
model.employee = employee.copyWith(id: 0);
model.user = AssignedEmployee(
userId: employee.user?.id,
userName: employee.user?.name,
);
});
}
},
),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.fieldBgColor(context),
date: model.startDate,
formatDateWithTime: true,
from: DateTime.tryParse(createdDate ?? ''),
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
final selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (createdDate != null && selectedDateTime.isBefore(DateTime.tryParse(createdDate ?? '')!)) {
"Start time is before the request time.".showToast;
return;
}
if (selectedDateTime.isAfter(DateTime.now())) {
"Start time is after the current time".showToast;
return;
}
onUpdate((model) {
model.startDate = selectedDateTime;
CMRequestUtils.calculateAndAssignWorkingHours(
startTime: model.startDate,
endTime: model.endDate,
workingHoursController: workingHoursController,
updateModel: (hours) => model.workingHours = hours,
);
});
}
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.fieldBgColor(context),
date: model.endDate,
formatDateWithTime: true,
from: DateTime.tryParse(createdDate ?? ''),
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
final endDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (!endDateTime.isBefore(DateTime.now())) {
"Please select a time before the current time.".showToast;
return;
}
if (model.startDate == null || !endDateTime.isAfter(model.startDate!)) {
"End date must be after start date".showToast;
return;
}
onUpdate((model) {
model.endDate = endDateTime;
CMRequestUtils.calculateAndAssignWorkingHours(
startTime: model.startDate,
endTime: model.endDate,
workingHoursController: workingHoursController,
updateModel: (hours) => model.workingHours = hours,
);
});
}
});
},
).expanded,
],
),
8.height,
AppTextFormField(
labelText: context.translation.workingHours,
backgroundColor: AppColor.fieldBgColor(context),
controller: workingHoursController,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
textAlign: TextAlign.center,
enable: false,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
initialValue: model.comment,
labelText: context.translation.technicalComment,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: context.isDark ? AppColor.white10 : AppColor.black10),
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) => onUpdate((model) => model.comment = value),
// onSaved: (value) => onUpdate((model) => model.technicalComment = value),
),
8.height,
],
)
],
).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)).paddingOnly(bottom: 12);
}
}