maintenance request flow in progress

design_3.0_latest
muhammad.abbasi 1 year ago
parent b04cd1e042
commit 0095facdf5

@ -48,10 +48,13 @@ class URLs {
static get engineerUpdateWorkOrderUrl=> '$_baseUrl/ServiceRequest/EngineerUpdateWorkOrder'; static get engineerUpdateWorkOrderUrl=> '$_baseUrl/ServiceRequest/EngineerUpdateWorkOrder';
static get getWorkOrderByIdUrl=> '$_baseUrl/ServiceRequest/GetWorkOrderById'; static get getWorkOrderByIdUrl=> '$_baseUrl/ServiceRequest/GetWorkOrderById';
static get deleteActivitySparePartUrl=> '$_baseUrl/ServiceRequest/DeleteActivitySparePart'; static get deleteActivitySparePartUrl=> '$_baseUrl/ServiceRequest/DeleteActivitySparePart';
static get deleteActivityMaintenanceUrl=> '$_baseUrl/ServiceRequest/DeleteActivityMaintenance';
static get createActivitySparePartUrl=> '$_baseUrl/ServiceRequest/CreateActivitySparePart'; static get createActivitySparePartUrl=> '$_baseUrl/ServiceRequest/CreateActivitySparePart';
static get createActivityMaintenanceUrl=> '$_baseUrl/ServiceRequest/CreateActivityMaintenance';
static get createActivityAssetToBeRetiredUrl=> '$_baseUrl/ServiceRequest/CreateActivityAssetToBeRetired'; static get createActivityAssetToBeRetiredUrl=> '$_baseUrl/ServiceRequest/CreateActivityAssetToBeRetired';
static get createWorkOrderUrl=> '$_baseUrl/ServiceRequest/CreateWorkOrder'; static get createWorkOrderUrl=> '$_baseUrl/ServiceRequest/CreateWorkOrder';
static get updateActivitySparePartUrl=> '$_baseUrl/ServiceRequest/UpdateActivitySparePart'; static get updateActivitySparePartUrl=> '$_baseUrl/ServiceRequest/UpdateActivitySparePart';
static get updateActivityMaintenanceUrl=> '$_baseUrl/ServiceRequest/UpdateActivityMaintenance';
static get assignEngineerToWorkOrderUrl=> '$_baseUrl/ServiceRequest/AssignEngineerToWorkOrder'; static get assignEngineerToWorkOrderUrl=> '$_baseUrl/ServiceRequest/AssignEngineerToWorkOrder';
static get getArrivalVerificationTypeUrl=> '$_baseUrl/ArrivalVerificationType/GetArrivalVerificationType'; static get getArrivalVerificationTypeUrl=> '$_baseUrl/ArrivalVerificationType/GetArrivalVerificationType';
static get sendOtpUrl=> '$_baseUrl/SmsNotification/SendOTP/'; static get sendOtpUrl=> '$_baseUrl/SmsNotification/SendOTP/';

@ -79,9 +79,9 @@ extension WidgetExtensions on Widget {
).toShadowContainer(context) ).toShadowContainer(context)
: this; : this;
Widget toShadowContainer(BuildContext context, {bool showShadow = true,Color? backgroundColor, double padding = 16}) => showShadow Widget toShadowContainer(BuildContext context, {bool showShadow = true,Color? backgroundColor, double padding = 16,EdgeInsets ?paddingValue}) => showShadow
? Container( ? Container(
padding: EdgeInsets.all(padding), padding:paddingValue?? EdgeInsets.all(padding),
width: double.infinity, width: double.infinity,
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: backgroundColor?? AppColor.background(context), color: backgroundColor?? AppColor.background(context),

@ -0,0 +1,93 @@
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/new_models/assigned_employee.dart';
class ActivityMaintenanceHelperModel {
int? workOrderId;
int? lastSituationId;
Lookup? activityStatus;
DateTime? startTime;
DateTime? endTime;
int? workingHour;
int? travelHours;
Lookup? repairLocation;
String? assignedEmployeeId;
String? technicalComment;
int? supplierId;
int? supplierEngineerId;
DateTime? supplierStartTime;
DateTime? supplierEndTime;
int? supplierWorkingHour;
AssignedEmployee? assignedEmployee;
List<AssistantEmployees>? assistantEmployees;
ActivityMaintenanceHelperModel(
{this.workOrderId,
this.lastSituationId,
this.startTime,
this.endTime,
this.workingHour,
this.travelHours,
this.repairLocation,
this.assignedEmployeeId,
this.technicalComment,
this.supplierId,
this.supplierEngineerId,
this.supplierStartTime,
this.supplierEndTime,
this.supplierWorkingHour,
this.assignedEmployee,
this.assistantEmployees});
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['workOrderId'] = workOrderId;
data['lastSituationId'] = lastSituationId;
data['activityStatusId'] = activityStatus?.id;
data['startTime'] = startTime?.toIso8601String();
data['endTime'] = endTime?.toIso8601String();
data['workingHour'] = workingHour;
data['travelHours'] = travelHours;
data['repairLocationId'] = repairLocation?.id;
data['assignedEmployeeId'] = assignedEmployeeId;
data['technicalComment'] = technicalComment;
data['supplierId'] = supplierId;
data['supplierEngineerId'] = supplierEngineerId;
data['supplierStartTime'] = supplierStartTime?.toIso8601String();
data['supplierEndTime'] = supplierEndTime?.toIso8601String();
data['supplierWorkingHour'] = supplierWorkingHour;
if (assistantEmployees != null) {
data['assistantEmployees'] =
assistantEmployees!.map((v) => v.toJson()).toList();
}
return data;
}
}
class AssistantEmployees {
int? id;
String? userId;
DateTime? startDate;
DateTime? endDate;
int? workingHours;
String? technicalComment;
AssistantEmployees(
{this.id,
this.userId,
this.startDate,
this.endDate,
this.workingHours,
this.technicalComment});
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['userId'] = userId;
data['startDate'] = startDate?.toIso8601String();
data['endDate'] = endDate?.toIso8601String();
data['workingHours'] = workingHours;
data['technicalComment'] = technicalComment;
return data;
}
}

