Skip to content

Commit 6d0a304

Browse files
committed
feat: update presentation scheduling flow and enhance UI components
1 parent 5d590a9 commit 6d0a304

8 files changed

Lines changed: 242 additions & 115 deletions

File tree

backend/src/controllers/team.controllers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const getSchedulePresentation = async (
5757
const userId = req.userId!;
5858
const { teamId } = req.params;
5959
console.log("teamId", userId, teamId);
60-
// chỉ có thành viên mới get dc
60+
6161
const result = await teamService.getSchedulePresentation(userId, teamId);
6262
return res.status(HTTP_STATUS.OK).json(new ResponseClient({ result }));
6363
} catch (error) {

backend/src/services/team.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,14 @@ class TeamService {
166166
const isMember = await teamRepository.isMember(teamId, userId);
167167
if (!isMember) {
168168
throw new ErrorWithStatus({
169-
status: HTTP_STATUS.FORBIDDEN,
169+
status: HTTP_STATUS.OK,
170170
message: "Bạn không có quyền xem lịch trình thuyết trình của nhóm này.",
171171
});
172172
}
173173
const schedule = await teamRepository.findSchedulePresentationByTeamId(teamId);
174174
if (!schedule) {
175175
throw new ErrorWithStatus({
176-
status: HTTP_STATUS.NOT_FOUND,
176+
status: HTTP_STATUS.OK,
177177
message: "Lịch trình thuyết trình của nhóm không tồn tại.",
178178
});
179179
}

frontend/src/api-requests/team.requests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class TeamApi {
4242
}
4343

4444
static async getSchedulePresentation(teamId: string) {
45-
const res = await privateApi.get<ResponseDetailData<SchedulePresentType>>(`/teams/present/${teamId}`);
45+
const res = await privateApi.get<ResponseDetailData<SchedulePresentType>>(`/teams/get-schedule/${teamId}`);
4646
return res.data;
4747
}
4848
}

frontend/src/components/Header/Candidate.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Helper from "~/utils/helper";
22
import { NavLink } from "./NavLink";
3-
import { Presentation, Send } from "lucide-react";
3+
import { Presentation } from "lucide-react";
44
import { useLocation } from "react-router";
55

66
const CandidateHeader = () => {

frontend/src/pages/Present/FormRegisterPresent.tsx

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState } from "react";
2-
import { useMutation } from "@tanstack/react-query";
2+
import { useMutation, useQueryClient } from "@tanstack/react-query";
33
import { Calendar, Clock, Send } from "lucide-react";
44
import { Button } from "~/components/ui/button";
55
import { RadioGroup, RadioGroupItem } from "~/components/ui/radio-group";
@@ -17,22 +17,33 @@ interface TimeSlots {
1717
}
1818

1919
const trialTimeSlots: TimeSlots = {
20-
"17/01/2026": ["7:00 - 7:45", "8:00 - 8:45", "9:00 - 9:45", "10:00 - 10:45"],
21-
"18/01/2026": ["7:00 - 7:45", "8:00 - 8:45", "9:00 - 9:45", "10:00 - 10:45"],
22-
"19/01/2026": ["7:00 - 7:45", "8:00 - 8:45", "9:00 - 9:45", "10:00 - 10:45"],
23-
"20/01/2026": ["7:00 - 7:45", "8:00 - 8:45", "9:00 - 9:45", "10:00 - 10:45"],
20+
"17/01/2026": ["10h05 - 10h50", "16h05 - 16h50", "19h05 - 19h50", "20h05 - 20h50"],
21+
"18/01/2026": ["15h05 - 15h50", "16h05 - 16h50", "19h05 - 19h50", "20h05 - 20h50"],
22+
"19/01/2026": ["09h05 - 09h50", "10h05 - 10h50", "19h05 - 19h50", "20h05 - 20h50"],
23+
"20/01/2026": ["19h05 - 19h50", "20h05 - 20h50"],
24+
"21/01/2026": ["19h05 - 19h50", "20h05 - 20h50"],
2425
};
2526

2627
const officialTimeSlots: TimeSlots = {
27-
"17/01/2026": ["13:00 - 13:45", "14:00 - 14:45"],
28-
"18/01/2026": ["13:00 - 13:45", "14:00 - 14:45"],
29-
"19/01/2026": ["13:00 - 13:45", "14:00 - 14:45"],
30-
"20/01/2026": ["13:00 - 13:45", "14:00 - 14:45"],
28+
"24/01/2026": ["18h - 19h", "19h15 - 20h15"],
29+
"26/01/2026": ["18h - 19h", "19h15 - 20h15"],
30+
"27/01/2026": ["18h - 19h", "19h15 - 20h15"],
31+
"28/01/2026": ["18h - 19h", "19h15 - 20h15"],
32+
"29/01/2026": ["18h - 19h", "19h15 - 20h15"],
33+
"30/01/2026": ["18h - 19h", "19h15 - 20h15"],
34+
"31/01/2026": ["18h - 19h", "19h15 - 20h15"],
3135
};
3236

33-
const FormRegisterPresent = () => {
37+
const FormRegisterPresent = ({
38+
isReload,
39+
setIsReload,
40+
}: {
41+
isReload: boolean;
42+
setIsReload: React.Dispatch<React.SetStateAction<boolean>>;
43+
}) => {
3444
const userInfo = useAppSelector((state) => state.user.userInfo);
3545
const teamId = userInfo.candidate?.teamId || "";
46+
const queryClient = useQueryClient();
3647

3748
const [trialSlot, setTrialSlot] = useState<string>("");
3849
const [officialSlots, setOfficialSlots] = useState<string[]>([]);
@@ -48,9 +59,11 @@ const FormRegisterPresent = () => {
4859
});
4960
},
5061
onSuccess: () => {
62+
queryClient.invalidateQueries({ queryKey: ["schedulePresentation", teamId] });
5163
Notification.success({
5264
text: "Đăng ký thời gian thuyết trình thành công!",
5365
});
66+
setIsReload(!isReload);
5467
setTrialSlot("");
5568
setOfficialSlots([]);
5669
},
@@ -101,13 +114,13 @@ const FormRegisterPresent = () => {
101114
</div>
102115
<p className="text-sm text-gray-600">
103116
Chọn <span className="font-semibold">MỘT</span> khung giờ để thuyết trình thử nghiệm và nhận
104-
phản hồi từ mentor.
117+
phản hồi từ Ban Giám Khảo.
105118
</p>
106119
<div className="rounded-md border-l-4 border-blue-400 bg-blue-50 p-3">
107120
<p className="text-xs text-blue-800">
108-
<span className="font-semibold">Lưu ý:</span> Chỉ {" "}
109-
<span className="font-bold">10 slot</span> thuyết trình thử cho toàn bộ các nhóm. Mỗi nhóm
110-
chỉ được chọn 1 khung giờ tham gia.
121+
<span className="font-semibold">Lưu ý:</span> Chỉ còn{" "}
122+
<span className="font-bold">10 slot</span> thuyết trình thử. Hãy chọn một khung giờ phù hợp
123+
có đủ tất cả các thành viên trong nhóm để tham gia.
111124
</p>
112125
</div>
113126

frontend/src/pages/Present/Notification.tsx

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,5 @@
1-
import React from "react";
2-
import { AlertCircle, CheckCircle, Info } from "lucide-react";
3-
1+
import { Info } from "lucide-react";
42
const Notification = () => {
5-
// TODO: Replace with actual notification data from API/store
6-
const hasRegistered = false; // Example state
7-
const registrationStatus = "pending"; // 'pending' | 'approved' | 'rejected'
8-
9-
if (hasRegistered) {
10-
return (
11-
<div className="mb-6 overflow-hidden rounded-md border border-blue-200 bg-blue-50">
12-
<div className="flex gap-3 p-4">
13-
<CheckCircle className="h-5 w-5 flex-shrink-0 text-blue-600" />
14-
<div className="flex-1">
15-
<h3 className="text-sm font-semibold text-blue-900">Đã đăng ký thành công</h3>
16-
<p className="mt-1 text-sm text-blue-700">
17-
Bạn đã đăng ký thời gian thuyết trình. Ban tổ chức sẽ xác nhận và thông báo lại cho bạn.
18-
</p>
19-
</div>
20-
</div>
21-
</div>
22-
);
23-
}
24-
253
return (
264
<div className="mb-6 overflow-hidden rounded-md border border-amber-200 bg-amber-50">
275
<div className="flex gap-3 p-4">
@@ -30,26 +8,25 @@ const Notification = () => {
308
<h3 className="text-sm font-semibold text-amber-900">Hướng dẫn đăng ký</h3>
319
<ul className="mt-2 space-y-1 text-sm text-amber-700">
3210
<li className="flex items-start gap-2">
33-
<span className="mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full bg-amber-600"></span>
11+
<span className="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-amber-600"></span>
3412
<span>
35-
<strong>Thuyết trình thử:</strong> Chọn 1 khung giờ để thử nghiệm và nhận phản hồi từ
36-
mentor
13+
<strong>Thuyết trình thử (Online - 45 phút):</strong> 20 phút trình bày + 25 phút hỏi
14+
đáp/góp ý.
3715
</span>
3816
</li>
3917
<li className="flex items-start gap-2">
40-
<span className="mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full bg-amber-600"></span>
18+
<span className="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-amber-600"></span>
4119
<span>
42-
<strong>Thuyết trình chính thức:</strong> Chọn nhiều khung giờ bạn có thể tham gia, BTC
43-
sẽ sắp xếp cụ thể
20+
<strong>Thuyết trình chính thức (Offline - 60 phút):</strong> 25 phút trình bày + 35
21+
phút hỏi đáp.
4422
</span>
4523
</li>
4624
<li className="flex items-start gap-2">
47-
<span className="mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full bg-amber-600"></span>
48-
<span>Mỗi slot thuyết trình kéo dài tối đa 45 phút</span>
49-
</li>
50-
<li className="flex items-start gap-2">
51-
<span className="mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full bg-amber-600"></span>
52-
<span>Vui lòng đăng ký trước thời hạn để đảm bảo có slot phù hợp</span>
25+
<span className="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-amber-600"></span>
26+
<span>
27+
<strong>Lưu ý:</strong> Thời gian và địa điểm/Google Meet sẽ được BTC cập nhật trên hệ
28+
thống trước khi diễn ra buổi thuyết trình.
29+
</span>
5330
</li>
5431
</ul>
5532
</div>

0 commit comments

Comments
 (0)