-
Notifications
You must be signed in to change notification settings - Fork 0
자잘한 수정 (#issue 303) #307
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 303) #307
Conversation
|
""" Walkthrough다양한 컴포넌트와 훅, 스타일, 인증 관련 로직에 걸쳐 리팩토링과 기능 추가가 이루어졌습니다. 주요 변경점으로는 OAuth 로그인 시 userData 반환, 에러바운더리의 라우터 변경 시 리셋, /auth/refresh API 추가(주석 포함), 스타일의 min-height/height 조정, 상태 관리 방식 및 토큰 로직 단순화 등이 있습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant LoginApiPage
participant AuthAPI
participant AuthStore
participant Router
User->>LoginApiPage: OAuth 리다이렉트로 접근
LoginApiPage->>LoginApiPage: URL에서 access_token 추출
alt access_token 있음
LoginApiPage->>AuthAPI: getOauthLogin(access_token)
AuthAPI-->>LoginApiPage: { accessToken, userData }
LoginApiPage->>AuthStore: login(accessToken, userData)
LoginApiPage->>Router: 메인 페이지로 이동
else access_token 없음
LoginApiPage->>LoginApiPage: 모달 오픈(에러 메시지)
LoginApiPage->>Router: 로그인 페이지로 이동
end
Assessment against linked issues
Suggested labels
Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm warn config production Use 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
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. 🪧 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: 26
🔭 Outside diff range comments (1)
src/store/authStore.ts (1)
14-24: 💡 Verification agent🧩 Analysis chain
미사용 함수들을 제거해야 합니다.
새로운 store 구조에서
getStoredUserData와getTokens함수는 더 이상 필요하지 않습니다. 이러한 함수들이 남아있으면 혼란을 야기할 수 있습니다.
🏁 Script executed:
#!/bin/bash # Description: getStoredUserData와 getTokens 함수의 사용 여부 확인 # getStoredUserData 함수 사용 검색 echo "=== getStoredUserData 사용 검색 ===" rg "getStoredUserData" --type ts --type tsx -A 2 -B 2 # getTokens 함수 사용 검색 echo -e "\n=== getTokens 사용 검색 ===" rg "getTokens" --type ts --type tsx -A 2 -B 2Length of output: 291
스크립트에서
--type tsx옵션이 인식되지 않아 검색이 누락되었습니다. TS 및 TSX 파일 확장자로 다시 검색하도록 수정합니다.
🏁 Script executed:
#!/bin/bash # getStoredUserData 함수 사용 검색 (TS/TSX) echo "=== getStoredUserData 사용 검색 ===" rg "getStoredUserData" -g '*.ts' -g '*.tsx' -C 2 # getTokens 함수 사용 검색 (TS/TSX) echo -e "\n=== getTokens 사용 검색 ===" rg "getTokens" -g '*.ts' -g '*.tsx' -C 2Length of output: 774
미사용 함수 제거 필요
src/store/authStore.ts에 정의된 아래 함수들은 코드베이스 전반에서 참조되지 않습니다. 혼란 방지를 위해 제거를 권장합니다.· getStoredUserData
· getTokens제거 예시:
-export const getStoredUserData = () => { - const encryptedData = localStorage.getItem('userData'); - return encryptedData ? decryptData(encryptedData) : null; -}; - -export const getTokens = () => { - const accessToken = localStorage.getItem('accessToken'); - const refreshToken = localStorage.getItem('refreshToken'); - - return { accessToken, refreshToken }; -};
🧹 Nitpick comments (15)
src/components/user/customerService/faq/FAQContent.tsx (1)
24-29: 애니메이션을 위한 좋은 아키텍처 변경입니다만, 접근성 개선이 필요합니다.조건부 렌더링에서 CSS 기반 가시성 제어로 변경한 것은 부드러운 애니메이션을 구현하기 위한 좋은 접근입니다. 하지만 접근성을 위해 숨겨진 콘텐츠가 스크린 리더에서도 적절히 숨겨져야 합니다.
다음과 같이 접근성을 개선할 수 있습니다:
- <S.ListContentWrapper $isShowContent={isFAQContentOpen}> + <S.ListContentWrapper + $isShowContent={isFAQContentOpen} + aria-hidden={!isFAQContentOpen} + >src/components/user/customerService/faq/FAQContent.styled.ts (1)
35-63: 애니메이션 구현이 잘 되어있습니다!max-height 전환과 fade-in 애니메이션을 조합한 구현이 훌륭합니다. 다음과 같은 장점이 있습니다:
- 부드러운 확장/축소 애니메이션
- 적절한 애니메이션 지속 시간 (300ms)
- 깔끔한 조건부 스타일링
성능 최적화를 위한 개선 제안:
${({ $isShowContent }) => $isShowContent && css` - max-height: 100vh; + max-height: 500px; /* 실제 필요한 최대 높이로 조정 */ opacity: 1; cursor: auto; background: ${({ theme }) => theme.color.lightgrey}; padding: 1.5rem 1rem; display: flex; gap: 0.5rem; - animation: slice-show 300ms; + animation: slice-show 300ms ease-out; + transition: max-height 300ms ease-out; `}실제 콘텐츠 높이에 맞는 max-height 값을 사용하면 더 정확한 애니메이션을 구현할 수 있습니다.
src/hooks/user/useAlarmPatch.ts (1)
7-7: 인증 상태 변경 시 쿼리 무효화 문제 가능성
useAuthStore.getState().userData?.id로 변경하면 userId가 훅 생성 시점에만 캡처되어, 이후 로그인 상태 변경에 반응하지 않습니다.이는 쿼리 무효화(line 14)에서 잘못된 userId를 사용할 수 있으며, 알람 목록이 올바르게 업데이트되지 않을 수 있습니다.
만약 이 변경이 성능 최적화를 위한 것이라면, 다음과 같은 대안을 고려해보세요:
export const useAlarmPatch = () => { - const userId = useAuthStore.getState().userData?.id; const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: (id: number) => patchAlarm(id), onSuccess: () => { + const userId = useAuthStore.getState().userData?.id; queryClient.invalidateQueries({ queryKey: [AlarmList.myAlarmList, userId], }); }, });src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts (1)
50-54: GitHub 아이콘 스타일링 추가새로운
GithubImg컴포넌트가 잘 정의되었습니다.filter: invert(1)을 사용한 색상 반전도 적절합니다.반응형 디자인을 위해 모바일에서의 크기 조정을 고려해보세요:
export const GithubImg = styled.img` width: 1.5rem; margin-right: 0.3rem; filter: invert(1); + + @media ${({ theme }) => theme.mediaQuery.mobile} { + width: 1.2rem; + } `;src/pages/login/LoginSuccess.tsx (1)
19-19: 프로덕션 환경에서 디버깅 코드 제거 필요개발 디버깅용 console.log가 남아있습니다. 프로덕션 배포 전에 제거해주세요.
- console.log('accessToken', accessToken);src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts (1)
54-54: styled component 네이밍 개선을 고려해보세요
WrapperNoContentAppliedProjects라는 이름이 다소 길고 명확하지 않습니다. 더 간결하고 용도가 명확한 이름을 고려해보세요.예를 들어:
-export const WrapperNoContentAppliedProjects = styled(WrapperNoContent)``; +export const NoContentWrapper = styled(WrapperNoContent)``;또는 구체적인 용도에 맞게:
-export const WrapperNoContentAppliedProjects = styled(WrapperNoContent)``; +export const InquiriesNoContentWrapper = styled(WrapperNoContent)``;src/models/auth.ts (1)
25-28: ApiOauth 인터페이스 구조 개선 제안새로운 ApiOauth 인터페이스의 구조가 다소 복잡해 보입니다.
data필드에서Pick<LoginResponse, 'accessToken'>을 사용하는 것보다 직접accessToken: string으로 정의하는 것이 더 명확할 수 있습니다.다음과 같이 구조를 단순화하는 것을 고려해보세요:
export interface ApiOauth extends ApiCommonType { - data: Pick<LoginResponse, 'accessToken'>; + data: { + accessToken: string; + }; user: UserData; }src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx (1)
5-11: 키워드 매개변수 처리 로직 개선키워드를 URL 쿼리 매개변수로 전달하는 로직이 잘 구현되어 있습니다. 하지만 URL 인코딩을 고려하는 것이 좋겠습니다.
URL 안전성을 위해 다음과 같이 개선할 수 있습니다:
export default function ListButton({ keyword }: ListButtonProps) { - const isKeyword = keyword ? `?keyword=${keyword}` : ``; + const isKeyword = keyword ? `?keyword=${encodeURIComponent(keyword)}` : ``;src/hooks/user/useNotification.ts (1)
37-37: Authorization 헤더 처리 개선 필요
accessToken이undefined일 때 빈 문자열로 설정되는 것을 검토해야 합니다. 토큰이 없을 때는 헤더 자체를 생략하는 것이 더 적절할 수 있습니다.다음과 같이 조건부로 헤더를 설정하는 것을 고려해보세요:
- Authorization: accessToken ? `Bearer ${accessToken}` : '', + ...(accessToken && { Authorization: `Bearer ${accessToken}` }),src/pages/login/LoginApi.tsx (1)
38-46: 컴포넌트 구조 및 접근성 개선현재 로딩 상태만 표시하고 있지만, 사용자 경험을 위해 로딩 텍스트를 추가하고 접근성을 개선할 수 있습니다.
return ( <S.LoginSuccessContainer> - <Spinner /> + <Spinner /> + <div aria-live="polite">로그인 처리 중...</div> <Modal isOpen={isOpen} onClose={handleModalClose}> {message} </Modal> </S.LoginSuccessContainer> );src/components/user/mypage/myProfile/editProfile/EditProfile.tsx (1)
47-49: GitHub OAuth 리다이렉션 함수 구현 검토 필요.OAuth URL로 직접 리다이렉션하는 방식은 간단하지만, 보안과 에러 처리 측면에서 개선이 필요할 수 있습니다.
다음과 같은 개선사항을 고려해보세요:
const handleClickGithubValidation = () => { + try { + if (!BASE_URL || !github.url) { + console.error('OAuth configuration is missing'); + return; + } window.location.href = `${BASE_URL}/${github.url}`; + } catch (error) { + console.error('Failed to initiate OAuth flow:', error); + } };src/api/http.api.ts (1)
69-72: 401 에러 처리 로직 검토가 필요합니다.재시도 횟수 초과 시 강제 로그아웃과 페이지 리다이렉션을 하는 것은 적절하지만, 사용자 경험 측면에서 개선이 필요할 수 있습니다.
사용자에게 더 나은 경험을 제공하기 위해 다음과 같은 개선을 고려해보세요:
- logout(); - useAuthStore.persist.clearStorage(); - window.location.href = '/login'; - return Promise.reject(error); + logout(); + useAuthStore.persist.clearStorage(); + + // 사용자에게 알림 후 리다이렉션 + alert('인증이 만료되었습니다. 다시 로그인해주세요.'); + window.location.href = '/login'; + return Promise.reject(error);또는 토스트 메시지나 모달을 사용하여 더 부드러운 UX를 제공할 수 있습니다.
src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts (1)
30-32: 컴포넌트 네이밍을 개선하는 것이 좋겠습니다.현재 네이밍이 너무 길고 구체적입니다. 또한
WrapperNoContentMyJoinedProjects는 스타일이 없어 불필요해 보입니다.더 간결한 네이밍을 제안합니다:
-export const ContainerNoContentMyJoinedProjects = styled(WrapperNoContent)``; - -export const WrapperNoContentMyJoinedProjects = styled.div``; +export const NoContentContainer = styled(WrapperNoContent)``;src/store/authStore.ts (1)
33-38: 불필요한 삼항 연산자를 제거하세요.
userData가 이미null일 수 있으므로 삼항 연산자는 불필요합니다.login: (accessToken: string, userData: UserData | null) => { set({ isLoggedIn: true, accessToken, - userData: userData ? userData : null, + userData, });src/components/user/customerService/inquiry/Inquiry.tsx (1)
72-81: 파일 필터링 로직을 더 명확하게 작성하는 것이 좋겠습니다.
forEach내부의 early return보다filter를 사용하면 의도가 더 명확해집니다.- imageFiles.forEach((file) => { - if ( - file.fileValue === My_INQUIRIES_MESSAGE.fileDefault || - file.image === null - ) { - return; - } else { - formData.append('images', file.image); - } - }); + imageFiles + .filter(file => + file.fileValue !== My_INQUIRIES_MESSAGE.fileDefault && + file.image !== null + ) + .forEach(file => { + formData.append('images', file.image!); + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/assets/githubIcon.svgis excluded by!**/*.svg
📒 Files selected for processing (58)
src/api/auth.api.ts(5 hunks)src/api/http.api.ts(2 hunks)src/components/common/ProtectRoute.tsx(1 hunks)src/components/common/error/QueryErrorBoundary.tsx(2 hunks)src/components/common/header/Header.tsx(1 hunks)src/components/common/noContent/NoContent.styled.ts(2 hunks)src/components/common/sidebar/Sidebar.tsx(1 hunks)src/components/user/customerService/CustomerServiceHeader.styled.ts(1 hunks)src/components/user/customerService/CustomerServiceHeader.tsx(5 hunks)src/components/user/customerService/faq/FAQContent.styled.ts(1 hunks)src/components/user/customerService/faq/FAQContent.tsx(1 hunks)src/components/user/customerService/inquiry/Inquiry.styled.ts(3 hunks)src/components/user/customerService/inquiry/Inquiry.tsx(7 hunks)src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx(2 hunks)src/components/user/customerService/noticeDetail/bottom/NoticeDetailBottom.tsx(2 hunks)src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx(1 hunks)src/components/user/mypage/ContentTab.styled.ts(1 hunks)src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts(1 hunks)src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx(1 hunks)src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts(2 hunks)src/components/user/mypage/activityLog/inquiries/Inquiries.tsx(1 hunks)src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts(1 hunks)src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts(3 hunks)src/components/user/mypage/joinedProject/MyJoinProjects.tsx(1 hunks)src/components/user/mypage/joinedProject/Project.styled.ts(1 hunks)src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts(1 hunks)src/components/user/mypage/myProfile/editProfile/EditProfile.tsx(6 hunks)src/components/user/mypage/notifications/all/All.styled.ts(1 hunks)src/components/user/mypage/notifications/all/All.tsx(2 hunks)src/components/user/mypage/notifications/appliedProjects/AppliedProjects.styled.ts(1 hunks)src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx(1 hunks)src/components/user/userPage/userProfile/UserProfile.tsx(1 hunks)src/components/user/userPage/userProjectList/UserProjectList.tsx(2 hunks)src/constants/user/customerService.ts(2 hunks)src/constants/user/routes.ts(2 hunks)src/hooks/useAuth.ts(3 hunks)src/hooks/useOauth.ts(1 hunks)src/hooks/user/useAlarmDelete.ts(1 hunks)src/hooks/user/useAlarmList.ts(1 hunks)src/hooks/user/useAlarmPatch.ts(1 hunks)src/hooks/user/useGetMyComments.ts(1 hunks)src/hooks/user/useGetMyInquiries.ts(1 hunks)src/hooks/user/useMyInfo.ts(3 hunks)src/hooks/user/useNotification.ts(3 hunks)src/hooks/user/usePostInquiry.ts(1 hunks)src/hooks/user/useUserInfo.ts(1 hunks)src/models/auth.ts(1 hunks)src/pages/login/LoginApi.tsx(1 hunks)src/pages/login/LoginSuccess.tsx(1 hunks)src/pages/user/apply/Apply.tsx(1 hunks)src/pages/user/apply/ApplyStep.tsx(1 hunks)src/pages/user/customerService/notice/Notice.tsx(4 hunks)src/pages/user/manage/myProjectList/MyProjectList.styled.ts(1 hunks)src/pages/user/manage/myProjectList/MyProjectList.tsx(1 hunks)src/pages/user/projectDetail/ProjectDetail.tsx(1 hunks)src/routes/AppRoutes.tsx(3 hunks)src/store/authStore.ts(2 hunks)src/util/cryptoUtils.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (26)
src/components/user/mypage/activityLog/inquiries/Inquiries.tsx (2)
src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)src/components/common/noContent/NoContent.tsx (1)
NoContent(14-30)
src/components/user/userPage/userProfile/UserProfile.tsx (1)
src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)
src/api/auth.api.ts (2)
src/api/http.api.ts (1)
httpClient(81-81)src/models/auth.ts (1)
ApiOauth(25-28)
src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx (1)
src/components/user/customerService/noticeDetail/bottom/NoticeDetailBottom.tsx (1)
NoticeDetailBottom(13-45)
src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts (1)
src/components/user/mypage/notifications/all/All.styled.ts (1)
WrapperNoContent(3-8)
src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts (1)
src/components/user/mypage/notifications/all/All.styled.ts (1)
WrapperNoContent(3-8)
src/components/user/customerService/noticeDetail/bottom/NoticeDetailBottom.tsx (1)
src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx (1)
ListButton(9-24)
src/components/user/mypage/notifications/all/All.tsx (1)
src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)
src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts (3)
src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts (1)
WrapperNoContentAppliedProjects(54-54)src/components/user/mypage/notifications/appliedProjects/AppliedProjects.styled.ts (1)
WrapperNoContentAppliedProjects(4-4)src/components/user/mypage/notifications/all/All.styled.ts (1)
WrapperNoContent(3-8)
src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx (2)
src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)src/components/common/noContent/NoContent.tsx (1)
NoContent(14-30)
src/components/user/customerService/CustomerServiceHeader.tsx (2)
src/hooks/useModal.ts (1)
useModal(3-36)src/constants/user/customerService.ts (1)
MODAL_MESSAGE_CUSTOMER_SERVICE(11-13)
src/store/authStore.ts (1)
src/models/auth.ts (1)
UserData(18-23)
src/pages/user/manage/myProjectList/MyProjectList.tsx (2)
src/hooks/user/useManagedProjects.ts (1)
useManagedProjects(6-14)src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)
src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx (2)
src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)src/components/common/noContent/NoContent.tsx (1)
NoContent(14-30)
src/hooks/useOauth.ts (1)
src/api/auth.api.ts (1)
getOauthLogin(89-102)
src/models/auth.ts (1)
src/models/apiCommon.ts (1)
ApiCommonType(1-4)
src/pages/login/LoginSuccess.tsx (3)
src/hooks/useModal.ts (1)
useModal(3-36)src/constants/user/routes.ts (1)
ROUTES(1-32)src/constants/user/authConstants.ts (1)
AUTH_MESSAGE(6-8)
src/hooks/user/useNotification.ts (1)
src/models/alarm.ts (1)
AlarmLive(28-33)
src/components/user/mypage/notifications/appliedProjects/AppliedProjects.styled.ts (1)
src/components/user/mypage/notifications/all/All.styled.ts (1)
WrapperNoContent(3-8)
src/pages/user/manage/myProjectList/MyProjectList.styled.ts (1)
src/components/user/mypage/notifications/all/All.styled.ts (1)
WrapperNoContent(3-8)
src/routes/AppRoutes.tsx (1)
src/pages/login/LoginApi.tsx (1)
LoginApi(12-46)
src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx (1)
src/constants/user/routes.ts (1)
ROUTES(1-32)
src/pages/login/LoginApi.tsx (5)
src/hooks/useModal.ts (1)
useModal(3-36)src/api/auth.api.ts (1)
getOauthLogin(89-102)src/constants/user/routes.ts (1)
ROUTES(1-32)src/constants/user/authConstants.ts (1)
AUTH_MESSAGE(6-8)src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
Spinner(21-28)
src/components/user/customerService/inquiry/Inquiry.tsx (1)
src/constants/user/customerService.ts (2)
My_INQUIRIES_MESSAGE(15-20)INQUIRY_MESSAGE(22-30)
src/components/user/userPage/userProjectList/UserProjectList.tsx (1)
src/components/common/noContent/NoContent.tsx (1)
NoContent(14-30)
src/pages/user/customerService/notice/Notice.tsx (2)
src/models/customerService.ts (1)
NoticeSearch(46-48)src/hooks/user/useGetNotice.ts (1)
useGetNotice(6-17)
🪛 Biome (1.9.4)
src/components/user/mypage/joinedProject/MyJoinProjects.tsx
[error] 20-20: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with
(lint/complexity/noUselessTernary)
🔇 Additional comments (86)
src/components/user/customerService/faq/FAQContent.styled.ts (1)
35-63: 부드러운 애니메이션을 위한 우수한 CSS 구현입니다.max-height와 overflow를 활용한 show/hide 메커니즘과 slice-show 키프레임 애니메이션이 잘 구현되었습니다. 300ms 애니메이션 지속시간과 fade-in 효과가 사용자 경험을 향상시킬 것입니다.
src/components/user/customerService/faq/FAQContent.tsx (1)
24-29: 부드러운 애니메이션을 위한 좋은 리팩토링입니다!조건부 렌더링에서 CSS 기반 가시성 제어로 변경한 것은 좋은 개선사항입니다. 이를 통해 FAQ 콘텐츠가 펼쳐지고 접힐 때 부드러운 애니메이션 효과를 구현할 수 있습니다.
src/components/user/mypage/notifications/all/All.styled.ts (1)
7-7: LGTM! 중앙 정렬 개선
justify-content: center추가로 콘텐츠가 수평과 수직 모두 중앙에 정렬되도록 개선되었습니다. 다른 여러 컴포넌트에서 공유 기반으로 사용되는 스타일 컴포넌트이므로 일관성 있는 UI를 제공하는 좋은 변경입니다.src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx (1)
61-61: 키워드 전달 로직이 잘 구현되었습니다
NoticeDetailBottom컴포넌트에keywordprops를 전달하여 검색 컨텍스트를 유지하는 기능이 잘 구현되었습니다. 이를 통해 사용자가 공지사항 상세 페이지에서 목록으로 돌아갈 때 검색 상태가 유지될 것입니다.src/components/user/userPage/userProfile/UserProfile.tsx (1)
18-18: 스피너 props 제거가 적절합니다
Spinner컴포넌트에서size와colorprops를 제거한 것이 좋습니다. 스타일드 컴포넌트에서 이미 고정된 크기(50px)와 테마 색상을 사용하고 있어 props가 실제로는 효과가 없었습니다. 이 변경으로 코드가 더 간결해지고 다른 컴포넌트들과 일관성도 확보됩니다.src/util/cryptoUtils.ts (1)
2-2: 타입 import 경로 리팩토링이 적절합니다
UserData타입을store에서models레이어로 이동시키고 type-only import를 사용한 것이 좋습니다. 이는 관심사의 분리와 아키텍처 개선에 도움이 되며, 런타임에는 영향을 주지 않으면서 타입 안전성을 유지합니다.src/hooks/user/usePostInquiry.ts (1)
13-13:Details
❓ Verification inconclusive
인증 상태 변경에 대한 반응성 검증 필요
useAuthStore((state) => state.userData?.id)에서useAuthStore.getState().userData?.id로 변경하면 userId가 훅 실행 시점에만 캡처되고, 이후 인증 상태 변경에 반응하지 않습니다.잠재적 문제:
- 사용자가 비로그인 상태에서 이 훅을 사용하는 컴포넌트가 마운트된 후 로그인하면, userId가 여전히 undefined일 수 있습니다
- 이는 쿼리 무효화(line 21)에서 잘못된 키를 사용할 수 있습니다
다음 스크립트로 이 훅이 사용되는 컨텍스트를 확인해주세요:
🏁 Script executed:
#!/bin/bash # 설명: usePostInquiry 훅이 사용되는 위치와 인증 상태를 확인 # usePostInquiry 훅 사용처 검색 rg -A 10 -B 5 "usePostInquiry" # 인증이 필요한 경로에서 사용되는지 확인 rg -A 5 -B 5 "ProtectRoute.*usePostInquiry|usePostInquiry.*ProtectRoute"Length of output: 4193
useAuthStore.getState() 호출로 인한 userId 반응성 이슈 확인 필요
useAuthStore((state) => state.userData?.id)대신useAuthStore.getState().userData?.id를 사용하면 훅 실행 시점에만 userId를 캡처해 이후 인증 상태 변경에 반응하지 않습니다.잠재적 문제:
- 비로그인 상태에서 컴포넌트가 마운트된 후 로그인해도 userId가 여전히
undefined로 남아 있을 수 있습니다.- 이로 인해 쿼리 키(inquiry 요청 무효화 등)에 잘못된
userId가 사용될 위험이 있습니다.확인 요청:
Inquiry.tsx페이지(또는 이 훅을 사용하는 모든 컴포넌트)가 항상 로그인된 사용자만 접근 가능한 auth guard(예: ProtectRoute/PrivateRoute)로 감싸져 있는지 검증해주세요.- 만약 인증 상태 변경에 따라 userId를 즉시 반영해야 한다면,
useAuthStore(selector)형태로 구독하는 방식으로 변경하는 방안을 고려해주세요.src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts (1)
94-97: 반응형 이미지 제약사항 추가 - 훌륭한 개선사항!모달 이미지에
max-width: 90vw와max-height: 90vh제약사항을 추가한 것은 다음과 같은 이점을 제공합니다:
- 대형 이미지가 뷰포트를 넘지 않아 사용자 경험이 개선됩니다
- 모바일 기기에서도 적절한 크기로 표시됩니다
- 접근성이 향상됩니다
src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts (1)
47-48: GitHub OAuth 버튼을 위한 너비 조정GitHub 입력 필드의 너비를 70%로 줄여 OAuth 버튼을 위한 공간을 확보한 것이 적절합니다.
src/components/user/mypage/activityLog/inquiries/Inquiries.tsx (2)
12-16: 로딩 상태 UI 표준화로딩 상태를
WrapperNoContentAppliedProjects로 감싸고data-type='noContent'속성을 추가한 것이 좋습니다. 이는 다른 컴포넌트들과의 UI 일관성을 개선합니다.
21-24: 빈 상태 UI 표준화빈 상태도 동일한 래퍼 패턴을 사용하여 일관된 사용자 경험을 제공합니다.
src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx (2)
21-25: 빈 상태 래핑이 일관성 있게 적용되었습니다.NoContent 컴포넌트를 동일한 wrapper로 감싸는 것이 UI 일관성을 위해 좋은 변경사항입니다.
13-17:Details
✅ Verification successful
스타일 일관성 개선이 잘 적용되었습니다.
로딩 상태를 styled wrapper로 감싸는 변경사항이 다른 컴포넌트들과의 일관성을 높이는 좋은 개선입니다. 다만 Spinner에서
size와colorprops가 제거된 것이 의도적인지 확인해 주세요.
🏁 Script executed:
#!/bin/bash # Spinner 컴포넌트의 기본 스타일링 확인 rg -A 10 "export.*Spinner" src/components/common/loadingSpinner/Length of output: 900
Spinner 기본 스타일 확인 완료
LoadingSpinner.styled.ts에서 Spinner는 기본 크기(50px)와 색상(theme.color.grey/navy)을 styled 컴포넌트로 지정하고 있어,size·colorprops를 지원하지 않습니다. 따라서 props 제거는 의도된 동작이며, 스타일 일관성 개선도 적절합니다.변경사항을 승인합니다.
src/components/common/noContent/NoContent.styled.ts (2)
6-6: 레이아웃 안정성을 위한 좋은 개선사항입니다.기존
height: 100%와 함께min-height: 100%를 추가하여 컨텐츠가 적을 때도 최소 높이를 보장하는 것은 좋은 개선입니다.
18-18: 텍스트 컴포넌트 높이 설정이 적절합니다.NoContentText가 컨테이너의 전체 높이를 차지하도록 하는 것은 센터링과 레이아웃에 도움이 됩니다.
src/routes/AppRoutes.tsx (2)
18-18: OAuth 플로우 개선을 위한 적절한 컴포넌트 추가입니다.LoginApi 컴포넌트 import가 OAuth 로그인 처리를 위해 추가되었습니다.
118-118: OAuth 로그인 플로우를 위한 적절한 라우트 변경입니다.LoginSuccess에서 LoginApi로의 변경이 새로운 OAuth 처리 로직에 맞게 잘 적용되었습니다.
src/components/user/mypage/notifications/appliedProjects/AppliedProjects.styled.ts (1)
2-4: 공유 스타일 컴포넌트 활용이 좋습니다.
WrapperNoContent를 공통 모듈에서 가져와서 확장하는 리팩토링이 좋은 접근입니다. 현재는 추가 스타일이 없지만, 향후 커스터마이징이 필요할 때 유연하게 대응할 수 있고 컴포넌트 간 일관성도 유지됩니다.src/hooks/user/useGetMyComments.ts (1)
7-7:Details
✅ Verification successful
상태 접근 방식 변경이 적절한지 확인 필요
useAuthStore.getState()로 변경하여 불필요한 리렌더링을 방지하는 것은 좋은 접근입니다. 하지만userId가 변경될 때 쿼리가 적절히 업데이트되는지 확인이 필요합니다.다음 스크립트로 userId 변경 시 쿼리 동작을 확인해보세요:
🏁 Script executed:
#!/bin/bash # Description: useGetMyComments 훅이 사용되는 곳에서 userId 변경 처리를 확인 # useGetMyComments 훅 사용처 찾기 rg -A 10 -B 5 "useGetMyComments"Length of output: 3253
getState() 기반 userId 조회는 안전합니다
useGetMyComments훅은 컴포넌트 마운트 시 한 번만 userId를 읽어오며, 컴포넌트 생명주기 동안 userId가 변경되지 않습니다.- 따라서 구독 없이
useAuthStore.getState()를 사용해도 쿼리 키와enabled플래그에 영향을 주지 않아 불필요한 리렌더링을 방지하면서도 동작이 올바르게 유지됩니다.추가 수정 없이 현 구현을 유지하셔도 좋습니다.
src/constants/user/routes.ts (2)
31-31: OAuth 리다이렉트 URL 변경 확인
loginSuccess경로가/login/oauth2/code에서/oauth-redirect로 변경되어 더 명확해졌습니다. OAuth 흐름 처리 로직도 함께 업데이트되었는지 확인해보세요.
13-13:Details
✅ Verification successful
절대 경로에서 상대 경로로의 변경 영향도 확인 필요
mypageEdit경로가 절대 경로('/mypage/edit')에서 상대 경로('edit')로 변경되었습니다. 이 변경사항이 애플리케이션 전체에서 일관되게 적용되었는지 확인이 필요합니다.다음 스크립트로 mypageEdit 라우트 사용처를 확인해보세요:
🏁 Script executed:
#!/bin/bash # Description: mypageEdit 라우트 사용처와 관련된 네비게이션 코드 확인 # mypageEdit 라우트 사용처 찾기 rg -A 3 -B 3 "mypageEdit" # mypage/edit 관련 경로 사용 확인 rg -A 3 -B 3 "mypage.*edit"Length of output: 3326
mypageEdit 경로 상대 적용 확인 완료
AppRoutes.tsx의 중첩 라우트(
path: 'edit')와 MyProfile.tsx의<Link to="edit">모두 React Router v6의 상대 경로로 의도한 대로 동작하며, 코드베이스에 더 이상'/mypage/edit'문자열 참조가 남아있지 않습니다.src/components/common/error/QueryErrorBoundary.tsx (1)
5-5: 라우트 변경 시 에러 바운더리 리셋 기능 추가가 훌륭합니다.
useLocation훅을 사용하여 라우트 변경 시 에러 바운더리를 자동으로 리셋하는 기능이 추가되었습니다. 이는 사용자가 다른 페이지로 이동할 때 이전 에러 상태를 자동으로 클리어하여 더 나은 사용자 경험을 제공합니다.
key={location.pathname}속성을 통해 경로가 변경될 때마다 ErrorBoundary 컴포넌트가 새로 마운트되는 React의 표준 패턴을 잘 활용했습니다.Also applies to: 9-9, 18-18
src/hooks/user/useGetMyInquiries.ts (1)
7-7:Details
❓ Verification inconclusive
인증 상태 변경 시 쿼리 무효화 문제 우려
useAuthStore.getState()를 사용하면 인증 상태가 변경되어도 컴포넌트가 재렌더링되지 않습니다. 사용자가 로그아웃 후 다른 계정으로 로그인할 경우,userId가 변경되어도 쿼리가 자동으로 무효화되지 않아 이전 사용자의 데이터가 표시될 수 있습니다.반응형 스토어 구독 방식으로 되돌리거나, 컴포넌트 레벨에서 인증 상태 변경을 감지하는 로직이 필요할 수 있습니다.
🏁 Script executed:
#!/bin/bash # 설명: 다른 훅들에서도 동일한 패턴이 사용되는지 확인하여 일관성 있는 해결방안이 필요한지 검증 echo "useAuthStore.getState() 패턴을 사용하는 파일들 검색:" rg -A 3 -B 1 "useAuthStore\.getState\(\)" --type tsx --type ts echo -e "\n반응형 훅 패턴을 여전히 사용하는 파일들 검색:" rg -A 3 -B 1 "useAuthStore\(\(state\)" --type tsx --type tsLength of output: 342
tsx 파일 타입 미인식으로 검색이 실패했습니다. 파일 타입 필터를 제거하고 전역에서 패턴을 재검색해 보겠습니다.
#!/bin/bash echo "useAuthStore.getState() 패턴 검색:" rg -A 3 -B 1 "useAuthStore\.getState\(\)" echo -e "\nreactive 훅(useAuthStore(state => …)) 패턴 검색:" rg -A 3 -B 1 "useAuthStore\([^)]*=>"
다른 훅에서도 동일한 패턴이 사용되는지 전역에서 확인해 보겠습니다.
#!/bin/bash echo "useAuthStore.getState() 패턴 검색:" rg -A3 -B1 "useAuthStore\.getState\(" echo -e "\nreactive 구독 패턴(useAuthStore(state => …)) 검색:" rg -A3 -B1 "useAuthStore\([^)]*=>"
인증 상태 변화 반응 실패로 인한 쿼리 무효화 누락 위험
src/hooks/user/useGetMyInquiries.ts에서와 같이 동기 스냅샷 방식으로 전환되어, 스토어 업데이트 시 컴포넌트 리렌더링과 쿼리 자동 갱신이 발생하지 않습니다.// 변경 전 const userId = useAuthStore(state => state.userData?.id); // 변경 후 const userId = useAuthStore.getState().userData?.id;- 로그인·로그아웃 등으로
userId가 변경되더라도useQuery의queryKey가 업데이트되지 않아 이전 사용자 데이터가 계속 표시될 수 있습니다.제안
- 반응형 구독 방식(
useAuthStore(state => …))으로 복원하거나,userId변화를 감지해useQuery를 수동으로refetch또는invalidate처리할 수 있는 로직 추가- 동일한 패턴(
useAuthStore.getState())이 다른 파일에서도 사용되는지 검토하여 일관된 대응 필요src/pages/user/manage/myProjectList/MyProjectList.tsx (3)
1-1: 적절한 import 추가로딩 상태 처리를 위한 Spinner 컴포넌트 import가 적절히 추가되었습니다.
8-8: 로딩 상태 처리 개선
useManagedProjects훅에서isLoading상태를 올바르게 구조분해할당으로 가져왔습니다. 이는 로딩 상태 처리를 위한 적절한 준비 단계입니다.
10-16: 우수한 로딩 상태 UI 구현로딩 중일 때 스피너를 표시하는 조건부 렌더링이 잘 구현되었습니다. early return 패턴을 사용하여 코드 가독성을 높였고, 전용 스타일 컴포넌트(
WrapperNoContentMyProjectList)를 사용하여 일관된 레이아웃을 제공합니다.이는 사용자 경험을 크게 개선하는 변경사항입니다.
src/pages/login/LoginSuccess.tsx (1)
13-13:Details
✅ Verification successful
인증 스토어 메서드 변경 확인 필요
storeLogin에서login으로 메서드명이 변경되고, 두 번째 매개변수로null을 전달하고 있습니다. 새로운login메서드의 시그니처가(accessToken: string, userData: any | null)형태인지 확인이 필요합니다.다음 스크립트를 실행하여 authStore의 login 메서드 시그니처를 확인해주세요:
Also applies to: 22-22, 30-30
🏁 Script executed:
#!/bin/bash # authStore의 login 메서드 정의 확인 ast-grep --pattern 'login: ($$$) => $$$'Length of output: 42
🏁 Script executed:
#!/bin/bash # useAuthStore 정의 파일 찾기 file=$(grep -R "useAuthStore" -n src | head -n1 | cut -d: -f1) echo "useAuthStore 정의 파일: $file" # login 메서드 정의 및 시그니처 확인 grep -R "login" -n "$file" | sed -n '1,10p'Length of output: 370
추가로 아래 스크립트를 실행해 Zustand로 정의된 Auth 스토어 파일을 찾고, 해당 파일에서
login메서드의 정의 및 시그니처를 확인해주세요.
🏁 Script executed:
#!/bin/bash # 1) Zustand로 정의된 스토어 파일 경로 수집 store_files=$(grep -R "from ['\"]zustand['\"]" -n src | cut -d: -f1 | sort | uniq) echo "Zustand 스토어 파일 목록:" echo "$store_files" echo "" # 2) 각 파일에서 login 메서드 정의 위치와 시그니처 출력 for file in $store_files; do echo "==> $file <==" grep -R -n "login\s*:" "$file" | sed -n '1,10p' echo "" doneLength of output: 537
Auth 스토어 login 메서드 시그니처 확인됨
src/store/authStore.ts에서login메서드가 아래와 같이 정의되어 있어, 두 번째 인자로null을 전달하는 것이 유효합니다.10: login: (accessToken: string, userData: UserData | null) => void; 33: login: (accessToken: string, userData: UserData | null) => { … }src/components/user/mypage/notifications/all/All.tsx (1)
32-36: UI 상태 표준화 개선로딩 상태와 빈 콘텐츠 상태를 일관된 래퍼 컨테이너로 감싸는 변경사항이 좋습니다.
data-type='noContent'속성을 통해 CSS에서 일관된 스타일링이 가능하며, 사용자 경험 개선에 도움이 됩니다.Also applies to: 50-52
src/components/user/mypage/ContentTab.styled.ts (1)
80-85:Details
✅ Verification successful
CSS :has() 선택자 브라우저 호환성 확인 필요
:has()선택자를 사용한 조건부 스타일링이 깔끔하게 구현되었습니다. 다만:has()선택자는 비교적 최신 CSS 기능이므로 타겟 브라우저에서의 지원 여부를 확인해주세요.다음 웹 검색을 통해 최신 브라우저 지원 현황을 확인해주세요:
🌐 Web query:
CSS :has() selector browser support 2024💡 Result:
As of May 2025, the CSS
:has()pseudo-class selector is supported by the latest versions of major browsers, including Chrome, Firefox, Safari, and Edge. This selector allows developers to apply styles to an element based on the presence of specific child elements, effectively enabling parent selectors in CSS.Browser Support:
- Chrome: Full support from version 105 onwards.
- Firefox: Full support from version 121 onwards.
- Safari: Full support from version 15.4 onwards.
- Edge: Full support from version 105 onwards.
For a comprehensive overview of browser compatibility, you can refer to the Can I use website.
Usage Example:
The
:has()selector can be particularly useful for styling elements based on their child content. For instance, to apply a border to any<article>element that contains an<img>tag:article:has(img) { border: 2px solid blue; }This rule will add a blue border around articles that include images, distinguishing them from those without. (freecodecamp.org)
Performance Considerations:
While the
:has()selector offers powerful styling capabilities, it's important to use it judiciously. Overusing this selector, especially with complex descendant selectors, can impact performance, as the browser needs to evaluate the presence of child elements for each parent element. To mitigate potential performance issues, consider scoping the:has()selector to specific containers and avoid applying it to a large number of elements. (verpex.com)In summary, the
:has()selector is a valuable addition to CSS, providing enhanced flexibility in styling elements based on their child content. With broad browser support and mindful usage, it can significantly improve the efficiency and maintainability of your CSS code.Citations:
- 1: https://www.freecodecamp.org/news/how-to-use-the-has-selector-in-css?utm_source=openai
- 2: https://verpex.com/blog/website-tips/understanding-the-has-pseudo-class-in-css?utm_source=openai
CSS
:has()선택자 브라우저 호환성 관련 업데이트현대 주요 브라우저(Chrome 105+, Firefox 121+, Safari 15.4+, Edge 105+)에서
:has()선택자를 모두 지원하므로 본 PR에 도입해도 무방합니다.
다만, 성능 영향을 최소화하기 위해 범위가 넓은 요소에 과도하게 적용하기보다는 특정 컨테이너 내로 스코핑하여 사용하시길 권장드립니다.src/pages/user/manage/myProjectList/MyProjectList.styled.ts (2)
2-7: 기존 컴포넌트 재사용을 통한 일관성 개선
WrapperNoContent를 가져와서 확장하는 방식으로 코드 재사용성을 높이고 UI 일관성을 개선했습니다.80vh높이 설정으로 프로젝트 리스트 페이지에 적합한 레이아웃을 제공합니다.
13-13: 레이아웃 개선컨테이너에 하단 마진을 추가하여 페이지 레이아웃이 개선되었습니다.
src/components/user/mypage/activityLog/inquiries/Inquiries.styled.ts (1)
2-2: 공통 styled component 재사용 - 좋은 리팩토링입니다!코드 중복을 제거하고 공통 스타일을 재사용하는 좋은 방향의 변경입니다.
src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx (2)
12-17: 로딩 상태 wrapper 표준화 - 좋은 개선입니다!로딩 상태를
WrapperNoContentAppliedProjects로 감싸고data-type속성을 추가하여 스타일링을 표준화한 것은 좋은 변경입니다. 다른 컴포넌트들과 일관성을 유지하고 있습니다.
20-25: 빈 컨텐츠 상태 wrapper 표준화빈 컨텐츠 상태도 동일한 wrapper로 감싸여 일관된 레이아웃을 제공합니다. 좋은 리팩토링입니다.
src/components/user/customerService/noticeDetail/bottom/NoticeDetailBottom.tsx (1)
10-10: 키워드 상태 전파 기능 추가 - 좋은 UX 개선입니다!
keywordprop을 추가하여 공지사항 상세 페이지에서 목록으로 돌아갈 때 검색 필터 상태를 유지할 수 있게 한 것은 사용자 경험을 향상시키는 좋은 변경입니다. 데이터 플로우도 명확하고 적절합니다.Also applies to: 16-16, 42-42
src/models/auth.ts (1)
18-23:Details
✅ Verification successful
UserData 인터페이스의 로컬 정의 검토 필요
UserData 인터페이스를 로컬에서 정의하고 있는데, 이전에 auth store에서 import하던 것과 동일한 구조인지 확인이 필요합니다. 타입 정의의 중복을 방지하기 위해 공통 타입 파일로 이동하는 것을 고려해보세요.
다음 스크립트로 UserData 타입의 기존 정의와 사용처를 확인하겠습니다:
🏁 Script executed:
#!/bin/bash # UserData 타입의 정의와 사용처 확인 rg -A 5 "interface UserData|type UserData" --type ts echo "=== UserData 사용처 ===" rg "UserData" --type ts -nLength of output: 1020
UserData 인터페이스 중복 정의 없음
src/models/auth.ts에서만 한 번 정의된UserData인터페이스가
여러 위치(cryptoUtils.ts,authStore.ts등)에서 일관되게 사용되고 있어
현재로서는 별도 공통 타입 파일로 이동할 필요가 없습니다.다만, 향후 프로젝트 규모가 커져 여러 도메인에서 광범위하게 사용될 경우에는
types/디렉터리 등으로 분리 관리하는 방안을 고려해보시면 좋겠습니다.src/hooks/useAuth.ts (3)
100-100: 명시적 스토리지 클리어 로직 확인
useAuthStore.persist.clearStorage()호출이 추가되었는데, 이는 좋은 변경입니다. 하지만 이 메서드가 Zustand persist 미들웨어에서 제공하는 표준 API인지 확인이 필요합니다.명시적 스토리지 클리어는 로그아웃 시 데이터 정리를 위한 좋은 방법입니다.
16-16:Details
❓ Verification inconclusive
상태 접근 방식 변경으로 인한 반응성 검토 필요
useAuthStore훅 대신useAuthStore.getState()를 사용하는 것은 컴포넌트의 반응성을 제거합니다. 인증 상태가 변경될 때 컴포넌트가 리렌더링되지 않을 수 있습니다.이 변경이 의도된 것인지, 그리고 다른 컴포넌트에서도 동일한 패턴이 적용되었는지 확인해보겠습니다:
🏁 Script executed:
#!/bin/bash # useAuthStore 사용 패턴 확인 echo "=== useAuthStore() 훅 사용 ===" rg "useAuthStore\(\)" --type ts -n -A 2 echo "=== useAuthStore.getState() 직접 접근 ===" rg "useAuthStore\.getState\(\)" --type ts -n -A 2Length of output: 5403
상태 변경 시 컴포넌트 리렌더링 보장 여부 검토 필요
현재 모든 컴포넌트에서
useAuthStore.getState()를 통해 상태를 조회하고 있어, 내부 상태 변경 시 자동 리렌더링(반응성)이 발생하지 않습니다. 이 변경이 의도된 것인지 확인해 주시고, 인증 상태 변화에 따라 리랜더링이 필요한 컴포넌트에는 아래와 같이 selector 기반 훅 사용을 유지하는 방안을 검토해 주세요:주요 적용 위치 (일부 발췌):
- src/hooks/useAuth.ts (Line 16)
- src/pages/login/LoginApi.tsx (Line 13)
- src/components/common/ProtectRoute.tsx (Line 12)
- src/routes/AppRoutes.tsx (Line 105)
- 기타 다수 컴포넌트 및 훅
→ 필요 시
const login = useAuthStore(state => state.login);와 같이 selector 훅을 사용해 구독을 유지하세요.
64-72:Details
❓ Verification inconclusive
리프레시 토큰 제거에 따른 영향 검토
리프레시 토큰 처리가 완전히 제거되었습니다. 이는 사용자가 액세스 토큰 만료 시 다시 로그인해야 함을 의미합니다. 이것이 의도된 UX 변경인지 확인이 필요합니다.
HTTP 클라이언트에서 토큰 갱신 로직이 어떻게 처리되는지 확인해보겠습니다:
🏁 Script executed:
#!/bin/bash # HTTP 클라이언트의 토큰 갱신 로직 확인 rg -A 10 -B 5 "refresh.*token|token.*refresh" src/api/ --type ts echo "=== 401 에러 처리 ===" rg -A 5 "401|unauthorized" src/api/ --type tsLength of output: 423
추가 확인을 위해 리프레시 토큰 네이밍 사용 여부와 401 처리 로직 전체를 조회하겠습니다.
🏁 Script executed:
#!/bin/bash # 1) 대소문자 구분 없이 refreshToken 사용 여부 확인 rg -i 'refreshToken' -n -A 5 -B 5 src/api/ --type ts # 2) HTTP 클라이언트의 401 처리 블록 전체 확인 rg -n 'if (error.response.status === 401' -A 20 src/api/http.api.tsLength of output: 210
refreshToken 관련 로직과 401 에러 처리 전체 컨텍스트를 다시 확인하기 위해 아래 스크립트를 실행해주세요.
🏁 Script executed:
#!/bin/bash # 1) 대소문자 구분 없이 refreshToken 키워드 검색 rg -i 'refresh.*token|token.*refresh' -n src/api/ --type ts # 2) HTTP 클라이언트의 401 에러 처리 로직 전체 컨텍스트 검색 rg -n "error\.response\.status === 401" -A 20 src/api/http.api.tsLength of output: 952
리프레시 토큰 로직 주석 처리 확인 요청
현재 src/api/http.api.ts의 401 에러 처리 구간에서 리프레시 토큰 재발급 로직이 모두 주석 처리되어 있어, 액세스 토큰 만료 시 자동 갱신이 불가능합니다. 이로 인해 사용자는 토큰 만료 시 매번 재로그인해야 하는 UX 변화가 발생합니다.
해당 변경이 의도된 것인지, 배포 전 리프레시 로직 재활성화 계획이 있는지 확인 부탁드립니다.
- src/api/http.api.ts (라인 50–64): 리프레시 토큰 재발급 (
postRefresh호출) 로직 전부 주석 처리됨src/components/user/mypage/joinedProject/Project.styled.ts (2)
119-120: 스타일 속성 분리에 따른 레이아웃 확인
Skill컴포넌트에서flex-wrap과gap속성이 제거되고justify-content: space-between이 추가되었습니다. 이 변경이 기존 레이아웃을 깨뜨리지 않는지 확인이 필요합니다.스타일 관리의 모듈화는 좋은 접근입니다.
122-145:Details
✅ Verification successful
새로운 SkillArea 컴포넌트 구조 확인
새로 추가된
SkillArea컴포넌트가 기존의 스킬 관련 스타일링을 담당하게 되었습니다. 반응형 디자인도 잘 고려되어 있습니다.반응형 디자인과 함께 스킬 영역의 레이아웃을 별도 컴포넌트로 분리한 것은 좋은 구조입니다.
이 새로운 SkillArea 컴포넌트가 실제로 사용되는지 확인해보겠습니다:
🏁 Script executed:
#!/bin/bash # SkillArea 컴포넌트 사용처 확인 rg "SkillArea" --type tsx --type ts -n -A 2Length of output: 71
🏁 Script executed:
#!/bin/bash # SkillArea 컴포넌트 실제 사용처 확인 (JSX/TSX) rg "<SkillArea" -n -A 2Length of output: 25
🏁 Script executed:
#!/bin/bash # 전체 리포지토리에서 SkillArea 사용 여부 확인 rg "SkillArea" -nLength of output: 274
SkillArea 컴포넌트 사용 확인 완료
src/components/user/mypage/joinedProject/Project.styled.ts(122라인)에서 스타일 정의src/components/user/mypage/joinedProject/Project.tsx(34–41라인)에서<S.SkillArea>로 실제 사용src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx (1)
16-18: 라우팅 구조 확인링크 구조가 올바르게 구성되어 있고, 키워드 상태 보존이 잘 구현되었습니다. 사용자 경험 향상에 도움이 될 것입니다.
검색 키워드 상태를 유지하는 네비게이션 구현이 잘 되어 있습니다.
src/components/user/customerService/CustomerServiceHeader.styled.ts (2)
40-42: 버튼 래퍼의 중앙 정렬 개선 승인
ButtonWrapper에justify-content: center와align-items: center를 추가하여 플렉스 컨테이너 내 요소들을 수평, 수직으로 중앙 정렬하는 개선사항이 좋습니다. 일관된 UI 레이아웃을 제공합니다.
45-46: 컴포넌트 명명 개선 및 높이 스타일링 승인
UturnButton에서XButton으로 이름 변경과height: fit-content추가가 적절합니다. 버튼의 의미적 명확성이 향상되었고, 불필요한 세로 확장을 방지합니다.src/api/auth.api.ts (4)
1-1: Import 추가 승인
ApiOauth타입 import 추가가 새로운getOauthLogin함수에서 사용되므로 적절합니다.
20-20: 코드 포맷팅 일관성 개선return 문 앞에 빈 줄을 추가하여 코드 가독성과 일관성을 개선했습니다.
Also applies to: 46-46, 59-59, 70-70
78-87: 토큰 갱신 API 함수 구현 승인
postRefresh함수가 기존 패턴을 따라 적절히 구현되었습니다. 에러 처리와 로깅이 일관되게 적용되었습니다.
89-102: OAuth 로그인 API 함수 구현 승인
getOauthLogin함수가 올바르게 구현되었습니다:
- Bearer 토큰을 사용한 Authorization 헤더 형식이 표준을 따름
ApiOauth타입 지정이 적절함- 에러 처리가 일관됨
src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts (2)
2-2: 공통 스타일 컴포넌트 Import 개선 승인
WrapperNoContent를 다른 파일에서 import하여 코드 중복을 제거하는 리팩토링이 우수합니다. DRY 원칙을 잘 따르고 있습니다.
8-8: 확장 스타일 컴포넌트 생성 승인
WrapperNoContent를 확장하여WrapperNoContentAppliedProjects를 생성하는 방식이 적절합니다. 관련 코드 스니펫에서 확인한 바와 같이 다른 컴포넌트들과 일관된 패턴을 따르고 있습니다.src/hooks/user/useNotification.ts (2)
6-6: 인증 상태 접근 패턴 변경 승인
useAuthStore.getState()를 사용하여 직접 상태에 접근하는 방식으로 변경한 것이 broader refactoring과 일치하며 구독 오버헤드를 줄입니다.Also applies to: 12-13
65-65: 의존성 배열 업데이트 승인
accessToken과EventSourceImpl을 의존성 배열에 추가하여 토큰이나 EventSource 구현체가 변경될 때 effect가 다시 실행되도록 한 것이 적절합니다.src/components/user/userPage/userProjectList/UserProjectList.tsx (1)
22-42: 컴포넌트 구조 개선 승인
ScrollWrapper를 조건부 렌더링 외부로 이동하고 내부에서 조건부 콘텐츠를 렌더링하도록 리팩토링한 것이 좋은 개선입니다. 이는 스크롤 컨테이너의 일관성을 보장하고 레이아웃 안정성을 향상시킵니다.새로운 스타일 컨테이너 구조(
ContainerNoContentMyJoinedProjects,WrapperNoContentMyJoinedProjects)도 다른 컴포넌트와의 일관성을 위한 좋은 변경입니다.src/constants/user/customerService.ts (3)
11-13: 새로운 모달 메시지 상수 추가 승인검색어 입력 유효성 검사를 위한 새로운 모달 메시지 상수가 적절히 추가되었습니다. 명확하고 사용자 친화적인 메시지입니다.
17-17: 파일 선택 메시지 개선 승인파일 업로드 제한사항(최대 3개)을 명시한 메시지 업데이트가 사용자 경험 개선에 도움이 됩니다.
29-29: 파일 개수 제한 메시지 추가 승인최대 파일 업로드 개수 제한에 대한 명확한 안내 메시지가 추가되어 사용자가 제한사항을 쉽게 이해할 수 있습니다.
src/components/user/mypage/joinedProject/MyJoinProjects.tsx (1)
18-50: 컴포넌트 구조 리팩토링 승인조건부 렌더링을
ScrollWrapper내부로 이동하고 컨테이너에$isNoContentprop을 추가한 것이 좋은 개선입니다. 이는 다른 사용자 페이지 컴포넌트와의 일관성을 향상시키고 스타일링 제어를 개선합니다.새로운 스타일 컨테이너 구조도 빈 상태 표시의 표준화에 기여합니다.
🧰 Tools
🪛 Biome (1.9.4)
[error] 20-20: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with(lint/complexity/noUselessTernary)
src/components/user/customerService/CustomerServiceHeader.tsx (8)
4-8: 새로운 의존성 추가가 적절합니다.URL 쿼리 파라미터 관리를 위한
useSearchParams와 모달 기능을 위한 훅들이 추가되었습니다. 모든 임포트가 올바르게 설정되어 있습니다.
22-23: 상태 관리 구조가 깔끔합니다.모달 상태와 URL 검색 파라미터를 분리하여 관리하는 것이 좋은 접근법입니다.
25-33: URL 쿼리 파라미터 동기화 로직이 잘 구현되었습니다.검색어가 비어있을 때 URL에서
keyword파라미터를 제거하고, 있을 때 설정하는 로직이 명확합니다.URLSearchParams를 올바르게 사용하고 있습니다.
37-44: 검색어 유효성 검사와 모달 통합이 우수합니다.빈 문자열과 공백만 있는 검색어를 적절히 검증하고, 모달을 통해 사용자에게 피드백을 제공하는 것이 좋은 UX입니다.
trim()메서드 사용도 적절합니다.
54-54: 리셋 기능에 URL 동기화 추가가 적절합니다.검색어를 초기화할 때 URL 쿼리 파라미터도 함께 제거하여 일관성을 유지하는 것이 좋습니다.
67-67: 입력 값 우선순위 로직이 명확합니다.
keywordprop이 있을 때 우선적으로 표시하고, 없을 때 로컬 상태를 사용하는 조건부 렌더링이 적절합니다.
72-78: 버튼 컴포넌트 이름 변경이 적절합니다.
UturnButton에서XButton으로 변경한 것이 아이콘의 실제 기능(닫기/제거)을 더 잘 표현합니다.
88-90: 모달 컴포넌트 통합이 잘 되었습니다.모달 상태와 메시지를 적절히 연결하여 사용자에게 유효성 검사 피드백을 제공합니다.
src/components/user/mypage/myProfile/editProfile/EditProfile.tsx (6)
1-1: import 경로 수정이 적절합니다.상대 경로를 통해 styled components를 가져오는 것이 올바릅니다.
18-22: OAuth 관련 상수와 아이콘 import가 적절합니다.GitHub OAuth 기능 구현을 위한 필요한 의존성들이 올바르게 추가되었습니다.
29-36: 변수명 통일성이 향상되었습니다.
myData에서userInfoData로 변경하여 변수명이 더 명확하고 일관성 있게 되었습니다.
42-45: 환경변수와 OAuth 제공자 설정이 적절합니다.
VITE_APP_API_BASE_URL환경변수를 사용하고, GitHub OAuth 제공자를 필터링하여 선택하는 로직이 올바릅니다.
77-108: useEffect의 의존성 배열이 적절합니다.
userInfoData변수명 변경에 따라 의존성 배열도 올바르게 업데이트되었습니다.
279-288: GitHub 인증 버튼 UI 구현이 우수합니다.아이콘과 텍스트를 포함한 버튼 구성이 직관적이고, OAuth 플로우 시작을 위한 적절한 트리거입니다.
src/pages/user/customerService/notice/Notice.tsx (5)
1-12: 필요한 React 훅과 라우터 기능 추가가 적절합니다.
useEffect와useLocation추가로 URL 쿼리 파라미터 처리가 가능해졌습니다.
15-20: 상태 구조 개선이 우수합니다.단순한
keyword문자열에서NoticeSearch객체로 변경하여 키워드와 페이지를 함께 관리하는 것이 더 체계적입니다.useGetNotice훅의 타입과도 일치합니다.
34-39: 상태 업데이트 로직이 일관성 있게 개선되었습니다.이전 상태를 유지하면서 특정 필드만 업데이트하는 패턴이 올바르게 구현되었습니다.
67-67: 네비게이션 상태에 키워드 전달이 적절합니다.공지사항 상세 페이지로 이동할 때 현재 검색 키워드를 상태로 전달하여 뒤로가기 시 검색 컨텍스트를 유지할 수 있습니다.
79-79: 페이지네이션 prop 업데이트가 적절합니다.새로운 상태 구조에 맞게
noticeSearch.page를 전달하는 것이 올바릅니다.src/api/http.api.ts (5)
2-3: 인증 관련 import 변경이 적절합니다.
useAuthStore에서 직접 상태에 접근하고postRefresh함수를 추가한 것이 새로운 인증 플로우에 맞습니다.
9-9: 인증 스토어에서 함수 구조분해할당이 적절합니다.
login과logout함수를 미리 추출하여 사용하는 것이 깔끔합니다.
20-24: 동적 토큰 주입 방식이 우수합니다.요청마다 최신 토큰을 가져와서 Authorization 헤더에 설정하는 것이 토큰 상태 변화를 실시간으로 반영할 수 있어 좋습니다.
39-48: 재시도 로직 개선이 우수합니다.단순한
_retry플래그에서retryCount숫자로 변경하여 5회까지 재시도할 수 있도록 한 것이 더 유연한 에러 처리를 가능하게 합니다.
50-67: 리프레시 토큰 로직 주석처리의 이유가 명확합니다.로컬 환경에서 httpOnly 쿠키 제약사항으로 인한 일시적 비활성화라는 설명이 있어 향후 배포 시 활성화할 계획임을 알 수 있습니다.
src/components/user/mypage/joinedProject/MyJoinProjects.styled.ts (2)
1-2: 변경사항이 적절합니다!
csshelper 추가와WrapperNoContent재사용은 코드 일관성과 유지보수성을 향상시킵니다.
47-47:min-height사용이 적절합니다!콘텐츠가 늘어날 때 더 유연한 레이아웃을 제공합니다.
src/components/user/customerService/inquiry/Inquiry.styled.ts (2)
115-122: 파일 컨테이너 스타일링이 잘 구성되었습니다!다중 파일 업로드 UI를 위한 적절한 레이아웃 구조입니다.
160-160: 테마 값 사용이 적절합니다!일관된 디자인을 위해 테마의 border-radius를 사용하는 것이 좋습니다.
src/store/authStore.ts (1)
1-12: 인터페이스 정의가 깔끔해졌습니다!
UserData타입을 외부 모델에서 import하여 타입 일관성이 향상되었습니다.
src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx
Outdated
Show resolved
Hide resolved
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/components/user/customerService/inquiry/Inquiry.tsx (1)
125-142: 파일 상태 관리 로직을 단순화할 수 있습니다.현재 로직이 동작하지만 복잡성으로 인해 유지보수가 어려울 수 있습니다.
다음과 같이 리팩토링을 고려해보세요:
setImageFiles((prev) => { - if ( - fileValue.trim() === '' || - prev.some((file) => file.fileValue === fileValue) || - preview === '' - ) - return prev; - if ( - prev.some((file) => file.fileValue === My_INQUIRIES_MESSAGE.fileDefault) - ) { - const removeDefault = prev.filter( - (file) => file.fileValue !== My_INQUIRIES_MESSAGE.fileDefault - ); - - return [...removeDefault, { fileValue, preview, image }]; - } - return [...prev, { fileValue, preview, image }]; + // 유효하지 않은 파일은 무시 + if (fileValue.trim() === '' || preview === '' || + prev.some((file) => file.fileValue === fileValue)) { + return prev; + } + + // 기본값 제거 후 새 파일 추가 + const filteredFiles = prev.filter( + (file) => file.fileValue !== My_INQUIRIES_MESSAGE.fileDefault + ); + + return [...filteredFiles, { fileValue, preview, image }]; });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/components/user/customerService/inquiry/Inquiry.tsx(6 hunks)src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx(2 hunks)src/pages/login/LoginApi.tsx(1 hunks)src/pages/login/LoginSuccess.tsx(1 hunks)src/pages/user/apply/Apply.tsx(1 hunks)src/pages/user/projectDetail/ProjectDetail.tsx(1 hunks)src/routes/AppRoutes.tsx(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/pages/user/apply/Apply.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
- src/routes/AppRoutes.tsx
- src/pages/login/LoginApi.tsx
- src/pages/login/LoginSuccess.tsx
- src/components/user/customerService/noticeDetail/NoticeDetailBundle.tsx
- src/pages/user/projectDetail/ProjectDetail.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/user/customerService/inquiry/Inquiry.tsx (1)
src/constants/user/customerService.ts (2)
My_INQUIRIES_MESSAGE(15-20)INQUIRY_MESSAGE(22-30)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Run Chromatic
🔇 Additional comments (7)
src/components/user/customerService/inquiry/Inquiry.tsx (7)
8-8: XMarkIcon 추가가 적절합니다.파일 삭제 기능을 위한 아이콘 추가가 UI 개선에 도움이 됩니다.
35-39: 다중 파일 상태 관리 구조가 잘 설계되었습니다.파일 배열의 각 객체가
fileValue,preview,image속성을 가지고 있어 파일 관리가 체계적으로 이루어지며,MAX_FILE_COUNT상수 정의도 적절합니다.Also applies to: 45-45
70-80: 폼 제출 시 파일 처리 로직이 올바릅니다.유효한 파일만 FormData에 추가하는 로직이 정확하며, 기본값과 null 체크를 통한 필터링이 적절합니다.
115-122: 파일 개수 검증 로직이 개선되었습니다.과거 리뷰에서 지적된 기본 placeholder를 포함한 검증 문제가 해결되어, 실제 파일 개수만을 정확히 검증하고 있습니다.
147-161: 파일 삭제 로직이 적절하게 구현되었습니다.마지막 파일 삭제 시 기본 placeholder로 복원하는 로직과 개별 파일 삭제 로직이 올바르게 작동합니다.
165-171: useEffect 정리 로직이 개선되었습니다.과거 리뷰에서 지적된 문제들이 해결되어, 유효한 preview URL만을 안전하게 해제하고 있습니다.
235-263: 다중 파일 UI 렌더링이 잘 구현되었습니다.각 파일에 대한 미리보기와 삭제 버튼이 적절히 배치되어 사용자 경험이 향상되었습니다. 조건부 렌더링을 통해 preview가 있는 경우에만 이미지와 삭제 버튼을 표시하는 것도 적절합니다.
구현내용
자잘한 수정
연관이슈
close #303
Summary by CodeRabbit
신규 기능
버그 수정/개선
디자인/스타일
기타