Skip to content

Commit

Permalink
feat:implement loading student summary using nestjs (#2471)
Browse files Browse the repository at this point in the history
* feat: implement nestjs route returning mock data

* feat: implement getting student summary from new api

* refactor: fix eslint issue

* fix: fixed incorrect display of technical screening results on student dashboard page

* refactor: remove unused code

* refactor: remove redundant code

* refactor: fix linter issue

* fix: fix student summary api response type

* fix: throw not found error when student is not found

* fix: reactor if-else to ternary operation

* refactor: rewrite database queries

* refactor: make function getCurrentTaskScore more readable

* refactor:refactor getStudentSummary function return statement

* refactor: update course-student.service.ts imports not to use files from commons

* refactor: use StudentSummaryDto instead of (MentorBasic & MentorContact)

* reafactor: remove unused code

* refactor: avoid using 'me' to load student summary data

* refactor: fix syntax error at comment

* refactor: shorten return statement at getStageInterviewRating function

* refactor: remove unused import

* refactor: avoid using unnecessary typecast

* refactor: add destructuring to convertToMentorBasic function

* refactor: remove types duplication

* refactor: fix eslint error

* fix: fix merge issues

* refactor: fix eslint issue

---------

Co-authored-by: Maksim Shylau <[email protected]>
  • Loading branch information
Alphajax and AlreadyBored authored Jul 11, 2024
1 parent 1f4be2d commit 0ed6eba
Show file tree
Hide file tree
Showing 18 changed files with 654 additions and 47 deletions.
217 changes: 217 additions & 0 deletions client/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3905,6 +3905,91 @@ export interface MentorStudentDto {
*/
'repoUrl': string | null;
}
/**
*
* @export
* @interface MentorStudentSummaryDto
*/
export interface MentorStudentSummaryDto {
/**
*
* @type {number}
* @memberof MentorStudentSummaryDto
*/
'id': number;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'githubId': string;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'name': string;
/**
*
* @type {boolean}
* @memberof MentorStudentSummaryDto
*/
'isActive': boolean;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'cityName': string;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'countryName': string;
/**
*
* @type {Array<string>}
* @memberof MentorStudentSummaryDto
*/
'students': Array<string>;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'contactsEmail': string | null;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'contactsPhone': string | null;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'contactsSkype': string | null;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'contactsTelegram': string | null;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'contactsNotes': string | null;
/**
*
* @type {string}
* @memberof MentorStudentSummaryDto
*/
'contactsWhatsApp': string | null;
}
/**
*
* @export
Expand Down Expand Up @@ -4449,6 +4534,25 @@ export interface PutInterviewFeedbackDto {
*/
'score'?: number;
}
/**
*
* @export
* @interface ResultDto
*/
export interface ResultDto {
/**
*
* @type {number}
* @memberof ResultDto
*/
'score'?: number;
/**
*
* @type {number}
* @memberof ResultDto
*/
'courseTaskId'?: number;
}
/**
*
* @export
Expand Down Expand Up @@ -5230,6 +5334,49 @@ export interface StudentId {
*/
'id': number;
}
/**
*
* @export
* @interface StudentSummaryDto
*/
export interface StudentSummaryDto {
/**
*
* @type {number}
* @memberof StudentSummaryDto
*/
'totalScore': number;
/**
*
* @type {Array<ResultDto>}
* @memberof StudentSummaryDto
*/
'results': Array<ResultDto>;
/**
*
* @type {boolean}
* @memberof StudentSummaryDto
*/
'isActive': boolean;
/**
*
* @type {MentorStudentSummaryDto}
* @memberof StudentSummaryDto
*/
'mentor': MentorStudentSummaryDto | null;
/**
*
* @type {number}
* @memberof StudentSummaryDto
*/
'rank': number;
/**
*
* @type {string}
* @memberof StudentSummaryDto
*/
'repository': string | null;
}
/**
*
* @export
Expand Down Expand Up @@ -15915,6 +16062,43 @@ export const StudentsApiAxiosParamCreator = function (configuration?: Configurat



setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};

return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {number} courseId
* @param {string} githubId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getStudentSummary: async (courseId: number, githubId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'courseId' is not null or undefined
assertParamExists('getStudentSummary', 'courseId', courseId)
// verify required parameter 'githubId' is not null or undefined
assertParamExists('getStudentSummary', 'githubId', githubId)
const localVarPath = `/courses/{courseId}/students/{githubId}/summary`
.replace(`{${"courseId"}}`, encodeURIComponent(String(courseId)))
.replace(`{${"githubId"}}`, encodeURIComponent(String(githubId)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}

const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;



setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
Expand Down Expand Up @@ -16012,6 +16196,17 @@ export const StudentsApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.getStudent(studentId, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {number} courseId
* @param {string} githubId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getStudentSummary(courseId: number, githubId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<StudentSummaryDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getStudentSummary(courseId, githubId, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} current
Expand Down Expand Up @@ -16047,6 +16242,16 @@ export const StudentsApiFactory = function (configuration?: Configuration, baseP
getStudent(studentId: number, options?: any): AxiosPromise<StudentDto> {
return localVarFp.getStudent(studentId, options).then((request) => request(axios, basePath));
},
/**
*
* @param {number} courseId
* @param {string} githubId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getStudentSummary(courseId: number, githubId: string, options?: any): AxiosPromise<StudentSummaryDto> {
return localVarFp.getStudentSummary(courseId, githubId, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} current
Expand Down Expand Up @@ -16083,6 +16288,18 @@ export class StudentsApi extends BaseAPI {
return StudentsApiFp(this.configuration).getStudent(studentId, options).then((request) => request(this.axios, this.basePath));
}

/**
*
* @param {number} courseId
* @param {string} githubId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof StudentsApi
*/
public getStudentSummary(courseId: number, githubId: string, options?: AxiosRequestConfig) {
return StudentsApiFp(this.configuration).getStudentSummary(courseId, githubId, options).then((request) => request(this.axios, this.basePath));
}

/**
*
* @param {string} current
Expand Down
6 changes: 3 additions & 3 deletions client/src/modules/Home/components/HomeSummary/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Card, Col, Row, Statistic, Typography } from 'antd';
import { StudentSummaryDto } from 'api';
import { GithubUserLink } from 'components/GithubUserLink';
import * as React from 'react';
import { StudentSummary } from 'services/course';

type Props = {
summary: StudentSummary;
summary: StudentSummaryDto;
courseTasks: { id: number }[];
};

Expand All @@ -19,7 +19,7 @@ export function HomeSummary({ summary, courseTasks }: Props) {
contactsNotes,
contactsWhatsApp,
} = summary.mentor ?? {};
const tasksCount = summary.results.filter(r => r.score > 0).length;
const tasksCount = summary.results.filter(r => Number(r.score) > 0).length;
const totalTaskCount = courseTasks.length;

const contacts = [
Expand Down
4 changes: 2 additions & 2 deletions client/src/modules/Home/data/loadHomeData.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { CoursesTasksApi } from 'api';
import { CourseService } from 'services/course';

export async function loadHomeData(courseId: number) {
export async function loadHomeData(courseId: number, githubId: string) {
const [studentSummary, { data: courseTasks }] = await Promise.all([
new CourseService(courseId).getStudentSummary('me'),
new CourseService(courseId).getStudentSummary(githubId),
new CoursesTasksApi().getCourseTasks(courseId),
]);
return {
Expand Down
6 changes: 3 additions & 3 deletions client/src/modules/Home/hooks/useStudentSummary.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { StudentSummaryDto } from 'api';
import { Session } from 'components/withSession';
import { isStudent } from 'domain/user';
import { loadHomeData } from 'modules/Home/data/loadHomeData';
import { useState } from 'react';
import { useAsync } from 'react-use';
import { StudentSummary } from 'services/course';
import { Course } from 'services/models';

export function useStudentSummary(session: Session, course: Course | null) {
const [studentSummary, setStudentSummary] = useState<StudentSummary | null>(null);
const [studentSummary, setStudentSummary] = useState<StudentSummaryDto | null>(null);
const [courseTasks, setCourseTasks] = useState<{ id: number }[]>([]);

useAsync(async () => {
const showData = course && isStudent(session, course.id);
const data = showData ? await loadHomeData(course.id) : null;
const data = showData ? await loadHomeData(course.id, session.githubId) : null;
setStudentSummary(data?.studentSummary ?? null);
setCourseTasks(data?.courseTasks ?? []);
}, [course]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Col, Typography, Row } from 'antd';
import { MentorBasic } from 'common/models';
import CommonCard from '../CommonDashboardCard';
import { MentorContact, MentorInfo } from '../MentorInfo';
import { MentorInfo } from '../MentorInfo';
import { SubmitTaskSolution } from '../SubmitTaskSolution';
import { MentorStudentSummaryDto } from 'api';

export type MentorCardProps = {
mentor?: (MentorBasic & MentorContact) | null;
mentor?: MentorStudentSummaryDto | null;
courseId: number;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Col, Row, Space, Typography } from 'antd';
import React from 'react';
import { MentorBasic } from 'common/models';
import GithubFilled from '@ant-design/icons/GithubFilled';
import EnvironmentFilled from '@ant-design/icons/EnvironmentFilled';
import { GithubAvatar } from 'components/GithubAvatar';
import { MentorStudentSummaryDto } from 'api';

const { Text, Link } = Typography;

Expand All @@ -15,10 +15,8 @@ export interface MentorContact {
contactsNotes?: string;
}

type Contact = { name: string; value: string | undefined };

interface Props {
mentor: MentorBasic & MentorContact;
mentor: MentorStudentSummaryDto;
}

function MentorInfo({ mentor }: Props) {
Expand All @@ -42,7 +40,7 @@ function MentorInfo({ mentor }: Props) {
{ name: 'Notes', value: contactsNotes },
];

const filledContacts = contacts.filter(({ value }: Contact) => value);
const filledContacts = contacts.filter(({ value }) => value);

return (
<div style={{ marginBottom: 16 }}>
Expand Down
5 changes: 3 additions & 2 deletions client/src/pages/course/student/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import omitBy from 'lodash/omitBy';
import { LoadingScreen } from 'components/LoadingScreen';
import { PageLayout } from 'components/PageLayout';

import { CourseService, StudentSummary } from 'services/course';
import { CourseService } from 'services/course';
import { UserService } from 'services/user';
import {
MainStatsCard,
Expand All @@ -29,6 +29,7 @@ import {
CourseScheduleItemDtoStatusEnum,
AvailableReviewStatsDto,
CourseScheduleItemDtoTypeEnum,
StudentSummaryDto,
} from 'api';
import { ActiveCourseProvider, SessionContext, SessionProvider, useActiveCourseContext } from 'modules/Course/contexts';

Expand All @@ -44,7 +45,7 @@ function Page() {
const courseService = useMemo(() => new CourseService(course.id), [course.id]);
const userService = useMemo(() => new UserService(), []);

const [studentSummary, setStudentSummary] = useState({} as StudentSummary);
const [studentSummary, setStudentSummary] = useState<StudentSummaryDto>();
const [repositoryUrl, setRepositoryUrl] = useState('');
const [courseTasks, setCourseTasks] = useState<CourseTaskDto[]>([]);
const [nextEvents, setNextEvent] = useState([] as CourseScheduleItemDto[]);
Expand Down
Loading

0 comments on commit 0ed6eba

Please sign in to comment.