[feature] 동아리 커버 이미지 업로드 및 삭제 hook 추가#957
Conversation
- useUploadCover: Presigned URL 발급, 스토리지 업로드, 완료 처리 로직 구현 - useDeleteCover: 커버 이미지 삭제 로직 구현 - 공통: 성공 시 clubDetail 쿼리 무효화 및 에러 핸들링 추가
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Change Summary |
|---|---|
클럽 커버 이미지 관리 훅 frontend/src/hooks/queries/club/cover/useCoverMutation.ts |
두 개의 React Query 뮤테이션 훅 신규 추가: useUploadCover(Presigned URL 획득 → 파일 업로드 → API 최종화 → 캐시 무효화)와 useDeleteCover(API 삭제 → 캐시 무효화). 양쪽 모두 에러 처리 및 useQueryClient 활용 |
Estimated code review effort
🎯 2 (Simple) | ⏱️ ~10 minutes
- 명확한 React Query 뮤테이션 패턴 적용
- 두 개의 유사한 구조의 훅 구현
- 표준적인 에러 처리 및 캐시 무효화 로직
Possibly related issues
- [feature] MOA-444 동아리 커버 이미지 업로드 및 삭제 hook 추가 #950: 클럽 커버 이미지 업로드/삭제를 위한 동일한 React Query 뮤테이션 훅(
useUploadCover,useDeleteCover)이 도입되므로 직접적으로 관련됨
Suggested reviewers
- oesnuj
Pre-merge checks and finishing touches
❌ Failed checks (2 warnings)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Linked Issues check | PR의 실제 변경사항(커버 이미지 업로드/삭제 hook)은 연결된 이슈 MOA-433(모집 기간 API 형식 변경)의 목적과 불일치합니다. | 이 PR이 MOA-433과 관련이 있는지 확인하고, 실제 목적을 반영하는 올바른 이슈를 연결하거나 PR 설명을 수정하세요. | |
| Out of Scope Changes check | 커버 이미지 업로드/삭제 기능은 연결된 이슈 MOA-433(모집 기간 처리)의 범위를 벗어난 변경사항입니다. | 커버 이미지 기능을 다루는 올바른 이슈와 연결하거나, 이 변경사항이 MOA-433과 관련된 이유를 설명하세요. |
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목은 커버 이미지 업로드 및 삭제 hook 추가에 대해 명확하게 설명하고 있으며, 실제 변경사항과 일치합니다. |
| 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
refactor/#944-recruitment-date-utc-kst-handling-MOA-433
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: 0
🧹 Nitpick comments (3)
frontend/src/hooks/queries/club/cover/useCoverMutation.ts (3)
10-36: 에러 처리 개선 및 코드 품질 향상을 권장합니다.현재 구현은 기능적으로 정확하지만, 다음 개선사항을 고려해주세요:
- 에러 UI 개선:
alert()대신 토스트 알림이나 모달을 사용하면 더 나은 사용자 경험을 제공할 수 있습니다.- 에러 로깅 부재:
onError콜백이 에러 파라미터를 받지 않아 디버깅이 어려울 수 있습니다.- 매직 스트링:
'clubDetail'쿼리 키를 상수로 추출하면 유지보수성이 향상됩니다 (코딩 가이드라인 참고).🔎 개선된 구현 제안
+// 쿼리 키를 상수로 추출 +const CLUB_DETAIL_QUERY_KEY = 'clubDetail'; + export const useUploadCover = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ clubId, file }: CoverUploadParams) => { const { presignedUrl, finalUrl } = await coverApi.getUploadUrl( clubId, file.name, file.type, ); await uploadToStorage(presignedUrl, file); await coverApi.completeUpload(clubId, finalUrl); return { clubId }; }, onSuccess: (data) => { - queryClient.invalidateQueries({ queryKey: ['clubDetail', data.clubId] }); + queryClient.invalidateQueries({ queryKey: [CLUB_DETAIL_QUERY_KEY, data.clubId] }); }, - onError: () => { - alert('커버 이미지 업로드에 실패했어요. 다시 시도해주세요!'); + onError: (error) => { + console.error('Cover upload failed:', error); + // TODO: alert 대신 토스트 알림 시스템 사용 + alert('커버 이미지 업로드에 실패했어요. 다시 시도해주세요!'); }, }); };
38-55: useUploadCover와 동일한 개선사항 적용을 권장합니다.이 훅도
useUploadCover와 동일한 패턴을 따르고 있어 일관성이 좋습니다. 하지만 동일한 개선사항이 적용되면 좋겠습니다:
alert()대신 토스트 알림 사용onError에서 에러 로깅 추가- 쿼리 키 상수화
🔎 개선된 구현 제안
export const useDeleteCover = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: async (clubId: string) => { await coverApi.delete(clubId); return { clubId }; }, onSuccess: (data) => { - queryClient.invalidateQueries({ queryKey: ['clubDetail', data.clubId] }); + queryClient.invalidateQueries({ queryKey: [CLUB_DETAIL_QUERY_KEY, data.clubId] }); }, - onError: () => { - alert('커버 이미지 삭제에 실패했어요. 다시 시도해주세요!'); + onError: (error) => { + console.error('Cover deletion failed:', error); + // TODO: alert 대신 토스트 알림 시스템 사용 + alert('커버 이미지 삭제에 실패했어요. 다시 시도해주세요!'); }, }); };
10-10: 명시적 반환 타입 추가를 고려해보세요 (선택사항).코딩 가이드라인에 따르면 유사한 함수/훅에 일관된 반환 타입을 사용하도록 권장됩니다. 두 훅 모두 명시적 반환 타입을 추가하면 코드 가독성과 타입 안전성이 향상됩니다.
🔎 명시적 반환 타입 추가 제안
+import { useMutation, useQueryClient, UseMutationResult } from '@tanstack/react-query'; -export const useUploadCover = () => { +export const useUploadCover = (): UseMutationResult< + { clubId: string }, + Error, + CoverUploadParams +> => { const queryClient = useQueryClient(); // ... }; -export const useDeleteCover = () => { +export const useDeleteCover = (): UseMutationResult< + { clubId: string }, + Error, + string +> => { const queryClient = useQueryClient(); // ... };Also applies to: 38-38
📜 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 (1)
frontend/src/hooks/queries/club/cover/useCoverMutation.ts
🧰 Additional context used
📓 Path-based instructions (2)
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/hooks/queries/club/cover/useCoverMutation.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/hooks/queries/club/cover/useCoverMutation.ts
🧬 Code graph analysis (1)
frontend/src/hooks/queries/club/cover/useCoverMutation.ts (2)
frontend/src/apis/image/cover.ts (1)
coverApi(9-59)frontend/src/apis/image/uploadToStorage.ts (1)
uploadToStorage(1-14)
🔇 Additional comments (2)
frontend/src/hooks/queries/club/cover/useCoverMutation.ts (2)
1-8: LGTM! 임포트 및 타입 정의가 명확합니다.필요한 의존성을 적절히 임포트하고,
CoverUploadParams인터페이스도 명확하게 정의되어 있습니다.
1-55: PR 목표와 코드 내용의 불일치를 확인해주세요.이 PR의 브랜치 이름(
refactor/#944-recruitment-date-utc-kst-handling-MOA-433)과 연결된 이슈(MOA-433: 모집 기간 API 응답 형식 변경 및 KST/UTC 시간대 처리)는 모집 기간 및 시간대 처리에 관한 것인데, 실제 코드는 커버 이미지 업로드/삭제 기능입니다.다음 중 하나를 확인해주세요:
- 잘못된 브랜치에 커밋되었는지
- 잘못된 이슈가 연결되었는지
- 이 코드가 이 PR에 포함되어야 하는지
#️⃣연관된 이슈
📝작업 내용
useUploadCover: Presigned URL 발급, 스토리지 업로드, 완료 처리 로직 구현useDeleteCover: 커버 이미지 삭제 로직 구현중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
새로운 기능
클럽 커버 이미지 업로드: 사용자가 클럽의 커버 이미지를 간편하게 업로드할 수 있습니다. 이미지는 안전한 저장소에 보관되며, 업로드 완료 후 클럽 정보가 자동으로 즉시 갱신되어 모든 사용자에게 실시간으로 반영됩니다.
클럽 커버 이미지 삭제: 더 이상 필요하지 않은 커버 이미지를 언제든지 쉽게 삭제할 수 있으며, 삭제 후에도 클럽 정보가 자동으로 업데이트됩니다.
✏️ Tip: You can customize this high-level summary in your review settings.