Skip to content
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: 1 addition & 1 deletion client/src/features/trainee-profile/TraineePage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ErrorBox, Loader } from '../../components';

import { Box } from '@mui/material';
import TraineeProfile from './profile/components/TraineeProfile';
import { TraineeProfile } from './profile/components/TraineeProfile';
import { TraineeProfileProvider } from './context/useTraineeProfileProvider';
import { useParams } from 'react-router-dom';
import { useTraineeInfoData } from './personal-info/data/useTraineeInfoData';
Expand Down
136 changes: 69 additions & 67 deletions client/src/features/trainee-profile/profile/ProfileSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Avatar, Box, IconButton, Link, Stack, Typography } from '@mui/material';

import { LearningStatus } from '../../../data/types/Trainee';
import LinkedInLogo from '../../../assets/LinkedIn_logo.png';
import { Box, IconButton, Link, Stack, Typography } from '@mui/material';
import { SidebarJobPath } from '../../../components/SidebarJobPath';
import { SidebarLearningStatus } from '../../../components/SidebarLearningStatus';
import { LearningStatus } from '../../../data/types/Trainee';
import LinkedInLogo from '../../../assets/LinkedIn_logo.png';
import githubLogo from '../../../assets/github.png';
import slackLogo from '../../../assets/slack.png';
import { useTraineeInfoData } from '../personal-info/data/useTraineeInfoData';
import { ProfilePictureModal } from './components/ProfilePictureModal';

