From d2ec2e877555a7d696e89e6e780a88961432b9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20PAILHAREY?= <rpailharey@grandlyon.com> Date: Mon, 28 Aug 2023 09:32:14 +0000 Subject: [PATCH] feat(analysis): incomplete data warning --- src/assets/icons/ico/warning-dark.svg | 3 + .../IncompleteDataWarning.spec.tsx | 21 + .../IncompleteDataWarning.tsx | 38 ++ .../incompleteDataWarning.scss | 30 ++ .../Analysis/MonthlyAnalysis.spec.tsx | 1 + src/components/Analysis/MonthlyAnalysis.tsx | 18 + .../MonthlyAnalysis.spec.tsx.snap | 61 +++ src/locales/fr.json | 5 + src/services/consumption.service.spec.ts | 30 ++ src/services/consumption.service.ts | 32 ++ src/utils/utils.spec.ts | 18 + src/utils/utils.ts | 29 ++ tests/__mocks__/fetchDayData.mock.ts | 375 ++++++++++++++++++ 13 files changed, 661 insertions(+) create mode 100644 src/assets/icons/ico/warning-dark.svg create mode 100644 src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.spec.tsx create mode 100644 src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.tsx create mode 100644 src/components/Analysis/IncompleteDataWarning/incompleteDataWarning.scss create mode 100644 tests/__mocks__/fetchDayData.mock.ts diff --git a/src/assets/icons/ico/warning-dark.svg b/src/assets/icons/ico/warning-dark.svg new file mode 100644 index 000000000..95597cf93 --- /dev/null +++ b/src/assets/icons/ico/warning-dark.svg @@ -0,0 +1,3 @@ +<svg width="30" height="27" viewBox="0 0 30 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M16.5142 0.874208C15.8412 -0.2914 14.1588 -0.291404 13.4858 0.874204L0.236852 23.8221C-0.436112 24.9877 0.405088 26.4447 1.75102 26.4447H28.249C29.5949 26.4447 30.4361 24.9877 29.7632 23.8221L16.5142 0.874208ZM13.8973 15.3611V9.61627H16.058V15.3611C16.058 15.834 16.0307 16.3043 15.976 16.772C15.9214 17.2346 15.8494 17.7075 15.76 18.1906H14.1953C14.1059 17.7075 14.0339 17.2346 13.9793 16.772C13.9246 16.3043 13.8973 15.834 13.8973 15.3611ZM16.2145 20.4573C16.279 20.6166 16.3113 20.7888 16.3113 20.9739C16.3113 21.1589 16.279 21.3337 16.2145 21.4981C16.1449 21.6575 16.053 21.7962 15.9388 21.9145C15.8196 22.0327 15.6805 22.1252 15.5215 22.192C15.3626 22.2588 15.1888 22.2922 15 22.2922C14.8162 22.2922 14.6449 22.2588 14.4859 22.192C14.327 22.1252 14.1879 22.0327 14.0687 21.9145C13.9495 21.7962 13.8576 21.6575 13.793 21.4981C13.7235 21.3337 13.6887 21.1589 13.6887 20.9739C13.6887 20.7888 13.7235 20.6166 13.793 20.4573C13.8576 20.298 13.9495 20.1592 14.0687 20.041C14.1879 19.9228 14.327 19.8302 14.4859 19.7634C14.6449 19.6915 14.8162 19.6555 15 19.6555C15.1888 19.6555 15.3626 19.6915 15.5215 19.7634C15.6805 19.8302 15.8196 19.9228 15.9388 20.041C16.053 20.1592 16.1449 20.298 16.2145 20.4573Z" fill="#1B1C22"/> +</svg> diff --git a/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.spec.tsx b/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.spec.tsx new file mode 100644 index 000000000..c833c8c14 --- /dev/null +++ b/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.spec.tsx @@ -0,0 +1,21 @@ +import { FluidType } from 'enums' +import { mount } from 'enzyme' +import React from 'react' +import IncompleteDataWarning from './IncompleteDataWarning' + +jest.mock('cozy-ui/transpiled/react/I18n', () => ({ + useI18n: jest.fn(() => ({ + t: (str: string) => str, + })), +})) + +describe('IncompleteDataWarning', () => { + it('renders component correctly', () => { + const incompleteFluidTypes = [FluidType.ELECTRICITY, FluidType.GAS] + const wrapper = mount( + <IncompleteDataWarning incompleteDataFluids={incompleteFluidTypes} /> + ) + expect(wrapper.find('h1').text()).toBe('analysis.warning_title') + expect(wrapper.find('p').text()).toBe('analysis.warning_text') + }) +}) diff --git a/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.tsx b/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.tsx new file mode 100644 index 000000000..10fb96acb --- /dev/null +++ b/src/components/Analysis/IncompleteDataWarning/IncompleteDataWarning.tsx @@ -0,0 +1,38 @@ +import warningDark from 'assets/icons/ico/warning-dark.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import { FluidType } from 'enums' +import React from 'react' +import { formatListWithAnd } from 'utils/utils' +import './incompleteDataWarning.scss' + +const IncompleteDataWarning = ({ + incompleteDataFluids, +}: { + incompleteDataFluids: FluidType[] +}) => { + const { t } = useI18n() + + const formattedFluidList = formatListWithAnd( + incompleteDataFluids.map(fluidType => + t(`FLUID.${FluidType[fluidType]}.LABEL_PREPOSITION`) + ) + ) + return ( + <div className="analysis-warning"> + <div className="warning-header"> + <StyledIcon icon={warningDark} size={30} /> + <h1>{t('analysis.warning_title')}</h1> + </div> + <div className="warning-content"> + <p> + {t('analysis.warning_text', { + fluidList: formattedFluidList, + })} + </p> + </div> + </div> + ) +} + +export default IncompleteDataWarning diff --git a/src/components/Analysis/IncompleteDataWarning/incompleteDataWarning.scss b/src/components/Analysis/IncompleteDataWarning/incompleteDataWarning.scss new file mode 100644 index 000000000..8b5c72b10 --- /dev/null +++ b/src/components/Analysis/IncompleteDataWarning/incompleteDataWarning.scss @@ -0,0 +1,30 @@ +@import 'src/styles/base/color'; + +.analysis-warning { + background: $grey-linear-gradient-background; + border: 1px solid $multi-color; + border-radius: 4px; + + .warning-header { + display: flex; + align-items: center; + padding: 0 1rem; + background-color: $multi-color; + gap: 0.5rem; + h1 { + color: black; + font-size: 1rem; + font-weight: normal; + } + } + + .warning-content { + padding: 1rem; + p { + margin: 0; + font-size: 1rem; + font-weight: bold; + color: $grey-bright; + } + } +} diff --git a/src/components/Analysis/MonthlyAnalysis.spec.tsx b/src/components/Analysis/MonthlyAnalysis.spec.tsx index b5ed125cc..243264d3a 100644 --- a/src/components/Analysis/MonthlyAnalysis.spec.tsx +++ b/src/components/Analysis/MonthlyAnalysis.spec.tsx @@ -28,6 +28,7 @@ jest.mock('services/consumption.service', () => { return jest.fn(() => { return { getFluidsWithDataForTimePeriod: jest.fn(() => [0, 1, 2]), + getFluidsWithIncompleteData: jest.fn(() => [0]), getPerformanceIndicators: jest.fn(() => mockPI), } }) diff --git a/src/components/Analysis/MonthlyAnalysis.tsx b/src/components/Analysis/MonthlyAnalysis.tsx index a8b4c3065..a5e3e2e0b 100644 --- a/src/components/Analysis/MonthlyAnalysis.tsx +++ b/src/components/Analysis/MonthlyAnalysis.tsx @@ -9,6 +9,7 @@ import PerformanceIndicatorService from 'services/performanceIndicator.service' import { useAppSelector } from 'store/hooks' import Comparison from './Comparison/Comparison' import ElecHalfHourMonthlyAnalysis from './ElecHalfHourMonthlyAnalysis/ElecHalfHourMonthlyAnalysis' +import IncompleteDataWarning from './IncompleteDataWarning/IncompleteDataWarning' import MaxConsumptionCard from './MaxConsumptionCard/MaxConsumptionCard' import ProfileComparator from './ProfileComparator/ProfileComparator' import TotalAnalysisChart from './TotalAnalysisChart/TotalAnalysisChart' @@ -37,6 +38,9 @@ const MonthlyAnalysis = ({ const [loadAnalysis, setLoadAnalysis] = useState<boolean>(true) const [fluidsWithData, setFluidsWithData] = useState<FluidType[]>([]) + const [incompleteDataFluids, setIncompleteDataFluids] = useState<FluidType[]>( + [] + ) const [performanceIndicators, setPerformanceIndicators] = useState< PerformanceIndicator[] >([]) @@ -67,6 +71,13 @@ const MonthlyAnalysis = ({ timePeriod ) + const fetchedIncompleteDataFluids = + await consumptionService.getFluidsWithIncompleteData( + [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS], + timePeriod.startDate + ) + setIncompleteDataFluids(fetchedIncompleteDataFluids) + const fetchedPerformanceIndicators = await consumptionService.getPerformanceIndicators( timePeriod, @@ -121,6 +132,13 @@ const MonthlyAnalysis = ({ {!loadAnalysis && ( <Fade in={!loadAnalysis}> <div className="analysis-root"> + {incompleteDataFluids.length !== 0 && ( + <div className="analysis-content"> + <IncompleteDataWarning + incompleteDataFluids={incompleteDataFluids} + /> + </div> + )} <div className="analysis-content"> <Comparison fluidsWithData={fluidsWithData} diff --git a/src/components/Analysis/__snapshots__/MonthlyAnalysis.spec.tsx.snap b/src/components/Analysis/__snapshots__/MonthlyAnalysis.spec.tsx.snap index 130afdd5c..70fef5256 100644 --- a/src/components/Analysis/__snapshots__/MonthlyAnalysis.spec.tsx.snap +++ b/src/components/Analysis/__snapshots__/MonthlyAnalysis.spec.tsx.snap @@ -80,6 +80,67 @@ exports[`MonthlyAnalysis component should be rendered correctly 1`] = ` } } > + <div + className="analysis-content" + > + <IncompleteDataWarning + incompleteDataFluids={ + Array [ + 0, + ] + } + > + <div + className="analysis-warning" + > + <div + className="warning-header" + > + <StyledIcon + icon="test-file-stub" + size={30} + > + <Icon + aria-hidden={true} + icon="test-file-stub" + size={30} + spin={false} + > + <Component + aria-hidden={true} + className="styles__icon___23x3R" + height={30} + style={Object {}} + width={30} + > + <svg + aria-hidden={true} + className="styles__icon___23x3R" + height={30} + style={Object {}} + width={30} + > + <use + xlinkHref="#test-file-stub" + /> + </svg> + </Component> + </Icon> + </StyledIcon> + <h1> + analysis.warning_title + </h1> + </div> + <div + className="warning-content" + > + <p> + analysis.warning_text + </p> + </div> + </div> + </IncompleteDataWarning> + </div> <div className="analysis-content" > diff --git a/src/locales/fr.json b/src/locales/fr.json index d48b63611..d576c7b44 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -32,6 +32,7 @@ "ELECTRICITY": { "NAME": "Électricité", "LABEL": "Électricité", + "LABEL_PREPOSITION": "d'électricité", "UNIT": "kWh", "ADD": "Ajouter l'électricité", "MEGAUNIT": "MWh", @@ -40,6 +41,7 @@ "WATER": { "NAME": "Eau", "LABEL": "Eau", + "LABEL_PREPOSITION": "d'eau", "ADD": "Ajouter l'eau", "UNIT": "L", "MEGAUNIT": "m³", @@ -48,6 +50,7 @@ "GAS": { "NAME": "Gaz", "LABEL": "Gaz", + "LABEL_PREPOSITION": "de gaz", "ADD": "Ajouter le gaz", "UNIT": "kWh", "MEGAUNIT": "MWh", @@ -83,6 +86,8 @@ }, "analysis": { "viewTitle": "Analyse", + "warning_title": "Analyse incomplète", + "warning_text": "Ecolyo n'a pas encore reçu toutes les données %{fluidList} pour ce mois", "comparison": "Comparatif", "analysis_date": "Conso totale", "challenge": "Défis terminés en", diff --git a/src/services/consumption.service.spec.ts b/src/services/consumption.service.spec.ts index 4ba1838b0..f402858a3 100644 --- a/src/services/consumption.service.spec.ts +++ b/src/services/consumption.service.spec.ts @@ -11,6 +11,10 @@ import { TimePeriod, } from 'models' import mockClient from 'tests/__mocks__/client' +import { + fetchDayDataComplete, + fetchDayDataIncomplete, +} from 'tests/__mocks__/fetchDayData.mock' import { fluidPrices } from 'tests/__mocks__/fluidPrice.mock' import { fluidStatusConnectedData } from 'tests/__mocks__/fluidStatusData.mock' import { loadDayData } from 'tests/__mocks__/loadDayData.mock' @@ -607,4 +611,30 @@ describe('Consumption service', () => { expect(fluidsWithData).toEqual([]) }) }) + + describe('getFluidsWithIncompleteDataForTimePeriod', () => { + const allFluids = [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS] + const month = DateTime.local(2023, 7, 1) + + it('should return 2 fluids', async () => { + mockFetchFluidData.mockResolvedValueOnce(fetchDayDataComplete) + mockFetchFluidData.mockResolvedValueOnce(fetchDayDataIncomplete) + mockFetchFluidData.mockResolvedValueOnce(fetchDayDataIncomplete) + const fluidsWithIncompleteData = + await consumptionDataManager.getFluidsWithIncompleteData( + allFluids, + month + ) + expect(fluidsWithIncompleteData).toEqual([FluidType.WATER, FluidType.GAS]) + }) + it('should return no fluids', async () => { + mockFetchFluidData.mockResolvedValue(fetchDayDataComplete) + const fluidsWithData = + await consumptionDataManager.getFluidsWithIncompleteData( + allFluids, + month + ) + expect(fluidsWithData).toEqual([]) + }) + }) }) diff --git a/src/services/consumption.service.ts b/src/services/consumption.service.ts index 594b5806b..70565175f 100644 --- a/src/services/consumption.service.ts +++ b/src/services/consumption.service.ts @@ -365,6 +365,38 @@ export default class ConsumptionDataManager { return fluidsWithData } + /** + * Retrieves an array of fluid types that have incomplete data for a given month. + * + * Data is incomplete if at least one daily data is missing for the month. + * + * @param {FluidType[]} fluidTypes + * @param {DateTime} month - The month for which to check the data completeness. + * @returns {Promise<FluidType[]>} + + */ + public async getFluidsWithIncompleteData( + fluidTypes: FluidType[], + month: DateTime + ): Promise<FluidType[]> { + const fluidsWithIncompleteData: FluidType[] = [] + const timePeriod: TimePeriod = { + startDate: month.startOf('month'), + endDate: month.endOf('month'), + } + for (const fluidType of fluidTypes) { + const data = await this._queryRunnerService.fetchFluidData( + timePeriod, + TimeStep.DAY, + fluidType + ) + if (data?.length && data?.length < month.daysInMonth) { + fluidsWithIncompleteData.push(fluidType) + } + } + return fluidsWithIncompleteData + } + public async fetchAllFirstDateData( fluidTypes: FluidType[], timeStep?: TimeStep diff --git a/src/utils/utils.spec.ts b/src/utils/utils.spec.ts index 0b6e70feb..db1e042d0 100644 --- a/src/utils/utils.spec.ts +++ b/src/utils/utils.spec.ts @@ -8,6 +8,7 @@ import { import { DateTime } from 'luxon' import { FluidStatus } from 'models' import { + formatListWithAnd, formatNumberValues, getChallengeTitleWithLineReturn, getFluidName, @@ -227,4 +228,21 @@ describe('utils test', () => { expect(getFluidName(FluidType.MULTIFLUID)).toBe('multifluid') }) }) + + describe('formatListWithAnd', () => { + it('should return empty string', () => { + expect(formatListWithAnd([])).toBe('') + }) + it('should return single element', () => { + expect(formatListWithAnd(['pomme'])).toBe('pomme') + }) + it('should return two elements joined by "et"', () => { + expect(formatListWithAnd(['pomme', 'banane'])).toBe('pomme et banane') + }) + it('should return elements joined by commas except the last one with "et"', () => { + expect(formatListWithAnd(['pomme', 'banane', 'cerise'])).toBe( + 'pomme, banane et cerise' + ) + }) + }) }) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 4b35b19c7..7dfa903ed 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -294,3 +294,32 @@ export const getTodayDate = () => keepLocalTime: true, }) .startOf('day') + +/** + * Formats an array of strings into a list with commas and an "et" (and) before the last element. + * + * @param {string[]} array - The array of strings to be formatted. + * @returns {string} The formatted list string. + * + * If the array is empty, an empty string is returned. + * If the array has only one element, that element is returned as is. + * If the array has two elements, they are joined with " et " (and). + * If the array has more than two elements, all but the last element are joined with commas, + * and " et " (and) is placed before the last element. + * + * @example + * // Returns "pomme, banane et cerise" + * formatListWithAnd(['pomme', 'banane', 'cerise']); + */ +export const formatListWithAnd = (array: string[]) => { + if (array.length === 0) { + return '' + } else if (array.length === 1) { + return array[0] + } else if (array.length === 2) { + return array.join(' et ') + } else { + const lastElement = array.pop() + return array.join(', ') + ' et ' + lastElement + } +} diff --git a/tests/__mocks__/fetchDayData.mock.ts b/tests/__mocks__/fetchDayData.mock.ts new file mode 100644 index 000000000..800fdcf75 --- /dev/null +++ b/tests/__mocks__/fetchDayData.mock.ts @@ -0,0 +1,375 @@ +import { DataloadState } from 'enums' +import { DateTime } from 'luxon' +import { Dataload } from 'models' + +export const fetchDayDataIncomplete: Dataload[] = [ + { + date: DateTime.fromISO('2023-07-02T00:00:00.000Z'), + value: 56.8, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-03T00:00:00.000Z'), + value: 37.66, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-04T00:00:00.000Z'), + value: 39.58, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-05T00:00:00.000Z'), + value: 46.81, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-06T00:00:00.000Z'), + value: 45.83, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-07T00:00:00.000Z'), + value: 22.95, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-08T00:00:00.000Z'), + value: 38.95, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-09T00:00:00.000Z'), + value: 22.23, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-10T00:00:00.000Z'), + value: 49.86, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-11T00:00:00.000Z'), + value: 62.78, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-12T00:00:00.000Z'), + value: 45.44, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-13T00:00:00.000Z'), + value: 66.06, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-14T00:00:00.000Z'), + value: 22.29, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-15T00:00:00.000Z'), + value: 43.06, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-16T00:00:00.000Z'), + value: 25.35, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-17T00:00:00.000Z'), + value: 16.24, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-18T00:00:00.000Z'), + value: 36.4, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-19T00:00:00.000Z'), + value: 54.38, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-20T00:00:00.000Z'), + value: 55.99, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-21T00:00:00.000Z'), + value: 55.96, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-22T00:00:00.000Z'), + value: 30.11, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-23T00:00:00.000Z'), + value: 17.08, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-24T00:00:00.000Z'), + value: 63.52, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-25T00:00:00.000Z'), + value: 23.64, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-26T00:00:00.000Z'), + value: 61.71, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-27T00:00:00.000Z'), + value: 25.13, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-28T00:00:00.000Z'), + value: 50.61, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-29T00:00:00.000Z'), + value: 25.86, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-30T00:00:00.000Z'), + value: 44.85, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-31T00:00:00.000Z'), + value: 34.09, + state: DataloadState.VALID, + valueDetail: null, + }, +] + +export const fetchDayDataComplete: Dataload[] = [ + { + date: DateTime.fromISO('2023-07-01T00:00:00.000Z'), + value: 35.53, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-02T00:00:00.000Z'), + value: 56.8, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-03T00:00:00.000Z'), + value: 37.66, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-04T00:00:00.000Z'), + value: 39.58, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-05T00:00:00.000Z'), + value: 46.81, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-06T00:00:00.000Z'), + value: 45.83, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-07T00:00:00.000Z'), + value: 22.95, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-08T00:00:00.000Z'), + value: 38.95, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-09T00:00:00.000Z'), + value: 22.23, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-10T00:00:00.000Z'), + value: 49.86, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-11T00:00:00.000Z'), + value: 62.78, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-12T00:00:00.000Z'), + value: 45.44, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-13T00:00:00.000Z'), + value: 66.06, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-14T00:00:00.000Z'), + value: 22.29, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-15T00:00:00.000Z'), + value: 43.06, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-16T00:00:00.000Z'), + value: 25.35, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-17T00:00:00.000Z'), + value: 16.24, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-18T00:00:00.000Z'), + value: 36.4, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-19T00:00:00.000Z'), + value: 54.38, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-20T00:00:00.000Z'), + value: 55.99, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-21T00:00:00.000Z'), + value: 55.96, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-22T00:00:00.000Z'), + value: 30.11, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-23T00:00:00.000Z'), + value: 17.08, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-24T00:00:00.000Z'), + value: 63.52, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-25T00:00:00.000Z'), + value: 23.64, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-26T00:00:00.000Z'), + value: 61.71, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-27T00:00:00.000Z'), + value: 25.13, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-28T00:00:00.000Z'), + value: 50.61, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-29T00:00:00.000Z'), + value: 25.86, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-30T00:00:00.000Z'), + value: 44.85, + state: DataloadState.VALID, + valueDetail: null, + }, + { + date: DateTime.fromISO('2023-07-31T00:00:00.000Z'), + value: 34.09, + state: DataloadState.VALID, + valueDetail: null, + }, +] -- GitLab