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

Fix: rendering error #141

Merged
merged 9 commits into from
Oct 16, 2024
12 changes: 7 additions & 5 deletions src/api/axios.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios, { AxiosError, AxiosRequestConfig } from 'axios';
import { getToken, removeToken, setToken } from '@/utils/tokenUtils';
import axios, { AxiosError, AxiosRequestConfig } from 'axios';

import { refreshToken } from '@/components/login/queries';
import { toast } from 'sonner';
Expand Down Expand Up @@ -66,25 +66,27 @@ export const createClient = (config?: AxiosRequestConfig) => {
try {
await refreshToken();
const newAccessToken = getToken();

if (!newAccessToken) {
throw new Error('๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
}

originalRequest.headers = originalRequest.headers || {};
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
setToken(newAccessToken);

return await axiosInstance(originalRequest);
} catch (refreshError) {
handleTokenError('๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.');
return Promise.reject(refreshError);
}
} else {
removeToken();
Copy link
Contributor

Choose a reason for hiding this comment

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

logout ์˜ค๋ฅ˜ ์ˆ˜์ •ํ•œ๊ฑฐ ์ถ”ํ›„์— ๊ธฐ๋Šฅ์˜ค๋ฅ˜์ƒ๊ธฐ๋ฉด ๋ณด๊ฐ•ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค... ๊ณ ์ƒํ•˜์…จ์Šต๋‹ˆ๋‹ค๐Ÿ‘

}
}

return Promise.reject(error);
},
}
);

return axiosInstance;
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/CustomCarousel.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ReactNode } from 'react';
import { Carousel, CarouselContent, CarouselNext, CarouselPrevious } from '../ui/carousel';

import { ReactNode } from 'react';

