ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,36 @@
+import EventCalendar from '../../src/domain/EventCalendar';
+import { CHRISTMAS_D_DAY, GIFT, SPECIAL } from '../../src/domain/Events';
+
+import {
+  EVENT_MONTH,
+  EVENT_NAMES,
+  EVENT_YEAR,
+} from '../../src/constants/event';
+import { MAIN_COURSES } from '../../src/constants/menus';
+
+describe('EventCalendar 테스트', () => {
+  test('getEventBenefit 기능 테스트', () => {
+    // given
+    const YEAR = EVENT_YEAR;
+    const MONTH = EVENT_MONTH;
+    const DATE = 25;
+    const TOTAL_PRICE = 130_000;
+    const ORDER_CATEGORIES = [MAIN_COURSES];
+
+    const RESULT = {
+      [EVENT_NAMES.CHRISTMAS_D_DAY]: CHRISTMAS_D_DAY.getEvent().getBenefit,
+      [EVENT_NAMES.SPECIAL]: SPECIAL.getEvent().getBenefit,
+      [EVENT_NAMES.GIFT]: GIFT.getEvent().getBenefit,
+    };
+
+    // when
+    const eventCalendar = new EventCalendar(YEAR, MONTH, DATE);
+    eventCalendar.setAvailableEvents({
+      totalPrice: TOTAL_PRICE,
+      orderCategories: ORDER_CATEGORIES,
+    });
+
+    //then
+    expect(eventCalendar.availableEvents).toEqual(RESULT);
+  });
+});

리뷰: 테스트 코드의 의존성을 줄여야 하기 때문일까요? 그렇게 생각하시는 이유가 궁금합니다..!
@@ -0,0 +1,117 @@
+import { EVENT_NAMES } from '../constants/event.js';
+import { DESSERTS, MAIN_COURSES } from '../constants/menus.js';
+
+export const CHRISTMAS_D_DAY = {
+  getBenefit({ date }) {
+    const baseAmount = 1000;
+    const weightAmount = 100;
+
+    return {
+      amount: 1,
+      price: baseAmount + weightAmount * (date - 1),
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.CHRISTMAS_D_DAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isChristmasPeriod }) {
+    return isChristmasPeriod === true;
+  },
+};
+
+export const WEEKDAY = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[DESSERTS],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKDAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === false && orderCategories.includes(DESSERTS);
+  },
+};
+
+export const WEEKEND = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[MAIN_COURSES],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKEND,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === true && orderCategories.includes(MAIN_COURSES);
+  },
+};
+
+export const SPECIAL = {
+  getBenefit() {
+    const discountAmount = 1_000;
+    return {
+      amount: 1,
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.SPECIAL,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isSpecialDate }) {
+    return isSpecialDate === true;
+  },
+};
+
+export const GIFT = {
+  getBenefit() {
+    return {
+      menu: '샴페인',
+      amount: 1,
+      price: 25_000,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.GIFT,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ totalPrice }) {
+    return totalPrice >= 120_000;
+  },
+};
+
+export const ALL_EVENTS = Object.freeze({
+  CHRISTMAS_D_DAY,
+  WEEKDAY,
+  WEEKEND,
+  SPECIAL,
+  GIFT,
+});

리뷰: 물론 Truthy를 사용할 수도 있는 상황이지만, 실제로 운영하는 서비스라면 상태가 이상하거나 서버에서 잘못된 값이 날아왔을 때 잡을 수 있는 코드여야 한다고 생각했습니다! 그래서 타입과 값을 정확히 검사하는 방식으로 작성했어요.
@@ -0,0 +1,117 @@
+import { EVENT_NAMES } from '../constants/event.js';
+import { DESSERTS, MAIN_COURSES } from '../constants/menus.js';
+
+export const CHRISTMAS_D_DAY = {
+  getBenefit({ date }) {
+    const baseAmount = 1000;
+    const weightAmount = 100;
+
+    return {
+      amount: 1,
+      price: baseAmount + weightAmount * (date - 1),
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.CHRISTMAS_D_DAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isChristmasPeriod }) {
+    return isChristmasPeriod === true;
+  },
+};
+
+export const WEEKDAY = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[DESSERTS],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKDAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === false && orderCategories.includes(DESSERTS);
+  },
+};
+
+export const WEEKEND = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[MAIN_COURSES],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKEND,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === true && orderCategories.includes(MAIN_COURSES);
+  },
+};
+
+export const SPECIAL = {
+  getBenefit() {
+    const discountAmount = 1_000;
+    return {
+      amount: 1,
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.SPECIAL,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isSpecialDate }) {
+    return isSpecialDate === true;
+  },
+};
+
+export const GIFT = {
+  getBenefit() {
+    return {
+      menu: '샴페인',
+      amount: 1,
+      price: 25_000,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.GIFT,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ totalPrice }) {
+    return totalPrice >= 120_000;
+  },
+};
+
+export const ALL_EVENTS = Object.freeze({
+  CHRISTMAS_D_DAY,
+  WEEKDAY,
+  WEEKEND,
+  SPECIAL,
+  GIFT,
+});

