Implemented crud operation API for organization membership screen

feature/passo/PASSO-#1-Sync-data-from-device-to-postgre-and-vice-versa
PGAN-MIS 2023-03-27 16:59:08 +08:00
parent 12bc51335d
commit 58e1167613
18 changed files with 1250 additions and 104 deletions

View File

@ -3,6 +3,9 @@ import 'package:equatable/equatable.dart';
import 'package:unit2/sevices/profile/non_academic_services.dart';
import '../../../../model/profile/other_information/non_acedimic_recognition.dart';
import '../../../../model/utils/agency.dart';
import '../../../../model/utils/category.dart';
import '../../../../utils/profile_utilities.dart';
part 'non_academic_recognition_event.dart';
@ -11,6 +14,9 @@ part 'non_academic_recognition_state.dart';
class NonAcademicRecognitionBloc extends Bloc<NonAcademicRecognitionEvent, NonAcademicRecognitionState> {
NonAcademicRecognitionBloc() : super(NonAcademicRecognitionInitial()) {
List<NonAcademicRecognition> nonAcademicRecognitions = [];
List<Agency> agencies = [];
List<Category> agencyCategory = [];
////GET
on<GetNonAcademicRecognition>((event, emit)async {
emit(NonAcademicRecognitionLoadingState());
try{
@ -21,5 +27,26 @@ class NonAcademicRecognitionBloc extends Bloc<NonAcademicRecognitionEvent, NonAc
emit(NonAcademicRecognitionErrorState(message: e.toString()));
}
});
////SHOW ADD FORM
on<ShowAddNonAcademeRecognitionForm>((event, emit)async{
emit(NonAcademicRecognitionLoadingState());
try{
if(agencies.isEmpty){
List<Agency> newAgencies = await ProfileUtilities.instance.getAgecies();
agencies = newAgencies;
}
if(agencyCategory.isEmpty){
List<Category>newAgencyCategories = await ProfileUtilities.instance.agencyCategory();
agencyCategory = newAgencyCategories;
}
emit(AddNonAcademeRecognitionState(agencies: agencies, agencyCategories: agencyCategory));
}catch(e){
emit(NonAcademicRecognitionErrorState(message: e.toString()));
}
},);
////ADD
on<AddNonAcademeRecognition>((event,emit){
emit(NonAcademicRecognitionLoadingState());
});
}
}

View File

