Skip to content

Commit

Permalink
Add option to "Read and Agree" with mentor and mentee guides at the a…
Browse files Browse the repository at this point in the history
…pplication process (#190)

Co-authored-by: Anjula Shanaka <[email protected]>
  • Loading branch information
Madhawa97 and anjula-sack authored Oct 5, 2024
1 parent 021ab78 commit e56a4e1
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 41 deletions.
24 changes: 24 additions & 0 deletions src/assets/svg/Icons/OpenIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';

const OpenIcon: React.FC = () => {
return (
<div>
<svg
className="h-5 w-5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="none"
>
<path
className="stroke-gray-500"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M10 4H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4m-8-2 8-8m0 0v5m0-5h-5"
/>
</svg>
</div>
);
};

export default OpenIcon;
165 changes: 165 additions & 0 deletions src/components/TermsAgreementModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import React from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import Tooltip from '../Tooltip';
import OpenIcon from '../../assets/svg/Icons/OpenIcon';
import {
menteeTermsAgreementModalSchema,
mentorTermsAgreementModalSchema,
} from '../../schemas';

type MentorFormData = z.infer<typeof mentorTermsAgreementModalSchema>;
type MenteeFormData = z.infer<typeof menteeTermsAgreementModalSchema>;

interface TermsAgreementModalProps {
isOpen: boolean;
onClose: () => void;
onAgree: (data: MentorFormData | MenteeFormData) => void;
isMentor: boolean;
guideUrl: string;
}

const TermsAgreementModal: React.FC<TermsAgreementModalProps> = ({
isOpen,
onClose,
onAgree,
isMentor,
guideUrl,
}) => {
const schema = isMentor
? mentorTermsAgreementModalSchema
: menteeTermsAgreementModalSchema;
const {
register,
handleSubmit,
formState: { errors, isValid },
} = useForm({
resolver: zodResolver(schema),
mode: 'onChange',
defaultValues: isMentor
? { agreed: false, canCommit: false }
: { agreed: false, consentGiven: false },
});

const onSubmit = (data: MentorFormData | MenteeFormData) => {
if (isValid) {
onAgree(data);
} else {
console.error('Form is invalid. Errors:', errors);
}
};

if (!isOpen) return null;

const guideType = isMentor ? 'Mentor' : 'Mentee';
const title = isMentor
? 'One Last Step to Join as a ScholarX Mentor'
: 'ScholarX Mentee Terms and Privacy';

return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div className="bg-white rounded-lg shadow-xl max-w-full md:max-w-4xl w-full max-h-[95vh] overflow-y-auto">
<form className="text-gray-800" onSubmit={handleSubmit(onSubmit)}>
<div className="p-6 pb-2">
<h2 className="text-2xl font-bold mb-4 text-center text-gray-600">
<span className="inline-block sm:inline">{title}</span>
</h2>

<div className="flex items-center relative">
<p className="text-md font-semibold mt-4 mb-1 text-gray-900">
ScholarX {guideType} Guide
</p>
<div className="flex items-center justify-center absolute left-[14.2rem] top-[18.5px]">
<Tooltip content={`Open ${guideType} Guide`} isVisible={true}>
<a href={guideUrl} target="_blank" rel="noreferrer">
<OpenIcon />
</a>
</Tooltip>
</div>
</div>

<div className="sm:h-[30vh] md:h-[35vh] overflow-y-auto mb-4 border border-gray-200 rounded mt-1">
<iframe
src={`${guideUrl}/preview?rm=minimal`}
width="100%"
height="100%"
></iframe>
</div>

{!isMentor && (
<>
<p className="text-md font-semibold text-gray-900">
Privacy Statement
</p>
<p>
Sustainable Foundation Education assures that your video
submission will be used exclusively for application evaluation
purposes. We are committed to protecting your privacy and will
not use your video for any other activities, such as general
AI training or public distribution. Your personal information
and video content will be handled with the utmost
confidentiality.
</p>
</>
)}

<div className="space-y-2 mt-5">
<label className="flex items-top space-x-2">
<input
type="checkbox"
{...register('agreed')}
className="form-checkbox h-4 w-4 text-blue-600 flex-shrink-0 mt-1"
/>
<span className="text-md">
I have read and agree to the ScholarX {guideType} Guide
</span>
</label>
{errors.agreed && (
<p className="text-red-500 text-sm ml-6">
{errors.agreed.message}
</p>
)}

<label className="flex items-top space-x-2">
<input
type="checkbox"
{...register(isMentor ? 'canCommit' : 'consentGiven')}
className="form-checkbox h-4 w-4 text-blue-600 flex-shrink-0 mt-1"
/>
<span className="text-md">
{isMentor
? 'Are you able to commit to a period of 6 months for the program? (We expect a minimum of 6 calls with a mentee in a span of 6 month period)'
: 'I grant Sustainable Foundation Education permission to use my video submission solely for the internal evaluation of my application to ScholarX.'}
</span>
</label>
{(errors.canCommit ?? errors.consentGiven) && (
<p className="text-red-500 text-sm ml-6">
{errors.canCommit?.message ?? errors.consentGiven?.message}
</p>
)}
</div>
</div>

<div className="px-6 py-3 flex justify-end rounded-b-lg">
<button
type="button"
onClick={onClose}
className="bg-gray-200 hover:bg-gray-300 focus:ring-4 focus:ring-blue-300 text-gray-800 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2"
>
Cancel
</button>
<button
type="submit"
className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2"
>
Agree and Continue
</button>
</div>
</form>
</div>
</div>
);
};

