diff --git a/Dockerfile b/Dockerfile index 15da58dc..dc81090b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,11 +4,10 @@ COPY package*.json ./ COPY . . ENV REACT_APP_KAKAO_API_KEY=d573e4a7b2fcae0f0289d5807605d726 -ENV REACT_APP_API_URL=http://localhost:8080 RUN npm ci RUN npm run build RUN npm install -g serve EXPOSE 3000 -CMD ["serve", "build"] +CMD ["serve", "-s", "build"] diff --git a/k8s/confingMap.yaml b/k8s/confingMap.yaml new file mode 100644 index 00000000..012f6ef7 --- /dev/null +++ b/k8s/confingMap.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: frontconfig +data: + nginx.conf: |- + server { + root /build; + error_page 404 index.html; + location / { + try_files $uri $uri/ /index.html; + } + } \ No newline at end of file diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index c2abdcf9..4c723021 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -10,8 +10,15 @@ spec: metadata: labels: app: frontend - spec: + spec: containers: - name: frontend # 여러분의 image 주소를 입력해주세요. - image: krmp-d2hub-idock.9rum.cc/dev-test/repo_0b6943ee814a \ No newline at end of file + image: krmp-d2hub-idock.9rum.cc/dev-test/repo_9d9678dcd735 + volumeMounts: + - name: config + mountPath: /etc/nginx/nginx.conf + volumes: + - name: config + configMap: + name: frontconfig \ No newline at end of file diff --git a/playwright.config.ts b/playwright.config.ts index fa8072fb..9b9860d0 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -2,8 +2,9 @@ import { defineConfig, devices } from '@playwright/test'; import path from 'path'; require('dotenv').config(); -export const ADMINSTATE = path.join(__dirname, './playwright/.auth/admin.json'); -export const ALBASTATE = path.join(__dirname, './playwright/.auth/alba.json'); +const ADMINSTATE = path.join(__dirname, './tests/state/admin.json'); +const ALBASTATE = path.join(__dirname, './tests/state/alba.json'); + /** * See https://playwright.dev/docs/test-configuration. */ @@ -25,7 +26,6 @@ export default defineConfig({ use: { /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: `${process.env.REACT_APP_BASE_URL}`, - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', }, diff --git a/src/App.tsx b/src/App.tsx index 67bbbc37..9e4e7285 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,6 @@ import ViewPortContainer from 'components/@commons/ViewPortContainer'; import ErrorFallback from 'error/ErrorFallback'; import { Provider } from 'jotai'; import HomeIndex from 'pages/HomeIndex'; -import KakaoAuthPage from 'pages/KakaoAuthPage'; import SelectWeekPage from 'pages/SelectWeekPage'; import SignupPage from 'pages/SignupPage'; import AddGroupPage from 'pages/admin/AddGroupPage'; @@ -12,6 +11,7 @@ import ApplicationClosePage from 'pages/admin/ApplicationClosePage'; import ApplicationOpenPage from 'pages/admin/ApplicationOpenPage'; import ApplyPage from 'pages/alba/ApplyPage'; import InvitedPage from 'pages/alba/InvitedPage'; +import KakaoAuthPage from 'pages/auth/KakaoAuthPage'; import LogoutOnlyPrivate from 'privateRoutes/LogoutOnlyPrivate'; import UserTypePrivate from 'privateRoutes/UserTypePrivate'; import { ErrorBoundary } from 'react-error-boundary'; diff --git a/src/apis/convertURI.ts b/src/apis/convertURI.ts index 36c035e1..22746fe1 100644 --- a/src/apis/convertURI.ts +++ b/src/apis/convertURI.ts @@ -1,8 +1,8 @@ const staticServerUrl_: string = process.env.REACT_APP_PATH || ''; -export const apiURL: string = process.env.REACT_APP_API_URL; export const convertPath = (path: string): string => { return staticServerUrl_ + path; }; -export const baseURL = new URL(window.location.href).origin; +export const baseURL = process.env.REACT_APP_BASE_URL || new URL(window.location.href).origin; +export const apiURL: string = process.env.REACT_APP_API_URL || baseURL + '/api'; diff --git a/src/apis/instance.ts b/src/apis/instance.ts index 6babdcba..40ea75f6 100644 --- a/src/apis/instance.ts +++ b/src/apis/instance.ts @@ -1,6 +1,6 @@ -import axios from 'axios'; import { apiURL } from 'apis/convertURI'; -import { getLoginData } from 'utils/loginDatahandlers'; +import axios from 'axios'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; const instance = axios.create({ baseURL: apiURL, @@ -12,7 +12,7 @@ const instance = axios.create({ export const requestDefault = instance.interceptors.request.use( (config) => { // 로그인 상태일 때 토큰 싣기 - const loginState = getLoginData(); + const loginState = loginDatahandlers.getLoginData(); if (loginState.isLogin) { config.headers.Authorization = loginState.token; } diff --git a/src/apis/types.ts b/src/apis/types.ts index e6e5bdd4..e0e07f04 100644 --- a/src/apis/types.ts +++ b/src/apis/types.ts @@ -50,7 +50,7 @@ export interface ErrorData { response?: { status: number; data?: { - code: number; + errorCode: number; }; }; } diff --git a/src/components/@commons/BorderBox.tsx b/src/components/@commons/BorderBox.tsx index b5799748..9826721e 100644 --- a/src/components/@commons/BorderBox.tsx +++ b/src/components/@commons/BorderBox.tsx @@ -7,11 +7,12 @@ interface Props { border?: boolean; borderColor?: string; children: React.ReactNode; + as?: string; } -const BorderBox = ({ width, gradation, border, borderColor, children }: Props): JSX.Element => { +const BorderBox = ({ width, gradation, border, borderColor, children, as }: Props): JSX.Element => { return ( - + {children} ); diff --git a/src/components/@commons/PageContainer.tsx b/src/components/@commons/PageContainer.tsx index efd57b7d..7d449d4e 100644 --- a/src/components/@commons/PageContainer.tsx +++ b/src/components/@commons/PageContainer.tsx @@ -1,8 +1,8 @@ +import { AdminBottomNB, AlbaBottomNB } from 'components/BottomNB/BottomNB'; +import HeaderNB from 'components/HeaderNB/HeaderNB'; import React from 'react'; import styled from 'styled-components'; -import HeaderNB from 'components/HeaderNB/HeaderNB'; -import { AlbaBottomNB, AdminBottomNB } from 'components/BottomNB/BottomNB'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; interface Props { children: React.ReactNode; @@ -23,7 +23,7 @@ const PageContainer = ({ justify, maxWidth, }: Props): JSX.Element => { - const isAdmin = getLoginData().isAdmin; + const isAdmin = loginDatahandlers.getLoginData().isAdmin; return ( <> diff --git a/src/components/Calendar/CalendarStyle.tsx b/src/components/Calendar/CalendarStyle.tsx index d0af153d..9e076394 100644 --- a/src/components/Calendar/CalendarStyle.tsx +++ b/src/components/Calendar/CalendarStyle.tsx @@ -20,7 +20,7 @@ export const BadgeText = styled.span` } `; -export const Badge = styled.ol<{ $color?: string }>` +export const Badge = styled.li<{ $color?: string }>` background-color: ${(props) => props.$color}; display: flex; @@ -30,7 +30,7 @@ export const Badge = styled.ol<{ $color?: string }>` border-radius: 8px; `; -export const BadgeCont = styled.div` +export const BadgeCont = styled.ol` width: 100%; display: flex; flex-direction: column; diff --git a/src/components/DailyWorkersTable/index.tsx b/src/components/DailyWorkersTable/index.tsx index 9b90e667..5d6e128b 100644 --- a/src/components/DailyWorkersTable/index.tsx +++ b/src/components/DailyWorkersTable/index.tsx @@ -7,7 +7,7 @@ import { NameBox, TitleBox } from './styles'; export const DailyWorkersTable = ({ dailyData }: { dailyData: TimeWorkerListData[] | undefined }): JSX.Element => { return ( - + {dailyData?.map((timeData: TimeWorkerListData, timeindex) => ( @@ -18,9 +18,9 @@ export const DailyWorkersTable = ({ dailyData }: { dailyData: TimeWorkerListData {strTimeProcessor(timeData.startTime)} ~ {strTimeProcessor(timeData.endTime)} - + {timeData.workerList.map((w: UserData, i) => ( - + {w.name} ))} @@ -33,7 +33,7 @@ export const DailyWorkersTable = ({ dailyData }: { dailyData: TimeWorkerListData export const NotFixedDateBox = (): JSX.Element => { return ( - + 아직 확정된 스케줄이 없습니다 diff --git a/src/components/HeaderNB/HeaderNB.tsx b/src/components/HeaderNB/HeaderNB.tsx index 27241f32..39fdd582 100644 --- a/src/components/HeaderNB/HeaderNB.tsx +++ b/src/components/HeaderNB/HeaderNB.tsx @@ -10,9 +10,9 @@ import { import Sidebar from 'components/Sidebar'; import { useState } from 'react'; import { useLocation } from 'react-router-dom'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; -const isAdmin = getLoginData().isAdmin; +const isAdmin = loginDatahandlers.getLoginData().isAdmin; const HeaderNB = (): JSX.Element => { const [isOpen, setIsOpen] = useState(false); @@ -29,7 +29,7 @@ const HeaderNB = (): JSX.Element => { - + {isAdmin ? adminTitle[nowPath] : albaTitle[nowPath]} diff --git a/src/components/LoginSignUpButton/LoginOrSignup.tsx b/src/components/LoginSignUpButton/LoginOrSignup.tsx index c7283721..07036245 100644 --- a/src/components/LoginSignUpButton/LoginOrSignup.tsx +++ b/src/components/LoginSignUpButton/LoginOrSignup.tsx @@ -1,7 +1,6 @@ import FlexContainer from 'components/@commons/FlexContainer'; import SubmitButton from 'components/@commons/SubmitButton'; -import useLogin from 'hooks/auth/useLogin'; -import React from 'react'; +import useLogin from 'pages/auth/hooks/useLogin'; interface Props { redirectPage?: string; diff --git a/src/components/Sidebar/index.tsx b/src/components/Sidebar/index.tsx index c2dea600..4b49fd7b 100644 --- a/src/components/Sidebar/index.tsx +++ b/src/components/Sidebar/index.tsx @@ -1,11 +1,11 @@ import { UserData } from 'apis/types'; import Loader from 'components/Suspenses/Loader'; import GetInviteKeyModal from 'components/modals/GetInviteKeyModal'; -import useLogin from 'hooks/auth/useLogin'; import useGetMyInfo from 'hooks/useGetMyInfo'; import useModal from 'hooks/useModal'; +import useLogin from 'pages/auth/hooks/useLogin'; import { Suspense } from 'react'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; import FlexContainer from '../@commons/FlexContainer'; import Text from '../@commons/Text'; import { HorizontalLine, SidebarBackground, SidebarBox } from './styles'; @@ -25,7 +25,7 @@ const Sidebar = ({ closeHandler }: { closeHandler: () => void }): JSX.Element => export default Sidebar; const SideBarContent = () => { - const isAdmin = getLoginData().isAdmin; + const isAdmin = loginDatahandlers.getLoginData().isAdmin; const { userName, userType, groupName, members } = useGetMyInfo(); return ( @@ -92,11 +92,11 @@ const SideBarMemberList = ({ memberList }: { memberList?: UserData[] }) => { - + {memberList?.map((member: UserData) => ( -
    +
  1. {member.name} -
