[TIL] 221121

먼지·2022년 11월 21일
0

TIL

목록 보기
45/57
post-thumbnail

인증 빈도 authFrequency와 기간 peroid에 따라 챌린지 종료일 구하는 getChallengeEndData 함수 수정 & 리팩토링

기존 코드

변수명을 짧게 작성하려다 보니 어떤 값을 담는 건지 알 수 없고
함수 안에 여러 함수가 들어있고
시작일을 구하던 함수처럼 말월이 아닌 말일만을 생각해 작성함
갈아엎자ㅜㅜ

export function getChallengeEndData(af: AuthFrequency, p: string, s: string) {
  const year = new Date().getFullYear();
  const [m, de, dy] = s.split('.'); // string type
  const [month, date, day] = [+m, +de, +dy];

  function getEverydayEndData({ y, m, d }: GetEndDataParams) {
    const { year, month } = getCurrentDate();
    const lastDate = getLastDate(year, month);
    let [tempYear, tempMonth, tempDate] = [y, m, d];
    let day = getDay(y, m, d); // 시작일 요일
    let leftDay = 7 - day;
    tempDate += leftDay;
    if (tempDate > lastDate) {
      tempMonth += 1;
      tempDate = Math.abs(lastDate - tempDate);
    }
    return [tempYear, tempMonth, tempDate];
  }

  function getWeekdayEndData({ y, m, d, o = false }: GetEndDataParams) {
    const { year, month } = getCurrentDate();
    const lastDate = getLastDate(year, month);
    let [tempYear, tempMonth, tempDate] = [y, m, d];
    let day = getDay(y, m, d); // 시작일 요일
    if (day === 5 && o) {
      day = 1;
      tempDate += 3;
    }
    let leftDay = 5 - day;
    tempDate += leftDay;
    if (tempDate > lastDate) {
      tempMonth += 1;
      tempDate = Math.abs(lastDate - tempDate);
    }
    return [tempYear, tempMonth, tempDate];
  }

  function getWeekendEndDate({ y, m, d, o = false }: GetEndDataParams) {
    const { year, month } = getCurrentDate();
    const lastDate = getLastDate(year, month);
    let [tempYear, tempMonth, tempDate] = [y, m, d];
    let day = getDay(y, m, d); // 시작일 요일
    if (day === 6) tempDate += 1;
    if (o) tempDate += 7;
    if (tempDate > lastDate) {
      tempMonth += 1;
      tempDate = Math.abs(lastDate - tempDate);
    }
    return [tempYear, tempMonth, tempDate];
  }

  function getNTimesAWeekEndData({ y, m, d, o = false }: GetEndDataParams) {
    const { year, month } = getCurrentDate();
    const lastDate = getLastDate(year, month);
    let [tempYear, tempMonth, tempDate] = [y, m, d];
    if (o) tempDate += 7;
    else tempDate += 6;
    if (tempDate > lastDate) {
      tempMonth += 1;
      tempDate = Math.abs(lastDate - tempDate);
    }
    return [tempYear, tempMonth, tempDate];
  }

  switch (af) {
    case 'EVERYDAY':
      const e1 = getEverydayEndData({ y: year, m: +month, d: +date });
      const e2 = getEverydayEndData({ y: e1[0], m: e1[1], d: e1[2] });
      const e3 = getEverydayEndData({ y: e2[0], m: e2[1], d: e2[2] });
      const e4 = getEverydayEndData({ y: e3[0], m: e3[1], d: e3[2] });
      if (p === 'ONEWEEK') return e1;
      else if (p === 'TWOWEEK') return e2;
      else if (p === 'THREEWEEK') return e3;
      else return e4;
    case 'WEEKDAY':
      const w1 = getWeekdayEndData({ y: year, m: +month, d: +date });
      const w2 = getWeekdayEndData({ y: w1[0], m: w1[1], d: w1[2], o: true });
      const w3 = getWeekdayEndData({ y: w2[0], m: w2[1], d: w2[2], o: true });
      const w4 = getWeekdayEndData({ y: w3[0], m: w3[1], d: w3[2], o: true });
      if (p === 'ONEWEEK') return w1;
      else if (p === 'TWOWEEK') return w2;
      else if (p === 'THREEWEEK') return w3;
      else return w4;
    case 'WEEKEND':
      const k1 = getWeekendEndDate({ y: year, m: +month, d: +date });
      const k2 = getWeekendEndDate({ y: k1[0], m: k1[1], d: k1[2], o: true });
      const k3 = getWeekendEndDate({ y: k2[0], m: k2[1], d: k2[2], o: true });
      const k4 = getWeekendEndDate({ y: k3[0], m: k3[1], d: k3[2], o: true });
      if (p === 'ONEWEEK') return k1;
      else if (p === 'TWOWEEK') return k2;
      else if (p === 'THREEWEEK') return k3;
      else return k4;
    default:
      const n1 = getNTimesAWeekEndData({ y: year, m: +month, d: +date });
      const n2 = getNTimesAWeekEndData({ y: n1[0], m: n1[1], d: n1[2], o: true });
      const n3 = getNTimesAWeekEndData({ y: n2[0], m: n2[1], d: n2[2], o: true });
      const n4 = getNTimesAWeekEndData({ y: n3[0], m: n3[1], d: n3[2], o: true });
      if (p === 'ONEWEEK') return n1;
      else if (p === 'TWOWEEK') return n2;
      else if (p === 'THREEWEEK') return n3;
      else return n4;
  }
}

