diff --git a/admin-wcc-app/__tests__/services/mentorshipService.test.ts b/admin-wcc-app/__tests__/services/mentorshipService.test.ts index 9b0f60289..13db97f2a 100644 --- a/admin-wcc-app/__tests__/services/mentorshipService.test.ts +++ b/admin-wcc-app/__tests__/services/mentorshipService.test.ts @@ -3,7 +3,7 @@ import { getMenteeApplications, getMentorshipRecommendations, } from '@/services/mentorshipService'; -import {apiFetch} from '@/lib/api'; +import { apiFetch } from '@/lib/api'; jest.mock('../../lib/api', () => ({ apiFetch: jest.fn(), @@ -28,8 +28,8 @@ describe('mentorshipService', () => { const result = await getMentorshipRecommendations(token); expect(apiFetch).toHaveBeenCalledWith( - '/api/platform/v1/admin/mentorship/matches/recommendations', - {token} + '/api/platform/v1/admin/mentorship/matches/recommendations', + { token } ); expect(result).toEqual(mockResponse); }); @@ -37,14 +37,14 @@ describe('mentorshipService', () => { describe('getMenteeApplications', () => { it('should fetch mentee applications without mentor filter', async () => { - const mockApps = [{menteeId: 1, status: 'PENDING'}]; + const mockApps = [{ menteeId: 1, status: 'PENDING' }]; (apiFetch as jest.Mock).mockResolvedValue(mockApps); const result = await getMenteeApplications(5, ['PENDING', 'ACCEPTED'], token); expect(apiFetch).toHaveBeenCalledWith( - '/api/platform/v1/admin/mentorship/cycles/5/applications?status=PENDING%2CACCEPTED', - {token} + '/api/platform/v1/admin/mentorship/cycles/5/applications?status=PENDING%2CACCEPTED', + { token } ); expect(result).toEqual(mockApps); }); @@ -55,8 +55,8 @@ describe('mentorshipService', () => { await getMenteeApplications(5, ['PENDING'], token, 10); expect(apiFetch).toHaveBeenCalledWith( - '/api/platform/v1/admin/mentorship/cycles/5/applications?status=PENDING&mentorId=10', - {token} + '/api/platform/v1/admin/mentorship/cycles/5/applications?status=PENDING&mentorId=10', + { token } ); }); }); @@ -69,7 +69,7 @@ describe('mentorshipService', () => { expect(apiFetch).toHaveBeenCalledWith('/api/platform/v1/mentees/20/cycles/5/assign-mentor', { method: 'POST', - body: {mentorId: 10, notes: undefined}, + body: { mentorId: 10, notes: undefined }, token, }); }); @@ -81,7 +81,7 @@ describe('mentorshipService', () => { expect(apiFetch).toHaveBeenCalledWith('/api/platform/v1/mentees/20/cycles/5/assign-mentor', { method: 'POST', - body: {mentorId: 10, notes: 'Good match for React skills'}, + body: { mentorId: 10, notes: 'Good match for React skills' }, token, }); }); diff --git a/admin-wcc-app/components/AdminLayout.tsx b/admin-wcc-app/components/AdminLayout.tsx index 62246d2ea..8d2784af0 100644 --- a/admin-wcc-app/components/AdminLayout.tsx +++ b/admin-wcc-app/components/AdminLayout.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import {AppBar, Button, Container, Stack, Toolbar, Typography} from '@mui/material'; +import { AppBar, Button, Container, Stack, Toolbar, Typography } from '@mui/material'; import Link from 'next/link'; -import {useAuth} from '@/components/AuthProvider'; +import { useAuth } from '@/components/AuthProvider'; -export default function AdminLayout({children}: { children: React.ReactNode }) { - const {logout, roles} = useAuth(); +export default function AdminLayout({ children }: { children: React.ReactNode }) { + const { logout, roles } = useAuth(); const isAdmin = roles.includes('ADMIN'); const isMentorshipAdmin = roles.includes('MENTORSHIP_ADMIN'); @@ -12,53 +12,53 @@ export default function AdminLayout({children}: { children: React.ReactNode }) { const isMentor = roles.includes('MENTOR'); return ( - <> - - - - WCC Admin - - - + {(isAdmin || isMentor) && ( + - {(isAdmin || isMentor) && ( - - )} - {(isAdmin || isMentorshipAdmin || isLeader) && ( - - )} - {(isAdmin || isMentorshipAdmin || isLeader) && ( - - )} - {(isAdmin || isMentorshipAdmin) && ( - - )} - {(isAdmin || isMentorshipAdmin) && ( - - )} - {(isAdmin || isLeader) && ( - - )} - - - - - {children} - + )} + {(isAdmin || isMentorshipAdmin || isLeader) && ( + + )} + {(isAdmin || isMentorshipAdmin) && ( + + )} + {(isAdmin || isMentorshipAdmin) && ( + + )} + {(isAdmin || isLeader) && ( + + )} + + + + + {children} + ); } diff --git a/admin-wcc-app/components/mentors/SkillsSection.tsx b/admin-wcc-app/components/mentors/SkillsSection.tsx index bb3dc8357..806c9f5cb 100644 --- a/admin-wcc-app/components/mentors/SkillsSection.tsx +++ b/admin-wcc-app/components/mentors/SkillsSection.tsx @@ -1,9 +1,9 @@ -import {Box, Chip, Typography} from '@mui/material'; -import {MentorSkills} from '@/types/mentor'; -import {TECHNICAL_AREAS} from '@/lib/technicalAreas'; -import {PROGRAMMING_LANGUAGES} from '@/lib/programmingLanguages'; -import {MENTORSHIP_FOCUS_AREAS} from '@/lib/mentorshipFocusAreas'; -import {PROFICIENCY_LEVELS} from '@/lib/proficiencyLevels'; +import { Box, Chip, Typography } from '@mui/material'; +import { MentorSkills } from '@/types/mentor'; +import { TECHNICAL_AREAS } from '@/lib/technicalAreas'; +import { PROGRAMMING_LANGUAGES } from '@/lib/programmingLanguages'; +import { MENTORSHIP_FOCUS_AREAS } from '@/lib/mentorshipFocusAreas'; +import { PROFICIENCY_LEVELS } from '@/lib/proficiencyLevels'; interface SkillsSectionProps { skills: MentorSkills; @@ -25,52 +25,52 @@ function focusLabel(value: string): string { return MENTORSHIP_FOCUS_AREAS.find((f) => f.value === value)?.label ?? value; } -export default function SkillsSection({skills}: SkillsSectionProps) { +export default function SkillsSection({ skills }: SkillsSectionProps) { return ( - - {skills.yearsExperience !== undefined && ( - - {skills.yearsExperience} years experience - - )} - {skills.languages && skills.languages.length > 0 && ( - - {skills.languages.map((l) => ( - - ))} - - )} - {skills.areas && skills.areas.length > 0 && ( - - {skills.areas.map((a) => ( - - ))} - - )} - {skills.mentorshipFocus && skills.mentorshipFocus.length > 0 && ( - - {skills.mentorshipFocus.map((f) => ( - - ))} - - )} - + + {skills.yearsExperience !== undefined && ( + + {skills.yearsExperience} years experience + + )} + {skills.languages && skills.languages.length > 0 && ( + + {skills.languages.map((l) => ( + + ))} + + )} + {skills.areas && skills.areas.length > 0 && ( + + {skills.areas.map((a) => ( + + ))} + + )} + {skills.mentorshipFocus && skills.mentorshipFocus.length > 0 && ( + + {skills.mentorshipFocus.map((f) => ( + + ))} + + )} + ); } diff --git a/admin-wcc-app/components/mentorship/MatchCard.tsx b/admin-wcc-app/components/mentorship/MatchCard.tsx index 38e62ed5f..ceb982776 100644 --- a/admin-wcc-app/components/mentorship/MatchCard.tsx +++ b/admin-wcc-app/components/mentorship/MatchCard.tsx @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import { Alert, Box, @@ -10,10 +10,10 @@ import { Grid, Typography, } from '@mui/material'; -import {MentorMatches} from '@/types/mentorship'; +import { MentorMatches } from '@/types/mentorship'; import MentorInfoCard from './MentorInfoCard'; import MenteeCard from './MenteeCard'; -import {createManualMatch} from '@/services/mentorshipService'; +import { createManualMatch } from '@/services/mentorshipService'; interface MatchCardProps { match: MentorMatches; @@ -22,7 +22,7 @@ interface MatchCardProps { onMenteeMatched: (mentorId: string | number, menteeId: number) => void; } -export default function MatchCard({match, cycleId, token, onMenteeMatched}: MatchCardProps) { +export default function MatchCard({ match, cycleId, token, onMenteeMatched }: MatchCardProps) { const [loadingMenteeId, setLoadingMenteeId] = useState(null); const [error, setError] = useState<{ id: number; message: string } | null>(null); const [successId, setSuccessId] = useState(null); @@ -36,91 +36,91 @@ export default function MatchCard({match, cycleId, token, onMenteeMatched}: Matc setSuccessId(menteeId); onMenteeMatched(match.mentor.id, menteeId); } catch (e) { - setError({id: menteeId, message: e instanceof Error ? e.message : 'Failed to match'}); + setError({ id: menteeId, message: e instanceof Error ? e.message : 'Failed to match' }); } finally { setLoadingMenteeId(null); } }; return ( - - - - - - Mentor #{match.mentor.id} + + + + + + Mentor #{match.mentor.id} + + + + + Review mentor profile and availability before matching. - - - - Review mentor profile and availability before matching. - - - + + - - - Recommended {match.mentees.length || 0} mentees - - {match.mentees.length > 0 ? ( - match.mentees.map((suggestion) => ( - - + + + Recommended {match.mentees.length || 0} mentees + + {match.mentees.length > 0 ? ( + match.mentees.map((suggestion) => ( + + - - {suggestion.applicationStatus ? ( - - ) : ( - - )} + + {suggestion.applicationStatus ? ( + + ) : ( + + )} - {successId === suggestion.mentee.id && ( - - Matched successfully! Status: MENTOR_REVIEWING - - )} - {error?.id === suggestion.mentee.id && ( - - {error.message} - - )} - - - )) - ) : ( - - No recommended mentees for this mentor. - - )} - + {successId === suggestion.mentee.id && ( + + Matched successfully! Status: MENTOR_REVIEWING + + )} + {error?.id === suggestion.mentee.id && ( + + {error.message} + + )} + + + )) + ) : ( + + No recommended mentees for this mentor. + + )} - - + + + ); } diff --git a/admin-wcc-app/components/mentorship/MenteeApplicationCard.tsx b/admin-wcc-app/components/mentorship/MenteeApplicationCard.tsx index e91405980..b1a799b04 100644 --- a/admin-wcc-app/components/mentorship/MenteeApplicationCard.tsx +++ b/admin-wcc-app/components/mentorship/MenteeApplicationCard.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import {Alert, Avatar, Box, Card, CardContent, Chip, Stack, Typography} from '@mui/material'; +import { Alert, Avatar, Box, Card, CardContent, Chip, Stack, Typography } from '@mui/material'; import { Business as BusinessIcon, Public as PublicIcon, Work as WorkIcon, } from '@mui/icons-material'; -import {MenteeApplicationItem} from '@/types/mentorship'; +import { MenteeApplicationItem } from '@/types/mentorship'; interface MenteeApplicationCardProps { application: MenteeApplicationItem; @@ -24,85 +24,85 @@ const STATUS_COLOR: Record - - - + + + + {mentee.fullName.charAt(0)} + + + + + {mentee.fullName} + + + + - {mentee.fullName.charAt(0)} - + + {mentee.position || 'N/A'} + + {mentee.companyName || 'N/A'} + + {location || 'N/A'} + - - - {mentee.fullName} - + {mentee.skills?.areas && mentee.skills.areas.length > 0 && ( + + {mentee.skills.areas.slice(0, 4).map((a) => ( + + ))} + {mentee.skills.areas.length > 4 && ( + + )} + )} - - - {mentee.position || 'N/A'} - - {mentee.companyName || 'N/A'} - - {location || 'N/A'} - - - {mentee.skills?.areas && mentee.skills.areas.length > 0 && ( - - {mentee.skills.areas.slice(0, 4).map((a) => ( - - ))} - {mentee.skills.areas.length > 4 && ( - - )} - - )} - - {appliedAt && ( - - Applied: {new Date(appliedAt).toLocaleDateString()} - - )} + Applied: {new Date(appliedAt).toLocaleDateString()} + + )} - {showRejectionReason && rejectionReason && ( - - Rejection reason: {rejectionReason} - - )} - - - - + {showRejectionReason && rejectionReason && ( + + Rejection reason: {rejectionReason} + + )} + + + + ); } diff --git a/admin-wcc-app/components/mentorship/MenteeCard.tsx b/admin-wcc-app/components/mentorship/MenteeCard.tsx index d5e64b16c..8df35b8e4 100644 --- a/admin-wcc-app/components/mentorship/MenteeCard.tsx +++ b/admin-wcc-app/components/mentorship/MenteeCard.tsx @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import { Avatar, Box, @@ -20,164 +20,164 @@ import { Public as PublicIcon, Work as WorkIcon, } from '@mui/icons-material'; -import {MenteeItem} from '@/types/mentorship'; +import { MenteeItem } from '@/types/mentorship'; import LinkedInIcon from '@mui/icons-material/LinkedIn'; -import SkillsSection, {langLabel, profLabel} from '@/components/mentors/SkillsSection'; +import SkillsSection, { langLabel, profLabel } from '@/components/mentors/SkillsSection'; interface MenteeCardProps { mentee: MenteeItem; score?: number; } -export default function MenteeCard({mentee, score}: MenteeCardProps) { +export default function MenteeCard({ mentee, score }: MenteeCardProps) { const [expanded, setExpand] = useState(false); const location = [mentee.city, mentee.country?.countryName].filter(Boolean).join(', '); return ( - - {score !== undefined && ( - - {score} - - )} - - - - {mentee.fullName.charAt(0)} - - - {mentee.fullName} - - Mentee Id: {mentee.id} - {mentee.network && mentee.network.length > 0 && ( - - {mentee.network.map((n) => ( - - - - ))} - - )} - - - - {mentee.position || 'N/A'} - - - - {mentee.companyName || 'N/A'} - - - - {location || 'N/A'} - - - {mentee.skills?.areas && mentee.skills.areas.length > 0 && ( - - - {mentee.skills.areas.slice(0, 3).map((a) => ( - - ))} - {mentee.skills.areas.length > 3 && ( - - )} - - + + {score !== undefined && ( + + {score} + + )} + + + + {mentee.fullName.charAt(0)} + + + {mentee.fullName} + + Mentee Id: {mentee.id} + {mentee.network && mentee.network.length > 0 && ( + + {mentee.network.map((n) => ( + + + + ))} + )} + + + + {mentee.position || 'N/A'} + + + + {mentee.companyName || 'N/A'} + + + + {location || 'N/A'} + - {mentee.skills?.languages && mentee.skills.languages.length > 0 && ( - - - {mentee.skills.languages.slice(0, 3).map((l) => ( - - ))} - {mentee.skills.languages.length > 3 && ( - - )} - - - )} - - setExpand(!expanded)}> - {expanded ? : } - - + {mentee.skills?.areas && mentee.skills.areas.length > 0 && ( + + + {mentee.skills.areas.slice(0, 3).map((a) => ( + + ))} + {mentee.skills.areas.length > 3 && ( + + )} + + + )} - - - + {mentee.skills?.languages && mentee.skills.languages.length > 0 && ( + + + {mentee.skills.languages.slice(0, 3).map((l) => ( + + ))} + {mentee.skills.languages.length > 3 && ( + + )} + + + )} + + setExpand(!expanded)}> + {expanded ? : } + + + + + + + + Bio + + + {mentee.bio || 'No bio provided.'} + + + {mentee.skills && } + - Bio + Languages - - {mentee.bio || 'No bio provided.'} + + {mentee.spokenLanguages?.map((l) => ( + } /> + ))} + + + + + Available hours/month: {mentee.availableHsMonth || 'N/A'} - - {mentee.skills && } - - - Languages - - - {mentee.spokenLanguages?.map((l) => ( - }/> - ))} - - - - - Available hours/month: {mentee.availableHsMonth || 'N/A'} - - - - - + + + + ); } diff --git a/admin-wcc-app/components/mentorship/MentorApplicationsPanel.tsx b/admin-wcc-app/components/mentorship/MentorApplicationsPanel.tsx index 2354abf19..d406f2bae 100644 --- a/admin-wcc-app/components/mentorship/MentorApplicationsPanel.tsx +++ b/admin-wcc-app/components/mentorship/MentorApplicationsPanel.tsx @@ -1,7 +1,7 @@ -import React, {useEffect, useState} from 'react'; -import {Alert, Box, CircularProgress, Divider, Typography} from '@mui/material'; -import {getMenteeApplications} from '@/services/mentorshipService'; -import {MenteeApplicationItem} from '@/types/mentorship'; +import React, { useEffect, useState } from 'react'; +import { Alert, Box, CircularProgress, Divider, Typography } from '@mui/material'; +import { getMenteeApplications } from '@/services/mentorshipService'; +import { MenteeApplicationItem } from '@/types/mentorship'; import MenteeApplicationCard from './MenteeApplicationCard'; interface MentorApplicationsPanelProps { @@ -22,10 +22,10 @@ const ALL_STATUSES = [ ]; export default function MentorApplicationsPanel({ - mentorId, - cycleId, - token, - }: MentorApplicationsPanelProps) { + mentorId, + cycleId, + token, +}: MentorApplicationsPanelProps) { const [applications, setApplications] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); @@ -37,28 +37,28 @@ export default function MentorApplicationsPanel({ setError(null); getMenteeApplications(cycleId, ALL_STATUSES, token, mentorId) - .then(setApplications) - .catch((err) => setError(err.message || 'Failed to load applications')) - .finally(() => setLoading(false)); + .then(setApplications) + .catch((err) => setError(err.message || 'Failed to load applications')) + .finally(() => setLoading(false)); }, [mentorId, cycleId, token]); return ( - - - Applications for Mentor #{mentorId} - - + + + Applications for Mentor #{mentorId} + + - {loading && } - {error && {error}} + {loading && } + {error && {error}} - {!loading && !error && applications.length === 0 && ( - No applications found for this mentor. - )} + {!loading && !error && applications.length === 0 && ( + No applications found for this mentor. + )} - {applications.map((app) => ( - - ))} - + {applications.map((app) => ( + + ))} + ); } diff --git a/admin-wcc-app/components/mentorship/MentorInfoCard.tsx b/admin-wcc-app/components/mentorship/MentorInfoCard.tsx index c9711f6c1..b0517dce7 100644 --- a/admin-wcc-app/components/mentorship/MentorInfoCard.tsx +++ b/admin-wcc-app/components/mentorship/MentorInfoCard.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import {Avatar, Box, Card, CardContent, Stack, Typography} from '@mui/material'; +import { Avatar, Box, Card, CardContent, Stack, Typography } from '@mui/material'; import { Business as BusinessIcon, Public as PublicIcon, Work as WorkIcon, } from '@mui/icons-material'; -import {MentorItem} from '@/types/mentor'; +import { MentorItem } from '@/types/mentor'; import SkillsSection from '@/components/mentors/SkillsSection'; import BioSection from '@/components/mentors/BioSection'; @@ -13,69 +13,69 @@ interface MentorInfoCardProps { mentor: MentorItem; } -export default function MentorInfoCard({mentor}: MentorInfoCardProps) { +export default function MentorInfoCard({ mentor }: MentorInfoCardProps) { const location = [mentor.city, mentor.country?.countryName].filter(Boolean).join(', '); return ( - - - - - {mentor.fullName.charAt(0)} - - - {mentor.fullName} - - - {mentor.position || 'N/A'} - - - - {mentor.companyName || 'N/A'} - - - - {location || 'N/A'} - - - - - {mentor.bio && } - {mentor.skills && } - - - - Availability Long Term: - {mentor.menteeSection?.longTerm?.numMentee || 0} mentees,{' '} - {mentor.menteeSection?.longTerm?.hours || 0} hours - + + + + + {mentor.fullName.charAt(0)} + + + {mentor.fullName} + + + {mentor.position || 'N/A'} - - - - Ideal Mentee - - - {mentor.menteeSection?.idealMentee} + + + {mentor.companyName || 'N/A'} - - - - Additional - - - {mentor.menteeSection?.additional} + + + {location || 'N/A'} - - + + + {mentor.bio && } + {mentor.skills && } + + + + Availability Long Term: + {mentor.menteeSection?.longTerm?.numMentee || 0} mentees,{' '} + {mentor.menteeSection?.longTerm?.hours || 0} hours + + + + + + Ideal Mentee + + + {mentor.menteeSection?.idealMentee} + + + + + Additional + + + {mentor.menteeSection?.additional} + + + + ); } diff --git a/admin-wcc-app/pages/admin/mentorship/index.tsx b/admin-wcc-app/pages/admin/mentorship/index.tsx index 955b585fc..7103dfda7 100644 --- a/admin-wcc-app/pages/admin/mentorship/index.tsx +++ b/admin-wcc-app/pages/admin/mentorship/index.tsx @@ -1,4 +1,4 @@ -import React, {useEffect, useState} from 'react'; +import React, { useEffect, useState } from 'react'; import { Alert, Box, @@ -10,10 +10,10 @@ import { Typography, } from '@mui/material'; import AdminLayout from '@/components/AdminLayout'; -import {getMenteeApplications, getMentorshipRecommendations} from '@/services/mentorshipService'; -import {MenteeApplicationItem, MentorshipRecommendationResponse} from '@/types/mentorship'; -import {getStoredToken, isTokenExpired} from '@/lib/auth'; -import {useRouter} from 'next/router'; +import { getMenteeApplications, getMentorshipRecommendations } from '@/services/mentorshipService'; +import { MenteeApplicationItem, MentorshipRecommendationResponse } from '@/types/mentorship'; +import { getStoredToken, isTokenExpired } from '@/lib/auth'; +import { useRouter } from 'next/router'; import MatchCard from '@/components/mentorship/MatchCard'; import MenteeCard from '@/components/mentorship/MenteeCard'; import MentorInfoCard from '@/components/mentorship/MentorInfoCard'; @@ -26,18 +26,18 @@ interface TabPanelProps { } function CustomTabPanel(props: TabPanelProps) { - const {children, value, index, ...other} = props; + const { children, value, index, ...other } = props; return ( - + ); } @@ -63,14 +63,14 @@ export default function MentorshipAdminPage() { } getMentorshipRecommendations(token) - .then((res) => { - setData(respToRecommendationResponse(res)); - setLoading(false); - }) - .catch((err) => { - setError(err.message || 'Failed to fetch recommendations'); - setLoading(false); - }); + .then((res) => { + setData(respToRecommendationResponse(res)); + setLoading(false); + }) + .catch((err) => { + setError(err.message || 'Failed to fetch recommendations'); + setLoading(false); + }); }, [router]); useEffect(() => { @@ -87,8 +87,8 @@ export default function MentorshipAdminPage() { }; const setterMap: Record< - number, - React.Dispatch> + number, + React.Dispatch> > = { 3: setPendingApps, 4: setAcceptedApps, @@ -96,13 +96,13 @@ export default function MentorshipAdminPage() { }; if (setterMap[tabValue]) { - setAppsLoading((prev) => ({...prev, [tabValue]: true})); - setAppsError((prev) => ({...prev, [tabValue]: ''})); + setAppsLoading((prev) => ({ ...prev, [tabValue]: true })); + setAppsError((prev) => ({ ...prev, [tabValue]: '' })); getMenteeApplications(cycleId, statusMap[tabValue], token) - .then(setterMap[tabValue]) - .catch((err) => setAppsError((prev) => ({...prev, [tabValue]: err.message}))) - .finally(() => setAppsLoading((prev) => ({...prev, [tabValue]: false}))); + .then(setterMap[tabValue]) + .catch((err) => setAppsError((prev) => ({ ...prev, [tabValue]: err.message }))) + .finally(() => setAppsLoading((prev) => ({ ...prev, [tabValue]: false }))); } }, [tabValue, loading]); @@ -128,135 +128,134 @@ export default function MentorshipAdminPage() { if (loading) { return ( - - - - - + + + + + ); } return ( - - - - Mentorship - Manual Matching - + + + + Mentorship - Manual Matching + - {error && ( - - {error} - - )} + {error && ( + + {error} + + )} - - - - - - - - - - - + + + + + + + + + + + - - {data?.matchedMentors.map((match, idx) => ( - + + {data?.matchedMentors.map((match, idx) => ( + + ))} + {data?.matchedMentors.length === 0 && ( + + No matches found. + + )} + + + + + {data?.notMatchedMentors.map((mentor) => ( + ))} - {data?.matchedMentors.length === 0 && ( - - No matches found. - + {data?.notMatchedMentors.length === 0 && ( + + All mentors have recommendations. + )} - - - - - {data?.notMatchedMentors.map((mentor) => ( - - ))} - {data?.notMatchedMentors.length === 0 && ( - - All mentors have recommendations. - - )} - - + + - - - {data?.notMatchedMentees.map((mentee) => ( - - ))} - {data?.notMatchedMentees.length === 0 && ( - - All mentees have recommendations. - - )} - - + + + {data?.notMatchedMentees.map((mentee) => ( + + ))} + {data?.notMatchedMentees.length === 0 && ( + + All mentees have recommendations. + + )} + + - - - {appsLoading[3] ? ( - - ) : appsError[3] ? ( - {appsError[3]} - ) : ( - pendingApps.map((app) => ( - - )) - )} - {!appsLoading[3] && pendingApps.length === 0 && ( - No pending applications. - )} - - + + + {appsLoading[3] ? ( + + ) : appsError[3] ? ( + {appsError[3]} + ) : ( + pendingApps.map((app) => ( + + )) + )} + {!appsLoading[3] && pendingApps.length === 0 && ( + No pending applications. + )} + + - - - {appsLoading[4] ? ( - - ) : appsError[4] ? ( - {appsError[4]} - ) : ( - acceptedApps.map((app) => ( - - )) - )} - {!appsLoading[4] && acceptedApps.length === 0 && ( - No accepted applications. - )} - - + + + {appsLoading[4] ? ( + + ) : appsError[4] ? ( + {appsError[4]} + ) : ( + acceptedApps.map((app) => ( + + )) + )} + {!appsLoading[4] && acceptedApps.length === 0 && ( + No accepted applications. + )} + + - - - {appsLoading[5] ? ( - - ) : appsError[5] ? ( - {appsError[5]} - ) : ( - rejectedApps.map((app) => ( - - )) - )} - {!appsLoading[5] && rejectedApps.length === 0 && ( - No rejected applications. - )} - - - - - + + + {appsLoading[5] ? ( + + ) : appsError[5] ? ( + {appsError[5]} + ) : ( + rejectedApps.map((app) => ( + + )) + )} + {!appsLoading[5] && rejectedApps.length === 0 && ( + No rejected applications. + )} + + + + + ); } diff --git a/admin-wcc-app/services/mentorshipService.ts b/admin-wcc-app/services/mentorshipService.ts index ad7d642ed..2840e46fe 100644 --- a/admin-wcc-app/services/mentorshipService.ts +++ b/admin-wcc-app/services/mentorshipService.ts @@ -1,44 +1,44 @@ -import {apiFetch} from '@/lib/api'; -import {MenteeApplicationItem, MentorshipRecommendationResponse} from '@/types/mentorship'; +import { apiFetch } from '@/lib/api'; +import { MenteeApplicationItem, MentorshipRecommendationResponse } from '@/types/mentorship'; const MENTORSHIP_ADMIN_PATH = '/api/platform/v1/admin/mentorship'; const MENTEES_PATH = '/api/platform/v1/mentees'; export async function getMentorshipRecommendations( - token: string + token: string ): Promise { return apiFetch( - `${MENTORSHIP_ADMIN_PATH}/matches/recommendations`, - {token} + `${MENTORSHIP_ADMIN_PATH}/matches/recommendations`, + { token } ); } export async function getMenteeApplications( - cycleId: number, - statuses: string[], - token: string, - mentorId?: number + cycleId: number, + statuses: string[], + token: string, + mentorId?: number ): Promise { - const params = new URLSearchParams({status: statuses.join(',')}); + const params = new URLSearchParams({ status: statuses.join(',') }); if (mentorId !== undefined) { params.append('mentorId', String(mentorId)); } return apiFetch( - `${MENTORSHIP_ADMIN_PATH}/cycles/${cycleId}/applications?${params.toString()}`, - {token} + `${MENTORSHIP_ADMIN_PATH}/cycles/${cycleId}/applications?${params.toString()}`, + { token } ); } export async function createManualMatch( - menteeId: number | string, - cycleId: number | string, - mentorId: number | string, - token: string, - notes?: string + menteeId: number | string, + cycleId: number | string, + mentorId: number | string, + token: string, + notes?: string ): Promise { return apiFetch(`${MENTEES_PATH}/${menteeId}/cycles/${cycleId}/assign-mentor`, { method: 'POST', - body: {mentorId, notes}, + body: { mentorId, notes }, token, }); } diff --git a/admin-wcc-app/types/mentorship.ts b/admin-wcc-app/types/mentorship.ts index 10e39c0b3..3d93fa780 100644 --- a/admin-wcc-app/types/mentorship.ts +++ b/admin-wcc-app/types/mentorship.ts @@ -1,4 +1,4 @@ -import {MentorItem} from './mentor'; +import { MentorItem } from './mentor'; export interface MenteeItem { id: number; diff --git a/src/main/java/com/wcc/platform/domain/platform/mentorship/Mentor.java b/src/main/java/com/wcc/platform/domain/platform/mentorship/Mentor.java index 0e1dcf5f2..6a9d510b1 100644 --- a/src/main/java/com/wcc/platform/domain/platform/mentorship/Mentor.java +++ b/src/main/java/com/wcc/platform/domain/platform/mentorship/Mentor.java @@ -45,6 +45,7 @@ public class Mentor extends Member { private String calendlyLink; private Boolean acceptMale; private Boolean acceptPromotion; + private String meetingLink; /** Mentor Constructor. */ @SuppressWarnings("PMD.ExcessiveParameterList") @@ -72,7 +73,8 @@ public Mentor( final String calendlyLink, final Boolean acceptMale, final Boolean acceptPromotion, - final List memberTypes) { + final List memberTypes, + final String meetingLink) { super( id, fullName, @@ -100,6 +102,13 @@ public Mentor( this.acceptMale = acceptMale; this.acceptPromotion = acceptPromotion; this.memberTypes = memberTypes; + this.meetingLink = meetingLink; + } + + @Override + public void setMemberTypes(final List memberTypes) { + super.setMemberTypes(memberTypes); + this.memberTypes = memberTypes; } /** Checks for empty or null and returns a capitalized list of string. */ @@ -156,7 +165,8 @@ private MentorDtoBuilder buildFromMentor(final Mentor mentor) { .isWomen(mentor.getIsWomen()) .calendlyLink(mentor.getCalendlyLink()) .acceptMale(mentor.getAcceptMale()) - .acceptPromotion(mentor.getAcceptPromotion()); + .acceptPromotion(mentor.getAcceptPromotion()) + .meetingLink(mentor.getMeetingLink()); } /** Mentor Builder implementation to ensure proper inheritance. */ @@ -214,6 +224,11 @@ public B acceptPromotion(final Boolean acceptPromotion) { return (B) this; } + public B meetingLink(final String meetingLink) { + this.meetingLink = meetingLink; + return (B) this; + } + @Override public B memberTypes(final List memberTypes) { this.memberTypes = memberTypes; diff --git a/src/main/java/com/wcc/platform/domain/platform/mentorship/MentorDto.java b/src/main/java/com/wcc/platform/domain/platform/mentorship/MentorDto.java index 850811966..fa7781677 100644 --- a/src/main/java/com/wcc/platform/domain/platform/mentorship/MentorDto.java +++ b/src/main/java/com/wcc/platform/domain/platform/mentorship/MentorDto.java @@ -55,6 +55,7 @@ public class MentorDto extends MemberDto { private Boolean acceptMale; private Boolean acceptPromotion; private Boolean isWomen; + private String meetingLink; /** Mentor Builder. */ @SuppressWarnings("PMD.ExcessiveParameterList") @@ -81,7 +82,8 @@ public MentorDto( final Boolean isWomen, final String calendlyLink, final Boolean acceptMale, - final Boolean acceptPromotion) { + final Boolean acceptPromotion, + final String meetingLink) { super( id, fullName, @@ -110,6 +112,7 @@ public MentorDto( this.acceptMale = acceptMale; this.acceptPromotion = acceptPromotion; this.isWomen = isWomen; + this.meetingLink = meetingLink; } /** @@ -143,6 +146,7 @@ public Mentor toMentor() { .calendlyLink(getCalendlyLink()) .acceptMale(getAcceptMale()) .acceptPromotion(getAcceptPromotion()) + .meetingLink(getMeetingLink()) .build(); } @@ -183,6 +187,7 @@ public Mentor merge(final Mentor mentor) { .calendlyLink(mergeString(this.getCalendlyLink(), mentor.getCalendlyLink())) .acceptMale(mergeNullable(this.getAcceptMale(), mentor.getAcceptMale())) .acceptPromotion(mergeNullable(this.getAcceptPromotion(), mentor.getAcceptPromotion())) + .meetingLink(mergeString(this.getMeetingLink(), mentor.getMeetingLink())) .build(); } diff --git a/src/main/java/com/wcc/platform/repository/postgres/component/MentorMapper.java b/src/main/java/com/wcc/platform/repository/postgres/component/MentorMapper.java index c11e668bf..12c141340 100644 --- a/src/main/java/com/wcc/platform/repository/postgres/component/MentorMapper.java +++ b/src/main/java/com/wcc/platform/repository/postgres/component/MentorMapper.java @@ -61,7 +61,8 @@ public Mentor mapRowToMentor(final ResultSet rs) throws SQLException { .bio(rs.getString(COLUMN_BIO)) .calendlyLink(rs.getString(COL_CALENDLY_LINK)) .acceptMale(rs.getBoolean(COL_ACCEPT_MALE)) - .acceptPromotion(rs.getBoolean(COL_ACCEPT_PROMO)); + .acceptPromotion(rs.getBoolean(COL_ACCEPT_PROMO)) + .meetingLink(rs.getString(COL_MEET_LINK)); return builder.build(); } diff --git a/src/main/java/com/wcc/platform/repository/postgres/constants/MentorConstants.java b/src/main/java/com/wcc/platform/repository/postgres/constants/MentorConstants.java index eeb7d1752..4d75a242f 100644 --- a/src/main/java/com/wcc/platform/repository/postgres/constants/MentorConstants.java +++ b/src/main/java/com/wcc/platform/repository/postgres/constants/MentorConstants.java @@ -12,6 +12,7 @@ public final class MentorConstants { public static final String COL_CALENDLY_LINK = "calendly_link"; public static final String COL_ACCEPT_MALE = "accept_male_mentee"; public static final String COL_ACCEPT_PROMO = "accept_promote_social_media"; + public static final String COL_MEET_LINK = "meeting_link"; // MENTOR_MENTEE_SECTION table public static final String COLUMN_IDEAL_MENTEE = "ideal_mentee"; diff --git a/src/main/java/com/wcc/platform/repository/postgres/mentorship/PostgresMentorRepository.java b/src/main/java/com/wcc/platform/repository/postgres/mentorship/PostgresMentorRepository.java index 498c21dc4..0f3bee9a7 100644 --- a/src/main/java/com/wcc/platform/repository/postgres/mentorship/PostgresMentorRepository.java +++ b/src/main/java/com/wcc/platform/repository/postgres/mentorship/PostgresMentorRepository.java @@ -46,7 +46,8 @@ public class PostgresMentorRepository implements MentorRepository { + "is_available = ?, " + "calendly_link = ?, " + "accept_male_mentee = ?, " - + "accept_promote_social_media = ? " + + "accept_promote_social_media = ?, " + + "meeting_link = ? " + "WHERE mentor_id = ?"; private static final String SQL_SET_MENTOR_STATUS = "UPDATE mentors SET profile_status = ? WHERE mentor_id = ?"; @@ -55,7 +56,7 @@ public class PostgresMentorRepository implements MentorRepository { private static final String SQL_INSERT_MENTOR = "INSERT INTO mentors (mentor_id, profile_status, bio, years_experience, " + " spoken_languages, is_available, calendly_link, " - + " accept_male_mentee, accept_promote_social_media) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + " accept_male_mentee, accept_promote_social_media, meeting_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String SQL_GET_BY_ID = "SELECT * FROM mentors WHERE mentor_id = ?"; private static final String SQL_DELETE_BY_ID = "DELETE FROM mentors WHERE mentor_id = ?"; private static final String SQL_GET_BY_EMAIL = @@ -227,7 +228,8 @@ private void insertMentor(final Mentor mentor, final Long memberId) { true, mentor.getCalendlyLink(), mentor.getAcceptMale(), - mentor.getAcceptPromotion()); + mentor.getAcceptPromotion(), + mentor.getMeetingLink()); } /** @@ -251,6 +253,7 @@ private void updateMentorDetails(final Mentor mentor, final Long mentorId) { mentor.getCalendlyLink(), mentor.getAcceptMale(), mentor.getAcceptPromotion(), + mentor.getMeetingLink(), mentorId); } } diff --git a/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java b/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java index 0ac6eb529..0a8558195 100644 --- a/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java +++ b/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java @@ -136,7 +136,7 @@ public void sendPairingConfirmation( "mentor_email", mentor.getEmail(), "mentee_email", mentee.getEmail(), "mentor_calendly_link", Optional.ofNullable(mentor.getCalendlyLink()).orElse(""), - "meeting_link", "", + "meeting_link", Optional.ofNullable(mentor.getMeetingLink()).orElse(""), "month", month.getDisplayName(TextStyle.FULL, Locale.ENGLISH), "year", year), List.of(mentor.getEmail(), mentee.getEmail(), notificationConfig.getMentorshipEmail())); diff --git a/src/main/java/com/wcc/platform/service/MentorshipService.java b/src/main/java/com/wcc/platform/service/MentorshipService.java index d507416fb..ef60de3bf 100644 --- a/src/main/java/com/wcc/platform/service/MentorshipService.java +++ b/src/main/java/com/wcc/platform/service/MentorshipService.java @@ -98,6 +98,8 @@ public Mentor create(final Mentor mentor) { .calendlyLink(mentor.getCalendlyLink()) .acceptMale(mentor.getAcceptMale()) .acceptPromotion(mentor.getAcceptPromotion()) + .meetingLink(mentor.getMeetingLink()) + .memberTypes(mentor.getMemberTypes()) .build(); return mentorRepository.create(mentorWithExistingId); @@ -217,6 +219,7 @@ private MentorDto enrichWithProfilePicture(final MentorDto dto) { .calendlyLink(dto.getCalendlyLink()) .acceptMale(dto.getAcceptMale()) .acceptPromotion(dto.getAcceptPromotion()) + .meetingLink(dto.getMeetingLink()) .build(); } @@ -235,6 +238,7 @@ private Mentor enrichMentorWithProfilePicture(final Mentor mentor) { .slackDisplayName(mentor.getSlackDisplayName()) .country(mentor.getCountry()) .city(mentor.getCity()) + .memberTypes(mentor.getMemberTypes()) .companyName(mentor.getCompanyName()) .images(List.of(profilePicture.get())) .network(mentor.getNetwork()) @@ -251,6 +255,7 @@ private Mentor enrichMentorWithProfilePicture(final Mentor mentor) { .calendlyLink(mentor.getCalendlyLink()) .acceptMale(mentor.getAcceptMale()) .acceptPromotion(mentor.getAcceptPromotion()) + .meetingLink(mentor.getMeetingLink()) .build(); } diff --git a/src/test/java/com/wcc/platform/domain/platform/mentorship/MentorDtoTest.java b/src/test/java/com/wcc/platform/domain/platform/mentorship/MentorDtoTest.java index 2e2975fd4..9bc778ca4 100644 --- a/src/test/java/com/wcc/platform/domain/platform/mentorship/MentorDtoTest.java +++ b/src/test/java/com/wcc/platform/domain/platform/mentorship/MentorDtoTest.java @@ -100,7 +100,7 @@ void shouldReturnStringOfMentor() { + "skills=null, spokenLanguages=[English, Spanish], bio=bio info," + " menteeSection=null, feedbackSection=null, resources=null, " + "calendlyLink=null, acceptMale=null, acceptPromotion=null, " - + "isWomen=null)"; + + "isWomen=null, meetingLink=null)"; assertEquals(expected, mentor.toString()); } diff --git a/src/test/java/com/wcc/platform/service/MentorshipServiceTest.java b/src/test/java/com/wcc/platform/service/MentorshipServiceTest.java index 1602cb914..5197e0ff7 100644 --- a/src/test/java/com/wcc/platform/service/MentorshipServiceTest.java +++ b/src/test/java/com/wcc/platform/service/MentorshipServiceTest.java @@ -221,6 +221,7 @@ void shouldPreserveAllFieldsWhenMentorReRegistersWithExistingEmail() { when(mentor.getCalendlyLink()).thenReturn("https://calendly.com/myname"); when(mentor.getAcceptMale()).thenReturn(true); when(mentor.getAcceptPromotion()).thenReturn(false); + when(mentor.getMeetingLink()).thenReturn("https://google.com/meet/name"); Member existingMember = Member.builder() @@ -248,6 +249,7 @@ void shouldPreserveAllFieldsWhenMentorReRegistersWithExistingEmail() { assertThat(captured.getAcceptPromotion()).isFalse(); assertThat(captured.getSkills()).isEqualTo(skills); assertThat(captured.getMenteeSection()).isEqualTo(menteeSection); + assertThat(captured.getMeetingLink()).isEqualTo("https://google.com/meet/name"); } @Test diff --git a/src/testInt/java/com/wcc/platform/service/mentorship/MentorshipServiceIntegrationTest.java b/src/testInt/java/com/wcc/platform/service/mentorship/MentorshipServiceIntegrationTest.java index a66bf8af5..877c6f857 100644 --- a/src/testInt/java/com/wcc/platform/service/mentorship/MentorshipServiceIntegrationTest.java +++ b/src/testInt/java/com/wcc/platform/service/mentorship/MentorshipServiceIntegrationTest.java @@ -227,6 +227,7 @@ void shouldReturnMentorsWithPronounsFromDatabase() { .calendlyLink(baseMentor.getCalendlyLink()) .acceptMale(baseMentor.getAcceptMale()) .acceptPromotion(baseMentor.getAcceptPromotion()) + .meetingLink(baseMentor.getMeetingLink()) .build(); memberRepository.deleteByEmail(mentor.getEmail());