Skip to content

[DEPLOY] 회원 탈퇴 API 연결 등 적용#269

Merged
drddyn merged 17 commits intomainfrom
develop
Feb 5, 2026
Merged

[DEPLOY] 회원 탈퇴 API 연결 등 적용#269
drddyn merged 17 commits intomainfrom
develop

Conversation

@drddyn
Copy link
Contributor

@drddyn drddyn commented Feb 5, 2026

✅ Summary

이하의 작업들을 완료하여 main에 병합합니다

📝 Description

  • GA4
  • 회원 탈퇴 API 연결
  • 리포트 내역 삭제 딜레이 수정

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @drddyn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 사용자 경험 개선과 데이터 기반 의사결정을 위한 중요한 업데이트를 포함합니다. GA4 통합을 통해 사용자 행동에 대한 심층적인 인사이트를 얻고, 회원 탈퇴 기능을 제공하여 사용자에게 더 많은 제어권을 부여합니다. 또한, 리포트 삭제 시 즉각적인 UI 반응을 제공하여 애플리케이션의 전반적인 반응성을 높였습니다.

Highlights

  • GA4 (Google Analytics 4) 통합: 사용자 행동 분석을 위해 GA4를 프론트엔드에 통합했습니다. 로그인, 온보딩, 아이디어 생성, 리포트 조회, 탭 전환, 북마크 등 다양한 사용자 인터랙션에 대한 이벤트 트래킹이 추가되었습니다. 이를 통해 서비스 사용 패턴을 더 정확하게 파악할 수 있습니다.
  • 회원 탈퇴 기능 구현: 회원 탈퇴 API 연동 및 관련 프론트엔드 로직을 구현했습니다. 사용자는 설정 페이지에서 계정을 안전하게 탈퇴할 수 있으며, 탈퇴 시 인증 정보가 초기화되고 메인 페이지로 이동됩니다.
  • 리포트 삭제 UX 개선 (낙관적 업데이트): 마이페이지에서 리포트 삭제 시, UI에서 해당 리포트가 즉시 사라지도록 낙관적 업데이트(Optimistic Update)를 적용하여 사용자 경험을 향상시켰습니다. 실제 API 호출 결과에 따라 UI가 최종적으로 반영됩니다.
  • 피드백 링크 추가: 내비게이션 바에 외부 피드백 채널(카카오톡 오픈채팅)로 연결되는 링크를 추가하여 사용자 소통을 강화했습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • frontend/package.json
    • GA4 라이브러리 'react-ga4' 의존성 추가
  • frontend/pnpm-lock.yaml
    • 'react-ga4' 의존성 추가 및 다양한 플랫폼별 패키지에 'libc' 정의 추가
  • frontend/src/App.tsx
    • 코드 포맷팅 개선 (ReactQueryDevtools 아래 빈 줄 추가)
  • frontend/src/api/user.ts
    • 회원 탈퇴를 위한 'withdrawMember' API 호출 함수 추가
  • frontend/src/assets/icons/feedback.svg
    • 새로운 피드백 아이콘 SVG 파일 추가
  • frontend/src/components/GoogleAnalytics.tsx
    • GA4 초기화 및 페이지뷰 트래킹을 담당하는 'GoogleAnalytics' 컴포넌트 추가
  • frontend/src/hooks/idea/usePatchIdeaBookmark.ts
    • 코드 포맷팅 개선 (import 문 사이 빈 줄 추가)
  • frontend/src/hooks/idea/usePostIdea.ts
    • 아이디어 생성 실패 시 에러 메시지 처리를 개선하여 기본 메시지 제공
  • frontend/src/hooks/main/useUrlInput.ts
    • GA4 이벤트 트래킹을 위한 'onTrackEvent' 콜백을 'useUrlInput' 훅에 추가
    • 리포트 생성 요청 및 로그인 필요 시 GA4 이벤트 트래킹 로직 추가
  • frontend/src/hooks/report/useDeleteMyReport.ts
    • 리포트 삭제 시 낙관적 업데이트 로직을 추가하여 UI 반응성 개선
    • 삭제 전 쿼리 캐시 취소 및 업데이트, 에러 발생 시 이전 데이터로 롤백 기능 구현
  • frontend/src/hooks/setting/useWithdrawSettings.ts
    • 회원 탈퇴 로직을 관리하는 'useWithdrawSettings' 훅 추가 (인증 정보 초기화, 페이지 이동 포함)
  • frontend/src/hooks/setting/userMutations.ts
    • 회원 탈퇴 API 호출을 위한 'useWithdrawMember' 뮤테이션 훅 추가
  • frontend/src/hooks/useScrollTracking.ts
    • 스크롤 임계값 도달 시 콜백을 실행하는 'useScrollTracking' 커스텀 훅 추가
  • frontend/src/layouts/RootLayout.tsx
    • 'GoogleAnalytics' 컴포넌트를 통합하여 전역 GA4 트래킹 활성화
  • frontend/src/layouts/_components/navbar/NavbarLinksList.tsx
    • 내비게이션 바에 피드백 링크를 추가하고, 로그인 버튼 위치 조정
  • frontend/src/layouts/_components/navbar/navbarLinks.ts
    • 피드백 링크 ('FEEDBACK_LINK') 정의 및 'LinkItem' 타입에 'isExternal' 속성 추가
  • frontend/src/pages/auth/GoogleRedirectPage.tsx
    • 구글 로그인 성공/실패 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/auth/NavbarModalsContainer.tsx
    • 온보딩 모달(Viewer, Concept) 열림 및 제출 성공/실패 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/auth/_components/LoginModal.tsx
    • 로그인 모달 열림 및 구글 로그인 버튼 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/idea/_components/ContentsIdea.tsx
    • 아이디어 북마크 추가/제거 및 에러 발생 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/idea/_components/GeneratingIdea.tsx
    • 아이디어 생성 관련 사용자 인터랙션(툴팁 열기, 영상 형식 선택, 키워드/추가 정보 입력 시작, 아이디어 생성 요청/성공/실패)에 대한 GA4 이벤트 트래킹 추가
  • frontend/src/pages/idea/_components/TextareaWithLimit.tsx
    • 'onFocus' prop을 추가하여 텍스트 영역 포커스 이벤트 처리 확장
  • frontend/src/pages/library/LibraryPage.tsx
    • 라이브러리 페이지의 메인 탭 전환 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/library/_components/IdeaCard.tsx
    • 아이디어 북마크 제거 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/library/_components/RecentReportCard.tsx
    • 리포트 카드 삭제 및 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/library/_components/RecentReportShortsCard.tsx
    • 쇼츠 리포트 카드 삭제 및 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/library/_components/ReportTab.tsx
    • 리포트 탭 내 서브 탭(동영상/쇼츠) 전환 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/main/_components/DummyVideoCard.tsx
    • 데모 비디오 카드 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/main/_components/MyVideoCard.tsx
    • 내 비디오 카드 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/main/_components/UrlInputForm.tsx
    • 'useUrlInput' 훅에 'onTrackEvent' 콜백을 전달하여 GA4 트래킹 연동
  • frontend/src/pages/main/_components/UrlInputModal.tsx
    • 'useUrlInput' 훅에 'onTrackEvent' 콜백을 전달하여 GA4 트래킹 연동
  • frontend/src/pages/my/_components/conceptbox.tsx
    • 채널 콘셉트 수정 시작 및 업데이트 성공/실패 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/my/_components/myShortsCard.tsx
    • 내 쇼츠 카드 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/my/_components/myVideoCard.tsx
    • 내 비디오 카드 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/my/_components/targetbox.tsx
    • 채널 타겟 수정 시작 및 업데이트 성공/실패 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/my/_components/videolist.tsx
    • 내 채널 비디오 리스트 탭 전환 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/report/DummyReportPage.tsx
    • 데모 리포트 페이지 조회 및 탭 전환 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/report/ReportPage.tsx
    • 실제 리포트 페이지 조회, 탭 전환, 업데이트 버튼 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/report/_components/UpdateModal.tsx
    • 리포트 업데이트 모달에서 업데이트 요청, 성공, 실패 및 취소 시 GA4 이벤트 트래킹 추가
    • 모달에 'reportId' prop 추가
  • frontend/src/pages/report/_components/analysis/TabAnalysis.tsx
    • 분석 탭 스크롤 트래킹을 위해 'useScrollTracking' 훅 적용 및 GA4 이벤트 트래킹 추가
  • frontend/src/pages/report/_components/overview/CommentFeedback.tsx
    • 댓글 피드백 탭 전환 및 차트 세그먼트 클릭 시 GA4 이벤트 트래킹 추가
  • frontend/src/pages/setting/SettingPage.tsx
    • 회원 탈퇴 모달 ('WithdrawModal') 상태 관리 및 'useWithdrawSettings' 훅 연동
    • 로그인 상태에 따라 회원 탈퇴 모달 활성화 여부 결정
  • frontend/src/pages/setting/_components/WithdrawModal.tsx
    • 파일 이름이 'WithdrawlModal.tsx'에서 'WithdrawModal.tsx'로 변경
    • 탈퇴 처리 중 버튼 비활성화를 위한 'isPending' prop 추가
  • frontend/src/utils/analytics.ts
    • GA4 초기화, 페이지뷰 및 이벤트 트래킹을 위한 유틸리티 함수 ('initGA', 'trackPageView', 'trackEvent') 추가
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@drddyn drddyn merged commit 88e811f into main Feb 5, 2026
5 checks passed
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

