Skip to content

Commit

Permalink
#12 - feat: add cache operation and add value object
Browse files Browse the repository at this point in the history
  • Loading branch information
nullist0 committed May 30, 2021
1 parent 2433eb4 commit 4cadf49
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 96 deletions.
Binary file removed public/favicon.ico
Binary file not shown.
1 change: 0 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
Expand Down
Binary file removed public/logo192.png
Binary file not shown.
Binary file removed public/logo512.png
Binary file not shown.
43 changes: 4 additions & 39 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,11 @@
import React, { useState } from 'react';
import 'react-date-range/dist/styles.css';
import 'react-date-range/dist/theme/default.css';
import * as locales from 'react-date-range/dist/locale';
import { DateRange } from 'react-date-range';
import Range from './domain/range';

function CountResult({ count }) {
return (
<p data-testid='result'>{count}</p>
);
}

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 (
<DateRange
locale={locales['ko']}
editableDateInputs={true}
onChange={item => 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 (
Expand Down
20 changes: 0 additions & 20 deletions src/cache/holidayCache.js

This file was deleted.

7 changes: 7 additions & 0 deletions src/components/CountResult.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

export function CountResult({ count }) {
return (
<p data-testid='result'>{count}</p>
);
}
30 changes: 30 additions & 0 deletions src/components/DateRangePicker.js
Original file line number Diff line number Diff line change
@@ -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 (
<DateRange
locale={locales['ko']}
editableDateInputs={true}
onChange={item => handleChangeDateRange(item)}
ranges={[dateRange]}
dateDisplayFormat={'yyyy/MM/dd'} />
);
}
47 changes: 37 additions & 10 deletions src/dataSource/herokuHolidayDataSource.js
Original file line number Diff line number Diff line change
@@ -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));
Expand All @@ -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
}
13 changes: 13 additions & 0 deletions src/dataSource/month.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
27 changes: 3 additions & 24 deletions src/domain/weekdayCounter.js
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
}
Expand Down
3 changes: 1 addition & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<React.StrictMode>
<App
counter={new WeekdayCounter(new HolidayCache(HerokuHolidayDataSource))}
counter={new WeekdayCounter(HerokuHolidayDataSource)}
/>
</React.StrictMode>,
document.getElementById('root')
Expand Down

0 comments on commit 4cadf49

Please sign in to comment.