const CustomCarousel = ({ contentStyle, length, children }: { contentStyle?: string; length: number; children: ReactNode }) => {
return (
<Carousel
opts={{
align: 'start',
dragFree: true,
watchDrag: false,
loop: true,
}}
className='w-full overflow-scroll'
>
Expand Down
15 changes: 8 additions & 7 deletions src/components/common/boundary/APIAsyncBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ReactNode, Suspense } from 'react';
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';

import ErrorIcon from '@/assets/icons/error.svg';
import { useQueryErrorResetBoundary } from '@tanstack/react-query';
import { QueryErrorResetBoundary } from '@tanstack/react-query';
import { isAxiosError } from 'axios';
import { useLocation } from 'react-router-dom';
import Button from '../Button';
Expand All @@ -29,14 +29,15 @@ const FallbackComponent = ({ error, resetErrorBoundary }: FallbackProps) => {

const APIAsyncBoundary = ({ children }: { children: ReactNode }) => {
const { pathname, key } = useLocation();
const { reset } = useQueryErrorResetBoundary()

return (
<ErrorBoundary onReset={reset} FallbackComponent={FallbackComponent} resetKeys={[pathname, key]}>
<Suspense fallback={<GlobalSpinner />}>
{children}
</Suspense>
</ErrorBoundary>
<QueryErrorResetBoundary>
{({ reset }) => (<ErrorBoundary onReset={reset} FallbackComponent={FallbackComponent} resetKeys={[pathname, key]}>
<Suspense fallback={<GlobalSpinner />}>
{children}
</Suspense>
</ErrorBoundary>)}
</QueryErrorResetBoundary>
);
};

Expand Down
17 changes: 9 additions & 8 deletions src/components/common/boundary/LocalAPIAsyncBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { ReactNode, Suspense } from 'react';
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';

import ErrorIcon from '@/assets/icons/error.svg';
import { useQueryErrorResetBoundary } from '@tanstack/react-query';
import { QueryErrorResetBoundary } from '@tanstack/react-query';
import { isAxiosError } from 'axios';
import Button from '../Button';
import GlobalSpinner from '../loading/GlobalSpinner';
import LocalSpinner from '../loading/LocalSpinner';

interface FallbackComponentProps extends FallbackProps {
height: number
Expand All @@ -29,14 +29,15 @@ const FallbackComponent = ({ error, resetErrorBoundary, height }: FallbackCompon
};

const LocalAPIAsyncBoundary = ({ children, height }: { children: ReactNode, height: number }) => {
const { reset } = useQueryErrorResetBoundary()

return (
<ErrorBoundary onReset={reset} FallbackComponent={(props) => <FallbackComponent height={height} {...props} />}>
<Suspense fallback={<GlobalSpinner />}>
{children}
</Suspense>
</ErrorBoundary>
<QueryErrorResetBoundary>
{({ reset }) => (<ErrorBoundary onReset={reset} FallbackComponent={(props) => <FallbackComponent height={height} {...props} />}>
<Suspense fallback={<LocalSpinner height={height} />}>
{children}
</Suspense>
</ErrorBoundary>)}
</QueryErrorResetBoundary>
);
};

Expand Down
9 changes: 9 additions & 0 deletions src/components/common/loading/LocalSpinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const LocalSpinner = ({ height }: { height: number }) => {
return (
<div className={`flex items-center justify-center w-full h-[${height}px]`}>
<div className='border-4 border-white rounded-full size-10 border-b-cheeseYellow animate-spin' />
</div>
);
}

export default LocalSpinner;
62 changes: 33 additions & 29 deletions src/components/details/queries.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { IAuctionDetails, IPreAuctionDetails } from 'AuctionDetails';
import { API_END_POINT } from '@/constants/api';
import { UseMutateFunction, useMutation, useQuery, useQueryClient, useSuspenseQuery } from '@tanstack/react-query';
import type { IAuctionDetails, IPreAuctionDetails } from 'AuctionDetails';

import { httpClient } from '@/api/axios';
import { API_END_POINT } from '@/constants/api';
import { queryKeys } from '@/constants/queryKeys';
import {
UseMutateFunction,
useMutation,
useQueryClient,
useSuspenseQuery,
} from '@tanstack/react-query';

export const useConvertToAuction = (): {
mutate: UseMutateFunction<any, Error, number, unknown>;
Expand All @@ -16,10 +12,8 @@ export const useConvertToAuction = (): {

const { mutate } = useMutation({
mutationFn: async (productId: number) => {
const response = await httpClient.post(
`${API_END_POINT.AUCTIONS}/start`,
productId
);
const response = await httpClient.post(`${API_END_POINT.AUCTIONS}/start`, productId);

return response.data;
},
onSuccess: (_, productId) => {
Expand Down Expand Up @@ -47,9 +41,8 @@ export const useLikeAuctionItem = (): {
mutate: UseMutateFunction<any, Error, number, unknown>;
} => {
const likeAuctionItem = async (auctionId: number) => {
const response = await httpClient.post(
`${API_END_POINT.PRE_AUCTION}/${auctionId}/likes`
);
const response = await httpClient.post(`${API_END_POINT.PRE_AUCTION}/${auctionId}/likes`);

return response.data;
};

Expand All @@ -75,9 +68,8 @@ export const useCancelBid = (): {
const queryClient = useQueryClient();

const cancelBid = async (bidId: number) => {
const response = await httpClient.patch(
`${API_END_POINT.BID}/${bidId}/cancel`
);
const response = await httpClient.patch(`${API_END_POINT.BID}/${bidId}/cancel`);

return response.data;
};

Expand All @@ -98,9 +90,8 @@ export const useCancelBid = (): {

export const useGetAuctionDetails = (auctionId: number) => {
const getAuctionDetails = async (): Promise<IAuctionDetails> => {
const response = await httpClient.get(
`${API_END_POINT.AUCTIONS}/${auctionId}`
);
const response = await httpClient.get(`${API_END_POINT.AUCTIONS}/${auctionId}`);


return response.data;
};
Expand All @@ -115,13 +106,27 @@ export const useGetAuctionDetails = (auctionId: number) => {
};
};

export const useGetPreAuctionDetails = (preAuctionId: number) => {
if (!preAuctionId) return { preAuctionDetails: undefined };
export const useGetPreAuctionDetails = (preAuctionId: number | undefined) => {
const getPreAuctionDetails = async (): Promise<IPreAuctionDetails> => {
const response = await httpClient.get(`${API_END_POINT.PRE_AUCTION}/${preAuctionId}`);

return response.data;
};

const { data: preAuctionDetails } = useQuery({
queryKey: [queryKeys.PRE_AUCTION_DETAILS, preAuctionId],
queryFn: getPreAuctionDetails,
enabled: preAuctionId === undefined ? false : true,
});

return {
preAuctionDetails,
};
};

export const useGetPreAuctionDetailsWithSuspense = (preAuctionId: number) => {
const getPreAuctionDetails = async (): Promise<IPreAuctionDetails> => {
const response = await httpClient.get(
`${API_END_POINT.PRE_AUCTION}/${preAuctionId}`
);
const response = await httpClient.get(`${API_END_POINT.PRE_AUCTION}/${preAuctionId}`);

return response.data;
};
Expand All @@ -142,9 +147,8 @@ export const useDeletePreAuction = (): {
const queryClient = useQueryClient();

const deletePreAuction = async (preAuctionId: number) => {
const response = await httpClient.delete(
`${API_END_POINT.PRE_AUCTION}/${preAuctionId}`
);
const response = await httpClient.delete(`${API_END_POINT.PRE_AUCTION}/${preAuctionId}`);

return response.data;
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/home/CategoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const CategoryItem = ({ code, name, icon }: { code: string; name: string; icon:
const navigate = useNavigate();

const onClickCategory = () => {
navigate(`/product/list?category=${code}`);
navigate(`/product/list?category=${code.toLocaleLowerCase().replaceAll('_', '-')}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

๋ฆฌํŒฉํ† ๋งํ• ๋•Œ ๋Œ€๋ฌธ์ž, _ ๋“ค์–ด๊ฐ„ ๊ฒƒ๋“ค ์ˆ˜์ •ํ•ด๋†“๊ฒ ์Šต๋‹ˆ๋‹ค!

};
return (
<li className='flex flex-col items-center w-full h-full gap-3 cursor-pointer' onClick={onClickCategory}>
Expand Down
29 changes: 12 additions & 17 deletions src/components/login/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { removeToken, setToken } from '@/utils/tokenUtils';

import { API_END_POINT } from '@/constants/api';
// eslint-disable-next-line import/no-cycle
import { User } from '@/@types/user';
import type { User } from '@/@types/user';
import { httpClient } from '@/api/axios';
import { useMutation } from '@tanstack/react-query';
import { useDispatch } from 'react-redux';
import { storeLogin } from '@/store/authSlice';
import { toast } from 'sonner';
import { useDispatch } from 'react-redux';
import { useEffect } from 'react';
import { useMutation } from '@tanstack/react-query';

export const postSignup = async (data: User) => {
const response = await httpClient.post(API_END_POINT.SIGNUP, { ...data }, { withCredentials: true });
const response = await httpClient.post(API_END_POINT.SIGNUP, { ...data });

const accessToken = response.headers.authorization?.split(' ')[1];

Expand All @@ -22,23 +23,19 @@ export const postSignup = async (data: User) => {
};

export const logout = async () => {
try {
await refreshToken();
await httpClient.post(API_END_POINT.LOGOUT, { withCredentials: true });
removeToken();
} catch (error) {
throw error;
}
await refreshToken();
await httpClient.post(API_END_POINT.LOGOUT);
removeToken();
};

export const refreshToken = async () => {
try {
const response = await httpClient.post(API_END_POINT.REFRESH_TOKEN, {}, { withCredentials: true });

const response = await httpClient.post(API_END_POINT.REFRESH_TOKEN);
const newAccessToken = response.headers.authorization?.split(' ')[1];

if (newAccessToken) {
setToken(newAccessToken);
toast.success('๋กœ๊ทธ์ธ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
}

return newAccessToken;
Expand All @@ -50,7 +47,7 @@ export const refreshToken = async () => {
export const nicknameCheck = async (nickname: string) => {
const response = await httpClient.get(`${API_END_POINT.NICKNAME_CHECK}/${nickname}`);
return response.data;
}
};

export const useRefreshTokenOnSuccess = () => {
const dispatch = useDispatch();
Expand All @@ -65,9 +62,7 @@ export const useRefreshTokenOnSuccess = () => {
dispatch(storeLogin({ token: newAccessToken }));
}
},
onError: () => {

},
onError: () => {},
});

useEffect(() => {
Expand Down
25 changes: 12 additions & 13 deletions src/components/navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,26 @@ import { navIcons } from '@/constants/navIcons';
import { useNavigate } from 'react-router-dom';
import { useGetNotifications } from '../notification/queries';

interface NavigationItemProps {
name: string;
active: boolean;
path: string
unreadNotificationsCount: number;
}

const NavigationItem = ({
name,
active,
onClick,
path,
unreadNotificationsCount = 0,
}: {
name: string;
active: boolean;
onClick: () => void;
unreadNotificationsCount: number;
}) => {
}: NavigationItemProps) => {
const navigate = useNavigate();
const iconSrc = navIcons[name][active ? 'on' : 'off'];
const notificationCondition = name === 'notification' && unreadNotificationsCount > 0;

return (
<li className='flex justify-center transition-all items-center w-[11.25rem] h-[3.75rem] relative'>
<img onClick={onClick} src={iconSrc} alt={`${name}_${active ? 'on' : 'off'}_icon`} className='cursor-pointer size-6' />
<img onClick={() => navigate(path)} src={iconSrc} alt={`${name}_${active ? 'on' : 'off'}_icon`} className='cursor-pointer size-6' />
{notificationCondition && (
<div aria-label='์ฝ์ง€ ์•Š์€ ์•Œ๋ฆผ์„ ํ‘œ์‹œํ•˜๋Š” ๋นจ๊ฐ„ ์ ' className='absolute top-[25%] right-[42%] rounded-full size-1 bg-cheeseYellow' />
)}
Expand All @@ -27,9 +30,7 @@ const NavigationItem = ({
};

const Navigation = ({ active }: { active: string }) => {
const navigate = useNavigate();
const { notifications } = useGetNotifications();

const unreadNotificationsCount = notifications ? notifications.reduce(
(acc, cur) => (!cur.isRead ? acc + 1 : acc),
0,
Expand All @@ -42,9 +43,7 @@ const Navigation = ({ active }: { active: string }) => {
key={name}
name={name}
active={active === name}
onClick={() => {
navigate(value.path);
}}
path={value.path}
unreadNotificationsCount={unreadNotificationsCount}
/>
))}
Expand Down
Loading