fix(client): add tooltip for calendar-heatmap (#36008)
This commit is contained in:
9
client/package-lock.json
generated
9
client/package-lock.json
generated
@ -16617,6 +16617,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-tooltip": {
|
||||||
|
"version": "3.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.10.0.tgz",
|
||||||
|
"integrity": "sha512-GGdxJvM1zSFztkTP7gCQbLTstWr1OOoMpJ5WZUGhimj0nhRY+MPz+92MpEnKmj0cftJ9Pd/M6FfSl0sfzmZWkg==",
|
||||||
|
"requires": {
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"prop-types": "^15.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-transition-group": {
|
"react-transition-group": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.1.0.tgz",
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
"react-responsive": "^6.1.1",
|
"react-responsive": "^6.1.1",
|
||||||
"react-spinkit": "^3.0.0",
|
"react-spinkit": "^3.0.0",
|
||||||
"react-stripe-elements": "^2.0.3",
|
"react-stripe-elements": "^2.0.3",
|
||||||
|
"react-tooltip": "^3.10.0",
|
||||||
"react-transition-group": "^4.1.0",
|
"react-transition-group": "^4.1.0",
|
||||||
"react-youtube": "^7.9.0",
|
"react-youtube": "^7.9.0",
|
||||||
"redux": "^4.0.1",
|
"redux": "^4.0.1",
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Helmet } from 'react-helmet';
|
|
||||||
import CalendarHeatMap from 'react-calendar-heatmap';
|
import CalendarHeatMap from 'react-calendar-heatmap';
|
||||||
import startOfMonth from 'date-fns/start_of_month';
|
import ReactTooltip from 'react-tooltip';
|
||||||
|
import addDays from 'date-fns/add_days';
|
||||||
|
import addMonths from 'date-fns/add_months';
|
||||||
import startOfDay from 'date-fns/start_of_day';
|
import startOfDay from 'date-fns/start_of_day';
|
||||||
import format from 'date-fns/format';
|
import format from 'date-fns/format';
|
||||||
|
|
||||||
@ -20,44 +21,42 @@ const propTypes = {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
const today = new Date(now);
|
|
||||||
const sixMonthsInMillseconds = 15780000000;
|
|
||||||
const sixMonthsAgoInMilliseconds = now - sixMonthsInMillseconds;
|
|
||||||
const sixMonthsAgo = startOfMonth(sixMonthsAgoInMilliseconds);
|
|
||||||
|
|
||||||
function HeatMap({ calendar, streak }) {
|
function HeatMap({ calendar, streak }) {
|
||||||
const dateValueMap = Object.keys(calendar)
|
const startOfToday = startOfDay(Date.now());
|
||||||
.map(ts => Number(ts * 1000) || null)
|
const sixMonthsAgo = addMonths(startOfToday, -6);
|
||||||
.filter(Boolean)
|
const startOfCalendar = format(addDays(sixMonthsAgo, -1), 'YYYY-MM-DD');
|
||||||
.reduce((map, current) => {
|
const endOfCalendar = format(startOfToday, 'YYYY-MM-DD');
|
||||||
const startOfCurrent = format(startOfDay(current), 'YYYY-MM-DD');
|
|
||||||
if (startOfCurrent in map) {
|
|
||||||
map[startOfCurrent] = map[startOfCurrent] + 1;
|
|
||||||
} else {
|
|
||||||
map[startOfCurrent] = 1;
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const calendarValues = Object.keys(dateValueMap).map(key => ({
|
let calendarData = {};
|
||||||
|
let dayCounter = sixMonthsAgo;
|
||||||
|
|
||||||
|
while (dayCounter <= startOfToday) {
|
||||||
|
calendarData[format(dayCounter, 'YYYY-MM-DD')] = 0;
|
||||||
|
dayCounter = addDays(dayCounter, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let timestamp in calendar) {
|
||||||
|
if (calendar.hasOwnProperty(timestamp)) {
|
||||||
|
timestamp = Number(timestamp * 1000) || null;
|
||||||
|
if (timestamp) {
|
||||||
|
const startOfTimestampDay = format(startOfDay(timestamp), 'YYYY-MM-DD');
|
||||||
|
calendarData[startOfTimestampDay] =
|
||||||
|
calendarData[startOfTimestampDay] + 1 || 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const calendarValues = Object.keys(calendarData).map(key => ({
|
||||||
date: key,
|
date: key,
|
||||||
count: dateValueMap[key]
|
count: calendarData[key]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FullWidthRow id='cal-heatmap-container'>
|
<FullWidthRow>
|
||||||
<Helmet>
|
|
||||||
<script
|
|
||||||
src='https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js'
|
|
||||||
type='text/javascript'
|
|
||||||
/>
|
|
||||||
<link href='/css/cal-heatmap.css' rel='stylesheet' />
|
|
||||||
</Helmet>
|
|
||||||
<FullWidthRow>
|
<FullWidthRow>
|
||||||
<CalendarHeatMap
|
<CalendarHeatMap
|
||||||
classForValue={value => {
|
classForValue={value => {
|
||||||
if (!value) {
|
if (!value || value.count < 1) {
|
||||||
return 'colour-empty';
|
return 'colour-empty';
|
||||||
}
|
}
|
||||||
if (value.count > 4) {
|
if (value.count > 4) {
|
||||||
@ -65,19 +64,39 @@ function HeatMap({ calendar, streak }) {
|
|||||||
}
|
}
|
||||||
return `colour-scale-${value.count}`;
|
return `colour-scale-${value.count}`;
|
||||||
}}
|
}}
|
||||||
endDate={today}
|
endDate={endOfCalendar}
|
||||||
startDate={sixMonthsAgo}
|
startDate={startOfCalendar}
|
||||||
|
tooltipDataAttrs={value => {
|
||||||
|
let valueCount;
|
||||||
|
if (value && value.count === 1) {
|
||||||
|
valueCount = '1 point';
|
||||||
|
} else if (value && value.count > 1) {
|
||||||
|
valueCount = `${value.count} points`;
|
||||||
|
} else {
|
||||||
|
valueCount = 'No points';
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'data-tip': `<strong>${valueCount}</strong> on ${new Date(
|
||||||
|
value.date
|
||||||
|
).toLocaleDateString('en-US', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric'
|
||||||
|
})}`
|
||||||
|
};
|
||||||
|
}}
|
||||||
values={calendarValues}
|
values={calendarValues}
|
||||||
/>
|
/>
|
||||||
|
<ReactTooltip className='react-tooltip' effect='solid' html={true} />
|
||||||
</FullWidthRow>
|
</FullWidthRow>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<FullWidthRow>
|
<FullWidthRow>
|
||||||
<div className='streak-container'>
|
<div className='streak-container'>
|
||||||
<span className='streak'>
|
<span className='streak'>
|
||||||
<strong>Longest Streak:</strong> {streak.longest || 1}
|
<strong>Longest Streak:</strong> {streak.longest || 0}
|
||||||
</span>
|
</span>
|
||||||
<span className='streak'>
|
<span className='streak'>
|
||||||
<strong>Current Streak:</strong> {streak.current || 1}
|
<strong>Current Streak:</strong> {streak.current || 0}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</FullWidthRow>
|
</FullWidthRow>
|
||||||
|
@ -31,3 +31,8 @@
|
|||||||
.react-calendar-heatmap .colour-scale-a-lot {
|
.react-calendar-heatmap .colour-scale-a-lot {
|
||||||
fill: #006400;
|
fill: #006400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.react-tooltip {
|
||||||
|
background-color: #006400 !important;
|
||||||
|
border: 1px solid black !important;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user