Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: #230 유저 프로필 이미지 삭제 기능 구현 #272

Merged
merged 7 commits into from
Dec 4, 2024
15 changes: 10 additions & 5 deletions src/components/user/auth-form/ProfileImageContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { USER_SETTINGS } from '@constants/settings';
import { JPG, PNG, SVG, WEBP } from '@constants/mimeFileType';
import useAxios from '@hooks/useAxios';
import useToast from '@hooks/useToast';
import { useUploadProfileImage } from '@hooks/query/useUserQuery';
import { useDeleteProfileImage, useUploadProfileImage } from '@hooks/query/useUserQuery';
import useStore from '@stores/useStore';
import { getProfileImage } from '@services/userService';

Expand All @@ -17,8 +17,9 @@ type ProfileImageContainerProps = {

export default function ProfileImageContainer({ imageUrl, setImageUrl }: ProfileImageContainerProps) {
const { toastWarn } = useToast();
const { editUserInfo, userInfo } = useStore();
const { userInfo } = useStore();
const { mutate: uploadImageMutate } = useUploadProfileImage();
const { mutateAsync: deleteImageMutate } = useDeleteProfileImage();
Yoonyesol marked this conversation as resolved.
Show resolved Hide resolved
const { fetchData } = useAxios(getProfileImage);
const { toastError } = useToast();

Expand Down Expand Up @@ -63,9 +64,13 @@ export default function ProfileImageContainer({ imageUrl, setImageUrl }: Profile
uploadImageMutate({ file });
};

const handleRemoveImg = () => {
setImageUrl('');
editUserInfo({ profileImageName: null });
const handleRemoveImg = async () => {
try {
await deleteImageMutate();
setImageUrl('');
} catch (error) {
console.error('이미지 삭제 중 에러 발생:', error);
}
Yoonyesol marked this conversation as resolved.
Show resolved Hide resolved
};

return (
Expand Down
24 changes: 23 additions & 1 deletion src/hooks/query/useUserQuery.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import useToast from '@hooks/useToast';
import { updateLinks, updateUserInfo, uploadProfileImage } from '@services/userService';
import { deleteProfileImage, updateLinks, updateUserInfo, uploadProfileImage } from '@services/userService';
import useStore from '@stores/useStore';
import { generateLinksQueryKey, generateProfileFileQueryKey, generateUserInfoQueryKey } from '@utils/queryKeyGenerator';
import type { EditUserInfoRequest, EditUserLinksForm } from '@/types/UserType';
Expand Down Expand Up @@ -48,6 +48,28 @@ export function useUploadProfileImage() {
return mutation;
}

export function useDeleteProfileImage() {
const queryClient = useQueryClient();
const { toastSuccess, toastError } = useToast();
const { userInfo, editUserInfo } = useStore();
const userProfileImageQueryKey = generateProfileFileQueryKey(userInfo.userId);

const mutation = useMutation({
mutationFn: () => deleteProfileImage(),
onError: () => toastError('이미지 삭제에 실패했습니다. 다시 시도해 주세요.'),
onSuccess: () => {
toastSuccess('이미지가 삭제되었습니다.');
editUserInfo({ profileImageName: null });
queryClient.invalidateQueries({ queryKey: userProfileImageQueryKey });
},
});

return {
...mutation,
mutateAsync: mutation.mutateAsync,
};
}

export function useUpdateLinks() {
const { userInfo } = useStore();
const queryClient = useQueryClient();
Expand Down
27 changes: 27 additions & 0 deletions src/mocks/services/userServiceHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,33 @@ const userServiceHandler = [
},
});
}),
// 유저 프로필 이미지 삭제 API
http.delete(`${BASE_URL}/user/profile/image`, async ({ request }) => {
const accessToken = request.headers.get('Authorization');
if (!accessToken) return new HttpResponse(null, { status: 401 });

const userId = convertTokenToUserId(accessToken);
if (!userId) {
return HttpResponse.json({ message: '토큰에 유저 정보가 존재하지 않습니다.' }, { status: 401 });
}

const userIndex = USER_DUMMY.findIndex((user) => user.userId === userId);
if (userIndex === -1) {
return HttpResponse.json(
{ message: '해당 사용자를 찾을 수 없습니다. 입력 정보를 확인해 주세요.' },
{ status: 401 },
);
}

const fileIndex = PROFILE_IMAGE_DUMMY.findIndex((file) => file.userId === userId);
if (fileIndex === -1) {
return HttpResponse.json({ message: '삭제할 프로필 이미지가 없습니다.' }, { status: 404 });
}

PROFILE_IMAGE_DUMMY.splice(fileIndex, 1);

return new HttpResponse(null, { status: 204 });
}),
Yoonyesol marked this conversation as resolved.
Show resolved Hide resolved
// 전체 팀 목록 조회 API (가입한 팀, 대기중인 팀)
http.get(`${BASE_URL}/user/team`, ({ request }) => {
const accessToken = request.headers.get('Authorization');
Expand Down
12 changes: 12 additions & 0 deletions src/services/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ export async function getProfileImage(fileName: string, axiosConfig: AxiosReques
});
}

/**
* 유저 프로필 이미지 삭제 API
*
* @export
* @async
* @param {AxiosRequestConfig} [axiosConfig={}] - axios 요청 옵션 설정 객체
* @returns {Promise<AxiosResponse<void>>}
*/
export async function deleteProfileImage(axiosConfig: AxiosRequestConfig = {}) {
return authAxios.delete('/user/profile/image', axiosConfig);
}

/**
* 유저 목록을 검색하는 API
*
Expand Down