Skip to content

Commit

Permalink
Merge pull request #160 from GDSC-Hongik/feature/students-pagination
Browse files Browse the repository at this point in the history
[Feature] 스터디 수강생 페이지네이션 적용, 엑셀 다운로드
  • Loading branch information
hamo-o authored Nov 10, 2024
2 parents fc7196b + 0d094b3 commit fbefe9e
Show file tree
Hide file tree
Showing 37 changed files with 617 additions and 988 deletions.
19 changes: 16 additions & 3 deletions apps/admin/apis/study/studyApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import type {
import type { AttendanceApiResponseDto } from "types/dtos/attendance";
import type { CurriculumApiResponseDto } from "types/dtos/curriculumList";
import type { StudyBasicInfoApiResponseDto } from "types/dtos/studyBasicInfo";
import type { StudyStudentApiResponseDto } from "types/dtos/studyStudent";
import type { PaginatedStudyStudentResponseDto } from "types/dtos/studyStudent";
import type { PageableType } from "types/entities/page";
import type { StudyAnnouncementType } from "types/entities/study";

import type { StudyListApiResponseDto } from "../../types/dtos/studyList";
Expand Down Expand Up @@ -149,14 +150,26 @@ export const studyApi = {
);
return response.data;
},
getStudyStudents: async (studyId: number) => {
const response = await fetcher.get<StudyStudentApiResponseDto[]>(
getStudyStudents: async (studyId: number, pageable: PageableType) => {
const response = await fetcher.get<PaginatedStudyStudentResponseDto>(
`/mentor/studies/${studyId}/students`,
{
next: { tags: [tags.students] },
cache: "force-cache",
},
pageable
);
return response.data;
},
getStudyStudentsExcel: async (studyId: number) => {
const response = await fetcher.get(
`/mentor/studies/${studyId}/students/excel`,
{
next: { tags: [tags.studentsExcel] },
cache: "force-cache",
}
);

return response.data;
},
};
13 changes: 13 additions & 0 deletions apps/admin/app/students/_components/StudentFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Flex } from "@styled-system/jsx";
import Chip from "wowds-ui/Chip";

const StudentFilter = () => {
return (
<Flex gap="0.5rem">
<Chip clickable label="우수 회원 보기" />
<Chip clickable label="수료 회원 보기" />
</Flex>
);
};

export default StudentFilter;
50 changes: 0 additions & 50 deletions apps/admin/app/students/_components/StudentList.tsx

This file was deleted.

51 changes: 0 additions & 51 deletions apps/admin/app/students/_components/StudentListItem.tsx

This file was deleted.

20 changes: 20 additions & 0 deletions apps/admin/app/students/_components/StudentPagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { PaginatedStudyStudentResponseDto } from "types/dtos/studyStudent";
import Pagination from "wowds-ui/Pagination";

const StudentPagination = ({
pageInfo,
handleClickChangePage,
}: {
pageInfo: Omit<PaginatedStudyStudentResponseDto, "content"> | null;
handleClickChangePage: (nextPage: number) => void;
}) => {
if (!pageInfo || !pageInfo.numberOfElements) return null;
return (
<Pagination
totalPages={pageInfo.totalPages}
onChange={handleClickChangePage}
/>
);
};

export default StudentPagination;
51 changes: 51 additions & 0 deletions apps/admin/app/students/_components/StudentTable/StudentList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Text } from "@wow-class/ui";
import type { StudyStudentApiResponseDto } from "types/dtos/studyStudent";
import Table from "wowds-ui/Table";

import StudentListItem from "./StudentListItem";
import { StudyTasksThs } from "./StudyTasks";

const STUENT_INFO_LIST_BEFORE = [
"수료",
"1차 우수회원",
"2차 우수회원",
"이름",
"학번",
"디스코드 사용자명",
"디스코드 닉네임",
"깃허브 링크",
];

const STUDENT_INFO_LIST_AFTER = ["출석률", "과제 수행률", "전체 수행정도"];

const StudentList = ({
studentList,
}: {
studentList: StudyStudentApiResponseDto[] | [];
}) => {
if (!studentList) return null;
if (!studentList.length) return <Text>스터디 수강생이 없어요.</Text>;

return (
<Table>
<Table.Thead>
{STUENT_INFO_LIST_BEFORE.map((info) => (
<Table.Th key={info}>{info}</Table.Th>
))}
{studentList[0] && <StudyTasksThs tasks={studentList[0].studyTasks} />}
{STUDENT_INFO_LIST_AFTER.map((info) => (
<Table.Th key={info}>{info}</Table.Th>
))}
</Table.Thead>
<Table.Tbody>
{studentList.map((student) => (
<Table.Tr key={student.memberId} value={student.memberId}>
<StudentListItem {...student} />
</Table.Tr>
))}
</Table.Tbody>
</Table>
);
};