이 PR은 GA4를 통한 사용자 행동 추적 기능 추가, 회원 탈퇴 기능 구현, 그리고 리포트 삭제 시의 사용자 경험 개선을 포함하고 있습니다. 전반적으로 코드 변경 사항이 많지만, 각 기능의 구현이 체계적으로 잘 이루어졌습니다. 특히 GA 추적 로직이 애플리케이션 전반에 걸쳐 상세하게 추가된 점이 인상적입니다. 몇 가지 개선점을 제안드렸으며, 특히 리포트 삭제 시의 낙관적 업데이트 로직과 이벤트 추적 방식에 대한 검토가 필요해 보입니다.

Comment on lines +20 to +40
onMutate: async ({ reportId }) => {
if (typeof channelId !== 'number') return {}
const queryKey = ['my', 'report', channelId]
await queryClient.cancelQueries({ queryKey })
const previousData = queryClient.getQueryData<MyReportQueryData>(queryKey)
queryClient.setQueryData<MyReportQueryData>(queryKey, (old) => {
if (!old) return old
return {
...old,
reportList: old.reportList.filter((report) => report.reportId !== reportId),
totalElements: old.totalElements - 1,
}
})
return { previousData }
},
onError: (_error, _variables, context) => {
if (typeof channelId === 'number' && context?.previousData) {
queryClient.setQueryData(['my', 'report', channelId], context.previousData)
}
alert('리포트 삭제 중 오류가 발생했습니다.')
},
Copy link
Contributor

