Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] 캘린더 바 버그 수정 및 안정성 개선 #123

Merged
merged 2 commits into from
Jul 20, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 77 additions & 46 deletions frontend/src/utils/generateScheduleBars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,58 @@ interface Position {
type CalendarObject = Record<string, Position>;

/**
* 《convertSchedulesToBars
* 《generateScheduleBars
* 이 유틸 함수는 가공 전의 스케줄 데이터를 받고, 이를 즉시 랜더링이 가능한 바 형태로 내보내는 역할을 수행합니다.
* - 스케줄 바를 한 줄에 랜더링할 수 있도록 여러 줄에 걸친 스케줄을 여러 개의 작은 스케줄로 쪼갭니다.
* - 스케줄이 중첩될 경우 겹치지 않는 적절한 위치에 랜더링할 수 있도록 level 값을 포함하여 제공합니다.
*
* - 잘리는 일정이나 잘못된 일정이 있는 경우도 처리가 가능합니다.
*
* @param year - 스케줄 바를 표시할 연도
* @param month - 스케줄 바를 표시할 월 (주의: 일상생활에서의 월 그대로를 사용해 주세요 - 7월일 경우: 7)
* @param month - 스케줄 바를 표시할 월
* @param schedules - 가공되기 전의 스케줄 데이터가 저장된 배열
* @returns leveledScheduleBars - ScheduleBarProps 타입의 형태로 결과물을 반환합니다
*/
export const generateScheduleBars = (
year: number,
month: number,
schedules: Schedule[],
) => {
const calendarObject = generateCalendarObject(year, month);
const rawScheduleBars = generateRawScheduleBars(schedules, calendarObject);
const slicedScheduleBars = sliceScheduleBars(rawScheduleBars);
const leveledScheduleBars = giveLevelToScheduleBars(slicedScheduleBars);
const rawScheduleBars = generateRawScheduleBars(
year,
month,
schedules,
calendarObject,
);
const leveledScheduleBars = giveLevelToScheduleBars(rawScheduleBars);
const slicedScheduleBars = sliceScheduleBars(leveledScheduleBars);

return leveledScheduleBars;
return slicedScheduleBars;
};

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 = {
Expand All @@ -62,45 +78,62 @@ 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(startDate, endDate);
const id = crypto.randomUUID();
const { row, column } = calendarObject[formatDate(startDate)];

rawScheduleBars.push({
id,
scheduleId,
title,
row,
column,
duration,
level: 0,
color: '#000',
});
}
});

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());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseDate 써도 좋을듯?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉... 아쉽게도 parseDate 유틸함수를 두 번 써야 하는 경우라 변수명이 겹쳐서 당장은 힘들어 보인다
그치만 이 코드들은 계속해서 개선해볼게

const diff = new Date(startDate).getTime() - new Date(endDate).getTime();

return Math.abs(diff / ONE_DAY) + 1;
Expand Down Expand Up @@ -129,7 +162,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,
Expand All @@ -153,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,
Expand Down