Skip to content

Conversation

@young-jin-son
Copy link
Collaborator

@young-jin-son young-jin-son commented Jul 15, 2025

Issue Number

close #292

As-Is

  • 회원 탈퇴 기능 없었음

To-Be

  • 회원 탈퇴 기능 추가

Check List

  • 테스트가 전부 통과되었나요?
  • 모든 commit이 push 되었나요?
  • merge할 branch를 확인했나요?
  • Assignee를 지정했나요?
  • Label을 지정했나요?

Test Screenshot

변경 전 변경 후
image image

(Optional) Additional Description

Summary by CodeRabbit

  • New Features
    • Added a "Delete Account" button to the MyPage screen, allowing users to permanently delete their accounts after confirmation.
  • Style
    • Updated various components to improve spacing, color schemes, and introduce conditional styling based on edit mode.
    • Refined the layout of editable sections and buttons for a clearer user experience.
  • Refactor
    • Renamed the logout hook for consistency.
    • Reorganized component structures for better separation of editable content and actions.
  • Chores
    • Updated API endpoint constants to support account deletion.

@young-jin-son young-jin-son self-assigned this Jul 15, 2025
@young-jin-son young-jin-son added feat 새로운 기능 구현 FE 프론트엔드 작업 labels Jul 15, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 15, 2025

Walkthrough

A user account deletion feature was added to the frontend. This includes a new API call, a button with confirmation modal, mutation hooks, and integration into the MyPage screen. Various style and layout adjustments were made to support the new feature and improve edit mode UI consistency across MyPage components.

Changes