@ -6,7 +6,7 @@ abstract class NonAcademicRecognitionEvent extends Equatable {
@override
List<Object> get props => [];
}
//// GET EVENT
class GetNonAcademicRecognition extends NonAcademicRecognitionEvent{
final int profileId;
final String token;
@ -14,3 +14,39 @@ class GetNonAcademicRecognition extends NonAcademicRecognitionEvent{
@override
List<Object> get props => [profileId,token];
}
////LOAD EVENT
class LoadNonAcademeRecognition extends NonAcademicRecognitionEvent{
final List<NonAcademicRecognition> nonAcademicRecognitions;
const LoadNonAcademeRecognition({required this.nonAcademicRecognitions});
@override
List<Object> get props => [nonAcademicRecognitions];
}
////SHOW ADD FORM EVENT
class ShowAddNonAcademeRecognitionForm extends NonAcademicRecognitionEvent{
}
//// ADD EVENT
class AddNonAcademeRecognition extends NonAcademicRecognitionEvent{
final int profileId;
final String token;
final NonAcademicRecognition nonAcademicRecognition;
const AddNonAcademeRecognition({required this.nonAcademicRecognition, required this.profileId, required this.token});
@override
List<Object> get props => [nonAcademicRecognition,profileId,token];
}
//// DELETE EVENT
class DeleteNonAcademeRecognition extends NonAcademicRecognitionEvent{
final int profileId;
final String token;
final int id;
final String title;
const DeleteNonAcademeRecognition({required this.id,required this.profileId, required this.title,required this.token});
@override
List<Object> get props => [profileId,token,id,title];
}

View File

@ -9,16 +9,49 @@ abstract class NonAcademicRecognitionState extends Equatable {
class NonAcademicRecognitionInitial extends NonAcademicRecognitionState {}
////LOADING STATE
class NonAcademicRecognitionLoadingState extends NonAcademicRecognitionState{
}
////LOADED STATE
class NonAcademicRecognitionLoadedState extends NonAcademicRecognitionState{
final List<NonAcademicRecognition> nonAcademicRecognition;
const NonAcademicRecognitionLoadedState({required this.nonAcademicRecognition});
@override
List<Object> get props => [];
}
////DELETED STATE
class NonAcademeRecognitionDeletedState extends NonAcademicRecognitionState{
final List<NonAcademicRecognition> nonAcademicRecognition;
final bool success;
const NonAcademeRecognitionDeletedState({required this.nonAcademicRecognition, required this.success});
@override
List<Object> get props => [nonAcademicRecognition,success];
}
////ADDED STATE
class NonAcademeRecognitionAddedState extends NonAcademicRecognitionState{
final List<NonAcademicRecognition> nonAcademicRecognition;
final Map<dynamic,dynamic> response;
const NonAcademeRecognitionAddedState({required this.nonAcademicRecognition, required this.response});
@override
List<Object> get props => [nonAcademicRecognition,response];
}
////ADDING STATE
class AddNonAcademeRecognitionState extends NonAcademicRecognitionState{
final List<Agency> agencies;
final List<Category> agencyCategories;
const AddNonAcademeRecognitionState({required this.agencies, required this.agencyCategories});
@override
List<Object> get props => [agencies,agencyCategories];
}
////ERROR STATE
class NonAcademicRecognitionErrorState extends NonAcademicRecognitionState{
final String message;
const NonAcademicRecognitionErrorState({required this.message});

View File

@ -1,6 +1,10 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:unit2/model/profile/work_history.dart';
import 'package:unit2/model/utils/agency.dart';
import 'package:unit2/model/utils/category.dart';
import 'package:unit2/sevices/profile/orgmembership_services.dart';
import 'package:unit2/utils/profile_utilities.dart';
import '../../../../model/profile/other_information/organization_memberships.dart';
@ -8,17 +12,75 @@ part 'organization_membership_event.dart';
part 'organization_membership_state.dart';
class OrganizationMembershipBloc extends Bloc<OrganizationMembershipEvent, OrganizationMembershipState> {
List<Agency> agencies = [];
List<Category> agencyCategory = [];
OrganizationMembershipBloc() : super(OrganizationMembershipInitial()) {
List<OrganizationMembership> organizationMemberships=[];
on<GetOrganizationMembership>((event, emit) async{
emit(OrgmembershipLoadingState());
try{
List<OrganizationMembership> orgs = await OrganizationMembershipServices.instance.getOrgMemberships(event.profileId, event.token);
if(organizationMemberships.isEmpty){
List<OrganizationMembership> orgs = await OrganizationMembershipServices.instance.getOrgMemberships(event.profileId!, event.token!);
organizationMemberships = orgs;
}
emit(OrganizationMembershipLoaded(orgMemberships: organizationMemberships));
}catch(e){
OrganizationMembershipErrorState(message: e.toString());
}
});
on<LoadOrganizationMemberships>((event,emit){
emit(OrganizationMembershipLoaded(orgMemberships: event.organizationMemberships));
});
////SHOW ADD ORG MEMBERSHIP FORM
on<ShowAddOrgMembershipForm>((event,emit)async{
emit(OrgmembershipLoadingState());
try{
if(agencies.isEmpty){
List<Agency> newAgencies = await ProfileUtilities.instance.getAgecies();
agencies = newAgencies;
}
if(agencyCategory.isEmpty){
List<Category>newAgencyCategories = await ProfileUtilities.instance.agencyCategory();
agencyCategory = newAgencyCategories;
}
emit(AddOrgMembershipState(agencies: agencies, agencyCategories: agencyCategory));
}catch(e){
emit(OrganizationMembershipErrorState(message: e.toString()));
}
});
//// ADD ORGMEMBERSHIP
on<AddOrgMembership>((event,emit)async{
emit(OrgmembershipLoadingState());
try{
Map<dynamic,dynamic> status= await OrganizationMembershipServices.instance.add(agency: event.agency, token: event.token, profileId: event.profileId.toString());
if(status["success"]){
OrganizationMembership organizationMembership = OrganizationMembership.fromJson(status["data"]);
organizationMemberships.add(organizationMembership);
emit(OrgMembershipAddedState(orgMemberships: organizationMemberships, response: status));
}else{
emit(OrgMembershipAddedState(orgMemberships: organizationMemberships, response: status));
}
}catch(e){
emit(OrganizationMembershipErrorState(message: e.toString()));
}
});
////DELETE ORGMEMBERSHIP
on<DeleteOrgMemberShip>((event,emit)async{
emit(OrgmembershipLoadingState());
try{
final bool success = await OrganizationMembershipServices.instance.delete(agency: event.org.agency!, profileId: event.profileId, token: event.token);
if(success){
event.organizationMemberships.removeWhere((element) => element.agency!.id == event.org.agency!.id );
List<OrganizationMembership> orgmemberships = event.organizationMemberships;
emit(OrgMembershipDeletedState(organizationMemberships: orgmemberships, success: success));
}else{
emit(OrgMembershipDeletedState(organizationMemberships: organizationMemberships, success: success));
}
}catch(e){
emit(OrganizationMembershipErrorState(message: e.toString()));
}
});
}
}

View File

@ -7,10 +7,39 @@ abstract class OrganizationMembershipEvent extends Equatable {
List<Object> get props => [];
}
class LoadOrganizationMemberships extends OrganizationMembershipEvent{
final List<OrganizationMembership> organizationMemberships;
const LoadOrganizationMemberships({required this.organizationMemberships});
@override
List<Object> get props => [organizationMemberships];
}
class GetOrganizationMembership extends OrganizationMembershipEvent{
final int? profileId;
final String? token;
const GetOrganizationMembership({ this.profileId, this.token});
}
class ShowAddOrgMembershipForm extends OrganizationMembershipEvent{
}
class AddOrgMembership extends OrganizationMembershipEvent{
final int profileId;
final String token;
const GetOrganizationMembership({required this.profileId, required this.token});
final Agency agency;
const AddOrgMembership({required this.agency, required this.profileId, required this.token});
@override
List<Object> get props => [profileId,token];
List<Object> get props => [profileId,token,agency];
}
class DeleteOrgMemberShip extends OrganizationMembershipEvent{
final int profileId;
final String token;
final OrganizationMembership org;
final List<OrganizationMembership> organizationMemberships;
const DeleteOrgMemberShip({required this.profileId, required this.token, required this.org, required this.organizationMemberships});
@override
List<Object> get props => [profileId,token,org,organizationMemberships];
}

View File

@ -26,3 +26,23 @@ class OrganizationMembershipErrorState extends OrganizationMembershipState{
class OrgmembershipLoadingState extends OrganizationMembershipState{
}
class OrgMembershipDeletedState extends OrganizationMembershipState{
final List<OrganizationMembership> organizationMemberships;
final bool success;
const OrgMembershipDeletedState({required this.organizationMemberships, required this.success});
@override
List<Object> get props => [organizationMemberships,success];
}
class OrgMembershipAddedState extends OrganizationMembershipState{
final List<OrganizationMembership> orgMemberships;
final Map<dynamic,dynamic> response;
const OrgMembershipAddedState({required this.orgMemberships, required this.response});
@override
List<Object> get props => [orgMemberships,response];
}
class AddOrgMembershipState extends OrganizationMembershipState{
final List<Agency> agencies;
final List<Category> agencyCategories;
const AddOrgMembershipState({required this.agencies, required this.agencyCategories});
}

View File

@ -6,6 +6,7 @@ import 'package:unit2/model/utils/agency.dart';
import 'package:unit2/model/utils/agency_position.dart';
import 'package:unit2/model/utils/position.dart';
import 'package:unit2/sevices/profile/work_history_services.dart';
import 'package:unit2/utils/profile_utilities.dart';
import '../../../model/utils/category.dart';
@ -37,6 +38,7 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
workExperiences = event.workHistories;
emit(WorkHistoryLoaded(workExperiences: workExperiences));
});
////DELETE
on<DeleteWorkHistory>((event, emit) async {
emit(WorkHistoryLoadingState());
try {
@ -116,14 +118,14 @@ on<UpdateWorkHistory>((event, emit)async{
/////AGENCIES------------------------------------------
if (agencies.isEmpty) {
List<Agency> newAgencies =
await WorkHistoryService.instance.getAgecies();
await ProfileUtilities.instance.getAgecies();
agencies = newAgencies;
}
/////Category Agency------------------------------------------
if (agencyCategory.isEmpty) {
List<Category> categoryAgencies =
await WorkHistoryService.instance.agencyCategory();
await ProfileUtilities.instance.agencyCategory();
agencyCategory = categoryAgencies;
}
/////////-------------------------------------
@ -154,12 +156,12 @@ on<UpdateWorkHistory>((event, emit)async{
/////AGENCIES------------------------------------------
List<Agency> newAgencies =
await WorkHistoryService.instance.getAgecies();
await ProfileUtilities.instance.getAgecies();
agencies = newAgencies;
/////Category Agency------------------------------------------
List<Category> categoryAgencies =
await WorkHistoryService.instance.agencyCategory();
await ProfileUtilities.instance.agencyCategory();
agencyCategory = categoryAgencies;
/////////-------------------------------------
List<AppoinemtStatus> status =

View File

@ -4,7 +4,7 @@
import 'dart:convert';
import '../../utils/category.dart';
import 'package:unit2/model/utils/agency.dart';
NonAcademicRecognition nonAcademicRecognitionFromJson(String str) => NonAcademicRecognition.fromJson(json.decode(str));
@ -19,12 +19,12 @@ class NonAcademicRecognition {
final int? id;
final String? title;
final Presenter? presenter;
final Agency? presenter;
factory NonAcademicRecognition.fromJson(Map<String, dynamic> json) => NonAcademicRecognition(
id: json["id"],
title: json["title"],
presenter: json["presenter"] == null ? null : Presenter.fromJson(json["presenter"]),
presenter: json["presenter"] == null ? null : Agency.fromJson(json["presenter"]),
);
Map<String, dynamic> toJson() => {
@ -34,31 +34,4 @@ class NonAcademicRecognition {
};
}
class Presenter {
Presenter({
this.id,
this.name,
this.category,
this.privateEntity,
});
final int? id;
final String? name;
final Category? category;
final bool? privateEntity;
factory Presenter.fromJson(Map<String, dynamic> json) => Presenter(
id: json["id"],
name: json["name"],
category: json["category"] == null ? null : Category.fromJson(json["category"]),
privateEntity: json["private_entity"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"category": category?.toJson(),
"private_entity": privateEntity,
};
}

View File

@ -0,0 +1,343 @@
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:searchfield/searchfield.dart';
import 'package:unit2/bloc/profile/other_information/non_academic_recognition.dart/non_academic_recognition_bloc.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/model/profile/other_information/non_acedimic_recognition.dart';
import 'package:unit2/theme-data.dart/form-style.dart';
import 'package:unit2/utils/global.dart';
import '../../../../../model/utils/agency.dart';
import '../../../../../model/utils/category.dart';
import '../../../../../theme-data.dart/box_shadow.dart';
import '../../../../../theme-data.dart/btn-style.dart';
import '../../../../../theme-data.dart/colors.dart';
class AddNonAcademicRecognitionScreen extends StatefulWidget {
const AddNonAcademicRecognitionScreen({super.key});
@override
State<AddNonAcademicRecognitionScreen> createState() =>
_AddNonAcademicRecognitionScreenState();
}
class _AddNonAcademicRecognitionScreenState
extends State<AddNonAcademicRecognitionScreen> {
bool showAgencyCategory = false;
final agencyFocusNode = FocusNode();
final agencyCategoryFocusNode = FocusNode();
final addAgencyController = TextEditingController();
Agency? selectedAgency;
Category? selectedCategory;
Agency? newAgency;
bool showIsPrivateRadio = false;
bool? isPrivate = false;
NonAcademicRecognition? nonAcademicRecognition;
final _formKey = GlobalKey<FormBuilderState>();
int? profileId;
String? token;
@override
Widget build(BuildContext context) {
return BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoggedIn) {
return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) {
if (state is ProfileLoaded) {
return BlocBuilder<NonAcademicRecognitionBloc,
NonAcademicRecognitionState>(
builder: (context, state) {
if (state is AddNonAcademeRecognitionState) {
return SizedBox(
height: blockSizeVertical * 90,
child: SingleChildScrollView(
child: FormBuilder(child: Padding(
padding: const EdgeInsets.symmetric(vertical: 25,horizontal: 18),
child: Column(
children: [
FormBuilderTextField(name: 'title',
decoration: normalTextFieldStyle("Recognition / Award Title *", "Recognition / Award Title"),
validator: FormBuilderValidators.required(errorText: "this field is required"),
),
const SizedBox(height: 12,),
StatefulBuilder(
builder: (context, setState) {
//// AGENCY SEARCHFIELD
return Column(
children: [
SearchField(
itemHeight: 70,
suggestions: state.agencies
.map((Agency agency) =>
SearchFieldListItem(
agency.name!,
item: agency,
child: ListTile(
title: Text(
agency.name!
.toUpperCase(),
overflow:
TextOverflow
.ellipsis,
),
subtitle: Text(agency
.privateEntity ==
true
? "Private"
: agency.privateEntity ==
false
? "Government"
: ""),
)))
.toList(),
validator: FormBuilderValidators
.required(
errorText:
"This field is required"),
focusNode: agencyFocusNode,
searchInputDecoration:
normalTextFieldStyle(
"Agency *", "")
.copyWith(
suffixIcon:
const Icon(Icons
.arrow_drop_down)),
////agency suggestion tap
onSuggestionTap: (agency) {
setState(() {
selectedAgency = agency.item;
agencyFocusNode.unfocus();
if (selectedAgency
?.category ==
null) {
showAgencyCategory = true;
showIsPrivateRadio = true;
} else {
showAgencyCategory = false;
showIsPrivateRadio = false;
}
});
},
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(
//// Add agency onpressed
onPressed: () {
showDialog(
context:
context,
builder:
(BuildContext
context) {
return AlertDialog(
title: const Text(
"Add Agency?"),
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
onPressed: () {
setState(() {
newAgency = Agency(id: null, name: addAgencyController.text.toUpperCase(), category: null, privateEntity: null);
state.agencies.insert(0, newAgency!);
addAgencyController.clear();
Navigator.pop(context);
});
},
child: const Text("Add"))),
],
),
),
);
});
},
child: const Text(
"Add position"))
]),
),
),
const SizedBox(
height: 8,
),
SizedBox(
child: showAgencyCategory
? SearchField(
focusNode:
agencyCategoryFocusNode,
itemHeight: 70,
suggestions: state
.agencyCategories
.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 ...")),
),
////agency controller suggestion tap
onSuggestionTap:
(agencyCategory) {
setState(() {
selectedCategory =
agencyCategory
.item;
agencyCategoryFocusNode
.unfocus();
});
},
searchInputDecoration:
normalTextFieldStyle(
"Category *",
"")
.copyWith(
suffixIcon:
const Icon(
Icons
.arrow_drop_down)),
validator:
FormBuilderValidators
.required(
errorText:
"This field is required"),
)
: 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;
} else {
isPrivate = false;
}
});
},
name: 'isPrivate',
validator:
FormBuilderValidators
.required(
errorText:
"This field is required"),
options: ["YES", "NO"]
.map((lang) =>
FormBuilderFieldOption(
value:
lang))
.toList(
growable:
false),
)
: const SizedBox()),
],
);
})
],
),
)),
)
);
}
return Container();
},
);
}
return Container();
},
);
}
return Container();
},
);
}
}

View File

@ -4,6 +4,7 @@ import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/screens/profile/components/other_information/non_academic/add_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';
@ -20,12 +21,16 @@ class NonAcademicRecognitionScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
int? profileId;
String? token;
return Scaffold(
appBar: AppBar(
title: const Text(nonAcademicRecTitle),
centerTitle: true,
backgroundColor: primary,
actions: [AddLeading(onPressed: () {})],
actions: [AddLeading(onPressed: () {
context.read<NonAcademicRecognitionBloc>().add(ShowAddNonAcademeRecognitionForm());
})],
),
body: ProgressHUD(
padding: const EdgeInsets.all(24),
@ -34,6 +39,8 @@ class NonAcademicRecognitionScreen extends StatelessWidget {
child: BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoggedIn) {
token = state.userData!.user!.login!.token;
profileId = state.userData!.user!.login!.user!.profileId!;
return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) {
if (state is ProfileLoaded) {
@ -45,7 +52,7 @@ class NonAcademicRecognitionScreen extends StatelessWidget {
progress!.showWithText("Please wait...");
}
if (state is NonAcademicRecognitionLoadedState ||
state is NonAcademicRecognitionErrorState) {
state is NonAcademicRecognitionErrorState || state is AddNonAcademeRecognitionState) {
final progress = ProgressHUD.of(context);
progress!.dismiss();
}
@ -116,6 +123,8 @@ class NonAcademicRecognitionScreen extends StatelessWidget {
message:
"You don't have any Non Academic Recognition added. Please click + to add");
}
}if(state is AddNonAcademeRecognitionState){
return const AddNonAcademicRecognitionScreen();
}
return Container();
},

View File

@ -0,0 +1,373 @@
import 'package:flutter/material.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:searchfield/searchfield.dart';
import 'package:unit2/bloc/profile/other_information/org_membership/organization_membership_bloc.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/model/utils/agency.dart';
import 'package:unit2/utils/text_container.dart';
import '../../../../../model/utils/category.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 AddOrgMemberShipScreen extends StatefulWidget {
const AddOrgMemberShipScreen({super.key});
@override
State<AddOrgMemberShipScreen> createState() => _AddOrgMemberShipScreenState();
}
bool showAgencyCategory = false;
final agencyFocusNode = FocusNode();
final agencyCategoryFocusNode = FocusNode();
final addAgencyController = TextEditingController();
Agency? selectedAgency;
Category? selectedCategory;
Agency? newAgency;
bool showIsPrivateRadio = false;
bool? isPrivate = false;
final _formKey = GlobalKey<FormBuilderState>();
int? profileId;
String? token;
class _AddOrgMemberShipScreenState extends State<AddOrgMemberShipScreen> {
@override
Widget build(BuildContext context) {
return BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoggedIn) {
token = state.userData!.user!.login!.token;
profileId = state.userData!.user!.login!.user!.profileId;
return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) {
if (state is ProfileLoaded) {
return BlocBuilder<OrganizationMembershipBloc,
OrganizationMembershipState>(
builder: (context, state) {
if (state is AddOrgMembershipState) {
return SingleChildScrollView(
child: FormBuilder(
key: _formKey,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 25, horizontal: 18),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
const SizedBox(
height: 100,
),
StatefulBuilder(
builder: (context, setState) {
//// AGENCY SEARCHFIELD
return Column(
children: [
SearchField(
itemHeight: 70,
suggestions: state.agencies
.map((Agency agency) =>
SearchFieldListItem(
agency.name!,
item: agency,
child: ListTile(
title: Text(
agency.name!
.toUpperCase(),
overflow:
TextOverflow
.ellipsis,
),
subtitle: Text(agency
.privateEntity ==
true
? "Private"
: agency.privateEntity ==
false
? "Government"
: ""),
)))
.toList(),
validator: FormBuilderValidators
.required(
errorText:
"This field is required"),
focusNode: agencyFocusNode,
searchInputDecoration:
normalTextFieldStyle(
"Agency *", "")
.copyWith(
suffixIcon:
const Icon(Icons
.arrow_drop_down)),
////agency suggestion tap
onSuggestionTap: (agency) {
setState(() {
selectedAgency = agency.item;
agencyFocusNode.unfocus();
if (selectedAgency
?.category ==
null) {
showAgencyCategory = true;
showIsPrivateRadio = true;
} else {
showAgencyCategory = false;
showIsPrivateRadio = false;
}
});
},
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(
//// Add agency onpressed
onPressed: () {
showDialog(
context:
context,
builder:
(BuildContext
context) {
return AlertDialog(
title: const Text(
"Add Agency?"),
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
onPressed: () {
setState(() {
newAgency = Agency(id: null, name: addAgencyController.text.toUpperCase(), category: null, privateEntity: null);
state.agencies.insert(0, newAgency!);
addAgencyController.clear();
Navigator.pop(context);
});
},
child: const Text("Add"))),
],
),
),
);
});
},
child: const Text(
"Add position"))
]),
),
),
const SizedBox(
height: 8,
),
SizedBox(
child: showAgencyCategory
? SearchField(
focusNode:
agencyCategoryFocusNode,
itemHeight: 70,
suggestions: state
.agencyCategories
.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 ...")),
),
////agency controller suggestion tap
onSuggestionTap:
(agencyCategory) {
setState(() {
selectedCategory =
agencyCategory
.item;
agencyCategoryFocusNode
.unfocus();
});
},
searchInputDecoration:
normalTextFieldStyle(
"Category *",
"")
.copyWith(
suffixIcon:
const Icon(
Icons
.arrow_drop_down)),
validator:
FormBuilderValidators
.required(
errorText:
"This field is required"),
)
: 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;
} else {
isPrivate = false;
}
});
},
name: 'isPrivate',
validator:
FormBuilderValidators
.required(
errorText:
"This field is required"),
options: ["YES", "NO"]
.map((lang) =>
FormBuilderFieldOption(
value:
lang))
.toList(
growable:
false),
)
: const SizedBox()),
],
);
}),
////SHOW CATEGORY AGENCY
const SizedBox(
height: 24,
),
SizedBox(
height: 60,
width: double.infinity,
child: ElevatedButton(
style: mainBtnStyle(primary,
Colors.transparent, second),
onPressed: () {
if (_formKey.currentState!
.saveAndValidate()) {
if(selectedAgency?.privateEntity != null){
newAgency = selectedAgency;
}else{
newAgency = Agency(
id: selectedAgency?.id,
name: selectedAgency!.name,
category:
selectedCategory,
privateEntity: isPrivate);
}
context.read<OrganizationMembershipBloc>().add(AddOrgMembership(agency: newAgency!, profileId: profileId!, token: token!));
setState(() {
showAgencyCategory = false;
showIsPrivateRadio = false;
});
}
},
child: const Text(submit)),
)
]),
)),
);
}
return Container();
},
);
}
return Container();
},
);
}
return const Placeholder();
},
);
}
}

