Skip to content

feat(client): 사이드바 유저 정보 모달 및 api 작업#219

Closed
jllee000 wants to merge 2 commits intodevelopfrom
feat/#218/sidebar-popup
Closed

feat(client): 사이드바 유저 정보 모달 및 api 작업#219
jllee000 wants to merge 2 commits intodevelopfrom
feat/#218/sidebar-popup

Conversation

@jllee000
Copy link
Copy Markdown
Member

@jllee000 jllee000 commented Dec 18, 2025

📌 Related Issues

관련된 Issue를 태그해주세요. (e.g. - close #25)

📄 Tasks

  1. 사이드바 유저 정보 모달 ui 작업
  2. api 세팅
  3. 로그아웃 처리
  4. portal 처리
  5. 렌더링 최적화

⭐ PR Point (To Reviewer)

📷 Screenshot

image

Summary by CodeRabbit

  • 새로운 기능

    • 사이드바에 사용자 정보 팝업 추가 — 프로필 사진, 이름, 이메일, 알림 시간 및 로그아웃 버튼 표시.
    • 클라이언트에 사이드 정보 조회 기능 추가하여 팝업에서 사용자를 동적으로 불러옴.
  • 스타일/레이아웃

    • 온보딩 마지막 단계에 좌우 여백을 추가해 레이아웃 간격을 개선.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown

vercel bot commented Dec 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
pinback-client-client Ready Ready Preview, Comment Dec 19, 2025 11:28am
pinback-client-landing Ready Ready Preview, Comment Dec 19, 2025 11:28am

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 18, 2025

Walkthrough

사이드바 프로필 팝업 기능을 추가했습니다. API 호출(getSideInfo), React Query 훅(useGetSideInfo), 팝업 컴포넌트(SideInfoPop)와 사이드바 통합(Sidebar)에 해당 변경을 적용했습니다.

Changes

Cohort / File(s) 변경 요약
API 함수 추가
apps/client/src/shared/apis/axios.ts
getSideInfo 추가: /api/v2/users/me에 GET 요청 후 data.data 반환
React Query 훅 추가
apps/client/src/shared/apis/queries.ts
useGetSideInfo 추가: queryKey ['sideInfo'], 내부에서 getSideInfo() 호출
사이드바 팝업 컴포넌트
apps/client/src/shared/components/sidebar/SideInfoPop.tsx
SideInfoPop 컴포넌트 추가: 프로필 이미지, 이름, 이메일/알람 시간 표시, 로그아웃 버튼 렌더링 (기본 텍스트 플레이스홀더 사용)
사이드바 통합
apps/client/src/shared/components/sidebar/Sidebar.tsx
SideInfoPopuseGetSideInfo 임포트 추가, useGetSideInfo() 호출하여 데이터 획득(콘솔 로그 포함), 팝업 컴포넌트 렌더링, aside에 relative 포지셔닝 추가
소소한 레이아웃 변경
apps/client/src/pages/onBoarding/components/funnel/step/FinalStep.tsx
루트 컨테이너에 수평 패딩 px-[3.2rem] 추가 (레이아웃 조정)

Sequence Diagram(s)

sequenceDiagram
    participant Sidebar as Sidebar 컴포넌트
    participant Query as React Query (useGetSideInfo)
    participant API as apiRequest (axios) 
    participant Server as 서버 (/api/v2/users/me)

    Sidebar->>Query: useGetSideInfo() 호출
    Query->>API: GET /api/v2/users/me
    API->>Server: HTTP GET 요청 전달
    Server-->>API: 200 { data: { ... } }
    API-->>Query: { data }
    Query-->>Sidebar: 반환된 data.data
    Sidebar->>Sidebar: SideInfoPop 렌더링 (수신 데이터 사용)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • 주의할 파일/영역:
    • apps/client/src/shared/apis/axios.ts: API 호출의 에러 핸들링 관행(타입, 예외 처리) 확인 필요
    • apps/client/src/shared/components/sidebar/SideInfoPop.tsx: 정적 플레이스홀더가 실제 API 데이터에 맞는지 및 접근성/스타일 확인
    • apps/client/src/shared/components/sidebar/Sidebar.tsx: 사이드 이펙트(콘솔 로그 제거 여부)와 위치 변경(relative)으로 인한 레이아웃 영향 검토

Possibly related PRs

Suggested labels

🛠️ Feature, api

Suggested reviewers

  • constantly-dev
  • jjangminii

Poem

🐰 새 팝업이 쑥, 나타났어요
API 한입에 훅으로 데려와
사이드바에 포근히 앉아
이름과 알람, 로그아웃 한 번에
깡총깡총 축하의 당근을 줍니다 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 2 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Linked Issues check ❓ Inconclusive PR은 이슈 #218의 요구사항인 사이드바 프로필 팝업 UI 및 유저 정보 API 연동을 구현했으나, 이슈 #25(Progress bar)와는 무관한 상태입니다. 이슈 #25는 현재 PR의 범위와 무관합니다. PR이 실제로 이슈 #25와 연관이 있는지 재확인하거나, 관련성이 없다면 연결을 제거하세요.
Out of Scope Changes check ❓ Inconclusive 대부분의 변경사항이 이슈 #218에 맞춰 있으나, FinalStep.tsx의 패딩 추가는 문서화되지 않은 변경사항입니다. FinalStep.tsx에서 px-[3.2rem] 패딩 추가의 목적이 명확하지 않습니다. 이것이 필요한 변경사항인지 확인하고, 필요하다면 설명을 추가하세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 사이드바 유저 정보 모달 및 API 작업을 명확하게 설명하며, 실제 변경사항과 완전히 관련이 있습니다.
Description check ✅ Passed PR 설명이 템플릿의 모든 필수 섹션을 포함하고 있으며, 관련 이슈, 작업 내용, 스크린샷이 충실하게 작성되어 있습니다.
✨ 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 feat/#218/sidebar-popup

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ccb9b59 and ef38406.

📒 Files selected for processing (1)
  • apps/client/src/pages/onBoarding/components/funnel/step/FinalStep.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: storybook
🔇 Additional comments (1)
apps/client/src/pages/onBoarding/components/funnel/step/FinalStep.tsx (1)

7-7: PR 범위와 무관한 변경사항인지 확인이 필요합니다.

이 변경사항은 온보딩 플로우의 스타일 조정이지만, PR의 주요 목적(사이드바 유저 정보 모달 및 API 작업)과는 직접적인 연관이 없어 보입니다.

  • 이 변경이 의도된 것인지 확인해 주세요.
  • 만약 별도의 UI 개선 작업이라면, 코드 리뷰 및 변경 이력 관리를 위해 별도 PR로 분리하는 것을 권장합니다.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the feat 기능 개발하라 개발 달려라 달려 label Dec 18, 2025
@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 18, 2025

✅ Storybook chromatic 배포 확인:
🐿️ storybook

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
apps/client/src/shared/apis/axios.ts (1)

75-78: 반환 타입 명시를 추가하세요.

API 함수의 반환 타입이 명시되어 있지 않습니다. 타입 안정성을 위해 @shared/types/api에 응답 인터페이스를 정의하고 반환 타입을 명시하는 것을 권장합니다.

🔎 제안하는 수정 방법

먼저 @shared/types/api에 응답 타입을 정의하세요:

export interface SideInfoResponse {
  // API 응답 구조에 맞게 필드를 정의하세요
  name: string;
  email: string;
  profileImage?: string;
  remindTime?: string;
}

그런 다음 함수에 타입을 적용하세요:

-export const getSideInfo = async () => {
+export const getSideInfo = async (): Promise<SideInfoResponse> => {
   const { data } = await apiRequest.get('/api/v2/users/me');
   return data.data;
 };
apps/client/src/shared/apis/queries.ts (1)

141-146: 타입 안정성을 위해 반환 타입을 명시하세요.

다른 쿼리 훅들(예: useGetDashboardCategories, useGetArcons)과 일관성을 유지하기 위해 반환 타입과 에러 타입을 명시해야 합니다.

🔎 제안하는 수정 방법
-export const useGetSideInfo = () => {
+export const useGetSideInfo = (): UseQueryResult<SideInfoResponse, AxiosError> => {
   return useQuery({
     queryKey: ['sideInfo'],
     queryFn: () => getSideInfo(),
   });
 };

참고: SideInfoResponse 타입은 @shared/types/api에서 import해야 합니다.

apps/client/src/shared/components/sidebar/SideInfoPop.tsx (1)

4-25: 접근성 개선이 필요합니다.

모달/팝업 컴포넌트에 접근성 속성이 누락되어 있습니다. 키보드 네비게이션과 스크린 리더 지원이 필요합니다.

🔎 제안하는 수정 방법
       <div 
+        role="dialog"
+        aria-modal="true"
+        aria-labelledby="side-info-title"
         className="bg-white-bg common-shadow absolute left-[19.6rem] top-[6.8rem] z-10 flex h-[32rem] w-[26rem] flex-col items-center justify-center rounded-[12px] py-[2.4rem]"
       >
         {/* ... */}
-        <p className="sub1-sb text-font-black-1 mb-[0.4rem]">{sideInfo?.name}</p>
+        <p id="side-info-title" className="sub1-sb text-font-black-1 mb-[0.4rem]">{sideInfo?.name}</p>

그리고 ESC 키로 닫기 기능을 추가하세요:

useEffect(() => {
  const handleEscape = (e: KeyboardEvent) => {
    if (e.key === 'Escape') onClose?.();
  };
  document.addEventListener('keydown', handleEscape);
  return () => document.removeEventListener('keydown', handleEscape);
}, [onClose]);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52d5d81 and ccb9b59.

📒 Files selected for processing (4)
  • apps/client/src/shared/apis/axios.ts (1 hunks)
  • apps/client/src/shared/apis/queries.ts (2 hunks)
  • apps/client/src/shared/components/sidebar/SideInfoPop.tsx (1 hunks)
  • apps/client/src/shared/components/sidebar/Sidebar.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-07-15T20:00:13.756Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 80
File: apps/client/src/shared/components/ui/modalPop/ModalPop.tsx:36-41
Timestamp: 2025-07-15T20:00:13.756Z
Learning: In apps/client/src/shared/components/ui/modalPop/ModalPop.tsx, the InfoBox component uses hardcoded values for title, location, and icon URL as temporary test data. These should be replaced with dynamic data from props when implementing actual functionality and should be marked with TODO comments for future changes.

Applied to files:

  • apps/client/src/shared/components/sidebar/SideInfoPop.tsx
  • apps/client/src/shared/components/sidebar/Sidebar.tsx
📚 Learning: 2025-07-17T09:18:13.818Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 102
File: apps/extension/src/components/modalPop/ModalPop.tsx:166-172
Timestamp: 2025-07-17T09:18:13.818Z
Learning: In apps/extension/src/components/modalPop/ModalPop.tsx, the categories array should include "안 읽은 정보" (Unread Information) as the first default category that cannot be deleted. This default category is used consistently across the client-side dashboard and should be protected from deletion in the extension as well.

Applied to files:

  • apps/client/src/shared/components/sidebar/SideInfoPop.tsx
  • apps/client/src/shared/components/sidebar/Sidebar.tsx
📚 Learning: 2025-09-03T08:57:48.626Z
Learnt from: jjangminii
Repo: Pinback-Team/pinback-client PR: 52
File: apps/client/src/shared/components/sidebar/SideItem.tsx:57-60
Timestamp: 2025-09-03T08:57:48.626Z
Learning: SideItem 컴포넌트에서 아이콘 디자인이 일반적인 기대와 반대여서, 회전 로직도 반대로 구현되었습니다. 이를 명확히 하기 위해 prop 이름을 open에서 close로 변경하여 실제 동작과 일치시켰습니다.

Applied to files:

  • apps/client/src/shared/components/sidebar/SideInfoPop.tsx
📚 Learning: 2025-07-08T11:47:10.642Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 30
File: apps/extension/src/App.tsx:10-21
Timestamp: 2025-07-08T11:47:10.642Z
Learning: In apps/extension/src/App.tsx, the InfoBox component currently uses a hardcoded external URL for the icon prop as a temporary static placeholder. The plan is to replace this with dynamic favicon extraction from bookmarked websites in future iterations.

Applied to files:

  • apps/client/src/shared/components/sidebar/SideInfoPop.tsx
🧬 Code graph analysis (2)
apps/client/src/shared/apis/queries.ts (1)
apps/client/src/shared/apis/axios.ts (1)
  • getSideInfo (75-78)
apps/client/src/shared/components/sidebar/Sidebar.tsx (1)
apps/client/src/shared/apis/queries.ts (1)
  • useGetSideInfo (141-146)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: storybook

const { mutate: createCategory } = usePostCategory();
const { data, isPending } = useGetArcons();
const { mutate: deleteCategory } = useDeleteCategory();
const { data: sideInfo } = useGetSideInfo();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

데이터 연동이 완료되지 않았습니다.

useGetSideInfo()로 데이터를 가져오고 있지만, 이 데이터가 SideInfoPop 컴포넌트에 전달되지 않고 있습니다. 또한 로딩 상태와 에러 처리도 필요합니다.

🔎 제안하는 수정 방법
- const { data: sideInfo } = useGetSideInfo();
+ const { data: sideInfo, isLoading: isSideInfoLoading, isError: isSideInfoError } = useGetSideInfo();

그리고 Line 134에서 SideInfoPop에 데이터를 전달하세요:

- <SideInfoPop />
+ <SideInfoPop 
+   sideInfo={sideInfo}
+   isLoading={isSideInfoLoading}
+   isError={isSideInfoError}
+ />
📝 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.

Suggested change
const { data: sideInfo } = useGetSideInfo();
const { data: sideInfo, isLoading: isSideInfoLoading, isError: isSideInfoError } = useGetSideInfo();
🤖 Prompt for AI Agents
In apps/client/src/shared/components/sidebar/Sidebar.tsx around line 38 (and
update at line 134), the hook call const { data: sideInfo } = useGetSideInfo();
fetches data but the component never passes it to SideInfoPop and lacks
loading/error handling; update the component to: extract loading and error from
useGetSideInfo (e.g., { data: sideInfo, isLoading, error }), render a loading
state while isLoading, render an error message or fallback when error is
present, and pass sideInfo as a prop to SideInfoPop at line 134 (ensure
null/undefined safe-checks before accessing fields).

const { mutate: deleteCategory } = useDeleteCategory();
const { data: sideInfo } = useGetSideInfo();

console.log('여기', sideInfo);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

디버그용 console.log를 제거하세요.

프로덕션 코드에 디버그용 console.log가 남아있습니다.

🔎 제안하는 수정 방법
- console.log('여기', sideInfo);
📝 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.

Suggested change
console.log('여기', sideInfo);
🤖 Prompt for AI Agents
In apps/client/src/shared/components/sidebar/Sidebar.tsx around line 40 there is
a leftover debug console.log('여기', sideInfo); — remove this console.log from
production code; if you need runtime diagnostics instead, replace it with a
proper logger(DEBUG) call behind an environment/dev check or use React devtools,
but do not leave console.log in the committed file.

return (
<aside className="bg-white-bg sticky top-0 h-screen w-[24rem] border-r border-gray-300">
<aside className="bg-white-bg relative sticky top-0 h-screen w-[24rem] border-r border-gray-300">
<SideInfoPop />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

팝업 표시/숨김 로직이 구현되지 않았습니다.

SideInfoPop 컴포넌트가 항상 렌더링되고 있습니다. 사용자 인터랙션(예: 프로필 클릭)에 따라 팝업을 표시/숨김 처리하는 로직이 필요합니다.

🔎 제안하는 수정 방법

상태를 추가하여 팝업의 표시 여부를 제어하세요:

+ const [isSideInfoOpen, setIsSideInfoOpen] = useState(false);

  return (
    <aside className="bg-white-bg relative sticky top-0 h-screen w-[24rem] border-r border-gray-300">
-     <SideInfoPop />
+     {isSideInfoOpen && (
+       <SideInfoPop 
+         sideInfo={sideInfo}
+         onClose={() => setIsSideInfoOpen(false)}
+       />
+     )}

그리고 프로필 이미지나 버튼을 추가하여 팝업을 열 수 있도록 하세요.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/client/src/shared/components/sidebar/Sidebar.tsx around line 134,
SideInfoPop is always rendered; add local state (e.g., isSideInfoOpen) to
control visibility, render <SideInfoPop /> only when that state is true, and
wire a clickable element (profile image or button) to toggle the state to
open/close the popup; also close the popup on outside clicks or Escape key by
adding an effect/listener to set the state to false so the popup hides
appropriately.

@@ -0,0 +1,28 @@
import { Icon } from '@pinback/design-system/icons';
const SideInfoPop = () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

컴포넌트에 props 인터페이스를 추가하세요.

컴포넌트가 props를 받지 않아 동적 데이터를 표시할 수 없습니다. 유저 정보와 이벤트 핸들러를 받을 수 있도록 props 인터페이스를 정의해야 합니다.

🔎 제안하는 수정 방법
+ interface SideInfoPopProps {
+   sideInfo?: {
+     name: string;
+     email: string;
+     profileImage?: string;
+     remindTime?: string;
+   };
+   isLoading?: boolean;
+   isError?: boolean;
+   onClose?: () => void;
+   onLogout?: () => void;
+ }
+
- const SideInfoPop = () => {
+ const SideInfoPop = ({ sideInfo, isLoading, isError, onClose, onLogout }: SideInfoPopProps) => {
+   if (isLoading) return <div>로딩 중...</div>;
+   if (isError || !sideInfo) return null;
+
   return (

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/client/src/shared/components/sidebar/SideInfoPop.tsx around line 2, the
component is declared without a props interface so it cannot accept dynamic
data; define and export a TypeScript interface (e.g., SideInfoPopProps) that
includes the needed fields such as user info (id, name, avatarUrl, email, etc.)
and event handler callbacks (onClose, onEdit, onLogout, etc.), update the
component signature to accept (props: SideInfoPopProps) or destructure the props
in the parameter list, and update any internal usage to reference these typed
props to enable type-checked dynamic rendering and event handling.

import { Icon } from '@pinback/design-system/icons';
const SideInfoPop = () => {
return (
<div className="bg-white-bg common-shadow absolute left-[19.6rem] top-[6.8rem] z-10 flex h-[32rem] w-[26rem] flex-col items-center justify-center rounded-[12px] py-[2.4rem]">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Portal을 사용하여 팝업을 렌더링하세요.

PR 목표에 "Portal 처리"가 명시되어 있지만, 현재 팝업이 일반 DOM 구조로 렌더링되고 있습니다. position: absolute를 사용한 위치 지정은 스크롤이나 레이아웃 변경 시 문제를 일으킬 수 있습니다.

🔎 제안하는 수정 방법

React의 createPortal을 사용하여 팝업을 document body에 렌더링하세요:

import { createPortal } from 'react-dom';

const SideInfoPop = ({ sideInfo, onClose, onLogout }: SideInfoPopProps) => {
  if (!sideInfo) return null;
  
  return createPortal(
    <>
      <div 
        className="fixed inset-0 bg-black/20 z-40"
        onClick={onClose}
      />
      <div className="bg-white-bg common-shadow fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-50 flex h-[32rem] w-[26rem] flex-col items-center justify-center rounded-[12px] py-[2.4rem]">
        {/* 기존 내용 */}
      </div>
    </>,
    document.body
  );
};

참고: 기존 PopupPortal 컴포넌트의 패턴을 참고하여 일관성을 유지하세요.

🤖 Prompt for AI Agents
In apps/client/src/shared/components/sidebar/SideInfoPop.tsx around line 4, the
popup is currently rendered inline with position:absolute which breaks on
scroll/layout changes; refactor it to use ReactDOM.createPortal to render the
popup into document.body (or the existing PopupPortal root) instead of the
normal DOM tree, replace absolute positioning with fixed positioning (centered
or positioned relative to viewport), add a backdrop overlay element that
captures clicks to call onClose, and follow the existing PopupPortal component
pattern for consistent z-index and accessibility.

Comment on lines +6 to +9
src="https://blog.kakaocdn.net/dna/kXF6L/btrt5yaCuuH/AAAAAAAAAAAAAAAAAAAAAEC2uoT7qWaQUOtDL18xi3PXMOakg5-QzqBlHNEzXJJv/%EC%B9%B4%ED%86%A1%20%EA%B8%B0%EB%B3%B8%ED%94%84%EB%A1%9C%ED%95%84%20%EC%82%AC%EC%A7%84(%EC%97%B0%EC%97%B0%EB%91%90ver).jpg?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1767193199&allow_ip=&allow_referer=&signature=nnJLy%2F48M51zZd6WvzDD0VJiMZA%3D&attach=1&knm=img.jpg"
className="my-[0.8rem] h-[13.2rem] w-[13.2rem] rounded-full"
alt="유저 프로필 이미지"
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

외부 이미지 URL을 안전한 방식으로 변경하세요.

카카오 CDN의 임시 자격 증명이 포함된 외부 URL을 하드코딩하는 것은 보안 위험이 있습니다. 자격 증명이 만료되면 이미지가 로드되지 않을 수 있습니다.

🔎 제안하는 수정 방법
       <img
-        src="https://blog.kakaocdn.net/dna/kXF6L/btrt5yaCuuH/AAAAAAAAAAAAAAAAAAAAAEC2uoT7qWaQUOtDL18xi3PXMOakg5-QzqBlHNEzXJJv/%EC%B9%B4%ED%86%A1%20%EA%B8%B0%EB%B3%B8%ED%94%84%EB%A1%9C%ED%95%84%20%EC%82%AC%EC%A7%84(%EC%97%B0%EC%97%B0%EB%91%90ver).jpg?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1767193199&allow_ip=&allow_referer=&signature=nnJLy%2F48M51zZd6WvzDD0VJiMZA%3D&attach=1&knm=img.jpg"
+        src={sideInfo?.profileImage || '/default-profile.png'}
         className="my-[0.8rem] h-[13.2rem] w-[13.2rem] rounded-full"
         alt="유저 프로필 이미지"
       />

참고: 기본 프로필 이미지를 프로젝트 assets에 추가하세요.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/client/src/shared/components/sidebar/SideInfoPop.tsx around lines 6 to
9, replace the hardcoded Kakao CDN URL (which contains temporary credentials)
with a safe, local asset or a stable public URL: add a default profile image to
the project assets (or /public), import or reference that asset instead of the
external URL, and use it as the src value with an optional prop/fallback so
expiring credentials won’t break the UI; remove any query/credential fragments
and do not commit secret-bearing URLs.

Comment on lines +10 to +17
<p className="sub1-sb text-font-black-1 mb-[0.4rem]">이름</p>
<div className="flex flex-col items-center justify-center gap-[0.2rem]">
<p className="body4-r text-font-gray-3">이메일</p>
<div className="mb-[1.86em] flex justify-between gap-[0.4rem]">
<Icon name="ic_clock_active" width={16} height={16} />
<p className="caption2-m text-font-gray-3">리마인드 알람</p>
<p className="caption2-m text-font-gray-3">AM 09:00</p>
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

하드코딩된 데이터를 동적 데이터로 교체하세요.

"이름", "이메일", "AM 09:00" 등의 텍스트가 하드코딩되어 있습니다. API에서 받아온 실제 사용자 데이터를 표시해야 합니다.

Based on learnings, 하드코딩된 값은 임시 테스트 데이터로 실제 기능 구현 시 동적 데이터로 교체되어야 합니다.

🔎 제안하는 수정 방법
-      <p className="sub1-sb text-font-black-1 mb-[0.4rem]">이름</p>
+      <p className="sub1-sb text-font-black-1 mb-[0.4rem]">{sideInfo?.name}</p>
       <div className="flex flex-col items-center justify-center gap-[0.2rem]">
-        <p className="body4-r text-font-gray-3">이메일</p>
+        <p className="body4-r text-font-gray-3">{sideInfo?.email}</p>
         <div className="mb-[1.86em] flex justify-between gap-[0.4rem]">
           <Icon name="ic_clock_active" width={16} height={16} />
           <p className="caption2-m text-font-gray-3">리마인드 알람</p>
-          <p className="caption2-m text-font-gray-3">AM 09:00</p>
+          <p className="caption2-m text-font-gray-3">{sideInfo?.remindTime || 'AM 09:00'}</p>
         </div>
       </div>
📝 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.

Suggested change
<p className="sub1-sb text-font-black-1 mb-[0.4rem]">이름</p>
<div className="flex flex-col items-center justify-center gap-[0.2rem]">
<p className="body4-r text-font-gray-3">이메일</p>
<div className="mb-[1.86em] flex justify-between gap-[0.4rem]">
<Icon name="ic_clock_active" width={16} height={16} />
<p className="caption2-m text-font-gray-3">리마인드 알람</p>
<p className="caption2-m text-font-gray-3">AM 09:00</p>
</div>
<p className="sub1-sb text-font-black-1 mb-[0.4rem]">{sideInfo?.name}</p>
<div className="flex flex-col items-center justify-center gap-[0.2rem]">
<p className="body4-r text-font-gray-3">{sideInfo?.email}</p>
<div className="mb-[1.86em] flex justify-between gap-[0.4rem]">
<Icon name="ic_clock_active" width={16} height={16} />
<p className="caption2-m text-font-gray-3">리마인드 알람</p>
<p className="caption2-m text-font-gray-3">{sideInfo?.remindTime || 'AM 09:00'}</p>
</div>
</div>
🤖 Prompt for AI Agents
In apps/client/src/shared/components/sidebar/SideInfoPop.tsx around lines 10 to
17, several UI strings ("이름", "이메일", "AM 09:00") are hardcoded; replace them
with props or state populated from the user API (or context) so the component
renders actual user.name, user.email and user.reminderTime. Fetch or receive the
user object higher up (or use existing user store), pass it into SideInfoPop,
and change those text nodes to render the corresponding fields, handling
loading/undefined states (show skeleton or fallback) and formatting the reminder
time to the displayed "AM/PM hh:mm" locale before rendering. Ensure you do not
hardcode test values and add appropriate TypeScript types for the user
prop/state.

Comment on lines +19 to +24
<button
type="button"
className="sub5-sb text-font-black-1 border-gray200 h-[3.6rem] w-[10.8rem] rounded-[4px] border py-[0.8rem] text-center"
>
로그아웃
</button>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

로그아웃 버튼에 핸들러를 추가하세요.

PR 목표에 "로그아웃 처리"가 명시되어 있지만, 로그아웃 버튼에 클릭 핸들러가 구현되지 않았습니다.

🔎 제안하는 수정 방법
       <button
         type="button"
         className="sub5-sb text-font-black-1 border-gray200 h-[3.6rem] w-[10.8rem] rounded-[4px] border py-[0.8rem] text-center"
+        onClick={onLogout}
       >
         로그아웃
       </button>

그리고 부모 컴포넌트(Sidebar.tsx)에서 로그아웃 로직을 구현하세요:

const handleLogout = () => {
  localStorage.removeItem('token');
  // 추가 로그아웃 처리 (예: 쿼리 캐시 초기화, 리다이렉트 등)
  navigate('/login');
};
📝 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.

Suggested change
<button
type="button"
className="sub5-sb text-font-black-1 border-gray200 h-[3.6rem] w-[10.8rem] rounded-[4px] border py-[0.8rem] text-center"
>
로그아웃
</button>
<button
type="button"
className="sub5-sb text-font-black-1 border-gray200 h-[3.6rem] w-[10.8rem] rounded-[4px] border py-[0.8rem] text-center"
onClick={onLogout}
>
로그아웃
</button>
🤖 Prompt for AI Agents
In apps/client/src/shared/components/sidebar/SideInfoPop.tsx around lines 19 to
24, the logout button has no click handler; add an onClick that calls a logout
prop (e.g., onLogout) passed from the parent, and in the parent Sidebar.tsx
implement that handler to remove the auth token from localStorage, clear any
relevant client/query caches, perform any additional cleanup, and navigate to
the login route; ensure the SideInfoPop component accepts the onLogout prop in
its props interface and that Sidebar passes handleLogout down.

Copy link
Copy Markdown
Collaborator

@jjangminii jjangminii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

소통 오류가 있어서 겹쳤네요.. 저는 포탈로 띄우려다가 복잡해질것 같기도하고 사이드바의 다른 팝업들과 달리 항상 고정된 위치에서 나타날거라 생각해 fixed로 했는데 이 부분에 대해서 어떤게 더 좋은 방식이라 생각하는지 궁금합니다-!

return (
<div className="bg-white-bg common-shadow absolute left-[19.6rem] top-[6.8rem] z-10 flex h-[32rem] w-[26rem] flex-col items-center justify-center rounded-[12px] py-[2.4rem]">
<img
src="https://blog.kakaocdn.net/dna/kXF6L/btrt5yaCuuH/AAAAAAAAAAAAAAAAAAAAAEC2uoT7qWaQUOtDL18xi3PXMOakg5-QzqBlHNEzXJJv/%EC%B9%B4%ED%86%A1%20%EA%B8%B0%EB%B3%B8%ED%94%84%EB%A1%9C%ED%95%84%20%EC%82%AC%EC%A7%84(%EC%97%B0%EC%97%B0%EB%91%90ver).jpg?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1767193199&allow_ip=&allow_referer=&signature=nnJLy%2F48M51zZd6WvzDD0VJiMZA%3D&attach=1&knm=img.jpg"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 어떤 url인가요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 기능 개발하라 개발 달려라 달려

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 사이드바 프로필 상세 팝업

2 participants