From f1ed33a6c06887eea47cd363c8199932ac2a58b2 Mon Sep 17 00:00:00 2001 From: PGAN-MIS Date: Tue, 21 Mar 2023 09:37:55 +0800 Subject: [PATCH] implemented delete,update, and edit in work history screen --- ios/Podfile.lock | 6 - .../profile/workHistory/workHistory_bloc.dart | 281 +++--- .../workHistory/workHistory_event.dart | 27 + .../workHistory/workHistory_state.dart | 31 +- lib/model/utils/agency_position.dart | 22 - .../components/eligibility/edit_modal.dart | 8 +- .../profile/components/loading_screen.dart | 6 +- .../components/work_history/add_modal.dart | 242 +++-- .../components/work_history/edit_modal.dart | 828 ++++++++++++++++++ .../components/work_history_screen.dart | 49 +- .../profile/work_history_services.dart | 93 +- lib/utils/custom_dropdown_button.dart | 292 +++--- lib/utils/urls.dart | 11 +- lib/utils/validators.dart | 16 + pubspec.lock | 40 - pubspec.yaml | 5 - 16 files changed, 1495 insertions(+), 462 deletions(-) create mode 100644 lib/screens/profile/components/work_history/edit_modal.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 26d9bc2..e6a0ac0 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -22,8 +22,6 @@ PODS: - FlutterMacOS - permission_handler_apple (9.0.4): - Flutter - - search_choices (0.0.1): - - Flutter - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -42,7 +40,6 @@ DEPENDENCIES: - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - - search_choices (from `.symlinks/plugins/search_choices/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) @@ -70,8 +67,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider_foundation/ios" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" - search_choices: - :path: ".symlinks/plugins/search_choices/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/ios" sqflite: @@ -88,7 +83,6 @@ SPEC CHECKSUMS: package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce - search_choices: b50731e8c425078048f681f39c34375c58d6ce8d shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 SwiftProtobuf: b02b5075dcf60c9f5f403000b3b0c202a11b6ae1 diff --git a/lib/bloc/profile/workHistory/workHistory_bloc.dart b/lib/bloc/profile/workHistory/workHistory_bloc.dart index bf5a416..c645ad0 100644 --- a/lib/bloc/profile/workHistory/workHistory_bloc.dart +++ b/lib/bloc/profile/workHistory/workHistory_bloc.dart @@ -1,9 +1,10 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:select2dot1/select2dot1.dart'; +import 'package:unit2/bloc/profile/eligibility/eligibility_bloc.dart'; import 'package:unit2/model/profile/work_history.dart'; import 'package:unit2/model/utils/agency.dart'; import 'package:unit2/model/utils/agency_position.dart'; +import 'package:unit2/model/utils/position.dart'; import 'package:unit2/sevices/profile/work_history_services.dart'; import '../../../model/utils/category.dart'; @@ -13,11 +14,12 @@ part 'workHistory_state.dart'; class WorkHistoryBloc extends Bloc { List workExperiences = []; - List agencyPositions = []; + List agencyPositions = []; List agencies = []; List appointmentStatus = []; List agencyCategory = []; WorkHistoryBloc() : super(EducationInitial()) { + ////GET WORK HISTORIES on((event, emit) async { emit(WorkHistoryLoadingState()); try { @@ -29,196 +31,145 @@ class WorkHistoryBloc extends Bloc { emit(WorkHistoryErrorState(message: e.toString())); } }); - - on((event,emit){ +///// LOAD WORK HISTORIES + on((event, emit) { emit(WorkHistoryLoadingState()); workExperiences = event.workHistories; emit(WorkHistoryLoaded(workExperiences: workExperiences)); }); - on((event,emit)async{ + on((event, emit) async { emit(WorkHistoryLoadingState()); - try{ - final bool success = await WorkHistoryService.instance.delete(profileId: event.profileId,token: event.token, work: event.workHistory); - if(success){ - event.workHistories.removeWhere((WorkHistory element) => element.id == event.workHistory.id); + try { + final bool success = await WorkHistoryService.instance.delete( + profileId: event.profileId, + token: event.token, + work: event.workHistory); + if (success) { + event.workHistories.removeWhere( + (WorkHistory element) => element.id == event.workHistory.id); List newWorkHistories = event.workHistories; - emit(DeletedState(success: success,workHistories: newWorkHistories)); - }else{ - emit(DeletedState(success: success, workHistories: event.workHistories)); + emit(DeletedState(success: success, workHistories: newWorkHistories)); + } else { + emit(DeletedState( + success: success, workHistories: event.workHistories)); } - - }catch(e){ + } catch (e) { emit(WorkHistoryErrorState(message: e.toString())); } }); + //// ADD WORK HISTORIES + on((event, emit) async { + try { + emit(WorkHistoryLoadingState()); + Map status = await WorkHistoryService.instance.add( + isPrivate: event.isPrivate, + workHistory: event.workHistory, + token: event.token, + profileId: event.profileId); + if (status['success']) { + WorkHistory workHistory = WorkHistory.fromJson(status['data']); + workExperiences.add(workHistory); + emit(WorkHistoryAddedState( + response: status, workExperiences: workExperiences)); + } else { + emit(WorkHistoryAddedState( + response: status, workExperiences: workExperiences)); + } + } catch (e) { + emit(WorkHistoryErrorState(message: e.toString())); + } + }); + + +////UPDATE WORK HISTORY +on((event, emit)async{ + emit(WorkHistoryLoadingState()); + // try{ + Map status = await WorkHistoryService.instance.update(oldWorkHistory: event.oldWorkHistory, newWorkHistory: event.workHistory, token: event.token, profileId: event.profileId); + if(status['success']){ + WorkHistory workHistory = WorkHistory.fromJson(status['data']); + workExperiences.removeWhere((WorkHistory work) { + return work.id == event.oldWorkHistory.id; + }); + workExperiences.add(workHistory); + emit(WorkHistoryEditedState(workExperiences: workExperiences,response: status)); + }else{ + emit(WorkHistoryEditedState(response: status, workExperiences: workExperiences)); + } + + // }catch(e){ + // emit(WorkHistoryErrorState(message: e.toString())); + // } +}); + + +////SHOW EDIT WORK HISTORIES + on((event, emit) async { + try { + /////POSITIONS------------------------------------------ + if (agencyPositions.isEmpty) { + List positions = + await WorkHistoryService.instance.getAgencyPosition(); + agencyPositions = positions; + } + + /////AGENCIES------------------------------------------ + if (agencies.isEmpty) { + List newAgencies = + await WorkHistoryService.instance.getAgecies(); + agencies = newAgencies; + } + + /////Category Agency------------------------------------------ + if (agencyCategory.isEmpty) { + List categoryAgencies = + await WorkHistoryService.instance.agencyCategory(); + agencyCategory = categoryAgencies; + } + /////////------------------------------------- + if (appointmentStatus.isEmpty) { + List status = + WorkHistoryService.instance.getAppointmentStatusList(); + appointmentStatus = status; + } + + emit(EditWorkHistoryState( + workHistory: event.workHistory, + agencyPositions: agencyPositions, + appointmentStatus: appointmentStatus, + agencyCategory: agencyCategory, + agencies: agencies)); + } catch (e) { + emit(WorkHistoryErrorState(message: e.toString())); + } + }); + ////SHOW ADD FORM WORK HISTORIES on((event, emit) async { emit(WorkHistoryLoadingState()); try { /////POSITIONS------------------------------------------ - List positions = + List positions = await WorkHistoryService.instance.getAgencyPosition(); agencyPositions = positions; - + /////AGENCIES------------------------------------------ List newAgencies = await WorkHistoryService.instance.getAgecies(); - agencies = newAgencies; + agencies = newAgencies; - /////Category Agency------------------------------------------ + /////Category Agency------------------------------------------ List categoryAgencies = await WorkHistoryService.instance.agencyCategory(); agencyCategory = categoryAgencies; /////////------------------------------------- - List status = WorkHistoryService.instance.getAppointmentStatusList(); - appointmentStatus = status; + List status = + WorkHistoryService.instance.getAppointmentStatusList(); + appointmentStatus = status; - -List agricultureList =[]; -List businessInfoList =[]; -List constructionList =[]; -List educationList =[]; -List financeList =[]; -List foodList =[]; -List gamingList =[]; -List healthList =[]; -List motorList =[]; -List naturalList =[]; -List otherList =[]; -List personalList =[]; -List publicList =[]; -List realStateList =[]; -List safetyList =[]; -List transportList =[]; - for (Category category in agencyCategory) { - if (category.industryClass!.name == "Agriculture & Forestry/Wildlife") { - agricultureList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Business & Information") { - businessInfoList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Construction/Utilities/Contracting") { - constructionList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Education") { - educationList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Finance & Insurance") { - financeList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Food & Hospitality") { - foodList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Gaming") { - gamingList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Health Services") { - healthList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Motor Vehicle") { - motorList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Natural Resources/Environmental") { - naturalList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Other") { - otherList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Personal Services") { - personalList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Public Governance") { - publicList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Real Estate & Housing") { - realStateList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Safety/Security & Legal") { - safetyList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - if (category.industryClass!.name == "Transportation") { - transportList - .add(SingleItemCategoryModel(nameSingleItem: category.name!)); - } - } - - SingleCategoryModel agricultureForestryWildlife = - SingleCategoryModel( - nameCategory: "Agriculture & Forestry/Wildlife", - singleItemCategoryList: agricultureList); - - SingleCategoryModel businessInformation = SingleCategoryModel( - nameCategory: "Business & Information", singleItemCategoryList: businessInfoList); - - SingleCategoryModel constructionUtilitiesContracting = - SingleCategoryModel( - nameCategory: "Construction/Utilities/Contracting", - singleItemCategoryList: constructionList); - SingleCategoryModel education = SingleCategoryModel( - nameCategory: "Education", singleItemCategoryList: educationList); - SingleCategoryModel financeInsurance = SingleCategoryModel( - nameCategory: "Finance & Insurance", singleItemCategoryList: financeList); - SingleCategoryModel foodHospitality = SingleCategoryModel( - nameCategory: "Food & Hospitality", singleItemCategoryList: foodList); - SingleCategoryModel gaming = SingleCategoryModel( - nameCategory: "Gaming", singleItemCategoryList: gamingList); - SingleCategoryModel healthServices = SingleCategoryModel( - nameCategory: "Health Services", singleItemCategoryList: healthList); - SingleCategoryModel motorVehicle = SingleCategoryModel( - nameCategory: "Motor Vehicle", singleItemCategoryList: motorList); - SingleCategoryModel naturalResourcesEnvironmental = - SingleCategoryModel( - nameCategory: "Natural Resources/Environmental", - singleItemCategoryList: naturalList); - SingleCategoryModel others = SingleCategoryModel( - nameCategory: "Others", singleItemCategoryList: otherList); - SingleCategoryModel personalServices = SingleCategoryModel( - nameCategory: "Personal Services", singleItemCategoryList: personalList); - SingleCategoryModel publicGovernance = SingleCategoryModel( - nameCategory: "Public Governance", singleItemCategoryList: publicList); - SingleCategoryModel realStateHousing = SingleCategoryModel( - nameCategory: "Real Estate & Housing", singleItemCategoryList: realStateList); - SingleCategoryModel safetySecurityLegal = SingleCategoryModel( - nameCategory: "Safety/Security & Legal", - singleItemCategoryList: safetyList); - SingleCategoryModel transportation = SingleCategoryModel( - nameCategory: "Transportation", singleItemCategoryList: transportList); - final List agencyCategoryDropdownData = [ - agricultureForestryWildlife, - businessInformation, - constructionUtilitiesContracting, - education, - financeInsurance, - foodHospitality, - gaming, - healthServices, - motorVehicle, - naturalResourcesEnvironmental, - others, - personalServices, - publicGovernance, - realStateHousing, - safetySecurityLegal, - transportation, - ]; emit(AddWorkHistoryState( - agencyPositions:agencyPositions, + agencyPositions: agencyPositions, appointmentStatus: appointmentStatus, - agencyCategory: agencyCategoryDropdownData, + agencyCategory: agencyCategory, agencies: agencies)); } catch (e) { emit(WorkHistoryErrorState(message: e.toString())); diff --git a/lib/bloc/profile/workHistory/workHistory_event.dart b/lib/bloc/profile/workHistory/workHistory_event.dart index 5624086..5a0dbe1 100644 --- a/lib/bloc/profile/workHistory/workHistory_event.dart +++ b/lib/bloc/profile/workHistory/workHistory_event.dart @@ -26,6 +26,13 @@ class LoadWorkHistories extends WorkHistorytEvent{ class ShowAddWorkHistoryForm extends WorkHistorytEvent{ +} +class ShowEditWorkHistoryForm extends WorkHistorytEvent{ + final WorkHistory workHistory; + const ShowEditWorkHistoryForm({required this.workHistory}); + @override + List get props => [workHistory]; + } class DeleteWorkHistory extends WorkHistorytEvent{ final List workHistories; @@ -37,4 +44,24 @@ class DeleteWorkHistory extends WorkHistorytEvent{ List get props => [token, profileId,workHistory, workHistories]; } +class UpdateWorkHistory extends WorkHistorytEvent{ + final WorkHistory workHistory; + final WorkHistory oldWorkHistory; + final String profileId; + final String token; + const UpdateWorkHistory({required this.oldWorkHistory, required this.profileId, required this.token, required this.workHistory}); + @override + List get props => [profileId,token,workHistory,oldWorkHistory]; +} + +class AddWorkHostory extends WorkHistorytEvent{ + final WorkHistory workHistory; + final bool isPrivate; + final int profileId; + final String token; + const AddWorkHostory({required this.workHistory, required this.isPrivate, required this.profileId, required this.token}); + @override + List get props => [workHistory,profileId,token,isPrivate]; +} + diff --git a/lib/bloc/profile/workHistory/workHistory_state.dart b/lib/bloc/profile/workHistory/workHistory_state.dart index ae4a74f..12a2037 100644 --- a/lib/bloc/profile/workHistory/workHistory_state.dart +++ b/lib/bloc/profile/workHistory/workHistory_state.dart @@ -30,9 +30,9 @@ class WorkHistoryErrorState extends WorkHistoryState{ class AddWorkHistoryState extends WorkHistoryState{ - final List agencyPositions; + final List agencyPositions; final List agencies; - final List agencyCategory; + final List agencyCategory; final List appointmentStatus; const AddWorkHistoryState({required this.agencyPositions, required this.appointmentStatus,required this.agencies,required this.agencyCategory}); @@ -41,6 +41,17 @@ class AddWorkHistoryState extends WorkHistoryState{ } +class EditWorkHistoryState extends WorkHistoryState{ + final WorkHistory workHistory; + final List agencyPositions; + final List agencies; + final List agencyCategory; + final List appointmentStatus; + const EditWorkHistoryState({required this.workHistory, required this.agencies,required this.agencyCategory, required this.agencyPositions, required this.appointmentStatus}); + @override + List get props => [workHistory, agencyPositions,appointmentStatus,agencies,agencyCategory]; +} + class DeletedState extends WorkHistoryState{ final List workHistories; final bool success; @@ -48,3 +59,19 @@ class DeletedState extends WorkHistoryState{ @override List get props => [workHistories,success]; } + +class WorkHistoryEditedState extends WorkHistoryState{ + final List workExperiences; + final Map response; + const WorkHistoryEditedState({required this.response, required this.workExperiences}); + @override + List get props => [workExperiences,response]; +} + +class WorkHistoryAddedState extends WorkHistoryState{ + final List workExperiences; + final Map response; + const WorkHistoryAddedState({required this.response, required this.workExperiences}); + @override + List get props => [workExperiences,response]; +} diff --git a/lib/model/utils/agency_position.dart b/lib/model/utils/agency_position.dart index 3e6e48d..f2d4f01 100644 --- a/lib/model/utils/agency_position.dart +++ b/lib/model/utils/agency_position.dart @@ -1,29 +1,7 @@ import 'dart:convert'; -AgencyPosition agencyPositionFromJson(String str) => AgencyPosition.fromJson(json.decode(str)); -String agencyPositionToJson(AgencyPosition data) => json.encode(data.toJson()); - -class AgencyPosition { - AgencyPosition({ - required this.id, - required this.title, - }); - - final int? id; - final String? title; - - factory AgencyPosition.fromJson(Map json) => AgencyPosition( - id: json["id"], - title: json["title"], - ); - - Map toJson() => { - "id": id, - "title": title, - }; -} // To parse this JSON data, do // // final appoinemtStatus = appoinemtStatusFromJson(jsonString); diff --git a/lib/screens/profile/components/eligibility/edit_modal.dart b/lib/screens/profile/components/eligibility/edit_modal.dart index e221f4d..69b7f64 100644 --- a/lib/screens/profile/components/eligibility/edit_modal.dart +++ b/lib/screens/profile/components/eligibility/edit_modal.dart @@ -99,7 +99,7 @@ class _EditEligibilityScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - //ELIGIBILITIES DROPDOWN + ////ELIGIBILITIES DROPDOWN DropdownButtonFormField( validator: (value) => value == null ? 'required' : null, @@ -125,7 +125,7 @@ class _EditEligibilityScreenState extends State { width: screenWidth, child: Row( children: [ - //LICENSE NUMBER + ////LICENSE NUMBER Flexible( flex: 1, child: FormBuilderTextField( @@ -142,7 +142,7 @@ class _EditEligibilityScreenState extends State { const SizedBox( width: 12, ), - //RATING + // //RATING Flexible( flex: 1, child: FormBuilderTextField( @@ -169,7 +169,7 @@ class _EditEligibilityScreenState extends State { width: screenWidth, child: Row( children: [ - //EXAM DATE + // //EXAM DATE Flexible( flex: 1, child: DateTimePicker( diff --git a/lib/screens/profile/components/loading_screen.dart b/lib/screens/profile/components/loading_screen.dart index f3078be..36952e2 100644 --- a/lib/screens/profile/components/loading_screen.dart +++ b/lib/screens/profile/components/loading_screen.dart @@ -135,8 +135,8 @@ class LoadingScreen extends StatelessWidget { ), Center( child: Container( - height: 150, - width: 150, + height: 120, + width: 120, decoration:const BoxDecoration( color: Colors.black87, borderRadius: BorderRadius.all(Radius.circular(25)) @@ -149,7 +149,7 @@ class LoadingScreen extends StatelessWidget { color: Colors.white), SizedBox(height: 10,), - Text("Loading Profile",textAlign: TextAlign.center, style: TextStyle(color: Colors.white),) + Text("Loading Profile",textAlign: TextAlign.center, style: TextStyle(color: Colors.white,fontSize: 10),) ], ), ), diff --git a/lib/screens/profile/components/work_history/add_modal.dart b/lib/screens/profile/components/work_history/add_modal.dart index 522b6ac..d8382e3 100644 --- a/lib/screens/profile/components/work_history/add_modal.dart +++ b/lib/screens/profile/components/work_history/add_modal.dart @@ -6,12 +6,14 @@ import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:fluttericon/font_awesome_icons.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:searchfield/searchfield.dart'; -import 'package:select2dot1/select2dot1.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/workHistory/workHistory_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart'; +import 'package:unit2/model/profile/work_history.dart'; import 'package:unit2/model/utils/agency.dart'; import 'package:unit2/model/utils/agency_position.dart'; +import 'package:unit2/model/utils/category.dart'; +import 'package:unit2/theme-data.dart/box_shadow.dart'; import 'package:unit2/theme-data.dart/btn-style.dart'; import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/theme-data.dart/form-style.dart'; @@ -19,6 +21,8 @@ import 'package:unit2/utils/global.dart'; import 'package:unit2/utils/text_container.dart'; import 'package:unit2/utils/validators.dart'; +import '../../../../model/utils/position.dart'; + class AddWorkHistoryScreen extends StatefulWidget { const AddWorkHistoryScreen({super.key}); @@ -32,15 +36,13 @@ class _AddWorkHistoryScreenState extends State { final toDateController = TextEditingController(); final fromDateController = TextEditingController(); final _formKey = GlobalKey(); - AgencyPosition? selectedPosition; + Position? selectedPosition; Agency? selectedAgency; AppoinemtStatus? selectedStatus; + Category? selectedAgencyCategory; String? salary; String? salaryGrade; String? salaryGradeStep; - SingleItemCategoryModel selectedAgencyCategory = - const SingleItemCategoryModel(nameSingleItem: ""); - ScrollController agencyScrollController = ScrollController(); bool showAgency = false; bool showSalaryGradeAndSalaryStep = false; bool? isPrivate = false; @@ -49,6 +51,9 @@ class _AddWorkHistoryScreenState extends State { final agencyFocusNode = FocusNode(); final positionFocusNode = FocusNode(); final appointmentStatusNode = FocusNode(); + final agencyCategoryFocusNode = FocusNode(); + int? profileId; + String? token; @override void dispose() { addPositionController.dispose(); @@ -60,10 +65,11 @@ class _AddWorkHistoryScreenState extends State { @override Widget build(BuildContext context) { - print("exc"); return BlocBuilder( builder: (context, state) { if (state is UserLoggedIn) { + profileId = state.userData!.user!.login!.user!.profileId; + token = state.userData!.user!.login!.token; return BlocBuilder( builder: (context, state) { if (state is ProfileLoaded) { @@ -88,10 +94,20 @@ class _AddWorkHistoryScreenState extends State { ////POSITIONS StatefulBuilder(builder: (context, setState) { return SearchField( + itemHeight: 50, + suggestionsDecoration: box1(), suggestions: state.agencyPositions - .map((AgencyPosition position) => + .map((Position position) => SearchFieldListItem(position.title!, - item: position)) + item: position, + child: Padding( + padding: const EdgeInsets + .symmetric( + horizontal: 10), + child: ListTile( + title: + Text(position.title!), + )))) .toList(), focusNode: positionFocusNode, searchInputDecoration: @@ -99,11 +115,6 @@ class _AddWorkHistoryScreenState extends State { .copyWith( suffixIcon: const Icon( Icons.arrow_drop_down)), - initialValue: selectedPosition != null - ? SearchFieldListItem( - selectedPosition!.title!, - item: selectedPosition) - : null, onSuggestionTap: (position) { setState(() { selectedPosition = position.item; @@ -111,7 +122,7 @@ class _AddWorkHistoryScreenState extends State { }); }, emptyWidget: Container( - color: Colors.white, + decoration: box1(), height: 100, child: Column( mainAxisAlignment: @@ -122,7 +133,7 @@ class _AddWorkHistoryScreenState extends State { const SizedBox( height: 20, ), - const Text("No result found"), + const Text("No result found..."), const SizedBox( height: 10, ), @@ -134,7 +145,7 @@ class _AddWorkHistoryScreenState extends State { context) { return AlertDialog( title: const Text( - "Add Position"), + "Add Position?"), content: SizedBox( height: 130, child: Column( @@ -157,21 +168,20 @@ class _AddWorkHistoryScreenState extends State { child: ElevatedButton( style: mainBtnStyle(primary, Colors.transparent, second), onPressed: () { - AgencyPosition - newAgencyPosition = - AgencyPosition(id: null, title: addPositionController.text.toUpperCase()); - - state.agencyPositions.insert( - 0, - newAgencyPosition); - selectedPosition = - newAgencyPosition; - addPositionController.text = - ""; setState( - () {}); - Navigator.pop( - context); + () { + Position + newAgencyPosition = + Position(id: null, title: addPositionController.text.toUpperCase()); + + state.agencyPositions.insert(0, + newAgencyPosition); + selectedPosition = + newAgencyPosition; + addPositionController.text = + ""; + Navigator.pop(context); + }); }, child: const Text("Add"))), ], @@ -284,7 +294,7 @@ class _AddWorkHistoryScreenState extends State { return null; }, emptyWidget: Container( - color: Colors.white, + decoration: box1(), height: 100, child: Column( mainAxisAlignment: @@ -357,37 +367,70 @@ class _AddWorkHistoryScreenState extends State { ]), ), ), - ////AGENCY CATEGORY - + + SizedBox( + height: showAgency ? 12 : 0, + ), + ////SHOW CATEGORY AGENCY SizedBox( child: showAgency - ? Select2dot1( - selectEmptyInfoSettings: - const SelectEmptyInfoSettings( - text: - "Select Agency Category"), - - scrollController: - agencyScrollController, - selectDataController: - SelectDataController( - isMultiSelect: false, - data: state - .agencyCategory, - initSelected: [ - selectedAgencyCategory - ]), - onChanged: (value) { - print("sdasdsa"); - // print(value[0].nameSingleItem); - // setState(() { - // selectedAgencyCategory = - // value[0]; - // print(value[0].nameSingleItem); - // agencyFocusNode.unfocus(); - // }); + ? SearchField( + focusNode: + agencyCategoryFocusNode, + itemHeight: 70, + suggestions: state + .agencyCategory + .map((Category category) => + SearchFieldListItem( + category.name!, + item: category, + child: ListTile( + title: Text( + category + .name!), + subtitle: Text( + category + .industryClass! + .name!), + ))) + .toList(), + emptyWidget: Container( + height: 100, + decoration: box1(), + child: const Center( + child: Text( + "No result found ...")), + ), + onSuggestionTap: + (agencyCategory) { + setState(() { + selectedAgencyCategory = + agencyCategory.item; + agencyCategoryFocusNode + .unfocus(); + selectedAgency = Agency( + id: null, + name: selectedAgency! + .name, + category: + selectedAgencyCategory, + privateEntity: null); + }); }, - ) + searchInputDecoration: + normalTextFieldStyle( + "Category *", "") + .copyWith( + suffixIcon: + const Icon(Icons + .arrow_drop_down)), + validator: (value) { + if (value!.isEmpty) { + return "This field is required"; + } + return null; + }, + ) : const SizedBox(), ), @@ -427,7 +470,16 @@ class _AddWorkHistoryScreenState extends State { showSalaryGradeAndSalaryStep = true; } + selectedAgency = Agency( + id: null, + name: selectedAgency! + .name, + category: + selectedAgencyCategory, + privateEntity: value == "YES"?true:false); agencyFocusNode.unfocus(); + agencyCategoryFocusNode + .unfocus(); }); }, @@ -466,6 +518,22 @@ class _AddWorkHistoryScreenState extends State { salaryGrade = value; }, + validator: + FormBuilderValidators + .compose([ + FormBuilderValidators + .integer( + radix: 10, + errorText: + "Please enter a number"), + FormBuilderValidators + .numeric( + errorText: + "Please enter a number") + ]), + autovalidateMode: + AutovalidateMode + .onUserInteraction, ), ), const SizedBox( @@ -483,6 +551,22 @@ class _AddWorkHistoryScreenState extends State { normalTextFieldStyle( "SG Step (SG)", "0"), + validator: + FormBuilderValidators + .compose([ + FormBuilderValidators + .integer( + radix: 10, + errorText: + "Please enter a number"), + FormBuilderValidators + .numeric( + errorText: + "Please enter a number") + ]), + autovalidateMode: + AutovalidateMode + .onUserInteraction, onChanged: (value) { setState(() { salaryGradeStep = @@ -601,7 +685,6 @@ class _AddWorkHistoryScreenState extends State { ) : DateTimePicker( validator: (val) { - print(val); return null; }, controller: @@ -646,11 +729,44 @@ class _AddWorkHistoryScreenState extends State { print(salary); print(fromDateController.text); print(toDateController.text); - print(isPrivate); + print(salaryGrade); print(salaryGradeStep); - if (_formKey.currentState! - .validate()) {} + print(isPrivate); + if (_formKey.currentState!.validate()) { + WorkHistory workHistory = WorkHistory( + position: selectedPosition, + id: null, + agency: selectedAgency, + fromDate: fromDateController + .text.isEmpty + ? null + : DateTime.parse( + fromDateController.text), + toDate: toDateController.text.isEmpty || + toDateController.text + .toUpperCase() == + "PRESENT" + ? null + : DateTime.parse( + toDateController.text), + salaryGrade: salaryGrade == null + ? null + : int.parse(salaryGrade!), + sgStep: salaryGradeStep == null + ? null + : int.parse(salaryGradeStep!), + monthlySalary: + double.parse(salary!), + appointmentStatus: + selectedStatus!.value); + context.read().add( + AddWorkHostory( + workHistory: workHistory, + profileId: profileId!, + token: token!, + isPrivate: isPrivate!)); + } }, child: const Text(submit)), ), diff --git a/lib/screens/profile/components/work_history/edit_modal.dart b/lib/screens/profile/components/work_history/edit_modal.dart new file mode 100644 index 0000000..975bfcd --- /dev/null +++ b/lib/screens/profile/components/work_history/edit_modal.dart @@ -0,0 +1,828 @@ +import 'package:date_time_picker/date_time_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:flutter_progress_hud/flutter_progress_hud.dart'; +import 'package:fluttericon/font_awesome_icons.dart'; +import 'package:form_builder_validators/form_builder_validators.dart'; +import 'package:searchfield/searchfield.dart'; +import '../../../../bloc/profile/profile_bloc.dart'; +import '../../../../bloc/profile/workHistory/workHistory_bloc.dart'; +import '../../../../bloc/user/user_bloc.dart'; +import '../../../../model/profile/work_history.dart'; +import '../../../../model/utils/agency.dart'; +import '../../../../model/utils/agency_position.dart'; +import '../../../../model/utils/category.dart'; +import '../../../../model/utils/position.dart'; +import '../../../../theme-data.dart/box_shadow.dart'; +import '../../../../theme-data.dart/btn-style.dart'; +import '../../../../theme-data.dart/colors.dart'; +import '../../../../theme-data.dart/form-style.dart'; +import '../../../../utils/global.dart'; +import '../../../../utils/text_container.dart'; +import '../../../../utils/validators.dart'; + +class EditWorkHistoryScreen extends StatefulWidget { + const EditWorkHistoryScreen({super.key}); + + @override + State createState() => _EditWorkHistoryScreenState(); +} + +class _EditWorkHistoryScreenState extends State { + final addAgencyController = TextEditingController(); + final addPositionController = TextEditingController(); + final toDateController = TextEditingController(); + final fromDateController = TextEditingController(); + final oldPositionController = TextEditingController(); + final oldAppointmentStatusController = TextEditingController(); + final oldAgencyController = TextEditingController(); + final _formKey = GlobalKey(); + Position? selectedPosition; + Agency? selectedAgency; + AppoinemtStatus? selectedStatus; + Category? selectedAgencyCategory; + String? salary; + String? salaryGrade; + String? salaryGradeStep; + //show agency category is a variable to show adding of agency category if you add agency manually + bool showAgencyCategory = false; + //showSalaryGadeAndSalaryStep is a variable that will show salary + //and salary step if selected agency is government + bool showSalaryGradeAndSalaryStep = false; + //isPrivate is the value of the isPrivate radion button + bool? isPrivate = false; + //showIsPrivateRadion is a variable that will show isPrivate radio if you + //add agency manually + bool showIsPrivateRadio = false; + bool currentlyEmployed = false; + final agencyFocusNode = FocusNode(); + final positionFocusNode = FocusNode(); + final appointmentStatusNode = FocusNode(); + final agencyCategoryFocusNode = FocusNode(); + int? profileId; + String? token; + @override + void dispose() { + addPositionController.dispose(); + addAgencyController.dispose(); + toDateController.dispose(); + fromDateController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is UserLoggedIn) { + profileId = state.userData!.user!.login!.user!.profileId; + token = state.userData!.user!.login!.token; + return BlocBuilder( + builder: (context, state) { + if (state is ProfileLoaded) { + return BlocConsumer( + listener: (context, state) { + if (state is AddWorkHistoryState) { + final progress = ProgressHUD.of(context); + progress!.dismiss(); + } + }, builder: (context, state) { + if (state is EditWorkHistoryState) { + oldPositionController.text = + state.workHistory.position!.title!; + oldAppointmentStatusController.text = + state.workHistory.appointmentStatus!; + oldAgencyController.text = state.workHistory.agency!.name!; + currentlyEmployed = + state.workHistory.toDate == null ? true : false; + showSalaryGradeAndSalaryStep = + !state.workHistory.agency!.privateEntity!; + fromDateController.text = + state.workHistory.fromDate.toString(); + toDateController.text = state.workHistory.toDate.toString(); + currentlyEmployed = + state.workHistory.toDate == null ? true : false; + + return SingleChildScrollView( + child: SizedBox( + height: blockSizeVertical * 90, + child: FormBuilder( + key: _formKey, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 25, horizontal: 18), + child: Column( + children: [ + ////POSITIONS + StatefulBuilder(builder: (context, setState) { + return SearchField( + controller: oldPositionController, + itemHeight: 50, + suggestionsDecoration: box1(), + suggestions: state.agencyPositions + .map((Position position) => + SearchFieldListItem(position.title!, + item: position, + child: Padding( + padding: const EdgeInsets + .symmetric( + horizontal: 10), + child: ListTile( + title: + Text(position.title!), + )))) + .toList(), + focusNode: positionFocusNode, + searchInputDecoration: + normalTextFieldStyle("Position *", "") + .copyWith( + suffixIcon: const Icon( + Icons.arrow_drop_down)), + onSuggestionTap: (position) { + setState(() { + selectedPosition = position.item; + positionFocusNode.unfocus(); + }); + }, + emptyWidget: Container( + decoration: box1(), + height: 100, + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + const SizedBox( + height: 20, + ), + const Text("No result found..."), + const SizedBox( + height: 10, + ), + TextButton( + onPressed: () { + showDialog( + context: context, + builder: (BuildContext + context) { + return AlertDialog( + title: const Text( + "Add Position?"), + content: SizedBox( + height: 130, + child: Column( + children: [ + TextFormField( + controller: + addPositionController, + decoration: + normalTextFieldStyle( + "", + ""), + ), + const SizedBox( + height: 12, + ), + SizedBox( + width: double + .infinity, + height: 50, + child: ElevatedButton( + style: mainBtnStyle(primary, Colors.transparent, second), + onPressed: () { + setState( + () { + Position + newAgencyPosition = + Position(id: null, title: addPositionController.text.toUpperCase()); + state.agencyPositions.insert(0, + newAgencyPosition); + selectedPosition = + newAgencyPosition; + addPositionController.text = + ""; + Navigator.pop(context); + }); + }, + child: const Text("Add"))), + ], + ), + ), + ); + }); + }, + child: + const Text("Add position")) + ]), + ), + validator: (position) { + if (position!.isEmpty) { + return "This field is required"; + } + return null; + }, + ); + }), + const SizedBox( + height: 12, + ), + ////APPOINTMENT STATUS' + SearchField( + controller: oldAppointmentStatusController, + suggestions: state.appointmentStatus + .map((AppoinemtStatus status) => + SearchFieldListItem(status.label, + item: status)) + .toList(), + focusNode: appointmentStatusNode, + validator: (value) { + if (value!.isEmpty) { + return "This field is required"; + } + return null; + }, + onSuggestionTap: (status) { + selectedStatus = status.item; + appointmentStatusNode.unfocus(); + }, + searchInputDecoration: normalTextFieldStyle( + "Appointment Status", "") + .copyWith( + suffixIcon: const Icon( + Icons.arrow_drop_down)), + ), + + const SizedBox( + height: 12, + ), + + ////AGENCY + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + SearchField( + controller: oldAgencyController, + itemHeight: 70, + focusNode: agencyFocusNode, + suggestions: state.agencies + .map((Agency agency) => + SearchFieldListItem( + agency.name!, + item: agency, + child: ListTile( + title: Text( + agency.name!, + overflow: TextOverflow + .ellipsis, + ), + subtitle: Text( + agency.privateEntity == + true + ? "Private" + : "Government"), + ))) + .toList(), + searchInputDecoration: + normalTextFieldStyle("Agency *", "") + .copyWith( + suffixIcon: const Icon( + Icons.arrow_drop_down)), + onSuggestionTap: (agency) { + setState(() { + selectedAgency = agency.item; + if (selectedAgency!.privateEntity == + null) { + showIsPrivateRadio = true; + } else { + showIsPrivateRadio = false; + } + if (selectedAgency!.privateEntity == + true) { + showSalaryGradeAndSalaryStep = + false; + } + if (selectedAgency!.privateEntity == + false) { + showSalaryGradeAndSalaryStep = + true; + } + agencyFocusNode.unfocus(); + }); + }, + validator: (agency) { + if (agency!.isEmpty) { + return "This field is required"; + } + return null; + }, + emptyWidget: Container( + decoration: box1(), + height: 100, + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + const SizedBox( + height: 20, + ), + const Text("No result found"), + const SizedBox( + height: 10, + ), + TextButton( + onPressed: () { + showDialog( + context: context, + builder: (BuildContext + context) { + return AlertDialog( + title: const Text( + "Add Position"), + content: SizedBox( + height: 130, + child: Column( + children: [ + TextFormField( + controller: + addAgencyController, + decoration: + normalTextFieldStyle( + "", + ""), + ), + const SizedBox( + height: + 12, + ), + SizedBox( + width: double + .infinity, + height: + 50, + child: ElevatedButton( + style: mainBtnStyle(primary, Colors.transparent, second), + onPressed: () { + setState(() { + Agency newAgency = Agency(id: null, name: addAgencyController.text.toUpperCase(), category: null, privateEntity: null); + state.agencies.insert(0, newAgency); + selectedAgency = newAgency; + addAgencyController.text = ""; + showAgencyCategory = true; + + showIsPrivateRadio = true; + + Navigator.pop(context); + }); + }, + child: const Text("Add"))), + ], + ), + ), + ); + }); + }, + child: const Text( + "Add Agency")) + ]), + ), + ), + + SizedBox( + height: showAgencyCategory ? 12 : 0, + ), + ////SHOW AGENCY CATEGORY + SizedBox( + child: showAgencyCategory + ? SearchField( + focusNode: + agencyCategoryFocusNode, + itemHeight: 70, + suggestions: state + .agencyCategory + .map((Category category) => + SearchFieldListItem( + category.name!, + item: category, + child: ListTile( + title: Text( + category + .name!), + subtitle: Text( + category + .industryClass! + .name!), + ))) + .toList(), + emptyWidget: Container( + height: 100, + decoration: box1(), + child: const Center( + child: Text( + "No result found ...")), + ), + onSuggestionTap: + (agencyCategory) { + setState(() { + selectedAgencyCategory = + agencyCategory.item; + agencyCategoryFocusNode + .unfocus(); + selectedAgency = Agency( + id: null, + name: selectedAgency! + .name, + category: + selectedAgencyCategory, + privateEntity: null); + }); + }, + searchInputDecoration: + normalTextFieldStyle( + "Category *", "") + .copyWith( + suffixIcon: + const Icon(Icons + .arrow_drop_down)), + validator: (value) { + if (value!.isEmpty) { + return "This field is required"; + } + return null; + }, + ) + : const SizedBox(), + ), + + ////PRVIATE SECTOR + SizedBox( + child: showIsPrivateRadio + ? FormBuilderRadioGroup( + decoration: InputDecoration( + border: InputBorder.none, + label: Row( + children: [ + Text( + "Is this private sector? ", + style: Theme.of( + context) + .textTheme + .headlineSmall! + .copyWith( + fontSize: 24), + ), + const Icon(FontAwesome + .help_circled) + ], + ), + ), + + ////onvhange private sector + onChanged: (value) { + setState(() { + if (value.toString() == + "YES") { + isPrivate = true; + showSalaryGradeAndSalaryStep = + false; + } else { + isPrivate = false; + showSalaryGradeAndSalaryStep = + true; + } + selectedAgency = Agency( + id: null, + name: selectedAgency! + .name, + category: + selectedAgencyCategory, + privateEntity: + value == "YES" + ? true + : false); + agencyFocusNode.unfocus(); + agencyCategoryFocusNode + .unfocus(); + }); + }, + + name: 'isPrivate', + validator: + FormBuilderValidators + .required(), + options: ["YES", "NO"] + .map((lang) => + FormBuilderFieldOption( + value: lang)) + .toList(growable: false), + ) + : const SizedBox()), + SizedBox( + height: showSalaryGradeAndSalaryStep + ? 12 + : 0, + ), + ////SALARY GRADE AND SALARY GRADE STEP + SizedBox( + child: showSalaryGradeAndSalaryStep + ? Column( + children: [ + Row( + children: [ + ////SALARY GRADE + Flexible( + flex: 1, + child: + FormBuilderTextField( + initialValue: state + .workHistory + .salaryGrade + ?.toString(), + name: + 'salary_grade', + keyboardType: + TextInputType + .number, + decoration: + normalTextFieldStyle( + "Salary Grade (SG)", + "0"), + validator: + integerAndNumeric, + autovalidateMode: + AutovalidateMode + .onUserInteraction, + ), + ), + const SizedBox( + width: 12, + ), + //// SALARY STEP + Flexible( + flex: 1, + child: + FormBuilderTextField( + initialValue: state + .workHistory + .sgStep + ?.toString(), + name: 'salary_step', + keyboardType: + TextInputType + .number, + decoration: + normalTextFieldStyle( + "SG Step (SG)", + "0"), + validator: + integerAndNumeric, + autovalidateMode: + AutovalidateMode + .onUserInteraction, + ), + ) + ], + ) + ], + ) + : null), + ], + ); + }), + const SizedBox( + height: 12, + ), + ////MONTHLY SALARY + FormBuilderTextField( + initialValue: state.workHistory.monthlySalary + .toString(), + onChanged: (value) { + setState(() { + salary = value; + }); + }, + validator: numericRequired, + name: "salary", + decoration: normalTextFieldStyle( + "Monthly Salary *", "") + .copyWith(prefix: const Text("₱ ")), + ), + + const SizedBox( + height: 12, + ), + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + ////CURRENTLY EMPLOYED + FormBuilderSwitch( + initialValue: currentlyEmployed, + activeColor: second, + onChanged: (value) { + setState(() { + if (value == true) { + currentlyEmployed = true; + toDateController.text = "PRESENT"; + } else { + currentlyEmployed = false; + toDateController.text = ""; + } + }); + }, + decoration: + normalTextFieldStyle("", ''), + name: 'overseas', + title: + const Text("Currently Employed?"), + ), + const SizedBox( + height: 12, + ), + SizedBox( + width: screenWidth, + child: Row( + children: [ + //// FROM DATE + Flexible( + flex: 1, + child: DateTimePicker( + validator: (value) { + if (value == null) { + return "This field is required"; + } + return null; + }, + use24HourFormat: false, + icon: const Icon( + Icons.date_range), + controller: + fromDateController, + firstDate: DateTime(1970), + lastDate: DateTime(2100), + timeHintText: + "Date of Examination/Conferment", + decoration: + normalTextFieldStyle( + "From *", + "From *") + .copyWith( + prefixIcon: + const Icon( + Icons.date_range, + color: Colors.black87, + )), + initialValue: null, + )), + const SizedBox( + width: 12, + ), + //// TO DATE + Flexible( + flex: 1, + child: currentlyEmployed + ? TextFormField( + enabled: false, + initialValue: "PRESENT", + style: const TextStyle( + color: + Colors.black45), + decoration: + normalTextFieldStyle( + "", "") + .copyWith( + prefixIcon: + const Icon( + Icons.date_range, + color: Colors.black45, + )), + ) + : DateTimePicker( + validator: (val) { + return null; + }, + controller: + toDateController, + firstDate: DateTime(1970), + lastDate: DateTime(2100), + decoration: normalTextFieldStyle( + "To *", "To *") + .copyWith( + prefixIcon: + const Icon( + Icons + .date_range, + color: Colors + .black87, + ), + prefixText: + currentlyEmployed + ? "PRESENT" + : ""), + initialValue: null, + ), + ), + ], + ), + ), + ], + ); + }), + const Expanded(child: SizedBox()), + ////SUBMIT BUTTON + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: mainBtnStyle( + primary, Colors.transparent, second), + onPressed: () { + if (_formKey.currentState! + .saveAndValidate()) { + salary = _formKey + .currentState!.value['salary']; + selectedPosition ??= + state.workHistory.position; + salaryGrade = _formKey.currentState! + .value['salary_grade']; + salaryGradeStep = _formKey + .currentState! + .value['salary_step']; + selectedAgency ??= + state.workHistory.agency; + + selectedStatus ??= AppoinemtStatus( + value: state.workHistory + .appointmentStatus!, + label: state.workHistory + .appointmentStatus!); + WorkHistory newWorkHistory = + WorkHistory( + id: state.workHistory.id, + position: selectedPosition, + agency: selectedAgency, + fromDate: fromDateController + .text.isEmpty + ? null + : DateTime.parse( + fromDateController.text), + toDate: toDateController + .text.isEmpty || + toDateController.text + .toUpperCase() == + "PRESENT" || + toDateController.text + .toLowerCase() == + 'null' + ? null + : DateTime.parse( + toDateController.text), + monthlySalary: + double.parse(salary!), + appointmentStatus: + selectedStatus!.value, + salaryGrade: salaryGrade == null + ? null + : int.parse(salaryGrade!), + sgStep: salaryGradeStep == null + ? null + : int.parse(salaryGradeStep!), + ); + context.read().add( + UpdateWorkHistory( + oldWorkHistory: + state.workHistory, + profileId: + profileId.toString(), + token: token!, + workHistory: newWorkHistory)); + } + }, + child: const Text(submit)), + ), + const SizedBox( + height: 20, + ), + ], + ), + ), + ), + ), + ); + } + return Container(); + }); + } + return Container(); + }, + ); + } + return const Center( + child: Text("Add Work History"), + ); + }, + ); + } +} diff --git a/lib/screens/profile/components/work_history_screen.dart b/lib/screens/profile/components/work_history_screen.dart index 580d33a..c725291 100644 --- a/lib/screens/profile/components/work_history_screen.dart +++ b/lib/screens/profile/components/work_history_screen.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -8,6 +10,7 @@ import 'package:intl/intl.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/screens/profile/components/work_history/add_modal.dart'; +import 'package:unit2/screens/profile/components/work_history/edit_modal.dart'; import 'package:unit2/theme-data.dart/box_shadow.dart'; import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/utils/text_container.dart'; @@ -16,6 +19,7 @@ import 'package:unit2/widgets/empty_data.dart'; import 'package:unit2/widgets/error_state.dart'; import '../../../bloc/profile/workHistory/workHistory_bloc.dart'; +import '../../../model/profile/work_history.dart'; import '../../../utils/alerts.dart'; import '../../../utils/global.dart'; @@ -64,7 +68,7 @@ class WorkHistoryScreen extends StatelessWidget { } if (state is WorkHistoryLoaded || state is WorkHistoryErrorState || - state is AddWorkHistoryState) { + state is AddWorkHistoryState ||state is WorkHistoryAddedState || state is EditWorkHistoryState) { final progress = ProgressHUD.of(context); progress!.dismiss(); } @@ -88,6 +92,44 @@ class WorkHistoryScreen extends StatelessWidget { }); } } + ////ADDED STATE + if(state is WorkHistoryAddedState){ + if (state.response['success']) { + successAlert(context, "Adding Successfull!", + state.response['message'], () { + Navigator.of(context).pop(); + context.read().add(LoadWorkHistories( + workHistories: state.workExperiences)); + }); + } else { + errorAlert(context, "Adding Failed", + "Something went wrong. Please try again.", + () { + Navigator.of(context).pop(); + context.read().add(LoadWorkHistories( + workHistories: state.workExperiences)); + }); + } + } + //// EDITED STATE + if(state is WorkHistoryEditedState){ + if (state.response['success']) { + successAlert(context, "Update Successfull!", + state.response['message'], () { + Navigator.of(context).pop(); + context.read().add(LoadWorkHistories( + workHistories: state.workExperiences)); + }); + } else { + errorAlert(context, "Update Failed", + "Something went wrong. Please try again.", + () { + Navigator.of(context).pop(); + context.read().add(LoadWorkHistories( + workHistories: state.workExperiences)); + }); + } + } }, builder: (context, state) { if (state is WorkHistoryLoaded) { @@ -188,6 +230,8 @@ class WorkHistoryScreen extends StatelessWidget { } if (value == 1) { ////edit eligibilty-= = = = = = = = =>> + WorkHistory workHistory = state.workExperiences[index]; + context.read().add(ShowEditWorkHistoryForm(workHistory: workHistory)); } }, menuItems: [ @@ -227,6 +271,9 @@ class WorkHistoryScreen extends StatelessWidget { if (state is AddWorkHistoryState) { return const AddWorkHistoryScreen(); } + if(state is EditWorkHistoryState){ + return const EditWorkHistoryScreen(); + } if (state is WorkHistoryErrorState) { return SomethingWentWrong( message: state.message, onpressed: () {}); diff --git a/lib/sevices/profile/work_history_services.dart b/lib/sevices/profile/work_history_services.dart index cb93409..bb43770 100644 --- a/lib/sevices/profile/work_history_services.dart +++ b/lib/sevices/profile/work_history_services.dart @@ -6,6 +6,7 @@ import 'package:http/http.dart' as http; import 'package:unit2/model/utils/agency.dart'; import 'package:unit2/model/utils/agency_position.dart'; import 'package:unit2/model/utils/category.dart'; +import 'package:unit2/model/utils/position.dart'; import 'package:unit2/utils/request.dart'; import '../../utils/urls.dart'; @@ -14,6 +15,7 @@ class WorkHistoryService { static final WorkHistoryService _instance = WorkHistoryService(); static WorkHistoryService get instance => _instance; +//get all workhistories Future> getWorkExperiences( int profileId, String token) async { List workExperiences = []; @@ -40,6 +42,7 @@ class WorkHistoryService { return workExperiences; } +//get agencies Future> getAgecies() async { List agencies = []; String path = Url.instance.getAgencies(); @@ -64,6 +67,7 @@ class WorkHistoryService { return agencies; } +//delete workhistory Future delete( {required int profileId, required String token, @@ -103,6 +107,7 @@ class WorkHistoryService { return success!; } +//get agency category Future> agencyCategory() async { List agencyCategory = []; String path = Url.instance.getAgencyCategory(); @@ -127,8 +132,89 @@ class WorkHistoryService { return agencyCategory; } - Future> getAgencyPosition() async { - List agencyPositions = []; + //edit work history + Future> update({required WorkHistory oldWorkHistory, required WorkHistory newWorkHistory, required String token, required String profileId})async{ + Map? statusResponse={}; + String authtoken = "Token $token"; + String path = '${Url.instance.updateWorkHistories()}$profileId/'; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': authtoken + }; + Map body = { + "id":newWorkHistory.id, + "position_id":newWorkHistory.position!.id, + "agency_id":newWorkHistory.agency!.id, + "from_date":newWorkHistory.fromDate?.toString(), + "to_date":newWorkHistory.toDate?.toString(), + "monthly_salary":newWorkHistory.monthlySalary, + "appointment_status":newWorkHistory.appointmentStatus, + "salary_grade":newWorkHistory.salaryGrade, + "sg_step":newWorkHistory.sgStep, + "_positionName":newWorkHistory.position!.title!, + "_agencyName":newWorkHistory.agency!.name!, + "_agencyCatId":newWorkHistory.agency!.category!.id!, + "_privateEntity":newWorkHistory.agency!.privateEntity, + "oldPosId":oldWorkHistory.position!.id, + "_oldAgencyId":oldWorkHistory.agency!.id, + "oldFromDate":oldWorkHistory.fromDate?.toString(), + }; + // try{ + http.Response response = await Request.instance.putRequest(path: path, headers: headers, body: body, param: {}); + if(response.statusCode == 200 ){ + Map data = jsonDecode(response.body); + statusResponse = data; + }else{ + statusResponse.addAll({'success':false}); + } + return statusResponse; + // }catch(e){ + // throw e.toString(); + // } + } + + //Add work history + Future>add({required WorkHistory workHistory, required String token, required int profileId , required bool isPrivate})async{ + String authtoken = "Token $token"; + String path = '${Url.instance.addWorkHistory()}$profileId/'; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': authtoken + }; + Map statusResponse = {}; + Map body = { + 'position_id':workHistory.position?.id, + 'agency_id': workHistory.agency?.id, + 'from_date': workHistory.fromDate?.toString(), + 'to_date': workHistory.toDate?.toString(), + 'monthly_salary': workHistory.monthlySalary, + 'appointment_status': workHistory.appointmentStatus, + 'salary_grade': workHistory.salaryGrade, + 'sg_step':workHistory.sgStep, + '_positionName':workHistory.position?.title, + '_agencyName':workHistory.agency?.name, + '_agencyCatId':workHistory.agency?.category?.id, + '_privateEntity':workHistory.agency?.privateEntity, + }; + try{ + http.Response response = await Request.instance.postRequest(path: path,param: {},body: body,headers: headers); + if(response.statusCode == 201){ + Map data = jsonDecode(response.body); + statusResponse = data; + + }else{ + statusResponse.addAll({'success':false}); + } + return statusResponse; + }catch(e){ + throw e.toString(); + } + + } + +//get agency position + Future> getAgencyPosition() async { + List agencyPositions = []; String path = Url.instance.getPositions(); Map headers = { 'Content-Type': 'application/json; charset=UTF-8', @@ -140,7 +226,7 @@ class WorkHistoryService { Map data = jsonDecode(response.body); if (data['data'] != null) { data['data'].forEach((var agencyPosition) { - AgencyPosition position = AgencyPosition.fromJson(agencyPosition); + Position position = Position.fromJson(agencyPosition); agencyPositions.add(position); }); } @@ -151,6 +237,7 @@ class WorkHistoryService { return agencyPositions; } +//get appointment status List getAppointmentStatusList() { return [ AppoinemtStatus(value: "Appointed", label: "Appointed"), diff --git a/lib/utils/custom_dropdown_button.dart b/lib/utils/custom_dropdown_button.dart index 11bf81d..308c72b 100644 --- a/lib/utils/custom_dropdown_button.dart +++ b/lib/utils/custom_dropdown_button.dart @@ -1,149 +1,149 @@ -import 'package:dropdown_button2/dropdown_button2.dart'; -import 'package:flutter/material.dart'; +// import 'package:dropdown_button2/dropdown_button2.dart'; +// import 'package:flutter/material.dart'; -class CustomDropdownButton2 extends StatelessWidget { - final String hint; - final String? value; - final List dropdownItems; - final ValueChanged? onChanged; - final DropdownButtonBuilder? selectedItemBuilder; - final Alignment? hintAlignment; - final Alignment? valueAlignment; - final double? buttonHeight, buttonWidth; - final EdgeInsetsGeometry? buttonPadding; - final BoxDecoration? buttonDecoration; - final int? buttonElevation; - final Widget? icon; - final double? iconSize; - final Color? iconEnabledColor; - final Color? iconDisabledColor; - final double? itemHeight; - final EdgeInsetsGeometry? itemPadding; - final double? dropdownHeight, dropdownWidth; - final EdgeInsetsGeometry? dropdownPadding; - final BoxDecoration? dropdownDecoration; - final int? dropdownElevation; - final Radius? scrollbarRadius; - final double? scrollbarThickness; - final bool? scrollbarAlwaysShow; - final Offset offset; +// class CustomDropdownButton2 extends StatelessWidget { +// final String hint; +// final String? value; +// final List dropdownItems; +// final ValueChanged? onChanged; +// final DropdownButtonBuilder? selectedItemBuilder; +// final Alignment? hintAlignment; +// final Alignment? valueAlignment; +// final double? buttonHeight, buttonWidth; +// final EdgeInsetsGeometry? buttonPadding; +// final BoxDecoration? buttonDecoration; +// final int? buttonElevation; +// final Widget? icon; +// final double? iconSize; +// final Color? iconEnabledColor; +// final Color? iconDisabledColor; +// final double? itemHeight; +// final EdgeInsetsGeometry? itemPadding; +// final double? dropdownHeight, dropdownWidth; +// final EdgeInsetsGeometry? dropdownPadding; +// final BoxDecoration? dropdownDecoration; +// final int? dropdownElevation; +// final Radius? scrollbarRadius; +// final double? scrollbarThickness; +// final bool? scrollbarAlwaysShow; +// final Offset offset; - const CustomDropdownButton2({ - required this.hint, - required this.value, - required this.dropdownItems, - required this.onChanged, - this.selectedItemBuilder, - this.hintAlignment, - this.valueAlignment, - this.buttonHeight, - this.buttonWidth, - this.buttonPadding, - this.buttonDecoration, - this.buttonElevation, - this.icon, - this.iconSize, - this.iconEnabledColor, - this.iconDisabledColor, - this.itemHeight, - this.itemPadding, - this.dropdownHeight, - this.dropdownWidth, - this.dropdownPadding, - this.dropdownDecoration, - this.dropdownElevation, - this.scrollbarRadius, - this.scrollbarThickness, - this.scrollbarAlwaysShow, - this.offset = const Offset(0, 0), - Key? key, - }) : super(key: key); +// const CustomDropdownButton2({ +// required this.hint, +// required this.value, +// required this.dropdownItems, +// required this.onChanged, +// this.selectedItemBuilder, +// this.hintAlignment, +// this.valueAlignment, +// this.buttonHeight, +// this.buttonWidth, +// this.buttonPadding, +// this.buttonDecoration, +// this.buttonElevation, +// this.icon, +// this.iconSize, +// this.iconEnabledColor, +// this.iconDisabledColor, +// this.itemHeight, +// this.itemPadding, +// this.dropdownHeight, +// this.dropdownWidth, +// this.dropdownPadding, +// this.dropdownDecoration, +// this.dropdownElevation, +// this.scrollbarRadius, +// this.scrollbarThickness, +// this.scrollbarAlwaysShow, +// this.offset = const Offset(0, 0), +// Key? key, +// }) : super(key: key); - @override - Widget build(BuildContext context) { - return DropdownButtonHideUnderline( - child: DropdownButton2( - //To avoid long text overflowing. - isExpanded: true, - hint: Container( - alignment: hintAlignment, - child: Text( - hint, - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: TextStyle( - fontSize: 14, - color: Theme.of(context).hintColor, - ), - ), - ), - value: value, - items: dropdownItems - .map((item) => DropdownMenuItem( - value: item, - child: Container( - alignment: valueAlignment, - child: Text( - item, - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: const TextStyle( - fontSize: 14, - ), - ), - ), - )) - .toList(), - onChanged: onChanged, - selectedItemBuilder: selectedItemBuilder, - buttonStyleData: ButtonStyleData( - height: buttonHeight ?? 40, - width: buttonWidth ?? 140, - padding: buttonPadding ?? const EdgeInsets.only(left: 14, right: 14), - decoration: buttonDecoration ?? - BoxDecoration( - borderRadius: BorderRadius.circular(14), - border: Border.all( - color: Colors.black45, - ), - ), - elevation: buttonElevation, - ), - iconStyleData: IconStyleData( - icon: icon ?? const Icon(Icons.arrow_forward_ios_outlined), - iconSize: iconSize ?? 12, - iconEnabledColor: iconEnabledColor, - iconDisabledColor: iconDisabledColor, - ), - dropdownStyleData: DropdownStyleData( - //Max height for the dropdown menu & becoming scrollable if there are more items. If you pass Null it will take max height possible for the items. - maxHeight: dropdownHeight ?? 200, - width: dropdownWidth ?? 140, - padding: dropdownPadding, - decoration: dropdownDecoration ?? - BoxDecoration( - borderRadius: BorderRadius.circular(14), - ), - elevation: dropdownElevation ?? 8, - //Null or Offset(0, 0) will open just under the button. You can edit as you want. - offset: offset, - //Default is false to show menu below button - isOverButton: false, - scrollbarTheme: ScrollbarThemeData( - radius: scrollbarRadius ?? const Radius.circular(40), - thickness: scrollbarThickness != null - ? MaterialStateProperty.all(scrollbarThickness!) - : null, - thumbVisibility: scrollbarAlwaysShow != null - ? MaterialStateProperty.all(scrollbarAlwaysShow!) - : null, - ), - ), - menuItemStyleData: MenuItemStyleData( - height: itemHeight ?? 40, - padding: itemPadding ?? const EdgeInsets.only(left: 14, right: 14), - ), - ), - ); - } -} \ No newline at end of file +// @override +// Widget build(BuildContext context) { +// return DropdownButtonHideUnderline( +// child: DropdownButton2( +// //To avoid long text overflowing. +// isExpanded: true, +// hint: Container( +// alignment: hintAlignment, +// child: Text( +// hint, +// overflow: TextOverflow.ellipsis, +// maxLines: 1, +// style: TextStyle( +// fontSize: 14, +// color: Theme.of(context).hintColor, +// ), +// ), +// ), +// value: value, +// items: dropdownItems +// .map((item) => DropdownMenuItem( +// value: item, +// child: Container( +// alignment: valueAlignment, +// child: Text( +// item, +// overflow: TextOverflow.ellipsis, +// maxLines: 1, +// style: const TextStyle( +// fontSize: 14, +// ), +// ), +// ), +// )) +// .toList(), +// onChanged: onChanged, +// selectedItemBuilder: selectedItemBuilder, +// buttonStyleData: ButtonStyleData( +// height: buttonHeight ?? 40, +// width: buttonWidth ?? 140, +// padding: buttonPadding ?? const EdgeInsets.only(left: 14, right: 14), +// decoration: buttonDecoration ?? +// BoxDecoration( +// borderRadius: BorderRadius.circular(14), +// border: Border.all( +// color: Colors.black45, +// ), +// ), +// elevation: buttonElevation, +// ), +// iconStyleData: IconStyleData( +// icon: icon ?? const Icon(Icons.arrow_forward_ios_outlined), +// iconSize: iconSize ?? 12, +// iconEnabledColor: iconEnabledColor, +// iconDisabledColor: iconDisabledColor, +// ), +// dropdownStyleData: DropdownStyleData( +// //Max height for the dropdown menu & becoming scrollable if there are more items. If you pass Null it will take max height possible for the items. +// maxHeight: dropdownHeight ?? 200, +// width: dropdownWidth ?? 140, +// padding: dropdownPadding, +// decoration: dropdownDecoration ?? +// BoxDecoration( +// borderRadius: BorderRadius.circular(14), +// ), +// elevation: dropdownElevation ?? 8, +// //Null or Offset(0, 0) will open just under the button. You can edit as you want. +// offset: offset, +// //Default is false to show menu below button +// isOverButton: false, +// scrollbarTheme: ScrollbarThemeData( +// radius: scrollbarRadius ?? const Radius.circular(40), +// thickness: scrollbarThickness != null +// ? MaterialStateProperty.all(scrollbarThickness!) +// : null, +// thumbVisibility: scrollbarAlwaysShow != null +// ? MaterialStateProperty.all(scrollbarAlwaysShow!) +// : null, +// ), +// ), +// menuItemStyleData: MenuItemStyleData( +// height: itemHeight ?? 40, +// padding: itemPadding ?? const EdgeInsets.only(left: 14, right: 14), +// ), +// ), +// ); +// } +// } \ No newline at end of file diff --git a/lib/utils/urls.dart b/lib/utils/urls.dart index fb0fd90..bff5d0e 100644 --- a/lib/utils/urls.dart +++ b/lib/utils/urls.dart @@ -3,10 +3,10 @@ class Url { static Url get instance => _instance; String host() { - // // // return '192.168.10.221:3003'; + return '192.168.10.221:3003'; // return 'agusandelnorte.gov.ph'; // return "192.168.10.219:3000"; - return "devweb.agusandelnorte.gov.ph"; + // return "devweb.agusandelnorte.gov.ph"; // return 'devapi.agusandelnorte.gov.ph:3004'; } @@ -51,6 +51,13 @@ String getPositions(){ String getAgencies(){ return "/api/jobnet_app/agencies/"; } +String updateWorkHistories(){ + return "/api/jobnet_app/profile/pds/work/"; +} + +String addWorkHistory(){ + return "/api/jobnet_app/profile/pds/work/"; +} String getAgencyCategory(){ return "api/jobnet_app/agency_categories/"; } diff --git a/lib/utils/validators.dart b/lib/utils/validators.dart index fb4ab79..b2c05e6 100644 --- a/lib/utils/validators.dart +++ b/lib/utils/validators.dart @@ -16,3 +16,19 @@ final registerPasswordValidator = FormBuilderValidators.compose([ FormBuilderValidators.minLength(6, errorText: "Password must be equal or greater than 6 characters"), ]); + +final integerAndNumeric = + FormBuilderValidators + .compose([ + FormBuilderValidators + .integer( + radix: 10, + errorText: + "Please enter a number"), + FormBuilderValidators + .numeric( + errorText: + "Please enter a number") + ]); + + diff --git a/pubspec.lock b/pubspec.lock index f3b631c..2a90114 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -201,22 +201,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.6" - dropdown_button2: - dependency: "direct main" - description: - name: dropdown_button2 - sha256: "4458d81bfd24207f3d58f66f78097064e02f810f94cf1bc80bf20fe7685ebc80" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - dropdown_plus: - dependency: "direct main" - description: - name: dropdown_plus - sha256: "707c364066dcfcd2f5b672116d5adee8e3454ede3ff6fc34f5b351bfbbfbecbe" - url: "https://pub.dev" - source: hosted - version: "0.0.9" easy_app_installer: dependency: "direct main" description: @@ -326,14 +310,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" - flutter_dropdown_search: - dependency: "direct main" - description: - name: flutter_dropdown_search - sha256: ead6f0e5dc67ae20822b211d26e617efe1d8922159de9b07a8a2168805b541d1 - url: "https://pub.dev" - source: hosted - version: "0.0.2" flutter_form_builder: dependency: "direct main" description: @@ -797,14 +773,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.3" - search_choices: - dependency: "direct main" - description: - name: search_choices - sha256: "4c379407ea642613669f788ec9b41cfb156f55800e8f69c727478c37db025c47" - url: "https://pub.dev" - source: hosted - version: "2.2.5" searchfield: dependency: "direct main" description: @@ -813,14 +781,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.5" - select2dot1: - dependency: "direct main" - description: - name: select2dot1 - sha256: bce3cef060d48b9c728924aa76f2fbcefb887fe7219e370391696902739cb2ed - url: "https://pub.dev" - source: hosted - version: "1.0.2" shared_preferences: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3b0fda0..c2bbe76 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,11 +70,6 @@ dependencies: badges: ^3.0.2 app_popup_menu: ^1.0.0 modal_progress_hud_nsn: ^0.3.0 - search_choices: ^2.2.5 - dropdown_button2: ^2.0.0 - flutter_dropdown_search: ^0.0.2 - select2dot1: ^1.0.2 - dropdown_plus: ^0.0.9 searchfield: ^0.7.5