View File

@ -1,16 +1,21 @@
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/other_information/organization_memberships.dart';
import 'package:unit2/screens/profile/components/other_information/org_membership/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';
import 'package:unit2/widgets/Leadings/add_leading.dart';
import 'package:unit2/widgets/Leadings/close_leading.dart';
import 'package:unit2/widgets/empty_data.dart';
import '../../../../bloc/profile/other_information/org_membership/organization_membership_bloc.dart';
import '../../../../utils/alerts.dart';
import '../../../../utils/global.dart';
class OrgMembershipsScreen extends StatelessWidget {
@ -18,12 +23,22 @@ class OrgMembershipsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
String? token;
int profileId;
return Scaffold(
appBar: AppBar(
title: const Text(orgMembershipTitle),
backgroundColor: primary,
centerTitle: true,
actions: [AddLeading(onPressed: () {})],
actions: context.watch<OrganizationMembershipBloc>().state is OrganizationMembershipLoaded?[
AddLeading(onPressed: () {
context
.read<OrganizationMembershipBloc>()
.add(ShowAddOrgMembershipForm());
})
]: context.watch<OrganizationMembershipBloc>().state is AddOrgMembershipState ?[CloseLeading(onPressed: (){
context.read<OrganizationMembershipBloc>().add(const GetOrganizationMembership());
})]:[]
),
body: ProgressHUD(
padding: const EdgeInsets.all(24),
@ -32,6 +47,8 @@ class OrgMembershipsScreen extends StatelessWidget {
child: BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoggedIn) {
token = state.userData!.user!.login!.token;
profileId = state.userData!.user!.login!.user!.profileId!;
return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) {
if (state is ProfileLoaded) {
@ -42,10 +59,56 @@ class OrgMembershipsScreen extends StatelessWidget {
final progress = ProgressHUD.of(context);
progress!.showWithText("Please wait...");
}
if(state is OrganizationMembershipLoaded || state is OrganizationMembershipErrorState){
if (state is OrganizationMembershipLoaded ||
state is OrganizationMembershipErrorState ||
state is AddOrgMembershipState || state is OrgMembershipDeletedState) {
final progress = ProgressHUD.of(context);
progress!.dismiss();
}
////ADDED STATE
if (state is OrgMembershipAddedState) {
if (state.response['success']) {
successAlert(context, "Adding Successfull!",
state.response['message'], () {
Navigator.of(context).pop();
context.read<OrganizationMembershipBloc>().add(
LoadOrganizationMemberships(
organizationMemberships:
state.orgMemberships));
});
} else {
errorAlert(context, "Adding Failed",
"Something went wrong. Please try again.",
() {
Navigator.of(context).pop();
context.read<OrganizationMembershipBloc>().add(
LoadOrganizationMemberships(
organizationMemberships:
state.orgMemberships));
});
}
}
////DELETED STATE
if (state is OrgMembershipDeletedState) {
if (state.success) {
successAlert(context, "Deletion Successfull",
"Work has been deleted successfully", () {
Navigator.of(context).pop();
context.read<OrganizationMembershipBloc>().add(
LoadOrganizationMemberships(
organizationMemberships: state.organizationMemberships));
});
} else {
errorAlert(context, "Deletion Failed",
"Error deleting Work History", () {
Navigator.of(context).pop();
context.read<OrganizationMembershipBloc>().add(
LoadOrganizationMemberships(
organizationMemberships: state.organizationMemberships));
});
}
}
},
builder: (context, state) {
if (state is OrganizationMembershipLoaded) {
@ -55,8 +118,7 @@ class OrgMembershipsScreen extends StatelessWidget {
vertical: 8, horizontal: 10),
itemBuilder: (BuildContext context, int index) {
String entity = state.orgMemberships[index]
.agency!
.privateEntity ==
.agency!.privateEntity ==
false
? governmentText.toUpperCase()
: privateText.toUpperCase();
@ -95,12 +157,37 @@ class OrgMembershipsScreen extends StatelessWidget {
),
],
)),
IconButton(
onPressed: () {},
AppPopupMenu<int>(
offset: const Offset(-10, -10),
elevation: 3,
onSelected: (value) {
final progress =
ProgressHUD.of(context);
progress!
.showWithText("Loading...");
////delete orgmembership-= = = = = = = = =>>
if (value == 1) {
confirmAlert(context, () {
context.read<OrganizationMembershipBloc>().add(DeleteOrgMemberShip(profileId: profileId, token: token!, org: state.orgMemberships[index], organizationMemberships: state.orgMemberships));
}, "Delete?",
"Confirm Delete?");
}
},
menuItems: [
popMenuItem(
text: "Delete",
value: 1,
icon: Icons.delete),
],
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
))
),
tooltip: "Options",
)
]),
),
const SizedBox(
@ -110,6 +197,11 @@ class OrgMembershipsScreen extends StatelessWidget {
);
});
}
if (state is AddOrgMembershipState) {
return const AddOrgMemberShipScreen();
}if(state is OrganizationMembershipErrorState){
return Container(child: Text(state.message),);
}
return Container();
},
);
@ -124,5 +216,24 @@ class OrgMembershipsScreen extends StatelessWidget {
));
}
}
PopupMenuItem<int> popMenuItem({String? text, int? value, IconData? icon}) {
return PopupMenuItem(
value: value,
child: Row(
children: [
Icon(
icon,
),
const SizedBox(
width: 10,
),
Text(
text!,
),
],
),
);
}
// const EmptyData(message: "You don't have any Organization Membership added. Please click + to add."),

