From 4f6098ac7db5f6ac84892257b9fdd0e9d04f7176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Mon, 17 Feb 2025 15:49:18 +0900 Subject: [PATCH 01/25] =?UTF-8?q?feat:=20=EB=8B=A4=EA=B0=80=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EC=9D=BC=EC=A0=95=EC=97=90=20=EB=8C=80=ED=95=9C=20?= =?UTF-8?q?api=20=ED=86=B5=EC=8B=A0=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/shared-schedule/api/index.ts | 0 .../src/features/shared-schedule/model/index.ts | 1 + .../shared-schedule/model/upcomingSchedules.ts | 17 +++++++++++++++++ .../ui/UpcomingSchedules/index.tsx | 2 -- .../src/pages/UpcomingSchedulePage/index.css.ts | 7 ++++++- 5 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 frontend/src/features/shared-schedule/api/index.ts create mode 100644 frontend/src/features/shared-schedule/model/upcomingSchedules.ts diff --git a/frontend/src/features/shared-schedule/api/index.ts b/frontend/src/features/shared-schedule/api/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/features/shared-schedule/model/index.ts b/frontend/src/features/shared-schedule/model/index.ts index e69de29b..bb2d07ee 100644 --- a/frontend/src/features/shared-schedule/model/index.ts +++ b/frontend/src/features/shared-schedule/model/index.ts @@ -0,0 +1 @@ +export * from './upcomingSchedules'; diff --git a/frontend/src/features/shared-schedule/model/upcomingSchedules.ts b/frontend/src/features/shared-schedule/model/upcomingSchedules.ts new file mode 100644 index 00000000..074f14fb --- /dev/null +++ b/frontend/src/features/shared-schedule/model/upcomingSchedules.ts @@ -0,0 +1,17 @@ +import { z } from 'zod'; + +const Schedule = z.object({ + id: z.number(), + title: z.string(), + startDateTime: z.date(), + endDateTime: z.date(), + meetingMethodOrLocation: z.enum(['ONLINE', 'OFFLINE']), + participantPictureUrls: z.array(z.string()), +}); + +export const UpcomingSchedulesResponseSchema = z.object({ + data: z.array(Schedule), +}); + +export type Schedule = z.infer; +export type UpcomingSchedulesResponse = z.infer; diff --git a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/index.tsx index 87268e41..bdb8d608 100644 --- a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/index.tsx @@ -18,13 +18,11 @@ const UpcomingSchedules = ({ schedules, children }: UpcomingSchedulesProps) => { }); return ( diff --git a/frontend/src/pages/UpcomingSchedulePage/index.css.ts b/frontend/src/pages/UpcomingSchedulePage/index.css.ts index 5c7b5e47..050ddac4 100644 --- a/frontend/src/pages/UpcomingSchedulePage/index.css.ts +++ b/frontend/src/pages/UpcomingSchedulePage/index.css.ts @@ -4,8 +4,13 @@ import { recipe } from '@vanilla-extract/recipes'; import { vars } from '@/theme/index.css'; export const containerStyle = style({ - width: '100%', + width: 1284, paddingBottom: 218, + + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + gap: 120, }); export const controlButtonStyle = recipe({ From f597cd8d094afe9b21c13de34d2555495eac9300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Mon, 17 Feb 2025 17:53:42 +0900 Subject: [PATCH 02/25] =?UTF-8?q?feat:=20api=20=EC=8A=A4=ED=82=A4=EB=A7=88?= =?UTF-8?q?=20=EB=B0=8F=20request=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/shared-schedule/api/index.ts | 25 ++++++++++++++ .../src/features/shared-schedule/api/keys.ts | 7 ++++ .../features/shared-schedule/api/queries.ts | 25 ++++++++++++++ .../model/finishedSchedules.ts | 33 +++++++++++++++++++ .../features/shared-schedule/model/index.ts | 4 ++- .../shared-schedule/model/ongoingSchedules.ts | 23 +++++++++++++ .../model/upcomingSchedules.ts | 6 ++-- frontend/src/utils/zod/index.ts | 3 ++ 8 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 frontend/src/features/shared-schedule/api/keys.ts create mode 100644 frontend/src/features/shared-schedule/api/queries.ts create mode 100644 frontend/src/features/shared-schedule/model/finishedSchedules.ts create mode 100644 frontend/src/features/shared-schedule/model/ongoingSchedules.ts diff --git a/frontend/src/features/shared-schedule/api/index.ts b/frontend/src/features/shared-schedule/api/index.ts index e69de29b..bb8f9655 100644 --- a/frontend/src/features/shared-schedule/api/index.ts +++ b/frontend/src/features/shared-schedule/api/index.ts @@ -0,0 +1,25 @@ +import { request } from '@/utils/fetch'; + +import type { OngoingQueryType } from '../model/finishedSchedules'; + +const ENDPOINT_PREFIX = '/api/v1/schedules'; + +export const schedulesApi = { + getUpcomingSchedules: async () => request.get(ENDPOINT_PREFIX + '/upcoming'), + getOngoingSchedules: async (page: number, size: number, type: OngoingQueryType) => + request.get(ENDPOINT_PREFIX + '/ongoing', { + params: { + page: page.toString(), + size: size.toString(), + type: type, + }, + }), + getFinishedSchedules: async (page: number, size: number, year: number) => + request.get(ENDPOINT_PREFIX + '/finished', { + params: { + page: page.toString(), + size: size.toString(), + year: year.toString(), + }, + }), +}; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/api/keys.ts b/frontend/src/features/shared-schedule/api/keys.ts new file mode 100644 index 00000000..ff620294 --- /dev/null +++ b/frontend/src/features/shared-schedule/api/keys.ts @@ -0,0 +1,7 @@ +import type { OngoingQueryType } from '../model/finishedSchedules'; + +export const querykeys = { + upcoming: ['upcoming'], + ongoing: (page: number, size: number, type: OngoingQueryType) => ['ongoing', page, size, type], + finished: (page: number, size: number, year: number) => ['finished', page, size, year], +}; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/api/queries.ts b/frontend/src/features/shared-schedule/api/queries.ts new file mode 100644 index 00000000..76fbe6c4 --- /dev/null +++ b/frontend/src/features/shared-schedule/api/queries.ts @@ -0,0 +1,25 @@ +import { useQuery } from '@tanstack/react-query'; + +import type { UpcomingSchedulesResponse } from '../model'; +import type { FinishedSchedulesResponse, OngoingQueryType } from '../model/finishedSchedules'; +import type { OngoingSchedulesResponse } from '../model/ongoingSchedules'; +import { schedulesApi } from '.'; +import { querykeys } from './keys'; + +export const useUpcomingQuery = () => useQuery({ + queryKey: querykeys.upcoming, + queryFn: () => schedulesApi.getUpcomingSchedules(), +}); + +export const useOngoingQuery = (page: number, size: number, type: OngoingQueryType) => + useQuery({ + queryKey: querykeys.ongoing(page, size, type), + queryFn: () => schedulesApi.getOngoingSchedules(page, size, type), + }); + +export const useFinishedQuery = (page: number, size: number, year: number) => + useQuery({ + queryKey: querykeys.finished(page, size, year), + queryFn: () => schedulesApi.getFinishedSchedules(page, size, year), + }); + diff --git a/frontend/src/features/shared-schedule/model/finishedSchedules.ts b/frontend/src/features/shared-schedule/model/finishedSchedules.ts new file mode 100644 index 00000000..fcad230e --- /dev/null +++ b/frontend/src/features/shared-schedule/model/finishedSchedules.ts @@ -0,0 +1,33 @@ +import { z } from 'zod'; + +import { zCoerceToDate } from '@/utils/zod'; + +const SharedEventDto = z.object({ + id: z.number(), + startDateTime: zCoerceToDate, + endDateTime: zCoerceToDate, +}); + +const FinishedDiscussion = z.object({ + id: z.number(), + title: z.string(), + meetingMethodOrLocation: z.string(), + sharedEventDto: SharedEventDto, + participantPictureUrls: z.array(z.string()), +}); + +export const FinishedSchedulesResponseSchema = z.object({ + currentYear: z.number(), + currentPage: z.number(), + totalPages: z.number(), + hasNext: z.boolean(), + hasPrevious: z.boolean(), + finisnedDiscussions: z.array(FinishedDiscussion), +}); + +export type OngoingQueryType = 'HOST' | 'ATTENDEE' | 'ALL'; +export type MeetingMethod = 'ONLINE' | 'OFFLINE'; + +export type FinishedSchedulesResponse = z.infer; +export type FinisnedDiscussion = z.infer; +export type SharedEventDto = z.infer; diff --git a/frontend/src/features/shared-schedule/model/index.ts b/frontend/src/features/shared-schedule/model/index.ts index bb2d07ee..bbf1e441 100644 --- a/frontend/src/features/shared-schedule/model/index.ts +++ b/frontend/src/features/shared-schedule/model/index.ts @@ -1 +1,3 @@ -export * from './upcomingSchedules'; +export * from './finishedSchedules'; +export * from './ongoingSchedules'; +export * from './upcomingSchedules'; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts new file mode 100644 index 00000000..0ca87529 --- /dev/null +++ b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts @@ -0,0 +1,23 @@ +import { z } from 'zod'; + +import { zCoerceToDate } from '@/utils/zod'; + +const OngoingDiscussion = z.object({ + id: z.number(), + title: z.string(), + dateRangeStart: zCoerceToDate, + dateRangeEnd: zCoerceToDate, + timeLeft: z.number(), + participantPictureUrls: z.array(z.string()), +}); + +export const OngoingSchedulesResponseSchema = z.object({ + currentPage: z.number(), + totalPages: z.number(), + hasNext: z.boolean(), + hasPrevious: z.boolean(), + ongoingDiscussions: z.array(OngoingDiscussion), +}); + +export type OngoingSchedulesResponse = z.infer; +export type OngoingDiscussion = z.infer; diff --git a/frontend/src/features/shared-schedule/model/upcomingSchedules.ts b/frontend/src/features/shared-schedule/model/upcomingSchedules.ts index 074f14fb..aaa993b7 100644 --- a/frontend/src/features/shared-schedule/model/upcomingSchedules.ts +++ b/frontend/src/features/shared-schedule/model/upcomingSchedules.ts @@ -1,10 +1,12 @@ import { z } from 'zod'; +import { zCoerceToDate } from '@/utils/zod'; + const Schedule = z.object({ id: z.number(), title: z.string(), - startDateTime: z.date(), - endDateTime: z.date(), + startDateTime: zCoerceToDate, + endDateTime: zCoerceToDate, meetingMethodOrLocation: z.enum(['ONLINE', 'OFFLINE']), participantPictureUrls: z.array(z.string()), }); diff --git a/frontend/src/utils/zod/index.ts b/frontend/src/utils/zod/index.ts index dbf4b496..c80a96d3 100644 --- a/frontend/src/utils/zod/index.ts +++ b/frontend/src/utils/zod/index.ts @@ -7,3 +7,6 @@ export const zDate = z.string().regex(DATE_BAR) export const zTime = z.string().regex(TIME) .transform((v) => new Date(v)); + +const datelike = z.union([z.number(), z.string(), z.date()]); +export const zCoerceToDate = datelike.pipe(z.coerce.date()); \ No newline at end of file From 2bc20c9f9a3c424f4d4e5120f981462d3e90d0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Mon, 17 Feb 2025 19:03:09 +0900 Subject: [PATCH 03/25] =?UTF-8?q?feat:=20response=20body=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/shared-schedule/api/index.ts | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/frontend/src/features/shared-schedule/api/index.ts b/frontend/src/features/shared-schedule/api/index.ts index bb8f9655..e8f024ca 100644 --- a/frontend/src/features/shared-schedule/api/index.ts +++ b/frontend/src/features/shared-schedule/api/index.ts @@ -1,25 +1,49 @@ import { request } from '@/utils/fetch'; -import type { OngoingQueryType } from '../model/finishedSchedules'; +import type { OngoingSchedulesResponse, UpcomingSchedulesResponse } from '../model'; +import { + FinishedSchedulesResponseSchema, + OngoingSchedulesResponseSchema, + UpcomingSchedulesResponseSchema, +} from '../model'; +import type { FinishedSchedulesResponse, OngoingQueryType } from '../model/finishedSchedules'; const ENDPOINT_PREFIX = '/api/v1/schedules'; export const schedulesApi = { - getUpcomingSchedules: async () => request.get(ENDPOINT_PREFIX + '/upcoming'), - getOngoingSchedules: async (page: number, size: number, type: OngoingQueryType) => - request.get(ENDPOINT_PREFIX + '/ongoing', { + getUpcomingSchedules: async (): Promise => { + const response = await request.get(ENDPOINT_PREFIX + '/upcoming'); + const validData = UpcomingSchedulesResponseSchema.parse(response.data); + return validData; + }, + getOngoingSchedules: async ( + page: number, + size: number, + type: OngoingQueryType, + ): Promise => { + const response = await request.get(ENDPOINT_PREFIX + '/ongoing', { params: { page: page.toString(), size: size.toString(), type: type, }, - }), - getFinishedSchedules: async (page: number, size: number, year: number) => - request.get(ENDPOINT_PREFIX + '/finished', { + }); + const validData = OngoingSchedulesResponseSchema.parse(response.data); + return validData; + }, + getFinishedSchedules: async ( + page: number, + size: number, + year: number, + ): Promise => { + const response = await request.get(ENDPOINT_PREFIX + '/finished', { params: { page: page.toString(), size: size.toString(), year: year.toString(), }, - }), + }); + const validData = FinishedSchedulesResponseSchema.parse(response.data); + return validData; + }, }; \ No newline at end of file From 7df11d485966f3b9216ada1fdf4599db5b99157f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Mon, 17 Feb 2025 19:29:05 +0900 Subject: [PATCH 04/25] =?UTF-8?q?refactor:=20query=20options=EB=A5=BC=20?= =?UTF-8?q?=EB=B3=84=EA=B0=9C=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EC=97=AC=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/shared-schedule/api/queries.ts | 24 ++++++++----------- .../shared-schedule/api/queryOptions.ts | 18 ++++++++++++++ .../ui/UpcomingSchedules/index.tsx | 1 - 3 files changed, 28 insertions(+), 15 deletions(-) create mode 100644 frontend/src/features/shared-schedule/api/queryOptions.ts diff --git a/frontend/src/features/shared-schedule/api/queries.ts b/frontend/src/features/shared-schedule/api/queries.ts index 76fbe6c4..638aeaf0 100644 --- a/frontend/src/features/shared-schedule/api/queries.ts +++ b/frontend/src/features/shared-schedule/api/queries.ts @@ -3,23 +3,19 @@ import { useQuery } from '@tanstack/react-query'; import type { UpcomingSchedulesResponse } from '../model'; import type { FinishedSchedulesResponse, OngoingQueryType } from '../model/finishedSchedules'; import type { OngoingSchedulesResponse } from '../model/ongoingSchedules'; -import { schedulesApi } from '.'; -import { querykeys } from './keys'; +import { sharedSchedulesQueryOptions } from './queryOptions'; -export const useUpcomingQuery = () => useQuery({ - queryKey: querykeys.upcoming, - queryFn: () => schedulesApi.getUpcomingSchedules(), -}); +export const useUpcomingQuery = () => useQuery( + sharedSchedulesQueryOptions.upcoming, +); export const useOngoingQuery = (page: number, size: number, type: OngoingQueryType) => - useQuery({ - queryKey: querykeys.ongoing(page, size, type), - queryFn: () => schedulesApi.getOngoingSchedules(page, size, type), - }); + useQuery( + sharedSchedulesQueryOptions.ongoing(page, size, type), + ); export const useFinishedQuery = (page: number, size: number, year: number) => - useQuery({ - queryKey: querykeys.finished(page, size, year), - queryFn: () => schedulesApi.getFinishedSchedules(page, size, year), - }); + useQuery( + sharedSchedulesQueryOptions.finished(page, size, year), + ); diff --git a/frontend/src/features/shared-schedule/api/queryOptions.ts b/frontend/src/features/shared-schedule/api/queryOptions.ts new file mode 100644 index 00000000..e6731061 --- /dev/null +++ b/frontend/src/features/shared-schedule/api/queryOptions.ts @@ -0,0 +1,18 @@ +import type { OngoingQueryType } from '../model'; +import { schedulesApi } from '.'; +import { querykeys } from './keys'; + +export const sharedSchedulesQueryOptions = { + upcoming: { + queryKey: querykeys.upcoming, + queryFn: () => schedulesApi.getUpcomingSchedules(), + }, + ongoing: (page: number, size: number, type: OngoingQueryType) => ({ + queryKey: querykeys.ongoing(page, size, type), + queryFn: () => schedulesApi.getOngoingSchedules(page, size, type), + }), + finished: (page: number, size: number, year: number) => ({ + queryKey: querykeys.finished(page, size, year), + queryFn: () => schedulesApi.getFinishedSchedules(page, size, year), + }), +}; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/index.tsx index bdb8d608..2b64065c 100644 --- a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/index.tsx @@ -1,4 +1,3 @@ -import { Link } from '@tanstack/react-router'; import type { PropsWithChildren } from 'react'; import { Flex } from '@/components/Flex'; From cfbc877ae6f0ccae3f91bfd4cb44399152801d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 00:57:29 +0900 Subject: [PATCH 05/25] =?UTF-8?q?feat:=20UpcomingSchedules=EC=97=90=20api?= =?UTF-8?q?=20=EC=97=B0=EA=B2=B0,=20homePage=EC=97=90=20prefetch=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/shared-schedule/api/index.ts | 2 +- .../src/features/shared-schedule/api/keys.ts | 4 +- .../features/shared-schedule/api/prefetch.ts | 17 ++++++ .../features/shared-schedule/api/queries.ts | 1 - .../shared-schedule/api/queryOptions.ts | 10 ++-- .../model/finishedSchedules.ts | 12 ++-- .../shared-schedule/model/ongoingSchedules.ts | 6 +- .../model/upcomingSchedules.ts | 6 +- .../ui/UpcomingSchedules/ScheduleCard.tsx | 58 +++++++++++++------ .../ui/UpcomingSchedules/UpcomingCarousel.tsx | 11 +++- .../ui/UpcomingSchedules/index.tsx | 14 +++-- .../ui/UpcomingSchedules/scheduleCard.css.ts | 4 +- frontend/src/pages/HomePage/index.tsx | 17 +++++- frontend/src/utils/date/date.ts | 41 +++++++++---- frontend/src/utils/date/format.ts | 13 ++++- 15 files changed, 154 insertions(+), 62 deletions(-) create mode 100644 frontend/src/features/shared-schedule/api/prefetch.ts diff --git a/frontend/src/features/shared-schedule/api/index.ts b/frontend/src/features/shared-schedule/api/index.ts index e8f024ca..18b14afe 100644 --- a/frontend/src/features/shared-schedule/api/index.ts +++ b/frontend/src/features/shared-schedule/api/index.ts @@ -46,4 +46,4 @@ export const schedulesApi = { const validData = FinishedSchedulesResponseSchema.parse(response.data); return validData; }, -}; \ No newline at end of file +}; diff --git a/frontend/src/features/shared-schedule/api/keys.ts b/frontend/src/features/shared-schedule/api/keys.ts index ff620294..485b161b 100644 --- a/frontend/src/features/shared-schedule/api/keys.ts +++ b/frontend/src/features/shared-schedule/api/keys.ts @@ -1,7 +1,7 @@ import type { OngoingQueryType } from '../model/finishedSchedules'; -export const querykeys = { +export const sharedScheduleQuerykeys = { upcoming: ['upcoming'], ongoing: (page: number, size: number, type: OngoingQueryType) => ['ongoing', page, size, type], finished: (page: number, size: number, year: number) => ['finished', page, size, year], -}; \ No newline at end of file +}; diff --git a/frontend/src/features/shared-schedule/api/prefetch.ts b/frontend/src/features/shared-schedule/api/prefetch.ts new file mode 100644 index 00000000..bfe2776a --- /dev/null +++ b/frontend/src/features/shared-schedule/api/prefetch.ts @@ -0,0 +1,17 @@ +import type { QueryClient } from '@tanstack/react-query'; + +import { sharedSchedulesQueryOptions } from './queryOptions'; + +export const prefetchUpcomingSchedules = async (queryClient: QueryClient) => { + await queryClient.prefetchQuery(sharedSchedulesQueryOptions.upcoming); +}; + +export const prefetchOngoingSchedules = async (queryClient: QueryClient) => { + await queryClient.prefetchQuery(sharedSchedulesQueryOptions.ongoing(1, 10, 'ALL')); +}; + +export const prefetchFinishedSchedules = async (queryClient: QueryClient) => { + await queryClient.prefetchQuery( + sharedSchedulesQueryOptions.finished(1, 10, new Date().getFullYear()), + ); +}; diff --git a/frontend/src/features/shared-schedule/api/queries.ts b/frontend/src/features/shared-schedule/api/queries.ts index 638aeaf0..f8fd63a7 100644 --- a/frontend/src/features/shared-schedule/api/queries.ts +++ b/frontend/src/features/shared-schedule/api/queries.ts @@ -18,4 +18,3 @@ export const useFinishedQuery = (page: number, size: number, year: number) => useQuery( sharedSchedulesQueryOptions.finished(page, size, year), ); - diff --git a/frontend/src/features/shared-schedule/api/queryOptions.ts b/frontend/src/features/shared-schedule/api/queryOptions.ts index e6731061..79e92948 100644 --- a/frontend/src/features/shared-schedule/api/queryOptions.ts +++ b/frontend/src/features/shared-schedule/api/queryOptions.ts @@ -1,18 +1,18 @@ import type { OngoingQueryType } from '../model'; import { schedulesApi } from '.'; -import { querykeys } from './keys'; +import { sharedScheduleQuerykeys } from './keys'; export const sharedSchedulesQueryOptions = { upcoming: { - queryKey: querykeys.upcoming, + queryKey: sharedScheduleQuerykeys.upcoming, queryFn: () => schedulesApi.getUpcomingSchedules(), }, ongoing: (page: number, size: number, type: OngoingQueryType) => ({ - queryKey: querykeys.ongoing(page, size, type), + queryKey: sharedScheduleQuerykeys.ongoing(page, size, type), queryFn: () => schedulesApi.getOngoingSchedules(page, size, type), }), finished: (page: number, size: number, year: number) => ({ - queryKey: querykeys.finished(page, size, year), + queryKey: sharedScheduleQuerykeys.finished(page, size, year), queryFn: () => schedulesApi.getFinishedSchedules(page, size, year), }), -}; \ No newline at end of file +}; diff --git a/frontend/src/features/shared-schedule/model/finishedSchedules.ts b/frontend/src/features/shared-schedule/model/finishedSchedules.ts index fcad230e..2f624205 100644 --- a/frontend/src/features/shared-schedule/model/finishedSchedules.ts +++ b/frontend/src/features/shared-schedule/model/finishedSchedules.ts @@ -2,17 +2,17 @@ import { z } from 'zod'; import { zCoerceToDate } from '@/utils/zod'; -const SharedEventDto = z.object({ +const SharedEventDtoSchema = z.object({ id: z.number(), startDateTime: zCoerceToDate, endDateTime: zCoerceToDate, }); -const FinishedDiscussion = z.object({ +const FinishedDiscussionSchema = z.object({ id: z.number(), title: z.string(), meetingMethodOrLocation: z.string(), - sharedEventDto: SharedEventDto, + sharedEventDto: SharedEventDtoSchema, participantPictureUrls: z.array(z.string()), }); @@ -22,12 +22,12 @@ export const FinishedSchedulesResponseSchema = z.object({ totalPages: z.number(), hasNext: z.boolean(), hasPrevious: z.boolean(), - finisnedDiscussions: z.array(FinishedDiscussion), + finisnedDiscussions: z.array(FinishedDiscussionSchema), }); export type OngoingQueryType = 'HOST' | 'ATTENDEE' | 'ALL'; export type MeetingMethod = 'ONLINE' | 'OFFLINE'; export type FinishedSchedulesResponse = z.infer; -export type FinisnedDiscussion = z.infer; -export type SharedEventDto = z.infer; +export type FinisnedDiscussion = z.infer; +export type SharedEventDto = z.infer; diff --git a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts index 0ca87529..61871347 100644 --- a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts +++ b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { zCoerceToDate } from '@/utils/zod'; -const OngoingDiscussion = z.object({ +const OngoingDiscussionSchema = z.object({ id: z.number(), title: z.string(), dateRangeStart: zCoerceToDate, @@ -16,8 +16,8 @@ export const OngoingSchedulesResponseSchema = z.object({ totalPages: z.number(), hasNext: z.boolean(), hasPrevious: z.boolean(), - ongoingDiscussions: z.array(OngoingDiscussion), + ongoingDiscussions: z.array(OngoingDiscussionSchema), }); export type OngoingSchedulesResponse = z.infer; -export type OngoingDiscussion = z.infer; +export type OngoingDiscussion = z.infer; diff --git a/frontend/src/features/shared-schedule/model/upcomingSchedules.ts b/frontend/src/features/shared-schedule/model/upcomingSchedules.ts index aaa993b7..2b190b42 100644 --- a/frontend/src/features/shared-schedule/model/upcomingSchedules.ts +++ b/frontend/src/features/shared-schedule/model/upcomingSchedules.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { zCoerceToDate } from '@/utils/zod'; -const Schedule = z.object({ +const UpcomingScheduleSchema = z.object({ id: z.number(), title: z.string(), startDateTime: zCoerceToDate, @@ -12,8 +12,8 @@ const Schedule = z.object({ }); export const UpcomingSchedulesResponseSchema = z.object({ - data: z.array(Schedule), + data: z.array(UpcomingScheduleSchema), }); -export type Schedule = z.infer; +export type UpcomingSchedule = z.infer; export type UpcomingSchedulesResponse = z.infer; diff --git a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/ScheduleCard.tsx b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/ScheduleCard.tsx index e323d2ea..88ecf2a5 100644 --- a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/ScheduleCard.tsx +++ b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/ScheduleCard.tsx @@ -4,33 +4,34 @@ import { Flex } from '@/components/Flex'; import { ChevronRight } from '@/components/Icon'; import { Text } from '@/components/Text'; import { vars } from '@/theme/index.css'; +import { getDateTimeRangeString } from '@/utils/date'; +import { formatDateToDdayString } from '@/utils/date/format'; +import type { UpcomingSchedule } from '../../model'; import { chevronButtonStyle, containerStyle } from './scheduleCard.css'; interface ScheduleCardProps { - selected: boolean; - // scheduleInfo: object; + schedule: UpcomingSchedule; + latest: boolean; } -const ScheduleCard = ({ selected }: ScheduleCardProps) => ( +const ScheduleCard = ({ schedule, latest }: ScheduleCardProps) => ( - - D-day - - 기업디(3) 첫 팀플 + + {schedule.title} - 12월 30일 오후 11시 ~ 오후 12시 - 강남역 4번 출구 + + + {schedule.meetingMethodOrLocation} + ( justify='space-between' width='full' > - - ); }; diff --git a/frontend/src/components/SegmentControl/index.tsx b/frontend/src/components/SegmentControl/index.tsx index 1299678f..d66844c4 100644 --- a/frontend/src/components/SegmentControl/index.tsx +++ b/frontend/src/components/SegmentControl/index.tsx @@ -7,8 +7,12 @@ import ControlButton from './ControlButton'; import { controlButtonContainerStyle } from './index.css'; import { SegmentControlContext } from './SegmentControlContext'; +export interface SegmentOption { + label: string; + value: string; +} export interface SegmentControlProps extends PropsWithChildren { - values: string[]; + segmentOptions: SegmentOption[]; style?: 'weak' | 'filled'; shadow?: boolean; defaultValue?: string; @@ -17,10 +21,10 @@ export interface SegmentControlProps extends PropsWithChildren { }; const SegmentControl = ({ - values, + segmentOptions, style = 'filled', shadow = true, - defaultValue = values[0] ?? '', + defaultValue = segmentOptions[0]?.value ?? '', onValueChange, children, className, @@ -40,11 +44,11 @@ const SegmentControl = ({ className={controlButtonContainerStyle({ style, shadow })} direction='row' > - {values.map((value, idx) => ( - ( + ))} From 3c4493fbfd4ea3e416191fa3fb375faa0aee2345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 01:46:56 +0900 Subject: [PATCH 07/25] feat: Refactor ongoing schedules and update related components --- .../SegmentControl/SegmentControl.stories.tsx | 21 +++++-- .../src/features/shared-schedule/api/index.ts | 8 ++- .../src/features/shared-schedule/api/keys.ts | 2 +- .../features/shared-schedule/api/queries.ts | 4 +- .../model/finishedSchedules.ts | 3 - .../features/shared-schedule/model/index.ts | 4 +- .../shared-schedule/model/ongoingSchedules.ts | 2 + .../ui/ExpiredSchedules/index.tsx | 37 ++++++------ .../OngoingSchedules/OngoingScheduleList.tsx | 57 +++++++++++++++++++ .../OngoingScheduleListItem.tsx} | 10 ++-- .../ScheduleDetails.css.ts | 0 .../ScheduleDetails.tsx | 0 .../index.css.ts | 0 .../ui/OngoingSchedules/index.tsx | 43 ++++++++++++++ .../ongoingScheduleList.css.ts} | 0 .../ongoingScheduleListItem.css.ts} | 0 .../UnconfirmedScheduleList.tsx | 45 --------------- .../ui/UnConfirmedSchedules/index.tsx | 31 ---------- frontend/src/pages/HomePage/index.tsx | 2 +- .../src/pages/UpcomingSchedulePage/index.tsx | 3 +- 20 files changed, 153 insertions(+), 119 deletions(-) create mode 100644 frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx rename frontend/src/features/shared-schedule/ui/{UnConfirmedSchedules/UnconfirmedScheduleListItem.tsx => OngoingSchedules/OngoingScheduleListItem.tsx} (85%) rename frontend/src/features/shared-schedule/ui/{UnConfirmedSchedules => OngoingSchedules}/ScheduleDetails.css.ts (100%) rename frontend/src/features/shared-schedule/ui/{UnConfirmedSchedules => OngoingSchedules}/ScheduleDetails.tsx (100%) rename frontend/src/features/shared-schedule/ui/{UnConfirmedSchedules => OngoingSchedules}/index.css.ts (100%) create mode 100644 frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx rename frontend/src/features/shared-schedule/ui/{UnConfirmedSchedules/unconfirmedScheduleList.css.ts => OngoingSchedules/ongoingScheduleList.css.ts} (100%) rename frontend/src/features/shared-schedule/ui/{UnConfirmedSchedules/unconfirmedscheduleListItem.css.ts => OngoingSchedules/ongoingScheduleListItem.css.ts} (100%) delete mode 100644 frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/UnconfirmedScheduleList.tsx delete mode 100644 frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/index.tsx diff --git a/frontend/src/components/SegmentControl/SegmentControl.stories.tsx b/frontend/src/components/SegmentControl/SegmentControl.stories.tsx index 33de26f2..c2eb7685 100644 --- a/frontend/src/components/SegmentControl/SegmentControl.stories.tsx +++ b/frontend/src/components/SegmentControl/SegmentControl.stories.tsx @@ -19,15 +19,26 @@ export default meta; export const Default: StoryObj = { args: { - values: ['라벨1', '라벨2', '라벨3'], + segmentOptions: [ + { label: '라벨1', value: 'value1' }, + { label: '라벨2', value: 'value2' }, + { label: '라벨3', value: 'value3' }, + ], defaultValue: '라벨1', }, }; export const WithContent = () => ( - - 컨텐츠1 - 컨텐츠2 - 컨텐츠3 + + 컨텐츠1 + 컨텐츠2 + 컨텐츠3 ); \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/api/index.ts b/frontend/src/features/shared-schedule/api/index.ts index 18b14afe..3400617f 100644 --- a/frontend/src/features/shared-schedule/api/index.ts +++ b/frontend/src/features/shared-schedule/api/index.ts @@ -1,12 +1,16 @@ import { request } from '@/utils/fetch'; -import type { OngoingSchedulesResponse, UpcomingSchedulesResponse } from '../model'; +import type { + OngoingQueryType, + OngoingSchedulesResponse, + UpcomingSchedulesResponse, +} from '../model'; import { FinishedSchedulesResponseSchema, OngoingSchedulesResponseSchema, UpcomingSchedulesResponseSchema, } from '../model'; -import type { FinishedSchedulesResponse, OngoingQueryType } from '../model/finishedSchedules'; +import type { FinishedSchedulesResponse } from '../model/finishedSchedules'; const ENDPOINT_PREFIX = '/api/v1/schedules'; diff --git a/frontend/src/features/shared-schedule/api/keys.ts b/frontend/src/features/shared-schedule/api/keys.ts index 485b161b..f26a4d8b 100644 --- a/frontend/src/features/shared-schedule/api/keys.ts +++ b/frontend/src/features/shared-schedule/api/keys.ts @@ -1,4 +1,4 @@ -import type { OngoingQueryType } from '../model/finishedSchedules'; +import type { OngoingQueryType } from '../model'; export const sharedScheduleQuerykeys = { upcoming: ['upcoming'], diff --git a/frontend/src/features/shared-schedule/api/queries.ts b/frontend/src/features/shared-schedule/api/queries.ts index f8fd63a7..20a743fe 100644 --- a/frontend/src/features/shared-schedule/api/queries.ts +++ b/frontend/src/features/shared-schedule/api/queries.ts @@ -1,8 +1,8 @@ import { useQuery } from '@tanstack/react-query'; import type { UpcomingSchedulesResponse } from '../model'; -import type { FinishedSchedulesResponse, OngoingQueryType } from '../model/finishedSchedules'; -import type { OngoingSchedulesResponse } from '../model/ongoingSchedules'; +import type { FinishedSchedulesResponse } from '../model/finishedSchedules'; +import type { OngoingQueryType, OngoingSchedulesResponse } from '../model/ongoingSchedules'; import { sharedSchedulesQueryOptions } from './queryOptions'; export const useUpcomingQuery = () => useQuery( diff --git a/frontend/src/features/shared-schedule/model/finishedSchedules.ts b/frontend/src/features/shared-schedule/model/finishedSchedules.ts index 2f624205..db981f99 100644 --- a/frontend/src/features/shared-schedule/model/finishedSchedules.ts +++ b/frontend/src/features/shared-schedule/model/finishedSchedules.ts @@ -25,9 +25,6 @@ export const FinishedSchedulesResponseSchema = z.object({ finisnedDiscussions: z.array(FinishedDiscussionSchema), }); -export type OngoingQueryType = 'HOST' | 'ATTENDEE' | 'ALL'; -export type MeetingMethod = 'ONLINE' | 'OFFLINE'; - export type FinishedSchedulesResponse = z.infer; export type FinisnedDiscussion = z.infer; export type SharedEventDto = z.infer; diff --git a/frontend/src/features/shared-schedule/model/index.ts b/frontend/src/features/shared-schedule/model/index.ts index bbf1e441..3d755cf3 100644 --- a/frontend/src/features/shared-schedule/model/index.ts +++ b/frontend/src/features/shared-schedule/model/index.ts @@ -1,3 +1,5 @@ export * from './finishedSchedules'; export * from './ongoingSchedules'; -export * from './upcomingSchedules'; \ No newline at end of file +export * from './upcomingSchedules'; + +export type MeetingMethod = 'ONLINE' | 'OFFLINE'; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts index 61871347..bcd8649e 100644 --- a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts +++ b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts @@ -19,5 +19,7 @@ export const OngoingSchedulesResponseSchema = z.object({ ongoingDiscussions: z.array(OngoingDiscussionSchema), }); +export type OngoingQueryType = 'HOST' | 'ATTENDEE' | 'ALL'; + export type OngoingSchedulesResponse = z.infer; export type OngoingDiscussion = z.infer; diff --git a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.tsx index 4891f570..1111045a 100644 --- a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.tsx @@ -3,28 +3,23 @@ import { ChevronLeft, ChevronRight } from '@/components/Icon'; import { Text } from '@/components/Text'; import { vars } from '@/theme/index.css'; -import UnconfirmedScheduleList from '../UnConfirmedSchedules/UnconfirmedScheduleList'; - -const ExpiredSchedules = () => { - const schedules = [{}, {}, {}]; - return ( - - - 지난 일정 - - - 2024년 - - +const ExpiredSchedules = () => ( + + + 지난 일정 + + + 2024년 + - - ); -}; + {/* */} + +); export default ExpiredSchedules; diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx new file mode 100644 index 00000000..f1f3d529 --- /dev/null +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx @@ -0,0 +1,57 @@ + +import { useState } from 'react'; + +import { Flex } from '@/components/Flex'; +import Pagination from '@/components/Pagination'; + +import { useOngoingQuery } from '../../api/queries'; +import type { OngoingSegmentOption } from '.'; +import { paginationStyle } from './ongoingScheduleList.css'; +import OngoingScheduleListItem from './OngoingScheduleListItem'; + +const PAGE_SIZE = 6; + +interface OngoingScheduleListProps { + segmentOption: OngoingSegmentOption; +} + +const OngoingScheduleList = ({ segmentOption }: OngoingScheduleListProps) => { + const [page, setPage] = useState(1); + const { data, isPending } = useOngoingQuery(page, PAGE_SIZE, segmentOption.value); + if (isPending) return
pending...
; + if (!data) return
No data available
; + const schedules = data.ongoingDiscussions; + + return ( + + + {schedules.map((schedule, index) => ( + ))} + + setPage(page)} + totalPages={data.totalPages} + /> + + ); +}; + +OngoingScheduleList.Item = OngoingScheduleListItem; + +export default OngoingScheduleList; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/UnconfirmedScheduleListItem.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleListItem.tsx similarity index 85% rename from frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/UnconfirmedScheduleListItem.tsx rename to frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleListItem.tsx index 8ec4305c..7778a827 100644 --- a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/UnconfirmedScheduleListItem.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleListItem.tsx @@ -7,9 +7,9 @@ import { detailsContainerStyle, scheduleItemContainerStyle, updateIndicatorStyle, -} from './unconfirmedscheduleListItem.css'; +} from './ongoingScheduleListItem.css'; -interface UnconfirmedScheduleListItemProps { +interface OngoingScheduleListItemProps { scheduleTitle: string; participantImageUrls: string[]; selected: boolean; @@ -18,12 +18,12 @@ interface UnconfirmedScheduleListItemProps { onClick?: () => void; } -const UnconfimredScheduleListItem = ({ +const OngoingScheduleListItem = ({ scheduleTitle, participantImageUrls, selected, isUpdated = false, -}: UnconfirmedScheduleListItemProps) => ( +}: OngoingScheduleListItemProps) => ( ); -export default UnconfimredScheduleListItem; \ No newline at end of file +export default OngoingScheduleListItem; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/ScheduleDetails.css.ts b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.css.ts similarity index 100% rename from frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/ScheduleDetails.css.ts rename to frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.css.ts diff --git a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/ScheduleDetails.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx similarity index 100% rename from frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/ScheduleDetails.tsx rename to frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx diff --git a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/index.css.ts b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.css.ts similarity index 100% rename from frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/index.css.ts rename to frontend/src/features/shared-schedule/ui/OngoingSchedules/index.css.ts diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx new file mode 100644 index 00000000..fb0177d1 --- /dev/null +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx @@ -0,0 +1,43 @@ + +import { Flex } from '@/components/Flex'; +import SegmentControl from '@/components/SegmentControl'; +import { Text } from '@/components/Text'; + +import type { OngoingQueryType } from '../../model'; +import { containerStyle, mainContainerStyle, titleStyle } from './index.css'; +import OngoingScheduleList from './OngoingScheduleList'; +import ScheduleContents from './ScheduleDetails'; + +export interface OngoingSegmentOption { + label: string; + value: OngoingQueryType; +} + +const segmentOptions: OngoingSegmentOption[] = [ + { label: '모든 일정', value: 'ALL' }, + { label: '내가 만든 일정', value: 'HOST' }, + { label: '공유 받은 일정', value: 'ATTENDEE' }, +]; + +const UnConfirmedSchedules = () => ( + + 확정되지 않은 일정 + + {segmentOptions.map((option, idx) => ( +
+ + + + +
+ ))} +
+
+); + +export default UnConfirmedSchedules; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/unconfirmedScheduleList.css.ts b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ongoingScheduleList.css.ts similarity index 100% rename from frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/unconfirmedScheduleList.css.ts rename to frontend/src/features/shared-schedule/ui/OngoingSchedules/ongoingScheduleList.css.ts diff --git a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/unconfirmedscheduleListItem.css.ts b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ongoingScheduleListItem.css.ts similarity index 100% rename from frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/unconfirmedscheduleListItem.css.ts rename to frontend/src/features/shared-schedule/ui/OngoingSchedules/ongoingScheduleListItem.css.ts diff --git a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/UnconfirmedScheduleList.tsx b/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/UnconfirmedScheduleList.tsx deleted file mode 100644 index dd1e1ca6..00000000 --- a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/UnconfirmedScheduleList.tsx +++ /dev/null @@ -1,45 +0,0 @@ - -import type { PropsWithChildren } from 'react'; - -import { Flex } from '@/components/Flex'; -import Pagination from '@/components/Pagination'; - -import { paginationStyle } from './unconfirmedScheduleList.css'; -import UnconfimredScheduleListItem from './UnconfirmedScheduleListItem'; - -interface UnconfirmedScheduleListProps extends PropsWithChildren { - schedules: object[]; -} - -const UnconfirmedScheduleList = ({ schedules }: UnconfirmedScheduleListProps) => ( - - - {schedules.map((_, index) => ( - ))} - - { /**/ }} - totalPages={5} - /> - -); - -UnconfirmedScheduleList.Item = UnconfimredScheduleListItem; - -export default UnconfirmedScheduleList; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/index.tsx deleted file mode 100644 index e5423876..00000000 --- a/frontend/src/features/shared-schedule/ui/UnConfirmedSchedules/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ - -import { Flex } from '@/components/Flex'; -import SegmentControl from '@/components/SegmentControl'; -import { Text } from '@/components/Text'; - -import { containerStyle, mainContainerStyle, titleStyle } from './index.css'; -import ScheduleContents from './ScheduleDetails'; -import UnconfirmedScheduleList from './UnconfirmedScheduleList'; - -const segmentValues = ['모든 일정', '내가 만든 일정', '공유 받은 일정']; -const UnConfirmedSchedules = () => { - const schedules = [{}, {}, {}]; - - return ( - - 확정되지 않은 일정 - -
- - -
-
- ); -}; - -export default UnConfirmedSchedules; \ No newline at end of file diff --git a/frontend/src/pages/HomePage/index.tsx b/frontend/src/pages/HomePage/index.tsx index 2526d795..53ea8709 100644 --- a/frontend/src/pages/HomePage/index.tsx +++ b/frontend/src/pages/HomePage/index.tsx @@ -10,7 +10,7 @@ import { prefetchUpcomingSchedules, } from '@/features/shared-schedule/api/prefetch'; import ExpiredSchedules from '@/features/shared-schedule/ui/ExpiredSchedules'; -import UnConfirmedSchedules from '@/features/shared-schedule/ui/UnConfirmedSchedules'; +import UnConfirmedSchedules from '@/features/shared-schedule/ui/OngoingSchedules'; import UpcomingSchedules from '@/features/shared-schedule/ui/UpcomingSchedules'; import { containerStyle } from './index.css'; diff --git a/frontend/src/pages/UpcomingSchedulePage/index.tsx b/frontend/src/pages/UpcomingSchedulePage/index.tsx index 983d8308..2d0a306a 100644 --- a/frontend/src/pages/UpcomingSchedulePage/index.tsx +++ b/frontend/src/pages/UpcomingSchedulePage/index.tsx @@ -14,9 +14,8 @@ const UpcomingSchedulePage = () => { direction='column' gap={700} > - + 다가오는 일정 -
From dd9c47cc3b595970c75c0c4112295616cc6984cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 01:52:04 +0900 Subject: [PATCH 08/25] =?UTF-8?q?chore:=20Expired=20Schedule=20->=20Finish?= =?UTF-8?q?ed=20Schedule=EB=A1=9C=20=EB=AA=85=EC=B9=AD=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/shared-schedule/ui/ExpiredSchedules/index.css.ts | 0 .../FinishedScheduleList.tsx} | 4 ++-- .../FinishedScheduleListItem.tsx} | 2 +- .../finishedScheduleList.css.ts} | 0 .../finishedScheduleListItem.css.ts} | 0 .../ui/{ExpiredSchedules => FinishedSchedules}/index.tsx | 4 ++-- frontend/src/pages/HomePage/index.tsx | 4 ++-- 7 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.css.ts rename frontend/src/features/shared-schedule/ui/{ExpiredSchedules/ExpiredScheduleList.tsx => FinishedSchedules/FinishedScheduleList.tsx} (88%) rename frontend/src/features/shared-schedule/ui/{ExpiredSchedules/ExpiredScheduleListItem.tsx => FinishedSchedules/FinishedScheduleListItem.tsx} (97%) rename frontend/src/features/shared-schedule/ui/{ExpiredSchedules/expiredScheduleList.css.ts => FinishedSchedules/finishedScheduleList.css.ts} (100%) rename frontend/src/features/shared-schedule/ui/{ExpiredSchedules/expiredScheduleListItem.css.ts => FinishedSchedules/finishedScheduleListItem.css.ts} (100%) rename frontend/src/features/shared-schedule/ui/{ExpiredSchedules => FinishedSchedules}/index.tsx (91%) diff --git a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.css.ts b/frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.css.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/ExpiredScheduleList.tsx b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx similarity index 88% rename from frontend/src/features/shared-schedule/ui/ExpiredSchedules/ExpiredScheduleList.tsx rename to frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx index e8241f48..3f4770e1 100644 --- a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/ExpiredScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx @@ -4,8 +4,8 @@ import type { PropsWithChildren } from 'react'; import { Flex } from '@/components/Flex'; import Pagination from '@/components/Pagination'; -import { paginationStyle } from './expiredScheduleList.css'; -import ExpiredScheduleListItem from './ExpiredScheduleListItem'; +import { paginationStyle } from './finishedScheduleList.css'; +import ExpiredScheduleListItem from './FinishedScheduleListItem'; interface ScheduleListProps extends PropsWithChildren { schedules: object[]; diff --git a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/ExpiredScheduleListItem.tsx b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleListItem.tsx similarity index 97% rename from frontend/src/features/shared-schedule/ui/ExpiredSchedules/ExpiredScheduleListItem.tsx rename to frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleListItem.tsx index 36188266..2ec5fe95 100644 --- a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/ExpiredScheduleListItem.tsx +++ b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleListItem.tsx @@ -8,7 +8,7 @@ import { detailsContainerStyle, dotStyle, scheduleItemContainerStyle, -} from './expiredScheduleListItem.css'; +} from './finishedScheduleListItem.css'; interface ExpiredScheduleListItemProps { scheduleTitle: string; diff --git a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/expiredScheduleList.css.ts b/frontend/src/features/shared-schedule/ui/FinishedSchedules/finishedScheduleList.css.ts similarity index 100% rename from frontend/src/features/shared-schedule/ui/ExpiredSchedules/expiredScheduleList.css.ts rename to frontend/src/features/shared-schedule/ui/FinishedSchedules/finishedScheduleList.css.ts diff --git a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/expiredScheduleListItem.css.ts b/frontend/src/features/shared-schedule/ui/FinishedSchedules/finishedScheduleListItem.css.ts similarity index 100% rename from frontend/src/features/shared-schedule/ui/ExpiredSchedules/expiredScheduleListItem.css.ts rename to frontend/src/features/shared-schedule/ui/FinishedSchedules/finishedScheduleListItem.css.ts diff --git a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/FinishedSchedules/index.tsx similarity index 91% rename from frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.tsx rename to frontend/src/features/shared-schedule/ui/FinishedSchedules/index.tsx index 1111045a..c65ff253 100644 --- a/frontend/src/features/shared-schedule/ui/ExpiredSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/FinishedSchedules/index.tsx @@ -3,7 +3,7 @@ import { ChevronLeft, ChevronRight } from '@/components/Icon'; import { Text } from '@/components/Text'; import { vars } from '@/theme/index.css'; -const ExpiredSchedules = () => ( +const FinishedSchedules = () => ( ( ); -export default ExpiredSchedules; +export default FinishedSchedules; diff --git a/frontend/src/pages/HomePage/index.tsx b/frontend/src/pages/HomePage/index.tsx index 53ea8709..4fd1a1b7 100644 --- a/frontend/src/pages/HomePage/index.tsx +++ b/frontend/src/pages/HomePage/index.tsx @@ -9,7 +9,7 @@ import { prefetchOngoingSchedules, prefetchUpcomingSchedules, } from '@/features/shared-schedule/api/prefetch'; -import ExpiredSchedules from '@/features/shared-schedule/ui/ExpiredSchedules'; +import FinishedSchedules from '@/features/shared-schedule/ui/FinishedSchedules'; import UnConfirmedSchedules from '@/features/shared-schedule/ui/OngoingSchedules'; import UpcomingSchedules from '@/features/shared-schedule/ui/UpcomingSchedules'; @@ -37,7 +37,7 @@ const HomePage = () => { - + ); }; From c8c29846ad9cd03a5cb9cdd21e03c24fe0b558a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 10:23:21 +0900 Subject: [PATCH 09/25] =?UTF-8?q?feat:=20usePagination=20=ED=9B=85=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SegmentControl/SegmentControl.stories.tsx | 4 ++-- frontend/src/hooks/usePagination.ts | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 frontend/src/hooks/usePagination.ts diff --git a/frontend/src/components/SegmentControl/SegmentControl.stories.tsx b/frontend/src/components/SegmentControl/SegmentControl.stories.tsx index c2eb7685..72d98310 100644 --- a/frontend/src/components/SegmentControl/SegmentControl.stories.tsx +++ b/frontend/src/components/SegmentControl/SegmentControl.stories.tsx @@ -24,13 +24,13 @@ export const Default: StoryObj = { { label: '라벨2', value: 'value2' }, { label: '라벨3', value: 'value3' }, ], - defaultValue: '라벨1', + defaultValue: 'value1', }, }; export const WithContent = () => ( { + const [currentPage, setCurrentPage] = useState(initialPage); + const onPageChange = (page: number) => { + setCurrentPage(page); + }; + + return { + currentPage, + onPageChange, + totalPages, + }; +}; From 1d64b5cb47b06f7f6586e9e0cba61523e6bf0b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 14:39:50 +0900 Subject: [PATCH 10/25] feat: update SegmentControl to accept className prop and refactor ongoing schedules API types --- .../src/components/SegmentControl/index.tsx | 1 + .../src/features/shared-schedule/api/index.ts | 12 +++++----- .../src/features/shared-schedule/api/keys.ts | 4 ++-- .../features/shared-schedule/api/queries.ts | 7 +++--- .../shared-schedule/api/queryOptions.ts | 8 +++---- .../shared-schedule/model/ongoingSchedules.ts | 2 +- .../ui/OngoingSchedules/index.css.ts | 5 ++++ .../ui/OngoingSchedules/index.tsx | 24 +++++++++++-------- frontend/src/pages/HomePage/index.tsx | 16 ++++++------- 9 files changed, 44 insertions(+), 35 deletions(-) diff --git a/frontend/src/components/SegmentControl/index.tsx b/frontend/src/components/SegmentControl/index.tsx index d66844c4..69f06230 100644 --- a/frontend/src/components/SegmentControl/index.tsx +++ b/frontend/src/components/SegmentControl/index.tsx @@ -26,6 +26,7 @@ const SegmentControl = ({ shadow = true, defaultValue = segmentOptions[0]?.value ?? '', onValueChange, + className, children, className, }: SegmentControlProps) => { diff --git a/frontend/src/features/shared-schedule/api/index.ts b/frontend/src/features/shared-schedule/api/index.ts index 3400617f..052e3504 100644 --- a/frontend/src/features/shared-schedule/api/index.ts +++ b/frontend/src/features/shared-schedule/api/index.ts @@ -1,7 +1,7 @@ import { request } from '@/utils/fetch'; import type { - OngoingQueryType, + AttendType, OngoingSchedulesResponse, UpcomingSchedulesResponse, } from '../model'; @@ -17,22 +17,22 @@ const ENDPOINT_PREFIX = '/api/v1/schedules'; export const schedulesApi = { getUpcomingSchedules: async (): Promise => { const response = await request.get(ENDPOINT_PREFIX + '/upcoming'); - const validData = UpcomingSchedulesResponseSchema.parse(response.data); + const validData = UpcomingSchedulesResponseSchema.parse(response); return validData; }, getOngoingSchedules: async ( page: number, size: number, - type: OngoingQueryType, + attendType: AttendType, ): Promise => { const response = await request.get(ENDPOINT_PREFIX + '/ongoing', { params: { page: page.toString(), size: size.toString(), - type: type, + attendType: attendType, }, }); - const validData = OngoingSchedulesResponseSchema.parse(response.data); + const validData = OngoingSchedulesResponseSchema.parse(response); return validData; }, getFinishedSchedules: async ( @@ -47,7 +47,7 @@ export const schedulesApi = { year: year.toString(), }, }); - const validData = FinishedSchedulesResponseSchema.parse(response.data); + const validData = FinishedSchedulesResponseSchema.parse(response); return validData; }, }; diff --git a/frontend/src/features/shared-schedule/api/keys.ts b/frontend/src/features/shared-schedule/api/keys.ts index f26a4d8b..8c5a87c0 100644 --- a/frontend/src/features/shared-schedule/api/keys.ts +++ b/frontend/src/features/shared-schedule/api/keys.ts @@ -1,7 +1,7 @@ -import type { OngoingQueryType } from '../model'; +import type { AttendType } from '../model'; export const sharedScheduleQuerykeys = { upcoming: ['upcoming'], - ongoing: (page: number, size: number, type: OngoingQueryType) => ['ongoing', page, size, type], + ongoing: (page: number, size: number, type: AttendType) => ['ongoing', page, size, type], finished: (page: number, size: number, year: number) => ['finished', page, size, year], }; diff --git a/frontend/src/features/shared-schedule/api/queries.ts b/frontend/src/features/shared-schedule/api/queries.ts index 20a743fe..3c3f1c26 100644 --- a/frontend/src/features/shared-schedule/api/queries.ts +++ b/frontend/src/features/shared-schedule/api/queries.ts @@ -1,15 +1,14 @@ import { useQuery } from '@tanstack/react-query'; -import type { UpcomingSchedulesResponse } from '../model'; -import type { FinishedSchedulesResponse } from '../model/finishedSchedules'; -import type { OngoingQueryType, OngoingSchedulesResponse } from '../model/ongoingSchedules'; +import type { FinishedSchedulesResponse, UpcomingSchedulesResponse } from '../model'; +import type { AttendType, OngoingSchedulesResponse } from '../model/ongoingSchedules'; import { sharedSchedulesQueryOptions } from './queryOptions'; export const useUpcomingQuery = () => useQuery( sharedSchedulesQueryOptions.upcoming, ); -export const useOngoingQuery = (page: number, size: number, type: OngoingQueryType) => +export const useOngoingQuery = (page: number, size: number, type: AttendType) => useQuery( sharedSchedulesQueryOptions.ongoing(page, size, type), ); diff --git a/frontend/src/features/shared-schedule/api/queryOptions.ts b/frontend/src/features/shared-schedule/api/queryOptions.ts index 79e92948..482e87b7 100644 --- a/frontend/src/features/shared-schedule/api/queryOptions.ts +++ b/frontend/src/features/shared-schedule/api/queryOptions.ts @@ -1,4 +1,4 @@ -import type { OngoingQueryType } from '../model'; +import type { AttendType } from '../model'; import { schedulesApi } from '.'; import { sharedScheduleQuerykeys } from './keys'; @@ -7,9 +7,9 @@ export const sharedSchedulesQueryOptions = { queryKey: sharedScheduleQuerykeys.upcoming, queryFn: () => schedulesApi.getUpcomingSchedules(), }, - ongoing: (page: number, size: number, type: OngoingQueryType) => ({ - queryKey: sharedScheduleQuerykeys.ongoing(page, size, type), - queryFn: () => schedulesApi.getOngoingSchedules(page, size, type), + ongoing: (page: number, size: number, attendtype: AttendType) => ({ + queryKey: sharedScheduleQuerykeys.ongoing(page, size, attendtype), + queryFn: () => schedulesApi.getOngoingSchedules(page, size, attendtype), }), finished: (page: number, size: number, year: number) => ({ queryKey: sharedScheduleQuerykeys.finished(page, size, year), diff --git a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts index bcd8649e..357ddfa9 100644 --- a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts +++ b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts @@ -19,7 +19,7 @@ export const OngoingSchedulesResponseSchema = z.object({ ongoingDiscussions: z.array(OngoingDiscussionSchema), }); -export type OngoingQueryType = 'HOST' | 'ATTENDEE' | 'ALL'; +export type AttendType = 'HOST' | 'ATTENDEE' | 'ALL'; export type OngoingSchedulesResponse = z.infer; export type OngoingDiscussion = z.infer; diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.css.ts b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.css.ts index 91bd6871..3f15da2d 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.css.ts +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.css.ts @@ -10,9 +10,14 @@ export const titleStyle = style({ paddingBottom: vars.spacing[700], }); +export const segmentControlStyle = style({ + width: '100%', +}); + export const mainContainerStyle = style({ width: '100%', display: 'flex', + justifyContent: 'space-between', flexDirection: 'row', gap: 44, paddingTop: vars.spacing[800], diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx index fb0177d1..248cd5e6 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx @@ -3,14 +3,14 @@ import { Flex } from '@/components/Flex'; import SegmentControl from '@/components/SegmentControl'; import { Text } from '@/components/Text'; -import type { OngoingQueryType } from '../../model'; -import { containerStyle, mainContainerStyle, titleStyle } from './index.css'; +import type { AttendType } from '../../model/'; +import { containerStyle, mainContainerStyle, segmentControlStyle, titleStyle } from './index.css'; import OngoingScheduleList from './OngoingScheduleList'; import ScheduleContents from './ScheduleDetails'; export interface OngoingSegmentOption { label: string; - value: OngoingQueryType; + value: AttendType; } const segmentOptions: OngoingSegmentOption[] = [ @@ -19,7 +19,7 @@ const segmentOptions: OngoingSegmentOption[] = [ { label: '공유 받은 일정', value: 'ATTENDEE' }, ]; -const UnConfirmedSchedules = () => ( +const OngoingSchedules = () => ( ( width='full' > 확정되지 않은 일정 - + {segmentOptions.map((option, idx) => ( -
- + +
- -
+
+ ))}
); -export default UnConfirmedSchedules; \ No newline at end of file +export default OngoingSchedules; \ No newline at end of file diff --git a/frontend/src/pages/HomePage/index.tsx b/frontend/src/pages/HomePage/index.tsx index 4fd1a1b7..4cbd0049 100644 --- a/frontend/src/pages/HomePage/index.tsx +++ b/frontend/src/pages/HomePage/index.tsx @@ -10,7 +10,7 @@ import { prefetchUpcomingSchedules, } from '@/features/shared-schedule/api/prefetch'; import FinishedSchedules from '@/features/shared-schedule/ui/FinishedSchedules'; -import UnConfirmedSchedules from '@/features/shared-schedule/ui/OngoingSchedules'; +import OngoingSchedules from '@/features/shared-schedule/ui/OngoingSchedules'; import UpcomingSchedules from '@/features/shared-schedule/ui/UpcomingSchedules'; import { containerStyle } from './index.css'; @@ -20,14 +20,14 @@ const HomePage = () => { const queryClient = useQueryClient(); useEffect(() => { - prefetchUpcomingSchedules(queryClient); + // prefetchUpcomingSchedules(queryClient); prefetchOngoingSchedules(queryClient); - prefetchFinishedSchedules(queryClient); - }); + // prefetchFinishedSchedules(queryClient); + }, [queryClient]); return (
- + {/* 다가오는 일정 - - - + */} + + {/* */}
); }; From 761b069312bdb64598ce3f97165cc99881a7dd8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 15:18:46 +0900 Subject: [PATCH 11/25] =?UTF-8?q?feat:=20FinishedSchedule=20api=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/finishedSchedules.ts | 8 +-- .../FinishedScheduleList.tsx | 72 ++++++++++--------- .../FinishedScheduleListItem.tsx | 8 +-- .../ui/FinishedSchedules/index.tsx | 50 ++++++++----- .../ui/OngoingSchedules/ScheduleDetails.tsx | 54 ++++++++------ .../ui/OngoingSchedules/index.tsx | 4 +- frontend/src/pages/HomePage/index.tsx | 6 +- frontend/src/utils/date/date.ts | 6 ++ frontend/src/utils/date/format.ts | 6 +- 9 files changed, 127 insertions(+), 87 deletions(-) diff --git a/frontend/src/features/shared-schedule/model/finishedSchedules.ts b/frontend/src/features/shared-schedule/model/finishedSchedules.ts index db981f99..1f9bc8cd 100644 --- a/frontend/src/features/shared-schedule/model/finishedSchedules.ts +++ b/frontend/src/features/shared-schedule/model/finishedSchedules.ts @@ -8,7 +8,7 @@ const SharedEventDtoSchema = z.object({ endDateTime: zCoerceToDate, }); -const FinishedDiscussionSchema = z.object({ +const FinishedScheduleSchema = z.object({ id: z.number(), title: z.string(), meetingMethodOrLocation: z.string(), @@ -17,14 +17,14 @@ const FinishedDiscussionSchema = z.object({ }); export const FinishedSchedulesResponseSchema = z.object({ - currentYear: z.number(), currentPage: z.number(), + currentYear: z.number(), totalPages: z.number(), hasNext: z.boolean(), hasPrevious: z.boolean(), - finisnedDiscussions: z.array(FinishedDiscussionSchema), + finishedDiscussions: z.array(FinishedScheduleSchema), }); export type FinishedSchedulesResponse = z.infer; -export type FinisnedDiscussion = z.infer; +export type FinishedSchedule = z.infer; export type SharedEventDto = z.infer; diff --git a/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx index 3f4770e1..8a1b73da 100644 --- a/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx @@ -1,46 +1,54 @@ -import type { PropsWithChildren } from 'react'; +import { useState } from 'react'; import { Flex } from '@/components/Flex'; import Pagination from '@/components/Pagination'; +import { useFinishedQuery } from '../../api/queries'; import { paginationStyle } from './finishedScheduleList.css'; -import ExpiredScheduleListItem from './FinishedScheduleListItem'; +import FinishedScheduleListItem from './FinishedScheduleListItem'; -interface ScheduleListProps extends PropsWithChildren { - schedules: object[]; +const PAGE_SIZE = 7; + +interface FinishedScheduleListProps { + baseYear: number; } -const ScheduleList = ({ schedules }: ScheduleListProps) => ( - +const FinishedScheduleList = ({ baseYear }: FinishedScheduleListProps) => { + const [currentPage, setCurrentPage] = useState(1); + const { data, isPending } = useFinishedQuery(currentPage, PAGE_SIZE, baseYear); + if (isPending) return
pending...
; + if (!data) return
No data available
; + + return ( - {schedules.map((_, index) => ( - ))} + + {data.finishedDiscussions.map((schedule) => ( + ))} + + setCurrentPage(page)} + totalPages={data.totalPages} + /> - { /**/ }} - totalPages={5} - /> -
-); - -ScheduleList.Item = ExpiredScheduleListItem; - -export default ScheduleList; \ No newline at end of file + ); +}; + +export default FinishedScheduleList; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleListItem.tsx b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleListItem.tsx index 2ec5fe95..7119b2ab 100644 --- a/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleListItem.tsx +++ b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleListItem.tsx @@ -10,7 +10,7 @@ import { scheduleItemContainerStyle, } from './finishedScheduleListItem.css'; -interface ExpiredScheduleListItemProps { +interface FinishedScheduleListItemProps { scheduleTitle: string; participantImageUrls: string[]; meetingPlace?: string; @@ -19,13 +19,13 @@ interface ExpiredScheduleListItemProps { onClick?: () => void; } -const ExpiredScheduleListItem = ({ +const FinishedScheduleListItem = ({ scheduleTitle, participantImageUrls, meetingPlace, startDate, endDate, -}: ExpiredScheduleListItemProps) => ( +}: FinishedScheduleListItemProps) => ( ); -export default ExpiredScheduleListItem; \ No newline at end of file +export default FinishedScheduleListItem; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/FinishedSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/FinishedSchedules/index.tsx index c65ff253..65a4d85f 100644 --- a/frontend/src/features/shared-schedule/ui/FinishedSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/FinishedSchedules/index.tsx @@ -1,25 +1,43 @@ +import { useState } from 'react'; + import { Flex } from '@/components/Flex'; import { ChevronLeft, ChevronRight } from '@/components/Icon'; import { Text } from '@/components/Text'; import { vars } from '@/theme/index.css'; -const FinishedSchedules = () => ( - - - 지난 일정 - - - 2024년 - +import FinishedScheduleList from './FinishedScheduleList'; + +const FinishedSchedules = () => { + const [currentYear, setCurrentYear] = useState(new Date().getFullYear()); + return ( + + + 지난 일정 + + {/* TODO: 연도 validation */} + setCurrentYear(currentYear - 1)} + /> + + {`${currentYear}년`} + + setCurrentYear(currentYear + 1)} + /> + + - {/* */} - -); + ); +}; export default FinishedSchedules; diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx index 15effd2f..17c03a42 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx @@ -3,7 +3,9 @@ import { Chip } from '@/components/Chip'; import { Flex } from '@/components/Flex'; import { Text } from '@/components/Text'; import { vars } from '@/theme/index.css'; +import { getDateRangeString, getDday } from '@/utils/date'; +import type { OngoingDiscussion } from '../../model'; import { containerStyle, recommendContainerStyle, @@ -11,51 +13,59 @@ import { subTextContainerStyle, } from './ScheduleDetails.css'; -// interface ScheduleDetailsProps { -// schedule: object; -// } +interface ScheduleDetailsProps { + discussion: OngoingDiscussion; +} -const ScheduleContents = () => ( +const ScheduleContents = ({ discussion }: ScheduleDetailsProps) => ( - + - + ); -const ScheduleInfo = () => ( - - 마감까지 15일 - 기업디(3) 첫 팀플 +const ScheduleInfo = ({ discussion }: { + discussion: OngoingDiscussion; +}) => { + const { title, dateRangeStart, dateRangeEnd } = discussion; + return ( - 12월 30일 ~ 1월 5일 - 강남역 4번 출구 - 1시간 + + {`마감까지 ${getDday(dateRangeEnd)}일`} + + {title} + + + {getDateRangeString(dateRangeStart, dateRangeEnd)} + + 강남역 4번 출구 + 1시간 + - -); - + ); +}; const RecommendedSchedules = () => ( 추천 일정 diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx index 248cd5e6..0b79aa7e 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx @@ -36,8 +36,8 @@ const OngoingSchedules = () => (
- -
+ {/* */} +
))}
diff --git a/frontend/src/pages/HomePage/index.tsx b/frontend/src/pages/HomePage/index.tsx index 4cbd0049..ded4a622 100644 --- a/frontend/src/pages/HomePage/index.tsx +++ b/frontend/src/pages/HomePage/index.tsx @@ -21,7 +21,7 @@ const HomePage = () => { useEffect(() => { // prefetchUpcomingSchedules(queryClient); - prefetchOngoingSchedules(queryClient); + // prefetchOngoingSchedules(queryClient); // prefetchFinishedSchedules(queryClient); }, [queryClient]); @@ -36,8 +36,8 @@ const HomePage = () => { 모두보기 */} - - {/* */} + {/* */} + ); }; diff --git a/frontend/src/utils/date/date.ts b/frontend/src/utils/date/date.ts index d616c1b0..97b9a03f 100644 --- a/frontend/src/utils/date/date.ts +++ b/frontend/src/utils/date/date.ts @@ -236,3 +236,9 @@ export const getDateTimeRangeString = (start: Date, end: Date): string => { } return `${startMonth}월 ${startDay}일 ${startTime} ~ ${endMonth}월 ${endDay}일 ${endTime}`; }; + +export const getDday = (date: Date): number => { + const today = new Date(); + const diff = date.getTime() - today.getTime(); + return Math.floor(diff / DAY_IN_MILLISECONDS); +}; diff --git a/frontend/src/utils/date/format.ts b/frontend/src/utils/date/format.ts index eee8a666..6a21a7f7 100644 --- a/frontend/src/utils/date/format.ts +++ b/frontend/src/utils/date/format.ts @@ -1,4 +1,4 @@ -import { DAY_IN_MILLISECONDS, getYearMonthDay } from './date'; +import { getDday, getYearMonthDay } from './date'; import { HOUR } from './time'; /** @@ -95,9 +95,7 @@ export const formatTimeStringToLocaleString = (timeString: string): string => { }; export const formatDateToDdayString = (date: Date): string => { - const now = new Date(); - const diff = date.getTime() - now.getTime(); - const diffDays = Math.floor(diff / DAY_IN_MILLISECONDS); + const diffDays = getDday(date); if (diffDays === 0) return 'D-Day'; if (diffDays > 0) return `D-${diffDays}`; From 667fa6dd91162431aaab1c393e062f41f9bfa716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 16:20:25 +0900 Subject: [PATCH 12/25] =?UTF-8?q?feat:=20ongoingSchedule=20api=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/shared-schedule/api/index.ts | 12 ++++++------ .../src/features/shared-schedule/api/queries.ts | 4 ++-- .../features/shared-schedule/api/queryOptions.ts | 8 ++++++++ .../shared-schedule/model/ongoingSchedules.ts | 2 +- .../ui/OngoingSchedules/OngoingScheduleList.tsx | 2 +- frontend/src/pages/HomePage/index.tsx | 16 +--------------- frontend/src/utils/date/time.ts | 1 + 7 files changed, 20 insertions(+), 25 deletions(-) diff --git a/frontend/src/features/shared-schedule/api/index.ts b/frontend/src/features/shared-schedule/api/index.ts index 052e3504..6d8d1b80 100644 --- a/frontend/src/features/shared-schedule/api/index.ts +++ b/frontend/src/features/shared-schedule/api/index.ts @@ -17,8 +17,8 @@ const ENDPOINT_PREFIX = '/api/v1/schedules'; export const schedulesApi = { getUpcomingSchedules: async (): Promise => { const response = await request.get(ENDPOINT_PREFIX + '/upcoming'); - const validData = UpcomingSchedulesResponseSchema.parse(response); - return validData; + UpcomingSchedulesResponseSchema.parse(response); + return response; }, getOngoingSchedules: async ( page: number, @@ -32,8 +32,8 @@ export const schedulesApi = { attendType: attendType, }, }); - const validData = OngoingSchedulesResponseSchema.parse(response); - return validData; + OngoingSchedulesResponseSchema.parse(response); + return response; }, getFinishedSchedules: async ( page: number, @@ -47,7 +47,7 @@ export const schedulesApi = { year: year.toString(), }, }); - const validData = FinishedSchedulesResponseSchema.parse(response); - return validData; + FinishedSchedulesResponseSchema.parse(response); + return response; }, }; diff --git a/frontend/src/features/shared-schedule/api/queries.ts b/frontend/src/features/shared-schedule/api/queries.ts index 3c3f1c26..811b6596 100644 --- a/frontend/src/features/shared-schedule/api/queries.ts +++ b/frontend/src/features/shared-schedule/api/queries.ts @@ -8,9 +8,9 @@ export const useUpcomingQuery = () => useQuery( sharedSchedulesQueryOptions.upcoming, ); -export const useOngoingQuery = (page: number, size: number, type: AttendType) => +export const useOngoingQuery = (page: number, size: number, attendType: AttendType) => useQuery( - sharedSchedulesQueryOptions.ongoing(page, size, type), + sharedSchedulesQueryOptions.ongoing(page, size, attendType), ); export const useFinishedQuery = (page: number, size: number, year: number) => diff --git a/frontend/src/features/shared-schedule/api/queryOptions.ts b/frontend/src/features/shared-schedule/api/queryOptions.ts index 482e87b7..972dea94 100644 --- a/frontend/src/features/shared-schedule/api/queryOptions.ts +++ b/frontend/src/features/shared-schedule/api/queryOptions.ts @@ -1,3 +1,5 @@ +import { MINUTE_IN_MILLISECONDS } from '@/utils/date'; + import type { AttendType } from '../model'; import { schedulesApi } from '.'; import { sharedScheduleQuerykeys } from './keys'; @@ -6,13 +8,19 @@ export const sharedSchedulesQueryOptions = { upcoming: { queryKey: sharedScheduleQuerykeys.upcoming, queryFn: () => schedulesApi.getUpcomingSchedules(), + staleTime: 4 * MINUTE_IN_MILLISECONDS, + cacheTime: 5 * MINUTE_IN_MILLISECONDS, }, ongoing: (page: number, size: number, attendtype: AttendType) => ({ queryKey: sharedScheduleQuerykeys.ongoing(page, size, attendtype), queryFn: () => schedulesApi.getOngoingSchedules(page, size, attendtype), + staleTime: 4 * MINUTE_IN_MILLISECONDS, + cacheTime: 5 * MINUTE_IN_MILLISECONDS, }), finished: (page: number, size: number, year: number) => ({ queryKey: sharedScheduleQuerykeys.finished(page, size, year), queryFn: () => schedulesApi.getFinishedSchedules(page, size, year), + staleTime: 4 * MINUTE_IN_MILLISECONDS, + cacheTime: 5 * MINUTE_IN_MILLISECONDS, }), }; diff --git a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts index 357ddfa9..5c256a4d 100644 --- a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts +++ b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; import { zCoerceToDate } from '@/utils/zod'; const OngoingDiscussionSchema = z.object({ - id: z.number(), + discussionId: z.number(), title: z.string(), dateRangeStart: zCoerceToDate, dateRangeEnd: zCoerceToDate, diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx index f1f3d529..325f10ae 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx @@ -38,7 +38,7 @@ const OngoingScheduleList = ({ segmentOption }: OngoingScheduleListProps) => { ))}
diff --git a/frontend/src/pages/HomePage/index.tsx b/frontend/src/pages/HomePage/index.tsx index ded4a622..d83b8f85 100644 --- a/frontend/src/pages/HomePage/index.tsx +++ b/frontend/src/pages/HomePage/index.tsx @@ -1,14 +1,7 @@ -import { useQueryClient } from '@tanstack/react-query'; import { useNavigate } from '@tanstack/react-router'; -import { useEffect } from 'react'; import Button from '@/components/Button'; import { Text } from '@/components/Text'; -import { - prefetchFinishedSchedules, - prefetchOngoingSchedules, - prefetchUpcomingSchedules, -} from '@/features/shared-schedule/api/prefetch'; import FinishedSchedules from '@/features/shared-schedule/ui/FinishedSchedules'; import OngoingSchedules from '@/features/shared-schedule/ui/OngoingSchedules'; import UpcomingSchedules from '@/features/shared-schedule/ui/UpcomingSchedules'; @@ -17,13 +10,6 @@ import { containerStyle } from './index.css'; const HomePage = () => { const navigate = useNavigate(); - const queryClient = useQueryClient(); - - useEffect(() => { - // prefetchUpcomingSchedules(queryClient); - // prefetchOngoingSchedules(queryClient); - // prefetchFinishedSchedules(queryClient); - }, [queryClient]); return (
@@ -36,7 +22,7 @@ const HomePage = () => { 모두보기 */} - {/* */} +
); diff --git a/frontend/src/utils/date/time.ts b/frontend/src/utils/date/time.ts index 29523954..6de51cf9 100644 --- a/frontend/src/utils/date/time.ts +++ b/frontend/src/utils/date/time.ts @@ -1,5 +1,6 @@ export const HOUR = 60; const HOUR_IN_MILLISECONDS = 1000 * 60 * 60; +export const MINUTE_IN_MILLISECONDS = 60000; export const formatDateToTimeString = (date: Date | null): string => { if (!date) return ''; From 4d1a06d9503d55998a5174bfdbc0f03e4a8dc7fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 16:30:58 +0900 Subject: [PATCH 13/25] feat: set fixed height for ongoing schedule list and list items --- .../shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx | 1 + .../ui/OngoingSchedules/ongoingScheduleListItem.css.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx index 325f10ae..10f3380a 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx @@ -31,6 +31,7 @@ const OngoingScheduleList = ({ segmentOption }: OngoingScheduleListProps) => { > diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/ongoingScheduleListItem.css.ts b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ongoingScheduleListItem.css.ts index fd42e90b..1df0883e 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/ongoingScheduleListItem.css.ts +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ongoingScheduleListItem.css.ts @@ -9,6 +9,7 @@ export const scheduleItemContainerStyle = recipe({ padding: `${vars.spacing[400]} ${vars.spacing[600]}`, borderRadius: vars.radius[500], cursor: 'pointer', + height: '5rem', }, variants: { selected: { From d5f118996be2d92b8de50b43a3c2a940e7c8f557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 17:21:21 +0900 Subject: [PATCH 14/25] feat: refactor ongoing schedules components and add recommended schedules UI --- .../src/components/SegmentControl/index.tsx | 1 - .../src/features/discussion/api/queries.ts | 2 +- .../src/features/shared-schedule/api/index.ts | 12 +-- .../shared-schedule/model/ongoingSchedules.ts | 6 +- .../OngoingSchedules/OngoingScheduleList.tsx | 7 +- .../OngoingScheduleListItem.tsx | 26 +++-- .../OngoingSchedules/RecommendedSchedules.tsx | 43 +++++++++ .../OngoingSchedules/ScheduleDetails.css.ts | 8 -- .../ui/OngoingSchedules/ScheduleDetails.tsx | 95 +++++++------------ .../ui/OngoingSchedules/index.tsx | 54 ++++++----- .../recommendedSchedules.css.ts | 22 +++++ 11 files changed, 161 insertions(+), 115 deletions(-) create mode 100644 frontend/src/features/shared-schedule/ui/OngoingSchedules/RecommendedSchedules.tsx create mode 100644 frontend/src/features/shared-schedule/ui/OngoingSchedules/recommendedSchedules.css.ts diff --git a/frontend/src/components/SegmentControl/index.tsx b/frontend/src/components/SegmentControl/index.tsx index 69f06230..d66844c4 100644 --- a/frontend/src/components/SegmentControl/index.tsx +++ b/frontend/src/components/SegmentControl/index.tsx @@ -26,7 +26,6 @@ const SegmentControl = ({ shadow = true, defaultValue = segmentOptions[0]?.value ?? '', onValueChange, - className, children, className, }: SegmentControlProps) => { diff --git a/frontend/src/features/discussion/api/queries.ts b/frontend/src/features/discussion/api/queries.ts index a217b728..dcc12ef8 100644 --- a/frontend/src/features/discussion/api/queries.ts +++ b/frontend/src/features/discussion/api/queries.ts @@ -72,4 +72,4 @@ export const useDiscussionParticipantsQuery = (discussionId: string) => { ); return { participants, isLoading }; -}; \ No newline at end of file +}; diff --git a/frontend/src/features/shared-schedule/api/index.ts b/frontend/src/features/shared-schedule/api/index.ts index 6d8d1b80..4229730a 100644 --- a/frontend/src/features/shared-schedule/api/index.ts +++ b/frontend/src/features/shared-schedule/api/index.ts @@ -17,8 +17,8 @@ const ENDPOINT_PREFIX = '/api/v1/schedules'; export const schedulesApi = { getUpcomingSchedules: async (): Promise => { const response = await request.get(ENDPOINT_PREFIX + '/upcoming'); - UpcomingSchedulesResponseSchema.parse(response); - return response; + const parsedData = UpcomingSchedulesResponseSchema.parse(response); + return parsedData; }, getOngoingSchedules: async ( page: number, @@ -32,8 +32,8 @@ export const schedulesApi = { attendType: attendType, }, }); - OngoingSchedulesResponseSchema.parse(response); - return response; + const parsedData = OngoingSchedulesResponseSchema.parse(response); + return parsedData; }, getFinishedSchedules: async ( page: number, @@ -47,7 +47,7 @@ export const schedulesApi = { year: year.toString(), }, }); - FinishedSchedulesResponseSchema.parse(response); - return response; + const parsedData = FinishedSchedulesResponseSchema.parse(response); + return parsedData; }, }; diff --git a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts index 5c256a4d..fd99f867 100644 --- a/frontend/src/features/shared-schedule/model/ongoingSchedules.ts +++ b/frontend/src/features/shared-schedule/model/ongoingSchedules.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { zCoerceToDate } from '@/utils/zod'; -const OngoingDiscussionSchema = z.object({ +const OngoingScheduleSchema = z.object({ discussionId: z.number(), title: z.string(), dateRangeStart: zCoerceToDate, @@ -16,10 +16,10 @@ export const OngoingSchedulesResponseSchema = z.object({ totalPages: z.number(), hasNext: z.boolean(), hasPrevious: z.boolean(), - ongoingDiscussions: z.array(OngoingDiscussionSchema), + ongoingDiscussions: z.array(OngoingScheduleSchema), }); export type AttendType = 'HOST' | 'ATTENDEE' | 'ALL'; export type OngoingSchedulesResponse = z.infer; -export type OngoingDiscussion = z.infer; +export type OngoingSchedule = z.infer; diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx index 10f3380a..bb86126b 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx @@ -13,9 +13,10 @@ const PAGE_SIZE = 6; interface OngoingScheduleListProps { segmentOption: OngoingSegmentOption; + onSelect: (discussionId: number) => void; } -const OngoingScheduleList = ({ segmentOption }: OngoingScheduleListProps) => { +const OngoingScheduleList = ({ segmentOption, onSelect }: OngoingScheduleListProps) => { const [page, setPage] = useState(1); const { data, isPending } = useOngoingQuery(page, PAGE_SIZE, segmentOption.value); if (isPending) return
pending...
; @@ -38,8 +39,8 @@ const OngoingScheduleList = ({ segmentOption }: OngoingScheduleListProps) => { {schedules.map((schedule, index) => ( onSelect(id)} + schedule={schedule} selected={false} />))}
diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleListItem.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleListItem.tsx index 7778a827..6dc8e3e8 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleListItem.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleListItem.tsx @@ -2,7 +2,9 @@ import Avatar from '@/components/Avatar'; import { Flex } from '@/components/Flex'; import { Text } from '@/components/Text'; import { vars } from '@/theme/index.css'; +import { getDateRangeString } from '@/utils/date'; +import type { OngoingSchedule } from '../../model'; import { detailsContainerStyle, scheduleItemContainerStyle, @@ -10,24 +12,23 @@ import { } from './ongoingScheduleListItem.css'; interface OngoingScheduleListItemProps { - scheduleTitle: string; - participantImageUrls: string[]; + schedule: OngoingSchedule; selected: boolean; isUpdated?: boolean; - meetingPlace?: string; - onClick?: () => void; + onSelect: (id: number) => void; } const OngoingScheduleListItem = ({ - scheduleTitle, - participantImageUrls, + schedule, selected, isUpdated = false, + onSelect, }: OngoingScheduleListItemProps) => ( onSelect(schedule.discussionId)} > - {scheduleTitle} - {isUpdated && 일정을 업데이트한 사람이 있어요!} + {schedule.title} + {/* {isUpdated && + + 일정을 업데이트한 사람이 있어요! + } */} - 12월 28일 ~ 1월 23일 + + {getDateRangeString(schedule.dateRangeStart, schedule.dateRangeEnd)} + - + ); diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/RecommendedSchedules.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/RecommendedSchedules.tsx new file mode 100644 index 00000000..1c141e2b --- /dev/null +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/RecommendedSchedules.tsx @@ -0,0 +1,43 @@ +import { Chip } from '@/components/Chip'; +import { Flex } from '@/components/Flex'; +import { Text } from '@/components/Text'; +import { vars } from '@/theme/index.css'; + +import { recommendContainerStyle, recommendItemStyle } from './recommendedSchedules.css'; + +// interface RecommendedSchedulesProps { +// discussionId: number; +// } + +const RecommendedSchedules = () => ( + + 추천 일정 + + + + +); + +const RecommendedScheduleItem = () => ( + + + 12월 11일 목요일 + 오전 11시 ~ 오후 2시 (3시간) + + + 모두 가능 + + +); + +export default RecommendedSchedules; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.css.ts b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.css.ts index e596d017..f66b5ee6 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.css.ts +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.css.ts @@ -12,11 +12,3 @@ export const containerStyle = style({ export const subTextContainerStyle = style({ paddingTop: vars.spacing[100], }); - -export const recommendContainerStyle = style({ - padding: `${vars.spacing[300]} 0`, -}); - -export const recommendItemStyle = style({ - padding: `${vars.spacing[400]} 0`, -}); \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx index 17c03a42..6d5a5542 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/ScheduleDetails.tsx @@ -1,46 +1,51 @@ import Button from '@/components/Button'; -import { Chip } from '@/components/Chip'; import { Flex } from '@/components/Flex'; import { Text } from '@/components/Text'; +import { useDiscussionQuery } from '@/features/discussion/api/queries'; +import type { DiscussionResponse } from '@/features/discussion/model'; import { vars } from '@/theme/index.css'; -import { getDateRangeString, getDday } from '@/utils/date'; -import type { OngoingDiscussion } from '../../model'; -import { +import RecommendedSchedules from './RecommendedSchedules'; +import { containerStyle, - recommendContainerStyle, - recommendItemStyle, - subTextContainerStyle, + subTextContainerStyle, } from './ScheduleDetails.css'; interface ScheduleDetailsProps { - discussion: OngoingDiscussion; + discussionId: number; } -const ScheduleContents = ({ discussion }: ScheduleDetailsProps) => ( - - - +// TODO: Date 타입 변환 후 변경사항 적용 +const ScheduleContents = ({ discussionId }: ScheduleDetailsProps) => { + const { discussion, isLoading } = useDiscussionQuery(discussionId.toString()); + if (isLoading) return
pending ...
; + if (!discussion) return
No data available
; + + return ( - - + + + + + + -
-); + ); +}; const ScheduleInfo = ({ discussion }: { - discussion: OngoingDiscussion; + discussion: DiscussionResponse; }) => { - const { title, dateRangeStart, dateRangeEnd } = discussion; + const { title, location, duration } = discussion; return ( - {`마감까지 ${getDday(dateRangeEnd)}일`} + {/* {`마감까지 ${getDday(dateRangeEnd)}일`} */} {title} - {getDateRangeString(dateRangeStart, dateRangeEnd)} + {/* {getDateRangeString(dateRangeStart, dateRangeEnd)} */} - 강남역 4번 출구 - 1시간 + {location && {location}} + {duration} ); }; -const RecommendedSchedules = () => ( - - 추천 일정 - - - - -); - -const RecommendedScheduleItem = () => ( - - - 12월 11일 목요일 - 오전 11시 ~ 오후 2시 (3시간) - - - 모두 가능 - - -); export default ScheduleContents; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx index 0b79aa7e..4f848730 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx @@ -1,4 +1,6 @@ +import { useState } from 'react'; + import { Flex } from '@/components/Flex'; import SegmentControl from '@/components/SegmentControl'; import { Text } from '@/components/Text'; @@ -19,29 +21,35 @@ const segmentOptions: OngoingSegmentOption[] = [ { label: '공유 받은 일정', value: 'ATTENDEE' }, ]; -const OngoingSchedules = () => ( - - 확정되지 않은 일정 - { + const [selectedDiscussionId, setSelectedDiscussionId] = useState(1); + return ( + - {segmentOptions.map((option, idx) => ( - -
- - {/* */} -
-
- ))} -
-
-); + 확정되지 않은 일정 + + {segmentOptions.map((option, idx) => ( + +
+ setSelectedDiscussionId(id)} + segmentOption={option} + /> + +
+
+ ))} +
+
+ ); +}; export default OngoingSchedules; \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/recommendedSchedules.css.ts b/frontend/src/features/shared-schedule/ui/OngoingSchedules/recommendedSchedules.css.ts new file mode 100644 index 00000000..e596d017 --- /dev/null +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/recommendedSchedules.css.ts @@ -0,0 +1,22 @@ +import { style } from '@vanilla-extract/css'; + +import { vars } from '@/theme/index.css'; + +export const containerStyle = style({ + width: 396, + height: 552, + flexShrink: 0, + padding: '12px 0 28px 0', +}); + +export const subTextContainerStyle = style({ + paddingTop: vars.spacing[100], +}); + +export const recommendContainerStyle = style({ + padding: `${vars.spacing[300]} 0`, +}); + +export const recommendItemStyle = style({ + padding: `${vars.spacing[400]} 0`, +}); \ No newline at end of file From 8c4205d75867ad65d18490736fbdcb04977aa02a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 18:08:25 +0900 Subject: [PATCH 15/25] =?UTF-8?q?feat:=20OngoingFallback=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84,=20home=20route=EC=97=90=EC=84=9C=20prefetch=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Icon/component/CheckGraphic.tsx | 65 +++++++++++++++++++ .../Icon/component/ClockGraphic.tsx | 28 ++++++++ frontend/src/components/Icon/index.ts | 2 + .../src/components/Icon/svg/check-graphic.svg | 55 ++++++++++++++++ .../src/components/Icon/svg/clock-graphic.svg | 18 +++++ .../ui/Fallbacks/OngoingFallback.tsx | 19 ++++++ .../shared-schedule/ui/Fallbacks/index.css.ts | 0 .../OngoingSchedules/OngoingScheduleList.tsx | 3 +- .../ui/OngoingSchedules/index.tsx | 7 ++ .../discussion/candidate/index.lazy.tsx | 2 +- frontend/src/routes/_main/home/index.lazy.tsx | 17 ----- frontend/src/routes/_main/home/index.tsx | 25 +++++++ 12 files changed, 222 insertions(+), 19 deletions(-) create mode 100644 frontend/src/components/Icon/component/CheckGraphic.tsx create mode 100644 frontend/src/components/Icon/component/ClockGraphic.tsx create mode 100644 frontend/src/components/Icon/svg/check-graphic.svg create mode 100644 frontend/src/components/Icon/svg/clock-graphic.svg create mode 100644 frontend/src/features/shared-schedule/ui/Fallbacks/OngoingFallback.tsx create mode 100644 frontend/src/features/shared-schedule/ui/Fallbacks/index.css.ts rename frontend/src/routes/{ => _main}/discussion/candidate/index.lazy.tsx (81%) delete mode 100644 frontend/src/routes/_main/home/index.lazy.tsx create mode 100644 frontend/src/routes/_main/home/index.tsx diff --git a/frontend/src/components/Icon/component/CheckGraphic.tsx b/frontend/src/components/Icon/component/CheckGraphic.tsx new file mode 100644 index 00000000..d76280ce --- /dev/null +++ b/frontend/src/components/Icon/component/CheckGraphic.tsx @@ -0,0 +1,65 @@ + +import type { IconProps } from '../Icon.d.ts'; + +export const CheckGraphic = ({ clickable = false, className, width = 24, height = 24 , stroke = "white", fill = "white", ...rest }: IconProps) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +CheckGraphic.displayName = 'CheckGraphic'; diff --git a/frontend/src/components/Icon/component/ClockGraphic.tsx b/frontend/src/components/Icon/component/ClockGraphic.tsx new file mode 100644 index 00000000..12e3fe62 --- /dev/null +++ b/frontend/src/components/Icon/component/ClockGraphic.tsx @@ -0,0 +1,28 @@ + +import type { IconProps } from '../Icon.d.ts'; + +export const ClockGraphic = ({ clickable = false, className, width = 24, height = 24 , stroke = "white", fill = "white", ...rest }: IconProps) => { + return ( + + + + + + + + + + + + + + + + + + + + ); +}; + +ClockGraphic.displayName = 'ClockGraphic'; diff --git a/frontend/src/components/Icon/index.ts b/frontend/src/components/Icon/index.ts index d98e8072..d8beb31c 100644 --- a/frontend/src/components/Icon/index.ts +++ b/frontend/src/components/Icon/index.ts @@ -1,11 +1,13 @@ export * from "./component/ArrowLeft.tsx"; export * from "./component/CalendarCheck.tsx"; export * from "./component/Calendar.tsx"; +export * from "./component/CheckGraphic.tsx"; export * from "./component/Check.tsx"; export * from "./component/ChevronDown.tsx"; export * from "./component/ChevronLeft.tsx"; export * from "./component/ChevronRight.tsx"; export * from "./component/CircleCheck.tsx"; +export * from "./component/ClockGraphic.tsx"; export * from "./component/Clock.tsx"; export * from "./component/Close.tsx"; export * from "./component/GoogleCalendar.tsx"; diff --git a/frontend/src/components/Icon/svg/check-graphic.svg b/frontend/src/components/Icon/svg/check-graphic.svg new file mode 100644 index 00000000..bc04a29d --- /dev/null +++ b/frontend/src/components/Icon/svg/check-graphic.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/components/Icon/svg/clock-graphic.svg b/frontend/src/components/Icon/svg/clock-graphic.svg new file mode 100644 index 00000000..5ee6bd50 --- /dev/null +++ b/frontend/src/components/Icon/svg/clock-graphic.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/features/shared-schedule/ui/Fallbacks/OngoingFallback.tsx b/frontend/src/features/shared-schedule/ui/Fallbacks/OngoingFallback.tsx new file mode 100644 index 00000000..f5f952aa --- /dev/null +++ b/frontend/src/features/shared-schedule/ui/Fallbacks/OngoingFallback.tsx @@ -0,0 +1,19 @@ +import { Flex } from '@/components/Flex'; +import { CheckGraphic } from '@/components/Icon/component/CheckGraphic'; +import { Text } from '@/components/Text'; +import { vars } from '@/theme/index.css'; + +const OngoingFallback = () => ( + + + 아직 다가오는 일정이 없어요! + +); + +export default OngoingFallback; diff --git a/frontend/src/features/shared-schedule/ui/Fallbacks/index.css.ts b/frontend/src/features/shared-schedule/ui/Fallbacks/index.css.ts new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx index bb86126b..22d3f7b7 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx @@ -5,6 +5,7 @@ import { Flex } from '@/components/Flex'; import Pagination from '@/components/Pagination'; import { useOngoingQuery } from '../../api/queries'; +import OngoingFallback from '../Fallbacks/OngoingFallback'; import type { OngoingSegmentOption } from '.'; import { paginationStyle } from './ongoingScheduleList.css'; import OngoingScheduleListItem from './OngoingScheduleListItem'; @@ -20,7 +21,7 @@ const OngoingScheduleList = ({ segmentOption, onSelect }: OngoingScheduleListPro const [page, setPage] = useState(1); const { data, isPending } = useOngoingQuery(page, PAGE_SIZE, segmentOption.value); if (isPending) return
pending...
; - if (!data) return
No data available
; + if (!data || data.ongoingDiscussions.length === 0) return
no data available
; const schedules = data.ongoingDiscussions; return ( diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx index 4f848730..124fe7b8 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx @@ -1,11 +1,14 @@ +import { useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; import { Flex } from '@/components/Flex'; import SegmentControl from '@/components/SegmentControl'; import { Text } from '@/components/Text'; +import { sharedScheduleQuerykeys } from '../../api/keys'; import type { AttendType } from '../../model/'; +import OngoingFallback from '../Fallbacks/OngoingFallback'; import { containerStyle, mainContainerStyle, segmentControlStyle, titleStyle } from './index.css'; import OngoingScheduleList from './OngoingScheduleList'; import ScheduleContents from './ScheduleDetails'; @@ -23,6 +26,10 @@ const segmentOptions: OngoingSegmentOption[] = [ const OngoingSchedules = () => { const [selectedDiscussionId, setSelectedDiscussionId] = useState(1); + const queryClient = useQueryClient(); + if (!queryClient.getQueryCache().find({ queryKey: sharedScheduleQuerykeys.ongoing(1, 6, 'ALL') })) + return ; + return ( ( ); -export const Route = createLazyFileRoute('/discussion/candidate/')({ +export const Route = createLazyFileRoute('/_main/discussion/candidate/')({ component: CandidateSchedule, }); diff --git a/frontend/src/routes/_main/home/index.lazy.tsx b/frontend/src/routes/_main/home/index.lazy.tsx deleted file mode 100644 index c5ad1d23..00000000 --- a/frontend/src/routes/_main/home/index.lazy.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { createLazyFileRoute } from '@tanstack/react-router'; - -import GlobalNavBar from '@/layout/GlobalNavBar'; -import HomePage from '@/pages/HomePage'; - -const Home = () => ( - <> - - - - - - -); -export const Route = createLazyFileRoute('/_main/home/')({ - component: Home, -}); diff --git a/frontend/src/routes/_main/home/index.tsx b/frontend/src/routes/_main/home/index.tsx new file mode 100644 index 00000000..675cd885 --- /dev/null +++ b/frontend/src/routes/_main/home/index.tsx @@ -0,0 +1,25 @@ +import { createFileRoute } from '@tanstack/react-router'; + +import { sharedSchedulesQueryOptions } from '@/features/shared-schedule/api/queryOptions'; +import GlobalNavBar from '@/layout/GlobalNavBar'; +import HomePage from '@/pages/HomePage'; + +const Home = () => ( + <> + + + + + + +); +export const Route = createFileRoute('/_main/home/')({ + loader: async ({ + context: { queryClient }, + }) => { + queryClient.prefetchQuery(sharedSchedulesQueryOptions.upcoming); + queryClient.prefetchQuery(sharedSchedulesQueryOptions.ongoing(1, 6, 'ALL')); + queryClient.prefetchQuery(sharedSchedulesQueryOptions.finished(1, 6, new Date().getFullYear())); + }, + component: Home, +}); From 84b5c1998d4c1529c71645e14556a07342bbbafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 18:32:18 +0900 Subject: [PATCH 16/25] =?UTF-8?q?feat:=20=EC=A7=80=EB=82=9C=20=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=EC=97=90=20Fallback=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/Fallbacks/FinishedFallback.tsx | 19 ++++++ .../ui/Fallbacks/OngoingFallback.tsx | 11 ++-- .../ui/Fallbacks/UpcomingFallback.tsx | 22 +++++++ .../shared-schedule/ui/Fallbacks/index.css.ts | 8 +++ .../FinishedScheduleList.tsx | 4 +- .../ui/FinishedSchedules/index.tsx | 2 +- .../ui/OngoingSchedules/index.tsx | 60 ++++++++++--------- 7 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 frontend/src/features/shared-schedule/ui/Fallbacks/FinishedFallback.tsx create mode 100644 frontend/src/features/shared-schedule/ui/Fallbacks/UpcomingFallback.tsx diff --git a/frontend/src/features/shared-schedule/ui/Fallbacks/FinishedFallback.tsx b/frontend/src/features/shared-schedule/ui/Fallbacks/FinishedFallback.tsx new file mode 100644 index 00000000..661ac577 --- /dev/null +++ b/frontend/src/features/shared-schedule/ui/Fallbacks/FinishedFallback.tsx @@ -0,0 +1,19 @@ +import { Flex } from '@/components/Flex'; +import { ClockGraphic } from '@/components/Icon/component/ClockGraphic'; +import { Text } from '@/components/Text'; +import { vars } from '@/theme/index.css'; + +const FinishedFallback = () => ( + + + 지난 일정이 없어요 + +); + +export default FinishedFallback; diff --git a/frontend/src/features/shared-schedule/ui/Fallbacks/OngoingFallback.tsx b/frontend/src/features/shared-schedule/ui/Fallbacks/OngoingFallback.tsx index f5f952aa..a107602c 100644 --- a/frontend/src/features/shared-schedule/ui/Fallbacks/OngoingFallback.tsx +++ b/frontend/src/features/shared-schedule/ui/Fallbacks/OngoingFallback.tsx @@ -1,18 +1,21 @@ import { Flex } from '@/components/Flex'; -import { CheckGraphic } from '@/components/Icon/component/CheckGraphic'; +import { ClockGraphic } from '@/components/Icon/component/ClockGraphic'; import { Text } from '@/components/Text'; import { vars } from '@/theme/index.css'; +import { containerStyle } from './index.css'; + const OngoingFallback = () => ( - - 아직 다가오는 일정이 없어요! + + 확정되지 않은 일정이 없어요 ); diff --git a/frontend/src/features/shared-schedule/ui/Fallbacks/UpcomingFallback.tsx b/frontend/src/features/shared-schedule/ui/Fallbacks/UpcomingFallback.tsx new file mode 100644 index 00000000..24c6113b --- /dev/null +++ b/frontend/src/features/shared-schedule/ui/Fallbacks/UpcomingFallback.tsx @@ -0,0 +1,22 @@ +import { Flex } from '@/components/Flex'; +import { CheckGraphic } from '@/components/Icon/component/CheckGraphic'; +import { Text } from '@/components/Text'; +import { vars } from '@/theme/index.css'; + +import { containerStyle } from './index.css'; + +const OngoingFallback = () => ( + + + 아직 다가오는 일정이 없어요! + +); + +export default OngoingFallback; diff --git a/frontend/src/features/shared-schedule/ui/Fallbacks/index.css.ts b/frontend/src/features/shared-schedule/ui/Fallbacks/index.css.ts index e69de29b..f6019752 100644 --- a/frontend/src/features/shared-schedule/ui/Fallbacks/index.css.ts +++ b/frontend/src/features/shared-schedule/ui/Fallbacks/index.css.ts @@ -0,0 +1,8 @@ +import { style } from '@vanilla-extract/css'; + +import { vars } from '@/theme/index.css'; + +export const containerStyle = style({ + backgroundColor: vars.color.Ref.CoolGrey[50], + borderRadius: vars.radius[700], +}); \ No newline at end of file diff --git a/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx index 8a1b73da..7995f5fd 100644 --- a/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx @@ -5,6 +5,7 @@ import { Flex } from '@/components/Flex'; import Pagination from '@/components/Pagination'; import { useFinishedQuery } from '../../api/queries'; +import FinishedFallback from '../Fallbacks/FinishedFallback'; import { paginationStyle } from './finishedScheduleList.css'; import FinishedScheduleListItem from './FinishedScheduleListItem'; @@ -18,7 +19,8 @@ const FinishedScheduleList = ({ baseYear }: FinishedScheduleListProps) => { const [currentPage, setCurrentPage] = useState(1); const { data, isPending } = useFinishedQuery(currentPage, PAGE_SIZE, baseYear); if (isPending) return
pending...
; - if (!data) return
No data available
; + if (!data) return
data is undefined or null
; + if (data.finishedDiscussions.length === 0) return ; return ( { {/* TODO: 연도 validation */} setCurrentYear(currentYear - 1)} /> diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx index 124fe7b8..cd6d9451 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx @@ -7,7 +7,7 @@ import SegmentControl from '@/components/SegmentControl'; import { Text } from '@/components/Text'; import { sharedScheduleQuerykeys } from '../../api/keys'; -import type { AttendType } from '../../model/'; +import type { AttendType, OngoingSchedulesResponse } from '../../model/'; import OngoingFallback from '../Fallbacks/OngoingFallback'; import { containerStyle, mainContainerStyle, segmentControlStyle, titleStyle } from './index.css'; import OngoingScheduleList from './OngoingScheduleList'; @@ -24,38 +24,44 @@ const segmentOptions: OngoingSegmentOption[] = [ { label: '공유 받은 일정', value: 'ATTENDEE' }, ]; -const OngoingSchedules = () => { +const OngoingSchedules = () => ( + + 확정되지 않은 일정 + + +); + +const Content = () => { const [selectedDiscussionId, setSelectedDiscussionId] = useState(1); const queryClient = useQueryClient(); - if (!queryClient.getQueryCache().find({ queryKey: sharedScheduleQuerykeys.ongoing(1, 6, 'ALL') })) + if (queryClient.getQueryData( + sharedScheduleQuerykeys.ongoing(1, 6, 'ALL'), + )?.totalPages === 0) return ; return ( - - 확정되지 않은 일정 - - {segmentOptions.map((option, idx) => ( - -
- setSelectedDiscussionId(id)} - segmentOption={option} - /> - -
-
- ))} -
-
+ {segmentOptions.map((option, idx) => ( + +
+ setSelectedDiscussionId(id)} + segmentOption={option} + /> + +
+
+ ))} +
); }; From e64c52b50883629e59a30a5d86645a5c8d5241ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 18:37:42 +0900 Subject: [PATCH 17/25] =?UTF-8?q?chore:=20=EB=B9=8C=EB=93=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/discussion/ui/DiscussionRank/index.tsx | 6 +++++- .../ui/OngoingSchedules/OngoingScheduleList.tsx | 1 - frontend/src/pages/HomePage/index.tsx | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/features/discussion/ui/DiscussionRank/index.tsx b/frontend/src/features/discussion/ui/DiscussionRank/index.tsx index 60c368a5..a4f48688 100644 --- a/frontend/src/features/discussion/ui/DiscussionRank/index.tsx +++ b/frontend/src/features/discussion/ui/DiscussionRank/index.tsx @@ -6,6 +6,10 @@ import { useDiscussionRankQuery } from '../../api/queries'; import { segmentControlContentsStyle, segmentControlStyle } from './index.css'; import { RankContents } from './RankContents'; +const segmentOptions = [ + { label: '참가자 많은 순', value: 'participant' }, + { label: '빠른 시간 순', value: 'time' }, +]; const DiscussionRank = () => { const params: { id: string } = useParams({ from: '/_main/discussion/$id' }); const { rank, isLoading } @@ -15,8 +19,8 @@ const DiscussionRank = () => { {!isLoading && } diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx index 22d3f7b7..9679e9ad 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx @@ -5,7 +5,6 @@ import { Flex } from '@/components/Flex'; import Pagination from '@/components/Pagination'; import { useOngoingQuery } from '../../api/queries'; -import OngoingFallback from '../Fallbacks/OngoingFallback'; import type { OngoingSegmentOption } from '.'; import { paginationStyle } from './ongoingScheduleList.css'; import OngoingScheduleListItem from './OngoingScheduleListItem'; diff --git a/frontend/src/pages/HomePage/index.tsx b/frontend/src/pages/HomePage/index.tsx index d83b8f85..62a449de 100644 --- a/frontend/src/pages/HomePage/index.tsx +++ b/frontend/src/pages/HomePage/index.tsx @@ -13,7 +13,7 @@ const HomePage = () => { return (
- {/* + 다가오는 일정 - */} +
From fa4eae22e957fdafb5ce48e6f2ffa4f6ba0e6431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Tue, 18 Feb 2025 21:07:29 +0900 Subject: [PATCH 18/25] =?UTF-8?q?chore:=20=EC=9E=90=EC=9E=98=ED=95=9C=20?= =?UTF-8?q?=ED=9C=B4=EB=A8=BC=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared-schedule/ui/Fallbacks/UpcomingFallback.tsx | 4 ++-- .../shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/features/shared-schedule/ui/Fallbacks/UpcomingFallback.tsx b/frontend/src/features/shared-schedule/ui/Fallbacks/UpcomingFallback.tsx index 24c6113b..3dbe1baf 100644 --- a/frontend/src/features/shared-schedule/ui/Fallbacks/UpcomingFallback.tsx +++ b/frontend/src/features/shared-schedule/ui/Fallbacks/UpcomingFallback.tsx @@ -5,7 +5,7 @@ import { vars } from '@/theme/index.css'; import { containerStyle } from './index.css'; -const OngoingFallback = () => ( +const UpcomingFallback = () => ( ( ); -export default OngoingFallback; +export default UpcomingFallback; diff --git a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx index cf268119..472f668c 100644 --- a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx +++ b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx @@ -16,7 +16,7 @@ const UpcomingCarousel = ({ schedules, offsetX }: UpcomingCarouselProps) => ( > {schedules.map((schedule, index) => ( From d4998d25aab32b06617bb37e15c2cda999e6355c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Wed, 19 Feb 2025 14:55:15 +0900 Subject: [PATCH 19/25] =?UTF-8?q?feat:=20staletime=EC=9D=84=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20infinity=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/discussion/model/invitation.ts | 17 +++++++++++++++++ .../shared-schedule/api/queryOptions.ts | 14 +++++++------- frontend/src/main.tsx | 8 +++++++- 3 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 frontend/src/features/discussion/model/invitation.ts diff --git a/frontend/src/features/discussion/model/invitation.ts b/frontend/src/features/discussion/model/invitation.ts new file mode 100644 index 00000000..6c1cc36d --- /dev/null +++ b/frontend/src/features/discussion/model/invitation.ts @@ -0,0 +1,17 @@ +import { z } from 'zod'; + +import { zCoerceToBoolean, zCoerceToDate, zCoerceToTime } from '@/utils/zod'; + +export const InvitationResponseSchema = z.object({ + host: z.string(), + title: z.string(), + dateRangeStart: zCoerceToDate, + dateRangeEnd: zCoerceToDate, + timeRangeStart: zCoerceToTime, + timeRangeEnd: zCoerceToTime, + duration: z.number(), + isFull: zCoerceToBoolean, + requirePassword: zCoerceToBoolean, +}); + +export type InviteResponse = z.infer; diff --git a/frontend/src/features/shared-schedule/api/queryOptions.ts b/frontend/src/features/shared-schedule/api/queryOptions.ts index 972dea94..48b91b17 100644 --- a/frontend/src/features/shared-schedule/api/queryOptions.ts +++ b/frontend/src/features/shared-schedule/api/queryOptions.ts @@ -1,4 +1,4 @@ -import { MINUTE_IN_MILLISECONDS } from '@/utils/date'; +import { MINUTE_IN_MILLISECOND } from '@/utils/date'; import type { AttendType } from '../model'; import { schedulesApi } from '.'; @@ -8,19 +8,19 @@ export const sharedSchedulesQueryOptions = { upcoming: { queryKey: sharedScheduleQuerykeys.upcoming, queryFn: () => schedulesApi.getUpcomingSchedules(), - staleTime: 4 * MINUTE_IN_MILLISECONDS, - cacheTime: 5 * MINUTE_IN_MILLISECONDS, + staleTime: 4 * MINUTE_IN_MILLISECOND, + cacheTime: 5 * MINUTE_IN_MILLISECOND, }, ongoing: (page: number, size: number, attendtype: AttendType) => ({ queryKey: sharedScheduleQuerykeys.ongoing(page, size, attendtype), queryFn: () => schedulesApi.getOngoingSchedules(page, size, attendtype), - staleTime: 4 * MINUTE_IN_MILLISECONDS, - cacheTime: 5 * MINUTE_IN_MILLISECONDS, + staleTime: 4 * MINUTE_IN_MILLISECOND, + cacheTime: 5 * MINUTE_IN_MILLISECOND, }), finished: (page: number, size: number, year: number) => ({ queryKey: sharedScheduleQuerykeys.finished(page, size, year), queryFn: () => schedulesApi.getFinishedSchedules(page, size, year), - staleTime: 4 * MINUTE_IN_MILLISECONDS, - cacheTime: 5 * MINUTE_IN_MILLISECONDS, + staleTime: 4 * MINUTE_IN_MILLISECOND, + cacheTime: 5 * MINUTE_IN_MILLISECOND, }), }; diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index f06c875e..d72ed3a6 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -8,7 +8,13 @@ import { createRoot } from 'react-dom/client'; import { routeTree } from './routeTree.gen'; -const queryClient = new QueryClient(); +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + }, + }, +}); const router = createRouter({ routeTree, From 32beb3c4f883dcddef52a8b6dafa7cf3fa4e1d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Wed, 19 Feb 2025 15:15:39 +0900 Subject: [PATCH 20/25] =?UTF-8?q?feat:=20pagination=20hover=20=EC=8B=9C=20?= =?UTF-8?q?prefetch=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Pagination/PaginationItem.tsx | 9 ++++++++- frontend/src/components/Pagination/index.tsx | 1 + .../features/shared-schedule/api/prefetch.ts | 10 ++++++++-- .../FinishedScheduleList.tsx | 4 ++-- .../OngoingSchedules/OngoingScheduleList.tsx | 19 ++++++++++++------- frontend/src/hooks/usePagination.ts | 2 -- 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/Pagination/PaginationItem.tsx b/frontend/src/components/Pagination/PaginationItem.tsx index e44d443d..eebfcbac 100644 --- a/frontend/src/components/Pagination/PaginationItem.tsx +++ b/frontend/src/components/Pagination/PaginationItem.tsx @@ -11,9 +11,15 @@ interface PaginationItemProps { item: PaginationItemType; currentPage: number; onPageChange: (page: number) => void; + prefetchCallback?: (page: number) => void; } -const PaginationItem = ({ item, currentPage, onPageChange }: PaginationItemProps) => { +const PaginationItem = ({ + item, + currentPage, + onPageChange, + prefetchCallback, +}: PaginationItemProps) => { // 구분자 렌더링 if (item === SEPARATOR) { return ( @@ -30,6 +36,7 @@ const PaginationItem = ({ item, currentPage, onPageChange }: PaginationItemProps className={paginationItemStyle({ selected: isSelected })} key={`page-${item}`} onClick={() => onPageChange(item)} + onMouseEnter={() => prefetchCallback?.(item)} > {item} diff --git a/frontend/src/components/Pagination/index.tsx b/frontend/src/components/Pagination/index.tsx index 3cee8861..90fb1656 100644 --- a/frontend/src/components/Pagination/index.tsx +++ b/frontend/src/components/Pagination/index.tsx @@ -13,6 +13,7 @@ interface PaginationProps { totalPages: number; onPageChange: (page: number) => void; className?: string; + prefetchCallback?: (page: number) => void; } const Pagination = ({ diff --git a/frontend/src/features/shared-schedule/api/prefetch.ts b/frontend/src/features/shared-schedule/api/prefetch.ts index bfe2776a..a1f0f201 100644 --- a/frontend/src/features/shared-schedule/api/prefetch.ts +++ b/frontend/src/features/shared-schedule/api/prefetch.ts @@ -1,13 +1,19 @@ import type { QueryClient } from '@tanstack/react-query'; +import type { AttendType } from '../model'; import { sharedSchedulesQueryOptions } from './queryOptions'; export const prefetchUpcomingSchedules = async (queryClient: QueryClient) => { await queryClient.prefetchQuery(sharedSchedulesQueryOptions.upcoming); }; -export const prefetchOngoingSchedules = async (queryClient: QueryClient) => { - await queryClient.prefetchQuery(sharedSchedulesQueryOptions.ongoing(1, 10, 'ALL')); +export const prefetchOngoingSchedules = async ( + queryClient: QueryClient, + page: number, + size: number, + attendType: AttendType, +) => { + await queryClient.prefetchQuery(sharedSchedulesQueryOptions.ongoing(page, size, attendType)); }; export const prefetchFinishedSchedules = async (queryClient: QueryClient) => { diff --git a/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx index 7995f5fd..a0d757ee 100644 --- a/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/FinishedSchedules/FinishedScheduleList.tsx @@ -9,7 +9,7 @@ import FinishedFallback from '../Fallbacks/FinishedFallback'; import { paginationStyle } from './finishedScheduleList.css'; import FinishedScheduleListItem from './FinishedScheduleListItem'; -const PAGE_SIZE = 7; +export const FINISHED_PAGE_SIZE = 7; interface FinishedScheduleListProps { baseYear: number; @@ -17,7 +17,7 @@ interface FinishedScheduleListProps { const FinishedScheduleList = ({ baseYear }: FinishedScheduleListProps) => { const [currentPage, setCurrentPage] = useState(1); - const { data, isPending } = useFinishedQuery(currentPage, PAGE_SIZE, baseYear); + const { data, isPending } = useFinishedQuery(currentPage, FINISHED_PAGE_SIZE, baseYear); if (isPending) return
pending...
; if (!data) return
data is undefined or null
; if (data.finishedDiscussions.length === 0) return ; diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx index 9679e9ad..97fba149 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx @@ -1,15 +1,17 @@ -import { useState } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; import { Flex } from '@/components/Flex'; import Pagination from '@/components/Pagination'; +import { usePagination } from '@/hooks/usePagination'; +import { prefetchOngoingSchedules } from '../../api/prefetch'; import { useOngoingQuery } from '../../api/queries'; import type { OngoingSegmentOption } from '.'; import { paginationStyle } from './ongoingScheduleList.css'; import OngoingScheduleListItem from './OngoingScheduleListItem'; -const PAGE_SIZE = 6; +export const ONGOING_PAGE_SIZE = 6; interface OngoingScheduleListProps { segmentOption: OngoingSegmentOption; @@ -17,12 +19,13 @@ interface OngoingScheduleListProps { } const OngoingScheduleList = ({ segmentOption, onSelect }: OngoingScheduleListProps) => { - const [page, setPage] = useState(1); - const { data, isPending } = useOngoingQuery(page, PAGE_SIZE, segmentOption.value); + const queryClient = useQueryClient(); + const paginationProps = usePagination(1); + const { data, isPending } = useOngoingQuery(1, ONGOING_PAGE_SIZE, segmentOption.value); if (isPending) return
pending...
; if (!data || data.ongoingDiscussions.length === 0) return
no data available
; const schedules = data.ongoingDiscussions; - + return ( setPage(page)} + {...paginationProps} + prefetchCallback={(page) => prefetchOngoingSchedules( + queryClient, page, ONGOING_PAGE_SIZE, segmentOption.value, + )} totalPages={data.totalPages} /> diff --git a/frontend/src/hooks/usePagination.ts b/frontend/src/hooks/usePagination.ts index 601b20d0..281ce15f 100644 --- a/frontend/src/hooks/usePagination.ts +++ b/frontend/src/hooks/usePagination.ts @@ -2,7 +2,6 @@ import { useState } from 'react'; export const usePagination = ( initialPage: number, - totalPages: number, ) => { const [currentPage, setCurrentPage] = useState(initialPage); const onPageChange = (page: number) => { @@ -12,6 +11,5 @@ export const usePagination = ( return { currentPage, onPageChange, - totalPages, }; }; From 282dd36ab3288754e9566ad404a066ad834f3a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Wed, 19 Feb 2025 15:26:31 +0900 Subject: [PATCH 21/25] =?UTF-8?q?feat:=20Segment=20Control=EC=97=90?= =?UTF-8?q?=EB=8F=84=20button=20hover=20=EC=8B=9C=20prefetch=20=EB=84=98?= =?UTF-8?q?=EA=B8=B8=20=EC=88=98=20=EC=9E=88=EA=B2=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Pagination/PaginationItem.tsx | 6 +++--- frontend/src/components/Pagination/index.tsx | 4 +++- frontend/src/components/SegmentControl/ControlButton.tsx | 3 +++ frontend/src/components/SegmentControl/index.tsx | 4 +++- .../ui/OngoingSchedules/OngoingScheduleList.tsx | 4 ++-- .../features/shared-schedule/ui/OngoingSchedules/index.tsx | 7 ++++++- 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/Pagination/PaginationItem.tsx b/frontend/src/components/Pagination/PaginationItem.tsx index eebfcbac..49de6fa9 100644 --- a/frontend/src/components/Pagination/PaginationItem.tsx +++ b/frontend/src/components/Pagination/PaginationItem.tsx @@ -11,14 +11,14 @@ interface PaginationItemProps { item: PaginationItemType; currentPage: number; onPageChange: (page: number) => void; - prefetchCallback?: (page: number) => void; + onHover?: (page: number) => void; } const PaginationItem = ({ item, currentPage, onPageChange, - prefetchCallback, + onHover, }: PaginationItemProps) => { // 구분자 렌더링 if (item === SEPARATOR) { @@ -36,7 +36,7 @@ const PaginationItem = ({ className={paginationItemStyle({ selected: isSelected })} key={`page-${item}`} onClick={() => onPageChange(item)} - onMouseEnter={() => prefetchCallback?.(item)} + onMouseEnter={() => onHover?.(item)} > {item} diff --git a/frontend/src/components/Pagination/index.tsx b/frontend/src/components/Pagination/index.tsx index 90fb1656..28089c19 100644 --- a/frontend/src/components/Pagination/index.tsx +++ b/frontend/src/components/Pagination/index.tsx @@ -13,13 +13,14 @@ interface PaginationProps { totalPages: number; onPageChange: (page: number) => void; className?: string; - prefetchCallback?: (page: number) => void; + onPageButtonHover?: (page: number) => void; } const Pagination = ({ currentPage, totalPages, onPageChange, + onPageButtonHover, className, }: PaginationProps) => { const pages = getPaginationItems(currentPage, totalPages); @@ -31,6 +32,7 @@ const Pagination = ({ currentPage={currentPage} item={item} key={index} + onHover={onPageButtonHover} onPageChange={onPageChange} />, )} diff --git a/frontend/src/components/SegmentControl/ControlButton.tsx b/frontend/src/components/SegmentControl/ControlButton.tsx index 29475959..1e7a675f 100644 --- a/frontend/src/components/SegmentControl/ControlButton.tsx +++ b/frontend/src/components/SegmentControl/ControlButton.tsx @@ -7,11 +7,13 @@ import { SegmentControlContext } from './SegmentControlContext'; interface ControlButtonProps { segmentOption: SegmentOption; segmentControlStyle: SegmentControlProps['style']; + onButtonHover?: (value: string) => void; } const ControlButton = ({ segmentOption, segmentControlStyle, + onButtonHover, }: ControlButtonProps ) => { const { selectedValue, handleSelect } = useSafeContext(SegmentControlContext); const { label, value } = segmentOption; @@ -19,6 +21,7 @@ const ControlButton = ({ - + + + +
From a570fc1c3217d9ed4d59246de788aceadb8783b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Wed, 19 Feb 2025 18:11:17 +0900 Subject: [PATCH 24/25] =?UTF-8?q?feat:=20=ED=99=95=EC=A0=95=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=9D=BC=EC=A0=95=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OngoingSchedules/OngoingScheduleList.tsx | 27 ++++++++++--------- .../ui/OngoingSchedules/index.tsx | 5 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx index bbe3cf04..0e00dfa4 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/OngoingScheduleList.tsx @@ -15,16 +15,16 @@ export const ONGOING_PAGE_SIZE = 6; interface OngoingScheduleListProps { segmentOption: OngoingSegmentOption; + selectedId: number; onSelect: (discussionId: number) => void; } -const OngoingScheduleList = ({ segmentOption, onSelect }: OngoingScheduleListProps) => { +const OngoingScheduleList = ({ segmentOption, selectedId, onSelect }: OngoingScheduleListProps) => { const queryClient = useQueryClient(); const { currentPage, onPageChange } = usePagination(1); const { data, isPending } = useOngoingQuery(currentPage, ONGOING_PAGE_SIZE, segmentOption.value); if (isPending) return
pending...
; if (!data || data.ongoingDiscussions.length === 0) return
no data available
; - const schedules = data.ongoingDiscussions; return ( - {schedules.map((schedule, index) => ( + {data.ongoingDiscussions.map((schedule, index) => ( onSelect(id)} schedule={schedule} - selected={false} + selected={selectedId === schedule.discussionId} />))} - prefetchOngoingSchedules( - queryClient, page, ONGOING_PAGE_SIZE, segmentOption.value, - )} - onPageChange={onPageChange} - totalPages={data.totalPages} - /> + {data.totalPages > 0 && + prefetchOngoingSchedules( + queryClient, page, ONGOING_PAGE_SIZE, segmentOption.value, + )} + onPageChange={onPageChange} + totalPages={data.totalPages} + />}
); }; diff --git a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx index 56ece9d3..db2fd953 100644 --- a/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx +++ b/frontend/src/features/shared-schedule/ui/OngoingSchedules/index.tsx @@ -59,8 +59,9 @@ const Content = () => {
setSelectedDiscussionId(id)} - segmentOption={option} + onSelect={(id) => setSelectedDiscussionId(id)} + segmentOption={option} + selectedId={selectedDiscussionId} />
From 797402ac4886970a9cdcfa03ee921503576824cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=98=81?= Date: Wed, 19 Feb 2025 18:48:20 +0900 Subject: [PATCH 25/25] =?UTF-8?q?chore:=20=EB=B9=8C=EB=93=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/discussion/model/invitation.ts | 6 ++--- .../ui/UpcomingSchedules/UpcomingCarousel.tsx | 2 +- frontend/src/utils/date/time.ts | 27 +++++++++++++++++++ frontend/src/utils/zod/index.ts | 4 +++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/frontend/src/features/discussion/model/invitation.ts b/frontend/src/features/discussion/model/invitation.ts index 585647ef..ee5f94d6 100644 --- a/frontend/src/features/discussion/model/invitation.ts +++ b/frontend/src/features/discussion/model/invitation.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { zCoerceToBoolean, zCoerceToDate, zCoerceToTime } from '@/utils/zod'; +import { zCoerceToDate, zCoerceToTime } from '@/utils/zod'; export const InvitationResponseSchema = z.object({ host: z.string(), @@ -10,8 +10,8 @@ export const InvitationResponseSchema = z.object({ timeRangeStart: zCoerceToTime, timeRangeEnd: zCoerceToTime, duration: z.number(), - isFull: zCoerceToBoolean, - requirePassword: zCoerceToBoolean, + isFull: z.boolean(), + requirePassword: z.boolean(), }); export const InvitationJoinRequestSchema = z.object({ diff --git a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx index 472f668c..797cec31 100644 --- a/frontend/src/features/shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx +++ b/frontend/src/features/shared-schedule/ui/UpcomingSchedules/UpcomingCarousel.tsx @@ -14,7 +14,7 @@ const UpcomingCarousel = ({ schedules, offsetX }: UpcomingCarouselProps) => ( className={carouselTrackStyle} style={{ transform: `translateX(${offsetX}px)` }} > - {schedules.map((schedule, index) => ( + {schedules.map((schedule) => ( { + const parts = timeStr.trim().split(':'); + if (parts.length < 2 || parts.length > 3) { + throw new Error('parseTime: Invalid time format'); + } + + const [hourStr, minuteStr, secondStr = '0'] = parts; + const hour = Number(hourStr); + const minute = Number(minuteStr); + const second = Number(secondStr); + + if (isNaN(hour) || isNaN(minute) || isNaN(second)) { + throw new Error('parseTime: Invalid numeric values in time string'); + } + if (hour < 0 || hour > 23) throw new Error('parseTime: Hour must be between 0 and 23'); + if (minute < 0 || minute > 59) throw new Error('parseTime: Minute must be between 0 and 59'); + if (second < 0 || second > 59) throw new Error('parseTime: Second must be between 0 and 59'); + + return { hour, minute, second }; +}; diff --git a/frontend/src/utils/zod/index.ts b/frontend/src/utils/zod/index.ts index 4bbeb2e9..06dd4399 100644 --- a/frontend/src/utils/zod/index.ts +++ b/frontend/src/utils/zod/index.ts @@ -2,6 +2,8 @@ import { z } from 'zod'; import { DATE_BAR, TIME } from '@/constants/regex'; +import { parseTime } from '../date'; + export const zDate = z.string().regex(DATE_BAR) .transform((v) => new Date(v)); @@ -11,3 +13,5 @@ export const zTime = z.string().regex(TIME) const datelike = z.union([z.number(), z.string(), z.date()]); export const zCoerceToDate = datelike.pipe(z.coerce.date()); +export const zCoerceToTime = z.string().time() + .transform((timeStr) => parseTime(timeStr)); \ No newline at end of file