From 7f39bd5cd9fab0765e3c57fda71d7f8bffd30dcc Mon Sep 17 00:00:00 2001 From: PGAN-MIS Date: Tue, 25 Apr 2023 15:50:36 +0800 Subject: [PATCH] implemented education profile API --- lib/bloc/docsms/docsms_bloc.dart | 28 + lib/bloc/docsms/docsms_event.dart | 15 + lib/bloc/docsms/docsms_state.dart | 28 + .../profile/education/education_bloc.dart | 108 +- .../profile/education/education_event.dart | 58 +- .../profile/education/education_state.dart | 61 +- .../profile/eligibility/eligibility_bloc.dart | 28 +- .../address/address_bloc.dart | 48 + .../address/address_event.dart | 10 + .../address/address_state.dart | 42 +- .../voluntary_works/voluntary_work_bloc.dart | 42 + .../voluntary_works/voluntary_work_event.dart | 8 + .../voluntary_works/voluntary_work_state.dart | 17 +- .../profile/workHistory/workHistory_bloc.dart | 2 +- lib/model/docsms/document.dart | 207 +++ lib/model/profile/educational_background.dart | 2 +- .../{ => components}/request_receipt.dart | 10 +- lib/screens/docsms/index.dart | 52 + .../basic_information/address/add_modal.dart | 474 +++++++ .../basic_information/address/edit_modal.dart | 474 +++++++ .../basic_information/address_screen.dart | 133 +- .../components/education/add_modal.dart | 510 +++++++ .../components/education/edit_modal.dart | 564 ++++++++ .../profile/components/education_screen.dart | 182 ++- .../components/eligibility/add_modal.dart | 714 +++++----- .../components/voluntary_works_screen.dart | 14 +- .../components/work_history/add_modal.dart | 1183 +++++++---------- .../components/work_history/edit_modal.dart | 293 ++-- .../voluntary_works/add_modal.dart | 597 +++++++++ .../profile/shared/add_for_empty_search.dart | 68 + .../homepage.dart/components/dashboard.dart | 277 ++-- .../unit2/homepage.dart/module-screen.dart | 10 +- lib/sevices/docsms/docsms_service.dart | 36 + lib/sevices/profile/education_services.dart | 201 ++- .../profile/work_history_services.dart | 2 +- lib/utils/app_router.dart | 3 + lib/utils/profile_utilities.dart | 88 +- lib/utils/qr_scanner.dart | 17 + lib/utils/urls.dart | 22 +- pubspec.lock | 32 + pubspec.yaml | 2 +- 41 files changed, 5233 insertions(+), 1429 deletions(-) create mode 100644 lib/bloc/docsms/docsms_bloc.dart create mode 100644 lib/bloc/docsms/docsms_event.dart create mode 100644 lib/bloc/docsms/docsms_state.dart create mode 100644 lib/model/docsms/document.dart rename lib/screens/docsms/{ => components}/request_receipt.dart (96%) create mode 100644 lib/screens/docsms/index.dart create mode 100644 lib/screens/profile/components/basic_information/address/add_modal.dart create mode 100644 lib/screens/profile/components/basic_information/address/edit_modal.dart create mode 100644 lib/screens/profile/components/education/add_modal.dart create mode 100644 lib/screens/profile/components/education/edit_modal.dart create mode 100644 lib/screens/profile/components/work_history/voluntary_works/add_modal.dart create mode 100644 lib/screens/profile/shared/add_for_empty_search.dart create mode 100644 lib/sevices/docsms/docsms_service.dart create mode 100644 lib/utils/qr_scanner.dart diff --git a/lib/bloc/docsms/docsms_bloc.dart b/lib/bloc/docsms/docsms_bloc.dart new file mode 100644 index 0000000..be473b2 --- /dev/null +++ b/lib/bloc/docsms/docsms_bloc.dart @@ -0,0 +1,28 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:unit2/sevices/docsms/docsms_service.dart'; + +import '../../model/docsms/document.dart'; + +part 'docsms_event.dart'; +part 'docsms_state.dart'; + +class DocsmsBloc extends Bloc { + DocsmsBloc() : super(DocsmsInitial()) { + Document? document; + on((event, emit)async { + emit(DocSmsLoadingState()); + try { + document = await AutoReceiveDocumentServices.instance.getDocument(event.documentId); + if(document != null){ + emit(DocumentLoaded(document: document!)); + }else{ + emit(const DocSmsErrorState(message: "Invalid Qr code")); + } + +} catch (e) { + emit(DocSmsErrorState(message: e.toString())); + } + }); + } +} diff --git a/lib/bloc/docsms/docsms_event.dart b/lib/bloc/docsms/docsms_event.dart new file mode 100644 index 0000000..190fd98 --- /dev/null +++ b/lib/bloc/docsms/docsms_event.dart @@ -0,0 +1,15 @@ +part of 'docsms_bloc.dart'; + +abstract class DocsmsEvent extends Equatable { + const DocsmsEvent(); + + @override + List get props => []; +} + +class LoadDocument extends DocsmsEvent{ +final String documentId; +const LoadDocument({required this.documentId}); + @override + List get props => []; +} diff --git a/lib/bloc/docsms/docsms_state.dart b/lib/bloc/docsms/docsms_state.dart new file mode 100644 index 0000000..c06433a --- /dev/null +++ b/lib/bloc/docsms/docsms_state.dart @@ -0,0 +1,28 @@ +part of 'docsms_bloc.dart'; + +abstract class DocsmsState extends Equatable { + const DocsmsState(); + + @override + List get props => []; +} + +class DocsmsInitial extends DocsmsState {} + +class DocSmsLoadingState extends DocsmsState{ + +} +class DocumentLoaded extends DocsmsState{ + final Document document; + const DocumentLoaded({required this.document}); + @override + List get props => [document]; + +} + +class DocSmsErrorState extends DocsmsState{ + final String message; + const DocSmsErrorState({required this.message}); + @override + List get props => [message]; +} diff --git a/lib/bloc/profile/education/education_bloc.dart b/lib/bloc/profile/education/education_bloc.dart index bb19420..73f08b3 100644 --- a/lib/bloc/profile/education/education_bloc.dart +++ b/lib/bloc/profile/education/education_bloc.dart @@ -8,10 +8,13 @@ part 'education_state.dart'; class EducationBloc extends Bloc { List educationalBackgrounds = []; + List schools = []; + List programs = []; + List honors = []; EducationBloc() : super(EducationInitial()) { on((event, emit) async { emit(EducationalBackgroundLoadingState()); - try { + try { List educations = await EducationService.instace .getEducationalBackground(event.profileId, event.token); educationalBackgrounds = educations; @@ -21,5 +24,108 @@ class EducationBloc extends Bloc { emit(EducationalBackgroundErrorState(message: e.toString())); } }); + //// SHOW ADD FORM + on((event, emit) async { + emit(EducationalBackgroundLoadingState()); + try { + if (schools.isEmpty) { + List newSchools = await EducationService.instace.getSchools(); + schools = newSchools; + } + if (programs.isEmpty) { + List newPrograms = + await EducationService.instace.getPrograms(); + programs = newPrograms; + } + if (honors.isEmpty) { + List newHonors = await EducationService.instace.getHonors(); + honors = newHonors; + } + emit(AddEducationState( + schools: schools, programs: programs, honors: honors)); + } catch (e) { + emit(EducationalBackgroundErrorState(message: e.toString())); + } + }); + ////Add + on((event, emit) async { + Map status = await EducationService.instace.add( + honors: event.honors, + educationalBackground: event.educationalBackground, + token: event.token, + profileId: event.profileId); + if (status['success']) { + EducationalBackground educationalBackground = + EducationalBackground.fromJson(status['data']); + educationalBackgrounds.add(educationalBackground); + emit(EducationAddedState(response: status)); + } else { + emit(EducationAddedState(response: status)); + } + }); + ////Update + on((event, emit) async { + Map status = await EducationService.instace.edit( + honors: event.honors, + educationalBackground: event.educationalBackground, + token: event.token, + profileId: event.profileId); + if (status['success']) { + EducationalBackground educationalBackground = + EducationalBackground.fromJson(status['data']); + educationalBackgrounds.add(educationalBackground); + emit(EditedEducationState(response: status)); + } else { + emit(EditedEducationState(response: status)); + } + }); + ////LOAD + on((event, emit) { + emit(EducationalBackgroundLoadedState( + educationalBackground: educationalBackgrounds)); + }); + //// SHOW EDIT FORM + on((event, emit) async { + try { + if (schools.isEmpty) { + List newSchools = await EducationService.instace.getSchools(); + schools = newSchools; + } + if (programs.isEmpty) { + List newPrograms = + await EducationService.instace.getPrograms(); + programs = newPrograms; + } + if (honors.isEmpty) { + List newHonors = await EducationService.instace.getHonors(); + honors = newHonors; + } + emit(EditEducationState( + schools: schools, + programs: programs, + honors: honors, + educationalBackground: event.educationalBackground)); + } catch (e) { + emit(EducationalBackgroundErrorState(message: e.toString())); + } + }); + ////delete + on((event, emit) async { + try { + final bool success = await EducationService.instace.delete( + profileId: event.profileId, + token: event.token, + educationalBackground: event.educationalBackground); + if (success) { + educationalBackgrounds.removeWhere( + (element) => element.id == event.educationalBackground.id); + emit(EducationDeletedState(success: success)); + } else { + emit(EducationDeletedState(success: success)); + } + } catch (e) { + emit(EducationalBackgroundErrorState(message: e.toString())); + } + }); } } diff --git a/lib/bloc/profile/education/education_event.dart b/lib/bloc/profile/education/education_event.dart index cfe1db7..59a431b 100644 --- a/lib/bloc/profile/education/education_event.dart +++ b/lib/bloc/profile/education/education_event.dart @@ -6,10 +6,60 @@ abstract class EducationEvent extends Equatable { @override List get props => []; } -class GetEducationalBackground extends EducationEvent{ + +class GetEducationalBackground extends EducationEvent { final int profileId; final String token; - const GetEducationalBackground({required this.profileId, required this.token}); - @override - List get props => [profileId,token]; + const GetEducationalBackground( + {required this.profileId, required this.token}); + @override + List get props => [profileId, token]; +} +////show add form +class ShowAddEducationForm extends EducationEvent {} +////show edit form +class ShowEditEducationForm extends EducationEvent { + final EducationalBackground educationalBackground; + final int profileId; + final String token; + const ShowEditEducationForm({required this.educationalBackground,required this.profileId, required this.token}); + @override + List get props => [educationalBackground]; +} +////load +class LoadEducations extends EducationEvent {} +////add +class AddEducation extends EducationEvent { + final List honors; + final EducationalBackground educationalBackground; + final int profileId; + final String token; + const AddEducation( + {required this.educationalBackground, + required this.profileId, + required this.token, required this.honors}); + @override + List get props => [educationalBackground, profileId, token]; +} +////update education +class UpdateEducation extends EducationEvent{ + final List honors; + final EducationalBackground educationalBackground; + final int profileId; + final String token; + const UpdateEducation( + {required this.educationalBackground, + required this.profileId, + required this.token,required this.honors}); + @override + List get props => [educationalBackground, profileId, token]; +} +////delete +class DeleteEducation extends EducationEvent{ + final int profileId; + final String token; + final EducationalBackground educationalBackground; + const DeleteEducation({required this.educationalBackground, required this.profileId, required this.token}); + @override + List get props => [educationalBackground, profileId, token]; } diff --git a/lib/bloc/profile/education/education_state.dart b/lib/bloc/profile/education/education_state.dart index cc75963..2a0f1ec 100644 --- a/lib/bloc/profile/education/education_state.dart +++ b/lib/bloc/profile/education/education_state.dart @@ -2,28 +2,73 @@ part of 'education_bloc.dart'; abstract class EducationState extends Equatable { const EducationState(); - + @override List get props => []; } class EducationInitial extends EducationState {} - - -class EducationalBackgroundLoadedState extends EducationState{ +class EducationalBackgroundLoadedState extends EducationState { final List educationalBackground; const EducationalBackgroundLoadedState({required this.educationalBackground}); - @override + @override List get props => [educationalBackground]; } -class EducationalBackgroundErrorState extends EducationState{ +class EducationalBackgroundErrorState extends EducationState { final String message; const EducationalBackgroundErrorState({required this.message}); - @override + @override List get props => [message]; } -class EducationalBackgroundLoadingState extends EducationState{ +class EducationalBackgroundLoadingState extends EducationState {} + +////Add +class AddEducationState extends EducationState { + final List schools; + final List programs; + final List honors; + const AddEducationState( + {required this.honors, required this.programs, required this.schools}); + @override + List get props => [schools, programs, honors]; +} + +////Edit +class EditEducationState extends EducationState { + final EducationalBackground educationalBackground; + final List schools; + final List programs; + final List honors; + const EditEducationState({ + required this.educationalBackground, + required this.honors, + required this.programs, + required this.schools, + }); +} + +//// Added State +class EducationAddedState extends EducationState { + final Map response; + const EducationAddedState({required this.response}); + @override + List get props => [response]; +} +//// Edited State +class EditedEducationState extends EducationState { + final Map response; + const EditedEducationState({required this.response}); + @override + List get props => [response]; +} + +////deleted State +class EducationDeletedState extends EducationState { + final bool success; + const EducationDeletedState({required this.success}); + @override + List get props => [success]; } diff --git a/lib/bloc/profile/eligibility/eligibility_bloc.dart b/lib/bloc/profile/eligibility/eligibility_bloc.dart index 28c0627..4f03727 100644 --- a/lib/bloc/profile/eligibility/eligibility_bloc.dart +++ b/lib/bloc/profile/eligibility/eligibility_bloc.dart @@ -14,8 +14,8 @@ part 'eligibility_state.dart'; class EligibilityBloc extends Bloc { EligibilityBloc() : super(EligibilityInitial()) { - List? globalCountries; - List? globalRegions; + List globalCountries = []; + List globalRegions = []; List globalEligibilities = []; List eligibilities = []; //// LOAD ELIGIBILTY @@ -67,11 +67,11 @@ class EligibilityBloc extends Bloc { //// SHOW EDIT FORM on((event, emit) async { try { - if (globalCountries == null) { + if (globalCountries.isEmpty) { List countries = await LocationUtils.instance.getCountries(); globalCountries = countries; } - if (globalRegions == null) { + if (globalRegions.isEmpty) { List regions = await LocationUtils.instance.getRegions(); globalRegions = regions; } @@ -84,13 +84,13 @@ class EligibilityBloc extends Bloc { (Eligibility eligibility) => event.eligibityCert.eligibility!.id == eligibility.id); bool? isOverseas = event.eligibityCert.overseas; - Country currentCountry = globalCountries!.firstWhere( + Country currentCountry = globalCountries.firstWhere( (Country country) => event.eligibityCert.examAddress!.country!.code == country.code); if (event.eligibityCert.examAddress?.cityMunicipality?.province ?.region != null) { - Region currrentRegion = globalRegions!.firstWhere((Region region) => + Region currrentRegion = globalRegions.firstWhere((Region region) => event.eligibityCert.examAddress!.cityMunicipality!.province! .region!.code == region.code); @@ -117,8 +117,8 @@ class EligibilityBloc extends Bloc { cities: cities, isOverseas: isOverseas!, eligibityCert: event.eligibityCert, - countries: globalCountries!, - regions: globalRegions!, + countries: globalCountries, + regions: globalRegions, eligibilities: globalEligibilities)); } else { emit(EditEligibilityState( @@ -131,8 +131,8 @@ class EligibilityBloc extends Bloc { currentEligibility: currentEligibility, isOverseas: isOverseas!, eligibityCert: event.eligibityCert, - countries: globalCountries!, - regions: globalRegions!, + countries: globalCountries, + regions: globalRegions, eligibilities: globalEligibilities)); } } catch (e) { @@ -164,7 +164,7 @@ class EligibilityBloc extends Bloc { //// SHOW ADD FORM on((event, emit) async { emit(EligibilityLoadingState()); - if (globalRegions == null) { + if (globalRegions.isEmpty) { List regions = await LocationUtils.instance.getRegions(); globalRegions = regions; } @@ -173,15 +173,15 @@ class EligibilityBloc extends Bloc { await ProfileUtilities.instance.getEligibilities(); globalEligibilities = eligibilities; } - if (globalCountries == null) { + if (globalCountries.isEmpty) { List countries = await LocationUtils.instance.getCountries(); globalCountries = countries; } emit(AddEligibilityState( eligibilities: globalEligibilities, - regions: globalRegions!, - countries: globalCountries!)); + regions: globalRegions, + countries: globalCountries)); }); //// ADD diff --git a/lib/bloc/profile/primary_information/address/address_bloc.dart b/lib/bloc/profile/primary_information/address/address_bloc.dart index 30195bc..00f09c0 100644 --- a/lib/bloc/profile/primary_information/address/address_bloc.dart +++ b/lib/bloc/profile/primary_information/address/address_bloc.dart @@ -1,13 +1,21 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:unit2/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/basic_information/adress.dart'; +import '../../../../utils/location_utilities.dart'; part 'address_event.dart'; part 'address_state.dart'; class AddressBloc extends Bloc { AddressBloc() : super(AddressInitial()) { + List globalCountries=[]; + List globalRegions=[]; List addresses = []; on((event, emit) { emit(AddressLoadingState()); @@ -17,6 +25,46 @@ class AddressBloc extends Bloc { }catch(e){ emit(AddressErrorState(message: e.toString())); } + //// show add form + });on((event,emit)async{ + emit(AddressLoadingState()); + try{ + if (globalRegions.isEmpty) { + List regions = await LocationUtils.instance.getRegions(); + globalRegions = regions; + } + if (globalCountries.isEmpty) { + List countries = await LocationUtils.instance.getCountries(); + globalCountries = countries; + } + emit(AddAddressState(countries: globalCountries, regions: globalRegions)); + }catch(e){ + emit(AddressErrorState(message: e.toString())); + } + }); + + //// Show Edit Form + on((event,emit)async{ + + try{ + if (globalRegions.isEmpty) { + List regions = await LocationUtils.instance.getRegions(); + globalRegions = regions; + } + if (globalCountries.isEmpty) { + List countries = await LocationUtils.instance.getCountries(); + globalCountries = countries; + } + emit(EditAddressState(countries: globalCountries, regions: globalRegions,address: event.address)); + }catch(e){ + emit(AddressErrorState(message: e.toString())); + } + }); + + ////call error state + on((event, emit) { + emit(const AddressErrorState( + message: "Something went wrong. Please try again")); }); } } diff --git a/lib/bloc/profile/primary_information/address/address_event.dart b/lib/bloc/profile/primary_information/address/address_event.dart index 1f4ba71..f1d36f4 100644 --- a/lib/bloc/profile/primary_information/address/address_event.dart +++ b/lib/bloc/profile/primary_information/address/address_event.dart @@ -13,3 +13,13 @@ class GetAddress extends AddressEvent{ @override List get props => [addresses]; } +class ShowAddAddressForm extends AddressEvent{ + +} +class ShowEditAddressForm extends AddressEvent{ + final MainAdress address; + const ShowEditAddressForm({required this.address}); +} +class CallErrorState extends AddressEvent{ + +} diff --git a/lib/bloc/profile/primary_information/address/address_state.dart b/lib/bloc/profile/primary_information/address/address_state.dart index fcdeea3..563a5f4 100644 --- a/lib/bloc/profile/primary_information/address/address_state.dart +++ b/lib/bloc/profile/primary_information/address/address_state.dart @@ -2,26 +2,46 @@ part of 'address_bloc.dart'; abstract class AddressState extends Equatable { const AddressState(); - + @override List get props => []; } class AddressInitial extends AddressState {} - -class AddressLoadedState extends AddressState{ - final List addresses; - const AddressLoadedState({required this.addresses}); - @override +//// LOADED STATE +class AddressLoadedState extends AddressState { + final List addresses; + const AddressLoadedState({required this.addresses}); + @override List get props => [addresses]; } - -class AddressErrorState extends AddressState{ +////ERROR STATE +class AddressErrorState extends AddressState { final String message; const AddressErrorState({required this.message}); - @override + @override List get props => [message]; } -class AddressLoadingState extends AddressState{ - +//// LOADING STATE +class AddressLoadingState extends AddressState {} + +////ADD ADDRESS STATE +class AddAddressState extends AddressState { + final List countries; + final List regions; + const AddAddressState( + { + required this.countries, + required this.regions}); + @override + List get props => [countries, regions,]; } + +class EditAddressState extends AddressState{ + final MainAdress address; + final List countries; + final List regions; + const EditAddressState({required this.address, required this.countries, required this.regions}); + @override + List get props => [countries, regions,address]; +} \ No newline at end of file diff --git a/lib/bloc/profile/voluntary_works/voluntary_work_bloc.dart b/lib/bloc/profile/voluntary_works/voluntary_work_bloc.dart index d2bbd22..0480f9c 100644 --- a/lib/bloc/profile/voluntary_works/voluntary_work_bloc.dart +++ b/lib/bloc/profile/voluntary_works/voluntary_work_bloc.dart @@ -1,8 +1,14 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:unit2/sevices/profile/volunatary_services.dart'; +import 'package:unit2/utils/profile_utilities.dart'; +import '../../../model/location/country.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'; part 'voluntary_work_event.dart'; part 'voluntary_work_state.dart'; @@ -10,6 +16,12 @@ 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{ emit(VoluntaryWorkLoadingState()); try{ @@ -20,5 +32,35 @@ class VoluntaryWorkBloc extends Bloc { emit(VoluntaryWorkErrorState(message: e.toString())); } }); + //// Show Add form Event + on((event,emit)async{ + try{ + emit(VoluntaryWorkLoadingState()); + if (agencyPositions.isEmpty) { + List positions = + await ProfileUtilities.instance.getAgencyPosition(); + agencyPositions = positions; + } + + /////AGENCIES------------------------------------------ + if (agencies.isEmpty) { + List newAgencies = + await ProfileUtilities.instance.getAgecies(); + agencies = newAgencies; + } + + /////Category Agency------------------------------------------ + if (agencyCategory.isEmpty) { + List categoryAgencies = + await ProfileUtilities.instance.agencyCategory(); + agencyCategory = categoryAgencies; + } + 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)); + }); } } diff --git a/lib/bloc/profile/voluntary_works/voluntary_work_event.dart b/lib/bloc/profile/voluntary_works/voluntary_work_event.dart index 0e62010..52aba14 100644 --- a/lib/bloc/profile/voluntary_works/voluntary_work_event.dart +++ b/lib/bloc/profile/voluntary_works/voluntary_work_event.dart @@ -14,3 +14,11 @@ class GetVoluntarWorks extends VoluntaryWorkEvent{ @override List get props => [profileId,token]; } +class ShowAddVoluntaryWorks extends VoluntaryWorkEvent{ + +} + +class ShowErrorState extends VoluntaryWorkEvent{ + final String message; + const ShowErrorState({required this.message}); +} diff --git a/lib/bloc/profile/voluntary_works/voluntary_work_state.dart b/lib/bloc/profile/voluntary_works/voluntary_work_state.dart index 8c2c912..3024e12 100644 --- a/lib/bloc/profile/voluntary_works/voluntary_work_state.dart +++ b/lib/bloc/profile/voluntary_works/voluntary_work_state.dart @@ -8,20 +8,33 @@ abstract class VoluntaryWorkState extends Equatable { } class VoluntaryWorkInitial extends VoluntaryWorkState {} +////Loaded State class VoluntaryWorkLoadedState extends VoluntaryWorkState{ final List voluntaryWorks; const VoluntaryWorkLoadedState({required this.voluntaryWorks}); @override List get props => [voluntaryWorks]; } - +////Error State class VoluntaryWorkErrorState extends VoluntaryWorkState{ final String message; const VoluntaryWorkErrorState({required this.message}); @override List get props => [message]; } - +////Loading State class VoluntaryWorkLoadingState extends VoluntaryWorkState{ } + + +class AddVoluntaryWorkState extends VoluntaryWorkState{ + final List positions; + final List agencies; + final List agencyCategory; + final List countries; + final List regions; + 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 diff --git a/lib/bloc/profile/workHistory/workHistory_bloc.dart b/lib/bloc/profile/workHistory/workHistory_bloc.dart index d19eca5..a3c9f4b 100644 --- a/lib/bloc/profile/workHistory/workHistory_bloc.dart +++ b/lib/bloc/profile/workHistory/workHistory_bloc.dart @@ -26,7 +26,7 @@ class WorkHistoryBloc extends Bloc { try { if (workExperiences.isEmpty) { List works = await WorkHistoryService.instance - .getWorkExperiences(event.profileId!, event.token!); + .getWorkExperiences(event.profileId, event.token); workExperiences = works; } diff --git a/lib/model/docsms/document.dart b/lib/model/docsms/document.dart new file mode 100644 index 0000000..354ca18 --- /dev/null +++ b/lib/model/docsms/document.dart @@ -0,0 +1,207 @@ +// To parse this JSON data, do +// +// final document = documentFromJson(jsonString); + +class Document { + Document({ + required this.id, + required this.sk, + required this.dsk, + required this.slug, + required this.files, + required this.title, + required this.agency, + required this.office, + required this.subject, + required this.fileType, + required this.isPublic, + required this.createdAt, + required this.createdBy, + required this.validatedAt, + required this.validatedBy, + required this.documentType, + required this.documentRoutes, + required this.alternateMobile, + required this.attachedDocument, + required this.enableNotification, + required this.createdByPersonId, + }); + + final int? id; + final String? sk; + final String? dsk; + final String? slug; + final List? files; + final String? title; + final String? agency; + final String? office; + final String? subject; + final FileType? fileType; + final bool? isPublic; + final String? createdAt; + final String? createdBy; + final String? validatedAt; + final String? validatedBy; + final DocumentType? documentType; + final dynamic documentRoutes; + final AlternateMobile? alternateMobile; + final dynamic attachedDocument; + final bool? enableNotification; + final int? createdByPersonId; + + factory Document.fromJson(Map json) => Document( + id: json["id"], + sk: json["sk"], + dsk: json["dsk"], + slug: json["slug"], + files: List.from(json["files"].map((x) => FileElement.fromJson(x))), + title: json["title"], + agency: json["agency"], + office: json["office"], + subject: json["subject"], + fileType: FileType.fromJson(json["file_type"]), + isPublic: json["is_public"], + createdAt: json["created_at"], + createdBy: json["created_by"], + validatedAt: json["validated_at"], + validatedBy: json["validated_by"], + documentType: DocumentType.fromJson(json["document_type"]), + documentRoutes: json["document_routes"], + alternateMobile: AlternateMobile.fromJson(json["alternate_mobile"]), + attachedDocument: json["attached_document"], + enableNotification: json["enable_notification"], + createdByPersonId: json["created_by_person_id"], + ); + + Map toJson() => { + "id": id, + "sk": sk, + "dsk": dsk, + "slug": slug, + "files": List.from(files!.map((x) => x.toJson())), + "title": title, + "agency": agency, + "office": office, + "subject": subject, + "file_type": fileType?.toJson(), + "is_public": isPublic, + "created_at": createdAt, + "created_by": createdBy, + "validated_at": validatedAt, + "validated_by": validatedBy, + "document_type": documentType?.toJson(), + "document_routes": documentRoutes, + "alternate_mobile": alternateMobile?.toJson(), + "attached_document": attachedDocument, + "enable_notification": enableNotification, + "created_by_person_id": createdByPersonId, + }; +} + +class AlternateMobile { + AlternateMobile({ + required this.id, + required this.mobileNo, + required this.documentId, + }); + + final dynamic id; + final dynamic mobileNo; + final dynamic documentId; + + factory AlternateMobile.fromJson(Map json) => AlternateMobile( + id: json["id"], + mobileNo: json["mobile_no"], + documentId: json["document_id"], + ); + + Map toJson() => { + "id": id, + "mobile_no": mobileNo, + "document_id": documentId, + }; +} + +class DocumentType { + DocumentType({ + required this.id, + required this.name, + required this.slug, + required this.categoryId, + required this.priorityNumber, + }); + + final int id; + final String name; + final dynamic slug; + final int categoryId; + final dynamic priorityNumber; + + factory DocumentType.fromJson(Map json) => DocumentType( + id: json["id"], + name: json["name"], + slug: json["slug"], + categoryId: json["category_id"], + priorityNumber: json["priority_number"], + ); + + Map toJson() => { + "id": id, + "name": name, + "slug": slug, + "category_id": categoryId, + "priority_number": priorityNumber, + }; +} + +class FileType { + FileType({ + required this.id, + required this.name, + required this.isActive, + required this.extensions, + }); + + final int id; + final String name; + final bool isActive; + final List extensions; + + factory FileType.fromJson(Map json) => FileType( + id: json["id"], + name: json["name"], + isActive: json["is_active"], + extensions: List.from(json["extensions"].map((x) => x)), + ); + + Map toJson() => { + "id": id, + "name": name, + "is_active": isActive, + "extensions": List.from(extensions.map((x) => x)), + }; +} + +class FileElement { + FileElement({ + required this.path, + required this.extnsn, + required this.dateTime, + }); + + final String path; + final String extnsn; + final String dateTime; + + factory FileElement.fromJson(Map json) => FileElement( + path: json["path"], + extnsn: json["extnsn"], + dateTime: json["date_time"], + ); + + Map toJson() => { + "path": path, + "extnsn": extnsn, + "date_time": dateTime, + }; +} diff --git a/lib/model/profile/educational_background.dart b/lib/model/profile/educational_background.dart index 83c2086..4deaee4 100644 --- a/lib/model/profile/educational_background.dart +++ b/lib/model/profile/educational_background.dart @@ -26,7 +26,7 @@ class EducationalBackground { final String? periodTo; final dynamic attachments; final String? periodFrom; - final dynamic unitsEarned; + final int? unitsEarned; final String? yearGraduated; factory EducationalBackground.fromJson(Map json) => EducationalBackground( diff --git a/lib/screens/docsms/request_receipt.dart b/lib/screens/docsms/components/request_receipt.dart similarity index 96% rename from lib/screens/docsms/request_receipt.dart rename to lib/screens/docsms/components/request_receipt.dart index b72897a..d2e2491 100644 --- a/lib/screens/docsms/request_receipt.dart +++ b/lib/screens/docsms/components/request_receipt.dart @@ -9,10 +9,10 @@ import 'package:unit2/utils/text_container.dart'; import 'package:unit2/widgets/costum_divider.dart'; import 'package:unit2/widgets/text_icon.dart'; -import '../../test_data.dart'; -import '../../theme-data.dart/btn-style.dart'; -import '../../theme-data.dart/form-style.dart'; -import '../../utils/global.dart'; +import '../../../test_data.dart'; +import '../../../theme-data.dart/btn-style.dart'; +import '../../../theme-data.dart/form-style.dart'; +import '../../../utils/global.dart'; class RequetAutoReceipt extends StatefulWidget { RequetAutoReceipt({super.key}); @@ -124,7 +124,7 @@ class _RequetAutoReceiptState extends State { height: screenHeight * .06, child: ElevatedButton( style: secondaryBtnStyle( - second, Colors.transparent, Colors.white54), + primary, Colors.transparent, Colors.white54), child: const Text( requestAutoReceipt, style: TextStyle(color: Colors.white), diff --git a/lib/screens/docsms/index.dart b/lib/screens/docsms/index.dart new file mode 100644 index 0000000..d1730f0 --- /dev/null +++ b/lib/screens/docsms/index.dart @@ -0,0 +1,52 @@ +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_progress_hud/flutter_progress_hud.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:unit2/bloc/docsms/docsms_bloc.dart'; +import 'package:unit2/screens/docsms/components/request_receipt.dart'; +import 'package:unit2/widgets/error_state.dart'; + +class AutoReceiveDocument extends StatefulWidget { + const AutoReceiveDocument({super.key}); + + @override + State createState() => _AutoReceiveDocumentState(); +} + +class _AutoReceiveDocumentState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + body: ProgressHUD( + padding: const EdgeInsets.all(24), + backgroundColor: Colors.black87, + indicatorWidget: const SpinKitFadingCircle( + color: Colors.white, + + ), + child: BlocConsumer( + listener: (context, state) { + if (state is DocSmsLoadingState) { + final progress = ProgressHUD.of(context); + progress!.showWithText("Please wait..."); + } + if (state is DocSmsErrorState || state is DocumentLoaded) { + final progress = ProgressHUD.of(context); + progress!.dismiss(); + } + }, + builder: (context, state) { + if (state is DocumentLoaded) { + return RequetAutoReceipt(); + }if(state is DocSmsErrorState){ + return SomethingWentWrong(message: state.message.toString(), onpressed: (){}); + } + return Container(); + }, + ), + ), + ); + } +} diff --git a/lib/screens/profile/components/basic_information/address/add_modal.dart b/lib/screens/profile/components/basic_information/address/add_modal.dart new file mode 100644 index 0000000..c790d4d --- /dev/null +++ b/lib/screens/profile/components/basic_information/address/add_modal.dart @@ -0,0 +1,474 @@ +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: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/utils/category.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 '../../../../../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'; + +class AddAddressScreen extends StatefulWidget { + final int profileId; + final String token; + const AddAddressScreen( + {super.key, required this.profileId, required this.token}); + + @override + State createState() => _AddAddressScreenState(); +} + +class _AddAddressScreenState extends State { + ////boolean + bool hasLotandBlock = false; + bool overseas = false; + bool provinceCall = false; + bool cityCall = false; + bool barangayCall = false; + ////selected + Region? selectedRegion; + Province? selectedProvince; + CityMunicipality? selectedMunicipality; + Barangay? selectedBarangay; + Country? selectedCountry; + ////Lists + final List areaClass = [ + const Area(value: "Rural Area", group: 0), + const Area(value: "Sitio", group: 1), + const Area(value: "Village", group: 1), + const Area(value: "Urban Area", group: 0), + const Area(value: "Town", group: 1), + const Area(value: "City", group: 1), + const Area(value: "Metropolis", group: 1), + const Area(value: "Megacity", group: 1), + ]; + final List category = ["Permanent", "Residential", "Birthplace"]; + List? provinces; + List? citymuns; + List? barangays; + final formKey = GlobalKey(); + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is AddAddressState) { + return SingleChildScrollView( + child: SizedBox( + height: screenHeight * .90, + child: FormBuilder( + key: formKey, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 25, horizontal: 18), + child: Column( + children: [ + //// category + FormBuilderDropdown( + validator: FormBuilderValidators.required( + errorText: "This field is required"), + decoration: + normalTextFieldStyle("Category*", "Category"), + name: "category", + onChanged: (String? category) {}, + items: category.map>( + (String category) { + return DropdownMenuItem( + value: category, child: Text(category)); + }).toList()), + const SizedBox( + height: 12, + ), + ////Area Class + FormBuilderDropdown( + validator: FormBuilderValidators.required( + errorText: "This field is required"), + decoration: normalTextFieldStyle( + "Area class *", "Area class"), + name: "area_class", + onChanged: (Area? area) {}, + items: areaClass + .map>((Area area) { + return area.group == 0 + ? DropdownMenuItem( + enabled: false, + value: area, + child: Text(area.value.toUpperCase(), + style: const TextStyle( + color: Colors.black38))) + : DropdownMenuItem( + value: area, + enabled: true, + child: Text( + " ${area.value.toUpperCase()}")); + }).toList()), + const SizedBox( + height: 12, + ), + ////stateful builder + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + ////with block & Lot Switch + FormBuilderSwitch( + initialValue: hasLotandBlock, + activeColor: second, + onChanged: (value) { + setState(() { + hasLotandBlock = value!; + }); + }, + decoration: normalTextFieldStyle( + "With Lot and Block?", 'Graduated?'), + name: 'graudated', + title: Text(hasLotandBlock ? "YES" : "NO"), + ), + SizedBox( + height: hasLotandBlock ? 12 : 0, + ), + SizedBox( + width: screenWidth, + child: hasLotandBlock + ? Row( + children: [ + ////block # + Flexible( + flex: 1, + child: FormBuilderTextField( + name: "block_number", + decoration: + normalTextFieldStyle( + "Block #*", "Block #"), + )), + const SizedBox( + width: 8, + ), + //// lot # + Flexible( + flex: 1, + child: FormBuilderTextField( + name: "lot_number", + decoration: + normalTextFieldStyle( + "Lot #*", "Lot #"), + )), + ], + ) + : Container(), + ), + ], + ); + }), + const SizedBox( + height: 12, + ), + //// Address Line + FormBuilderTextField( + name: "address_line", + decoration: normalTextFieldStyle( + "Address Line *", "Address Line"), + ), + 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) { + setState(() { + barangayCall = true; + }); + selectedMunicipality = city; + getBarangays(); + } + }, + decoration: + normalTextFieldStyle( + "Municipality*", + "Municipality"), + value: selectedMunicipality, + items: citymuns == null + ? [] + : citymuns!.map< + DropdownMenuItem< + CityMunicipality>>( + (CityMunicipality c) { + return DropdownMenuItem( + value: c, + child: Text(c + .description!)); + }).toList(), + ), + ), + ), + //// BARANGAY + SizedBox( + height: 60, + child: ModalProgressHUD( + color: Colors.white, + inAsyncCall: barangayCall, + child: DropdownButtonFormField< + Barangay>( + isExpanded: true, + onChanged: (Barangay? baragay) { + selectedBarangay = baragay; + }, + decoration: + normalTextFieldStyle( + "Barangay*", + "Barangay"), + value: selectedBarangay, + items: barangays == null + ? [] + : barangays!.map< + DropdownMenuItem< + Barangay>>( + (Barangay barangay) { + return DropdownMenuItem( + value: barangay, + child: Text(barangay + .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) {}, + ), + ), + ), + + ], + ); + }), + ////sumit button + const Expanded(child: SizedBox()), + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: mainBtnStyle( + primary, Colors.transparent, second), + onPressed: () {}, + child: const Text(submit)), + ), + const SizedBox( + height: 20, + ), + ], + ), + + )), + ), + ); + } + return 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(CallErrorState()); + } + } + + Future getCities() async { + try { + List newCities = await LocationUtils.instance + .getCities(code: selectedProvince!.code.toString()); + citymuns = newCities; + setState(() { + selectedMunicipality = newCities[0]; + cityCall = false; + barangayCall = true; + getBarangays(); + }); + } catch (e) { + context.read().add(CallErrorState()); + } + } + + Future getBarangays() async { + try { + List newBarangays = await LocationUtils.instance + .getBarangay(code: selectedMunicipality!.code.toString()); + barangays = newBarangays; + setState(() { + selectedBarangay = newBarangays[0]; + barangayCall = false; + }); + } catch (e) { + context.read().add(CallErrorState()); + } + } +} + +class Area { + final int group; + final String value; + const Area({required this.group, required this.value}); +} diff --git a/lib/screens/profile/components/basic_information/address/edit_modal.dart b/lib/screens/profile/components/basic_information/address/edit_modal.dart new file mode 100644 index 0000000..5760b17 --- /dev/null +++ b/lib/screens/profile/components/basic_information/address/edit_modal.dart @@ -0,0 +1,474 @@ +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: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/utils/category.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 '../../../../../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'; + +class EditAddressScreen extends StatefulWidget { + final int profileId; + final String token; + const EditAddressScreen( + {super.key, required this.profileId, required this.token}); + + @override + State createState() => _EditAddressScreenState(); +} + +class _EditAddressScreenState extends State { + ////boolean + bool hasLotandBlock = false; + bool overseas = false; + bool provinceCall = false; + bool cityCall = false; + bool barangayCall = false; + ////selected + Region? selectedRegion; + Province? selectedProvince; + CityMunicipality? selectedMunicipality; + Barangay? selectedBarangay; + Country? selectedCountry; + ////Lists + final List areaClass = [ + const Area(value: "Rural Area", group: 0), + const Area(value: "Sitio", group: 1), + const Area(value: "Village", group: 1), + const Area(value: "Urban Area", group: 0), + const Area(value: "Town", group: 1), + const Area(value: "City", group: 1), + const Area(value: "Metropolis", group: 1), + const Area(value: "Megacity", group: 1), + ]; + final List category = ["Permanent", "Residential", "Birthplace"]; + List? provinces; + List? citymuns; + List? barangays; + final formKey = GlobalKey(); + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is EditAddressState) { + return SingleChildScrollView( + child: SizedBox( + height: screenHeight * .90, + child: FormBuilder( + key: formKey, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 25, horizontal: 18), + child: Column( + children: [ + //// category + FormBuilderDropdown( + validator: FormBuilderValidators.required( + errorText: "This field is required"), + decoration: + normalTextFieldStyle("Category*", "Category"), + name: "category", + onChanged: (String? category) {}, + items: category.map>( + (String category) { + return DropdownMenuItem( + value: category, child: Text(category)); + }).toList()), + const SizedBox( + height: 12, + ), + ////Area Class + FormBuilderDropdown( + validator: FormBuilderValidators.required( + errorText: "This field is required"), + decoration: normalTextFieldStyle( + "Area class *", "Area class"), + name: "area_class", + onChanged: (Area? area) {}, + items: areaClass + .map>((Area area) { + return area.group == 0 + ? DropdownMenuItem( + enabled: false, + value: area, + child: Text(area.value.toUpperCase(), + style: const TextStyle( + color: Colors.black38))) + : DropdownMenuItem( + value: area, + enabled: true, + child: Text( + " ${area.value.toUpperCase()}")); + }).toList()), + const SizedBox( + height: 12, + ), + ////stateful builder + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + ////with block & Lot Switch + FormBuilderSwitch( + initialValue: hasLotandBlock, + activeColor: second, + onChanged: (value) { + setState(() { + hasLotandBlock = value!; + }); + }, + decoration: normalTextFieldStyle( + "With Lot and Block?", 'Graduated?'), + name: 'graudated', + title: Text(hasLotandBlock ? "YES" : "NO"), + ), + SizedBox( + height: hasLotandBlock ? 12 : 0, + ), + SizedBox( + width: screenWidth, + child: hasLotandBlock + ? Row( + children: [ + ////block # + Flexible( + flex: 1, + child: FormBuilderTextField( + name: "block_number", + decoration: + normalTextFieldStyle( + "Block #*", "Block #"), + )), + const SizedBox( + width: 8, + ), + //// lot # + Flexible( + flex: 1, + child: FormBuilderTextField( + name: "lot_number", + decoration: + normalTextFieldStyle( + "Lot #*", "Lot #"), + )), + ], + ) + : Container(), + ), + ], + ); + }), + const SizedBox( + height: 12, + ), + //// Address Line + FormBuilderTextField( + name: "address_line", + decoration: normalTextFieldStyle( + "Address Line *", "Address Line"), + ), + 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) { + setState(() { + barangayCall = true; + }); + selectedMunicipality = city; + getBarangays(); + } + }, + decoration: + normalTextFieldStyle( + "Municipality*", + "Municipality"), + value: selectedMunicipality, + items: citymuns == null + ? [] + : citymuns!.map< + DropdownMenuItem< + CityMunicipality>>( + (CityMunicipality c) { + return DropdownMenuItem( + value: c, + child: Text(c + .description!)); + }).toList(), + ), + ), + ), + //// BARANGAY + SizedBox( + height: 60, + child: ModalProgressHUD( + color: Colors.white, + inAsyncCall: barangayCall, + child: DropdownButtonFormField< + Barangay>( + isExpanded: true, + onChanged: (Barangay? baragay) { + selectedBarangay = baragay; + }, + decoration: + normalTextFieldStyle( + "Barangay*", + "Barangay"), + value: selectedBarangay, + items: barangays == null + ? [] + : barangays!.map< + DropdownMenuItem< + Barangay>>( + (Barangay barangay) { + return DropdownMenuItem( + value: barangay, + child: Text(barangay + .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) {}, + ), + ), + ), + + ], + ); + }), + ////sumit button + const Expanded(child: SizedBox()), + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: mainBtnStyle( + primary, Colors.transparent, second), + onPressed: () {}, + child: const Text(submit)), + ), + const SizedBox( + height: 20, + ), + ], + ), + + )), + ), + ); + } + return 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(CallErrorState()); + } + } + + Future getCities() async { + try { + List newCities = await LocationUtils.instance + .getCities(code: selectedProvince!.code.toString()); + citymuns = newCities; + setState(() { + selectedMunicipality = newCities[0]; + cityCall = false; + barangayCall = true; + getBarangays(); + }); + } catch (e) { + context.read().add(CallErrorState()); + } + } + + Future getBarangays() async { + try { + List newBarangays = await LocationUtils.instance + .getBarangay(code: selectedMunicipality!.code.toString()); + barangays = newBarangays; + setState(() { + selectedBarangay = newBarangays[0]; + barangayCall = false; + }); + } catch (e) { + context.read().add(CallErrorState()); + } + } +} + +class Area { + final int group; + final String value; + const Area({required this.group, required this.value}); +} diff --git a/lib/screens/profile/components/basic_information/address_screen.dart b/lib/screens/profile/components/basic_information/address_screen.dart index b394883..9801069 100644 --- a/lib/screens/profile/components/basic_information/address_screen.dart +++ b/lib/screens/profile/components/basic_information/address_screen.dart @@ -1,10 +1,15 @@ +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:unit2/bloc/profile/primary_information/address/address_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/model/profile/basic_information/adress.dart'; +import 'package:unit2/screens/profile/components/basic_information/address/add_modal.dart'; +import 'package:unit2/screens/profile/components/basic_information/address/edit_modal.dart'; import 'package:unit2/theme-data.dart/box_shadow.dart'; import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/utils/global.dart'; @@ -13,23 +18,37 @@ import 'package:unit2/widgets/Leadings/add_leading.dart'; import 'package:unit2/widgets/empty_data.dart'; import 'package:unit2/widgets/error_state.dart'; -class AddressScreen extends StatelessWidget { +import '../../../../utils/alerts.dart'; +class AddressScreen extends StatelessWidget { const AddressScreen({super.key}); @override Widget build(BuildContext context) { + int? profileId; + String? token; return Scaffold( appBar: AppBar( title: const Text(adressScreenTitle), centerTitle: true, backgroundColor: primary, - actions: [AddLeading(onPressed: () {})], + actions: [ + AddLeading(onPressed: () { + context.read().add(ShowAddAddressForm()); + }) + ], ), body: ProgressHUD( + padding: const EdgeInsets.all(24), + indicatorWidget: const SpinKitFadingCircle( + color: Colors.white, + ), + backgroundColor: Colors.black87, child: BlocBuilder( builder: (context, state) { if (state is UserLoggedIn) { + token = state.userData!.user!.login!.token; + profileId = state.userData!.user!.login!.user!.profileId; return BlocBuilder( builder: (context, state) { if (state is ProfileLoaded) { @@ -40,7 +59,9 @@ class AddressScreen extends StatelessWidget { progress!.showWithText("Please wait..."); } if (state is AddressLoadedState || - state is AddressErrorState) { + state is AddressErrorState || + state is AddAddressState || + state is EditAddressState) { final progress = ProgressHUD.of(context); progress!.dismiss(); } @@ -48,7 +69,7 @@ class AddressScreen extends StatelessWidget { builder: (context, state) { if (state is AddressLoadedState) { if (state.addresses.isNotEmpty) { - return ListView.builder( + return ListView.builder( padding: const EdgeInsets.symmetric( vertical: 8, horizontal: 10), itemCount: state.addresses.length, @@ -57,25 +78,25 @@ class AddressScreen extends StatelessWidget { String? subdivision = state.addresses[index].details ?? ''; String category = state.addresses[index] - .address! - .category! - .name!; + .address!.category!.name!; String? barangay = state.addresses[index] - .address! - .barangay != + .address!.barangay != null ? '${state.addresses[index].address!.barangay!.description!.toUpperCase()},' : ''; - String cityMunicipality = state.addresses[index] + String cityMunicipality = state + .addresses[index] .address! .cityMunicipality! .description!; - String province = state.addresses[index] + String province = state + .addresses[index] .address! .cityMunicipality! .province! .description!; - String region = state.addresses[index] + String region = state + .addresses[index] .address! .cityMunicipality! .province! @@ -128,12 +149,59 @@ class AddressScreen extends StatelessWidget { ), ], )), - IconButton( - onPressed: () {}, - icon: const Icon( - Icons.more_vert, - color: Colors.grey, - )) + 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..."); + }, "Delete?", + "Confirm Delete?"); + } + if (value == 1) { + ////edit eligibilty-= = = = = = = = =>> + final progress = + ProgressHUD.of( + context); + progress!.showWithText( + "Loading..."); + + context + .read() + .add(ShowEditAddressForm( + address: state + .addresses[ + index])); + } + }, + 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", + ) ]), ), ], @@ -150,6 +218,16 @@ class AddressScreen extends StatelessWidget { "You don't have address added. Please click + to add."); } } + if (state is AddressErrorState) { + return SomethingWentWrong( + message: state.message, onpressed: () {}); + } + if (state is AddAddressState) { + return AddAddressScreen( + profileId: profileId!, token: token!); + }if(state is EditAddressState){ + return EditAddressScreen(profileId: profileId!, token: token!); + } return Container(); }, ); @@ -163,4 +241,23 @@ class AddressScreen 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/education/add_modal.dart b/lib/screens/profile/components/education/add_modal.dart new file mode 100644 index 0000000..a4701e1 --- /dev/null +++ b/lib/screens/profile/components/education/add_modal.dart @@ -0,0 +1,510 @@ +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:form_builder_validators/form_builder_validators.dart'; +import 'package:searchfield/searchfield.dart'; +import 'package:unit2/bloc/profile/education/education_bloc.dart'; +import 'package:unit2/model/profile/educational_background.dart'; +import 'package:unit2/theme-data.dart/box_shadow.dart'; +import 'package:unit2/theme-data.dart/form-style.dart'; +import 'package:unit2/utils/global.dart'; +import 'package:multi_dropdown/multiselect_dropdown.dart'; + +import '../../../../theme-data.dart/btn-style.dart'; +import '../../../../theme-data.dart/colors.dart'; +import '../../../../utils/text_container.dart'; +import '../../shared/add_for_empty_search.dart'; + +class AddEducationScreen extends StatefulWidget { + final int profileId; + final String token; + const AddEducationScreen( + {super.key, required this.profileId, required this.token}); + + @override + State createState() => _AddEducationScreenState(); +} + +class _AddEducationScreenState extends State { + final List educationLevel = [ + const EducationLevel(type: "label", value: "Basic Education", group: 1), + const EducationLevel(type: "level", value: "Elementary", group: 1), + const EducationLevel(type: "level", value: "Secondary (non-K12)", group: 1), + const EducationLevel(type: "level", value: "Junior High", group: 1), + const EducationLevel(type: "level", value: "Senior High", group: 1), + const EducationLevel(type: "label", value: "Higher Education", group: 2), + const EducationLevel(type: "level", value: "Collegiate", group: 2), + const EducationLevel(type: "level", value: "Vocational", group: 2), + const EducationLevel(type: "label", value: "Post Graduate", group: 2), + const EducationLevel(type: "level", value: "Masteral", group: 2), + const EducationLevel(type: "level", value: "Doctorate", group: 2), + ]; + List valueItemHonorList = []; +////selected + EducationLevel? selectedLevel; + School? selectedSchool; + Course? selectedProgram; + List selectedHonors = []; + List? selectedValueItem; + final formKey = GlobalKey(); + ////congrollers + final addProgramController = TextEditingController(); + final addSchoolController = TextEditingController(); + final fromController = TextEditingController(); + final untilController = TextEditingController(); + final yearGraduated = TextEditingController(); + ////focus node + final programFocusNode = FocusNode(); + final schoolFocusNode = FocusNode(); + final honorFocusNode = FocusNode(); + ////booleans + bool graduated = true; + int? unitsEarned; + //// + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is AddEducationState) { + valueItemHonorList = state.honors.map((Honor honor) { + return ValueItem(label: honor.name!, value: honor.name); + }).toList(); + return Container( + padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 18), + child: FormBuilder( + key: formKey, + child: SingleChildScrollView( + child: SizedBox( + height: blockSizeVertical * 85, + child: Column(children: [ + const SizedBox( + height: 12, + ), + //// LEVEL + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + FormBuilderDropdown( + validator: FormBuilderValidators.required( + errorText: "This field is required"), + decoration: + normalTextFieldStyle("level*", "level"), + name: "education_level", + onChanged: (EducationLevel? level) { + setState(() { + selectedLevel = level; + }); + }, + items: educationLevel + .map>( + (EducationLevel level) { + return level.type == "label" + ? DropdownMenuItem( + enabled: false, + value: level, + child: Text(level.value.toUpperCase(), + style: const TextStyle( + color: Colors.black38))) + : DropdownMenuItem( + value: level, + enabled: true, + child: Text( + " ${level.value.toUpperCase()}")); + }).toList()), + const SizedBox( + height: 12, + ), + ////school + StatefulBuilder(builder: (context, setState) { + return SearchField( + itemHeight: 50, + suggestionsDecoration: box1(), + suggestions: state.schools + .map((School school) => + SearchFieldListItem(school.name!, + item: school, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10), + child: ListTile( + title: Text(school.name!)), + ))) + .toList(), + validator: (agency) { + if (agency!.isEmpty) { + return "This field is required"; + } + return null; + }, + focusNode: schoolFocusNode, + searchInputDecoration: + normalTextFieldStyle("School *", "").copyWith( + suffixIcon: + const Icon(Icons.arrow_drop_down)), + onSuggestionTap: (school) { + setState(() { + selectedSchool = school.item; + schoolFocusNode.unfocus(); + }); + }, + emptyWidget: EmptyWidget( + title: "Add School", + controller: addSchoolController, + onpressed: () { + setState(() { + School newSchool = School( + id: null, + name: addSchoolController.text.toUpperCase()); + state.schools.insert(0, newSchool); + addSchoolController.text = ""; + + Navigator.pop(context); + }); + }), + ); + }), + const SizedBox( + height: 12, + ), + ////Programs + Container( + child: selectedLevel != null && + selectedLevel!.group != 1 + ? SearchField( + itemHeight: 50, + suggestionsDecoration: box1(), + suggestions: state.programs + .map((Course program) => + SearchFieldListItem( + program.program!, + item: program, + child: Padding( + padding: const EdgeInsets + .symmetric( + horizontal: 10), + child: ListTile( + title: Text( + program.program!)), + ))) + .toList(), + validator: (agency) { + if (agency!.isEmpty) { + return "This field is required"; + } + return null; + }, + focusNode: programFocusNode, + searchInputDecoration: + normalTextFieldStyle( + "Course/Programs *", "") + .copyWith( + suffixIcon: const Icon( + Icons.arrow_drop_down)), + onSuggestionTap: (position) { + setState(() { + selectedProgram = position.item; + programFocusNode.unfocus(); + }); + }, + emptyWidget: EmptyWidget( + title: "Add Program", + controller: addProgramController, + onpressed: () { + setState(() { + Course newProgram = Course( + id: null, + program: addProgramController + .text.toUpperCase()); + state.programs.insert(0,newProgram); + addProgramController.text = ""; + + Navigator.pop(context); + }); + }), + ) + : Container()) + ], + ); + }), + const SizedBox( + height: 12, + ), + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + //// GRADUATED SWITCH + FormBuilderSwitch( + initialValue: graduated, + activeColor: second, + onChanged: (value) { + setState(() { + graduated = value!; + if (graduated) { + unitsEarned = null; + } else { + yearGraduated.text = ""; + } + }); + }, + decoration: normalTextFieldStyle( + "Graduated?", 'Graduated?'), + name: 'graudated', + title: Text(graduated ? "YES" : "NO"), + ), + const SizedBox( + height: 12, + ), + ////FROM + SizedBox( + width: screenWidth, + child: Row( + children: [ + Flexible( + flex: 1, + child: FormBuilderTextField( + validator: FormBuilderValidators.required( + errorText: "This fied is required"), + decoration: + normalTextFieldStyle("from *", "from"), + name: "", + controller: fromController, + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: SizedBox( + width: 300, + height: 300, + child: YearPicker( + firstDate: DateTime( + DateTime.now().year - 100, + 1), + lastDate: DateTime( + DateTime.now().year + 100, + 1), + initialDate: DateTime.now(), + selectedDate: DateTime.now(), + onChanged: (DateTime dateTime) { + fromController.text = + dateTime.year.toString(); + Navigator.pop(context); + }, + ), + ), + ); + }, + ); + }, + ), + ), + const SizedBox( + width: 8, + ), + ////UNTIL + Flexible( + flex: 1, + child: FormBuilderTextField( + validator: FormBuilderValidators.required( + errorText: "This fied is required"), + decoration: normalTextFieldStyle( + "until *", "until"), + name: "", + controller: untilController, + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: SizedBox( + width: 300, + height: 300, + child: YearPicker( + firstDate: DateTime( + DateTime.now().year - 100, + 1), + lastDate: DateTime( + DateTime.now().year + 100, + 1), + initialDate: DateTime.now(), + selectedDate: DateTime.now(), + onChanged: (DateTime dateTime) { + untilController.text = + dateTime.year.toString(); + Navigator.pop(context); + }, + ), + ), + ); + }, + ); + }, + ), + ), + const SizedBox( + width: 8, + ), + ], + ), + ), + const SizedBox( + height: 12, + ), + SizedBox( + child: graduated + ////GRADUATED YEAR + ? FormBuilderTextField( + validator: FormBuilderValidators.required( + errorText: "This fied is required"), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: SizedBox( + width: 300, + height: 300, + child: YearPicker( + firstDate: DateTime( + DateTime.now().year - 100, + 1), + lastDate: DateTime( + DateTime.now().year + 100, + 1), + initialDate: DateTime.now(), + selectedDate: DateTime.now(), + onChanged: (DateTime dateTime) { + yearGraduated.text = + dateTime.year.toString(); + Navigator.pop(context); + }, + ), + ), + ); + }, + ); + }, + name: "year_graduated", + controller: yearGraduated, + decoration: normalTextFieldStyle( + "Year Graduated *", "Year Graduated *"), + ) + //// HIGHEST UNITS EARNED + : FormBuilderTextField( + validator: FormBuilderValidators.required( + errorText: "This fied is required"), + name: "units_earned", + decoration: normalTextFieldStyle( + "Highest Level/Units Earned *", + "Highest Level/Units Earned *")), + ), + ], + ); + }), + + const SizedBox( + height: 12, + ), + //// HONORS + MultiSelectDropDown( + onOptionSelected: (List selectedOptions) { + selectedValueItem = selectedOptions; + }, + borderColor: Colors.grey, + borderWidth: 1, + borderRadius: 5, + hint: "Honors", + padding: const EdgeInsets.all(8), + options: valueItemHonorList, + selectionType: SelectionType.multi, + chipConfig: const ChipConfig(wrapType: WrapType.wrap), + dropdownHeight: 300, + optionTextStyle: const TextStyle(fontSize: 16), + selectedOptionIcon: const Icon(Icons.check_circle), + ), + ////sumit button + const Expanded(child: SizedBox()), + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: + mainBtnStyle(primary, Colors.transparent, second), + onPressed: () { + if (formKey.currentState!.saveAndValidate()) { + //// program + if (selectedLevel!.value == "Elementary" || + selectedLevel!.value == + "Secondary (non-K12)" || + selectedLevel!.value == "Junior High" || + selectedLevel!.value == "Senior High") { + selectedProgram = null; + } + if (!graduated) { + unitsEarned = int.parse(formKey + .currentState!.value['units_earned']); + } + ////education + Education newEducation = Education( + id: null, + level: selectedLevel!.value, + course: selectedProgram, + school: selectedSchool); + ////honors + if (selectedValueItem != null) { + for (var honor in selectedValueItem!) { + Honor newHonor = state.honors.firstWhere((element) => element.name == honor.value); + selectedHonors.add(newHonor); + } + } + + EducationalBackground educationalBackground = + EducationalBackground( + id: null, + honors: null, + education: newEducation, + periodTo: untilController.text, + periodFrom: fromController.text, + yearGraduated: + graduated ? yearGraduated.text : null, + unitsEarned: !graduated ? unitsEarned : null, + attachments: null, + ); + final progress = ProgressHUD.of(context); + progress!.showWithText("Loading..."); + context.read().add(AddEducation( + educationalBackground: educationalBackground, + profileId: widget.profileId, + token: widget.token, + honors: selectedHonors)); + } + }, + child: const Text(submit)), + ), + const SizedBox( + height: 20, + ), + ]), + ), + ), + ), + ); + } + return Container(); + }, + ); + } +} + +class EducationLevel { + final String value; + final String type; + final int group; + const EducationLevel( + {required this.type, required this.value, required this.group}); +} diff --git a/lib/screens/profile/components/education/edit_modal.dart b/lib/screens/profile/components/education/edit_modal.dart new file mode 100644 index 0000000..1038bbf --- /dev/null +++ b/lib/screens/profile/components/education/edit_modal.dart @@ -0,0 +1,564 @@ +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:form_builder_validators/form_builder_validators.dart'; +import 'package:searchfield/searchfield.dart'; +import 'package:unit2/bloc/profile/education/education_bloc.dart'; +import 'package:unit2/model/profile/educational_background.dart'; +import 'package:unit2/theme-data.dart/box_shadow.dart'; +import 'package:unit2/theme-data.dart/form-style.dart'; +import 'package:unit2/utils/global.dart'; + +import '../../../../theme-data.dart/btn-style.dart'; +import '../../../../theme-data.dart/colors.dart'; +import '../../../../utils/text_container.dart'; +import '../../shared/add_for_empty_search.dart'; +import 'package:multi_dropdown/multiselect_dropdown.dart'; + +class EditEducationScreen extends StatefulWidget { + final int profileId; + final String token; + const EditEducationScreen( + {super.key, required this.profileId, required this.token}); + + @override + State createState() => _EditEducationScreenState(); +} + +class _EditEducationScreenState extends State { + final List educationLevel = [ + const EducationLevel(type: "label", value: "Basic Education", group: 1), + const EducationLevel(type: "level", value: "Elementary", group: 1), + const EducationLevel(type: "level", value: "Secondary (non-K12)", group: 1), + const EducationLevel(type: "level", value: "Junior High", group: 1), + const EducationLevel(type: "level", value: "Senior High", group: 1), + const EducationLevel(type: "label", value: "Higher Education", group: 2), + const EducationLevel(type: "level", value: "Collegiate", group: 2), + const EducationLevel(type: "level", value: "Vocational", group: 2), + const EducationLevel(type: "label", value: "Post Graduate", group: 2), + const EducationLevel(type: "level", value: "Masteral", group: 2), + const EducationLevel(type: "level", value: "Doctorate", group: 2), + ]; + List valueItemHonorList = []; + List selectedValueItem = []; +////selected + EducationLevel? selectedLevel; + School? selectedSchool; + Course? selectedProgram; + List selectedHonors = []; + final formKey = GlobalKey(); + ////congrollers + final addProgramController = TextEditingController(); + final addSchoolController = TextEditingController(); + final fromController = TextEditingController(); + final untilController = TextEditingController(); + final yearGraduated = TextEditingController(); + final currentSchoolController = TextEditingController(); + final currentProgramController = TextEditingController(); + final unitsController = TextEditingController(); ////focus node + final programFocusNode = FocusNode(); + final schoolFocusNode = FocusNode(); + final honorFocusNode = FocusNode(); + ////booleans + bool graduated = true; + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is EditEducationState) { + ////selected level + selectedLevel = educationLevel.firstWhere((element) => + element.value.toUpperCase() == + state.educationalBackground.education!.level); + + currentSchoolController.text = + state.educationalBackground.education!.school!.name!; + if (selectedLevel != null && selectedLevel!.group != 1) { + currentProgramController.text = + state.educationalBackground.education!.course!.program!; + } +////year grduated and units earned + if (state.educationalBackground.yearGraduated != null) { + graduated = true; + yearGraduated.text = state.educationalBackground.yearGraduated!; + } else { + unitsController.text = + state.educationalBackground.unitsEarned.toString(); + graduated = false; + } + fromController.text = state.educationalBackground.periodFrom!; + untilController.text = state.educationalBackground.periodTo!; + ////honors + + ////get all honors + valueItemHonorList = state.honors.map((Honor honor) { + return ValueItem(label: honor.name!, value: honor.name); + }).toList(); + return Container( + padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 18), + child: FormBuilder( + key: formKey, + child: SingleChildScrollView( + child: SizedBox( + height: blockSizeVertical * 85, + child: Column(children: [ + const SizedBox( + height: 12, + ), + //// LEVEL + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + FormBuilderDropdown( + initialValue: selectedLevel, + validator: FormBuilderValidators.required( + errorText: "This field is required"), + decoration: + normalTextFieldStyle("level*", "level"), + name: "education_level", + onChanged: (EducationLevel? level) { + setState(() { + selectedLevel = level; + }); + }, + items: educationLevel + .map>( + (EducationLevel level) { + return level.type == "label" + ? DropdownMenuItem( + enabled: false, + value: level, + child: Text(level.value.toUpperCase(), + style: const TextStyle( + color: Colors.black38))) + : DropdownMenuItem( + value: level, + enabled: true, + child: Text( + " ${level.value.toUpperCase()}")); + }).toList()), + const SizedBox( + height: 12, + ), + ////school + StatefulBuilder(builder: (context, setState) { + return SearchField( + controller: currentSchoolController, + itemHeight: 50, + suggestionsDecoration: box1(), + suggestions: state.schools + .map((School school) => + SearchFieldListItem(school.name!, + item: school, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10), + child: ListTile( + title: Text(school.name!)), + ))) + .toList(), + validator: (agency) { + if (agency!.isEmpty) { + return "This field is required"; + } + return null; + }, + focusNode: schoolFocusNode, + searchInputDecoration: + normalTextFieldStyle("School *", "").copyWith( + suffixIcon: + const Icon(Icons.arrow_drop_down)), + onSuggestionTap: (school) { + setState(() { + selectedSchool = school.item; + schoolFocusNode.unfocus(); + }); + }, + emptyWidget: EmptyWidget( + title: "Add School", + controller: addSchoolController, + onpressed: () { + setState(() { + School newSchool = School( + id: null, + name: addSchoolController.text + .toUpperCase()); + state.schools.insert(0, newSchool); + addSchoolController.text = ""; + + Navigator.pop(context); + }); + }), + ); + }), + const SizedBox( + height: 12, + ), + ////Programs + Container( + child: selectedLevel != null && + selectedLevel!.group != 1 + ? SearchField( + suggestionAction: + SuggestionAction.unfocus, + controller: currentProgramController, + itemHeight: 50, + suggestionsDecoration: box1(), + suggestions: state.programs + .map((Course program) => + SearchFieldListItem( + program.program!, + item: program, + child: Padding( + padding: const EdgeInsets + .symmetric( + horizontal: 10), + child: ListTile( + title: Text( + program.program!)), + ))) + .toList(), + validator: (agency) { + if (agency!.isEmpty) { + return "This field is required"; + } + return null; + }, + focusNode: programFocusNode, + searchInputDecoration: + normalTextFieldStyle( + "Course/Programs *", "") + .copyWith( + suffixIcon: const Icon( + Icons.arrow_drop_down)), + onSuggestionTap: (position) { + setState(() { + selectedProgram = position.item; + programFocusNode.unfocus(); + }); + }, + emptyWidget: EmptyWidget( + title: "Add Program", + controller: addProgramController, + onpressed: () { + setState(() { + Course newProgram = Course( + id: null, + program: addProgramController + .text + .toUpperCase()); + state.programs + .insert(0, newProgram); + addProgramController.text = ""; + + Navigator.pop(context); + }); + }), + ) + : Container()) + ], + ); + }), + const SizedBox( + height: 12, + ), + StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + //// GRADUATED SWITCH + FormBuilderSwitch( + initialValue: graduated, + activeColor: second, + onChanged: (value) { + setState(() { + graduated = value!; + if (graduated) { + unitsController.text = ""; + } else { + yearGraduated.text = ""; + } + }); + }, + decoration: normalTextFieldStyle( + "Graduated?", 'Graduated?'), + name: 'graudated', + title: Text(graduated ? "YES" : "NO"), + ), + const SizedBox( + height: 12, + ), + ////FROM + SizedBox( + width: screenWidth, + child: Row( + children: [ + Flexible( + flex: 1, + child: FormBuilderTextField( + validator: FormBuilderValidators.required( + errorText: "This fied is required"), + decoration: + normalTextFieldStyle("from *", "from"), + name: "", + controller: fromController, + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: SizedBox( + width: 300, + height: 300, + child: YearPicker( + firstDate: DateTime( + DateTime.now().year - 100, + 1), + lastDate: DateTime( + DateTime.now().year + 100, + 1), + initialDate: DateTime.now(), + selectedDate: DateTime.now(), + onChanged: (DateTime dateTime) { + fromController.text = + dateTime.year.toString(); + Navigator.pop(context); + }, + ), + ), + ); + }, + ); + }, + ), + ), + const SizedBox( + width: 8, + ), + ////UNTIL + Flexible( + flex: 1, + child: FormBuilderTextField( + validator: FormBuilderValidators.required( + errorText: "This fied is required"), + decoration: normalTextFieldStyle( + "until *", "until"), + name: "", + controller: untilController, + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: SizedBox( + width: 300, + height: 300, + child: YearPicker( + firstDate: DateTime( + DateTime.now().year - 100, + 1), + lastDate: DateTime( + DateTime.now().year + 100, + 1), + initialDate: DateTime.now(), + selectedDate: DateTime.now(), + onChanged: (DateTime dateTime) { + untilController.text = + dateTime.year.toString(); + Navigator.pop(context); + }, + ), + ), + ); + }, + ); + }, + ), + ), + const SizedBox( + width: 8, + ), + Flexible( + flex: 1, + child: graduated + ////GRADUATED YEAR + ? FormBuilderTextField( + validator: + FormBuilderValidators.required( + errorText: + "This fied is required"), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: SizedBox( + width: 300, + height: 300, + child: YearPicker( + firstDate: DateTime( + DateTime.now().year - + 100, + 1), + lastDate: DateTime( + DateTime.now().year + + 100, + 1), + initialDate: + DateTime.now(), + selectedDate: + DateTime.now(), + onChanged: + (DateTime dateTime) { + yearGraduated.text = + dateTime.year + .toString(); + Navigator.pop(context); + }, + ), + ), + ); + }, + ); + }, + name: "year_graduated", + controller: yearGraduated, + decoration: normalTextFieldStyle( + "Year Graduated *", + "Year Graduated *"), + ) + //// HIGHEST UNITS EARNED + : FormBuilderTextField( + validator: + FormBuilderValidators.required( + errorText: + "This fied is required"), + controller: unitsController, + name: "units_earned", + decoration: normalTextFieldStyle( + "Highest Level/Units Earned *", + "Highest Level/Units Earned *")), + ) + ], + ), + ) + ], + ); + }), + const SizedBox( + height: 12, + ), + //// HONORS + + StatefulBuilder(builder: (context, setState) { + return MultiSelectDropDown( + onOptionSelected: (List selectedOptions) { + selectedValueItem = selectedOptions; + }, + borderColor: Colors.grey, + borderWidth: 1, + borderRadius: 5, + hint: "Honors", + padding: const EdgeInsets.all(8), + options: valueItemHonorList, + selectionType: SelectionType.multi, + chipConfig: const ChipConfig(wrapType: WrapType.wrap), + dropdownHeight: 300, + optionTextStyle: const TextStyle(fontSize: 16), + selectedOptionIcon: const Icon(Icons.check_circle), + selectedOptions: + (state.educationalBackground.honors!.isNotEmpty && + state.educationalBackground.honors != null) + ? selectedValueItem = state + .educationalBackground.honors! + .map((Honor honor) => ValueItem( + label: honor.name!, value: honor.name)) + .toList() + : [], + ); + }), + ////sumit button + const Expanded(child: SizedBox()), + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: + mainBtnStyle(primary, Colors.transparent, second), + onPressed: () { + if (formKey.currentState!.saveAndValidate()) { + //// program + if (selectedLevel!.value == "Elementary" || + selectedLevel!.value == + "Secondary (non-K12)" || + selectedLevel!.value == "Junior High" || + selectedLevel!.value == "Senior High") { + selectedProgram = null; + }else{ + selectedProgram ??= state.educationalBackground.education!.course; + } + selectedSchool ??= state.educationalBackground.education!.school; + ////education + Education newEducation = Education( + id: null, + level: selectedLevel!.value, + course: selectedProgram, + school: selectedSchool); + ////honors + if (selectedValueItem.isNotEmpty) { + for (var honor in selectedValueItem) { + Honor newHonor = state.honors.firstWhere( + (element) => element.name == honor.value); + selectedHonors.add(newHonor); + } + } + EducationalBackground educationalBackground = + EducationalBackground( + id: state.educationalBackground.id, + honors: null, + education: newEducation, + periodTo: untilController.text, + periodFrom: fromController.text, + yearGraduated: + graduated ? yearGraduated.text : null, + unitsEarned: !graduated + ? int.parse(unitsController.text) + : null, + attachments: null, + ); + final progress = ProgressHUD.of(context); + progress!.showWithText("Loading..."); + context.read().add(UpdateEducation( + educationalBackground: educationalBackground, + profileId: widget.profileId, + token: widget.token, + honors: selectedHonors)); + } + }, + child: const Text(submit)), + ), + const SizedBox( + height: 20, + ), + ]), + ), + ), + ), + ); + } + return Container(); + }, + ); + } +} + +class EducationLevel { + final String value; + final String type; + final int group; + const EducationLevel( + {required this.type, required this.value, required this.group}); +} diff --git a/lib/screens/profile/components/education_screen.dart b/lib/screens/profile/components/education_screen.dart index 4771db8..a7f68df 100644 --- a/lib/screens/profile/components/education_screen.dart +++ b/lib/screens/profile/components/education_screen.dart @@ -1,11 +1,14 @@ +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:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/model/profile/educational_background.dart'; +import 'package:unit2/screens/profile/components/education/add_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'; @@ -14,18 +17,26 @@ import 'package:unit2/widgets/empty_data.dart'; import 'package:unit2/widgets/error_state.dart'; import '../../../bloc/profile/education/education_bloc.dart'; +import '../../../utils/alerts.dart'; +import 'education/edit_modal.dart'; class EducationScreen extends StatelessWidget { const EducationScreen({super.key}); @override Widget build(BuildContext context) { + int profileId; + String? token; return Scaffold( appBar: AppBar( title: const Text(educationScreenTitle), centerTitle: true, backgroundColor: primary, - actions: [AddLeading(onPressed: () {})], + actions: [ + AddLeading(onPressed: () { + context.read().add(ShowAddEducationForm()); + }) + ], ), //userbloc body: ProgressHUD( @@ -35,6 +46,8 @@ class EducationScreen extends StatelessWidget { child: BlocBuilder( builder: (context, state) { if (state is UserLoggedIn) { + token = state.userData!.user!.login!.token; + profileId = state.userData!.user!.login!.user!.profileId!; //profilebloc return BlocBuilder( builder: (context, state) { @@ -47,10 +60,77 @@ class EducationScreen extends StatelessWidget { progress!.showWithText("Please wait..."); } if (state is EducationalBackgroundLoadedState || - state is EducationalBackgroundErrorState) { + state is EducationalBackgroundErrorState || + state is AddEducationState || + state is EditEducationState || + state is EducationDeletedState || state is EditedEducationState) { final progress = ProgressHUD.of(context); progress!.dismiss(); } + ////ADDED STATE + if (state is EducationAddedState) { + if (state.response['success']) { + successAlert(context, "Adding Successfull!", + state.response['message'], () { + Navigator.of(context).pop(); + context + .read() + .add(LoadEducations()); + }); + } else { + errorAlert(context, "Adding Failed", + "Something went wrong. Please try again.", + () { + Navigator.of(context).pop(); + context + .read() + .add(LoadEducations()); + }); + } + } + ////EDITED STATE + + if (state is EditedEducationState) { + if (state.response['success']) { + successAlert(context, "Update Successfull!", + state.response['message'], () { + Navigator.of(context).pop(); + context + .read() + .add(LoadEducations()); + }); + } else { + errorAlert(context, "Updated Failed", + "Something went wrong. Please try again.", + () { + Navigator.of(context).pop(); + context + .read() + .add(LoadEducations()); + }); + } + } + ////DELETED STATE + if (state is EducationDeletedState) { + if (state.success) { + successAlert(context, "Deletion Successfull", + "Educational Background has been deleted successfully", + () { + Navigator.of(context).pop(); + context + .read() + .add(LoadEducations()); + }); + } else { + errorAlert(context, "Deletion Failed", + "Error deleting Education Background", () { + Navigator.of(context).pop(); + context + .read() + .add(LoadEducations()); + }); + } + } }, builder: (context, state) { if (state is EducationalBackgroundLoadedState) { @@ -181,12 +261,67 @@ class EducationScreen extends StatelessWidget { ), ]), ), - IconButton( - onPressed: () {}, - icon: const Icon( - Icons.more_vert, - color: Colors.grey, - )) + AppPopupMenu( + offset: const Offset(-10, -10), + elevation: 3, + onSelected: (value) { + ////delete -= = = = = = = = =>> + if (value == 2) { + confirmAlert(context, () { + final progress = + ProgressHUD.of( + context); + progress!.showWithText( + "Loading..."); + context + .read() + .add(DeleteEducation( + educationalBackground: + state.educationalBackground[ + index], + profileId: + profileId, + token: token!)); + }, "Delete?", + "Confirm Delete?"); + } + if (value == 1) { + ////edit -= = = = = = = = =>> + final progress = + ProgressHUD.of(context); + progress!.showWithText( + "Loading..."); + context + .read() + .add(ShowEditEducationForm( + profileId: + profileId, + token: token!, + educationalBackground: + state.educationalBackground[ + index])); + } + }, + 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", + ) ], ), ), @@ -206,6 +341,18 @@ class EducationScreen extends StatelessWidget { return SomethingWentWrong( message: state.message, onpressed: () {}); } + if (state is AddEducationState) { + return AddEducationScreen( + token: token!, + profileId: profileId, + ); + } + if (state is EditEducationState) { + return EditEducationScreen( + token: token!, + profileId: profileId, + ); + } return Container(); }, ); @@ -219,4 +366,23 @@ class EducationScreen 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/eligibility/add_modal.dart b/lib/screens/profile/components/eligibility/add_modal.dart index 07068e9..453bdf3 100644 --- a/lib/screens/profile/components/eligibility/add_modal.dart +++ b/lib/screens/profile/components/eligibility/add_modal.dart @@ -64,383 +64,399 @@ class _AddEligibilityScreenState extends State { return SingleChildScrollView( child: SizedBox( height: screenHeight * .95, - child: ProgressHUD( - child: Center( - child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 25, horizontal: 18), - child: FormBuilder( - key: formKey, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - ////ELIGIBILITIES DROPDOWN - FormBuilderDropdown( - onChanged: (Eligibility? eligibility) { - selectedEligibility = eligibility; - }, - autovalidateMode: - AutovalidateMode.onUserInteraction, - validator: (value) => - value == null ? 'required' : null, - items: state.eligibilities - .map>( - (Eligibility eligibility) { - return DropdownMenuItem( - value: eligibility, - child: Text(eligibility.title)); - }).toList(), - name: "eligibility", - decoration: normalTextFieldStyle( - "Eligibility", "Eligibility")), - const SizedBox( - height: 8, + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 25, horizontal: 18), + child: FormBuilder( + key: formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ////ELIGIBILITIES DROPDOWN + FormBuilderDropdown( + onChanged: (Eligibility? eligibility) { + selectedEligibility = eligibility; + }, + autovalidateMode: + AutovalidateMode.onUserInteraction, + validator: (value) => + value == null ? 'required' : null, + items: state.eligibilities + .map>( + (Eligibility eligibility) { + return DropdownMenuItem( + value: eligibility, + child: Text(eligibility.title)); + }).toList(), + name: "eligibility", + decoration: normalTextFieldStyle( + "Eligibility", "Eligibility")), + const SizedBox( + height: 8, + ), + + SizedBox( + width: screenWidth, + child: Row( + children: [ + ////LICENSE NUMBER + Flexible( + flex: 1, + child: FormBuilderTextField( + onChanged: (value) { + license = value; + }, + name: 'license_number', + decoration: normalTextFieldStyle( + "license number", "license number"), + ), + ), + const SizedBox( + width: 8, + ), + ////RATING + Flexible( + flex: 1, + child: FormBuilderTextField( + keyboardType: const TextInputType + .numberWithOptions(), + onChanged: (value) { + rating = value; + }, + name: 'rating', + decoration: normalTextFieldStyle( + 'rating %', 'rating'), + ), + ), + ], ), - - SizedBox( - width: screenWidth, - child: Row( - children: [ - ////LICENSE NUMBER - Flexible( - flex: 1, - child: FormBuilderTextField( - onChanged: (value) { - license = value; - }, - name: 'license_number', - decoration: normalTextFieldStyle( - "license number", "license number"), - ), - ), - const SizedBox( - width: 8, - ), - ////RATING - Flexible( - flex: 1, - child: FormBuilderTextField( - keyboardType: - const TextInputType.numberWithOptions(), - onChanged: (value) { - rating = value; - }, - name: 'rating', - decoration: normalTextFieldStyle( - 'rating %', 'rating'), - ), - ), - ], - ), - ), - const SizedBox( - height: 8, - ), - SizedBox( - width: screenWidth, - child: Row( - children: [ - ////EXAM DATE - Flexible( - flex: 1, - child: DateTimePicker( - validator: FormBuilderValidators.required( - errorText: "This field is required"), - use24HourFormat: false, - icon: const Icon(Icons.date_range), - controller: examDateController, - firstDate: DateTime(1970), - lastDate: DateTime(2100), - timeHintText: - "Date of Examination/Conferment", - decoration: - normalTextFieldStyle("Exam date", "") - .copyWith( - prefixIcon: const Icon( - Icons.date_range, - color: Colors.black87, - )), - initialValue: null, - )), - const SizedBox( - width: 8, - ), - ////VALIDITY DATE - Flexible( + ), + const SizedBox( + height: 8, + ), + SizedBox( + width: screenWidth, + child: Row( + children: [ + ////EXAM DATE + Flexible( flex: 1, child: DateTimePicker( - validator: FormBuilderValidators.required( - errorText: "This field is required"), - controller: validityDateController, + validator: + FormBuilderValidators.required( + errorText: + "This field is required"), + use24HourFormat: false, + icon: const Icon(Icons.date_range), + controller: examDateController, firstDate: DateTime(1970), lastDate: DateTime(2100), + timeHintText: + "Date of Examination/Conferment", decoration: normalTextFieldStyle( - "Validity date", "Validity date") + "Exam date", "") .copyWith( prefixIcon: const Icon( Icons.date_range, color: Colors.black87, )), initialValue: null, - ), - ), - ], - ), - ), - const SizedBox( - height: 8, - ), - Text( - "Placement of Examination/Conferment", - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith(fontSize: blockSizeVertical * 2), - ), - const SizedBox( - height: 8, - ), - ////OVERSEAS ADDRESS SWITCH - Column( - children: [ - FormBuilderSwitch( - validator: FormBuilderValidators.required( - errorText: 'This field is required'), - initialValue: overseas, - activeColor: second, - onChanged: (value) { - setState(() { - overseas = value; - }); - }, - decoration: normalTextFieldStyle("", ''), - name: 'overseas', - title: const Text("Overseas Address?"), - ), + )), const SizedBox( - height: 8, + width: 8, ), - ////COUNTRY DROPDOWN - SizedBox( - child: overseas == true - ? 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; - }, - ) - : Column( - children: [ - ////REGION DROPDOWN - FormBuilderDropdown( - autovalidateMode: AutovalidateMode - .onUserInteraction, - validator: - FormBuilderValidators.required( - errorText: - "This field is required"), - //// region onchange - onChanged: (Region? region) async { - - if(selectedRegion != region){ - setState(() { + ////VALIDITY DATE + Flexible( + flex: 1, + child: DateTimePicker( + validator: FormBuilderValidators.required( + errorText: "This field is required"), + controller: validityDateController, + firstDate: DateTime(1970), + lastDate: DateTime(2100), + decoration: normalTextFieldStyle( + "Validity date", "Validity date") + .copyWith( + prefixIcon: const Icon( + Icons.date_range, + color: Colors.black87, + )), + initialValue: null, + ), + ), + ], + ), + ), + const SizedBox( + height: 8, + ), + Text( + "Placement of Examination/Conferment", + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith(fontSize: blockSizeVertical * 2), + ), + const SizedBox( + height: 8, + ), + ////OVERSEAS ADDRESS SWITCH + Column( + children: [ + FormBuilderSwitch( + validator: FormBuilderValidators.required( + errorText: 'This field is required'), + initialValue: overseas, + activeColor: second, + onChanged: (value) { + setState(() { + overseas = value; + }); + }, + decoration: normalTextFieldStyle("", ''), + name: 'overseas', + title: const Text("Overseas Address?"), + ), + const SizedBox( + height: 8, + ), + ////COUNTRY DROPDOWN + SizedBox( + child: overseas == true + ? 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; + }, + ) + : Column( + children: [ + ////REGION DROPDOWN + FormBuilderDropdown( + autovalidateMode: + AutovalidateMode + .onUserInteraction, + validator: FormBuilderValidators + .required( + errorText: + "This field is required"), + //// region onchange + onChanged: + (Region? region) async { + if (selectedRegion != + region) { + setState(() { provinceCall = true; }); - selectedRegion = region; + selectedRegion = region; getProvinces(); - } - }, - initialValue: selectedRegion, - 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: 70, - 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")), - ), - ), - - //// CityMunicipalities dropdown - SizedBox( - height: 60, - child: ModalProgressHUD( - color: Colors.white, - inAsyncCall: cityCall, - child: DropdownButtonFormField< - CityMunicipality>( + } + }, + initialValue: selectedRegion, + decoration: + normalTextFieldStyle( + "Region*", "Region"), + name: 'region', + items: state.regions.map< + DropdownMenuItem< + Region>>( + (Region region) { + return DropdownMenuItem< + Region>( + value: region, + child: Text( + region.description!)); + }).toList(), + ), + const SizedBox( + height: 8, + ), + ////PROVINCE DROPDOWN + SizedBox( + height: 70, + child: ModalProgressHUD( + color: Colors.transparent, + inAsyncCall: provinceCall, + child: DropdownButtonFormField< + Province?>( + autovalidateMode: + AutovalidateMode + .onUserInteraction, validator: (value) => value == null ? 'required' : null, isExpanded: true, + value: selectedProvince, onChanged: - (CityMunicipality? city) { - selectedMunicipality = city; + (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( - "Municipality*", - "Municipality"), - value: selectedMunicipality, - items: citymuns == null - ? [] - : citymuns!.map< - DropdownMenuItem< - CityMunicipality>>( - (CityMunicipality c) { - return DropdownMenuItem( - value: c, - child: Text(c - .description!)); - }).toList(), - ), + "Province*", + "Province")), + ), + ), + + //// CityMunicipalities dropdown + SizedBox( + height: 60, + child: ModalProgressHUD( + color: Colors.white, + inAsyncCall: cityCall, + child: + DropdownButtonFormField< + CityMunicipality>( + validator: (value) => + value == null + ? 'required' + : null, + isExpanded: true, + onChanged: + (CityMunicipality? + 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(), ), ), - - ], - )), - ], - ), - - const Expanded( - child: SizedBox(), - ), - - SizedBox( - width: screenWidth, - height: 60, - child: ElevatedButton( - style: mainBtnStyle( - primary, Colors.transparent, second), - onPressed: () { - //rating - double? rate = rating == null - ? null - : double.parse(rating!); - //lisence - String? licenseNumber = license; - CityMunicipality? cityMunicipality = - selectedMunicipality; - DateTime? examDate = examDateController - .text.isEmpty - ? null - : DateTime.parse(examDateController.text); - DateTime? validityDate = - validityDateController.text.isEmpty - ? null - : DateTime.parse( - validityDateController.text); - - ExamAddress examAddress = ExamAddress( - barangay: null, - id: null, - addressCategory: null, - examAddressClass: null, - country: selectedCountry ?? - Country( - id: 175, - name: 'Philippines', - code: 'PH'), - cityMunicipality: cityMunicipality); - EligibityCert eligibityCert = EligibityCert( - id: null, - rating: rate, - examDate: examDate, - attachments: null, - eligibility: selectedEligibility, - examAddress: examAddress, - validityDate: validityDate, - licenseNumber: licenseNumber, - overseas: overseas); - if (formKey.currentState!.saveAndValidate()) { - final progress = ProgressHUD.of(context); - progress!.showWithText("Loading..."); - context.read().add( - AddEligibility( - eligibityCert: eligibityCert, - profileId: - widget.profileId.toString(), - token: widget.token)); - } - // context.read().add(AddEligibility(eligibityCert: eligibityCert, profileId: profileId, token: token)) - }, - child: const Text(submit)), - ), - const SizedBox( - height: 20, - ), - ]), - ), + ), + ], + )), + ], + ), + + const Expanded( + child: SizedBox(), + ), + + SizedBox( + width: screenWidth, + height: 60, + child: ElevatedButton( + style: mainBtnStyle( + primary, Colors.transparent, second), + onPressed: () { + //rating + double? rate = rating == null + ? null + : double.parse(rating!); + //lisence + String? licenseNumber = license; + CityMunicipality? cityMunicipality = + selectedMunicipality; + DateTime? examDate = + examDateController.text.isEmpty + ? null + : DateTime.parse( + examDateController.text); + DateTime? validityDate = + validityDateController.text.isEmpty + ? null + : DateTime.parse( + validityDateController.text); + + ExamAddress examAddress = ExamAddress( + barangay: null, + id: null, + addressCategory: null, + examAddressClass: null, + country: selectedCountry ?? + Country( + id: 175, + name: 'Philippines', + code: 'PH'), + cityMunicipality: cityMunicipality); + EligibityCert eligibityCert = EligibityCert( + id: null, + rating: rate, + examDate: examDate, + attachments: null, + eligibility: selectedEligibility, + examAddress: examAddress, + validityDate: validityDate, + licenseNumber: licenseNumber, + overseas: overseas); + if (formKey.currentState! + .saveAndValidate()) { + final progress = ProgressHUD.of(context); + progress!.showWithText("Loading..."); + context.read().add( + AddEligibility( + eligibityCert: eligibityCert, + profileId: + widget.profileId.toString(), + token: widget.token)); + } + // context.read().add(AddEligibility(eligibityCert: eligibityCert, profileId: profileId, token: token)) + }, + child: const Text(submit)), + ), + const SizedBox( + height: 20, + ), + ]), ), ), ), diff --git a/lib/screens/profile/components/voluntary_works_screen.dart b/lib/screens/profile/components/voluntary_works_screen.dart index a26ff67..fbe0da8 100644 --- a/lib/screens/profile/components/voluntary_works_screen.dart +++ b/lib/screens/profile/components/voluntary_works_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter_spinkit/flutter_spinkit.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/theme-data.dart/box_shadow.dart'; import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/utils/text_container.dart'; @@ -18,12 +19,16 @@ class VolunataryWorkScreen extends StatelessWidget { @override Widget build(BuildContext context) { + String? token; + int? profileId; DateFormat dteFormat2 = DateFormat.yMMMMd('en_US'); return Scaffold( appBar: AppBar( title: const Text(voluntaryScreenTitle), backgroundColor: primary, - actions: [AddLeading(onPressed: () {})], + actions: [AddLeading(onPressed: () { + context.read().add(ShowAddVoluntaryWorks()); + })], ), body: ProgressHUD( padding: const EdgeInsets.all(24), @@ -32,6 +37,9 @@ 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; return BlocBuilder( builder: (context, state) { if (state is ProfileLoaded) { @@ -43,7 +51,7 @@ class VolunataryWorkScreen extends StatelessWidget { progress!.showWithText("Please wait..."); } if (state is VoluntaryWorkLoadedState || - state is VoluntaryWorkErrorState) { + state is VoluntaryWorkErrorState|| state is AddVoluntaryWorkState) { final progress = ProgressHUD.of(context); progress!.dismiss(); } @@ -138,6 +146,8 @@ 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!,); } return Container(); }, diff --git a/lib/screens/profile/components/work_history/add_modal.dart b/lib/screens/profile/components/work_history/add_modal.dart index 3ba5b84..6db6239 100644 --- a/lib/screens/profile/components/work_history/add_modal.dart +++ b/lib/screens/profile/components/work_history/add_modal.dart @@ -22,11 +22,13 @@ import 'package:unit2/utils/text_container.dart'; import 'package:unit2/utils/validators.dart'; import '../../../../model/utils/position.dart'; +import '../../shared/add_for_empty_search.dart'; class AddWorkHistoryScreen extends StatefulWidget { final int profileId; final String token; - const AddWorkHistoryScreen({super.key, required this.profileId, required this.token}); + const AddWorkHistoryScreen( + {super.key, required this.profileId, required this.token}); @override State createState() => _AddWorkHistoryScreenState(); @@ -54,8 +56,6 @@ class _AddWorkHistoryScreenState extends State { final positionFocusNode = FocusNode(); final appointmentStatusNode = FocusNode(); final agencyCategoryFocusNode = FocusNode(); - int? profileId; - String? token; @override void dispose() { addPositionController.dispose(); @@ -67,705 +67,526 @@ class _AddWorkHistoryScreenState extends State { @override Widget build(BuildContext context) { - - return BlocConsumer( - listener: (context, state) { - if (state is AddWorkHistoryState) { - final progress = ProgressHUD.of(context); - progress!.dismiss(); - } - }, builder: (context, state) { - if (state is AddWorkHistoryState) { - 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( - 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!), - )))) + return BlocConsumer( + listener: (context, state) { + if (state is AddWorkHistoryState) { + final progress = ProgressHUD.of(context); + progress!.dismiss(); + } + }, builder: (context, state) { + if (state is AddWorkHistoryState) { + 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( + 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(); + }); + }, + ////EMPTY WIDGET + emptyWidget: EmptyWidget( + title: "Add Position", + controller: addPositionController, + onpressed: () { + setState(() { + Position newAgencyPosition = Position( + id: null, + title: addPositionController.text + .toUpperCase()); + + state.agencyPositions + .insert(0, newAgencyPosition); + selectedPosition = newAgencyPosition; + addPositionController.text = ""; + Navigator.pop(context); + }); + }), + validator: (position) { + if (position!.isEmpty) { + return "This field is required"; + } + return null; + }, + ); + }), + const SizedBox( + height: 12, + ), + ////APPOINTMENT STATUS' + SearchField( + 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( + 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(() { + 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: EmptyWidget( + controller: addAgencyController, + onpressed: () { + setState(() { + Agency newAgency = Agency( + id: null, + name: addAgencyController.text + .toUpperCase(), + category: null, + privateEntity: null); + + state.agencies.insert(0, newAgency); + selectedAgency = newAgency; + addAgencyController.text = ""; + showAgency = true; + + showIsPrivateRadio = true; + + 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(), - focusNode: positionFocusNode, + 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("Position *", "") + normalTextFieldStyle("Category *", "") .copyWith( suffixIcon: const Icon( Icons.arrow_drop_down)), - onSuggestionTap: (position) { - setState(() { - selectedPosition = position.item; - positionFocusNode.unfocus(); - }); - }, - ////EMPTY WIDGET - 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: () { - ////ADD POSITION DIALOG - 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) { + validator: (value) { + if (value!.isEmpty) { return "This field is required"; } return null; }, - ); - }), - const SizedBox( - height: 12, - ), - ////APPOINTMENT STATUS' - SearchField( - 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(), + ), - 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(() { - 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 = ""; - showAgency = true; - - showIsPrivateRadio = true; - - Navigator.pop(context); - }); - }, - child: const Text("Add"))), - ], - ), - ), - ); - }); - }, - child: const Text( - "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(() { - 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()), - ////SALARY GRADE AND SALARY GRADE STEP - SizedBox( - child: showSalaryGradeAndSalaryStep - ? Column( - children: [ - Row( - children: [ - Flexible( - flex: 1, - child: - FormBuilderTextField( - name: - 'salary_grade', - keyboardType: - TextInputType - .number, - decoration: - normalTextFieldStyle( - "Salary Grade (SG)", - "0"), - onChanged: (value) { - 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( - width: 12, - ), - Flexible( - flex: 1, - child: - FormBuilderTextField( - name: 'salary_step', - keyboardType: - TextInputType - .number, - decoration: - 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 = - value; - }); - }, - ), - ) - ], - ) - ], - ) - : null), - ], - ); - }), - const SizedBox( - height: 12, - ), - ////MONTHLY SALARY - FormBuilderTextField( - 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( + ////PRVIATE SECTOR + SizedBox( + child: showIsPrivateRadio + ? FormBuilderRadioGroup( + decoration: InputDecoration( + border: InputBorder.none, + label: 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: currentlyEmployed - ? 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: - currentlyEmployed - ? "PRESENT" - : ""), - initialValue: null, - ), + Text( + "Is this private sector? ", + style: Theme.of(context) + .textTheme + .headlineSmall! + .copyWith(fontSize: 24), ), + const Icon(FontAwesome.help_circled) ], ), ), - ], - ); - }), - const Expanded(child: SizedBox()), - ////SUBMIT BUTTON - SizedBox( - width: double.infinity, - height: 60, - child: ElevatedButton( - style: mainBtnStyle( - primary, Colors.transparent, second), - onPressed: () { - - if (_formKey.currentState!.validate()) { - final progress = - ProgressHUD.of(context); - progress!.showWithText( - "Loading..."); - WorkHistory workHistory = WorkHistory( - position: selectedPosition, + + ////onvhange private sector + onChanged: (value) { + setState(() { + if (value.toString() == "YES") { + isPrivate = true; + showSalaryGradeAndSalaryStep = + false; + } else { + isPrivate = false; + showSalaryGradeAndSalaryStep = true; + } + selectedAgency = Agency( 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!)); - } + name: selectedAgency!.name, + category: selectedAgencyCategory, + privateEntity: value == "YES" + ? true + : false); + agencyFocusNode.unfocus(); + agencyCategoryFocusNode.unfocus(); + }); }, - child: const Text(submit)), - ), + + name: 'isPrivate', + validator: + FormBuilderValidators.required(), + options: ["YES", "NO"] + .map((lang) => FormBuilderFieldOption( + value: lang)) + .toList(growable: false), + ) + : const SizedBox()), + ////SALARY GRADE AND SALARY GRADE STEP + SizedBox( + child: showSalaryGradeAndSalaryStep + ? Column( + children: [ + Row( + children: [ + Flexible( + flex: 1, + child: FormBuilderTextField( + name: 'salary_grade', + keyboardType: + TextInputType.number, + decoration: + normalTextFieldStyle( + "Salary Grade (SG)", + "0"), + onChanged: (value) { + 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( + width: 12, + ), + Flexible( + flex: 1, + child: FormBuilderTextField( + name: 'salary_step', + keyboardType: + TextInputType.number, + decoration: + 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 = value; + }); + }, + ), + ) + ], + ) + ], + ) + : null), + ], + ); + }), + const SizedBox( + height: 12, + ), + ////MONTHLY SALARY + FormBuilderTextField( + 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: 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( - height: 20, + width: 12, + ), + //// TO DATE + Flexible( + flex: 1, + child: currentlyEmployed + ? 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: currentlyEmployed + ? "PRESENT" + : ""), + initialValue: null, + ), ), ], ), ), - ), - ), - ); - } - return Container(); - }); + ], + ); + }), + const Expanded(child: SizedBox()), + ////SUBMIT BUTTON + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: + mainBtnStyle(primary, Colors.transparent, second), + onPressed: () { + if (_formKey.currentState!.validate()) { + final progress = ProgressHUD.of(context); + progress!.showWithText("Loading..."); + 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: widget.profileId, + token: widget.token, + isPrivate: isPrivate!)); + } + }, + child: const Text(submit)), + ), + const SizedBox( + height: 20, + ), + ], + ), + ), + ), + ), + ); + } + return Container(); + }); } } diff --git a/lib/screens/profile/components/work_history/edit_modal.dart b/lib/screens/profile/components/work_history/edit_modal.dart index bff0072..61303b8 100644 --- a/lib/screens/profile/components/work_history/edit_modal.dart +++ b/lib/screens/profile/components/work_history/edit_modal.dart @@ -6,6 +6,7 @@ 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:unit2/screens/profile/shared/add_for_empty_search.dart'; import '../../../../bloc/profile/profile_bloc.dart'; import '../../../../bloc/profile/workHistory/workHistory_bloc.dart'; import '../../../../bloc/user/user_bloc.dart'; @@ -129,84 +130,22 @@ class _EditWorkHistoryScreenState extends State { 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")) - ]), - ), + emptyWidget: EmptyWidget( + controller: addPositionController, + onpressed: () { + setState(() { + Position newAgencyPosition = Position( + id: null, + title: addPositionController.text + .toUpperCase()); + state.agencyPositions + .insert(0, newAgencyPosition); + selectedPosition = newAgencyPosition; + addPositionController.text = ""; + Navigator.pop(context); + }); + }, + title: "Add Position"), validator: (position) { if (position!.isEmpty) { return "This field is required"; @@ -253,139 +192,77 @@ class _EditWorkHistoryScreenState extends State { 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; + 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"; } - 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; + 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); + selectedAgency = newAgency; + addAgencyController.text = ""; + showAgencyCategory = true; - showIsPrivateRadio = - true; + showIsPrivateRadio = true; - Navigator.pop(context); - }); - }, - child: const Text( - "Add"))), - ], - ), - ), - ); - }); - }, - child: const Text("Add Agency")) - ]), - ), - ), + Navigator.pop(context); + }); + }, + title: "Add Agency")), SizedBox( height: showAgencyCategory ? 12 : 0, 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 new file mode 100644 index 0000000..e7cf6cb --- /dev/null +++ b/lib/screens/profile/components/work_history/voluntary_works/add_modal.dart @@ -0,0 +1,597 @@ +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/screens/profile/shared/add_for_empty_search.dart b/lib/screens/profile/shared/add_for_empty_search.dart new file mode 100644 index 0000000..2685e51 --- /dev/null +++ b/lib/screens/profile/shared/add_for_empty_search.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.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'; + +class EmptyWidget extends StatelessWidget { + final TextEditingController controller; + final Function()? onpressed; + final String title; + const EmptyWidget( + {super.key, required this.controller, required this.onpressed,required this.title}); + + @override + Widget build(BuildContext context) { + return 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: () { + ////ADD POSITION DIALOG + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text(title), + content: SizedBox( + height: 130, + child: Column( + children: [ + TextFormField( + controller: controller, + decoration: normalTextFieldStyle("", ""), + ), + const SizedBox( + height: 12, + ), + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + style: mainBtnStyle(primary, + Colors.transparent, second), + onPressed: onpressed, + child: const Text("Add"))), + ], + ), + ), + ); + }); + }, + child: Text(title)) + ]), + ); + } +} \ No newline at end of file diff --git a/lib/screens/unit2/homepage.dart/components/dashboard.dart b/lib/screens/unit2/homepage.dart/components/dashboard.dart index eed381c..5a94357 100644 --- a/lib/screens/unit2/homepage.dart/components/dashboard.dart +++ b/lib/screens/unit2/homepage.dart/components/dashboard.dart @@ -1,97 +1,224 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:unit2/screens/docsms/components/request_receipt.dart'; +import 'package:unit2/screens/docsms/index.dart'; import 'package:unit2/screens/unit2/homepage.dart/module-screen.dart'; import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/utils/global.dart'; +import 'package:unit2/utils/global_context.dart'; +import 'package:unit2/utils/qr_scanner.dart'; +import 'package:unit2/utils/text_container.dart'; + +import '../../../../bloc/docsms/docsms_bloc.dart'; class DashBoard extends StatelessWidget { final List roles; const DashBoard({super.key, required this.roles}); @override Widget build(BuildContext context) { + List finishRoles = []; return Container( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24), height: MediaQuery.of(context).size.height, - //listview builder + ////listview builder child: ListView.builder( scrollDirection: Axis.vertical, shrinkWrap: true, itemCount: roles.length, itemBuilder: (BuildContext context, int index) { - // gridview.count - return SizedBox( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - roles[index].name.toUpperCase(), - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(fontSize: 12), - ), - - const SizedBox( - height: 8, - ), - GridView.count( - shrinkWrap: true, - crossAxisCount: 4, - crossAxisSpacing: 8, - mainAxisSpacing: 10, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.symmetric( - vertical: 5, horizontal: 5), - children: roles[index].roles.map((role) { - return Container( - padding: const EdgeInsetsDirectional.fromSTEB(8,5,8,13), - alignment: Alignment.center, - - decoration:const BoxDecoration( - color: Colors.white, - boxShadow:[ BoxShadow(color: Colors.black12,spreadRadius: 2,blurRadius: 3)], - borderRadius: BorderRadius.all(Radius.circular(8)) - ), - child: GestureDetector( - onTap: () { - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Icon( - - role.icon, - size: 20, - weight: 100, - grade: 100, - color:second, - ), - ), - const SizedBox( - height: 5, - ), - Text( - role.role.name!.toLowerCase() == "establishment point-person"?"Est. point-person": - role.role.name!, - textAlign: TextAlign.center, - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith( - fontSize: blockSizeVertical*1.1, - fontWeight: FontWeight.bold), - ), - ]), - ), - ); - }).toList()), - const SizedBox(height: 8,) - ], - ), - ); + //// gridview.count + return roles[index].roles.isNotEmpty + ? SizedBox( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + roles[index].name.toUpperCase(), + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith(fontSize: 12), + ), + const SizedBox( + height: 8, + ), + GridView.count( + shrinkWrap: true, + crossAxisCount: 4, + crossAxisSpacing: 8, + mainAxisSpacing: 10, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.symmetric( + vertical: 5, horizontal: 5), + children: roles[index].roles.map((role) { + //// if role name is qr code && finishRoles not contain security + //// this card will visible if the user has qr code scanner or security role + if (role.role.name!.toLowerCase() == + 'qr code scanner' && + !finishRoles.contains("security")) { + finishRoles.add('scanner'); + //// loop thru module to find unit module exist + for (var element in role.role.modules!) { + if (element!.name!.toLowerCase() == 'unit2') { + for (var element in element.objects!) { + //// loop thru objects to find pass check exist + if (element!.id == 9 && + //// check if operations contains read and write + element.operations! + .contains("read")) { + //// if all conditions are true return card + return CardLabel( + ontap: () {}, + icon: role.icon, + title: "Pass Check", + ); + } + } + } + } + return Container(); + //// if role name is security + //// this card will visible if the user has qr code scanner or security role + } else if (role.role.name!.toLowerCase() == + 'security guard' && + !finishRoles.contains('scanner')) { + finishRoles.add('security'); + for (var element in role.role.modules!) { + if (element!.name!.toLowerCase() == 'unit2') { + for (var element in element.objects!) { + if (element!.id == 9 && + element.operations! + .contains("read")) { + return CardLabel( + ontap: () {}, + icon: role.icon, + title: "Pass Check", + ); + } + } + } + } + return Container(); + //// if role name is field surveyor + } else if (role.role.name!.toLowerCase() == + 'field surveyor') { + for (var element in role.role.modules!) { + if (element!.name!.toLowerCase() == 'rpass') { + for (var element in element.objects!) { + if (element!.id == 11 && + element.operations! + .contains("read")) { + return CardLabel( + ontap: () {}, + icon: role.icon, + title: "Field Surveyor", + ); + } + } + } + } + return Container(); + //// if role name is process server + } else if (role.role.name!.toLowerCase() == + 'process server') { + for (var element in role.role.modules!) { + if (element!.name!.toLowerCase() == + 'document management') { + for (var element in element.objects!) { + if (element!.id == 3 && + element.operations! + .contains("read")) { + return CardLabel( + ontap: () async { + String? qrBarcode = + await qrScanner(); + if (qrBarcode != null) { + Navigator.push(NavigationService.navigatorKey.currentContext!, MaterialPageRoute(builder: + (BuildContext context) { + return BlocProvider( + create: (context) => DocsmsBloc() + ..add(LoadDocument( + documentId: qrBarcode)), + child: + const AutoReceiveDocument(), + ); + })); + } + }, + icon: role.icon, + title: "Process Server", + ); + } + } + } + } + return Container(); + } else { + return Container(); + } + }).toList()), + const SizedBox( + height: 8, + ) + ], + ), + ) + : Container(); }), ); } } + +// ignore: must_be_immutable +class CardLabel extends StatelessWidget { + final String title; + final IconData icon; + final Function()? ontap; + const CardLabel( + {super.key, + required this.icon, + required this.title, + required this.ontap}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: ontap, + child: Container( + padding: const EdgeInsetsDirectional.fromSTEB(8, 5, 8, 13), + alignment: Alignment.center, + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow(color: Colors.black12, spreadRadius: 2, blurRadius: 3) + ], + borderRadius: BorderRadius.all(Radius.circular(8))), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Icon( + icon, + size: 20, + weight: 100, + grade: 100, + color: second, + ), + ), + const SizedBox( + height: 5, + ), + Text( + title, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.labelLarge!.copyWith( + fontSize: blockSizeVertical * 1.2, + fontWeight: FontWeight.bold), + ), + ]), + ), + ); + } +} diff --git a/lib/screens/unit2/homepage.dart/module-screen.dart b/lib/screens/unit2/homepage.dart/module-screen.dart index ba232cc..5638de6 100644 --- a/lib/screens/unit2/homepage.dart/module-screen.dart +++ b/lib/screens/unit2/homepage.dart/module-screen.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_zoom_drawer/flutter_zoom_drawer.dart'; import 'package:fluttericon/font_awesome5_icons.dart'; import 'package:fluttericon/font_awesome_icons.dart'; +import 'package:fluttericon/rpg_awesome_icons.dart'; import 'package:fluttericon/typicons_icons.dart'; import 'package:unit2/screens/unit2/homepage.dart/components/dashboard.dart'; import 'package:unit2/theme-data.dart/colors.dart'; @@ -21,7 +22,8 @@ class MainScreen extends StatefulWidget { class _MainScreenState extends State { List roles = [ Module(name: 'UniT2 module operations', roles: []), - Module(name: 'DocSms module operations', roles: []) + Module(name: 'DocSms module operations', roles: []), + Module(name: "RPAss module operations",roles:[] ) ]; @override Widget build(BuildContext context) { @@ -43,6 +45,10 @@ class _MainScreenState extends State { IconData iconData = iconGenerator(getRole!.name!); Roles newRole = Roles(role: getRole, icon: iconData); roles[1].roles.add(newRole); + } if (module.name!.toLowerCase() == 'rpass') { + IconData iconData = iconGenerator(getRole!.name!); + Roles newRole = Roles(role: getRole, icon: iconData); + roles[2].roles.add(newRole); } } } @@ -97,6 +103,8 @@ class _MainScreenState extends State { case 'process server': iconData = Typicons.doc_text; break; + case 'field surveyor': + iconData = RpgAwesome.telescope; } return iconData!; } diff --git a/lib/sevices/docsms/docsms_service.dart b/lib/sevices/docsms/docsms_service.dart new file mode 100644 index 0000000..f6bb665 --- /dev/null +++ b/lib/sevices/docsms/docsms_service.dart @@ -0,0 +1,36 @@ +import 'dart:convert'; + +import 'package:unit2/utils/request.dart'; +import 'package:unit2/utils/urls.dart'; +import 'package:http/http.dart' as http; +import '../../model/docsms/document.dart'; + +class AutoReceiveDocumentServices{ + static final AutoReceiveDocumentServices _instance = AutoReceiveDocumentServices(); + static AutoReceiveDocumentServices get instance => _instance; + + Future getDocument(String documentId) async { + String path = Url.instance.getDocument(); + Document? document; + Map params = {"t1.id": documentId.toString()}; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + }; + try { + http.Response response = await Request.instance.getRequest(param: params,path:path,headers:headers); + + if (response.statusCode == 200) { + Map data = json.decode(response.body); + if(data['message'].toString().toLowerCase() == "data successfully fetched."){ + document = Document.fromJson(data['data']); + }else{ + document = null; + } + } + } catch (e) { + throw (e.toString()); + } + return document; + } + +} \ No newline at end of file diff --git a/lib/sevices/profile/education_services.dart b/lib/sevices/profile/education_services.dart index 1d6d93e..05a86f5 100644 --- a/lib/sevices/profile/education_services.dart +++ b/lib/sevices/profile/education_services.dart @@ -9,12 +9,12 @@ import 'package:http/http.dart' as http; class EducationService { static final EducationService _instance = EducationService(); static EducationService get instace => _instance; - +////get educational background Future> getEducationalBackground( int profileId, String token) async { List educationalBackgrounds = []; String authToken = "Token $token"; - String path = "${Url.instance.getEducationalBackgrounds()}$profileId/"; + String path = "${Url.instance.educationalBackground()}$profileId/"; Map headers = { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': authToken @@ -38,4 +38,201 @@ class EducationService { return educationalBackgrounds; } + + ////Add + Future> add( + {required EducationalBackground educationalBackground, + required String token, + required int profileId, + required List honors}) async { + String authtoken = "Token $token"; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': authtoken + }; + String path = '${Url.instance.educationalBackground()}$profileId/'; + Map statusResponse = {}; + Map body = { + "_level": educationalBackground.education!.level, + "_schoolId": educationalBackground.education?.school?.id, + "_schoolName": educationalBackground.education!.school!.name, + "_programId": educationalBackground.education?.course?.id, + "_programName": educationalBackground.education?.course?.program, + "_course": null, + "period_from": educationalBackground.periodFrom.toString(), + "period_to": educationalBackground.periodTo.toString(), + "units_earned": educationalBackground.unitsEarned, + "year_graduated": educationalBackground.yearGraduated, + "honors": honors.isEmpty ? [] : honors, + }; + 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}); + } + } catch (e) { + throw e.toString(); + } + return statusResponse; + } + + ////Edit + Future> edit( + {required EducationalBackground educationalBackground, + required String token, + required int profileId, + required List honors}) async { + String authtoken = "Token $token"; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': authtoken + }; + String path = '${Url.instance.educationalBackground()}$profileId/'; + Map statusResponse = {}; + Map body = { + "id": educationalBackground.id, + "_level": educationalBackground.education!.level, + "_schoolId": educationalBackground.education?.school?.id, + "_schoolName": educationalBackground.education!.school!.name, + "_programId": educationalBackground.education?.course?.id, + "_programName": educationalBackground.education?.course?.program, + "_course": null, + "period_from": educationalBackground.periodFrom.toString(), + "period_to": educationalBackground.periodTo.toString(), + "units_earned": educationalBackground.unitsEarned, + "year_graduated": educationalBackground.yearGraduated, + "honors": honors.isEmpty ? [] : honors, + }; + try { + http.Response response = await Request.instance + .putRequest(path: path, param: {}, body: body, headers: headers); + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + statusResponse = data; + } else { + statusResponse.addAll({'success': false}); + } + } catch (e) { + throw e.toString(); + } + return statusResponse; + } + + //// delete + Future delete( + {required int profileId, + required String token, + required EducationalBackground educationalBackground}) async { + String authToken = "Token $token"; + String path = "${Url.instance.educationalBackground()}$profileId/"; + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Authorization': authToken + }; + bool? success; + Map params = {"force_mode": "true"}; + Map body = { + "id": educationalBackground.id, + "_level": educationalBackground.education!.level, + "_schoolId": educationalBackground.education!.school!.id, + "education_id": educationalBackground.education!.id, + "period_from": educationalBackground.periodFrom, + "period_to": educationalBackground.periodTo, + "units_earned": educationalBackground.unitsEarned, + "year_graduated": educationalBackground.yearGraduated, + "honors": educationalBackground.honors + }; + 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']; + } else { + success = false; + } + } catch (e) { + throw e.toString(); + } + return success!; + } + +//// get schools + Future> getSchools() async { + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + }; + List schools = []; + String path = Url.instance.getSchools(); + try { + http.Response response = await Request.instance + .getRequest(param: {}, path: path, headers: headers); + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + if (data['data'] != null) { + data['data'].forEach((school) { + School newSchool = School.fromJson(school); + schools.add(newSchool); + }); + } + } + } catch (e) { + throw e.toString(); + } + return schools; + } + + Future> getPrograms() async { + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + }; + List programs = []; + String path = Url.instance.getPrograms(); + try { + http.Response response = await Request.instance + .getRequest(param: {}, path: path, headers: headers); + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + if (data['data'] != null) { + data['data'].forEach((course) { + Course newCourse = Course.fromJson(course); + programs.add(newCourse); + }); + } + } + } catch (e) { + throw e.toString(); + } + return programs; + } + +////get honors + Future> getHonors() async { + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + }; + List honors = []; + String path = Url.instance.getHonors(); + try { + http.Response response = await Request.instance + .getRequest(param: {}, path: path, headers: headers); + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + if (data['data'] != null) { + data['data'].forEach((honor) { + Honor newHonor = Honor.fromJson(honor); + honors.add(newHonor); + }); + } + } + } catch (e) { + throw e.toString(); + } + return honors; + } } diff --git a/lib/sevices/profile/work_history_services.dart b/lib/sevices/profile/work_history_services.dart index 8e45820..99d7582 100644 --- a/lib/sevices/profile/work_history_services.dart +++ b/lib/sevices/profile/work_history_services.dart @@ -164,7 +164,7 @@ class WorkHistoryService { } -//get agency position +////get agency position Future> getAgencyPosition() async { List agencyPositions = []; String path = Url.instance.getPositions(); diff --git a/lib/utils/app_router.dart b/lib/utils/app_router.dart index 9db2326..2769d80 100644 --- a/lib/utils/app_router.dart +++ b/lib/utils/app_router.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:unit2/bloc/docsms/docsms_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/sos/sos_bloc.dart'; +import 'package:unit2/screens/docsms/index.dart'; import 'package:unit2/screens/sos/index.dart'; import 'package:unit2/screens/unit2/homepage.dart/components/menu.dart'; import 'package:unit2/screens/unit2/login/login.dart'; @@ -51,6 +53,7 @@ class AppRouter { child: const SosScreen(), ); }); + default: return MaterialPageRoute(builder: (context) { return Container(); diff --git a/lib/utils/profile_utilities.dart b/lib/utils/profile_utilities.dart index 310dc61..6debf6f 100644 --- a/lib/utils/profile_utilities.dart +++ b/lib/utils/profile_utilities.dart @@ -1,4 +1,3 @@ - import 'dart:convert'; import 'package:unit2/model/location/country.dart'; @@ -11,35 +10,63 @@ import 'package:unit2/utils/urls.dart'; import '../model/profile/basic_information/contact_information.dart'; import '../model/utils/agency.dart'; import '../model/utils/category.dart'; +import '../model/utils/position.dart'; + class ProfileUtilities { static final ProfileUtilities _instance = ProfileUtilities(); static ProfileUtilities get instance => _instance; - Future>getEligibilities()async{ - List eligibilities=[]; + Future> getEligibilities() async { + List eligibilities = []; String path = Url.instance.eligibilities(); - + Map headers = { 'Content-Type': 'application/json; charset=UTF-8', }; - 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 eligibility){ - Eligibility newEligibilities = Eligibility.fromJson(eligibility); - eligibilities.add(newEligibilities); - }); + 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 eligibility) { + Eligibility newEligibilities = Eligibility.fromJson(eligibility); + eligibilities.add(newEligibilities); + }); + } + } + } catch (e) { + throw (e.toString()); } - } - }catch(e){ - throw(e.toString()); - } - return eligibilities; + return eligibilities; } - //get agencies +////get agency position + Future> getAgencyPosition() async { + List agencyPositions = []; + String path = Url.instance.getPositions(); + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + }; + try { + http.Response response = await Request.instance + .getRequest(param: {}, path: path, headers: headers); + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + if (data['data'] != null) { + data['data'].forEach((var agencyPosition) { + Position position = Position.fromJson(agencyPosition); + agencyPositions.add(position); + }); + } + } + } catch (e) { + throw (e.toString()); + } + return agencyPositions; + } + + ////get agencies Future> getAgecies() async { List agencies = []; String path = Url.instance.getAgencies(); @@ -64,8 +91,7 @@ class ProfileUtilities { return agencies; } - -//get agency category +////get agency category Future> agencyCategory() async { List agencyCategory = []; String path = Url.instance.getAgencyCategory(); @@ -91,28 +117,28 @@ class ProfileUtilities { } //// get service type - Future> getServiceType()async{ + Future> getServiceType() async { List serviceTypes = []; - Map headers = { + Map headers = { 'Content-Type': 'application/json; charset=UTF-8', }; String path = Url.instance.getServiceTypes(); - try{ - http.Response response = await Request.instance.getRequest(param: {},path:path,headers: headers ); - if(response.statusCode == 200){ + try { + http.Response response = await Request.instance + .getRequest(param: {}, path: path, headers: headers); + if (response.statusCode == 200) { Map data = jsonDecode(response.body); - if(data['data'] != null){ - for(var element in data['data']){ + if (data['data'] != null) { + for (var element in data['data']) { ServiceType newServiceType = ServiceType.fromJson(element); serviceTypes.add(newServiceType); } } } - }catch(e){ + } catch (e) { throw e.toString(); } return serviceTypes; } - -} \ No newline at end of file +} diff --git a/lib/utils/qr_scanner.dart b/lib/utils/qr_scanner.dart new file mode 100644 index 0000000..003161d --- /dev/null +++ b/lib/utils/qr_scanner.dart @@ -0,0 +1,17 @@ +import 'package:barcode_scan2/barcode_scan2.dart'; +import 'package:unit2/utils/scanner.dart'; + +Future qrScanner() async { + String? result; + try { + ScanResult afterScan = await QRCodeBarCodeScanner.instance.scanner(); + if (afterScan.type == ResultType.Barcode) { + result = afterScan.rawContent; + return result; + } + } catch (e) { + throw e.toString(); + } + + return null; +} diff --git a/lib/utils/urls.dart b/lib/utils/urls.dart index 0d165e9..de84310 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() { @@ -27,6 +27,11 @@ class Url { return "/api/sos_app/sos_request/"; } + //// DOCSMS paths + String getDocument(){ + return "/api/web_app/public/document_viewer/"; + } + ////ELIGIBILITIES PATHS String eligibilities(){ return "/api/jobnet_app/eligibilities/"; @@ -57,17 +62,24 @@ String getAgencies(){ return "/api/jobnet_app/agencies/"; } - - String getAgencyCategory(){ return "api/jobnet_app/agency_categories/"; } ////educational background paths -String getEducationalBackgrounds(){ +String educationalBackground(){ return "/api/jobnet_app/profile/pds/education/"; } +String getSchools(){ + return "/api/jobnet_app/schools/"; +} +String getPrograms(){ + return "api/jobnet_app/education_programs/"; +} +String getHonors(){ + return "/api/jobnet_app/honors"; +} //// learning and development paths diff --git a/pubspec.lock b/pubspec.lock index c34bf28..1f2ef3f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -677,6 +677,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + location: + dependency: "direct main" + description: + name: location + sha256: "9051959f6f2ccadd887b28b66e9cbbcc25b6838e37cf9e894c421ccc0ebf80b5" + url: "https://pub.dev" + source: hosted + version: "4.4.0" + location_platform_interface: + dependency: transitive + description: + name: location_platform_interface + sha256: "62eeaf1658e92e4459b727f55a3c328eccbac8ba043fa6d262ac5286ad48384c" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + location_web: + dependency: transitive + description: + name: location_web + sha256: "6c08c408a040534c0269c4ff9fe17eebb5a36dea16512fbaf116b9c8bc21545b" + url: "https://pub.dev" + source: hosted + version: "3.1.1" logging: dependency: transitive description: @@ -741,6 +765,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" + multi_dropdown: + dependency: "direct main" + description: + name: multi_dropdown + sha256: "65b8f505b251c5173e8eff64c09cd37460d8f8be906c2069a03815ad2641dcd1" + url: "https://pub.dev" + source: hosted + version: "1.0.9" nested: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ab0bffe..943b2ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -77,7 +77,7 @@ 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, dev_dependencies: flutter_test: