Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat create edit organization #1178

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9e00e6b
feat createEditOrganization: routes/header setup
NSUWAL123 Feb 5, 2024
7557377
feat createEditOrganization: conditionally showing consent/createEdit…
NSUWAL123 Feb 5, 2024
35e94f3
fix createEditOrganizationHeader: component renamed
NSUWAL123 Feb 6, 2024
5adf5b3
feat consentQuestions: consent questions schema setup in constants
NSUWAL123 Feb 6, 2024
e49f4c8
feat consentDetailsForm: leftSide container UI add
NSUWAL123 Feb 6, 2024
65d5dfa
feat checkbox: custom radixUI checkbox component add
NSUWAL123 Feb 6, 2024
3658856
fix radioButton: className prop add to radioButton
NSUWAL123 Feb 6, 2024
c560748
fix consentQuestions: questions update
NSUWAL123 Feb 6, 2024
8dfde6c
fix button: hover effect added to btn type other
NSUWAL123 Feb 6, 2024
5fdaba8
fix checkBox: UI fix
NSUWAL123 Feb 6, 2024
b9f22cd
feat consentDetailsForm: UI complete
NSUWAL123 Feb 6, 2024
d49e004
feat consentDetailsForm: useForm integration & validations add
NSUWAL123 Feb 6, 2024
8eb9d57
fix createEditOrganizationForm: organizationId props pass
NSUWAL123 Feb 6, 2024
3adb6f7
fix RadioButton: required prop added
NSUWAL123 Feb 6, 2024
dc84e02
fix inputTextField: sublabel add
NSUWAL123 Feb 6, 2024
193728f
feat createEditOrganizationForm: form UI & validation complete
NSUWAL123 Feb 6, 2024
40506b5
fix inputTextField: subLabel update
NSUWAL123 Feb 6, 2024
91b0e4b
fix consentQuestions: redirection links added
NSUWAL123 Feb 7, 2024
91e8714
fix organizationForm: post create organization detail
NSUWAL123 Feb 7, 2024
9e90dc4
feat editOrganizationForm: individualOrganization api fetch
NSUWAL123 Feb 7, 2024
6c5cc1a
feat organizationForm: patch organizationData on update
NSUWAL123 Feb 7, 2024
8b50ddc
fix organizationForm: naming change
NSUWAL123 Feb 7, 2024
4cc6b0e
fix organization: instructions updated & seperated to another component
NSUWAL123 Feb 7, 2024
ec3708a
fix manageOrganization: hide profile, org_type, osm_profile fields fo…
NSUWAL123 Feb 7, 2024
626edd6
Merge branch 'development' of github.com:hotosm/fmtm into feat-create…
NSUWAL123 Feb 7, 2024
feeca06
fix projectDetails: dowloadOptions open/close issue fix
NSUWAL123 Feb 7, 2024
75d16a5
feat approveOrganization: UI complete
NSUWAL123 Feb 7, 2024
85412f5
fix organizationService: loading state false
NSUWAL123 Feb 7, 2024
e8e57fc
fix createEditOrganizationForm: osm_profile remove from form
NSUWAL123 Feb 7, 2024
cdea525
Merge branch 'development' of github.com:hotosm/fmtm into feat-create…
NSUWAL123 Feb 7, 2024
0b8be89
fix createEditOrganizationForm: filedType changed to password
NSUWAL123 Feb 7, 2024
cd36dc8
feat userRole: userRole set to localStorage
NSUWAL123 Feb 8, 2024
2f6bcf3
fix manageOrganizations: UI fix, verified show/hide based on userRoles
NSUWAL123 Feb 8, 2024
d7445ed
fix manageOrganization: UI update
NSUWAL123 Feb 8, 2024
3c5ee08
fix organizationDetailsValidation: osmProfile removed
NSUWAL123 Feb 8, 2024
039b37c
fix createEditOrganization: clear consentForm state on organization c…
NSUWAL123 Feb 8, 2024
cfa55c0
feat approveOrganization: approve api hit on verify click
NSUWAL123 Feb 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@mui/lab": "^5.0.0-alpha.134",
"@mui/material": "^5.14.12",
"@mui/system": "^5.14.12",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-select": "^1.2.2",
Expand Down
31 changes: 31 additions & 0 deletions src/frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

92 changes: 89 additions & 3 deletions src/frontend/src/api/OrganisationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,110 @@ export const PostOrganisationDataService: Function = (url: string, payload: any)
dispatch(
CommonActions.SetSnackBar({
open: true,
message: 'Organization Successfully Created.',
message: 'Organization Request Submitted.',
variant: 'success',
duration: 2000,
}),
);
} catch (error: any) {
dispatch(OrganisationAction.PostOrganisationDataLoading(false));
dispatch(
CommonActions.SetSnackBar({
open: true,
message: error.response.data.detail,
message: error.response.data.detail || 'Failed to create organization.',
variant: 'error',
duration: 2000,
}),
);
dispatch(OrganisationAction.PostOrganisationDataLoading(false));
}
};

await postOrganisationData(url, payload);
};
};

