Newer
Older
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
import { FluidType, TimeStep } from 'enums'
import React, { useEffect, useState } from 'react'
import DateChartService from 'services/dateChart.service'
import { useAppDispatch, useAppSelector } from 'store/hooks'
import { formatDate } from 'utils/date'
import { getFluidName, getFluidUnit } from 'utils/utils'
xScale: ScaleBand<string>
yScale: ScaleLinear<number, number>
height: number
isMultiMissingFluid?: boolean
weekdays?: 'week' | 'weekend'
clickable?: boolean
average?: number
focusable?: boolean
const Bar = ({
index,
dataload,
xScale,
yScale,
height,
isSwitching,
isMultiMissingFluid,
weekdays,
clickable = true,
average,
const { t } = useI18n()
chart: { selectedDate, currentTimeStep },
global: { fluidStatus },
} = useAppSelector(state => state.ecolyo)
const [clicked, setClicked] = useState(false)
const [animationEnded, setAnimationEnded] = useState(false)
const [compareAnimationEnded, setCompareAnimationEnded] = useState(false)
const isMulti = fluidType === FluidType.MULTIFLUID
const FLUIDNAME = getFluidName(fluidType).toUpperCase()
if (!isSwitching && !isDuel && clickable) {
}
const onAnimationEnd = () => {
setClicked(false)
setAnimationEnded(true)
}
const onCompareAnimationEnd = () => {
setClicked(false)
setCompareAnimationEnded(true)
}
/** Get date of each fluid to display placeholder bar for multifluid */
const lastDataDates = fluidStatus.map(
fluid => fluid.lastDataDate ?? DateTime.local(0)
)
/** Pick current fluid date or max for multi */
let lastDataDate = isMulti
? DateTime.max(...lastDataDates)
: lastDataDates[fluidType]
/** Remove a day when viewing half-hour */
lastDataDate = lastDataDate.plus({
days: currentTimeStep === TimeStep.HALF_AN_HOUR ? 1 : 0,
})
/** True when between lastData and today's range */
const isDataMissingOrUpcoming = Boolean(
dataload.date > lastDataDate && dataload.date < DateTime.local()
)
let value = dataload.value
/** Adjust value for upcoming data (placeholder bars) */
if (isDataMissingOrUpcoming && average) {
// Use 10% of average if average is above 1
value = average * 0.1
} else {
value = average
}
const yScaleValue = yScale(value) ?? 0
const yScaleCompareValue = yScale(compareDataload?.value ?? 0) ?? 0
const xScaleValue =
xScale(dataload.date.toLocaleString(DateTime.DATETIME_SHORT)) ?? 0
const isSelectedDate = isDuel
? false
: new DateChartService().compareStepDate(
timeStep,
selectedDate,
dataload.date
)
const clickedAnim = clicked ? 'bounce-2 delay' : ''
const disabled = clickable ? '' : 'disabled'
const selected = isSelectedDate ? 'selected' : ''
const upcoming = dataload.value === -1 ? 'bar-UPCOMING' : ''
const baseStyles = [
`bar-${FLUIDNAME}`,
upcoming,
weekdays,
selected,
disabled,
]
.filter(Boolean)
.join(' ')
return `${baseStyles} ${clickedAnim}`
if (animationEnded) {
return baseStyles
}
return `${baseStyles} bounce-1 delay--${index}`
}
const getCompareBarClass = () => {
const animate = `bounce-2 delay--${clicked ? 0 : index}`
const animationClass = compareAnimationEnded ? '' : animate
return `bar-compare-${FLUIDNAME} ${selected} ${animationClass} ${clickedAnim}`
}
const barBackgroundClass = isSelectedDate
return compare ? xScale.bandwidth() / 2 : xScale.bandwidth()
x: number,
y: number,
width: number,
height: number
const radius = height > 4 ? 4 : height / 4
return `
M${x},${y + radius}
a${radius},${radius} 0 0 1 ${radius},${-radius}
h${width - 2 * radius}
a${radius},${radius} 0 0 1 ${radius},${radius}
v${height - radius}
h${-width}
z`
{/* selected background bar */}
<g
transform={`translate(${xScaleValue}, -40)`}
className={`barContainer ${disabled}`}
onClick={!weekdays ? handleClick : () => undefined}
width={compare ? getBandWidth() * 2 : getBandWidth()}
height={height + 40}
className={`background-${barBackgroundClass}`}
{/* placeholder bar for upcoming values */}
{height > 0 && isDataMissingOrUpcoming && (
<g
transform={`translate(${xScaleValue}, ${yScaleValue})`}
className="barFill"
>
<defs>
<linearGradient id="gradient" x1="0" x2="0" y1="0" y2="1">
<stop id="stop-color-1" offset="0%" />
<stop id="stop-color-2" offset="100%" />
</linearGradient>
</defs>
<path
d={topRoundedRect(
compare ? getBandWidth() : 0,
0,
weekdays ? 3 : getBandWidth(),
height - yScaleValue
)}
className={getBarClass()}
onClick={!weekdays ? handleClick : () => undefined}
onAnimationEnd={onAnimationEnd}
/>
</g>
)}
{height > 0 && dataload.value >= 0 && isMultiMissingFluid ? (

Guilhem CARRON
committed
<g
transform={`translate(${xScaleValue}, ${yScaleValue})`}
fill="#00000"

Guilhem CARRON
committed
>
<defs>
<linearGradient
id="gradient"
className={getBarClass()}
x1="0"
x2="0"
y1="0"
y2="1"
>
<stop id="stop-color-1" offset="0%" />
<stop id="stop-color-2" offset="100%" />
</linearGradient>
<pattern
id="diagonalHatch"
patternUnits="userSpaceOnUse"

Guilhem CARRON
committed
patternTransform="scale(1) rotate(-45)"

Guilhem CARRON
committed
<rect x="0" y="0" width="100%" height="100%" fill="#121212" />
<path d="M0 8h20z" strokeWidth="3" stroke="#71612E" fill="none" />
</pattern>
<pattern
id="diagonalHatchSelected"
patternUnits="userSpaceOnUse"

Guilhem CARRON
committed
patternTransform="scale(1) rotate(-45)"

Guilhem CARRON
committed
<rect x="0" y="0" width="100%" height="100%" fill="#121212" />
<path d="M0 8h20z" strokeWidth="3" stroke="#E3B82A" fill="none" />
</pattern>
</defs>
<path
d={topRoundedRect(
compare ? getBandWidth() : 0,
0,
getBandWidth(),
height - yScaleValue
)}

Guilhem CARRON
committed
stroke={!isSelectedDate ? '#71612E' : '#e3b82a'}
fill={
isSelectedDate
? 'url(#diagonalHatchSelected)'
: 'url(#diagonalHatch)'
}
onClick={!weekdays ? handleClick : () => undefined}
onAnimationEnd={onAnimationEnd}
/>
</g>
Boolean(height > 0 && dataload.value && dataload.value >= 0) && (
<g
className="barValue"
transform={`translate(${xScaleValue}, ${yScaleValue})`}
tabIndex={focusable ? 0 : -1}
onKeyDown={event => {
if (event.key === ' ') {
event.preventDefault() // prevent from scrolling page
handleClick()
}
}}
>
<title>
{t('consumption.accessibility.bar', {
date: formatDate(currentTimeStep, dataload.date),
value: Math.round(dataload.value * 100) / 100,
unit: getFluidUnit(fluidType),
})}
</title>
className={getBarClass()}
x1="0"
x2="0"
y1="0"
y2="1"
>
<stop id="stop-color-1" offset="0%" />
<stop id="stop-color-2" offset="100%" />
</linearGradient>
</defs>
<path
d={topRoundedRect(
compare ? getBandWidth() : 0,
0,
weekdays ? 3 : getBandWidth(),
height - yScaleValue
)}
className={isDuel ? 'bar-duel' : getBarClass()}
onClick={!weekdays ? handleClick : () => undefined}
onAnimationEnd={onAnimationEnd}
/>
</g>
)
)}
{compare && compareDataload && compareDataload.value >= 0 && (
<g transform={`translate(${xScaleValue}, ${yScaleCompareValue})`}>
<defs>
<linearGradient
id="gradient-compare"
className={getCompareBarClass()}
x1="0"
x2="0"
y1="0"
y2="1"
>
<stop id="stop-compare-color-1" offset="0%" />
<stop id="stop-compare-color-2" offset="100%" />
</linearGradient>
</defs>
<path
d={topRoundedRect(
0,
0,
getBandWidth(),
height - yScaleCompareValue
)}
className={getCompareBarClass()}
onClick={handleClick}
onAnimationEnd={onCompareAnimationEnd}
/>
</g>
)}