+ ))}
diff --git a/src/components/WeekBar/index.tsx b/src/components/WeekBar/index.tsx new file mode 100644 index 00000000..58bfaaf8 --- /dev/null +++ b/src/components/WeekBar/index.tsx @@ -0,0 +1,32 @@ +import FlexContainer from 'components/@commons/FlexContainer'; +import Text from 'components/@commons/Text'; +import styled from 'styled-components'; +import weekdayArray from 'utils/weekdayArray'; + +const WeekBar = ({ day, selectDayHandler }: { day: number; selectDayHandler: (i: number) => void }): JSX.Element => { + return ( + + {weekdayArray.map((e, i) => ( + + ))} + + ); +}; + +export default WeekBar; + +const Button = styled.button<{ $isSelected: boolean }>` + width: 10%; + aspect-ratio: 1; + + background: ${(props) => (props.$isSelected ? props.theme.color.yellow : props.theme.color.lightGray)}; + border: 1px solid; + border-color: ${({ theme }) => theme.color.textColor}; + border-radius: 100%; + + display: flex; + justify-content: center; + align-items: center; +`; diff --git a/src/components/modals/GetInviteKeyModal/index.tsx b/src/components/modals/GetInviteKeyModal/index.tsx index 454f26f7..811548da 100644 --- a/src/components/modals/GetInviteKeyModal/index.tsx +++ b/src/components/modals/GetInviteKeyModal/index.tsx @@ -19,7 +19,7 @@ const GetInviteKeyModal = (): JSX.Element => { const link = `${baseURL}/invited/${inviteKeyData?.data.invitationKey}`; return ( - + 초대 링크 diff --git a/src/error/ErrorFallback.tsx b/src/error/ErrorFallback.tsx index c52c7241..21e826cf 100644 --- a/src/error/ErrorFallback.tsx +++ b/src/error/ErrorFallback.tsx @@ -1,18 +1,17 @@ -import React from 'react'; import { convertPath } from 'apis/convertURI'; -import { useNavigate } from 'react-router-dom'; -import ErrorPage from './ErrorPage'; import { ErrorFallbackProps } from 'apis/types'; import { AdminNoGroupPage, AdminNoMemberPage } from 'pages/admin/ETCMainPage'; import { AlbaNoGroupPage } from 'pages/alba/AlbaMainIndex'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { useNavigate } from 'react-router-dom'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; +import ErrorPage from './ErrorPage'; const ErrorFallback = ({ error, resetErrorBoundary }: ErrorFallbackProps) => { console.log(error); const navigate = useNavigate(); - const isAdmin = getLoginData().isAdmin; - const code = error.response?.data?.code || 0; + const isAdmin = loginDatahandlers.getLoginData().isAdmin; + const code = error.response?.data?.errorCode || 0; switch (code) { case -10000: diff --git a/src/error/defaultErrorHandler.ts b/src/error/defaultErrorHandler.ts index d32f9f0a..6ef19a89 100644 --- a/src/error/defaultErrorHandler.ts +++ b/src/error/defaultErrorHandler.ts @@ -1,6 +1,6 @@ import { convertPath } from 'apis/convertURI'; import { ErrorData } from 'apis/types'; -import { removeLoginData } from 'utils/loginDatahandlers'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; export const defaultErrorHandler = (error: ErrorData) => { console.log('defaultErrorHandler', error); @@ -11,13 +11,13 @@ export const defaultErrorHandler = (error: ErrorData) => { if (error.response === undefined) { alert('서버 오류'); - removeLoginData(); + loginDatahandlers.removeLoginData(); return; } // 서버 에러 응답 - console.log('defaultErrorHandler', error.response?.data); - const code = error.response.data?.code; + console.log('defaultErrorHandler', error.response); + const code = error.response.data?.errorCode; switch (code) { case -10000: // 타임 아웃 @@ -66,13 +66,13 @@ export const defaultErrorHandler = (error: ErrorData) => { case -21000: // 토큰 유효하지 않음 alert('로그인이 만료되었습니다.'); - removeLoginData(); + loginDatahandlers.removeLoginData(); redirect(convertPath('/')); return; default: alert(`잘못된 접근입니다`); - removeLoginData(); + loginDatahandlers.removeLoginData(); redirect(convertPath('/')); return; } diff --git a/src/hooks/SchedulePage/useSchedule.ts b/src/hooks/SchedulePage/useSchedule.ts deleted file mode 100644 index 81078b3b..00000000 --- a/src/hooks/SchedulePage/useSchedule.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useAtomValue, useSetAtom } from 'jotai'; -import React from 'react'; -import { dateAtom, monthAtom } from 'pages/SchedulePage/states'; - -const useSchedule = () => { - const { year, month } = useAtomValue(monthAtom); - - const setSelectedDate = useSetAtom(dateAtom); - const dateOnClick = (isFixed: boolean, date: string) => { - setSelectedDate({ date: date, isFixed: isFixed }); - }; - - React.useEffect(() => { - setSelectedDate({ date: '', isFixed: false }); - }, [year, month]); - - return { dateOnClick }; -}; - -export default useSchedule; diff --git a/src/hooks/SelectWeekPage/useSelectWeek.ts b/src/hooks/SelectWeekPage/useSelectWeek.ts deleted file mode 100644 index e9c3c17b..00000000 --- a/src/hooks/SelectWeekPage/useSelectWeek.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { WeekStatusData, WeekStatusTypes } from 'apis/types'; -import { useAtomValue, useSetAtom } from 'jotai'; -import { selectedWeekAtom, weekStatusMonthAtom } from 'pages/SelectWeekPage/states'; -import React from 'react'; -import { getLoginData } from 'utils/loginDatahandlers'; - -const useSelectWeek = () => { - const isAdmin = getLoginData().isAdmin; - const setSelectedWeek = useSetAtom(selectedWeekAtom); - - const weekOnClickHandler = (weekObj: WeekStatusData) => { - if (!isAdmin && weekObj.weekStatus !== 'inProgress') return; - const newObj = { startWeekDate: weekObj.dates[0], weekStatus: weekObj.weekStatus }; - setSelectedWeek(newObj); - }; - - const statusConverter = (weekStatus: WeekStatusTypes) => { - switch (weekStatus) { - case 'allocatable': - return '모집 전'; - case 'inProgress': - return '모집 중'; - case 'closed': - return '모집 마감'; - } - }; - - const nowMonth = useAtomValue(weekStatusMonthAtom); - const { year, month } = nowMonth; - - // 선택 주 초기화 - React.useEffect(() => { - setSelectedWeek({ startWeekDate: '', weekStatus: '' }); - }, [year, month]); - - return { weekOnClickHandler, statusConverter }; -}; - -export default useSelectWeek; diff --git a/src/hooks/useGetMyInfo.ts b/src/hooks/useGetMyInfo.ts index eba51a11..c4ed6771 100644 --- a/src/hooks/useGetMyInfo.ts +++ b/src/hooks/useGetMyInfo.ts @@ -1,8 +1,7 @@ import { useQuery } from '@tanstack/react-query'; -import { getMyInfo } from 'apis/userInfo'; -import { getLoginData } from 'utils/loginDatahandlers'; -import React from 'react'; import { UserData } from 'apis/types'; +import { getMyInfo } from 'apis/userInfo'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; const useGetMyInfo = () => { const { data: myInfo } = useQuery(['myInfo'], getMyInfo, { @@ -29,7 +28,7 @@ export default useGetMyInfo; type UserType = 'NON_USER' | 'ADMIN_NO_GROUP' | 'ADMIN_NO_MEMBER' | 'ADMIN' | 'ALBA_NO_GROUP' | 'ALBA'; const userTypeCheck = (groupName: string | null, members: UserData[]): UserType => { - const loginState = getLoginData(); + const loginState = loginDatahandlers.getLoginData(); if (!loginState.isLogin) { return 'NON_USER'; diff --git a/src/hooks/useWeekSelector.tsx b/src/hooks/useWeekSelector.tsx index 726e8f46..d63e2272 100644 --- a/src/hooks/useWeekSelector.tsx +++ b/src/hooks/useWeekSelector.tsx @@ -1,8 +1,5 @@ -import FlexContainer from 'components/@commons/FlexContainer'; -import Text from 'components/@commons/Text'; -import React, { useCallback, useState } from 'react'; -import styled from 'styled-components'; -import weekdayArray from 'utils/weekdayArray'; +import WeekBar from 'components/WeekBar'; +import { useCallback, useState } from 'react'; const useWeekSelector = (initial: number) => { const [day, setDay] = useState(initial); @@ -14,33 +11,11 @@ const useWeekSelector = (initial: number) => { [day], ); - const WeekBarComponent = (): JSX.Element => { - return ( - - {weekdayArray.map((e, i) => ( - - ))} - - ); + const WeekBarComponent = () => { + return ; }; return { day, selectDayHandler, WeekBarComponent }; }; export default useWeekSelector; - -const Button = styled.button<{ $isSelected: boolean }>` - width: 10%; - aspect-ratio: 1; - - background: ${(props) => (props.$isSelected ? props.theme.color.yellow : props.theme.color.lightGray)}; - border: 1px solid; - border-color: ${({ theme }) => theme.color.textColor}; - border-radius: 100%; - - display: flex; - justify-content: center; - align-items: center; -`; diff --git a/src/pages/HomeIndex.tsx b/src/pages/HomeIndex.tsx index 2552cc4c..a60dc02e 100644 --- a/src/pages/HomeIndex.tsx +++ b/src/pages/HomeIndex.tsx @@ -1,12 +1,12 @@ -import React, { Suspense } from 'react'; +import Loader from 'components/Suspenses/Loader'; import OnBoardingPage from 'pages/OnBoardingPage'; -import AlbaMainIndex from './alba/AlbaMainIndex'; import AdminMainIndex from 'pages/admin/AdminMainIndex'; -import Loader from 'components/Suspenses/Loader'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { Suspense } from 'react'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; +import AlbaMainIndex from './alba/AlbaMainIndex'; const HomeIndex = () => { - const loginState = getLoginData(); + const loginState = loginDatahandlers.getLoginData(); const isLogin: boolean = loginState.isLogin; const isAdmin: boolean = loginState.isAdmin; diff --git a/src/pages/SchedulePage/CalendarSection/CalenderConents.tsx b/src/pages/SchedulePage/CalendarSection/CalenderConents.tsx index a1094356..bbf548cb 100644 --- a/src/pages/SchedulePage/CalendarSection/CalenderConents.tsx +++ b/src/pages/SchedulePage/CalendarSection/CalenderConents.tsx @@ -1,15 +1,16 @@ import { DailyWorkTimeData } from 'apis/types'; import { MonthBox, WeekGrid } from 'components/Calendar/CalendarStyle'; -import { useGetMonthly } from 'hooks/SchedulePage/fetch'; -import useSchedule from 'hooks/SchedulePage/useSchedule'; -import { useAtomValue } from 'jotai'; -import { dateAtom } from '../states'; +import { useAtomValue, useSetAtom } from 'jotai'; +import { useGetMonthly } from 'pages/SchedulePage/hooks/fetch'; +import { dateAtom, monthAtom } from '../states'; import CalendarDayBox from './CalendarDayBox'; const CalenderConents = (): JSX.Element => { - const { scheduleData } = useGetMonthly(); - const { dateOnClick } = useSchedule(); + const selectedMonth = useAtomValue(monthAtom); + const { scheduleData } = useGetMonthly(selectedMonth); + const selectedDate = useAtomValue(dateAtom); + const setSelectedDate = useSetAtom(dateAtom); return ( @@ -20,7 +21,7 @@ const CalenderConents = (): JSX.Element => { key={e.date} dateString={e.date} timeList={e.workTime} - onClick={() => dateOnClick(e.workTime !== null, e.date)} + onClick={() => setSelectedDate({ isFixed: e.workTime !== null, date: e.date })} isSelected={selectedDate.date === e.date} colors={scheduleData.badgeColor} /> diff --git a/src/pages/SchedulePage/DailyWorkerSection/DailyWorkers.tsx b/src/pages/SchedulePage/DailyWorkerSection/DailyWorkers.tsx index 0124124b..63dfefd6 100644 --- a/src/pages/SchedulePage/DailyWorkerSection/DailyWorkers.tsx +++ b/src/pages/SchedulePage/DailyWorkerSection/DailyWorkers.tsx @@ -1,6 +1,6 @@ import { DailyWorkersTable, NotFixedDateBox } from 'components/DailyWorkersTable'; -import { useGetDailyWorkers } from 'hooks/SchedulePage/fetch'; import { useAtomValue } from 'jotai'; +import { useGetDailyWorkers } from 'pages/SchedulePage/hooks/fetch'; import { dateAtom } from '../states'; const DailyWorkers = (): JSX.Element => { diff --git a/src/pages/SchedulePage/HeaderSection/Dropdown.tsx b/src/pages/SchedulePage/HeaderSection/Dropdown.tsx index 7126ac01..e2ab4f4f 100644 --- a/src/pages/SchedulePage/HeaderSection/Dropdown.tsx +++ b/src/pages/SchedulePage/HeaderSection/Dropdown.tsx @@ -23,22 +23,26 @@ const Dropdown = ({ members }: { members: UserData[] }): JSX.Element => { return ( - + {member.name || '선택'} {isOpen ? : } {isOpen && ( - + {members.map((member: UserData, index) => ( -
    contentOnClick(member)}> - - - {member.name} - - -
+ contentOnClick(member)} + > + + {member.name} + + ))}
)} diff --git a/src/hooks/SchedulePage/fetch.ts b/src/pages/SchedulePage/hooks/fetch.ts similarity index 83% rename from src/hooks/SchedulePage/fetch.ts rename to src/pages/SchedulePage/hooks/fetch.ts index 08cd7561..e1cc3c48 100644 --- a/src/hooks/SchedulePage/fetch.ts +++ b/src/pages/SchedulePage/hooks/fetch.ts @@ -2,15 +2,13 @@ import { useQuery } from '@tanstack/react-query'; import { getDailyWorkers } from 'apis/schedule/getDailyWorkers'; import { getMonthly } from 'apis/schedule/getMonthly'; import { useAtomValue, useSetAtom } from 'jotai'; -import { memberAtom, monthAtom, workTimeAtom } from 'pages/SchedulePage/states'; +import { SelectedMonthData, memberAtom, workTimeAtom } from 'pages/SchedulePage/states'; import { useEffect } from 'react'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; -export const useGetMonthly = () => { +export const useGetMonthly = ({ year, month }: SelectedMonthData) => { const nowMember = useAtomValue(memberAtom); - const { year, month } = useAtomValue(monthAtom); - const setWorkTime = useSetAtom(workTimeAtom); - const isAdmin = getLoginData().isAdmin; + const isAdmin = loginDatahandlers.getLoginData().isAdmin; const { data: scheduleData } = useQuery( ['getMonthly', year, month, nowMember.userId], @@ -27,6 +25,7 @@ export const useGetMonthly = () => { }, ); + const setWorkTime = useSetAtom(workTimeAtom); useEffect(() => { if (scheduleData === undefined) return; setWorkTime({ ...scheduleData?.totalTime }); diff --git a/src/pages/SchedulePage/index.tsx b/src/pages/SchedulePage/index.tsx index a8770c9f..ba8bc620 100644 --- a/src/pages/SchedulePage/index.tsx +++ b/src/pages/SchedulePage/index.tsx @@ -10,11 +10,11 @@ import DailyWorkers from 'pages/SchedulePage/DailyWorkerSection/DailyWorkers'; import Dropdown from 'pages/SchedulePage/HeaderSection/Dropdown'; import TotalWorkTime from 'pages/SchedulePage/HeaderSection/TotalWorkTime'; import { Suspense } from 'react'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; import { memberAtom, monthAtom } from './states'; const SchedulePage = ({ members }: { members?: UserData[] }): JSX.Element => { - const isAdmin = getLoginData().isAdmin; + const isAdmin = loginDatahandlers.getLoginData().isAdmin; const nowMember = useAtomValue(memberAtom); return ( diff --git a/src/pages/SchedulePage/states.ts b/src/pages/SchedulePage/states.ts index db4359a6..396cc54e 100644 --- a/src/pages/SchedulePage/states.ts +++ b/src/pages/SchedulePage/states.ts @@ -1,15 +1,31 @@ import { TotalWorkedTimeData, UserData } from 'apis/types'; import { atom } from 'jotai'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; -const isAdmin = getLoginData().isAdmin; +const isAdmin = loginDatahandlers.getLoginData().isAdmin; -export const workTimeAtom = atom({ monthly: 0, weekly: 0 }); -export const memberAtom = atom( - isAdmin ? { userId: 0, name: '', isSelected: false } : { userId: 0, name: '', isSelected: true }, -); // 선택된 멤버 정보 -export const dateAtom = atom({ date: '', isFixed: false }); // 선택된 날짜 정보 -export const monthAtom = atom({ year: new Date().getFullYear(), month: new Date().getMonth() }); // 선택된 달 정보 +const workTimeDefault = { monthly: 0, weekly: 0 }; +const memberDefault = isAdmin ? { userId: 0, name: '', isSelected: false } : { userId: 0, name: '', isSelected: true }; +const dateDefault = { date: '', isFixed: false }; +const monthDefault = { year: new Date().getFullYear(), month: new Date().getMonth() }; + +export const workTimeAtom = atom(workTimeDefault); +export const memberAtom = atom(memberDefault); // 선택된 멤버 정보 +export const dateAtom = atom(dateDefault); // 선택된 날짜 정보 +export const monthAtom = atom(monthDefault, (get, set, update: SelectedMonthData) => { + set(monthAtom, update); + set(dateAtom, dateDefault); +}); + +export interface SelectedMonthData { + year: number; + month: number; +} + +export interface SelectedDateData { + date: string; + isFixed: boolean; +} interface MemberType extends UserData { isSelected: boolean; diff --git a/src/pages/SelectWeekPage/AdminDetailSection/index.tsx b/src/pages/SelectWeekPage/AdminDetailSection/index.tsx index 4f78f769..e920ddd7 100644 --- a/src/pages/SelectWeekPage/AdminDetailSection/index.tsx +++ b/src/pages/SelectWeekPage/AdminDetailSection/index.tsx @@ -2,11 +2,11 @@ import SubmitButton from 'components/@commons/SubmitButton'; import Text from 'components/@commons/Text'; import { DailyWorkersTable } from 'components/DailyWorkersTable'; import Loader from 'components/Suspenses/Loader'; -import { useGetDailyWorkers } from 'hooks/SchedulePage/fetch'; -import { useGetApplyStatus } from 'hooks/SelectWeekPage/fetch'; -import useWeeklyDetail from 'hooks/SelectWeekPage/useWeeklyDetail'; import useWeekSelector from 'hooks/useWeekSelector'; import { useAtomValue } from 'jotai'; +import { useGetDailyWorkers } from 'pages/SchedulePage/hooks/fetch'; +import { useGetApplyStatus } from 'pages/SelectWeekPage/hooks/fetch'; +import useWeeklyDetail from 'pages/SelectWeekPage/hooks/useWeeklyDetail'; import { Suspense } from 'react'; import { stringDateMove } from 'utils/dateToString'; import { selectedWeekAtom } from '../states'; @@ -36,18 +36,18 @@ const AdminDetailSection = (): JSX.Element => { export default AdminDetailSection; const OpenDetail = (): JSX.Element => { - const { openHandler } = useWeeklyDetail(); - return 스케줄 모집 시작하기; + const { gotoOpenApply } = useWeeklyDetail(); + return 스케줄 모집 시작하기; }; const InProgressDetail = (): JSX.Element => { const { day, WeekBarComponent } = useWeekSelector(0); const { applicantsStatusRes } = useGetApplyStatus(); - const { closeHandler } = useWeeklyDetail(); + const { gotoCloseApply } = useWeeklyDetail(); return ( <> - 모집 마감하고 배정하기 + 모집 마감하고 배정하기 diff --git a/src/pages/SelectWeekPage/AlbaSubmitButton/index.tsx b/src/pages/SelectWeekPage/AlbaSubmitButton/index.tsx index 1269de7a..6c639c4e 100644 --- a/src/pages/SelectWeekPage/AlbaSubmitButton/index.tsx +++ b/src/pages/SelectWeekPage/AlbaSubmitButton/index.tsx @@ -1,17 +1,16 @@ import SubmitButton from 'components/@commons/SubmitButton'; import Text from 'components/@commons/Text'; -import React from 'react'; import { useAtomValue } from 'jotai'; +import useWeeklyDetail from 'pages/SelectWeekPage/hooks/useWeeklyDetail'; import { selectedWeekAtom } from 'pages/SelectWeekPage/states'; -import useWeeklyDetail from 'hooks/SelectWeekPage/useWeeklyDetail'; const AlbaSubmitButton = (): JSX.Element => { const selectedWeek = useAtomValue(selectedWeekAtom); - const { albaBtnHandler } = useWeeklyDetail(); + const { gotoApply } = useWeeklyDetail(); return ( <> - {selectedWeek.startWeekDate !== '' && 신청하러가기} + {selectedWeek.startWeekDate !== '' && 신청하러가기} {selectedWeek.startWeekDate === '' && 주차를 선택해 주세요} ); diff --git a/src/pages/SelectWeekPage/Calendar/StatusCalendar.tsx b/src/pages/SelectWeekPage/Calendar/StatusCalendar.tsx index f560b9be..0f8144b3 100644 --- a/src/pages/SelectWeekPage/Calendar/StatusCalendar.tsx +++ b/src/pages/SelectWeekPage/Calendar/StatusCalendar.tsx @@ -1,21 +1,22 @@ import { WeekStatusData } from 'apis/types'; import { MonthBox } from 'components/Calendar/CalendarStyle'; import { BorderWeekBox, WeekContainer, WeekStatusBar } from 'components/PageStyledComponents/admin/SelectWeekPage'; -import { useGetWeekProgress } from 'hooks/SelectWeekPage/fetch'; -import useSelectWeek from 'hooks/SelectWeekPage/useSelectWeek'; import { useAtomValue } from 'jotai'; import StatusCalendarWeekly from 'pages/SelectWeekPage/Calendar/StatusCalendarWeekly'; +import { useGetWeekProgress } from 'pages/SelectWeekPage/hooks/fetch'; +import useSelectWeek from 'pages/SelectWeekPage/hooks/useSelectWeek'; import { selectedWeekAtom } from 'pages/SelectWeekPage/states'; +import { weekStatusConverter } from 'utils/weekStatusConverter'; const StatusCalendar = (): JSX.Element => { const { weekStatusData } = useGetWeekProgress(); - const { weekOnClickHandler, statusConverter } = useSelectWeek(); + const { weekOnClickHandler } = useSelectWeek(); const selectedWeek = useAtomValue(selectedWeekAtom); return ( - + {weekStatusData?.table.map((weekObj: WeekStatusData, i) => ( - weekOnClickHandler(weekObj)}> - {statusConverter(weekObj.weekStatus)} + weekOnClickHandler(weekObj)} key={`${i}주`} data-testid={`${i}주`}> + {weekStatusConverter(weekObj.weekStatus)} {weekObj.dates[0] === selectedWeek.startWeekDate && } diff --git a/src/hooks/SelectWeekPage/fetch.ts b/src/pages/SelectWeekPage/hooks/fetch.ts similarity index 100% rename from src/hooks/SelectWeekPage/fetch.ts rename to src/pages/SelectWeekPage/hooks/fetch.ts diff --git a/src/pages/SelectWeekPage/hooks/useSelectWeek.ts b/src/pages/SelectWeekPage/hooks/useSelectWeek.ts new file mode 100644 index 00000000..f3f0b237 --- /dev/null +++ b/src/pages/SelectWeekPage/hooks/useSelectWeek.ts @@ -0,0 +1,19 @@ +import { WeekStatusData } from 'apis/types'; +import { useSetAtom } from 'jotai'; +import { selectedWeekAtom } from 'pages/SelectWeekPage/states'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; + +const useSelectWeek = () => { + const isAdmin = loginDatahandlers.getLoginData().isAdmin; + const setSelectedWeek = useSetAtom(selectedWeekAtom); + + const weekOnClickHandler = (weekObj: WeekStatusData) => { + if (!isAdmin && weekObj.weekStatus !== 'inProgress') return; + const newObj = { startWeekDate: weekObj.dates[0], weekStatus: weekObj.weekStatus }; + setSelectedWeek(newObj); + }; + + return { weekOnClickHandler }; +}; + +export default useSelectWeek; diff --git a/src/hooks/SelectWeekPage/useWeeklyDetail.ts b/src/pages/SelectWeekPage/hooks/useWeeklyDetail.ts similarity index 77% rename from src/hooks/SelectWeekPage/useWeeklyDetail.ts rename to src/pages/SelectWeekPage/hooks/useWeeklyDetail.ts index 1d9f542f..c625e080 100644 --- a/src/hooks/SelectWeekPage/useWeeklyDetail.ts +++ b/src/pages/SelectWeekPage/hooks/useWeeklyDetail.ts @@ -1,27 +1,25 @@ -import React, { useCallback } from 'react'; - -import { useNavigate } from 'react-router-dom'; import { convertPath } from 'apis/convertURI'; import { useAtomValue } from 'jotai'; import { selectedWeekAtom } from 'pages/SelectWeekPage/states'; +import { useNavigate } from 'react-router-dom'; const useWeeklyDetail = () => { const startWeekDate = useAtomValue(selectedWeekAtom).startWeekDate; const navigate = useNavigate(); - const openHandler = () => { + const gotoOpenApply = () => { navigate(convertPath('/newSchedule/open'), { state: { startWeekDate: startWeekDate } }); }; - const closeHandler = () => { + const gotoCloseApply = () => { navigate(convertPath('/newSchedule/close'), { state: { startWeekDate: startWeekDate } }); }; - const albaBtnHandler = () => { + const gotoApply = () => { navigate(convertPath('/apply/selectTimes'), { state: { startWeekDate: startWeekDate } }); }; - return { openHandler, closeHandler, albaBtnHandler }; + return { gotoOpenApply, gotoCloseApply, gotoApply }; }; export default useWeeklyDetail; diff --git a/src/pages/SelectWeekPage/states.ts b/src/pages/SelectWeekPage/states.ts index 60785110..4f33c99e 100644 --- a/src/pages/SelectWeekPage/states.ts +++ b/src/pages/SelectWeekPage/states.ts @@ -1,4 +1,11 @@ import { atom } from 'jotai'; +import { SelectedMonthData } from 'pages/SchedulePage/states'; -export const weekStatusMonthAtom = atom({ year: new Date().getFullYear(), month: new Date().getMonth() }); -export const selectedWeekAtom = atom({ startWeekDate: '', weekStatus: '' }); +const weekStatusInitial = { year: new Date().getFullYear(), month: new Date().getMonth() }; +const selectedWeekInitial = { startWeekDate: '', weekStatus: '' }; + +export const selectedWeekAtom = atom(selectedWeekInitial); +export const weekStatusMonthAtom = atom(weekStatusInitial, (get, set, update: SelectedMonthData) => { + set(weekStatusMonthAtom, update); + set(selectedWeekAtom, selectedWeekInitial); +}); diff --git a/src/hooks/SignUpPage/useSignUpForm.ts b/src/pages/SignupPage/hooks/useSignUpForm.ts similarity index 93% rename from src/hooks/SignUpPage/useSignUpForm.ts rename to src/pages/SignupPage/hooks/useSignUpForm.ts index 029f2b0e..29c55aff 100644 --- a/src/hooks/SignUpPage/useSignUpForm.ts +++ b/src/pages/SignupPage/hooks/useSignUpForm.ts @@ -1,5 +1,5 @@ import useErrorHandler from 'error/useErrorHandler'; -import useLogin from 'hooks/auth/useLogin'; +import useLogin from 'pages/auth/hooks/useLogin'; import { useLocation } from 'react-router-dom'; const useSignUpForm = ({ isAdmin, userName }: { isAdmin: boolean | null; userName: string }) => { diff --git a/src/pages/SignupPage/index.tsx b/src/pages/SignupPage/index.tsx index cf4538ce..d9c364aa 100644 --- a/src/pages/SignupPage/index.tsx +++ b/src/pages/SignupPage/index.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import FlexContainer from 'components/@commons/FlexContainer'; import PageContainer from 'components/@commons/PageContainer'; import SubmitButton from 'components/@commons/SubmitButton'; @@ -7,9 +6,9 @@ import SelectTypeSection from 'pages/SignupPage/SelectTypeSection'; import useForm from 'hooks/useForm'; -import { nameValidator } from 'utils/validators'; -import useSignUpForm from 'hooks/SignUpPage/useSignUpForm'; import LogoPicture from 'components/@commons/LogoPicture'; +import useSignUpForm from 'pages/SignupPage/hooks/useSignUpForm'; +import { nameValidator } from 'utils/validators'; const signupPage = (): JSX.Element => { const { diff --git a/src/pages/admin/AddGroupPage/FormSection/index.tsx b/src/pages/admin/AddGroupPage/FormSection/index.tsx index c5c2092e..feee85ad 100644 --- a/src/pages/admin/AddGroupPage/FormSection/index.tsx +++ b/src/pages/admin/AddGroupPage/FormSection/index.tsx @@ -1,7 +1,7 @@ import FlexContainer from 'components/@commons/FlexContainer'; import SubmitButton from 'components/@commons/SubmitButton'; import Text from 'components/@commons/Text'; -import useAddGroupForm from 'hooks/admin/AddGroupPage/useAddGroupForm'; +import useAddGroupForm from 'pages/admin/AddGroupPage/hooks/useAddGroupForm'; import { marketNoValidator, nameValidator } from 'utils/validators'; import InputBar from './InputBar'; diff --git a/src/hooks/admin/AddGroupPage/useAddGroupForm.tsx b/src/pages/admin/AddGroupPage/hooks/useAddGroupForm.tsx similarity index 100% rename from src/hooks/admin/AddGroupPage/useAddGroupForm.tsx rename to src/pages/admin/AddGroupPage/hooks/useAddGroupForm.tsx diff --git a/src/pages/admin/ApplicationClosePage/SelectRecommendsSection/index.tsx b/src/pages/admin/ApplicationClosePage/SelectRecommendsSection/index.tsx index 45e9b07f..a9df549c 100644 --- a/src/pages/admin/ApplicationClosePage/SelectRecommendsSection/index.tsx +++ b/src/pages/admin/ApplicationClosePage/SelectRecommendsSection/index.tsx @@ -1,16 +1,15 @@ -import React from 'react'; -import { DailyWorkersTable } from 'components/DailyWorkersTable'; +import BorderBox from 'components/@commons/BorderBox'; import ColorBox from 'components/@commons/ColorBox'; import FlexContainer from 'components/@commons/FlexContainer'; import SubmitButton from 'components/@commons/SubmitButton'; import Text from 'components/@commons/Text'; -import { myTheme } from 'styles/myTheme'; -import { stringDateMoveKor } from 'utils/dateToString'; +import { DailyWorkersTable } from 'components/DailyWorkersTable'; import { ScrollContainer } from 'components/PageStyledComponents/admin/ApplicationClose'; -import useClose from 'hooks/admin/ApplicationClosePage/useClose'; import useWeekSelector from 'hooks/useWeekSelector'; -import BorderBox from 'components/@commons/BorderBox'; -import { useGetRecommends } from 'hooks/admin/ApplicationClosePage/fetch'; +import { useGetRecommends } from 'pages/admin/ApplicationClosePage/hooks/fetch'; +import useClose from 'pages/admin/ApplicationClosePage/hooks/useClose'; +import { myTheme } from 'styles/myTheme'; +import { stringDateMoveKor } from 'utils/dateToString'; const SelectRecommendsSection = ({ startWeekDate }: { startWeekDate: string }): JSX.Element => { const { recommendsRes } = useGetRecommends(startWeekDate); @@ -19,11 +18,12 @@ const SelectRecommendsSection = ({ startWeekDate }: { startWeekDate: string }): return ( <> - + {recommendsRes?.data.recommends.map((e, candidateIndex: number) => ( setCandidate(candidateIndex)} > diff --git a/src/hooks/admin/ApplicationClosePage/fetch.ts b/src/pages/admin/ApplicationClosePage/hooks/fetch.ts similarity index 100% rename from src/hooks/admin/ApplicationClosePage/fetch.ts rename to src/pages/admin/ApplicationClosePage/hooks/fetch.ts diff --git a/src/hooks/admin/ApplicationClosePage/useClose.ts b/src/pages/admin/ApplicationClosePage/hooks/useClose.ts similarity index 100% rename from src/hooks/admin/ApplicationClosePage/useClose.ts rename to src/pages/admin/ApplicationClosePage/hooks/useClose.ts diff --git a/src/pages/admin/ApplicationOpenPage/SetPeopleSection/EditAmountForm.tsx b/src/pages/admin/ApplicationOpenPage/SetPeopleSection/EditAmountForm.tsx index d6cd0f28..10c86378 100644 --- a/src/pages/admin/ApplicationOpenPage/SetPeopleSection/EditAmountForm.tsx +++ b/src/pages/admin/ApplicationOpenPage/SetPeopleSection/EditAmountForm.tsx @@ -1,6 +1,5 @@ -import React from 'react'; import { InputPeople } from 'components/PageStyledComponents/admin/ApplicationOpenPage'; -import { usePeopleValidation } from 'hooks/admin/ApplicationOpenPage/usePeopleValidation'; +import { usePeopleValidation } from 'pages/admin/ApplicationOpenPage/hooks/usePeopleValidation'; const EditAmountForm = ({ timeIndex, day }: { timeIndex: number; day: number }): JSX.Element => { const { val, onBlurHandler, onChangeHandler } = usePeopleValidation(timeIndex, day); diff --git a/src/pages/admin/ApplicationOpenPage/SetPeopleSection/index.tsx b/src/pages/admin/ApplicationOpenPage/SetPeopleSection/index.tsx index d3f9e609..24683c52 100644 --- a/src/pages/admin/ApplicationOpenPage/SetPeopleSection/index.tsx +++ b/src/pages/admin/ApplicationOpenPage/SetPeopleSection/index.tsx @@ -1,13 +1,12 @@ -import FlexContainer from 'components/@commons/FlexContainer'; import BorderBox from 'components/@commons/BorderBox'; +import FlexContainer from 'components/@commons/FlexContainer'; import SubmitButton from 'components/@commons/SubmitButton'; import Text from 'components/@commons/Text'; -import React from 'react'; import useWeekSelector from 'hooks/useWeekSelector'; -import EditAmountForm from './EditAmountForm'; import { useAtomValue, useSetAtom } from 'jotai'; -import { usePostOpenApplication } from 'hooks/admin/ApplicationOpenPage/fetch'; +import { usePostOpenApplication } from 'pages/admin/ApplicationOpenPage/hooks/fetch'; import { openStepAtom, timeTemplateAtom } from '../states'; +import EditAmountForm from './EditAmountForm'; const SetPeopleSection = ({ startWeekDate }: { startWeekDate: string }): JSX.Element => { const { day, WeekBarComponent } = useWeekSelector(0); @@ -19,9 +18,9 @@ const SetPeopleSection = ({ startWeekDate }: { startWeekDate: string }): JSX.Ele - + {timeTemplate.map((timeData, timeIndex) => ( - + {timeData.title} diff --git a/src/pages/admin/ApplicationOpenPage/SetTimeTemplateSection/index.tsx b/src/pages/admin/ApplicationOpenPage/SetTimeTemplateSection/index.tsx index af20de24..04c1e62b 100644 --- a/src/pages/admin/ApplicationOpenPage/SetTimeTemplateSection/index.tsx +++ b/src/pages/admin/ApplicationOpenPage/SetTimeTemplateSection/index.tsx @@ -5,8 +5,8 @@ import SubmitButton from 'components/@commons/SubmitButton'; import Text from 'components/@commons/Text'; import { AddButton } from 'components/@commons/icons/buttons'; import SetTimeTemplateSkeleton from 'components/Suspenses/PageSkeletons/SetTimeTemplateSkeleton'; -import { useGetOpenTemplate } from 'hooks/admin/ApplicationOpenPage/fetch'; -import useTimeTemplate from 'hooks/admin/ApplicationOpenPage/useTimeTemplate'; +import { useGetOpenTemplate } from 'pages/admin/ApplicationOpenPage/hooks/fetch'; +import useTimeTemplate from 'pages/admin/ApplicationOpenPage/hooks/useTimeTemplate'; import { Suspense } from 'react'; import { myTheme } from 'styles/myTheme'; import { stringDateMoveKor } from 'utils/dateToString'; @@ -21,11 +21,11 @@ const SetTimeTemplateSection = ({ startWeekDate }: { startWeekDate: string }): J 근무 시간대를 설정하세요 - + }> {timeTemplate.map((time: TimeData, timeIndex: number) => ( - + { const { submitApplyHandler, checkedTimeOnly, goSelectHandler } = usePreviewSelected(startWeekDate); @@ -23,8 +22,8 @@ const PreviewSection = ({ startWeekDate }: { startWeekDate: string }): JSX.Eleme {weekdayArray.map((weekday, dayIndex) => ( - - + + {stringDateMoveKor(startWeekDate, dayIndex)} diff --git a/src/pages/alba/ApplyPage/TimeSelectSection/DailyTimeSelectForm.tsx b/src/pages/alba/ApplyPage/TimeSelectSection/DailyTimeSelectForm.tsx index 98f7ef19..cf7987cd 100644 --- a/src/pages/alba/ApplyPage/TimeSelectSection/DailyTimeSelectForm.tsx +++ b/src/pages/alba/ApplyPage/TimeSelectSection/DailyTimeSelectForm.tsx @@ -2,9 +2,9 @@ import BorderBox from 'components/@commons/BorderBox'; import CheckBox from 'components/@commons/CheckBox'; import FlexContainer from 'components/@commons/FlexContainer'; import Text from 'components/@commons/Text'; -import { useGetApplyForm } from 'hooks/alba/apply/fetch'; -import useSelectTime from 'hooks/alba/apply/useSelectTime'; import { useAtomValue } from 'jotai'; +import { useGetApplyForm } from 'pages/alba/ApplyPage/hooks/fetch'; +import useSelectTime from 'pages/alba/ApplyPage/hooks/useSelectTime'; import { weeklySelectAtom } from '../states'; const DailyTimeSelectForm = ({ day, startWeekDate }: { day: number; startWeekDate: string }): JSX.Element => { @@ -16,30 +16,28 @@ const DailyTimeSelectForm = ({ day, startWeekDate }: { day: number; startWeekDat const { selectTimeHandler } = useSelectTime(); return ( - <> - - {weeklySelect[day].map((timeObject, timeIndex) => ( - - ))} - - + + {weeklySelect[day].map((timeObject, timeIndex) => ( + + ))} + ); }; export default DailyTimeSelectForm; diff --git a/src/pages/alba/ApplyPage/TimeSelectSection/index.tsx b/src/pages/alba/ApplyPage/TimeSelectSection/index.tsx index d91e1b3c..d77b5c25 100644 --- a/src/pages/alba/ApplyPage/TimeSelectSection/index.tsx +++ b/src/pages/alba/ApplyPage/TimeSelectSection/index.tsx @@ -3,7 +3,7 @@ import FlexContainer from 'components/@commons/FlexContainer'; import Text from 'components/@commons/Text'; import TimeSelectSkeleton from 'components/Suspenses/PageSkeletons/TimeSelectSkeleton'; import useWeekSelector from 'hooks/useWeekSelector'; -import React from 'react'; +import { Suspense } from 'react'; import { stringDateMoveKor } from 'utils/dateToString'; import DailyTimeSelectForm from './DailyTimeSelectForm'; @@ -14,15 +14,15 @@ const TimeSelectSection = ({ startWeekDate }: { startWeekDate: string; previewPa - + {stringDateMoveKor(startWeekDate, day)} - }> + }> - + ); }; diff --git a/src/hooks/alba/apply/fetch.ts b/src/pages/alba/ApplyPage/hooks/fetch.ts similarity index 100% rename from src/hooks/alba/apply/fetch.ts rename to src/pages/alba/ApplyPage/hooks/fetch.ts diff --git a/src/hooks/alba/apply/usePreviewSelected.ts b/src/pages/alba/ApplyPage/hooks/usePreviewSelected.ts similarity index 100% rename from src/hooks/alba/apply/usePreviewSelected.ts rename to src/pages/alba/ApplyPage/hooks/usePreviewSelected.ts diff --git a/src/hooks/alba/apply/useSelectTime.ts b/src/pages/alba/ApplyPage/hooks/useSelectTime.ts similarity index 100% rename from src/hooks/alba/apply/useSelectTime.ts rename to src/pages/alba/ApplyPage/hooks/useSelectTime.ts diff --git a/src/pages/alba/InvitedPage/InvitationContent.tsx b/src/pages/alba/InvitedPage/InvitationContent.tsx index 2fcabde0..2c8a6c29 100644 --- a/src/pages/alba/InvitedPage/InvitationContent.tsx +++ b/src/pages/alba/InvitedPage/InvitationContent.tsx @@ -1,7 +1,6 @@ import FlexContainer from 'components/@commons/FlexContainer'; import Text from 'components/@commons/Text'; -import { useGetInvitation } from 'hooks/alba/invitation/fetch'; -import React from 'react'; +import { useGetInvitation } from 'pages/alba/InvitedPage/hooks/fetch'; interface Props { invitationKey: string; diff --git a/src/hooks/alba/invitation/fetch.ts b/src/pages/alba/InvitedPage/hooks/fetch.ts similarity index 100% rename from src/hooks/alba/invitation/fetch.ts rename to src/pages/alba/InvitedPage/hooks/fetch.ts diff --git a/src/hooks/alba/invitation/useInvitation.tsx b/src/pages/alba/InvitedPage/hooks/useInvitation.tsx similarity index 77% rename from src/hooks/alba/invitation/useInvitation.tsx rename to src/pages/alba/InvitedPage/hooks/useInvitation.tsx index 6c756542..401c2585 100644 --- a/src/hooks/alba/invitation/useInvitation.tsx +++ b/src/pages/alba/InvitedPage/hooks/useInvitation.tsx @@ -1,11 +1,11 @@ -import React from 'react'; import useModal from 'hooks/useModal'; -import { getLoginData } from 'utils/loginDatahandlers'; -import { usePostGroupJoin } from 'hooks/alba/invitation/fetch'; import usePopUpPage from 'hooks/usePopUpPage'; +import { usePostGroupJoin } from 'pages/alba/InvitedPage/hooks/fetch'; +import React from 'react'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; const useInvitation = (invitationKey: string, donePage: React.ReactNode, loginModal: React.ReactNode) => { - const loginState = getLoginData(); + const loginState = loginDatahandlers.getLoginData(); const { modalOnHandler } = useModal(); const { popUpOnHandler } = usePopUpPage(); diff --git a/src/pages/alba/InvitedPage/index.tsx b/src/pages/alba/InvitedPage/index.tsx index 76f0a294..54a94064 100644 --- a/src/pages/alba/InvitedPage/index.tsx +++ b/src/pages/alba/InvitedPage/index.tsx @@ -1,13 +1,13 @@ -import React, { Suspense } from 'react'; -import { useParams } from 'react-router-dom'; -import PageContainer from 'components/@commons/PageContainer'; -import JoinDone from 'pages/alba/InvitedPage/JoinDone'; import FlexContainer from 'components/@commons/FlexContainer'; -import InvitationSkeleton from 'components/Suspenses/PageSkeletons/InvitationSkeleton'; -import InvitationContent from './InvitationContent'; +import PageContainer from 'components/@commons/PageContainer'; import SubmitButton from 'components/@commons/SubmitButton'; +import InvitationSkeleton from 'components/Suspenses/PageSkeletons/InvitationSkeleton'; import LoginSignupModal from 'components/modals/LoginSignupModal'; -import useInvitation from 'hooks/alba/invitation/useInvitation'; +import JoinDone from 'pages/alba/InvitedPage/JoinDone'; +import useInvitation from 'pages/alba/InvitedPage/hooks/useInvitation'; +import { Suspense } from 'react'; +import { useParams } from 'react-router-dom'; +import InvitationContent from './InvitationContent'; const InvitedPage = (): JSX.Element => { const invitationKey: string = useParams()?.invitationKey || ''; diff --git a/src/pages/KakaoAuthPage.tsx b/src/pages/auth/KakaoAuthPage.tsx similarity index 94% rename from src/pages/KakaoAuthPage.tsx rename to src/pages/auth/KakaoAuthPage.tsx index 2da57fa7..e1bbec56 100644 --- a/src/pages/KakaoAuthPage.tsx +++ b/src/pages/auth/KakaoAuthPage.tsx @@ -1,7 +1,7 @@ import { convertPath } from 'apis/convertURI'; import PageContainer from 'components/@commons/PageContainer'; import Loader from 'components/Suspenses/Loader'; -import useLogin from 'hooks/auth/useLogin'; +import useLogin from 'pages/auth/hooks/useLogin'; import React from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; diff --git a/src/hooks/auth/fetch.ts b/src/pages/auth/hooks/fetch.ts similarity index 100% rename from src/hooks/auth/fetch.ts rename to src/pages/auth/hooks/fetch.ts diff --git a/src/hooks/auth/useLogin.ts b/src/pages/auth/hooks/useLogin.ts similarity index 90% rename from src/hooks/auth/useLogin.ts rename to src/pages/auth/hooks/useLogin.ts index edc6abfa..2d04f484 100644 --- a/src/hooks/auth/useLogin.ts +++ b/src/pages/auth/hooks/useLogin.ts @@ -1,7 +1,7 @@ import { SignupRequest } from 'apis/auth'; import { baseURL, convertPath } from 'apis/convertURI'; import { useNavigate } from 'react-router-dom'; -import { removeLoginData } from 'utils/loginDatahandlers'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; import { useLoginFetch } from './fetch'; const useLogin = (redirectPage?: string) => { @@ -25,7 +25,7 @@ const useLogin = (redirectPage?: string) => { }; const logout = () => { - removeLoginData(); + loginDatahandlers.removeLoginData(); navigate(convertPath('/')); }; diff --git a/src/hooks/auth/useLoginState.ts b/src/pages/auth/hooks/useLoginState.ts similarity index 75% rename from src/hooks/auth/useLoginState.ts rename to src/pages/auth/hooks/useLoginState.ts index fdab89a0..dc229330 100644 --- a/src/hooks/auth/useLoginState.ts +++ b/src/pages/auth/hooks/useLoginState.ts @@ -1,7 +1,6 @@ -import { useNavigate } from 'react-router-dom'; import { convertPath } from 'apis/convertURI'; -import React from 'react'; -import { saveLoginData } from 'utils/loginDatahandlers'; +import { useNavigate } from 'react-router-dom'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; export const useLoginState = () => { const navigate = useNavigate(); @@ -11,7 +10,7 @@ export const useLoginState = () => { isAdmin: boolean; }, ) => { - saveLoginData(token, userData); + loginDatahandlers.saveLoginData(token, userData); navigate(convertPath(sessionStorage.getItem('beforeLoginURL') || '/')); }; diff --git a/src/privateRoutes/LogoutOnlyPrivate.tsx b/src/privateRoutes/LogoutOnlyPrivate.tsx index 4cb18eb6..1adfcfe1 100644 --- a/src/privateRoutes/LogoutOnlyPrivate.tsx +++ b/src/privateRoutes/LogoutOnlyPrivate.tsx @@ -1,10 +1,9 @@ -import React from 'react'; -import { Navigate, Outlet } from 'react-router-dom'; import { convertPath } from 'apis/convertURI'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { Navigate, Outlet } from 'react-router-dom'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; const LogoutOnlyPrivate = (): JSX.Element => { - const loginState = getLoginData(); + const loginState = loginDatahandlers.getLoginData(); return loginState.isLogin ? : ; }; diff --git a/src/privateRoutes/UserTypePrivate.tsx b/src/privateRoutes/UserTypePrivate.tsx index 128209b6..2b4adb7a 100644 --- a/src/privateRoutes/UserTypePrivate.tsx +++ b/src/privateRoutes/UserTypePrivate.tsx @@ -1,10 +1,9 @@ -import React from 'react'; -import { Navigate, Outlet } from 'react-router-dom'; import { convertPath } from 'apis/convertURI'; -import { getLoginData } from 'utils/loginDatahandlers'; +import { Navigate, Outlet } from 'react-router-dom'; +import { loginDatahandlers } from 'utils/loginDatahandlers'; const UserTypePrivate = ({ when }: { when: 'admin' | 'alba' }): JSX.Element => { - const loginState = getLoginData(); + const loginState = loginDatahandlers.getLoginData(); const isLogin: boolean = loginState.isLogin; const isAdmin: boolean = loginState.isAdmin; diff --git a/src/utils/loginDatahandlers.ts b/src/utils/loginDatahandlers.ts index 895e1597..2bc97f86 100644 --- a/src/utils/loginDatahandlers.ts +++ b/src/utils/loginDatahandlers.ts @@ -1,22 +1,34 @@ -const storage: Storage = localStorage; +class LoginData { + saveLoginData = (token: string, userData: UserDataType) => { + sessionStorage.removeItem('beforeLoginURL'); + sessionStorage.removeItem('code'); + + const loginData = { + token: token, + isLogin: true, + isAdmin: userData.isAdmin, + }; + + storage.setItem('login', JSON.stringify(loginData)); + return; + }; -export const saveLoginData = (token: string, userData: UserDataType) => { - sessionStorage.removeItem('beforeLoginURL'); - sessionStorage.removeItem('code'); + removeLoginData = () => { + storage.removeItem('login'); + location.reload(); + return; + }; - const loginData = { - token: token, - isLogin: true, - isAdmin: userData.isAdmin, + getLoginData = () => { + const stringData = storage.getItem('login'); + if (stringData === null) return defaultLoginState; + return JSON.parse(stringData); }; +} - storage.setItem('login', JSON.stringify(loginData)); -}; +export const loginDatahandlers = new LoginData(); -export const removeLoginData = () => { - storage.removeItem('login'); - location.reload(); -}; +const storage: Storage = localStorage; const defaultLoginState = { isLogin: false, @@ -24,13 +36,6 @@ const defaultLoginState = { isAdmin: false, }; -export const getLoginData = () => { - const stringData = storage.getItem('login'); - if (stringData === null) return defaultLoginState; - - return JSON.parse(stringData); -}; - interface UserDataType { isAdmin: boolean; } diff --git a/src/utils/weekStatusConverter.ts b/src/utils/weekStatusConverter.ts new file mode 100644 index 00000000..36799557 --- /dev/null +++ b/src/utils/weekStatusConverter.ts @@ -0,0 +1,12 @@ +import { WeekStatusTypes } from 'apis/types'; + +export const weekStatusConverter = (weekStatus: WeekStatusTypes) => { + switch (weekStatus) { + case 'allocatable': + return '모집 전'; + case 'inProgress': + return '모집 중'; + case 'closed': + return '모집 마감'; + } +}; diff --git a/tests/admin/addGroup.spec.ts b/tests/admin/addGroup.spec.ts index fddbcf26..a83e63c0 100644 --- a/tests/admin/addGroup.spec.ts +++ b/tests/admin/addGroup.spec.ts @@ -1,17 +1,25 @@ import { expect, test } from '@playwright/test'; -import { mockMapper, mockResponse } from '../mock/mockResponse'; +import { mockResponse } from '../mock/mockResponse'; import { getMyinfoNoGroup } from '../mock/responseBody/getMyInfo'; test.beforeEach(async ({ page }) => { - mockMapper({ page, url: 'group', method: 'GET', response: mockResponse(getMyinfoNoGroup) }); - mockMapper({ page, url: 'group', method: 'POST', response: mockResponse(null) }); + // await mockMapper({ page, url: 'group', method: 'GET', response: mockResponse(getMyinfoNoGroup) }); + // await mockMapper({ page, url: 'group', method: 'POST', response: mockResponse(null) }); + + await page.route(`*/**/group`, async (route) => { + if (route.request().method() === 'GET') { + await route.fulfill(mockResponse(getMyinfoNoGroup)); + } else if (route.request().method() === 'POST') { + await route.fulfill(mockResponse(null)); + } + }); }); test.describe('그룹 생성 페이지', () => { test('그룹 생성', async ({ page, baseURL }) => { // 1. 접속 await page.goto(`${baseURL}/addGroup`); - expect(page.getByText('매장 등록하기')).toBeVisible(); + await expect(page.getByText('매장 등록하기')).toBeVisible(); const marketName = page.getByLabel('상호명'); const marketNumber = page.getByLabel('사업자 번호'); @@ -34,15 +42,20 @@ test.describe('그룹 생성 페이지', () => { await mainAddress.click(); // 5. 다음 주소 - 검색 - const searchBox = page.locator('//fieldset/div/span'); - await searchBox.click(); + const frame = page + .frameLocator('iframe[title="우편번호서비스 레이어 프레임"]') + .frameLocator('iframe[title="우편번호 검색 프레임"]'); + const searchBox = frame.getByLabel('검색할 도로명/지번주소를 입력, 예시) 판교역로 166, 분당 주공, 백현동 532'); + const searchBtn = frame.getByRole('button', { name: '검색' }); + const searchResult = frame.locator('//button[@class="link_post"]'); + + // // 5. 다음 주소 - 첫번째 결과 클릭 await searchBox.fill('강남구'); + await searchBtn.click(); + await searchBtn.click(); + await searchResult.first().click(); - // 5. 다음 주소 - 첫번째 결과 클릭 - await page.locator('//div[@id="postCodeSuggestLayer"]//li[1]').click(); - await page.locator('//ul/li[1]/dl/dd[1]/span/button').click(); - - // 6. 제출 + // // 6. 제출 await page.getByRole('button', { name: '그룹 생성하기' }).click(); await expect(page.getByText('매장 등록에 성공했습니다')).toBeVisible(); diff --git a/tests/admin/checkSchedule.spec.ts b/tests/admin/checkSchedule.spec.ts index b706704b..9dc17ece 100644 --- a/tests/admin/checkSchedule.spec.ts +++ b/tests/admin/checkSchedule.spec.ts @@ -1,29 +1,28 @@ import { expect, test } from '@playwright/test'; -import { CheckRequest, requestParamGetter } from '../mock/CheckRequest'; +import { CheckRequest } from '../mock/CheckRequest'; import { mockMapper, mockResponse } from '../mock/mockResponse'; import { getMyinfo } from '../mock/responseBody/getMyInfo'; -import { getDailyWorker, getMonthly } from '../mock/responseBody/getSchedule'; +import { getDailyWorker, getMonthly } from '../mock/responseBody/schedulePage'; test('스케줄 확인', async ({ page, baseURL }) => { await mockMapper({ page, url: 'group', method: 'GET', response: mockResponse(getMyinfo) }); await mockMapper({ page, url: 'schedule/fix/month*', method: 'GET', response: mockResponse(getMonthly) }); await mockMapper({ page, url: 'schedule/fix/day*', method: 'GET', response: mockResponse(getDailyWorker) }); - await requestParamGetter({ page, url: 'schedule/fix/month*' }); const check = new CheckRequest({ page, url: 'schedule/fix/month*' }); - await check.requestParamGetter(); + await check.requestParamParser(); await page.goto(`${baseURL}`); // 1. 드롭다운에서 멤버를 선택하면 이번달 캘린더가 표시된다. await page.getByRole('button', { name: '선택' }).click(); - await page.getByTestId('멤버리스트').locator('ol').nth(1).click(); + await page.getByTestId('멤버리스트').locator('li').nth(1).click(); const calendar = page.getByTestId('월간스케줄'); await expect(page.getByTestId('월간스케줄')).toBeVisible(); // 2. 캘린더 날짜를 누르면 - const firstDate = calendar.locator('div').nth(1).locator('div').nth(1); + const firstDate = calendar.locator('div').first().locator('div').first(); await firstDate.click(); - const badge = firstDate.locator('div').locator('ol'); + const badge = firstDate.locator('div').locator('li'); if (badge === null) { // 확정 스케줄이 없으면 아직 스케줄이 확정되지 않았습니다 가 표시된다. diff --git a/tests/admin/closeApply.spec.ts b/tests/admin/closeApply.spec.ts new file mode 100644 index 00000000..d1ec0b8b --- /dev/null +++ b/tests/admin/closeApply.spec.ts @@ -0,0 +1,73 @@ +import { expect, test } from '@playwright/test'; +import { CheckRequest } from '../mock/CheckRequest'; +import { getApplyStatus, getRecommends } from '../mock/responseBody/close'; +import { getWeekProgressInprogress } from '../mock/responseBody/selectWeek'; +import { mockMapper, mockResponse } from './../mock/mockResponse'; + +test.describe('스케줄 모집 마감', () => { + test('스케줄 모집 마감', async ({ page }) => { + const inProgress = page.getByText('모집 중').first(); + await inProgress.click(); + + // 모집 중일 경우 : 마감하고 배정하기 버튼과 요일별 근무표가 뜬다 + const closeBtn = page.getByRole('button', { name: '모집 마감하고 배정하기' }); + const dailyWorkerTable = page.getByTestId('일간근무표'); + await expect(closeBtn).toBeVisible(); + await expect(dailyWorkerTable).toBeVisible(); + + // 마감하고 배정하기 버튼을 클릭하면 모집 마감하기 페이지로 이동한다 + await closeBtn.click(); + + // 후보와 근무표가 표시된다. + const recommendsList = page.getByTestId('후보목록'); + await expect(recommendsList).toBeVisible(); + await expect(dailyWorkerTable).toBeVisible(); + + // 후보 박스를 클릭하면 선택 후보가 바뀐다. + const amount = await page.getByTestId('후보목록').locator('li').all(); + await page.getByTestId('후보목록').last().click(); + + // 스케줄 확정하기 버튼을 누르면 제출되고 메인으로 이동한다. + const check = new CheckRequest({ page, url: 'schedule/fix' }); + await check.requestBodyParser(); + + await page.getByRole('button', { name: '스케줄 확정하기 (그룹원에게 알림이 가요!)' }).click(); + + const body = check.getRequestBody(); + + expect(body.selection).toBe(amount.length); + }); +}); + +test.beforeEach(async ({ page, baseURL }) => { + await mockMapper({ + page, + url: `schedule/status*`, + method: 'GET', + response: mockResponse(getWeekProgressInprogress), + }); + + await mockMapper({ + page, + url: `schedule/recommend*`, + method: 'GET', + response: mockResponse(getRecommends), + }); + + await mockMapper({ + page, + url: `schedule/fix*`, + method: 'POST', + response: mockResponse(null), + }); + + await mockMapper({ + page, + url: `schedule/remain/week*`, + method: 'GET', + response: mockResponse(getApplyStatus), + }); + + await page.goto(`${baseURL}/newSchedule`); + await page.getByLabel('다음').click(); +}); diff --git a/tests/admin/mainPage.spec.ts b/tests/admin/mainPage.spec.ts index ec9e4fc7..5148459b 100644 --- a/tests/admin/mainPage.spec.ts +++ b/tests/admin/mainPage.spec.ts @@ -8,7 +8,7 @@ test.describe('매니저 메인 페이지', () => { await mockMapper({ page: page, url: 'group', method: 'GET', response: mockResponse(getMyinfo) }); await page.goto(`${baseURL}`); - await expect(page.locator('//span[contains(text(), "확정 스케줄")]')).toBeVisible(); + await expect(page.getByRole('button', { name: '선택' })).toBeVisible(); }); // 그룹이 있고 멤버가 없으면 초대하기 화면이 표시된다. diff --git a/tests/admin/openApply.spec.ts b/tests/admin/openApply.spec.ts new file mode 100644 index 00000000..598e5f20 --- /dev/null +++ b/tests/admin/openApply.spec.ts @@ -0,0 +1,96 @@ +import { expect, test } from '@playwright/test'; +import { getWeekProgressAllocatable } from '../mock/responseBody/selectWeek'; +import { CheckRequest } from './../mock/CheckRequest'; +import { mockMapper, mockResponse } from './../mock/mockResponse'; +import { getTimeTemplate } from './../mock/responseBody/open'; + +test.describe('스케줄 모집 시작', () => { + test('스케줄 모집 시작', async ({ page }) => { + const allocatable = page.getByText('모집 전').first(); + + // 주를 클릭하면 시작하기 버튼이 뜬다 + await allocatable.click(); + const startBtn = page.getByRole('button', { name: '스케줄 모집 시작하기' }); + await expect(startBtn).toBeVisible(); + + // 시작하기 버튼을 클릭하면 모집 시작하기 페이지로 이동한다. + await startBtn.click(); + await page.getByText('근무 시간대를 설정하세요').isVisible(); + expect(page.url()).toContain('open'); + + // 삭제 버튼을 누르면 삭제된다. + const remove = page.getByLabel('제거').first(); + await remove.click(); + await remove.click(); + await remove.click(); + + // 추가 버튼을 누르면 추가된다. + const add = page.getByLabel('추가').first(); + await add.click(); + + const title = page.getByPlaceholder('시간대 이름을 입력하세요').first(); + const startTime = page.locator('#startTime').first(); + const endTime = page.locator('#endTime').first(); + + // 시간을 편집하면 시간이 변경된다. + await startTime.fill('05:00'); + await endTime.fill('13:00'); + + // 이름을 편집하면 이름이 변경된다. + await title.fill('테스트'); + + // 요일별 모집 인원 설정하기 버튼을 누르면 인원 설정 화면으로 이동한다. + const gotoAmountbutton = page.getByRole('button', { name: '요일별 모집 인원 설정하기' }); + await gotoAmountbutton.click(); + + // 앞에서 편집한 시간대가 뜬다. + await expect(page.getByText('테스트')).toBeVisible(); + + // 요일 버튼을 클릭하면 선택 요일이 변경된다. + const tuesday = page.getByRole('button', { name: '화' }); + await tuesday.click(); + + // 인원을 입력하면 인원이 변경된다. + const amount = page.locator('//li//input').first(); + await amount.fill('10'); + + // 스케줄 모집 시작하기 버튼을 누르면 제출되고 메인으로 이동한다. + const check = new CheckRequest({ page, url: 'schedule/worktime' }); + await check.requestBodyParser(); + + const doneButton = page.getByRole('button', { name: '스케줄 모집 시작하기 (그룹원에게 알림이 가요!)' }); + await doneButton.click(); + const body = check.getRequestBody(); + + expect(body.amount[1][0]).toBe(10); + expect(body.template[0].title).toBe('테스트'); + expect(body.template[0].startTime).toBe('05:00:00'); + expect(body.template[0].endTime).toBe('13:00:00'); + }); +}); + +test.beforeEach(async ({ page, baseURL }) => { + await mockMapper({ + page, + url: `schedule/status*`, + method: 'GET', + response: mockResponse(getWeekProgressAllocatable), + }); + + await mockMapper({ + page, + url: `schedule/worktime?*`, + method: 'GET', + response: mockResponse(getTimeTemplate), + }); + + await mockMapper({ + page, + url: `schedule/worktime`, + method: 'POST', + response: mockResponse(null), + }); + + await page.goto(`${baseURL}/newSchedule`); + await page.getByLabel('다음').click(); +}); diff --git a/tests/admin/selectWeek.spec.ts b/tests/admin/selectWeek.spec.ts new file mode 100644 index 00000000..8ebfa467 --- /dev/null +++ b/tests/admin/selectWeek.spec.ts @@ -0,0 +1,32 @@ +import { expect, test } from '@playwright/test'; +import { getDailyWorker } from '../mock/responseBody/schedulePage'; +import { getWeekProgressClosed } from '../mock/responseBody/selectWeek'; +import { mockMapper, mockResponse } from './../mock/mockResponse'; + +test.describe('매니저 주차 선택', () => { + test('접속', async ({ page }) => { + // 접속하면 이번달 (주차선택)캘린더가 표시된다. + await expect(page.getByTestId('주차선택캘린더')).toBeVisible(); + }); + + test('모집 마감', async ({ page }) => { + // 모집 마감일 경우 : 요일별 근무표가 뜬다 + const closed = page.getByText('모집 마감').first(); + await closed.click(); + + await expect(page.getByTestId('일간근무표')).toBeVisible(); + }); +}); + +test.beforeEach(async ({ page, baseURL }) => { + await mockMapper({ + page, + url: `schedule/status*`, + method: 'GET', + response: mockResponse(getWeekProgressClosed), + }); + + await mockMapper({ page, url: 'schedule/fix/day*', method: 'GET', response: mockResponse(getDailyWorker) }); + + await page.goto(`${baseURL}/newSchedule`); +}); diff --git a/tests/alba/apply.spec.ts b/tests/alba/apply.spec.ts new file mode 100644 index 00000000..35a72b0c --- /dev/null +++ b/tests/alba/apply.spec.ts @@ -0,0 +1,69 @@ +import { expect, test } from '@playwright/test'; +import { getApplyForm } from '../mock/responseBody/apply'; +import { getWeekProgressInprogress } from '../mock/responseBody/selectWeek'; +import { mockMapper, mockResponse } from './../mock/mockResponse'; + +test.describe('알바 스케줄 신청', () => { + test('알바 스케줄 신청', async ({ page, baseURL }) => { + // 접속 + await page.getByText('모집 중').first().click(); + await page.getByRole('button', { name: '신청하러가기' }).click(); + + // 모집중인 시간대가 뜬다 + const list = page.getByTestId('체크리스트'); + await expect(list).toBeVisible(); + + // 시간대 박스를 클릭하면 체크된다. + for (let checkbox of await list.locator('label').all()) { + if ((await checkbox.getAttribute('data-testid')) === 'false') { + await checkbox.click(); + } + } + + // 미리보기 버튼을 클릭하면 미리보기 화면이 뜬다. + await page.getByRole('button', { name: '미리보기' }).click(); + const submit = page.getByRole('button', { name: '제출하기' }); + await expect(submit).toBeVisible(); + + // 체크한 시간대가 정리되어 표시된다. + const preview = await page.getByTestId('요일별선택미리보기').all(); + for (let i = 0; i < 7; i++) { + const time = await preview[i].locator('span').last().innerText(); + if (i === 0) { + expect(time).not.toBe('휴무'); + } else { + expect(time).toBe('휴무'); + } + } + + // 제출하면 메인화면으로 이동한다. + await submit.click(); + await page.waitForURL(baseURL || ''); + expect(page.url()).toBe(baseURL + '/'); + }); +}); + +test.beforeEach(async ({ page, baseURL }) => { + await mockMapper({ + page, + url: `schedule/status*`, + method: 'GET', + response: mockResponse(getWeekProgressInprogress), + }); + + await mockMapper({ + page, + url: `schedule/application*`, + method: 'GET', + response: mockResponse(getApplyForm), + }); + + await mockMapper({ + page, + url: `schedule/application`, + method: 'POST', + response: mockResponse(null), + }); + + await page.goto(`${baseURL}/apply`); +}); diff --git a/tests/alba/checkSchedule.spec.ts b/tests/alba/checkSchedule.spec.ts index 7a2d3d2a..d4a92509 100644 --- a/tests/alba/checkSchedule.spec.ts +++ b/tests/alba/checkSchedule.spec.ts @@ -1,17 +1,16 @@ import { expect, test } from '@playwright/test'; -import { CheckRequest, requestParamGetter } from '../mock/CheckRequest'; +import { CheckRequest } from '../mock/CheckRequest'; import { mockMapper, mockResponse } from '../mock/mockResponse'; import { getMyinfo } from '../mock/responseBody/getMyInfo'; -import { getDailyWorker, getMonthly } from '../mock/responseBody/getSchedule'; +import { getDailyWorker, getMonthly } from '../mock/responseBody/schedulePage'; test('스케줄 확인', async ({ page, baseURL }) => { await mockMapper({ page, url: 'group', method: 'GET', response: mockResponse(getMyinfo) }); await mockMapper({ page, url: 'schedule/fix/month*', method: 'GET', response: mockResponse(getMonthly) }); await mockMapper({ page, url: 'schedule/fix/day*', method: 'GET', response: mockResponse(getDailyWorker) }); - await requestParamGetter({ page, url: 'schedule/fix/month*' }); const check = new CheckRequest({ page, url: 'schedule/fix/month*' }); - await check.requestParamGetter(); + await check.requestParamParser(); // 1. 접속하면 이번달 캘린더가 표시된다. await page.goto(`${baseURL}`); @@ -19,9 +18,9 @@ test('스케줄 확인', async ({ page, baseURL }) => { await expect(page.getByTestId('월간스케줄')).toBeVisible(); // 2. 캘린더 날짜를 누르면 - const firstDate = calendar.locator('div').nth(1).locator('div').nth(1); + const firstDate = calendar.locator('div').first().locator('div').first(); await firstDate.click(); - const badge = firstDate.locator('div').locator('ol'); + const badge = firstDate.locator('div').locator('li'); if (badge === null) { // 2-1. 확정 스케줄이 없으면 아직 스케줄이 확정되지 않았습니다 가 표시된다. diff --git a/tests/alba/invitation.spec.ts b/tests/alba/invitation.spec.ts index 37efa814..1077e174 100644 --- a/tests/alba/invitation.spec.ts +++ b/tests/alba/invitation.spec.ts @@ -1,6 +1,6 @@ import { expect, test } from '@playwright/test'; import { mockMapper, mockResponse } from '../mock/mockResponse'; -import { getGroupInfo } from '../mock/responseBody/getInvitation'; +import { getGroupInfo } from '../mock/responseBody/invitation'; test.describe('초대장', () => { test('접속', async ({ page, baseURL }) => { diff --git a/tests/alba/mainPage.spec.ts b/tests/alba/mainPage.spec.ts index 8a41514d..af9a08e7 100644 --- a/tests/alba/mainPage.spec.ts +++ b/tests/alba/mainPage.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test'; import { mockMapper, mockResponse } from '../mock/mockResponse'; import { getMyinfo, getMyinfoNoGroup } from '../mock/responseBody/getMyInfo'; -import { getMonthly } from './../mock/responseBody/getSchedule'; +import { getMonthly } from './../mock/responseBody/schedulePage'; test.describe('알바 메인 페이지', () => { // 그룹이 있으면 스케줄 화면이 표시된다. diff --git a/tests/alba/selectWeek.spec.ts b/tests/alba/selectWeek.spec.ts new file mode 100644 index 00000000..04d2e540 --- /dev/null +++ b/tests/alba/selectWeek.spec.ts @@ -0,0 +1,27 @@ +import { expect, test } from '@playwright/test'; +import { getWeekProgressInprogress } from '../mock/responseBody/selectWeek'; +import { mockMapper, mockResponse } from './../mock/mockResponse'; + +test.describe('알바 주차 선택', () => { + test('접속', async ({ page }) => { + // 접속하면 이번달 (주차선택)캘린더가 표시된다. + await expect(page.getByTestId('주차선택캘린더')).toBeVisible(); + }); + + test('모집 중', async ({ page }) => { + // 모집 중일 경우 : 신청하러가기 버튼이 뜬다 + await page.getByText('모집 중').first().click(); + await expect(page.getByRole('button', { name: '신청하러가기' })).toBeVisible(); + }); +}); + +test.beforeEach(async ({ page, baseURL }) => { + await mockMapper({ + page, + url: `schedule/status*`, + method: 'GET', + response: mockResponse(getWeekProgressInprogress), + }); + + await page.goto(`${baseURL}/apply`); +}); diff --git a/tests/mock/CheckRequest.ts b/tests/mock/CheckRequest.ts index 540074d8..79bcfae5 100644 --- a/tests/mock/CheckRequest.ts +++ b/tests/mock/CheckRequest.ts @@ -1,8 +1,6 @@ import { Page } from '@playwright/test'; class CheckRequest { - // public requestParam: string | null; - // public requestBody: string | null; page: Page; url: string; requestParam: string[] = []; @@ -20,21 +18,23 @@ class CheckRequest { public getRequestBody = () => { if (this.requestBody.length === 0) return null; - return this.requestBody.at(-1); + const stringBody = this.requestBody.at(-1); + return JSON.parse(stringBody || ''); }; - public requestParamGetter = async () => { + public requestParamParser = async () => { await this.page.route(`*/**/${this.url}`, async (route) => { if (route.request().method() === 'GET') { this.requestParam.push(route.request().url()); route.continue(); return; } + route.continue(); return; }); }; - public requestBodyGetter = async () => { + public requestBodyParser = async () => { await this.page.route(`*/**/${this.url}`, async (route) => { if (route.request().method() === 'POST' || route.request().method() === 'PUT') { const response = route.request().postData(); @@ -44,30 +44,10 @@ class CheckRequest { return; } } + route.continue(); + return; }); }; } export { CheckRequest }; - -export const requestParamGetter = async ({ page, url }: { page: Page; url: string }) => { - await page.route(`*/**/${url}`, async (route) => { - if (route.request().method() === 'GET') { - const request = route.request().url(); - route.continue(); - return request; - } - return null; - }); -}; - -export const requestBodyGetter = async ({ page, url }: { page: Page; url: string }) => { - await page.route(`*/**/${url}`, async (route) => { - if (route.request().method() === 'POST' || route.request().method() === 'PUT') { - const request = route.request().postData(); - route.continue(); - return request; - } - return null; - }); -}; diff --git a/tests/mock/mockResponse.ts b/tests/mock/mockResponse.ts index db2b4947..3bd50d72 100644 --- a/tests/mock/mockResponse.ts +++ b/tests/mock/mockResponse.ts @@ -21,8 +21,6 @@ export const mockMapper = async ({ await page.route(`*/**/${url}`, async (route) => { if (route.request().method() === method) { await route.fulfill(response); - } else { - await route.continue(); } }); }; diff --git a/tests/mock/responseBody/apply.ts b/tests/mock/responseBody/apply.ts new file mode 100644 index 00000000..cd439da7 --- /dev/null +++ b/tests/mock/responseBody/apply.ts @@ -0,0 +1,122 @@ +export const getApplyForm = { + template: [ + { + title: '오픈', + workTimeId: 1, + startTime: '10:00:00', + endTime: '12:00:00', + }, + { + title: '미들', + workTimeId: 2, + startTime: '12:00:00', + endTime: '16:00:00', + }, + { + title: '마감', + workTimeId: 3, + startTime: '16:00:00', + endTime: '22:00:00', + }, + ], + selected: [ + [ + { + workTimeId: 1, + isChecked: false, + }, + { + workTimeId: 2, + isChecked: false, + }, + { + workTimeId: 3, + isChecked: false, + }, + ], + [ + { + workTimeId: 1, + isChecked: false, + }, + { + workTimeId: 2, + isChecked: false, + }, + { + workTimeId: 3, + isChecked: false, + }, + ], + [ + { + workTimeId: 1, + isChecked: false, + }, + { + workTimeId: 2, + isChecked: false, + }, + { + workTimeId: 3, + isChecked: false, + }, + ], + [ + { + workTimeId: 1, + isChecked: false, + }, + { + workTimeId: 2, + isChecked: false, + }, + { + workTimeId: 3, + isChecked: false, + }, + ], + [ + { + workTimeId: 1, + isChecked: false, + }, + { + workTimeId: 2, + isChecked: false, + }, + { + workTimeId: 3, + isChecked: false, + }, + ], + [ + { + workTimeId: 1, + isChecked: false, + }, + { + workTimeId: 2, + isChecked: false, + }, + { + workTimeId: 3, + isChecked: false, + }, + ], + [ + { + workTimeId: 1, + isChecked: false, + }, + { + workTimeId: 2, + isChecked: false, + }, + { + workTimeId: 3, + isChecked: false, + }, + ], + ], +}; diff --git a/tests/mock/responseBody/auth.ts b/tests/mock/responseBody/auth.ts new file mode 100644 index 00000000..eddba144 --- /dev/null +++ b/tests/mock/responseBody/auth.ts @@ -0,0 +1,15 @@ +export const postLoginNoUser = { + status: 404, + body: JSON.stringify({ + errorCode: -10006, + }), +}; + +export const postLoginAdmin = { + token: 'Bearer ABC', + isAdmin: true, +}; +export const postLoginAlba = { + token: 'Bearer ABC', + isAdmin: false, +}; diff --git a/tests/mock/responseBody/close.ts b/tests/mock/responseBody/close.ts new file mode 100644 index 00000000..41ad2d4b --- /dev/null +++ b/tests/mock/responseBody/close.ts @@ -0,0 +1,994 @@ +export const getApplyStatus = { + template: [ + { + workTimeId: 1, + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + }, + { + workTimeId: 2, + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + }, + { + workTimeId: 3, + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + }, + ], + applyStatus: [ + [ + { + workTimeId: 1, + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + workTimeId: 2, + workerList: [ + { + userId: 3, + name: '데이지', + }, + { + userId: 4, + name: '스카이', + }, + ], + }, + { + workTimeId: 3, + workerList: [ + { + userId: 3, + name: '데이지', + }, + { + userId: 4, + name: '스카이', + }, + ], + }, + ], + [ + { + workTimeId: 1, + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + workTimeId: 2, + workerList: [ + { + userId: 3, + name: '데이지', + }, + { + userId: 4, + name: '스카이', + }, + ], + }, + ], + [ + { + workTimeId: 1, + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + workTimeId: 2, + workerList: [ + { + userId: 3, + name: '데이지', + }, + { + userId: 4, + name: '스카이', + }, + ], + }, + ], + [ + { + workTimeId: 1, + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + workTimeId: 2, + workerList: [ + { + userId: 3, + name: '데이지', + }, + { + userId: 4, + name: '스카이', + }, + ], + }, + ], + [ + { + workTimeId: 1, + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + workTimeId: 2, + workerList: [ + { + userId: 3, + name: '데이지', + }, + { + userId: 4, + name: '스카이', + }, + ], + }, + ], + [ + { + workTimeId: 1, + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + workTimeId: 2, + workerList: [ + { + userId: 3, + name: '데이지', + }, + { + userId: 4, + name: '스카이', + }, + ], + }, + ], + [ + { + workTimeId: 1, + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + workTimeId: 2, + workerList: [ + { + userId: 3, + name: '데이지', + }, + { + userId: 4, + name: '스카이', + }, + ], + }, + ], + ], +}; + +export const getRecommends = { + recommends: [ + [ + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + ], + [ + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '어피치', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '어피치', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '어피치', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '미들', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '어피치', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + { + title: '마감', + startTime: '10:00:00', + endTime: '12:00:00', + workerList: [ + { + userId: 1, + name: '라이언', + }, + { + userId: 2, + name: '어피치', + }, + ], + }, + ], + ], + ], +}; diff --git a/tests/mock/responseBody/getTimeTemplate.ts b/tests/mock/responseBody/getTimeTemplate.ts deleted file mode 100644 index 60402730..00000000 --- a/tests/mock/responseBody/getTimeTemplate.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { TimeData } from './../../../src/apis/types'; -// schedule/worktime -export const getTimeTemplate = {}; - -interface GetReturn { - template: TimeData[]; -} -// /schedule/worktime -export const postOpenApplication = {}; - -interface PostRequest { - weekStartDate: string; - template: TimeData[]; - amount: number[][]; -} diff --git a/tests/mock/responseBody/getInvitation.ts b/tests/mock/responseBody/invitation.ts similarity index 100% rename from tests/mock/responseBody/getInvitation.ts rename to tests/mock/responseBody/invitation.ts diff --git a/tests/mock/responseBody/open.ts b/tests/mock/responseBody/open.ts new file mode 100644 index 00000000..c46a632a --- /dev/null +++ b/tests/mock/responseBody/open.ts @@ -0,0 +1,33 @@ +import { TimeData } from '../../../src/apis/types'; +// schedule/worktime +export const getTimeTemplate = { + template: [ + { + title: '오픈', + startTime: '10:00:00', + endTime: '12:00:00', + }, + { + title: '미들', + startTime: '12:00:00', + endTime: '16:00:00', + }, + { + title: '마감', + startTime: '16:00:00', + endTime: '22:00:00', + }, + ], +}; + +interface GetReturn { + template: TimeData[]; +} +// /schedule/worktime +export const postOpenApplication = {}; + +interface PostRequest { + weekStartDate: string; + template: TimeData[]; + amount: number[][]; +} diff --git a/tests/mock/responseBody/postAuth.ts b/tests/mock/responseBody/postAuth.ts index 5de9a1fe..eddba144 100644 --- a/tests/mock/responseBody/postAuth.ts +++ b/tests/mock/responseBody/postAuth.ts @@ -1,7 +1,7 @@ export const postLoginNoUser = { status: 404, body: JSON.stringify({ - code: -10006, + errorCode: -10006, }), }; diff --git a/tests/mock/responseBody/getSchedule.ts b/tests/mock/responseBody/schedulePage.ts similarity index 100% rename from tests/mock/responseBody/getSchedule.ts rename to tests/mock/responseBody/schedulePage.ts diff --git a/tests/mock/responseBody/selectWeek.ts b/tests/mock/responseBody/selectWeek.ts new file mode 100644 index 00000000..8459252e --- /dev/null +++ b/tests/mock/responseBody/selectWeek.ts @@ -0,0 +1,11 @@ +export const getWeekProgressInprogress = { + weekStatus: 'inProgress', +}; + +export const getWeekProgressAllocatable = { + weekStatus: 'allocatable', +}; + +export const getWeekProgressClosed = { + weekStatus: 'closed', +}; diff --git a/tests/state/admin.json b/tests/state/admin.json new file mode 100644 index 00000000..482a482e --- /dev/null +++ b/tests/state/admin.json @@ -0,0 +1,14 @@ +{ + "cookies": [], + "origins": [ + { + "origin": "*", + "localStorage": [ + { + "name": "login", + "value": "{\"token\":\"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjE0LCJzdWIiOiJ1c2VyIiwiaWF0IjoxNjk5MjExMDkzLCJleHAiOjE2OTkyMTk3MzN9.I7ejmrZrlo4CDr0xkShI4fZTWGe6S1kUgBxvsO1VMqA\",\"isLogin\":true,\"isAdmin\":true}" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/state/alba.json b/tests/state/alba.json new file mode 100644 index 00000000..999e7e91 --- /dev/null +++ b/tests/state/alba.json @@ -0,0 +1,14 @@ +{ + "cookies": [], + "origins": [ + { + "origin": "*", + "localStorage": [ + { + "name": "login", + "value": "{\"token\":\"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjE0LCJzdWIiOiJ1c2VyIiwiaWF0IjoxNjk5MjExMDkzLCJleHAiOjE2OTkyMTk3MzN9.I7ejmrZrlo4CDr0xkShI4fZTWGe6S1kUgBxvsO1VMqA\",\"isLogin\":true,\"isAdmin\":false}" + } + ] + } + ] +} \ No newline at end of file