File(s) / Path(s) Change Summary
frontend/src/api/deleteAccount.ts, frontend/src/constants/url.ts Added new API endpoint and function for account deletion.
frontend/src/components/Button/DeleteAccountButton/* Introduced DeleteAccountButton component, styled button, mutation hook, and modal confirmation logic.
frontend/src/pages/MyPage/index.ts Integrated DeleteAccountButton into MyPage, removing previous notification info section.
frontend/src/components/Button/LogoutButton/hooks/useLogoutMutation.ts, .../LogoutButton/index.ts Renamed logout hook and updated its usage in the LogoutButton component.
frontend/src/pages/MyPage/MyPage.styled.ts Adjusted container heights, overflow, and spacing for improved scrolling and layout.
.../MyPageEditableSection/MyPageAddress/MyPageAddress.styled.ts, .../index.tsx Added conditional styling for address items/labels based on edit mode; updated icon color logic.
.../MyPageEditableSection/MyPageGoal/MyPageGoal.styled.ts, .../index.tsx Updated goal item/button styles to support edit mode; centralized icon color logic.
.../MyPageEditableSection/MyPageEditableSection.styled.ts, .../index.tsx Refactored layout and conditional rendering for edit/cancel/save buttons; added new styled containers and divider.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MyPage
    participant DeleteAccountButton
    participant Modal
    participant useDeleteAccountMutation
    participant API

    User->>MyPage: Navigates to MyPage
    MyPage->>DeleteAccountButton: Renders button
    User->>DeleteAccountButton: Clicks "회원 탈퇴"
    DeleteAccountButton->>Modal: Opens confirmation modal
    User->>Modal: Confirms deletion
    Modal->>useDeleteAccountMutation: Triggers mutation
    useDeleteAccountMutation->>API: Sends DELETE /api/v1/auth/account
    API-->>useDeleteAccountMutation: Responds with result
    useDeleteAccountMutation->>User: Clears token, redirects to /landing
Loading

Assessment against linked issues

Objective (Issue #) Addressed Explanation
회원탈퇴 기능 추가 (#292)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Suggested labels

design

Poem

A button appears, so bold and bright,
"탈퇴" it whispers, "End your site!"
With modals and hooks, the journey’s begun—
Confirm, then farewell, your account is done.
A hop, a click, a gentle sigh,
The rabbit waves a soft goodbye. 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 2

🧹 Nitpick comments (4)
frontend/src/api/deleteAccount.ts (1)

5-9: Add return type annotation and consider error handling documentation.

The function lacks a return type annotation, which reduces type safety. Consider adding proper typing and JSDoc documentation.

+/**
+ * Deletes the current user's account
+ * @returns Promise containing the deletion result
+ */
-export const deleteAccount = async () => {
+export const deleteAccount = async (): Promise<unknown> => {
  const result = await fetchClient.delete(API_URL.deleteAccount);

  return result;
};

Additionally, consider documenting where error handling occurs (e.g., in the mutation hook) if it's intentionally omitted here.

frontend/src/components/Button/DeleteAccountButton/DeleteAccountButton.styled.ts (1)

3-8: Consider extracting shared button styling to reduce duplication.

The styling is identical to LogoutButton in terms of font, color, text decoration, and margin. Consider creating a shared base component or utility to avoid code duplication.

+// Consider creating a shared base styled component
+const BaseActionButton = styled.button`
+  ${({ theme }) => theme.fonts.label14Med};
+  color: ${({ theme }) => theme.colors.gray600};
+  text-decoration: underline;
+  margin-top: 1.6rem;
+`;

-export const DeleteAccountButton = styled.button`
-  ${({ theme }) => theme.fonts.label14Med};
-  color: ${({ theme }) => theme.colors.gray600};
-  text-decoration: underline;
-  margin-top: 1.6rem;
-`;
+export const DeleteAccountButton = styled(BaseActionButton)`
+  /* Additional specific styling if needed */
+`;
frontend/src/components/Button/DeleteAccountButton/index.tsx (1)

29-42: Consider adding loading state for better UX.

The deletion modal would benefit from showing a loading state while the deletion is in progress to prevent users from clicking multiple times and provide feedback.

Consider adding a loading state:

+  const [isDeleting, setIsDeleting] = useState(false);
+
   const handleConfirmDelete = async () => {
+    setIsDeleting(true);
     try {
       await deleteAccountMutation();
       setIsModalOpen(false);
     } catch (error) {
       console.error('Account deletion failed:', error);
+    } finally {
+      setIsDeleting(false);
     }
   };

And pass the loading state to the modal:

   <HomeModal
     title="회원 탈퇴"
     content={[...]}
     close={handleCloseModal}
     onConfirm={handleConfirmDelete}
     confirmText="탈퇴하기"
+    isLoading={isDeleting}
   />
frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageEditableSection.styled.ts (1)

19-24: Consider reusing existing Divider component to avoid duplication.

There's a similar Divider component in frontend/src/pages/MyPage/MyPage.styled.ts (lines 44-50) with slight differences. The existing one has full width and vertical margin, while this one uses flex: 1 and no margin.

Consider extracting a shared Divider component or reusing the existing one if the styling differences can be reconciled:

-export const Divider = styled.div`
-  flex: 1;
-  height: 0.15rem;
-  background-color: ${({ theme }) => theme.colors.gray200};
-  border-radius: 0.6rem;
-`;

Import the existing Divider and adjust the container styling if needed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36f695b and f9fe9b1.

📒 Files selected for processing (15)
  • frontend/src/api/deleteAccount.ts (1 hunks)
  • frontend/src/components/Button/DeleteAccountButton/DeleteAccountButton.styled.ts (1 hunks)
  • frontend/src/components/Button/DeleteAccountButton/hooks/deleteAccountMutation.ts (1 hunks)
  • frontend/src/components/Button/DeleteAccountButton/index.tsx (1 hunks)
  • frontend/src/components/Button/LogoutButton/hooks/useLogoutMutation.ts (2 hunks)
  • frontend/src/components/Button/LogoutButton/index.tsx (1 hunks)
  • frontend/src/constants/url.ts (1 hunks)
  • frontend/src/pages/MyPage/MyPage.styled.ts (2 hunks)
  • frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageAddress/MyPageAddress.styled.ts (2 hunks)
  • frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageAddress/index.tsx (2 hunks)
  • frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageEditableSection.styled.ts (3 hunks)
  • frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageGoal/MyPageGoal.styled.ts (1 hunks)
  • frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageGoal/index.tsx (2 hunks)
  • frontend/src/pages/MyPage/components/MyPageEditableSection/index.tsx (1 hunks)
  • frontend/src/pages/MyPage/index.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
frontend/src/pages/MyPage/MyPage.styled.ts (1)
Learnt from: rbgksqkr
PR: softeer5th/Team6-DuBu#37
File: frontend/src/components/Icon/icons/Alert.tsx:16-17
Timestamp: 2025-02-04T05:12:55.556Z
Learning: In React components, SVG attributes should use camelCase (e.g., strokeLinecap instead of stroke-linecap) to prevent console warning messages.
🧬 Code Graph Analysis (7)
frontend/src/components/Button/LogoutButton/index.tsx (1)
frontend/src/components/Button/LogoutButton/LogoutButton.styled.ts (1)
  • LogoutButton (3-9)
frontend/src/api/deleteAccount.ts (1)
frontend/src/constants/url.ts (1)
  • API_URL (5-77)
frontend/src/components/Button/DeleteAccountButton/hooks/deleteAccountMutation.ts (1)
frontend/src/api/deleteAccount.ts (1)
  • deleteAccount (5-9)
frontend/src/components/Button/DeleteAccountButton/index.tsx (1)
frontend/src/components/Button/DeleteAccountButton/DeleteAccountButton.styled.ts (1)
  • DeleteAccountButton (3-8)
frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageGoal/index.tsx (1)
frontend/src/types/filter.ts (1)
  • CategoryType (2-2)
frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageEditableSection.styled.ts (1)
frontend/src/pages/MyPage/MyPage.styled.ts (1)
  • Divider (44-50)
frontend/src/pages/MyPage/index.tsx (1)
frontend/src/components/Button/DeleteAccountButton/DeleteAccountButton.styled.ts (1)
  • DeleteAccountButton (3-8)
🔇 Additional comments (22)
frontend/src/constants/url.ts (1)

30-32: LGTM! Well-structured API endpoint addition.

The new deleteAccount endpoint follows the existing URL structure and is appropriately categorized under the authentication section.

frontend/src/components/Button/LogoutButton/index.tsx (2)

1-1: Good naming consistency improvement.

The hook rename from useLogout to useLogoutMutation improves consistency with other mutation hooks in the codebase.


5-5: Hook usage updated correctly.

The hook invocation properly reflects the renamed import while maintaining the same functionality.

frontend/src/components/Button/LogoutButton/hooks/useLogoutMutation.ts (2)

6-6: Consistent hook naming improves code organization.

The rename from useLogout to useLogoutMutation follows mutation hook naming conventions and improves consistency across the codebase.


20-20: Export updated correctly.

The default export properly reflects the renamed hook function.

frontend/src/pages/MyPage/MyPage.styled.ts (2)

6-7: Layout improvements look good.

The gap reduction and addition of vertical scrolling improve the page layout and user experience. The overflow-y: scroll ensures proper scrolling behavior when content exceeds the container height.


49-49: Proper divider spacing added.

The margin addition provides consistent spacing around the divider element, which aligns with the updated layout structure.

frontend/src/components/Button/DeleteAccountButton/hooks/deleteAccountMutation.ts (1)

12-13: Token cleanup and navigation logic is appropriate.

The localStorage token removal and navigation to the landing page correctly handles the post-deletion state, ensuring the user is logged out and redirected appropriately.

frontend/src/pages/MyPage/index.tsx (2)

10-10: Clean integration of the DeleteAccountButton component.

The import and placement of the DeleteAccountButton component is well-positioned and follows the existing component structure.


43-44: Appropriate placement of destructive action.

The divider and DeleteAccountButton placement at the bottom of the page with visual separation is a good UX pattern for destructive actions like account deletion.

frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageAddress/index.tsx (3)

8-8: Theme import is necessary for dynamic color logic.

The theme import enables the getLabelColor function to access color values for conditional styling based on edit mode.


51-53: Clean helper function for conditional styling.

The getLabelColor function centralizes the color logic and provides consistent visual feedback for edit mode across the address section.


62-72: Proper integration of edit mode styling.

The $editMode prop is correctly passed to styled components, and the conditional styling provides clear visual feedback when users can interact with address items.

frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageAddress/MyPageAddress.styled.ts (3)

22-22: Consistent color update for message text.

The color change from green700 to green600 aligns with the overall color scheme and provides consistent visual feedback.


31-36: Effective conditional border styling for edit mode.

The $editMode prop enables dynamic border colors that clearly indicate when address items are interactive (green600) versus read-only (gray200).


41-46: Proper conditional text color for edit mode feedback.

The conditional text color based on $editMode provides clear visual feedback to users about the interactive state of address labels.

frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageGoal/index.tsx (2)

43-50: Excellent refactoring of icon color logic.

The new getIconColor helper function centralizes the color determination logic, making it more maintainable and testable. The function clearly handles the three states (not selected, selected in edit mode, selected in view mode) with appropriate color values.


63-68: Good prop passing for consistent edit mode behavior.

The editMode prop is properly passed to both S.GoalItem and S.GoalItemText styled components, ensuring consistent styling behavior across the goal selection interface.

frontend/src/pages/MyPage/components/MyPageEditableSection/index.tsx (1)

43-66: Excellent UI restructuring for better user experience.

The separation of edit controls (EditButtonContainer) from editable content (EditContentContainer) creates a cleaner interface with better visual hierarchy. The conditional rendering logic is now more intuitive - edit button appears in view mode, and cancel/save buttons appear in edit mode.

frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageEditableSection.styled.ts (1)

35-40: Improved button styling with consistent theme usage.

The font styling change to theme.fonts.label13 and the addition of flex-shrink: 0 and padding-right: 0 create better visual consistency and prevent layout issues.

frontend/src/pages/MyPage/components/MyPageEditableSection/MyPageGoal/MyPageGoal.styled.ts (2)

32-50: Excellent conditional styling implementation for edit mode.

The GoalItem styled component now provides clear visual feedback for different states:

  • Unselected: gray background with gray border
  • Selected in edit mode: white background with green border
  • Selected in view mode: white background with gray border

This creates intuitive visual cues for users to understand the current state and available actions.


52-60: Consistent text color scheme across all states.

The GoalItemText color logic properly matches the visual hierarchy:

  • Gray for unselected items
  • Green for selected items in edit mode
  • Gray for selected items in view mode

This ensures readability and visual consistency throughout the interface.

Comment on lines +9 to +15
const { mutate: deleteAccountMutation } = useMutation({
mutationFn: deleteAccount,
onSuccess: () => {
localStorage.removeItem('accessToken');
navigate('/landing');
},
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding error handling to the mutation.

The current implementation handles the success case well, but there's no error handling for failed deletion attempts. Consider adding an onError callback to handle network failures or server errors gracefully.

 const { mutate: deleteAccountMutation } = useMutation({
   mutationFn: deleteAccount,
   onSuccess: () => {
     localStorage.removeItem('accessToken');
     navigate('/landing');
   },
+  onError: (error) => {
+    // Handle deletion failure - show user feedback
+    console.error('Account deletion failed:', error);
+  },
 });
📝 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 { mutate: deleteAccountMutation } = useMutation({
mutationFn: deleteAccount,
onSuccess: () => {
localStorage.removeItem('accessToken');
navigate('/landing');
},
});
const { mutate: deleteAccountMutation } = useMutation({
mutationFn: deleteAccount,
onSuccess: () => {
localStorage.removeItem('accessToken');
navigate('/landing');
},
onError: (error) => {
// Handle deletion failure - show user feedback
console.error('Account deletion failed:', error);
},
});
🤖 Prompt for AI Agents
In
frontend/src/components/Button/DeleteAccountButton/hooks/deleteAccountMutation.ts
around lines 9 to 15, the useMutation call lacks error handling for failed
deletion attempts. Add an onError callback to the mutation options to handle
network or server errors gracefully, such as showing an error message or logging
the failure, ensuring the user is informed if the deletion does not succeed.

Comment on lines +16 to +19
const handleConfirmDelete = () => {
deleteAccountMutation();
setIsModalOpen(false);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle deletion errors and avoid race conditions.

The current implementation has a potential race condition where the modal closes immediately after calling the mutation, regardless of whether the deletion succeeds or fails. This could lead to poor user experience if the deletion fails silently.

Consider waiting for the mutation to complete before closing the modal:

-  const handleConfirmDelete = () => {
-    deleteAccountMutation();
-    setIsModalOpen(false);
-  };
+  const handleConfirmDelete = async () => {
+    try {
+      await deleteAccountMutation();
+      setIsModalOpen(false);
+    } catch (error) {
+      // Handle error (show error message, keep modal open, etc.)
+      console.error('Account deletion failed:', error);
+    }
+  };
📝 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 handleConfirmDelete = () => {
deleteAccountMutation();
setIsModalOpen(false);
};
const handleConfirmDelete = async () => {
try {
await deleteAccountMutation();
setIsModalOpen(false);
} catch (error) {
// Handle error (show error message, keep modal open, etc.)
console.error('Account deletion failed:', error);
}
};
🤖 Prompt for AI Agents
In frontend/src/components/Button/DeleteAccountButton/index.tsx around lines 16
to 19, the modal closes immediately after calling deleteAccountMutation without
waiting for the mutation to complete, which can cause race conditions and poor
UX if deletion fails. Modify handleConfirmDelete to await the completion of
deleteAccountMutation, then close the modal only if the mutation succeeds. Also,
handle any errors from the mutation to provide feedback or keep the modal open
if deletion fails.

@young-jin-son young-jin-son merged commit 6b43870 into develop Jul 15, 2025
3 checks passed
@young-jin-son young-jin-son deleted the feat/#292 branch July 15, 2025 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FE 프론트엔드 작업 feat 새로운 기능 구현

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 회원탈퇴 기능 추가

2 participants