diff --git a/.github/workflows/vitest.yaml b/.github/workflows/vitest.yaml new file mode 100644 index 00000000..1eaab08f --- /dev/null +++ b/.github/workflows/vitest.yaml @@ -0,0 +1,29 @@ +name: vitest-workflow + +on: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + branches: + - main + - develop + paths: + - 'src/**' + +jobs: + vitest: + if: github.event.pull_request.draft == false + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install node.js v20 + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install yarn dependencies + run: yarn install + + - name: Run tests with vitest + run: yarn run test -- --passWithNoTests \ No newline at end of file diff --git a/.gitignore b/.gitignore index 22e8f244..af00a142 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,10 @@ dist-ssr .env.test.local .env.production.local +# https local cert +localhost-key.pem +localhost.pem + # etc .history .eslintcache diff --git a/index.html b/index.html index 77d6abce..84f92b33 100644 --- a/index.html +++ b/index.html @@ -2,9 +2,8 @@ - + - Vite + React + TS
diff --git a/package.json b/package.json index bd1a3ed6..b5de9617 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,13 @@ "type": "module", "scripts": { "dev": "vite", - "staging": "tsc --project tsconfig.prod.json && vite build --mode staging", + "build:staging": "tsc --project tsconfig.prod.json && vite build --mode staging", + "serve:staging": "serve -s dist -l 5713 --ssl-cert localhost.pem --ssl-key localhost-key.pem", "build": "tsc --project tsconfig.prod.json && vite build", - "serve:dist": "serve -s dist -l 5713", "lint": "eslint . --ext ts,tsx,js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", - "test": "vitest --watch", + "test": "vitest", + "test:watch": "vitest --watch", "test-ui": "vitest --ui", "coverage": "vitest run --coverage", "prepare": "husky" @@ -28,6 +29,7 @@ "react": "^18.2.0", "react-big-calendar": "^1.13.0", "react-dom": "^18.2.0", + "react-helmet-async": "^2.0.5", "react-hook-form": "^7.51.4", "react-icons": "^5.2.1", "react-markdown": "^9.0.1", diff --git a/public/.gitkeep b/public/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..d127d08e Binary files /dev/null and b/public/favicon.ico differ diff --git a/src/assets/og_logo.png b/src/assets/og_logo.png new file mode 100644 index 00000000..0ea3a870 Binary files /dev/null and b/src/assets/og_logo.png differ diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx index 152dd7df..63782aee 100644 --- a/src/components/common/Header.tsx +++ b/src/components/common/Header.tsx @@ -45,9 +45,9 @@ export default function Header() { diff --git a/src/components/common/Meta.tsx b/src/components/common/Meta.tsx new file mode 100644 index 00000000..fd9df5a0 --- /dev/null +++ b/src/components/common/Meta.tsx @@ -0,0 +1,20 @@ +import { Helmet } from 'react-helmet-async'; +import logo from '@assets/og_logo.png'; + +type MetaProps = { + title?: string; +}; + +export default function Meta({ title = 'Grow up' }: MetaProps) { + return ( + + {title} + + + + + + + + ); +} diff --git a/src/components/common/RoleTooltip.tsx b/src/components/common/RoleTooltip.tsx index 47e0f05e..da0972cf 100644 --- a/src/components/common/RoleTooltip.tsx +++ b/src/components/common/RoleTooltip.tsx @@ -9,7 +9,7 @@ type RoleTooltipProps = { export default function RoleTooltip({ showTooltip, rolesInfo }: RoleTooltipProps) { return (
{rolesInfo.map((role) => (
diff --git a/src/components/common/UserRoleSelectBox.tsx b/src/components/common/UserRoleSelectBox.tsx index 7dc86d8a..85e98ea8 100644 --- a/src/components/common/UserRoleSelectBox.tsx +++ b/src/components/common/UserRoleSelectBox.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { IoMdCloseCircle } from 'react-icons/io'; -import { PROJECT_ROLES, TEAM_ROLES } from '@constants/role'; +import { PROJECT_ROLES, TEAM_CREATE_ROLES, TEAM_ROLES } from '@constants/role'; import type { User } from '@/types/UserType'; import type { RoleName } from '@/types/RoleType'; @@ -8,7 +8,7 @@ type UserRoleSelectBoxProps = { userId: User['userId']; nickname: User['nickname']; defaultValue: RoleName; - roles: typeof TEAM_ROLES | typeof PROJECT_ROLES; + roles: typeof TEAM_CREATE_ROLES | typeof TEAM_ROLES | typeof PROJECT_ROLES; onRoleChange: (userId: number, roleName: T) => void; onRemoveUser: (userId: number) => void; }; diff --git a/src/components/modal/team/ModalTeamForm.tsx b/src/components/modal/team/ModalTeamForm.tsx index faa61ca1..84168f75 100644 --- a/src/components/modal/team/ModalTeamForm.tsx +++ b/src/components/modal/team/ModalTeamForm.tsx @@ -3,7 +3,7 @@ import { FormProvider, useForm } from 'react-hook-form'; import useAxios from '@hooks/useAxios'; import useToast from '@hooks/useToast'; import { useReadTeams } from '@hooks/query/useTeamQuery'; -import { TEAM_DEFAULT_ROLE, TEAM_ROLE_INFO, TEAM_ROLES } from '@constants/role'; +import { TEAM_CREATE_ROLES, TEAM_DEFAULT_ROLE, TEAM_ROLE_INFO } from '@constants/role'; import { TEAM_VALIDATION_RULES } from '@constants/formValidationRules'; import { findUser } from '@services/userService'; import Spinner from '@components/common/Spinner'; @@ -150,7 +150,7 @@ export default function ModalTeamForm({ formId, onSubmit }: ModalTeamFormProps) key={userId} userId={userId} nickname={nickname} - roles={TEAM_ROLES} + roles={TEAM_CREATE_ROLES} defaultValue={TEAM_DEFAULT_ROLE} onRoleChange={handleRoleChange} onRemoveUser={handleRemoveUser} diff --git a/src/components/user/auth-form/ProfileImageContainer.tsx b/src/components/user/auth-form/ProfileImageContainer.tsx index fdd5c39c..c961f47d 100644 --- a/src/components/user/auth-form/ProfileImageContainer.tsx +++ b/src/components/user/auth-form/ProfileImageContainer.tsx @@ -61,9 +61,6 @@ export default function ProfileImageContainer({ imageUrl, setImageUrl }: Profile } uploadImageMutate({ file }); - - const localImageUrl = URL.createObjectURL(file); - setImageUrl(localImageUrl); }; const handleRemoveImg = () => { diff --git a/src/constants/role.ts b/src/constants/role.ts index ed241b68..aff8bcd8 100644 --- a/src/constants/role.ts +++ b/src/constants/role.ts @@ -2,27 +2,45 @@ import { deepFreeze } from '@utils/deepFreeze'; import type { RoleInfo } from '@/types/RoleType'; export const TEAM_ROLES = deepFreeze(['HEAD', 'LEADER', 'MATE'] as const); +export const TEAM_CREATE_ROLES = deepFreeze(['LEADER', 'MATE'] as const); export const PROJECT_ROLES = deepFreeze(['ADMIN', 'LEADER', 'ASSIGNEE'] as const); export const PROJECT_DEFAULT_ROLE = 'ASSIGNEE'; export const TEAM_DEFAULT_ROLE = 'MATE'; export const TEAM_ROLE_INFO: RoleInfo[] = [ - { roleName: 'HEAD', label: 'HEAD', description: '모든 권한 가능' }, + { + roleName: 'HEAD', + label: 'HEAD', + description: '- 팀: 수정 | 삭제\n- 팀원: 초대 | 추방\n- 프로젝트: 생성 | 수정 | 삭제\n- 모든 프로젝트의 ADMIN 권한', + }, { roleName: 'LEADER', label: 'LEADER', - description: '팀원 탈퇴(Mate만)\n프로젝트 생성 권한\n프로젝트 삭제(본인이 생성한 것만)', + description: '- 프로젝트: 생성 | 수정 | 삭제', + }, + { + roleName: 'MATE', + label: 'Mate', + description: '- 팀: 읽기만 가능', }, - { roleName: 'MATE', label: 'Mate', description: '프로젝트 읽기만 가능, 수정 및 생성 불가' }, ]; export const PROJECT_ROLE_INFO: RoleInfo[] = [ - { roleName: 'ADMIN', label: 'ADMIN', description: '프로젝트 모든 권한 가능' }, + { + roleName: 'ADMIN', + label: 'ADMIN', + description: + '- 프로젝트: 수정 | 삭제\n- 프로젝트원: 초대 | 추방\n- 상태: 생성 | 수정 | 삭제\n- 일정: 생성 | 수정 | 삭제', + }, { roleName: 'LEADER', label: 'LEADER', - description: '상태 및 일정 생성 권한\n수행자 할당 가능\n', + description: '- 상태: 생성 | 수정 | 삭제\n- 일정: 생성 | 수정 | 삭제', + }, + { + roleName: 'ASSIGNEE', + label: 'ASSIGNEE', + description: '- 일정: 생성 | 수정 | 삭제', }, - { roleName: 'ASSIGNEE', label: 'ASSIGNEE', description: '일정 쓰기\n일정 삭제(본인 것만) ' }, ]; diff --git a/src/hooks/query/useTeamQuery.ts b/src/hooks/query/useTeamQuery.ts index d41a24f0..26f30f77 100644 --- a/src/hooks/query/useTeamQuery.ts +++ b/src/hooks/query/useTeamQuery.ts @@ -42,8 +42,8 @@ export function useReadTeams() { }, }); - const joinedTeamList = teamList.filter((team) => team.isPendingApproval === true); - const invitedTeamList = teamList.filter((team) => team.isPendingApproval === false); + const joinedTeamList = teamList.filter((team) => team.isPendingApproval === false); + const invitedTeamList = teamList.filter((team) => team.isPendingApproval === true); return { joinedTeamList, invitedTeamList, teamList, isLoading, isError, error }; } diff --git a/src/main.tsx b/src/main.tsx index 18f99bbf..ffa11156 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,6 +5,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import MainRouter from '@routes/MainRouter.tsx'; import { queryClient } from '@hooks/query/queryClient'; import '@/globals.css'; +import { HelmetProvider } from 'react-helmet-async'; async function enableMocking() { if (!import.meta.env.DEV) return; @@ -16,10 +17,12 @@ async function enableMocking() { enableMocking().then(() => { ReactDOM.createRoot(document.getElementById('root')!).render( - - - - + + + + + + , ); }); diff --git a/src/mocks/mockData.ts b/src/mocks/mockData.ts index 29d3dc09..01bc8f64 100644 --- a/src/mocks/mockData.ts +++ b/src/mocks/mockData.ts @@ -327,123 +327,123 @@ export const TEAM_USER_DUMMY: TeamUser[] = [ teamId: 1, userId: 1, roleId: 1, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 1, userId: 3, roleId: 2, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 1, userId: 4, roleId: 3, - isPendingApproval: false, + isPendingApproval: true, }, { teamId: 1, userId: 8, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 1, userId: 9, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 1, userId: 11, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 1, userId: 12, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 1, userId: 13, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 1, userId: 14, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 1, userId: 15, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, // 팀2 소속 유저 정보 { teamId: 2, userId: 1, roleId: 2, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 2, userId: 3, roleId: 2, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 2, userId: 4, roleId: 1, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 2, userId: 5, roleId: 3, - isPendingApproval: false, + isPendingApproval: true, }, { teamId: 2, userId: 7, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 2, userId: 10, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, // 팀3 소속 유저 정보 { teamId: 3, userId: 1, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 3, userId: 2, roleId: 3, - isPendingApproval: true, + isPendingApproval: false, }, { teamId: 3, userId: 5, roleId: 2, - isPendingApproval: false, + isPendingApproval: true, }, { teamId: 3, userId: 6, roleId: 1, - isPendingApproval: true, + isPendingApproval: false, }, ] as const; diff --git a/src/mocks/services/authServiceHandler.ts b/src/mocks/services/authServiceHandler.ts index cbc9b51f..4096e34f 100644 --- a/src/mocks/services/authServiceHandler.ts +++ b/src/mocks/services/authServiceHandler.ts @@ -17,11 +17,11 @@ import { UserSignUpRequest, } from '@/types/UserType'; -const BASE_URL = import.meta.env.VITE_BASE_URL; +const API_URL = import.meta.env.VITE_API_URL; const authServiceHandler = [ // 회원가입 API - http.post(`${BASE_URL}/user`, async ({ request }) => { + http.post(`${API_URL}/user`, async ({ request }) => { const { verificationCode, email, ...restSignUpData } = (await request.json()) as UserSignUpRequest; if (verificationCode !== VERIFICATION_CODE_DUMMY) { @@ -51,7 +51,7 @@ const authServiceHandler = [ }), // 닉네임 중복 확인 API - http.post(`${BASE_URL}/user/nickname`, async ({ request }) => { + http.post(`${API_URL}/user/nickname`, async ({ request }) => { const { nickname } = (await request.json()) as CheckNicknameForm; const nicknameExists = USER_DUMMY.some((user) => user.nickname === nickname); @@ -61,7 +61,7 @@ const authServiceHandler = [ }), // 로그인 API - http.post(`${BASE_URL}/user/login`, async ({ request }) => { + http.post(`${API_URL}/user/login`, async ({ request }) => { const { username, password } = (await request.json()) as UserSignInForm; const foundUser = USER_DUMMY.find((user) => user.username === username && user.password === password); @@ -84,7 +84,7 @@ const authServiceHandler = [ }), // 소셜 로그인 API - http.post(`${BASE_URL}/user/login/:provider`, async ({ request, params }) => { + http.post(`${API_URL}/user/login/:provider`, async ({ request, params }) => { const { provider } = params as { provider: SocialLoginProvider }; const { code } = (await request.json()) as { code: string }; @@ -208,10 +208,7 @@ const authServiceHandler = [ }), // 액세스 토큰 갱신 API - http.post(`${BASE_URL}/user/refresh`, async ({ cookies, request }) => { - const accessToken = request.headers.get('Authorization'); - if (!accessToken) return new HttpResponse(null, { status: 401 }); - + http.post(`${API_URL}/user/refresh`, async ({ cookies }) => { const { refreshToken, refreshTokenExpiresAt } = cookies; const cookieRefreshToken = Cookies.get('refreshToken'); @@ -228,7 +225,7 @@ const authServiceHandler = [ return HttpResponse.json({ message: '리프레시 토큰이 만료되었습니다.' }, { status: 401 }); } - const userId = convertTokenToUserId(accessToken); + const userId = convertTokenToUserId(refreshToken); if (!userId) return new HttpResponse(null, { status: 401 }); const newAccessToken = generateDummyToken(userId); @@ -246,7 +243,7 @@ const authServiceHandler = [ }), // 로그인 한 사용자 정보 조회 API - http.get(`${BASE_URL}/user/me`, async ({ request }) => { + http.get(`${API_URL}/user/me`, async ({ request }) => { const accessToken = request.headers.get('Authorization'); if (!accessToken) return new HttpResponse(null, { status: 401 }); @@ -261,8 +258,13 @@ const authServiceHandler = [ }), // 로그아웃 API - http.post(`${BASE_URL}/user/logout`, async ({ cookies }) => { + http.post(`${API_URL}/user/logout`, async ({ request, cookies }) => { + const accessToken = request.headers.get('Authorization'); const { refreshToken } = cookies; + + if (!accessToken) return new HttpResponse(null, { status: 401 }); + if (!refreshToken) return new HttpResponse(null, { status: 400 }); + const currentTime = Date.now(); return new HttpResponse(null, { @@ -277,7 +279,7 @@ const authServiceHandler = [ }), // 액세스 토큰 테스트용 API - http.post(`${BASE_URL}/test`, ({ request }) => { + http.post(`${API_URL}/test`, ({ request }) => { console.log('테스트용 API 작동 중'); const authHeader = request.headers.get('Authorization'); @@ -297,7 +299,7 @@ const authServiceHandler = [ }), // 이메일 인증 번호 요청 API - http.post(`${BASE_URL}/user/verify/send`, async ({ request }) => { + http.post(`${API_URL}/user/verify/send`, async ({ request }) => { const { email } = (await request.json()) as RequestEmailCode; if (!email || !EMAIL_REGEX.test(email)) @@ -307,7 +309,7 @@ const authServiceHandler = [ }), // 이메일 인증 번호 확인 API - http.post(`${BASE_URL}/user/verify/code`, async ({ request }) => { + http.post(`${API_URL}/user/verify/code`, async ({ request }) => { const { email, verificationCode } = (await request.json()) as EmailVerificationForm; const verifyUserEmailAndCode = (userEmail: string, code: string) => { @@ -322,7 +324,7 @@ const authServiceHandler = [ }), // 아이디 찾기 API - http.post(`${BASE_URL}/user/recover/username`, async ({ request }) => { + http.post(`${API_URL}/user/recover/username`, async ({ request }) => { const { email, verificationCode } = (await request.json()) as EmailVerificationForm; if (verificationCode !== VERIFICATION_CODE_DUMMY) { @@ -339,7 +341,7 @@ const authServiceHandler = [ }), // 비밀번호 찾기 API - http.post(`${BASE_URL}/user/recover/password`, async ({ request }) => { + http.post(`${API_URL}/user/recover/password`, async ({ request }) => { const { username, email, verificationCode } = (await request.json()) as SearchPasswordForm; if (verificationCode !== VERIFICATION_CODE_DUMMY) { @@ -357,7 +359,7 @@ const authServiceHandler = [ }), // 비밀번호 변경 API - http.patch(`${BASE_URL}/user/password`, async ({ request }) => { + http.patch(`${API_URL}/user/password`, async ({ request }) => { const accessToken = request.headers.get('Authorization'); if (!accessToken) return HttpResponse.json({ message: '인증 정보가 존재하지 않습니다.' }, { status: 401 }); diff --git a/src/mocks/services/projectServiceHandler.ts b/src/mocks/services/projectServiceHandler.ts index 01c2f376..258ccde3 100644 --- a/src/mocks/services/projectServiceHandler.ts +++ b/src/mocks/services/projectServiceHandler.ts @@ -29,12 +29,12 @@ import { convertTokenToUserId } from '@utils/converter'; import type { SearchUser, UserWithRole } from '@/types/UserType'; import type { Project, ProjectCoworkerForm, ProjectForm } from '@/types/ProjectType'; -const BASE_URL = import.meta.env.VITE_BASE_URL; +const API_URL = import.meta.env.VITE_API_URL; let autoIncrementIdForProject = PROJECT_DUMMY.length + 1; const projectServiceHandler = [ // 프로젝트 소속 유저 검색 API - http.get(`${BASE_URL}/project/:projectId/user/search`, ({ request, params }) => { + http.get(`${API_URL}/project/:projectId/user/search`, ({ request, params }) => { const url = new URL(request.url); const nickname = url.searchParams.get('nickname') || ''; const accessToken = request.headers.get('Authorization'); @@ -69,7 +69,7 @@ const projectServiceHandler = [ }), // 프로젝트 생성 API - http.post(`${BASE_URL}/team/:teamId/project`, async ({ request, params }) => { + http.post(`${API_URL}/team/:teamId/project`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const teamId = Number(params.teamId); const { coworkers, ...projectInfo } = (await request.json()) as ProjectForm; @@ -117,7 +117,7 @@ const projectServiceHandler = [ }), // 프로젝트 목록 조회 API - http.get(`${BASE_URL}/team/:teamId/project`, ({ request, params }) => { + http.get(`${API_URL}/team/:teamId/project`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const teamId = Number(params.teamId); @@ -139,7 +139,7 @@ const projectServiceHandler = [ }), // 프로젝트 팀원 목록 조회 API - http.get(`${BASE_URL}/project/:projectId/user`, ({ request, params }) => { + http.get(`${API_URL}/project/:projectId/user`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); @@ -177,7 +177,7 @@ const projectServiceHandler = [ }), // 프로젝트 삭제 API - http.delete(`${BASE_URL}/project/:projectId`, ({ request, params }) => { + http.delete(`${API_URL}/project/:projectId`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); @@ -222,7 +222,7 @@ const projectServiceHandler = [ }), // 프로젝트 수정 API - http.patch(`${BASE_URL}/team/:teamId/project/:projectId`, async ({ request, params }) => { + http.patch(`${API_URL}/team/:teamId/project/:projectId`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const teamId = Number(params.teamId); @@ -265,7 +265,7 @@ const projectServiceHandler = [ }), // 프로젝트 팀원 추가 API - http.post(`${BASE_URL}/project/:projectId/user/invitation`, async ({ request, params }) => { + http.post(`${API_URL}/project/:projectId/user/invitation`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const { userId: projectCoworkerId, roleName } = (await request.json()) as ProjectCoworkerForm; @@ -310,7 +310,7 @@ const projectServiceHandler = [ }), // 프로젝트 팀원 권한 변경 API - http.patch(`${BASE_URL}/project/:projectId/user/:userId/role`, async ({ request, params }) => { + http.patch(`${API_URL}/project/:projectId/user/:userId/role`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const projectCoworkerId = Number(params.userId); @@ -355,7 +355,7 @@ const projectServiceHandler = [ }), // 프로젝트 팀원 삭제 API - http.delete(`${BASE_URL}/project/:projectId/user/:userId`, async ({ request, params }) => { + http.delete(`${API_URL}/project/:projectId/user/:userId`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const projectCoworkerId = Number(params.userId); diff --git a/src/mocks/services/statusServiceHandler.ts b/src/mocks/services/statusServiceHandler.ts index 65d26ab6..9f485693 100644 --- a/src/mocks/services/statusServiceHandler.ts +++ b/src/mocks/services/statusServiceHandler.ts @@ -15,12 +15,12 @@ import { convertTokenToUserId } from '@utils/converter'; import type { ProjectStatusForm, StatusOrderForm } from '@/types/ProjectStatusType'; -const BASE_URL = import.meta.env.VITE_BASE_URL; +const API_URL = import.meta.env.VITE_API_URL; let authIncrementIdForStatus = STATUS_DUMMY.length + 1; const statusServiceHandler = [ // 프로젝트 상태 목록 조회 API - http.get(`${BASE_URL}/project/:projectId/status`, ({ request, params }) => { + http.get(`${API_URL}/project/:projectId/status`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); @@ -46,7 +46,7 @@ const statusServiceHandler = [ }), // 프로젝트 상태 생성 API - http.post(`${BASE_URL}/project/:projectId/status`, async ({ request, params }) => { + http.post(`${API_URL}/project/:projectId/status`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const formData = (await request.json()) as ProjectStatusForm; @@ -69,7 +69,7 @@ const statusServiceHandler = [ }), // 프로젝트 상태 순서 변경 API - http.patch(`${BASE_URL}/project/:projectId/status/order`, async ({ request, params }) => { + http.patch(`${API_URL}/project/:projectId/status/order`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { statuses: statusOrders } = (await request.json()) as StatusOrderForm; const projectId = Number(params.projectId); @@ -100,7 +100,7 @@ const statusServiceHandler = [ }), // 프로젝트 상태 수정 API - http.patch(`${BASE_URL}/project/:projectId/status/:statusId`, async ({ request, params }) => { + http.patch(`${API_URL}/project/:projectId/status/:statusId`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const statusId = Number(params.statusId); @@ -128,7 +128,7 @@ const statusServiceHandler = [ }), // 프로젝트 상태 삭제 API - http.delete(`${BASE_URL}/project/:projectId/status/:statusId`, ({ request, params }) => { + http.delete(`${API_URL}/project/:projectId/status/:statusId`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const statusId = Number(params.statusId); diff --git a/src/mocks/services/taskServiceHandler.ts b/src/mocks/services/taskServiceHandler.ts index 13efd3fa..2c80788b 100644 --- a/src/mocks/services/taskServiceHandler.ts +++ b/src/mocks/services/taskServiceHandler.ts @@ -34,13 +34,13 @@ import { TASK_DUMMY, TASK_FILE_DUMMY } from '@mocks/mockData'; import type { UserWithRole } from '@/types/UserType'; import type { TaskAssigneeForm, TaskCreationForm, TaskOrderForm, TaskUpdateForm } from '@/types/TaskType'; -const BASE_URL = import.meta.env.VITE_BASE_URL; +const API_URL = import.meta.env.VITE_API_URL; let autoIncrementIdForTask = TASK_DUMMY.length + 1; let autoIncrementIdForTaskFile = TASK_FILE_DUMMY.length + 1; const taskServiceHandler = [ // 일정 목록 조회 API - http.get(`${BASE_URL}/project/:projectId/task`, ({ request, params }) => { + http.get(`${API_URL}/project/:projectId/task`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); @@ -74,7 +74,7 @@ const taskServiceHandler = [ }), // 일정 생성 API - http.post(`${BASE_URL}/project/:projectId/task`, async ({ request, params }) => { + http.post(`${API_URL}/project/:projectId/task`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { assignees, ...taskInfoForm } = (await request.json()) as TaskCreationForm; const projectId = Number(params.projectId); @@ -106,7 +106,7 @@ const taskServiceHandler = [ }), // 일정 단일 파일 업로드 API - http.post(`${BASE_URL}/project/:projectId/task/:taskId/upload`, async ({ request, params }) => { + http.post(`${API_URL}/project/:projectId/task/:taskId/upload`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const taskId = Number(params.taskId); @@ -155,7 +155,7 @@ const taskServiceHandler = [ }), // 일정 파일 다운로드 API - http.get(`${BASE_URL}/file/project/:projectId/:taskId/:fileName`, async ({ request, params }) => { + http.get(`${API_URL}/file/project/:projectId/:taskId/:fileName`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { projectId, taskId, fileName } = params; @@ -188,7 +188,7 @@ const taskServiceHandler = [ }), // 일정 파일 삭제 API - http.delete(`${BASE_URL}/project/:projectId/task/:taskId/file/:fileId`, ({ request, params }) => { + http.delete(`${API_URL}/project/:projectId/task/:taskId/file/:fileId`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const taskId = Number(params.taskId); @@ -222,7 +222,7 @@ const taskServiceHandler = [ }), // 일정 순서 변경 API - http.patch(`${BASE_URL}/project/:projectId/task/order`, async ({ request, params }) => { + http.patch(`${API_URL}/project/:projectId/task/order`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { tasks: taskOrders } = (await request.json()) as TaskOrderForm; const projectId = Number(params.projectId); @@ -256,7 +256,7 @@ const taskServiceHandler = [ }), // 일정 수행자 목록 조회 - http.get(`${BASE_URL}/project/:projectId/task/:taskId/taskuser`, ({ request, params }) => { + http.get(`${API_URL}/project/:projectId/task/:taskId/taskuser`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const taskId = Number(params.taskId); @@ -300,7 +300,7 @@ const taskServiceHandler = [ }), // 일정 파일 목록 조회 API - http.get(`${BASE_URL}/project/:projectId/task/:taskId/attachment`, ({ request, params }) => { + http.get(`${API_URL}/project/:projectId/task/:taskId/attachment`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const taskId = Number(params.taskId); @@ -328,7 +328,7 @@ const taskServiceHandler = [ }), // 일정 정보 수정 API - http.patch(`${BASE_URL}/project/:projectId/task/:taskId`, async ({ request, params }) => { + http.patch(`${API_URL}/project/:projectId/task/:taskId`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const taskId = Number(params.taskId); @@ -361,7 +361,7 @@ const taskServiceHandler = [ }), // 일정 삭제 API - http.delete(`${BASE_URL}/project/:projectId/task/:taskId`, ({ request, params }) => { + http.delete(`${API_URL}/project/:projectId/task/:taskId`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const taskId = Number(params.taskId); @@ -405,7 +405,7 @@ const taskServiceHandler = [ }), // 일정 수행자 추가 API - http.post(`${BASE_URL}/project/:projectId/task/:taskId/assignee`, async ({ request, params }) => { + http.post(`${API_URL}/project/:projectId/task/:taskId/assignee`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const taskAssigneeForm = (await request.json()) as TaskAssigneeForm; const projectId = Number(params.projectId); @@ -446,7 +446,7 @@ const taskServiceHandler = [ }), // 일정 수행자 삭제 API - http.delete(`${BASE_URL}/project/:projectId/task/:taskId/assignee/:userId`, async ({ request, params }) => { + http.delete(`${API_URL}/project/:projectId/task/:taskId/assignee/:userId`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const projectId = Number(params.projectId); const taskId = Number(params.taskId); diff --git a/src/mocks/services/teamServiceHandler.ts b/src/mocks/services/teamServiceHandler.ts index 3ebdc244..8f6ad844 100644 --- a/src/mocks/services/teamServiceHandler.ts +++ b/src/mocks/services/teamServiceHandler.ts @@ -16,11 +16,11 @@ import { convertTokenToUserId } from '@/utils/converter'; import { findAllTeamUsers, findTeamUser, findUser } from '../mockAPI'; import { SearchUser } from '@/types/UserType'; -const BASE_URL = import.meta.env.VITE_BASE_URL; +const API_URL = import.meta.env.VITE_API_URL; const teamServiceHandler = [ // 팀 소속 유저 검색 API - http.get(`${BASE_URL}/team/:teamId/user/search`, ({ request, params }) => { + http.get(`${API_URL}/team/:teamId/user/search`, ({ request, params }) => { const url = new URL(request.url); const nickname = url.searchParams.get('nickname') || ''; const accessToken = request.headers.get('Authorization'); @@ -54,7 +54,7 @@ const teamServiceHandler = [ return HttpResponse.json(matchedSearchUsers); }), // 팀 생성 API - http.post(`${BASE_URL}/team`, async ({ request }) => { + http.post(`${API_URL}/team`, async ({ request }) => { const accessToken = request.headers.get('Authorization'); const { teamName, content, coworkers } = (await request.json()) as TeamForm; @@ -85,7 +85,7 @@ const teamServiceHandler = [ teamId: newTeamId, userId: coworker.userId, roleId: role.roleId, - isPendingApproval: false, + isPendingApproval: true, }); } TEAM_USER_DUMMY.push(...validTeamUsers); @@ -99,7 +99,7 @@ const teamServiceHandler = [ teamId: newTeamId, userId, roleId: creatorRole.roleId, - isPendingApproval: true, + isPendingApproval: false, }); return new HttpResponse(null, { @@ -111,7 +111,7 @@ const teamServiceHandler = [ }), // 팀 탈퇴 API - http.post(`${BASE_URL}/team/:teamId/leave`, ({ request, params }) => { + http.post(`${API_URL}/team/:teamId/leave`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; // 유저 인증 확인 @@ -154,7 +154,7 @@ const teamServiceHandler = [ }), // 팀 삭제 API - http.delete(`${BASE_URL}/team/:teamId`, ({ request, params }) => { + http.delete(`${API_URL}/team/:teamId`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; @@ -210,7 +210,7 @@ const teamServiceHandler = [ }), // 팀 초대 수락 API - http.post(`${BASE_URL}/team/:teamId/invitation/accept`, ({ request, params }) => { + http.post(`${API_URL}/team/:teamId/invitation/accept`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; @@ -225,14 +225,12 @@ const teamServiceHandler = [ (teamUser) => teamUser.teamId === Number(teamId) && teamUser.userId === Number(userId), ); - if (teamUser) { - teamUser.isPendingApproval = true; - } + if (teamUser) teamUser.isPendingApproval = false; return new HttpResponse(null, { status: 200 }); }), // 팀 초대 거절 API - http.post(`${BASE_URL}/team/:teamId/invitation/decline`, ({ request, params }) => { + http.post(`${API_URL}/team/:teamId/invitation/decline`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; @@ -254,7 +252,7 @@ const teamServiceHandler = [ }), // 팀원 목록 조회 API - http.get(`${BASE_URL}/team/:teamId/user`, ({ request, params }) => { + http.get(`${API_URL}/team/:teamId/user`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; @@ -279,7 +277,7 @@ const teamServiceHandler = [ }), // 팀 정보 수정 API - http.patch(`${BASE_URL}/team/:teamId`, async ({ request, params }) => { + http.patch(`${API_URL}/team/:teamId`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; const { teamName, content } = (await request.json()) as TeamForm; @@ -299,7 +297,7 @@ const teamServiceHandler = [ }), // 팀원 추가 API - http.post(`${BASE_URL}/team/:teamId/invitation`, async ({ request, params }) => { + http.post(`${API_URL}/team/:teamId/invitation`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; const { userId, roleName } = (await request.json()) as TeamCoworkerForm; @@ -321,7 +319,7 @@ const teamServiceHandler = [ teamId: Number(teamId), userId: Number(userId), roleId: role.roleId, - isPendingApproval: true, + isPendingApproval: false, }; TEAM_USER_DUMMY.push(newUser); @@ -330,7 +328,7 @@ const teamServiceHandler = [ }), // 팀원 삭제 API - http.delete(`${BASE_URL}/team/:teamId/user/:userId`, ({ request, params }) => { + http.delete(`${API_URL}/team/:teamId/user/:userId`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId, userId } = params; @@ -363,7 +361,7 @@ const teamServiceHandler = [ }), // 팀원 권한 변경 API - http.patch(`${BASE_URL}/team/:teamId/user/:userId/role`, async ({ request, params }) => { + http.patch(`${API_URL}/team/:teamId/user/:userId/role`, async ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId, userId } = params; const { roleName } = (await request.json()) as TeamCoworkerForm; diff --git a/src/mocks/services/userServiceHandler.ts b/src/mocks/services/userServiceHandler.ts index 36719709..77fe1426 100644 --- a/src/mocks/services/userServiceHandler.ts +++ b/src/mocks/services/userServiceHandler.ts @@ -5,14 +5,14 @@ import { convertTokenToUserId } from '@utils/converter'; import { fileNameParser } from '@utils/fileNameParser'; import type { Team } from '@/types/TeamType'; import type { Role } from '@/types/RoleType'; -import type { EditUserInfoForm, EditUserLinksForm, User } from '@/types/UserType'; +import type { EditUserInfoForm, EditUserLinksForm, SearchUser, User } from '@/types/UserType'; -const BASE_URL = import.meta.env.VITE_BASE_URL; +const API_URL = import.meta.env.VITE_API_URL; // ToDo: Dummy 데이터 Hash화 한 곳으로 모으기 const userServiceHandler = [ // 유저 정보 변경 API - http.patch(`${BASE_URL}/user`, async ({ request }) => { + http.patch(`${API_URL}/user`, async ({ request }) => { const accessToken = request.headers.get('Authorization'); if (!accessToken) return new HttpResponse(null, { status: 401 }); @@ -46,7 +46,7 @@ const userServiceHandler = [ return HttpResponse.json(userInfo, { status: 200 }); }), // 링크 변경 API - http.patch(`${BASE_URL}/user/links`, async ({ request }) => { + http.patch(`${API_URL}/user/links`, async ({ request }) => { const accessToken = request.headers.get('Authorization'); if (!accessToken) return new HttpResponse(null, { status: 401 }); @@ -67,7 +67,7 @@ const userServiceHandler = [ return HttpResponse.json(null, { status: 200 }); }), // 유저 프로필 이미지 업로드 API - http.post(`${BASE_URL}/user/profile/image`, async ({ request }) => { + http.post(`${API_URL}/user/profile/image`, async ({ request }) => { const accessToken = request.headers.get('Authorization'); if (!accessToken) return new HttpResponse(null, { status: 401 }); @@ -111,7 +111,7 @@ const userServiceHandler = [ return HttpResponse.json({ imageName: uploadName }, { status: 200 }); }), // 유저 프로필 이미지 조회 API - http.get(`${BASE_URL}/file/profile/:fileName`, async ({ request, params }) => { + http.get(`${API_URL}/file/profile/:fileName`, async ({ request, params }) => { const { fileName } = params; const accessToken = request.headers.get('Authorization'); @@ -145,7 +145,7 @@ const userServiceHandler = [ }); }), // 전체 팀 목록 조회 API (가입한 팀, 대기중인 팀) - http.get(`${BASE_URL}/user/team`, ({ request }) => { + http.get(`${API_URL}/user/team`, ({ request }) => { const accessToken = request.headers.get('Authorization'); if (!accessToken) return new HttpResponse(null, { status: 401 }); @@ -186,6 +186,27 @@ const userServiceHandler = [ return HttpResponse.json(teamJoinStatusList); }), + + // 전체 유저 검색 + http.get(`${API_URL}/user/search`, ({ request }) => { + const url = new URL(request.url); + const nickname = url.searchParams.get('nickname') || ''; + const accessToken = request.headers.get('Authorization'); + + // 유저 인증 확인 + if (!accessToken) return new HttpResponse(null, { status: 401 }); + + // 유저 ID 정보 취득 + const userId = convertTokenToUserId(accessToken); + if (!userId) return new HttpResponse(null, { status: 401 }); + + // 접두사(nickname)와 일치하는 유저 정보 최대 5명 추출 + const matchedSearchUsers = USER_DUMMY.filter((user) => user.nickname.startsWith(nickname)) + .slice(0, 5) + .map((user) => ({ userId: user.userId, nickname: user.nickname })); + + return HttpResponse.json(matchedSearchUsers); + }), ]; export default userServiceHandler; diff --git a/src/pages/NotFoundPage.tsx b/src/pages/NotFoundPage.tsx index 192f156c..62256fb2 100644 --- a/src/pages/NotFoundPage.tsx +++ b/src/pages/NotFoundPage.tsx @@ -1,10 +1,12 @@ import { PiSmileySadFill } from 'react-icons/pi'; import { Link } from 'react-router-dom'; +import Meta from '@components/common/Meta'; import Header from '@components/common/Header'; export default function NotFoundPage() { return ( <> +
diff --git a/src/pages/project/CalendarPage.tsx b/src/pages/project/CalendarPage.tsx index 4711bf46..7911583e 100644 --- a/src/pages/project/CalendarPage.tsx +++ b/src/pages/project/CalendarPage.tsx @@ -1,6 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { DateTime, Settings } from 'luxon'; import { Calendar, luxonLocalizer, Views } from 'react-big-calendar'; +import Meta from '@components/common/Meta'; import Spinner from '@components/common/Spinner'; import DetailModalTask from '@components/modal/task/DetailModalTask'; import UpdateModalTask from '@components/modal/task/UpdateModalTask'; @@ -117,6 +118,7 @@ export default function CalendarPage() { ) : ( <> + - - {(statusDropProvided) => ( -
- {localStatusTaskList.map((statusTask) => ( - - ))} - {statusDropProvided.placeholder} -
- )} -
- + <> + + + + {(statusDropProvided) => ( +
+ {localStatusTaskList.map((statusTask) => ( + + ))} + {statusDropProvided.placeholder} +
+ )} +
+
+ ); } diff --git a/src/pages/setting/TeamInvitedPage.tsx b/src/pages/setting/TeamInvitedPage.tsx index c77e1b73..82ebb27e 100644 --- a/src/pages/setting/TeamInvitedPage.tsx +++ b/src/pages/setting/TeamInvitedPage.tsx @@ -1,3 +1,4 @@ +import Meta from '@components/common/Meta'; import Spinner from '@components/common/Spinner'; import { useApproveTeamInvitation, useRejectTeamInvitation, useReadTeams } from '@hooks/query/useTeamQuery'; @@ -8,50 +9,53 @@ export default function InvitedTeamPage() { if (isLoading) return ; return ( -
- {invitedTeamList && invitedTeamList.length > 0 ? ( -
    - {invitedTeamList.map((invite) => ( -
  • -
    -
    - team -

    {invite.teamName}

    + <> + +
    + {invitedTeamList && invitedTeamList.length > 0 ? ( +
      + {invitedTeamList.map((invite) => ( +
    • +
      +
      + team +

      {invite.teamName}

      +
      +
      + head +

      {invite.creator}

      +
      +
      + desc +

      {invite.content}

      +
      -
      - head -

      {invite.creator}

      +
      + +
      -
      - desc -

      {invite.content}

      -
      -
      -
      - - -
      -
    • - ))} -
    - ) : ( -
    - 현재 가입 대기중인 팀이 없습니다!
    - 팀에 가입해 보세요 😄 -
    - )} -
    +
  • + ))} +
+ ) : ( +
+ 현재 가입 대기중인 팀이 없습니다!
+ 팀에 가입해 보세요 😄 +
+ )} +
+ ); } diff --git a/src/pages/setting/TeamJoinedPage.tsx b/src/pages/setting/TeamJoinedPage.tsx index b12f3618..3892b81c 100644 --- a/src/pages/setting/TeamJoinedPage.tsx +++ b/src/pages/setting/TeamJoinedPage.tsx @@ -1,6 +1,6 @@ +import Meta from '@components/common/Meta'; import Spinner from '@components/common/Spinner'; import { useDeleteTeam, useLeaveTeam, useReadTeams } from '@hooks/query/useTeamQuery'; - import { useStore } from '@stores/useStore'; export default function JoinedTeamPage() { @@ -11,52 +11,55 @@ export default function JoinedTeamPage() { if (isLoading) return ; return ( -
- {joinedTeamList && joinedTeamList.length > 0 ? ( -
    - {joinedTeamList.map((team) => ( -
  • -
    -
    - team -

    {team.teamName}

    -
    -
    - head -

    {team.creator}

    + <> + +
    + {joinedTeamList && joinedTeamList.length > 0 ? ( +
      + {joinedTeamList.map((team) => ( +
    • +
      +
      + team +

      {team.teamName}

      +
      +
      + head +

      {team.creator}

      +
      +
      + desc +

      {team.content}

      +
      -
      - desc -

      {team.content}

      -
      -
    -
    - {team.creatorId === userInfo.userId && ( +
    + {team.creatorId === userInfo.userId && ( + + )} - )} - -
    -
  • - ))} -
- ) : ( -
- 현재 가입된 팀이 없습니다!
- 팀에 가입해 보세요 😄 -
- )} -
+
+ + ))} + + ) : ( +
+ 현재 가입된 팀이 없습니다!
+ 팀에 가입해 보세요 😄 +
+ )} + + ); } diff --git a/src/pages/setting/UserAuthenticatePage.tsx b/src/pages/setting/UserAuthenticatePage.tsx index 7bd03079..2dbfc99e 100644 --- a/src/pages/setting/UserAuthenticatePage.tsx +++ b/src/pages/setting/UserAuthenticatePage.tsx @@ -3,6 +3,7 @@ import { AxiosError } from 'axios'; import { useForm } from 'react-hook-form'; import { USER_AUTH_VALIDATION_RULES } from '@constants/formValidationRules'; import useEmailVerification from '@hooks/useEmailVerification'; +import Meta from '@components/common/Meta'; import ValidationInput from '@components/common/ValidationInput'; import VerificationButton from '@components/user/auth-form/VerificationButton'; import useToast from '@hooks/useToast'; @@ -38,41 +39,44 @@ function UserAuthenticatePage() { }; return ( -
-
-

- 개인정보 변경을 위한 이메일 인증 단계입니다. -
- 인증요청 버튼 클릭 후, 이메일로 발송된 인증번호를 입력해주세요. -

+ <> + +
+
+

+ 개인정보 변경을 위한 이메일 인증 단계입니다. +
+ 인증요청 버튼 클릭 후, 이메일로 발송된 인증번호를 입력해주세요. +

-
- {/* 이메일 */} - - - {isVerificationRequested && ( + + {/* 이메일 */} - )} - {/* 인증 요청 및 확인 버튼 */} - requestVerificationCode(watch('email')))} - expireVerificationCode={expireVerificationCode} - buttonLabel="확인" - /> - + {isVerificationRequested && ( + + )} + + {/* 인증 요청 및 확인 버튼 */} + requestVerificationCode(watch('email')))} + expireVerificationCode={expireVerificationCode} + buttonLabel="확인" + /> + +
-
+ ); } diff --git a/src/pages/setting/UserPasswordSettingPage.tsx b/src/pages/setting/UserPasswordSettingPage.tsx index b7b8cb92..9d538837 100644 --- a/src/pages/setting/UserPasswordSettingPage.tsx +++ b/src/pages/setting/UserPasswordSettingPage.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { AxiosError } from 'axios'; import { useForm } from 'react-hook-form'; +import Meta from '@components/common/Meta'; import ValidationInput from '@components/common/ValidationInput'; import { USER_AUTH_VALIDATION_RULES } from '@constants/formValidationRules'; import useToast from '@hooks/useToast'; @@ -43,38 +44,41 @@ export default function UserPasswordSettingPage() { }; return ( -
-
- {/* 현재 비밀번호 */} - + <> + +
+ + {/* 현재 비밀번호 */} + - {/* 신규 비밀번호 */} - + {/* 신규 비밀번호 */} + - {/* 신규 비밀번호 확인 */} - + {/* 신규 비밀번호 확인 */} + -
- -
- -
+
+ +
+ +
+ ); } diff --git a/src/pages/setting/UserSettingPage.tsx b/src/pages/setting/UserSettingPage.tsx index edad2b27..caef0dd1 100644 --- a/src/pages/setting/UserSettingPage.tsx +++ b/src/pages/setting/UserSettingPage.tsx @@ -1,5 +1,6 @@ import { FormProvider, useForm } from 'react-hook-form'; import { USER_AUTH_VALIDATION_RULES } from '@constants/formValidationRules'; +import Meta from '@components/common/Meta'; import ValidationInput from '@components/common/ValidationInput'; import ProfileImageContainer from '@components/user/auth-form/ProfileImageContainer'; import LinkContainer from '@components/user/auth-form/LinkContainer'; @@ -48,74 +49,77 @@ export default function UserSettingPage() { }; return ( - -
-
- {/* 프로필 이미지 */} - setValue('profileImageName', url)} - /> - - {/* 아이디 */} - + <> + + +
+ + {/* 프로필 이미지 */} + setValue('profileImageName', url)} + /> - {/* 이메일 */} - + {/* 아이디 */} + - {/* 닉네임, 중복 확인 */} - + {/* 이메일 */} + - {/* 자기소개 */} -
- -