export default StudentList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { AwardIcon, StarCheckIcon, Text } from "@wow-class/ui";
import Link from "next/link";
import type { CSSProperties } from "react";
import type { StudyStudentApiResponseDto } from "types/dtos/studyStudent";
import { formatNumberToPercent } from "utils/formatNumber";
import Table from "wowds-ui/Table";
import TextButton from "wowds-ui/TextButton";

import { StudyTasksTds } from "./StudyTasks";

const StudentListItem = ({
studyHistoryStatus,
isFirstRoundOutstandingStudent,
isSecondRoundOutstandingStudent,
name,
studentId,
discordUsername,
nickname,
githubLink,
studyTasks,
assignmentRate,
attendanceRate,
}: StudyStudentApiResponseDto) => {
return (
<>
<Table.Td>
<StarCheckIcon checked={studyHistoryStatus === "COMPLETED"} />
</Table.Td>
<Table.Td>
<Text style={awardTextStyle} typo="body2">
<AwardIcon disabled={!isFirstRoundOutstandingStudent} />
1차
</Text>
</Table.Td>
<Table.Td>
<Text style={awardTextStyle} typo="body2">
<AwardIcon disabled={!isSecondRoundOutstandingStudent} />
2차
</Text>
</Table.Td>
<Table.Td>{name}</Table.Td>
<Table.Td>{studentId}</Table.Td>
<Table.Td>{discordUsername}</Table.Td>
<Table.Td>{nickname}</Table.Td>
<Table.Td>
<TextButton
asProp={Link}
href={githubLink || ""}
style={textButtonStyle}
text={githubLink}
/>
</Table.Td>
<StudyTasksTds tasks={studyTasks} />
<Table.Td>{formatNumberToPercent(assignmentRate)}</Table.Td>
<Table.Td>{formatNumberToPercent(attendanceRate)}</Table.Td>
</>
);
};

const textButtonStyle: CSSProperties = {
width: "fit-content",
padding: 0,
};

const awardTextStyle: CSSProperties = {
display: "flex",
gap: "0.25rem",
alignItems: "center",
};

export default StudentListItem;
40 changes: 40 additions & 0 deletions apps/admin/app/students/_components/StudentTable/StudyTasks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { StudyTaskResponseDto } from "types/dtos/studyStudent";
import Table from "wowds-ui/Table";

import TaskTag from "./TaskTag";

export const StudyTasksThs = ({
tasks,
}: {
tasks: (
| StudyTaskResponseDto<"ASSIGNMENT">
| StudyTaskResponseDto<"ATTENDANCE">
)[];
}) => {
return tasks.map((task) => {
const { week, taskType } = task;
return (
<Table.Th key={taskType + week}>
{taskType === "ATTENDANCE" ? `${week}주차 출석` : `${week}주차 과제`}
</Table.Th>
);
});
};

export const StudyTasksTds = ({
tasks,
}: {
tasks: (
| StudyTaskResponseDto<"ASSIGNMENT">
| StudyTaskResponseDto<"ATTENDANCE">
)[];
}) => {
return tasks.map((task) => {
const { week, taskType } = task;
return (
<Table.Td key={taskType + week}>
<TaskTag task={task} />
</Table.Td>
);
});
};
29 changes: 29 additions & 0 deletions apps/admin/app/students/_components/StudentTable/TaskTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { assignmentSubmissionStatusMap } from "constants/status/assignmentStatusMap";
import { attendanceTaskStatusMap } from "constants/status/attendanceStatusMap";
import type { StudyTaskResponseDto } from "types/dtos/studyStudent";
import type { TaskType } from "types/entities/task";
import Tag from "wowds-ui/Tag";

const TaskTag = ({ task }: { task: StudyTaskResponseDto<TaskType> }) => {
const formatTaskToTagInfo = () => {
if (task.taskType === "ATTENDANCE") {
return attendanceTaskStatusMap[task.attendanceStatus];
}
if (task.taskType === "ASSIGNMENT") {
return assignmentSubmissionStatusMap[task.assignmentSubmissionStatus];
}
return null;
};

const tagInfo = formatTaskToTagInfo();
if (!tagInfo) return null;
const { tagText, tagColor } = tagInfo;

return (
<Tag color={tagColor} variant="solid2">
{tagText}
</Tag>
);
};

export default TaskTag;
Loading

0 comments on commit fbefe9e

Please sign in to comment.