From c0a2293f68e85d77beb2e7690b9c40a21719b8b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Sat, 30 Aug 2025 16:21:40 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20Data-selector=20=EB=82=A0=EC=A7=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/ui/data-selector.tsx | 11 ++++++----- src/features/study/ui/study-card.tsx | 24 +++++++++++++++--------- src/shared/lib/time.ts | 16 +++++++++++++++- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/features/study/ui/data-selector.tsx b/src/features/study/ui/data-selector.tsx index e1c94d2c..0f75625e 100644 --- a/src/features/study/ui/data-selector.tsx +++ b/src/features/study/ui/data-selector.tsx @@ -1,7 +1,8 @@ 'use client'; -import { startOfWeek, addDays, format, isSameDay } from 'date-fns'; +import { addDays, format, isSameDay } from 'date-fns'; import { useMemo } from 'react'; +import { getKoreaDisplayMonday } from '@/shared/lib/time'; interface Props { value: Date; @@ -9,12 +10,12 @@ interface Props { } export default function DateSelector({ value, onChange }: Props) { - const today = new Date(); - const monday = startOfWeek(today, { weekStartsOn: 1 }); const dayLabels = ['월', '화', '수', '목', '금']; + + const displayMonday = useMemo(() => getKoreaDisplayMonday(), []); const dates = useMemo( - () => Array.from({ length: 5 }, (_, i) => addDays(monday, i)), - [monday], + () => Array.from({ length: 5 }, (_, i) => addDays(displayMonday, i)), + [displayMonday], ); return ( diff --git a/src/features/study/ui/study-card.tsx b/src/features/study/ui/study-card.tsx index 0edb1e8d..04082f97 100644 --- a/src/features/study/ui/study-card.tsx +++ b/src/features/study/ui/study-card.tsx @@ -1,7 +1,12 @@ 'use client'; import { getMonth, getDay, startOfWeek, getDate } from 'date-fns'; -import { useState } from 'react'; +import { useMemo, useState } from 'react'; +import { + formatKoreaYMD, + getKoreaDate, + getKoreaDisplayMonday, +} from '@/shared/lib/time'; import DateSelector from './data-selector'; import TodayStudyCard from './today-study-card'; import StudyListSection from '../../../widgets/home/study-list-table'; @@ -12,13 +17,13 @@ import ReservationList from '../participation/ui/reservation-list'; // 스터디 주차 구하는 함수 function getWeekly(date: Date): { month: number; week: number } { const weekStartsOn = 0; - const target = new Date(date); - const currentWeekStart = startOfWeek(target, { weekStartsOn }); + const targetKST = getKoreaDate(date); + const currentWeekStart = startOfWeek(targetKST, { weekStartsOn }); const baseMonth = getMonth(currentWeekStart); // 목요일 기준 월의 첫 주 시작일 계산 - const firstOfMonth = new Date(target.getFullYear(), baseMonth, 1); + const firstOfMonth = new Date(targetKST.getFullYear(), baseMonth, 1); const firstWeekStart = startOfWeek(firstOfMonth, { weekStartsOn }); const firstDayOfWeek = getDay(firstOfMonth); const officialFirstWeekStart = @@ -56,17 +61,18 @@ function getWeekly(date: Date): { month: number; week: number } { export default function StudyCard() { const [selectedDate, setSelectedDate] = useState(new Date()); - const offset = selectedDate.getTimezoneOffset() * 60000; // ms단위라 60000곱해줌 - const dateOffset = new Date(selectedDate.getTime() - offset); - - const studyDate = dateOffset.toISOString().split('T')[0]; + const studyDate = formatKoreaYMD(selectedDate); const { data: status } = useStudyStatusQuery(); const { data: participationData } = useWeeklyParticipation(studyDate); const isParticipate = participationData?.isParticipate ?? false; - const { month, week } = getWeekly(selectedDate); + const displayMonday = useMemo( + () => getKoreaDisplayMonday(selectedDate), + [selectedDate], + ); + const { month, week } = getWeekly(displayMonday); return ( <> diff --git a/src/shared/lib/time.ts b/src/shared/lib/time.ts index 662bba84..9ef0d565 100644 --- a/src/shared/lib/time.ts +++ b/src/shared/lib/time.ts @@ -1,10 +1,13 @@ import { + addDays, differenceInDays, differenceInHours, differenceInMinutes, + format, + getDay, parseISO, + startOfWeek, } from 'date-fns'; -import { format } from 'path'; export const getKoreaDate = (targetDate?: Date) => { const date = targetDate || new Date(); @@ -17,6 +20,9 @@ export const getKoreaDate = (targetDate?: Date) => { return koreaNow; }; +export const formatKoreaYMD = (targetDate?: Date) => + format(getKoreaDate(targetDate), 'yyyy-MM-dd'); + export const formatKoreaRelativeTime = (targetDateStr: string): string => { const targetDate = parseISO(targetDateStr); const koreaTarget = getKoreaDate(targetDate); // 한국 시간 변환 @@ -35,3 +41,11 @@ export const formatKoreaRelativeTime = (targetDateStr: string): string => { return targetDateStr; }; + +export const getKoreaDisplayMonday = (base?: Date) => { + const todayKST = getKoreaDate(base); + const monday = startOfWeek(todayKST, { weekStartsOn: 1 }); // 월요일 시작 + const dow = getDay(todayKST); // 0=일, 6=토 + + return dow === 0 || dow === 6 ? addDays(monday, 7) : monday; +}; From 525cf7cb86e725a0a79421a0a6f776feff54bd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Sat, 30 Aug 2025 16:30:09 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=EC=BA=98=EB=A6=B0=EB=8D=94=20count?= =?UTF-8?q?=EA=B0=80=20undefined=20=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/api/types.ts | 4 ++-- src/widgets/home/calendar.tsx | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/features/study/api/types.ts b/src/features/study/api/types.ts index a77cbd89..70fd16c9 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/api/types.ts @@ -59,8 +59,8 @@ export interface StudyCalendarDay { export interface MonthlyCalendarResponse { calendar: StudyCalendarDay[]; - monthlyCompletedCount: number; - totalCompletedCount: number; + monthlyCompletedCount?: number; + totalCompletedCount?: number; } export interface PostDailyRetrospectRequest { diff --git a/src/widgets/home/calendar.tsx b/src/widgets/home/calendar.tsx index 1d4769a0..402fd09d 100644 --- a/src/widgets/home/calendar.tsx +++ b/src/widgets/home/calendar.tsx @@ -79,6 +79,11 @@ const Calendar = (props: React.ComponentProps) => { if (isLoading) return
로딩 중...
; + const monthlyCount = data?.monthlyCompletedCount; + const totalCount = data?.totalCompletedCount; + const showFooter = + typeof monthlyCount === 'number' && typeof totalCount === 'number'; + return (
) => { day: 'text-center font-designer-14m rounded-full', }} footer={ -
-
- {month}월은 {data.monthlyCompletedCount}번의 스터디를 완료했어요. -
-
- 총 {data.totalCompletedCount}번의 스터디를 완료했어요. + showFooter ? ( +
+
+ {month}월은 {data.monthlyCompletedCount}번의 스터디를 + 완료했어요. +
+
+ 총 {data.totalCompletedCount}번의 스터디를 완료했어요. +
-
+ ) : undefined } {...props} />