Choose a reason for hiding this comment

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

high

리포트 목록에 대한 낙관적 업데이트를 구현하신 점이 좋습니다. 하지만 현재 onMutateonError에서 사용된 setQueryDatagetQueryData는 정확한 쿼리 키를 필요로 합니다. 리포트 목록 쿼리는 페이징 및 필터링(type)을 포함하므로, ['my', 'report', channelId]와 같은 부분적인 키로는 캐시된 데이터를 정확히 찾아 업데이트하거나 롤백하기 어렵습니다. 이로 인해 낙관적 업데이트가 UI에 반영되지 않을 가능성이 높습니다.

모든 관련 페이지 캐시에 대해 업데이트를 적용하려면 setQueriesData를 필터와 함께 사용하는 것을 고려해 보세요. 이 로직이 의도한 대로 동작하는지 다시 한번 확인해 보시는 것을 추천합니다.

Comment on lines +42 to +58
export const trackEvent = ({ category, action, label, value }: EventParams) => {
// 비동기로 실행하여 메인 로직 블로킹 방지
setTimeout(() => {
try {
if (!isInitialized) return

ReactGA.event({
category,
action,
label,
value,
})
} catch (error) {
console.error('[GA4] 이벤트 트래킹 실패:', error)
}
}, 0)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

trackEvent 함수를 setTimeout으로 감싸 비동기로 처리하셨는데, 이는 메인 스레드를 블로킹하지 않으려는 좋은 의도입니다. 하지만 사용자가 이벤트를 발생시키는 행동(예: 링크 클릭) 후 페이지가 바로 이동하는 경우, setTimeout의 콜백이 실행되기 전에 페이지가 언로드되어 이벤트가 유실될 수 있습니다. 예를 들어, 로그인 버튼 클릭 후 즉시 페이지를 리디렉션하는 경우에 해당합니다.

이벤트 추적의 정확성을 높이기 위해 setTimeout을 제거하고 동기적으로 처리하는 것을 고려해 보세요. ReactGA.event 호출로 인한 성능 영향은 대부분의 경우 미미합니다.

export const trackEvent = ({ category, action, label, value }: EventParams) => {
    try {
        if (!isInitialized) return

        ReactGA.event({
            category,
            action,
            label,
            value,
        })
    } catch (error) {
        console.error('[GA4] 이벤트 트래킹 실패:', error)
    }
}

Comment on lines +33 to 38
// ✅ 페이지 진입 시 해당 리포트 ID로 상태가 없을 때만 일회성으로 서버에 상태 조회
const needsPolling = useMemo(() => pendingReportIds.includes(reportId), [pendingReportIds, reportId])
usePollReportStatus(reportId, { enabled: needsPolling })

// ✅ 리포트 생성에 실패한 경우
// ✅ 해당 리포트 ID가 PENDING 중일 경우 로컬 폴링
const isKnownToHaveFailed = useMemo(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

코드의 가독성을 위해 남겨주신 주석들이 실제 코드 내용과 일치하지 않는 것 같습니다. 33행의 주석은 폴링에 대한 내용이어야 하고, 37행의 주석은 실패 케이스 처리에 대한 내용이어야 합니다. 주석을 코드에 맞게 수정하면 나중에 코드를 이해하는 데 도움이 될 것입니다.

Suggested change
// ✅ 페이지 진입 시 해당 리포트 ID로 상태가 없을 때만 일회성으로 서버에 상태 조회
const needsPolling = useMemo(() => pendingReportIds.includes(reportId), [pendingReportIds, reportId])
usePollReportStatus(reportId, { enabled: needsPolling })
// ✅ 리포트 생성에 실패한 경우
// ✅ 해당 리포트 ID가 PENDING 중일 경우 로컬 폴링
const isKnownToHaveFailed = useMemo(() => {
// ✅ 해당 리포트 ID가 PENDING 중일 경우 로컬 폴링
const needsPolling = useMemo(() => pendingReportIds.includes(reportId), [pendingReportIds, reportId])
usePollReportStatus(reportId, { enabled: needsPolling })
// ✅ 리포트 생성에 실패한 경우
const isKnownToHaveFailed = useMemo(() => {

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants