diff --git a/src/api/reviewService.js b/src/api/reviewService.js
index ea2b8ed..3f73cd1 100644
--- a/src/api/reviewService.js
+++ b/src/api/reviewService.js
@@ -1,55 +1,51 @@
// src/api/reviewService.js
-
-// 중요: 백엔드 주소를 정확하게 입력 (Proxy 설정이 없다면 전체 주소 필수)
const BASE_URL = "http://localhost:8080/api";
-export const fetchCodeReview = async (code, comment) => {
- // 1. 데이터 객체 생성
+export const fetchCodeReview = async (code, comment, repoUrl) => {
const payload = {
code: code,
comment: comment && comment.trim() ? comment.trim() : null,
+ repoUrl: repoUrl && repoUrl.trim() ? repoUrl.trim() : null,
};
try {
- // 2. fetch 요청 (JSON 모드)
const res = await fetch(`${BASE_URL}/review`, {
method: "POST",
headers: {
- "Content-Type": "application/json", // 나 JSON 보낸다고 알려줌
+ "Content-Type": "application/json",
},
- body: JSON.stringify(payload), // 객체를 문자열로 변환
+ body: JSON.stringify(payload),
});
- // 3. 에러 처리
const raw = await res.text();
-
+
if (!res.ok) {
- // 서버가 에러 응답을 준 경우
- let errMsg = raw;
try {
- const json = JSON.parse(raw);
- errMsg = json.message || json.error || json.detail || raw;
+ const errJson = JSON.parse(raw);
+ throw new Error(
+ errJson.message ||
+ errJson.error ||
+ `코드 리뷰 요청 실패 (status: ${res.status})`
+ );
} catch {
- // JSON 파싱 실패 시 raw text 사용
+ throw new Error(
+ raw || `코드 리뷰 요청 실패 (status: ${res.status})`
+ );
}
- throw new Error(errMsg || `요청 실패 (${res.status})`);
}
- if (!raw) return {};
-
- // 정상 응답 파싱
try {
return JSON.parse(raw);
} catch {
return { review: raw, questions: [] };
}
-
} catch (error) {
console.error("API 요청 실패:", error);
- // "Failed to fetch"는 보통 서버가 꺼져있거나 주소가 틀렸을 때 발생
if (error.message === "Failed to fetch") {
- throw new Error("서버에 연결할 수 없습니다. 백엔드 서버가 켜져 있는지 확인해주세요.");
+ throw new Error(
+ "서버에 연결할 수 없습니다. 백엔드 서버가 켜져 있는지 확인해주세요."
+ );
}
throw error;
}
-};
\ No newline at end of file
+};
diff --git a/src/features/codingTest/CodingTest.jsx b/src/features/codingTest/CodingTest.jsx
index 7aafd00..393bf32 100644
--- a/src/features/codingTest/CodingTest.jsx
+++ b/src/features/codingTest/CodingTest.jsx
@@ -4,7 +4,6 @@ import { Link } from "react-router-dom";
import {
Sparkles,
Send,
- Play,
CheckCircle2,
XCircle,
Terminal,
@@ -30,7 +29,9 @@ const fetchRandomProblem = async (difficulty) => {
if (!response.ok) {
const text = await response.text().catch(() => "");
- throw new Error(text || `랜덤 문제를 불러오지 못했습니다. (status: ${response.status})`);
+ throw new Error(
+ text || `랜덤 문제를 불러오지 못했습니다. (status: ${response.status})`
+ );
}
return await response.json();
@@ -41,7 +42,7 @@ const submitCode = async ({ problemId, code, language, userId }) => {
problemId,
sourceCode: code,
language,
- userId: userId ?? 1 // userId가 null/undefined일 경우 기본값 1 사용 (Long 타입 일치)
+ userId: userId ?? 1, // userId가 null/undefined일 경우 기본값 1 사용 (Long 타입 일치)
};
// API 경로: /api/coding/submissions
@@ -65,12 +66,26 @@ const submitCode = async ({ problemId, code, language, userId }) => {
// 컴포넌트 시작
// -----------------------------------------------------------
-
// 언어 옵션
const LANGUAGE_OPTIONS = [
- { value: "python", label: "Python", color: "text-blue-400", activeBorder: "border-blue-400/60 bg-blue-500/10" },
- { value: "java", label: "Java", color: "text-orange-400", activeBorder: "border-orange-400/60 bg-orange-500/10" },
- { value: "cpp", label: "C++", color: "text-purple-400", activeBorder: "border-purple-400/60 bg-purple-500/10" },
+ {
+ value: "python",
+ label: "Python",
+ color: "text-blue-400",
+ activeBorder: "border-blue-400/60 bg-blue-500/10",
+ },
+ {
+ value: "java",
+ label: "Java",
+ color: "text-orange-400",
+ activeBorder: "border-orange-400/60 bg-orange-500/10",
+ },
+ {
+ value: "cpp",
+ label: "C++",
+ color: "text-purple-400",
+ activeBorder: "border-purple-400/60 bg-purple-500/10",
+ },
];
// 기본 템플릿
@@ -109,9 +124,21 @@ int main() {
// 난이도 색
const DIFFICULTY_CONFIG = {
- EASY: { label: "쉬움", color: "text-emerald-300 bg-emerald-500/20 border-emerald-400/30 shadow-[0_0_15px_rgba(52,211,153,0.15)]" },
- MEDIUM: { label: "보통", color: "text-amber-300 bg-amber-500/20 border-amber-400/30 shadow-[0_0_15px_rgba(251,191,36,0.15)]" },
- HARD: { label: "어려움", color: "text-rose-300 bg-rose-500/20 border-rose-400/30 shadow-[0_0_15px_rgba(251,113,133,0.15)]" },
+ EASY: {
+ label: "쉬움",
+ color:
+ "text-emerald-300 bg-emerald-500/20 border-emerald-400/30 shadow-[0_0_15px_rgba(52,211,153,0.15)]",
+ },
+ MEDIUM: {
+ label: "보통",
+ color:
+ "text-amber-300 bg-amber-500/20 border-amber-400/30 shadow-[0_0_15px_rgba(251,191,36,0.15)]",
+ },
+ HARD: {
+ label: "어려움",
+ color:
+ "text-rose-300 bg-rose-500/20 border-rose-400/30 shadow-[0_0_15px_rgba(251,113,133,0.15)]",
+ },
};
export default function CodingTest() {
@@ -124,16 +151,17 @@ export default function CodingTest() {
const [result, setResult] = useState(null);
const [errorMsg, setErrorMsg] = useState("");
- // AI 피드백(리뷰/면접질문) 구역을 열지 말지 토글
- const [showFeedback, setShowFeedback] = useState(false);
-
// 코드 리뷰 vs 예상 면접 질문 토글 상태
const [showInterview, setShowInterview] = useState(false);
// 언어 변경
const handleChangeLanguage = (nextLang) => {
if (code !== LANGUAGE_TEMPLATES[language] && code.trim() !== "") {
- if (!window.confirm("언어를 변경하면 작성 중인 코드가 초기화됩니다. 계속하시겠습니까?")) {
+ if (
+ !window.confirm(
+ "언어를 변경하면 작성 중인 코드가 초기화됩니다. 계속하시겠습니까?"
+ )
+ ) {
return;
}
}
@@ -146,8 +174,8 @@ export default function CodingTest() {
setIsLoadingProblem(true);
setErrorMsg("");
setResult(null);
- setShowFeedback(false);
setShowInterview(false);
+
try {
const data = await fetchRandomProblem(difficulty);
setProblem(data);
@@ -174,7 +202,6 @@ export default function CodingTest() {
setIsSubmitting(true);
setErrorMsg("");
setResult(null);
- setShowFeedback(false);
setShowInterview(false);
try {
@@ -185,17 +212,9 @@ export default function CodingTest() {
userId: 1, // Long 타입이므로 숫자 1 사용
});
setResult(res);
-
- // aiFeedback 또는 interviewQuestions가 있으면 피드백 영역 기본 ON
- if (res.aiFeedback || (res.interviewQuestions && res.interviewQuestions.length > 0)) {
- setShowFeedback(true);
- } else {
- setShowFeedback(false);
- }
+ // showInterview는 기본 false (코드 리뷰 먼저 보여줌)
} catch (err) {
- setErrorMsg(
- err?.message || "채점 서버 통신 중 오류가 발생했습니다."
- );
+ setErrorMsg(err?.message || "채점 서버 통신 중 오류가 발생했습니다.");
} finally {
setIsSubmitting(false);
}
@@ -205,29 +224,37 @@ export default function CodingTest() {
return ["AC", "SUCCESS", "PASSED"].includes(status?.toUpperCase());
};
+ const hasFeedback =
+ !!result?.aiFeedback ||
+ (Array.isArray(result?.interviewQuestions) &&
+ result.interviewQuestions.length > 0);
+
return (
// 배경: 딥 블루 그라데이션
-
{/* 배경 조명 효과 */}
{/* 헤더 */}
-
{/* 왼쪽: Home 버튼 */}
-
- Home
+
+
+ Home
+
@@ -274,45 +301,56 @@ export default function CodingTest() {
{isLoadingProblem ? (
) : (
-
+
)}
- {isLoadingProblem ? "생성 중..." : "문제 생성"}
+
+ {isLoadingProblem ? "생성 중..." : "문제 생성"}
+
{/* 메인 컨텐츠 영역 */}
-
{/* 에러 알림 */}
{errorMsg && (
)}
{/* 메인 작업 영역 (Grid) */}
-
{/* 왼쪽: 문제 설명 패널 */}
-
- {/* 패널 헤더 (고정) */}
+ {/* 패널 헤더 (고정) */}
- 문제 설명
+
+ 문제 설명
+
{problem && (
-
+
{DIFFICULTY_CONFIG[problem.difficulty].label}
)}
{/* 컨텐츠 영역 (여기가 스크롤됨) */}
-
+
{isLoadingProblem ? (
// 로딩 스켈레톤
@@ -330,34 +368,45 @@ export default function CodingTest() {
{problem.title}
-
+
-
{problem.description}
+
+ {problem.description}
+
{problem.samples && problem.samples.length > 0 && (
-
+
예시 입력/출력
{problem.samples.map((sample, idx) => (
-
+
- Case #{idx + 1}
+
+ Case #{idx + 1}
+
-
입력
+
+ 입력
+
{sample.inputData}
-
출력
+
+ 출력
+
{sample.expectedOutput}
@@ -374,12 +423,20 @@ export default function CodingTest() {
-
문제가 선택되지 않았습니다.
-
우측 상단의 "문제 생성" 버튼을 눌러 시작하세요.
+
+ 문제가 선택되지 않았습니다.
+
+
+ 우측 상단의 "문제 생성" 버튼을 눌러 시작하세요.
+
)}
@@ -388,7 +445,6 @@ export default function CodingTest() {
{/* 오른쪽: 코드 에디터 및 실행 결과 */}
-
{/* 1. 코드 에디터 카드 */}
{/* 에디터 툴바 */}
@@ -400,11 +456,19 @@ export default function CodingTest() {
onClick={() => handleChangeLanguage(opt.value)}
className={`px-3 py-1 text-[11px] font-medium rounded-md flex items-center gap-1.5 transition-all duration-200 ${
language === opt.value
- ? `bg-[#1e293b] text-white shadow-lg border ${opt.activeBorder || 'border-white/10'}`
+ ? `bg-[#1e293b] text-white shadow-lg border ${
+ opt.activeBorder || "border-white/10"
+ }`
: "text-slate-400 hover:text-slate-200 hover:bg-white/5"
}`}
>
-
+
{opt.label}
))}
@@ -427,9 +491,9 @@ export default function CodingTest() {
{/* 에디터 영역 */}
-