Skip to content

Commit 9f397ec

Browse files
Merge pull request #141 from HackYourFutureProjects/FE-BE/teacher-moderation
Fe be/teacher moderation
2 parents 906a9eb + d3845b1 commit 9f397ec

29 files changed

Lines changed: 788 additions & 116 deletions

File tree

‎client/src/api/auth/types.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { StudentType } from "../student/student.type";
22
import { TeacherType } from "../teacher/teacher.type";
3+
import { ModeratorType } from "../moderator/moderator.type.ts";
34

45
export type Role = "student" | "teacher" | "moderator";
56

@@ -14,7 +15,7 @@ export type RegisterFinalType = RegisterFormTypes & {
1415
role: Role;
1516
};
1617

17-
export type UserType = StudentType | TeacherType;
18+
export type UserType = StudentType | TeacherType | ModeratorType;
1819

1920
export type LoginFormTypes = {
2021
email: string;
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
import { LoginFormTypes } from "../auth/types.ts";
2-
import { apiPublic } from "../api.ts";
2+
import { apiProtected, apiPublic } from "../api.ts";
3+
import { TeacherStatus } from "../teacher/teacher.type.ts";
34

45
export async function loginModeratorApi(data: LoginFormTypes) {
56
const res = await apiPublic.post("/api/moderator/auth/login", data);
67
return res.data as { accessToken: string };
78
}
9+
10+
export async function moderatorChangeTeacherStatusApi({
11+
id,
12+
status,
13+
}: {
14+
id: string;
15+
status: TeacherStatus;
16+
}) {
17+
return await apiProtected.patch(`/api/moderator/teachers/${id}/status`, {
18+
status,
19+
});
20+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export type ModeratorType = {
2+
id: string;
3+
firstName: string;
4+
lastName: string;
5+
email: string;
6+
profileImageUrl: string | null;
7+
createdAt: Date;
8+
role: "moderator";
9+
};

‎client/src/api/teacher/teacher.api.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { apiProtected, apiPublic } from "../api.ts";
22
import {
33
TeacherOutputModel,
4+
TeachersForModeratorQuery,
45
TeachersQuery,
56
TeacherType,
67
UpdateTeacherProfileInput,
@@ -14,11 +15,31 @@ export async function getAllTeachersApi(query: TeachersQuery) {
1415
return res.data;
1516
}
1617

18+
export async function getAllTeachersForModeratorApi(
19+
query: TeachersForModeratorQuery,
20+
) {
21+
const res = await apiProtected.get<TeacherOutputModel>(
22+
"/api/teachers/get-teachers-moderator",
23+
{
24+
params: query,
25+
},
26+
);
27+
28+
return res.data;
29+
}
30+
1731
export async function getTeacherByIdApi(teacherId: string) {
1832
const res = await apiPublic.get<TeacherType>(`/api/teachers/${teacherId}`);
1933
return res.data;
2034
}
2135

36+
export async function getTeacherByIdForModeratorApi(teacherId: string) {
37+
const res = await apiProtected.get<TeacherType>(
38+
`/api/teachers/${teacherId}/moderator`,
39+
);
40+
return res.data;
41+
}
42+
2243
type ApiSlot = { start: string; end: string };
2344
type ApiAvailability = {
2445
monday: ApiSlot[];

‎client/src/api/teacher/teacher.type.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { Role } from "../auth/types";
2-
2+
export type TeacherStatus =
3+
| "draft"
4+
| "pending"
5+
| "active"
6+
| "rejected"
7+
| "blocked";
38
type EducationItem = {
49
degree: string;
510
institution: string;
@@ -58,6 +63,7 @@ export type TeacherType = {
5863
availability: AvailabilityItem;
5964
address: AddressItem;
6065
createdAt: Date;
66+
status: TeacherStatus;
6167
role: Role;
6268
};
6369

@@ -71,6 +77,7 @@ export type TeacherOutputModel = {
7177

7278
export type SortDirection = "asc" | "desc";
7379
export type SortBy = "createdAt" | "priceFrom" | "rating";
80+
export type SortByTeachersForModerator = "status" | "createdAt";
7481

7582
export type TeachersQuery = {
7683
subject?: string;
@@ -83,6 +90,13 @@ export type TeachersQuery = {
8390
pageSize?: number;
8491
};
8592

93+
export type TeachersForModeratorQuery = {
94+
sortBy?: SortByTeachersForModerator;
95+
sortDirection?: SortDirection;
96+
pageNumber?: number;
97+
pageSize?: number;
98+
};
99+
86100
export type UpdateTeacherProfileInput = {
87101
firstName?: string;
88102
lastName?: string;

‎client/src/components/cardsList/CardsList.tsx‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
import { TeacherCard } from "../teacherCard/teacherCard";
2-
import { TeacherType } from "../../api/teacher/teacher.type";
2+
import { TeacherStatus, TeacherType } from "../../api/teacher/teacher.type";
33
import { motion, type Variants, useReducedMotion } from "framer-motion";
44
import { useRef } from "react";
55
type CardsListType = {
66
cards: TeacherType[];
7+
changeStatus?: (id: string, status: TeacherStatus) => void;
8+
isStatusPending?: boolean;
79
};
810

9-
export const CardsList = ({ cards }: CardsListType) => {
11+
export const CardsList = ({
12+
cards,
13+
changeStatus,
14+
isStatusPending,
15+
}: CardsListType) => {
1016
const reduceMotion = useReducedMotion();
1117

1218
const listVariants: Variants = {
@@ -44,7 +50,11 @@ export const CardsList = ({ cards }: CardsListType) => {
4450
>
4551
{cards.map((teacher) => (
4652
<motion.div key={teacher.id} variants={itemVariants}>
47-
<TeacherCard teacher={teacher} />
53+
<TeacherCard
54+
isStatusPending={isStatusPending}
55+
changeStatus={changeStatus}
56+
teacher={teacher}
57+
/>
4858
</motion.div>
4959
))}
5060
</motion.div>

‎client/src/components/sidebar/sidebarMenuItems.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import Chat from "../icons/Chat";
55
import UsersIcon from "../icons/UsersIcon";
66
import {
77
chatRoutes,
8+
moderatorBase,
9+
moderatorPrivatesRoutesVariables,
810
studentBase,
911
studentPrivatesRoutesVariables,
1012
teacherBase,
@@ -63,3 +65,16 @@ export const defaultTeacherMenuItems: MenuItem[] = [
6365
icon: Chat,
6466
},
6567
];
68+
69+
export const defaultModeratorMenuItems: MenuItem[] = [
70+
{
71+
name: "Teachers",
72+
link: joinPath(moderatorBase, moderatorPrivatesRoutesVariables.teachers),
73+
icon: DashboardIcon,
74+
},
75+
{
76+
name: "Chat",
77+
link: joinPath(moderatorBase, chatRoutes.root),
78+
icon: Chat,
79+
},
80+
];
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import {
2+
getStatusButtonClass,
3+
statusOptions,
4+
statusUi,
5+
} from "../../util/statusButtons.tsx";
6+
import { Button } from "../ui/button/Button.tsx";
7+
import { TeacherStatus } from "../../api/teacher/teacher.type.ts";
8+
9+
type StatusChangeProps = {
10+
id: string;
11+
changeStatus: (id: string, status: TeacherStatus) => void;
12+
status: TeacherStatus;
13+
};
14+
15+
export const StatusChange = ({
16+
changeStatus,
17+
id,
18+
status,
19+
}: StatusChangeProps) => {
20+
return (
21+
<>
22+
<div className="flex flex-wrap items-center gap-2">
23+
{statusOptions.map((s) => (
24+
<Button
25+
key={s}
26+
type="button"
27+
variant="link"
28+
className={getStatusButtonClass(s, s === status)}
29+
onClick={() => changeStatus(id, s)}
30+
>
31+
{statusUi[s].label}
32+
</Button>
33+
))}
34+
</div>
35+
</>
36+
);
37+
};

0 commit comments

Comments
 (0)