[TIL] 221116

먼지·2022년 11월 16일
0

TIL

목록 보기
44/57
post-thumbnail

챌린지 생성 - 인증 빈도에 따라 시작일 구하는 함수 수정

인증 빈도에 따라 시작일 구하기

다음년이 넘어가는 데이터를 생각하지 못하고 말일을 기준으로 작성해서 올해가 넘어가는 경우도 생각해서 다시 작성하기!

테스트 날짜 : 2022.12.26(월) --js--> 2022 11 26(1)

EVERYDAY

내일부터 7일을 표시하는데 말일중에서도 12월 말일이 넘으면 다음 년 1월부터 이어서 표시해야 함
기존 함수 결과 => 11.27 11.28 11.29 11.30 11.31 12.1 12.2
원하는 결과 => 11.27 11.28 11.29 11.30 11.31 0.1 0.2

export function getChallengeStartDate(af: AuthFrequency) {
  // const { year, month, date, day } = getCurrentDate();
  const year = 2022;
  const month = 11; // -1
  const date = 26;
  const day = 1; // 월

  const lastDate = getLastDate(year, month);
  const lastMonth = 11; // 말월
  
  // 7로 수정
  const overflow7 = date + 7 > lastDate;
  const overflowDay7 = Math.abs(lastDate - (date + 7));
  
  // - 매일
  const everydayData = !overflow7
    ? new Array(7).fill('').map((_, i) => ({
        year,
        month,
        date: date + i + 1,
        day: getDay(year, month, date + i + 1),
      }))
    : [
        ...new Array(7 - overflowDay7).fill('').map((_, i) => ({
          year,
          month,
          date: date + i + 1,
          day: getDay(year, month, date + i + 1),
        })),
        ...new Array(overflowDay7).fill('').map((_, i) => ({
          year: month + 1 > lastMonth ? year + 1 : year,
          month: month + 1 > lastMonth ? 0 : month + 1,
          date: i + 1,
          day: getDay(
            month + 1 > lastMonth ? year + 1 : year,
            month + 1 > lastMonth ? 0 : month + 1,
            i + 1
          ),
        })),
      ];

WEEKDAY

기존 코드

단순히 말일만을 생각하고 작성했던 코드

export function getChallengeStartDate(af: AuthFrequency) {
  ...
  const overflow9 = date + 9 > lastDate;
  // const overflowDay9 = lastDate - (date + 9);
  const nineDays = new Array(9).fill('').map((_, i) => date + i + 1);
  // [26, 27, 28, 29, 30, 31, 32, 33, 34]
  const weekDays = removeWeekend(year, month, nineDays);
  const removeOverLastDate = nineDays.filter((d, _) => d <= lastDate);
  const removeOAndW = removeWeekend(
    year,
    month,
    nineDays.filter((d, _) => d <= lastDate)
  );
  const nextMonthDays = removeWeekend(
    year,
    month + 1,
    new Array(9 - removeOverLastDate.length).fill('').map((_, i) => i + 1)
  );

매일과 비슷한데 주말을 제거해야 하므로 일단 중복제거 리팩토링은 나중에 생각하고 작성해보기..
왜 overflow9이면 매일, 평일 매일은 내일로부터 7개의 시작일을 보여줘야 함. 근데 평일은 그냥 +7이지만 얘는 주말이 제거되므로 9개의 날짜 배열을 만들고 시작.

export function getChallengeStartDate(af: AuthFrequency) {
  ...
  
  // - 평일 매일
  const overflow9 = date + 9 > lastDate;
  const overflowDay9 = Math.abs(lastDate - (date + 9));
  const nineDays = !overflow9
    ? getEmptyStringArr(9).map((_, i) => ({
        year,
        month,
        date: date + i + 1,
        day: getDay(year, month, date + i + 1),
      }))
    : [
        ...getEmptyStringArr(9 - overflowDay9).map((_, i) => ({
          year,
          month,
          date: date + i + 1,
          day: getDay(year, month, date + i + 1),
        })),
        ...getEmptyStringArr(overflowDay9).map((_, i) => ({
          year: month + 1 > lastMonth ? year + 1 : year,
          month: month + 1 > lastMonth ? 0 : month + 1,
          date: i + 1,
          day: getDay(
            month + 1 > lastMonth ? year + 1 : year,
            month + 1 > lastMonth ? 0 : month + 1,
            i + 1
          ),
        })),
      ];
  console.log(nineDays);

주말 제거

day가 0, 1 인 데이터를 제거

function removeWeekendData(
  dates: { year: number; month: number; date: number; day: number }[]
) {
  return dates.filter(({ day }) => day > 0 && day < 6);
}

export function getChallengeStartDate(af: AuthFrequency) {
  ...
  const nineDays = ...
  const weekdayData = removeWeekendData(nineDays);
  console.log(weekdayData);

기존 코드와 다르게 이미 nineDays에서 말월, 말일을 고려한 year, month, date, day 객체 배열을 구한 상태로 시작해서 넘치는 날을 구할 필요가 없이 주말에 해당하는 데이터만 제거하면 됐다.

WEEKEND

얘는 가까운 2주치의 주말을 보여줘야 하는데, 오늘이 주말이면 다음 주 주말부터 보여줘야 함

2022.12.26(월) 기준으로 하니까
=> 2022.12.31(토), 2023.1.1(일), 2023.1.7(토), 2023.1.8(일)
이렇게 나와야 함..

export function getNearSaturday(year: number, month: number, date: number, day: number) {
  console.log('getNearSaturday:', year, month, date, day);

  const lastDate = getLastDate(year, month);
  let tempYear = year;
  let tempMonth = month;
  let tempDate = date;
  let tempDay = day;

  // 현재 주말이면 다음주주말로 표시해야하니까 일단 월요일로만들기 => 토+2, 일+1
  if (day === 6) {
    tempDate += 2;
    tempDay += 2;
  } else if (day === 0) {
    tempDate += 1;
    tempDay += 1;
  }

  // ex) 2021.12.31 -> 2021.12.33
  // 원하는 결과 : 2022 12 31 토 -> 2023 1 7 토 (o)
  if (tempDate > lastDate) {
    tempMonth += 1;
    if (tempMonth > 11) {
      tempYear += 1;
      tempMonth = 0;
    }
    tempDate = tempDate - lastDate;
    tempDay = getDay(tempYear, tempMonth, tempDate);
  }
  console.log('tempDate', tempYear, tempMonth, tempDate, tempDay);

  // 말월말일체크 & 토요일(6)될때까지day+=1
  const daysLeftUntilSat = 6 - tempDay;
  const overflow = tempDate + daysLeftUntilSat > lastDate;
  const overflowDay = tempDate + daysLeftUntilSat - lastDate;
  if (overflow) {
    tempMonth += 1;
    if (tempMonth > 11) {
      tempYear += 1;
      tempMonth = 0;
    }
    tempDate = overflowDay;
  } else {
    tempDate += daysLeftUntilSat;
  }

  return { year: tempYear, month: tempMonth, date: tempDate, day: 6 };
}

export function getSunday({ year, month, date }: DateData) {
  // 4.30 토 ~ 5.1 일 or 2022.12.31 토 ~ 2023.1.1 일
  const lastDate = getLastDate(year, month);
  let tempYear = year;
  let tempMonth = month;
  let tempDate = date + 1;
  if (tempDate > lastDate) {
    tempMonth += 1;
    if (tempMonth > 11) {
      tempYear += 1;
      tempMonth = 0;
    }
    tempDate = 1;
  }
  return { year: tempYear, month: tempMonth, date: tempDate, day: 0 };
}

export function getChallengeStartDate(af: AuthFrequency) {
  ...
  // - 주말 매일
  const firstSat = getNearSaturday(year, month, date, day);
  const { year: fYear, month: fMonth, date: fDate, day: fDay } = firstSat;
  const firstSun = getSunday(firstSat);
  const secondSat = getNearSaturday(fYear, fMonth, fDate, fDay);
  const secondSun = getSunday(secondSat);
  const weekendData = [firstSat, firstSun, secondSat, secondSun];
  console.log(weekendData);

NWEEK

  • 주 1~6일 인증
  • 2주치 월요일을 표시
  • 토요일은 6이고 일요일이 0이라 이 부분을 유의

기존코드

day(0~6)를 기준으로 반복문으로 월(1)을 만드는 방식으로 작성함

export function getNearMonday(month: number, date: number, day: number) {
  const lastDate = getLastDate(new Date().getFullYear(), month);
  let tempMonth = month;
  let tempDate = date;
  let tempDay = day;
  if (day === 1) {
    tempDate += 1;
    tempDay = 2;
  } else if (day === 6) {
    tempDate += 1;
    tempDay = 0;
  }
  while (tempDay !== 1) {
    if (tempDate >= lastDate) {
      tempDate = 1;
      tempMonth += 1;
    }
    if (tempDay === 6) {
      tempDate += 1;
      tempDay = 0;
    }
    tempDay++;
    tempDate++;
  }
  return [tempMonth, tempDate, tempDay];
}

export function getChallengeStartDate(af: AuthFrequency) {
  ...
  
  // - 주 n일
  const firstMon = getNearMonday(month, date, day);
  const secondMon = getNearMonday(firstMon[0], firstMon[1], firstMon[2]);
  const firstAndSecondMondayData = [
    { month: firstMon[0], date: firstMon[1], day: firstMon[2] },
    { month: secondMon[0], date: secondMon[1], day: secondMon[2] },
  ];
  
  ...
}

반복문 제거 후 규칙을 찾음.

  • 일(0)이면 + 1
  • 월(1)이면 + 7
  • 화(2)이면 + 6
  • 수(3)이면 + 5
  • 목(4)이면 + 4
  • 금(5)이면 + 3
  • 토(6)이면 + 2
    일요일은 +1일, 월요일은 +7, 나머지는 8 - dayNum 을 date에 더해주면 가까운 월요일을 구할 수 있다
export function getNearMonday({ year, month, date, day }: DateData): DateData {
  const lastDate = getLastDate(year, month);
  let tempYear = year;
  let tempMonth = month;
  let tempDate = date;
  let tempDay = day;

  if (day === 0) tempDate += 1;
  else if (day === 1) tempDate += 7;
  else tempDate += 8 - tempDay;

위에 다른 코드처럼 말일과 말월일 경우도 조건문을 체크하면 일단 끝..!

export function getNearMonday({ year, month, date, day }: DateData): DateData {
  ...
  if (tempDate > lastDate) {
    tempMonth += 1;
    if (tempMonth > 11) {
      tempYear += 1;
      tempMonth = 0;
    }
    tempDate = tempDate - lastDate;
    tempDay = getDay(tempYear, tempMonth, tempDate);
  }

  return { year: tempYear, month: tempMonth, date: tempDate, day: 1 };
}

2022.11.20 (일)
=> 2022.11.21 (월), 2022.11.28 (월)

20222.12.26 (월)
=> 2023.01.02 (월), 2023.01.09 (월)

정리?

전엔 뭔가 되긴 되는데 이상한 방식.. 급하게 정리도 안 하고 일단 만들다 보니 나도 이해할 수 없었다. 지금은 자바스크립트의 방식으로 년, 월, 일, 요일 객체로 이루어진 배열을 만들어서 잘 가공해서 UI에 보여주면 될 것 같다.

앞으로 해야 할 것은
getChallengeStartDate에서 너무 많은 일을 하고 있음. 얘는 authFrequency에 따라 다른 결과를 반환하는 역할만 할 수 있게 함수 분리하기. 전체적으로 중복되는 코드들도 함수 분리!

리팩토링

function getEverydayData({ year, month, date }: DateData) {
  const lastDate = getLastDate(year, month);
  const lastMonth = 11;
  const overflow7 = date + 7 > lastDate;
  const overflowDay7 = Math.abs(lastDate - (date + 7));
  const everydayData = !overflow7
    ? getEmptyStringArr(7).map((_, i) => ({
        year,
        month,
        date: date + i + 1,
        day: getDay(year, month, date + i + 1),
      }))
    : [
        ...getEmptyStringArr(7 - overflowDay7).map((_, i) => ({
          year,
          month,
          date: date + i + 1,
          day: getDay(year, month, date + i + 1),
        })),
        ...getEmptyStringArr(overflowDay7).map((_, i) => ({
          year: month + 1 > lastMonth ? year + 1 : year,
          month: month + 1 > lastMonth ? 0 : month + 1,
          date: i + 1,
          day: getDay(
            month + 1 > lastMonth ? year + 1 : year,
            month + 1 > lastMonth ? 0 : month + 1,
            i + 1
          ),
        })),
      ];
  return everydayData;
}

function getWeekdayData({ year, month, date }: DateData) {
  ...
  return weekdayData;
}

function getWeekendData({ year, month, date, day }: DateData) {
  ...
  return weekendData;
}

function getNWeekData({ year, month, date, day }: DateData) {
  ...
  return nWeekData;
}

export function getChallengeStartDate(authFrequency: AuthFrequency) {
  const { year, month, date, day } = getCurrentDate();
  switch (authFrequency) {
    case 'EVERYDAY':
      return getEverydayData({ year, month, date, day });
    case 'WEEKDAY':
      return getWeekdayData({ year, month, date, day });
    case 'WEEKEND':
      return getWeekendData({ year, month, date, day });
    default:
      return getNWeekData({ year, month, date, day });
  }
}
profile
꾸준히 자유롭게 즐겁게

0개의 댓글