Memoized heatmap
This commit is contained in:
parent
2f23fcfd32
commit
decfc2b7e6
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useEffect, useRef, Fragment } from 'react';
|
import { useState, useEffect, useRef, useMemo, Fragment } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import localeData from 'dayjs/plugin/localeData';
|
import localeData from 'dayjs/plugin/localeData';
|
||||||
|
|
@ -65,49 +65,7 @@ const AvailabilityViewer = ({
|
||||||
setTouched(people.length <= 1);
|
setTouched(people.length <= 1);
|
||||||
}, [people]);
|
}, [people]);
|
||||||
|
|
||||||
return (
|
const heatmap = useMemo(() => (
|
||||||
<>
|
|
||||||
<StyledMain>
|
|
||||||
<Legend
|
|
||||||
min={Math.min(min, filteredPeople.length)}
|
|
||||||
max={Math.min(max, filteredPeople.length)}
|
|
||||||
total={people.filter(p => p.availability.length > 0).length}
|
|
||||||
onSegmentFocus={count => setFocusCount(count)}
|
|
||||||
/>
|
|
||||||
<Center style={{textAlign: 'center'}}>{t('event:group.info1')}</Center>
|
|
||||||
{people.length > 1 && (
|
|
||||||
<>
|
|
||||||
<Center style={{textAlign: 'center'}}>{t('event:group.info2')}</Center>
|
|
||||||
<People>
|
|
||||||
{people.map((person, i) =>
|
|
||||||
<Person
|
|
||||||
key={i}
|
|
||||||
filtered={filteredPeople.includes(person.name)}
|
|
||||||
onClick={() => {
|
|
||||||
setTempFocus(null);
|
|
||||||
if (filteredPeople.includes(person.name)) {
|
|
||||||
if (!touched) {
|
|
||||||
setTouched(true);
|
|
||||||
setFilteredPeople([person.name]);
|
|
||||||
} else {
|
|
||||||
setFilteredPeople(filteredPeople.filter(n => n !== person.name));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setFilteredPeople([...filteredPeople, person.name]);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onMouseOver={() => setTempFocus(person.name)}
|
|
||||||
onMouseOut={() => setTempFocus(null)}
|
|
||||||
title={person.created && dayjs.unix(person.created).fromNow()}
|
|
||||||
>{person.name}</Person>
|
|
||||||
)}
|
|
||||||
</People>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</StyledMain>
|
|
||||||
|
|
||||||
<Wrapper ref={wrapper}>
|
|
||||||
<ScrollWrapper>
|
|
||||||
<Container>
|
<Container>
|
||||||
<TimeLabels>
|
<TimeLabels>
|
||||||
{!!timeLabels.length && timeLabels.map((label, i) =>
|
{!!timeLabels.length && timeLabels.map((label, i) =>
|
||||||
|
|
@ -178,6 +136,68 @@ const AvailabilityViewer = ({
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Container>
|
</Container>
|
||||||
|
), [
|
||||||
|
people,
|
||||||
|
filteredPeople,
|
||||||
|
tempFocus,
|
||||||
|
focusCount,
|
||||||
|
highlight,
|
||||||
|
locale,
|
||||||
|
dates,
|
||||||
|
isSpecificDates,
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
t,
|
||||||
|
timeFormat,
|
||||||
|
timeLabels,
|
||||||
|
times,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<StyledMain>
|
||||||
|
<Legend
|
||||||
|
min={Math.min(min, filteredPeople.length)}
|
||||||
|
max={Math.min(max, filteredPeople.length)}
|
||||||
|
total={people.filter(p => p.availability.length > 0).length}
|
||||||
|
onSegmentFocus={count => setFocusCount(count)}
|
||||||
|
/>
|
||||||
|
<Center style={{textAlign: 'center'}}>{t('event:group.info1')}</Center>
|
||||||
|
{people.length > 1 && (
|
||||||
|
<>
|
||||||
|
<Center style={{textAlign: 'center'}}>{t('event:group.info2')}</Center>
|
||||||
|
<People>
|
||||||
|
{people.map((person, i) =>
|
||||||
|
<Person
|
||||||
|
key={i}
|
||||||
|
filtered={filteredPeople.includes(person.name)}
|
||||||
|
onClick={() => {
|
||||||
|
setTempFocus(null);
|
||||||
|
if (filteredPeople.includes(person.name)) {
|
||||||
|
if (!touched) {
|
||||||
|
setTouched(true);
|
||||||
|
setFilteredPeople([person.name]);
|
||||||
|
} else {
|
||||||
|
setFilteredPeople(filteredPeople.filter(n => n !== person.name));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setFilteredPeople([...filteredPeople, person.name]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseOver={() => setTempFocus(person.name)}
|
||||||
|
onMouseOut={() => setTempFocus(null)}
|
||||||
|
title={person.created && dayjs.unix(person.created).fromNow()}
|
||||||
|
>{person.name}</Person>
|
||||||
|
)}
|
||||||
|
</People>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</StyledMain>
|
||||||
|
|
||||||
|
<Wrapper ref={wrapper}>
|
||||||
|
<ScrollWrapper>
|
||||||
|
{heatmap}
|
||||||
|
|
||||||
{tooltip && (
|
{tooltip && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
x={tooltip.x}
|
x={tooltip.x}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export const Time = styled.div`
|
||||||
border-top: 2px dotted ${props.theme.text};
|
border-top: 2px dotted ${props.theme.text};
|
||||||
`}
|
`}
|
||||||
|
|
||||||
${props => props.highlight && props.peopleCount === props.maxPeople ? `
|
${props => props.highlight && props.peopleCount === props.maxPeople && props.peopleCount > 0 ? `
|
||||||
background-image: repeating-linear-gradient(
|
background-image: repeating-linear-gradient(
|
||||||
45deg,
|
45deg,
|
||||||
${props.theme.primary},
|
${props.theme.primary},
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ const Legend = ({
|
||||||
<Grade
|
<Grade
|
||||||
key={i}
|
key={i}
|
||||||
color={`${theme.primary}${Math.round((i/(max))*255).toString(16)}`}
|
color={`${theme.primary}${Math.round((i/(max))*255).toString(16)}`}
|
||||||
highlight={highlight && i === max}
|
highlight={highlight && i === max && max > 0}
|
||||||
onMouseOver={() => onSegmentFocus(i)}
|
onMouseOver={() => onSegmentFocus(i)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue