diff --git a/client/src/components/Profile/MentorStatsCard.tsx b/client/src/components/Profile/MentorStatsCard.tsx index 44ea9fc639..75b00a5250 100644 --- a/client/src/components/Profile/MentorStatsCard.tsx +++ b/client/src/components/Profile/MentorStatsCard.tsx @@ -1,134 +1,129 @@ -import * as React from 'react'; -import isEqual from 'lodash/isEqual'; +import { useMemo, useState } from 'react'; import { List, Typography, Button, Tag } from 'antd'; import CommonCard from './CommonCard'; import MentorStatsModal from './MentorStatsModal'; import { MentorStats, Student } from 'common/models/profile'; -import { TeamOutlined, FullscreenOutlined } from '@ant-design/icons'; +import { TeamOutlined, FullscreenOutlined, FileTextOutlined } from '@ant-design/icons'; +import { MentorEndorsement } from 'modules/Profile/components/MentorEndorsement'; const { Text } = Typography; type Props = { + isAdmin?: boolean; + githubId: string; data: MentorStats[]; }; -type State = { - courseIndex: number; - isMentorStatsModalVisible: boolean; -}; - -class MentorStatsCard extends React.Component { - state = { - courseIndex: 0, - isMentorStatsModalVisible: false, - }; +export function MentorStatsCard(props: Props) { + const [courseIndex, setCourseIndex] = useState(0); + const [isMentorStatsModalVisible, setIsMentorStatsModalVisible] = useState(false); + const [isEndorsmentModalVisible, setIsEndorsmentModalVisible] = useState(false); - private showMentorStatsModal = (courseIndex: number) => { - this.setState({ courseIndex, isMentorStatsModalVisible: true }); + const showMentorStatsModal = (courseIndex: number) => { + setCourseIndex(courseIndex); + setIsMentorStatsModalVisible(true); }; - private hideMentortStatsModal = () => { - this.setState({ isMentorStatsModalVisible: false }); + const hideMentortStatsModal = () => { + setIsMentorStatsModalVisible(false); }; - private countStudents = (data: MentorStats[]) => - data.reduce((acc: Student[], cur: MentorStats) => (cur?.students?.length ? acc.concat(cur.students) : acc), []) - .length; + const stats = props.data; + const count = useMemo( + () => props.data.reduce((acc, cur) => acc.concat(cur.students ?? []), []).length, + [], + ); - shouldComponentUpdate = (_nextProps: Props, nextState: State) => - !isEqual(nextState.isMentorStatsModalVisible, this.state.isMentorStatsModalVisible); - - render() { - const stats = this.props.data; - const { courseIndex, isMentorStatsModalVisible } = this.state; - - return ( - <> - - } - content={ - <> -
-

- Mentored Students:{' '} - - {this.countStudents(stats)} - -

-

- Courses as Mentor:{' '} - - {stats.length} - -

-
- ( - -
-

- - {courseName} - {courseLocationName && ` / ${courseLocationName}`} - -

- {students ? ( - idx === 0 && ( - ( - -
-

- {name}{' '} - {isExpelled ? expelled : active} -

-

- Score: {totalScore} -

-
-
- )} - /> - ) - ) : ( -

Does not have students at this course yet

- )} -
- {students && ( - + return ( + <> + + setIsEndorsmentModalVisible(false)} + open={isEndorsmentModalVisible} + githubId={props.githubId} + /> + } + content={ + <> +
+

+ Mentored Students:{' '} + + {count} + +

+

+ Courses as Mentor:{' '} + + {stats.length} + +

+
+ {props.isAdmin ? ( + + ) : null} + ( + +
+

+ + {courseName} + {courseLocationName && ` / ${courseLocationName}`} + +

+ {students ? ( + idx === 0 && ( + ( + +
+

+ {name}{' '} + {isExpelled ? expelled : active} +

+

+ Score: {totalScore} +

+
+
+ )} + /> + ) + ) : ( +

Does not have students at this course yet

)} - - )} - /> - - } - /> - - ); - } +
+ {students && ( + + )} +
+ )} + /> + + } + /> + + ); } - -export default MentorStatsCard; diff --git a/client/src/components/Profile/__test__/MentorStatsCard.test.tsx b/client/src/components/Profile/__test__/MentorStatsCard.test.tsx index 386d083e85..f78240cbd8 100644 --- a/client/src/components/Profile/__test__/MentorStatsCard.test.tsx +++ b/client/src/components/Profile/__test__/MentorStatsCard.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { render } from '@testing-library/react'; -import MentorStatsCard from '../MentorStatsCard'; +import { MentorStatsCard } from '../MentorStatsCard'; describe('MentorStatsCard', () => { const mentorStats = [ @@ -31,7 +31,7 @@ describe('MentorStatsCard', () => { ]; it('should render correctly', () => { - const { container } = render(); + const { container } = render(); expect(container).toMatchSnapshot(); }); }); diff --git a/client/src/modules/Mentor/components/MentorEndorsement/MentorEndorsement.tsx b/client/src/modules/Profile/components/MentorEndorsement/MentorEndorsement.tsx similarity index 76% rename from client/src/modules/Mentor/components/MentorEndorsement/MentorEndorsement.tsx rename to client/src/modules/Profile/components/MentorEndorsement/MentorEndorsement.tsx index c8cb3f253b..650be0ef51 100644 --- a/client/src/modules/Mentor/components/MentorEndorsement/MentorEndorsement.tsx +++ b/client/src/modules/Profile/components/MentorEndorsement/MentorEndorsement.tsx @@ -1,4 +1,4 @@ -import { Input, Modal, Spin, Typography } from 'antd'; +import { Alert, Input, Modal, Spin, Typography } from 'antd'; import { useMemo } from 'react'; import { ProfileApi } from 'api'; import { useAsync } from 'react-use'; @@ -7,31 +7,42 @@ import isObject from 'lodash/isObject'; import omitBy from 'lodash/omitBy'; export interface Props { - githubId: string | null; + open: boolean; + githubId: string; onClose: () => void; } const api = new ProfileApi(); export function MentorEndorsement(props: Props) { - const { value, loading } = useAsync(async () => { - if (props.githubId) { + const { value, loading, error } = useAsync(async () => { + if (props.open) { const { data } = await api.getEndorsement(props.githubId); return data; } - }, [props.githubId]); + }, [props.githubId, props.open]); const data = useMemo(() => (value?.data ? cleanData(value.data) : null), [value?.data]); + return ( -
+
+ {error ? ( + + ) : null} + {value ? ( <> Generated Text @@ -46,6 +57,7 @@ export function MentorEndorsement(props: Props) { ) : null}
+ {data ? (
Data Model diff --git a/client/src/modules/Mentor/components/MentorEndorsement/index.tsx b/client/src/modules/Profile/components/MentorEndorsement/index.tsx similarity index 100% rename from client/src/modules/Mentor/components/MentorEndorsement/index.tsx rename to client/src/modules/Profile/components/MentorEndorsement/index.tsx diff --git a/client/src/pages/course/admin/mentors.tsx b/client/src/pages/course/admin/mentors.tsx index 60a068baea..ca339d70eb 100644 --- a/client/src/pages/course/admin/mentors.tsx +++ b/client/src/pages/course/admin/mentors.tsx @@ -6,7 +6,6 @@ import { AssignStudentModal } from 'components/Student'; import { PersonCell, getColumnSearchProps, numberSorter, stringSorter } from 'components/Table'; import withCourseData from 'components/withCourseData'; import { Session, withSession } from 'components/withSession'; -import { MentorEndorsement } from 'modules/Mentor/components/MentorEndorsement'; import { MenuInfo } from 'rc-menu/lib/interface'; import { useMemo, useState } from 'react'; import { useAsync } from 'react-use'; @@ -53,7 +52,6 @@ function Page(props: CoursePageProps) { const [loading, setLoading] = useState(false); const [stats, setStats] = useState(null as Stats | null); const [mentors, setMentors] = useState([]); - const [endorsementGithubId, setEndorsementGithubId] = useState(null); const [currentMentor, setCurrentMentor] = useState(null); const [modal, contextHolder] = Modal.useModal(); @@ -151,9 +149,6 @@ function Page(props: CoursePageProps) { title: 'Do you want to restore the mentor?', }); break; - case 'endorsment': - setEndorsementGithubId(mentor.githubId); - break; } }; @@ -306,7 +301,6 @@ function Page(props: CoursePageProps) { }, ]} /> - setEndorsementGithubId(null)} githubId={endorsementGithubId} /> setCurrentMentor(null)} courseId={courseId} diff --git a/client/src/pages/profile/index.tsx b/client/src/pages/profile/index.tsx index b15d6a300a..bcfbffff62 100644 --- a/client/src/pages/profile/index.tsx +++ b/client/src/pages/profile/index.tsx @@ -14,7 +14,7 @@ import EducationCard from 'components/Profile/EducationCard'; import ContactsCard from 'components/Profile/ContactsCard'; import PublicFeedbackCard from 'components/Profile/PublicFeedbackCard'; import StudentStatsCard from 'components/Profile/StudentStatsCard'; -import MentorStatsCard from 'components/Profile/MentorStatsCard'; +import { MentorStatsCard } from 'components/Profile/MentorStatsCard'; import CoreJsIviewsCard from 'components/Profile/CoreJsIviewsCard'; import LanguagesCard from 'components/Profile/LanguagesCard'; import { CoreJsInterviewsData } from 'components/Profile/CoreJsIviewsCard'; @@ -196,6 +196,9 @@ export class ProfilePage extends React.Component { const aboutMyself = profile?.generalInfo?.aboutMyself ?? ''; const languages = profile?.generalInfo?.languages ?? []; + const githubId = this.props.session.githubId; + const isAdmin = this.props.session.isAdmin; + const cards = [ profile?.generalInfo && ( @@ -237,7 +240,9 @@ export class ProfilePage extends React.Component { isProfileOwner={isProfileOwner} /> ), - profile?.mentorStats?.length && , + profile?.mentorStats?.length && githubId && ( + + ), profile?.studentStats?.length && this.hadStudentCoreJSInterview(profile.studentStats) && ( ),