View File

@ -256,7 +256,7 @@ class _AddWorkHistoryScreenState extends State<AddWorkHistoryScreen> {
agency.privateEntity ==
true
? "Private"
: "Government"),
: agency.privateEntity == false? "Government":""),
)))
.toList(),
searchInputDecoration:

View File

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:unit2/bloc/profile/other_information/non_academic_recognition.dart/non_academic_recognition_bloc.dart';
import 'package:unit2/utils/request.dart';
import '../../model/profile/other_information/non_acedimic_recognition.dart';
@ -10,7 +11,7 @@ class NonAcademicRecognitionServices {
static final NonAcademicRecognitionServices _instance =
NonAcademicRecognitionServices();
static NonAcademicRecognitionServices get instance => _instance;
////GET
Future<List<NonAcademicRecognition>> getNonAcademicRecognition(
int profileId, String token) async {
List<NonAcademicRecognition> nonAcademicRecognitions = [];
@ -38,4 +39,71 @@ class NonAcademicRecognitionServices {
}
return nonAcademicRecognitions;
}
////ADD
Future<Map<dynamic, dynamic>> add(
{required String token,
required int profileId,
required NonAcademicRecognition nonAcademicRecognition}) async {
String authToken = "Token $token";
String path = "${Url.instance.getNonAcademicRecognition()}$profileId/";
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authToken
};
Map body = {
"title": nonAcademicRecognition.title,
"presenter_id": nonAcademicRecognition.presenter?.id,
"_presenterName": nonAcademicRecognition.presenter!.name,
"_presenterCatId": nonAcademicRecognition.presenter!.category!.id,
"_privateEntity": nonAcademicRecognition.presenter!.privateEntity,
};
Map<dynamic, dynamic> statusResponse = {};
try {
http.Response response = await Request.instance
.postRequest(path: path, body: body, param: {}, 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;
}
////DELETE
Future<bool> delete(
{required String title,
required int id,
required String token,
required int profileId}) async {
String authToken = "Token $token";
Map<String, dynamic> params = {"force_mode": "true"};
String path = "${Url.instance.getNonAcademicRecognition()}$profileId/";
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authToken
};
bool success = false;
Map body = {
"id": id,
"title": title,
};
try {
http.Response response = await Request.instance.deleteRequest(
path: path, headers: headers, body: body, param: params);
if (response.statusCode == 200) {
Map data = jsonDecode(response.body);
success = data['success'];
}
} catch (e) {
throw e.toString();
}
return success;
}
}

