Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 5 additions & 62 deletions src/components/enroll/CoursesList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,8 @@ import { useState } from "react";
import { useEffect } from "react";
import { toast } from "react-toastify";

const CoursesList = ({ courses, onEnrollSuccess }) => {
const [capa, setCapa] = useState([]);

useEffect(() => {
let eventSource;
// 기존 연결 닫기
if (eventSource) {
eventSource.close();
}
if (!courses || courses.length === 0) return;
// 초기 capa 세팅
setCapa(
courses.map((c) => ({
courseId: c.courseId,
participant: c.participant ?? 0,
}))
);
const courseIds = courses.map((c) => `courseIds=${c.courseId}`).join("&");
const token = localStorage.getItem("accessToken");
// console.log(token);
if (!token) {
console.error("Access token is missing!");
return;
}
const sseUrl = `${
import.meta.env.VITE_API_BASE_SECURE_SSE_URL
}/api/v1/seats/subscribe?${courseIds}`;
// console.log("SSE URL:", sseUrl);

eventSource = new EventSourcePolyfill(sseUrl, {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!eventSource) return;

eventSource.onopen = () => {
console.log("SSE 연결");
};

eventSource.addEventListener("seat", (event) => {
const data = JSON.parse(event.data);
console.log("seat 데이터: ", data);
setCapa((prevCapa) =>
prevCapa.map((capa) =>
capa.courseId === data.courseId
? { ...capa, participant: data.remaining }
: capa
)
);
});

// 오류 발생 시 SSE 종료
eventSource.onerror = (err) => {
console.error("EventSource 에러: ", err);
toast.error("연결에 문제가 발생했습니다. 다시 시도해주세요.");
eventSource.close();
};
return () => eventSource.close();
}, [courses]);

const CoursesList = ({ courses, capacities, onEnrollSuccess }) => {
console.log("[CoursesList] capacities 출력: ", capacities);
return (
<div
className="w-[814px] h-[607px] overflow-y-auto
Expand All @@ -75,7 +16,9 @@ const CoursesList = ({ courses, onEnrollSuccess }) => {
>
<div className="grid grid-cols-3 gap-x-2 gap-y-3">
{courses?.map((course) => {
const current = capa.find((c) => c.courseId === course.courseId);
const current = capacities?.find(
(c) => c.courseId === course.courseId
);
return (
<CourseItem
key={course.courseId}
Expand Down
12 changes: 7 additions & 5 deletions src/components/enroll/EnrollForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import RegisteredCoursesList from "@/components/enroll/RegisteredCoursesList";
import CreditsStatus from "@/components/enroll/CreditsStatus";
import { getCredits } from "@/services/student";
import { useFilter } from "@/hooks/useFilter";
import { useCapaSSE } from "@/hooks/useCapaSSE";

const EnrollForm = () => {
const {
Expand All @@ -25,7 +26,6 @@ const EnrollForm = () => {

const [generalCourses, setGeneralCourses] = useState([]);
const [registerCourses, setRegisterCourses] = useState([]);
const [capacities, setCapacities] = useState([]);

const [credits, setCredits] = useState({
totalCredit: null,
Expand All @@ -39,14 +39,16 @@ const EnrollForm = () => {
const courseRes = await getCourses(filters);
setGeneralCourses(courseRes.data);

const ids = courseRes.data.map((c) => c.courseId);
//const capaRes = await getCapacities(ids);
//setCapacities(capaRes.data);
// const ids = courseRes.data.map((c) => c.courseId);
// const capaRes = await getCapacities(ids);
// setCapacities(capaRes.data);
} catch (error) {
console.error("수강 목록 조회 실패", error);
}
};

const { capa } = useCapaSSE({ courses: generalCourses });

// 수강 신청 현황 조회
const getRegisterCourses = async () => {
try {
Expand Down Expand Up @@ -109,7 +111,7 @@ const EnrollForm = () => {
/>
<CoursesList
courses={filteredCourses}
//capacities={capacities}
capacities={capa}
onEnrollSuccess={handleAfterAction}
/>
</div>
Expand Down
69 changes: 69 additions & 0 deletions src/hooks/useCapaSSE.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { toast } from "react-toastify";
import { useEffect } from "react";
import { useState } from "react";
import { EventSourcePolyfill } from "event-source-polyfill";

export const useCapaSSE = ({ courses }) => {
const [capa, setCapa] = useState(courses);

//console.log("[useCapaSSE] courses: ", courses);

useEffect(() => {
let eventSource;
// 기존 연결 닫기
if (eventSource) {
eventSource.close();
}

if (!courses || courses.length === 0) return;
// 초기 capa 세팅
setCapa(
courses.map((c) => ({
courseId: c.courseId,
participant: c.participant ?? 0,
}))
);
const courseIds = courses.map((c) => `courseIds=${c.courseId}`).join("&");
const token = localStorage.getItem("accessToken");
if (!token) {
console.error("Access token is missing!");
return;
}
const sseUrl = `${
import.meta.env.VITE_API_BASE_SECURE_SSE_URL
}/api/v1/seats/subscribe?${courseIds}`;

eventSource = new EventSourcePolyfill(sseUrl, {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!eventSource) return;

eventSource.onopen = () => {
console.log("SSE 연결");
};

eventSource.addEventListener("seat", (event) => {
const data = JSON.parse(event.data);
console.log("seat 데이터: ", data);
setCapa((prevCapa) =>
prevCapa.map((capa) =>
capa.courseId === data.courseId
? { ...capa, participant: data.remaining }
: capa
)
);
});

// 오류 발생 시 SSE 종료
eventSource.onerror = (err) => {
console.error("EventSource 에러: ", err);
toast.error("연결에 문제가 발생했습니다. 다시 시도해주세요.");
eventSource.close();
};
return () => eventSource.close();
}, [courses]);

return { capa };
};