-
Notifications
You must be signed in to change notification settings - Fork 0
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: login #13
feat: login #13
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ ์ง์ง ์ ๊ธฐํ์ด์ ๋ง์ด ๋ฐฐ์๊ฐ๋๋ค!!!
๋๊ฒ ์ธ์ฌํ ๋ถ๋ถ๊น์ง ๋ค ํ๋ํ๋ ์ ๊ฒฝ์จ์ฃผ์๋ค์
baseURL: process.env.NODE_ENV === 'development' ? DEV_SERVER_URL : PROD_SERVER_URL, | ||
headers: { | ||
Authorization: `Bearer ${authToken.access}`, | ||
'Content-Type': 'application/json; charset=utf-8', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ ์ด๊ฑธ ๋ค ์ ๊ฒฝ์จ์ฃผ์๋ค์ ์ ๊ฑฐ ์ฐ๋ ๊ฒ ์ฒ์๋ด์
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐๐๐
try { | ||
return (error as EffError).isEffError === true; | ||
} catch { | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error ๊ฐ null ์ด ๋ค์ด์ค๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด
return (error as EffError).isEffError===true;
์ด๋ ๊ฒ ์ ์ด๋ ์ข์ ๊ฒ ๊ฐ์์
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์กฐ๊ธ ๋ ์ค์ผ ์ ์์ ๊ฑฐ ๊ฐ์์!
return (error as EffError).isEffError;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ด๋ ๊ฒ ๋์์ ๋, isEffError ๊ฐ ์ค์ ๋์ง ์์๋ค๋ฉด undefined ๊ฐ์ ๊ฐ์ด ์ฌ ์๋ ์๊ณ , ๋ง์ฝ ๋ฐ์ดํฐ๊ฐ ์์๋ค๋ฉด, isEffError ์ ์ด์ํ ๋ฐ์ดํฐ๊ฐ ๋ด๊ฒจ์ ์ฌ ์๋ ์์ ๊ฒ ๊ฐ์์ as ๋ก ์บ์คํ
ํ ์ดํ์ ๊ฐ์ ธ์ค๋๊น์
๊ทธ๋์ ๊ฒ์ฆ ๊ณผ์ ์ผ๋ก ===true ๋ฅผ ๋ถํ๋ ์ชฝ์ด ์ข์๋ณด์ฌ์
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ํ์
๋จ์ธ ๋๋ฌธ์ด๊ตฐ์~ ํ์คํ as ์ฌ์ฉ ๋๋ฌธ์ ์ ๋งคํ ์ ์๊ฒ ๋ค์ === true
๋ก ์ฒดํฌํด์ฃผ๋๊ฒ ๋ ํ์คํ๊ฒ ๋ค์ ๐
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๋ต ์ค์ผ ์ ์๋ ๋ถ๋ถ์ ์ค์ฌ๋ณผ๊ฒ์ !
error: unknown | ||
): error is AxiosError & { response: AxiosResponse } { | ||
try { | ||
return axios.isAxiosError(error) && error.response?.data != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ฌ๊ธฐ๋ try catch ๋ฌธ์ด ์์ด๋ ๊ด์ฐฎ์ ๊ฒ ๊ฐ์์!
return axios.isAxiosError(error)&&error.response?.data!==null;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
axios ๊ฐ์ ๊ฒฝ์ฐ๋ ์๋ฌ๊ฐ ๋ฌ์ ๋ ๋ ์ด์ ๋ค์ ๋์์ด ์คํ์ด ์๋๋๊ฑธ๋ก ์๊ณ ์์ด์ ๊ผผ๊ผผํ๊ฒ try catch๋ก ์ฒ๋ฆฌํ๋ ค๊ณ ํ๋๋ฐ ์ฝ๋๊ฐ ๊ธธ์ด์ง ๊ฐ์ด ์๊ตฐ์ ์ฌ๊ธฐ๋ ์ค์ผ ์ ์๋ ๋ถ๋ถ์ ์ค์ฌ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค!
if (config?.headers == null) { | ||
throw new Error(`config.header is undefined`); | ||
} | ||
config.headers['Content-Type'] = 'application/json; charset=utf-8'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ ์ฌ๊ธฐ๋ ๋ฉ์๋ค์
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ํด ์๋๋๋ค ํํ ..
baseURL: process.env.NODE_ENV === 'development' ? DEV_SERVER_URL : PROD_SERVER_URL, | ||
headers: { | ||
Authorization: `Bearer ${authToken.access}`, | ||
'Content-Type': 'application/json; charset=utf-8', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐๐๐
try { | ||
return (error as EffError).isEffError === true; | ||
} catch { | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์กฐ๊ธ ๋ ์ค์ผ ์ ์์ ๊ฑฐ ๊ฐ์์!
return (error as EffError).isEffError;
//axios์๋ฌ๋ฅผ ์ปค์คํ ํ ์๋ฌ๋ก ๋ณํ | ||
function createEffErrorFromAxiosError(error: AxiosError): EffErrorResponse | AxiosError { | ||
if (isAxiosErrorWithResponseData(error)) { | ||
const effError = error as EffError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์๋ฌ ํ์ธํ๊ณ ์ปค์คํ
์๋ฌ ๋ง๋๋ ๋ก์ง๋ค์ ๋ฐ๋ก apis
ํด๋ ์์ utils
ํ์ผ ๊ฐ์๊ฑฐ๋ก ๋ฐ๋ก ์ ๋ฆฌํด๋ ์ข์ ๊ฑฐ ๊ฐ์์!
๋ค์ด๋ฐ์ด ๋ช ํํ ์๋์ด ์๊ณ ๋์๋ ๊ฐ๋จํด์ ๊ตณ์ด ํ๋์ฉ ์ฝ์ผ๋ฉด์ ํ์ธํ ํ์ ์์ ๊ฑฐ ๊ฐ์์.
axiosClient.interceptors.request.use( | ||
function (config) { | ||
if (config?.headers == null) { | ||
throw new Error(`config.header is undefined`); | ||
} | ||
config.headers['Content-Type'] = 'application/json; charset=utf-8'; | ||
config.headers['Authorization'] = authToken.access; | ||
|
||
export const patch = <T>(...args: Parameters<typeof axiosClient.patch>) => { | ||
return axiosClient.patch<T, T>(...args); | ||
}; | ||
return config; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isAxiosErrorWithResponseData
์ฒ๋ผ ์์ ํจ์๋ ๋ฐ๋ก ๋ถ๋ฆฌํด์ฃผ๋ฉด ์ถ์ํ ๋จ๊ณ๊ฐ ๋์ผํด์ ๋ ์ฝ๊ธฐ ์ข์ ๊ฑฐ ๊ฐ์์!
๊ทธ๋ฆฌ๊ณ axiosClient
๋ฅผ ์์ฑํ ๋ Content-Type
๊ณผ Authorization
๊ฐ์ ๋ฃ์ด์ฃผ๋๋ฐ ๋ฐ๋ก ์ธํฐ์
ํฐ๋ฅผ ํตํด ๋ฃ์ด์ฃผ๋ ์ด์ ๊ฐ ์์๊น์?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
request ์์ฒญ์ ํน์ ๋ชจ๋ฅด๊ฒ ๋ฐ์ํ ์ ์๋ auth์๋ฌ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ request์์ ํ ๋ฒ ๋ ์ฒ๋ฆฌํด์ฃผ๋ ค๊ณ ํ์ด์ !
function delay(time: number) { | ||
return new Promise(res => setTimeout(res, time)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delay
๋ ์ด๊ณณ ์ ๊ณณ์์ ์ฌ์ฉํ ์ ์์ ๊ฑฐ ๊ฐ์์ ๋ฐ๋ก utils
ํด๋๋ก ๋ถ๋ฆฌํ๋ฉด ์ข์ ๊ฑฐ ๊ฐ์์~!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๋ต axios ํ๋จ์ utils ํด๋ ํ๋ ์์ฑํด๋๊ฒ ์ต๋๋น
<Button variant="largePrimary" onClick={onClick}> | ||
ํ์ธ | ||
</Button> | ||
</> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐๐ CD๊ฐ ๋์๊ฐ๊ฒ ๊ตฐ์~~
const isDisabled = !isDirty || !isValid; | ||
|
||
const isRequiredText = useCallback( | ||
(text: string) => (text === '๋น๋ฐ๋ฒํธ' ? `${text}๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์.` : `${text}์ ์ ๋ ฅํด์ฃผ์ธ์.`), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(text: string) => `${text}๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.`
์ด๋ ๊ฒ ํํํด๋ ๊ด์ฐฎ์ง ์๋์!?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๋น๋ฐ๋ฒํธ ๊ฐ์ ๊ฒฝ์ฐ ๋ค์ ๋ฅผ์ด ๋ค์ด๊ฐ์ผํ๊ณ ์ด๋ฉ์ผ ๊ฐ์ ๊ฒฝ์ฐ๋ ์์ด ๋ค์ด๊ฐ์ผํด์ ์๋ ๊ฒ ์ฒ๋ฆฌํ์ด์ ํํ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ํ ์
,๋ฅผ
์ฐจ์ด๋ฅผ ์ ๊ฐ ๋ชป ๋ดค์๋ค์..!
const { mutate: loginMutation } = useMutation(async () => { | ||
const { email, password } = getValues(); | ||
try { | ||
const data = await postLogin(email, password); | ||
if (data) { | ||
const { accessToken, refreshToken } = data; | ||
localStorage.setItem('accessToken', accessToken); | ||
localStorage.setItem('refreshToken', refreshToken); | ||
} | ||
// ๋ก์ปฌ์คํ ๋ฆฌ์ง์ ์ ๋๋ก aT, rT ๋ค์ด๊ฐ์ผ๋ฉด ์นดํ ๊ณ ๋ฆฌ ์ ํ ํ์ด์ง๋ก ๋ผ์ฐํ | ||
} catch (error: unknown) { | ||
if (isEffError(error)) { | ||
// TODO: toast ์ถ๊ฐ | ||
console.log(error.message, error.errorCode); | ||
} | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
react-query
๊ด๋ จ ๋ถ๋ถ์ ๋ฐ๋ก hook
์ผ๋ก ๋นผ์ ์ฌ์ฉํ๋ฉด ๋ ์ข์ ๊ฑฐ ๊ฐ์์!!
์ถ๊ฐ๋ก ์๋ฌ ๊ด๋ จ ์ฒ๋ฆฌ๋ ErrorBoundary
ํ์ฉํด์ ์ ์ธ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ฉด ์ด๋จ๊น์!?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ ๋ ์ด๋ถ๋ถ์ ๋ํด์ ๊ณ ๋ฏผ์ด ๋ง์๋๋ฐ form hook์์ submit๊น์ง ํธ๋ค๋งํ๋๊ฒ useForm๋ค์ ์ญํ ์ด๋ผ๋ ์๊ฐ์ด ๋ค์ด์ ์ฌ๊ธฐ์ ๋์์ด์! ์ ๋ ๊ฐ์ธ์ ์ผ๋ก ๋ฐ๋ณตํด์ ์ฌ์ฉ๋๋ react-query hook์ด ์๋๋ผ๋ฉด ์ญํ ์ ๋ง๋ ๊ณณ์ ์์นํ๋๊ฒ ์ฝ๋๋ฅผ ๋ณด๋ ์ ์ฅ, ์์ฑํ๋ ์ ์ฅ์์๋ ํธ๋ฆฌํ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐ์ด ๋๋๋ฐ ์ด๋ป๊ฒ ์๊ฐํ์๋์?!?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
์ํ ๊ทธ๋ ๊ตฐ์..! ์ ๋ ๊ฐ์ธ์ ์ผ๋ก react-query
๋ฅผ hook
์ผ๋ก ๋ถ๋ฆฌํ๋ ๊ฒ์ด ๋ฐ๋ณต ๋ฟ๋ง ์๋๋ผ ์ฌ์ฉํ๋ ๊ณณ์์ ์ ์ธ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ด์ ์ข๋ค๊ณ ์๊ฐํ์ด์. useForm
์ ์ฌ์ฉํ ๋ login
mutation
์ ๋ํ ๊ตฌํ์ ๊ตณ์ด ์ ํ์๊ฐ ์๋ค๊ณ ์๊ฐํด์์!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
* feat: ๋ก๊ทธ์ธ, ํ์๊ฐ์ ๋ ์ด์์ ๋ฐ ๋ก๊ทธ์ธ ๋ก์ง ๊ตฌํ * feat: axios ์๋ฌ ์ปค์คํ * chore: ์ฃผ์ ์ถ๊ฐ * feat: axios request interceptors ์ถ๊ฐ
* feat: input ์ปดํฌ๋ํธ ๊ตฌํ (#2) * feat: input ์ปดํฌ๋ํธ ๊ตฌํ * fix: install pnpm * refactor: ํ์ดํฌ ํ ํฐ ์ ์ฉ * feat: modal ์ปดํฌ๋ํธ ๊ตฌํ (#4) * feat: modal ์ปดํฌ๋ํธ ์์ฑ * feat: modal ์ปดํฌ๋ํธ ๊ตฌํ * refactor: type ๋ณ๊ฒฝ ๋ฐ ๋ฆฌ๋ทฐ ๋ฐ์ * refactor: modal interface ์ ๊ฑฐ * feat: icon ์ปดํฌ๋ํธ ๊ตฌํ (#3) * feat: svg ์ ์ฅ * feat: icon ์ปดํฌ๋ํธ ๊ตฌํ * refactor: icon ๋ฐ๋ก export * refactor: span ํ๊ทธ๋ก ๋ณ๊ฒฝ * refactor: icon type * feat: button ์ปดํฌ๋ํธ ๊ตฌํ (#6) * fix: rem์ ์ํ html fontSize ์์ * refactor: text ์ปดํฌ๋ํธ type ์ ์ธ ์์น ๋ณ๊ฒฝ * style: ๋๋ฝ ๋ฐ ๋ณ๊ฒฝ๋ theme ์ถ๊ฐ * feat(button): button ์ปดํฌ๋ํธ ์ถ๊ฐ * chore(button): button ์ปดํฌ๋ํธ ์์ ์ถ๊ฐ * refactor(text): text ์ปดํฌ๋ํธ ์คํ์ผ ํ์ ๋ช ๋ณ๊ฒฝ * feat: jest, react-testing-library setting (#5) * feat: jest, react-testing-library setting * chore: paths ์์ * fix: fix conflict * feat: select ์ปดํฌ๋ํธ ๊ตฌํ (#7) * feat: mount, update ๊ด๋ จ hooks ์ถ๊ฐ * feat: void callback type ์ถ๊ฐ * feat: select ์ปดํฌ๋ํธ ์ถ๊ฐ * feat: select ์ปดํฌ๋ํธ ์์ ์ฝ๋ ์ถ๊ฐ * chore: local pnpm ํจํค์ง ์ ๊ฑฐ * style: select ์ปดํฌ๋ํธ margin top ์ถ๊ฐ * feat: header ์ปดํฌ๋ํธ ๊ตฌํ (#9) * feat: sign up ๋ ์ด์์๊ณผ ๋ก์ง ๊ตฌํ (#10) * feat: ํ์๊ฐ์ ๋ ์ด์์ ๋ฐ ๋ก์ง ์์ * feat: sign up validation check ๋ก์ง ์ถ๊ฐ * feat: signUp ์ฑ๊ณต์ ๋ชจ๋ฌ์ฐฝ ๋ณด์ฌ์ฃผ๊ธฐ * chore: console ์ญ์ ๋ฐ ์ฃผ์ ๋ฌ๊ธฐ * feat: ๋น๋ฐ๋ฒํธ ์ต๋ ๊ธธ์ด 20์๋ก ์ ํ * refactor: button ์ปดํฌ๋ํธ ๋ฆฌํฉํ ๋ง (#11) * style: reset css ๋ฒํผ disabled cursor ์กฐ๊ฑด ์ถ๊ฐ * style: theme ๋์์ธ ์์คํ ๋ณ๊ฒฝ ์ ์ฉ * refactor: button ์ปดํฌ๋ํธ ๋ฆฌํฉํ ๋ง * feat: toast component ๊ตฌํ (#14) * feat: login (#13) * feat: ๋ก๊ทธ์ธ, ํ์๊ฐ์ ๋ ์ด์์ ๋ฐ ๋ก๊ทธ์ธ ๋ก์ง ๊ตฌํ * feat: axios ์๋ฌ ์ปค์คํ * chore: ์ฃผ์ ์ถ๊ฐ * feat: axios request interceptors ์ถ๊ฐ * feat: ๋ต๋ณ Bubble ์ปดํฌ๋ํธ ๊ตฌํ (#16) * feat: ๋ต๋ณ Bubble ์ปดํฌ๋ํธ ๊ตฌํ * chore: ํด๋ rename * refactor: ์ค๋ณต ์ฝ๋ ์ ๊ฑฐ * feat: user answer bubble ์ปดํฌ๋ํธ ๊ตฌํ (#17) * feat: input bubble ์ปดํฌ๋ํธ ๊ตฌํ (#18) * refactor: toast design system ์ ์ฉ (#21) * setting: jest eslint ์ค์ ์ถ๊ฐ ๋ฐ ์ ํธ ํ์ผ ์ถ๊ฐ (#19) * chore: jest ๊ด๋ จ ์ฌ์ฉํ์ง ์๋ ํจํค์ง ์ ๊ฑฐ * chore: ์ง์์ ์ผ๋ก ๋ฌธ์ ๊ฐ ์๊ธฐ๋ Home ํ ์คํธ ์ฝ๋ ์ ๊ฑฐ * chore: main์ button์์ ๋ฐ์ํ๋ ๋ฌธ์ ํด๊ฒฐ * feat: jest ๊ด๋ จ eslint plugins ์ถ๊ฐ * feat: jest eslint plugin ์ค์ ์ ์ฉ * chore: testing library ํจํค์ง ์ฌ์ค์น * fix: jest-dom eslint ์ค์ ์คํ์ ์์ * fix: jest ์ค์ ๋ณ๊ฒฝ * feat: ์ปค์คํ ๋๋๋ฅผ ์ํ testUtils ์ถ๊ฐ * feat: button ๋๋๋ง ๋ฐ ์๋ ํ ์คํธ ์ถ๊ฐ * chore: ๋ถํ์ํ export ์ ๊ฑฐ * fix: button test describe ์ด๋ฆ ๋ณ๊ฒฝ * setting: test CI ๋ฐ codecov ๋ถ์ฐฉ (#20) * feat: test ci ์ถ๊ฐ * feat: codecov ์ค์ ๋ฐ CI ์ถ๊ฐ * fix: ์คํฌ๋ฆฝํธ ์คํ์ ์์ * feat: ๋ก๊ทธ์ธ ๋ก์ง ์์ ์๋ฃ ๋ฐ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ๋ ์ด์์ (#22) * feat: ๋ก๊ทธ์ธ ๋ก์ง ์์ ์๋ฃ ๋ฐ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ๋ ์ด์์ * refactor: console ์ญ์ * refactor: ํ๊ฒฝ๋ณ์ ์ ์ฉ * feat: ๋น๋ฐ๋ฒํธ ์ฌ์ค์ api fetching (#23) * feat: category ํ์ด์ง ๊ตฌํ (#24) * feat: useBackGroundColor hook ์ถ๊ฐ * feat: layout์ background color ์ ์ฉ * refactor: ๊ณตํต hook ํด๋ ๋ถ๋ฆฌ * fix: axios request interceptors ํค๋ Bearer ์ถ๊ฐ * feat(hooks): useMounted hook ์ถ๊ฐ * feat: client suspense ์ถ๊ฐ * feat: client suspense ์ ์ฉ * feat: ๋ก๊ทธ์ธ ์ฑ๊ณต ์ดํ ์นดํ ๊ณ ๋ฆฌ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ ์ถ๊ฐ * feat: main ์นดํ ๊ณ ๋ฆฌ ํธ์ถ api ๋ก์ง ์ถ๊ฐ * fix: select ์ปดํฌ๋ํธ๊ฐ undefined ๋ํ ์ฃผ์ ๋ฐ์ ์ ์๊ฒ ์ค์ ์ถ๊ฐ * feat: bottom fixed button ์ถ๊ฐ * feat: category ํ์ด์ง ์ถ๊ฐ * feat: production env ํ์ผ git ignore ์ถ๊ฐ * feat: dynamic category ํ์ด์ง ์ถ๊ฐ * feat: single bottom fixed button ํ ์คํธ ์ถ๊ฐ * feat: category detail ํ์ด์ง ๊ตฌํ (#25) * feat: category ํ์ด์ง getStaticProps ๋ฆฌํด ํ์ ์ถ๊ฐ * fix: suspense ๋ฌธ์ ์์ ์กฐ์น * feat: mid category api ๊ด๋ จ ๋ก์ง ์ถ๊ฐ * feat: next ์ธ๋ถ ์ด๋ฏธ์ง ์ฌ์ฉ ์ค์ ์ถ๊ฐ * feat: category detail ํ์ด์ง ์ถ๊ฐ * fix: next config image hostname ๋ณ๊ฒฝ * feat: question ํ์ด์ง ๊ตฌํ (#26) * feat: question ๊ด๋ จ api ๋ก์ง ์ถ๊ฐ ๋ฐ ์ผ๋ถ ๋ค์ด๋ฐ ์์ * fix: ๋ณ๊ฒฝ๋ api ์ด๋ฆ ์ ์ฉ * fix: question dynamic route path ๋ณ๊ฒฝ * refactor: useBackGroundColor route ๋ก์ง ๊ฐ์ * feat: question ํ์ด์ง ์ถ๊ฐ * fix: next config s3 url ์์ * refactor: early return์ ํตํ ํ์ undefined ๋ฌธ์ ๊ฐ์ * refactor: category ํ์ด์ง early return์ ํตํ ํ์ undefined ๋ฌธ์ ๊ฐ์ * feat: onboarding page ์์ ์๋ฃ (#27) * feat: chip component ๊ตฌํ (#28) * feat: chip component ๊ตฌํ * chore: ๊ณต๋ฐฑ ์ญ์ * test: Icon ์ปดํฌ๋ํธ ํ ์คํธ ์ถ๊ฐ (#30) * feat: jest svg ๊ด๋ จ ์ค์ ์์ ๋ฐ ์ถ๊ฐ * refactor: icon import ๋ฐฉ์ ๋ณ๊ฒฝ * test: icon ํ ์คํธ ์ถ๊ฐ * feat: question answer ๊ธฐ๋ฅ ๊ตฌํ (#31) * feat: main ์นดํ ๊ณ ๋ฆฌ ํธ์ถ api ๋ก์ง ์ถ๊ฐ * feat: mid category api ๊ด๋ จ ๋ก์ง ์ถ๊ฐ * feat: question ๊ด๋ จ api ๋ก์ง ์ถ๊ฐ ๋ฐ ์ผ๋ถ ๋ค์ด๋ฐ ์์ * feat: question ํ์ด์ง ์ถ๊ฐ * feat: question answer ๊ด๋ จ api ๋ก์ง ์ถ๊ฐ * feat: double bottom fixed button ์ถ๊ฐ * feat: question answer ๋ก์ง ์ถ๊ฐ * chore: ๋ถํ์ํ ๋ณ๊ฒฝ ์ ๊ฑฐ * feat: token refetch ๋ก์ง ์ถ๊ฐ (#32) * feat: analytics tools ์ถ๊ฐ (#34) * feat: google analytics ์ค์ ์ถ๊ฐ * feat: hotjar ์ค์ ์ถ๊ฐ * feat: mypage ์์ ์๋ฃ (#33) * feat: mypage ์์ ์๋ฃ * chore: tsconfig ์์ * fix: ์คํ ์์ * fix: querykey ๋ฐ๋ ๊ฒ ์์ * feat: 404page ์์ (#35) * feat: 404 page ๊ตฌํ * chore: fix lint error * setting: playwright ์ค์ ๋ฐ ์์ ์ถ๊ฐ (#36) * feat: playwright ์ค์ ๋ฐ ์์ ์ถ๊ฐ * feat: playwright eslint plugin ์ถ๊ฐ ๋ฐ ์ ์ฉ * chore: jest test ignore pattern ์ถ๊ฐ * chore: response.d.ts lint ์ ์ฉ * test: ๋น๋ก๊ทธ์ธ์ ํํ๋ฉด์ ๋ํ e2e ํ ์คํธ ์ถ๊ฐ * feat: question ํ์ด์ง ๊ตฌํ v2 (#37) * refactor: api base url ์์ ๋ฐ deprecated api ๋ช ์ * refactor: deprecated response ๋ช ์ * refactor: ์ง๋ฌธ ์์ฑ api v2 ์ถ๊ฐ ๋ฐ ์ ์ฉ * feat: ์ง๋ฌธ ๋ต๋ณ ์ ์ฅ api ๋ฐ mutation hook ์ถ๊ฐ * feat: ์ง๋ฌธ api v2 ์ถ๊ฐ ๋ฐ query hook ์ถ๊ฐ * refactor: question api ๋ณ๊ฒฝ์ ์ถ๊ฐ ๋ฐ ์ ์ฉ * feat: question ์ปดํฌ๋ํธ ์ถ๊ฐ * feat: questions ํ์ด์ง ๊ตฌํ * refactor: AIBubble ๋ณ๊ฒฝ๋ ๋์์ธ ์ ์ฉ (#39) * refactor: api base url ์์ ๋ฐ deprecated api ๋ช ์ * feat: ์ง๋ฌธ api v2 ์ถ๊ฐ ๋ฐ query hook ์ถ๊ฐ * refactor: question api ๋ณ๊ฒฝ์ ์ถ๊ฐ ๋ฐ ์ ์ฉ * refactor: bubble์ chip ์ปดํฌ๋ํธ ์ ์ฉ * refactor: ๋ณ๊ฒฝ๋ AI ๋ต๋ณ ํ ์คํธ ๋์์ธ ์ ์ฉ * feat: ํค๋ ๋ณ๊ฒฝ ๋ฐ favicon, og tag ์ ์ฉ (#40) * feat: ์นดํ ๊ณ ๋ฆฌ ํค๋ ์ ์ฉ ๋ฐ ๋ค๋ก๊ฐ๊ธฐ ๋ฒํผ ํด๋ฆญ์ ๋ชจ๋ฌ overlay * feat: right icon ์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ๊ฒ ์์ * feat: favicon, og-tag ์ ์ฉ * feat: responsive ๋์์ธ ์ ์ฉ (#41) * feat: desktop media query theme ์ถ๊ฐ * feat: ๋์์ธ์ ๋ฐ๋ฅธ desktop ๋ฐ์ํ ์ ์ฉ * setting: auto release tag action ์ถ๊ฐ (#42) * chore: ๋ฐฐํฌ ๋ฒ์ ๋ช ์ * feat: auto release tag action ์ถ๊ฐ * hotfix: Release 1.0.0 deploy error ํด๊ฒฐ (#44) * fix: ๋ณ๊ฒฝ๋ s3 url ์ ์ฉ * fix: useShowLoginModal prop undefined ์๋ฌ ์์ ์กฐ์น * feat: useModal Dimmer ๋ฐ์ํ ์ ์ฉ * fix: useQuestionAnswer hook api import ์๋ฌ ํด๊ฒฐ * fix: useModal import warning ํด๊ฒฐ * feat: title ,description seo ์ถ๊ฐ * fix: page api ์บ์ฑ์ผ๋ก ์ธํด ์ด์ ์ง๋ฌธ์ด ์ ์ ๋ณด์ด๋ ๋ฌธ์ ํด๊ฒฐ --------- Co-authored-by: chaerim kim <89721027+chaaerim@users.noreply.github.com>
๐ ์์ ๋ด์ฉ
โ๏ธ ์์ธ ์ค๋ช
๐ท ์คํฌ๋ฆฐ์ท
๐ ์ฐธ๊ณ ์๋ฃ