View File

@ -5,6 +5,7 @@ import 'package:unit2/utils/request.dart';
import '../../model/profile/other_information/organization_memberships.dart';
import 'package:http/http.dart' as http;
import '../../model/utils/agency.dart';
import '../../utils/urls.dart';
class OrganizationMembershipServices {
@ -39,4 +40,56 @@ class OrganizationMembershipServices {
}
return orgMemberships;
}
Future<Map<dynamic,dynamic>>add({required Agency? agency,required String token, required String profileId})async{
String authToken = "Token $token";
String path = "${Url.instance.getOrgMemberShips()}$profileId/";
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authToken
};
Map<dynamic,dynamic> statusResponse = {};
Map body = {
"agency_id": agency?.id,
"_agencyName": agency!.name,
"_agencyCatId": agency.category!.id,
"_privateEntity": agency.privateEntity
};
try{
http.Response response = await Request.instance.postRequest(path: path,body: body,headers: headers,param: {});
if(response.statusCode == 201){
Map data = jsonDecode(response.body);
statusResponse = data;
}else{
statusResponse.addAll({"success":false});
}
}catch(e){
throw e.toString();
}
return statusResponse;
}
Future<bool> delete({required Agency agency, required int profileId, required String token})async{
bool success = false;
Map<String, dynamic> params = {"force_mode": "true"};
String authToken = "Token $token";
String path = "${Url.instance.getOrgMemberShips()}$profileId/";
Map body ={
"agency_id": agency.id
};
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authToken
};
try{
http.Response response = await Request.instance.deleteRequest(path: path, headers: headers, body: body, param: params);
if(response.statusCode == 200){
Map data = jsonDecode(response.body);
success = data["success"];
}
}catch(e){
throw e.toString();
}
return success;
}
}

