Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/common/apis/usePatchFCMToken.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMutation } from '@tanstack/react-query';

import client from '@/common/utils/client';
import { useHandleError } from '@/common/hooks/useHandleError';

const patchFCMToken = async (token: string) => {
const response = await client.patch('/api/v1/user/fcm-token', token, {
Expand All @@ -12,7 +13,9 @@ const patchFCMToken = async (token: string) => {
};

export const usePatchFCMToken = () => {
const handleError = useHandleError();
return useMutation({
mutationFn: patchFCMToken,
onError: error => handleError(error, '푸시 알림 설정에 실패했어요'),
});
};
17 changes: 17 additions & 0 deletions src/common/hooks/useHandleError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useToast } from '@/common/hooks/useToast';
import type { ErrorResponse } from '@/libs/types';
import { isAxiosError } from 'axios';

export const useHandleError = () => {
const { openToast } = useToast();

const handleError = (error: Error, customMessage?: string) => {
if (isAxiosError<ErrorResponse>(error)) {
openToast({
message: error.response?.data.message || customMessage || '알 수 없는 오류가 발생했습니다',
});
}
};
Comment thread
halionaz marked this conversation as resolved.

return handleError;
};
7 changes: 3 additions & 4 deletions src/features/chatList/api/usePatchExit.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useHandleError } from '@/common/hooks/useHandleError';
import { useToast } from '@/common/hooks/useToast';
import client from '@/common/utils/client';
import { QUERY_KEYS } from '@/libs/queryKeys';
Expand All @@ -18,6 +19,7 @@ const patchExit = async (chatRoomId: number) => {

export const usePatchExit = () => {
const queryClient = useQueryClient();
const handleError = useHandleError();
const { openToast } = useToast();

return useMutation<ExitResponse, AxiosError<ExitResponse>, number, unknown>({
Expand All @@ -27,9 +29,6 @@ export const usePatchExit = () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.CHAT_LIST] });
openToast({ message: '채팅방에서 퇴장했어요' });
},
onError: () => {
openToast({ message: '퇴장에 실패했어요. 다시 시도해주세요!' });
// console.error('퇴장 실패', error);
},
onError: error => handleError(error, '퇴장에 실패했어요. 다시 시도해주세요!'),
});
};
3 changes: 3 additions & 0 deletions src/features/detail/apis/useDeleteItem.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useHandleError } from '@/common/hooks/useHandleError';
import client from '@/common/utils/client';
import { QUERY_KEYS } from '@/libs/queryKeys';
import { useMutation, useQueryClient } from '@tanstack/react-query';
Expand All @@ -9,11 +10,13 @@ const deleteItem = async (itemId: number) => {

export const useDeleteItem = () => {
const queryClient = useQueryClient();
const handleError = useHandleError();

return useMutation({
mutationFn: deleteItem,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.ITEM_LIST] });
},
onError: error => handleError(error, '제품 삭제에 실패했어요'),
});
};
8 changes: 3 additions & 5 deletions src/features/myEdit/apis/usePutUser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { s3PutImageToUrl } from '@/common/apis/s3PutImageToUrl';
import { useToast } from '@/common/hooks/useToast';
import { useHandleError } from '@/common/hooks/useHandleError';
import client from '@/common/utils/client';
import { QUERY_KEYS } from '@/libs/queryKeys';
import type { Gender, UserInterface } from '@/libs/types/user';
Expand Down Expand Up @@ -32,15 +32,13 @@ const putUser = async ({ userData, fileData }: { userData: UserPayload; fileData

export const usePutUser = () => {
const queryClient = useQueryClient();
const { openToast } = useToast();
const handleError = useHandleError();

return useMutation({
mutationFn: putUser,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.USER] });
},
onError: () => {
openToast({ message: '유저 정보 수정에 실패했어요. 다시 시도해주세요!' });
},
onError: error => handleError(error, '유저 정보 수정에 실패했어요. 다시 시도해주세요!'),
});
};
19 changes: 19 additions & 0 deletions src/features/pick/apis/useGetSaleAvailability.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import client from '@/common/utils/client';
import { QUERY_KEYS } from '@/libs/queryKeys';
import { useQuery } from '@tanstack/react-query';

interface GetSaleAvailabilityResponse {
message: string;
data: string;
}
const getSaleAvailability = async (itemId: number) => {
const response = await client.get<GetSaleAvailabilityResponse>(`/api/v1/item/${itemId}/sale-availability`);
return response.data.data;
};

export const useGetSaleAvailability = (itemId: number) => {
return useQuery({
queryKey: [QUERY_KEYS.SALE_AVAILABILITY, itemId],
queryFn: () => getSaleAvailability(itemId),
});
};
5 changes: 4 additions & 1 deletion src/features/pick/apis/usePatchAppointment.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useHandleError } from '@/common/hooks/useHandleError';
import client from '@/common/utils/client';
import { QUERY_KEYS } from '@/libs/queryKeys';
import type { TradeMethods } from '@/libs/types/item';
Expand All @@ -14,18 +15,20 @@ interface PatchAppointmentRequest {
tradeMethod: TradeMethods;
}

// TODO: url 수정!!!!
const patchAppointment = async (data: PatchAppointmentRequest) => {
const response = await client.patch('/api/v1/appointment', data);
return response.data.data;
};

export const usePatchAppointment = () => {
const queryClient = useQueryClient();
const handleError = useHandleError();

return useMutation({
mutationFn: patchAppointment,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.PICK_DETAIL] });
},
onError: error => handleError(error, 'PICK 수정에 실패했어요'),
});
};
4 changes: 4 additions & 0 deletions src/features/pick/apis/usePatchCancelPick.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useHandleError } from '@/common/hooks/useHandleError';
import client from '@/common/utils/client';
import { QUERY_KEYS } from '@/libs/queryKeys';
import { useMutation, useQueryClient } from '@tanstack/react-query';
Expand All @@ -8,11 +9,14 @@ const patchCancelPick = async (id: number) => {
};
export const usePatchCancelPick = () => {
const queryClient = useQueryClient();
const handleError = useHandleError();

return useMutation({
mutationFn: patchCancelPick,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.PICK_DETAIL] });
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.ITEM_STATUS] });
},
onError: error => handleError(error, 'PICK 취소에 실패했어요'),
});
};
4 changes: 4 additions & 0 deletions src/features/pick/apis/usePatchConfirmPick.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useHandleError } from '@/common/hooks/useHandleError';
import client from '@/common/utils/client';
import { QUERY_KEYS } from '@/libs/queryKeys';
import { useMutation, useQueryClient } from '@tanstack/react-query';
Expand All @@ -9,11 +10,14 @@ const patchConfirmPick = async (id: number) => {

export const usePatchConfirmPick = () => {
const queryClient = useQueryClient();
const handleError = useHandleError();

return useMutation({
mutationFn: patchConfirmPick,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.PICK_DETAIL] });
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.ITEM_STATUS] });
},
onError: error => handleError(error, 'PICK 확정에 실패했어요'),
});
};
4 changes: 4 additions & 0 deletions src/features/pick/apis/usePostRentalAppointment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useMutation } from '@tanstack/react-query';
import client from '@/common/utils/client';
import type { PostAppointmentResponse } from '@/features/pick/apis/usePostSaleAppointment';
import type { TradeMethods } from '@/libs/types/item';
import { useHandleError } from '@/common/hooks/useHandleError';

interface PostRentalAppointmentRequest {
itemId: number;
Expand All @@ -18,7 +19,10 @@ const postRentalAppointment = async (data: PostRentalAppointmentRequest) => {
return response.data.data;
};
export const usePostRentalAppointment = () => {
const handleError = useHandleError();

return useMutation({
mutationFn: postRentalAppointment,
onError: error => handleError(error, 'PICK 생성에 실패했어요'),
});
};
4 changes: 4 additions & 0 deletions src/features/pick/apis/usePostSaleAppointment.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useHandleError } from '@/common/hooks/useHandleError';
import client from '@/common/utils/client';
import type { TradeMethods, TransactionType } from '@/libs/types/item';
import { useMutation } from '@tanstack/react-query';
Expand Down Expand Up @@ -38,7 +39,10 @@ const postSaleAppointment = async (data: PostSaleAppointmentRequest) => {
};

export const usePostSaleAppointment = () => {
const handleError = useHandleError();

return useMutation({
mutationFn: postSaleAppointment,
onError: error => handleError(error, 'PICK 생성에 실패했어요'),
});
};
20 changes: 16 additions & 4 deletions src/features/pick/components/DateDrawer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import DatePicker, { type Value } from '@/common/components/DatePicker';

import * as s from './style.css.ts';
import { formatDate } from 'date-fns';
import { formatDate, isBefore } from 'date-fns';
import { useGetRentalAvailability } from '@/features/pick/apis/useGetRentalAvailability.ts';
import { useState } from 'react';
import type { TileDisabledFunc } from 'react-calendar';
import { useGetSaleAvailability } from '@/features/pick/apis/useGetSaleAvailability.ts';

interface Props {
itemId: number;
Expand All @@ -18,7 +19,12 @@ interface Props {
const DateDrawer = ({ itemId, dateTime, setDateTime, transactionText, next, minDate = new Date(), maxDate }: Props) => {
const [year, setYear] = useState(new Date().getFullYear());
const [month, setMonth] = useState(new Date().getMonth() + 1);
const { data: rentalAvailability } = useGetRentalAvailability({ itemId, year, month });
const { data: rentalAvailability, isSuccess: isRentalAvailabilitySuccess } = useGetRentalAvailability({
itemId,
year,
month,
});
const { data: saleAvailability } = useGetSaleAvailability(itemId);
const value = dateTime as Value;
const setValue = (value: Value) => {
if (Array.isArray(value)) return;
Expand All @@ -28,18 +34,24 @@ const DateDrawer = ({ itemId, dateTime, setDateTime, transactionText, next, minD
const reset = () => setDateTime(null);

const tileDisabled: TileDisabledFunc = ({ date }) => {
if (rentalAvailability === undefined) return true;
if (rentalAvailability === undefined) {
if (isRentalAvailabilitySuccess) return true;
return false;
}

const canRental = !!rentalAvailability[formatDate(date, 'yyyy-MM-dd')];
return !canRental;
};

const saleAvailabilityDate = saleAvailability ? new Date(saleAvailability) : new Date();

return (
<div className={s.Container}>
<div className={s.DateWrapper}>
<DatePicker
value={value}
setValue={setValue}
minDate={minDate}
minDate={isBefore(saleAvailabilityDate, minDate) ? minDate : saleAvailabilityDate}
maxDate={maxDate}
tileDisabled={tileDisabled}
checkMonthYear={(month, year) => {
Expand Down
9 changes: 7 additions & 2 deletions src/features/post/apis/usePostItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { PostItemRequest, PostPayload } from '../types/post';
import type { ItemDetailResponse } from '@/features/detail/types';
import { useMutation } from '@tanstack/react-query';
import { s3PutImageToUrl } from '@/common/apis/s3PutImageToUrl';
import { useHandleError } from '@/common/hooks/useHandleError';

const postItem = async ({
data,
Expand All @@ -23,8 +24,12 @@ const postItem = async ({
return res.data;
};

export const usePostItem = () =>
useMutation({
export const usePostItem = () => {
const handleError = useHandleError();

return useMutation({
mutationFn: postItem,
retry: 0,
onError: error => handleError(error, '제품 등록에 실패했어요'),
});
};
9 changes: 7 additions & 2 deletions src/features/post/apis/usePutItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { PostItemRequest, PostPayload } from '../types/post';
import type { ItemDetailResponse } from '@/features/detail/types';
import { useMutation } from '@tanstack/react-query';
import { s3PutImageToUrl } from '@/common/apis/s3PutImageToUrl';
import { useHandleError } from '@/common/hooks/useHandleError';

const putItem = async ({
data,
Expand All @@ -29,8 +30,12 @@ const putItem = async ({
return res.data;
};

export const usePutItem = () =>
useMutation({
export const usePutItem = () => {
const handleError = useHandleError();

return useMutation({
mutationFn: putItem,
retry: 0,
onError: error => handleError(error, '제품 수정에 실패했어요'),
});
};
6 changes: 4 additions & 2 deletions src/features/report/apis/usePostReport.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useHandleError } from '@/common/hooks/useHandleError';
import client from '@/common/utils/client';
import { useMutation } from '@tanstack/react-query';

Expand All @@ -13,15 +14,16 @@ interface PostInterface {
}

const postReport = async ({ body }: { body: PostInterface }) => {
console.log(body);

const res = await client.post('api/v1/user/report', body);

return res.data;
};

export const usePostReport = () => {
const handleError = useHandleError();

return useMutation({
mutationFn: postReport,
onError: error => handleError(error, '신고에 실패했어요'),
});
};
9 changes: 7 additions & 2 deletions src/features/review/apis/usePostReview.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import client from '@/common/utils/client';
import { useMutation } from '@tanstack/react-query';
import type { ReviewRequest } from '../types/review';
import { useHandleError } from '@/common/hooks/useHandleError';

const postReview = async (data: ReviewRequest) => {
const res = await client.post('api/v1/review', data);

return res.data;
};

export const usePostReview = () =>
useMutation({
export const usePostReview = () => {
const handleError = useHandleError();

return useMutation({
mutationFn: postReview,
retry: 0,
onError: error => handleError(error, '리뷰 작성에 실패했어요'),
});
};
1 change: 1 addition & 0 deletions src/libs/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export const QUERY_KEYS = {
PICK_DETAIL: 'pick', // 특정 id에 해당하는 약속 상세
APPOINTMENT_LIST: 'pick-list', // 나의 픽 페이지 리스트
RENTAL_AVAILABILITY: 'rental-availability', // 특정 아이템에 대한 렌탈 가능 여부
SALE_AVAILABILITY: 'sale-availability', // 특정 아이템에 대한 판매 가능 여부
};
4 changes: 4 additions & 0 deletions src/libs/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ErrorResponse {
code: string;
message: string;
}