Conversation
- getTime() 결과가 NaN인 경우 예외 발생 - 사용자 입력이 잘못된 형식일 때 빠르게 원인 파악 가능 - 형식 예시 포함된 에러 메시지로 가독성 개선
- stringToDate: "YYYY.MM.DD HH:mm" 형식의 문자열을 Date 객체로 변환 - parseRecruitmentPeriod: 모집 기간 문자열을 시작일과 종료일로 파싱 - 날짜 형식 검증 및 에러 처리 로직 구현 - 단위 테스트 케이스 추가
- 날짜 부분 누락된 경우 - 빈 문자열인 경우
- JavaScript의 Date 객체는 자동으로 날짜를 조정하므로 불필요
- 연속된 함수 호출을 제어하는 debounce 함수 구현 - 지정된 시간(delay) 동안 마지막 호출만 실행되도록 처리 - 함수 인자 전달 기능 지원 - 타이머 자동 리셋 기능 구현
- 초기 로딩 상태에서 스피너 표시 테스트 - 이미지 로드 완료 후 UI 상태 변경 테스트 - Header, Footer 컴포넌트 렌더링 테스트 - 외부 컴포넌트 모킹 설정
- 카테고리 선택 상태(selectedCategory)를 Context로 전역 관리하도록 CategoryContext.tsx 구현 - 페이지 이동 시에도 카테고리 선택 상태가 유지되도록 구조 개선
- CategoryButtonList에서 카테고리 선택 시 setSelectedCategory(Context)로 상태 관리 - 페이지 이동 후에도 선택 상태가 유지되도록 구조 개
- useCategory 훅에서 CategoryContext가 undefined일 경우 에러를 던지도록 처리 - Provider로 감싸지 않은 경우 실수를 빠르게 인지할 수 있도록 안전성 강화
- 카테고리 선택 시 localStorage에 값 저장 - 페이지 이동, 새로고침, 다른 탭에서도 선택 상태가 유지되도록 useEffect 및 storage 이벤트 핸들러 추가
- 중복되는 테스트 코드를 test.each로 통합하여 코드 간결화 - 테스트 케이스 추가 및 수정이 용이하도록 구조 개선
- 빌드 성능 향상을 위한 캐시 타입 설정
…-FE-124 [feature] debounce 유틸함수 단위 테스트 추가
- 기존 split/replace/new Date 방식 제거 - date-fns의 parse와 isValid로 날짜 파싱 및 유효성 검사 일원화
- YYYY.MM.DD HH:mm 형식이 아닌 입력값에 대해 에러를 던지도록 정규식 검증 추가 - 잘못된 자리수의 날짜 문자열을 엄격하게 필터링
- YYYY.MM.DD HH:mm 형식이 아닌 입력값에 대해 예외가 발생하는지 검증
- 카테고리 선택값을 sessionStorage에 저장하도록 수정 - 창/탭을 닫으면 값이 자동으로 삭제되어 더 일시적인 상태 관리 가능
…obal-state-MOA-41 [feature] 카테고리 선택 상태 Context 전역 관리로 변경 및 페이지 이동 시 상태 유지
- clubDetail을 전역에서 가져오기 - 믹스패널 이벤트 추가
- createDefaultButton 방식에서 커스텀 버튼(onClick + sendDefault) 방식으로 변경 - 버튼 클릭 시 카카오 공유와 믹스패널 트래킹이 정확히 동작하도록 개선
- 환경변수 미설정 시 경고 출력 - Kakao SDK 미로딩 시 에러 출력 - 초기화 실패 시 예외 처리
- 접근성 속성(role, aria-label) 추가
…g-ui-MOA-106 [refactor] 관리자페이지 로그인 로딩 중 UI를 스피너로 변경한다
…-112 [feature] 카카오톡 공유하기 기능을 추가한다
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
frontend/src/utils/initSDK.ts (1)
40-56: Kakao SDK 초기화 함수가 잘 구현되었지만 일부 개선사항이 있습니다.함수의 전반적인 구조와 에러 처리는 좋지만, 다음 사항들을 고려해보세요:
- 환경변수명이
KAKAO_JAVASCRIPT_KEY인지REACT_APP_KAKAO_JAVASCRIPT_KEY인지 확인이 필요합니다.- 에러 메시지가 한국어로 되어 있어 다른 함수들과 일관성이 부족합니다.
다음과 같이 개선할 수 있습니다:
export function initializeKakaoSDK() { - if (!process.env.KAKAO_JAVASCRIPT_KEY) { - console.warn('환경변수가 설정되어 있지 않습니다.'); + if (!process.env.REACT_APP_KAKAO_JAVASCRIPT_KEY) { + console.warn('KAKAO_JAVASCRIPT_KEY environment variable is not set.'); return; } if (!window.Kakao) { - console.error('카카오 SDK가 로드되지 않았습니다.'); + console.error('Kakao SDK is not loaded.'); return; } try { - window.Kakao.init(`${process.env.KAKAO_JAVASCRIPT_KEY}`); + window.Kakao.init(process.env.REACT_APP_KAKAO_JAVASCRIPT_KEY); } catch (error) { - console.error('카카오 SDK 초기화에 실패했습니다:', error); + console.error('Failed to initialize Kakao SDK:', error); } }frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx (4)
11-13: 상수 정의를 더 명확하게 개선할 수 있습니다.하드코딩된 URL들이 상수로 정의되어 있지만, 코딩 가이드라인에 따라 더 명확한 이름을 사용하고 관련 로직과 가까운 곳에 정의하는 것이 좋습니다.
다음과 같이 개선할 수 있습니다:
-const MOADONG_BASE_URL = 'https://www.moadong.com/club/'; -const DEFAULT_IMAGE_URL = - 'https://avatars.githubusercontent.com/u/200371900?s=200&v=4'; +const CLUB_DETAIL_BASE_URL = 'https://www.moadong.com/club/'; +const MOADONG_DEFAULT_LOGO_URL = + 'https://avatars.githubusercontent.com/u/200371900?s=200&v=4';또는 이러한 상수들을 별도의 constants 파일로 분리하여 재사용성을 높일 수도 있습니다.
25-45: 복잡한 SDK 설정 객체를 별도 함수로 분리하는 것을 고려해보세요.KakaoTalk 공유 설정 객체가 복잡하여 가독성을 저해하고 있습니다. 코딩 가이드라인에 따라 복잡한 로직을 별도 함수로 분리하는 것이 좋습니다.
다음과 같이 리팩터링할 수 있습니다:
+const createShareContent = (clubDetail: any) => ({ + objectType: 'feed', + content: { + title: clubDetail.name, + description: clubDetail.description, + imageUrl: clubDetail.logo || MOADONG_DEFAULT_LOGO_URL, + link: { + mobileWebUrl: `${CLUB_DETAIL_BASE_URL}${clubDetail.id}`, + webUrl: `${CLUB_DETAIL_BASE_URL}${clubDetail.id}`, + }, + }, + buttons: [ + { + title: '모아동에서 지원하기', + link: { + mobileWebUrl: `${CLUB_DETAIL_BASE_URL}${clubDetail.id}`, + webUrl: `${CLUB_DETAIL_BASE_URL}${clubDetail.id}`, + }, + }, + ], +}); const handleShare = () => { if (!window.Kakao || !window.Kakao.isInitialized()) { console.error('Kakao SDK is not initialized'); return; } if (!clubDetail) return; - window.Kakao.Share.sendDefault({ - objectType: 'feed', - content: { - title: clubDetail.name, - description: clubDetail.description, - imageUrl: clubDetail.logo ? clubDetail.logo : DEFAULT_IMAGE_URL, - link: { - mobileWebUrl: `${MOADONG_BASE_URL}${clubDetail.id}`, - webUrl: `${MOADONG_BASE_URL}${clubDetail.id}`, - }, - }, - buttons: [ - { - title: '모아동에서 지원하기', - link: { - mobileWebUrl: `${MOADONG_BASE_URL}${clubDetail.id}`, - webUrl: `${MOADONG_BASE_URL}${clubDetail.id}`, - }, - }, - ], - }); + window.Kakao.Share.sendDefault(createShareContent(clubDetail)); trackEvent(`${clubDetail.name} 공유하기 버튼 클릭`); };
30-30: 삼항 연산자를 더 명확한 방식으로 개선할 수 있습니다.코딩 가이드라인에 따라 복잡한 삼항 연산자를 명명된 변수로 교체하는 것이 좋습니다.
+const shareImageUrl = clubDetail.logo || MOADONG_DEFAULT_LOGO_URL; - imageUrl: clubDetail.logo ? clubDetail.logo : DEFAULT_IMAGE_URL, + imageUrl: shareImageUrl,
49-57: 접근성 구현이 잘 되어 있습니다.
role='button'과aria-label속성을 적절히 사용하여 접근성을 고려한 구현이 되어 있습니다. 키보드 네비게이션을 위해tabIndex와onKeyDown핸들러 추가를 고려해볼 수 있습니다.키보드 접근성을 더 향상시키려면:
<Styled.ShareButtonContainer onClick={handleShare} role='button' aria-label='카카오톡으로 동아리 정보 공유하기' + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + handleShare(); + } + }} >
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
frontend/src/assets/images/icons/share_icon.svgis excluded by!**/*.svg
📒 Files selected for processing (7)
frontend/public/index.html(3 hunks)frontend/src/index.tsx(1 hunks)frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx(2 hunks)frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.ts(1 hunks)frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx(1 hunks)frontend/src/types/window.d.ts(1 hunks)frontend/src/utils/initSDK.ts(1 hunks)
✅ Files skipped from review due to trivial changes (3)
- frontend/src/index.tsx
- frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.ts
- frontend/src/types/window.d.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/public/index.html
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/utils/initSDK.tsfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
frontend/**/*.tsx
📄 CodeRabbit Inference Engine (frontend/.cursorrules)
frontend/**/*.tsx: Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Separate significantly different conditional UI/logic into distinct components.
Colocate simple, localized logic or use inline definitions to reduce context switching.
Choose field-level or form-level cohesion based on form requirements.
Break down broad state management into smaller, focused hooks or contexts.
Use component composition instead of props drilling.
Files:
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
🧠 Learnings (2)
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (5)
Learnt from: seongwon030
PR: #195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Learnt from: seongwon030
PR: #548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Separate significantly different conditional UI/logic into distinct components.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Colocate simple, localized logic or use inline definitions to reduce context switching.
frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx (4)
Learnt from: seongwon030
PR: #195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Separate significantly different conditional UI/logic into distinct components.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Learnt from: seongwon030
PR: #541
File: frontend/src/pages/ClubDetailPage/components/ClubDetailHeader/ClubDetailHeader.tsx:41-43
Timestamp: 2025-07-20T11:48:50.207Z
Learning: moadong 프로젝트는 Next.js가 아닌 순수 React + react-router-dom 기반의 CSR(Client-Side Rendering) SPA이므로, window 객체 사용에 대한 SSR 호환성 문제를 제기하지 않아야 합니다.
🧬 Code Graph Analysis (1)
frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx (1)
frontend/src/hooks/queries/club/useGetClubDetail.ts (1)
useGetClubDetail(6-20)
🔇 Additional comments (1)
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)
16-16: ShareButton 컴포넌트 import가 적절합니다.새로운 ShareButton 컴포넌트의 import 구문이 기존 컴포넌트들과 일관된 패턴을 따르고 있습니다.
frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
Show resolved
Hide resolved
…calstorage-MOA-108 지원서 입력값을 localStorage에 저장하여 임시 보관 기능 구현
…ts-MOA-110 관리자 페이지 UI/UX 개선 및 버그 수정 (모집대상 텍스트, 탭 경고, 로고 업로드)
There was a problem hiding this comment.
Actionable comments posted: 9
♻️ Duplicate comments (4)
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (4)
65-67: 복잡한 인라인 로직을 네임드 함수로 추출하세요복잡한 값 검증 로직을 별도 함수로 분리하면 가독성과 재사용성이 향상됩니다.
+const isAnswerEmpty = (value: string | string[]): boolean => { + return (Array.isArray(value) && value.every((v) => v.trim() === '')) || + (!Array.isArray(value) && value.trim() === ''); +}; const onAnswerChange = (id: number, value: string | string[]) => { rawOnAnswerChange(id, value); - const isEmpty = - (Array.isArray(value) && value.every((v) => v.trim() === '')) || - (!Array.isArray(value) && value.trim() === ''); + const isEmpty = isAnswerEmpty(value); if (!isEmpty && invalidQuestionIds.includes(id)) { setInvalidQuestionIds((prev) => prev.filter((qid) => qid !== id)); } };
102-102: 매직 넘버를 네임드 상수로 대체하세요하드코딩된 패딩 값을 네임드 상수로 정의하여 유지보수성을 향상시키세요.
+const HEADER_HEIGHT = '80px'; // 컴포넌트 내부에서 - <PageContainer style={{ paddingTop: '80px' }}> + <PageContainer style={{ paddingTop: HEADER_HEIGHT }}>
17-137: 컴포넌트의 책임을 분리하세요현재 컴포넌트가 데이터 페칭, 폼 상태 관리, 검증, UI 렌더링을 모두 담당하여 단일 책임 원칙에 위배됩니다.
다음과 같이 분리하는 것을 고려해보세요:
useApplicationForm- 데이터 페칭과 상태 관리를 담당하는 커스텀 훅ApplicationFormValidator- 검증 로직을 담당하는 유틸리티ApplicationFormRenderer- UI 렌더링만 담당하는 프레젠테이션 컴포넌트// 예시: 커스텀 훅으로 로직 분리 const useApplicationForm = (clubId: string) => { // 데이터 페칭, 답변 관리, 검증 로직 return { formData, isLoading, answers, onAnswerChange, handleSubmit, invalidQuestionIds }; }; const ApplicationFormRenderer = ({ formData, onSubmit, ... }) => { // UI 렌더링만 담당 };
93-95: 사용자 피드백을 개선하세요
alert사용은 좋지 않은 UX를 제공합니다. 토스트 알림이나 적절한 알림 시스템을 사용해야 합니다.try { await applyToClub(clubId, answers); localStorage.removeItem(STORAGE_KEY); - alert('답변이 성공적으로 제출되었습니다.'); + // TODO: 토스트 알림이나 성공 페이지로 대체 필요 + alert('답변이 성공적으로 제출되었습니다.'); } catch { - alert('답변 제출에 실패했습니다. 잠시 후 다시 시도해 주세요.'); + // TODO: 적절한 에러 알림 시스템으로 대체 필요 + alert('답변 제출에 실패했습니다. 잠시 후 다시 시도해 주세요.'); }
🧹 Nitpick comments (1)
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (1)
128-130: styled component 네이밍 컨벤션을 수정하세요
submitButton은 PascalCase로 작성되어야 합니다.- <Styled.submitButton onClick={handleSubmit}> + <Styled.SubmitButton onClick={handleSubmit}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
frontend/src/hooks/useAnswers.ts(2 hunks)frontend/src/pages/AdminPage/components/ClubLogoEditor/ClubLogoEditor.tsx(3 hunks)frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx(2 hunks)frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx(1 hunks)frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsx(2 hunks)frontend/src/pages/ClubDetailPage/components/ClubDetailHeader/ClubDetailHeader.tsx(2 hunks)frontend/src/utils/parseRecruitmentPeriod.test.ts(1 hunks)frontend/src/utils/recruitmentPeriodParser.test.ts(1 hunks)frontend/src/utils/recruitmentPeriodParser.ts(1 hunks)
✅ Files skipped from review due to trivial changes (4)
- frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx
- frontend/src/pages/AdminPage/components/ClubLogoEditor/ClubLogoEditor.tsx
- frontend/src/utils/parseRecruitmentPeriod.test.ts
- frontend/src/utils/recruitmentPeriodParser.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- frontend/src/pages/ClubDetailPage/components/ClubDetailHeader/ClubDetailHeader.tsx
- frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsx
- frontend/src/hooks/useAnswers.ts
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/utils/recruitmentPeriodParser.tsfrontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx
frontend/**/*.tsx
📄 CodeRabbit Inference Engine (frontend/.cursorrules)
frontend/**/*.tsx: Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Separate significantly different conditional UI/logic into distinct components.
Colocate simple, localized logic or use inline definitions to reduce context switching.
Choose field-level or form-level cohesion based on form requirements.
Break down broad state management into smaller, focused hooks or contexts.
Use component composition instead of props drilling.
Files:
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx
🧠 Learnings (1)
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (17)
Learnt from: seongwon030
PR: #195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Choose field-level or form-level cohesion based on form requirements.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Separate significantly different conditional UI/logic into distinct components.
Learnt from: lepitaaar
PR: #406
File: backend/src/main/java/moadong/club/service/ClubApplyService.java:34-38
Timestamp: 2025-05-19T05:45:52.957Z
Learning: The code duplication between createClubApplication and editClubApplication methods in ClubApplyService.java is acknowledged but will be addressed in a future refactoring, as per the developer's plan.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Break down broad state management into smaller, focused hooks or contexts.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Use component composition instead of props drilling.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Colocate simple, localized logic or use inline definitions to reduce context switching.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Use consistent return types for similar functions and hooks.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Assign complex boolean conditions to named variables.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Replace magic numbers with named constants for clarity.
Learnt from: seongwon030
PR: #548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Define constants near related logic or ensure names link them clearly.
Learnt from: seongwon030
PR: #541
File: frontend/src/pages/ClubDetailPage/components/ClubDetailHeader/ClubDetailHeader.tsx:41-43
Timestamp: 2025-07-20T11:48:50.207Z
Learning: moadong 프로젝트는 Next.js가 아닌 순수 React + react-router-dom 기반의 CSR(Client-Side Rendering) SPA이므로, window 객체 사용에 대한 SSR 호환성 문제를 제기하지 않아야 합니다.
🪛 Biome (2.1.2)
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx
[error] 33-33: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
Hooks should not be called after an early return.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
[error] 35-35: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
Hooks should not be called after an early return.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
[error] 41-41: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
Hooks should not be called after an early return.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
[error] 43-43: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
Hooks should not be called after an early return.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
#️⃣연관된 이슈
📝작업 내용
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
신규 기능
기능 개선
버그 수정
테스트
기타