-
Notifications
You must be signed in to change notification settings - Fork 0
활동기록 구현 (#issue 261) #264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
활동기록 구현 (#issue 261) #264
Conversation
|
""" Walkthrough이 변경사항은 마이페이지 내 활동기록(내 댓글, 내 문의) 기능을 전면적으로 도입하고, 관련 API 연동, 데이터 모델 정의, React Query 기반의 데이터 패칭 훅, UI 컴포넌트 및 스타일링을 추가 및 개선합니다. 또한 기존 프로젝트, 문의, 알림 관련 API 함수의 에러 처리 방식을 개선하여 에러를 상위로 전파하도록 변경하였고, 일부 컴포넌트에서는 로딩 및 비어있는 상태에 대한 처리가 추가되었습니다. 문의 및 댓글 관련 모델, 상수, 스타일드 컴포넌트, 상세 UI 컴포넌트가 신규로 도입되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CommentsActivity
participant useGetMyComments
participant getMyComments API
participant Server
User->>CommentsActivity: 컴포넌트 마운트
CommentsActivity->>useGetMyComments: 훅 호출
useGetMyComments->>getMyComments API: API 요청
getMyComments API->>Server: GET /user/my-comments
Server-->>getMyComments API: 댓글 데이터 반환
getMyComments API-->>useGetMyComments: 데이터 반환
useGetMyComments-->>CommentsActivity: 데이터 및 로딩 상태 반환
CommentsActivity->>User: UI 렌더(로딩/비어있음/목록)
sequenceDiagram
participant User
participant Inquiries
participant useGetMyInquiries
participant getMyInquiries API
participant Server
User->>Inquiries: 컴포넌트 마운트
Inquiries->>useGetMyInquiries: 훅 호출
useGetMyInquiries->>getMyInquiries API: API 요청
getMyInquiries API->>Server: GET /user/my-inquiries
Server-->>getMyInquiries API: 문의 데이터 반환
getMyInquiries API-->>useGetMyInquiries: 데이터 반환
useGetMyInquiries-->>Inquiries: 데이터 및 로딩 상태 반환
Inquiries->>User: UI 렌더(로딩/비어있음/목록)
Assessment against linked issues
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
⏰ Context from checks skipped due to timeout of 90000ms (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 19
🔭 Outside diff range comments (1)
src/components/mypage/activityLog/inquiries/Inquiries.styled.ts (1)
3-5: 🛠️ Refactor suggestion컴포넌트 명명 규칙을 통일해주세요.
styled-component의 명명 규칙은 일반적으로 PascalCase를 사용합니다.
container는 camelCase로 작성되어 있어 파일 내 다른 컴포넌트들과 일관성이 없습니다. 또한container와InquiriesContainer의 역할 구분이 모호합니다.-export const container = styled.div` +export const Container = styled.div` height: 100%; `;
🧹 Nitpick comments (23)
src/components/mypage/notifications/all/All.tsx (1)
28-40: 전반적인 조건부 렌더링 흐름 개선로딩 상태, 데이터 없음, 빈 배열 상태를 명확히 구분하여 처리하는 방식으로 개선하셨네요. 이러한 패턴은 다른 유사한 컴포넌트(CommentsActivity, Inquiries 등)와 일관성을 유지하여 코드 가독성과 유지보수성을 높입니다.
아래와 같이 조건문을 좀 더 간결하게 작성할 수도 있습니다:
if (isLoading) { return <Spinner size='50px' color='#3e5879;' />; } - if (!alarmListData) return; - - if (alarmListData?.length === 0) { + if (!alarmListData || alarmListData.length === 0) { return ( <S.WrapperNoContent> <NoContent type='notification' /> </S.WrapperNoContent> ); }하지만 현재 구현도 명확하고 좋습니다.
src/components/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts (2)
13-18: 컴포넌트 이름 및 스타일 구조 개선 제안
CommentsWrapper라는 이름이 구체적인 역할을 바로 드러내지 못할 수 있습니다. 예를 들어CommentsListContainer또는CommentListWrapper등 더 명확한 네이밍을 고려해보세요.
20-24: 섬세한 구분선 스타일 검토 제안
height: 0.5px는 일부 디바이스에서 렌더링 이슈가 발생할 수 있습니다.border-bottom: 1px solid나 투명도 조절을 통한 hairline 효과로 대체를 고려해주세요.src/api/activityLog.api.ts (2)
1-2: 경로 임포트 방식 개선이 필요합니다.상대 경로 임포트(
'./../models/activityLog')는 프로젝트의 다른 파일들에서 사용하는 절대 경로 임포트 방식과 일관성이 없습니다. 절대 경로를 사용하면 코드의 가독성과 유지보수성이 향상됩니다.다음과 같이 수정해 주세요:
-import type { ApiMyComments, ApiMyInquiries } from './../models/activityLog'; +import type { ApiMyComments, ApiMyInquiries } from '../models/activityLog'; import { httpClient } from './http.api';
1-22: 페이지네이션 및 필터링 매개변수 추가 고려현재 API 함수들은 페이지네이션이나 필터링을 위한 매개변수를 제공하지 않습니다. 데이터가 많아질 경우 페이지네이션을 구현하거나 특정 조건에 따라 필터링할 수 있는 기능을 추가하는 것이 좋습니다.
다음과 같은 방식으로 매개변수를 추가할 수 있습니다:
-export const getMyComments = async () => { +export const getMyComments = async (page = 1, limit = 10) => { try { - const response = await httpClient.get<ApiMyComments>(`user/my-comments`); + const response = await httpClient.get<ApiMyComments>(`user/my-comments?page=${page}&limit=${limit}`); return response.data.data; } catch (e) { console.error('내 댓글 에러', e); return []; } }; -export const getMyInquiries = async () => { +export const getMyInquiries = async (page = 1, limit = 10) => { try { - const response = await httpClient.get<ApiMyInquiries>(`user/my-inquiries`); + const response = await httpClient.get<ApiMyInquiries>(`user/my-inquiries?page=${page}&limit=${limit}`); return response.data.data; } catch (e) { console.error('내 문의글 에러 ', e); return []; } };src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.tsx (1)
13-15: 레이아웃 스타일이 부족합니다.컴포넌트 요소들 간에 여백이나 레이아웃 스타일이 정의되어 있지 않습니다. 가독성을 높이기 위해 적절한 마진이나 패딩을 추가하는 것이 좋겠습니다.
CommentActivity.styled.ts 파일에 다음과 같은 스타일을 추가해보세요:
export const CommentContent = styled.div``; + +export const CommentContent = styled.div` + margin-bottom: 0.5rem; +`; export const CommentDate = styled.div` font-size: 0.8rem; color: ${({ theme }) => theme.color.placeholder}; + margin-bottom: 0.3rem; `;src/components/mypage/activityLog/inquiries/Inquiries.tsx (2)
26-26: 스타일 컴포넌트 이름의 케이스 일관성이 없습니다.
S.container는 소문자로 시작하지만 다른 스타일 컴포넌트들은 대문자로 시작합니다. 일관성을 위해 PascalCase로 통일하는 것이 좋습니다.- <S.container> + <S.Container>
35-42: 배열이 비어있는지 다시 확인하는 불필요한 조건이 있습니다.16번 라인에서 이미 빈 배열인 경우를 처리했기 때문에, 35번 라인의
myCommentsData.length > 0조건은 불필요합니다.- {myCommentsData.length > 0 && - myCommentsData.map((list, index) => ( + {myCommentsData.map((list, index) => ( <Inquiry key={list.title} list={list} no={myCommentsData.length - index} /> - ))} + ))}src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx (3)
1-1: Fragment는 필요한지 확인해 주세요.'react/jsx-runtime'에서 Fragment를 가져오고 있지만 코드에서 실제로 사용하는 곳은 'Fragment key={list.id}'로 jsx-runtime이 아닌 일반 React Fragment를 사용하는 것 같습니다. 불필요한 임포트를 제거하거나 수정하는 것이 좋겠습니다.
-import { Fragment } from 'react/jsx-runtime'; +import { Fragment } from 'react';
12-12: 하드코딩된 색상값을 theme 상수로 대체하세요.색상값을 직접 하드코딩하는 것보다 theme 객체를 사용하면 일관된 스타일 관리가 가능합니다. 또한 색상값 끝에 세미콜론(;)이 포함되어 있어 제거해야 합니다.
- return <Spinner size='50px' color='#3e5879;' />; + return <Spinner size='50px' color='#3e5879' />;더 나은 방법:
- return <Spinner size='50px' color='#3e5879;' />; + return <Spinner size='50px' color={theme.color.navy} />;
15-15: 명시적인 반환값 사용을 권장합니다.데이터가 없을 때 함수가 undefined를 반환하는 것보다 명시적으로 null을 반환하는 것이 더 좋은 방식입니다. React 컴포넌트에서는 일반적으로 null 또는 JSX를 반환합니다.
- if (!myCommentsData) return; + if (!myCommentsData) return null;src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx (2)
1-4: 사용하지 않는 임포트를 제거해주세요.
Fragment와XMarkIcon을 임포트했지만 컴포넌트 내에서 사용하고 있지 않습니다. 사용하지 않는 임포트는 제거하는 것이 좋습니다.-import { Fragment, useState } from 'react'; +import { useState } from 'react'; import type { MyInquiries } from '../../../../../models/activityLog'; import * as S from './Inquiry.styled'; -import { XMarkIcon } from '@heroicons/react/24/outline';🧰 Tools
🪛 ESLint
[error] 1-1: 'Fragment' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 4-4: 'XMarkIcon' is defined but never used.
(@typescript-eslint/no-unused-vars)
18-21: 상태 관리를 간소화할 수 있습니다.이미지 모달의 상태를 객체로 관리하고 있는데, 두 개의 개별 상태 변수로 분리하면 상태 업데이트가 더 간단해질 수 있습니다.
- const [isImageOpen, setIsImageOpen] = useState<IsImageOpen>({ - isImageOpen: false, - url: '', - }); + const [isImageModalOpen, setIsImageModalOpen] = useState<boolean>(false); + const [selectedImageUrl, setSelectedImageUrl] = useState<string>('');그리고 이에 맞게 이후 코드도 수정해야 합니다:
- onClick={() => - setIsImageOpen((prev) => ({ - isImageOpen: !prev.isImageOpen, - url, - })) - } + onClick={() => { + setSelectedImageUrl(url); + setIsImageModalOpen(true); + }}src/components/mypage/activityLog/inquiries/Inquiries.styled.ts (1)
15-15: 반응형 레이아웃을 고려해보세요.현재 테이블 헤더의 그리드 템플릿 컬럼에 하드코딩된 백분율을 사용하고 있습니다. 다양한 화면 크기에 대응하기 위해
fr단위나minmax()함수를 활용한 반응형 그리드 레이아웃을 고려해보세요.- grid-template-columns: 8% 18% 62% 12%; + grid-template-columns: minmax(50px, 8%) minmax(100px, 18%) minmax(200px, 1fr) minmax(80px, 12%);src/components/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts (9)
3-6: 테마 기반 타이포그래피 사용 권장
현재font-size: 1.1rem이 하드코딩되어 있습니다. 테마에 정의된 폰트 사이즈 스케일(예:theme.fontSizes.md)을 활용하면 디자인 일관성을 유지하고, 전체 코드베이스에서 폰트 크기 관리가 용이해집니다.
8-12: 그리드 단위에 fr 단위 사용 고려
grid-template-columns: 8% 18% 62% 12%;보다8fr 18fr 62fr 12fr과 같이 fr 단위를 사용하면 칼럼 비율 비례가 더 직관적이며, 컨테이너 크기 변화에도 유연하게 대응할 수 있습니다.
18-20: 불필요한 빈 styled 컴포넌트 정리 제안
InquiryCategory,InquiryTitle,InquiryContent,ModalImg등 스타일이 비어 있는 컴포넌트는 기본 태그로 대체하거나, 실제 스타일이 필요해질 때 추가 정의하는 것이 코드 가독성과 유지보수성에 도움이 됩니다.Also applies to: 32-32, 82-82
26-30: 테마 기반 스페이싱 유틸 사용 제안
margin: 0.5rem 0; padding: 1rem;대신 테마의 spacing 유틸(예:theme.spacing.sm,theme.spacing.md)을 활용하면 전반적인 간격 관리가 일관되고 조정이 쉬워집니다.
39-42: 모달 내 이미지 간격 정의
InquiryModalImgWrapper에display: flex;만 지정되어 있는데,gap: ${({ theme }) => theme.spacing.xs};등을 추가하여 이미지 간 일관된 간격을 확보하는 것을 고려해보세요.
43-45: 이미지 비율 유지(Aspect Ratio) 지정
InquiryImg에height: auto;또는max-width: 100%; height: auto;속성을 추가하면 원본 비율이 유지되어 다양한 이미지 크기에 안정적으로 대응할 수 있습니다.
47-60: 모달 오픈 시 배경 스크롤 잠금 처리
ModalImgContainer에overflow: hidden;을 추가하거나, 모달 토글 로직에서body에 스크롤 락(lock)을 적용하여 배경 컨텐츠가 스크롤되지 않도록 처리하면 UX가 개선됩니다.
62-72: 모달 이미지 래퍼 반응형 및 최대 너비 설정
ModalImgWrapper에max-width: 90vw; max-height: 90vh;와 같은 속성을 추가하거나, 미디어 쿼리를 통해 작은 화면에서도 이미지가 화면을 벗어나지 않도록 대응하는 것을 추천합니다.
74-80: 버튼 래퍼에 시각적 피드백 및 접근성 강화
ModalImgButtonWrapper가 클릭 인터랙션을 담당한다면,cursor: pointer;,:hover,:active상태 스타일을 추가하거나 실제<button>요소로 변경하여 키보드 접근성과 시각적 피드백을 보강하는 것을 권장합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
src/api/activityLog.api.ts(1 hunks)src/api/inquiry.api.ts(1 hunks)src/api/projectLists.api.ts(2 hunks)src/api/projectSearchFiltering.api.ts(3 hunks)src/components/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts(2 hunks)src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx(1 hunks)src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.styled.ts(1 hunks)src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.tsx(1 hunks)src/components/mypage/activityLog/inquiries/Inquiries.styled.ts(1 hunks)src/components/mypage/activityLog/inquiries/Inquiries.tsx(1 hunks)src/components/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts(1 hunks)src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx(1 hunks)src/components/mypage/notifications/all/All.tsx(2 hunks)src/hooks/queries/keys.ts(1 hunks)src/hooks/useGetMyComments.ts(1 hunks)src/hooks/useGetMyInquires.ts(1 hunks)src/models/activityLog.ts(1 hunks)src/models/alarm.ts(1 hunks)src/util/formatDate.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (9)
src/api/activityLog.api.ts (2)
src/api/http.api.ts (1)
httpClient(78-78)src/models/activityLog.ts (2)
ApiMyComments(23-25)ApiMyInquiries(11-13)
src/hooks/useGetMyComments.ts (2)
src/hooks/queries/keys.ts (1)
ActivityLog(42-45)src/api/activityLog.api.ts (1)
getMyComments(4-12)
src/components/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts (2)
src/components/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts (1)
Container(3-6)src/components/mypage/myProfile/MyProfile.styled.ts (1)
Container(17-32)
src/hooks/useGetMyInquires.ts (2)
src/hooks/queries/keys.ts (1)
ActivityLog(42-45)src/api/activityLog.api.ts (1)
getMyInquiries(14-22)
src/components/mypage/activityLog/inquiries/Inquiries.tsx (4)
src/hooks/useGetMyInquires.ts (1)
useGetMyInquires(6-15)src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)src/components/common/noContent/NoContent.tsx (1)
NoContent(14-30)src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx (1)
Inquiry(16-72)
src/models/activityLog.ts (1)
src/models/apiCommon.ts (1)
ApiCommonType(1-4)
src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.tsx (2)
src/models/activityLog.ts (1)
MyComments(15-21)src/util/formatDate.ts (1)
formatDate(3-6)
src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx (4)
src/hooks/useGetMyComments.ts (1)
useGetMyComments(6-15)src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)src/components/common/noContent/NoContent.tsx (1)
NoContent(14-30)src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.tsx (1)
CommentActivity(10-18)
src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx (1)
src/models/activityLog.ts (1)
MyInquiries(3-9)
🪛 ESLint
src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx
[error] 1-1: 'Fragment' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 4-4: 'XMarkIcon' is defined but never used.
(@typescript-eslint/no-unused-vars)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: accessibility-test
🔇 Additional comments (20)
src/components/mypage/notifications/all/All.tsx (5)
8-8: 로딩 상태 표시를 위한 Spinner 컴포넌트 추가비동기 데이터 로딩 상태를 사용자에게 시각적으로 표시하기 위한 Spinner 컴포넌트를 추가하셨네요. 사용자 경험 향상을 위한 좋은 개선입니다.
11-11: useAlarmList 훅에서 isLoading 상태 활용useAlarmList 훅에서 isLoading 상태를 구조분해할당하여 가져오는 방식으로 개선하셨네요. 비동기 데이터 페칭 상태를 명확하게 처리할 수 있어 좋은 패턴입니다.
28-31: 로딩 상태 처리 로직 추가데이터 로딩 중일 때 Spinner 컴포넌트를 표시하는 조건부 렌더링을 추가하셨네요. 사용자에게 현재 데이터를 가져오는 중임을 명확히 알려주어 좋은 사용자 경험을 제공합니다.
32-33: 데이터 없음 처리를 위한 조기 반환alarmListData가 falsy일 경우 조기 반환하는 방어적 프로그래밍 패턴을 적용하셨네요. 데이터가 없는 경우를 명시적으로 처리하여 불필요한 렌더링을 방지합니다.
34-34: 빈 배열 체크 로직 개선빈 배열 확인 로직을 더 명확하게 개선하셨네요. 이전에는 null과 빈 배열 체크가 결합되어 있었던 것으로 보이는데, 이를 분리하여 더 명확한 조건부 렌더링 흐름을 만드셨습니다.
src/models/alarm.ts (1)
21-21: 필드명 camelCase로 일관성 유지
AlarmFilterId→alarmFilterId로 변경되어 기존 PascalCase에서 camelCase로 맞추셨습니다. 네이밍 컨벤션이 개선되었으니, API 응답 매핑이나 직렬화 로직에서 필드명이 올바르게 변환되는지 확인해주세요.src/util/formatDate.ts (1)
5-5: 날짜 포맷 변경에 따른 일괄 적용 여부 검증 필요
'yyyy년 MM월 dd일'에서'yyyy.MM.dd'로 변경하셨습니다. UI 전반의 날짜 표시가 일관되도록 다른 컴포넌트와 테스트에서도 동일한 포맷을 사용하고 있는지 확인해주세요.src/components/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts (1)
3-5: PascalCase 네이밍 일관성 유지
container를Container로 변경하여 다른 styled-component와 동일한 PascalCase 규칙을 따르셨습니다. 네이밍 컨벤션이 일관적이라 가독성이 향상됩니다.src/api/inquiry.api.ts (1)
12-12: 에러 로깅 방식 개선이 적절하게 적용되었습니다.
console.log에서console.error로 변경하여 에러 로깅 방식이 개선되었습니다. 이는 에러의 심각성을 더 정확히 나타내며, 프로젝트 전반에 걸친 에러 로깅 방식 표준화에 기여합니다.src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.styled.ts (4)
3-5: 스타일 컴포넌트 구성이 깔끔합니다.커서 스타일을 pointer로 설정하여 사용자에게 클릭 가능함을 시각적으로 알려주는 좋은 UX 요소입니다.
7-7: 추가 스타일 정의가 필요한지 확인해 주세요.CommentContent에 스타일이 정의되어 있지 않습니다. 의도적인 것인지, 추가 스타일링이 필요한지 검토해 보세요.
9-12: 테마 색상 활용이 적절합니다.테마의 placeholder 색상을 활용하여 날짜 텍스트의 중요도를 낮추는 좋은 접근법입니다.
14-16: 프로젝트 제목 스타일이 적절합니다.프로젝트 제목에 약간 더 큰 폰트 크기를 적용하여 시각적 계층 구조를 만들어 주었습니다.
src/hooks/useGetMyInquires.ts (1)
9-12: 쿼리 키 구성이 적절합니다.사용자 ID를 쿼리 키에 포함시켜 사용자별로 데이터를 구분하는 좋은 방식입니다.
src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.tsx (1)
6-8: 인터페이스 정의가 명확합니다.props 인터페이스가 간결하고 명확하게 정의되어 있습니다.
src/components/mypage/activityLog/inquiries/Inquiries.tsx (1)
10-12: 로딩 상태 처리가 잘 구현되었습니다.데이터 로딩 중일 때 Spinner 컴포넌트를 표시하는 좋은 UX 구현입니다.
src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx (1)
28-35: 댓글 표시 구조가 잘 구현되었습니다.댓글 목록을 순회하며 각 댓글을 CommentActivity 컴포넌트로 표시하고, 마지막 항목을 제외한 모든 항목 사이에 구분선을 추가하는 로직이 잘 구현되었습니다.
src/models/activityLog.ts (1)
3-25: 인터페이스 구조가 명확히 설계되었습니다.사용자 활동 로그(문의, 댓글)에 대한 인터페이스가 명확하게 정의되어 있습니다. 공통 API 응답 타입을 확장하여 재사용성을 높인 것도 좋은 접근입니다.
다만,
createdAt필드의 날짜 형식에 대한 주석이나 타입을 추가하면 더 명확할 것 같습니다:export interface MyComments { id: number; content: string; - createdAt: string; + createdAt: string; // ISO 8601 format: YYYY-MM-DDTHH:mm:ss.sssZ projectId: number; projectTitle: string; }src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx (1)
38-38: 배열 요소에 더 안정적인 키 사용을 고려하세요.현재 이미지 배열을 매핑할 때 카테고리, 제목, URL을 조합하여 키를 생성하고 있습니다. 이 방식은 같은 URL을 가진 이미지가 있을 경우 중복 키가 생성될 가능성이 있습니다. 가능하다면 고유 ID나 인덱스를 활용하는 것이 더 안전합니다.
- key={`${list.category}-${list.title}-${url}`} + key={`${list.category}-${list.title}-${url}-${index}`}src/components/mypage/activityLog/inquiries/Inquiries.styled.ts (1)
38-42: 스타일링 구조가 잘 정의되었습니다.
InquiriesWrapper컴포넌트가 플렉스 레이아웃을 사용하여 문의 목록을 수직으로 정렬하고 gap을 적용한 점이 좋습니다. 이렇게 하면 간격 조정이 쉽고 레이아웃이 깔끔하게 유지됩니다.
| {myCommentsData.length > 0 && | ||
| myCommentsData.map((list, index) => ( | ||
| <Inquiry | ||
| key={list.title} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
더 안정적인 키 값이 필요합니다.
리스트의 key로 list.title을 사용하는 것은 제목이 중복될 경우 문제가 될 수 있습니다. list.id와 같은 고유 식별자를 사용하는 것이 더 안정적입니다.
<Inquiry
- key={list.title}
+ key={list.id}
list={list}
no={myCommentsData.length - index}
/>📝 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.
| key={list.title} | |
| <Inquiry | |
| key={list.id} | |
| list={list} | |
| no={myCommentsData.length - index} | |
| /> |
| {isImageOpen.isImageOpen && ( | ||
| <S.ModalImgContainer> | ||
| <S.ModalImgWrapper | ||
| onClick={() => | ||
| setIsImageOpen({ | ||
| isImageOpen: false, | ||
| url: '', | ||
| }) | ||
| } | ||
| > | ||
| <S.ModalImgButtonWrapper> | ||
| 이미지를 클릭하면 사라집니다. | ||
| </S.ModalImgButtonWrapper> | ||
| <S.ModalImg src={isImageOpen.url} /> | ||
| </S.ModalImgWrapper> | ||
| </S.ModalImgContainer> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
모달 닫기 기능 개선이 필요합니다.
현재 모달을 닫는 로직이 객체 전체를 다시 설정하고 있습니다. 모달 표시 여부만 토글하는 방식으로 단순화할 수 있고, 모달 닫기 버튼을 추가하는 것도 UX 관점에서 좋을 것 같습니다.
- onClick={() =>
- setIsImageOpen({
- isImageOpen: false,
- url: '',
- })
- }
+ onClick={() => setIsImageOpen(prev => ({...prev, isImageOpen: false}))}또한 하드코딩된 메시지 "이미지를 클릭하면 사라집니다"는 상수 파일로 분리하여 국제화를 쉽게 지원할 수 있도록 하는 것이 좋습니다.
📝 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.
| {isImageOpen.isImageOpen && ( | |
| <S.ModalImgContainer> | |
| <S.ModalImgWrapper | |
| onClick={() => | |
| setIsImageOpen({ | |
| isImageOpen: false, | |
| url: '', | |
| }) | |
| } | |
| > | |
| <S.ModalImgButtonWrapper> | |
| 이미지를 클릭하면 사라집니다. | |
| </S.ModalImgButtonWrapper> | |
| <S.ModalImg src={isImageOpen.url} /> | |
| </S.ModalImgWrapper> | |
| </S.ModalImgContainer> | |
| )} | |
| {isImageOpen.isImageOpen && ( | |
| <S.ModalImgContainer> | |
| <S.ModalImgWrapper | |
| - onClick={() => | |
| - setIsImageOpen({ | |
| - isImageOpen: false, | |
| - url: '', | |
| - }) | |
| - } | |
| + onClick={() => setIsImageOpen(prev => ({ ...prev, isImageOpen: false }))} | |
| > | |
| <S.ModalImgButtonWrapper> | |
| 이미지를 클릭하면 사라집니다. | |
| </S.ModalImgButtonWrapper> | |
| <S.ModalImg src={isImageOpen.url} /> | |
| </S.ModalImgWrapper> | |
| </S.ModalImgContainer> | |
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/api/alarm.api.ts (1)
33-34: 에러 로깅 메시지를 더 명확히 하면 좋겠습니다.에러 로깅 시 구체적인 메시지를 추가하면 디버깅에 더 도움이 될 것입니다. 예를 들어,
console.error('알림 패치 에러:', e);와 같이 명확한 컨텍스트를 제공하는 것이 좋습니다.- console.error(e); + console.error('알림 상태 업데이트 에러:', e);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/api/activityLog.api.ts(1 hunks)src/api/alarm.api.ts(2 hunks)src/api/inquiry.api.ts(1 hunks)src/api/projectLists.api.ts(2 hunks)src/api/projectSearchFiltering.api.ts(3 hunks)src/components/mypage/activityLog/inquiries/Inquiries.styled.ts(1 hunks)src/components/mypage/activityLog/inquiries/Inquiries.tsx(1 hunks)src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx(1 hunks)src/constants/customerService.ts(1 hunks)src/hooks/useGetMyInquires.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/constants/customerService.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- src/api/inquiry.api.ts
- src/api/projectLists.api.ts
- src/hooks/useGetMyInquires.ts
- src/components/mypage/activityLog/inquiries/Inquiries.tsx
- src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx
- src/api/activityLog.api.ts
- src/api/projectSearchFiltering.api.ts
- src/components/mypage/activityLog/inquiries/Inquiries.styled.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: accessibility-test
🔇 Additional comments (1)
src/api/alarm.api.ts (1)
19-20: 에러 처리가 개선되었습니다!이전 코드에서
console.log를 사용하여 에러를 기록하던 것을console.error로 변경하고, 에러를 다시 throw하여 호출자에게 전파하는 방식으로 개선한 것이 좋습니다. 이는 에러 처리의 일관성을 유지하는 데 도움이 됩니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
src/components/mypage/activityLog/inquiries/Inquiries.tsx (1)
34-34: 더 안정적인 키 값이 필요합니다.리스트의
key로 인덱스와 제목의 조합을 사용하는 것은 제목이 중복될 경우 문제가 될 수 있습니다.list.id와 같은 고유 식별자를 사용하는 것이 더 안정적입니다.다음과 같이 수정하는 것을 제안합니다:
<Inquiry - key={`${index}-${list.title}`} + key={list.id} list={list} no={myInquiriesData.length - index} />
🧹 Nitpick comments (3)
src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.styled.ts (3)
3-3: CommentContent에 스타일 속성이 없습니다CommentContent 스타일드 컴포넌트에 스타일 속성이 정의되어 있지 않습니다. 이는 의도적인 설계인지, 아니면 향후 스타일링을 위한 자리 표시자인지 확인해 보세요. 추가적인 스타일이 필요하지 않다면 일반 div 태그를 사용하는 것이 더 나을 수 있습니다.
10-12: CommentProject 스타일링 적절함CommentProject 컴포넌트에 0.9rem 글꼴 크기를 적용한 것은 프로젝트 정보를 표시하는 데 적합합니다. 다만, 가독성을 위해 추가적인 스타일링(예: 글꼴 굵기, 줄 간격 등)을 고려해 볼 수 있습니다.
1-13: 컴포넌트 간 계층 구조 고려현재 세 컴포넌트(CommentContent, CommentDate, CommentProject)가 독립적으로 정의되어 있습니다. 이 컴포넌트들 간의 계층 구조나 상호 작용 방식을 고려하여 스타일링을 더 체계적으로 구성할 수 있습니다. 예를 들어, 반응형 디자인을 위한 미디어 쿼리나 중첩 스타일링을 추가할 수 있습니다.
import styled from 'styled-components'; -export const CommentContent = styled.div``; +export const CommentContent = styled.div` + margin-bottom: 0.5rem; +`; export const CommentDate = styled.div` font-size: 0.8rem; color: ${({ theme }) => theme.color.placeholder}; `; export const CommentProject = styled.div` font-size: 0.9rem; + font-weight: 500; + margin-bottom: 0.3rem; `;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx(1 hunks)src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.styled.ts(1 hunks)src/components/mypage/activityLog/inquiries/Inquiries.tsx(1 hunks)src/components/mypage/notifications/all/All.tsx(2 hunks)src/components/mypage/notifications/appliedProjects/AppliedProjects.tsx(1 hunks)src/hooks/queries/keys.ts(1 hunks)src/hooks/useGetMyComments.ts(1 hunks)src/hooks/useGetMyInquiries.ts(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/hooks/queries/keys.ts
- src/hooks/useGetMyComments.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/components/mypage/notifications/all/All.tsx
- src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/hooks/useGetMyInquiries.ts (2)
src/hooks/queries/keys.ts (1)
ActivityLog(42-45)src/api/activityLog.api.ts (1)
getMyInquiries(15-24)
src/components/mypage/activityLog/inquiries/Inquiries.tsx (4)
src/hooks/useGetMyInquiries.ts (1)
useGetMyInquiries(6-15)src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)src/components/common/noContent/NoContent.tsx (1)
NoContent(14-30)src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx (1)
Inquiry(16-72)
src/components/mypage/notifications/appliedProjects/AppliedProjects.tsx (1)
src/components/common/noContent/NoContent.tsx (1)
NoContent(14-30)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: accessibility-test
🔇 Additional comments (2)
src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.styled.ts (2)
1-2: styled-components 라이브러리 가져오기 적절함React 컴포넌트 스타일링을 위한 styled-components 라이브러리를 적절하게 가져오고 있습니다.
5-8: CommentDate 스타일링 적절함CommentDate 컴포넌트에 작은 글꼴 크기와 placeholder 색상을 적용한 것은 날짜 표시를 위한 적절한 스타일링입니다. 테마 시스템을 활용해 색상을 일관되게 관리하고 있어 좋습니다.
src/components/mypage/notifications/appliedProjects/AppliedProjects.tsx
Outdated
Show resolved
Hide resolved
| export const useGetMyInquiries = () => { | ||
| const userId = useAuthStore((state) => state.userData?.id); | ||
|
|
||
| const { data: myInquiriesData, isLoading } = useQuery({ | ||
| queryKey: [ActivityLog.myInquiries, userId], | ||
| queryFn: () => getMyInquiries(), | ||
| }); | ||
|
|
||
| return { myInquiriesData, isLoading }; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
에러 상태 처리가 필요합니다.
현재 코드는 데이터와 로딩 상태만 반환하고 있습니다. API 호출이 실패할 경우 사용자에게 적절한 피드백을 제공하기 위해 에러 상태도 반환하는 것이 좋습니다.
다음과 같이 수정하는 것을 제안합니다:
export const useGetMyInquiries = () => {
const userId = useAuthStore((state) => state.userData?.id);
- const { data: myInquiriesData, isLoading } = useQuery({
+ const { data: myInquiriesData, isLoading, error } = useQuery({
queryKey: [ActivityLog.myInquiries, userId],
queryFn: () => getMyInquiries(),
});
- return { myInquiriesData, isLoading };
+ return { myInquiriesData, isLoading, error };
};이렇게 하면 컴포넌트에서 에러 상태에 따라 적절한 UI를 표시할 수 있습니다.
📝 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.
| export const useGetMyInquiries = () => { | |
| const userId = useAuthStore((state) => state.userData?.id); | |
| const { data: myInquiriesData, isLoading } = useQuery({ | |
| queryKey: [ActivityLog.myInquiries, userId], | |
| queryFn: () => getMyInquiries(), | |
| }); | |
| return { myInquiriesData, isLoading }; | |
| }; | |
| export const useGetMyInquiries = () => { | |
| const userId = useAuthStore((state) => state.userData?.id); | |
| const { data: myInquiriesData, isLoading, error } = useQuery({ | |
| queryKey: [ActivityLog.myInquiries, userId], | |
| queryFn: () => getMyInquiries(), | |
| }); | |
| return { myInquiriesData, isLoading, error }; | |
| }; |
hyeongjun6364
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
폴더 depth가 너무 깊어져서 어느 파일이 어디에 있는지 접근성이 어려워지는 것 같습니다!
예를 들어, component -> mypage -> activityLog -> commentsActivity (...생략) 의 구조에서
component -> mypage -> activityLog -> 하위컴포넌트들(CommentsActivity.tsx, commentActivity.tsx)로 가볍게 제안 드립니다~
|
|
||
| if (!alarmListData || (alarmListData && alarmListData?.length === 0)) { | ||
| if (isLoading) { | ||
| return <Spinner size='50px' color='#3e5879;' />; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spinner는 공통 컴포넌트에 있는데 또 만드신 이유가 있나요?
구현내용
활동기록 데이터 ui, api 연결 기능구현
알림 인터페이스 필드명 수정, 로딩시 스피너 추가
연관이슈
close #261
Summary by CodeRabbit
신규 기능
버그 수정
스타일
기타