diff --git a/public/favicon.ico b/public/favicon.ico
deleted file mode 100644
index a11777c..0000000
Binary files a/public/favicon.ico and /dev/null differ
diff --git a/public/index.html b/public/index.html
index aa069f2..0eb6c96 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,7 +2,6 @@
-
{count} 일
- );
-}
-
-function DateRangePicker({ onChangeRange }) {
- const [dateRange, setRange] = useState({
- startDate: new Date(),
- endDate: new Date(),
- key: 'dateRange'
- });
- const handleChangeDateRange = ({ dateRange }) => {
- const range = new Range(dateRange.startDate, dateRange.endDate);
-
- setRange(dateRange);
- onChangeRange(range);
- };
-
- return (
- handleChangeDateRange(item)}
-
- ranges={[dateRange]}
- dateDisplayFormat={'yyyy/MM/dd'}
- />
- );
-}
+import { DateRangePicker } from './components/DateRangePicker';
+import { CountResult } from './components/CountResult';
function App({ counter }) {
const [count, setCount] = useState(0);
- const handleChangeRange = async (range) => {
- const newCount = await counter.countWeekdayInRange(range);
- setCount(newCount);
+ const handleChangeRange = (range) => {
+ counter.countWeekdayInRange(range).then(setCount);
};
return (
diff --git a/src/cache/holidayCache.js b/src/cache/holidayCache.js
deleted file mode 100644
index ceb0e62..0000000
--- a/src/cache/holidayCache.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import format from 'date-fns/format';
-
-function getKey(date) {
- return format(date, 'yyyy/MM');
-}
-
-export default class HolidayCache {
- constructor(dataSource) {
- this.dataSource = dataSource;
- this.cache = {};
- }
-
- getHolidaysIn = async (month) => {
- const key = getKey(month);
- if (!(key in Object.keys(this.cache))) {
- this.cache[key] = await this.dataSource.getHolidaysIn(month);
- }
- return this.cache[key];
- }
-}
\ No newline at end of file
diff --git a/src/components/CountResult.js b/src/components/CountResult.js
new file mode 100644
index 0000000..2abb9fd
--- /dev/null
+++ b/src/components/CountResult.js
@@ -0,0 +1,7 @@
+import React from 'react';
+
+export function CountResult({ count }) {
+ return (
+ {count} 일
+ );
+}
diff --git a/src/components/DateRangePicker.js b/src/components/DateRangePicker.js
new file mode 100644
index 0000000..bceadcf
--- /dev/null
+++ b/src/components/DateRangePicker.js
@@ -0,0 +1,30 @@
+import React, { useState } from 'react';
+import * as locales from 'react-date-range/dist/locale';
+import { DateRange } from 'react-date-range';
+import Range from '../domain/range';
+
+import 'react-date-range/dist/styles.css';
+import 'react-date-range/dist/theme/default.css';
+
+export function DateRangePicker({ onChangeRange }) {
+ const [dateRange, setRange] = useState({
+ startDate: new Date(),
+ endDate: new Date(),
+ key: 'dateRange'
+ });
+ const handleChangeDateRange = ({ dateRange }) => {
+ const range = new Range(dateRange.startDate, dateRange.endDate);
+
+ setRange(dateRange);
+ onChangeRange(range);
+ };
+
+ return (
+ handleChangeDateRange(item)}
+ ranges={[dateRange]}
+ dateDisplayFormat={'yyyy/MM/dd'} />
+ );
+}
diff --git a/src/dataSource/herokuHolidayDataSource.js b/src/dataSource/herokuHolidayDataSource.js
index 50d94f3..bc3d6d3 100644
--- a/src/dataSource/herokuHolidayDataSource.js
+++ b/src/dataSource/herokuHolidayDataSource.js
@@ -1,5 +1,10 @@
import axios from 'axios';
-import { format } from 'date-fns';
+import { isBefore } from 'date-fns';
+import addMonths from 'date-fns/addMonths';
+import isWeekend from 'date-fns/isWeekend';
+import isWithinInterval from 'date-fns/isWithinInterval';
+import startOfMonth from 'date-fns/startOfMonth';
+import Month from './month';
function readDate(dateString) {
const year = parseInt(dateString.substr(0, 4));
@@ -9,17 +14,39 @@ function readDate(dateString) {
return new Date(year, month - 1, day);
}
-async function getHolidaysIn(month) {
- const params = {
- year: format(month, 'yyyy'),
- month: format(month, 'MM')
- };
- const apiUrl = `https://shielded-forest-67184.herokuapp.com/holidays?year=${params.year}&month=${params.month}`;
- const { data: { dates } } = await axios.get(apiUrl);
+const cache = {};
+
+async function getHolidaysInMonth({ year, month }) {
+ const apiUrl = `https://shielded-forest-67184.herokuapp.com/holidays?year=${year}&month=${month}`;
+
+ if (cache[apiUrl] === undefined) {
+ const { data: { dates } } = await axios.get(apiUrl);
+ const holidays = dates.map(readDate);
+ cache[apiUrl] = holidays;
+ }
+ return cache[apiUrl];
+}
+
+function* monthsInRange(range) {
+ const {start, end} = range;
+ const endMonth = startOfMonth(addMonths(end, 1));
+ let currentMonth = startOfMonth(start);
+
+ while(isBefore(currentMonth, endMonth)) {
+ yield new Month(currentMonth);
+ currentMonth = addMonths(currentMonth, 1);
+ }
+}
+
+async function getHolidaysInRange(range) {
+ const months = Array.from(monthsInRange(range));
- return dates.map(readDate);
+ return (await Promise.all(months.map(getHolidaysInMonth)))
+ .flat()
+ .filter(date => isWithinInterval(date, range))
+ .filter(date => !isWeekend(date));
}
export {
- getHolidaysIn
+ getHolidaysInRange
}
\ No newline at end of file
diff --git a/src/dataSource/month.js b/src/dataSource/month.js
new file mode 100644
index 0000000..4f63b21
--- /dev/null
+++ b/src/dataSource/month.js
@@ -0,0 +1,13 @@
+export default class Month {
+ constructor(date) {
+ const year = date.getFullYear();
+ const month = date.getMonth() + 1;
+
+ this.year = year.toString();
+ this.month = month.toString().padStart(2, '0');
+ }
+
+ toString() {
+ return this.year + this.month;
+ }
+}
\ No newline at end of file
diff --git a/src/domain/weekdayCounter.js b/src/domain/weekdayCounter.js
index 35e9b69..090cef1 100644
--- a/src/domain/weekdayCounter.js
+++ b/src/domain/weekdayCounter.js
@@ -1,16 +1,4 @@
-import { differenceInBusinessDays, addDays, isWithinInterval, startOfMonth, addMonths, isBefore, isWeekend } from 'date-fns';
-
-function* monthsInRange(range) {
- const {start, end} = range;
- const endMonth = startOfMonth(addMonths(end, 1));
-
- let currentMonth = startOfMonth(start);
-
- while(isBefore(currentMonth, endMonth)) {
- yield currentMonth;
- currentMonth = addMonths(currentMonth, 1);
- }
-}
+import { differenceInBusinessDays, addDays } from 'date-fns';
function countAllNonWeekendIn(range) {
const {start, end} = range;
@@ -19,19 +7,10 @@ function countAllNonWeekendIn(range) {
return differenceInBusinessDays(nextEndDate, start);
}
-async function countWeekdayHolidaysIn(dataSource, range) {
- const months = Array.from(monthsInRange(range));
- const holidaysInRange = (await Promise.all(months.map(dataSource.getHolidaysIn)))
- .flat()
- .filter(date => isWithinInterval(date, range))
- .filter(date => !isWeekend(date));
-
- return holidaysInRange.length;
-}
-
async function countWeekdayInRange(dataSource, range) {
const nonWeekendCount = countAllNonWeekendIn(range);
- const holidaysCount = await countWeekdayHolidaysIn(dataSource, range);
+ const holidaysInRange = await dataSource.getHolidaysInRange(range);
+ const holidaysCount = holidaysInRange.length;
return nonWeekendCount - holidaysCount;
}
diff --git a/src/index.js b/src/index.js
index 921cd6b..fc4114c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,12 +3,11 @@ import React from 'react';
import App from './App';
import WeekdayCounter from './domain/weekdayCounter';
import * as HerokuHolidayDataSource from './dataSource/herokuHolidayDataSource';
-import HolidayCache from './cache/holidayCache';
ReactDOM.render(
,
document.getElementById('root')