export const GetIndividualOrganizationService: Function = (url: string) => {
return async (dispatch) => {
const getOrganisationData = async (url) => {
try {
const getOrganisationDataResponse = await axios.get(url);
const response: GetOrganisationDataModel = getOrganisationDataResponse.data;
dispatch(OrganisationAction.SetIndividualOrganization(response));
} catch (error) {}
};
await getOrganisationData(url);
};
};

export const PatchOrganizationDataService: Function = (url: string, payload: any) => {
return async (dispatch) => {
dispatch(OrganisationAction.PostOrganisationDataLoading(true));

const patchOrganisationData = async (url, payload) => {
dispatch(OrganisationAction.SetOrganisationFormData(payload));

try {
const generateApiFormData = new FormData();
appendObjectToFormData(generateApiFormData, payload);

const patchOrganisationData = await axios.patch(url, payload, {
headers: {
'Content-Type': 'multipart/form-data',
},
});

const resp: HomeProjectCardModel = patchOrganisationData.data;
dispatch(OrganisationAction.PostOrganisationDataLoading(false));
dispatch(OrganisationAction.postOrganisationData(resp));
dispatch(
CommonActions.SetSnackBar({
open: true,
message: 'Organization Updated Successfully.',
variant: 'success',
duration: 2000,
}),
);
} catch (error: any) {
dispatch(OrganisationAction.PostOrganisationDataLoading(false));
dispatch(
CommonActions.SetSnackBar({
open: true,
message: error.response.data.detail || 'Failed to update organization.',
variant: 'error',
duration: 2000,
}),
);
}
};

await patchOrganisationData(url, payload);
};
};

