Info

  • ์ผ์ • ๋ฐ์ดํ„ฐ.
  • class ํ˜•ํƒœ๋กœ ๊ตฌํ˜„.
  • TIME/TASK ์œผ๋กœ type์ด ๊ตฌ๋ถ„๋จ.
    • TIME: ๋…„/์›”/์ผ/์‹œ/๋ถ„ ๋‹จ์œ„๋กœ ์ผ์ •์„ ๊ด€๋ฆฌ
    • TASK: ๋…„/์›”/์ผ ๋‹จ์œ„๋กœ ์ผ์ •์„ ๊ด€๋ฆฌ

Schedule

  • DB์—์„œ ๊ด€๋ฆฌ๋˜๋Š” Schedule ๋ฐ์ดํ„ฐ ์ž์ฒด.
  • FE์—์„œ ๋‹ค์–‘ํ•œ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ตœ๋Œ€ํ•œ ๊ธฐ๋ณธ ํ˜•ํƒœ๋กœ ๊ตฌํ˜„.
  • ๋‚ ์งœ ํ•„๋“œ๋Š” string ํƒ€์ž…์œผ๋กœ "YYYY/MM/DD HH:mm:ss" ํ˜•ํƒœ
    • ์‚ฌ์šฉ ์‹œ, dayjs๋ฅผ ์‚ฌ์šฉ ํ•˜์—ฌ, ํฌ๋ฉง ํ•„์š”.

Structure

  • Schedule ๊ฐ์ฒด๋Š” ํฌ๊ด„์ ์ธ ๋‚ ์งœ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ๊ฐ์˜ ๋‚ ์งœ์— ๋Œ€ํ•œ ์ผ์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ScheduleOfDate ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ ํ•„์š”.
  • Schedule ๋‚ด๋ถ€์˜ getScheduleOfDateList() function์„ ํ†ตํ•ด ScheduleOfDate๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅ
  • getScheduleOfDateList()๋Š” ์ผ์ •์ด ๊ธธ์ˆ˜๋ก ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฐ›์Œ. O(n)
Schedule.ts
import { ScheduleOfDate } from '@typings/ScheduleOfDate'  
import dateFormatUtil from '@utils/date/dateFormatUtil'  
import { scheduleType, ScheduleType } from '@typings/constants/ScheduleType'  
  
// if date format DateFormat.ts -> use DateFormat  
export class Schedule {  
  id: number  
  type: ScheduleType  
  startedAt: string  
  endedAt: string  
  title: string  
  contents: string  
  
  isImportant: boolean  
  
  createdAt: string  
  updatedAt: string  
  
  constructor(schedule: {  
    id: number | null  
    type?: ScheduleType  
    startedAt: string  
    endedAt: string  
    title: string  
    contents: string  
    isImportant?: boolean  
    createdAt: string  
    updatedAt: string  
  }) {  
    const { dateToString, getDate } = dateFormatUtil  
  
    const now = dateToString(getDate())  
  
    const {  
      id,  
      type = scheduleType.TIME,  
      startedAt,  
      endedAt,  
      title,  
      contents,  
      isImportant = false,  
      createdAt = now,  
      updatedAt = now,  
    } = schedule  
  
    this.id = id  
    this.type = type  
    this.startedAt = startedAt  
    this.endedAt = endedAt  
    this.title = title  
    this.contents = contents  
    this.createdAt = createdAt  
    this.updatedAt = updatedAt  
    this.isImportant = isImportant  
  }  
  
  getScheduleOfDateList(index: number) {  
    if (this._isOneDaySchedule()) {  
      const { stringToDate } = dateFormatUtil  
      const startedAt = stringToDate(this.startedAt)  
      const endedAt = stringToDate(this.endedAt)  
      return [  
        new ScheduleOfDate({  
          isMultiple: false,  
  
          id: this.id,  
          type: this.type,  
          year: startedAt.year(),  
          month: startedAt.month() + 1,  
          day: startedAt.date(),  
          startHour: startedAt.hour(),  
          startMinute: startedAt.minute(),  
          endHour: endedAt.hour(),  
          endMinute: endedAt.minute(),  
          title: this.title,  
          contents: this.contents,  
          createdAt: this.createdAt,  
          updatedAt: this.updatedAt,  
          startedAt: this.startedAt,  
          endedAt: this.endedAt,  
          isImportant: this.isImportant,  
        }),  
      ] as ScheduleOfDate[]  
    }  
    return this._calculateSchedule(index)  
  }  
  
