fix(client): accuracy issue with heatmap (#38137)
* fix/accuracy-issue-with-heatmap * fix: typo * feat: add test and simplify logic * test: mock Date.now and update snapshot Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@ -22,35 +22,55 @@ const propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function HeatMap({ calendar, streak }) {
|
function HeatMap({ calendar, streak }) {
|
||||||
const startOfToday = startOfDay(Date.now());
|
// an issue with react-calendar-heatmap makes the days off by one
|
||||||
|
// see this https://github.com/kevinsqi/react-calendar-heatmap/issues/112
|
||||||
|
// I have added one day in the marked places to account for the offset
|
||||||
|
|
||||||
|
// this logic adds a day to all the timestamps (remove if issue gets fixed)
|
||||||
|
let tempCalendar = {};
|
||||||
|
const secondsInADay = 60 * 60 * 24;
|
||||||
|
for (let timestamp of Object.keys(calendar)) {
|
||||||
|
tempCalendar[parseInt(timestamp, 10) + secondsInADay] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
calendar = tempCalendar;
|
||||||
|
|
||||||
|
// the addDays of 1 to startOfToday (remove if issue gets fixed)
|
||||||
|
const startOfToday = addDays(startOfDay(Date.now()), 1);
|
||||||
const sixMonthsAgo = addMonths(startOfToday, -6);
|
const sixMonthsAgo = addMonths(startOfToday, -6);
|
||||||
const startOfCalendar = format(addDays(sixMonthsAgo, -1), 'YYYY-MM-DD');
|
const startOfCalendar = format(addDays(sixMonthsAgo, -1), 'YYYY-MM-DD');
|
||||||
const endOfCalendar = format(startOfToday, 'YYYY-MM-DD');
|
const endOfCalendar = format(startOfToday, 'YYYY-MM-DD');
|
||||||
|
|
||||||
let calendarData = {};
|
let calendarData = [];
|
||||||
let dayCounter = sixMonthsAgo;
|
let dayCounter = sixMonthsAgo;
|
||||||
|
|
||||||
|
// create a data point for each day of the calendar period (six months)
|
||||||
while (dayCounter <= startOfToday) {
|
while (dayCounter <= startOfToday) {
|
||||||
calendarData[format(dayCounter, 'YYYY-MM-DD')] = 0;
|
// this is the format needed for react-calendar-heatmap
|
||||||
|
const newDay = {
|
||||||
|
date: format(dayCounter, 'YYYY-MM-DD'),
|
||||||
|
count: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
calendarData.push(newDay);
|
||||||
dayCounter = addDays(dayCounter, 1);
|
dayCounter = addDays(dayCounter, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let timestamp in calendar) {
|
// this adds one to the count of the day for each timestamp
|
||||||
if (calendar.hasOwnProperty(timestamp)) {
|
for (let timestamp of Object.keys(calendar)) {
|
||||||
timestamp = Number(timestamp * 1000) || null;
|
timestamp = Number(timestamp * 1000) || null;
|
||||||
if (timestamp) {
|
if (timestamp) {
|
||||||
const startOfTimestampDay = format(startOfDay(timestamp), 'YYYY-MM-DD');
|
const startOfTimestampDay = format(startOfDay(timestamp), 'YYYY-MM-DD');
|
||||||
calendarData[startOfTimestampDay] =
|
const index = calendarData.findIndex(
|
||||||
calendarData[startOfTimestampDay] + 1 || 1;
|
day => day.date === startOfTimestampDay
|
||||||
|
);
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
calendarData[index].count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const calendarValues = Object.keys(calendarData).map(key => ({
|
|
||||||
date: key,
|
|
||||||
count: calendarData[key]
|
|
||||||
}));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FullWidthRow>
|
<FullWidthRow>
|
||||||
<FullWidthRow>
|
<FullWidthRow>
|
||||||
@ -83,7 +103,7 @@ function HeatMap({ calendar, streak }) {
|
|||||||
})}`
|
})}`
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
values={calendarValues}
|
values={calendarData}
|
||||||
/>
|
/>
|
||||||
<ReactTooltip className='react-tooltip' effect='solid' html={true} />
|
<ReactTooltip className='react-tooltip' effect='solid' html={true} />
|
||||||
</FullWidthRow>
|
</FullWidthRow>
|
||||||
|
37
client/src/components/profile/components/HeatMap.test.js
Normal file
37
client/src/components/profile/components/HeatMap.test.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/* global expect jest */
|
||||||
|
|
||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
|
import React from 'react';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import HeatMap from './HeatMap';
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
calendar: {
|
||||||
|
1580393017: 1,
|
||||||
|
1580397504: 1
|
||||||
|
},
|
||||||
|
streak: {
|
||||||
|
current: 2,
|
||||||
|
longest: 2
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let dateNowMockFn;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
dateNowMockFn = jest
|
||||||
|
.spyOn(Date, 'now')
|
||||||
|
.mockImplementation(() => 1580729769714);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
dateNowMockFn.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('<HeatMap/>', () => {
|
||||||
|
it('renders correctly', () => {
|
||||||
|
const { container } = render(<HeatMap {...props} />);
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user