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

Show mentees under the mentor profile #152

Merged
merged 7 commits into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import MenteeApplications from './pages/MenteeApplicationsView/MenteeApplications.component.tsx';
import { LoginModalProvider } from './contexts/LoginModalContext.tsx';
import PasswordReset from './pages/PasswordReset/index.tsx';
import MenteeProfile from './pages/MenteeProfile/MenteeProfile.component.tsx';

const queryClient = new QueryClient();

Expand Down Expand Up @@ -45,6 +46,7 @@ const App: React.FC = () => {
<Route path="/mentor/my-mentees/*" element={<MyMentees />} />
<Route path="/mentors" element={<Mentors />} />
<Route path="/mentors/:mentorId" element={<MentorProfile />} />
<Route path="/mentees/:menteeId" element={<MenteeProfile />} />
<Route path="/settings" element={<EditProfileForm />} />
<Route path="/resetpassword" element={<PasswordReset />} />
</Routes>
Expand Down
28 changes: 16 additions & 12 deletions src/components/MenteeCard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
import React from 'react';
import { Link } from 'react-router-dom';

import UserIcon from '../../assets/svg/Icons/UserIcon.tsx';
import { Mentee } from '../../types.ts';
import ProfilePic from '../ProfilePic/index.tsx';

interface MenteeCardProps {
mentee: Mentee;
showPublicProfile?: boolean;
}

const MenteeCard: React.FC<MenteeCardProps> = ({ mentee }) => {
const MenteeCard: React.FC<MenteeCardProps> = ({
mentee,
showPublicProfile = false,
}) => {
return (
<Link
className="border border-gray-200 p-4 rounded-md shadow-sm w-52 flex flex-col h-full"
to={`/mentor/my-mentees/${mentee.uuid}`}
to={
showPublicProfile
? `/mentees/${mentee.uuid}`
: `/mentor/my-mentees/${mentee.uuid}`
}
>
{mentee.profile.image_url !== '' ? (
<img
src={mentee.profile.image_url}
<div className="mx-auto mb-4">
<ProfilePic
src={mentee.profile?.image_url}
alt="Mentee Avatar"
className="w-24 h-24 rounded-full mx-auto mb-4 object-cover"
size="6rem"
/>
) : (
<div className="w-24 h-24 bg-gray-200 rounded-full mx-auto mb-4 flex items-center justify-center">
<UserIcon />
</div>
)}
</div>
<div className="text-center">
<h5 className="text-lg font-bold">
{mentee.application.firstName} {mentee.application.lastName}
Expand Down
18 changes: 8 additions & 10 deletions src/components/MenteeProfile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import { useParams } from 'react-router-dom';

import UserIcon from '../../assets/svg/Icons/UserIcon';
import { ApplicationStatus } from '../../enums';
import useMentee from '../../hooks/useMentee';
import { useMentees } from '../../hooks/useMentees';
import { getStateColor } from '../../utils';
import Toast from '../Toast';
import ActionButtons from '../ActionButtons';
import ProfilePic from '../ProfilePic';

const MenteeProfile: React.FC = () => {
const { menteeId } = useParams();
Expand All @@ -31,17 +31,15 @@ const MenteeProfile: React.FC = () => {
<div className="w-full space-y-5">
<div className="md:flex items-center">
<div className="flex">
{mentee?.profile.image_url !== '' ? (
<img
src={mentee?.profile.image_url}
<div className="mx-auto mb-4">
<ProfilePic
src={
mentee?.profile?.image_url ?? mentee?.application?.profilePic
}
alt="Mentee Avatar"
className="w-12 h-12 md:w-24 md:h-24 rounded-full mx-auto mb-4 object-cover"
size="6rem"
/>
) : (
<div className="w-12 h-12 md:w-24 md:h-24 bg-gray-200 rounded-full flex items-center justify-center">
<UserIcon />
</div>
)}
</div>
<div className="ml-5">
<div className="flex items-center space-x-3">
<span className="text-lg md:text-2xl font-semibold">
Expand Down
35 changes: 35 additions & 0 deletions src/components/ProfilePic/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useState } from 'react';
import UserIcon from '../../assets/svg/Icons/UserIcon';

const ProfilePic: React.FC<{
src: string | undefined;
alt: string;
size: string;
}> = ({ src, alt, size }) => {
const [isError, setIsError] = useState(false);

if (isError || !src) {
return (
<div
style={{ height: size, width: size }}
className="inline-block bg-gray-200 rounded-full ring-2 ring-white flex items-center justify-center"
>
<UserIcon />
</div>
);
}
return (
<img
src={src}
alt={alt}
className="inline-block rounded-full ring-2 ring-white"
style={{ height: size, width: size }}
referrerPolicy="no-referrer"
onError={() => {
setIsError(true);
}}
/>
);
};

export default ProfilePic;
4 changes: 3 additions & 1 deletion src/hooks/useMentee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ const useMentee = (menteeId: string | undefined) => {
enabled: !(menteeId == null),
queryFn: async () => {
if (menteeId != null) {
const { data } = await axios.get(`${API_URL}/mentees/${menteeId}`);
const { data } = await axios.get(`${API_URL}/mentees/${menteeId}`, {
withCredentials: true,
});
return data.mentee as Mentee;
}
},
Expand Down
28 changes: 28 additions & 0 deletions src/hooks/usePublicMentee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useQuery } from '@tanstack/react-query';
import { API_URL } from '../constants';
import axios from 'axios';
import { type Mentee } from '../types';

const usePublicMentee = (menteeId: string | undefined) => {
const { isLoading, error, data } = useQuery({
queryKey: ['mentee', menteeId],
initialData: null,
enabled: !(menteeId == null),
queryFn: async () => {
if (menteeId != null) {
const { data } = await axios.get(
`${API_URL}/mentees/public/${menteeId}`
);
return data.mentee as Mentee;
}
},
});

return {
isLoading,
error,
data,
};
};

export default usePublicMentee;
136 changes: 136 additions & 0 deletions src/pages/MenteeProfile/MenteeProfile.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React from 'react';
import { Link, useParams } from 'react-router-dom';

import { getStateColor } from '../../utils';
import ProfilePic from '../../components/ProfilePic';
import ChevronRightIcon from '../../assets/svg/Icons/ChevronRightIcon';
import { ApplicationStatus } from '../../enums';
import usePublicMentee from '../../hooks/usePublicMentee';

const MenteeProfile: React.FC = () => {
const { menteeId } = useParams();
const { data: mentee } = usePublicMentee(menteeId);

return (
<>
<nav aria-label="Breadcrumb">
<ol className="flex items-center gap-1 text-sm text-gray-600">
<li>
<Link
to="/mentors"
className="block transition hover:text-gray-700"
>
Mentors
</Link>
</li>
<li>
<ChevronRightIcon />
</li>
<li>
<Link
to={`/mentors/${mentee?.mentor.uuid ?? ''}`}
className="block transition hover:text-gray-700"
>
<span className="block transition">
{mentee?.mentor?.profile?.first_name}{' '}
{mentee?.mentor?.profile?.last_name}
</span>
</Link>
</li>
<li>
<ChevronRightIcon />
</li>
<li>
<span className="block transition">Mentees</span>
</li>
<li>
<ChevronRightIcon />
</li>
<li>
<span className="block transition">
{mentee?.application.firstName} {mentee?.application.lastName}
</span>
</li>
</ol>
</nav>
<div className="w-full space-y-5">
<div className="md:flex items-center">
<div className="flex mt-10">
<div className="mx-auto mb-4">
<ProfilePic
src={mentee?.profile?.image_url}
alt="Mentee Avatar"
size="7rem"
/>
</div>
<div className="ml-5">
<div className="flex items-center space-x-3 mb-1">
<span className="text-lg md:text-2xl font-semibold">
{mentee?.application.firstName} {mentee?.application.lastName}
</span>
{mentee?.state !== ApplicationStatus.APPROVED && (
<span
className={`whitespace-nowrap rounded-full px-2.5 py-0.5 text-sm ${getStateColor(
mentee?.state
)}`}
>
{mentee?.state}
</span>
)}
</div>
{mentee?.application.isUndergrad ? (
<span className="text-xl font-light">
{mentee?.application.university}
</span>
) : (
<span className="text-md md:text-xl font-light">
{mentee?.application.position}, {mentee?.application.company}
</span>
)}
</div>
</div>
</div>
<hr className="w-full pb-10" />
<div className="md:grid md:grid-cols-5 md:gap-12">
<div className="col-span-3">
<div className="grid grid-cols-2 gap-4">
{mentee?.application.isUndergrad ? (
<>
<div>
<h3 className="text-base font-semibold">Year of Study</h3>
<p>{mentee?.application.yearOfStudy}</p>
</div>
<div>
<h3 className="text-base font-semibold">Course</h3>
<p>{mentee?.application.course}</p>
</div>
<div>
<h3 className="text-base font-semibold">University</h3>
<p>{mentee?.application.university}</p>
</div>
</>
) : (
<>
<div>
<h3 className="text-base font-semibold">Company</h3>
<p>{mentee?.application.company}</p>
</div>
<div>
<h3 className="text-base font-semibold">Position</h3>
<p>{mentee?.application.position}</p>
</div>
<div>
<h3 className="text-base font-semibold">Graduated year</h3>
<p>{mentee?.application.graduatedYear}</p>
</div>
</>
)}
</div>
</div>
</div>
</div>
</>
);
};

export default MenteeProfile;
Loading
Loading