  private _isOneDaySchedule: () => boolean = () => {  
    const { stringToDate } = dateFormatUtil  
    return stringToDate(this.startedAt).isSame(stringToDate(this.endedAt), 'date')  
  }  
  
  private _calculateSchedule: (index: number) => ScheduleOfDate[] = index => {  
    const scheduleOfDateList: ScheduleOfDate[] = []  
    const { stringToDate } = dateFormatUtil  
    const startedAt = stringToDate(this.startedAt)  
    const endedAt = stringToDate(this.endedAt)  
  
    let start = startedAt.clone()  
    const end = endedAt.clone().add(1, 'day')  
  
    while (!start.isSame(end, 'date')) {  
      let startHour: number  
      let startMinute: number  
      let endHour: number  
      let endMinute: number  
      if (start.isSame(endedAt, 'date')) {  
        startHour = 0  
        startMinute = 0  
        endHour = endedAt.hour()  
        endMinute = endedAt.minute()  
      } else if (start.isSame(startedAt, 'date')) {  
        startHour = startedAt.hour()  
        startMinute = startedAt.minute()  
        endHour = 23  
        endMinute = 59  
      } else {  
        startHour = 0  
        startMinute = 0  
        endHour = 23  
        endMinute = 59  
      }  
  
      scheduleOfDateList.push(  
        new ScheduleOfDate({  
          isMultiple: true,  
  
          id: this.id,  
          type: this.type,  
          year: start.year(),  
          month: start.month() + 1,  
          day: start.date(),  
          startHour: startHour,  
          startMinute: startMinute,  
          endHour: endHour,  
          endMinute: endMinute,  
          title: this.title,  
          contents: this.contents,  
          createdAt: this.createdAt,  
          updatedAt: this.updatedAt,  
          startedAt: this.startedAt,  
          endedAt: this.endedAt,  
          isImportant: this.isImportant,  
          order: index,  
        }),  
      )  
  
      start = start.add(1, 'day')  
    }  
  
    if (scheduleOfDateList.length) {  
      scheduleOfDateList[0].isStart = true  
      scheduleOfDateList[scheduleOfDateList.length - 1].isEnd = true  
    }  
    return scheduleOfDateList  
  }  
}
 

ScheduleOfDate

  • ๊ฐ๊ฐ์˜ ๋‚ ์งœ์— ํ•ด๋‹นํ•˜๋Š” Schedule ๋ฐ์ดํ„ฐ.
  • ์กฐํšŒ ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉ๋จ. (์กฐํšŒ ์ด์™ธ์˜ ๋ชฉ์ ์—๋Š” Schedule ์ž์ฒด๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผํ•จ.)

Structure

  • ์‹œ์ž‘ ๋˜๋Š” ์ข…๋ฃŒ ๋…„/์›”/์ผ/์‹œ/๋ถ„ ๊ฐ๊ฐ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ํ•„๋“œ๋กœ ๊ด€๋ฆฌ.
  • Schedule ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ๊ฐ์˜ ๋‚ ์งœ์— ๋”ฐ๋ผ ๋ถ„๋ฆฌํ•˜์˜€์œผ๋ฉฐ, ๋‚ ์งœ๋Š” ์—ฌ๋Ÿฌ ScheduleOfDate๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ. (์ค‘๋ณต X)
  • Schedule ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ์™€ ๊ด€๊ณ„์—†์ด ์‚ฌ์šฉ๋˜๋Š” ๋‚ด์šฉ๋“ค์„ get()์„ ํ†ตํ•ด ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉ.
ScheduleOfDate.ts
import { ScheduleType } from '@typings/constants/ScheduleType'  
  
export class ScheduleOfDate {  
  id: number  
  type: ScheduleType  
  year: number  
  month: number  
  day: number  
  
  startHour: number  
  startMinute: number  
  
  endHour: number  
  endMinute: number  
  
  title: string  
  contents: string  
  
  order: number = 0  
  isMultiple: boolean  
  
  isStart: boolean = false  
  isEnd: boolean = false  
  
  isImportant: boolean = false  
  
  startedAt: string  
  endedAt: string  
  
  createdAt: string  
  updatedAt: string  
  
