Conversation
Walkthrough브라우저 Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25분
Possibly related PRs
Suggested labels
Suggested reviewers
시
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (7)
frontend/src/components/login/LoginForm.jsx (1)
13-14: alert → toast 전환은 UX 측면에서 훨씬 자연스럽습니다.다만
AbortController로 취소된 요청까지 모두"로그인에 실패하였습니다..."토스트를 띄우면, 사용자가 단순히 연속 제출/화면 전환을 했을 때도 실패처럼 보일 수 있습니다.
login내부에서 사용하는 클라이언트(예: axios)의 에러 형태에 맞춰, 요청 취소(ERR_CANCELED등)인 경우에는 토스트를 생략하거나 무시하는 분기를 두는 것도 고려해 보셔도 좋겠습니다.Also applies to: 69-71
frontend/src/utils/bettingInfo.js (1)
2-2: 토스트로 에러를 알려주는 방향은 좋지만,null반환 패턴은 호출 측에서 에러를 구분하기 애매합니다.현재는 네트워크/서버 에러가 나도 호출자는 단순히
null만 받고, 구체적인 에러 타입을 알 수 없습니다.
throw를 유지해서 상위에서 오류별 처리(예: 4xx, 5xx 구분)를 하거나,{ data: null, error }형태의 결과 객체를 반환하는 식으로 호출자가 더 풍부한 정보를 다룰 수 있게 개선하는 것도 고려해 보시면 좋겠습니다.Also applies to: 8-11, 18-21
frontend/src/utils/bettingHistory.js (1)
2-2: 토스트 +[]폴백 패턴은 단순하지만, “데이터 없음”과 “요청 실패”가 구분되지 않습니다.현재 구조에서는 API 실패 시 토스트는 뜨지만, 호출자는 항상
[]만 받아서 진짜로 내역이 없는 경우와 네트워크/서버 오류를 구분할 수 없습니다.
필요하다면betHistory가{ data, error }를 반환하거나, 에러는 그대로 throw 해서 상위(UI)에서 “에러 상태 vs 빈 상태”를 분리 렌더링하도록 설계를 확장하는 것도 좋겠습니다.Also applies to: 10-13
frontend/src/components/stockgame/Betting.jsx (1)
11-12: 베팅 관련 알림을 toast로 통일한 부분은 아주 보기 좋습니다.다만 몇 가지 확인/개선 포인트가 있습니다.
409 상태 코드 분기 확인 필요
일반적인 axios 에러 객체라면error.status대신error.response.status를 쓰는 패턴이 많습니다.
현재if (error.status === 409)분기가 실제로 동작하는지,api래퍼에서 status를 top-level로 노출해 주는지 한 번만 확인해 주세요.
의도치 않게 항상 일반 에러 토스트만 뜨는 상황일 수도 있습니다.API 에러 시
Loading...가 계속 보이는 UX
dailyBet/weeklyBet가 에러 시null을 반환하고, 컴포넌트에서는if (!data) return <div>Loading...</div>;로 처리하고 있어서,
요청 실패 후에도 사용자는 “로딩 중” 화면만 계속 보게 됩니다(실제론 더 이상 로딩이 아님).
- 에러 상태용
errorstate를 추가해서 “오류가 발생했습니다. 새로고침/재시도 해주세요.” 같은 메시지를 보여주거나data를null대신 별도의 에러 플래그와 함께 관리하는 쪽이 더 명확할 것 같습니다.이미 베팅/성공/실패 메시지
"이미 베팅하셨습니다.","베팅이 완료되었습니다.","베팅 가능 시간이 아닙니다."토스트 문구와 위치도 사용자 입장에서 충분히 이해하기 쉬운 것 같습니다.Also applies to: 63-87, 89-113, 115-123, 127-127
frontend/src/components/login/ResetPasswordModal.jsx (1)
3-3: 토스트 기반 피드백과 버튼 비활성화 로직은 좋지만, 동등 비교는===가 더 안전합니다.
- 비밀번호 불일치/길이 검증에
toast.error, 성공 시toast.success를 사용하는 구조는 명확하고 UX도 좋습니다.- 다만
const isPasswordValid = password == confirmPassword && ...부분은 JS 관례상===를 사용하는 편이 더 안전하고 린트 규칙(eqeqeq 등)과도 잘 맞습니다.- const isPasswordValid = password == confirmPassword && password.length >= 8; + const isPasswordValid = password === confirmPassword && password.length >= 8;Also applies to: 12-13, 16-17, 20-21, 24-24, 55-57
frontend/src/utils/attendanceList.js (1)
1-37: 목데이터 구조는 명확하지만, 날짜 형식·key 컬럼을 미리 정리해 두는 편이 좋겠습니다.
date: '25-09-01'처럼 연·월·일 순서가 모호한 문자열은, 나중에 파싱/정렬·백엔드 연동 시 혼선을 줄이려면'2025-09-01'같은 ISO 형식으로 통일해 두는 게 안전합니다.SessionManage.jsx에서key={s.date}를 쓰고 있어, 같은 날짜에 여러 세션이 생기는 순간 key 충돌 가능성이 있습니다.id필드를 하나 두고 key는 그 값을 쓰는 구조를 추천합니다.예시:
export const attendanceList = [ { - date: '25-09-01', + id: 1, + date: '2025-09-01', @@ }, { - date: '25-09-08', + id: 2, + date: '2025-09-08', @@ }, { - date: '25-09-15', + id: 3, + date: '2025-09-15', @@ }, { - date: '25-09-22', + id: 4, + date: '2025-09-22', @@ }, { - date: '25-09-29', + id: 5, + date: '2025-09-29', @@ }, ];이후
SessionManage.jsx에서는key={s.id}로 변경하는 식으로 연동하면 됩니다.frontend/src/components/attendance/SessionManage.jsx (1)
1-43: 테이블 ARIA role, row key, 버튼 type을 한 번 정리해 두면 좋겠습니다.
<table>에role="grid"를 주면 보조기기가 인터랙티브 그리드를 기대하는데, 현재는 일반 데이터 테이블에 가깝습니다. 특별한 키보드 인터랙션을 붙일 계획이 없다면 기본 role(table)에 맡기는 편이 더 자연스럽습니다.key={s.date}는 같은 날짜에 여러 세션이 생길 때 중복될 수 있습니다. 앞서 제안한 것처럼attendanceList에id를 두고key={s.id}로 사용하는 쪽이 안전합니다.<button>은 기본이type="submit"이라, 나중에 이 테이블이<form>안으로 들어가면 의도치 않은 submit이 발생할 수 있습니다. 지금 단계에서type="button"을 명시해 두는 게 좋습니다.예시:
- <table className={styles.table} role="grid"> + <table className={styles.table}> @@ - {attendanceList.map((s) => ( - <tr key={s.date}> + {attendanceList.map((s) => ( + <tr key={s.id ?? s.date}> @@ - <button className={styles.button}>출석</button> + <button type="button" className={styles.button}> + 출석 + </button>(실제 key는
attendanceList측에id를 추가한 뒤key={s.id}로 정리하는 것을 권장합니다.)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
frontend/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (20)
frontend/package.json(1 hunks)frontend/src/components/VerificationModal.jsx(3 hunks)frontend/src/components/attendance/AttendanceSelectBox.css(0 hunks)frontend/src/components/attendance/AttendanceSelectBox.jsx(0 hunks)frontend/src/components/attendance/ExcusedTime.jsx(1 hunks)frontend/src/components/attendance/ExcusedTime.module.css(1 hunks)frontend/src/components/attendance/SessionManage.jsx(1 hunks)frontend/src/components/attendance/SessionManage.module.css(1 hunks)frontend/src/components/attendance/SessionSelectBox.jsx(1 hunks)frontend/src/components/attendance/SessionSelectBox.module.css(1 hunks)frontend/src/components/login/LoginForm.jsx(2 hunks)frontend/src/components/login/ResetPasswordModal.jsx(2 hunks)frontend/src/components/signup/SignUpForm.jsx(4 hunks)frontend/src/components/stockgame/Betting.jsx(5 hunks)frontend/src/pages/Attendance.css(0 hunks)frontend/src/pages/Attendance.jsx(1 hunks)frontend/src/pages/Attendance.module.css(1 hunks)frontend/src/utils/attendanceList.js(1 hunks)frontend/src/utils/bettingHistory.js(1 hunks)frontend/src/utils/bettingInfo.js(2 hunks)
💤 Files with no reviewable changes (3)
- frontend/src/pages/Attendance.css
- frontend/src/components/attendance/AttendanceSelectBox.css
- frontend/src/components/attendance/AttendanceSelectBox.jsx
🧰 Additional context used
🧬 Code graph analysis (5)
frontend/src/components/VerificationModal.jsx (2)
frontend/src/components/signup/SignUpForm.jsx (1)
phoneNumber(25-25)frontend/src/components/login/ResetPasswordModal.jsx (1)
handleSubmit(9-22)
frontend/src/components/stockgame/Betting.jsx (4)
frontend/src/components/login/LoginForm.jsx (1)
res(17-17)frontend/src/utils/bettingHistory.js (1)
res(6-6)frontend/src/utils/bettingInfo.js (2)
res(6-6)res(16-16)frontend/src/components/stockgame/BettingHistory.jsx (1)
error(15-15)
frontend/src/components/signup/SignUpForm.jsx (1)
frontend/src/components/login/LoginForm.jsx (1)
nav(26-26)
frontend/src/utils/bettingHistory.js (2)
frontend/src/components/login/LoginForm.jsx (1)
res(17-17)frontend/src/utils/bettingInfo.js (2)
res(6-6)res(16-16)
frontend/src/pages/Attendance.jsx (3)
frontend/src/components/attendance/SessionSelectBox.jsx (1)
SessionSelectBox(14-31)frontend/src/components/attendance/ExcusedTime.jsx (1)
ExcusedTime(3-10)frontend/src/components/attendance/SessionManage.jsx (1)
SessionManage(5-41)
🔇 Additional comments (6)
frontend/package.json (1)
15-22:lucide-react추가는 적절해 보이며, 아이콘 사용 일관성에 도움이 됩니다.단, 새 아이콘 라이브러리 도입인 만큼 현재 React/Vite 환경(React 19, ESM 번들)과의 호환성 및 번들 크기 영향이 문서/릴리스 노트 기준으로 문제 없는지 한 번만 체크해 주세요.
frontend/src/components/VerificationModal.jsx (1)
3-3: 전화번호/인증번호 검증에 toast를 사용한 변경이 직관적이고, 다른 폼들과도 일관적입니다.검증 실패/성공 케이스별 메시지가 명확하고, 모달 내에서 추가적인 상태 변경도 잘 처리되어 있어 별도 이슈는 없어 보입니다.
Also applies to: 16-17, 24-25, 32-33, 41-42, 45-46
frontend/src/pages/Attendance.module.css (1)
1-23: 출석 페이지 레이아웃 CSS 무난합니다.플렉스 레이아웃과 타이포 설정이 단순·일관적이고, 다른 컴포넌트들과도 잘 맞는 구조라 현재 요구사항 기준으로는 별도 수정 필요 없어 보입니다.
frontend/src/components/attendance/SessionSelectBox.module.css (1)
1-35: SessionSelectBox 스타일 정의 깔끔합니다.컨테이너·제목·셀렉트 박스가 명확하게 분리돼 있고, 타이포·여백 값도 다른 출석 컴포넌트들과 톤이 잘 맞습니다. 현재 단계에서는 그대로 사용해도 무방해 보입니다.
frontend/src/components/attendance/ExcusedTime.module.css (1)
1-28: ExcusedTime 카드 스타일 잘 정의되어 있습니다.카드 크기·정렬·타이포가 단순하고 명확해서, 출석 인정 시간 정보만 보여주는 용도에 잘 맞습니다. 특별히 손볼 부분 없이 그대로 사용하셔도 될 것 같습니다.
frontend/src/pages/Attendance.jsx (1)
1-23: 페이지를 컴포넌트 단위로 잘 분리했고,useAuthGuard적용 위치도 적절합니다.레이아웃을 CSS 모듈로 관리하고, 출석 선택/인정 시간/세션 관리 영역을 각각 컴포넌트로 나눈 구조가 명확합니다. 상단에서
useAuthGuard()를 호출해 진입 가드를 거는 패턴도 일관되고 이해하기 좋습니다.
| const ExcusedTime = () => { | ||
| return ( | ||
| <div className={styles.card}> | ||
| <span className={styles.excuse}>1회차 출석 인정 시간</span> | ||
| <span className={styles.time}>18 : 00 PM ~ 18 : 30 PM</span> | ||
| </div> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
컴포넌트를 재사용 가능하도록 props를 받도록 리팩토링하세요.
현재 컴포넌트는 하드코딩된 값(1회차, 시간)만 표시합니다. 다른 회차나 시간대를 표시하려면 컴포넌트를 재사용할 수 없습니다.
다음 diff를 적용하여 props를 받도록 리팩토링하세요:
-const ExcusedTime = () => {
+const ExcusedTime = ({ sessionNumber, startTime, endTime }) => {
return (
<div className={styles.card}>
- <span className={styles.excuse}>1회차 출석 인정 시간</span>
- <span className={styles.time}>18 : 00 PM ~ 18 : 30 PM</span>
+ <span className={styles.excuse}>{sessionNumber}회차 출석 인정 시간</span>
+ <span className={styles.time}>{startTime} ~ {endTime}</span>
</div>
);
};사용 예시:
<ExcusedTime sessionNumber={1} startTime="18:00" endTime="18:30" />🤖 Prompt for AI Agents
In frontend/src/components/attendance/ExcusedTime.jsx around lines 3 to 10, the
component currently renders hardcoded session and time values; refactor it to
accept props (sessionNumber, startTime, endTime) and render them instead. Update
the function signature to accept props (or destructure { sessionNumber,
startTime, endTime }), replace the hardcoded strings with those prop values (for
example render `${sessionNumber}회차 출석 인정 시간` and `${startTime} PM ~ ${endTime}
PM` or just `${startTime} ~ ${endTime}` depending on desired format), and add
sensible defaults or propTypes/defaultProps if needed to preserve existing
behavior when props are omitted. Ensure styling and classNames remain unchanged.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/components/signup/SignUpForm.jsx (1)
57-60: 전화번호 유효성 검사가 실제로는 동작하지 않는 버그입니다
isPhoneNumberValid가 함수로 정의되어 있는데,isFormValid에서 호출이 아닌 “함수 객체 자체”를 사용하고 있어 항상 truthy로 평가됩니다. 그 결과, 전화번호가 유효하지 않아도 회원가입 버튼이 활성화될 수 있습니다.const isPhoneNumberValid = () => { const phoneRegex = /^0\d{8,10}$/; return phoneRegex.test(phoneNumber); }; const isFormValid = nickname.trim() !== '' && isEmailValid() && isVerificationSent && isVerificationChecked && isPhoneNumberValid && // ← 여기서 함수 호출 누락 isPasswordValid && password === confirmPassword;아래처럼 함수 호출로 수정하는 것이 맞습니다.
- const isFormValid = + const isFormValid = nickname.trim() !== '' && isEmailValid() && isVerificationSent && isVerificationChecked && - isPhoneNumberValid && + isPhoneNumberValid() && isPasswordValid && password === confirmPassword;Also applies to: 65-72
🧹 Nitpick comments (2)
frontend/src/components/signup/SignUpForm.jsx (2)
88-91: 인증번호 발송 알림을 toast로 통일한 것은 좋고, 로그만console.error로 바꾸는 것을 제안합니다
- 이전 리뷰에서 지적되었던
alert + toast이중 알림이 제거되고, 이제 성공 시toast.success만 사용되어 UX가 자연스러워졌습니다.- 에러 로그는
console.log보다는console.error가 디버깅/모니터링에 유리합니다.- } catch (error) { - console.log(error); - toast.error('오류가 발생했습니다.'); - } finally { + } catch (error) { + console.error(error); + toast.error('오류가 발생했습니다.'); + } finally {
109-112: 인증번호 확인 흐름도 toast 기반으로 정리된 점은 좋고, 에러 로그 방식만 통일하면 더 좋겠습니다
- 성공 시
setVerificationChecked(true)+toast.success('인증되었습니다.')로 흐름이 명확합니다.- 위 함수와 마찬가지로 에러 쪽도
console.error로 통일하면 로그 수준 관리가 수월해집니다.- } catch (error) { - console.log(error); - toast.error('인증에 실패했습니다.'); - } + } catch (error) { + console.error(error); + toast.error('인증에 실패했습니다.'); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/src/components/attendance/ExcusedTime.jsx(1 hunks)frontend/src/components/attendance/SessionManage.module.css(1 hunks)frontend/src/components/attendance/SessionSelectBox.jsx(1 hunks)frontend/src/components/signup/SignUpForm.jsx(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- frontend/src/components/attendance/ExcusedTime.jsx
- frontend/src/components/attendance/SessionSelectBox.jsx
- frontend/src/components/attendance/SessionManage.module.css
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/signup/SignUpForm.jsx (1)
frontend/src/components/login/LoginForm.jsx (1)
nav(26-26)
🔇 Additional comments (2)
frontend/src/components/signup/SignUpForm.jsx (2)
5-5:react-toastify도입 방향 좋습니다회원가입 폼에서도
toast를 사용하도록 한 것은 PR 목적(알림 UX 통일)에 잘 맞고, 코드 상 특별한 문제는 없어 보입니다.
133-137: 회원가입 성공/실패 알림을 toast로 바꾼 방향은 적절하며, 페이지 전환 시 토스트 표시 여부만 한 번 확인해 주세요
- 성공 시
toast.success('회원가입이 완료되었습니다.');후nav('/login');으로 흐름이 깔끔합니다.- 실패 시에도
toast.error('회원가입에 실패하였습니다.');로 일관된 UX를 제공하는 점 좋습니다.다만
ToastContainer가 최상단 레이아웃(페이지 전환과 무관하게 유지되는 위치)에 있어야,/login으로 이동한 뒤에도 성공 토스트가 자연스럽게 보입니다. 현재 구조상 이미 그렇게 되어 있다면 그대로 괜찮습니다.
gxuoo
left a comment
There was a problem hiding this comment.
UI 기초구현이라 크게 리뷰드릴 점은 없어서 바로 Approve 처리했습니다. 고생하셨습니다!
1) 작업한 이슈번호
SISC1-226
2) 변경 요약 (What & Why)
3) 스크린샷/동영상 (UI 변경 시)
4) 상세 변경사항 (전부 다)
5) 참고사항
Summary by CodeRabbit
New Features
Refactor
Dependencies
✏️ Tip: You can customize this high-level summary in your review settings.