Skip to content

Commit

Permalink
Merge pull request #778 from woowacourse-teams/FE/feature/#749
Browse files Browse the repository at this point in the history
[FE] 회원 탈퇴 API 연동
  • Loading branch information
dle234 authored Oct 16, 2024
2 parents d482ccb + 542f5ea commit 5353e89
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 21 deletions.
7 changes: 7 additions & 0 deletions frontend/src/apis/member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ export const getMember = async (): Promise<{ username: string }> => {
return response.json();
};

export const deleteMember = async () => {
await fetcher.delete({
url: `${API_URL}/member`,
errorMessage: ERROR_MESSAGES.DELETE_MEMBER,
});
};

interface GetMyPairRoomsResponse {
id: number;
status: PairRoomStatus;
Expand Down
51 changes: 51 additions & 0 deletions frontend/src/components/MyPage/ConfirmModal/ConfirmModal.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import styled, { css } from 'styled-components';

export const cancelButtonStyles = css`
font-size: ${({ theme }) => theme.fontSize.md};
`;

export const confirmButtonStyles = css`
border-color: ${({ theme }) => theme.color.black[40]};
background-color: ${({ theme }) => theme.color.black[40]};
font-size: ${({ theme }) => theme.fontSize.md};
&:hover {
border-color: ${({ theme }) => theme.color.black[50]};
background-color: ${({ theme }) => theme.color.black[50]};
}
&:active {
border-color: ${({ theme }) => theme.color.black[50]};
background-color: ${({ theme }) => theme.color.black[50]};
}
`;

export const Layout = styled.div`
display: flex;
flex-direction: column;
align-items: center;
gap: 3rem;
width: 100%;
`;

export const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
padding: 2rem 0 3.4rem;
color: ${({ theme }) => theme.color.danger[600]};
font-size: ${({ theme }) => theme.fontSize.md};
p {
color: ${({ theme }) => theme.color.black[90]};
font-size: ${({ theme }) => theme.fontSize.base};
font-weight: ${({ theme }) => theme.fontWeight.medium};
}
`;
32 changes: 32 additions & 0 deletions frontend/src/components/MyPage/ConfirmModal/ConfirmModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Button from '@/components/common/Button/Button';
import { Modal } from '@/components/common/Modal';

import * as S from './ConfirmModal.styles';

interface ConfirmModalProps {
isOpen: boolean;
onConfirm: () => void;
close: () => void;
}

const ConfirmModal = ({ isOpen, onConfirm, close }: ConfirmModalProps) => {
return (
<Modal isOpen={isOpen} close={close} size="sm">
<Modal.CloseButton close={close} />
<S.Container>
<p>정말 탈퇴하시겠습니까?</p>
해당 작업은 다시 복구할 수 없습니다.
</S.Container>
<Modal.Footer position="CENTER">
<Button css={S.confirmButtonStyles} onClick={onConfirm}>
탈퇴
</Button>
<Button css={S.cancelButtonStyles} onClick={close}>
취소
</Button>
</Modal.Footer>
</Modal>
);
};

export default ConfirmModal;
1 change: 1 addition & 0 deletions frontend/src/components/common/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const Button = ({
}: React.PropsWithChildren<ButtonProp>) => {
return (
<S.Button
type="button"
$size={size}
$filled={filled}
$rounded={rounded}
Expand Down
35 changes: 18 additions & 17 deletions frontend/src/constants/message.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
export const ERROR_MESSAGES = {
GET_REFERENCE_LINKS: '레퍼런스 링크를 불러오지 못했습니다.',
ADD_REFERENCE_LINKS: '레퍼런스 링크를 저장하지 못했습니다.',
DELETE_REFERENCE_LINKS: '레퍼런스 링크 삭제에 실패했습니다.',
GET_PAIR_ROOM: '페어룸 정보를 불러오지 못했습니다.',
DELETE_PAIR_ROOM: '페어룸 삭제에 실패했습니다.',
ADD_PAIR_NAMES: '페어룸 생성에 실패했습니다.',
GET_TODOS: '투두 리스트를 불러오지 못했습니다.',
ADD_TODO: '투두 아이템을 저장하지 못했습니다.',
UPDATE_TODO: '투두 아이템을 수정하지 못했습니다.',
DELETE_TODO: '투두 아이템을 삭제하지 못했습니다.',
GET_CATEGORIES: '카테고리 정보를 가져오지 못했어요 🥲',
ADD_CATEGORY: '카테고리를 추가하지 못했어요 🥲',
SIGN_IN: '로그인에 실패했습니다.',
SIGN_UP: '회원가입에 실패했습니다.',
SIGN_OUT: '로그아웃에 실패했습니다.',
CHECK_USER_LOGIN: '유저 로그인 여부를 확인하지 못했습니다.',
GET_MEMBER: '유저 정보를 가져오지 못했습니다.',
GET_REFERENCE_LINKS: '레퍼런스 링크를 불러오지 못했습니다. 다시 시도해 주세요.',
ADD_REFERENCE_LINKS: '레퍼런스 링크를 저장하지 못했습니다. 다시 시도해 주세요.',
DELETE_REFERENCE_LINKS: '레퍼런스 링크 삭제에 실패했습니다. 다시 시도해 주세요.',
GET_PAIR_ROOM: '페어룸 정보를 불러오지 못했습니다. 다시 시도해 주세요.',
DELETE_PAIR_ROOM: '페어룸 삭제에 실패했습니다. 다시 시도해 주세요.',
ADD_PAIR_NAMES: '페어룸 생성에 실패했습니다. 다시 시도해 주세요.',
GET_TODOS: '투두 리스트를 불러오지 못했습니다. 다시 시도해 주세요.',
ADD_TODO: '투두 아이템을 저장하지 못했습니다. 다시 시도해 주세요.',
UPDATE_TODO: '투두 아이템을 수정하지 못했습니다. 다시 시도해 주세요.',
DELETE_TODO: '투두 아이템을 삭제하지 못했습니다. 다시 시도해 주세요.',
GET_CATEGORIES: '카테고리 정보를 가져오지 못했습니다. 다시 시도해 주세요.',
ADD_CATEGORY: '카테고리를 추가하지 못했습니다. 다시 시도해 주세요.',
SIGN_IN: '로그인에 실패했습니다. 다시 시도해 주세요.',
SIGN_UP: '회원가입에 실패했습니다. 다시 시도해 주세요.',
SIGN_OUT: '로그아웃에 실패했습니다. 다시 시도해 주세요.',
CHECK_USER_LOGIN: '로그인 여부를 확인하지 못했습니다. 다시 시도해 주세요.',
GET_MEMBER: '회원 정보를 가져오지 못했습니다. 다시 시도해 주세요.',
DELETE_MEMBER: '회원 탈퇴에 실패했습니다. 다시 시도해 주세요.',
};
10 changes: 9 additions & 1 deletion frontend/src/pages/MyPage/MyPage.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { IoIosArrowForward } from 'react-icons/io';

import Spinner from '@/components/common/Spinner/Spinner';
import ConfirmModal from '@/components/MyPage/ConfirmModal/ConfirmModal';
import PairRoomButton from '@/components/MyPage/PairRoomButton/PairRoomButton';

import useUserStore from '@/stores/userStore';

import useModal from '@/hooks/common/useModal';

import useDeleteMember from '@/queries/MyPage/useDeleteMember';
import useMyPairRooms from '@/queries/MyPage/useMyPairRooms';

import * as S from './MyPage.styles';

const MyPage = () => {
const { username } = useUserStore();

const { isModalOpen, openModal, closeModal } = useModal();

const { data: pairRooms, isFetching } = useMyPairRooms();
const { handleDeleteMember } = useDeleteMember();

return (
<S.Layout>
Expand Down Expand Up @@ -46,11 +53,12 @@ const MyPage = () => {
</S.List>
</div>
</S.ListWrapper>
<S.LeaveButton>
<S.LeaveButton onClick={openModal}>
회원 탈퇴하기
<IoIosArrowForward size="1.5rem" />
</S.LeaveButton>
</S.Container>
<ConfirmModal isOpen={isModalOpen} close={closeModal} onConfirm={handleDeleteMember} />
</S.Layout>
);
};
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/queries/MyPage/useDeleteMember.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useNavigate } from 'react-router-dom';

import { useMutation } from '@tanstack/react-query';

import useToastStore from '@/stores/toastStore';
import useUserStore from '@/stores/userStore';

import { deleteMember } from '@/apis/member';

const useDeleteMember = () => {
const navigate = useNavigate();

const { resetUser } = useUserStore();
const { addToast } = useToastStore();

const { mutate: handleDeleteMember, isSuccess } = useMutation({
mutationFn: deleteMember,
onSuccess: () => {
resetUser();
addToast({ status: 'SUCCESS', message: '지금까지 코딩해듀오와 함께 해 주셔서 감사해요. 다음에 또 만나요 👋🏻' });
navigate('/', { replace: true });
},
onError: (error) => addToast({ status: 'ERROR', message: error.message }),
});

return { handleDeleteMember, isSuccess };
};

export default useDeleteMember;
6 changes: 3 additions & 3 deletions frontend/src/stores/userStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ interface UserStore {
username: string;
userStatus: UserStatus;
setUser: (username: string, userStatus: UserStatus) => void;
resetUser: () => void;
}

const useUserStore = create<UserStore>((set) => ({
username: '',
userStatus: 'SIGNED_OUT',
setUser: (username, userStatus) => {
set(() => ({ username, userStatus }));
},
setUser: (username, userStatus) => set(() => ({ username, userStatus })),
resetUser: () => set(() => ({ username: '', userStatus: 'SIGNED_OUT' })),
}));

export default useUserStore;

0 comments on commit 5353e89

Please sign in to comment.