| import 'package:farm_tpf/data/api/dio_provider.dart'; | import 'package:farm_tpf/data/api/dio_provider.dart'; | ||||
| import 'package:farm_tpf/data/api/rest_client.dart'; | import 'package:farm_tpf/data/api/rest_client.dart'; | ||||
| import 'package:farm_tpf/models/PagedResult.dart'; | import 'package:farm_tpf/models/PagedResult.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/activity_request.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/models/activity_type.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_request.dart'; | import 'package:farm_tpf/presentation/screens/codes/models/stamp_request.dart'; | ||||
| import 'package:farm_tpf/utils/const_common.dart'; | import 'package:farm_tpf/utils/const_common.dart'; | ||||
| onError(AppException.handleError(e)); | onError(AppException.handleError(e)); | ||||
| } | } | ||||
| } | } | ||||
| Future<List<ActivityType>> activityTypes() async { | |||||
| try { | |||||
| var url = '${ConstCommon.baseUrl}/api/tb-activity-types-dropdown-list-after-harvest'; | |||||
| var res = await dio.get( | |||||
| url, | |||||
| ); | |||||
| return (res.data as List).map((e) => ActivityType.fromJson(e)).toList(); | |||||
| } catch (e) { | |||||
| rethrow; | |||||
| } | |||||
| } | |||||
| Future<void> updateActivity( | |||||
| Function(dynamic) onSuccess, | |||||
| Function(String) onError, { | |||||
| required ActivityRequest item, | |||||
| }) async { | |||||
| try { | |||||
| var url = '${ConstCommon.baseUrl}/api/tb-codes/create/activity'; | |||||
| await dio.post(url, data: item).then( | |||||
| (value) { | |||||
| onSuccess(value); | |||||
| }, | |||||
| ).catchError((e) { | |||||
| onError(AppException.handleError(e)); | |||||
| }); | |||||
| } catch (e) { | |||||
| onError(AppException.handleError(e)); | |||||
| } | |||||
| } | |||||
| } | } |
| import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart'; | import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/button/second_button.dart'; | import 'package:farm_tpf/presentation/custom_widgets/button/second_button.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/code_update_timeline_page.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/update_activity_page.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/widgets/item_code_timeline.dart'; | import 'package:farm_tpf/presentation/screens/codes/widgets/item_code_timeline.dart'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:get/get.dart'; | import 'package:get/get.dart'; | ||||
| appBar: AppBarWidget( | appBar: AppBarWidget( | ||||
| action: IconButton( | action: IconButton( | ||||
| onPressed: () { | onPressed: () { | ||||
| Get.to(() => CodeUpdateTimelinePage()); | |||||
| Get.to(() => UpdateActivityPage( | |||||
| stampCode: 'AC_494D9D90', | |||||
| )); | |||||
| }, | }, | ||||
| icon: Icon( | icon: Icon( | ||||
| Icons.edit, | Icons.edit, |
| import 'package:bloc/bloc.dart'; | |||||
| import 'package:equatable/equatable.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/codes/models/activity_request.dart'; | |||||
| import 'package:farm_tpf/utils/formatter.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:get/get.dart'; | |||||
| import '../../../../data/api/app_exception.dart'; | |||||
| import '../../../../data/repository/repository.dart'; | |||||
| import '../../../../models/item_dropdown.dart'; | |||||
| import '../../../../utils/utils.dart'; | |||||
| import '../../../custom_widgets/widget_utils.dart'; | |||||
| import '../models/activity_type.dart'; | |||||
| part 'update_activity_state.dart'; | |||||
| class UpdateActivityCubit extends Cubit<UpdateActivityState> { | |||||
| UpdateActivityCubit() : super(UpdateActivityInitial()); | |||||
| final repository = Repository(); | |||||
| final formKey = GlobalKey<FormState>(); | |||||
| var actionDate = ValueNotifier(DateTime.now()); | |||||
| final descriptionCtl = TextEditingController(); | |||||
| final locationCtl = TextEditingController(); | |||||
| final expiredDateCtl = TextEditingController(); | |||||
| var activityTypeRaws = <ActivityType>[]; | |||||
| var activityTypes = ValueNotifier(<ItemDropDown>[]); | |||||
| var selectedActivityType = ValueNotifier(''); | |||||
| // var existedUpdateActivity = UpdateUpdateActivity(); | |||||
| void dispose() { | |||||
| descriptionCtl.dispose(); | |||||
| locationCtl.dispose(); | |||||
| expiredDateCtl.dispose(); | |||||
| } | |||||
| Future<void> preparedData() async { | |||||
| try { | |||||
| await Future.delayed(const Duration(seconds: 0)); | |||||
| emit(UpdateActivityLoading()); | |||||
| activityTypeRaws = await repository.activityTypes(); | |||||
| activityTypes.value = activityTypeRaws | |||||
| .map( | |||||
| (e) => ItemDropDown(key: e.id?.toString(), value: e.description), | |||||
| ) | |||||
| .toList(); | |||||
| emit(UpdateActivityPrepareDataSuccessful()); | |||||
| } catch (e) { | |||||
| emit(UpdateActivityFailure(AppException.handleError(e))); | |||||
| } | |||||
| } | |||||
| Future<void> onSubmit(String stampCode) async { | |||||
| if (formKey.currentState!.validate()) { | |||||
| var requestActivity = ActivityRequest(); | |||||
| var activity = activityTypeRaws.firstWhere( | |||||
| (e) => selectedActivityType.value == e.id?.toString(), | |||||
| orElse: () => ActivityType(), | |||||
| ); | |||||
| requestActivity | |||||
| ..code = stampCode | |||||
| ..description = descriptionCtl.text | |||||
| ..location = locationCtl.text | |||||
| ..executeDate = actionDate.value.convertLocalDateTimeToStringUtcDateTime() | |||||
| ..activityTypeId = activity.id; | |||||
| print(requestActivity.toJson()); | |||||
| UtilWidget.showLoading(); | |||||
| await repository.updateActivity( | |||||
| (success) { | |||||
| UtilWidget.hideDialog(); | |||||
| Get.back(result: 'ok'); | |||||
| Utils.showSnackBarSuccess(); | |||||
| }, | |||||
| (errorMessage) { | |||||
| UtilWidget.hideDialog(); | |||||
| Utils.showSnackBarError(); | |||||
| }, | |||||
| item: requestActivity, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } |
| part of 'update_activity_cubit.dart'; | |||||
| class UpdateActivityState extends Equatable { | |||||
| const UpdateActivityState(); | |||||
| @override | |||||
| List<Object> get props => []; | |||||
| } | |||||
| class UpdateActivityInitial extends UpdateActivityState {} | |||||
| class UpdateActivityLoading extends UpdateActivityState {} | |||||
| class UpdateActivityFailure extends UpdateActivityState { | |||||
| final String errorMessage; | |||||
| UpdateActivityFailure(this.errorMessage); | |||||
| } | |||||
| class UpdateActivityPrepareDataSuccessful extends UpdateActivityState { | |||||
| UpdateActivityPrepareDataSuccessful(); | |||||
| } |
| class ActivityRequest { | |||||
| String? code; | |||||
| int? activityTypeId; | |||||
| String? executeDate; | |||||
| String? description; | |||||
| String? location; | |||||
| ActivityRequest({this.code, this.activityTypeId, this.executeDate, this.description, this.location}); | |||||
| ActivityRequest.fromJson(Map<String, dynamic> json) { | |||||
| code = json['code']; | |||||
| activityTypeId = json['activityTypeId']; | |||||
| executeDate = json['executeDate']; | |||||
| description = json['description']; | |||||
| location = json['location']; | |||||
| } | |||||
| Map<String, dynamic> toJson() { | |||||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
| data['code'] = this.code; | |||||
| data['activityTypeId'] = this.activityTypeId; | |||||
| data['executeDate'] = this.executeDate; | |||||
| data['description'] = this.description; | |||||
| data['location'] = this.location; | |||||
| return data; | |||||
| } | |||||
| } |
| class ActivityType { | |||||
| int? id; | |||||
| String? name; | |||||
| String? description; | |||||
| ActivityType({this.id, this.name, this.description}); | |||||
| ActivityType.fromJson(Map<String, dynamic> json) { | |||||
| id = json['id']; | |||||
| name = json['name']; | |||||
| description = json['description']; | |||||
| } | |||||
| Map<String, dynamic> toJson() { | |||||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
| data['id'] = this.id; | |||||
| data['name'] = this.name; | |||||
| data['description'] = this.description; | |||||
| return data; | |||||
| } | |||||
| } |
| import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart'; | import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/button_widget.dart'; | import 'package:farm_tpf/presentation/custom_widgets/button_widget.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/codes/cubit/code_update_timeline_cubit.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/scheduler.dart'; | import 'package:flutter/scheduler.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:keyboard_dismisser/keyboard_dismisser.dart'; | import 'package:keyboard_dismisser/keyboard_dismisser.dart'; | ||||
| import '../../../models/item_dropdown.dart'; | |||||
| import '../../../utils/utils.dart'; | import '../../../utils/utils.dart'; | ||||
| import '../../custom_widgets/date_picker/date_picker_widget.dart'; | import '../../custom_widgets/date_picker/date_picker_widget.dart'; | ||||
| import '../../custom_widgets/dropdown/dropdown_bottom_sheet.dart'; | import '../../custom_widgets/dropdown/dropdown_bottom_sheet.dart'; | ||||
| import '../../custom_widgets/textfield/text_field_normal.dart'; | import '../../custom_widgets/textfield/text_field_normal.dart'; | ||||
| import 'cubit/update_activity_cubit.dart'; | |||||
| import 'widgets/item_column.dart'; | import 'widgets/item_column.dart'; | ||||
| class CodeUpdateTimelinePage extends StatefulWidget { | |||||
| const CodeUpdateTimelinePage({super.key}); | |||||
| class UpdateActivityPage extends StatefulWidget { | |||||
| final String stampCode; | |||||
| const UpdateActivityPage({super.key, required this.stampCode}); | |||||
| @override | @override | ||||
| State<CodeUpdateTimelinePage> createState() => _CodeUpdateTimelinePageState(); | |||||
| State<UpdateActivityPage> createState() => _UpdateActivityPageState(); | |||||
| } | } | ||||
| class _CodeUpdateTimelinePageState extends State<CodeUpdateTimelinePage> { | |||||
| final bloc = CodeUpdateTimelineCubit(); | |||||
| class _UpdateActivityPageState extends State<UpdateActivityPage> { | |||||
| final bloc = UpdateActivityCubit(); | |||||
| @override | @override | ||||
| void initState() { | void initState() { | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Scaffold( | return Scaffold( | ||||
| appBar: AppBarWidget(), | appBar: AppBarWidget(), | ||||
| body: BlocListener<CodeUpdateTimelineCubit, CodeUpdateTimelineState>( | |||||
| body: BlocListener<UpdateActivityCubit, UpdateActivityState>( | |||||
| bloc: bloc, | bloc: bloc, | ||||
| listener: ((context, state) { | listener: ((context, state) { | ||||
| if (state is CodeUpdateTimelineLoading) { | |||||
| if (state is UpdateActivityLoading) { | |||||
| SchedulerBinding.instance.addPostFrameCallback((timeStamp) { | SchedulerBinding.instance.addPostFrameCallback((timeStamp) { | ||||
| UtilWidget.showLoading(); | UtilWidget.showLoading(); | ||||
| }); | }); | ||||
| } else if (state is CodeUpdateTimelineFailure) { | |||||
| } else if (state is UpdateActivityFailure) { | |||||
| SchedulerBinding.instance.addPostFrameCallback((timeStamp) { | SchedulerBinding.instance.addPostFrameCallback((timeStamp) { | ||||
| UtilWidget.hideLoading(); | UtilWidget.hideLoading(); | ||||
| // UtilWidget.showToastError(state.errorMessage); | // UtilWidget.showToastError(state.errorMessage); | ||||
| }); | }); | ||||
| } else if (state is CodeUpdateTimelinePrepareDataSuccessful) { | |||||
| } else if (state is UpdateActivityPrepareDataSuccessful) { | |||||
| SchedulerBinding.instance.addPostFrameCallback((timeStamp) { | SchedulerBinding.instance.addPostFrameCallback((timeStamp) { | ||||
| UtilWidget.hideLoading(); | UtilWidget.hideLoading(); | ||||
| }); | }); | ||||
| padding: const EdgeInsets.all(8.0), | padding: const EdgeInsets.all(8.0), | ||||
| child: ButtonWidget( | child: ButtonWidget( | ||||
| title: 'Cập nhật', | title: 'Cập nhật', | ||||
| onPressed: () {}, | |||||
| onPressed: () { | |||||
| bloc.onSubmit(widget.stampCode); | |||||
| }, | |||||
| ), | ), | ||||
| ), | ), | ||||
| ], | ], | ||||
| child: Column( | child: Column( | ||||
| crossAxisAlignment: CrossAxisAlignment.start, | crossAxisAlignment: CrossAxisAlignment.start, | ||||
| children: [ | children: [ | ||||
| ItemColumnWidget( | |||||
| title: 'Hoạt động', | |||||
| child: ValueListenableBuilder<String>( | |||||
| valueListenable: bloc.selectedActivityType, | |||||
| builder: (context, selected, _) { | |||||
| return ValueListenableBuilder<List<ItemDropDown>>( | |||||
| valueListenable: bloc.activityTypes, | |||||
| builder: (context, types, _) { | |||||
| return DropdownBottomSheet( | |||||
| dataSources: types, | |||||
| initValue: selected, | |||||
| onSelected: (val) { | |||||
| bloc.selectedActivityType.value = val.key ?? ''; | |||||
| }, | |||||
| hint: 'Hoạt động', | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| }), | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 8, | |||||
| ), | |||||
| ItemColumnWidget( | |||||
| title: 'Mô tả', | |||||
| child: TextFieldNormal( | |||||
| controller: bloc.descriptionCtl, | |||||
| maxLines: 1, | |||||
| hint: 'Mô tả', | |||||
| ), | |||||
| ), | |||||
| SizedBox( | |||||
| height: 8, | |||||
| ), | |||||
| ValueListenableBuilder<DateTime>( | ValueListenableBuilder<DateTime>( | ||||
| valueListenable: bloc.actionDate, | valueListenable: bloc.actionDate, | ||||
| builder: (context, actionDate, _) { | builder: (context, actionDate, _) { | ||||
| return ItemColumnWidget( | return ItemColumnWidget( | ||||
| title: 'Ngày nhập', | |||||
| title: 'Ngày cập nhập', | |||||
| child: DatePickerWidget( | child: DatePickerWidget( | ||||
| initDateTime: actionDate, | initDateTime: actionDate, | ||||
| onUpdateDateTime: (selectedDate) { | onUpdateDateTime: (selectedDate) { | ||||
| height: 8, | height: 8, | ||||
| ), | ), | ||||
| ItemColumnWidget( | ItemColumnWidget( | ||||
| title: 'Hoạt động', | |||||
| child: ValueListenableBuilder<String>( | |||||
| valueListenable: bloc.selectedActionType, | |||||
| builder: (context, selected, _) { | |||||
| return DropdownBottomSheet( | |||||
| dataSources: bloc.actionTypes, | |||||
| initValue: selected, | |||||
| onSelected: (val) { | |||||
| bloc.selectedActionType.value = val.key ?? ''; | |||||
| }, | |||||
| hint: 'Hoạt động', | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 8, | |||||
| ), | |||||
| ItemColumnWidget( | |||||
| title: 'Mô tả', | |||||
| title: 'Vị trí', | |||||
| child: TextFieldNormal( | child: TextFieldNormal( | ||||
| controller: bloc.descriptionCtl, | |||||
| maxLines: 2, | |||||
| hint: 'Mô tả', | |||||
| controller: bloc.locationCtl, | |||||
| maxLines: 1, | |||||
| hint: 'Vị trí', | |||||
| ), | ), | ||||
| ), | ), | ||||
| const SizedBox( | const SizedBox( |