@ -1,16 +1,35 @@
import 'package:test_sa/models/base.dart'; import 'package:test_sa/models/base.dart';
import 'package:test_sa/models/new_models/assigned_employee.dart'; import 'package:test_sa/models/new_models/assigned_employee.dart';
// int? id;
// String? userId;
// DateTime? startDate;
// DateTime? endDate;
// int? workingHours;
// String? technicalComment;
class AssistantEmployees extends Base { class AssistantEmployees extends Base {
String? userId;
DateTime? startDate;
DateTime? endDate;
int? workingHours;
String? technicalComment;
AssistantEmployees({ AssistantEmployees({
this.id, this.id,
this.user, this.user,
this.startDate,
this.technicalComment,
this.workingHours,
this.endDate,
this.userId,
}) : super(name: user?.name, identifier: user?.id); }) : super(name: user?.name, identifier: user?.id);
AssistantEmployees.fromJson(dynamic json) { AssistantEmployees.fromJson(dynamic json) {
id = json['id']; id = json['id'];
user = json['user'] != null ? AssignedEmployee.fromJson(json['user']) : null; user = json['user'] != null ? AssignedEmployee.fromJson(json['user']) : null;
name = user?.name; name = user?.name;
userId = user?.id;
identifier = user?.id; identifier = user?.id;
} }

@ -53,10 +53,9 @@ class _SingleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier
if (X != NullableLoadingProvider) { if (X != NullableLoadingProvider) {
provider = Provider.of<X>(widget.context, listen: false); provider = Provider.of<X>(widget.context, listen: false);
} }
print('initial value i got is ${widget.initialValue?.identifier}');
if (widget.initialValue != null) { if (widget.initialValue != null) {
final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier); final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
print('result value i got is ${result?.length}');
if (result?.isNotEmpty ?? false) _selectedItem = result!.first as T?; if (result?.isNotEmpty ?? false) _selectedItem = result!.first as T?;
if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) { if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) {
widget.onSelect!(_selectedItem); // Non-null assertion after null check widget.onSelect!(_selectedItem); // Non-null assertion after null check
@ -72,7 +71,6 @@ class _SingleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier
@override @override
void didUpdateWidget(covariant SingleItemDropDownMenu<T, X> oldWidget) { void didUpdateWidget(covariant SingleItemDropDownMenu<T, X> oldWidget) {
if (widget.initialValue != null) { if (widget.initialValue != null) {
final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier); final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
if (result?.isNotEmpty ?? false) { if (result?.isNotEmpty ?? false) {

@ -16,6 +16,7 @@ class ActivityStatusProvider extends LoadingListNotifier<Lookup> {
notifyListeners(); notifyListeners();
try { try {
Response response = await ApiManager.instance.get(URLs.getServiceReportActivityStatus); Response response = await ApiManager.instance.get(URLs.getServiceReportActivityStatus);
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
List categoriesListJson = json.decode(response.body)["data"]; List categoriesListJson = json.decode(response.body)["data"];

@ -7,6 +7,7 @@ import 'package:http/src/response.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/helper_data_models/asset_retired/asset_retired_model.dart'; import 'package:test_sa/models/helper_data_models/asset_retired/asset_retired_model.dart';
import 'package:test_sa/models/helper_data_models/maintenance_request/activity_maintenance_model.dart';
import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart';
import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart';
import 'package:test_sa/models/new_models/arrival_verification_type_model.dart'; import 'package:test_sa/models/new_models/arrival_verification_type_model.dart';
@ -64,6 +65,7 @@ class RequestDetailProvider extends ChangeNotifier {
//UI models //UI models
WorkOrderDetail? currentWorkOrder; WorkOrderDetail? currentWorkOrder;
AssetRetiredHelperModel? assetRetiredHelperModel=AssetRetiredHelperModel(); AssetRetiredHelperModel? assetRetiredHelperModel=AssetRetiredHelperModel();
ActivityMaintenanceHelperModel? activityMaintenanceHelperModel=ActivityMaintenanceHelperModel();
SparePartHelperModel? sparePartHelperModel; SparePartHelperModel? sparePartHelperModel;
FixRemotelyHelperModel? fixRemotelyHelperModel=FixRemotelyHelperModel(); FixRemotelyHelperModel? fixRemotelyHelperModel=FixRemotelyHelperModel();
NeedVisitHelperModel? needVisitHelperModel=NeedVisitHelperModel(); NeedVisitHelperModel? needVisitHelperModel=NeedVisitHelperModel();
@ -76,6 +78,10 @@ class RequestDetailProvider extends ChangeNotifier {
assetRetiredHelperModel = value; assetRetiredHelperModel = value;
notifyListeners(); notifyListeners();
} }
void updateActivityMaintenanceHelperModel(ActivityMaintenanceHelperModel? value) {
activityMaintenanceHelperModel = value;
notifyListeners();
}
void updateSparePartHelperModel(SparePartHelperModel? value) { void updateSparePartHelperModel(SparePartHelperModel? value) {
sparePartHelperModel = value; sparePartHelperModel = value;
@ -510,6 +516,34 @@ class RequestDetailProvider extends ChangeNotifier {
return -1; return -1;
} }
} }
Future<int> deleteActivityMaintenance({required int id, required int workOrderId}) async {
isLoading = true;
var body = {
'id': id,
'workOrderId': workOrderId,
};
try {
//TODO replace with delete model...
final response = await ApiManager.instance.post(
URLs.deleteActivityMaintenanceUrl,
body: body,
);
stateCode = response.statusCode;
print('response of delete activity spare part is ${response.statusCode}');
if (response.statusCode >= 200 && response.statusCode < 300) {
//map to the model...
notifyListeners();
}
isLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
notifyListeners();
return -1;
}
}
Future<int> createActivitySparePart() async { Future<int> createActivitySparePart() async {
isLoading = true; isLoading = true;
@ -533,6 +567,28 @@ class RequestDetailProvider extends ChangeNotifier {
return -1; return -1;
} }
} }
Future<int> createActivityMaintenanceRequest() async {
isLoading = true;
try {
final response = await ApiManager.instance.post(
URLs.createActivityMaintenanceUrl,
body: activityMaintenanceHelperModel!.toJson(),
);
stateCode = response.statusCode;
print('add maintenance activity response i got is ${response.body}');
if (response.statusCode >= 200 && response.statusCode < 300) {
notifyListeners();
}
isLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
notifyListeners();
return -1;
}
}
//create asset retired request.. //create asset retired request..
Future<int> createActivityAssetToBeRetired() async { Future<int> createActivityAssetToBeRetired() async {
isLoading = true; isLoading = true;

@ -0,0 +1,212 @@
import 'package:expansion_tile_card/expansion_tile_card.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/asset_transfer_provider.dart';
import 'package:test_sa/dashboard_latest/widgets/app_bar_widget.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/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/service_request_latest/request_detail_provider.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart';
class AssistantEmployeeCard extends StatefulWidget {
const AssistantEmployeeCard({super.key});
@override
State<AssistantEmployeeCard> createState() => _AssistantEmployeeCardState();
}
class _AssistantEmployeeCardState extends State<AssistantEmployeeCard> {
final GlobalKey<ExpansionTileCardState> cardA = GlobalKey();
bool status = false;
final TextEditingController _workingHoursController = TextEditingController();
@override
void initState() {
// TODO: implement initState
WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData();
});
super.initState();
}
Future<void> getInitialData() async {
}
@override
void dispose() {
// TODO: implement dispose
_workingHoursController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<RequestDetailProvider>(builder: (context, requestDetailProvider, child) {
return ExpansionTileCard(
key: cardA,
initialElevation: 0,
borderRadius: BorderRadius.zero,
expandedTextColor: AppColor.black20,
shadowColor: AppColor.white10,
baseColor: AppColor.white10,
contentPadding: EdgeInsets.zero,
expandedColor: AppColor.white10,
duration: Duration.zero,
elevation: 0,
title:context.translation.assistantEmployee.bodyText(context).custom(color: AppColor.black20),
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// ServiceReportAssistantEmployeeMenu(
// title: context.translation.assignAssistant,
// assetId: widget.workOrder!.callRequest!.asset!.id!.toInt(),
//
// initialValue: (_subWorkOrders.assistantEmployees?.isNotEmpty ?? false) ? _subWorkOrders.assistantEmployees?.first : null,
// // initialValue: !isCurrentAssigned
// // ? (widget.workOrder.assistantEmployees?.first)
// // : (_subWorkOrders.assistantEmployees?.isNotEmpty ?? false)
// // ? _subWorkOrders.assistantEmployees?.first
// // : null,
// enable: !isCurrentUserIsAssistantEmp,
// onSelect: (employee) {
// if (employee == null) {
// _subWorkOrders.assistantEmployees = [];
// } else {
// _subWorkOrders.assistantEmployees = [employee.copyWith(id: 0)];
// }
// },
// ),
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: requestDetailProvider.activityMaintenanceHelperModel?.startTime,
formatDateWithTime: true,
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,
);
requestDetailProvider.activityMaintenanceHelperModel?.startTime = selectedDateTime;
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
assignWorkingHours(requestDetailProvider: requestDetailProvider);
}
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: requestDetailProvider.activityMaintenanceHelperModel?.endTime,
formatDateWithTime: true,
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,
);
if (requestDetailProvider.activityMaintenanceHelperModel!.startTime!=null&&selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.startTime!)) {
"End Date time must be greater then start date".showToast;
return;
}
requestDetailProvider.activityMaintenanceHelperModel?.endTime = selectedDateTime;
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
assignWorkingHours(requestDetailProvider: requestDetailProvider);
}
});
},
).expanded,
],
),
8.height,
AppTextFormField(
labelText: context.translation.workingHours,
backgroundColor: AppColor.neutral80,
controller: _workingHoursController,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.workingHour.toString(),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
enable: false,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.technicalComment,
labelText: context.translation.technicalComment,
backgroundColor: AppColor.neutral100,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value){
requestDetailProvider.activityMaintenanceHelperModel?.technicalComment = value;
},
onSaved: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.technicalComment = value;
},
),
],
),
],
);
});
}
int calculateWorkingHours(DateTime? startTime, DateTime? endTime) {
if(startTime!=null&&endTime!=null){
Duration difference = endTime.difference(startTime);
int hours = difference.inHours;
int minutes = difference.inMinutes % 60;
return hours;
}else{
return -1;
}
}
assignWorkingHours({required RequestDetailProvider requestDetailProvider}){
int hours = calculateWorkingHours(requestDetailProvider.activityMaintenanceHelperModel!.startTime,requestDetailProvider.activityMaintenanceHelperModel!.endTime);
if(hours!=-1){
_workingHoursController.text = hours.toString();
requestDetailProvider.activityMaintenanceHelperModel!.workingHour=hours;
}
}
final ButtonStyle flatButtonStyle = TextButton.styleFrom(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4.0)),
),
);
}

