diff --git a/.eslintrc.json b/.eslintrc.json
index 10f001f8..2180e0d1 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -28,7 +28,8 @@
"no-duplicate-imports": "error", //중복 Import 안돼
"no-console": ["warn", { "allow": ["warn", "error", "info"] }], //콘솔은 확인 뒤 지우기
- "no-unused-vars": "error", //사용하지 않은 변수면 없애기
+ "no-unused-vars": "off", //사용하지 않은 변수면 없애기
+ "@typescript-eslint/no-unused-vars": ["error"], //사용하지 않은 변수면 없애기
"no-multiple-empty-lines": "error", //공백 금지
"no-undef": "error", //정의 안 한 변수 사용 x
"indent": "off", // 프리티어 충돌로 인한 OFF
diff --git a/package.json b/package.json
index 1a45c503..5826cc24 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,8 @@
"lint:css": "stylelint './src/**/*.{ts,tsx}'"
},
"dependencies": {
+ "@tanstack/react-query": "^5.45.1",
+ "@tanstack/react-query-devtools": "^5.45.1",
"@types/axios": "^0.14.0",
"@types/react-copy-to-clipboard": "^5.0.4",
"axios": "^1.4.0",
diff --git a/src/App.css b/src/App.css
index a19e07a5..a37449c4 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,58 +1,57 @@
#app {
- height: 100%;
+ height: 100%;
}
html,
body {
- position: relative;
- height: 100%;
+ position: relative;
+ height: 100%;
}
body {
- margin: 0;
- background: #eee;
- padding: 0;
- color: #000;
- font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
- font-size: 14px;
+ margin: 0;
+ padding: 0;
+ color: #000;
+ font-size: 14px;
+ font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
+ background: #eee;
}
.swiper {
- z-index: 0;
- width: 100%;
- height: 100%;
+ z-index: 0;
+ width: 100%;
+ height: 100%;
}
.swiper-slide {
-
- /* Center slide text vertically */
- display: flex;
- align-items: center;
- justify-content: center;
- background: #141414;
- text-align: center;
- font-size: 18px;
+ /* Center slide text vertically */
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+ text-align: center;
+ background: #141414;
}
.swiper-slide img {
- display: block;
- width: 100%;
- height: 100%;
- object-fit: cover;
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
}
.swiper-button-prev {
- display: none;
+ display: none;
}
.swiper-button-next {
- display: none;
+ display: none;
}
.swiper-pagination-bullet {
- background-color: #A4A4A4;
+ background-color: #a4a4a4 !important;
}
.swiper-pagination-bullet-active {
- background-color: #3253FF;
-}
\ No newline at end of file
+ background-color: #3253ff !important;
+}
diff --git a/src/App.tsx b/src/App.tsx
index a5a64135..75914087 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,17 +1,18 @@
-import { useEffect } from 'react';
+/**카카오톡 인앱브라우저 종료후 크롬 및 사파리로 오픈하는 utils file */
+import './utils/changeBrowser';
+import 'react-toastify/dist/ReactToastify.css';
+import './App.css';
-import { ThemeProvider } from 'styled-components';
-import styled from 'styled-components/macro';
-import ToastContainerBox from 'utils/toast/ToastContainer';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import Router from './Router';
import GlobalStyle from './styles/globalStyles';
+import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
+import Router from './Router';
+import { ThemeProvider } from 'styled-components';
+import ToastContainerBox from 'utils/toast/ToastContainer';
+import styled from 'styled-components/macro';
import { theme } from './styles/theme';
-
-import './App.css';
-/**카카오톡 인앱브라우저 종료후 크롬 및 사파리로 오픈하는 utils file */
-import './utils/changeBrowser';
-import 'react-toastify/dist/ReactToastify.css';
+import { useEffect } from 'react';
const MobileWrapper = styled.div`
display: flex;
@@ -47,14 +48,19 @@ function App() {
window.removeEventListener('resize', setScreenSize);
};
}, []);
+
+ const queryClient = new QueryClient();
return (
<>
-
-
-
-
-
+
+
+
+
+
+
+
+
>
);
diff --git a/src/Router.tsx b/src/Router.tsx
index 2c3b3a27..93b95642 100644
--- a/src/Router.tsx
+++ b/src/Router.tsx
@@ -1,15 +1,16 @@
+import { BrowserRouter, Route, Routes } from 'react-router-dom';
+
import ChooseBestTime from 'pages/bestMeetTime/ChooseBestTime';
import CreateMeeting from 'pages/createMeeting/CreateMeeting';
import CueCard from 'pages/cueCard/CueCard';
import ErrorPage404 from 'pages/errorLoading/ErrorPage404';
import LoadingPage from 'pages/errorLoading/LoadingPage';
-import SelectSchedulePriority from 'pages/legacy/selectSchedule/SelectPriorityPage';
-import SelectPage from 'pages/legacy/selectSchedule/SelectSchedulePage';
import LoginEntrance from 'pages/loginEntrance/LoginEntrance';
import OnBoarding from 'pages/onBoarding/OnBoarding';
+import SelectPage from 'pages/legacy/selectSchedule/SelectSchedulePage';
import SelectSchedule from 'pages/selectSchedule/SelectSchedule';
+import SelectSchedulePriority from 'pages/legacy/selectSchedule/SelectPriorityPage';
import SteppingLayout from 'pages/steppingStone/SteppingLayout';
-import { BrowserRouter, Route, Routes } from 'react-router-dom';
const Router = () => {
return (
@@ -18,8 +19,6 @@ const Router = () => {
} />
} />
} />
- {/* } />
- } /> */}
} />
(undefined);
- const [selectedSlots, setSelectedSlots] = useState({});
-
const emptyDates = Array.from({ length: 7 - availableDates.length }, (_, i) => `empty${i + 1}`);
return (
-
+ <>
-
+
-
+
{availableDates.map((date) => {
const dateKey = Object.values(date).join('/');
- return {children({ date: dateKey, timeSlots })};
+ return (
+
+ {children({ date: dateKey, timeSlots })}
+
+ );
})}
- {emptyDates && emptyDates.map((value) => )}
-
-
+ {emptyDates && emptyDates.map((value) => )}
+
+
{bottomItem}
-
+ >
);
}
@@ -54,26 +47,26 @@ const TimetableWrapper = styled.div`
gap: 0.75rem;
`;
-const TableWrapper = styled.div`
+const TableWithDateWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 0.8rem;
`;
-const Table = styled.div`
+const TableWrapper = styled.div`
display: flex;
border-bottom: 1px solid ${({ theme }) => theme.colors.grey7};
border-left: 1px solid ${({ theme }) => theme.colors.grey7};
`;
-const Column = styled.div`
+const ColumnWrapper = styled.div`
display: flex;
flex-direction: column;
border-right: 1px solid ${({ theme }) => theme.colors.grey7};
`;
-const EmptyColumn = styled.div`
+const EmptyColumnWrapper = styled.div`
display: flex;
flex-direction: column;
border-top: 1px solid ${({ theme }) => theme.colors.grey7};
diff --git a/src/components/timetableComponents/context.ts b/src/components/timetableComponents/context.ts
deleted file mode 100644
index d6eb8a77..00000000
--- a/src/components/timetableComponents/context.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { createContext, useContext } from 'react';
-
-export interface SlotInfoType {
- date: string;
- startSlot: string;
- endSlot: string;
- priority: 0 | 1 | 2 | 3;
-}
-export interface SelectedSlotType {
- [key: number]: SlotInfoType;
-}
-
-type TimetableContextType = {
- startSlot?: string;
- setStartSlot: (startSlot?: string) => void;
- selectedSlots: SelectedSlotType;
- setSelectedSlots: (selectedSlots: SelectedSlotsType) => void;
-};
-
-export const TimetableContext = createContext({
- startSlot: undefined,
- setStartSlot: () => undefined,
- selectedSlots: {},
- setSelectedSlots: () => undefined,
-});
-
-export function useTimetableContext() {
- const context = useContext(TimetableContext);
- if (context == null) {
- throw new Error('TimetableContext Error');
- }
- return context;
-}
diff --git a/src/components/timetableComponents/types.ts b/src/components/timetableComponents/types.ts
index a3242267..bf73e819 100644
--- a/src/components/timetableComponents/types.ts
+++ b/src/components/timetableComponents/types.ts
@@ -15,3 +15,8 @@ export interface DateType {
day: string | undefined;
dayOfWeek: string | undefined;
}
+
+export interface SlotType {
+ startTime: string;
+ endTime: string;
+}
diff --git a/src/components/timetableComponents/utils.ts b/src/components/timetableComponents/utils.ts
index e89ccf60..d3f6d7bb 100644
--- a/src/components/timetableComponents/utils.ts
+++ b/src/components/timetableComponents/utils.ts
@@ -1,4 +1,4 @@
-import { SlotType } from 'pages/selectSchedule/SelectSchedule';
+import { SlotType } from './types';
/**
*
* @desc 문자열로 된 time('HH:MM')에 minutes을 더하는 함수
@@ -16,15 +16,12 @@ export const addMinutes = (time: string, minutes: number) => {
* @desc 시작 시간(startTime)과 종료 시간(endTime) 사이에서 30분 간격으로 시간 슬롯을 생성하여 반환하는 함수
*/
-export const getAvailableTimes = (times: SlotType) => {
- function getTimeSlots(startTime: string, endTime: string): string[] {
- const slots = [];
- let curTime = startTime;
- while (curTime < endTime) {
- slots.push(curTime);
- curTime = addMinutes(curTime, 30);
- }
- return slots;
+export const getAvailableTimes = ({ startTime, endTime }: SlotType) => {
+ const slots = [];
+ let curTime = startTime;
+ while (curTime < endTime) {
+ slots.push(curTime);
+ curTime = addMinutes(curTime, 30);
}
- return getTimeSlots(times.startTime, times.endTime);
+ return slots;
};
diff --git a/src/pages/LoginEntrance/components/MemberComponent.tsx b/src/pages/LoginEntrance/components/MemberComponent.tsx
index b1a30430..a87ea7ac 100644
--- a/src/pages/LoginEntrance/components/MemberComponent.tsx
+++ b/src/pages/LoginEntrance/components/MemberComponent.tsx
@@ -1,16 +1,16 @@
import React, { Dispatch, SetStateAction } from 'react';
-import { userNameAtom } from 'atoms/atom';
import Button from 'components/atomComponents/Button';
+import Header from 'components/moleculesComponents/Header';
import Text from 'components/atomComponents/Text';
import TextInput from 'components/atomComponents/TextInput';
-import Header from 'components/moleculesComponents/Header';
import TitleComponent from 'components/moleculesComponents/TitleComponents';
-import { useParams } from 'react-router';
-import { useNavigate } from 'react-router-dom';
-import { useRecoilState } from 'recoil';
import styled from 'styled-components/macro';
import { theme } from 'styles/theme';
+import { useNavigate } from 'react-router-dom';
+import { useParams } from 'react-router';
+import { useRecoilState } from 'recoil';
+import { userNameAtom } from 'atoms/atom';
interface HostInfoProps {
name: string;
@@ -38,7 +38,7 @@ function MemberComponent({ hostInfo, setHostInfo }: HostProps) {
const loginMember = () => {
setUserName(hostInfo.name);
- navigate(`/member/schedule/${meetingId}`);
+ navigate(`/member/select/${meetingId}`);
};
return (
diff --git a/src/pages/LoginEntrance/components/NoAvailableTimeModal.tsx b/src/pages/LoginEntrance/components/NoAvailableTimeModal.tsx
index 3b56bf2d..0b82b270 100644
--- a/src/pages/LoginEntrance/components/NoAvailableTimeModal.tsx
+++ b/src/pages/LoginEntrance/components/NoAvailableTimeModal.tsx
@@ -10,7 +10,7 @@ interface ModalProps {
setIsModalOpen: Dispatch>;
}
-function NoAvailableTimeModal ({ setIsModalOpen }: ModalProps) {
+function NoAvailableTimeModal({ setIsModalOpen }: ModalProps) {
const { meetingId } = useParams();
return (
@@ -29,7 +29,7 @@ function NoAvailableTimeModal ({ setIsModalOpen }: ModalProps) {
방장 페이지에 접속할 수 있어요!
-
+
가능 시간 입력하러 가기
diff --git a/src/pages/OverallSchedule/OverallSchedule.tsx b/src/pages/OverallSchedule/OverallSchedule.tsx
index f29f495f..84a2d4ef 100644
--- a/src/pages/OverallSchedule/OverallSchedule.tsx
+++ b/src/pages/OverallSchedule/OverallSchedule.tsx
@@ -1,167 +1,47 @@
-import React, { useEffect, useState } from 'react';
-
-import { availableDatesAtom, preferTimesAtom, timeSlotUserNameAtom } from 'atoms/atom';
-import Text from 'components/atomComponents/Text';
-import LoadingPage from 'pages/errorLoading/LoadingPage';
+import { getAvailableTimes } from 'components/timetableComponents/utils';
import { useParams } from 'react-router-dom';
-import { useRecoilState, useRecoilValue } from 'recoil';
-import { OverallScheduleData } from 'src/types/overallScheduleType';
-import { styled } from 'styled-components';
-import { theme } from 'styles/theme';
-import { availableScheduleOptionApi } from 'utils/apis/availbleScheduleOptionApi';
-import { overallScheduleApi } from 'utils/apis/overallScheduleApi';
-
-import TimeTable from './components/TimeTable';
-import { getFormattedAvailableDateTimes } from './utils/getFormattedAvailableDateTimes';
+import styled from 'styled-components';
+import { useGetOverallSchedule } from 'utils/apis/useGetOverallSchedule';
+import { useGetTimetable } from 'utils/apis/useGetTimetable';
+import OverallScheduleTable from './components/OverallScheduleTable';
+import Title from './components/Title';
-const OverallSchedule = () => {
+function OverallSchedule() {
const { meetingId } = useParams();
- const [overallScheduleData, setOverallScheduleData] = useState();
-
- const [availableDates, setAvailableDates] = useRecoilState(availableDatesAtom);
-
- const [preferTimes, setPreferTimes] = useRecoilState(preferTimesAtom);
-
- const timeSlotUserNames = useRecoilValue(timeSlotUserNameAtom);
-
- const [memberCount, setMemberCount] = useState(0);
- const [totalUserNames, setTotalUserNames] = useState();
-
- const getAvailableScheduleOption = async () => {
- try {
- const { data } = await availableScheduleOptionApi(meetingId);
- setAvailableDates(data.data.availableDates);
- setPreferTimes(data.data.preferTimes);
- } catch (err) {
- console.log(err);
- }
- };
-
-
- const getOverallSchedule = async () => {
- try {
- const result = await overallScheduleApi(meetingId);
- const { data } = result.data;
- const uniqueData = [...new Set(data.totalUserNames)];
- setOverallScheduleData(data);
- setMemberCount(data.memberCount);
- setTotalUserNames(uniqueData);
- } catch (err) {
- console.log(err);
- }
- };
-
- useEffect(() => {
- getAvailableScheduleOption();
- getOverallSchedule();
- }, []);
+ const { data: dataTimetable, isLoading: isLoadingTimetable } = useGetTimetable(meetingId);
+ const { data: dataOverallSchedule, isLoading: isLoadingOverallSchedule } = useGetOverallSchedule(
+ meetingId,
+ );
- const formattedAvailableDateTimes =
- overallScheduleData && getFormattedAvailableDateTimes(overallScheduleData);
+ // 시간대 선택 단계가 없어질 것을 고려하여 상수값을 설정해놓음
+ const PREFER_TIMES = { startTime: '06:00', endTime: '24:00' };
return (
- {overallScheduleData ? (
- <>
-
-
- 현재까지
-
-
- {memberCount.toString()}명
-
-
- 이 입력했어요
-
-
-
- {totalUserNames &&
- totalUserNames.map((name, idx) => (
-
- {name}
- {idx !== totalUserNames.length - 1 ? ',' : ''}
-
- ))}
-
-
+ {!isLoadingTimetable &&
+ !isLoadingOverallSchedule &&
+ dataTimetable &&
+ dataOverallSchedule && (
+
-
- {!timeSlotUserNames ? (
-
-
- 블럭을 선택하면 해당 시간대에 참여가능한
-
-
- 인원을 확인할 수 있어요
-
-
- ) : (
- timeSlotUserNames.map((name, idx) => (
-
- {name}
- {idx !== timeSlotUserNames.length - 1 ? ',' : ''}
-
- ))
- )}
-
- >
- ) : (
-
-
-
- )}
+ )}
);
-};
+}
export default OverallSchedule;
-const UserNameWrapper = styled.aside`
+const OverallScheduleWrapper = styled.div`
display: flex;
- position: fixed;
- bottom: 4.4rem;
- flex-wrap: wrap;
+ flex-direction: column;
+ align-items: center;
justify-content: center;
- border: 1px solid ${({ theme }) => theme.colors.grey5};
- border-radius: 0.8rem;
- background: ${({ theme }) => theme.colors.grey9};
- width: 33.5rem;
- min-height: 8.3rem;
- text-align: center;
- color: ${({ theme }) => theme.colors.white};
-`;
-
-const OverallScheduleWrapper = styled.main`
- margin-bottom: 16.1rem;
+ margin-bottom: 16.4rem;
`;
-const TextOneLine = styled.div`
- display: flex;
- flex-wrap: wrap;
- margin-top: 3.7rem;
- width: 100%;
-`;
-const TotalUserNames = styled.div`
- display: flex;
- margin-top: 1.2rem;
- margin-bottom: 2.4rem;
-`;
-
-const LoadingWrapper = styled.div`
- position: relative;
- top: 25rem;
- width: 100%;
-`;
-
-const TextTwoLine = styled.div`
- display:flex;
- flex-direction:column;
- align-items: center;
- justify-content:center;
-`
\ No newline at end of file
diff --git a/src/pages/OverallSchedule/components/OverallScheduleColumn.tsx b/src/pages/OverallSchedule/components/OverallScheduleColumn.tsx
new file mode 100644
index 00000000..96853a6d
--- /dev/null
+++ b/src/pages/OverallSchedule/components/OverallScheduleColumn.tsx
@@ -0,0 +1,45 @@
+import Slot from 'components/timetableComponents/parts/Slot';
+import { ColumnStructure } from 'components/timetableComponents/types';
+import { theme } from 'styles/theme';
+import { TimeSlot } from 'utils/apis/useGetOverallSchedule';
+
+import { useSlotClick } from '../hooks/useSlotClick';
+
+interface OverallScheduleColumnProps extends ColumnStructure {
+ availableSlotInfo: TimeSlot[];
+}
+
+function OverallScheduleColumn({ date, timeSlots, availableSlotInfo }: OverallScheduleColumnProps) {
+
+ const { clickedSlot, onClickSlot } = useSlotClick();
+
+ const getTimeSlotStyle = (colorLevel: number, slotId:string) => {
+ const COLOR :{ [key : number]: string } = {
+ 0: 'transparent',
+ 1: theme.colors.level1,
+ 2: theme.colors.level2,
+ 3: theme.colors.level3,
+ 4: theme.colors.level4,
+ 5: theme.colors.level5,
+ };
+
+ const isClickedSlot = clickedSlot === slotId;
+ return `
+ background-color: ${isClickedSlot && colorLevel!==0 ? theme.colors.sub1 : COLOR[colorLevel]};
+ cursor: ${colorLevel !== 0 ? 'pointer' : 'default'};
+ `
+ }
+
+ return (
+ <>
+ {timeSlots.map((timeSlot) => {
+ const { colorLevel = 0, userNames = [] } = availableSlotInfo.find((info) => info.time === timeSlot) ?? {};
+ const slotId = `${date}/${timeSlot}`;
+
+ return onClickSlot(slotId, userNames)}/>;
+ })}
+ >
+ );
+}
+
+export default OverallScheduleColumn;
diff --git a/src/pages/OverallSchedule/components/OverallScheduleTable.tsx b/src/pages/OverallSchedule/components/OverallScheduleTable.tsx
new file mode 100644
index 00000000..1553de8d
--- /dev/null
+++ b/src/pages/OverallSchedule/components/OverallScheduleTable.tsx
@@ -0,0 +1,65 @@
+import { useState } from 'react';
+
+import Timetable from 'components/timetableComponents/Timetable';
+import { ColumnStructure, TimetableStructure } from 'components/timetableComponents/types';
+import {
+ AvailableDateTime,
+ TimeSlot,
+ getOverallScheduleResponse,
+} from 'utils/apis/useGetOverallSchedule';
+
+import OverallScheduleColumn from './OverallScheduleColumn';
+import UserNames from './UserNames';
+import { ClickContext } from '../contexts/useClickContext';
+
+interface OverallScheduleTableProps extends TimetableStructure {
+ dataOverallSchedule: getOverallScheduleResponse['data'];
+}
+
+function OverallScheduleTable({
+ timeSlots,
+ availableDates,
+ dataOverallSchedule,
+}: OverallScheduleTableProps) {
+ const [clickedSlot, setClickedSlot] = useState(undefined);
+ const [clickedUserNames, setClickedUserNames] = useState([]);
+
+ const getAvailableTimesPerDate = (
+ availableDates: AvailableDateTime[],
+ date: string,
+ ): TimeSlot[] => {
+ const [month, day, dayOfWeek] = date.split('/');
+
+ const matchedDate = availableDates.find(
+ (date) => date.month === month && date.day === day && date.dayOfWeek === dayOfWeek,
+ );
+
+ return matchedDate ? matchedDate.timeSlots : [];
+ };
+
+ return (
+
+ }>
+ {({ date, timeSlots }: ColumnStructure) => (
+
+ )}
+
+
+ );
+}
+
+export default OverallScheduleTable;
diff --git a/src/pages/OverallSchedule/components/Title.tsx b/src/pages/OverallSchedule/components/Title.tsx
new file mode 100644
index 00000000..5fea4c8a
--- /dev/null
+++ b/src/pages/OverallSchedule/components/Title.tsx
@@ -0,0 +1,49 @@
+import Text from 'components/atomComponents/Text';
+import styled from 'styled-components';
+import { theme } from 'styles/theme';
+
+interface TitleProps {
+ memberCount?: number;
+ totalUserNames?: string[];
+}
+
+function Title({ memberCount, totalUserNames }: TitleProps) {
+ return (
+ <>
+
+
+ 현재까지
+
+
+ {memberCount !== undefined ? memberCount.toString() : ''}명
+
+
+ 이 입력했어요
+
+
+
+ {totalUserNames && (
+
+ {totalUserNames.join(',')}
+
+ )}
+
+ >
+ );
+}
+
+export default Title;
+
+const TextOneLine = styled.div`
+ display: flex;
+ flex-wrap: wrap;
+ margin-top: 3.7rem;
+ width: 100%;
+`;
+
+const TotalUserNames = styled.div`
+ display: flex;
+ margin-top: 1.2rem;
+ margin-bottom: 2.4rem;
+ width: 100%;
+`;
diff --git a/src/pages/OverallSchedule/components/UserNames.tsx b/src/pages/OverallSchedule/components/UserNames.tsx
new file mode 100644
index 00000000..48c04a8c
--- /dev/null
+++ b/src/pages/OverallSchedule/components/UserNames.tsx
@@ -0,0 +1,52 @@
+import Text from 'components/atomComponents/Text';
+import styled from 'styled-components';
+import { theme } from 'styles/theme';
+
+import { useClickContext } from '../contexts/useClickContext';
+
+function UserNames() {
+ const { clickedUserNames } = useClickContext();
+
+ return (
+
+ {clickedUserNames.length === 0 ? (
+
+
+ 블럭을 선택하면 해당 시간대에 참여가능한
+
+
+ 인원을 확인할 수 있어요
+
+
+ ) : (
+
+ {clickedUserNames.join(', ')}
+
+ )}
+
+ );
+}
+
+export default UserNames;
+
+const UserNamesWrapper = styled.aside`
+ display: flex;
+ position: fixed;
+ bottom: 4.4rem;
+ flex-wrap: wrap;
+ justify-content: center;
+ border: 1px solid ${({ theme }) => theme.colors.grey5};
+ border-radius: 0.8rem;
+ background: ${({ theme }) => theme.colors.grey9};
+ width: 33.5rem;
+ min-height: 8.3rem;
+ text-align: center;
+ color: ${({ theme }) => theme.colors.white};
+`;
+
+const Texts = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+`;
diff --git a/src/pages/OverallSchedule/contexts/useClickContext.ts b/src/pages/OverallSchedule/contexts/useClickContext.ts
new file mode 100644
index 00000000..4723cb90
--- /dev/null
+++ b/src/pages/OverallSchedule/contexts/useClickContext.ts
@@ -0,0 +1,23 @@
+import { Dispatch, SetStateAction, createContext, useContext } from 'react';
+
+interface ClickContextType {
+ clickedSlot: string | undefined;
+ setClickedSlot: Dispatch>;
+ clickedUserNames: string[];
+ setClickedUserNames: Dispatch>;
+}
+
+export const ClickContext = createContext({
+ clickedSlot: undefined,
+ setClickedSlot: () => undefined,
+ clickedUserNames: [],
+ setClickedUserNames: () => [],
+});
+
+export function useClickContext() {
+ const context = useContext(ClickContext);
+ if (context == null) {
+ throw new Error('ClickContext Error');
+ }
+ return context;
+}
diff --git a/src/pages/OverallSchedule/hooks/useSlotClick.ts b/src/pages/OverallSchedule/hooks/useSlotClick.ts
new file mode 100644
index 00000000..f49c5cd7
--- /dev/null
+++ b/src/pages/OverallSchedule/hooks/useSlotClick.ts
@@ -0,0 +1,12 @@
+import { useClickContext } from '../contexts/useClickContext';
+
+export const useSlotClick = () => {
+ const { clickedSlot, setClickedSlot, setClickedUserNames } = useClickContext();
+
+ const onClickSlot = (targetSlot: string, targetUserNames: string[]) => {
+ setClickedSlot(targetSlot);
+ setClickedUserNames(targetUserNames);
+ };
+
+ return { clickedSlot, onClickSlot };
+};
diff --git a/src/pages/createMeeting/CreateMeeting.tsx b/src/pages/createMeeting/CreateMeeting.tsx
index bcde5d43..b99eeccd 100644
--- a/src/pages/createMeeting/CreateMeeting.tsx
+++ b/src/pages/createMeeting/CreateMeeting.tsx
@@ -6,6 +6,7 @@ import ReturnBodyComponent from 'pages/createMeeting/components/ReturnBodyCompon
import ReturnTitleComponent from 'pages/createMeeting/components/ReturnTitleComponent';
import { funnelStep } from './data/meetingInfoData';
import styled from 'styled-components/macro';
+import { useGetTimetable } from 'utils/apis/useGetTimetable';
const initialMeetingInfo: MeetingInfo = {
title: '',
@@ -23,6 +24,7 @@ function CreateMeeting() {
const [step, setStep] = useState(0);
const [meetingInfo, setMeetingInfo] = useState(initialMeetingInfo);
const currentStep = funnelStep[step];
+
return (
<>
diff --git a/src/pages/createMeeting/components/useFunnel/SetAdditionalInfo.tsx b/src/pages/createMeeting/components/useFunnel/SetAdditionalInfo.tsx
index fc86d9e1..79179077 100644
--- a/src/pages/createMeeting/components/useFunnel/SetAdditionalInfo.tsx
+++ b/src/pages/createMeeting/components/useFunnel/SetAdditionalInfo.tsx
@@ -1,13 +1,13 @@
-import React from 'react';
+import { FunnelProps, MeetingInfo } from 'pages/createMeeting/types/useFunnelInterface';
-import { isAxiosError } from 'axios';
import Button from 'components/atomComponents/Button';
+import React from 'react';
import Text from 'components/atomComponents/Text';
import TextAreaInput from 'components/atomComponents/TextAreaInput';
-import { MeetingInfo, FunnelProps } from 'pages/createMeeting/types/useFunnelInterface';
-import { useNavigate } from 'react-router-dom';
+import { createMeetingApi } from 'utils/apis/legacy/createMeetingApi';
+import { isAxiosError } from 'axios';
import styled from 'styled-components/macro';
-import { createMeetingApi } from 'utils/apis/createMeetingApi';
+import { useNavigate } from 'react-router-dom';
function SetAdditionalInfo({ meetingInfo, setMeetingInfo, setStep }: FunnelProps) {
const navigate = useNavigate();
diff --git a/src/pages/legacy/overallSchedule/OverallSchedule.tsx b/src/pages/legacy/overallSchedule/OverallSchedule.tsx
new file mode 100644
index 00000000..e19b2805
--- /dev/null
+++ b/src/pages/legacy/overallSchedule/OverallSchedule.tsx
@@ -0,0 +1,165 @@
+import React, { useEffect, useState } from 'react';
+import { availableDatesAtom, preferTimesAtom, timeSlotUserNameAtom } from 'atoms/atom';
+import { useRecoilState, useRecoilValue } from 'recoil';
+
+import LoadingPage from 'pages/errorLoading/LoadingPage';
+import { OverallScheduleData } from 'src/types/overallScheduleType';
+import Text from 'components/atomComponents/Text';
+import TimeTable from './components/TimeTable';
+import { availableScheduleOptionApi } from 'utils/apis/legacy/availbleScheduleOptionApi';
+import { getFormattedAvailableDateTimes } from './utils/getFormattedAvailableDateTimes';
+import { overallScheduleApi } from 'utils/apis/legacy/overallScheduleApi';
+import { styled } from 'styled-components';
+import { theme } from 'styles/theme';
+import { useParams } from 'react-router-dom';
+
+const OverallSchedule = () => {
+ const { meetingId } = useParams();
+ const [overallScheduleData, setOverallScheduleData] = useState();
+
+ const [availableDates, setAvailableDates] = useRecoilState(availableDatesAtom);
+
+ const [preferTimes, setPreferTimes] = useRecoilState(preferTimesAtom);
+
+ const timeSlotUserNames = useRecoilValue(timeSlotUserNameAtom);
+
+ const [memberCount, setMemberCount] = useState(0);
+ const [totalUserNames, setTotalUserNames] = useState();
+
+ const getAvailableScheduleOption = async () => {
+ try {
+ const { data } = await availableScheduleOptionApi(meetingId);
+ setAvailableDates(data.data.availableDates);
+ setPreferTimes(data.data.preferTimes);
+ } catch (err) {
+ console.log(err);
+ }
+ };
+
+
+ const getOverallSchedule = async () => {
+ try {
+ const result = await overallScheduleApi(meetingId);
+ const { data } = result.data;
+ const uniqueData = [...new Set(data.totalUserNames)];
+ setOverallScheduleData(data);
+ setMemberCount(data.memberCount);
+ setTotalUserNames(uniqueData);
+ } catch (err) {
+ console.log(err);
+ }
+ };
+
+ useEffect(() => {
+ getAvailableScheduleOption();
+ getOverallSchedule();
+ }, []);
+
+ const formattedAvailableDateTimes =
+ overallScheduleData && getFormattedAvailableDateTimes(overallScheduleData);
+
+ return (
+
+ {overallScheduleData ? (
+ <>
+
+
+ 현재까지
+
+
+ {memberCount.toString()}명
+
+
+ 이 입력했어요
+
+
+
+ {totalUserNames &&
+ totalUserNames.map((name, idx) => (
+
+ {name}
+ {idx !== totalUserNames.length - 1 ? ',' : ''}
+
+ ))}
+
+
+
+ {!timeSlotUserNames ? (
+
+
+ 블럭을 선택하면 해당 시간대에 참여가능한
+
+
+ 인원을 확인할 수 있어요
+
+
+ ) : (
+ timeSlotUserNames.map((name, idx) => (
+
+ {name}
+ {idx !== timeSlotUserNames.length - 1 ? ',' : ''}
+
+ ))
+ )}
+
+ >
+ ) : (
+
+
+
+ )}
+
+ );
+};
+
+export default OverallSchedule;
+
+const UserNameWrapper = styled.aside`
+ display: flex;
+ position: fixed;
+ bottom: 4.4rem;
+ flex-wrap: wrap;
+ justify-content: center;
+ border: 1px solid ${({ theme }) => theme.colors.grey5};
+ border-radius: 0.8rem;
+ background: ${({ theme }) => theme.colors.grey9};
+ width: 33.5rem;
+ min-height: 8.3rem;
+ text-align: center;
+ color: ${({ theme }) => theme.colors.white};
+`;
+
+const OverallScheduleWrapper = styled.main`
+ margin-bottom: 16.1rem;
+`;
+
+const TextOneLine = styled.div`
+ display: flex;
+ flex-wrap: wrap;
+ margin-top: 3.7rem;
+ width: 100%;
+`;
+
+const TotalUserNames = styled.div`
+ display: flex;
+ margin-top: 1.2rem;
+ margin-bottom: 2.4rem;
+`;
+
+const LoadingWrapper = styled.div`
+ position: relative;
+ top: 25rem;
+ width: 100%;
+`;
+
+const TextTwoLine = styled.div`
+ display:flex;
+ flex-direction:column;
+ align-items: center;
+ justify-content:center;
+`
\ No newline at end of file
diff --git a/src/pages/OverallSchedule/components/Column.tsx b/src/pages/legacy/overallSchedule/components/Column.tsx
similarity index 100%
rename from src/pages/OverallSchedule/components/Column.tsx
rename to src/pages/legacy/overallSchedule/components/Column.tsx
diff --git a/src/pages/OverallSchedule/components/Row.tsx b/src/pages/legacy/overallSchedule/components/Row.tsx
similarity index 100%
rename from src/pages/OverallSchedule/components/Row.tsx
rename to src/pages/legacy/overallSchedule/components/Row.tsx
diff --git a/src/pages/OverallSchedule/components/TimeTable.tsx b/src/pages/legacy/overallSchedule/components/TimeTable.tsx
similarity index 100%
rename from src/pages/OverallSchedule/components/TimeTable.tsx
rename to src/pages/legacy/overallSchedule/components/TimeTable.tsx
diff --git a/src/pages/OverallSchedule/utils/getFormattedAvailableDateTimes.ts b/src/pages/legacy/overallSchedule/utils/getFormattedAvailableDateTimes.ts
similarity index 100%
rename from src/pages/OverallSchedule/utils/getFormattedAvailableDateTimes.ts
rename to src/pages/legacy/overallSchedule/utils/getFormattedAvailableDateTimes.ts
diff --git a/src/pages/OverallSchedule/utils/setUserNames.ts b/src/pages/legacy/overallSchedule/utils/setUserNames.ts
similarity index 100%
rename from src/pages/OverallSchedule/utils/setUserNames.ts
rename to src/pages/legacy/overallSchedule/utils/setUserNames.ts
diff --git a/src/pages/legacy/selectSchedule/SelectModal.tsx b/src/pages/legacy/selectSchedule/SelectModal.tsx
index 3e7a99d0..484f8e8e 100644
--- a/src/pages/legacy/selectSchedule/SelectModal.tsx
+++ b/src/pages/legacy/selectSchedule/SelectModal.tsx
@@ -1,28 +1,27 @@
-import { hostAvailableApi, userAvailableApi } from 'utils/apis/createHostAvailableSchedule';
-import { scheduleAtom, userNameAtom } from 'atoms/atom';
-import { transformHostScheduleType, transformUserScheduleType } from './utils/changeApiReq';
-import { useNavigate, useParams } from 'react-router';
-import { useRecoilState, useRecoilValue } from 'recoil';
-
-import { ExitIc } from 'components/Icon/icon';
-import { ScheduleStates } from './types/Schedule';
-import Text from 'components/atomComponents/Text';
+import { userNameAtom } from 'atoms/atom';
import { isAxiosError } from 'axios';
+import Text from 'components/atomComponents/Text';
+import { ExitIc } from 'components/Icon/icon';
+import { useSelectContext } from 'pages/selectSchedule/contexts/useSelectContext';
+import { formatHostScheduleScheme, formatMemberScheduleScheme } from 'pages/selectSchedule/utils';
+import { useNavigate, useParams } from 'react-router';
+import { useRecoilValue } from 'recoil';
import styled from 'styled-components/macro';
import { theme } from 'styles/theme';
+import { hostAvailableApi, userAvailableApi } from 'utils/apis/legacy/createHostAvailableSchedule';
interface ModalProps {
setShowModal: (isModalOpen: boolean) => void;
}
function SelectModal({ setShowModal }: ModalProps) {
- const [scheduleList, setScheduleList] = useRecoilState(scheduleAtom);
+ const { selectedSlots } = useSelectContext();
const userName = useRecoilValue(userNameAtom);
const navigate = useNavigate();
const { auth, meetingId } = useParams();
- const updateScheduleType = transformHostScheduleType(scheduleList);
- const updateMemberScheduleType = transformUserScheduleType(scheduleList, userName);
+ const updateScheduleType = formatHostScheduleScheme(selectedSlots);
+ const updateMemberScheduleType = formatMemberScheduleScheme(selectedSlots, userName);
const postHostAvailableApi = async () => {
try {
@@ -162,12 +161,15 @@ const MentContainer = styled.div`
`;
const ModalMent = styled.span`
- color: ${({ theme }) => theme.colors.white};
- ${({ theme }) => theme.fonts.body2};
+ margin-top: 2.4rem;
+ margin-bottom: 0.8rem;
+
width: 14.4rem;
+
text-align: center;
- margin-bottom: 0.8rem;
- margin-top: 2.4rem;
+
+ color: ${({ theme }) => theme.colors.white};
+ ${({ theme }) => theme.fonts.body2};
`;
const ModalHighlight = styled.span`
diff --git a/src/pages/legacy/selectSchedule/SelectPriorityPage.tsx b/src/pages/legacy/selectSchedule/SelectPriorityPage.tsx
index 8a4f0358..fbf5e6ed 100644
--- a/src/pages/legacy/selectSchedule/SelectPriorityPage.tsx
+++ b/src/pages/legacy/selectSchedule/SelectPriorityPage.tsx
@@ -1,19 +1,18 @@
import React, { useEffect, useState } from 'react';
-
import { availableDatesAtom, preferTimesAtom, scheduleAtom } from 'atoms/atom';
-import axios from 'axios';
+import { useNavigate, useParams } from 'react-router-dom';
+
import Button from 'components/atomComponents/Button';
-import Text from 'components/atomComponents/Text';
+import Header from 'components/moleculesComponents/Header';
import PriorityDropdown from 'components/legacy/scheduleComponents/components/PriorityDropdown';
+import SelectModal from './SelectModal';
+import Text from 'components/atomComponents/Text';
import TimeTable from 'components/legacy/scheduleComponents/components/TimeTable';
-import Header from 'components/moleculesComponents/Header';
-import { useNavigate, useParams } from 'react-router-dom';
-import { useRecoilState } from 'recoil';
+import { availableScheduleOptionApi } from 'utils/apis/legacy/availbleScheduleOptionApi';
+import axios from 'axios';
import styled from 'styled-components';
import { theme } from 'styles/theme';
-import { availableScheduleOptionApi } from 'utils/apis/availbleScheduleOptionApi';
-
-import SelectModal from './SelectModal';
+import { useRecoilState } from 'recoil';
const SelectSchedulePriority = () => {
const [availableDates, setAvailableDates] = useRecoilState(availableDatesAtom);
diff --git a/src/pages/legacy/selectSchedule/SelectSchedulePage.tsx b/src/pages/legacy/selectSchedule/SelectSchedulePage.tsx
index 5084ac55..93648246 100644
--- a/src/pages/legacy/selectSchedule/SelectSchedulePage.tsx
+++ b/src/pages/legacy/selectSchedule/SelectSchedulePage.tsx
@@ -1,21 +1,20 @@
import React, { useEffect, useRef, useState } from 'react';
-
import { availableDatesAtom, preferTimesAtom, scheduleAtom } from 'atoms/atom';
-import axios from 'axios';
+import { useNavigate, useParams } from 'react-router-dom';
+
import Button from 'components/atomComponents/Button';
-import Text from 'components/atomComponents/Text';
-import { PlusIc } from 'components/Icon/icon';
-import TimeTable from 'components/legacy/scheduleComponents/components/TimeTable';
import Header from 'components/moleculesComponents/Header';
-import { useNavigate, useParams } from 'react-router-dom';
-import { useRecoilState } from 'recoil';
import { MeetingDetail } from 'src/types/availbleScheduleType';
+import { PlusIc } from 'components/Icon/icon';
+import { ScheduleStates } from './types/Schedule';
+import SelectSchedule from './components/SelectSchedule';
+import Text from 'components/atomComponents/Text';
+import TimeTable from 'components/legacy/scheduleComponents/components/TimeTable';
+import { availableScheduleOptionApi } from 'utils/apis/legacy/availbleScheduleOptionApi';
+import axios from 'axios';
import styled from 'styled-components/macro';
import { theme } from 'styles/theme';
-import { availableScheduleOptionApi } from 'utils/apis/availbleScheduleOptionApi';
-
-import SelectSchedule from './components/SelectSchedule';
-import { ScheduleStates } from './types/Schedule';
+import { useRecoilState } from 'recoil';
function SelectSchedulePage() {
// 가능시간 선택지 - 날짜
diff --git a/src/pages/legacy/selectSchedule/utils/changeApiReq.ts b/src/pages/legacy/selectSchedule/utils/changeApiReq.ts
deleted file mode 100644
index 2aac57f0..00000000
--- a/src/pages/legacy/selectSchedule/utils/changeApiReq.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import {
- HostAvailableSchduleRequestType,
- UserAvailableScheduleRequestType,
-} from 'src/types/createAvailableSchduleType';
-
-import { ScheduleStates } from '../types/Schedule';
-
-export const transformHostScheduleType = (
- scheduleList: ScheduleStates[],
-): (HostAvailableSchduleRequestType | null)[] => {
- return scheduleList.map((item) => {
- const matchedResult = item.date.match(/(\d+)월 (\d+)일 \((\S+)\)/);
- if (!matchedResult) {
- return null;
- }
- const [, month, day, dateOfWeek] = matchedResult;
-
- return {
- id: item.id.toString(),
- month: month.padStart(2, '0'),
- day: day.padStart(2, '0'),
- dayOfWeek: dateOfWeek,
- startTime: item.startTime,
- endTime: item.endTime,
- priority: item.priority,
- };
- });
-};
-
-export const transformUserScheduleType = (
- scheduleList: ScheduleStates[],
- meetInfo: string,
-): UserAvailableScheduleRequestType => {
- const availableTimes = scheduleList.map((item) => {
- const matchedResult = item.date.match(/(\d+)월 (\d+)일 \((\S+)\)/);
- if (!matchedResult) {
- return {
- id: '',
- month: '',
- day: '',
- dayOfWeek: '',
- startTime: '',
- endTime: '',
- priority: 0,
- };
- }
- // const [, month, day, dateOfWeek]: string[] | null = item.date.match(
- // /(\d+)월 (\d+)일 \((\S+)\)/,
- // );
- const [, month, day, dateOfWeek] = matchedResult;
- return {
- id: item.id.toString(),
- month: month.padStart(2, '0'),
- day: day.padStart(2, '0'),
- dayOfWeek: dateOfWeek,
- startTime: item.startTime,
- endTime: item.endTime,
- priority: item.priority,
- };
- });
-
- const final: UserAvailableScheduleRequestType = {
- name: meetInfo,
- availableTimes,
- };
- return final;
-};
diff --git a/src/pages/onBoarding/OnBoarding.tsx b/src/pages/onBoarding/OnBoarding.tsx
index aafc912a..3457f444 100644
--- a/src/pages/onBoarding/OnBoarding.tsx
+++ b/src/pages/onBoarding/OnBoarding.tsx
@@ -2,19 +2,19 @@ import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
+import { Autoplay, Navigation, Pagination } from 'swiper/modules';
+import { Swiper, SwiperSlide } from 'swiper/react';
+
+import Button from 'components/atomComponents/Button';
import CardPng from 'assets/images/card.png';
+import Explain from './components/Explain';
+import Header from 'components/moleculesComponents/Header';
import InsertPng from 'assets/images/insert.png';
+import { Link } from 'react-router-dom';
import MakePng from 'assets/images/make.png';
import PointPng from 'assets/images/point.png';
-import Button from 'components/atomComponents/Button';
import Text from 'components/atomComponents/Text';
-import Header from 'components/moleculesComponents/Header';
-import { Link } from 'react-router-dom';
import styled from 'styled-components/macro';
-import { Autoplay, Navigation, Pagination } from 'swiper/modules';
-import { Swiper, SwiperSlide } from 'swiper/react';
-
-import Explain from './components/Explain';
const slides = [
{
@@ -60,7 +60,7 @@ function OnBoarding() {
pagination={{
clickable: true,
}}
- navigation={true}
+ navigation={false}
modules={[Autoplay, Pagination, Navigation]}
className="mySwiper"
>
diff --git a/src/pages/selectSchedule/SelectSchedule.tsx b/src/pages/selectSchedule/SelectSchedule.tsx
index e0435132..6e8dadc1 100644
--- a/src/pages/selectSchedule/SelectSchedule.tsx
+++ b/src/pages/selectSchedule/SelectSchedule.tsx
@@ -2,88 +2,50 @@ import { useState } from 'react';
import Header from 'components/moleculesComponents/Header';
import TitleComponents from 'components/moleculesComponents/TitleComponents';
-import { DateType } from 'components/timetableComponents/types';
import { getAvailableTimes } from 'components/timetableComponents/utils';
+import { useParams } from 'react-router-dom';
import styled from 'styled-components';
+import { useGetTimetable } from 'utils/apis/useGetTimetable';
import Description from './components/Description';
import SelectScheduleTable from './components/SelectScheduleTable';
-import { ScheduleStepContext } from './context';
+import { ScheduleStepContext } from './contexts/useScheduleStepContext';
import { ScheduleStepType } from './types';
-
-/***** api 연결 후 지울 것*****/
-
-const availableDates: DateType[] = [
- {
- month: '6',
- day: '20',
- dayOfWeek: '목',
- },
- {
- month: '6',
- day: '21',
- dayOfWeek: '금',
- },
- {
- month: '6',
- day: '22',
- dayOfWeek: '토',
- },
- {
- month: '6',
- day: '23',
- dayOfWeek: '일',
- },
-];
-
-export type SlotType = {
- startTime: string;
- endTime: string;
-};
-
-const preferTimes: SlotType = {
- startTime: '06:00',
- endTime: '24:00',
-};
-
-const timeSlots = getAvailableTimes(preferTimes);
-const duration = 'HALF';
-const place = 'OFFLINE';
-const placeDetail = undefined;
-/***** api 연결 후 지울 것*****/
+import { TITLES } from './utils';
function SelectSchedule() {
const [scheduleStep, setScheduleStep] = useState('selectTimeSlot');
+ const { meetingId } = useParams();
+ const { data, isLoading } = useGetTimetable(meetingId);
- interface TitlesType {
- [key: string]: {
- main: string;
- sub?: string;
- };
- }
- const titles: TitlesType = {
- selectTimeSlot: {
- main: '가능한 시간대를 등록해주세요',
- sub: '시작시간과 종료시간을 터치하여 블럭을 생성해주세요',
- },
- selectPriority: {
- main: '우선순위를 입력해주세요',
- },
- };
+ // 시간대 선택 단계가 없어질 것을 고려하여 상수값을 설정해놓음
+ const PREFER_TIMES = { startTime: '06:00', endTime: '24:00' };
return (
- {scheduleStep === 'selectTimeSlot' && (
-
- )}
-
-
+ {!isLoading &&
+ data && (
+ <>
+ {scheduleStep === 'selectTimeSlot' && (
+
+ )}
+
+
+ >
+ )}
);
diff --git a/src/pages/selectSchedule/components/Description.tsx b/src/pages/selectSchedule/components/Description.tsx
index e87e25fe..34e88e25 100644
--- a/src/pages/selectSchedule/components/Description.tsx
+++ b/src/pages/selectSchedule/components/Description.tsx
@@ -1,18 +1,18 @@
-import { formatDuration, formatPlace } from '../utils';
+import { DURATION, PLACE } from '../utils';
import Text from 'components/atomComponents/Text';
import styled from 'styled-components';
import { theme } from 'styles/theme';
interface DescriptionProps {
- duration: string;
- place: string;
+ duration: keyof typeof DURATION;
+ place: keyof typeof PLACE;
placeDetail?: string;
}
function Description({ duration: durationOg, place: placeOg, placeDetail }: DescriptionProps) {
- const duration = formatDuration(durationOg);
- const place = formatPlace(placeOg);
+ const duration = DURATION[durationOg];
+ const place = PLACE[placeOg];
return (
diff --git a/src/pages/selectSchedule/components/SelectScheduleTable.tsx b/src/pages/selectSchedule/components/SelectScheduleTable.tsx
index 65492546..4134e8bc 100644
--- a/src/pages/selectSchedule/components/SelectScheduleTable.tsx
+++ b/src/pages/selectSchedule/components/SelectScheduleTable.tsx
@@ -1,26 +1,32 @@
+import { useState } from 'react';
+
import Timetable from 'components/timetableComponents/Timetable';
import { ColumnStructure, TimetableStructure } from 'components/timetableComponents/types';
+import PriorityColumn from './selectPriority/PriorityColumn';
import PriorityCta from './selectPriority/PriorityCta';
import PriorityDropdown from './selectPriority/PriorityDropdown';
-import PrioritySlots from './selectPriority/PrioritySlots';
-import SelectionSlots from './selectTimeSlot/SelectionSlots';
+import SelectionColumn from './selectTimeSlot/SelectionColumn';
import TimeSlotCta from './selectTimeSlot/TimeSlotCta';
-import { useScheduleStepContext } from '../context';
+import { useScheduleStepContext } from '../contexts/useScheduleStepContext';
+import { SelectContext, SelectedSlotType } from '../contexts/useSelectContext';
import { StepSlotsType, StepbottomItemsType } from '../types';
function SelectScheduleTable({ timeSlots, availableDates }: TimetableStructure) {
+ const [startSlot, setStartSlot] = useState(undefined);
+ const [selectedSlots, setSelectedSlots] = useState({});
+
const { scheduleStep } = useScheduleStepContext();
- const stepSlots: StepSlotsType = {
+ const stepColumns: StepSlotsType = {
selectTimeSlot: ({ date, timeSlots }: ColumnStructure) => (
-
+
),
selectPriority: ({ date, timeSlots }: ColumnStructure) => (
-
+
),
};
- const stepSlot = stepSlots[scheduleStep];
+ const stepColumn = stepColumns[scheduleStep];
const bottomItems: StepbottomItemsType = {
selectTimeSlot: ,
@@ -34,9 +40,18 @@ function SelectScheduleTable({ timeSlots, availableDates }: TimetableStructure)
const bottomItem = bottomItems[scheduleStep];
return (
-
- {stepSlot}
-
+
+
+ {stepColumn}
+
+
);
}
diff --git a/src/pages/selectSchedule/components/selectPriority/PrioritySlots.tsx b/src/pages/selectSchedule/components/selectPriority/PriorityColumn.tsx
similarity index 81%
rename from src/pages/selectSchedule/components/selectPriority/PrioritySlots.tsx
rename to src/pages/selectSchedule/components/selectPriority/PriorityColumn.tsx
index 23187136..7c30d2b4 100644
--- a/src/pages/selectSchedule/components/selectPriority/PrioritySlots.tsx
+++ b/src/pages/selectSchedule/components/selectPriority/PriorityColumn.tsx
@@ -1,16 +1,17 @@
-import { ColumnStructure } from 'components/timetableComponents/types';
-import Slot from '../../../../components/timetableComponents/parts/Slot';
import Text from 'components/atomComponents/Text';
+import { ColumnStructure } from 'components/timetableComponents/types';
+import { useSelectContext } from 'pages/selectSchedule/contexts/useSelectContext';
import { theme } from 'styles/theme';
-import { useTimetableContext } from '../../../../components/timetableComponents/context';
-function PrioritySlots({ date, timeSlots }: ColumnStructure) {
- const { selectedSlots } = useTimetableContext();
+import Slot from '../../../../components/timetableComponents/parts/Slot';
+
+function PriorityColumn({ date, timeSlots }: ColumnStructure) {
+ const { selectedSlots } = useSelectContext();
const selectedSlotsPerDate = Object.entries(selectedSlots).filter(
([, slot]) => slot.date === date,
);
- const getPrioritySlotStyle = (selectedEntryId?: number, priority?: number) => {
+ const getPriorityColumntyle = (selectedEntryId?: number, priority?: number) => {
const isSelectedSlot = selectedEntryId !== undefined;
const slotColor =
priority === 1
@@ -49,7 +50,7 @@ function PrioritySlots({ date, timeSlots }: ColumnStructure) {
{isFirstSlot && priority !== 0 ? priority : ''}
@@ -61,4 +62,4 @@ function PrioritySlots({ date, timeSlots }: ColumnStructure) {
);
}
-export default PrioritySlots;
+export default PriorityColumn;
diff --git a/src/pages/selectSchedule/components/selectPriority/PriorityDropdown.tsx b/src/pages/selectSchedule/components/selectPriority/PriorityDropdown.tsx
index 007318f2..2631b4e2 100644
--- a/src/pages/selectSchedule/components/selectPriority/PriorityDropdown.tsx
+++ b/src/pages/selectSchedule/components/selectPriority/PriorityDropdown.tsx
@@ -2,12 +2,12 @@ import { useState } from 'react';
import Text from 'components/atomComponents/Text';
import { Circle1Ic, Circle2Ic, Circle3Ic, DropDownIc, DropUpIc } from 'components/Icon/icon';
+import { addMinutes } from 'components/timetableComponents/utils';
import {
SelectedSlotType,
- SlotInfoType,
- useTimetableContext,
-} from 'components/timetableComponents/context';
-import { addMinutes } from 'components/timetableComponents/utils';
+ SelectSlotType,
+ useSelectContext,
+} from 'pages/selectSchedule/contexts/useSelectContext';
import styled from 'styled-components/macro';
import { theme } from 'styles/theme';
@@ -17,7 +17,7 @@ import { theme } from 'styles/theme';
*/
function PriorityDropdown() {
- const { selectedSlots, setSelectedSlots } = useTimetableContext();
+ const { selectedSlots, setSelectedSlots } = useSelectContext();
const [timeSelect, setTimeSelect] = useState([false, false, false]);
const formatDate = (date: string) => {
@@ -56,7 +56,7 @@ function PriorityDropdown() {
}
};
- const handlePriority = (i: number, item: SlotInfoType, itemKey: string) => {
+ const handlePriority = (i: number, item: SelectSlotType, itemKey: string) => {
let temp: 0 | 1 | 2 | 3 = 0;
switch (i) {
case 0:
@@ -72,8 +72,9 @@ function PriorityDropdown() {
temp = 0;
break;
}
+
setSelectedSlots((prev: SelectedSlotType) => {
- const updatedSelectedSlots = Object.entries(prev).map(([key, value]) => {
+ const updatedSelectedSlots = Object.entries(prev).map(([_, value]) => {
if (value.priority === temp) {
return { ...value, priority: 0 };
}
diff --git a/src/pages/selectSchedule/components/selectTimeSlot/SelectionSlots.tsx b/src/pages/selectSchedule/components/selectTimeSlot/SelectionColumn.tsx
similarity index 85%
rename from src/pages/selectSchedule/components/selectTimeSlot/SelectionSlots.tsx
rename to src/pages/selectSchedule/components/selectTimeSlot/SelectionColumn.tsx
index b49bb142..17f97f40 100644
--- a/src/pages/selectSchedule/components/selectTimeSlot/SelectionSlots.tsx
+++ b/src/pages/selectSchedule/components/selectTimeSlot/SelectionColumn.tsx
@@ -1,11 +1,12 @@
import { ColumnStructure } from 'components/timetableComponents/types';
-import Slot from '../../../../components/timetableComponents/parts/Slot';
+import { useSelectContext } from 'pages/selectSchedule/contexts/useSelectContext';
import { theme } from 'styles/theme';
+
import useSlotSeletion from './hooks/useSlotSelection';
-import { useTimetableContext } from '../../../../components/timetableComponents/context';
+import Slot from '../../../../components/timetableComponents/parts/Slot';
-function SelectionSlots({ date, timeSlots }: ColumnStructure) {
- const { selectedSlots } = useTimetableContext();
+function SelectionColumn({ date, timeSlots }: ColumnStructure) {
+ const { selectedSlots } = useSelectContext();
const selectedSlotsPerDate = Object.entries(selectedSlots).filter(
([, slot]) => slot.date === date,
);
@@ -47,4 +48,4 @@ function SelectionSlots({ date, timeSlots }: ColumnStructure) {
);
}
-export default SelectionSlots;
+export default SelectionColumn;
diff --git a/src/pages/selectSchedule/components/selectTimeSlot/TimeSlotCta.tsx b/src/pages/selectSchedule/components/selectTimeSlot/TimeSlotCta.tsx
index 6656907c..d021e1aa 100644
--- a/src/pages/selectSchedule/components/selectTimeSlot/TimeSlotCta.tsx
+++ b/src/pages/selectSchedule/components/selectTimeSlot/TimeSlotCta.tsx
@@ -1,12 +1,12 @@
import Button from 'components/atomComponents/Button';
import Text from 'components/atomComponents/Text';
-import { useTimetableContext } from 'components/timetableComponents/context';
-import { useScheduleStepContext } from 'pages/selectSchedule/context';
+import { useScheduleStepContext } from 'pages/selectSchedule/contexts/useScheduleStepContext';
+import { useSelectContext } from 'pages/selectSchedule/contexts/useSelectContext';
import styled from 'styled-components';
function TimeSlotCta() {
const { setScheduleStep } = useScheduleStepContext();
- const { selectedSlots } = useTimetableContext();
+ const { selectedSlots } = useSelectContext();
const isValidSelection = Object.keys(selectedSlots).length !== 0;
return (
diff --git a/src/pages/selectSchedule/components/selectTimeSlot/hooks/useSlotSelection.ts b/src/pages/selectSchedule/components/selectTimeSlot/hooks/useSlotSelection.ts
index b4810c9e..abfadf2a 100644
--- a/src/pages/selectSchedule/components/selectTimeSlot/hooks/useSlotSelection.ts
+++ b/src/pages/selectSchedule/components/selectTimeSlot/hooks/useSlotSelection.ts
@@ -1,7 +1,7 @@
-import { useTimetableContext } from '../../../../../components/timetableComponents/context'
+import { useSelectContext } from 'pages/selectSchedule/contexts/useSelectContext';
const useSlotSeletion = () => {
- const {startSlot, setStartSlot, selectedSlots, setSelectedSlots} = useTimetableContext();
+ const {startSlot, setStartSlot, selectedSlots, setSelectedSlots} = useSelectContext();
const handleSelectSlot = (targetSlot: string) => {
setStartSlot(targetSlot);
@@ -10,7 +10,7 @@ const useSlotSeletion = () => {
const handleCompleteSlot = (targetSlot: string) => {
const dateOfStartSlot = startSlot?.substring(0, startSlot.lastIndexOf('/'));
const dateOfTargetSlot = targetSlot.substring(0, targetSlot.lastIndexOf('/'))
- if (dateOfStartSlot === dateOfTargetSlot){
+ if (startSlot && dateOfStartSlot === dateOfTargetSlot){
const newSelectedSlot = {
date:dateOfStartSlot,
startSlot:startSlot?.substring(startSlot.lastIndexOf('/')+1),
@@ -20,7 +20,9 @@ const useSlotSeletion = () => {
const keys = Object.keys(selectedSlots).map(Number)
const newKey = keys.length ? Math.max(...keys) + 1 : 0;
- setSelectedSlots({...selectedSlots, [newKey]:newSelectedSlot})
+ const newSelectedSlots = {...selectedSlots};
+ newSelectedSlots[newKey] = newSelectedSlot;
+ setSelectedSlots(newSelectedSlots)
}
setStartSlot(undefined);
}
diff --git a/src/pages/selectSchedule/context.ts b/src/pages/selectSchedule/contexts/useScheduleStepContext.ts
similarity index 69%
rename from src/pages/selectSchedule/context.ts
rename to src/pages/selectSchedule/contexts/useScheduleStepContext.ts
index a211ee8d..9488eaa4 100644
--- a/src/pages/selectSchedule/context.ts
+++ b/src/pages/selectSchedule/contexts/useScheduleStepContext.ts
@@ -1,10 +1,10 @@
-import { createContext, useContext } from 'react';
+import { Dispatch, SetStateAction, createContext, useContext } from 'react';
-import { ScheduleStepType } from './types';
+import { ScheduleStepType } from '../types';
interface ScheduleStepContextType {
scheduleStep: ScheduleStepType;
- setScheduleStep: (scheduleStep: ScheduleStepType) => void;
+ setScheduleStep: Dispatch>;
}
export const ScheduleStepContext = createContext({
diff --git a/src/pages/selectSchedule/contexts/useSelectContext.ts b/src/pages/selectSchedule/contexts/useSelectContext.ts
new file mode 100644
index 00000000..2ab073d0
--- /dev/null
+++ b/src/pages/selectSchedule/contexts/useSelectContext.ts
@@ -0,0 +1,34 @@
+import { Dispatch, SetStateAction, createContext, useContext } from 'react';
+
+export interface SelectSlotType {
+ date: string;
+ startSlot: string;
+ endSlot: string;
+ priority: number;
+}
+
+export interface SelectedSlotType {
+ [key: number]: SelectSlotType;
+}
+
+interface SelectContextType {
+ startSlot: string | undefined;
+ setStartSlot: Dispatch>;
+ selectedSlots: SelectedSlotType;
+ setSelectedSlots: Dispatch>;
+}
+
+export const SelectContext = createContext({
+ startSlot: undefined,
+ setStartSlot: () => undefined,
+ selectedSlots: {},
+ setSelectedSlots: () => undefined,
+});
+
+export function useSelectContext() {
+ const context = useContext(SelectContext);
+ if (context == null) {
+ throw new Error('SelectContext Error');
+ }
+ return context;
+}
diff --git a/src/pages/selectSchedule/types.ts b/src/pages/selectSchedule/types.ts
index de210574..54ceb704 100644
--- a/src/pages/selectSchedule/types.ts
+++ b/src/pages/selectSchedule/types.ts
@@ -5,3 +5,10 @@ import { ColumnStructure } from 'components/timetableComponents/types';
export type ScheduleStepType = 'selectTimeSlot' | 'selectPriority';
export type StepSlotsType = { [key in ScheduleStepType]: (props: ColumnStructure) => ReactNode };
export type StepbottomItemsType = { [key in ScheduleStepType]: ReactNode };
+
+export interface TitlesType {
+ [key: string]: {
+ main: string;
+ sub?: string;
+ };
+}
diff --git a/src/pages/selectSchedule/utils.ts b/src/pages/selectSchedule/utils.ts
index 2ecdbfda..f05805a3 100644
--- a/src/pages/selectSchedule/utils.ts
+++ b/src/pages/selectSchedule/utils.ts
@@ -1,42 +1,32 @@
-import { SelectedSlotType } from 'components/timetableComponents/context';
+import { addMinutes } from 'components/timetableComponents/utils';
-/**
- *
- * @desc 영어로 표현된 회의 진행 시간을 한글로 변환하는 함수
- */
-export const formatDuration = (duration: string): string => {
- switch (duration) {
- case 'HALF':
- return '30분';
- case 'HOUR':
- return '1시간';
- case 'HOUR_HALF':
- return '1시간 30분';
- case 'TWO_HOUR':
- return '2시간';
- case 'TWO_HOUR_HALF':
- return '2시간 30분';
- case 'THREE_HOUR':
- return '3시간';
- default:
- return 'UNDEFINED';
- }
-};
+import { SelectedSlotType } from './contexts/useSelectContext';
+import { TitlesType } from './types';
-/**
- *
- * @desc 영어로 표현된 회의 장소를 한글로 변환하는 함수
- */
-export const formatPlace = (place: string) => {
- switch (place) {
- case 'ONLINE':
- return '온라인';
- case 'OFFLINE':
- return '오프라인';
- case 'UNDEFINED':
- return undefined;
- }
-};
+export const DURATION = {
+ HALF: '30분',
+ HOUR: '1시간',
+ HOUR_HALF: '1시간 30분',
+ TWO_HOUR: '2시간',
+ TWO_HOUR_HALF: '2시간 30분',
+ THREE_HOUR: '3시간',
+} as const;
+
+export const PLACE = {
+ ONLINE: '온라인',
+ OFFLINE: '오프라인',
+ UNDEFINED: undefined,
+} as const;
+
+export const TITLES: TitlesType = {
+ selectTimeSlot: {
+ main: '가능한 시간대를 등록해주세요',
+ sub: '시작시간과 종료시간을 터치하여 블럭을 생성해주세요',
+ },
+ selectPriority: {
+ main: '우선순위를 입력해주세요',
+ },
+} as const;
/**
*
@@ -56,3 +46,50 @@ export const resetPriorities = (selectedSlots: SelectedSlotType): SelectedSlotTy
return updatedSlots;
};
+
+/**
+ *
+ * @desc 방장 시간표 입력 POST를 위한 형식을 맞추는 함수
+ */
+export const formatHostScheduleScheme = (selectedSlots: SelectedSlotType) => {
+ const availableTimes = Object.keys(selectedSlots).map((key) => {
+ const slot = selectedSlots[parseInt(key)];
+ const [month, day, dayOfWeek] = slot.date.split('/');
+
+ return {
+ id: key,
+ month: month.padStart(2, '0'),
+ day: day.padStart(2, '0'),
+ dayOfWeek: dayOfWeek,
+ startTime: slot.startSlot,
+ endTime: addMinutes(slot.endSlot, 30),
+ priority: slot.priority,
+ };
+ });
+ return availableTimes;
+};
+
+/**
+ *
+ * @desc 멤버 시간표 입력 POST를 위한 형식을 맞추는 함수
+ */
+export const formatMemberScheduleScheme = (selectedSlots: SelectedSlotType, userName: string) => {
+ const availableTimes = Object.keys(selectedSlots).map((key) => {
+ const slot = selectedSlots[parseInt(key)];
+ const [month, day, dayOfWeek] = slot.date.split('/');
+
+ return {
+ id: key,
+ month: month.padStart(2, '0'),
+ day: day.padStart(2, '0'),
+ dayOfWeek: dayOfWeek,
+ startTime: slot.startSlot,
+ endTime: addMinutes(slot.endSlot, 30),
+ priority: slot.priority,
+ };
+ });
+ return {
+ name: userName,
+ availableTimes: availableTimes,
+ };
+};
diff --git a/src/utils/apis/bestMeetTimeApi.ts b/src/utils/apis/bestMeetTimeApi.ts
deleted file mode 100644
index a6ea58c7..00000000
--- a/src/utils/apis/bestMeetTimeApi.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// import { BestMeetTimeResponse, BestMeetTimeRequest } from 'src/types/bestMeetTimeType';
-
-// import { client } from './axios';
-
-// export const BestMeetTimeApi = (BestMeetTimeRequest: BestMeetTimeRequest) => {
-// return client.post(`/meeting/${meetingId}/confirm`, BestMeetTimeRequest, {
-// headers: {
-// Authorization: `[Bearer] ${token}`,
-// },
-// });
-// };
diff --git a/src/utils/apis/availbleScheduleOptionApi.ts b/src/utils/apis/legacy/availbleScheduleOptionApi.ts
similarity index 89%
rename from src/utils/apis/availbleScheduleOptionApi.ts
rename to src/utils/apis/legacy/availbleScheduleOptionApi.ts
index 2f424339..b10400da 100644
--- a/src/utils/apis/availbleScheduleOptionApi.ts
+++ b/src/utils/apis/legacy/availbleScheduleOptionApi.ts
@@ -1,6 +1,5 @@
import { AvailableScheduleOptionResponse } from 'src/types/availbleScheduleType';
-
-import { client } from './axios';
+import { client } from '../axios';
/** 가능 시간 입력 선택지 조회 api */
export const availableScheduleOptionApi = (meetingId?: string) => {
diff --git a/src/utils/apis/createHostAvailableSchedule.ts b/src/utils/apis/legacy/createHostAvailableSchedule.ts
similarity index 88%
rename from src/utils/apis/createHostAvailableSchedule.ts
rename to src/utils/apis/legacy/createHostAvailableSchedule.ts
index c5915f09..0cc98699 100644
--- a/src/utils/apis/createHostAvailableSchedule.ts
+++ b/src/utils/apis/legacy/createHostAvailableSchedule.ts
@@ -1,12 +1,10 @@
-import { AxiosResponse } from 'axios';
import {
HostAvailableSchduleRequestType,
HostAvailableScheduleResponseType,
- UserAvailableScheduleResponseType,
UserAvailableScheduleRequestType,
+ UserAvailableScheduleResponseType,
} from 'src/types/createAvailableSchduleType';
-
-import { authClient, client } from './axios';
+import { authClient, client } from '../axios';
export const hostAvailableApi = (
meetingId: string,
diff --git a/src/utils/apis/createMeetingApi.ts b/src/utils/apis/legacy/createMeetingApi.ts
similarity index 88%
rename from src/utils/apis/createMeetingApi.ts
rename to src/utils/apis/legacy/createMeetingApi.ts
index ce62c47d..54f43623 100644
--- a/src/utils/apis/createMeetingApi.ts
+++ b/src/utils/apis/legacy/createMeetingApi.ts
@@ -1,6 +1,6 @@
import { CreateMeetingRequest, CreateMeetingResponse } from 'src/types/createMeetingType';
-import { client } from './axios';
+import { client } from '../axios';
export const createMeetingApi = (CreateMeetingRequest: CreateMeetingRequest) => {
return client.post(`/meeting`, CreateMeetingRequest);
diff --git a/src/utils/apis/cueCardAPI.ts b/src/utils/apis/legacy/cueCardAPI.ts
similarity index 75%
rename from src/utils/apis/cueCardAPI.ts
rename to src/utils/apis/legacy/cueCardAPI.ts
index f5f1d85f..fd7517ab 100644
--- a/src/utils/apis/cueCardAPI.ts
+++ b/src/utils/apis/legacy/cueCardAPI.ts
@@ -1,4 +1,4 @@
-import { client } from './axios';
+import { client } from '../axios';
export const cueCardApi = (meetingId: string) => {
return client.get(`/meeting/${meetingId}/card`);
diff --git a/src/utils/apis/overallScheduleApi.ts b/src/utils/apis/legacy/overallScheduleApi.ts
similarity index 92%
rename from src/utils/apis/overallScheduleApi.ts
rename to src/utils/apis/legacy/overallScheduleApi.ts
index 9cff94bd..50b40c6d 100644
--- a/src/utils/apis/overallScheduleApi.ts
+++ b/src/utils/apis/legacy/overallScheduleApi.ts
@@ -1,8 +1,8 @@
+import { authClient, client } from '../axios';
+
import { AvailableScheduleOptionResponse } from 'src/types/availbleScheduleType';
import { OverallScheduleResponse } from 'src/types/overallScheduleType';
-import { authClient, client } from './axios';
-
/** 가능 시간 입력 선택지 조회 api */
export const availbleScheduleOptionApi = (meetingId?: string) => {
return client.get(`/meeting/${meetingId}/schedule`);
diff --git a/src/utils/apis/useGetOverallSchedule.ts b/src/utils/apis/useGetOverallSchedule.ts
new file mode 100644
index 00000000..1e501114
--- /dev/null
+++ b/src/utils/apis/useGetOverallSchedule.ts
@@ -0,0 +1,54 @@
+import { useQuery } from '@tanstack/react-query';
+import { isAxiosError } from 'axios';
+import { useNavigate } from 'react-router-dom';
+
+import { authClient } from './axios';
+
+interface Date {
+ month: string;
+ day: string;
+ dayOfWeek: string;
+}
+
+export interface TimeSlot {
+ time: string;
+ userNames: string[];
+ colorLevel: number;
+}
+
+export interface AvailableDateTime extends Date {
+ timeSlots: TimeSlot[];
+}
+
+export interface getOverallScheduleResponse {
+ data: {
+ memberCount: number;
+ totalUserNames: string[];
+ availableDateTimes: AvailableDateTime[];
+ };
+}
+
+const getOverallSchedule = async (meetingId: string) => {
+ try {
+ const res = await authClient.get(`/meeting/${meetingId}/timetable`);
+ return res.data.data;
+ } catch (err) {
+ if (isAxiosError(err) && err.response) {
+ throw new Error(err.response.data.message);
+ }
+ }
+};
+
+export const useGetOverallSchedule = (meetingId?: string) => {
+ const navigate = useNavigate();
+ if (meetingId === undefined) {
+ navigate('/error');
+ throw new Error('잘못된 회의 아이디입니다.');
+ }
+ const { data, isLoading } = useQuery({
+ queryKey: ['getOverallSchedule', meetingId],
+ queryFn: () => getOverallSchedule(meetingId),
+ });
+
+ return { data, isLoading };
+};
diff --git a/src/utils/apis/useGetTimetable.ts b/src/utils/apis/useGetTimetable.ts
new file mode 100644
index 00000000..eb6ae73e
--- /dev/null
+++ b/src/utils/apis/useGetTimetable.ts
@@ -0,0 +1,51 @@
+import { useQuery } from '@tanstack/react-query';
+import { isAxiosError } from 'axios';
+import { DURATION, PLACE } from 'pages/selectSchedule/utils';
+import { useNavigate } from 'react-router-dom';
+
+import { client } from './axios';
+
+interface Date {
+ month: string;
+ day: string;
+ dayOfWeek: string;
+}
+interface TimeSlot {
+ startTime: string;
+ endTime: string;
+}
+
+interface getTimetableResponse {
+ data: {
+ duration: keyof typeof DURATION;
+ place: keyof typeof PLACE;
+ placeDetail: string;
+ availableDates: Date[];
+ preferTimes: TimeSlot[];
+ };
+}
+
+const getTimetable = async (meetingId: string) => {
+ try {
+ const res = await client.get(`/meeting/${meetingId}/schedule`);
+ return res.data.data;
+ } catch (err) {
+ if (isAxiosError(err) && err.response) {
+ throw new Error(err.response.data.message);
+ }
+ }
+};
+
+export const useGetTimetable = (meetingId?: string) => {
+ const navigate = useNavigate();
+ if (meetingId === undefined) {
+ navigate('/error');
+ throw new Error('잘못된 회의 아이디입니다.');
+ }
+ const { data, isLoading } = useQuery({
+ queryKey: ['getTimetable', meetingId],
+ queryFn: () => getTimetable(meetingId),
+ });
+
+ return { data, isLoading };
+};
diff --git a/yarn.lock b/yarn.lock
index 07569bdb..35168db7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1536,6 +1536,30 @@
"@svgr/hast-util-to-babel-ast" "^7.0.0"
svg-parser "^2.0.4"
+"@tanstack/query-core@5.45.0":
+ version "5.45.0"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.45.0.tgz#47a662d311c2588867341238960ec21dc7f0714e"
+ integrity sha512-RVfIZQmFUTdjhSAAblvueimfngYyfN6HlwaJUPK71PKd7yi43Vs1S/rdimmZedPWX/WGppcq/U1HOj7O7FwYxw==
+
+"@tanstack/query-devtools@5.37.1":
+ version "5.37.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.37.1.tgz#8dcfa1488b4f2e353be7eede6691b0ad9197183b"
+ integrity sha512-XcG4IIHIv0YQKrexTqo2zogQWR1Sz672tX2KsfE9kzB+9zhx44vRKH5si4WDILE1PIWQpStFs/NnrDQrBAUQpg==
+
+"@tanstack/react-query-devtools@^5.45.1":
+ version "5.45.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.45.1.tgz#bea7ba0ffd509f0930237c2df7feba9209f76aa6"
+ integrity sha512-4mrbk1g5jqlqh0pifZNsKzy7FtgeqgwzMICL4d6IJGayrrcrKq9K4N/OzRNbgRWrTn6YTY63qcAcKo+NJU2QMw==
+ dependencies:
+ "@tanstack/query-devtools" "5.37.1"
+
+"@tanstack/react-query@^5.45.1":
+ version "5.45.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.45.1.tgz#a0ac6bb89b4a2c2b0251f6647a0a370d86f05347"
+ integrity sha512-mYYfJujKg2kxmkRRjA6nn4YKG3ITsKuH22f1kteJ5IuVQqgKUgbaSQfYwVP0gBS05mhwxO03HVpD0t7BMN7WOA==
+ dependencies:
+ "@tanstack/query-core" "5.45.0"
+
"@types/axios@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46"