diff --git a/README.md b/README.md index 553e9d9..d008910 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,84 @@ ## ๐งโ๐ป ํ๋ก์ ํธ ์๊ฐ -### ์ฐ๋ฆฌ๋ค์ ํ๋ณตํ ์๊ฐ โฐ + +### ์ฐ๋ฆฌ๋ค์ ํ๋ณตํ ์๊ฐ โฐ + > ์ฐ๋ฆฌFIS ์์นด๋ฐ๋ฏธ ๊ต์ก์๋ค์ ๋์์ผ๋ก ๊ณต๋ถํ ์๊ฐ์ ์ธก์ ํ์ฌ ํ์ต ๊ธฐ๋ก์ ํ์ธํ ์ ์๋ ์๋น์ค -[์ฐํ์์ ์ ์ํ๊ณ ์ถ๋ค๋ฉด? ํด๋ฆญํด์ฃผ์ธ์! ๐](https://woohangshi.vercel.app/) -- ํ ์คํธ ์ ์ ID: test@test.com +[์ฐํ์์ ์ ์ํ๊ณ ์ถ๋ค๋ฉด? ํด๋ฆญํด์ฃผ์ธ์! ๐](https://woohangshi.vercel.app/) + +- ํ ์คํธ ์ ์ ID: test@test.com - ํ ์คํธ ์ ์ PW: test1234! ## ๐ป ํ์๊ตฌ์ฑ + | | | | -|:---:|:---:|:---:| -| [๊ฐ์ฌ์ฐ](https://github.com/riverkite0708) | [๊ณต์์ฐ](https://github.com/Kong-E) | [์ด๋์ด](https://github.com/doyi0107) | -| ํ๋ก ํธ์๋ | ํ๋ก ํธ์๋ | ํ๋ก ํธ์๋ | -| UI ๊ฐ์ด๋๋ผ์ธ, ๊ธฐ๋กํ์ธ, ๋ง์ดํ์ด์ง ๊ตฌํ | ์ธ์ฆ/์ธ๊ฐ, ๊ณต๋ถํ๊ธฐ ๊ตฌํ, API ์ค์ | ๋๋ฉ ํ์ด์ง, ๊ณผ๋ชฉ์ ํ, ์์์กฐํ ๊ตฌํ | +| :------------------------------------------------------------: | :-----------------------------------------------------: | :-------------------------------------------------------: | +| [๊ฐ์ฌ์ฐ](https://github.com/riverkite0708) | [๊ณต์์ฐ](https://github.com/Kong-E) | [์ด๋์ด](https://github.com/doyi0107) | +| ํ๋ก ํธ์๋ | ํ๋ก ํธ์๋ | ํ๋ก ํธ์๋ | +| UI ๊ฐ์ด๋๋ผ์ธ, ๊ธฐ๋กํ์ธ, ๋ง์ดํ์ด์ง ๊ตฌํ | ์ธ์ฆ/์ธ๊ฐ, ๊ณต๋ถํ๊ธฐ ๊ตฌํ, API ์ค์ | ๋๋ฉ ํ์ด์ง, ๊ณผ๋ชฉ์ ํ, ์์์กฐํ ๊ตฌํ | | | | | | -|:---:|:---:|:---:|:---:| -| [๊ฐํ์ฐ(ํ์ฅ)](https://github.com/khwoowoo) | [๊ธธ๊ฐ์](https://github.com/rlfrkdms1) | [๊นํ๋น](https://github.com/qbobl5) | [๊ณต์์ง](https://github.com/yaejinkong) | -| ๋ฐฑ์๋ | ๋ฐฑ์๋ | ๋ฐฑ์๋ | ๋ฐฑ์๋ | -| ํด๋ผ์ฐ๋ ์ธํ๋ผ ๊ตฌ์ถ, ๋ญํน API ๊ฐ๋ฐ | ์ธ์ฆ/์ธ๊ฐ, ์ด๋ฉ์ผ ์ธ์ฆ ๊ธฐ๋ฅ, ๊ณต๋ถ์๊ฐ ๊ธฐ๋ก API ๊ฐ๋ฐ | CI ํ๊ฒฝ ๊ตฌ์ถ, ํ์ด๋จธ ์กฐํ ๋ฐ ์บ๋ฆฐ๋ API ๊ฐ๋ฐ | ๊ณผ๋ชฉ ๋ฐ ํ์ ์ ๋ณด API ๊ฐ๋ฐ | +| :-------------------------------------------------------: | :--------------------------------------------------------: | :-----------------------------------------------------: | :---------------------------------------------------------: | +| [๊ฐํ์ฐ(ํ์ฅ)](https://github.com/khwoowoo) | [๊ธธ๊ฐ์](https://github.com/rlfrkdms1) | [๊นํ๋น](https://github.com/qbobl5) | [๊ณต์์ง](https://github.com/yaejinkong) | +| ๋ฐฑ์๋ | ๋ฐฑ์๋ | ๋ฐฑ์๋ | ๋ฐฑ์๋ | +| ํด๋ผ์ฐ๋ ์ธํ๋ผ ๊ตฌ์ถ, ๋ญํน API ๊ฐ๋ฐ | ์ธ์ฆ/์ธ๊ฐ, ์ด๋ฉ์ผ ์ธ์ฆ ๊ธฐ๋ฅ, ๊ณต๋ถ์๊ฐ ๊ธฐ๋ก API ๊ฐ๋ฐ | CI ํ๊ฒฝ ๊ตฌ์ถ, ํ์ด๋จธ ์กฐํ ๋ฐ ์บ๋ฆฐ๋ API ๊ฐ๋ฐ | ๊ณผ๋ชฉ ๋ฐ ํ์ ์ ๋ณด API ๊ฐ๋ฐ | ## โญ ํ๋ก์ ํธ ์ฃผ์ ๊ธฐ๋ฅ + ์ค๋น์ค ์ ๋๋ค. ## โ๏ธ ์์คํ ์ํคํ ์ฒ -### ํ๋ก์ ํธ ๊ตฌ์กฐ๋ -![ํ๋ก์ ํธ ๊ตฌ์กฐ๋](https://github.com/user-attachments/assets/97c151ee-4875-4c52-b446-0f5b88dabaaa) ---- -### ์ธํ๋ผ ๊ตฌ์กฐ๋ + +### ํ๋ก์ ํธ ๊ตฌ์กฐ๋ + +## ![ํ๋ก์ ํธ ๊ตฌ์กฐ๋](https://github.com/user-attachments/assets/97c151ee-4875-4c52-b446-0f5b88dabaaa) + +### ์ธํ๋ผ ๊ตฌ์กฐ๋ + ![์ธํ๋ผ ๊ตฌ์กฐ๋](https://github.com/user-attachments/assets/81017061-93c3-4720-9abc-eafc10874017) ## ๐ ๊ธฐ์ ์คํ -### Common + +### Common + ![Notion](https://img.shields.io/badge/Notion-eeeeee.svg?style=flat-square&logo=notion&logoColor=000000) ![GitHub](https://img.shields.io/badge/Github-%23121011.svg?style=flat-square&logo=github&logoColor=white) ![Postman](https://img.shields.io/badge/Postman-FF6C37?style=flat-square&logo=postman&logoColor=white) -### UI/UX +### UI/UX + ![Radix UI](https://img.shields.io/badge/Radix%20ui-161618.svg?style=flat-square&logo=radix-ui&logoColor=white) ![figma](https://img.shields.io/badge/Figma-f24e1e?style=flat-square&logo=figma&logoColor=ffffff) -### Frontend +### Frontend + ![Next JS](https://img.shields.io/badge/Next.js-black?style=flat-square&logo=next.js&logoColor=white) ![Zustand](https://img.shields.io/badge/Zustand-orange?style=flat-square&logo=zustand&logoColor=white) ![TypeScript](https://img.shields.io/badge/TypeScript-%23007ACC.svg?style=flat-square&logo=typescript&logoColor=white) ![authjs](https://img.shields.io/badge/Auth.js-1eabf4?style=flat-square&logo=nextauth&logoColor=black) -![SWR](https://img.shields.io/badge/SWR-black.svg?style=flat-square&logo=swr&logoColor=white) +![SWR](https://img.shields.io/badge/SWR-black.svg?style=flat-square&logo=swr&logoColor=white) ![ESLint](https://img.shields.io/badge/ESLint-4B3263?style=flat-square&logo=ESLint&logoColor=white) ![Prettier](https://img.shields.io/badge/Prettier-%23F7B93E.svg?style=flat-square&logo=prettier&logoColor=black) ![Vercel](https://img.shields.io/badge/Vercel-000000?style=flat-square&logo=Vercel&logoColor=white) -### Backend +### Backend + -### Infra & DB +### Infra & DB + -### CI/CD +### CI/CD + @@ -77,18 +92,18 @@ โย ย โโโ easteregg/ โถ๏ธ ์ด์คํฐ์๊ทธ ํด๋ โย ย โโโ icons/ โถ๏ธ ์์ด์ฝ ํด๋ โย ย โโโ imgs/ โถ๏ธ ์ด๋ฏธ์ง ํด๋ -โย ย โโโ fonts/ ํฐํธ ํด๋ +โย ย โโโ fonts/ ํฐํธ ํด๋ โโโ app/ โถ๏ธ ์ฑ ๋ผ์ฐํ ํด๋ -โย ย โโโ (auth)/ โถ๏ธ ์ธ์ฆ ์ธ๊ฐ ํด๋ -โย ย โโโ actions/ โถ๏ธ auth.js ํจ์ ํธ์ถ ํด๋ +โย ย โโโ (auth)/ โถ๏ธ ์ธ์ฆ ์ธ๊ฐ ํด๋ +โย ย โโโ actions/ โถ๏ธ auth.js ํจ์ ํธ์ถ ํด๋ โย ย โโโ api/auth/[...nextauth]/ โถ๏ธ auth.js ์ค์ ํด๋ โย ย โโโ mypage/ โถ๏ธ ๋ง์ดํ์ด์ง ํด๋ โย ย โโโ ranking/ โถ๏ธ ์์์กฐํ ํด๋ โย ย โโโ record/ โถ๏ธ ๊ธฐ๋กํ์ธ ํด๋ โย ย โโโ study/ โถ๏ธ ๊ณต๋ถ์์ ํด๋ -โย ย โโโ page.tsx โถ๏ธ root ๊ฒฝ๋ก ํ์ด์ง -โย ย โโโ layout.tsx โถ๏ธ root ๊ฒฝ๋ก ๋ ์ด์์ ๊ตฌ์กฐ -โโโ components/ โถ๏ธ ์ปดํฌ๋ํธ ํด๋ +โย ย โโโ page.tsx โถ๏ธ root ๊ฒฝ๋ก ํ์ด์ง +โย ย โโโ layout.tsx โถ๏ธ root ๊ฒฝ๋ก ๋ ์ด์์ ๊ตฌ์กฐ +โโโ components/ โถ๏ธ ์ปดํฌ๋ํธ ํด๋ โย ย โโโ common/ โถ๏ธ ๊ณตํต ์ปดํฌ๋ํธ ํด๋ โย ย โย ย โโโ Header/ โย ย โย ย โย ย โโโ Header์ปดํฌ๋ํธ.tsx @@ -99,7 +114,7 @@ โย ย โย ย โโโ ์ปดํฌ๋ํธ.tsx โย ย โย ย โโโ ์ปดํฌ๋ํธ.module.css โย ย โโโ ๋ผ์ฐํ ํด๋๋ช /์ปดํฌ๋ํธ.tsx -โย ย โโโ ๋ผ์ฐํ ํด๋๋ช /์ปดํฌ๋ํธ.module.css +โย ย โโโ ๋ผ์ฐํ ํด๋๋ช /์ปดํฌ๋ํธ.module.css โโโ constants/ โย ย โโโ ์์๋ช .ts โโโ hooks/ @@ -107,7 +122,7 @@ โโโ apis/ โย ย โโโ instancs.ts โถ๏ธ api ์์ฒญ ๊ธฐ๋ณธ ์ค์ ํ์ผ โย ย โโโ ๋๋ฉ์ธApi.ts -โโโ stores/ โถ๏ธ Zustand Store ํด๋ +โโโ stores/ โถ๏ธ Zustand Store ํด๋ โย ย โโโ ๋๋ฉ์ธStore.ts โโโ types/ โถ๏ธ TypeScript Interface ์ค์ ํด๋ โย ย โโโ ๋๋ฉ์ธType.ts @@ -121,7 +136,8 @@ โโโ package.json โถ๏ธ NPM ํ๋ก์ ํธ ์ค์ ํ์ผ ``` -## ๐ Commit ๋ฐฉ๋ฒ +## ๐ Commit ๋ฐฉ๋ฒ + ๊ผญ ๋ค์์ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ์ ์ปค๋ฐํ ํ์๋ ์์ง๋ง, ์์๋ณด๊ธฐ ์ฝ๊ฒํ๊ธฐ ์ํจ. \ ์ปค๋ฐ์ ์ ๋ชฉ์ ํ์ ์ ๊ธฐ์ฌ ํ ๊ฐ๋จํ ์์ฝ(๋ช ๋ น์กฐ)์ ๊ธฐ์ฌ ํจ. @@ -129,19 +145,20 @@ ๋ณธ๋ฌธ ์์ฑ์ ์์ธํ ๋ด์ฉ์ ๋๊ตฌ๋ ์์๋ณผ ์ ์๊ธฐ ๊ธฐ์ฌ ํจ(์ด๋ป๊ฒ ๋ณด๋ค **์**์ ์ด์ ์ ๋ง์ถฐ ์์ฑ). \ **ํ์ ์ ๋ค์๊ณผ ๊ฐ์.** -* feat : ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐ -* fix : ๋ฒ๊ทธ ์์ -* docs : ๋ฌธ์ ์์ -* style : ์ฝ๋ formatting, ์ธ๋ฏธ์ฝ๋ก (;) ๋๋ฝ, ์ฝ๋ ๋ณ๊ฒฝ์ด ์๋ ๊ฒฝ์ฐ -* refactor : ์ฝ๋ ๋ฆฌํฉํฐ๋ง -* test : ํ ์คํธ ์ฝ๋, ๋ฆฌํฉํฐ๋ง ํ ์คํธ ์ฝ๋ ์ถ๊ฐ(ํ๋ก๋์ ์ฝ๋ ๋ณ๊ฒฝ X) -* chore : ๋น๋ ์ ๋ฌด ์์ , ํจํค์ง ๋งค๋์ ์์ (ํ๋ก๋์ ์ฝ๋ ๋ณ๊ฒฝ X) -* design : CSS ๋ฑ ์ฌ์ฉ์ UI ๋์์ธ ๋ณ๊ฒฝ -* comment : ํ์ํ ์ฃผ์ ์ถ๊ฐ ๋ฐ ๋ณ๊ฒฝ -* rename : ํ์ผ ํน์ ํด๋๋ช ์ ์์ ํ๊ฑฐ๋ ์ฎ๊ธฐ๋ ์์ ๋ง์ธ ๊ฒฝ์ฐ -* remove : ํ์ผ์ ์ญ์ ํ๋ ์์ ๋ง ์ํํ ๊ฒฝ์ฐ -* !BREAKING CHANGE : ์ปค๋ค๋ API ๋ณ๊ฒฝ์ ๊ฒฝ์ฐ -* !HOTFIX : ๊ธํ๊ฒ ์น๋ช ์ ์ธ ๋ฒ๊ทธ๋ฅผ ๊ณ ์ณ์ผ ํ๋ ๊ฒฝ์ฐ + +- feat : ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐ +- fix : ๋ฒ๊ทธ ์์ +- docs : ๋ฌธ์ ์์ +- style : ์ฝ๋ formatting, ์ธ๋ฏธ์ฝ๋ก (;) ๋๋ฝ, ์ฝ๋ ๋ณ๊ฒฝ์ด ์๋ ๊ฒฝ์ฐ +- refactor : ์ฝ๋ ๋ฆฌํฉํฐ๋ง +- test : ํ ์คํธ ์ฝ๋, ๋ฆฌํฉํฐ๋ง ํ ์คํธ ์ฝ๋ ์ถ๊ฐ(ํ๋ก๋์ ์ฝ๋ ๋ณ๊ฒฝ X) +- chore : ๋น๋ ์ ๋ฌด ์์ , ํจํค์ง ๋งค๋์ ์์ (ํ๋ก๋์ ์ฝ๋ ๋ณ๊ฒฝ X) +- design : CSS ๋ฑ ์ฌ์ฉ์ UI ๋์์ธ ๋ณ๊ฒฝ +- comment : ํ์ํ ์ฃผ์ ์ถ๊ฐ ๋ฐ ๋ณ๊ฒฝ +- rename : ํ์ผ ํน์ ํด๋๋ช ์ ์์ ํ๊ฑฐ๋ ์ฎ๊ธฐ๋ ์์ ๋ง์ธ ๊ฒฝ์ฐ +- remove : ํ์ผ์ ์ญ์ ํ๋ ์์ ๋ง ์ํํ ๊ฒฝ์ฐ +- !BREAKING CHANGE : ์ปค๋ค๋ API ๋ณ๊ฒฝ์ ๊ฒฝ์ฐ +- !HOTFIX : ๊ธํ๊ฒ ์น๋ช ์ ์ธ ๋ฒ๊ทธ๋ฅผ ๊ณ ์ณ์ผ ํ๋ ๊ฒฝ์ฐ ์์ `[feat/#์ด์๋ฒํธ]: ํ์ ์ถ๊ฐ` diff --git a/apis/instance.ts b/apis/instance.ts index 2874d58..0fb83dc 100644 --- a/apis/instance.ts +++ b/apis/instance.ts @@ -7,7 +7,9 @@ import { redirect } from 'next/dist/server/api-utils'; interface RequestOptions { headers?: Record; - [key: string]: string | Record | undefined; + isMultipart?: boolean; // ๋ฉํฐํํธ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ์์ฑ ์ถ๊ฐ + body?: any; // ์์ฒญ ๋ณธ๋ฌธ์ ๋ํ ํ์ ์ ์ + [key: string]: any; // ๋ค๋ฅธ ์์ฑ ํ์ฉ } const fetchInstance = async (url: string, options: RequestOptions = {}) => { @@ -15,10 +17,16 @@ const fetchInstance = async (url: string, options: RequestOptions = {}) => { const accessToken = session?.user?.accessToken; const headers: RequestOptions['headers'] = { - 'Content-Type': 'application/json', ...options.headers, }; + // FormData์ธ ๊ฒฝ์ฐ Content-Type ์ค์ ์ ๊ฑฐ + if (options.body instanceof FormData) { + delete headers['Content-Type']; + } else { + headers['Content-Type'] = 'application/json'; + } + if (accessToken) { headers.Authorization = `Bearer ${accessToken}`; } @@ -35,7 +43,7 @@ const fetchInstance = async (url: string, options: RequestOptions = {}) => { console.error('Token Expired'); } console.error('Fetch Error:', errorResponse); - return { error: errorResponse }; + return response; } if (response.headers.get('Content-Type')?.includes('application/json')) { diff --git a/apis/memberApi.ts b/apis/memberApi.ts index a579bb8..544f362 100644 --- a/apis/memberApi.ts +++ b/apis/memberApi.ts @@ -1,3 +1,4 @@ +import { revalidatePath } from 'next/cache'; import { instance } from './instance'; // ์ ์ ์ ๋ณด ์กฐํ @@ -9,6 +10,16 @@ export const getUserInfo = async () => { return response; }; +// ์ ์ ์ ๋ณด ์์ +export const patchUserInfo = async ({ name, course }: { name: string; course: string }) => { + const response = await instance(`members`, { + method: 'PATCH', + body: JSON.stringify({ name, course }), + }); + + return response; +}; + // ๋น๋ฐ๋ฒํธ ์ ๋ฐ์ดํธ export const postPwUpdate = async ({ oldPassword, newPassword }: { oldPassword: string; newPassword: string }) => { const response = await instance('members', { diff --git a/apis/rankingApi.ts b/apis/rankingApi.ts index a577585..b28c22d 100644 --- a/apis/rankingApi.ts +++ b/apis/rankingApi.ts @@ -1,6 +1,6 @@ import { instance } from './instance'; import { ApiResponse } from '../types/rankingType'; -import rankingImg from '../assets/icons/ranking_profile_img.png'; +import rankingImg from '@/public/imgs/ranking/ranking_profile_img.png'; //๋ญํน ์กฐํ api export const getMemberRanking = async ({ diff --git a/app/font.css b/app/font.css index acc086e..5a3c3bf 100644 --- a/app/font.css +++ b/app/font.css @@ -4,15 +4,15 @@ font-weight: 900; font-display: swap; src: - url('/font/Pretendard-Black.subset.woff2') format('woff2'), - url('/font/Pretendard-Black.subset.woff') format('woff'); + url('/fonts/Pretendard-Black.subset.woff2') format('woff2'), + url('/fonts/Pretendard-Black.subset.woff') format('woff'); } @font-face { font-family: 'Pretendard'; font-weight: 700; font-display: swap; - src: url('/font/Pretendard-Bold.subset.woff') format('woff'); + src: url('/fonts/Pretendard-Bold.subset.woff') format('woff'); } @font-face { @@ -20,8 +20,8 @@ font-weight: 500; font-display: swap; src: - url('/font/Pretendard-Medium.subset.woff2') format('woff2'), - url('/font/Pretendard-Medium.subset.woff') format('woff'); + url('/fonts/Pretendard-Medium.subset.woff2') format('woff2'), + url('/fonts/Pretendard-Medium.subset.woff') format('woff'); } @font-face { @@ -29,8 +29,8 @@ font-weight: 400; font-display: swap; src: - url('/font/Pretendard-Regular.subset.woff2') format('woff2'), - url('/font/Pretendard-Regular.subset.woff') format('woff'); + url('/fonts/Pretendard-Regular.subset.woff2') format('woff2'), + url('/fonts/Pretendard-Regular.subset.woff') format('woff'); } @font-face { @@ -38,6 +38,6 @@ font-weight: 100; font-display: swap; src: - url('/font/Pretendard-Thin.subset.woff2') format('woff2'), - url('/font/Pretendard-Thin.subset.woff') format('woff'); + url('/fonts/Pretendard-Thin.subset.woff2') format('woff2'), + url('/fonts/Pretendard-Thin.subset.woff') format('woff'); } diff --git a/app/mypage/infoupdate/page.tsx b/app/mypage/infoupdate/page.tsx new file mode 100644 index 0000000..a553972 --- /dev/null +++ b/app/mypage/infoupdate/page.tsx @@ -0,0 +1,67 @@ +'use client'; + +import ClassRadioGroup from '@/components/auth/ClassRadioGroup'; +import InputField from '@/components/auth/InputField'; +import CommonButton from '@/components/common/CommonButton'; +import { Box } from '@radix-ui/themes'; +import { patchUserInfo } from '@/apis/memberApi'; +import { useState, useTransition } from 'react'; + +export default function InfoUpdate() { + const [isPending, startTransition] = useTransition(); + const [userInfo, setUserInfo] = useState({ + name: '', + course: '', + }); + + const handleNameChange = (name: string) => { + setUserInfo({ ...userInfo, name }); + }; + + const handleCourseChange = (value: string) => { + setUserInfo({ ...userInfo, course: value }); + }; + + const submitHandler = (e: React.FormEvent) => { + e.preventDefault(); + + if (userInfo.name.trim() === '') { + alert('์์ ํ ์ด๋ฆ์ ์ ๋ ฅํด์ฃผ์ธ์.'); + return; + } + if (userInfo.course === '') { + alert('์์ ํ ๊ณผ์ ์ ์ ํํด์ฃผ์ธ์.'); + return; + } + + // Transition ์์์ ๋น๋๊ธฐ ์์ ์์ + startTransition(() => { + patchUserInfo(userInfo); // ์ ์ ์ ๋ณด ํจ์น + localStorage.removeItem('userInfo'); // ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ์ ์ ์ ๋ณด ์ ๊ฑฐ + }); + }; + + return ( + + + + ) => handleNameChange(e.target.value)} + /> + + + + + + {isPending ? '์์ ์ค...' : '์์ ํ๊ธฐ'} + + + + + + ); +} diff --git a/app/page.tsx b/app/page.tsx index 069e358..1a64e8c 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,24 +1,29 @@ -import { Box, Flex, Text } from '@radix-ui/themes'; +import { Box } from '@radix-ui/themes'; import Image from 'next/image'; +import Landing from '@/components/landing/Landing'; export default function Page() { - const rand = Math.floor(Math.random() * 3); + // const rand = Math.floor(Math.random() * 3); return ( - - - - - - - ์ ๋ฐ์ดํธ ์์ ์ ๋๋ค ^^ - - + + + + // + // + // + // + // + // + // ์ ๋ฐ์ดํธ ์์ ์ ๋๋ค ^^ + // + // + // ); } diff --git a/app/ranking/page.tsx b/app/ranking/page.tsx index 3970ea0..fb9663c 100644 --- a/app/ranking/page.tsx +++ b/app/ranking/page.tsx @@ -4,7 +4,7 @@ import TopRankings from '@/components/ranking/topRanking'; import FullRankingList from '@/components/ranking/fullRankingList'; import { Box, Flex } from '@radix-ui/themes'; import styles from './page.module.css'; -import rankingImg from '@/assets/icons/ranking_profile_img.png'; +import rankingImg from '@/public/imgs/ranking/ranking_profile_img.png'; import { getMemberRanking } from '@/apis/rankingApi'; import { Student, ApiResponse } from '@/types/rankingType'; diff --git a/assets/icons/ranking_1.png b/assets/icons/ranking_1.png deleted file mode 100644 index 5673bc3..0000000 Binary files a/assets/icons/ranking_1.png and /dev/null differ diff --git a/assets/icons/ranking_2.png b/assets/icons/ranking_2.png deleted file mode 100644 index a8cf46f..0000000 Binary files a/assets/icons/ranking_2.png and /dev/null differ diff --git a/assets/icons/ranking_3.png b/assets/icons/ranking_3.png deleted file mode 100644 index abcfe68..0000000 Binary files a/assets/icons/ranking_3.png and /dev/null differ diff --git a/assets/icons/subject_edit_close_btn.png b/assets/icons/subject_edit_close_btn.png deleted file mode 100644 index 8a7a587..0000000 Binary files a/assets/icons/subject_edit_close_btn.png and /dev/null differ diff --git a/components/auth/ClassRadioGroup.tsx b/components/auth/ClassRadioGroup.tsx new file mode 100644 index 0000000..86704c7 --- /dev/null +++ b/components/auth/ClassRadioGroup.tsx @@ -0,0 +1,39 @@ +import { Flex, RadioGroup, Text } from '@radix-ui/themes'; + +interface ClassRadioGroupProps { + course: string; + onChange: (value: string) => void; +} + +export default function ClassRadioGroup({ course, onChange }: ClassRadioGroupProps) { + return ( + <> + + ํด๋์ค + + + + + AI ์์ง๋์ด๋ง + + + ํด๋ผ์ฐ๋ ์์ง๋์ด๋ง + + + ํด๋ผ์ฐ๋ ์๋น์ค ๊ฐ๋ฐ + + + + > + ); +} diff --git a/components/auth/InputField.tsx b/components/auth/InputField.tsx index 1a49982..ed3ace8 100644 --- a/components/auth/InputField.tsx +++ b/components/auth/InputField.tsx @@ -11,13 +11,13 @@ interface InputFieldProps { export default function InputField({ label, id, type = 'text', placeholder, value, onChange }: InputFieldProps) { return ( - + <> {label} - + > ); } diff --git a/components/auth/JoinForm.tsx b/components/auth/JoinForm.tsx index b739d81..809f26d 100644 --- a/components/auth/JoinForm.tsx +++ b/components/auth/JoinForm.tsx @@ -7,6 +7,7 @@ import AuthFormLayout from './AuthFormLayout'; import { useJoinStore } from '@/stores/authStore'; import { useState } from 'react'; import { isValidPassword } from '@/utils/validateUtils'; +import ClassRadioGroup from './ClassRadioGroup'; interface JoinFormProps { onJoin: (e: React.FormEvent) => void; @@ -78,84 +79,61 @@ export default function JoinForm({ onJoin }: JoinFormProps) { - ) => handleEmailChange(e.target.value)} - /> + + ) => handleEmailChange(e.target.value)} + /> + {error.email && ( ์ด๋ฉ์ผ ํ์์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค. )} - ) => handleNameChange(e.target.value)} - /> - ) => handlePasswordChange(e.target.value)} - /> + + ) => handleNameChange(e.target.value)} + /> + + + ) => handlePasswordChange(e.target.value)} + /> + {error.password && ( ์์ด, ์ซ์, ํน์๋ฌธ์๋ฅผ ํฌํจํ ์ต์ 8์ ์ด์, ์ต๋ 20์ ์ดํ์ฌ์ผ ํฉ๋๋ค. )} - ) => handlePasswordCheckChange(e.target.value)} - /> + + ) => handlePasswordCheckChange(e.target.value)} + /> + {error.passwordCheck && ( ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค. )} - - ํด๋์ค - - - - - AI ์์ง๋์ด๋ง - - - ํด๋ผ์ฐ๋ ์์ง๋์ด๋ง - - - ํด๋ผ์ฐ๋ ์๋น์ค ๊ฐ๋ฐ - - - + diff --git a/components/auth/LoginForm.tsx b/components/auth/LoginForm.tsx index 50a8f0b..d0fb11a 100644 --- a/components/auth/LoginForm.tsx +++ b/components/auth/LoginForm.tsx @@ -40,21 +40,25 @@ export default function LoginForm({ onLogin }: LoginFormProps) { - setEmail(e.target.value)} - /> - setPassword(e.target.value)} - /> + + setEmail(e.target.value)} + /> + + + setPassword(e.target.value)} + /> + diff --git a/components/common/CommonButton.tsx b/components/common/CommonButton.tsx index c3e332b..683784d 100644 --- a/components/common/CommonButton.tsx +++ b/components/common/CommonButton.tsx @@ -6,19 +6,20 @@ import Link from 'next/link'; interface CommonButtonProps { type: 'submit' | 'button' | 'link'; href?: string; + disabled?: boolean; style: 'dark_purple' | 'light_purple' | 'dark_gray' | 'light_gray'; children: React.ReactNode; } -export default function CommonButton({ type, href, style, children }: CommonButtonProps) { +export default function CommonButton({ type, href, disabled, style, children }: CommonButtonProps) { return ( <> {type == 'submit' ? ( - + {children} ) : type == 'button' ? ( - + {children} ) : ( diff --git a/components/common/Header/Header.module.css b/components/common/Header/Header.module.css index 6190e0e..16bdd9f 100644 --- a/components/common/Header/Header.module.css +++ b/components/common/Header/Header.module.css @@ -2,21 +2,34 @@ background-color: #fff; border-bottom: 2px solid var(--main-color-3); } + +.header_landing { + position: sticky; + top: 0; + border-bottom: none; + background-color: #fff; + transition: background-color 0.3s ease; + z-index: 100; +} + .header_inner { position: relative; } + .logo { position: absolute; left: 0; top: 50%; transform: translateY(-50%); } + .logo p { font-size: 28px; font-weight: 300; line-height: 1; color: var(--main-color-3); } + .logo p i { display: inline-block; font-weight: 700; @@ -26,9 +39,11 @@ height: 75px; line-height: 75px; } + .gnb ul li { position: relative; } + .gnb ul li:before { content: ''; display: block; @@ -41,6 +56,7 @@ border-radius: 100%; background-color: var(--main-color-2); } + .gnb ul li:first-of-type:before { display: none; } @@ -51,19 +67,23 @@ top: 50%; transform: translateY(-50%); } + .user_name { background-size: cover; background-position: 50% 50%; border-radius: 100%; overflow: hidden; } + .user_txt { line-height: 1; } + .user_txt strong { display: block; font-weight: 500; } + .user_txt p { line-height: 1; color: #bab2bb; @@ -83,9 +103,11 @@ line-height: 60px; gap: 32px; } + .gnb ul li:before { left: -17px; } + .gnb ul li p { font-size: 16px; } @@ -94,9 +116,11 @@ width: 30px; height: 30px; } + .user_txt strong { font-size: 14px; } + .user_txt p { font-size: 12px; } @@ -109,13 +133,16 @@ height: 60px; text-align: center; } + .logo p { font-size: 20px; line-height: 60px !important; } + .gnb { display: none; } + .user_info { display: none; } diff --git a/components/common/Header/Header.tsx b/components/common/Header/Header.tsx index eda4efb..6064033 100644 --- a/components/common/Header/Header.tsx +++ b/components/common/Header/Header.tsx @@ -4,22 +4,49 @@ import Link from 'next/link'; import { Box, Flex, Heading, Strong, Text } from '@radix-ui/themes'; import styles from './Header.module.css'; import HeaderNav from './HeaderNav'; -import rankingImg from '@/assets/icons/ranking_profile_img.png'; +import rankingImg from '@/public/imgs/ranking/ranking_profile_img.png'; import Image from 'next/image'; import { useUserInfoStore } from '@/stores/memberStore'; import { useSession } from 'next-auth/react'; -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { getUserInfo } from '@/apis/memberApi'; +import { usePathname } from 'next/navigation'; +import { gsap } from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; + +gsap.registerPlugin(ScrollTrigger); export default function Header() { const { userInfo, setUserInfo } = useUserInfoStore(); - const { data: session, update } = useSession(); + const { data: session } = useSession(); const accessToken = session?.user?.accessToken; const refreshToken = session?.user?.refreshToken; + // ๋ฃจํธ ๊ฒฝ๋ก์์๋ง ํน์ ์ด๋ฒคํธ ์ถ๊ฐ + const pathname = usePathname(); + const isRootPath = pathname === '/'; + + useEffect(() => { + if (isRootPath) { + const header = document.querySelector(`.${styles.header_landing}`); + + gsap.to(header, { + backgroundColor: 'rgba(255, 255, 255, 0.5)', + backdropFilter: 'blur(8px)', + scrollTrigger: { + trigger: document.body, + start: '2% 0%', + end: '10% 20%', + scrub: true, + markers: false, + }, + }); + } + }, [isRootPath]); + // update(); useEffect(() => { @@ -42,11 +69,11 @@ export default function Header() { } } })(); - }, [accessToken, refreshToken, setUserInfo]); + }); return ( - + diff --git a/components/landing/Landing.module.css b/components/landing/Landing.module.css new file mode 100644 index 0000000..701cfd2 --- /dev/null +++ b/components/landing/Landing.module.css @@ -0,0 +1,295 @@ +@font-face { + font-family: 'yg-jalnan'; + src: url('https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_four@1.2/JalnanOTF00.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'SUIT-Regular'; + src: url('https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_suit@1.0/SUIT-Regular.woff2') format('woff2'); + font-weight: normal; + font-style: normal; +} + +.landing_wrap { + position: relative; + width: 100%; + height: 100%; + top: 0; +} + +/* ์ธํธ๋ก ์น์ */ +.intro { + position: relative; + top: 0; + left: 0; + height: 95vh; + background: linear-gradient(to bottom, #fff 3%, #f9f9ff 10%, #e7dcfd 50%, #d0d4ff 100%); +} + +.intro_section { + display: flex; + justify-content: space-around; + align-items: center; +} + +.timer_icon_wrap { + width: 35%; + height: auto; +} + +.timer_icon { + animation: swing 2s infinite ease-in-out; +} + +@keyframes swing { + 0% { + transform: translateX(-10px) rotate(-5deg); + } + + 50% { + transform: translateX(10px) rotate(5deg); + } + + 100% { + transform: translateX(-10px) rotate(-5deg); + } +} + +.intro_text_wrap { + padding: 0px 50px; + display: flex; + flex-direction: column; + justify-content: center; +} + +.intro_text { + font: 90px 'yg-jalnan'; + color: rgb(68, 68, 68); +} + +.intro_btn_wrap { + margin-top: 30px; +} + +.intro_text_detail { + font-family: 'SUIT-Regular'; + color: rgb(68, 68, 68); +} + +.intro_btn { + font-weight: bold; + background-color: white; + padding: 12px 15px; + margin-right: 10px; + font-size: 16px; + cursor: pointer; + transition: + background-color 0.3s ease, + color 0.3s ease; + border-radius: 8px; +} + +.intro_btn:hover { + background-color: var(--main-color-2); + color: white; +} + +.inquiry_icon { + width: 27px; + padding-right: 8px; +} + +.notion_icon { + width: 25px; + padding-right: 10px; +} + +.intro_arrow_wrap { + position: absolute; + bottom: 100px; + left: 50%; + transform: translateX(-50%); +} + +.arrow { + width: 50px; + animation: blink 1.5s infinite ease-in-out; +} + +@keyframes blink { + 0% { + opacity: 1; + transform: translateY(0); + } + + 50% { + opacity: 0.4; + transform: translateY(10px); + } + + 100% { + opacity: 1; + transform: translateY(0); + } +} + +/* ๋ถ๊ฐ์ค๋ช */ + +.add_explane { + width: 100%; + background-color: #fdfdfd; + text-align: center; + padding: 150px 0px; +} + +.add_explane_text { + font-size: 30px; + line-height: 55px; + font-weight: 500; +} + +/* ํ์ด๋จธ์๊ฐ์น์ */ + +/* animation ์ค์ */ +.timer_detail_wrap, +.timer_img_wrap, +.ranking_detail_wrap, +.ranking_img_wrap, +.cal_detail_wrap, +.cal_img_wrap { + opacity: 0; + transform: translateY(150px); + transition: all 0.5s; +} + +.timer_detail, +.ranking_detail, +.cal_detail { + display: block; + margin-top: 15px; +} + +.timer_detail_wrap { + padding: 100px 0px 50px 0px; + text-align: center; +} + +.timer_title { + font-weight: bold; + display: flex; + align-items: center; + justify-content: center; +} + +.timer_title_icon { + width: 35px; + padding-right: 10px; +} + +.timer_img_wrap { + padding-bottom: 100px; +} + +.timer_img_desktop, +.timer_img_mobile { + position: relative; + width: 45%; + border-radius: 20px; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3); +} + +.timer_img_desktop { + left: 50%; + transform: translate(-50%, 0%); +} + +.timer_img_mobile { + width: 15%; + left: 25%; + transform: translate(-30%, 20%); +} + +/* ๋ญํน ์๊ฐ, ๊ธฐ๋ก ํ์ธ*/ + +.ranking, +.cal { + width: 100%; + display: flex; + justify-content: center; +} + +.ranking_inner, +.cal_inner { + width: 80%; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; +} + +.ranking_img_wrap, +.cal_img_wrap { + width: 50%; + display: flex; +} + +.ranking_img_wrap { + justify-content: flex-end; +} + +.cal_img_wrap { + justify-content: flex-start; +} + +.ranking_img_desktop, +.cal_img_desktop { + border-radius: 20px; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3); + width: 80%; +} + +.cal_img_desktop { + width: 85%; +} + +.ranking_title { + display: flex; + align-items: center; + font-weight: bold; +} + +.cal_title { + font-weight: bold; +} + +.cal_title_icon { + width: 42px; +} + +.cal_detail_wrap { + padding-left: 100px; + text-align: left; +} + +.cal_title_icon { + height: 40px; + padding-right: 5px; +} + +/* ๊ธฐ๋กํ์ธ */ + +.cal_img_desktop, +.cal_record_img { + position: relative; + border-radius: 20px; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3); +} + +.cal_record_img { + width: 50%; + height: 80%; + right: 20%; + transform: translate(-40%, 60%); +} diff --git a/components/landing/Landing.tsx b/components/landing/Landing.tsx new file mode 100644 index 0000000..a9bd3db --- /dev/null +++ b/components/landing/Landing.tsx @@ -0,0 +1,216 @@ +'use client'; +import { Box, Text } from '@radix-ui/themes'; +import styles from './Landing.module.css'; +import { useEffect, useRef } from 'react'; +import gsap from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; +import Image from 'next/image'; + +gsap.registerPlugin(ScrollTrigger); + +export default function Landing() { + const timerRef = useRef(null); + const rankingRef = useRef(null); + const calRef = useRef(null); + + const timerDetailRef = useRef(null); + const timerImgWrapRef = useRef(null); + const rankingDetailRef = useRef(null); + const rankingImgWrapRef = useRef(null); + const calDetailRef = useRef(null); + const calImgWrapRef = useRef(null); + + useEffect(() => { + const commonGsapAni = { + y: 0, + opacity: 1, + ease: 'circ.out', + }; + + const tl = gsap.timeline({ + scrollTrigger: { + trigger: timerRef.current, + start: '0% 80%', + end: '50% 50%', + scrub: true, + markers: false, + }, + }); + + tl.to(timerDetailRef.current, commonGsapAni).to(timerImgWrapRef.current, commonGsapAni); + + const t2 = gsap.timeline({ + scrollTrigger: { + trigger: rankingRef.current, + start: '60% bottom', + end: 'bottom 70%', + scrub: true, + markers: false, + }, + }); + + t2.to(rankingDetailRef.current, commonGsapAni, 0).to(rankingImgWrapRef.current, commonGsapAni, 0); + + const t3 = gsap.timeline({ + scrollTrigger: { + trigger: calRef.current, + start: '0% 50%', + end: '50% 30%', + scrub: true, + markers: false, + }, + }); + + t3.to(calDetailRef.current, commonGsapAni, 0).to(calImgWrapRef.current, commonGsapAni, 0); + }, []); + + return ( + + + + + + + + ์ฐํ์ + + ์ฐ๋ฆฌ๋ค์ ํ๋ณตํ ์๊ฐ์ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ์! + + ์ฝ๊ณ ๊ฐํธํ๊ฒ ๊ณต๋ถ ๊ธฐ๋ก์ ํ์ธํด๋ณด์ธ์. + + + + + ๋ฌธ์ํ๊ธฐ + + + + ๋ ธ์ ๋ณด๋ฌ๊ฐ๊ธฐ + + + + + + + + + + + ์๊ฐ ์ธก์ ๋ถํฐ ๊ณผ๋ชฉ ์ ํ, ๋ญํน ํ์ธ๊น์ง ํ ๋ฒ์! + ๊ต์ก์์ ํ์ต ์๊ฐ์ ์ฒด๊ณ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๋ ์๋น์ค, + ์ฐํ์์ ํจ๊ป๋ผ๋ฉด ์ฑ์ฅ์ ๋์ผ๋ก ํ์ธํ ์ ์์ต๋๋ค. + + + {/* ํ์ด๋จธ ์๊ฐ ์น์ */} + + + + + ๊ณต๋ถ์์ + + + ๋ด๊ฐ ์ ํํ ๊ณผ๋ชฉ์ผ๋ก ๊ณต๋ถ ์๊ฐ์ ์ค์๊ฐ์ผ๋ก ์ธก์ ํ ์ ์์ด์. + ์ธ์ ์ด๋์๋ ๊ณต๋ถ๋ฅผ ์์ํ๊ณ ์๊ฐ์ ๊ธฐ๋กํด๋ณด์ธ์. + + + + + + + + {/* ์์์กฐํ ์๊ฐ ์น์ */} + + + + + + ์์์กฐํ + + + + ์ผ, ์ฃผ, ์๋ณ๋ก ๋์ ํ์ต ์์๋ฅผ ํ์ธํ๊ณ , + ๋ค๋ฅธ ๋ฐ ํ์๋ค๊ณผ ๊ฒฝ์ํ ์ ์์ด์. + ๋งค์ผ ๊พธ์คํ ๊ณต๋ถํ ์๊ฐ๋งํผ ๋์ ์์์ ์ค๋ฅผ ์ ์์ต๋๋ค! + + + + + + + + {/* ๊ธฐ๋กํ์ธ ์๊ฐ ์น์ */} + + + + + + + + + + ๊ธฐ๋กํ์ธ + + + + ํ๋์ ๋์ ํ์ต ๊ธฐ๋ก์ ํ์ธํด๋ณด์ธ์. + + ์ผ๋ณ ๊ณต๋ถ ์๊ฐ์ ๋ฌ๋ ฅ์ ํ์ํ๊ณ , + ๊ฐ ๋ ์ง์ ๊ณต๋ถํ ๊ณผ๋ชฉ์ ์ฝ๊ฒ ํ์ธํ ์ ์์ด์. + + ํด๋น ๋ ์ง๋ฅผ ํด๋ฆญํ๋ฉด, + ๋ชจ๋ฌ์ฐฝ์์ ๋๋ง์ ํ๊ณ ๋ก์ ์์ฑํ ์ ์์ต๋๋ค. + + + + + + ); +} diff --git a/components/mypage/MypageTabMenu.tsx b/components/mypage/MypageTabMenu.tsx index e54bc6f..27b28e4 100644 --- a/components/mypage/MypageTabMenu.tsx +++ b/components/mypage/MypageTabMenu.tsx @@ -18,6 +18,7 @@ export default function MypageTabMenu() { { link: '/mypage', title: '๋ด ๋ฐฐ์ง ์กฐํ' }, { link: '/mypage/subjectedit', title: '๊ณผ๋ชฉ ํธ์ง' }, { link: '/mypage/pwupdate', title: '๋น๋ฐ๋ฒํธ ์์ ' }, + { link: '/mypage/infoupdate', title: 'ํ์์ ๋ณด ์์ ' }, ]; const [pathTabTitle] = tabMenu.filter((tab) => { diff --git a/components/mypage/PwUpdateForm.tsx b/components/mypage/PwUpdateForm.tsx index 429cc9d..f544d46 100644 --- a/components/mypage/PwUpdateForm.tsx +++ b/components/mypage/PwUpdateForm.tsx @@ -66,7 +66,7 @@ export default function PwUpdateForm({ onUpdate }: IUpdateForm) { }; return ( - + diff --git a/components/mypage/UserProfile.module.css b/components/mypage/UserProfile.module.css index 51da37e..410326b 100644 --- a/components/mypage/UserProfile.module.css +++ b/components/mypage/UserProfile.module.css @@ -2,17 +2,22 @@ font-size: 0; text-align: center; } + .img_box { position: relative; display: inline-block; } + .back_img { background-repeat: no-repeat; background-position: 50% 50%; border-radius: 100%; background-size: cover; overflow: hidden; + width: 180px; + height: 180px; } + .back_img span { width: 180px; height: 180px; @@ -21,6 +26,7 @@ .btn_file input[type='file'] { display: none; } + .btn_file button { position: absolute; right: 0px; diff --git a/components/ranking/fullRankingList.tsx b/components/ranking/fullRankingList.tsx index b81d058..4277a8e 100644 --- a/components/ranking/fullRankingList.tsx +++ b/components/ranking/fullRankingList.tsx @@ -4,7 +4,7 @@ import Image from 'next/image'; import styles from './fullRankingList.module.css'; import InfiniteScroll from 'react-infinite-scroller'; import { Student } from '@/types/rankingType'; -import rankingImg from '@/assets/icons/ranking_profile_img.png'; +import rankingImg from '@/public/imgs/ranking/ranking_profile_img.png'; import { formatTime } from '@/utils/formatTimeUtils'; interface FullRankingListProps { diff --git a/components/ranking/topRanking.tsx b/components/ranking/topRanking.tsx index 7d1abd1..44abd52 100644 --- a/components/ranking/topRanking.tsx +++ b/components/ranking/topRanking.tsx @@ -4,7 +4,7 @@ import styles from './topRankingList.module.css'; import rankingOne from '@/public/imgs/medal_first_on.svg'; import rankingTwo from '@/public/imgs/medal_second_on.svg'; import rankingThird from '@/public/imgs/medal_third_on.svg'; -import rankingImg from '@/assets/icons/ranking_profile_img.png'; +import rankingImg from '@/public/imgs/ranking/ranking_profile_img.png'; import Image from 'next/image'; import { Student } from '@/types/rankingType'; diff --git a/middleware.ts b/middleware.ts index 1a29c67..21285a1 100644 --- a/middleware.ts +++ b/middleware.ts @@ -31,5 +31,5 @@ export default async function middleware(request: NextRequest, response: NextRes // ๋ฏธ๋ค์จ์ด๊ฐ ์ ์ฉ๋ ๊ฒฝ๋ก ์ค์ export const config = { - matcher: ['/', '/ranking', '/record', '/study', '/mypage'], + matcher: ['/', '/ranking', '/record', '/study', '/mypage/:path*'], }; diff --git a/package-lock.json b/package-lock.json index dc16933..49913b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@radix-ui/react-icons": "^1.3.0", "@radix-ui/themes": "^3.1.1", "@vercel/analytics": "^1.3.1", + "gsap": "^3.12.5", "js-cookie": "^3.0.5", "lodash": "^4.17.21", "next": "14.2.5", @@ -8018,6 +8019,11 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/gsap": { + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.12.5.tgz", + "integrity": "sha512-srBfnk4n+Oe/ZnMIOXt3gT605BX9x5+rh/prT2F1SsNJsU1XuMiP0E2aptW481OnonOGACZWBqseH5Z7csHxhQ==" + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", diff --git a/package.json b/package.json index e0599fa..d291a80 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@radix-ui/react-icons": "^1.3.0", "@radix-ui/themes": "^3.1.1", "@vercel/analytics": "^1.3.1", + "gsap": "^3.12.5", "js-cookie": "^3.0.5", "lodash": "^4.17.21", "next": "14.2.5", diff --git a/public/imgs/landing/arrow.png b/public/imgs/landing/arrow.png new file mode 100644 index 0000000..9edef51 Binary files /dev/null and b/public/imgs/landing/arrow.png differ diff --git a/public/imgs/landing/cal.png b/public/imgs/landing/cal.png new file mode 100644 index 0000000..e5bb1f3 Binary files /dev/null and b/public/imgs/landing/cal.png differ diff --git a/public/imgs/landing/cal_timer.png b/public/imgs/landing/cal_timer.png new file mode 100644 index 0000000..51cda5a Binary files /dev/null and b/public/imgs/landing/cal_timer.png differ diff --git a/public/imgs/landing/clock.png b/public/imgs/landing/clock.png new file mode 100644 index 0000000..71837c7 Binary files /dev/null and b/public/imgs/landing/clock.png differ diff --git a/public/imgs/landing/inquiry.png b/public/imgs/landing/inquiry.png new file mode 100644 index 0000000..5496934 Binary files /dev/null and b/public/imgs/landing/inquiry.png differ diff --git a/public/imgs/landing/landing_cal_desktop.png b/public/imgs/landing/landing_cal_desktop.png new file mode 100644 index 0000000..8c96f8e Binary files /dev/null and b/public/imgs/landing/landing_cal_desktop.png differ diff --git a/public/imgs/landing/landing_cal_record.png b/public/imgs/landing/landing_cal_record.png new file mode 100644 index 0000000..d14c4a3 Binary files /dev/null and b/public/imgs/landing/landing_cal_record.png differ diff --git a/public/imgs/landing/landing_ranking_desktop.png b/public/imgs/landing/landing_ranking_desktop.png new file mode 100644 index 0000000..9ad1dc4 Binary files /dev/null and b/public/imgs/landing/landing_ranking_desktop.png differ diff --git a/public/imgs/landing/landing_timer.png b/public/imgs/landing/landing_timer.png new file mode 100644 index 0000000..066072f Binary files /dev/null and b/public/imgs/landing/landing_timer.png differ diff --git a/public/imgs/landing/landing_timer_desktop.png b/public/imgs/landing/landing_timer_desktop.png new file mode 100644 index 0000000..0a0ae2f Binary files /dev/null and b/public/imgs/landing/landing_timer_desktop.png differ diff --git a/public/imgs/landing/landing_timer_icon.png b/public/imgs/landing/landing_timer_icon.png new file mode 100644 index 0000000..95d792d Binary files /dev/null and b/public/imgs/landing/landing_timer_icon.png differ diff --git a/public/imgs/landing/landing_timer_mobile.png b/public/imgs/landing/landing_timer_mobile.png new file mode 100644 index 0000000..288866b Binary files /dev/null and b/public/imgs/landing/landing_timer_mobile.png differ diff --git a/public/imgs/landing/notion.png b/public/imgs/landing/notion.png new file mode 100644 index 0000000..2ebabb7 Binary files /dev/null and b/public/imgs/landing/notion.png differ diff --git a/public/imgs/landing/timer_caleander.png b/public/imgs/landing/timer_caleander.png new file mode 100644 index 0000000..a77a140 Binary files /dev/null and b/public/imgs/landing/timer_caleander.png differ diff --git a/public/imgs/landing/trophy.png b/public/imgs/landing/trophy.png new file mode 100644 index 0000000..3a74c44 Binary files /dev/null and b/public/imgs/landing/trophy.png differ diff --git a/assets/icons/profile_img_file.png b/public/imgs/mypage/profile_img_file.png similarity index 100% rename from assets/icons/profile_img_file.png rename to public/imgs/mypage/profile_img_file.png diff --git a/assets/icons/ranking_profile_img.png b/public/imgs/ranking/ranking_profile_img.png similarity index 100% rename from assets/icons/ranking_profile_img.png rename to public/imgs/ranking/ranking_profile_img.png diff --git a/assets/icons/subject_delete.png b/public/imgs/subject/subject_delete.png similarity index 100% rename from assets/icons/subject_delete.png rename to public/imgs/subject/subject_delete.png diff --git a/assets/icons/subject_edit_back.png b/public/imgs/subject/subject_edit_back.png similarity index 100% rename from assets/icons/subject_edit_back.png rename to public/imgs/subject/subject_edit_back.png diff --git a/public/timeout.png b/public/timeout.png index 7803f0d..558f239 100644 Binary files a/public/timeout.png and b/public/timeout.png differ diff --git a/stores/authStore.ts b/stores/authStore.ts index d99d7b6..33fadfc 100644 --- a/stores/authStore.ts +++ b/stores/authStore.ts @@ -5,11 +5,13 @@ interface joinState { name: string; password: string; passwordCheck: string; + image: File | null; course: string; setEmail: (email: string) => void; setName: (name: string) => void; setPassword: (password: string) => void; setPasswordCheck: (passwordCheck: string) => void; + setImage: (image: File | null) => void; setCourse: (course: string) => void; setAllEmpty: () => void; } @@ -19,11 +21,13 @@ export const useJoinStore = create((set) => ({ name: '', password: '', passwordCheck: '', + image: null, course: '', setEmail: (email: string) => set({ email }), setName: (name: string) => set({ name }), setPassword: (password: string) => set({ password }), setPasswordCheck: (passwordCheck: string) => set({ passwordCheck }), + setImage: (image: File | null) => set({ image }), setCourse: (course: string) => set({ course }), - setAllEmpty: () => set({ email: '', name: '', password: '', passwordCheck: '', course: '' }), + setAllEmpty: () => set({ email: '', name: '', password: '', passwordCheck: '', image: null, course: '' }), }));