@ -7,6 +7,7 @@ import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/device/asset.dart';
@ -17,7 +18,9 @@ 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_filled_button.dart';
import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/providers/work_order/reason_provider.dart'; import 'package:test_sa/providers/work_order/reason_provider.dart';
import 'package:test_sa/service_request_latest/request_detail_provider.dart';
import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; import 'package:test_sa/views/widgets/date_and_time/time_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
@ -42,10 +45,8 @@ class _ExternalMaintenanceRequestState extends State<ExternalMaintenanceRequest>
ServiceStatusProvider? _assetTypeProvider; ServiceStatusProvider? _assetTypeProvider;
ServiceReport ?_serviceReport; ServiceReport ?_serviceReport;
bool _isLoading = false; bool _isLoading = false;
TimeOfDay ?_startTime;
int _selectedValue = 1; int _selectedValue = 1;
final TextEditingController _workingHoursController = TextEditingController();
TimeOfDay ?_endTime;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _faultController = TextEditingController(); final TextEditingController _faultController = TextEditingController();
@ -93,123 +94,153 @@ class _ExternalMaintenanceRequestState extends State<ExternalMaintenanceRequest>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context); // _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_assetTypeProvider = Provider.of<ServiceStatusProvider>(context); // _assetTypeProvider = Provider.of<ServiceStatusProvider>(context);
if (_serviceReport?.callRequest == null) { // if (_serviceReport?.callRequest == null) {
getRequestForWorkOrder(); // getRequestForWorkOrder();
} // }
_serviceReport?.assetType = _assetTypeProvider?.statuses?.firstWhere( // _serviceReport?.assetType = _assetTypeProvider?.statuses?.firstWhere(
(element) => element.value == _serviceReport?.callRequest?.assetType, // (element) => element.value == _serviceReport?.callRequest?.assetType,
orElse: () => Lookup(), // orElse: () => Lookup(),
); // );
return LoadingManager( return Consumer<RequestDetailProvider>(
isLoading: _isLoading, builder: (context, RequestDetailProvider requestDetailProvider,child) {
isFailedLoading: false, return LoadingManager(
stateCode: 200, isLoading: _isLoading,
onRefresh: () async {}, isFailedLoading: false,
child: Stack( stateCode: 200,
children: [ onRefresh: () async {},
SingleChildScrollView( child: Stack(
child: Form( children: [
key: _formKey, SingleChildScrollView(
child: Column( child: Form(
crossAxisAlignment: CrossAxisAlignment.stretch, key: _formKey,
children: [ child: Column(
SingleItemDropDownMenu<Lookup, NullableLoadingProvider>( crossAxisAlignment: CrossAxisAlignment.stretch,
context: context,
height: 56.toScreenHeight,
title: context.translation.supplier,
showShadow: false,
backgroundColor: AppColor.neutral100,
staticData: Provider.of<ServiceReportLastCallsProvider>(context).calls,
initialValue: _serviceReport?.calllastSituation,
onSelect: (status) {
_serviceReport?.calllastSituation = status;
},
),
8.height,
AppTextFormField(
labelText: context.translation.engineerName,
backgroundColor: AppColor.neutral100,
initialValue: _serviceReport?.assignedEmployee?.name.toString(),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
ATimePicker( //TODO replace with correct component..
label: context.translation.startTime, SingleItemDropDownMenu<Lookup, NullableLoadingProvider>(
hint: context.translation.select, context: context,
withBorder: false,
icon: 'clock',
withIcon: true,
backgroundColor: AppColor.neutral100,
height: 56.toScreenHeight, height: 56.toScreenHeight,
time: _startTime, title: context.translation.supplier,
onTimePicker: (selectedTime) { showShadow: false,
if (selectedTime != null) {
print('time selected $selectedTime');
setState(() {
_startTime = selectedTime;
});
}
},
).expanded,
8.width,
ATimePicker(
label: context.translation.endTime,
hint: context.translation.select,
icon: 'clock',
withIcon: true,
backgroundColor: AppColor.neutral100, backgroundColor: AppColor.neutral100,
withBorder: false, staticData: Provider.of<ServiceReportLastCallsProvider>(context).calls,
height: 56.toScreenHeight, initialValue: _serviceReport?.calllastSituation,
time: _endTime, onSelect: (status) {
onTimePicker: (selectedTime) { _serviceReport?.calllastSituation = status;
if (selectedTime != null) {
setState(() {
_endTime = selectedTime;
});
}
}, },
).expanded, ),
8.height,
AppTextFormField(
labelText: context.translation.engineerName,
backgroundColor: AppColor.neutral100,
initialValue: _serviceReport?.assignedEmployee?.name.toString(),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: requestDetailProvider.activityMaintenanceHelperModel?.supplierStartTime,
formatDateWithTime: true,
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,
);
requestDetailProvider.activityMaintenanceHelperModel?.supplierStartTime = selectedDateTime;
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
assignWorkingHours(requestDetailProvider: requestDetailProvider);
}
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: requestDetailProvider.activityMaintenanceHelperModel?.supplierEndTime,
formatDateWithTime: true,
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,
);
if (requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime!=null&&selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime!)) {
"End Date time must be greater then start date".showToast;
return;
}
requestDetailProvider.activityMaintenanceHelperModel?.supplierEndTime = selectedDateTime;
requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
assignWorkingHours(requestDetailProvider: requestDetailProvider);
}
});
},
).expanded,
],
),
8.height,
AppTextFormField(
labelText: context.translation.workingHours,
backgroundColor: AppColor.neutral80,
controller: _workingHoursController,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.supplierWorkingHour.toString(),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
enable: false,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
], ],
), ),
8.height, ),
AppTextFormField( ).toShadowContainer(context).paddingOnly(start: 16, end: 16, top: 12),
labelText: context.translation.workingHours, FooterActionButton.footerContainer(
backgroundColor: AppColor.neutral80, child: AppFilledButton(
labelStyle: AppTextStyles.textFieldLabelStyle, label:context.translation.addExternalActivity, // Use the dynamic label
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), buttonColor: AppColor.primary10,
initialValue: _serviceReport?.workingHours.toString(), onPressed: () async {
textAlign: TextAlign.center, // Handle button press
showShadow: false,
enable: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
], },
),
), ),
), ],
).toShadowContainer(context).paddingOnly(start: 16, end: 16, top: 12),
FooterActionButton.footerContainer(
child: AppFilledButton(
label:context.translation.addExternalActivity, // Use the dynamic label
buttonColor: AppColor.primary10,
onPressed: () async {
// Handle button press
},
),
), ),
], );
), }
); );
} }
Widget repairLocationWidget(BuildContext context) { Widget repairLocationWidget(BuildContext context) {
@ -251,4 +282,22 @@ class _ExternalMaintenanceRequestState extends State<ExternalMaintenanceRequest>
], ],
); );
} }
int calculateWorkingHours(DateTime? startTime, DateTime? endTime) {
if(startTime!=null&&endTime!=null){
Duration difference = endTime.difference(startTime);
int hours = difference.inHours;
int minutes = difference.inMinutes % 60;
return hours;
}else{
return -1;
}
}
assignWorkingHours({required RequestDetailProvider requestDetailProvider}){
int hours = calculateWorkingHours(requestDetailProvider.activityMaintenanceHelperModel!.supplierStartTime,requestDetailProvider.activityMaintenanceHelperModel!.supplierEndTime);
if(hours!=-1){
_workingHoursController.text = hours.toString();
requestDetailProvider.activityMaintenanceHelperModel!.workingHour=hours;
}
}
} }