View File

@ -42,30 +42,6 @@ class WorkHistoryService {
return workExperiences;
}
//get agencies
Future<List<Agency>> getAgecies() async {
List<Agency> agencies = [];
String path = Url.instance.getAgencies();
Map<String, String> 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 agency) {
Agency newAgency = Agency.fromJson(agency);
agencies.add(newAgency);
});
}
}
} catch (e) {
throw e.toString();
}
return agencies;
}
//delete workhistory
Future<bool> delete(
@ -107,30 +83,6 @@ class WorkHistoryService {
return success!;
}
//get agency category
Future<List<Category>> agencyCategory() async {
List<Category> agencyCategory = [];
String path = Url.instance.getAgencyCategory();
Map<String, String> 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 agency) {
Category category = Category.fromJson(agency);
agencyCategory.add(category);
});
}
}
} catch (e) {
throw e.toString();
}
return agencyCategory;
}
//edit work history
Future<Map<dynamic,dynamic>> update({required WorkHistory oldWorkHistory, required WorkHistory newWorkHistory, required String token, required String profileId})async{

View File

@ -7,6 +7,9 @@ import 'package:unit2/model/location/region.dart';
import 'package:unit2/model/utils/eligibility.dart';
import 'package:unit2/utils/request.dart';
import 'package:unit2/utils/urls.dart';
import '../model/utils/agency.dart';
import '../model/utils/category.dart';
class ProfileUtilities {
static final ProfileUtilities _instance = ProfileUtilities();
static ProfileUtilities get instance => _instance;
@ -35,4 +38,56 @@ class ProfileUtilities {
return eligibilities;
}
//get agencies
Future<List<Agency>> getAgecies() async {
List<Agency> agencies = [];
String path = Url.instance.getAgencies();
Map<String, String> 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 agency) {
Agency newAgency = Agency.fromJson(agency);
agencies.add(newAgency);
});
}
}
} catch (e) {
throw e.toString();
}
return agencies;
}
//get agency category
Future<List<Category>> agencyCategory() async {
List<Category> agencyCategory = [];
String path = Url.instance.getAgencyCategory();
Map<String, String> 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 agency) {
Category category = Category.fromJson(agency);
agencyCategory.add(category);
});
}
}
} catch (e) {
throw e.toString();
}
return agencyCategory;
}
}

View File

@ -4,10 +4,10 @@ class Url {
String host() {
// return '192.168.10.221:3003';
return 'agusandelnorte.gov.ph';
// return 'agusandelnorte.gov.ph';
// return "192.168.10.219:3000";
// return "devweb.agusandelnorte.gov.ph";
// return 'devapi.agusandelnorte.gov.ph:3004';
return 'devapi.agusandelnorte.gov.ph:3004';
}
String authentication() {