리뷰: 비즈니스와 관련한 중요한 로직이기 때문에 그 정보가 빠르게 보여야 하면서 다른 곳에서 재사용되지 않는 수는 상수로 빼지 않았습니다. 
만약 '증정품 수령 최소 주문 금액'이라는 이름의 상수를 만든다면 그 의미는 담고 있겠지만, 그게 얼마인지 알기 위해서는 다른 파일을 열어 보거나 시선을 이동해야 하는 불편함이 생길 거라 생각했습니다. :)
비슷한 결정을 내린 사례로 EventPlanner의 getBadge 함수가 있습니다.😄
@@ -0,0 +1,117 @@
+import { EVENT_NAMES } from '../constants/event.js';
+import { DESSERTS, MAIN_COURSES } from '../constants/menus.js';
+
+export const CHRISTMAS_D_DAY = {
+  getBenefit({ date }) {
+    const baseAmount = 1000;
+    const weightAmount = 100;
+
+    return {
+      amount: 1,
+      price: baseAmount + weightAmount * (date - 1),
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.CHRISTMAS_D_DAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isChristmasPeriod }) {
+    return isChristmasPeriod === true;
+  },
+};
+
+export const WEEKDAY = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[DESSERTS],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKDAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === false && orderCategories.includes(DESSERTS);
+  },
+};
+
+export const WEEKEND = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[MAIN_COURSES],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKEND,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === true && orderCategories.includes(MAIN_COURSES);
+  },
+};
+
+export const SPECIAL = {
+  getBenefit() {
+    const discountAmount = 1_000;
+    return {
+      amount: 1,
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.SPECIAL,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isSpecialDate }) {
+    return isSpecialDate === true;
+  },
+};
+
+export const GIFT = {
+  getBenefit() {
+    return {
+      menu: '샴페인',
+      amount: 1,
+      price: 25_000,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.GIFT,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ totalPrice }) {
+    return totalPrice >= 120_000;
+  },
+};
+
+export const ALL_EVENTS = Object.freeze({
+  CHRISTMAS_D_DAY,
+  WEEKDAY,
+  WEEKEND,
+  SPECIAL,
+  GIFT,
+});

리뷰: 아하 그렇군요. 그렇다면 이렇게는 어떠신가요?
```
 isEventAvailable({ totalPrice }) {
    const evenAvaliableAmount = 120_000;
    return totalPrice >= evenAvaliableAmount;
```
불필요한 한 줄이라고 생각하실 수 있지만, 말씀하신 문제를 해결하면서도  의미를 담을 수 있다고 생각했습니다!
@@ -0,0 +1,36 @@
+import EventCalendar from '../../src/domain/EventCalendar';
+import { CHRISTMAS_D_DAY, GIFT, SPECIAL } from '../../src/domain/Events';
+
+import {
+  EVENT_MONTH,
+  EVENT_NAMES,
+  EVENT_YEAR,
+} from '../../src/constants/event';
+import { MAIN_COURSES } from '../../src/constants/menus';
+
+describe('EventCalendar 테스트', () => {
+  test('getEventBenefit 기능 테스트', () => {
+    // given
+    const YEAR = EVENT_YEAR;
+    const MONTH = EVENT_MONTH;
+    const DATE = 25;
+    const TOTAL_PRICE = 130_000;
+    const ORDER_CATEGORIES = [MAIN_COURSES];
+
+    const RESULT = {
+      [EVENT_NAMES.CHRISTMAS_D_DAY]: CHRISTMAS_D_DAY.getEvent().getBenefit,
+      [EVENT_NAMES.SPECIAL]: SPECIAL.getEvent().getBenefit,
+      [EVENT_NAMES.GIFT]: GIFT.getEvent().getBenefit,
+    };
+
+    // when
+    const eventCalendar = new EventCalendar(YEAR, MONTH, DATE);
+    eventCalendar.setAvailableEvents({
+      totalPrice: TOTAL_PRICE,
+      orderCategories: ORDER_CATEGORIES,
+    });
+
+    //then
+    expect(eventCalendar.availableEvents).toEqual(RESULT);
+  });
+});

