Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • web-et-numerique/factory/llle_project/ecolyo
1 result
Select Git revision
Show changes
Commits on Source (10)
Showing
with 362 additions and 662 deletions
...@@ -50,6 +50,18 @@ module.exports = { ...@@ -50,6 +50,18 @@ module.exports = {
'no-param-reassign': 'warn', 'no-param-reassign': 'warn',
'spaced-comment': ['error', 'always', { block: { exceptions: ['*'] } }], 'spaced-comment': ['error', 'always', { block: { exceptions: ['*'] } }],
'react/self-closing-comp': 'warn', 'react/self-closing-comp': 'warn',
// Rule to suggest using useAppDispatch instead of regular useDispatch
'no-restricted-imports': 'off',
'@typescript-eslint/no-restricted-imports': [
'warn',
{
name: 'react-redux',
importNames: ['useSelector', 'useDispatch'],
message:
'Use typed hooks `useAppDispatch` and `useAppSelector` instead.',
},
],
}, },
root: true, root: true,
settings: { settings: {
......
<svg width="27" height="26" viewBox="0 0 27 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_15041_508)">
<circle cx="13.5" cy="11" r="11" fill="#E3B82A"/>
<circle cx="13.5" cy="11" r="10.5" stroke="white"/>
</g>
<path d="M12.634 4.5C13.0189 3.83333 13.9811 3.83333 14.366 4.5L20.4282 15C20.8131 15.6667 20.332 16.5 19.5622 16.5H7.43782C6.66802 16.5 6.1869 15.6667 6.5718 15L12.634 4.5Z" fill="#1B1C22"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4001 7.5001C14.4001 7.00304 13.9972 6.6001 13.5001 6.6001C13.003 6.6001 12.6001 7.00304 12.6001 7.5001V12.0001C12.6001 12.4972 13.003 12.9001 13.5001 12.9001C13.9972 12.9001 14.4001 12.4972 14.4001 12.0001L14.4001 7.5001ZM14.4001 14.7001C14.4001 14.203 13.9972 13.8001 13.5001 13.8001C13.003 13.8001 12.6001 14.203 12.6001 14.7001C12.6001 15.1972 13.003 15.6001 13.5001 15.6001C13.9972 15.6001 14.4001 15.1972 14.4001 14.7001Z" fill="#E3B82A"/>
<defs>
<filter id="filter0_d_15041_508" x="0.5" y="0" width="26" height="26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_15041_508"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_15041_508" result="shape"/>
</filter>
</defs>
</svg>
...@@ -59,7 +59,7 @@ const ActionBegin = ({ ...@@ -59,7 +59,7 @@ const ActionBegin = ({
return () => { return () => {
subscribed = false subscribed = false
} }
}, [client, isProfileTypeCompleted, fluidTypes, action, currentAction]) }, [action, client, fluidTypes, isProfileTypeCompleted])
useEffect(() => { useEffect(() => {
async function handleEcogestureIcon() { async function handleEcogestureIcon() {
......
...@@ -109,7 +109,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` ...@@ -109,7 +109,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = `
> >
<defs> <defs>
<linearGradient <linearGradient
className="bar-ELECTRICITY weekend bounce-3 delay--0 " className="bar-ELECTRICITY weekend bounce-3 delay--0"
id="gradient" id="gradient"
x1="0" x1="0"
x2="0" x2="0"
...@@ -127,9 +127,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` ...@@ -127,9 +127,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = `
</linearGradient> </linearGradient>
</defs> </defs>
<path <path
className="bar-ELECTRICITY weekend bounce-3 delay--0 " className="bar-ELECTRICITY weekend bounce-3 delay--0"
d="M0,4 a4,4 0 0 1 4,-4h-5a4,4 0 0 1 4,4v136h-3z" d="
fill="url(#gradient)" M0,4
a4,4 0 0 1 4,-4
h-5
a4,4 0 0 1 4,4
v136
h-3
z"
onAnimationEnd={[Function]} onAnimationEnd={[Function]}
onClick={[Function]} onClick={[Function]}
/> />
...@@ -178,7 +184,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` ...@@ -178,7 +184,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = `
> >
<defs> <defs>
<linearGradient <linearGradient
className="bar-ELECTRICITY weekend bounce-3 delay--1 " className="bar-ELECTRICITY weekend bounce-3 delay--1"
id="gradient" id="gradient"
x1="0" x1="0"
x2="0" x2="0"
...@@ -196,9 +202,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` ...@@ -196,9 +202,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = `
</linearGradient> </linearGradient>
</defs> </defs>
<path <path
className="bar-ELECTRICITY weekend bounce-3 delay--1 " className="bar-ELECTRICITY weekend bounce-3 delay--1"
d="M0,4 a4,4 0 0 1 4,-4h-5a4,4 0 0 1 4,4v136h-3z" d="
fill="url(#gradient)" M0,4
a4,4 0 0 1 4,-4
h-5
a4,4 0 0 1 4,4
v136
h-3
z"
onAnimationEnd={[Function]} onAnimationEnd={[Function]}
onClick={[Function]} onClick={[Function]}
/> />
...@@ -247,7 +259,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` ...@@ -247,7 +259,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = `
> >
<defs> <defs>
<linearGradient <linearGradient
className="bar-ELECTRICITY weekend bounce-3 delay--2 " className="bar-ELECTRICITY weekend bounce-3 delay--2"
id="gradient" id="gradient"
x1="0" x1="0"
x2="0" x2="0"
...@@ -265,9 +277,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` ...@@ -265,9 +277,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = `
</linearGradient> </linearGradient>
</defs> </defs>
<path <path
className="bar-ELECTRICITY weekend bounce-3 delay--2 " className="bar-ELECTRICITY weekend bounce-3 delay--2"
d="M0,4 a4,4 0 0 1 4,-4h-5a4,4 0 0 1 4,4v136h-3z" d="
fill="url(#gradient)" M0,4
a4,4 0 0 1 4,-4
h-5
a4,4 0 0 1 4,4
v136
h-3
z"
onAnimationEnd={[Function]} onAnimationEnd={[Function]}
onClick={[Function]} onClick={[Function]}
/> />
...@@ -316,7 +334,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` ...@@ -316,7 +334,7 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = `
> >
<defs> <defs>
<linearGradient <linearGradient
className="bar-ELECTRICITY weekend bounce-3 delay--3 " className="bar-ELECTRICITY weekend bounce-3 delay--3"
id="gradient" id="gradient"
x1="0" x1="0"
x2="0" x2="0"
...@@ -334,9 +352,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = ` ...@@ -334,9 +352,15 @@ exports[`ElecHalfHourChart component should be rendered correctly 1`] = `
</linearGradient> </linearGradient>
</defs> </defs>
<path <path
className="bar-ELECTRICITY weekend bounce-3 delay--3 " className="bar-ELECTRICITY weekend bounce-3 delay--3"
d="M0,4 a4,4 0 0 1 4,-4h-5a4,4 0 0 1 4,4v136h-3z" d="
fill="url(#gradient)" M0,4
a4,4 0 0 1 4,-4
h-5
a4,4 0 0 1 4,4
v136
h-3
z"
onAnimationEnd={[Function]} onAnimationEnd={[Function]}
onClick={[Function]} onClick={[Function]}
/> />
......
import { ScaleBand, ScaleLinear } from 'd3-scale' import { ScaleBand, ScaleLinear } from 'd3-scale'
import { detect } from 'detect-browser' import { detect } from 'detect-browser'
import { FluidType, TimeStep } from 'enums' import { DataloadState, FluidType, TimeStep } from 'enums'
import { DateTime } from 'luxon' import { DateTime } from 'luxon'
import { Dataload } from 'models' import { Dataload } from 'models'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
...@@ -26,6 +26,7 @@ interface BarProps { ...@@ -26,6 +26,7 @@ interface BarProps {
isMultiMissingFluid?: boolean isMultiMissingFluid?: boolean
weekdays?: 'week' | 'weekend' weekdays?: 'week' | 'weekend'
clickable?: boolean clickable?: boolean
average?: number
} }
const Bar = ({ const Bar = ({
...@@ -43,6 +44,7 @@ const Bar = ({ ...@@ -43,6 +44,7 @@ const Bar = ({
isMultiMissingFluid, isMultiMissingFluid,
weekdays, weekdays,
clickable = true, clickable = true,
average,
}: BarProps) => { }: BarProps) => {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { selectedDate } = useAppSelector(state => state.ecolyo.chart) const { selectedDate } = useAppSelector(state => state.ecolyo.chart)
...@@ -71,16 +73,19 @@ const Bar = ({ ...@@ -71,16 +73,19 @@ const Bar = ({
setCompareAnimationEnded(true) setCompareAnimationEnded(true)
} }
const tempYScale: number | undefined = yScale(dataload.value) let value = dataload.value
const yScaleValue: number = tempYScale ? tempYScale : 0 /**
const tempCompareYScale: number | undefined = yScale( * Use 10% of average as the placeholder if average is above 1,
compareDataload ? compareDataload.value : 0 * otherwise use a minimum of 1 as the placeholder.
) */
const yScaleCompareValue: number = tempCompareYScale ? tempCompareYScale : 0 if (value === -1 && average) {
const tempXScale: number | undefined = xScale( value = average > 1 ? average * 0.1 : 1
dataload.date.toLocaleString(DateTime.DATETIME_SHORT) }
) const yScaleValue = yScale(value) ?? 0
const xScaleValue: number = tempXScale ? tempXScale : 0 const yScaleCompareValue = yScale(compareDataload?.value ?? 0) ?? 0
const xScaleValue =
xScale(dataload.date.toLocaleString(DateTime.DATETIME_SHORT)) ?? 0
const isSelectedDate = isDuel const isSelectedDate = isDuel
? false ? false
...@@ -90,47 +95,32 @@ const Bar = ({ ...@@ -90,47 +95,32 @@ const Bar = ({
dataload.date dataload.date
) )
const delayIndex = index % 13 const clickedAnim = clicked ? 'bounce-2 delay' : ''
const edgeBrowser = browser && browser.name !== 'edge' const disabled = clickable ? '' : 'disabled'
const selected = isSelectedDate ? ' selected' : '' const selected = isSelectedDate ? 'selected' : ''
const bounce = edgeBrowser ? '1' : '3'
const disabled = `${clickable ? '' : 'disabled'}`
const getBarClass = () => { const getBarClass = () => {
const bounceDelay = ` bounce-${bounce} delay--${delayIndex}` const upcoming = dataload.value === -1 ? 'bar-UNCOMING' : ''
const fluidWeekdays = `bar-${fluidStyle} ${weekdays}` const edgeBrowser = browser && browser.name !== 'edge'
const bounce = edgeBrowser ? '1' : '3'
const baseStyles = `bar-${fluidStyle} ${upcoming} ${weekdays} ${selected} ${disabled}`
if (clicked) { if (clicked) {
return `${fluidWeekdays}${selected} bounce-2 delay` return `${baseStyles} ${clickedAnim}`
} else if (animationEnded) {
return `${fluidWeekdays}${selected} ${disabled}`
} }
return `${fluidWeekdays}${bounceDelay}${selected} ${disabled}` if (animationEnded) {
return baseStyles
}
return `${baseStyles} bounce-${bounce} delay--${index}`
} }
const getCompareBarClass = () => { const getCompareBarClass = () => {
const bounceValue = clicked ? (edgeBrowser ? '2' : '3') : bounce const animate = `bounce-2 delay--${clicked ? 0 : index}`
const bounceDelay = ` bounce-${bounceValue} delay--${ const animationClass = compareAnimationEnded ? '' : animate
clicked ? 0 : delayIndex
}`
const fluidStyleClass = `bar-compare-${fluidStyle}`
if (clicked) { return `bar-compare-${fluidStyle} ${selected} ${animationClass} ${clickedAnim}`
return `${fluidStyleClass} ${selected}${bounceDelay}`
}
if (isSelectedDate) {
return compareAnimationEnded
? `${fluidStyleClass} ${selected}`
: `${fluidStyleClass} ${selected}${bounceDelay}`
}
return compareAnimationEnded
? fluidStyleClass
: `${fluidStyleClass} ${bounceDelay}`
} }
const compareBarClass = getCompareBarClass()
const barClass = getBarClass()
const barBackgroundClass = isSelectedDate const barBackgroundClass = isSelectedDate
const getBandWidth = (): number => { const getBandWidth = (): number => {
...@@ -138,41 +128,21 @@ const Bar = ({ ...@@ -138,41 +128,21 @@ const Bar = ({
} }
const topRoundedRect = ( const topRoundedRect = (
_x: number, x: number,
_y: number, y: number,
_width: number, width: number,
_height: number height: number
): string => { ): string => {
const radius = _height > 4 ? 4 : _height / 4 const radius = height > 4 ? 4 : height / 4
return (
'M' + return `
_x + M${x},${y + radius}
',' + a${radius},${radius} 0 0 1 ${radius},${-radius}
(_y + radius) + h${width - 2 * radius}
' a' + a${radius},${radius} 0 0 1 ${radius},${radius}
radius + v${height - radius}
',' + h${-width}
radius + z`
' 0 0 1 ' +
radius +
',' +
-radius +
'h' +
(_width - 2 * radius) +
'a' +
radius +
',' +
radius +
' 0 0 1 ' +
radius +
',' +
radius +
'v' +
(_height - radius) +
'h' +
-_width +
'z'
)
} }
useEffect(() => { useEffect(() => {
...@@ -184,6 +154,7 @@ const Bar = ({ ...@@ -184,6 +154,7 @@ const Bar = ({
return ( return (
<g> <g>
{/* selected background bar */}
{height > 0 && ( {height > 0 && (
<g <g
transform={`translate(${xScaleValue}, -40)`} transform={`translate(${xScaleValue}, -40)`}
...@@ -200,6 +171,33 @@ const Bar = ({ ...@@ -200,6 +171,33 @@ const Bar = ({
/> />
</g> </g>
)} )}
{/* placeholder bar for upcoming values */}
{height > 0 &&
dataload.state === DataloadState.COMING &&
dataload.date < DateTime.local() && (
<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 ? ( {height > 0 && dataload.value >= 0 && isMultiMissingFluid ? (
<g <g
transform={`translate(${xScaleValue}, ${yScaleValue})`} transform={`translate(${xScaleValue}, ${yScaleValue})`}
...@@ -209,7 +207,7 @@ const Bar = ({ ...@@ -209,7 +207,7 @@ const Bar = ({
<defs> <defs>
<linearGradient <linearGradient
id="gradient" id="gradient"
className={barClass} className={getBarClass()}
x1="0" x1="0"
x2="0" x2="0"
y1="0" y1="0"
...@@ -252,7 +250,6 @@ const Bar = ({ ...@@ -252,7 +250,6 @@ const Bar = ({
? 'url(#diagonalHatchSelected)' ? 'url(#diagonalHatchSelected)'
: 'url(#diagonalHatch)' : 'url(#diagonalHatch)'
} }
// className={isDuel ? 'bar-duel' : barClass}
onClick={!weekdays ? handleClick : () => undefined} onClick={!weekdays ? handleClick : () => undefined}
onAnimationEnd={onAnimationEnd} onAnimationEnd={onAnimationEnd}
/> />
...@@ -265,7 +262,7 @@ const Bar = ({ ...@@ -265,7 +262,7 @@ const Bar = ({
<defs> <defs>
<linearGradient <linearGradient
id="gradient" id="gradient"
className={barClass} className={getBarClass()}
x1="0" x1="0"
x2="0" x2="0"
y1="0" y1="0"
...@@ -282,8 +279,7 @@ const Bar = ({ ...@@ -282,8 +279,7 @@ const Bar = ({
weekdays ? 3 : getBandWidth(), weekdays ? 3 : getBandWidth(),
height - yScaleValue height - yScaleValue
)} )}
fill="url(#gradient)" className={isDuel ? 'bar-duel' : getBarClass()}
className={isDuel ? 'bar-duel' : barClass}
onClick={!weekdays ? handleClick : () => undefined} onClick={!weekdays ? handleClick : () => undefined}
onAnimationEnd={onAnimationEnd} onAnimationEnd={onAnimationEnd}
/> />
...@@ -296,7 +292,7 @@ const Bar = ({ ...@@ -296,7 +292,7 @@ const Bar = ({
<defs> <defs>
<linearGradient <linearGradient
id="gradient-compare" id="gradient-compare"
className={compareBarClass} className={getCompareBarClass()}
x1="0" x1="0"
x2="0" x2="0"
y1="0" y1="0"
...@@ -313,8 +309,7 @@ const Bar = ({ ...@@ -313,8 +309,7 @@ const Bar = ({
getBandWidth(), getBandWidth(),
height - yScaleCompareValue height - yScaleCompareValue
)} )}
fill="url(#gradient-compare)" className={getCompareBarClass()}
className={compareBarClass}
onClick={handleClick} onClick={handleClick}
onAnimationEnd={onCompareAnimationEnd} onAnimationEnd={onCompareAnimationEnd}
/> />
......
...@@ -11,6 +11,7 @@ interface BarChartProps { ...@@ -11,6 +11,7 @@ interface BarChartProps {
chartData: Datachart chartData: Datachart
fluidType: FluidType fluidType: FluidType
timeStep: TimeStep timeStep: TimeStep
/** showCompare should be false for analysis view */
showCompare: boolean showCompare: boolean
width?: number width?: number
height?: number height?: number
...@@ -76,6 +77,9 @@ const BarChart = ({ ...@@ -76,6 +77,9 @@ const BarChart = ({
.domain([0, getMaxLoad()]) .domain([0, getMaxLoad()])
.range([getContentHeight(), 0]) .range([getContentHeight(), 0])
const sum = chartData.actualData.reduce((a, b) => a + b.value, 0)
const averageConsumption = sum / chartData.actualData.length
return ( return (
<svg width={width} height={height}> <svg width={width} height={height}>
<AxisRight <AxisRight
...@@ -112,6 +116,7 @@ const BarChart = ({ ...@@ -112,6 +116,7 @@ const BarChart = ({
: false : false
} }
clickable={clickable} clickable={clickable}
average={averageConsumption}
/> />
))} ))}
</g> </g>
......
...@@ -6,7 +6,6 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' ...@@ -6,7 +6,6 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import { FluidState, FluidType, UsageEventType } from 'enums' import { FluidState, FluidType, UsageEventType } from 'enums'
import React, { useCallback, useEffect, useState } from 'react' import React, { useCallback, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import DateChartService from 'services/dateChart.service'
import UsageEventService from 'services/usageEvent.service' import UsageEventService from 'services/usageEvent.service'
import { useAppSelector } from 'store/hooks' import { useAppSelector } from 'store/hooks'
import { getNavPicto } from 'utils/picto' import { getNavPicto } from 'utils/picto'
...@@ -42,15 +41,6 @@ const FluidButton = ({ fluidType, isActive }: FluidButtonProps) => { ...@@ -42,15 +41,6 @@ const FluidButton = ({ fluidType, isActive }: FluidButtonProps) => {
return false return false
}, [fluidStatus, fluidType]) }, [fluidStatus, fluidType])
const isOutdated = useCallback(() => {
const dateChartService = new DateChartService()
return dateChartService.isDataOutdated(
fluidStatus[fluidType].lastDataDate,
fluidType
)
}, [fluidStatus, fluidType])
const iconType = getNavPicto(fluidType, isActive, isConnected()) const iconType = getNavPicto(fluidType, isActive, isConnected())
const goToFluid = useCallback(async () => { const goToFluid = useCallback(async () => {
...@@ -69,13 +59,10 @@ const FluidButton = ({ fluidType, isActive }: FluidButtonProps) => { ...@@ -69,13 +59,10 @@ const FluidButton = ({ fluidType, isActive }: FluidButtonProps) => {
useEffect(() => { useEffect(() => {
// Show errors only on connected konnectors that are in error, outdated, with no data (specific case), and not in multifluid // Show errors only on connected konnectors that are in error, outdated, with no data (specific case), and not in multifluid
if ( if (fluidType !== FluidType.MULTIFLUID && isConnected() && isErrored()) {
(fluidType !== FluidType.MULTIFLUID && isConnected() && isErrored()) ||
(fluidType !== FluidType.MULTIFLUID && isConnected() && isOutdated())
) {
setShowError(true) setShowError(true)
} }
}, [fluidStatus, fluidType, isConnected, isErrored, isOutdated]) }, [fluidStatus, fluidType, isConnected, isErrored])
return ( return (
<div <div
className={`fluid-title ${FluidType[ className={`fluid-title ${FluidType[
......
import { DataloadState, FluidType } from 'enums' import { DataloadState, FluidType } from 'enums'
import { mount } from 'enzyme' import { mount } from 'enzyme'
import toJson from 'enzyme-to-json' import toJson from 'enzyme-to-json'
import { DateTime } from 'luxon'
import { Dataload } from 'models' import { Dataload } from 'models'
import React from 'react' import React from 'react'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
...@@ -11,14 +12,21 @@ import { createMockEcolyoStore, mockChartState } from 'tests/__mocks__/store' ...@@ -11,14 +12,21 @@ import { createMockEcolyoStore, mockChartState } from 'tests/__mocks__/store'
import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import { waitForComponentToPaint } from 'tests/__mocks__/testUtils'
import DataloadConsumptionVisualizer from './DataloadConsumptionVisualizer' import DataloadConsumptionVisualizer from './DataloadConsumptionVisualizer'
const mockGetAllLastPrices = jest.fn()
jest.mock('services/fluidsPrices.service', () => { jest.mock('services/fluidsPrices.service', () => {
return jest.fn(() => ({ return jest.fn(() => ({
getAllLastPrices: mockGetAllLastPrices, getAllLastPrices: jest.fn(),
})) }))
}) })
const mockChartStateLoaded = { ...mockChartState, loading: false } jest.mock(
'components/ConsumptionVisualizer/DataloadNoValue.tsx',
() => 'mock-DataloadNoValue'
)
jest.mock(
'components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx',
() => 'mock-EstimatedConsumptionModal'
)
const emptyDataLoad = { ...baseDataLoad, value: -1 } const emptyDataLoad = { ...baseDataLoad, value: -1 }
const dataLoadWithValueDetailEmpty: Dataload = { const dataLoadWithValueDetailEmpty: Dataload = {
...baseDataLoad, ...baseDataLoad,
...@@ -34,10 +42,55 @@ const dataLoadWithValueDetail: Dataload = { ...@@ -34,10 +42,55 @@ const dataLoadWithValueDetail: Dataload = {
} }
describe('Dataload consumption visualizer component', () => { describe('Dataload consumption visualizer component', () => {
it('should render with single fluid', async () => { const store = createMockEcolyoStore()
const store = createMockEcolyoStore({ describe('should render nothing', () => {
chart: mockChartStateLoaded, it('should render nothing if dataload is null', () => {
const wrapper = mount(
<Provider store={store}>
<DataloadConsumptionVisualizer
fluidType={FluidType.ELECTRICITY}
dataload={null as unknown as Dataload}
compareDataload={baseDataLoad}
setActive={jest.fn()}
/>
</Provider>
)
expect(wrapper.find('.dataloadvisualizer-root').children()).toHaveLength(
0
)
})
it('should render nothing if dataload is in the future', () => {
const wrapper = mount(
<Provider store={store}>
<DataloadConsumptionVisualizer
fluidType={FluidType.ELECTRICITY}
dataload={{ ...baseDataLoad, date: DateTime.local(9999, 1, 1) }}
compareDataload={baseDataLoad}
setActive={jest.fn()}
/>
</Provider>
)
expect(wrapper.find('.dataloadvisualizer-root').children()).toHaveLength(
0
)
}) })
})
it('should render DataloadNoValue if dataload.state is not valid', () => {
const wrapper = mount(
<Provider store={store}>
<DataloadConsumptionVisualizer
fluidType={FluidType.ELECTRICITY}
dataload={{ ...baseDataLoad, state: DataloadState.MISSING }}
compareDataload={baseDataLoad}
setActive={jest.fn()}
/>
</Provider>
)
expect(wrapper.find('mock-DataloadNoValue').exists()).toBeTruthy()
})
it('should render with single fluid', async () => {
const wrapper = mount( const wrapper = mount(
<Provider store={store}> <Provider store={store}>
<DataloadConsumptionVisualizer <DataloadConsumptionVisualizer
...@@ -70,7 +123,7 @@ describe('Dataload consumption visualizer component', () => { ...@@ -70,7 +123,7 @@ describe('Dataload consumption visualizer component', () => {
it('should render with no value to compare available', async () => { it('should render with no value to compare available', async () => {
const store = createMockEcolyoStore({ const store = createMockEcolyoStore({
chart: { ...mockChartStateLoaded, showCompare: true }, chart: { ...mockChartState, showCompare: true },
}) })
const wrapper = mount( const wrapper = mount(
<Provider store={store}> <Provider store={store}>
...@@ -86,7 +139,7 @@ describe('Dataload consumption visualizer component', () => { ...@@ -86,7 +139,7 @@ describe('Dataload consumption visualizer component', () => {
}) })
it('should render with water comparison data', async () => { it('should render with water comparison data', async () => {
const store = createMockEcolyoStore({ const store = createMockEcolyoStore({
chart: { ...mockChartStateLoaded, showCompare: true }, chart: { ...mockChartState, showCompare: true },
}) })
const wrapper = mount( const wrapper = mount(
<Provider store={store}> <Provider store={store}>
...@@ -101,10 +154,6 @@ describe('Dataload consumption visualizer component', () => { ...@@ -101,10 +154,6 @@ describe('Dataload consumption visualizer component', () => {
expect(wrapper.find('.water-compare').exists()).toBeTruthy() expect(wrapper.find('.water-compare').exists()).toBeTruthy()
}) })
it('should render multifluid with no compare and display estimation modal', async () => { it('should render multifluid with no compare and display estimation modal', async () => {
const store = createMockEcolyoStore({
chart: mockChartStateLoaded,
})
const wrapper = mount( const wrapper = mount(
<Provider store={store}> <Provider store={store}>
<DataloadConsumptionVisualizer <DataloadConsumptionVisualizer
...@@ -115,16 +164,12 @@ describe('Dataload consumption visualizer component', () => { ...@@ -115,16 +164,12 @@ describe('Dataload consumption visualizer component', () => {
/> />
</Provider> </Provider>
) )
expect(wrapper.find('.estimated').first().simulate('click')) expect(wrapper.find('mock-EstimatedConsumptionModal').exists()).toBeTruthy()
}) })
it('should render multifluid with no compare and navigate to singleFluid page', async () => { it('should render multifluid with no compare and navigate to singleFluid page', async () => {
const store = createMockEcolyoStore({
chart: mockChartStateLoaded,
})
const mockLoadToEuro = jest.fn()
jest.mock('services/converter.service', () => { jest.mock('services/converter.service', () => {
return jest.fn(() => ({ return jest.fn(() => ({
LoadToEuro: mockLoadToEuro, LoadToEuro: jest.fn(),
})) }))
}) })
......
import { DataloadSectionType, DataloadState, FluidType } from 'enums' import { DataloadSectionType, DataloadState, FluidType } from 'enums'
import { DateTime } from 'luxon'
import { Dataload } from 'models' import { Dataload } from 'models'
import React, { useCallback, useState } from 'react' import React, { useCallback, useState } from 'react'
import { useAppSelector } from 'store/hooks' import { useAppSelector } from 'store/hooks'
...@@ -25,7 +26,7 @@ const DataloadConsumptionVisualizer = ({ ...@@ -25,7 +26,7 @@ const DataloadConsumptionVisualizer = ({
setOpenEstimationModal(prev => !prev) setOpenEstimationModal(prev => !prev)
}, []) }, [])
if (!dataload) { if (!dataload || dataload.date > DateTime.local()) {
return <div className="dataloadvisualizer-root" /> return <div className="dataloadvisualizer-root" />
} }
......
...@@ -66,9 +66,7 @@ const DataloadNoValue = ({ ...@@ -66,9 +66,7 @@ const DataloadNoValue = ({
return ( return (
<div <div
onClick={handleToggleKonnectionCard} onClick={handleToggleKonnectionCard}
className={classNames('dataloadvisualizer-content text-22-normal', { className={classNames('dataloadvisualizer-content text-22-normal')}
['error']: fluidType !== FluidType.MULTIFLUID,
})}
> >
{t('consumption_visualizer.missing_data')} {t('consumption_visualizer.missing_data')}
</div> </div>
......
...@@ -56,7 +56,7 @@ const InfoDataConsumptionVisualizer = ({ ...@@ -56,7 +56,7 @@ const InfoDataConsumptionVisualizer = ({
const lastDate = lastDataDate ? lastDataDate.toFormat("dd'/'MM'/'yy") : '-' const lastDate = lastDataDate ? lastDataDate.toFormat("dd'/'MM'/'yy") : '-'
return ( return (
<div onClick={() => moveToDate()} className="error-line"> <div onClick={() => moveToDate()} className="error-line">
<span className={`text-16-normal underlined-error`}> <span className="text-16-bold underlined-error">
{fluidType === FluidType.MULTIFLUID {fluidType === FluidType.MULTIFLUID
? t('consumption_visualizer.last_valid_data_multi', { ? t('consumption_visualizer.last_valid_data_multi', {
date: lastDate, date: lastDate,
......
...@@ -100,378 +100,10 @@ exports[`Dataload consumption visualizer component should render with single flu ...@@ -100,378 +100,10 @@ exports[`Dataload consumption visualizer component should render with single flu
</div> </div>
</DataloadSection> </DataloadSection>
</div> </div>
<EstimatedConsumptionModal <mock-EstimatedConsumptionModal
handleCloseClick={[Function]} handleCloseClick={[Function]}
open={false} open={false}
> />
<WithStyles(ForwardRef(Dialog))
aria-labelledby="accessibility-title"
classes={
Object {
"paper": "modal-paper",
"root": "modal-root",
}
}
onClose={[Function]}
open={false}
>
<ForwardRef(Dialog)
aria-labelledby="accessibility-title"
classes={
Object {
"container": "MuiDialog-container",
"paper": "MuiDialog-paper modal-paper",
"paperFullScreen": "MuiDialog-paperFullScreen",
"paperFullWidth": "MuiDialog-paperFullWidth",
"paperScrollBody": "MuiDialog-paperScrollBody",
"paperScrollPaper": "MuiDialog-paperScrollPaper",
"paperWidthFalse": "MuiDialog-paperWidthFalse",
"paperWidthLg": "MuiDialog-paperWidthLg",
"paperWidthMd": "MuiDialog-paperWidthMd",
"paperWidthSm": "MuiDialog-paperWidthSm",
"paperWidthXl": "MuiDialog-paperWidthXl",
"paperWidthXs": "MuiDialog-paperWidthXs",
"root": "MuiDialog-root modal-root",
"scrollBody": "MuiDialog-scrollBody",
"scrollPaper": "MuiDialog-scrollPaper",
}
}
onClose={[Function]}
open={false}
>
<ForwardRef(Modal)
BackdropComponent={
Object {
"$$typeof": Symbol(react.forward_ref),
"Naked": Object {
"$$typeof": Symbol(react.forward_ref),
"propTypes": Object {
"children": [Function],
"className": [Function],
"classes": [Function],
"invisible": [Function],
"open": [Function],
"transitionDuration": [Function],
},
"render": [Function],
},
"displayName": "WithStyles(ForwardRef(Backdrop))",
"options": Object {
"defaultTheme": Object {
"breakpoints": Object {
"between": [Function],
"down": [Function],
"keys": Array [
"xs",
"sm",
"md",
"lg",
"xl",
],
"only": [Function],
"up": [Function],
"values": Object {
"lg": 1280,
"md": 960,
"sm": 600,
"xl": 1920,
"xs": 0,
},
"width": [Function],
},
"direction": "ltr",
"mixins": Object {
"gutters": [Function],
"toolbar": Object {
"@media (min-width:0px) and (orientation: landscape)": Object {
"minHeight": 48,
},
"@media (min-width:600px)": Object {
"minHeight": 64,
},
"minHeight": 56,
},
},
"overrides": Object {},
"palette": Object {
"action": Object {
"activatedOpacity": 0.12,
"active": "rgba(0, 0, 0, 0.54)",
"disabled": "rgba(0, 0, 0, 0.26)",
"disabledBackground": "rgba(0, 0, 0, 0.12)",
"disabledOpacity": 0.38,
"focus": "rgba(0, 0, 0, 0.12)",
"focusOpacity": 0.12,
"hover": "rgba(0, 0, 0, 0.04)",
"hoverOpacity": 0.04,
"selected": "rgba(0, 0, 0, 0.08)",
"selectedOpacity": 0.08,
},
"augmentColor": [Function],
"background": Object {
"default": "#fafafa",
"paper": "#fff",
},
"common": Object {
"black": "#000",
"white": "#fff",
},
"contrastThreshold": 3,
"divider": "rgba(0, 0, 0, 0.12)",
"error": Object {
"contrastText": "#fff",
"dark": "#d32f2f",
"light": "#e57373",
"main": "#f44336",
},
"getContrastText": [Function],
"grey": Object {
"100": "#f5f5f5",
"200": "#eeeeee",
"300": "#e0e0e0",
"400": "#bdbdbd",
"50": "#fafafa",
"500": "#9e9e9e",
"600": "#757575",
"700": "#616161",
"800": "#424242",
"900": "#212121",
"A100": "#d5d5d5",
"A200": "#aaaaaa",
"A400": "#303030",
"A700": "#616161",
},
"info": Object {
"contrastText": "#fff",
"dark": "#1976d2",
"light": "#64b5f6",
"main": "#2196f3",
},
"primary": Object {
"contrastText": "#fff",
"dark": "#303f9f",
"light": "#7986cb",
"main": "#3f51b5",
},
"secondary": Object {
"contrastText": "#fff",
"dark": "#c51162",
"light": "#ff4081",
"main": "#f50057",
},
"success": Object {
"contrastText": "rgba(0, 0, 0, 0.87)",
"dark": "#388e3c",
"light": "#81c784",
"main": "#4caf50",
},
"text": Object {
"disabled": "rgba(0, 0, 0, 0.38)",
"hint": "rgba(0, 0, 0, 0.38)",
"primary": "rgba(0, 0, 0, 0.87)",
"secondary": "rgba(0, 0, 0, 0.54)",
},
"tonalOffset": 0.2,
"type": "light",
"warning": Object {
"contrastText": "rgba(0, 0, 0, 0.87)",
"dark": "#f57c00",
"light": "#ffb74d",
"main": "#ff9800",
},
},
"props": Object {},
"shadows": Array [
"none",
"0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)",
"0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)",
"0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)",
"0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)",
"0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)",
"0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)",
"0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)",
"0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)",
"0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)",
"0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)",
"0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)",
"0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)",
"0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)",
"0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)",
"0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)",
"0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)",
"0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)",
"0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)",
"0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)",
"0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)",
"0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)",
"0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)",
"0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)",
"0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)",
],
"shape": Object {
"borderRadius": 4,
},
"spacing": [Function],
"transitions": Object {
"create": [Function],
"duration": Object {
"complex": 375,
"enteringScreen": 225,
"leavingScreen": 195,
"short": 250,
"shorter": 200,
"shortest": 150,
"standard": 300,
},
"easing": Object {
"easeIn": "cubic-bezier(0.4, 0, 1, 1)",
"easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)",
"easeOut": "cubic-bezier(0.0, 0, 0.2, 1)",
"sharp": "cubic-bezier(0.4, 0, 0.6, 1)",
},
"getAutoHeightDuration": [Function],
},
"typography": Object {
"body1": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "1rem",
"fontWeight": 400,
"letterSpacing": "0.00938em",
"lineHeight": 1.5,
},
"body2": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "0.875rem",
"fontWeight": 400,
"letterSpacing": "0.01071em",
"lineHeight": 1.43,
},
"button": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "0.875rem",
"fontWeight": 500,
"letterSpacing": "0.02857em",
"lineHeight": 1.75,
"textTransform": "uppercase",
},
"caption": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "0.75rem",
"fontWeight": 400,
"letterSpacing": "0.03333em",
"lineHeight": 1.66,
},
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": 14,
"fontWeightBold": 700,
"fontWeightLight": 300,
"fontWeightMedium": 500,
"fontWeightRegular": 400,
"h1": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "6rem",
"fontWeight": 300,
"letterSpacing": "-0.01562em",
"lineHeight": 1.167,
},
"h2": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "3.75rem",
"fontWeight": 300,
"letterSpacing": "-0.00833em",
"lineHeight": 1.2,
},
"h3": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "3rem",
"fontWeight": 400,
"letterSpacing": "0em",
"lineHeight": 1.167,
},
"h4": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "2.125rem",
"fontWeight": 400,
"letterSpacing": "0.00735em",
"lineHeight": 1.235,
},
"h5": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "1.5rem",
"fontWeight": 400,
"letterSpacing": "0em",
"lineHeight": 1.334,
},
"h6": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "1.25rem",
"fontWeight": 500,
"letterSpacing": "0.0075em",
"lineHeight": 1.6,
},
"htmlFontSize": 16,
"overline": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "0.75rem",
"fontWeight": 400,
"letterSpacing": "0.08333em",
"lineHeight": 2.66,
"textTransform": "uppercase",
},
"pxToRem": [Function],
"round": [Function],
"subtitle1": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "1rem",
"fontWeight": 400,
"letterSpacing": "0.00938em",
"lineHeight": 1.75,
},
"subtitle2": Object {
"fontFamily": "\\"Roboto\\", \\"Helvetica\\", \\"Arial\\", sans-serif",
"fontSize": "0.875rem",
"fontWeight": 500,
"letterSpacing": "0.00714em",
"lineHeight": 1.57,
},
},
"zIndex": Object {
"appBar": 1100,
"drawer": 1200,
"mobileStepper": 1000,
"modal": 1300,
"snackbar": 1400,
"speedDial": 1050,
"tooltip": 1500,
},
},
"name": "MuiBackdrop",
},
"propTypes": Object {
"classes": [Function],
"innerRef": [Function],
},
"render": [Function],
"useStyles": [Function],
}
}
BackdropProps={
Object {
"transitionDuration": Object {
"enter": 225,
"exit": 195,
},
}
}
className="MuiDialog-root modal-root"
closeAfterTransition={true}
disableEscapeKeyDown={false}
onClose={[Function]}
open={false}
/>
</ForwardRef(Dialog)>
</WithStyles(ForwardRef(Dialog))>
</EstimatedConsumptionModal>
</div> </div>
</DataloadConsumptionVisualizer> </DataloadConsumptionVisualizer>
</Provider> </Provider>
......
...@@ -9,15 +9,7 @@ import { importIconById } from 'utils/utils' ...@@ -9,15 +9,7 @@ import { importIconById } from 'utils/utils'
import EfficiencyRating from '../EfficiencyRating/EfficiencyRating' import EfficiencyRating from '../EfficiencyRating/EfficiencyRating'
import './ecogestureCard.scss' import './ecogestureCard.scss'
interface EcogestureCardProps { const EcogestureCard = ({ ecogesture }: { ecogesture: Ecogesture }) => {
ecogesture: Ecogesture
selectionCompleted?: boolean
}
const EcogestureCard = ({
ecogesture,
selectionCompleted = false,
}: EcogestureCardProps) => {
const [ecogestureIcon, setEcogestureIcon] = useState<string>('') const [ecogestureIcon, setEcogestureIcon] = useState<string>('')
useEffect(() => { useEffect(() => {
async function handleEcogestureIcon() { async function handleEcogestureIcon() {
...@@ -34,7 +26,6 @@ const EcogestureCard = ({ ...@@ -34,7 +26,6 @@ const EcogestureCard = ({
to={{ to={{
pathname: `/ecogesture/${ecogesture.id}`, pathname: `/ecogesture/${ecogesture.id}`,
}} }}
state={{ selectionCompleted }}
component={RouterLink} component={RouterLink}
className="ecogesture-list-item" className="ecogesture-list-item"
> >
......
...@@ -76,11 +76,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` ...@@ -76,11 +76,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = `
"render": [Function], "render": [Function],
} }
} }
state={
Object {
"selectionCompleted": false,
}
}
to={ to={
Object { Object {
"pathname": "/ecogesture/ECOGESTURE001", "pathname": "/ecogesture/ECOGESTURE001",
...@@ -106,11 +101,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` ...@@ -106,11 +101,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = `
"render": [Function], "render": [Function],
} }
} }
state={
Object {
"selectionCompleted": false,
}
}
to={ to={
Object { Object {
"pathname": "/ecogesture/ECOGESTURE001", "pathname": "/ecogesture/ECOGESTURE001",
...@@ -129,11 +119,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` ...@@ -129,11 +119,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = `
} }
onBlur={[Function]} onBlur={[Function]}
onFocus={[Function]} onFocus={[Function]}
state={
Object {
"selectionCompleted": false,
}
}
to={ to={
Object { Object {
"pathname": "/ecogesture/ECOGESTURE001", "pathname": "/ecogesture/ECOGESTURE001",
...@@ -187,11 +172,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` ...@@ -187,11 +172,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = `
} }
onBlur={[Function]} onBlur={[Function]}
onFocus={[Function]} onFocus={[Function]}
state={
Object {
"selectionCompleted": false,
}
}
to={ to={
Object { Object {
"pathname": "/ecogesture/ECOGESTURE001", "pathname": "/ecogesture/ECOGESTURE001",
...@@ -203,11 +183,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = ` ...@@ -203,11 +183,6 @@ exports[`EcogestureCard component should be rendered correctly 1`] = `
className="MuiTypography-root MuiLink-root MuiLink-underlineHover ecogesture-list-item MuiTypography-colorPrimary" className="MuiTypography-root MuiLink-root MuiLink-underlineHover ecogesture-list-item MuiTypography-colorPrimary"
onBlur={[Function]} onBlur={[Function]}
onFocus={[Function]} onFocus={[Function]}
state={
Object {
"selectionCompleted": false,
}
}
to={ to={
Object { Object {
"pathname": "/ecogesture/ECOGESTURE001", "pathname": "/ecogesture/ECOGESTURE001",
......
...@@ -56,11 +56,7 @@ const EcogestureList = ({ ...@@ -56,11 +56,7 @@ const EcogestureList = ({
if (filteredEcogestures.length > 0) { if (filteredEcogestures.length > 0) {
return filteredEcogestures.map(ecogesture => ( return filteredEcogestures.map(ecogesture => (
<EcogestureCard <EcogestureCard key={ecogesture.id} ecogesture={ecogesture} />
key={ecogesture.id}
ecogesture={ecogesture}
selectionCompleted={selectionViewed === selectionTotal}
/>
)) ))
} }
......
...@@ -1872,7 +1872,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` ...@@ -1872,7 +1872,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = `
} }
} }
key="ECOGESTURE001" key="ECOGESTURE001"
selectionCompleted={true}
/> />
<mock-ecogesturecard <mock-ecogesturecard
ecogesture={ ecogesture={
...@@ -1910,7 +1909,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` ...@@ -1910,7 +1909,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = `
} }
} }
key="ECOGESTURE002" key="ECOGESTURE002"
selectionCompleted={true}
/> />
<mock-ecogesturecard <mock-ecogesturecard
ecogesture={ ecogesture={
...@@ -1951,7 +1949,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = ` ...@@ -1951,7 +1949,6 @@ exports[`EcogesturesList component should be rendered correctly 1`] = `
} }
} }
key="ECOGESTURE0013" key="ECOGESTURE0013"
selectionCompleted={true}
/> />
<WithStyles(ForwardRef(Button)) <WithStyles(ForwardRef(Button))
classes={ classes={
......
...@@ -8,18 +8,6 @@ import { createMockEcolyoStore } from 'tests/__mocks__/store' ...@@ -8,18 +8,6 @@ import { createMockEcolyoStore } from 'tests/__mocks__/store'
import { waitForComponentToPaint } from 'tests/__mocks__/testUtils' import { waitForComponentToPaint } from 'tests/__mocks__/testUtils'
import SingleEcogestureView from './SingleEcogestureView' import SingleEcogestureView from './SingleEcogestureView'
const mockedNavigate = jest.fn()
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockedNavigate,
useParams: () =>
jest.fn().mockReturnValue({ ecogestureID: 'ECOGESTURE0001' }),
useLocation: jest.fn().mockReturnValue({
state: { selectionCompleted: true },
}),
}))
jest.mock( jest.mock(
'components/Ecogesture/EfficiencyRating/EfficiencyRating', 'components/Ecogesture/EfficiencyRating/EfficiencyRating',
() => 'mock-EfficiencyRating' () => 'mock-EfficiencyRating'
...@@ -91,11 +79,9 @@ describe('SingleEcogesture component', () => { ...@@ -91,11 +79,9 @@ describe('SingleEcogesture component', () => {
) )
await waitForComponentToPaint(wrapper) await waitForComponentToPaint(wrapper)
wrapper.find('.toggle-text').first().simulate('click') wrapper.find('.showMore').first().simulate('click')
await waitForComponentToPaint(wrapper) await waitForComponentToPaint(wrapper)
expect(wrapper.find('.toggle-text').text()).toBe( expect(wrapper.find('.showMore').text()).toBe('ecogesture_modal.show_less')
'ecogesture_modal.show_less'
)
}) })
}) })
import { Collapse } from '@material-ui/core'
import IconButton from '@material-ui/core/IconButton' import IconButton from '@material-ui/core/IconButton'
import doingDisabledIcon from 'assets/icons/ico/doing-disabled.svg' import doingDisabledIcon from 'assets/icons/ico/doing-disabled.svg'
import doingEnabledIcon from 'assets/icons/ico/doing-enabled.svg' import doingEnabledIcon from 'assets/icons/ico/doing-enabled.svg'
import objectiveDisabledIcon from 'assets/icons/ico/objective-disabled.svg' import objectiveDisabledIcon from 'assets/icons/ico/objective-disabled.svg'
import objectiveEnabledIcon from 'assets/icons/ico/objective-enabled.svg' import objectiveEnabledIcon from 'assets/icons/ico/objective-enabled.svg'
import defaultIcon from 'assets/icons/visu/ecogesture/default.svg' import defaultIcon from 'assets/icons/visu/ecogesture/default.svg'
import classNames from 'classnames'
import ErrorPage from 'components/CommonKit/ErrorPage/ErrorPage' import ErrorPage from 'components/CommonKit/ErrorPage/ErrorPage'
import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import StyledIcon from 'components/CommonKit/Icon/StyledIcon'
import Content from 'components/Content/Content' import Content from 'components/Content/Content'
...@@ -17,23 +17,16 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n' ...@@ -17,23 +17,16 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import Icon from 'cozy-ui/transpiled/react/Icon' import Icon from 'cozy-ui/transpiled/react/Icon'
import { Ecogesture } from 'models' import { Ecogesture } from 'models'
import React, { useCallback, useEffect, useMemo, useState } from 'react' import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { Location, useLocation, useParams } from 'react-router-dom' import { useParams } from 'react-router-dom'
import EcogestureService from 'services/ecogesture.service' import EcogestureService from 'services/ecogesture.service'
import { useAppSelector } from 'store/hooks' import { useAppSelector } from 'store/hooks'
import { importIconById } from 'utils/utils' import { importIconById } from 'utils/utils'
import EfficiencyRating from './EfficiencyRating/EfficiencyRating' import EfficiencyRating from './EfficiencyRating/EfficiencyRating'
import './singleEcogestureView.scss' import './singleEcogestureView.scss'
interface EcogestureLocation extends Location {
state: {
selectionCompleted: boolean
}
}
const SingleEcogestureView = () => { const SingleEcogestureView = () => {
const { t } = useI18n() const { t } = useI18n()
const client = useClient() const client = useClient()
const location: EcogestureLocation = useLocation()
const [ecogesture, setEcogesture] = useState<Ecogesture>() const [ecogesture, setEcogesture] = useState<Ecogesture>()
const [ecogestureIcon, setEcogestureIcon] = useState<string>('') const [ecogestureIcon, setEcogestureIcon] = useState<string>('')
const [isMoreDetail, setIsMoreDetail] = useState<boolean>(false) const [isMoreDetail, setIsMoreDetail] = useState<boolean>(false)
...@@ -41,7 +34,6 @@ const SingleEcogestureView = () => { ...@@ -41,7 +34,6 @@ const SingleEcogestureView = () => {
const [isObjective, setIsObjective] = useState<boolean>(false) const [isObjective, setIsObjective] = useState<boolean>(false)
const [isLoading, setIsLoading] = useState<boolean>(true) const [isLoading, setIsLoading] = useState<boolean>(true)
const { ecogestureID } = useParams<{ ecogestureID: string }>() const { ecogestureID } = useParams<{ ecogestureID: string }>()
const selectionCompleted = location?.state?.selectionCompleted
const ecogestureService = useMemo( const ecogestureService = useMemo(
() => new EcogestureService(client), () => new EcogestureService(client),
...@@ -50,34 +42,33 @@ const SingleEcogestureView = () => { ...@@ -50,34 +42,33 @@ const SingleEcogestureView = () => {
const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge) const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge)
const [headerHeight, setHeaderHeight] = useState<number>(0) const [headerHeight, setHeaderHeight] = useState<number>(0)
const [, setValidExploration] = useExploration() const [, setValidExploration] = useExploration()
const toggleMoreDetail = () => {
setIsMoreDetail(prev => !prev)
}
const toggleObjective = useCallback(async () => {
if (ecogesture) {
const toUpdate: Ecogesture = { ...ecogesture, objective: !isObjective }
const updatedEcogesture = await ecogestureService.updateEcogesture(
toUpdate
)
if (updatedEcogesture) {
setIsObjective(prev => !prev)
setEcogesture(updatedEcogesture)
}
}
}, [ecogesture, ecogestureService, isObjective])
const toggleDoing = useCallback(async () => { const updateEcogesture = useCallback(
if (ecogesture) { async (objective, doing) => {
const toUpdate: Ecogesture = { ...ecogesture, doing: !isDoing } if (ecogesture) {
const updatedEcogesture = await ecogestureService.updateEcogesture( const updates: Ecogesture = {
toUpdate ...ecogesture,
) objective: objective,
if (updatedEcogesture) { doing: doing,
setIsDoing(prev => !prev) }
setEcogesture(updatedEcogesture) const result = await ecogestureService.updateEcogesture(updates)
if (result) {
setIsObjective(result.objective)
setIsDoing(result.doing)
setEcogesture(result)
}
} }
} },
}, [ecogesture, ecogestureService, isDoing]) [ecogesture, ecogestureService]
)
const toggleObjective = useCallback(() => {
updateEcogesture(!isObjective, false)
}, [isObjective, updateEcogesture])
const toggleDoing = useCallback(() => {
updateEcogesture(false, !isDoing)
}, [isDoing, updateEcogesture])
useEffect(() => { useEffect(() => {
let subscribed = true let subscribed = true
...@@ -160,62 +151,58 @@ const SingleEcogestureView = () => { ...@@ -160,62 +151,58 @@ const SingleEcogestureView = () => {
{ecogesture.longName} {ecogesture.longName}
</div> </div>
<div <div
className="toggle-text text-15-normal" className="showMore text-15-normal"
onClick={toggleMoreDetail} onClick={() => setIsMoreDetail(prev => !prev)}
role="button" role="button"
> >
{isMoreDetail {t(`ecogesture_modal.show_${isMoreDetail ? 'less' : 'more'}`)}
? t('ecogesture_modal.show_less')
: t('ecogesture_modal.show_more')}
</div> </div>
<div
className={classNames('description text-16-normal-150', { <Collapse in={isMoreDetail}>
['block']: isMoreDetail === true, <div className="longDescription text-16-normal-150">
})} {ecogesture.longDescription}
</div>
</Collapse>
</div>
<div className="buttons-selection">
<IconButton
aria-label={t('ecogesture.objective')}
onClick={toggleObjective}
classes={{
root: `btn-secondary-negative objective-btn ${
isObjective && 'active'
}`,
label: 'text-15-normal',
}}
> >
{ecogesture.longDescription} <Icon
</div> className="status-icon"
icon={
isObjective ? objectiveEnabledIcon : objectiveDisabledIcon
}
size={40}
/>
<span>{t('ecogesture.objective')}</span>
</IconButton>
<IconButton
aria-label={t('ecogesture.doing')}
onClick={toggleDoing}
classes={{
root: `btn-secondary-negative doing-btn ${
isDoing && 'active'
}`,
label: 'text-15-normal',
}}
>
<Icon
className="status-icon"
icon={isDoing ? doingEnabledIcon : doingDisabledIcon}
size={40}
/>
<span>{t('ecogesture.doing')}</span>
</IconButton>
</div> </div>
{selectionCompleted && (
<div className="buttons-selection">
<IconButton
aria-label={t('ecogesture.objective')}
onClick={toggleObjective}
classes={{
root: `btn-secondary-negative objective-btn ${
isObjective && 'active'
}`,
label: 'text-15-normal',
}}
>
<Icon
className="status-icon"
icon={
isObjective ? objectiveEnabledIcon : objectiveDisabledIcon
}
size={40}
/>
<span>{t('ecogesture.objective')}</span>
</IconButton>
<IconButton
aria-label={t('ecogesture.doing')}
onClick={toggleDoing}
classes={{
root: `btn-secondary-negative doing-btn ${
isDoing && 'active'
}`,
label: 'text-15-normal',
}}
>
<Icon
className="status-icon"
icon={isDoing ? doingEnabledIcon : doingDisabledIcon}
size={40}
/>
<span>{t('ecogesture.doing')}</span>
</IconButton>
</div>
)}
</div> </div>
)} )}
</Content> </Content>
......
...@@ -96,17 +96,68 @@ exports[`SingleEcogesture component should be rendered correctly 1`] = ` ...@@ -96,17 +96,68 @@ exports[`SingleEcogesture component should be rendered correctly 1`] = `
Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours. Je baisse le chauffage en mode hors gel lorsque je m'absente plus de 2 jours.
</div> </div>
<div <div
className="toggle-text text-15-normal" className="showMore text-15-normal"
onClick={[Function]} onClick={[Function]}
role="button" role="button"
> >
ecogesture_modal.show_more ecogesture_modal.show_more
</div> </div>
<div <WithStyles(ForwardRef(Collapse))
className="description text-16-normal-150" in={false}
> >
On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour… <ForwardRef(Collapse)
</div> classes={
Object {
"entered": "MuiCollapse-entered",
"hidden": "MuiCollapse-hidden",
"root": "MuiCollapse-root",
"wrapper": "MuiCollapse-wrapper",
"wrapperInner": "MuiCollapse-wrapperInner",
}
}
in={false}
>
<Transition
addEndListener={[Function]}
appear={false}
enter={true}
exit={true}
in={false}
mountOnEnter={false}
onEnter={[Function]}
onEntered={[Function]}
onEntering={[Function]}
onExit={[Function]}
onExited={[Function]}
onExiting={[Function]}
timeout={300}
unmountOnExit={false}
>
<div
className="MuiCollapse-root MuiCollapse-hidden"
style={
Object {
"minHeight": "0px",
}
}
>
<div
className="MuiCollapse-wrapper"
>
<div
className="MuiCollapse-wrapperInner"
>
<div
className="longDescription text-16-normal-150"
>
On se demande parfois si cela vaut le coup de "couper le chauffage" quand on s’absente… dès qu’il s’agit d’un week-end la réponse est « oui sûrement » ! Attention cependant au retour à ne pas faire de la surchauffe ! L’idéal est bien évidemment de régler sa programmation pour que le chauffage se relance quelques heures avant votre retour…
</div>
</div>
</div>
</div>
</Transition>
</ForwardRef(Collapse)>
</WithStyles(ForwardRef(Collapse))>
</div> </div>
<div <div
className="buttons-selection" className="buttons-selection"
......