interface ProfileSidebarProps {
traineeId: string;
Expand All @@ -18,76 +18,78 @@ interface ProfileSidebarProps {
* @param {string} traineeId trainee id.
* @returns {ReactNode} A React element that renders profile page sidebar information and profile image.
*/
const ProfileSidebar = ({ traineeId }: ProfileSidebarProps) => {
export const ProfileSidebar = ({ traineeId }: ProfileSidebarProps) => {
const { data } = useTraineeInfoData(traineeId);

const slackId = data?.contactInfo?.slackId;
const githubHandle = data?.contactInfo?.githubHandle;
const linkedIn = data?.contactInfo?.linkedin;

return (
<Box
display="flex"
flexDirection="column"
alignItems="center"
gap={2}
color="black"
bgcolor="hyfBeige.main"
height="95vh"
paddingX={4}
paddingY={4}
>
{/* Profile image */}
<Box height={180} width={180} display="flex" justifyContent="center">
<Avatar variant="square" sx={{ width: '100%', height: '100%' }} src={data?.imageURL} alt={data?.displayName} />
</Box>
<>
<Box
display="flex"
flexDirection="column"
alignItems="center"
gap={2}
color="black"
bgcolor="#d1fbe6"
height="100vh"
paddingX={4}
paddingY={4}
>
<ProfilePictureModal
imageUrl={data?.imageURL}
displayName={data?.displayName}
onUploadModalOpen={() => null}
onConfirmationDialogOpen={() => null}
/>

<Stack direction="column" spacing={1} justifyContent="center" alignItems="center">
{/* Name */}
<Typography variant="h6" fontWeight="bold" color="text.primary">
{data?.displayName}
</Typography>
{/* Pronouns */}
<Typography variant="body1" color="text.secondary">
{data?.personalInfo?.pronouns}
</Typography>
{/* Learning Status */}
{data?.educationInfo?.learningStatus === LearningStatus.Graduated ? (
<SidebarJobPath jobPath={data?.employmentInfo?.jobPath}></SidebarJobPath>
) : (
<SidebarLearningStatus learningStatus={data?.educationInfo?.learningStatus}></SidebarLearningStatus>
)}
{/* Cohort */}
<Typography variant="body1" color="text.secondary">
Cohort {data?.educationInfo?.currentCohort || 'not assigned'}
</Typography>
</Stack>

{/* social media contact info */}
<div style={{ display: 'flex', justifyContent: 'center', gap: '16px' }}>
{slackId && (
<Link href={`slack://user?team=T0EJTUQ87&id=${slackId}`}>
<IconButton aria-label="Slack Id">
<img src={slackLogo} alt="Slack" width="32" height="32" style={{ borderRadius: '50%' }} />
</IconButton>
</Link>
)}
{githubHandle && (
<Link href={`https://github.com/${githubHandle}`} target="_blank" rel="noopener">
<IconButton aria-label="GitHub handel">
<img src={githubLogo} alt="GitHub" width="32" height="32" style={{ borderRadius: '50%' }} />
</IconButton>
</Link>
)}
{linkedIn && (
<Link href={linkedIn} target="_blank" rel="noopener">
<IconButton aria-label="LinkedIn URL">
<img src={LinkedInLogo} alt="LinkedIn" width="32" height="32" />
</IconButton>
</Link>
)}
</div>
</Box>
<Stack direction="column" spacing={1} justifyContent="center" alignItems="center">
{/* Name */}
<Typography variant="h6" fontWeight="bold">
{data?.displayName}
</Typography>
{/* Pronouns */}
<Typography variant="body1" color="text.secondary">
{data?.personalInfo?.pronouns}
</Typography>
{/* Learning Status */}
{data?.educationInfo?.learningStatus === LearningStatus.Graduated ? (
<SidebarJobPath jobPath={data?.employmentInfo?.jobPath}></SidebarJobPath>
) : (
<SidebarLearningStatus learningStatus={data?.educationInfo?.learningStatus}></SidebarLearningStatus>
)}
{/* Cohort */}
<Typography variant="body1" color="text.secondary">
Cohort {data?.educationInfo?.currentCohort || 'not assigned'}
</Typography>
</Stack>
{/* social media contact info */}
<div style={{ display: 'flex', justifyContent: 'center', gap: '16px' }}>
{slackId && (
<Link href={`slack://user?team=T0EJTUQ87&id=${slackId}`}>
<IconButton aria-label="Slack Id">
<img src={slackLogo} alt="Slack" width="32" height="32" style={{ borderRadius: '50%' }} />
</IconButton>
</Link>
)}
{githubHandle && (
<Link href={`https://github.com/${githubHandle}`} target="_blank" rel="noopener">
<IconButton aria-label="GitHub handel">
<img src={githubLogo} alt="GitHub" width="32" height="32" style={{ borderRadius: '50%' }} />
</IconButton>
</Link>
)}
{linkedIn && (
<Link href={linkedIn} target="_blank" rel="noopener">
<IconButton aria-label="LinkedIn URL">
<img src={LinkedInLogo} alt="LinkedIn" width="32" height="32" />
</IconButton>
</Link>
)}
</div>
</Box>
</>
);
};
export default ProfileSidebar;
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { Avatar, Box, Fade, IconButton } from '@mui/material';
import React from 'react';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/Delete';

interface ProfilePictureModalProps {
imageUrl?: string | undefined;
displayName?: string | undefined;
onUploadModalOpen: () => void;
onConfirmationDialogOpen: () => void;
}

export const ProfilePictureModal = ({
imageUrl,
displayName,
onUploadModalOpen,
onConfirmationDialogOpen,
}: ProfilePictureModalProps) => {
const [isHovering, setIsHovering] = React.useState<boolean>(false);

return (
<Box
onMouseEnter={() => {
setIsHovering(true);
}}
onMouseLeave={() => {
setIsHovering(false);
}}
height={180}
width={180}
display="flex"
justifyContent="center"
position="relative"
>
<Avatar
src={imageUrl}
alt={displayName}
variant="square"
sx={{
width: '100%',
height: '100%',
filter: isHovering ? 'brightness(0.7)' : 'none',
}}
/>

{isHovering && (
<Box
sx={{
display: 'flex',
position: 'absolute',
justifyContent: 'center',
alignItems: 'center',
gap: 5,
top: 0,
bottom: 0,
left: 0,
right: 0,
}}
>
<Fade in={isHovering}>
<IconButton onClick={onUploadModalOpen} aria-label="Edit profile picture">
<EditIcon
sx={{
color: 'white',
fontSize: 40,
'&:hover': { transform: 'scale(1.1)' },
'&:active': { transform: 'scale(0.9)' },
}}
/>
</IconButton>
</Fade>
<Fade in={isHovering}>
<IconButton onClick={onConfirmationDialogOpen} aria-label="Delete profile picture">
<DeleteIcon
sx={{
color: 'white',
fontSize: 40,
'&:hover': { transform: 'scale(1.1)' },
'&:active': { transform: 'scale(0.9)' },
}}
/>
</IconButton>
</Fade>
</Box>
)}
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import InteractionsInfo from '../../interactions/InteractionsInfo';
import MuiAlert from '@mui/material/Alert';
import PersonalInfo from '../../personal-info/PersonalInfo';
import ProfileNav from './ProfileNav';
import ProfileSidebar from '../ProfileSidebar';
import { ProfileSidebar } from '../ProfileSidebar';
import { Trainee } from '../../../../data/types/Trainee';
import { useQueryClient } from '@tanstack/react-query';
import { useTraineeProfileContext } from '../../context/useTraineeProfileContext';
Expand All @@ -29,7 +29,7 @@ interface TraineeProfileProps {
* @param {string} id trainee id.
* @returns {ReactNode} A React element that renders profile page tabs and sidebar.
*/
const TraineeProfile = ({ id }: TraineeProfileProps) => {
export const TraineeProfile = ({ id }: TraineeProfileProps) => {
// Default active tab
const [activeTab, setActiveTab] = useState('personal');
const { data: traineeData } = useTraineeInfoData(id);
Expand Down Expand Up @@ -141,5 +141,3 @@ const TraineeProfile = ({ id }: TraineeProfileProps) => {
</Box>
);
};

export default TraineeProfile;