From 90a9e05b56be7bc3c7b597d271621ab0e927c812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9A=94=EC=88=A0=ED=86=A0=EB=81=BC?= Date: Wed, 19 Jul 2023 18:28:39 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EC=9D=BC=EC=A0=95=EC=9D=B4=20?= =?UTF-8?q?=ED=95=B4=EB=8B=B9=20=EB=8B=AC=EC=9D=98=20=EB=B2=94=EC=9C=84?= =?UTF-8?q?=EB=A5=BC=20=EB=B2=97=EC=96=B4=EB=82=98=EB=8D=94=EB=9D=BC?= =?UTF-8?q?=EB=8F=84=20=EB=B3=B4=EC=9D=B4=EB=8A=94=20=EB=B6=80=EB=B6=84?= =?UTF-8?q?=EC=9D=84=20=EC=A0=81=EC=A0=88=ED=9E=88=20=EB=9E=9C=EB=8D=94?= =?UTF-8?q?=EB=A7=81=ED=95=98=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/generateScheduleBars.ts | 90 +++++++++++++++------- 1 file changed, 61 insertions(+), 29 deletions(-) diff --git a/frontend/src/utils/generateScheduleBars.ts b/frontend/src/utils/generateScheduleBars.ts index dfc109492..6b921b74d 100644 --- a/frontend/src/utils/generateScheduleBars.ts +++ b/frontend/src/utils/generateScheduleBars.ts @@ -11,15 +11,15 @@ interface Position { type CalendarObject = Record; /** - * 《convertSchedulesToBars》 + * 《generateScheduleBars》 * 이 유틸 함수는 가공 전의 스케줄 데이터를 받고, 이를 즉시 랜더링이 가능한 바 형태로 내보내는 역할을 수행합니다. * - 스케줄 바를 한 줄에 랜더링할 수 있도록 여러 줄에 걸친 스케줄을 여러 개의 작은 스케줄로 쪼갭니다. * - 스케줄이 중첩될 경우 겹치지 않는 적절한 위치에 랜더링할 수 있도록 level 값을 포함하여 제공합니다. * - * * @param year - 스케줄 바를 표시할 연도 - * @param month - 스케줄 바를 표시할 월 (주의: 일상생활에서의 월 그대로를 사용해 주세요 - 7월일 경우: 7) + * @param month - 스케줄 바를 표시할 월 * @param schedules - 가공되기 전의 스케줄 데이터가 저장된 배열 + * @returns leveledScheduleBars - ScheduleBarProps 타입의 형태로 결과물을 반환합니다 */ export const generateScheduleBars = ( year: number, @@ -27,26 +27,41 @@ export const generateScheduleBars = ( schedules: Schedule[], ) => { const calendarObject = generateCalendarObject(year, month); - const rawScheduleBars = generateRawScheduleBars(schedules, calendarObject); + const rawScheduleBars = generateRawScheduleBars( + year, + month, + schedules, + calendarObject, + ); const slicedScheduleBars = sliceScheduleBars(rawScheduleBars); const leveledScheduleBars = giveLevelToScheduleBars(slicedScheduleBars); return leveledScheduleBars; }; -const generateCalendarObject = (year: number, month: number) => { - const firstDayOfMonth = new Date(year, month); - const firstDayOfCalendar = new Date( - firstDayOfMonth.getTime() - ONE_DAY * firstDayOfMonth.getDay(), +const getFirstLastDateOfCalendar = (year: number, month: number) => { + const firstDateOfMonth = new Date(year, month); + const firstDateOfCalendar = new Date( + firstDateOfMonth.getTime() - ONE_DAY * firstDateOfMonth.getDay(), + ); + const lastDateOfCalendar = new Date( + firstDateOfCalendar.getTime() + + CALENDAR.ROW_SIZE * CALENDAR.COLUMN_SIZE * ONE_DAY - + 1, ); + return { firstDateOfCalendar, lastDateOfCalendar }; +}; + +const generateCalendarObject = (year: number, month: number) => { + const { firstDateOfCalendar } = getFirstLastDateOfCalendar(year, month); const calendarObject: CalendarObject = {}; Array.from( { length: CALENDAR.ROW_SIZE * CALENDAR.COLUMN_SIZE }, (_, index) => { const currentDate = new Date( - firstDayOfCalendar.getTime() + index * ONE_DAY, + firstDateOfCalendar.getTime() + index * ONE_DAY, ); const formattedDate = formatDate(currentDate); const position = { @@ -62,34 +77,51 @@ const generateCalendarObject = (year: number, month: number) => { }; const formatDate = (rawDate: Date) => { - const { month, date } = parseDate(rawDate); - const formattedDate = `${month + 1}/${date}`; + const { year, month, date } = parseDate(rawDate); + const formattedDate = `${year}/${month + 1}/${date}`; return formattedDate; }; const generateRawScheduleBars = ( + year: number, + month: number, schedules: Schedule[], calendarObject: CalendarObject, ) => { - const rawScheduleBars: ScheduleBarProps[] = schedules.map((schedule) => { + const rawScheduleBars: ScheduleBarProps[] = []; + + schedules.forEach((schedule) => { const { startDateTime, endDateTime, id: scheduleId, title } = schedule; - const startDate = new Date(startDateTime); - const duration = calcDuration(startDateTime, endDateTime); - const { row, column } = calendarObject[formatDate(startDate)]; - const id = crypto.randomUUID(); - const randomColor = Math.floor(Math.random() * 16777215).toString(16); - - return { - id, - scheduleId, - title, - row, - column, - duration, - level: 0, - color: `#${randomColor}`, - }; + const { firstDateOfCalendar, lastDateOfCalendar } = + getFirstLastDateOfCalendar(year, month); + const startDate = new Date( + Math.max( + new Date(startDateTime).getTime(), + firstDateOfCalendar.getTime(), + ), + ); + const endDate = new Date( + Math.min(new Date(endDateTime).getTime(), lastDateOfCalendar.getTime()), + ); + + if (startDate <= endDate) { + const duration = calcDuration(startDateTime, endDateTime); + const id = crypto.randomUUID(); + const randomColor = Math.floor(Math.random() * 16777215).toString(16); + const { row, column } = calendarObject[formatDate(startDate)]; + + rawScheduleBars.push({ + id, + scheduleId, + title, + row, + column, + duration, + level: 0, + color: `#${randomColor}`, + }); + } }); return rawScheduleBars; @@ -129,7 +161,7 @@ const sliceScheduleBars = (rawScheduleBars: ScheduleBarProps[]) => { let currentRow = row; let currentColumn = column; - while (remainingDuration > 0 && currentRow <= CALENDAR.ROW_SIZE) { + while (remainingDuration > 0 && currentRow < CALENDAR.ROW_SIZE) { const currentDuration = Math.min( remainingDuration, CALENDAR.COLUMN_SIZE - currentColumn, From a106c25289ce60cd7e51a88332c724a966138619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9A=94=EC=88=A0=ED=86=A0=EB=81=BC?= Date: Wed, 19 Jul 2023 19:45:53 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=EC=97=AC=EB=9F=AC=20=EC=A3=BC?= =?UTF-8?q?=EC=9D=98=20=EA=B1=B8=EC=B9=9C=20=EC=9D=BC=EC=A0=95=EC=9D=98=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20level=EC=9D=B4=20=EC=9E=98=EB=AA=BB=20?= =?UTF-8?q?=EC=A0=95=ED=95=B4=EC=A7=80=EB=8A=94=20=EB=AC=B8=EC=A0=9C?= =?UTF-8?q?=EB=A5=BC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 예를 들어, 두 주에 걸친 일정이 첫 주에는 level 0, 두 번째 주에는 level 1에 배정되는 경우가 있었다. --- frontend/src/utils/generateScheduleBars.ts | 39 +++++++++++----------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/frontend/src/utils/generateScheduleBars.ts b/frontend/src/utils/generateScheduleBars.ts index 6b921b74d..0ab1a3c92 100644 --- a/frontend/src/utils/generateScheduleBars.ts +++ b/frontend/src/utils/generateScheduleBars.ts @@ -15,6 +15,7 @@ type CalendarObject = Record; * 이 유틸 함수는 가공 전의 스케줄 데이터를 받고, 이를 즉시 랜더링이 가능한 바 형태로 내보내는 역할을 수행합니다. * - 스케줄 바를 한 줄에 랜더링할 수 있도록 여러 줄에 걸친 스케줄을 여러 개의 작은 스케줄로 쪼갭니다. * - 스케줄이 중첩될 경우 겹치지 않는 적절한 위치에 랜더링할 수 있도록 level 값을 포함하여 제공합니다. + * - 잘리는 일정이나 잘못된 일정이 있는 경우도 처리가 가능합니다. * * @param year - 스케줄 바를 표시할 연도 * @param month - 스케줄 바를 표시할 월 @@ -33,10 +34,10 @@ export const generateScheduleBars = ( schedules, calendarObject, ); - const slicedScheduleBars = sliceScheduleBars(rawScheduleBars); - const leveledScheduleBars = giveLevelToScheduleBars(slicedScheduleBars); + const leveledScheduleBars = giveLevelToScheduleBars(rawScheduleBars); + const slicedScheduleBars = sliceScheduleBars(leveledScheduleBars); - return leveledScheduleBars; + return slicedScheduleBars; }; const getFirstLastDateOfCalendar = (year: number, month: number) => { @@ -106,9 +107,8 @@ const generateRawScheduleBars = ( ); if (startDate <= endDate) { - const duration = calcDuration(startDateTime, endDateTime); + const duration = calcDuration(startDate, endDate); const id = crypto.randomUUID(); - const randomColor = Math.floor(Math.random() * 16777215).toString(16); const { row, column } = calendarObject[formatDate(startDate)]; rawScheduleBars.push({ @@ -119,7 +119,7 @@ const generateRawScheduleBars = ( column, duration, level: 0, - color: `#${randomColor}`, + color: '#000', }); } }); @@ -127,12 +127,13 @@ const generateRawScheduleBars = ( return rawScheduleBars; }; -const calcDuration = ( - start: Schedule['startDateTime'], - end: Schedule['endDateTime'], -) => { - const [startDate] = start.split(' '); - const [endDate] = end.split(' '); +const calcDuration = (start: Date, end: Date) => { + const startDate = new Date( + start.getFullYear(), + start.getMonth(), + start.getDate(), + ); + const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate()); const diff = new Date(startDate).getTime() - new Date(endDate).getTime(); return Math.abs(diff / ONE_DAY) + 1; @@ -185,25 +186,23 @@ const sliceScheduleBars = (rawScheduleBars: ScheduleBarProps[]) => { const giveLevelToScheduleBars = (scheduleBars: ScheduleBarProps[]) => { const leveledScheduleBars: ScheduleBarProps[] = []; - const lastIndexes: number[][] = Array.from({ length: CALENDAR.ROW_SIZE }).map( - () => [], - ); + const lastIndexes: number[] = []; const sortedScheduleBars = sortScheduleBars(scheduleBars); sortedScheduleBars.forEach((scheduleBar) => { const { row, column, duration } = scheduleBar; - const level = lastIndexes[row].findIndex( - (lastIndex: number) => lastIndex < column, + const level = lastIndexes.findIndex( + (lastIndex: number) => lastIndex < row * CALENDAR.COLUMN_SIZE + column, ); if (level === -1) { - lastIndexes[row].push(column + duration - 1); + lastIndexes.push(row * CALENDAR.COLUMN_SIZE + column + duration - 1); leveledScheduleBars.push({ ...scheduleBar, - level: lastIndexes[row].length - 1, + level: lastIndexes.length - 1, }); } else { - lastIndexes[row][level] = column + duration - 1; + lastIndexes[level] = row * CALENDAR.COLUMN_SIZE + column + duration - 1; leveledScheduleBars.push({ ...scheduleBar, level,