feat: 피드 메인페이지 - 내 띱 목록 API 연동#104
Conversation
develp branch 작업내용 머지 : develop -> main
…to feat/api-auth
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
Caution Review failedThe pull request is closed. Walkthrough최근 검색·최근 팔로잉 API 모듈을 추가하고, 피드 상단 팔로우 리스트를 API 연동으로 교체했습니다. 사용자 검색에 isFinalized 옵션을 전파하고, OAuth 토큰 발급 훅 및 일부 회원가입·앱 초기화 관련 인증 로직을 단순화했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as FollowList
participant API as getRecentFollowing
participant HTTP as apiClient
participant BE as Backend
UI->>API: getRecentFollowing()
API->>HTTP: GET /users/my-followings/recent-feeds
HTTP->>BE: Request
BE-->>HTTP: Response { recentWriters[] }
HTTP-->>API: data
API-->>UI: recentWriters[]
UI->>UI: setState(loading=false, recentWriters)
alt Empty
UI->>User: Show "독자를 찾아보세요"
User->>UI: Click "찾기"
UI->>Router: navigate('/feed/search')
else Item click
User->>UI: Click writer
UI->>Router: navigate(`/profile/${userId}`)
end
sequenceDiagram
participant Page as UserSearch
participant Hook as useUserSearch
participant API as getUsers
participant HTTP as apiClient
participant BE as Backend
Page->>Hook: useUserSearch({ keyword, size, isFinalized })
Hook->>API: getUsers({ keyword, size, isFinalized })
API->>HTTP: GET /users?...&isFinalized=<bool>
HTTP->>BE: Request
BE-->>HTTP: Response { users... }
HTTP-->>API: data
API-->>Hook: data
Hook->>Hook: setResults(data)
Hook-->>Page: results
Page->>Page: render(results)
sequenceDiagram
participant Page as Feed/SignupNickname
participant Hook as useOAuthToken
participant HTTP as apiClient
participant BE as Backend
participant Router as Browser
Page->>Hook: mount -> useOAuthToken()
Hook->>Hook: read loginTokenKey from URL
alt loginTokenKey present & not requested
Hook->>HTTP: POST /oauth-success { loginTokenKey } (withCredentials)
HTTP->>BE: Request
BE-->>HTTP: Response (token set via cookie)
HTTP-->>Hook: success
Hook->>Router: replace URL without loginTokenKey
else failure
Hook->>Router: navigate('/')
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (7)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
src/components/feed/UserProfileItem.tsx (1)
58-61: null/undefined 대비 기본값 처리 좋습니다. 숫자 포맷·접근성 소소 개선 제안기본값 0 처리로 UI 누락을 방지한 점은 👍. 가독성과 접근성을 위해 아래 두 가지를 함께 적용하면 더 좋겠습니다.
- 큰 숫자 가독성: 천 단위 구분(1,234 등)
- 아이콘 대체 텍스트 추가
적용 예시는 아래 diff 참고하세요.
- <div>{followerCount ?? 0}명이 띱하는 중</div> + <div>{(followerCount ?? 0).toLocaleString('ko-KR')}명이 띱하는 중</div> - <img src={rightArrow} /> + <img src={rightArrow} alt="팔로워 목록 이동" />src/components/feed/BookInfoCard.tsx (1)
20-27: 고정 폭 대신 유연한 레이아웃으로 텍스트 잘림/오버플로우 리스크 완화.left를 width: 220px, .right .name을 width: 100px로 고정하면 번역 길이/사용자 환경에 따라 우측 영역이 과도하게 잘리거나 레이아웃이 깨질 수 있습니다. flex 기반으로 좌측은 가변, 우측은 축소되지 않도록 하는 편이 안전합니다.
.left { overflow: hidden; - width: 220px; + flex: 1; + min-width: 0; /* ellipsis 동작을 위한 최소값 */ white-space: nowrap; color: var(--color-white); text-overflow: ellipsis; font-size: var(--font-size-base); font-weight: var(--font-weight-semibold); line-height: 24px; } @@ .name { - width: 100px; + max-width: 120px; /* 환경에 맞게 적절히 조정 */ + flex-shrink: 0; /* 우측 이름이 과도하게 줄어들지 않도록 */ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }Also applies to: 42-47
src/api/recentsearch/getRecentSearch.ts (1)
23-26: 쿼리 파라미터 인코딩 및 반환 타입 명시로 견고성 향상type은 제한적이지만, 습관적으로 인코딩을 적용하면 안전합니다. 또한 반환 타입을 명시해 호출부에서 타입 추론을 더 확실히 할 수 있습니다.
-export const getRecentSearch = async (type: SearchType) => { - const response = await apiClient.get<GetRecentSearchResponse>(`/recent-search?type=${type}`); +export const getRecentSearch = async (type: SearchType): Promise<GetRecentSearchResponse> => { + const response = await apiClient.get<GetRecentSearchResponse>(`/recent-search?type=${encodeURIComponent(type)}`); return response.data; };src/api/users/getRecentFollowing.ts (1)
21-26: 에러 처리 전략을 개선해 보세요.현재 함수는 에러를 호출자에게 전파하도록 되어 있는데, API 호출 실패 시 더 구체적인 에러 처리나 로깅을 추가하는 것을 고려해 보세요.
다음과 같이 에러 처리를 개선할 수 있습니다:
export const getRecentFollowing = async () => { - const response = await apiClient.get<GetRecentFollowingResponse>( - '/users/my-followings/recent-feeds', - ); - return response.data; + try { + const response = await apiClient.get<GetRecentFollowingResponse>( + '/users/my-followings/recent-feeds', + ); + return response.data; + } catch (error) { + console.error('최근 팔로잉 조회 API 호출 실패:', error); + throw error; + } };src/components/feed/FollowList.tsx (1)
61-63: 로딩 상태 UI 개선이 필요합니다.현재 로딩 상태에서 아무것도 렌더링하지 않고 있는데, 사용자 경험을 위해 로딩 인디케이터를 표시하는 것이 좋겠습니다.
로딩 상태 UI를 개선해 보세요:
- {loading ? ( - <></> - ) : hasFollowers ? ( + {loading ? ( + <LoadingContainer> + <div>로딩 중...</div> + </LoadingContainer> + ) : hasFollowers ? (그리고 스타일 컴포넌트도 추가해야 합니다:
const LoadingContainer = styled.div` display: flex; justify-content: center; align-items: center; padding: 20px; color: var(--color-grey-100); font-size: var(--font-size-xs); `;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/api/recentsearch/getRecentSearch.ts(1 hunks)src/api/users/getRecentFollowing.ts(1 hunks)src/api/users/getUsers.ts(2 hunks)src/components/feed/BookInfoCard.tsx(3 hunks)src/components/feed/FollowList.tsx(2 hunks)src/components/feed/UserProfileItem.tsx(1 hunks)src/hooks/useUserSearch.ts(3 hunks)src/pages/feed/UserSearch.tsx(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/api/recentsearch/getRecentSearch.ts (1)
src/api/index.ts (1)
apiClient(27-33)
src/api/users/getRecentFollowing.ts (1)
src/api/index.ts (1)
apiClient(27-33)
src/components/feed/FollowList.tsx (1)
src/api/users/getRecentFollowing.ts (2)
RecentWriterData(4-8)getRecentFollowing(21-26)
🔇 Additional comments (18)
src/components/feed/BookInfoCard.tsx (1)
9-11: min/max-width 추가는 모바일 가로폭 제약 내에서 안전컨테이너 min-width: 280px, max-width: 500px 설정은 카드의 가로 영역을 안정화하는 데 도움이 됩니다. 위 유연 레이아웃 제안과 함께 사용하면 다양한 화면에서 텍스트 오버플로우를 보다 자연스럽게 처리할 수 있습니다.
src/api/recentsearch/getRecentSearch.ts (1)
3-20: 타입 정의와 응답 스키마 일관성 양호SearchType, RecentSearchData, GetRecentSearchResponse의 구조가 명확하고, 기존 apiClient 패턴과도 일관됩니다.
src/api/users/getUsers.ts (2)
38-41: isFinalized 쿼리 전송 조건 확인 요청현재 구현은 false인 경우에도 isFinalized=false를 항상 전송합니다. PR 목적은 “엔터/돋보기 검색 시 true 전송”인데, 입력 중(isSearched=false)에도 false가 붙는 동작이 백엔드 계약과 부합하는지 확인이 필요합니다. 서버가 파라미터 미지정과 false를 동일하게 처리한다면, 호출부에서 undefined일 때는 파라미터를 생략하도록 조정하는 편이 더 안전할 수 있습니다.
백엔드와 아래 두 점을 확인해 주세요:
- isFinalized=false를 명시적으로 보내는 것과 파라미터를 생략하는 것이 동등한가?
- isFinalized는 'true'/'false' 문자열을 기대하는가(현재 toString으로 해당 형식 전송)?
필요 시, 호출부(UserSearch.tsx)에서 isSearched가 false일 때 isFinalized를 undefined로 넘겨 파라미터 자체를 생략하도록 바꾸는 것을 제안드립니다.
24-25: 파라미터 추가 자체는 적절GetUsersParams에 isFinalized 추가는 다른 변경들과도 일관되고, 타입 정의가 명확합니다.
src/pages/feed/UserSearch.tsx (1)
23-24: isFinalized 파라미터 생략 처리 검토 요청현재
getUsers호출 시isFinalized: isSearched를 전달하면,isSearched === false일 때도?isFinalized=false가 항상 전송됩니다. 불필요한 파라미터 전송을 줄이고, “최종 검색 시에만 true”를 명확히 하기 위해 아래와 같이 수정할 것을 제안드립니다.수정 대상:
- 파일:
src/pages/feed/UserSearch.tsx- 라인: 23–24
- isFinalized: isSearched, + isFinalized: isSearched ? true : undefined,백엔드에서 false를 명시적으로 보내야 하는 경우엔 현 상태를 유지해도 무방합니다. 해당 변경이 API 계약에 부합하는지 확인해주세요.
src/hooks/useUserSearch.ts (4)
9-9: 인터페이스에 새로운 속성이 올바르게 추가되었습니다.
isFinalized옵션 속성이 적절하게 정의되어 검색 완료 상태를 나타낼 수 있습니다.
12-17: 훅 시그니처 및 기본값 처리가 적절합니다.
isFinalized파라미터의 기본값을false로 설정한 것은 기존 호출 코드와의 호환성을 보장하면서도 새로운 기능을 제공하는 좋은 방법입니다.
40-40: API 호출에 새 파라미터가 올바르게 전달되었습니다.
getUsers함수에isFinalized파라미터를 전달하는 것이 적절하게 구현되었습니다.
59-59: 의존성 배열이 올바르게 업데이트되었습니다.
useCallback의 의존성 배열에isFinalized를 추가한 것은 올바른 접근법입니다. 이를 통해isFinalized값이 변경될 때 함수가 재생성됩니다.src/api/users/getRecentFollowing.ts (2)
4-8: 타입 정의가 명확하고 적절합니다.
RecentWriterData인터페이스가 필요한 필드들을 잘 정의하고 있으며, 타입 안전성을 보장합니다.
11-18: 표준적인 API 응답 타입 구조를 따르고 있습니다.
GetRecentFollowingResponse타입이 프로젝트의 다른 API 응답 타입들과 일관성 있는 구조(isSuccess,code,message,data)를 따르고 있어 좋습니다.src/components/feed/FollowList.tsx (7)
3-3: 필요한 React 훅들이 적절하게 추가되었습니다.API 연동을 위해
useState와useEffect를 추가한 것이 적절합니다.
8-8: API 모듈 임포트가 올바릅니다.새로 생성된 API 함수와 타입을 적절하게 임포트하고 있습니다.
12-13: 상태 관리가 적절하게 구현되었습니다.
recentWriters와loading상태를 적절한 초기값으로 설정하고 올바른 타입을 지정했습니다.
16-33: API 호출 함수의 에러 처리가 잘 구현되었습니다.성공/실패 상황을 모두 적절히 처리하고 있으며, 에러 로깅도 포함되어 있어 디버깅에 도움이 됩니다. 로딩 상태 관리도 올바르게 구현되어 있습니다.
36-38: 컴포넌트 마운트 시 데이터 페칭이 적절합니다.
useEffect를 사용하여 컴포넌트가 마운트될 때 한 번만 데이터를 조회하도록 구현된 것이 올바릅니다.
66-70: API 데이터 매핑이 올바르게 구현되었습니다.구조 분해 할당을 통해 필요한 필드들(
userId,profileImageUrl,nickname)을 추출하고, 각각을 적절한 용도로 사용하고 있습니다.alt속성 추가도 접근성 측면에서 좋은 개선입니다.
44-44: 라우트/feed/search정의 수동 확인 필요
자동화된 검색 스크립트로 해당 경로를 찾지 못했습니다.
src/App.tsx또는 라우터 설정 파일(src/routes.tsx등)에서/feed/search가 실제로 등록되어 있는지 확인해 주세요.
#️⃣연관된 이슈
#71 [API] feeds API 연동
📝작업 내용
2. 사용자 검색 시, 엔터/돋보기 버튼을 눌렀을 때 isFinalized = true 쿼리파라미터 전송 (최근검색어 저장을 위한 변수)
💬리뷰 요구사항
특별히 없습니다!
Summary by CodeRabbit