수정 시작

챌린지 기간 : 'ONEWEEK' | 'TWOWEEK' | 'THREEWEEK' | 'FOURWEEK'
챌린지 인증 빈도 : 'EVERYDAY' | 'WEEKDAY' | 'WEEKEND' | NWEEK ('SIXTHAWEEK' | 'FIFTHAWEEK' | 'FORTHAWEEK' | 'THIRDAWEEK' | 'TWICEAWEEK' | 'ONCEAWEEK')

// pages/CreateChallenge.tsx
function CreateChallenge() {
  ...
  return (
    ...
        {authFrequency && (
          <div className="w-full mt-6">
            <label>
              <h2 className="font-bold">
                시작일<span className="text-red-400">*</span>
              </h2>
            </label>
            <div className="flex flex-wrap">
              {getChallengeStartDate(authFrequency as AuthFrequency).map(
                ({ year, month, date, day }, i) => (
                  <button
                    type="button"
                    key={i}
                    onClick={() =>
                      handleChangeStartDate(`${year}.${month}.${date}.${day}`)
                    }
  );
}

// modules/challenge/utils.ts
export function getChallengeEndData(
  authFrequency: AuthFrequency,
  peroid: ChallengePeroid,
  startDate: string
) {
  console.log('getChallengeEndData', authFrequency, peroid, startDate);

startData param 2022.11.27.2에서 년월일들을 추출하기 위해 split method를 이용

배열 디스트럭처링으로 y, m, de, dy를 가져오는데, 얘는 문자열이므로 숫자로 바꾸기

const [y, m, de, dy] = startDate.split('.'); // ['2022', '11', '27', '2']
const [year, month, date, day] = [+y, +m, +de, +dy]; // [2022, 11, 27, 2]
// => year: 2022, month: 11 (12월), date: 27, day: 2 (화욜)

EVERYDAY

ONWEEK

  • 시작일 : 2022.12.27 (화)
  • 언제 시작하든 항상 일요일에 끝

수정전

매일 + 1주 => 2023.1.1 (일)

  • 일요일이면 tempDay(=day)에 +0
  • 월요일이면 +6
  • 화요일이면 +5
  • ...
  • 토요일이면 +1
    => 일요일 제외 tempDay += (7 - day)
function getEverydayEndData({ year, month, date, day }: DateData) {
  const lastDate = getLastDate(year, month);
  let [tempYear, tempMonth, tempDate, tempDay] = [year, month, date, day];
  
  if (day === 0) tempDate += 1;
  else tempDate += 7 - day;
말일, 말월 체크

시작일 계산하는 함수와 동일한데, 이 로직이 많이 중복돼서 분리를 해야 함. 근데 아직 어떻게 분리하면 좋을지 생각하기 귀찮..아서 일단 작성

  if (tempDate > lastDate) {
    tempMonth += 1;
    if (tempMonth > 11) {
      tempYear += 1;
      tempMonth = 0;
    }
    tempDate = tempDate - lastDate;
    tempDay = getDay(tempYear, tempMonth, tempDate);
  }
1차 수정완
function getEverydayEndData({ year, month, date, day }: DateData) {
  const lastDate = getLastDate(year, month);
  let [tempYear, tempMonth, tempDate, tempDay] = [year, month, date, day];

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

  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: tempDay };
}
테스트완
export function getChallengeEndData(
  authFrequency: AuthFrequency,
  peroid: ChallengePeroid,
  startDate: string
) {
  console.log('getChallengeEndData', authFrequency, peroid, startDate);

  const [y, m, de, dy] = startDate.split('.'); 
  const [year, month, date, day] = [+y, +m, +de, +dy]; 

  const everydayEndDataTest = getEverydayEndData({ year, month, date, day });
  console.log('everydayEndDataTest :', everydayEndDataTest);

예상한 결과대로 나옴! 2023.01.01 (일-0)

TWOWEEK, THREEWEEK, FOURWEEK

얘넨 저 함수에 각각 이전 주 데이터(WEEKDAY면 ONEWEEK 반환값?)를 넣어주면 된다.

앞에서 나온 {year: 2023, month: 0, date: 1, day: 0} (2023.01.01 (0)) 이 데이터를 넣으면 2023.01.08 이 나오면 되는데,, 착각한 부분이 있다.

2주차부턴 무조건 +7 해야 함. 왜냐면 1주 차 결과가 일요일(0)로 나오니까 저렇게 작성하면 무조건 +1이 되기 때문에 결과가 이상하게 나온다. 2주 차 이상인지 확인하기 위한 로직을 작성하기 위해 opt 이름의 옵셔널 인자를 하나 더 받아서 조건문으로 체크 (전에도 작성했는데 까먹고 있었음ㅎ)

// type.ts
export interface GetEndDataParams {
  year: number;
  month: number;
  date: number;
  day: number;
  opt?: boolean; // option
  // { [key: string]: boolean | number; };
}

// utils.ts
function getEverydayEndData({ year, month, date, day, opt }: GetEndDataParams) {
  const lastDate = getLastDate(year, month);
  let [tempYear, tempMonth, tempDate, tempDay] = [year, month, date, day];

  if (opt) {
    tempDate += 7;
  } else {
    if (day === 0) tempDate += 1;
    else tempDate += 7 - day;
  }
  ...
}  
 
export function getChallengeEndData() {
  ...
  const oneweekEverydayDate = getEverydayEndData({ year, month, date, day });
  const twoweekEverydayDate = getEverydayEndData({
    year: oneweekEverydayDate.year,
    month: oneweekEverydayDate.month,
    date: oneweekEverydayDate.date,
    day: oneweekEverydayDate.day,
    opt: true,
  });
  console.log('twoweekEverydayDate :', twoweekEverydayDate);

2022.01.08 (일) 잘 나옴!

3,4주도 테스트

2023.01.15, 22일 일요일이 나오면 됨

  const threeweekEverydayData = getEverydayEndData({
    year: twoweekEverydayDate.year,
    month: twoweekEverydayDate.month,
    date: twoweekEverydayDate.date,
    day: twoweekEverydayDate.day,
    opt: true,
  });
  const foureweekEverydayData = getEverydayEndData({
    year: threeweekEverydayData.year, ...
  });
  console.log('threeweekEverydayData :', threeweekEverydayData);
  console.log('foureweekEverydayData :', foureweekEverydayData);

성..공

매일 + 1~4주 종료일 구하기 끝.
많이 적었지만 말일 말월 확인하는 로직이 중복되니 이거 수정하고, 전달해야 할 파라미터가 많아서 코드가 길어지는데 이것도 방법을 찾아봐야겠다

코드 줄이기?

2주부터는 옵션 파라미터와 앞 주의 데이터까지 전달해야 해서 코드가 너무 길어서 함수를 하나 만들었다. 이름을 뭐라 해야 할지 몰라서 endDateHelper 헬퍼 함수 느낌으로 작성함

eDate라는 종료일 날짜와, 종료일 계산 함수를 받아서 그 함수에 객체스프레드 문법을 이용해 opt 프로퍼티를 추가해서 호출해서 반환된 값을 다시 반환하는 함수

// 2주이상일때데이터추출
function endDateHelper(eDate: DateData, func: (param: GetEndDataParams) => DateData) {
  return func({ ...eDate, opt: true });
}

export function getChallengeEndData() {
  ...
  
  const oneweekEverydayEndDate = getEverydayEndData({ year, month, date, day });
  const twoweekEverydayEndDate = endDateHelper(
    oneweekEverydayEndDate,
    getEverydayEndData
  );
  console.log(twoweekEverydayEndDate); // {year: 2023, month: 0, date: 8, day: 0}

결과는 정상적으로 나오고 코드가 조금이라두 짧아졌다

  const oneweekEverydayEndDate = getEverydayEndData({ year, month, date, day });
  const twoweekEverydayEndDate = endDateHelper(
    oneweekEverydayEndDate,
    getEverydayEndData
  );
  const threeweekEverydayEndData = endDateHelper(
    twoweekEverydayEndDate,
    getEverydayEndData
  );
  const fourweekEverydayEndData = endDateHelper(
    threeweekEverydayEndData,
    getEverydayEndData
  );
  console.log(
    oneweekEverydayEndDate,
    twoweekEverydayEndDate,
    threeweekEverydayEndData,
    fourweekEverydayEndData
  );

WEEKDAY

  • 시작일 : 2022.12.27 (화)
  • 언제 시작하든 항상 금요일에 끝

ONEWEEK

평일 매일 + 1주 => 2022.12.30 (금)

  • 금(5) +0
  • 목(4) +1
  • 수(3) +2
    ...
    월~금이 시작일에 표시되므로 tempDate += (5 - day)
function getWeekdayEndData({
  year,
  month,
  date,
  day,
  opt = false,
}: GetEndDataParams): DateData {
  const lastDate = getLastDate(year, month);
  let [tempYear, tempMonth, tempDate, tempDay] = [year, month, date, day];

  tempDate += 5 - tempDay;

  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: 5 };
}

TWO, THREE, FOUR WEEK

1주 => 2022.12.30
2주 => 2023.01.06
3주 => 2023.01.13
4주 => 2023.01.20

2주 이상 (opt = true)은 앞 주의 데이터인 금요일(5)가 들어감. 그래서 3을 더해서 월요일(date += 3 && day = 1)을 만들어준다.

function getWeekdayEndData({
  year,
  month,
  date,
  day,
  opt = false,
}: GetEndDataParams): DateData {
  const lastDate = getLastDate(year, month);
  let [tempYear, tempMonth, tempDate, tempDay] = [year, month, date, day];

  // 
  if (opt) {
    tempDate += 3;
    tempDay = 1;
  }
  tempDate += 5 - tempDay;
  ...
}
  
export function getChallengeEndData(
  authFrequency: AuthFrequency,
  peroid: ChallengePeroid,
  startDate: string
) {
  ...

  // 평일 매일
  const oneweekWeekdayEndDate = getWeekdayEndData({ year, month, date, day });
  const twoweekWeekdayEndDate = endDateHelper(oneweekWeekdayEndDate, getWeekdayEndData);
  const threeweekWeekdayEndDate = endDateHelper(twoweekWeekdayEndDate, getWeekdayEndData);
  const fourweekWeekdayEndDate = endDateHelper(
    threeweekWeekdayEndDate,
    getWeekdayEndData
  );
  console.log('oneweekWeekdayEndDate :', oneweekWeekdayEndDate);
  console.log('twoweekWeekdayEndDate :', twoweekWeekdayEndDate);
  console.log('threeweekWeekdayEndDate :', threeweekWeekdayEndDate);
  console.log('fourweekWeekdayEndDate :', fourweekWeekdayEndDate);

WEEKEND

시작일 : 2022.12.31 (토)
토, 일 시작해서 항상 일요일에 끝

  • 1주 동안 => 2023.01.01
  • 2주 동안 => 2023.01.08
  • 3주 동안 => 2023.01.15
  • 4주 동안 => 2023.01.22

토요일(6)이면 tempDate+=1로 일요일로 만들고, 2주 이상(opt=true)이면 +7!

function getWeekendEndDate({
  year,
  month,
  date,
  day,
  opt = false,
}: GetEndDataParams): DateData {
  console.log('getWeekendEndDate :', year, month, date, day);

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

  if (day === 6) tempDate += 1; // 일요일로만들고
  if (opt) tempDate += 7; // opt면+7까지

  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: 0 };
}

NWEEK

시작일 : 2022.1.2 (월)
월요일 시작해서 일요일에 끝

  • 1주 동안 => 2023.01.08
  • 2주 동안 => 2023.01.15
  • 3주 동안 => 2023.01.22
  • 4주 동안 => 2023.01.29

function getNTimesAWeekEndData({
  year,
  month,
  date,
  day,
  opt = false,
}: GetEndDataParams): DateData {
  const lastDate = getLastDate(year, month);
  let [tempYear, tempMonth, tempDate, tempDay] = [year, month, date, day];

  if (opt) tempDate += 7;
  else tempDate += 6;

  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: 0 };
}

export function getChallengeEndData(
  authFrequency: AuthFrequency,
  peroid: ChallengePeroid,
  startDate: string
) {
  ...
  // 주 n일
  const n1weekWeekendEndDate = getNTimesAWeekEndData({ year, month, date, day });
  const n2weekWeekendEndDate = endDateHelper(n1weekWeekendEndDate, getNTimesAWeekEndData);
  const n3weekWeekendEndDate = endDateHelper(n2weekWeekendEndDate, getNTimesAWeekEndData);
  const n4weekWeekendEndDate = endDateHelper(n3weekWeekendEndDate, getNTimesAWeekEndData);
  console.log('n1weekWeekendEndDate :', n1weekWeekendEndDate);
  console.log('n2weekWeekendEndDate :', n2weekWeekendEndDate);
  console.log('n3weekWeekendEndDate :', n3weekWeekendEndDate);
  console.log('n4weekWeekendEndDate :', n4weekWeekendEndDate);
}

시작일 : 2023.01.09 (월)

리팩토링

switch 문이냐 객체냐,, 그거시 문제로다

원래는 switch 문으로 했는데 if 문이 여러 개라 뭔가 수정할 수 있을 것 같은데.. 생각생각

export function getChallengeEndData(
  authFrequency: AuthFrequency,
  peroid: ChallengePeroid,
  startDate: string
) {
  ...  
  switch (authFrequency) {
    case 'EVERYDAY':
      if (peroid === 'ONEWEEK') return oneweekEverydayEndDate;
      else if (peroid === 'TWOWEEK') return twoweekEverydayEndDate;
      else if (peroid === 'THREEWEEK') return threeweekEverydayEndData;
      else return fourweekEverydayEndData;
    case 'WEEKDAY':
      if (peroid === 'ONEWEEK') return oneweekWeekdayEndDate;
      else if (peroid === 'TWOWEEK') return twoweekWeekdayEndDate;
      else if (peroid === 'THREEWEEK') return threeweekWeekdayEndDate;
      else return fourweekWeekdayEndDate;
    case 'WEEKEND':
      if (peroid === 'ONEWEEK') return oneweekWeekendEndDate;
      else if (peroid === 'TWOWEEK') return twoweekWeekendEndDate;
      else if (peroid === 'THREEWEEK') return threeweekWeekendEndDate;
      else return fourweekWeekendEndDate;
    default:
      if (peroid === 'ONEWEEK') return n1weekWeekendEndDate;
      else if (peroid === 'TWOWEEK') return n2weekWeekendEndDate;
      else if (peroid === 'THREEWEEK') return n3weekWeekendEndDate;
      else return n4weekWeekendEndDate;
  }
}
profile
꾸준히 자유롭게 즐겁게

0개의 댓글