  constructor(schedule: {  
    id: number  
    type: ScheduleType  
    year: number  
    month: number  
    day: number  
    startHour: number  
    startMinute: number  
    endHour: number  
    endMinute: number  
    title: string  
    contents: string  
    isMultiple: boolean  
    createdAt: string  
    updatedAt: string  
    startedAt: string  
    endedAt: string  
    order?: number  
    isStart?: boolean  
    isEnd?: boolean  
    isImportant?: boolean  
  }) {  
    this.id = schedule.id  
    this.type = schedule.type  
    this.year = schedule.year  
    this.month = schedule.month  
    this.day = schedule.day  
    this.startHour = schedule.startHour  
    this.startMinute = schedule.startMinute  
    this.endHour = schedule.endHour  
    this.endMinute = schedule.endMinute  
    this.title = schedule.title  
    this.contents = schedule.contents  
    this.isMultiple = schedule.isMultiple  
    this.createdAt = schedule.createdAt  
    this.updatedAt = schedule.updatedAt  
    this.startedAt = schedule.startedAt  
    this.endedAt = schedule.endedAt  
    if (schedule.order) this.order = schedule.order  
    if (schedule.isStart) this.isStart = schedule.isStart  
    if (schedule.isEnd) this.isEnd = schedule.isEnd  
    if (schedule.isImportant) this.isImportant = schedule.isImportant  
  }  
  
  get startPercentage() {  
    return ((this.startHour * 60 + this.startMinute) / 1440) * 100  
  }  
  
  get endPercentage() {  
    return ((this.endHour * 60 + this.endMinute) / 1440) * 100  
  }  
  
  get isAllDay() {  
    return (  
      this.startHour == 0 && this.startMinute == 0 && this.endHour == 23 && this.endMinute == 59  
    )  
  }  
}

Repository

  • BE API๋ฅผ ํ†ตํ•ด DB์˜ ๊ฐ’์„ ์ œ๊ณต ๋ฐ›์Œ.
  • ๊ธฐ๋ณธ์ ์ธ CRUD ๊ธฐ๋Šฅ.
ScheduleRepository.ts
import { ApiResponse } from '@utils/api/models/ApiResponse'  
import { Schedule } from '@typings/Schedule'  
import api from '@utils/api/api'  
import ApiError from '@utils/error/ApiError'  
  
type ScheduleRepository = {  
  findAll: () => Promise<Schedule[]>  
  findById: (id: number) => Promise<Schedule>  
  findByDate: (date: { year: number; month?: number; day?: number }) => Promise<Schedule[]>  
  add: (schedule: Schedule) => Promise<null | number>  
  delete: (id: number) => Promise<void>  
  modify: (id: number, schedule: Schedule) => Promise<void>  
}  
  
const scheduleRepository: ScheduleRepository = {  
  findAll: async () => {  
    const response = await api().get('schedule')  
  
    const body = response.data.body.map(schedule => new Schedule(schedule))  
    const apiResponse = new ApiResponse<Schedule[]>().parseClass(response, body)  
  
    if (apiResponse.isFailure) throw new ApiError(apiResponse.code)  
  
    return apiResponse.body  
  },  
  findById: async (id: number) => {  
    const response = await api().get(`schedule/${id}`)  
    const apiResponse = new ApiResponse<Schedule>().parseData(response)  
  
    if (apiResponse.isFailure) throw new ApiError(apiResponse.code)  
  
    return apiResponse.body  
  },  
  findByDate: async (date: { year: number; month?: number; day?: number }) => {  
    const response = await api().get('schedule', { params: date })  
    const body = response.data.body.map(schedule => new Schedule(schedule))  
    const apiResponse = new ApiResponse<Schedule[]>().parseClass(response, body)  
  
    if (apiResponse.isFailure) throw new ApiError(apiResponse.code)  
    return apiResponse.body  
  },  
  add: async (schedule: Schedule) => {  
    const apiResponse: ApiResponse<number | null> = new ApiResponse<number | null>().parseData(  
      await api().post('schedule', schedule),  
    )  
    if (apiResponse.isFailure) return null  
    return apiResponse.body  
  },  
  delete: async id => {  
    const apiResponse: ApiResponse<null> = new ApiResponse<null>().parseData(  
      await api().delete(`schedule/${id}`),  
    )  
    if (apiResponse.isFailure) throw new ApiError(apiResponse.code)  
  },  
  modify: async (id, schedule) => {  
    const apiResponse: ApiResponse<null> = new ApiResponse<null>().parseData(  
      await api().put(`schedule/${id}`, schedule),  
    )  
    if (apiResponse.isFailure) throw new ApiError(apiResponse.code)  
  },  
}  
  
export default scheduleRepository