From 9c2678dad4cc4bae8ff4f17a2cb1b6c5493a205a Mon Sep 17 00:00:00 2001 From: hamo-o Date: Fri, 14 Feb 2025 14:54:54 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=EB=AF=B8=EB=93=A4=EC=9B=A8=EC=96=B4?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=ED=99=95=EC=9D=B8=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/cookies/index.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 frontend/src/utils/cookies/index.ts diff --git a/frontend/src/utils/cookies/index.ts b/frontend/src/utils/cookies/index.ts new file mode 100644 index 00000000..cfbf6dd6 --- /dev/null +++ b/frontend/src/utils/cookies/index.ts @@ -0,0 +1,12 @@ +export const cookies = (cookieHeader: string | undefined) => { + if (!cookieHeader) return {}; + + const cookieStore = cookieHeader.split('; ').reduce((acc, cookie) => { + const [key, value] = cookie.split('='); + acc[key] = decodeURIComponent(value); + return acc; + }, {} as Record); + + const get = (key: string): string | undefined => cookieStore[key]; + return { get }; +}; \ No newline at end of file From fa80084616654f3b3838623dbbcb5daf8397a772 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Fri, 14 Feb 2025 09:59:57 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=EA=B0=9C=EC=9D=B8=20=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=20model=20=EB=B0=8F=20get=20api=20=EC=A0=95=EC=9D=98,?= =?UTF-8?q?=20fetch=20=ED=8F=AC=EB=A7=B7=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../discussion/ui/DiscussionRank/index.tsx | 25 +++++++++++++++++ .../discussion/ui/DiscussionTab/index.tsx | 3 ++- .../src/features/my-calendar/api/index.ts | 14 ++++++++++ frontend/src/features/my-calendar/api/keys.ts | 7 +++++ .../src/features/my-calendar/api/queries.ts | 16 +++++++++++ .../src/features/my-calendar/model/index.ts | 18 +++++++++++++ .../my-calendar/ui/CalendarCardList/index.tsx | 15 +++++++---- .../my-calendar/ui/MyCalendar/index.tsx | 20 +++++++++++--- .../DiscussionCreateFinishPage/index.css.ts | 0 .../DiscussionCreateFinishPage/index.tsx | 0 .../DiscussionInvitePage/index.css.ts | 0 .../DiscussionInvitePage/index.tsx | 0 frontend/src/utils/date/date.ts | 21 +++++++++++++++ frontend/src/utils/fetch/index.ts | 27 ++++++++++++++----- 14 files changed, 149 insertions(+), 17 deletions(-) create mode 100644 frontend/src/features/discussion/ui/DiscussionRank/index.tsx create mode 100644 frontend/src/features/my-calendar/api/index.ts create mode 100644 frontend/src/features/my-calendar/api/keys.ts create mode 100644 frontend/src/features/my-calendar/api/queries.ts rename frontend/src/pages/{ => DiscussionPage}/DiscussionCreateFinishPage/index.css.ts (100%) rename frontend/src/pages/{ => DiscussionPage}/DiscussionCreateFinishPage/index.tsx (100%) rename frontend/src/pages/{ => DiscussionPage}/DiscussionInvitePage/index.css.ts (100%) rename frontend/src/pages/{ => DiscussionPage}/DiscussionInvitePage/index.tsx (100%) diff --git a/frontend/src/features/discussion/ui/DiscussionRank/index.tsx b/frontend/src/features/discussion/ui/DiscussionRank/index.tsx new file mode 100644 index 00000000..5afcafbb --- /dev/null +++ b/frontend/src/features/discussion/ui/DiscussionRank/index.tsx @@ -0,0 +1,25 @@ +import { useState } from 'react'; + +import { Tab } from '@/components/Tab'; + +const DiscussionRank = () => { + const [tab, setTab] = useState('eventsRankedDefault'); + const handleChange = (value: string) => { + setTab(value); + }; + + return ( +
+ + + 참가자 많은 순 + 빠른 시간 순 + + 캘린더 + 순위 + +
+ ); +}; + +export default DiscussionRank; \ No newline at end of file diff --git a/frontend/src/features/discussion/ui/DiscussionTab/index.tsx b/frontend/src/features/discussion/ui/DiscussionTab/index.tsx index eeca54d1..802ab04f 100644 --- a/frontend/src/features/discussion/ui/DiscussionTab/index.tsx +++ b/frontend/src/features/discussion/ui/DiscussionTab/index.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import { Tab } from '@/components/Tab'; import DiscussionCalendar from '../DiscussionCalendar'; +import DiscussionRank from '../DiscussionRank'; import { tabContainerStyle } from './index.css'; const DiscussionTab = () => { @@ -25,7 +26,7 @@ const DiscussionTab = () => { - 순위 + ); diff --git a/frontend/src/features/my-calendar/api/index.ts b/frontend/src/features/my-calendar/api/index.ts new file mode 100644 index 00000000..5ad3314d --- /dev/null +++ b/frontend/src/features/my-calendar/api/index.ts @@ -0,0 +1,14 @@ +import { request } from '@/utils/fetch'; + +import type { PersonalEventDTO, PersonalEventResponse } from '../model'; + +export const personalEventApi = { + getPersonalEvents: async ( + { startDateTime, endDateTime }: Pick, + ): Promise => { + const response = await request.get('/api/v1/personal-events', { + params: { startDateTime, endDateTime }, + }); + return response.data; + }, +}; \ No newline at end of file diff --git a/frontend/src/features/my-calendar/api/keys.ts b/frontend/src/features/my-calendar/api/keys.ts new file mode 100644 index 00000000..e77e5ac4 --- /dev/null +++ b/frontend/src/features/my-calendar/api/keys.ts @@ -0,0 +1,7 @@ +import type { PersonalEventDTO } from '../model'; + +export const personalEventKeys = { + all: ['personalEvents'], + detail: (data: Pick) => + [...personalEventKeys.all, data], +}; \ No newline at end of file diff --git a/frontend/src/features/my-calendar/api/queries.ts b/frontend/src/features/my-calendar/api/queries.ts new file mode 100644 index 00000000..12e09eca --- /dev/null +++ b/frontend/src/features/my-calendar/api/queries.ts @@ -0,0 +1,16 @@ +import { useQuery } from '@tanstack/react-query'; + +import type { PersonalEventDTO, PersonalEventResponse } from '../model'; +import { personalEventApi } from '.'; +import { personalEventKeys } from './keys'; + +export const usePersonalEventsQuery = ( + data: Pick, +) => { + const { data: personalEvents, isLoading } = useQuery({ + queryKey: personalEventKeys.detail(data), + queryFn: () => personalEventApi.getPersonalEvents(data), + }); + + return { personalEvents, isLoading }; +}; \ No newline at end of file diff --git a/frontend/src/features/my-calendar/model/index.ts b/frontend/src/features/my-calendar/model/index.ts index e058a3c3..d87a3396 100644 --- a/frontend/src/features/my-calendar/model/index.ts +++ b/frontend/src/features/my-calendar/model/index.ts @@ -1 +1,19 @@ +import { z } from 'zod'; + +const PersonalEventDTO = z.object({ + id: z.number(), + title: z.string(), + startDateTime: z.string().datetime(), + endDateTime: z.string().datetime(), + isAdjustable: z.boolean(), + syncWithGoogleCalendar: z.boolean(), + googleEventId: z.string(), + calendarId: z.string(), +}); + +const PersonalEventResponse = z.array(PersonalEventDTO.omit({ syncWithGoogleCalendar: true })); + +export type PersonalEventDTO = z.infer; +export type PersonalEventResponse = z.infer; + export type PopoverType = 'add' | 'edit'; \ No newline at end of file diff --git a/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx b/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx index 70d7dd84..3c08a126 100644 --- a/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx +++ b/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx @@ -1,6 +1,7 @@ import { TIME_HEIGHT } from '@/constants/date'; import { calcPositionByDate } from '@/utils/date/position'; +import type { PersonalEventDTO } from '../../model'; import { CalendarCard } from '../CalendarCard'; interface DateRange { @@ -14,19 +15,23 @@ const calcSize = (height: number) => { return 'lg'; }; -export const CalendarCardList = ({ cards }: { cards: DateRange[] }) => ( +export const CalendarCardList = ( + { cards }: { cards: Omit[] }, +) => ( <> {cards.map((card, idx) => { - const { x: sx, y: sy } = calcPositionByDate(card.startDate); - const { y: ey } = calcPositionByDate(card.endDate); + const start = new Date(card.startDateTime); + const end = new Date(card.endDateTime); + const { x: sx, y: sy } = calcPositionByDate(start); + const { y: ey } = calcPositionByDate(end); const height = ey - sy; return ( { +const CalendarTable = ( + { personalEvents = [] }: { personalEvents?: PersonalEventResponse }, +) => { const { handleMouseUp, ...time } = useSelectTime(); const [open, setOpen] = useState(false); const [cards, setCards] = useState([]); @@ -34,7 +40,7 @@ const CalendarTable = () => { startDate={time.doneStartTime} type='add' /> - + handleMouseUp(handleMouseUpAddSchedule), @@ -47,11 +53,17 @@ const CalendarTable = () => { export const MyCalendar = () => { const calendar = useSharedCalendarContext(); + const { startDate, endDate } = formatDateToWeekRange(calendar.selectedDate); + + const { personalEvents, isLoading } = usePersonalEventsQuery({ + startDateTime: formatDateToBarString(startDate), + endDateTime: formatDateToBarString(endDate), + }); + return ( - - + {isLoading ?
로딩중...
: }
); }; \ No newline at end of file diff --git a/frontend/src/pages/DiscussionCreateFinishPage/index.css.ts b/frontend/src/pages/DiscussionPage/DiscussionCreateFinishPage/index.css.ts similarity index 100% rename from frontend/src/pages/DiscussionCreateFinishPage/index.css.ts rename to frontend/src/pages/DiscussionPage/DiscussionCreateFinishPage/index.css.ts diff --git a/frontend/src/pages/DiscussionCreateFinishPage/index.tsx b/frontend/src/pages/DiscussionPage/DiscussionCreateFinishPage/index.tsx similarity index 100% rename from frontend/src/pages/DiscussionCreateFinishPage/index.tsx rename to frontend/src/pages/DiscussionPage/DiscussionCreateFinishPage/index.tsx diff --git a/frontend/src/pages/DiscussionInvitePage/index.css.ts b/frontend/src/pages/DiscussionPage/DiscussionInvitePage/index.css.ts similarity index 100% rename from frontend/src/pages/DiscussionInvitePage/index.css.ts rename to frontend/src/pages/DiscussionPage/DiscussionInvitePage/index.css.ts diff --git a/frontend/src/pages/DiscussionInvitePage/index.tsx b/frontend/src/pages/DiscussionPage/DiscussionInvitePage/index.tsx similarity index 100% rename from frontend/src/pages/DiscussionInvitePage/index.tsx rename to frontend/src/pages/DiscussionPage/DiscussionInvitePage/index.tsx diff --git a/frontend/src/utils/date/date.ts b/frontend/src/utils/date/date.ts index 9419fe51..27390cc3 100644 --- a/frontend/src/utils/date/date.ts +++ b/frontend/src/utils/date/date.ts @@ -91,6 +91,26 @@ export const formatDateToWeekDates = (date: Date | null): Date[] => { return dates; }; +/** + * + * @param date - 날짜 객체. + * @returns - 특정 날짜가 포함된 주의 첫째 날과 마지막 날의 날짜 객체. + */ + +export const formatDateToWeekRange = (date: Date): { + startDate: Date; + endDate: Date; +} => { + const selected = new Date(date); + const firstDateOfWeek = new Date(selected); + firstDateOfWeek.setDate(firstDateOfWeek.getDate() - selected.getDay()); + + const lastDateOfWeek = new Date(firstDateOfWeek); + lastDateOfWeek.setDate(firstDateOfWeek.getDate() + 6); + + return { startDate: firstDateOfWeek, endDate: lastDateOfWeek }; +}; + /** * * @param date1 - 비교할 날짜1 @@ -196,3 +216,4 @@ export const isAllday = (startDate: Date | null, endDate: Date | null): boolean if (!startDate || !endDate) return false; return endDate.getTime() - startDate.getTime() >= ALL_DAY; }; + diff --git a/frontend/src/utils/fetch/index.ts b/frontend/src/utils/fetch/index.ts index 7ff9914f..dc6d8cc6 100644 --- a/frontend/src/utils/fetch/index.ts +++ b/frontend/src/utils/fetch/index.ts @@ -25,16 +25,25 @@ const buildFetchOptions = (options?: RequestInit): RequestInit => { return { ...defaultOptions, ...options, headers }; }; +interface FetchRequest { + params?: Record; + body?: BodyInit; + options?: RequestOptions; +} + export const executeFetch = async ( method: Method, endpoint: string, - body?: BodyInit, - options?: RequestOptions, + { params, body, options }: FetchRequest = {}, ) => { const fetchOptions = buildFetchOptions(options); + const queryString = params && Object.keys(params).length > 0 + ? `?${new URLSearchParams(params).toString()}` + : ''; + const fullUrl = `${BASE_URL}${endpoint}${queryString}`; try { - const response = await fetch(BASE_URL + endpoint, { + const response = await fetch(fullUrl, { method: method, body: JSON.stringify(body), ...fetchOptions, @@ -67,8 +76,12 @@ export const executeFetch = async ( * @property delete - 지정된 엔드포인트로 HTTP DELETE 요청을 보냅니다. */ export const request = { - get: (endpoint: string) => executeFetch('GET', endpoint), - post: (endpoint: string, body?: BodyInit) => executeFetch('POST', endpoint, body), - put: (endpoint: string, body?: BodyInit) => executeFetch('PUT', endpoint, body), - delete: (endpoint: string) => executeFetch('DELETE', endpoint), + get: (endpoint: string, props?: Pick) => + executeFetch('GET', endpoint, props), + post: (endpoint: string, props?: Pick) => + executeFetch('POST', endpoint, props), + put: (endpoint: string, props?: Pick) => + executeFetch('PUT', endpoint, props), + delete: (endpoint: string) => + executeFetch('DELETE', endpoint), }; From 45a858dffa665992ff7840836be6292a1867f999 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Fri, 14 Feb 2025 10:29:01 +0900 Subject: [PATCH 3/7] =?UTF-8?q?fix:=20API=20URI=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/my-calendar/api/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/features/my-calendar/api/index.ts b/frontend/src/features/my-calendar/api/index.ts index 5ad3314d..b2c9b158 100644 --- a/frontend/src/features/my-calendar/api/index.ts +++ b/frontend/src/features/my-calendar/api/index.ts @@ -6,8 +6,11 @@ export const personalEventApi = { getPersonalEvents: async ( { startDateTime, endDateTime }: Pick, ): Promise => { - const response = await request.get('/api/v1/personal-events', { - params: { startDateTime, endDateTime }, + const response = await request.get('/api/v1/personal-event', { + params: { + startDateTime: `${startDateTime}T00:00:00`, + endDateTime: `${endDateTime}T00:00:00`, + }, }); return response.data; }, From 27f91b4ce0ca534bc38fed674bd5e11671c76209 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Fri, 14 Feb 2025 15:30:39 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20API=20=EC=9D=91=EB=8B=B5=EA=B0=92?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=B9=B4=EB=93=9C=20=EC=BB=A8=ED=85=90?= =?UTF-8?q?=EC=B8=A0=20=EB=9E=9C=EB=8D=94=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/my-calendar/ui/CalendarCardList/index.tsx | 6 +++--- frontend/src/features/my-calendar/ui/MyCalendar/index.tsx | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx b/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx index 3c08a126..c3414d22 100644 --- a/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx +++ b/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx @@ -29,10 +29,10 @@ export const CalendarCardList = ( return ( ); })} diff --git a/frontend/src/features/my-calendar/ui/MyCalendar/index.tsx b/frontend/src/features/my-calendar/ui/MyCalendar/index.tsx index bc1dc6da..e8306b3f 100644 --- a/frontend/src/features/my-calendar/ui/MyCalendar/index.tsx +++ b/frontend/src/features/my-calendar/ui/MyCalendar/index.tsx @@ -63,6 +63,7 @@ export const MyCalendar = () => { return ( + {isLoading ?
로딩중...
: }
); From 590e084ba3291d7926a112e3b80f9ef7e2884318 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Fri, 14 Feb 2025 18:41:05 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20=EA=B0=9C=EC=9D=B8=20=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=20=EC=83=9D=EC=84=B1=20API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/my-calendar/api/index.ts | 10 +- .../src/features/my-calendar/api/mutations.ts | 20 ++++ .../src/features/my-calendar/api/queries.ts | 4 +- .../src/features/my-calendar/model/index.ts | 6 +- .../my-calendar/ui/CalendarCardList/index.tsx | 7 +- .../my-calendar/ui/MyCalendar/index.tsx | 21 ++--- .../ui/SchedulePopover/PopoverForm.tsx | 93 ++++++++++++------- .../my-calendar/ui/SchedulePopover/index.tsx | 43 ++++----- frontend/src/hooks/useFormRef.ts | 11 +-- frontend/src/routes/discussion/create/$id.tsx | 2 +- frontend/src/utils/date/format.ts | 6 ++ frontend/src/utils/fetch/index.ts | 2 +- 12 files changed, 134 insertions(+), 91 deletions(-) create mode 100644 frontend/src/features/my-calendar/api/mutations.ts diff --git a/frontend/src/features/my-calendar/api/index.ts b/frontend/src/features/my-calendar/api/index.ts index b2c9b158..646982a3 100644 --- a/frontend/src/features/my-calendar/api/index.ts +++ b/frontend/src/features/my-calendar/api/index.ts @@ -1,11 +1,11 @@ import { request } from '@/utils/fetch'; -import type { PersonalEventDTO, PersonalEventResponse } from '../model'; +import type { PersonalEventDTO, PersonalEventRequest, PersonalEventResponse } from '../model'; export const personalEventApi = { - getPersonalEvents: async ( + getPersonalEvent: async ( { startDateTime, endDateTime }: Pick, - ): Promise => { + ): Promise => { const response = await request.get('/api/v1/personal-event', { params: { startDateTime: `${startDateTime}T00:00:00`, @@ -14,4 +14,8 @@ export const personalEventApi = { }); return response.data; }, + postPersonalEvent: async (body: PersonalEventRequest): Promise => { + const response = await request.post('/api/v1/personal-event', { body }); + return response; + }, }; \ No newline at end of file diff --git a/frontend/src/features/my-calendar/api/mutations.ts b/frontend/src/features/my-calendar/api/mutations.ts new file mode 100644 index 00000000..78483baa --- /dev/null +++ b/frontend/src/features/my-calendar/api/mutations.ts @@ -0,0 +1,20 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import type { PersonalEventRequest } from '../model'; +import { personalEventApi } from '.'; +import { personalEventKeys } from './keys'; + +export const usePersonalEventMutation = () => { + const queryClient = useQueryClient(); + + const { mutate } = useMutation({ + mutationFn: (body: PersonalEventRequest) => personalEventApi.postPersonalEvent(body), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: personalEventKeys.all, + }); + }, + }); + + return { mutate }; +}; \ No newline at end of file diff --git a/frontend/src/features/my-calendar/api/queries.ts b/frontend/src/features/my-calendar/api/queries.ts index 12e09eca..c76edb4b 100644 --- a/frontend/src/features/my-calendar/api/queries.ts +++ b/frontend/src/features/my-calendar/api/queries.ts @@ -7,9 +7,9 @@ import { personalEventKeys } from './keys'; export const usePersonalEventsQuery = ( data: Pick, ) => { - const { data: personalEvents, isLoading } = useQuery({ + const { data: personalEvents, isLoading } = useQuery({ queryKey: personalEventKeys.detail(data), - queryFn: () => personalEventApi.getPersonalEvents(data), + queryFn: () => personalEventApi.getPersonalEvent(data), }); return { personalEvents, isLoading }; diff --git a/frontend/src/features/my-calendar/model/index.ts b/frontend/src/features/my-calendar/model/index.ts index d87a3396..89554d1c 100644 --- a/frontend/src/features/my-calendar/model/index.ts +++ b/frontend/src/features/my-calendar/model/index.ts @@ -11,9 +11,13 @@ const PersonalEventDTO = z.object({ calendarId: z.string(), }); -const PersonalEventResponse = z.array(PersonalEventDTO.omit({ syncWithGoogleCalendar: true })); +const PersonalEventResponse = PersonalEventDTO.omit({ syncWithGoogleCalendar: true }); +const PersonalEventRequest = PersonalEventDTO.omit( + { id: true, googleEventId: true, calendarId: true }, +); export type PersonalEventDTO = z.infer; export type PersonalEventResponse = z.infer; +export type PersonalEventRequest = z.infer; export type PopoverType = 'add' | 'edit'; \ No newline at end of file diff --git a/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx b/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx index c3414d22..c1e52ecb 100644 --- a/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx +++ b/frontend/src/features/my-calendar/ui/CalendarCardList/index.tsx @@ -4,11 +4,6 @@ import { calcPositionByDate } from '@/utils/date/position'; import type { PersonalEventDTO } from '../../model'; import { CalendarCard } from '../CalendarCard'; -interface DateRange { - startDate: Date | null; - endDate: Date | null; -} - const calcSize = (height: number) => { if (height < TIME_HEIGHT) return 'sm'; if (height < TIME_HEIGHT * 2.5) return 'md'; @@ -19,7 +14,7 @@ export const CalendarCardList = ( { cards }: { cards: Omit[] }, ) => ( <> - {cards.map((card, idx) => { + {cards.map((card) => { const start = new Date(card.startDateTime); const end = new Date(card.endDateTime); const { x: sx, y: sy } = calcPositionByDate(start); diff --git a/frontend/src/features/my-calendar/ui/MyCalendar/index.tsx b/frontend/src/features/my-calendar/ui/MyCalendar/index.tsx index e8306b3f..7c8685f0 100644 --- a/frontend/src/features/my-calendar/ui/MyCalendar/index.tsx +++ b/frontend/src/features/my-calendar/ui/MyCalendar/index.tsx @@ -4,7 +4,7 @@ import { Calendar } from '@/components/Calendar'; import { useSharedCalendarContext } from '@/components/Calendar/context/SharedCalendarContext'; import { useSelectTime } from '@/hooks/useSelectTime'; import { formatDateToWeekRange } from '@/utils/date'; -import { formatDateToBarString } from '@/utils/date/format'; +import { formatDateToBarString, formatDateToDateTimeString } from '@/utils/date/format'; import { usePersonalEventsQuery } from '../../api/queries'; import type { PersonalEventResponse } from '../../model'; @@ -12,18 +12,11 @@ import { CalendarCardList } from '../CalendarCardList'; import { SchedulePopover } from '../SchedulePopover'; import { calendarStyle, containerStyle } from './index.css'; -// TODO: 자주 쓰이는 타입 정의는 따로 빼기 -interface DateRange { - startDate: Date | null; - endDate: Date | null; -} - const CalendarTable = ( - { personalEvents = [] }: { personalEvents?: PersonalEventResponse }, + { personalEvents = [] }: { personalEvents?: PersonalEventResponse[] }, ) => { const { handleMouseUp, ...time } = useSelectTime(); const [open, setOpen] = useState(false); - const [cards, setCards] = useState([]); const handleMouseUpAddSchedule = () => { setOpen(true); @@ -31,15 +24,13 @@ const CalendarTable = ( return (
+ {open && + />} ) => ( + + 시간 조정 가능 + +); -export const PopoverForm = ({ startDate, endDate }: PopoverFormProps) => - // form 관리 - ( - <> - , +) => + ; + +export const PopoverForm = ({ valuesRef, handleChange }: FormRef) => + <> + + + - - - - - - 시간 조정 가능 - - - 구글 캘린더 연동 - - - - ) -; \ No newline at end of file + + + + + + + 구글 캘린더 연동 + + + ; \ No newline at end of file diff --git a/frontend/src/features/my-calendar/ui/SchedulePopover/index.tsx b/frontend/src/features/my-calendar/ui/SchedulePopover/index.tsx index c05a4030..ffac164d 100644 --- a/frontend/src/features/my-calendar/ui/SchedulePopover/index.tsx +++ b/frontend/src/features/my-calendar/ui/SchedulePopover/index.tsx @@ -1,42 +1,40 @@ -import type { Dispatch, SetStateAction } from 'react'; - +import { useFormRef } from '@/hooks/useFormRef'; import { isSaturday } from '@/utils/date'; import { calcPositionByDate } from '@/utils/date/position'; -import type { PopoverType } from '../../model'; +import { usePersonalEventMutation } from '../../api/mutations'; +import type { PersonalEventRequest, PopoverType } from '../../model'; import { containerStyle } from './index.css'; import { PopoverButton } from './PopoverButton'; import { PopoverForm } from './PopoverForm'; import { Title } from './Title'; -interface DateRange { - startDate: Date | null; - endDate: Date | null; -} - -interface SchedulePopoverProps { - isOpen: boolean; +interface SchedulePopoverProps extends Pick { setIsOpen: (isOpen: boolean) => void; type: PopoverType; - startDate: Date | null; - endDate: Date | null; - - // TODO: API 연결 후 삭제 - cards: DateRange[]; - setCards: Dispatch>; } +const defaultEvent: Omit = { + title: '제목 없음', + isAdjustable: false, + syncWithGoogleCalendar: true, +}; + export const SchedulePopover = ( - { isOpen, setIsOpen, type, startDate, endDate, setCards }: SchedulePopoverProps, + { setIsOpen, type, ...event }: SchedulePopoverProps, ) => { - if (!isOpen) return null; + const { mutate } = usePersonalEventMutation(); + const startDate = new Date(event.startDateTime); const { x: sx, y: sy } = calcPositionByDate(startDate); - + const { valuesRef, handleChange } = useFormRef({ + startDateTime: event.startDateTime, + endDateTime: event.endDateTime, + ...defaultEvent, + }); const handleClickSave = () => { - setCards((prev: DateRange[]) => [...prev, { startDate, endDate }]); + mutate(valuesRef.current); setIsOpen(false); }; - const handleClickDelete = () => { // do something }; @@ -44,7 +42,6 @@ export const SchedulePopover = ( return( - <PopoverForm endDate={endDate} startDate={startDate} /> + <PopoverForm handleChange={handleChange} valuesRef={valuesRef} /> <PopoverButton onClickDelete={handleClickDelete} onClickSave={handleClickSave} diff --git a/frontend/src/hooks/useFormRef.ts b/frontend/src/hooks/useFormRef.ts index dce4e097..548cda0d 100644 --- a/frontend/src/hooks/useFormRef.ts +++ b/frontend/src/hooks/useFormRef.ts @@ -1,12 +1,13 @@ import type { ChangeEvent } from 'react'; import { useRef } from 'react'; -export type FormValues<T> = { [K in keyof T]: string | Date }; +// Form의 value로는 다양한 값이 올 수 있습니다. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type FormValues<T> = { [K in keyof T]: any }; export interface FormRef<T> { valuesRef: { current: FormValues<T> }; handleChange: (e: ChangeEvent<HTMLInputElement>) => void; - onSubmit: () => void; } export const useFormRef = <T>(initialValues: FormValues<T>): FormRef<T> => { @@ -16,9 +17,5 @@ export const useFormRef = <T>(initialValues: FormValues<T>): FormRef<T> => { valuesRef.current[e.target.name as keyof T] = e.target.value; }; - const onSubmit = () => { - // console.log(valuesRef.current); - }; - - return { valuesRef, handleChange, onSubmit }; + return { valuesRef, handleChange }; }; diff --git a/frontend/src/routes/discussion/create/$id.tsx b/frontend/src/routes/discussion/create/$id.tsx index 4b30a624..9c837f23 100644 --- a/frontend/src/routes/discussion/create/$id.tsx +++ b/frontend/src/routes/discussion/create/$id.tsx @@ -1,7 +1,7 @@ import { createFileRoute } from '@tanstack/react-router'; import GlobalNavBar from '@/layout/GlobalNavBar'; -import DiscussionCreateFinishPage from '@/pages/DiscussionCreateFinishPage'; +import DiscussionCreateFinishPage from '@/pages/DiscussionPage/DiscussionCreateFinishPage'; const DiscussionCreateFinish = () => ( <> diff --git a/frontend/src/utils/date/format.ts b/frontend/src/utils/date/format.ts index 7cf5749e..d6e8cb9c 100644 --- a/frontend/src/utils/date/format.ts +++ b/frontend/src/utils/date/format.ts @@ -1,4 +1,5 @@ import { getYearMonthDay } from './date'; +import { formatDateToTimeString } from './time'; /** * 날짜 객체를 YY-MM-DD 형식의 문자열로 변환합니다. @@ -15,4 +16,9 @@ export const formatDateToDotString = (date: Date | null): string => { if (!date) return ''; const { year, month, day } = getYearMonthDay(date); return `${year}. ${month.toString().padStart(2, '0')}. ${day.toString().padStart(2, '0')}`; +}; + +export const formatDateToDateTimeString = (date: Date | null): string => { + if (!date) return ''; + return `${formatDateToBarString(date)}T${formatDateToTimeString(date)}:00`; }; \ No newline at end of file diff --git a/frontend/src/utils/fetch/index.ts b/frontend/src/utils/fetch/index.ts index dc6d8cc6..932bff1f 100644 --- a/frontend/src/utils/fetch/index.ts +++ b/frontend/src/utils/fetch/index.ts @@ -27,7 +27,7 @@ const buildFetchOptions = (options?: RequestInit): RequestInit => { interface FetchRequest { params?: Record<string, string>; - body?: BodyInit; + body?: Record<string, unknown>; options?: RequestOptions; } From dab4348c41f7b7b7b0143748e6a767b20a641f03 Mon Sep 17 00:00:00 2001 From: hamo-o <yheel369@gmail.com> Date: Fri, 14 Feb 2025 18:45:47 +0900 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/routes/_main/discussion/invite/$id.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/_main/discussion/invite/$id.tsx b/frontend/src/routes/_main/discussion/invite/$id.tsx index dedf9012..d301dd2a 100644 --- a/frontend/src/routes/_main/discussion/invite/$id.tsx +++ b/frontend/src/routes/_main/discussion/invite/$id.tsx @@ -1,7 +1,7 @@ import { createFileRoute } from '@tanstack/react-router'; import GlobalNavBar from '@/layout/GlobalNavBar'; -import DiscussionInvitePage from '@/pages/DiscussionInvitePage'; +import DiscussionInvitePage from '@/pages/DiscussionPage/DiscussionInvitePage'; const DiscussionInvite = () => ( <> From 334e51c564478257e83b20493de4faa76a56b810 Mon Sep 17 00:00:00 2001 From: hamo-o <yheel369@gmail.com> Date: Fri, 14 Feb 2025 18:53:31 +0900 Subject: [PATCH 7/7] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20cookies=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/cookies/index.ts | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 frontend/src/utils/cookies/index.ts diff --git a/frontend/src/utils/cookies/index.ts b/frontend/src/utils/cookies/index.ts deleted file mode 100644 index cfbf6dd6..00000000 --- a/frontend/src/utils/cookies/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const cookies = (cookieHeader: string | undefined) => { - if (!cookieHeader) return {}; - - const cookieStore = cookieHeader.split('; ').reduce((acc, cookie) => { - const [key, value] = cookie.split('='); - acc[key] = decodeURIComponent(value); - return acc; - }, {} as Record<string, string>); - - const get = (key: string): string | undefined => cookieStore[key]; - return { get }; -}; \ No newline at end of file