리뷰: 네 의존성 문제라고 생각합니다.
저는 상수 자체도 하나의 모듈이라고 생각하는데요,
하나의 모듈이 실제 코드와, 테스트 코드 두 군데 모두 의존하는 것은 좋아보이지 않기 때문이기도 하고,
특히나 테스트는 독립적이어야 하기 때문이기도 합니다!
@@ -0,0 +1,83 @@
+import deepFreeze from '../utils/deepFreeze.js';
+import { EVENT_MONTH } from './event.js';
+
+const MESSAGES = deepFreeze({
+  // InputView
+  inputs: {
+    getVisitDate: `${EVENT_MONTH}월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)\n`,
+    getOrders:
+      '주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)\n',
+  },
+
+  // OutputView
+  outputs: {
+    sayHi: `안녕하세요! 우테코 식당 ${EVENT_MONTH}월 이벤트 플래너입니다.`,
+
+    eventPreview: (date) =>
+      `${EVENT_MONTH}월 ${date}일에 우테코 식당에서 받을 이벤트 혜택 미리 보기!\n`,
+
+    menus: {
+      title: '<주문 메뉴>',
+      printMsg: (menus) =>
+        menus.reduce(
+          (acc, { menu, amount }) => `${acc}${menu} ${amount}개\n`,
+          '',
+        ),
+    },
+
+    originalPrice: {
+      title: '<할인 전 총주문 금액>',
+      printMsg: (price) => `${price.toLocaleString()}원\n`,
+    },
+
+    gift: {
+      title: '<증정 메뉴>',
+      printMsg: (gift) => {
+        if (!gift) return '없음\n';
+
+        return `${gift.menu} ${gift.amount}개\n`;
+      },
+    },
+
+    benefits: {
+      title: '<혜택 내역>',
+      printMsg: (benefits) => {
+        if (!benefits) return '없음\n';
+
+        return Object.entries(benefits).reduce(
+          (acc, [eventName, { amount, price }]) =>
+            `${acc}${eventName}: -${(amount * price).toLocaleString()}원\n`,
+          '',
+        );
+      },
+    },
+
+    totalBenefitMoney: {
+      title: '<총혜택 금액>',
+      printMsg: (money) => {
+        if (!money) return '0원\n';
+
+        return `-${money.toLocaleString()}원\n`;
+      },
+    },
+
+    payment: {
+      title: '<할인 후 예상 결제 금액>',
+      printMsg: (money) => `${money.toLocaleString()}원\n`,
+    },
+
+    badge: {
+      title: '<12월 이벤트 배지>',
+      printMsg: (badge) => `${badge}`,
+    },
+  },
+
+  // Error
+  errors: {
+    prefix: '[ERROR]',
+    invalidDate: '유효하지 않은 날짜입니다. 다시 입력해 주세요.',
+    invalidOrders: '유효하지 않은 주문입니다. 다시 입력해 주세요.',
+  },
+});
+
+export default MESSAGES;