@ -1,15 +1,18 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/parts_provider.dart'; import 'package:test_sa/controllers/providers/api/parts_provider.dart';
import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/service_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/helper_data_models/maintenance_request/activity_maintenance_model.dart';
import 'package:test_sa/models/service_request/service_report.dart'; import 'package:test_sa/models/service_request/service_report.dart';
import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
@ -17,7 +20,10 @@ import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/providers/work_order/activity_status_provider.dart'; import 'package:test_sa/providers/work_order/activity_status_provider.dart';
import 'package:test_sa/providers/work_order/reason_provider.dart'; import 'package:test_sa/providers/work_order/reason_provider.dart';
import 'package:test_sa/service_request_latest/request_detail_provider.dart';
import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/service_request_latest/views/forms/maintenance_request/components/assistant_employee_card.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; import 'package:test_sa/views/widgets/date_and_time/time_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
@ -29,28 +35,24 @@ import '../../../../../new_views/common_widgets/single_item_drop_down_menu.dart'
class InternalMaintenanceRequest extends StatefulWidget { class InternalMaintenanceRequest extends StatefulWidget {
static const String id = "/add-internal-activity"; static const String id = "/add-internal-activity";
const InternalMaintenanceRequest({Key ?key}) : super(key: key); const InternalMaintenanceRequest({Key? key}) : super(key: key);
@override @override
_InternalMaintenanceRequestState createState() => _InternalMaintenanceRequestState(); _InternalMaintenanceRequestState createState() => _InternalMaintenanceRequestState();
} }
class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest> with TickerProviderStateMixin { class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest> with TickerProviderStateMixin {
ServiceRequest? _request; ServiceRequest? _request;
ServiceRequestsProvider ?_serviceRequestsProvider; ServiceRequestsProvider? _serviceRequestsProvider;
RequestDetailProvider? _requestDetailProvider;
ServiceStatusProvider? _assetTypeProvider; ServiceStatusProvider? _assetTypeProvider;
ActivityStatusProvider? _activityStatusProvider; ActivityStatusProvider? _activityStatusProvider;
ServiceReport ?_serviceReport; ServiceReport? _serviceReport;
bool _isLoading = false; bool _isLoading = false;
TimeOfDay ?_startTime; bool isCurrentUserIsAssignedEmployee=false;
int _selectedValue = 1;
TimeOfDay ?_endTime;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _faultController = TextEditingController(); final TextEditingController _workingHoursController = TextEditingController();
final TextEditingController _workPreformedController = TextEditingController();
final TextEditingController _partQtyController = TextEditingController(); final TextEditingController _partQtyController = TextEditingController();
@override @override
@ -61,34 +63,37 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
// device: widget.request.device, // device: widget.request.device,
sparePartsWorkOrders: [], sparePartsWorkOrders: [],
); );
_activityStatusProvider = Provider.of<ActivityStatusProvider>(context,listen: false); _activityStatusProvider = Provider.of<ActivityStatusProvider>(context, listen: false);
_requestDetailProvider = Provider.of<RequestDetailProvider>(context, listen: false);
super.initState(); super.initState();
if (context.mounted) { WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData(); getInitialData();
_request = Provider.of<ServiceRequestsProvider>(context, listen: false).currentSelectedRequest; });
Provider.of<ServiceReportLastCallsProvider>(context, listen: false).reset();
Provider.of<ReasonProvider>(context, listen: false).reset();
Provider.of<ReasonProvider>(context, listen: false).serviceRequestId = _request?.id??'0';
}
// _isLoading = true; // _isLoading = true;
} }
@override @override
void dispose() { void dispose() {
_faultController.dispose(); _workingHoursController.dispose();
_workPreformedController.dispose();
_partQtyController.dispose(); _partQtyController.dispose();
super.dispose(); super.dispose();
} }
Future<void> getInitialData()async {
_activityStatusProvider?.getDate(); Future<void> getInitialData() async {
_activityStatusProvider?.getDate();
Provider.of<ServiceReportRepairLocationProvider>(context,listen: false).getTypes();
final user = Provider.of<UserProvider>(context).user!;
isCurrentUserIsAssignedEmployee = (user.userID != _requestDetailProvider?.currentWorkOrder?.data?.assignedEmployee?.userId);
if (isCurrentUserIsAssignedEmployee) {
// _subWorkOrders.assistantEmployees = [widget.workOrder.assistantEmployees?.first?.copyWith(id: 0)];
}
} }
void getRequestForWorkOrder() async { void getRequestForWorkOrder() async {
_isLoading = true; _isLoading = true;
setState(() {}); setState(() {});
_serviceReport?.callRequest = await _serviceRequestsProvider?.getCallRequestForWorkOrder(callId: _request?.id??'0'); _serviceReport?.callRequest = await _serviceRequestsProvider?.getCallRequestForWorkOrder(callId: _request?.id ?? '0');
await _assetTypeProvider?.getTypes(); await _assetTypeProvider?.getTypes();
_serviceReport?.assignedEmployee = _serviceReport?.callRequest?.assignedEmployee; _serviceReport?.assignedEmployee = _serviceReport?.callRequest?.assignedEmployee;
_serviceReport?.equipmentStatus = _serviceReport?.callRequest?.defectType; _serviceReport?.equipmentStatus = _serviceReport?.callRequest?.defectType;
@ -99,214 +104,270 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
// _assetTypeProvider = Provider.of<ServiceStatusProvider>(context);
// if (_serviceReport?.callRequest == null) {
// getRequestForWorkOrder();
// }
// _serviceReport?.assetType = _assetTypeProvider?.statuses?.firstWhere(
// (element) => element.value == _serviceReport?.callRequest?.assetType,
// orElse: () => Lookup(),
// );
return LoadingManager( return Consumer<RequestDetailProvider>(builder: (context, requestDetailProvider, child) {
isLoading: _isLoading, return LoadingManager(
isFailedLoading: false, isLoading: _isLoading,
stateCode: 200, isFailedLoading: false,
onRefresh: () async {}, stateCode: 200,
child: Stack( onRefresh: () async {},
children: [ child: Stack(
SingleChildScrollView( children: [
child: Form( SingleChildScrollView(
key: _formKey,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
SingleItemDropDownMenu<Lookup, NullableLoadingProvider>( Form(
context: context, key: _formKey,
height: 56.toScreenHeight, child: Column(
title: context.translation.activityStatus, crossAxisAlignment: CrossAxisAlignment.stretch,
showShadow: false, children: [
backgroundColor: AppColor.neutral100, SingleItemDropDownMenu<Lookup, ActivityStatusProvider>(
staticData: Provider.of<ServiceReportLastCallsProvider>(context).calls, context: context,
initialValue: _serviceReport?.calllastSituation, height: 56.toScreenHeight,
onSelect: (status) { title: context.translation.activityStatus,
_serviceReport?.calllastSituation = status; showShadow: false,
}, backgroundColor: AppColor.neutral100,
), initialValue: requestDetailProvider.activityMaintenanceHelperModel?.activityStatus,
8.height, onSelect: (status) {
Row( requestDetailProvider.activityMaintenanceHelperModel?.activityStatus = status;
mainAxisSize: MainAxisSize.min, },
children: [ ),
ATimePicker( 8.height,
label: context.translation.startTime, Row(
hint: context.translation.select, mainAxisSize: MainAxisSize.min,
withBorder: false, children: [
icon: 'clock', ADatePicker(
withIcon: true, label: context.translation.startTime,
backgroundColor: AppColor.neutral100, hideShadow: true,
height: 56.toScreenHeight, backgroundColor: AppColor.neutral100,
time: _startTime, date: requestDetailProvider.activityMaintenanceHelperModel?.startTime,
onTimePicker: (selectedTime) { formatDateWithTime: true,
if (selectedTime != null) { onDatePicker: (selectedDate) {
print('time selected $selectedTime'); showTimePicker(
setState(() { context: context,
_startTime = selectedTime; initialTime: TimeOfDay.now(),
}); ).then((selectedTime) {
} // Handle the selected date and time here.
}, if (selectedTime != null) {
).expanded, DateTime selectedDateTime = DateTime(
8.width, selectedDate.year,
ATimePicker( selectedDate.month,
label: context.translation.endTime, selectedDate.day,
hint: context.translation.select, selectedTime.hour,
icon: 'clock', selectedTime.minute,
withIcon: true, );
backgroundColor: AppColor.neutral100, requestDetailProvider.activityMaintenanceHelperModel?.startTime = selectedDateTime;
withBorder: false, requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
height: 56.toScreenHeight, assignWorkingHours(requestDetailProvider: requestDetailProvider);
time: _endTime, }
onTimePicker: (selectedTime) { });
if (selectedTime != null) { },
setState(() { ).expanded,
_endTime = selectedTime; 8.width,
}); ADatePicker(
} label: context.translation.endTime,
}, hideShadow: true,
).expanded, backgroundColor: AppColor.neutral100,
], date: requestDetailProvider.activityMaintenanceHelperModel?.endTime,
), formatDateWithTime: true,
8.height, onDatePicker: (selectedDate) {
AppTextFormField( showTimePicker(
labelText: context.translation.workingHours, context: context,
backgroundColor: AppColor.neutral80, initialTime: TimeOfDay.now(),
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), ).then((selectedTime) {
// contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), // Handle the selected date and time here.
initialValue: _serviceReport?.workingHours.toString(), if (selectedTime != null) {
textAlign: TextAlign.center, DateTime selectedDateTime = DateTime(
labelStyle: AppTextStyles.textFieldLabelStyle, selectedDate.year,
enable: false, selectedDate.month,
showShadow: false, selectedDate.day,
style: Theme.of(context).textTheme.titleMedium, selectedTime.hour,
), selectedTime.minute,
8.height, );
if (requestDetailProvider.activityMaintenanceHelperModel!.startTime != null &&
//TODO need to be selected when submit... selectedDateTime.isBefore(requestDetailProvider.activityMaintenanceHelperModel!.startTime!)) {
// SingleItemDropDownMenu<Lookup, ServiceTypeProvider>( "End Date time must be greater then start date".showToast;
// context: context, return;
// title: context.translation.serviceType, }
// initialValue: _serviceReport.serviceType, requestDetailProvider.activityMaintenanceHelperModel?.endTime = selectedDateTime;
// onSelect: (value) { requestDetailProvider.updateActivityMaintenanceHelperModel(requestDetailProvider.activityMaintenanceHelperModel);
// _serviceReport.serviceType = value; assignWorkingHours(requestDetailProvider: requestDetailProvider);
// }, }
// ), });
//Provider.of<ServiceReportLastCallsProvider>(context) },
).expanded,
8.height, ],
AppTextFormField( ),
labelText: context.translation.travelingHours, 8.height,
backgroundColor: AppColor.neutral100, AppTextFormField(
showShadow: false, labelText: context.translation.workingHours,
labelStyle: AppTextStyles.textFieldLabelStyle, backgroundColor: AppColor.neutral80,
suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), controller: _workingHoursController,
initialValue: _serviceReport?.travelingHours?.toString(), suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
textInputType: TextInputType.number, initialValue: requestDetailProvider.activityMaintenanceHelperModel?.workingHour.toString(),
// contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), textAlign: TextAlign.center,
onSaved: (value) { labelStyle: AppTextStyles.textFieldLabelStyle,
_serviceReport?.travelingHours = double.tryParse(value) ?? 0.0; enable: false,
}, showShadow: false,
), style: Theme.of(context).textTheme.titleMedium,
16.height, ),
context.translation.repairLocation.bodyText(context).custom(color: AppColor.black20, fontWeight: FontWeight.w500), 8.height,
8.height, AppTextFormField(
repairLocationWidget(context), labelText: context.translation.travelingHours,
16.height, backgroundColor: AppColor.neutral100,
AppTextFormField( showShadow: false,
labelText: context.translation.assignedEmployee, labelStyle: AppTextStyles.textFieldLabelStyle,
backgroundColor: AppColor.neutral80, suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16),
initialValue: _serviceReport?.assignedEmployee?.name.toString(), initialValue: requestDetailProvider.activityMaintenanceHelperModel?.travelHours?.toString(),
textAlign: TextAlign.center, textInputType: TextInputType.number,
labelStyle: AppTextStyles.textFieldLabelStyle, onChange: (value) {
showShadow: false, requestDetailProvider.activityMaintenanceHelperModel?.travelHours = int.tryParse(value);
enable: false, },
style: Theme.of(context).textTheme.titleMedium, // contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth),
), onSaved: (value) {
8.height, requestDetailProvider.activityMaintenanceHelperModel?.travelHours = value as int?;
AppTextFormField( },
initialValue: _serviceReport?.comment, ),
labelText: context.translation.technicalComment, 16.height,
backgroundColor: AppColor.neutral100, repairLocationWidget(context,requestDetailProvider),
showShadow: false, 16.height,
labelStyle: AppTextStyles.textFieldLabelStyle, AppTextFormField(
alignLabelWithHint: true, labelText: context.translation.assignedEmployee,
textInputType: TextInputType.multiline, backgroundColor: AppColor.neutral80,
onSaved: (value) { initialValue: _serviceReport?.assignedEmployee?.name.toString(),
_serviceReport?.comment = value; textAlign: TextAlign.center,
}, labelStyle: AppTextStyles.textFieldLabelStyle,
), showShadow: false,
enable: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.technicalComment,
labelText: context.translation.technicalComment,
backgroundColor: AppColor.neutral100,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.technicalComment = value;
},
onSaved: (value) {
requestDetailProvider.activityMaintenanceHelperModel?.technicalComment = value;
},
),
],
),
).toShadowContainer(context).paddingOnly(start: 13, end: 14, top: 12),
const AssistantEmployeeCard().toShadowContainer(context, paddingValue: const EdgeInsets.symmetric(horizontal: 16)).paddingOnly(start: 13, end: 14, top: 12),
100.height,
], ],
), ),
), ),
).toShadowContainer(context).paddingOnly(start: 13, end: 14, top: 12), FooterActionButton.footerContainer(
child: AppFilledButton(
label: context.translation.addInternalActivity, // Use the dynamic label
buttonColor: AppColor.primary10,
onPressed: () async {
// Handle button press
},
),
),
],
),
);
});
}
FooterActionButton.footerContainer( Widget repairLocationWidget(BuildContext context,RequestDetailProvider requestDetailProvider) {
child: AppFilledButton( return Consumer<ServiceReportRepairLocationProvider>(builder: (cxt, snapshot, _) {
label:context.translation.addInternalActivity, // Use the dynamic label try {
buttonColor: AppColor.primary10, requestDetailProvider.activityMaintenanceHelperModel?.repairLocation ??= snapshot.reasons?.first;
onPressed: () async { } catch (ex) {
// Handle button press print("snapshot.items:${snapshot.reasons?.length}");
}
}, return Column(
), crossAxisAlignment: CrossAxisAlignment.start,
), mainAxisSize: MainAxisSize.min,
children: [
context.translation.repairLocation.bodyText(context).custom(color: AppColor.black20),
8.height,
Wrap(
runSpacing: 8,
spacing: 8,
children: [
for (var element in snapshot.reasons??[])
Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 24,
height: 24,
child: Radio(
value: element,
activeColor: Colors.red,
fillColor: WidgetStateColor.resolveWith((states) {
if (states.contains(WidgetState.selected)) return AppColor.primary10;
return AppColor.neutral130;
}),
groupValue: requestDetailProvider.activityMaintenanceHelperModel?.repairLocation,
onChanged: (state) {
setState(() {
requestDetailProvider.activityMaintenanceHelperModel?.repairLocation = element;
});
}),
),
8.width,
Text(element.name??'', style: AppTextStyles.tinyFont.copyWith(color:AppColor.neutral120)),
],
)
],
).toShimmer(isShow: snapshot.isLoading),
], ],
), );
); });
} }
Widget repairLocationWidget(BuildContext context) {
return Row( int calculateWorkingHours(DateTime? startTime, DateTime? endTime) {
mainAxisSize: MainAxisSize.min, if (startTime != null && endTime != null) {
children: [ Duration difference = endTime.difference(startTime);
radioButtonWidget(label: context.translation.remotely, value: 1), int hours = difference.inHours;
radioButtonWidget(label: context.translation.workshop, value: 2), int minutes = difference.inMinutes % 60;
radioButtonWidget(label: context.translation.abroad, value: 3), return hours;
], } else {
); return -1;
}
} }
Widget radioButtonWidget({required String label, required dynamic value}) { assignWorkingHours({required RequestDetailProvider requestDetailProvider}) {
return Row( int hours = calculateWorkingHours(requestDetailProvider.activityMaintenanceHelperModel!.startTime, requestDetailProvider.activityMaintenanceHelperModel!.endTime);
mainAxisSize: MainAxisSize.min, if (hours != -1) {
children: [ _workingHoursController.text = hours.toString();
SizedBox( requestDetailProvider.activityMaintenanceHelperModel!.workingHour = hours;
width: 20.toScreenWidth, }
height: 40.toScreenHeight,
//TODO use the type required according data..
child: Radio<int>(
fillColor: WidgetStateProperty.resolveWith((states) {
// active
if (states.contains(WidgetState.selected)) {
return AppColor.primary10;
}
// inactive
return AppColor.neutral130;
}),
value: value,
groupValue: _selectedValue,
onChanged: (int ?value) {
setState(() {
_selectedValue = value!;
});
},
),
),
8.width,
Text(
label,
style: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120),
),
13.width,
],
);
} }
Future<bool> validate({required ActivityMaintenanceHelperModel model }) async {
if (model.activityStatus == null) {
Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.activityStatus}");
return false;
} else if (model.startTime == null) {
Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.startTime}");
return false;
} else if (model.endTime == null) {
Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.endTime}");
return false;
} else if (model.travelHours==null) {
Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.travelingHours}");
return false;
}else if (model.repairLocation == null) {
Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.repairLocation}");
return false;
}
//write all other missing conditions..
return true;
}
} }

