From 1c6b2918894f4fd590988133f4b49e9a8ffce931 Mon Sep 17 00:00:00 2001 From: PGAN-MIS Date: Tue, 2 May 2023 08:26:42 +0800 Subject: [PATCH] Implemnent Voluntary works and civic API --- .../address/address_bloc.dart | 2 + .../address/address_event.dart | 9 + .../address/address_state.dart | 9 + .../voluntary_works/voluntary_work_bloc.dart | 225 +++++- .../voluntary_works/voluntary_work_event.dart | 64 +- .../voluntary_works/voluntary_work_state.dart | 42 +- lib/model/profile/voluntary_works.dart | 4 +- .../basic_information/address/add_modal.dart | 19 +- .../components/education/add_modal.dart | 3 + .../components/education/edit_modal.dart | 17 +- .../profile/components/education_screen.dart | 9 +- .../components/eligibility/add_modal.dart | 4 +- .../components/voluntary_works/add_modal.dart | 685 ++++++++++++++++ .../voluntary_works/edit_modal.dart | 754 ++++++++++++++++++ .../components/voluntary_works_screen.dart | 211 ++++- .../voluntary_works/add_modal.dart | 597 -------------- lib/sevices/profile/volunatary_services.dart | 157 +++- lib/utils/urls.dart | 4 +- pubspec.yaml | 3 +- 19 files changed, 2139 insertions(+), 679 deletions(-) create mode 100644 lib/screens/profile/components/voluntary_works/add_modal.dart create mode 100644 lib/screens/profile/components/voluntary_works/edit_modal.dart delete mode 100644 lib/screens/profile/components/work_history/voluntary_works/add_modal.dart diff --git a/lib/bloc/profile/primary_information/address/address_bloc.dart b/lib/bloc/profile/primary_information/address/address_bloc.dart index 00f09c0..75cafa4 100644 --- a/lib/bloc/profile/primary_information/address/address_bloc.dart +++ b/lib/bloc/profile/primary_information/address/address_bloc.dart @@ -1,6 +1,8 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:unit2/bloc/profile/eligibility/eligibility_bloc.dart'; import 'package:unit2/model/location/barangay.dart'; +import 'package:unit2/model/profile/voluntary_works.dart'; import '../../../../model/location/city.dart'; import '../../../../model/location/country.dart'; diff --git a/lib/bloc/profile/primary_information/address/address_event.dart b/lib/bloc/profile/primary_information/address/address_event.dart index f1d36f4..9446ba2 100644 --- a/lib/bloc/profile/primary_information/address/address_event.dart +++ b/lib/bloc/profile/primary_information/address/address_event.dart @@ -23,3 +23,12 @@ class ShowEditAddressForm extends AddressEvent{ class CallErrorState extends AddressEvent{ } + +class AddAddress extends EligibilityEvent{ + final MainAdress address; + final String token; + final int profileId; + const AddAddress({required this.address, required this.profileId, required this.token}); + @override + List get props => [address,token,profileId]; +} diff --git a/lib/bloc/profile/primary_information/address/address_state.dart b/lib/bloc/profile/primary_information/address/address_state.dart index 563a5f4..6c9e70d 100644 --- a/lib/bloc/profile/primary_information/address/address_state.dart +++ b/lib/bloc/profile/primary_information/address/address_state.dart @@ -37,6 +37,15 @@ class AddAddressState extends AddressState { List get props => [countries, regions,]; } +////AddedState +class AddressAddedState extends AddressState{ + final Map response; + const AddressAddedState({required this.response}); + @override + List get props => [response]; + +} + class EditAddressState extends AddressState{ final MainAdress address; final List countries; diff --git a/lib/bloc/profile/voluntary_works/voluntary_work_bloc.dart b/lib/bloc/profile/voluntary_works/voluntary_work_bloc.dart index 0480f9c..5c5afa2 100644 --- a/lib/bloc/profile/voluntary_works/voluntary_work_bloc.dart +++ b/lib/bloc/profile/voluntary_works/voluntary_work_bloc.dart @@ -1,14 +1,19 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:unit2/sevices/profile/volunatary_services.dart'; import 'package:unit2/utils/profile_utilities.dart'; +import '../../../model/location/city.dart'; import '../../../model/location/country.dart'; +import '../../../model/location/provinces.dart'; import '../../../model/location/region.dart'; import '../../../model/profile/voluntary_works.dart'; import '../../../model/utils/agency.dart'; import '../../../model/utils/category.dart'; import '../../../model/utils/position.dart'; +import '../../../utils/location_utilities.dart'; part 'voluntary_work_event.dart'; part 'voluntary_work_state.dart'; @@ -16,27 +21,42 @@ part 'voluntary_work_state.dart'; class VoluntaryWorkBloc extends Bloc { VoluntaryWorkBloc() : super(VoluntaryWorkInitial()) { List voluntaryWorks = []; - List globalCountries=[]; - List agencyCategory = []; - List globalRegions=[]; - List agencyPositions = []; - List agencies = []; - ////Get Voluntary Works - on((event, emit) async{ + List globalCountries = []; + List agencyCategory = []; + List globalRegions = []; + List agencyPositions = []; + List agencies = []; + List provinces = []; + List cities = []; + ///// current + Position currentPosition; + Agency currentAgency; + Region? currentRegion; + Country currentCountry; + Province? currentProvince; + CityMunicipality? currentCity; + ////Get Voluntary Works + on((event, emit) async { emit(VoluntaryWorkLoadingState()); - try{ - List works = await VoluntaryService.instance.getVoluntaryWorks(event.profileId, event.token); - voluntaryWorks = works; - emit(VoluntaryWorkLoadedState(voluntaryWorks: voluntaryWorks)); - }catch(e){ - emit(VoluntaryWorkErrorState(message: e.toString())); - } + try { + List works = await VoluntaryService.instance + .getVoluntaryWorks(event.profileId, event.token); + voluntaryWorks = works; + emit(VoluntaryWorkLoadedState(voluntaryWorks: voluntaryWorks)); + } catch (e) { + emit(VoluntaryWorkErrorState(message: e.toString())); + } + }); + //// Load + on((event, emit) { + emit(VoluntaryWorkLoadedState(voluntaryWorks: voluntaryWorks)); }); //// Show Add form Event - on((event,emit)async{ - try{ + on((event, emit) async { + try { emit(VoluntaryWorkLoadingState()); - if (agencyPositions.isEmpty) { + //// POSITIONS + if (agencyPositions.isEmpty) { List positions = await ProfileUtilities.instance.getAgencyPosition(); agencyPositions = positions; @@ -55,12 +75,177 @@ class VoluntaryWorkBloc extends Bloc { await ProfileUtilities.instance.agencyCategory(); agencyCategory = categoryAgencies; } - emit(AddVoluntaryWorkState(agencies: agencies,positions: agencyPositions,agencyCategory: agencyCategory,regions: globalRegions,countries: globalCountries)); + + ////regions + if (globalRegions.isEmpty) { + List regions = await LocationUtils.instance.getRegions(); + globalRegions = regions; + } + + //// country + if (globalCountries.isEmpty) { + List countries = await LocationUtils.instance.getCountries(); + globalCountries = countries; + } + + emit(AddVoluntaryWorkState( + agencies: agencies, + positions: agencyPositions, + agencyCategory: agencyCategory, + regions: globalRegions, + countries: globalCountries)); + } catch (e) { + emit(VoluntaryWorkErrorState(message: e.toString())); + } + }); + on((event, emit) { + emit(VoluntaryWorkErrorState(message: event.message)); + }); + //// Add Voluntary Work + on((event, emit) async { + try { + Map status = await VoluntaryService.instance.add( + voluntaryWork: event.work, + profileId: event.profileId, + token: event.token); + if (status['success']) { + VoluntaryWork work = VoluntaryWork.fromJson(status['data']); + voluntaryWorks.add(work); + emit(VoluntaryWorkAddedState(response: status)); + } else { + emit(VoluntaryWorkAddedState(response: status)); + } + } catch (e) { + emit(VoluntaryWorkErrorState(message: e.toString())); + } + }); + ////Update + on((event, emit) async { + final DateFormat formatter = DateFormat('yyyy-MM-dd'); + try{ + Map status = await VoluntaryService.instance.update( + voluntaryWork: event.work, + profileId: event.profileId, + token: event.token, + oldPosId: event.oldPosId, + oldAgencyId: event.oldAgencyId, + oldFromDate: formatter.format(DateTime.parse(event.oldFromDate))); + if (status['success']) { + VoluntaryWork work = VoluntaryWork.fromJson(status['data']); + voluntaryWorks.removeWhere((VoluntaryWork element) => + element.position!.id == event.oldPosId && + element.agency!.id == event.oldAgencyId && + element.fromDate.toString() == event.oldFromDate.toString()); + voluntaryWorks.add(work); + emit(VoluntaryWorkEditedState(response: status)); + } else { + emit(VoluntaryWorkEditedState(response: status)); + } }catch(e){ emit(VoluntaryWorkErrorState(message: e.toString())); } - });on((event,emit){ - emit(VoluntaryWorkErrorState(message: event.message)); + }); +/////SHOW EDIT FORM + on((event, emit) async { + try { + //// POSITIONS + if (agencyPositions.isEmpty) { + List positions = + await ProfileUtilities.instance.getAgencyPosition(); + agencyPositions = positions; + } + currentPosition = event.work.position!; + + /////AGENCIES------------------------------------------ + if (agencies.isEmpty) { + List newAgencies = + await ProfileUtilities.instance.getAgecies(); + agencies = newAgencies; + } + currentAgency = event.work.agency!; + + /////Category Agency------------------------------------------ + if (agencyCategory.isEmpty) { + List categoryAgencies = + await ProfileUtilities.instance.agencyCategory(); + agencyCategory = categoryAgencies; + } + + ////regions + if (globalRegions.isEmpty) { + List regions = await LocationUtils.instance.getRegions(); + globalRegions = regions; + } + + //// country + if (globalCountries.isEmpty) { + List countries = await LocationUtils.instance.getCountries(); + globalCountries = countries; + } + currentCountry = globalCountries.firstWhere((Country country) => + event.work.address!.country!.code == country.code); + ////If overseas + if (!event.isOverseas) { + //// if not overseas + currentRegion = globalRegions.firstWhere((Region region) => + event.work.address!.cityMunicipality!.province!.region!.code == + region.code); + provinces = await LocationUtils.instance + .getProvinces(regionCode: currentRegion!.code.toString()); + currentProvince = provinces.firstWhere((Province province) => + event.work.address!.cityMunicipality!.province!.code == + province.code); + + cities = await LocationUtils.instance + .getCities(code: currentProvince!.code.toString()); + + currentCity = cities.firstWhere((CityMunicipality cityMunicipality) => + event.work.address!.cityMunicipality!.code == + cityMunicipality.code); + } + emit(EditVoluntaryWorks( + overseas: event.isOverseas, + agencies: agencies, + agencyCategory: agencyCategory, + cities: cities, + countries: globalCountries, + positions: agencyPositions, + provinces: provinces, + regions: globalRegions, + work: event.work, + currentAgency: currentAgency, + currentCity: currentCity, + currentCountry: currentCountry, + currentPosition: currentPosition, + currentProvince: currentProvince, + currentRegion: currentRegion)); + } catch (e) { + emit(VoluntaryWorkErrorState(message: e.toString())); + } + }); + //// Delete + on((event, emit) async { + try { + final DateFormat formatter = DateFormat('yyyy-MM-dd'); + + final bool success = await VoluntaryService.instance.delete( + agencyId: event.work.agency!.id!, + positionId: event.work.position!.id!, + fromDate: formatter.format(event.work.fromDate!), + token: event.token, + profileId: event.profileId); + if (success) { + voluntaryWorks.removeWhere((VoluntaryWork element) => + element.position!.id == event.work.position!.id && + element.agency!.id == event.work.agency!.id && + element.fromDate == event.work.fromDate); + emit(VoluntaryWorkDeletedState(success: success)); + } else { + emit(VoluntaryWorkDeletedState(success: success)); + } + } catch (e) { + emit(VoluntaryWorkErrorState(message: e.toString())); + } }); } } diff --git a/lib/bloc/profile/voluntary_works/voluntary_work_event.dart b/lib/bloc/profile/voluntary_works/voluntary_work_event.dart index 52aba14..02ed79b 100644 --- a/lib/bloc/profile/voluntary_works/voluntary_work_event.dart +++ b/lib/bloc/profile/voluntary_works/voluntary_work_event.dart @@ -7,18 +7,68 @@ abstract class VoluntaryWorkEvent extends Equatable { List get props => []; } -class GetVoluntarWorks extends VoluntaryWorkEvent{ +class GetVoluntarWorks extends VoluntaryWorkEvent { final int profileId; final String token; const GetVoluntarWorks({required this.profileId, required this.token}); - @override - List get props => [profileId,token]; -} -class ShowAddVoluntaryWorks extends VoluntaryWorkEvent{ - + @override + List get props => [profileId, token]; } -class ShowErrorState extends VoluntaryWorkEvent{ +class ShowAddVoluntaryWorks extends VoluntaryWorkEvent {} + +class ShowEditVoluntaryWorks extends VoluntaryWorkEvent { + final VoluntaryWork work; + final int profileId; + final String token; + final bool isOverseas; + // final int oldPosId; + // final int oldAgencyId; + // final String oldFromDate; + const ShowEditVoluntaryWorks( + {required this.profileId, + required this.token, + required this.work, + // required this.oldAgencyId, + // required this.oldFromDate, + // required this.oldPosId, + required this.isOverseas}); + @override + List get props => [profileId, token, work]; +} + +class LoadVoluntaryWorks extends VoluntaryWorkEvent {} + +class ShowErrorState extends VoluntaryWorkEvent { final String message; const ShowErrorState({required this.message}); } + +class UpdateVolunataryWork extends VoluntaryWorkEvent{ + final int oldPosId; + final int oldAgencyId; + final String oldFromDate; + final VoluntaryWork work; + final int profileId; + final String token; + const UpdateVolunataryWork({required this.oldAgencyId, required this.oldFromDate, required this.oldPosId, required this.profileId, required this.token, required this.work}); +} +class AddVoluntaryWork extends VoluntaryWorkEvent { + final int profileId; + final String token; + final VoluntaryWork work; + const AddVoluntaryWork( + {required this.profileId, required this.token, required this.work}); + @override + List get props => [profileId, token, work]; +} + +class DeleteVoluntaryWork extends VoluntaryWorkEvent { + final String token; + final int profileId; + final VoluntaryWork work; + const DeleteVoluntaryWork( + {required this.profileId, required this.token, required this.work}); + @override + List get props => [profileId, token, work]; +} diff --git a/lib/bloc/profile/voluntary_works/voluntary_work_state.dart b/lib/bloc/profile/voluntary_works/voluntary_work_state.dart index 3024e12..a5baeeb 100644 --- a/lib/bloc/profile/voluntary_works/voluntary_work_state.dart +++ b/lib/bloc/profile/voluntary_works/voluntary_work_state.dart @@ -26,8 +26,41 @@ class VoluntaryWorkErrorState extends VoluntaryWorkState{ class VoluntaryWorkLoadingState extends VoluntaryWorkState{ } +////Added State +class VoluntaryWorkAddedState extends VoluntaryWorkState{ + final Map response; + const VoluntaryWorkAddedState({required this.response}); + @override + List get props => [response]; +} +////Added State +class VoluntaryWorkEditedState extends VoluntaryWorkState{ + final Map response; + const VoluntaryWorkEditedState({required this.response}); + @override + List get props => [response]; +} +class EditVoluntaryWorks extends VoluntaryWorkState{ + final VoluntaryWork work; + final List positions; + final List agencies; + final List agencyCategory; + final List countries; + final List regions; + final List provinces; + final List cities; + final Position currentPosition; + final Agency currentAgency; + final Region? currentRegion; + final Country currentCountry; + final Province? currentProvince; + final CityMunicipality? currentCity; + final bool overseas; + const EditVoluntaryWorks({required this.agencies, required this.agencyCategory, required this.cities, required this.countries,required this.positions, required this.provinces, required this.regions, required this.work, required this.currentAgency, required this.currentCity,required this.currentCountry, required this.currentPosition, required this.currentProvince, required this.currentRegion,required this.overseas}); +} +////Adding State class AddVoluntaryWorkState extends VoluntaryWorkState{ final List positions; final List agencies; @@ -37,4 +70,11 @@ class AddVoluntaryWorkState extends VoluntaryWorkState{ const AddVoluntaryWorkState({required this.agencies,required this.countries, required this.positions, required this.regions,required this.agencyCategory}); @override List get props => [positions,agencies,countries,regions]; -} \ No newline at end of file +} +//// Deleted State +class VoluntaryWorkDeletedState extends VoluntaryWorkState{ + final bool success; + const VoluntaryWorkDeletedState({required this.success}); + @override + List get props => [success]; +} diff --git a/lib/model/profile/voluntary_works.dart b/lib/model/profile/voluntary_works.dart index 8f5cdae..c86d35b 100644 --- a/lib/model/profile/voluntary_works.dart +++ b/lib/model/profile/voluntary_works.dart @@ -29,12 +29,12 @@ class VoluntaryWork { final DateTime? toDate; final Position? position; final DateTime? fromDate; - final int? totalHours; + final double? totalHours; factory VoluntaryWork.fromJson(Map json) => VoluntaryWork( agency: json["agency"] == null ? null : Agency.fromJson(json["agency"]), address: json["address"] == null ? null : Address.fromJson(json["address"]), - toDate: json["to_date"] == null? null : DateTime.parse(json['to_data']), + toDate: json["to_date"] == null? null : DateTime.parse(json['to_date']), position: json["position"] == null ? null : Position.fromJson(json["position"]), fromDate: json["from_date"] == null ? null : DateTime.parse(json["from_date"]), totalHours: json["total_hours"], diff --git a/lib/screens/profile/components/basic_information/address/add_modal.dart b/lib/screens/profile/components/basic_information/address/add_modal.dart index c790d4d..af4e8af 100644 --- a/lib/screens/profile/components/basic_information/address/add_modal.dart +++ b/lib/screens/profile/components/basic_information/address/add_modal.dart @@ -6,6 +6,7 @@ import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; import 'package:unit2/bloc/profile/primary_information/address/address_bloc.dart'; +import 'package:unit2/model/location/address_category.dart'; import 'package:unit2/model/utils/category.dart'; import 'package:unit2/utils/global.dart'; @@ -38,6 +39,8 @@ class _AddAddressScreenState extends State { bool cityCall = false; bool barangayCall = false; ////selected + AddressCategory? selectedAddressCategory; + String? selectedAreaClass; Region? selectedRegion; Province? selectedProvince; CityMunicipality? selectedMunicipality; @@ -54,7 +57,7 @@ class _AddAddressScreenState extends State { const Area(value: "Metropolis", group: 1), const Area(value: "Megacity", group: 1), ]; - final List category = ["Permanent", "Residential", "Birthplace"]; + final List category = [AddressCategory(id: 1, name: "Permanent", type: "home"), AddressCategory(id: 2, name: "Residential", type: "home"), AddressCategory(id: 3, name: "Birthplace", type: "home")]; List? provinces; List? citymuns; List? barangays; @@ -75,17 +78,17 @@ class _AddAddressScreenState extends State { child: Column( children: [ //// category - FormBuilderDropdown( + FormBuilderDropdown( validator: FormBuilderValidators.required( errorText: "This field is required"), decoration: normalTextFieldStyle("Category*", "Category"), name: "category", - onChanged: (String? category) {}, - items: category.map>( - (String category) { + onChanged: (AddressCategory? category) {}, + items: category.map>( + (AddressCategory category) { return DropdownMenuItem( - value: category, child: Text(category)); + value: category, child: Text(category.name!)); }).toList()), const SizedBox( height: 12, @@ -97,7 +100,9 @@ class _AddAddressScreenState extends State { decoration: normalTextFieldStyle( "Area class *", "Area class"), name: "area_class", - onChanged: (Area? area) {}, + onChanged: (Area? area) { + selectedAreaClass = area!.value; + }, items: areaClass .map>((Area area) { return area.group == 0 diff --git a/lib/screens/profile/components/education/add_modal.dart b/lib/screens/profile/components/education/add_modal.dart index a4701e1..556f36b 100644 --- a/lib/screens/profile/components/education/add_modal.dart +++ b/lib/screens/profile/components/education/add_modal.dart @@ -448,6 +448,9 @@ class _AddEducationScreenState extends State { if (!graduated) { unitsEarned = int.parse(formKey .currentState!.value['units_earned']); + yearGraduated.text = ''; + }else{ + } ////education Education newEducation = Education( diff --git a/lib/screens/profile/components/education/edit_modal.dart b/lib/screens/profile/components/education/edit_modal.dart index 1038bbf..2c969c3 100644 --- a/lib/screens/profile/components/education/edit_modal.dart +++ b/lib/screens/profile/components/education/edit_modal.dart @@ -92,7 +92,6 @@ class _EditEducationScreenState extends State { } fromController.text = state.educationalBackground.periodFrom!; untilController.text = state.educationalBackground.periodTo!; - ////honors ////get all honors valueItemHonorList = state.honors.map((Honor honor) { @@ -147,6 +146,10 @@ class _EditEducationScreenState extends State { ////school StatefulBuilder(builder: (context, setState) { return SearchField( + suggestionAction: SuggestionAction.next, + onSubmit: (p0) { + schoolFocusNode.unfocus(); + }, controller: currentSchoolController, itemHeight: 50, suggestionsDecoration: box1(), @@ -171,7 +174,9 @@ class _EditEducationScreenState extends State { searchInputDecoration: normalTextFieldStyle("School *", "").copyWith( suffixIcon: - const Icon(Icons.arrow_drop_down)), + GestureDetector(child: const Icon(Icons.arrow_drop_down),onTap: (){ + schoolFocusNode.unfocus(); + },)), onSuggestionTap: (school) { setState(() { selectedSchool = school.item; @@ -497,10 +502,12 @@ class _EditEducationScreenState extends State { selectedLevel!.value == "Junior High" || selectedLevel!.value == "Senior High") { selectedProgram = null; - }else{ - selectedProgram ??= state.educationalBackground.education!.course; + } else { + selectedProgram ??= state + .educationalBackground.education!.course; } - selectedSchool ??= state.educationalBackground.education!.school; + selectedSchool ??= + state.educationalBackground.education!.school; ////education Education newEducation = Education( id: null, diff --git a/lib/screens/profile/components/education_screen.dart b/lib/screens/profile/components/education_screen.dart index a7f68df..6b94216 100644 --- a/lib/screens/profile/components/education_screen.dart +++ b/lib/screens/profile/components/education_screen.dart @@ -18,6 +18,7 @@ import 'package:unit2/widgets/error_state.dart'; import '../../../bloc/profile/education/education_bloc.dart'; import '../../../utils/alerts.dart'; +import '../../../widgets/Leadings/close_leading.dart'; import 'education/edit_modal.dart'; class EducationScreen extends StatelessWidget { @@ -32,11 +33,15 @@ class EducationScreen extends StatelessWidget { title: const Text(educationScreenTitle), centerTitle: true, backgroundColor: primary, - actions: [ + actions: context.watch().state is EducationalBackgroundLoadedState?[ AddLeading(onPressed: () { context.read().add(ShowAddEducationForm()); }) - ], + ]:(context.watch().state is AddEducationState || context.watch().state is EditEducationState)?[ + CloseLeading(onPressed: () { + context.read().add( LoadEducations()); + }) + ]:[], ), //userbloc body: ProgressHUD( diff --git a/lib/screens/profile/components/eligibility/add_modal.dart b/lib/screens/profile/components/eligibility/add_modal.dart index 453bdf3..f5a71a6 100644 --- a/lib/screens/profile/components/eligibility/add_modal.dart +++ b/lib/screens/profile/components/eligibility/add_modal.dart @@ -398,11 +398,11 @@ class _AddEligibilityScreenState extends State { style: mainBtnStyle( primary, Colors.transparent, second), onPressed: () { - //rating + ////rating double? rate = rating == null ? null : double.parse(rating!); - //lisence + ////lisence String? licenseNumber = license; CityMunicipality? cityMunicipality = selectedMunicipality; diff --git a/lib/screens/profile/components/voluntary_works/add_modal.dart b/lib/screens/profile/components/voluntary_works/add_modal.dart new file mode 100644 index 0000000..58fedba --- /dev/null +++ b/lib/screens/profile/components/voluntary_works/add_modal.dart @@ -0,0 +1,685 @@ +import 'package:date_time_picker/date_time_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/src/widgets/placeholder.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:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; +import 'package:searchfield/searchfield.dart'; +import 'package:unit2/bloc/profile/voluntary_works/voluntary_work_bloc.dart'; +import 'package:unit2/utils/global.dart'; + +import '../../../../model/location/barangay.dart'; +import '../../../../model/location/city.dart'; +import '../../../../model/location/country.dart'; +import '../../../../model/location/provinces.dart'; +import '../../../../model/location/region.dart'; +import '../../../../model/profile/voluntary_works.dart'; +import '../../../../model/utils/agency.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/location_utilities.dart'; +import '../../../../utils/text_container.dart'; +import '../../shared/add_for_empty_search.dart'; + +class AddVoluntaryWorkScreen extends StatefulWidget { + final int profileId; + final String token; + const AddVoluntaryWorkScreen( + {super.key, required this.profileId, required this.token}); + + @override + State createState() => _AddVoluntaryWorkScreenState(); +} + +class _AddVoluntaryWorkScreenState extends State { + final formKey = GlobalKey(); + ////controllers + final addPositionController = TextEditingController(); + final addAgencyController = TextEditingController(); + final toDateController = TextEditingController(); + final fromDateController = TextEditingController(); + ////focus nodes + final positionFocusNode = FocusNode(); + final agencyFocusNode = FocusNode(); + final agencyCategoryFocusNode = FocusNode(); + ////booleans + bool showAgency = false; + bool showIsPrivateRadio = false; + bool currentlyInvolved = false; + bool overseas = false; + bool provinceCall = false; + bool cityCall = false; + bool isPrivate = false; + ////Lists + List? provinces; + List? citymuns; + ////Selected + Position? selectedPosition; + Agency? selectedAgency; + Category? selectedCategoty; + Region? selectedRegion; + Province? selectedProvince; + CityMunicipality? selectedMunicipality; + Country? selectedCountry; + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is AddVoluntaryWorkState) { + return Center( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 18), + child: FormBuilder( + key: formKey, + child: ListView( + children: [ + ////POSITIONS + StatefulBuilder(builder: (context, setState) { + return SearchField( + itemHeight: 50, + suggestionsDecoration: box1(), + suggestions: state.positions + .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: GestureDetector( + child: const Icon(Icons.arrow_drop_down), + onTap: () => positionFocusNode.unfocus(), + )), + onSuggestionTap: (position) { + setState(() { + selectedPosition = position.item; + positionFocusNode.unfocus(); + }); + }, + ////EMPTY WIDGET + emptyWidget: EmptyWidget( + title: "Add Position", + controller: addPositionController, + onpressed: () { + setState(() { + Position newAgencyPosition = Position( + id: null, + title: addPositionController.text + .toUpperCase()); + + state.positions.insert(0, newAgencyPosition); + + addPositionController.text = ""; + Navigator.pop(context); + }); + }), + validator: (position) { + if (position!.isEmpty) { + return "This field is required"; + } + return null; + }, + ); + }), + const SizedBox( + height: 12, + ), + ////AGENCY + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + SearchField( + 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" + : agency.privateEntity == + false + ? "Government" + : ""), + ))) + .toList(), + searchInputDecoration: + normalTextFieldStyle("Agency *", "") + .copyWith( + suffixIcon: GestureDetector( + child: const Icon( + Icons.arrow_drop_down, + ), + onTap: () => agencyFocusNode.unfocus(), + )), + ////SELETECTED + onSuggestionTap: (agency) { + setState(() { + selectedAgency = agency.item; + if (selectedAgency!.privateEntity == null) { + showAgency = true; + showIsPrivateRadio = true; + } else { + showAgency = false; + showIsPrivateRadio = false; + } + agencyFocusNode.unfocus(); + }); + }, + validator: (agency) { + if (agency!.isEmpty) { + return "This field is required"; + } + return null; + }, + emptyWidget: EmptyWidget( + controller: addAgencyController, + onpressed: () { + setState(() { + Agency newAgency = Agency( + id: null, + name: addAgencyController.text + .toUpperCase(), + category: null, + privateEntity: null); + state.agencies.insert(0, newAgency); + + addAgencyController.text = ""; + Navigator.pop(context); + }); + }, + title: "Add Agency")), + + SizedBox( + height: showAgency ? 12 : 0, + ), + ////SHOW CATEGORY AGENCY + SizedBox( + child: showAgency + ? 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(() { + selectedCategoty = + agencyCategory.item; + agencyCategoryFocusNode.unfocus(); + }); + }, + 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(), + ), + SizedBox( + height: showIsPrivateRadio ? 12 : 0, + ), + ////PRVIATE SECTOR + SizedBox( + child: showIsPrivateRadio + ? FormBuilderSwitch( + initialValue: false, + title: Text(isPrivate ? "YES" : "NO"), + decoration: normalTextFieldStyle( + "Private Entity?", + 'Private Entity?'), + + ////onvhange private sector + onChanged: (value) { + setState(() { + isPrivate = value!; + agencyCategoryFocusNode.unfocus(); + }); + }, + + name: 'isPrivate', + validator: + FormBuilderValidators.required(), + ) + : const SizedBox()), + const SizedBox( + height: 12, + ), + //// total hours + FormBuilderTextField( + validator: FormBuilderValidators.required( + errorText: "This Field is required"), + name: "total_hours", + keyboardType: TextInputType.number, + decoration: + normalTextFieldStyle("Total Hours*", "0"), + ), + const SizedBox( + height: 12, + ), + ////Currently Involved + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + FormBuilderSwitch( + initialValue: currentlyInvolved, + activeColor: second, + onChanged: (value) { + setState(() { + currentlyInvolved = value!; + }); + }, + decoration: normalTextFieldStyle( + "Currently Involved?", 'Graduated?'), + name: 'currently_involved', + title: + Text(currentlyInvolved ? "YES" : "NO"), + ), + const SizedBox( + height: 12, + ), + SizedBox( + width: screenWidth, + child: Row( + children: [ + //// FROM DATE + Flexible( + flex: 1, + child: DateTimePicker( + validator: FormBuilderValidators + .required( + errorText: + "This field is required"), + 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: currentlyInvolved + ? TextFormField( + enabled: false, + initialValue: "PRESENT", + style: const TextStyle( + color: Colors.black45), + decoration: + normalTextFieldStyle( + "", "") + .copyWith(), + ) + : DateTimePicker( + validator: FormBuilderValidators + .required( + errorText: + "This field is required"), + controller: toDateController, + firstDate: DateTime(1970), + lastDate: DateTime(2100), + decoration: normalTextFieldStyle( + "To *", "To *") + .copyWith( + prefixIcon: + const Icon( + Icons.date_range, + color: + Colors.black87, + ), + prefixText: + currentlyInvolved + ? "PRESENT" + : ""), + initialValue: null, + ), + ), + ], + ), + ), + ], + ); + }), + ], + ); + }), + const SizedBox( + height: 12, + ), + //// OVERSEAS + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + FormBuilderSwitch( + initialValue: overseas, + activeColor: second, + onChanged: (value) { + setState(() { + overseas = value!; + }); + }, + decoration: + normalTextFieldStyle("Overseas Address?", ''), + name: 'overseas', + title: Text(overseas ? "YES" : "NO"), + ), + SizedBox( + height: overseas == true ? 8 : 0, + ), + SizedBox( + child: overseas == false + ? Column( + children: [ + const SizedBox( + height: 12, + ), + ////REGION DROPDOWN + FormBuilderDropdown( + autovalidateMode: AutovalidateMode + .onUserInteraction, + validator: + FormBuilderValidators.required( + errorText: + "This field is required"), + onChanged: (Region? region) async { + if (selectedRegion != region) { + setState(() { + provinceCall = true; + }); + selectedRegion = region; + getProvinces(); + } + }, + initialValue: null, + decoration: normalTextFieldStyle( + "Region*", "Region"), + name: 'region', + items: state.regions + .map>( + (Region region) { + return DropdownMenuItem( + value: region, + child: + Text(region.description!)); + }).toList(), + ), + const SizedBox( + height: 8, + ), + //// PROVINCE DROPDOWN + SizedBox( + height: 60, + child: ModalProgressHUD( + color: Colors.transparent, + inAsyncCall: provinceCall, + child: DropdownButtonFormField< + Province?>( + autovalidateMode: + AutovalidateMode + .onUserInteraction, + validator: (value) => + value == null + ? 'required' + : null, + isExpanded: true, + value: selectedProvince, + onChanged: + (Province? province) { + if (selectedProvince != + province) { + setState(() { + cityCall = true; + }); + selectedProvince = province; + getCities(); + } + }, + items: provinces == null + ? [] + : provinces!.map< + DropdownMenuItem< + Province>>( + (Province province) { + return DropdownMenuItem( + value: province, + child: FittedBox( + child: Text(province + .description!), + )); + }).toList(), + decoration: + normalTextFieldStyle( + "Province*", + "Province")), + ), + ), + ////CITY MUNICIPALITY + SizedBox( + height: 60, + child: ModalProgressHUD( + color: Colors.white, + inAsyncCall: cityCall, + child: DropdownButtonFormField< + CityMunicipality>( + validator: FormBuilderValidators + .required( + errorText: + "This field is required"), + isExpanded: true, + onChanged: + (CityMunicipality? city) { + if (selectedMunicipality != + city) { + selectedMunicipality = city; + } + }, + decoration: normalTextFieldStyle( + "Municipality*", + "Municipality"), + value: selectedMunicipality, + items: citymuns == null + ? [] + : citymuns!.map< + DropdownMenuItem< + CityMunicipality>>( + (CityMunicipality c) { + return DropdownMenuItem( + value: c, + child: Text( + c.description!)); + }).toList(), + ), + ), + ), + ], + ) + //// COUNTRY DROPDOWN + : SizedBox( + height: 60, + child: FormBuilderDropdown( + initialValue: null, + validator: + FormBuilderValidators.required( + errorText: + "This field is required"), + items: state.countries + .map>( + (Country country) { + return DropdownMenuItem( + value: country, + child: FittedBox( + child: Text(country.name!))); + }).toList(), + name: 'country', + decoration: normalTextFieldStyle( + "Country*", "Country"), + onChanged: (Country? value) { + selectedCountry = value; + }, + ), + ), + ), + ], + ); + }), + Expanded( + child: SizedBox( + height: blockSizeVertical * 8, + )), + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: mainBtnStyle( + primary, Colors.transparent, second), + onPressed: () { + if (formKey.currentState!.saveAndValidate()) { + Country country = selectedCountry ??= + Country( + id: 175, + name: 'Philippines', + code: 'PH'); + Address address = Address( + barangay: null, + id: null, + addressCategory: null, + addressClass: null, + cityMunicipality: selectedMunicipality, + country: country); + if (selectedCategoty != null) { + selectedAgency = Agency( + id: selectedAgency?.id, + name: selectedAgency!.name, + category: selectedCategoty, + privateEntity: isPrivate); + } + VoluntaryWork work = VoluntaryWork( + ////address + address: address, + //// agency + agency: selectedAgency, + //// + position: selectedPosition, + ////total hours + totalHours: double.parse(formKey + .currentState!.value["total_hours"]), + ////to date + toDate: toDateController.text.isEmpty || + toDateController.text.toUpperCase() == + "PRESENT" + ? null + : DateTime.parse(toDateController.text), + ////from date + fromDate: + DateTime.parse(fromDateController.text), + ); + final progress = ProgressHUD.of(context); + progress!.showWithText("Loading..."); + context.read().add( + AddVoluntaryWork( + profileId: widget.profileId, + token: widget.token, + work: work)); + } + }, + child: const Text(submit)), + ) + ], + )), + ), + ); + } + return const Placeholder(); + }, + ); + } + + Future getProvinces() async { + try { + List newProvinces = await LocationUtils.instance + .getProvinces(regionCode: selectedRegion!.code.toString()); + setState(() { + provinces = newProvinces; + selectedProvince = provinces![0]; + provinceCall = false; + cityCall = true; + getCities(); + }); + } catch (e) { + context + .read() + .add(ShowErrorState(message: e.toString())); + } + } + + Future getCities() async { + try { + List newCities = await LocationUtils.instance + .getCities(code: selectedProvince!.code.toString()); + citymuns = newCities; + setState(() { + selectedMunicipality = newCities[0]; + cityCall = false; + }); + } catch (e) { + context + .read() + .add(ShowErrorState(message: e.toString())); + } + } +} diff --git a/lib/screens/profile/components/voluntary_works/edit_modal.dart b/lib/screens/profile/components/voluntary_works/edit_modal.dart new file mode 100644 index 0000000..3ad39ce --- /dev/null +++ b/lib/screens/profile/components/voluntary_works/edit_modal.dart @@ -0,0 +1,754 @@ +import 'package:date_time_picker/date_time_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/src/widgets/placeholder.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:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; +import 'package:searchfield/searchfield.dart'; +import 'package:unit2/bloc/profile/voluntary_works/voluntary_work_bloc.dart'; +import 'package:unit2/utils/global.dart'; +import 'package:unit2/utils/global_context.dart'; + +import '../../../../model/location/barangay.dart'; +import '../../../../model/location/city.dart'; +import '../../../../model/location/country.dart'; +import '../../../../model/location/provinces.dart'; +import '../../../../model/location/region.dart'; +import '../../../../model/profile/voluntary_works.dart'; +import '../../../../model/utils/agency.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/location_utilities.dart'; +import '../../../../utils/text_container.dart'; +import '../../shared/add_for_empty_search.dart'; + +class EditVoluntaryWorkScreen extends StatefulWidget { + final int profileId; + final String token; + const EditVoluntaryWorkScreen( + {super.key, required this.profileId, required this.token}); + + @override + State createState() => + _EditVoluntaryWorkScreenState(); +} + +class _EditVoluntaryWorkScreenState extends State { + final formKey = GlobalKey(); + ////controllers + final addPositionController = TextEditingController(); + final addAgencyController = TextEditingController(); + final toDateController = TextEditingController(); + final fromDateController = TextEditingController(); + final positionController = TextEditingController(); + final agencyController = TextEditingController(); + ////focus nodes + final positionFocusNode = FocusNode(); + final agencyFocusNode = FocusNode(); + final agencyCategoryFocusNode = FocusNode(); + ////booleans + bool showAgency = false; + bool showIsPrivateRadio = false; + bool currentlyInvolved = false; + bool overseas = false; + bool provinceCall = false; + bool cityCall = false; + bool isPrivate = false; + ////Lists + List? provinces; + List? citymuns; + + ////Selected + Position? selectedPosition; + Agency? selectedAgency; + Category? selectedCategoty; + Region? selectedRegion; + Province? selectedProvince; + CityMunicipality? selectedMunicipality; + Country? selectedCountry; + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) { + return false; + }, + builder: (context, state) { + if (state is EditVoluntaryWorks) { + ////config + String? todate = state.work.toDate?.toString(); + provinces = state.provinces; + citymuns = state.cities; + positionController.text = state.currentPosition.title!; + agencyController.text = state.currentAgency.name!; + fromDateController.text = state.work.fromDate.toString(); + toDateController.text = todate ??= ""; + currentlyInvolved = todate.isEmpty || todate == "null" ? true : false; + overseas = state.overseas; + selectedCountry = state.currentCountry; + selectedPosition = state.currentPosition; + selectedAgency = state.currentAgency; + selectedRegion = state.currentRegion; + selectedProvince = state.currentProvince; + selectedMunicipality = state.currentCity; + return Center( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 18), + child: FormBuilder( + key: formKey, + child: ListView( + children: [ + ////POSITIONS + StatefulBuilder(builder: (context, setState) { + return SearchField( + controller: positionController, + itemHeight: 50, + suggestionsDecoration: box1(), + suggestions: state.positions + .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: GestureDetector( + child: const Icon(Icons.arrow_drop_down), + onTap: () => positionFocusNode.unfocus(), + )), + onSuggestionTap: (position) { + setState(() { + selectedPosition = position.item; + positionFocusNode.unfocus(); + }); + }, + ////EMPTY WIDGET + emptyWidget: EmptyWidget( + title: "Add Position", + controller: addPositionController, + onpressed: () { + setState(() { + Position newAgencyPosition = Position( + id: null, + title: addPositionController.text + .toUpperCase()); + + state.positions.insert(0, newAgencyPosition); + + addPositionController.text = ""; + Navigator.pop(context); + }); + }), + validator: (position) { + if (position!.isEmpty) { + return "This field is required"; + } + return null; + }, + ); + }), + const SizedBox( + height: 12, + ), + ////AGENCY + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + SearchField( + controller: agencyController, + 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" + : agency.privateEntity == + false + ? "Government" + : ""), + ))) + .toList(), + searchInputDecoration: + normalTextFieldStyle("Agency *", "") + .copyWith( + suffixIcon: GestureDetector( + child: const Icon( + Icons.arrow_drop_down, + ), + onTap: () => agencyFocusNode.unfocus(), + )), + ////SELETECTED + onSuggestionTap: (agency) { + setState(() { + selectedAgency = agency.item; + if (selectedAgency!.privateEntity == null) { + showAgency = true; + showIsPrivateRadio = true; + } else { + showAgency = false; + showIsPrivateRadio = false; + } + agencyFocusNode.unfocus(); + }); + }, + validator: (agency) { + if (agency!.isEmpty) { + return "This field is required"; + } + return null; + }, + emptyWidget: EmptyWidget( + controller: addAgencyController, + onpressed: () { + setState(() { + Agency newAgency = Agency( + id: null, + name: addAgencyController.text + .toUpperCase(), + category: null, + privateEntity: null); + state.agencies.insert(0, newAgency); + + addAgencyController.text = ""; + Navigator.pop(context); + }); + }, + title: "Add Agency")), + + SizedBox( + height: showAgency ? 12 : 0, + ), + ////SHOW CATEGORY AGENCY + SizedBox( + child: showAgency + ? 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(() { + selectedCategoty = + agencyCategory.item; + agencyCategoryFocusNode.unfocus(); + }); + }, + 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(), + ), + SizedBox( + height: showIsPrivateRadio ? 12 : 0, + ), + ////PRVIATE SECTOR + SizedBox( + child: showIsPrivateRadio + ? FormBuilderSwitch( + initialValue: false, + title: Text(isPrivate ? "YES" : "NO"), + decoration: normalTextFieldStyle( + "Private Entity?", + 'Private Entity?'), + + ////onvhange private sector + onChanged: (value) { + setState(() { + isPrivate = value!; + agencyCategoryFocusNode.unfocus(); + }); + }, + + name: 'isPrivate', + validator: + FormBuilderValidators.required(), + ) + : const SizedBox()), + const SizedBox( + height: 12, + ), + //// total hours + FormBuilderTextField( + initialValue: state.work.totalHours.toString(), + validator: FormBuilderValidators.required( + errorText: "This Field is required"), + name: "total_hours", + keyboardType: TextInputType.number, + decoration: + normalTextFieldStyle("Total Hours*", "0"), + ), + const SizedBox( + height: 12, + ), + ////Currently Involved + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + FormBuilderSwitch( + initialValue: currentlyInvolved, + activeColor: second, + onChanged: (value) { + setState(() { + currentlyInvolved = value!; + }); + }, + decoration: normalTextFieldStyle( + "Currently Involved?", 'Graduated?'), + name: 'currently_involved', + title: + Text(currentlyInvolved ? "YES" : "NO"), + ), + const SizedBox( + height: 12, + ), + SizedBox( + width: screenWidth, + child: Row( + children: [ + //// FROM DATE + Flexible( + flex: 1, + child: DateTimePicker( + validator: FormBuilderValidators + .required( + errorText: + "This field is required"), + 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: currentlyInvolved + ? TextFormField( + enabled: false, + initialValue: "PRESENT", + style: const TextStyle( + color: Colors.black45), + decoration: + normalTextFieldStyle( + "", "") + .copyWith(), + ) + : DateTimePicker( + validator: FormBuilderValidators + .required( + errorText: + "This field is required"), + controller: toDateController, + firstDate: DateTime(1970), + lastDate: DateTime(2100), + decoration: normalTextFieldStyle( + "To *", "To *") + .copyWith( + prefixIcon: + const Icon( + Icons.date_range, + color: + Colors.black87, + ), + prefixText: + currentlyInvolved + ? "PRESENT" + : ""), + initialValue: null, + ), + ), + ], + ), + ), + ], + ); + }), + ], + ); + }), + const SizedBox( + height: 12, + ), + //// OVERSEAS + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + FormBuilderSwitch( + initialValue: overseas, + activeColor: second, + onChanged: (value) { + setState(() { + overseas = value!; + }); + }, + decoration: + normalTextFieldStyle("Overseas Address?", ''), + name: 'overseas', + title: Text(overseas ? "YES" : "NO"), + ), + SizedBox( + height: overseas == true ? 8 : 0, + ), + SizedBox( + child: overseas == false + ? Column( + children: [ + const SizedBox( + height: 12, + ), + ////REGION DROPDOWN + DropdownButtonFormField( + isExpanded: true, + autovalidateMode: AutovalidateMode + .onUserInteraction, + validator: + FormBuilderValidators.required( + errorText: + "This field is required"), + onChanged: (Region? region) async { + if (selectedRegion != region) { + setState(() { + provinceCall = true; + }); + selectedRegion = region; + try { + provinces = await LocationUtils + .instance + .getProvinces( + regionCode: + selectedRegion!.code + .toString()); + selectedProvince = + provinces![0]; + setState(() { + provinceCall = false; + cityCall = true; + }); + try { + citymuns = await LocationUtils + .instance + .getCities( + code: + selectedProvince! + .code + .toString()); + selectedMunicipality = + citymuns![0]; + setState(() { + cityCall = false; + }); + } catch (e) { + NavigationService.navigatorKey + .currentContext + ?.read< + VoluntaryWorkBloc>() + .add(ShowErrorState( + message: + e.toString())); + } + } catch (e) { + context + .read() + .add(ShowErrorState( + message: e.toString())); + } + } + }, + value: selectedRegion, + decoration: normalTextFieldStyle( + "Region*", "Region"), + items: state.regions + .map>( + (Region region) { + return DropdownMenuItem( + value: region, + child: + Text(region.description!)); + }).toList(), + ), + const SizedBox( + height: 8, + ), + //// PROVINCE DROPDOWN + SizedBox( + height: 60, + child: ModalProgressHUD( + color: Colors.transparent, + inAsyncCall: provinceCall, + child: DropdownButtonFormField< + Province?>( + autovalidateMode: + AutovalidateMode + .onUserInteraction, + validator: (value) => + value == null + ? 'required' + : null, + isExpanded: true, + value: selectedProvince, + onChanged: + (Province? province) async { + if (selectedProvince != + province) { + setState(() { + cityCall = true; + }); + selectedProvince = province; + try { + citymuns = await LocationUtils + .instance + .getCities( + code: selectedProvince! + .code + .toString()); + selectedMunicipality = + citymuns![0]; + setState(() { + cityCall = false; + }); + } catch (e) { + context + .read< + VoluntaryWorkBloc>() + .add(ShowErrorState( + message: e + .toString())); + } + } + }, + items: provinces == null + ? [] + : provinces!.map< + DropdownMenuItem< + Province>>( + (Province province) { + return DropdownMenuItem( + value: province, + child: FittedBox( + child: Text(province + .description!), + )); + }).toList(), + decoration: + normalTextFieldStyle( + "Province*", + "Province")), + ), + ), + ////CITY MUNICIPALITY + SizedBox( + height: 60, + child: ModalProgressHUD( + color: Colors.white, + inAsyncCall: cityCall, + child: DropdownButtonFormField< + CityMunicipality>( + validator: FormBuilderValidators + .required( + errorText: + "This field is required"), + isExpanded: true, + onChanged: + (CityMunicipality? city) { + if (selectedMunicipality != + city) { + selectedMunicipality = city; + } + }, + decoration: normalTextFieldStyle( + "Municipality*", + "Municipality"), + value: selectedMunicipality, + items: citymuns == null + ? [] + : citymuns!.map< + DropdownMenuItem< + CityMunicipality>>( + (CityMunicipality c) { + return DropdownMenuItem( + value: c, + child: Text( + c.description!)); + }).toList(), + ), + ), + ), + ], + ) + //// COUNTRY DROPDOWN + : SizedBox( + height: 60, + child: DropdownButtonFormField( + isExpanded: true, + validator: + FormBuilderValidators.required( + errorText: + "This field is required"), + items: state.countries + .map>( + (Country country) { + return DropdownMenuItem( + value: country, + child: FittedBox( + child: Text(country.name!))); + }).toList(), + value: selectedCountry, + decoration: normalTextFieldStyle( + "Country*", "Country"), + onChanged: (Country? value) { + selectedCountry = value; + }, + ), + ), + ), + ], + ); + }), + Expanded( + child: SizedBox( + height: blockSizeVertical * 8, + )), + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: mainBtnStyle( + primary, Colors.transparent, second), + onPressed: () { + if (formKey.currentState!.saveAndValidate()) { + Address address; + //// if not overseas + if (!overseas) { + address = Address( + barangay: null, + id: state.work.address?.id, + addressCategory: + state.work.address?.addressCategory, + addressClass: + state.work.address?.addressClass , + cityMunicipality: selectedMunicipality, + country: selectedCountry); + } else { + ////if overseas + address = Address( + barangay: null, + id: state.work.address?.id, + addressCategory: + state.work.address?.addressCategory, + addressClass: + state.work.address?.addressClass, + cityMunicipality: null, + country: selectedCountry); + } + + if (selectedCategoty != null) { + selectedAgency = Agency( + id: selectedAgency?.id, + name: selectedAgency!.name, + category: selectedCategoty, + privateEntity: isPrivate); + } + VoluntaryWork work = VoluntaryWork( + ////address + address: address, + //// agency + agency: selectedAgency, + //// + position: selectedPosition, + ////total hours + totalHours: double.parse(formKey + .currentState!.value["total_hours"]), + ////to date + toDate: toDateController.text.isEmpty || + toDateController.text.toUpperCase() == + "PRESENT" + ? null + : DateTime.parse(toDateController.text), + ////from date + fromDate: + DateTime.parse(fromDateController.text), + ); + final progress = ProgressHUD.of(context); + progress!.showWithText("Loading..."); + context.read().add( + UpdateVolunataryWork( + oldAgencyId: state.work.agency!.id!, + oldFromDate: + state.work.fromDate.toString(), + oldPosId: state.work.position!.id!, + profileId: widget.profileId, + token: widget.token, + work: work)); + } + }, + child: const Text(submit)), + ) + ], + )), + ), + ); + } + return const Placeholder(); + }, + ); + } +} diff --git a/lib/screens/profile/components/voluntary_works_screen.dart b/lib/screens/profile/components/voluntary_works_screen.dart index fbe0da8..20becc4 100644 --- a/lib/screens/profile/components/voluntary_works_screen.dart +++ b/lib/screens/profile/components/voluntary_works_screen.dart @@ -1,34 +1,41 @@ +import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:fluttericon/font_awesome_icons.dart'; 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/voluntary_works/add_modal.dart'; +import 'package:unit2/screens/profile/components/voluntary_works/add_modal.dart'; +import 'package:unit2/screens/profile/components/voluntary_works/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'; import 'package:unit2/widgets/Leadings/add_leading.dart'; import 'package:unit2/widgets/empty_data.dart'; +import 'package:unit2/widgets/error_state.dart'; import '../../../bloc/profile/voluntary_works/voluntary_work_bloc.dart'; +import '../../../utils/alerts.dart'; class VolunataryWorkScreen extends StatelessWidget { const VolunataryWorkScreen({super.key}); @override Widget build(BuildContext context) { - String? token; + String? token; int? profileId; DateFormat dteFormat2 = DateFormat.yMMMMd('en_US'); return Scaffold( appBar: AppBar( title: const Text(voluntaryScreenTitle), backgroundColor: primary, - actions: [AddLeading(onPressed: () { - context.read().add(ShowAddVoluntaryWorks()); - })], + actions: [ + AddLeading(onPressed: () { + context.read().add(ShowAddVoluntaryWorks()); + }) + ], ), body: ProgressHUD( padding: const EdgeInsets.all(24), @@ -37,9 +44,8 @@ class VolunataryWorkScreen extends StatelessWidget { child: BlocBuilder( builder: (context, state) { if (state is UserLoggedIn) { - token = state.userData!.user!.login!.token; - profileId = - state.userData!.user!.login!.user!.profileId; + token = state.userData!.user!.login!.token; + profileId = state.userData!.user!.login!.user!.profileId; return BlocBuilder( builder: (context, state) { if (state is ProfileLoaded) { @@ -51,10 +57,78 @@ class VolunataryWorkScreen extends StatelessWidget { progress!.showWithText("Please wait..."); } if (state is VoluntaryWorkLoadedState || - state is VoluntaryWorkErrorState|| state is AddVoluntaryWorkState) { + state is VoluntaryWorkErrorState || + state is AddVoluntaryWorkState || + state is VoluntaryWorkAddedState || + state is VoluntaryWorkDeletedState || + state is EditVoluntaryWorks) { final progress = ProgressHUD.of(context); progress!.dismiss(); } + //// Added State + if (state is VoluntaryWorkAddedState) { + if (state.response['success']) { + successAlert(context, "Adding Successfull!", + state.response['message'], () { + Navigator.of(context).pop(); + context + .read() + .add(LoadVoluntaryWorks()); + }); + } else { + errorAlert(context, "Adding Failed", + "Something went wrong. Please try again.", + () { + Navigator.of(context).pop(); + context + .read() + .add(LoadVoluntaryWorks()); + }); + } + } + //// Updated State + + if (state is VoluntaryWorkEditedState) { + if (state.response['success']) { + successAlert(context, "Updated Successfull!", + state.response['message'], () { + Navigator.of(context).pop(); + context + .read() + .add(LoadVoluntaryWorks()); + }); + } else { + errorAlert(context, "Update Failed", + "Something went wrong. Please try again.", + () { + Navigator.of(context).pop(); + context + .read() + .add(LoadVoluntaryWorks()); + }); + } + } + ////Deleted State + if (state is VoluntaryWorkDeletedState) { + if (state.success) { + successAlert(context, "Deletion Successfull!", + "Deleted Successfully", () { + Navigator.of(context).pop(); + context + .read() + .add(LoadVoluntaryWorks()); + }); + } else { + errorAlert(context, "Deletion Failed", + "Something went wrong. Please try again.", + () { + Navigator.of(context).pop(); + context + .read() + .add(LoadVoluntaryWorks()); + }); + } + } }, builder: (context, state) { if (state is VoluntaryWorkLoadedState) { @@ -128,10 +202,84 @@ class VolunataryWorkScreen extends StatelessWidget { "$numberOfHours : $hours hours"), ]), ), - IconButton( - onPressed: () {}, - icon: const Icon( - Icons.more_vert)) + AppPopupMenu( + offset: const Offset(-10, -10), + elevation: 3, + onSelected: (value) { + ////delete eligibilty-= = = = = = = = =>> + if (value == 2) { + confirmAlert(context, () { + final progress = + ProgressHUD.of( + context); + progress!.showWithText( + "Loading..."); + BlocProvider.of< + VoluntaryWorkBloc>( + context) + .add(DeleteVoluntaryWork( + work: state + .voluntaryWorks[ + index], + profileId: + profileId!, + token: token!)); + }, "Delete?", + "Confirm Delete?"); + } + if (value == 1) { + bool isOverseas; + ////edit voluntary work-= = = = = = = = =>> + final progress = + ProgressHUD.of(context); + progress!.showWithText( + "Loading..."); + + if (state + .voluntaryWorks[ + index] + .address?.cityMunicipality == null + ) { + isOverseas = true; + }else{ + isOverseas = false; + } + + + context + .read< + VoluntaryWorkBloc>() + .add(ShowEditVoluntaryWorks( + profileId: + profileId!, + token: token!, + work: state + .voluntaryWorks[ + index], + isOverseas: + isOverseas)); + } + }, + menuItems: [ + popMenuItem( + text: "Edit", + value: 1, + icon: Icons.edit), + popMenuItem( + text: "Delete", + value: 2, + icon: Icons.delete), + popMenuItem( + text: "Attachment", + value: 3, + icon: FontAwesome.attach) + ], + icon: const Icon( + Icons.more_vert, + color: Colors.grey, + ), + tooltip: "Options", + ) ], ), ), @@ -146,8 +294,22 @@ class VolunataryWorkScreen extends StatelessWidget { message: "You don't have any Voluntary Works added. Please click + to add."); } - }if(state is AddVoluntaryWorkState){ - return AddVoluntaryWorkScreen(profileId: profileId!,token: token!,); + } + if (state is AddVoluntaryWorkState) { + return AddVoluntaryWorkScreen( + profileId: profileId!, + token: token!, + ); + } + if (state is VoluntaryWorkErrorState) { + return SomethingWentWrong( + message: state.toString(), onpressed: () {}); + } + if (state is EditVoluntaryWorks) { + return EditVoluntaryWorkScreen( + profileId: profileId!, + token: token!, + ); } return Container(); }, @@ -162,4 +324,23 @@ class VolunataryWorkScreen extends StatelessWidget { )), ); } + + PopupMenuItem popMenuItem({String? text, int? value, IconData? icon}) { + return PopupMenuItem( + value: value, + child: Row( + children: [ + Icon( + icon, + ), + const SizedBox( + width: 10, + ), + Text( + text!, + ), + ], + ), + ); + } } diff --git a/lib/screens/profile/components/work_history/voluntary_works/add_modal.dart b/lib/screens/profile/components/work_history/voluntary_works/add_modal.dart deleted file mode 100644 index e7cf6cb..0000000 --- a/lib/screens/profile/components/work_history/voluntary_works/add_modal.dart +++ /dev/null @@ -1,597 +0,0 @@ -import 'package:date_time_picker/date_time_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/src/widgets/framework.dart'; -import 'package:flutter/src/widgets/placeholder.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:fluttericon/font_awesome_icons.dart'; -import 'package:form_builder_validators/form_builder_validators.dart'; -import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; -import 'package:searchfield/searchfield.dart'; -import 'package:unit2/bloc/profile/voluntary_works/voluntary_work_bloc.dart'; -import 'package:unit2/utils/global.dart'; - -import '../../../../../model/location/barangay.dart'; -import '../../../../../model/location/city.dart'; -import '../../../../../model/location/country.dart'; -import '../../../../../model/location/provinces.dart'; -import '../../../../../model/location/region.dart'; -import '../../../../../model/utils/agency.dart'; -import '../../../../../model/utils/category.dart'; -import '../../../../../model/utils/position.dart'; -import '../../../../../theme-data.dart/box_shadow.dart'; -import '../../../../../theme-data.dart/colors.dart'; -import '../../../../../theme-data.dart/form-style.dart'; -import '../../../../../utils/location_utilities.dart'; -import '../../../shared/add_for_empty_search.dart'; - -class AddVoluntaryWorkScreen extends StatefulWidget { - final int profileId; - final String token; - const AddVoluntaryWorkScreen( - {super.key, required this.profileId, required this.token}); - - @override - State createState() => _AddVoluntaryWorkScreenState(); -} - -class _AddVoluntaryWorkScreenState extends State { - final formKey = GlobalKey(); - ////controllers - final addPositionController = TextEditingController(); - final addAgencyController = TextEditingController(); - final toDateController = TextEditingController(); - final fromDateController = TextEditingController(); - ////focus nodes - final positionFocusNode = FocusNode(); - final agencyFocusNode = FocusNode(); - final agencyCategoryFocusNode = FocusNode(); - ////booleans - bool showAgency = false; - bool showIsPrivateRadio = false; - bool currentlyInvolved = false; - bool overseas = false; - bool provinceCall = false; - bool cityCall = false; - ////Lists - List? provinces; - List? citymuns; - ////Selected - Region? selectedRegion; - Province? selectedProvince; - CityMunicipality? selectedMunicipality; - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is AddVoluntaryWorkState) { - return SingleChildScrollView( - child: SizedBox( - height: screenHeight * .90, - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 25, horizontal: 18), - child: FormBuilder( - child: Column( - children: [ - ////POSITIONS - StatefulBuilder(builder: (context, setState) { - return SearchField( - itemHeight: 50, - suggestionsDecoration: box1(), - suggestions: state.positions - .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(() { - positionFocusNode.unfocus(); - }); - }, - ////EMPTY WIDGET - emptyWidget: EmptyWidget( - title: "Add Position", - controller: addPositionController, - onpressed: () { - setState(() { - Navigator.pop(context); - }); - }), - validator: (position) { - if (position!.isEmpty) { - return "This field is required"; - } - return null; - }, - ); - }), - const SizedBox( - height: 12, - ), - ////AGENCY - StatefulBuilder(builder: (context, setState) { - return Column( - children: [ - SearchField( - 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" - : agency.privateEntity == - false - ? "Government" - : ""), - ))) - .toList(), - searchInputDecoration: - normalTextFieldStyle("Agency *", "") - .copyWith( - suffixIcon: const Icon( - Icons.arrow_drop_down)), - onSuggestionTap: (agency) { - setState(() { - agencyFocusNode.unfocus(); - }); - }, - validator: (agency) { - if (agency!.isEmpty) { - return "This field is required"; - } - return null; - }, - emptyWidget: EmptyWidget( - controller: addAgencyController, - onpressed: () { - setState(() { - Navigator.pop(context); - }); - }, - title: "Add Agency")), - - SizedBox( - height: showAgency ? 12 : 0, - ), - ////SHOW CATEGORY AGENCY - SizedBox( - child: showAgency - ? 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(() {}); - }, - 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(() { - agencyCategoryFocusNode.unfocus(); - }); - }, - - name: 'isPrivate', - validator: - FormBuilderValidators.required(), - options: ["YES", "NO"] - .map((lang) => - FormBuilderFieldOption( - value: lang)) - .toList(growable: false), - ) - : const SizedBox()), - const SizedBox( - height: 12, - ), - FormBuilderTextField( - name: "total_hours", - keyboardType: TextInputType.number, - decoration: - normalTextFieldStyle("Total Hours*", "0"), - ), - const SizedBox( - height: 12, - ), - ////Currently Involved - StatefulBuilder(builder: (context, setState) { - return Column( - children: [ - FormBuilderSwitch( - initialValue: currentlyInvolved, - activeColor: second, - onChanged: (value) { - setState(() { - currentlyInvolved = value!; - }); - }, - decoration: normalTextFieldStyle( - "Currently Involved?", 'Graduated?'), - name: 'currently_involved', - title: Text( - currentlyInvolved ? "YES" : "NO"), - ), - const SizedBox( - height: 12, - ), - SizedBox( - width: screenWidth, - child: Row( - children: [ - //// FROM DATE - Flexible( - flex: 1, - child: DateTimePicker( - validator: FormBuilderValidators - .required( - errorText: - "This field is required"), - 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: currentlyInvolved - ? TextFormField( - enabled: false, - initialValue: "PRESENT", - style: const TextStyle( - color: Colors.black45), - decoration: - normalTextFieldStyle( - "", "") - .copyWith(), - ) - : DateTimePicker( - validator: FormBuilderValidators - .required( - errorText: - "This field is required"), - controller: - toDateController, - firstDate: DateTime(1970), - lastDate: DateTime(2100), - decoration: normalTextFieldStyle( - "To *", "To *") - .copyWith( - prefixIcon: - const Icon( - Icons.date_range, - color: Colors - .black87, - ), - prefixText: - currentlyInvolved - ? "PRESENT" - : ""), - initialValue: null, - ), - ), - ], - ), - ), - ], - ); - }), - ], - ); - }), - const SizedBox(height: 12,), - StatefulBuilder(builder: (context, setState) { - return Column( - children: [ - FormBuilderSwitch( - initialValue: overseas, - activeColor: second, - onChanged: (value) { - setState(() { - overseas = value!; - }); - }, - decoration: normalTextFieldStyle( - "Overseas Address?", ''), - name: 'overseas', - title: Text(overseas ? "YES" : "NO"), - ), - SizedBox( - height: overseas == true ? 8 : 0, - ), - SizedBox( - child: overseas == false - ? Column( - children: [ - const SizedBox( - height: 12, - ), - ////REGION DROPDOWN - FormBuilderDropdown( - autovalidateMode: AutovalidateMode - .onUserInteraction, - validator: - FormBuilderValidators.required( - errorText: - "This field is required"), - onChanged: (Region? region) async { - if (selectedRegion != region) { - setState(() { - provinceCall = true; - }); - selectedRegion = region; - getProvinces(); - } - }, - initialValue: null, - decoration: normalTextFieldStyle( - "Region*", "Region"), - name: 'region', - items: state.regions - .map>( - (Region region) { - return DropdownMenuItem( - value: region, - child: Text( - region.description!)); - }).toList(), - ), - const SizedBox( - height: 8, - ), - //// PROVINCE DROPDOWN - SizedBox( - height: 60, - child: ModalProgressHUD( - color: Colors.transparent, - inAsyncCall: provinceCall, - child: DropdownButtonFormField< - Province?>( - autovalidateMode: - AutovalidateMode - .onUserInteraction, - validator: (value) => - value == null - ? 'required' - : null, - isExpanded: true, - value: selectedProvince, - onChanged: - (Province? province) { - if (selectedProvince != - province) { - setState(() { - cityCall = true; - }); - selectedProvince = - province; - getCities(); - } - }, - items: provinces == null - ? [] - : provinces!.map< - DropdownMenuItem< - Province>>( - (Province province) { - return DropdownMenuItem( - value: province, - child: FittedBox( - child: Text(province - .description!), - )); - }).toList(), - decoration: - normalTextFieldStyle( - "Province*", - "Province")), - ), - ), - ////CITY MUNICIPALITY - SizedBox( - height: 60, - child: ModalProgressHUD( - color: Colors.white, - inAsyncCall: cityCall, - child: DropdownButtonFormField< - CityMunicipality>( - validator: FormBuilderValidators - .required( - errorText: - "This field is required"), - isExpanded: true, - onChanged: - (CityMunicipality? city) { - if (selectedMunicipality != - city) { - - selectedMunicipality = city; - - } - }, - decoration: - normalTextFieldStyle( - "Municipality*", - "Municipality"), - value: selectedMunicipality, - items: citymuns == null - ? [] - : citymuns!.map< - DropdownMenuItem< - CityMunicipality>>( - (CityMunicipality c) { - return DropdownMenuItem( - value: c, - child: Text(c - .description!)); - }).toList(), - ), - ), - ), - - ], - ) - //// COUNTRY DROPDOWN - : SizedBox( - height: 60, - child: FormBuilderDropdown( - initialValue: null, - validator: - FormBuilderValidators.required( - errorText: - "This field is required"), - items: state.countries - .map>( - (Country country) { - return DropdownMenuItem( - value: country, - child: FittedBox( - child: - Text(country.name!))); - }).toList(), - name: 'country', - decoration: normalTextFieldStyle( - "Country*", "Country"), - onChanged: (Country? value) {}, - ), - ), - ), - - ], - ); - }), - ], - )), - ), - )), - ); - } - return const Placeholder(); - }, - ); - } - Future getProvinces() async { - try { - List newProvinces = await LocationUtils.instance - .getProvinces(regionCode: selectedRegion!.code.toString()); - setState(() { - provinces = newProvinces; - selectedProvince = provinces![0]; - provinceCall = false; - cityCall = true; - getCities(); - }); - } catch (e) { - context.read().add(ShowErrorState(message: e.toString())); - } - } - - Future getCities() async { - try { - List newCities = await LocationUtils.instance - .getCities(code: selectedProvince!.code.toString()); - citymuns = newCities; - setState(() { - selectedMunicipality = newCities[0]; - cityCall = false; - }); - } catch (e) { - context.read().add(ShowErrorState(message: e.toString())); - } - } -} diff --git a/lib/sevices/profile/volunatary_services.dart b/lib/sevices/profile/volunatary_services.dart index 41d4974..0defef6 100644 --- a/lib/sevices/profile/volunatary_services.dart +++ b/lib/sevices/profile/volunatary_services.dart @@ -1,4 +1,3 @@ - import 'dart:convert'; import 'package:http/http.dart' as http; @@ -6,34 +5,156 @@ import 'package:unit2/utils/request.dart'; import '../../model/profile/voluntary_works.dart'; import '../../utils/urls.dart'; -class VoluntaryService{ +class VoluntaryService { static final VoluntaryService _instance = VoluntaryService(); static VoluntaryService get instance => _instance; - Future< List> getVoluntaryWorks(int profileId, String token)async{ + Future> getVoluntaryWorks( + int profileId, String token) async { List voluntaryWorks = []; - String authToken = "Token $token"; - String path = "${Url.instance.getVoluntaryWorks()}$profileId/"; + String authToken = "Token $token"; + String path = "${Url.instance.getVoluntaryWorks()}$profileId/"; Map headers = { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': authToken }; - try{ - http.Response response = await Request.instance.getRequest(path: path,param: {},headers: headers); - if(response.statusCode == 200){ + // try { + http.Response response = await Request.instance + .getRequest(path: path, param: {}, headers: headers); + if (response.statusCode == 200) { Map data = jsonDecode(response.body); - if(data['data'] != null){ - data['data'].forEach((var work){ - VoluntaryWork voluntaryWork = VoluntaryWork.fromJson(work); - voluntaryWorks.add(voluntaryWork); + if (data['data'] != null) { + data['data'].forEach((var work) { + VoluntaryWork voluntaryWork = VoluntaryWork.fromJson(work); + voluntaryWorks.add(voluntaryWork); }); } } - }catch(e){ - throw(e.toString()); - } + // } catch (e) { + // throw (e.toString()); + // } -return voluntaryWorks; - } -} \ No newline at end of file + return voluntaryWorks; + } + + Future> add( + {required VoluntaryWork voluntaryWork, + required int profileId, + required String token}) async { + Map? responseData = {}; + String authToken = "Token $token"; + String path = "${Url.instance.getVoluntaryWorks()}$profileId/"; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': authToken + }; + Map body = { + "position_id": voluntaryWork.position?.id, + "agency_id": voluntaryWork.agency?.id, + "address_id": voluntaryWork.address?.id, + "from_date": voluntaryWork.fromDate.toString(), + "to_date": voluntaryWork.toDate == null?null:voluntaryWork.toDate.toString(), + "total_hours": voluntaryWork.totalHours, + "_positionName": voluntaryWork.position!.title, + "_agencyName": voluntaryWork.agency!.name, + "_agencyCatId": voluntaryWork.agency!.category!.id, + "_privateEntity": voluntaryWork.agency!.privateEntity, + "_citymunCode": voluntaryWork.address?.cityMunicipality?.code, + "_countryId": voluntaryWork.address?.country?.id + }; + try { + http.Response response = await Request.instance + .postRequest(param: {}, path: path, body: body, headers: headers); + if (response.statusCode == 201) { + Map data = jsonDecode(response.body); + responseData = data; + } else { + responseData.addAll({'success': false}); + } + } catch (e) { + throw e.toString(); + } + return responseData; + } + +////update + Future> update( + {required VoluntaryWork voluntaryWork, + required int profileId, + required String token, + required int oldPosId, + required int oldAgencyId, + required String oldFromDate}) async { + Map? responseData = {}; + String authToken = "Token $token"; + String path = "${Url.instance.getVoluntaryWorks()}$profileId/"; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': authToken + }; + Map body = { + "position_id": voluntaryWork.position?.id, + "agency_id": voluntaryWork.agency?.id, + "address_id": voluntaryWork.address!.id, + "from_date": voluntaryWork.fromDate.toString(), + "to_date": voluntaryWork.toDate == null?null:voluntaryWork.toDate.toString(), + "total_hours": voluntaryWork.totalHours, + "_positionName": voluntaryWork.position!.title, + "_agencyName": voluntaryWork.agency!.name, + "_agencyCatId": voluntaryWork.agency!.category!.id, + "_privateEntity": voluntaryWork.agency!.privateEntity, + "_citymunCode": voluntaryWork.address?.cityMunicipality?.code, + "_countryId": voluntaryWork.address!.country!.id, + "_oldPosId": oldPosId, + "_oldAgencyId": oldAgencyId, + "_oldFromDate": oldFromDate + }; + try { + http.Response response = await Request.instance + .putRequest(param: {}, path: path, body: body, headers: headers); + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + responseData = data; + } else { + responseData.addAll({'success': false}); + } + } catch (e) { + throw e.toString(); + } + return responseData; + } + + ////delete + Future delete( + {required int agencyId, + required int positionId, + required String fromDate, + required String token, + required int profileId}) async { + bool success = false; + String authToken = "Token $token"; + String path = "${Url.instance.getVoluntaryWorks()}$profileId/"; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': authToken + }; + Map params = {"force_mode": "true"}; + Map body = { + "agency_id": agencyId, + "position_id": positionId, + "from_date": fromDate, + }; + try { + http.Response response = await Request.instance.deleteRequest( + path: path, headers: headers, body: body, param: params); + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + success = data['success']; + } + } catch (e) { + throw (e.toString()); + } + return success; + } +} diff --git a/lib/utils/urls.dart b/lib/utils/urls.dart index de84310..7f3839d 100644 --- a/lib/utils/urls.dart +++ b/lib/utils/urls.dart @@ -6,8 +6,8 @@ class Url { // return '192.168.10.183:3000'; // return 'agusandelnorte.gov.ph'; // return "192.168.10.219:3000"; - // return "devweb.agusandelnorte.gov.ph"; - return 'devapi.agusandelnorte.gov.ph:3004'; + return "devweb.agusandelnorte.gov.ph"; + // return 'devapi.agusandelnorte.gov.ph:3004'; } String authentication() { diff --git a/pubspec.yaml b/pubspec.yaml index 943b2ce..5a652da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -77,7 +77,8 @@ dependencies: hive_flutter: ^1.1.0 mask_text_input_formatter: ^2.4.0 location: ^4.3.0 - platform_device_id: ^1.0.1, + platform_device_id: ^1.0.1 + multi_dropdown: ^1.0.9 dev_dependencies: flutter_test: