Skip to content

Commit 5dd2f50

Browse files
์ด์ •์›์ด์ •์›
authored andcommitted
chore: dev์™€ merge
2 parents e32b9fb + db19331 commit 5dd2f50

17 files changed

Lines changed: 259 additions & 25 deletions

File tree

โ€Žsrc/App.tsxโ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const queryClient = new QueryClient({
1010
refetchOnReconnect: true, // ๋„คํŠธ์›Œํฌ ์žฌ์—ฐ๊ฒฐ ์‹œ ๋ฐ์ดํ„ฐ ์š”์ฒญ ์—ฌ๋ถ€
1111
refetchOnWindowFocus: true, // ๋ธŒ๋ผ์šฐ์ € ํฌ์ปค์Šค ์‹œ ๋ฐ์ดํ„ฐ ์š”์ฒญ ์—ฌ๋ถ€
1212
staleTime: 1000 * 10, // 10์ดˆ ๋™์•ˆ ๋ฐ์ดํ„ฐ ์‚ด์•„์žˆ์‚ผ
13-
throwOnError: true, // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์˜ˆ์™ธ ๋˜์ง€๊ธฐ ์—ฌ๋ถ€
13+
throwOnError: false, // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์˜ˆ์™ธ ๋˜์ง€๊ธฐ ์—ฌ๋ถ€
1414
},
1515
},
1616
});

โ€Žsrc/assets/icons/Arrow.tsxโ€Ž

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const Arrow = () => {
2+
return (
3+
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="13" viewBox="0 0 12 13" fill="none">
4+
<path
5+
d="M10.0152 4.24986C9.89675 4.13147 9.73615 4.06496 9.5687 4.06496C9.40125 4.06496 9.24065 4.13147 9.12222 4.24986L5.99626 7.37582L2.8703 4.24986C2.75119 4.13482 2.59167 4.07117 2.42609 4.07261C2.26051 4.07405 2.10212 4.14046 1.98504 4.25755C1.86795 4.37464 1.80154 4.53303 1.8001 4.69861C1.79866 4.86419 1.86231 5.02371 1.97734 5.14281L5.54978 8.71525C5.66821 8.83364 5.82881 8.90015 5.99626 8.90015C6.16371 8.90015 6.32431 8.83364 6.44274 8.71525L10.0152 5.14281C10.1336 5.02438 10.2001 4.86379 10.2001 4.69633C10.2001 4.52888 10.1336 4.36828 10.0152 4.24986Z"
6+
fill="currentColor"
7+
/>
8+
</svg>
9+
);
10+
};
11+
export default Arrow;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { PropsWithChildren } from 'react';
2+
import * as s from './style.css';
3+
4+
interface Props extends PropsWithChildren {
5+
color?: 'gray' | 'main';
6+
onClick?: () => void;
7+
}
8+
const Chip = ({ children, color = 'gray', onClick }: Props) => {
9+
return (
10+
<div className={s.Container({ color })} onClick={onClick}>
11+
{children}
12+
</div>
13+
);
14+
};
15+
export default Chip;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { cva } from '@styled-system/css';
2+
3+
export const Container = cva({
4+
base: {
5+
padding: '0.5rem 0.75rem',
6+
display: 'flex',
7+
alignItems: 'center',
8+
justifyContent: 'center',
9+
gap: '0.25rem',
10+
rounded: 'full',
11+
width: 'fit-content',
12+
fontSize: '0.875rem',
13+
fontWeight: 400,
14+
cursor: 'pointer',
15+
},
16+
variants: {
17+
color: {
18+
main: {
19+
backgroundColor: 'main-26',
20+
border: '1px solid',
21+
borderColor: 'main-54',
22+
color: '100',
23+
},
24+
gray: {
25+
backgroundColor: 'systemGray5',
26+
color: '80',
27+
},
28+
},
29+
},
30+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { PropsWithChildren } from 'react';
2+
3+
import * as s from './style.css';
4+
import Arrow from '@/assets/icons/Arrow';
5+
6+
interface Props extends PropsWithChildren {
7+
active: boolean;
8+
onClick?: () => void;
9+
}
10+
11+
const SelectButton = ({ children, active, onClick }: Props) => {
12+
// TODO: ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐ”๋€Œ๊ฒŒ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€
13+
return (
14+
<button className={s.Container({ color: active ? 'main' : 'gray' })} onClick={onClick}>
15+
{children}
16+
<div className={s.Icon({ direction: active ? 'up' : 'down' })}>
17+
<Arrow />
18+
</div>
19+
</button>
20+
);
21+
};
22+
export default SelectButton;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { cva } from '@styled-system/css';
2+
3+
export const Container = cva({
4+
base: {
5+
borderRadius: 'full',
6+
padding: '0.375rem 0.375rem 0.375rem 0.625rem',
7+
display: 'flex',
8+
alignItems: 'center',
9+
justifyContent: 'center',
10+
gap: '0.25rem',
11+
fontSize: '0.75rem',
12+
fontWeight: 500,
13+
cursor: 'pointer',
14+
color: '100',
15+
},
16+
variants: {
17+
color: {
18+
main: {
19+
border: '1px solid',
20+
borderColor: 'main-54',
21+
bgColor: 'main-26',
22+
},
23+
gray: {
24+
bgColor: 'systemGray5',
25+
},
26+
},
27+
},
28+
});
29+
30+
export const Icon = cva({
31+
base: {
32+
color: '54',
33+
},
34+
variants: {
35+
direction: {
36+
up: {
37+
transform: 'rotate(180deg)',
38+
},
39+
down: {
40+
transform: 'rotate(0deg)',
41+
},
42+
},
43+
},
44+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import useGetIsLogin from '@/common/hooks/apis/useGetIsLogin';
2+
3+
import * as s from './style.css';
4+
5+
const TestAPIButton = () => {
6+
const { refetch } = useGetIsLogin();
7+
return (
8+
<button className={s.Button} onClick={() => refetch()}>
9+
API ํ…Œ์ŠคํŒ…ํ•˜๊ธฐ
10+
</button>
11+
);
12+
};
13+
export default TestAPIButton;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { css } from '@styled-system/css';
2+
3+
export const Button = css({
4+
padding: '10px 24px',
5+
background: 'linear-gradient(90deg, #6a11cb 0%, #2575fc 100%)',
6+
color: 'white',
7+
border: 'none',
8+
borderRadius: '8px',
9+
fontWeight: 'bold',
10+
fontSize: '16px',
11+
cursor: 'pointer',
12+
boxShadow: '0 2px 8px rgba(106, 17, 203, 0.15)',
13+
transition: 'background 0.2s, transform 0.1s',
14+
_hover: {
15+
background: 'linear-gradient(90deg, #2575fc 0%, #6a11cb 100%)',
16+
transform: 'translateY(-2px) scale(1.03)',
17+
},
18+
_active: {
19+
background: 'linear-gradient(90deg, #6a11cb 0%, #2575fc 100%)',
20+
transform: 'scale(0.98)',
21+
},
22+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import client from '@/common/utils/client';
2+
import { useQuery } from '@tanstack/react-query';
3+
4+
const getIsLogin = async () => {
5+
try {
6+
const response = await client.get('/api/test/is-login');
7+
if (response.status === 200) {
8+
if (response.data.data) return true;
9+
}
10+
return false;
11+
} catch {
12+
return false;
13+
}
14+
};
15+
16+
const useGetIsLogin = () => {
17+
return useQuery({
18+
queryKey: ['isLogin'],
19+
queryFn: getIsLogin,
20+
});
21+
};
22+
23+
export default useGetIsLogin;

โ€Žsrc/common/utils/client.tsโ€Ž

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import axios, { AxiosError } from 'axios';
2+
3+
const client = axios.create({
4+
baseURL: import.meta.env.VITE_API_URL,
5+
headers: {
6+
'Content-Type': 'application/json',
7+
},
8+
withCredentials: true,
9+
});
10+
11+
const REFRESH_URL = '/api/v1/refresh-token';
12+
13+
// TODO: Pending Requests Queue ์ถ”๊ฐ€ ํ•„์š”
14+
// ์—ฌ๋Ÿฌ ์š”์ฒญ์ด ๋™์‹œ์— ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ๋ฌธ์ œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
15+
const responseErrorHandler = async (error: AxiosError) => {
16+
const { config, response } = error;
17+
18+
if (response?.status === 401 && config && config.url !== REFRESH_URL) {
19+
try {
20+
await client.post(REFRESH_URL);
21+
return client(config);
22+
} catch (err) {
23+
return Promise.reject(err);
24+
}
25+
}
26+
27+
return Promise.reject(error);
28+
};
29+
30+
client.interceptors.response.use(response => response, responseErrorHandler);
31+
export default client;

0 commit comments

Comments
ย (0)