export const ApproveOrganizationService: Function = (url: string, organizationId: string) => {
return async (dispatch) => {
const approveOrganization = async (url) => {
try {
await axios.post(url, organizationId);
dispatch(
CommonActions.SetSnackBar({
open: true,
message: 'Organization approved successfully.',
variant: 'success',
duration: 2000,
}),
);
} catch (error) {
dispatch(
CommonActions.SetSnackBar({
open: true,
message: 'Failed to approve organization.',
variant: 'error',
duration: 2000,
}),
);
}
};
await approveOrganization(url);
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import AssetModules from '@/shared/AssetModules.js';
import { useNavigate } from 'react-router-dom';

const ApproveOrganizationHeader = () => {
const navigate = useNavigate();
return (
<div className="fmtm-px-5 fmtm-border-b-white fmtm-border-[1px] fmtm-bg-[#F5F5F5]">
<div className="fmtm-flex fmtm-justify-between fmtm-items-center">
<div className="fmtm-pt-3 fmtm-pb-1">
<h1 className="sm:fmtm-text-xl md:fmtm-text-2xl">APPROVE ORGANIZATION</h1>
</div>
<div
className="hover:fmtm-bg-gray-200 fmtm-rounded-full fmtm-p-2 fmtm-duration-300 fmtm-cursor-pointer"
onClick={() => navigate('/organisation')}
>
<AssetModules.CloseIcon />
</div>
</div>
</div>
);
};

export default ApproveOrganizationHeader;
107 changes: 107 additions & 0 deletions src/frontend/src/components/ApproveOrganization/OrganizationForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';
import InputTextField from '@/components/common/InputTextField';
import TextArea from '@/components/common/TextArea';
import Button from '@/components/common/Button';
import { ApproveOrganizationService, GetIndividualOrganizationService } from '@/api/OrganisationService';
import CoreModules from '@/shared/CoreModules';

const OrganizationForm = () => {
const dispatch = useDispatch();
const params = useParams();
const organizationId = params.id;
const organisationFormData: any = CoreModules.useAppSelector((state) => state.organisation.organisationFormData);

useEffect(() => {
if (organizationId) {
dispatch(GetIndividualOrganizationService(`${import.meta.env.VITE_API_URL}/organisation/${organizationId}`));
}
}, [organizationId]);

const approveOrganization = () => {
dispatch(
ApproveOrganizationService(`${import.meta.env.VITE_API_URL}/organisation/approve`, { org_id: organizationId }),
);
};

return (
<div className="fmtm-max-w-[50rem] fmtm-bg-white fmtm-py-5 lg:fmtm-py-10 fmtm-px-5 lg:fmtm-px-9 fmtm-mx-auto">
<div className="fmtm-flex fmtm-justify-center">
<h5 className="fmtm-text-[#484848] fmtm-text-2xl fmtm-font-[600] fmtm-pb-3 lg:fmtm-pb-7 fmtm-font-archivo fmtm-tracking-wide">
Organizational Details
</h5>
</div>
<div className="fmtm-flex fmtm-flex-col fmtm-gap-6">
<InputTextField
id="name"
name="name"
label="Community or Organization Name"
value={organisationFormData?.name}
onChange={() => {}}
fieldType="text"
/>
<InputTextField
id="email"
name="email"
label="Email"
value={organisationFormData?.email}
onChange={() => {}}
fieldType="text"
/>
<InputTextField
id="url"
name="url"
label="Website URL"
value={organisationFormData?.url}
onChange={() => {}}
fieldType="text"
/>
<TextArea
id="description"
name="description"
label="Description"
rows={3}
value={organisationFormData?.description}
onChange={() => {}}
/>
<InputTextField
id="odk_central_url"
name="odk_central_url"
label="ODK Central URL "
value={organisationFormData?.odk_central_url}
onChange={() => {}}
fieldType="text"
/>
<InputTextField
id="url"
name="url"
label="Community or Organization are you applied for? "
value={organisationFormData?.organization_type}
onChange={() => {}}
fieldType="text"
/>
<div>
<p className="fmtm-text-[1rem] fmtm-font-semibold fmtm-mb-2">Logo</p>
{organisationFormData?.logo ? (
<div>
<img
src={organisationFormData?.logo}
alt=""
className="fmtm-h-[100px] fmtm-rounded-sm fmtm-border-[1px]"
/>
</div>
) : (
<p className="fmtm-ml-3">-</p>
)}
</div>
</div>
<div className="fmtm-flex fmtm-items-center fmtm-justify-center fmtm-gap-6 fmtm-mt-8 lg:fmtm-mt-16">
<Button btnText="Reject" btnType="other" className="fmtm-font-bold" onClick={() => {}} />
<Button btnText="Verify" btnType="primary" className="fmtm-font-bold" onClick={approveOrganization} />
</div>
</div>
);
};

export default OrganizationForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useState } from 'react';
import { consentQuestions } from '@/constants/ConsentQuestions';
import { CustomCheckbox } from '@/components/common/Checkbox';
import RadioButton from '@/components/common/RadioButton';
import Button from '@/components/common/Button';
import useForm from '@/hooks/useForm';
import CoreModules from '@/shared/CoreModules';
import ConsentDetailsValidation from '@/components/CreateEditOrganization/validation/ConsentDetailsValidation';
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { OrganisationAction } from '@/store/slices/organisationSlice';
import InstructionsSidebar from '@/components/CreateEditOrganization/InstructionsSidebar';

const ConsentDetailsForm = () => {
const navigate = useNavigate();
const dispatch = useDispatch();

const consentDetailsFormData: any = CoreModules.useAppSelector((state) => state.organisation.consentDetailsFormData);

const submission = () => {
dispatch(OrganisationAction.SetConsentApproval(true));
dispatch(OrganisationAction.SetConsentDetailsFormData(values));
};

const { handleSubmit, handleCustomChange, values, errors }: any = useForm(
consentDetailsFormData,
submission,
ConsentDetailsValidation,
);

return (
<div className="fmtm-flex fmtm-flex-col lg:fmtm-flex-row fmtm-gap-5 lg:fmtm-gap-10">
<InstructionsSidebar />
<div className="fmtm-bg-white lg:fmtm-w-[70%] xl:fmtm-w-[55rem] fmtm-py-5 lg:fmtm-py-10 fmtm-px-5 lg:fmtm-px-9">
<h5 className="fmtm-text-[#484848] fmtm-text-2xl fmtm-font-[600] fmtm-pb-3 lg:fmtm-pb-7 fmtm-font-archivo fmtm-tracking-wide">
Consent Details
</h5>
<div className="fmtm-flex fmtm-flex-col fmtm-gap-6">
{consentQuestions.map((question) => (
<div key={question.id}>
<div className="fmtm-mb-3 fmtm-flex fmtm-flex-col">
<h6 className="fmtm-text-lg">
{question.question} {question.required && <span className="fmtm-text-red-500">*</span>}
</h6>
{question.description && (
<p className="fmtm-text-[#7A7676] fmtm-font-archivo fmtm-text-base">{question.description}</p>
)}
</div>
{question.type === 'radio' ? (
<RadioButton
options={question.options}
direction="column"
value={values[question.id]}
onChangeData={(value) => {
handleCustomChange(question.id, value);
}}
className="fmtm-font-archivo fmtm-text-base fmtm-text-[#7A7676] fmtm-mt-1"
errorMsg={errors.give_consent}
/>
) : (
<div className="fmtm-flex fmtm-flex-col fmtm-gap-2">
{question.options.map((option) => (
<CustomCheckbox
key={option.id}
label={option.label}
checked={values[question.id].includes(option.id)}
onCheckedChange={(checked) => {
return checked
? handleCustomChange(question.id, [...values[question.id], option.id])
: handleCustomChange(
question.id,
values[question.id].filter((value) => value !== option.id),
);
}}
/>
))}
{errors[question.id] && <p className="fmtm-text-red-500 fmtm-text-sm">{errors[question.id]}</p>}
</div>
)}
</div>
))}
</div>

<div className="fmtm-flex fmtm-items-center fmtm-justify-center fmtm-gap-6 fmtm-mt-8 lg:fmtm-mt-16">
<Button
btnText="Cancel"
btnType="other"
className="fmtm-font-bold"
onClick={() => navigate('/organisation')}
/>
<Button btnText="NEXT" btnType="primary" className="fmtm-font-bold" onClick={handleSubmit} />
</div>
</div>
</div>
);
};

export default ConsentDetailsForm;
Loading
Loading