리뷰: EVENT_MONTH는 상수보다는 12월로 바로 넣는 것도 고려해보시면 좋을 것 같아요
이 부분에 대해서 많이 고민했었는데, 해당 크리스마스 이벤트는 내년에도 개최될 수 있으니까 년도는 바뀌더라도, 크리스마스니까 12월은 안변하겠다 싶었습니다!
@@ -0,0 +1,83 @@
+import deepFreeze from '../utils/deepFreeze.js';
+import { EVENT_MONTH } from './event.js';
+
+const MESSAGES = deepFreeze({
+  // InputView
+  inputs: {
+    getVisitDate: `${EVENT_MONTH}월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)\n`,
+    getOrders:
+      '주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)\n',
+  },
+
+  // OutputView
+  outputs: {
+    sayHi: `안녕하세요! 우테코 식당 ${EVENT_MONTH}월 이벤트 플래너입니다.`,
+
+    eventPreview: (date) =>
+      `${EVENT_MONTH}월 ${date}일에 우테코 식당에서 받을 이벤트 혜택 미리 보기!\n`,
+
+    menus: {
+      title: '<주문 메뉴>',
+      printMsg: (menus) =>
+        menus.reduce(
+          (acc, { menu, amount }) => `${acc}${menu} ${amount}개\n`,
+          '',
+        ),
+    },
+
+    originalPrice: {
+      title: '<할인 전 총주문 금액>',
+      printMsg: (price) => `${price.toLocaleString()}원\n`,
+    },
+
+    gift: {
+      title: '<증정 메뉴>',
+      printMsg: (gift) => {
+        if (!gift) return '없음\n';
+
+        return `${gift.menu} ${gift.amount}개\n`;
+      },
+    },
+
+    benefits: {
+      title: '<혜택 내역>',
+      printMsg: (benefits) => {
+        if (!benefits) return '없음\n';
+
+        return Object.entries(benefits).reduce(
+          (acc, [eventName, { amount, price }]) =>
+            `${acc}${eventName}: -${(amount * price).toLocaleString()}원\n`,
+          '',
+        );
+      },
+    },
+
+    totalBenefitMoney: {
+      title: '<총혜택 금액>',
+      printMsg: (money) => {
+        if (!money) return '0원\n';
+
+        return `-${money.toLocaleString()}원\n`;
+      },
+    },
+
+    payment: {
+      title: '<할인 후 예상 결제 금액>',
+      printMsg: (money) => `${money.toLocaleString()}원\n`,
+    },
+
+    badge: {
+      title: '<12월 이벤트 배지>',
+      printMsg: (badge) => `${badge}`,
+    },
+  },
+
+  // Error
+  errors: {
+    prefix: '[ERROR]',
+    invalidDate: '유효하지 않은 날짜입니다. 다시 입력해 주세요.',
+    invalidOrders: '유효하지 않은 주문입니다. 다시 입력해 주세요.',
+  },
+});
+
+export default MESSAGES;

리뷰: toLocaleString 부분이 가격을 반환해줄때는 다 쓰이는데, 따로 모듈화 시키는 것도 좋을 것 같아요!
@@ -0,0 +1,83 @@
+import deepFreeze from '../utils/deepFreeze.js';
+import { EVENT_MONTH } from './event.js';
+
+const MESSAGES = deepFreeze({
+  // InputView
+  inputs: {
+    getVisitDate: `${EVENT_MONTH}월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)\n`,
+    getOrders:
+      '주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)\n',
+  },
+
+  // OutputView
+  outputs: {
+    sayHi: `안녕하세요! 우테코 식당 ${EVENT_MONTH}월 이벤트 플래너입니다.`,
+
+    eventPreview: (date) =>
+      `${EVENT_MONTH}월 ${date}일에 우테코 식당에서 받을 이벤트 혜택 미리 보기!\n`,
+
+    menus: {
+      title: '<주문 메뉴>',
+      printMsg: (menus) =>
+        menus.reduce(
+          (acc, { menu, amount }) => `${acc}${menu} ${amount}개\n`,
+          '',
+        ),
+    },
+
+    originalPrice: {
+      title: '<할인 전 총주문 금액>',
+      printMsg: (price) => `${price.toLocaleString()}원\n`,
+    },
+
+    gift: {
+      title: '<증정 메뉴>',
+      printMsg: (gift) => {
+        if (!gift) return '없음\n';
+
+        return `${gift.menu} ${gift.amount}개\n`;
+      },
+    },
+
+    benefits: {
+      title: '<혜택 내역>',
+      printMsg: (benefits) => {
+        if (!benefits) return '없음\n';
+
+        return Object.entries(benefits).reduce(
+          (acc, [eventName, { amount, price }]) =>
+            `${acc}${eventName}: -${(amount * price).toLocaleString()}원\n`,
+          '',
+        );
+      },
+    },
+
+    totalBenefitMoney: {
+      title: '<총혜택 금액>',
+      printMsg: (money) => {
+        if (!money) return '0원\n';
+
+        return `-${money.toLocaleString()}원\n`;
+      },
+    },
+
+    payment: {
+      title: '<할인 후 예상 결제 금액>',
+      printMsg: (money) => `${money.toLocaleString()}원\n`,
+    },
+
+    badge: {
+      title: '<12월 이벤트 배지>',
+      printMsg: (badge) => `${badge}`,
+    },
+  },
+
+  // Error
+  errors: {
+    prefix: '[ERROR]',
+    invalidDate: '유효하지 않은 날짜입니다. 다시 입력해 주세요.',
+    invalidOrders: '유효하지 않은 주문입니다. 다시 입력해 주세요.',
+  },
+});
+
+export default MESSAGES;

