Conversation
|
Warning
|
| Cohort / File(s) | 요약 |
|---|---|
ClubDetailPage 통합 frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx |
ClubDetailFooter 컴포넌트 임포트 및 Footer 아래에 렌더링, 모집 시작/종료 날짜 전달 |
ClubApplyButton 컴포넌트 frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx, ClubApplyButton.styles.ts |
새 지원 버튼 컴포넌트: 모집 마감 확인, 지원 옵션 조회, 단일/다중 옵션 처리, 외부 URL 또는 내부 라우팅 지원, Mixpanel 이벤트 추적 |
ClubDetailFooter 컴포넌트 frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsx, ClubDetailFooter.styles.ts |
새 footer 컴포넌트: 모집 시작/종료 날짜 수신, 마감 텍스트 계산, ClubApplyButton 렌더링 |
ShareButton 컴포넌트 frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx, ShareButton.styles.ts |
새 공유 버튼 컴포넌트: Kakao SDK 통합 피드 공유, Mixpanel 이벤트 추적 |
타입 및 유틸리티 수정 frontend/src/types/club.ts, frontend/src/utils/recruitmentDateParser.ts, frontend/src/utils/recruitmentDateParser.test.ts |
ClubDetail의 recruitmentStart/recruitmentEnd를 nullable에서 non-nullable string으로 변경; recruitmentDateParser 반환 타입을 Date | null로 수정, '미정' 입력값 처리 추가 |
Sequence Diagram
sequenceDiagram
actor User
participant ClubApplyButton
participant API as API (Applications)
participant Modal as ApplicationSelectModal
participant Form as Application Form
participant Mixpanel
User->>ClubApplyButton: 지원하기 버튼 클릭
activate ClubApplyButton
ClubApplyButton->>Mixpanel: 이벤트 추적 (클릭)
ClubApplyButton->>ClubApplyButton: 모집 마감 확인
alt 마감 상태
ClubApplyButton-->>User: 아무 동작 없음
else 모집 중
ClubApplyButton->>API: 지원 옵션 조회
activate API
API-->>ClubApplyButton: 옵션 목록 반환
deactivate API
alt 옵션 0개
ClubApplyButton-->>User: 아무 동작 없음
else 옵션 1개
ClubApplyButton->>ClubApplyButton: 폼 상세 정보 조회
alt 외부 URL
ClubApplyButton->>User: 새 탭에서 URL 열기
else 내부 폼
ClubApplyButton->>Form: 내부 라우팅 이동
end
else 옵션 2개 이상
ClubApplyButton->>Modal: 모달 표시 (옵션 선택)
activate Modal
User->>Modal: 옵션 선택
Modal-->>ClubApplyButton: 선택 옵션 반환
deactivate Modal
ClubApplyButton->>ClubApplyButton: 선택한 옵션으로 폼 열기
ClubApplyButton->>Form: 라우팅 또는 URL 열기
end
end
deactivate ClubApplyButton
sequenceDiagram
actor User
participant ShareButton
participant Kakao as Kakao SDK
participant Mixpanel
User->>ShareButton: 공유 버튼 클릭
activate ShareButton
ShareButton->>Kakao: Kakao 초기화 확인
alt Kakao 미초기화
ShareButton-->>User: 공유 불가
else Kakao 초기화됨
ShareButton->>Kakao: 피드 공유 (클럽 정보)
activate Kakao
Kakao-->>User: 공유 완료
deactivate Kakao
ShareButton->>Mixpanel: 이벤트 추적 (SHARE_BUTTON_CLICKED)
end
deactivate ShareButton
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~50 minutes
Possibly related PRs
- [HotFix] 동아리 상세페이지 모집 버튼 푸터 삭제 복구 #978: 동일한 ClubDetailFooter 및 관련 하위 컴포넌트(ClubApplyButton, ShareButton)를 ClubDetailPage에 추가하고 모집 날짜 파싱/타입 변경을 모두 포함하는 거의 동일한 PR
- [feature] 상세 페이지 푸터 디자인 변경 #795: ClubDetailPage의 동일한 UI 컴포넌트들(ApplyButton 스타일, ShareButton 아이콘/스타일, footer 스타일링)을 수정하는 관련 PR
- [feat] 카카오 공유하기 설명문자 변경 #979: ShareButton 구현을 수정하여 Kakao 공유 텍스트로 introDescription을 사용하도록 변경하는 PR
Suggested reviewers
- oesnuj
- seongwon030
Pre-merge checks and finishing touches
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목은 '동아리 상세페이지 모집 버튼 푸터 삭제 복구'로, 변경사항의 핵심인 모집 푸터 컴포넌트 복구를 명확하게 요약하고 있습니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✨ Finishing touches
- 📝 Generate docstrings
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
fix/delete-clubdetailfooter
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 @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (5)
frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.styles.ts (1)
7-7: z-index를 상수로 관리하는 것을 고려해주세요.TODO 주석이 잘 작성되어 있습니다. Portal로 모달을 분리한 후, z-index 값들을 별도의 상수 파일(예:
@/constants/zIndex.ts)에서 관리하면 헤더, 모달, 푸터 간의 레이어 순서를 일관되게 유지할 수 있습니다.frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx (1)
19-19:return null을 명시적으로 반환해주세요.React 컴포넌트에서 아무것도 렌더링하지 않을 때는
undefined대신null을 명시적으로 반환하는 것이 관례입니다.🔎 제안된 수정
- if (!clubDetail) return; + if (!clubDetail) return null;frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.ts (1)
20-20: 색상 값을 상수로 관리하는 것을 고려해주세요.
#ff7543(브랜드 오렌지)과 같은 색상 값이 하드코딩되어 있습니다. 프로젝트에 테마 또는 색상 상수 파일이 있다면, 해당 값을 사용하여 일관성을 유지하는 것이 좋습니다.frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx (2)
35-54: 함수 책임 분리 검토 권장
goWithForm함수가 폼 데이터 조회, 외부 URL 처리, 내부 네비게이션을 모두 담당하고 있습니다. 단일 책임 원칙(SRP) 관점에서 여러 관심사가 혼재되어 있어 유지보수성이 저하될 수 있습니다.외부 폼 처리와 내부 폼 네비게이션 로직을 별도 함수로 분리하는 것을 고려해보세요.
🔎 제안하는 리팩토링
+ const openExternalForm = (url: string) => { + window.open(url, '_blank', 'noopener,noreferrer'); + }; + + const navigateToInternalForm = (formId: string, formDetail: any) => { + navigate(`/application/${clubId}/${formId}`, { state: { formDetail } }); + setIsOpen(false); + }; + const goWithForm = async (formId: string) => { try { const formDetail = await getApplication(clubId, formId); if (formDetail?.formMode === ApplicationFormMode.EXTERNAL) { const externalApplicationUrl = formDetail.externalApplicationUrl?.trim(); if (externalApplicationUrl) { - window.open(externalApplicationUrl, '_blank', 'noopener,noreferrer'); + openExternalForm(externalApplicationUrl); return; } } - navigate(`/application/${clubId}/${formId}`, { state: { formDetail } }); - setIsOpen(false); + navigateToInternalForm(formId, formDetail); } catch (error) { console.error('지원서 조회 중 오류가 발생했습니다', error); alert( '지원서 정보를 불러오는 중 오류가 발생했습니다. 다시 시도해주세요.', ); } };As per coding guidelines: "Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)"
62-88: 복잡한 로직을 커스텀 훅으로 추출 검토
handleClick함수가 이벤트 추적, 마감 확인, 옵션 조회, 모달 제어 등 여러 책임을 담당하고 있습니다. 함수의 복잡도가 높아 테스트와 유지보수가 어려울 수 있습니다.지원서 관련 로직을
useClubApplication같은 커스텀 훅으로 추출하는 것을 고려해보세요.💡 커스텀 훅 추출 예시
// useClubApplication.ts const useClubApplication = (clubId: string, clubName: string) => { const [isModalOpen, setIsModalOpen] = useState(false); const [options, setOptions] = useState<ApplicationForm[]>([]); const navigate = useNavigate(); const goWithForm = async (formId: string) => { // ... goWithForm 로직 }; const handleApplyClick = async (deadlineText?: string) => { if (deadlineText === RECRUITMENT_STATUS.CLOSED) { alert(`현재 ${clubName} 동아리는 모집 기간이 아닙니다.`); return; } try { const list = await getApplicationOptions(clubId); // ... 나머지 로직 } catch (e) { // ... 에러 처리 } }; return { isModalOpen, setIsModalOpen, options, handleApplyClick, openByOption: (option?: ApplicationForm) => { if (!option) return; void goWithForm(option.id); }, }; };그런 다음 컴포넌트에서:
const ClubApplyButton = ({ deadlineText }: ClubApplyButtonProps) => { const { clubId } = useParams<{ clubId: string }>(); const trackEvent = useMixpanelTrack(); const { data: clubDetail } = useGetClubDetail(clubId!); const { isModalOpen, setIsModalOpen, options, handleApplyClick, openByOption, } = useClubApplication(clubId!, clubDetail?.name || ''); if (!clubId || !clubDetail) return null; const handleClick = async () => { trackEvent(USER_EVENT.CLUB_APPLY_BUTTON_CLICKED); await handleApplyClick(deadlineText); }; // ... 렌더링 로직 };As per coding guidelines: "Abstract complex logic/interactions into dedicated components/HOCs" 및 "Break down broad state management into smaller, focused hooks/contexts to reduce coupling"
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (10)
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.tsfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsxfrontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.styles.tsfrontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.tsfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsxfrontend/src/types/club.tsfrontend/src/utils/recruitmentDateParser.test.tsfrontend/src/utils/recruitmentDateParser.ts
🧰 Additional context used
📓 Path-based instructions (3)
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries withif/elseor IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Files:
frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.styles.tsfrontend/src/types/club.tsfrontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.tsfrontend/src/utils/recruitmentDateParser.tsfrontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/utils/recruitmentDateParser.test.tsfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.tsfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.styles.tsfrontend/src/types/club.tsfrontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.tsfrontend/src/utils/recruitmentDateParser.tsfrontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/utils/recruitmentDateParser.test.tsfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.tsfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
frontend/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{tsx,jsx}: Abstract complex logic/interactions into dedicated 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 when using form libraries like react-hook-form
Use Component Composition instead of Props Drilling to reduce coupling
Files:
frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsxfrontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
🧠 Learnings (8)
📓 Common learnings
Learnt from: seongwon030
Repo: Moadong/moadong PR: 744
File: frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx:47-48
Timestamp: 2025-09-21T02:23:27.796Z
Learning: ClubApplyButton 컴포넌트에서 ShareButton은 항상 렌더링되어야 하므로 정적 import를 사용하는 것이 적절함. 동적 import는 불필요함.
Learnt from: seongwon030
Repo: Moadong/moadong 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
Repo: Moadong/moadong PR: 548
File: frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx:17-57
Timestamp: 2025-07-19T05:05:10.196Z
Learning: ClubDetailPage.tsx에서 notJoinedClubNames 배열의 하드코딩은 의도적인 설계 결정입니다. 개발자가 명시적으로 하드코딩을 선택했으므로 이에 대한 리팩토링 제안을 하지 않아야 합니다.
📚 Learning: 2025-09-21T02:23:27.796Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 744
File: frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx:47-48
Timestamp: 2025-09-21T02:23:27.796Z
Learning: ClubApplyButton 컴포넌트에서 ShareButton은 항상 렌더링되어야 하므로 정적 import를 사용하는 것이 적절함. 동적 import는 불필요함.
Applied to files:
frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.tsfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
📚 Learning: 2025-03-19T05:18:07.818Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Applied to files:
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsxfrontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Separate significantly different conditional UI/logic into distinct components
Applied to files:
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.tsfrontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Replace magic numbers with named constants for clarity
Applied to files:
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.ts
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Abstract complex logic/interactions into dedicated components/HOCs
Applied to files:
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Use Component Composition instead of Props Drilling to reduce coupling
Applied to files:
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{tsx,jsx} : Choose field-level or form-level cohesion based on form requirements when using form libraries like react-hook-form
Applied to files:
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
🧬 Code graph analysis (4)
frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsx (1)
frontend/src/utils/recruitmentDateParser.ts (1)
recruitmentDateParser(3-18)
frontend/src/utils/recruitmentDateParser.test.ts (1)
frontend/src/utils/recruitmentDateParser.ts (1)
recruitmentDateParser(3-18)
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx (3)
frontend/src/hooks/queries/club/useGetClubDetail.ts (1)
useGetClubDetail(6-20)frontend/src/types/application.ts (1)
ApplicationForm(65-68)frontend/src/constants/eventName.ts (1)
USER_EVENT(1-38)
frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx (2)
frontend/src/hooks/queries/club/useGetClubDetail.ts (1)
useGetClubDetail(6-20)frontend/src/constants/eventName.ts (1)
USER_EVENT(1-38)
🔇 Additional comments (8)
frontend/src/utils/recruitmentDateParser.ts (1)
3-4: LGTM!
Date | null반환 타입 변경과 '미정' 또는 빈 문자열에 대한null반환 처리가 적절합니다. 이를 통해 미정인 날짜를 예외 없이 우아하게 처리할 수 있습니다.frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)
83-86: LGTM!
ClubDetailFooter컴포넌트가 적절하게 통합되었습니다.recruitmentStart와recruitmentEndprops가 올바르게 전달되며,Footer아래에 배치되어 sticky 푸터로서 정상 동작할 것입니다.frontend/src/utils/recruitmentDateParser.test.ts (1)
37-45: LGTM!테스트 케이스가 파서의 새로운 동작에 맞게 적절히 업데이트되었습니다. 빈 문자열과 '미정' 입력에 대한
null반환을 명확하게 검증합니다.frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.styles.ts (1)
1-12: LGTM!
ShareButton스타일이 깔끔하게 정의되어 있습니다.frontend/src/pages/ClubDetailPage/components/ShareButton/ShareButton.tsx (1)
21-49: 공유 기능 구현이 잘 되어있습니다.카카오 SDK 초기화 확인, 에러 처리, 접근성(aria-label), 그리고 Mixpanel 이벤트 추적이 적절히 구현되어 있습니다. Based on learnings,
ShareButton은 항상 렌더링되어야 하므로 정적 import 사용이 올바릅니다.frontend/src/types/club.ts (1)
27-28: 타입 차이는 의도된 설계 패턴입니다.
ClubDetail과ClubDescription의recruitmentStart와recruitmentEnd타입 차이는 읽기(API 응답)와 쓰기(업데이트 요청) 작업에 대한 의도적인 분리입니다.RecruitEditTab에서 확인할 수 있듯이,ClubDetail의 값을ClubDescription형식으로 변환할 때toISOString() ?? null을 통해 null 가능성을 명시적으로 처리하고 있습니다. 이는 API 설계의 일반적인 패턴이므로 현재 상태를 유지하는 것이 적절합니다.frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx (2)
17-20: LGTM!상수 객체를 사용하여 매직 스트링을 제거한 점이 좋습니다. 코딩 가이드라인을 잘 준수하고 있습니다.
108-121: LGTM!ShareButton과의 컴포넌트 조합이 적절하게 구현되어 있습니다. 학습된 내용에 따르면 ShareButton은 항상 렌더링되어야 하므로 정적 import를 사용한 점이 올바릅니다.
Based on learnings: "ClubApplyButton 컴포넌트에서 ShareButton은 항상 렌더링되어야 하므로 정적 import를 사용하는 것이 적절함"
| img { | ||
| font-size: 12px; | ||
| font-weight: 600; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
img 요소에 대한 불필요한 폰트 스타일링을 제거해주세요.
font-size와 font-weight는 img 요소에 적용되지 않습니다. 이 스타일은 의도된 동작을 하지 않으므로 제거하는 것이 좋습니다.
🔎 제안된 수정
- img {
- font-size: 12px;
- font-weight: 600;
- }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| img { | |
| font-size: 12px; | |
| font-weight: 600; | |
| } |
🤖 Prompt for AI Agents
In
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.styles.ts
around lines 31 to 34, the img selector contains font-size and font-weight which
do not apply to images; remove those two properties from the img rule so the
selector only contains applicable styles (or delete the entire img rule if it
becomes empty).
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
Show resolved
Hide resolved
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
Show resolved
Hide resolved
| const deadlineText = getDeadlineText( | ||
| recruitmentDateParser(recruitmentStart), | ||
| recruitmentDateParser(recruitmentEnd), | ||
| new Date(), | ||
| ); |
There was a problem hiding this comment.
날짜 파싱 오류 처리 필요
recruitmentDateParser는 날짜 형식이 유효하지 않을 경우 에러를 throw합니다. 백엔드에서 예상치 못한 형식의 데이터가 전달되면 컴포넌트 렌더링이 실패할 수 있습니다.
try-catch로 감싸거나 Error Boundary를 활용하여 오류를 처리하는 것을 권장합니다.
🔎 제안하는 수정안
const ClubDetailFooter = ({
recruitmentStart,
recruitmentEnd,
}: ClubDetailFooterProps) => {
+ let deadlineText = '';
+ try {
- const deadlineText = getDeadlineText(
- recruitmentDateParser(recruitmentStart),
- recruitmentDateParser(recruitmentEnd),
- new Date(),
- );
+ deadlineText = getDeadlineText(
+ recruitmentDateParser(recruitmentStart),
+ recruitmentDateParser(recruitmentEnd),
+ new Date(),
+ );
+ } catch (error) {
+ console.error('날짜 파싱 오류:', error);
+ deadlineText = ''; // 또는 적절한 기본값
+ }
return (🤖 Prompt for AI Agents
In
frontend/src/pages/ClubDetailPage/components/ClubDetailFooter/ClubDetailFooter.tsx
around lines 15 to 19, the direct calls to recruitmentDateParser can throw on
unexpected date formats and crash rendering; wrap each parser call in a
try-catch (or use a safe parsing helper that returns null/undefined on failure),
log the parsing error, and pass guarded values (e.g., null) into getDeadlineText
or use a fallback deadline string so the component can render gracefully when
parsing fails; ensure the UI shows a sensible default (like "날짜 정보 없음" or
similar) instead of crashing.
#️⃣연관된 이슈
#977
📝작업 내용
상세페이지 푸터를 복구했습니더
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
릴리스 노트
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.