export default TermsAgreementModal;
62 changes: 41 additions & 21 deletions src/pages/MenteeRegistration/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { API_URL } from '../../constants';
import useProfile from '../../hooks/useProfile';
import { MenteeApplicationSchema } from '../../schemas';
import { MenteeApplication } from '../../types';
import TermsAgreementModal from '../../components/TermsAgreementModal';

const steps = [
{
Expand All @@ -35,9 +36,11 @@ const MenteeRegistration: React.FC = () => {
setError,
clearErrors,
trigger,
getValues,
formState: { errors },
} = useForm<MenteeApplication>({
resolver: zodResolver(MenteeApplicationSchema),
mode: 'onChange',
defaultValues: {
firstName: user?.first_name,
lastName: user?.last_name,
Expand All @@ -51,6 +54,8 @@ const MenteeRegistration: React.FC = () => {
const [currentStep, setCurrentStep] = useState(0);
const [image, setImage] = useState<File | null>(null);
const [profilePic, setProfilePic] = useState(user?.image_url);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);

const handleProfilePicChange = (event: ChangeEvent<HTMLInputElement>) => {
if (event.target.files != null) {
Expand Down Expand Up @@ -89,7 +94,7 @@ const MenteeRegistration: React.FC = () => {
}
}

const output = await trigger(fields as [keyof MenteeApplication], {
const output = await trigger(fields as Array<keyof MenteeApplication>, {
shouldFocus: true,
});

Expand All @@ -101,10 +106,31 @@ const MenteeRegistration: React.FC = () => {
setCurrentStep((prevStep) => prevStep - 1);
};

const onSubmit: SubmitHandler<MenteeApplication> = async (data) => {
await applyForMentor(data);
if (image) {
await updateProfile({ profile: null, image });
const onSubmit: SubmitHandler<MenteeApplication> = async () => {
setIsModalOpen(true);
};

const handleModalAgree = async (agreedData: {
agreed: boolean;
consentGive?: boolean;
canCommit?: boolean;
}) => {
setIsModalOpen(false);
setIsSubmitting(true);
const formData = getValues();
try {
const validatedData = MenteeApplicationSchema.parse({
...formData,
...agreedData,
});
await applyForMentor(validatedData);
if (image) {
await updateProfile({ profile: null, image });
}
} catch (error) {
console.error('Error submitting application:', error);
} finally {
setIsSubmitting(false);
}
};

Expand Down Expand Up @@ -355,22 +381,6 @@ const MenteeRegistration: React.FC = () => {
register={register}
error={errors.submission}
/>
<FormCheckbox
name="consentGiven"
label="I, hereby grant Sustainable Foundation Education permission to use my video submission solely for the internal evaluation of my application
to ScholarX. I understand that this video will not be used for any other purposes without my explicit consent."
register={register}
error={errors.consentGiven}
/>
<p className="text-md font-semibold">Privacy Statement</p>
<p>
Sustainable Foundation Education assures that your video
submission will be used exclusively for application evaluation
purposes. We are committed to protecting your privacy and will not
use your video for any other activities, such as general AI
training or public distribution. Your personal information and
video content will be handled with the utmost confidentiality.
</p>
</>
)}
{status === 'error' ? (
Expand Down Expand Up @@ -425,6 +435,7 @@ const MenteeRegistration: React.FC = () => {
{currentStep === 2 && !applicationSuccess && (
<button
type="submit"
disabled={isSubmitting}
className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2"
>
{isApplicationPending ? 'Submitting...' : 'Submit'}
Expand All @@ -440,6 +451,15 @@ const MenteeRegistration: React.FC = () => {
)}
</div>
</form>
<TermsAgreementModal
isOpen={isModalOpen}
onClose={() => {
setIsModalOpen(false);
}}
onAgree={handleModalAgree}
isMentor={false}
guideUrl="https://docs.google.com/document/d/1gIYte14FIQtqUhGiMErZRovhNErdUrFdQ0LnCFFnfag/"
/>
</div>
);
};
Expand Down
Loading

0 comments on commit e56a4e1

Please sign in to comment.