diff --git a/src/assets/icons/ico/warning-dark.svg b/src/assets/icons/ico/warning-dark.svg new file mode 100644 index 0000000000000000000000000000000000000000..95597cf93e2a311cbb3f92139be928311a5fb218 --- /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 0000000000000000000000000000000000000000..c833c8c1436ddc64079cd1305e5e715a3ec3553b --- /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 0000000000000000000000000000000000000000..10fb96acb4314971829e4319a738e615c61bdd53 --- /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 0000000000000000000000000000000000000000..8b5c72b10823e578a0a71f30643ffc19ae3f410d --- /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 b5ed125cceb3ef1a7625a20ecc497dae1cae9751..243264d3ab2c82835ea4e780e627ab5dd1209a32 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 a8b4c3065ae58ddb2a22d4286b53b748306440c5..a5e3e2e0bb859f1be1bb62b5bcb994e06acba78c 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 130afdd5cd7926a5ac27f414123662d4cebaee7c..70fef525666c5a60b75c5f4eff02818f890300f2 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 d48b636110ecb638ec8203369d77b15f43850523..d576c7b441b2022a1c9c8b06f225db6f24986e94 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 4ba1838b0f8695c96f9dec9a8fe08ace5412ffc3..f402858a3b6732e3308553b99c16c9241082144c 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 594b5806b54b0f828815da959ba76bea1040e0dd..70565175f3ce1a979417d41b05fd7a932314c873 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 0b6e70feb6bdd62d6a69cdb5deebfa15668aad69..db1e042d022b0931208d12cf19c20a6a4e307fe2 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 4b35b19c7f2b99a5a6123880ca2f1df864db38e3..7dfa903ed2156513f572c5f30da49107d37ae5ce 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 0000000000000000000000000000000000000000..800fdcf75058aecc9c709fc9001e0082c781ff17 --- /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, + }, +]