diff --git a/src/constants/cookie.ts b/src/constants/cookie.ts index 9d0d861..8d1febb 100644 --- a/src/constants/cookie.ts +++ b/src/constants/cookie.ts @@ -1,4 +1,5 @@ export const COOKIE_KEY = { ACCESS_TOKEN: 'depmat', REFRESH_TOKEN: 'depmrt', + ROLE: 'depmrole', }; diff --git a/src/features/admin/attendance/UserItem.tsx b/src/features/admin/attendance/UserItem.tsx index b25f6fe..ed1bd0d 100644 --- a/src/features/admin/attendance/UserItem.tsx +++ b/src/features/admin/attendance/UserItem.tsx @@ -14,7 +14,6 @@ function UserItem(props: AttendanceItemType) { const onChange = (value: ATTENDANCE_STATUS) => { // optimistic update setStatus(value); - console.log('value: ', value); // api call mutate({ attendanceId: props.attendanceId, attendanceStatus: value }); diff --git a/src/features/login/CertifyStep.tsx b/src/features/login/CertifyStep.tsx index 7e61cf5..ce785d2 100644 --- a/src/features/login/CertifyStep.tsx +++ b/src/features/login/CertifyStep.tsx @@ -2,7 +2,6 @@ import { useState } from 'react'; import { useRouter } from 'next/router'; import { usePostLogin } from '@/hooks/apis/auth/usePostLogin'; -import { getUserRoleByToken } from '@/hooks/apis/user/useGetInfo'; import LoginLayout from './LoginLayout'; import PasswordInput from './PasswordInput'; @@ -22,8 +21,9 @@ function CertifyStep(props: Props) { const isDisabled = value.length !== PASSWORD_LENGTH || Boolean(error); const { mutate } = usePostLogin({ - onSuccess: async ({ accessToken }) => { - const role = await getUserRoleByToken(accessToken); + onSuccess: async (data) => { + const role = data.member.generations[0].role; + if (role === 'ORGANIZER') { router.replace('/admin/attendance'); } else { diff --git a/src/features/login/JoinCompleteStep.tsx b/src/features/login/JoinCompleteStep.tsx index 20e978c..e75ef86 100644 --- a/src/features/login/JoinCompleteStep.tsx +++ b/src/features/login/JoinCompleteStep.tsx @@ -1,18 +1,18 @@ import Image from 'next/image'; import { useRouter } from 'next/router'; +import Cookies from 'js-cookie'; import styled from 'styled-components'; -import { useGetInfo } from '@/hooks/apis/user/useGetInfo'; - import LoginLayout from './LoginLayout'; import Img from './welcome-2.png'; function JoinCompleteStep() { const router = useRouter(); - const { data } = useGetInfo(); const onNext = () => { - if (data?.generations[0].role === 'ORGANIZER') { + const roleData = Cookies.get('role'); + + if (roleData?.includes('ORGANIZER')) { router.replace('/admin/attendance'); } else { router.replace('/'); diff --git a/src/hooks/apis/auth/usePostLogin.ts b/src/hooks/apis/auth/usePostLogin.ts index 5291885..cf14cf6 100644 --- a/src/hooks/apis/auth/usePostLogin.ts +++ b/src/hooks/apis/auth/usePostLogin.ts @@ -5,6 +5,7 @@ import Cookies from 'js-cookie'; import type { CustomError } from '@/apis'; import { api } from '@/apis'; import { COOKIE_KEY } from '@/constants/cookie'; +import type { UserInfo } from '@/hooks/apis/user/user'; interface PostLoginRequest { email: string; @@ -14,6 +15,7 @@ interface PostLoginRequest { interface PostLoginResponse { accessToken: string; refreshToken: string; + member: UserInfo; } const postLogin = async (request: PostLoginRequest): Promise => { @@ -27,6 +29,9 @@ export const usePostLogin = (options?: UseMutationOptions { Cookies.set(COOKIE_KEY.ACCESS_TOKEN, data.accessToken, { expires: 1 }); Cookies.set(COOKIE_KEY.REFRESH_TOKEN, data.refreshToken, { expires: 7 }); + Cookies.set(COOKIE_KEY.ROLE, `${data.member.generations[0].generationId}-${data.member.generations[0].role}`, { + expires: 1, + }); options?.onSuccess?.({ ...data }, ...rest); }, diff --git a/src/hooks/apis/user/useGetInfo.ts b/src/hooks/apis/user/useGetInfo.ts index 07f1804..23f9ba9 100644 --- a/src/hooks/apis/user/useGetInfo.ts +++ b/src/hooks/apis/user/useGetInfo.ts @@ -4,21 +4,13 @@ import { useQuery } from '@tanstack/react-query'; import type { CustomError } from '@/apis'; import { api } from '@/apis'; -type Role = 'ORGANIZER' | 'MEMBER'; - -interface GetInfoResponse { - id: string; - name: string; - email: string; - generations: { - generationId: number; - role: Role; - position: string; - }[]; -} +const GET_INFO_URL = '/v1/me'; +import type { Role, UserInfo } from './user'; + +type GetInfoResponse = UserInfo; export const getInfoByToken = async (token: string): Promise => { - return await api.get('/v1/me', { + return await api.get(GET_INFO_URL, { headers: { Authorization: `Bearer ${token}`, }, @@ -31,7 +23,7 @@ export const getUserRoleByToken = async (token: string): Promise => { return generations[0].role; }; -const getInfo = () => api.get('/v1/me'); +export const getInfo = () => api.get(GET_INFO_URL); export const useGetInfo = (options?: UseQueryOptions) => useQuery({ diff --git a/src/hooks/apis/user/user.d.ts b/src/hooks/apis/user/user.d.ts new file mode 100644 index 0000000..5e77923 --- /dev/null +++ b/src/hooks/apis/user/user.d.ts @@ -0,0 +1,12 @@ +export type Role = 'ORGANIZER' | 'MEMBER'; + +export interface UserInfo { + id: string; + name: string; + email: string; + generations: { + generationId: number; + role: Role; + position: string; + }[]; +} diff --git a/src/middleware.ts b/src/middleware.ts index 21bf8dd..a5dd693 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -25,6 +25,13 @@ export async function middleware(request: NextRequest) { } } + if (request.nextUrl.pathname.startsWith('/admin')) { + const role = request.cookies.get(COOKIE_KEY.ROLE)?.value; + if (!role?.includes('ORGANIZER')) { + return NextResponse.redirect(new URL('/', request.url)); + } + } + return response; } diff --git a/src/pages/admin/attendance.tsx b/src/pages/admin/attendance.tsx index e768030..d7daab8 100644 --- a/src/pages/admin/attendance.tsx +++ b/src/pages/admin/attendance.tsx @@ -5,7 +5,6 @@ import styled from 'styled-components'; import { BottomNav } from '@/components/BottomNav'; import IconButton from '@/components/Button/IconButton'; import Layout from '@/components/Layout'; -import { ATTENDANCE_STATUS } from '@/constants/attendance'; import { ADMIN_NAV_ITEMS } from '@/constants/bottomNav'; import TeamSelect from '@/features/admin/attendance/TeamSelect'; import UserItem from '@/features/admin/attendance/UserItem'; @@ -125,71 +124,3 @@ const UserSection = styled.section` border-top: 1px solid ${({ theme }) => theme.color.gray_200}; } `; - -const DUMMY_DATA: { - id: number; - name: string; - position: string; - status: ATTENDANCE_STATUS; -}[] = [ - { - id: 1, - name: '김민수', - position: '개발자', - status: ATTENDANCE_STATUS.출석대기, - }, - { - id: 2, - name: '홍길동', - position: '디자이너', - status: ATTENDANCE_STATUS.지각, - }, - { - id: 3, - name: '이영희', - position: '디자이너', - status: ATTENDANCE_STATUS.출석, - }, - { - id: 4, - name: '박철수', - position: '디자이너', - status: ATTENDANCE_STATUS.결석, - }, - { - id: 5, - name: '김지영', - position: '디자이너', - status: ATTENDANCE_STATUS.출석대기, - }, - { - id: 6, - name: '이승호', - position: '디자이너', - status: ATTENDANCE_STATUS.출석대기, - }, - { - id: 7, - name: '박지민', - position: '디자이너', - status: ATTENDANCE_STATUS.출석대기, - }, - { - id: 8, - name: '박지민', - position: '디자이너', - status: ATTENDANCE_STATUS.출석대기, - }, - { - id: 9, - name: '박지민', - position: '디자이너', - status: ATTENDANCE_STATUS.출석대기, - }, - { - id: 10, - name: '박지민', - position: '디자이너', - status: ATTENDANCE_STATUS.출석대기, - }, -]; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 79c7086..ce08957 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -52,7 +52,6 @@ const Home = () => { // NOTE: 유저 정보 가져오기 const { data } = useGetInfo(); - console.log('data: ', data); const handleClickCheckIn = () => { mutate();