리뷰: 밑에서는 `totalBenefitMoney`로 상세하게 메서드명을 지으셔서 이것도 `benefits`보다는 `benefitsDetail`로 좀더 구체적인건 어떨까요?
@@ -0,0 +1,83 @@
+import deepFreeze from '../utils/deepFreeze.js';
+import { EVENT_MONTH } from './event.js';
+
+const MESSAGES = deepFreeze({
+  // InputView
+  inputs: {
+    getVisitDate: `${EVENT_MONTH}월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)\n`,
+    getOrders:
+      '주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)\n',
+  },
+
+  // OutputView
+  outputs: {
+    sayHi: `안녕하세요! 우테코 식당 ${EVENT_MONTH}월 이벤트 플래너입니다.`,
+
+    eventPreview: (date) =>
+      `${EVENT_MONTH}월 ${date}일에 우테코 식당에서 받을 이벤트 혜택 미리 보기!\n`,
+
+    menus: {
+      title: '<주문 메뉴>',
+      printMsg: (menus) =>
+        menus.reduce(
+          (acc, { menu, amount }) => `${acc}${menu} ${amount}개\n`,
+          '',
+        ),
+    },
+
+    originalPrice: {
+      title: '<할인 전 총주문 금액>',
+      printMsg: (price) => `${price.toLocaleString()}원\n`,
+    },
+
+    gift: {
+      title: '<증정 메뉴>',
+      printMsg: (gift) => {
+        if (!gift) return '없음\n';
+
+        return `${gift.menu} ${gift.amount}개\n`;
+      },
+    },
+
+    benefits: {
+      title: '<혜택 내역>',
+      printMsg: (benefits) => {
+        if (!benefits) return '없음\n';
+
+        return Object.entries(benefits).reduce(
+          (acc, [eventName, { amount, price }]) =>
+            `${acc}${eventName}: -${(amount * price).toLocaleString()}원\n`,
+          '',
+        );
+      },
+    },
+
+    totalBenefitMoney: {
+      title: '<총혜택 금액>',
+      printMsg: (money) => {
+        if (!money) return '0원\n';
+
+        return `-${money.toLocaleString()}원\n`;
+      },
+    },
+
+    payment: {
+      title: '<할인 후 예상 결제 금액>',
+      printMsg: (money) => `${money.toLocaleString()}원\n`,
+    },
+
+    badge: {
+      title: '<12월 이벤트 배지>',
+      printMsg: (badge) => `${badge}`,
+    },
+  },
+
+  // Error
+  errors: {
+    prefix: '[ERROR]',
+    invalidDate: '유효하지 않은 날짜입니다. 다시 입력해 주세요.',
+    invalidOrders: '유효하지 않은 주문입니다. 다시 입력해 주세요.',
+  },
+});
+
+export default MESSAGES;

리뷰: 앗 앞에서는 상수값을 가져왔었는데, 이건 하드코딩되어있습니다! 하나로 통일하면 좋을 것 같아요!
@@ -0,0 +1,63 @@
+import { FRIDAY, SATURDAY, SPECIAL_DATES } from '../constants/calendar.js';
+import { EVENT_PERIOD } from '../constants/event.js';
+import { ALL_EVENTS } from './Events.js';
+
+class EventCalendar {
+  #year;
+
+  #month;
+
+  #date;
+
+  #availableEvents;
+
+  constructor(year, month, date) {
+    this.#year = year;
+    this.#month = month;
+    this.#date = date;
+    this.#availableEvents = {};
+  }
+
+  async setAvailableEvents({ totalPrice, orderCategories }) {
+    const state = this.#getState(totalPrice, orderCategories);
+
+    await Object.values(ALL_EVENTS).forEach((event) => {
+      const { name, getBenefit } = event.getEvent();
+
+      if (event.isEventAvailable(state))
+        this.#availableEvents[name] = getBenefit;
+    });
+  }
+
+  #getState(totalPrice, orderCategories) {
+    return {
+      isWeekend: this.#isWeekend(),
+      isSpecialDate: this.#isSpecialDate(),
+      isChristmasPeriod: this.#isChristmasPeriod(),
+      totalPrice,
+      orderCategories,
+    };
+  }
+
+  #isWeekend() {
+    const dayOfWeek = new Date(
+      `${this.#year}-${this.#month}-${this.#date}`,
+    ).getDay();
+    return dayOfWeek === FRIDAY || dayOfWeek === SATURDAY;
+  }
+
+  #isSpecialDate() {
+    return SPECIAL_DATES.includes(this.#date);
+  }
+
+  #isChristmasPeriod() {
+    const { startDate, endDate } = EVENT_PERIOD;
+    return this.#date >= startDate && this.#date <= endDate;
+  }
+
+  get availableEvents() {
+    return this.#availableEvents;
+  }
+}
+
+export default EventCalendar;

