From 17434905b322f2f5f0fa51372dc5dd347e5e6620 Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:58:28 +0900 Subject: [PATCH 01/15] =?UTF-8?q?design(Field):=20label=20=EB=B0=8F=20desc?= =?UTF-8?q?ription=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EC=A6=88=20=EB=B0=8F=20=EC=83=89=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/_common/Field/Field.styles.ts | 7 ++++--- frontend/src/components/_common/Input/Input.styles.ts | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/_common/Field/Field.styles.ts b/frontend/src/components/_common/Field/Field.styles.ts index b5d5e96d3..fd8abf2d5 100644 --- a/frontend/src/components/_common/Field/Field.styles.ts +++ b/frontend/src/components/_common/Field/Field.styles.ts @@ -4,14 +4,15 @@ export const s_field = css` display: flex; flex-direction: column; gap: 0.75rem; - height: 6rem; `; export const s_label = css` + font-size: 2.4rem; font-weight: 700; `; export const s_description = css` - font-size: 0.75rem; - font-weight: 200; + font-size: 1.2rem; + font-weight: 400; + color: #8c8989; `; diff --git a/frontend/src/components/_common/Input/Input.styles.ts b/frontend/src/components/_common/Input/Input.styles.ts index 36a959689..ef0550ec5 100644 --- a/frontend/src/components/_common/Input/Input.styles.ts +++ b/frontend/src/components/_common/Input/Input.styles.ts @@ -2,6 +2,6 @@ import { css } from '@emotion/react'; export const s_input = css` width: 100%; - height: 2.5rem; - padding: 0 0.5rem; + height: 4.4rem; + padding: 0.8rem; `; From bf2e66cf0aa16ccf9ea5dcf3f2f663189efce95b Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:04:07 +0900 Subject: [PATCH 02/15] =?UTF-8?q?fix(useRangeDropdown):=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EA=B0=80=EB=8A=A5=20=EC=8B=9C=EA=B0=84=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EC=9C=A0=ED=8B=B8=20=ED=95=A8=EC=88=98=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EA=B0=92=EC=9C=BC=EB=A1=9C=20=EB=B9=84=EA=B5=90?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts b/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts index 39a25b3da..b47e2a12a 100644 --- a/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts +++ b/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts @@ -40,8 +40,8 @@ export function generateEndTimeOptions(startTime: string) { // 만약 시작 시간보다 끝 시간이 빠르다면 false를 반환하는 함수(@낙타) export function isTimeSelectable(startTime: string, endTime: string) { - const [startHours, startMinutes] = startTime.split(':'); - const [endHours, endMinutes] = endTime.split(':'); + const [startHours, startMinutes] = startTime.split(':').map(Number); + const [endHours, endMinutes] = endTime.split(':').map(Number); if (endHours < startHours) return false; if (endHours === startHours && endMinutes < startMinutes) return false; From 5d3d87b688f429bc916962fc8727fca6a82a89a4 Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:21:25 +0900 Subject: [PATCH 03/15] =?UTF-8?q?refactor(Field):=20=EA=B3=B5=EC=9A=A9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=82=AC=EC=9A=A9=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/_common/Field/Field.stories.tsx | 8 -------- .../src/components/_common/Field/Field.styles.ts | 2 +- frontend/src/components/_common/Field/index.tsx | 16 +++++++++++----- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/_common/Field/Field.stories.tsx b/frontend/src/components/_common/Field/Field.stories.tsx index 84b3898b4..8c0b39154 100644 --- a/frontend/src/components/_common/Field/Field.stories.tsx +++ b/frontend/src/components/_common/Field/Field.stories.tsx @@ -20,9 +20,7 @@ export const Default: Story = { args: { labelText: '사용자 이름', description: '사용자 이름을 입력하세요.', - type: 'text', id: 'userName', - placeholder: '사용자 이름을 입력하세요.', }, }; @@ -30,9 +28,7 @@ export const WithDescription: Story = { args: { labelText: '이메일', description: '이메일 주소를 입력해 주세요.', - type: 'email', id: 'email', - placeholder: '이메일을 입력하세요.', }, }; @@ -40,17 +36,13 @@ export const WithLongDescription: Story = { args: { labelText: '비밀번호', description: '비밀번호는 최소 8자 이상이어야 하며, 문자와 숫자를 혼합하여 입력해 주세요.', - type: 'password', id: 'password', - placeholder: '비밀번호를 입력하세요.', }, }; export const WithoutDescription: Story = { args: { labelText: '검색', - type: 'text', id: 'search', - placeholder: '검색어를 입력하세요.', }, }; diff --git a/frontend/src/components/_common/Field/Field.styles.ts b/frontend/src/components/_common/Field/Field.styles.ts index fd8abf2d5..98ebc29f0 100644 --- a/frontend/src/components/_common/Field/Field.styles.ts +++ b/frontend/src/components/_common/Field/Field.styles.ts @@ -3,7 +3,7 @@ import { css } from '@emotion/react'; export const s_field = css` display: flex; flex-direction: column; - gap: 0.75rem; + gap: 0.8rem; `; export const s_label = css` diff --git a/frontend/src/components/_common/Field/index.tsx b/frontend/src/components/_common/Field/index.tsx index 3f5ccd7c8..f6b016ebf 100644 --- a/frontend/src/components/_common/Field/index.tsx +++ b/frontend/src/components/_common/Field/index.tsx @@ -1,21 +1,27 @@ -import type { InputHTMLAttributes } from 'react'; +import type { LabelHTMLAttributes, PropsWithChildren } from 'react'; -import Input from '../Input'; import { s_description, s_field, s_label } from './Field.styles'; -interface FieldProps extends InputHTMLAttributes { +interface FieldProps extends LabelHTMLAttributes { + id: string; labelText: string; description?: string; + flexDirection?: string; } -export default function Field({ labelText, id, description = '', ...props }: FieldProps) { +export default function Field({ + children, + labelText, + id, + description = '', +}: PropsWithChildren) { return (
{description &&
{description}
} - + {children}
); } From e894e4786743cf76980e72607f4e723f33cfddbe Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:28:02 +0900 Subject: [PATCH 04/15] =?UTF-8?q?design(GlobalLayout):=20=EC=A0=84?= =?UTF-8?q?=EC=97=AD=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/layouts/GlobalLayout.styles.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/layouts/GlobalLayout.styles.ts b/frontend/src/layouts/GlobalLayout.styles.ts index c05a4d68e..49aed4dba 100644 --- a/frontend/src/layouts/GlobalLayout.styles.ts +++ b/frontend/src/layouts/GlobalLayout.styles.ts @@ -1,6 +1,10 @@ import { css } from '@emotion/react'; export const s_globalContainer = css` + display: flex; + flex-direction: column; + gap: 2.4rem; + min-width: 39.3rem; max-width: 60rem; height: 100%; @@ -10,5 +14,7 @@ export const s_globalContainer = css` `; export const s_content = css` + overflow-y: scroll; + height: calc(100vh - 8.4rem); padding: 0 1.6rem; `; From c822e17997431dbb444ed72a82e1722cc8dfa2c5 Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:28:49 +0900 Subject: [PATCH 05/15] =?UTF-8?q?feat(CreateMeetingPage):=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B5=AC=EC=84=B1=20=EB=B0=8F=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EC=97=B0=EA=B2=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CreateMeetingPage.styles.ts | 41 +++++++ .../src/pages/CreateMeetingPage/index.tsx | 106 ++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 frontend/src/pages/CreateMeetingPage/CreateMeetingPage.styles.ts create mode 100644 frontend/src/pages/CreateMeetingPage/index.tsx diff --git a/frontend/src/pages/CreateMeetingPage/CreateMeetingPage.styles.ts b/frontend/src/pages/CreateMeetingPage/CreateMeetingPage.styles.ts new file mode 100644 index 000000000..6f3ec5690 --- /dev/null +++ b/frontend/src/pages/CreateMeetingPage/CreateMeetingPage.styles.ts @@ -0,0 +1,41 @@ +import { css } from '@emotion/react'; + +import theme from '@styles/theme'; + +export const s_formContainer = css` + display: flex; + flex-direction: column; + gap: 2.4rem; +`; + +export const s_dropdownContainer = css` + display: flex; + gap: 1.2rem; + justify-content: flex-start; +`; + +export const s_confirmContainer = css` + display: flex; + align-items: center; + justify-content: flex-end; + margin-bottom: 1.6rem; +`; + +export const s_confirm = css` + width: 20rem; + height: 4.8rem; + + font-size: 2rem; + font-weight: 800; + color: #fff; + + background: ${theme.color.primary}; + border: none; + border-radius: 8px; + + &:hover { + color: ${theme.color.primary}; + background: #fff; + border: 1px solid ${theme.color.primary}; + } +`; diff --git a/frontend/src/pages/CreateMeetingPage/index.tsx b/frontend/src/pages/CreateMeetingPage/index.tsx new file mode 100644 index 000000000..14950b3da --- /dev/null +++ b/frontend/src/pages/CreateMeetingPage/index.tsx @@ -0,0 +1,106 @@ +import { useState } from 'react'; + +import Calendar from '@components/_common/Calendar'; +import Dropdown from '@components/_common/Dropdown'; +import Field from '@components/_common/Field'; +import Input from '@components/_common/Input'; + +import useInput from '@hooks/useInput/useInput'; +import useTimeRangeDropdown from '@hooks/useTimeRangeDropdown/useTimeRangeDropdown'; +import { + generateEndTimeOptions, + generateStartTimeOptions, +} from '@hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils'; + +import { + s_confirm, + s_confirmContainer, + s_dropdownContainer, + s_formContainer, +} from './CreateMeetingPage.styles'; + +export default function CreateMeetingPage() { + const { value: meetingName, onValueChange: handleMeetingNameChange } = useInput(''); + const { value: hostName, onValueChange: handleHostNameChange } = useInput(''); + const { value: hostPassword, onValueChange: handleHostPasswordChange } = useInput(''); + const [selectedDates, setSelectedDates] = useState([]); + const { + startTime, + endTime, + onStartTimeChange: handleStartTimeChange, + onEndTimeChange: handleEndTimeChange, + } = useTimeRangeDropdown(); + + const hasDate = (date: string) => selectedDates.includes(date); + + const handleDateClick = (date: string) => { + setSelectedDates((prevDates) => + hasDate(date) ? prevDates.filter((d) => d !== date) : [...prevDates, date], + ); + }; + + return ( +
+ {/* 추후 form 태그로 수정 예정 (@Largopie) */} +
+ + + + + + + + + + + + + + + + + +
+ handleStartTimeChange(e.target.value)} + options={generateStartTimeOptions(endTime)} + /> + ~ + handleEndTimeChange(e.target.value)} + options={generateEndTimeOptions(startTime)} + /> +
+
+
+ +
+
+
+ ); +} From 92ef3cc178c17f44958a137f0b639e66b2d5b902 Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:29:25 +0900 Subject: [PATCH 06/15] =?UTF-8?q?feat(CreateMeetingPage):=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=84=B0=20=EC=A3=BC=EC=86=8C=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/router.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/router.tsx b/frontend/src/router.tsx index 07239ebaf..471e0abd4 100644 --- a/frontend/src/router.tsx +++ b/frontend/src/router.tsx @@ -4,6 +4,7 @@ import GlobalLayout from '@layouts/GlobalLayout'; import { TimePickerUpdateStateProvider } from '@contexts/TimePickerUpdateStateProvider'; +import CreateMeetingPage from '@pages/CreateMeetingPage'; import MeetingTimePickPage from '@pages/MeetingTimePickPage'; const router = createBrowserRouter( @@ -20,6 +21,10 @@ const router = createBrowserRouter( ), }, + { + path: 'create-meeting', + element: , + }, ], }, ], From 458cd0e56b6b8a16cd717503ea1f4885b40da083 Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:43:59 +0900 Subject: [PATCH 07/15] =?UTF-8?q?feat:=20=EC=95=BD=EC=86=8D=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20API=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EA=B8=B0?= =?UTF-8?q?=EC=A1=B4=20meeting=20API=20=ED=8C=8C=EC=9D=BC=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/apis/{getMeeting.ts => meetings.ts} | 29 +++++++++++++++++++ frontend/src/apis/schedule.ts | 2 +- .../components/Time/Picker/TimePicker.util.ts | 2 +- frontend/src/components/Time/Picker/index.tsx | 2 +- frontend/src/components/Time/Viewer/index.tsx | 2 +- .../src/stores/servers/meeting/mutations.ts | 2 +- .../src/stores/servers/meeting/queries.ts | 2 +- 7 files changed, 35 insertions(+), 6 deletions(-) rename frontend/src/apis/{getMeeting.ts => meetings.ts} (54%) diff --git a/frontend/src/apis/getMeeting.ts b/frontend/src/apis/meetings.ts similarity index 54% rename from frontend/src/apis/getMeeting.ts rename to frontend/src/apis/meetings.ts index 43646cdac..aaad1b4fc 100644 --- a/frontend/src/apis/getMeeting.ts +++ b/frontend/src/apis/meetings.ts @@ -13,6 +13,15 @@ export interface GetMeetingResponse { schedules: Schedules[]; } +export interface MeetingRequest { + hostName: string; + hostPassword: string; + meetingName: string; + meetingAvailableDates: string[]; + meetingStartTime: string; + meetingEndTime: string; +} + // uuid 기본값은 임시 설정된 uuid const getMeeting = async (uuid = '550e8400'): Promise => { const url = `${API_URL}/api/v1/meeting/${uuid}`; @@ -34,3 +43,23 @@ const getMeeting = async (uuid = '550e8400'): Promise => { }; export default getMeeting; + +export const postMeeting = async (request: MeetingRequest) => { + const url = `${API_URL}/api/v1/meeting`; + + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(request), + }); + + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + + return data.data; +}; diff --git a/frontend/src/apis/schedule.ts b/frontend/src/apis/schedule.ts index 670aff223..bbdba0a99 100644 --- a/frontend/src/apis/schedule.ts +++ b/frontend/src/apis/schedule.ts @@ -1,6 +1,6 @@ import { API_URL } from '@constants/api'; -import type { Schedules } from './getMeeting'; +import type { Schedules } from './meetings'; export const postSchedule = async (requestData: Schedules[]) => { const url = `${API_URL}/api/v1/schedule`; diff --git a/frontend/src/components/Time/Picker/TimePicker.util.ts b/frontend/src/components/Time/Picker/TimePicker.util.ts index 0627f2c37..9043e8488 100644 --- a/frontend/src/components/Time/Picker/TimePicker.util.ts +++ b/frontend/src/components/Time/Picker/TimePicker.util.ts @@ -1,4 +1,4 @@ -import type { GetMeetingResponse } from '@apis/getMeeting'; +import type { GetMeetingResponse } from '@apis/meetings'; type TimeSlot = Record; diff --git a/frontend/src/components/Time/Picker/index.tsx b/frontend/src/components/Time/Picker/index.tsx index 940981e28..a42b9f5aa 100644 --- a/frontend/src/components/Time/Picker/index.tsx +++ b/frontend/src/components/Time/Picker/index.tsx @@ -7,7 +7,7 @@ import TimeSlot from '@components/_common/TimeSlot'; import useTimePick from '@hooks/useTimePick/useTimePick'; -import type { GetMeetingResponse } from '@apis/getMeeting'; +import type { GetMeetingResponse } from '@apis/meetings'; import { usePostScheduleMutation } from '@stores/servers/meeting/mutations'; diff --git a/frontend/src/components/Time/Viewer/index.tsx b/frontend/src/components/Time/Viewer/index.tsx index 46461af5e..a8b9c2c55 100644 --- a/frontend/src/components/Time/Viewer/index.tsx +++ b/frontend/src/components/Time/Viewer/index.tsx @@ -5,7 +5,7 @@ import { TimePickerUpdateStateContext } from '@contexts/TimePickerUpdateStatePro import Button from '@components/_common/Button'; import TimeSlot from '@components/_common/TimeSlot'; -import type { GetMeetingResponse } from '@apis/getMeeting'; +import type { GetMeetingResponse } from '@apis/meetings'; import { generateScheduleMatrix } from '../Picker/TimePicker.util'; import { s_buttonContainer, s_cell, s_table, s_th } from '../Time.styles'; diff --git a/frontend/src/stores/servers/meeting/mutations.ts b/frontend/src/stores/servers/meeting/mutations.ts index 37d852b4d..cfc017b8a 100644 --- a/frontend/src/stores/servers/meeting/mutations.ts +++ b/frontend/src/stores/servers/meeting/mutations.ts @@ -1,6 +1,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import type { GetMeetingResponse } from '@apis/getMeeting'; +import type { GetMeetingResponse } from '@apis/meetings'; import { postSchedule } from '@apis/schedule'; import { QUERY_KEY } from '@constants/queryKeys'; diff --git a/frontend/src/stores/servers/meeting/queries.ts b/frontend/src/stores/servers/meeting/queries.ts index 588b4659c..fa8f07e98 100644 --- a/frontend/src/stores/servers/meeting/queries.ts +++ b/frontend/src/stores/servers/meeting/queries.ts @@ -1,6 +1,6 @@ import { useQuery } from '@tanstack/react-query'; -import getMeeting from '@apis/getMeeting'; +import getMeeting from '@apis/meetings'; import { QUERY_KEY } from '@constants/queryKeys'; From 2c1c486299ba079e6a15a8fdebb4c9dd187bed4c Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:47:10 +0900 Subject: [PATCH 08/15] =?UTF-8?q?refactor:=20schedule=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=84=9C=EB=B2=84=20=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=ED=8F=B4=EB=8D=94=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Time/Picker/index.tsx | 2 +- frontend/src/stores/servers/{meeting => schedule}/mutations.ts | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename frontend/src/stores/servers/{meeting => schedule}/mutations.ts (100%) diff --git a/frontend/src/components/Time/Picker/index.tsx b/frontend/src/components/Time/Picker/index.tsx index a42b9f5aa..eefe86caf 100644 --- a/frontend/src/components/Time/Picker/index.tsx +++ b/frontend/src/components/Time/Picker/index.tsx @@ -9,7 +9,7 @@ import useTimePick from '@hooks/useTimePick/useTimePick'; import type { GetMeetingResponse } from '@apis/meetings'; -import { usePostScheduleMutation } from '@stores/servers/meeting/mutations'; +import { usePostScheduleMutation } from '@stores/servers/schedule/mutations'; import { s_buttonContainer, s_cell, s_table, s_th } from '../Time.styles'; import { convertToSchedule, generateScheduleMatrix } from './TimePicker.util'; diff --git a/frontend/src/stores/servers/meeting/mutations.ts b/frontend/src/stores/servers/schedule/mutations.ts similarity index 100% rename from frontend/src/stores/servers/meeting/mutations.ts rename to frontend/src/stores/servers/schedule/mutations.ts From 6a85a84c172df858f904531cece7bc82687d4cbb Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:08:30 +0900 Subject: [PATCH 09/15] =?UTF-8?q?refactor(useTimeRangeDropdown):=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=EC=9D=B4=20=ED=95=9C=20=EC=9E=90=EB=A6=AC=20?= =?UTF-8?q?=EC=88=AB=EC=9E=90=EC=9D=BC=20=EB=95=8C=200=EC=9D=84=20?= =?UTF-8?q?=ED=8F=AC=ED=95=A8=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/hooks/useTimeRangeDropdown/constants.ts | 2 +- .../useTimeRangeDropdown/useTimeRangeDropdown.test.ts | 10 +++++----- .../useTimeRangeDropdown/useTimeRangeDropdown.utils.ts | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/hooks/useTimeRangeDropdown/constants.ts b/frontend/src/hooks/useTimeRangeDropdown/constants.ts index e75af361d..69472b37e 100644 --- a/frontend/src/hooks/useTimeRangeDropdown/constants.ts +++ b/frontend/src/hooks/useTimeRangeDropdown/constants.ts @@ -1,4 +1,4 @@ -export const INITIAL_START_TIME = '0:00'; +export const INITIAL_START_TIME = '00:00'; export const INITIAL_END_TIME = '24:00'; export const MINIMUM_TIME = 0; diff --git a/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.test.ts b/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.test.ts index c540adbe5..bbf97c90d 100644 --- a/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.test.ts +++ b/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.test.ts @@ -13,11 +13,11 @@ describe('useTimeRangeDropdown', () => { }); it('선택한 시작 시간(startTime)이 끝 시간(endTime)보다 느리다면 선택한 시간값으로 변경되지 않는다.', () => { - const CHANGE_TIME = '1:00'; + const CHANGE_TIME = '01:00'; const { result } = renderHook(() => useTimeRangeDropdown()); act(() => { - result.current.onEndTimeChange('0:00'); + result.current.onEndTimeChange('00:00'); }); act(() => { @@ -28,7 +28,7 @@ describe('useTimeRangeDropdown', () => { }); it('선택한 시작 시간(startTime)이 끝 시간(endTime)보다 빠르다면 값이 선택한 시간값으로 변경된다.', () => { - const CHANGE_TIME = '1:00'; + const CHANGE_TIME = '01:00'; const { result } = renderHook(() => useTimeRangeDropdown()); act(() => { @@ -43,7 +43,7 @@ describe('useTimeRangeDropdown', () => { }); it('선택한 끝 시간(endTime)이 시작 시간(startTime)보다 빠르다면 선택한 시간값으로 변경되지 않는다.', () => { - const CHANGE_TIME = '1:00'; + const CHANGE_TIME = '01:00'; const { result } = renderHook(() => useTimeRangeDropdown()); act(() => { @@ -62,7 +62,7 @@ describe('useTimeRangeDropdown', () => { const { result } = renderHook(() => useTimeRangeDropdown()); act(() => { - result.current.onStartTimeChange('0:00'); + result.current.onStartTimeChange('00:00'); }); act(() => { diff --git a/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts b/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts index b47e2a12a..f94fd0fd9 100644 --- a/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts +++ b/frontend/src/hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils.ts @@ -18,7 +18,7 @@ export function generateStartTimeOptions(endTime: string) { for (let i = MINIMUM_TIME; i < endHours; i++) { const label = formatHours(i); - times.push({ value: `${i}:00`, label: label + ':00' }); + times.push({ value: `${String(i).padStart(2, '0')}:00`, label: label + ':00' }); } return times; @@ -30,9 +30,9 @@ export function generateEndTimeOptions(startTime: string) { const startHours = Number(startTime.split(':')[0]); for (let i = startHours + 1; i <= MAXIMUM_TIME; i++) { - const label = formatHours(i); + const label = formatHours(i).padStart(2, '0'); - times.push({ value: `${i}:00`, label: label + ':00' }); + times.push({ value: `${String(i).padStart(2, '0')}:00`, label: label + ':00' }); } return times; From 4961a603ec923030e31a475fe69e0ea2c32d7ade Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:19:08 +0900 Subject: [PATCH 10/15] =?UTF-8?q?refactor:=20month,=20date=20=ED=95=9C=20?= =?UTF-8?q?=EC=9E=90=EB=A6=AC=20=EC=88=98=20=EC=9D=BC=20=EB=95=8C,=20?= =?UTF-8?q?=EC=95=9E=EC=97=90=20'0'=EC=9D=84=20=EB=B6=99=EC=9D=B4=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/hooks/useCalendarInfo/useCalendarInfo.utils.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/hooks/useCalendarInfo/useCalendarInfo.utils.ts b/frontend/src/hooks/useCalendarInfo/useCalendarInfo.utils.ts index 56764c7d9..0315f7694 100644 --- a/frontend/src/hooks/useCalendarInfo/useCalendarInfo.utils.ts +++ b/frontend/src/hooks/useCalendarInfo/useCalendarInfo.utils.ts @@ -32,9 +32,11 @@ export function getDayInfo({ }) { const date = index - firstDayIndex + 1; const isDate = index >= firstDayIndex; + // TODO: 추후에 padStart 사용하는 곳이 많다 보니, util 함수로 분리 필요 (@낙타) + const formattedMonth = String(month).padStart(2, '0'); - const dateString = `${year}-${month}-${date}`; - const todayString = `${year}-${month}-${currentDate.getDate()}`; + const dateString = `${year}-${formattedMonth}-${String(date).padStart(2, '0')}`; + const todayString = `${year}-${formattedMonth}-${String(currentDate.getDate()).padStart(2, '0')}`; const isToday = dateString === todayString; // TODO : 일단은 일요일만 isHolday로 설정되도록 구현, 추후에 진짜 공휴일도 포함할 것인지 논의 필요, 찾아보니 라이브러리가 있더라구요.(@해리) // TODO : 매직넘버 의미있는 상수화 필요(@해리) From fa2a27ba47f768010b48d12277ce3f7c267aa501 Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Fri, 26 Jul 2024 01:41:51 +0900 Subject: [PATCH 11/15] =?UTF-8?q?chore:=20router=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/webpack.common.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/webpack.common.js b/frontend/webpack.common.js index ad517ccb5..0d32112e9 100644 --- a/frontend/webpack.common.js +++ b/frontend/webpack.common.js @@ -54,6 +54,7 @@ module.exports = () => ({ filename: 'momo-bundle.js', path: path.resolve(__dirname, 'dist'), clean: true, + publicPath: '/', }, plugins: [ new HtmlWebpackPlugin({ From 9d197412ecdf8e8ac0b4148a7b4a92e289d07623 Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Fri, 26 Jul 2024 01:42:02 +0900 Subject: [PATCH 12/15] =?UTF-8?q?refactor:=20router=20=EA=B2=BD=EB=A1=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/router.tsx | 54 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/frontend/src/router.tsx b/frontend/src/router.tsx index 471e0abd4..b94326ceb 100644 --- a/frontend/src/router.tsx +++ b/frontend/src/router.tsx @@ -5,30 +5,38 @@ import GlobalLayout from '@layouts/GlobalLayout'; import { TimePickerUpdateStateProvider } from '@contexts/TimePickerUpdateStateProvider'; import CreateMeetingPage from '@pages/CreateMeetingPage'; +import MeetingLinkSharePage from '@pages/MeetingLinkSharePage'; import MeetingTimePickPage from '@pages/MeetingTimePickPage'; -const router = createBrowserRouter( - [ - { - path: '/', - element: , - children: [ - { - index: true, - element: ( - - - - ), - }, - { - path: 'create-meeting', - element: , - }, - ], - }, - ], - {}, -); +// TODO: 추후 라우팅 경로 다시 한 번 수정해야 함(@낙타) +const router = createBrowserRouter([ + { + path: '/', + element: , + children: [ + { + path: 'meeting', + children: [ + { + path: ':uuid', + element: ( + + + + ), + }, + { + path: 'create', + element: , + }, + { + path: 'complete', + element: , + }, + ], + }, + ], + }, +]); export default router; From 30b184a60bddb30547fbf5b9d84565f9d0f7308c Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:10:01 +0900 Subject: [PATCH 13/15] =?UTF-8?q?feat:=20post=20Meeting=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/stores/servers/meeting/mutation.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 frontend/src/stores/servers/meeting/mutation.ts diff --git a/frontend/src/stores/servers/meeting/mutation.ts b/frontend/src/stores/servers/meeting/mutation.ts new file mode 100644 index 000000000..28e32617d --- /dev/null +++ b/frontend/src/stores/servers/meeting/mutation.ts @@ -0,0 +1,16 @@ +import { useMutation } from '@tanstack/react-query'; +import { useState } from 'react'; + +import { postMeeting } from '@apis/meetings'; + +export const usePostMeetingMutation = () => { + const [data, setData] = useState(''); + + const mutation = useMutation({ + mutationFn: postMeeting, + onSuccess: (responseData) => { + setData(responseData.uuid); + }, + }); + return { mutation, uuid: data }; +}; From febe05408f066190cced29cb783fd75110f86b98 Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:10:26 +0900 Subject: [PATCH 14/15] =?UTF-8?q?refactor:=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EC=97=90=20uuid=20=EB=B0=9B=EC=9D=84=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/meetings.ts | 8 ++++++-- frontend/src/stores/servers/meeting/queries.ts | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/apis/meetings.ts b/frontend/src/apis/meetings.ts index aaad1b4fc..973708a6b 100644 --- a/frontend/src/apis/meetings.ts +++ b/frontend/src/apis/meetings.ts @@ -22,8 +22,12 @@ export interface MeetingRequest { meetingEndTime: string; } +export interface PostMeetingResponse { + uuid: string; +} + // uuid 기본값은 임시 설정된 uuid -const getMeeting = async (uuid = '550e8400'): Promise => { +const getMeeting = async (uuid: string): Promise => { const url = `${API_URL}/api/v1/meeting/${uuid}`; const response = await fetch(url, { @@ -44,7 +48,7 @@ const getMeeting = async (uuid = '550e8400'): Promise => { export default getMeeting; -export const postMeeting = async (request: MeetingRequest) => { +export const postMeeting = async (request: MeetingRequest): Promise => { const url = `${API_URL}/api/v1/meeting`; const response = await fetch(url, { diff --git a/frontend/src/stores/servers/meeting/queries.ts b/frontend/src/stores/servers/meeting/queries.ts index fa8f07e98..0ecbbd79e 100644 --- a/frontend/src/stores/servers/meeting/queries.ts +++ b/frontend/src/stores/servers/meeting/queries.ts @@ -4,9 +4,9 @@ import getMeeting from '@apis/meetings'; import { QUERY_KEY } from '@constants/queryKeys'; -export const useGetMeetingQuery = () => +export const useGetMeetingQuery = (uuid: string) => useQuery({ queryKey: [QUERY_KEY.meeting], - queryFn: () => getMeeting(), + queryFn: () => getMeeting(uuid), retry: 1, }); From 5676553bd6afddbbfd7c21933e56f859a5860c2b Mon Sep 17 00:00:00 2001 From: Largopie <106071687+Largopie@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:11:29 +0900 Subject: [PATCH 15/15] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20nav?= =?UTF-8?q?igation=20=EC=97=B0=EA=B2=B0=20=EB=B0=8F=20uuid=20=EC=A0=84?= =?UTF-8?q?=EB=8B=AC=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/CreateMeetingPage/index.tsx | 32 +++++++++++++++++-- .../src/pages/MeetingLinkSharePage/index.tsx | 6 ++-- .../src/pages/MeetingTimePickPage/index.tsx | 7 +++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/frontend/src/pages/CreateMeetingPage/index.tsx b/frontend/src/pages/CreateMeetingPage/index.tsx index 14950b3da..8154abdb4 100644 --- a/frontend/src/pages/CreateMeetingPage/index.tsx +++ b/frontend/src/pages/CreateMeetingPage/index.tsx @@ -1,4 +1,5 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import Calendar from '@components/_common/Calendar'; import Dropdown from '@components/_common/Dropdown'; @@ -12,6 +13,8 @@ import { generateStartTimeOptions, } from '@hooks/useTimeRangeDropdown/useTimeRangeDropdown.utils'; +import { usePostMeetingMutation } from '@stores/servers/meeting/mutation'; + import { s_confirm, s_confirmContainer, @@ -20,6 +23,8 @@ import { } from './CreateMeetingPage.styles'; export default function CreateMeetingPage() { + const navigate = useNavigate(); + const { uuid, mutation: postMeetingMutation } = usePostMeetingMutation(); const { value: meetingName, onValueChange: handleMeetingNameChange } = useInput(''); const { value: hostName, onValueChange: handleHostNameChange } = useInput(''); const { value: hostPassword, onValueChange: handleHostPasswordChange } = useInput(''); @@ -39,6 +44,27 @@ export default function CreateMeetingPage() { ); }; + const handleSubmit = () => { + postMeetingMutation.mutate({ + hostName: hostName, + hostPassword: hostPassword, + meetingName: meetingName, + meetingAvailableDates: selectedDates, + meetingStartTime: startTime, + meetingEndTime: endTime, + }); + }; + + useEffect(() => { + if (uuid !== '') { + navigate('/meeting/complete', { + state: { + uuid: uuid, + }, + }); + } + }, [uuid, navigate]); + return (
{/* 추후 form 태그로 수정 예정 (@Largopie) */} @@ -98,7 +124,9 @@ export default function CreateMeetingPage() {
- +
diff --git a/frontend/src/pages/MeetingLinkSharePage/index.tsx b/frontend/src/pages/MeetingLinkSharePage/index.tsx index 1091b4ba4..ad6556e5c 100644 --- a/frontend/src/pages/MeetingLinkSharePage/index.tsx +++ b/frontend/src/pages/MeetingLinkSharePage/index.tsx @@ -1,3 +1,5 @@ +import { useLocation } from 'react-router-dom'; + import { copyToClipboard } from '@utils/clipboard'; import LogoSunglass from '@assets/images/logoSunglass.svg'; @@ -11,8 +13,8 @@ import { } from './MeetingLinkSharePage.styles'; export default function MeetingLinkSharePage() { - // TODO: LINK를 실제 prop / useLocation에서 보내주는 값으로 교체하기 (@Yoonkyoungme) - const LINK = '🔮🍀🐫 생성된 링크 🔮🍀🐫'; + const location = useLocation(); + const LINK = `${window.location.host}/meeting/${location.state.uuid}`; return (
diff --git a/frontend/src/pages/MeetingTimePickPage/index.tsx b/frontend/src/pages/MeetingTimePickPage/index.tsx index 53ef8efb1..eb3944b40 100644 --- a/frontend/src/pages/MeetingTimePickPage/index.tsx +++ b/frontend/src/pages/MeetingTimePickPage/index.tsx @@ -1,4 +1,5 @@ import { useContext } from 'react'; +import { useLocation } from 'react-router-dom'; import { TimePickerUpdateStateContext } from '@contexts/TimePickerUpdateStateProvider'; @@ -10,7 +11,11 @@ import { useGetMeetingQuery } from '@stores/servers/meeting/queries'; import { s_title } from './MeetingTimePickPage.styles'; export default function MeetingTimePickPage() { - const { data } = useGetMeetingQuery(); + const location = useLocation(); + const pathSegments = location.pathname.split('/'); + const uuid = pathSegments[pathSegments.length - 1]; + + const { data } = useGetMeetingQuery(uuid); const { isTimePickerUpdate } = useContext(TimePickerUpdateStateContext); if (!data) return null;