@ -48,9 +48,10 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
@override @override
void initState() { void initState() {
print('status lenght is ${widget.statuses?.length}');
_selectedStatus = widget.statuses?.firstWhere( _selectedStatus = widget.statuses?.firstWhere(
(element) => element == widget.initialStatus, (element) => element == widget.initialStatus,
orElse: null); orElse: () => Lookup());
if (widget.initialStatus != _selectedStatus) { if (widget.initialStatus != _selectedStatus) {
widget.onSelect?.call(_selectedStatus); // Use null-aware operator widget.onSelect?.call(_selectedStatus); // Use null-aware operator

@ -5,10 +5,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: _flutterfire_internals name: _flutterfire_internals
sha256: ddc6f775260b89176d329dee26f88b9469ef46aa3228ff6a0b91caf2b2989692 sha256: "5534e701a2c505fed1f0799e652dd6ae23bd4d2c4cf797220e5ced5764a7c1c2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.42" version: "1.3.44"
another_flushbar: another_flushbar:
dependency: "direct main" dependency: "direct main"
description: description:
@ -225,6 +225,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
expansion_tile_card:
dependency: "direct main"
description:
name: expansion_tile_card
sha256: "27ce4cb518f00e21d0f2309aaa6462b26b148e93cee2029a73088cecf42b1eb0"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -269,10 +277,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: file_selector_macos name: file_selector_macos
sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385 sha256: cb284e267f8e2a45a904b5c094d2ba51d0aabfc20b1538ab786d9ef7dc2bf75c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.4" version: "0.9.4+1"
file_selector_platform_interface: file_selector_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -285,58 +293,58 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: file_selector_windows name: file_selector_windows
sha256: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69" sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.3+2" version: "0.9.3+3"
firebase_core: firebase_core:
dependency: "direct main" dependency: "direct main"
description: description:
name: firebase_core name: firebase_core
sha256: "40921de9795fbf5887ed5c0adfdf4972d5a8d7ae7e1b2bb98dea39bc02626a88" sha256: "51dfe2fbf3a984787a2e7b8592f2f05c986bfedd6fdacea3f9e0a7beb334de96"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.1" version: "3.6.0"
firebase_core_platform_interface: firebase_core_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: firebase_core_platform_interface name: firebase_core_platform_interface
sha256: f7d7180c7f99babd4b4c517754d41a09a4943a0f7a69b65c894ca5c68ba66315 sha256: e30da58198a6d4b49d5bce4e852f985c32cb10db329ebef9473db2b9f09ce810
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.2.1" version: "5.3.0"
firebase_core_web: firebase_core_web:
dependency: transitive dependency: transitive
description: description:
name: firebase_core_web name: firebase_core_web
sha256: f4ee170441ca141c5f9ee5ad8737daba3ee9c8e7efb6902aee90b4fbd178ce25 sha256: f967a7138f5d2ffb1ce15950e2a382924239eaa521150a8f144af34e68b3b3e5
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.18.0" version: "2.18.1"
firebase_messaging: firebase_messaging:
dependency: "direct main" dependency: "direct main"
description: description:
name: firebase_messaging name: firebase_messaging
sha256: cc02c4afd6510cd84586020670140c4a23fbe52af16cd260ccf8ede101bb8d1b sha256: eb6e28a3a35deda61fe8634967c84215efc19133ba58d8e0fc6c9a2af2cba05e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "15.1.1" version: "15.1.3"
firebase_messaging_platform_interface: firebase_messaging_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: firebase_messaging_platform_interface name: firebase_messaging_platform_interface
sha256: d8a4984635f09213302243ea670fe5c42f3261d7d8c7c0a5f7dcd5d6c84be459 sha256: b316c4ee10d93d32c033644207afc282d9b2b4372f3cf9c6022f3558b3873d2d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.5.44" version: "4.5.46"
firebase_messaging_web: firebase_messaging_web:
dependency: transitive dependency: transitive
description: description:
name: firebase_messaging_web name: firebase_messaging_web
sha256: "258b9d637965db7855299b123533609ed95e52350746a723dfd1d8d6f3fac678" sha256: d7f0147a1a9fe4313168e20154a01fd5cf332898de1527d3930ff77b8c7f5387
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.9.0" version: "3.9.2"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@ -450,10 +458,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: c500d5d9e7e553f06b61877ca6b9c8b92c570a4c8db371038702e8ce57f8a50f sha256: "49eeef364fddb71515bc78d5a8c51435a68bccd6e4d68e25a942c5e47761ae71"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "17.2.2" version: "17.2.3"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
@ -849,18 +857,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: open_file name: open_file
sha256: de371f549b1320a48980952473fae1903d4927975506534c8ea4643642eb5f98 sha256: a070625d8684aa35a35d6701b91d684592f1ea03f5a737ee0d39332526d09421
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.5.3" version: "3.5.7"
open_file_android: open_file_android:
dependency: transitive dependency: transitive
description: description:
name: open_file_android name: open_file_android
sha256: b5e1a2e9c5ea8e256b015403e94299039627c7205c2a5e6bb426c33235b6ca9a sha256: eaa52421c5e10ba42eb3958d2632be0fc8b4f7e53556296064339d363caa2233
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.3"
open_file_ios: open_file_ios:
dependency: transitive dependency: transitive
description: description:
@ -897,10 +905,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: open_file_web name: open_file_web
sha256: ba35c6f38c21c2bb4268a80927bb828353dda0edfce92e274e0b9639e4f31360 sha256: cfc9d6091a844e305a3698c45f47f5cd88aabb143665dcfb0f5fd6f7524d357e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.0.2" version: "0.0.3"
open_file_windows: open_file_windows:
dependency: transitive dependency: transitive
description: description:
@ -1145,10 +1153,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: rive name: rive
sha256: daa5394a7d064b4997b39e9afa02f6882c479c38b19fa0dd60f052b99c105400 sha256: cd45b071b288e4bef05f25423e1001a9b3218b81745deae18c9b4d2a2952cc56
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.13" version: "0.13.14"
rive_common: rive_common:
dependency: transitive dependency: transitive
description: description:
@ -1294,18 +1302,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: sqflite name: sqflite
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d sha256: ff5a2436ef8ebdfda748fbfe957f9981524cb5ff11e7bafa8c42771840e8a788
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.3+1" version: "2.3.3+2"
sqflite_common: sqflite_common:
dependency: transitive dependency: transitive
description: description:
name: sqflite_common name: sqflite_common
sha256: "7b41b6c3507854a159e24ae90a8e3e9cc01eb26a477c118d6dca065b5f55453e" sha256: "2d8e607db72e9cb7748c9c6e739e2c9618320a5517de693d5a24609c4671b1a4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.4+2" version: "2.5.4+4"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -1350,10 +1358,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: synchronized name: synchronized
sha256: a824e842b8a054f91a728b783c177c1e4731f6b124f9192468457a8913371255 sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "3.3.0+3"
table_calendar: table_calendar:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1438,10 +1446,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_macos name: url_launcher_macos
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "3.2.1"
url_launcher_platform_interface: url_launcher_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -1470,10 +1478,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: uuid name: uuid
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77 sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.5.0" version: "4.5.1"
vector_graphics: vector_graphics:
dependency: transitive dependency: transitive
description: description:
@ -1518,10 +1526,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.1.0"
win32: win32:
dependency: "direct overridden" dependency: "direct overridden"
description: description:

@ -60,6 +60,7 @@ dependencies:
permission_handler: ^11.3.1 permission_handler: ^11.3.1
rive: ^0.13.13 rive: ^0.13.13
another_flushbar: another_flushbar:
expansion_tile_card: ^3.0.0
pinput: pinput:
audioplayers: ^6.1.0 audioplayers: ^6.1.0
flare_flutter: ^3.0.2 flare_flutter: ^3.0.2

Loading…
Cancel
Save