리뷰: `Period` 꼼꼼하십니다! 👍👍👍
@@ -0,0 +1,63 @@
+import { FRIDAY, SATURDAY, SPECIAL_DATES } from '../constants/calendar.js';
+import { EVENT_PERIOD } from '../constants/event.js';
+import { ALL_EVENTS } from './Events.js';
+
+class EventCalendar {
+  #year;
+
+  #month;
+
+  #date;
+
+  #availableEvents;
+
+  constructor(year, month, date) {
+    this.#year = year;
+    this.#month = month;
+    this.#date = date;
+    this.#availableEvents = {};
+  }
+
+  async setAvailableEvents({ totalPrice, orderCategories }) {
+    const state = this.#getState(totalPrice, orderCategories);
+
+    await Object.values(ALL_EVENTS).forEach((event) => {
+      const { name, getBenefit } = event.getEvent();
+
+      if (event.isEventAvailable(state))
+        this.#availableEvents[name] = getBenefit;
+    });
+  }
+
+  #getState(totalPrice, orderCategories) {
+    return {
+      isWeekend: this.#isWeekend(),
+      isSpecialDate: this.#isSpecialDate(),
+      isChristmasPeriod: this.#isChristmasPeriod(),
+      totalPrice,
+      orderCategories,
+    };
+  }
+
+  #isWeekend() {
+    const dayOfWeek = new Date(
+      `${this.#year}-${this.#month}-${this.#date}`,
+    ).getDay();
+    return dayOfWeek === FRIDAY || dayOfWeek === SATURDAY;
+  }
+
+  #isSpecialDate() {
+    return SPECIAL_DATES.includes(this.#date);
+  }
+
+  #isChristmasPeriod() {
+    const { startDate, endDate } = EVENT_PERIOD;
+    return this.#date >= startDate && this.#date <= endDate;
+  }
+
+  get availableEvents() {
+    return this.#availableEvents;
+  }
+}
+
+export default EventCalendar;

리뷰: new Date(2023,11,25)등으로도 넣을 수 있습니다! 그런데 month의 경우 0으로 시작해서 1빼줘야 하더라구요...
@@ -0,0 +1,63 @@
+import { FRIDAY, SATURDAY, SPECIAL_DATES } from '../constants/calendar.js';
+import { EVENT_PERIOD } from '../constants/event.js';
+import { ALL_EVENTS } from './Events.js';
+
+class EventCalendar {
+  #year;
+
+  #month;
+
+  #date;
+
+  #availableEvents;
+
+  constructor(year, month, date) {
+    this.#year = year;
+    this.#month = month;
+    this.#date = date;
+    this.#availableEvents = {};
+  }
+
+  async setAvailableEvents({ totalPrice, orderCategories }) {
+    const state = this.#getState(totalPrice, orderCategories);
+
+    await Object.values(ALL_EVENTS).forEach((event) => {
+      const { name, getBenefit } = event.getEvent();
+
+      if (event.isEventAvailable(state))
+        this.#availableEvents[name] = getBenefit;
+    });
+  }
+
+  #getState(totalPrice, orderCategories) {
+    return {
+      isWeekend: this.#isWeekend(),
+      isSpecialDate: this.#isSpecialDate(),
+      isChristmasPeriod: this.#isChristmasPeriod(),
+      totalPrice,
+      orderCategories,
+    };
+  }
+
+  #isWeekend() {
+    const dayOfWeek = new Date(
+      `${this.#year}-${this.#month}-${this.#date}`,
+    ).getDay();
+    return dayOfWeek === FRIDAY || dayOfWeek === SATURDAY;
+  }
+
+  #isSpecialDate() {
+    return SPECIAL_DATES.includes(this.#date);
+  }
+
+  #isChristmasPeriod() {
+    const { startDate, endDate } = EVENT_PERIOD;
+    return this.#date >= startDate && this.#date <= endDate;
+  }
+
+  get availableEvents() {
+    return this.#availableEvents;
+  }
+}
+
+export default EventCalendar;

리뷰: 원래 반환되는 0,1,2,~ 대신 FRIDAY로 바꾸니까 훨씬 가독성 좋아지네요! 배워갑니다!👍👍👍