From 9a8867d356ab0eb8a2b8df191e5b5faf69292482 Mon Sep 17 00:00:00 2001 From: "Deepak Pradhan (Varun)" <37866666+varun2948@users.noreply.github.com> Date: Tue, 20 Feb 2024 16:45:35 +0545 Subject: [PATCH] feat (frontend,backend): my organisations tab implemented (#1227) * feat: my organisations api route added * feat: get my organisation function * feat: added get organisation api service * feat: organisationGridCard Component created * feat: Type added to organisation slice * Feat: My organisation tab for data fetching * refactor: remove missed print statement --------- Co-authored-by: spwoodcock --- .../app/organisations/organisation_crud.py | 19 +++++ .../app/organisations/organisation_routes.py | 11 +++ src/frontend/src/api/OrganisationService.ts | 16 ++++ .../organisation/OrganisationGridCard.tsx | 53 +++++++++++++ .../src/store/slices/organisationSlice.ts | 50 +++++++----- src/frontend/src/store/types/IOrganisation.ts | 23 ++++++ src/frontend/src/views/Organisation.tsx | 79 +++++++------------ 7 files changed, 179 insertions(+), 72 deletions(-) create mode 100644 src/frontend/src/components/organisation/OrganisationGridCard.tsx create mode 100644 src/frontend/src/store/types/IOrganisation.ts diff --git a/src/backend/app/organisations/organisation_crud.py b/src/backend/app/organisations/organisation_crud.py index f3e5e1b1e9..7fee72ac84 100644 --- a/src/backend/app/organisations/organisation_crud.py +++ b/src/backend/app/organisations/organisation_crud.py @@ -139,6 +139,25 @@ async def get_organisations( return db.query(db_models.DbOrganisation).filter_by(approved=True).all() +async def get_my_organisations( + db: Session, + current_user: AuthUser, +) -> list[db_models.DbOrganisation]: + """Get organisations filtered by the current user. + + Args: + db (Session): The database session. + current_user (AuthUser): The current user. + + Returns: + list[db_models.DbOrganisation]: A list of organisations + filtered by the current user. + """ + db_user = await get_user(db, current_user.id) + + return db_user.organisations + + async def get_unapproved_organisations( db: Session, ) -> list[db_models.DbOrganisation]: diff --git a/src/backend/app/organisations/organisation_routes.py b/src/backend/app/organisations/organisation_routes.py index 1c31a11ccd..ac81331a62 100644 --- a/src/backend/app/organisations/organisation_routes.py +++ b/src/backend/app/organisations/organisation_routes.py @@ -51,6 +51,17 @@ async def get_organisations( return await organisation_crud.get_organisations(db, current_user) +@router.get( + "/my-organisations", response_model=list[organisation_schemas.OrganisationOut] +) +async def get_my_organisations( + db: Session = Depends(database.get_db), + current_user: AuthUser = Depends(login_required), +) -> list[DbOrganisation]: + """Get a list of all organisations.""" + return await organisation_crud.get_my_organisations(db, current_user) + + @router.get("/unapproved/", response_model=list[organisation_schemas.OrganisationOut]) async def list_unapproved_organisations( db: Session = Depends(database.get_db), diff --git a/src/frontend/src/api/OrganisationService.ts b/src/frontend/src/api/OrganisationService.ts index b60e5805b3..5ebb841207 100644 --- a/src/frontend/src/api/OrganisationService.ts +++ b/src/frontend/src/api/OrganisationService.ts @@ -55,6 +55,22 @@ export const OrganisationDataService: Function = (url: string) => { }; }; +export const MyOrganisationDataService: Function = (url: string) => { + return async (dispatch) => { + dispatch(OrganisationAction.GetMyOrganisationDataLoading(true)); + const getMyOrganisationData = async (url) => { + try { + const getMyOrganisationDataResponse = await API.get(url); + const response: GetOrganisationDataModel[] = getMyOrganisationDataResponse.data; + dispatch(OrganisationAction.GetMyOrganisationsData(response)); + } catch (error) { + dispatch(OrganisationAction.GetMyOrganisationDataLoading(false)); + } + }; + await getMyOrganisationData(url); + }; +}; + export const PostOrganisationDataService: Function = (url: string, payload: any) => { return async (dispatch) => { dispatch(OrganisationAction.SetOrganisationFormData({})); diff --git a/src/frontend/src/components/organisation/OrganisationGridCard.tsx b/src/frontend/src/components/organisation/OrganisationGridCard.tsx new file mode 100644 index 0000000000..59c8252c0e --- /dev/null +++ b/src/frontend/src/components/organisation/OrganisationGridCard.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import CoreModules from '@/shared/CoreModules'; +import CustomizedImage from '@/utilities/CustomizedImage'; + +const OrganisationGridCard = ({ filteredData, allDataLength }) => { + const cardStyle = { + padding: '20px', + display: 'flex', + flexDirection: 'row', + cursor: 'pointer', + gap: '20px', + boxShadow: 'none', + borderRadius: '0px', + }; + return ( +
+

+ Showing {filteredData?.length} of {allDataLength} organizations +

+
+ {filteredData?.map((data, index) => ( + + {data.logo ? ( +
+ +
+ ) : ( +
+ +
+ )} + + +

+ {data.name} +

+

+ {data.description} +

+
+
+ ))} +
+
+ ); +}; +export default OrganisationGridCard; diff --git a/src/frontend/src/store/slices/organisationSlice.ts b/src/frontend/src/store/slices/organisationSlice.ts index d755196abd..cd98e10e2e 100644 --- a/src/frontend/src/store/slices/organisationSlice.ts +++ b/src/frontend/src/store/slices/organisationSlice.ts @@ -1,33 +1,43 @@ import CoreModules from '@/shared/CoreModules.js'; +import { IOrganisationState } from '../types/IOrganisation'; +const initialState: IOrganisationState = { + organisationFormData: {}, + organisationData: [], + myOrganisationData: [], + postOrganisationData: null, + organisationDataLoading: false, + myOrganisationDataLoading: false, + postOrganisationDataLoading: false, + consentDetailsFormData: { + give_consent: '', + review_documentation: [], + log_into: [], + participated_in: [], + }, + consentApproval: false, + organizationApprovalStatus: { + isSuccess: false, + organizationApproving: false, + organizationRejecting: false, + }, +}; const OrganisationSlice = CoreModules.createSlice({ name: 'organisation', - initialState: { - organisationFormData: {}, - organisationData: [], - postOrganisationData: null, - organisationDataLoading: false, - postOrganisationDataLoading: false, - consentDetailsFormData: { - give_consent: '', - review_documentation: [], - log_into: [], - participated_in: [], - }, - consentApproval: false, - organizationApprovalStatus: { - isSuccess: false, - organizationApproving: false, - organizationRejecting: false, - }, - }, + initialState: initialState, reducers: { GetOrganisationsData(state, action) { - state.oraganizationData = action.payload; + state.organisationData = action.payload; }, GetOrganisationDataLoading(state, action) { state.organisationDataLoading = action.payload; }, + GetMyOrganisationsData(state, action) { + state.myOrganisationData = action.payload; + }, + GetMyOrganisationDataLoading(state, action) { + state.myOrganisationDataLoading = action.payload; + }, postOrganisationData(state, action) { state.postOrganisationData = action.payload; }, diff --git a/src/frontend/src/store/types/IOrganisation.ts b/src/frontend/src/store/types/IOrganisation.ts new file mode 100644 index 0000000000..9dc4f1d1e8 --- /dev/null +++ b/src/frontend/src/store/types/IOrganisation.ts @@ -0,0 +1,23 @@ +import { GetOrganisationDataModel } from '@/models/organisation/organisationModel'; + +export interface IOrganisationState { + organisationFormData: any; + organisationData: GetOrganisationDataModel[]; + myOrganisationData: GetOrganisationDataModel[]; + postOrganisationData: any; + organisationDataLoading: Boolean; + postOrganisationDataLoading: Boolean; + myOrganisationDataLoading: false; + consentDetailsFormData: { + give_consent: any; + review_documentation: any; + log_into: any; + participated_in: any; + }; + consentApproval: Boolean; + organizationApprovalStatus: { + isSuccess: Boolean; + organizationApproving: Boolean; + organizationRejecting: Boolean; + }; +} diff --git a/src/frontend/src/views/Organisation.tsx b/src/frontend/src/views/Organisation.tsx index d0eadd7cba..bc2bc97182 100644 --- a/src/frontend/src/views/Organisation.tsx +++ b/src/frontend/src/views/Organisation.tsx @@ -1,23 +1,13 @@ import React, { useEffect, useState } from 'react'; import CoreModules from '@/shared/CoreModules'; import AssetModules from '@/shared/AssetModules'; -import { OrganisationDataService } from '@/api/OrganisationService'; +import { MyOrganisationDataService, OrganisationDataService } from '@/api/OrganisationService'; import { user_roles } from '@/types/enums'; -import CustomizedImage from '@/utilities/CustomizedImage'; import { GetOrganisationDataModel } from '@/models/organisation/organisationModel'; +import OrganisationGridCard from '@/components/organisation/OrganisationGridCard'; import { useNavigate } from 'react-router-dom'; const Organisation = () => { - const cardStyle = { - padding: '20px', - display: 'flex', - flexDirection: 'row', - cursor: 'pointer', - gap: '20px', - boxShadow: 'none', - borderRadius: '0px', - }; - const navigate = useNavigate(); const [searchKeyword, setSearchKeyword] = useState(''); @@ -31,13 +21,21 @@ const Organisation = () => { const dispatch = CoreModules.useAppDispatch(); - const oraganizationData: GetOrganisationDataModel[] = CoreModules.useAppSelector( - (state) => state.organisation.oraganizationData, + const organisationData: GetOrganisationDataModel[] = CoreModules.useAppSelector( + (state) => state.organisation.organisationData, ); - const filteredCardData: GetOrganisationDataModel[] = oraganizationData?.filter((data) => - data.name.toLowerCase().includes(searchKeyword.toLowerCase()), + const myOrganisationData: GetOrganisationDataModel[] = CoreModules.useAppSelector( + (state) => state.organisation.myOrganisationData, ); - + const filteredBySearch = (data, searchKeyword) => { + const filteredCardData: GetOrganisationDataModel[] = data?.filter((d) => + d.name.toLowerCase().includes(searchKeyword.toLowerCase()), + ); + return filteredCardData; + }; + useEffect(() => { + dispatch(MyOrganisationDataService(`${import.meta.env.VITE_API_URL}/organisation/my-organisations`)); + }, []); useEffect(() => { if (verifiedTab) { dispatch(OrganisationDataService(`${import.meta.env.VITE_API_URL}/organisation/`)); @@ -179,41 +177,18 @@ const Organisation = () => { className="fmtm-min-w-[14rem] lg:fmtm-w-[20%]" /> -
-

- Showing {filteredCardData?.length} of {oraganizationData?.length} organizations -

-
- - {filteredCardData?.map((data, index) => ( - !verifiedTab && approveOrganization(data.id)}> - {data.logo ? ( -
- -
- ) : ( -
- -
- )} - - -

- {data.name} -

-

- {data.description} -

-
-
- ))} -
+ {activeTab === 0 ? ( + + ) : null} + {activeTab === 1 ? ( + + ) : null} ); };