diff --git a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx index ef633974e471f917d59c3c818d6e5e833928ed00..299d2a4da67c4bdb964de2cc7608efca9c4dc1fe 100644 --- a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis.spec.tsx @@ -9,6 +9,8 @@ import { mockDataLoadEnedisAnalysis, mockEnedisMonthlyAnalysisArray, } from '../../../tests/__mocks__/enedisMonthlyAnalysisData.mock' +import { PerformanceIndicator } from 'models' +import { allLastFluidPrices } from '../../../tests/__mocks__/fluidPrice.mock' jest.mock('cozy-ui/transpiled/react/I18n', () => { return { @@ -47,6 +49,20 @@ jest.mock('services/enedisMonthlyAnalysisData.service', () => { } }) }) +const mockPerfIndicator: PerformanceIndicator = { + value: 10, + compareValue: null, + percentageVariation: null, + price: null, +} +const mockGetPrices = jest.fn() +jest.mock('services/fluidsPrices.service', () => { + return jest.fn(() => { + return { + getPrices: mockGetPrices, + } + }) +}) describe('ElecHalfHourMonthlyAnalysis component', () => { beforeEach(() => { @@ -57,11 +73,13 @@ describe('ElecHalfHourMonthlyAnalysis component', () => { it('should be rendered correctly when isHalfHourActivated is false', async () => { mockCheckDoctypeEntries.mockResolvedValueOnce(false) + mockGetPrices.mockResolvedValue(allLastFluidPrices[0]) const wrapper = mount( <ElecHalfHourMonthlyAnalysis analysisDate={DateTime.fromISO('2021-07-01T00:00:00.000Z', { zone: 'utc', })} + perfIndicator={mockPerfIndicator} /> ) await waitForComponentToPaint(wrapper) @@ -76,11 +94,14 @@ describe('ElecHalfHourMonthlyAnalysis component', () => { mockAggregateValuesToDataLoad.mockResolvedValueOnce( mockDataLoadEnedisAnalysis ) + mockGetPrices.mockResolvedValue(allLastFluidPrices[0]) + const wrapper = mount( <ElecHalfHourMonthlyAnalysis analysisDate={DateTime.fromISO('2021-07-01T00:00:00.000Z', { zone: 'utc', })} + perfIndicator={mockPerfIndicator} /> ) await waitForComponentToPaint(wrapper) @@ -95,11 +116,13 @@ describe('ElecHalfHourMonthlyAnalysis component', () => { mockAggregateValuesToDataLoad.mockResolvedValueOnce( mockDataLoadEnedisAnalysis ) + mockGetPrices.mockResolvedValue(allLastFluidPrices[0]) const wrapper = mount( <ElecHalfHourMonthlyAnalysis analysisDate={DateTime.fromISO('2021-07-01T00:00:00.000Z', { zone: 'utc', })} + perfIndicator={mockPerfIndicator} /> ) await waitForComponentToPaint(wrapper) @@ -119,11 +142,14 @@ describe('ElecHalfHourMonthlyAnalysis component', () => { mockAggregateValuesToDataLoad.mockResolvedValueOnce( mockDataLoadEnedisAnalysis ) + mockGetPrices.mockResolvedValue(allLastFluidPrices[0]) + const wrapper = mount( <ElecHalfHourMonthlyAnalysis analysisDate={DateTime.fromISO('2021-07-01T00:00:00.000Z', { zone: 'utc', })} + perfIndicator={mockPerfIndicator} /> ) await waitForComponentToPaint(wrapper) diff --git a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx b/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx index 68cf39659a63832172bbdf017190bc30ecbb1db2..e93d9fc31cbed610adf8676d93330ae83340ccc7 100644 --- a/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx +++ b/src/components/Analysis/ElecHalfHourMonthlyAnalysis.tsx @@ -25,16 +25,19 @@ import { TimeStep } from 'enum/timeStep.enum' import { Button } from '@material-ui/core' import StyledIcon from 'components/CommonKit/Icon/StyledIcon' import useExploration from 'components/Hooks/useExploration' -import { FluidConfig } from 'models' +import { FluidConfig, FluidPrice, PerformanceIndicator } from 'models' import ConfigService from 'services/fluidConfig.service' import ElecInfoModal from './ElecInfoModal' +import FluidPricesService from 'services/fluidsPrices.service' interface ElecHalfHourMonthlyAnalysisProps { analysisDate: DateTime + perfIndicator: PerformanceIndicator } const ElecHalfHourMonthlyAnalysis: React.FC<ElecHalfHourMonthlyAnalysisProps> = ({ analysisDate, + perfIndicator, }: ElecHalfHourMonthlyAnalysisProps) => { const { t } = useI18n() const client = useClient() @@ -49,6 +52,8 @@ const ElecHalfHourMonthlyAnalysis: React.FC<ElecHalfHourMonthlyAnalysisProps> = const [enedisAnalysisValues, setenedisAnalysisValues] = useState< EnedisMonthlyAnalysisData >() + const [facturePercentage, setFacturePercentage] = useState<number>() + const [elecPrice, setElecPrice] = useState<FluidPrice>() const [openInfoModal, setOpenInfoModal] = useState<boolean>(false) const handleChangeWeek = useCallback(() => { @@ -79,6 +84,11 @@ const ElecHalfHourMonthlyAnalysis: React.FC<ElecHalfHourMonthlyAnalysisProps> = const aggregatedData = emas.aggregateValuesToDataLoad(data[0]) setenedisAnalysisValues(data[0]) setMonthDataloads(aggregatedData) + if (data[0].minimumLoad && perfIndicator.value && subscribed) { + const percentage = + (data[0].minimumLoad / perfIndicator.value) * 100 + setFacturePercentage(percentage) + } } } else { setisHalfHourActivated(false) @@ -86,9 +96,26 @@ const ElecHalfHourMonthlyAnalysis: React.FC<ElecHalfHourMonthlyAnalysisProps> = setisLoading(false) } } - getEnedisAnalysisData() + return () => { + subscribed = false + } + }, [analysisDate, client, perfIndicator]) + + useEffect(() => { + let subscribed = true + const fluidsPricesService = new FluidPricesService(client) + async function getAllLastPrices() { + const price: FluidPrice = await fluidsPricesService.getPrices( + FluidType.ELECTRICITY, + analysisDate.minus({ month: 1 }) + ) + if (subscribed && price) { + setElecPrice(price) + } + } + getAllLastPrices() return () => { subscribed = false } @@ -147,43 +174,62 @@ const ElecHalfHourMonthlyAnalysis: React.FC<ElecHalfHourMonthlyAnalysisProps> = )} {enedisAnalysisValues && ( <div className="min-max"> - <div className="container"> - <Icon icon={MinIcon} size={40} className="minIcon" /> - <div className="text"> - <div className="min text-18-normal"> - {t('special_elec.min')} - </div> - <div className="value text-18-bold"> - {enedisAnalysisValues.minLoad !== 0 && - enedisAnalysisValues.minLoad !== null ? ( - <> - {enedisAnalysisValues.minLoad} <span> kWh</span> - </> - ) : ( - <span>----</span> - )} - </div> - </div> - </div> <div className="container"> <Icon icon={MaxPowerIcon} size={40} className="minIcon" /> <div className="text"> <div className="min text-18-normal"> {t('special_elec.maxPower')} </div> - <div className="value text-18-bold"> - {enedisAnalysisValues.maxPower !== 0 && - enedisAnalysisValues.maxPower !== null ? ( - <> - {enedisAnalysisValues.maxPower.toFixed(2)} - <span> kVA</span> - </> - ) : ( - <span>----</span> - )} - </div> + </div> + <div className="value kvAval"> + {enedisAnalysisValues.maxPower !== 0 && + enedisAnalysisValues.maxPower !== null ? ( + <div className="text-18-bold"> + {enedisAnalysisValues.maxPower.toFixed(1)} + <span className="text-18-normal"> kVA</span> + </div> + ) : ( + <span>----</span> + )} + </div> + </div> + <div className="container consomin"> + <Icon icon={MinIcon} size={40} className="minIcon" /> + <div className="text text-18-normal"> + <div>{t('special_elec.min')}</div> + <div>{t('special_elec.percentage')}</div> + <div>{t('special_elec.price')}</div> + </div> + <div className="value"> + {enedisAnalysisValues.minimumLoad !== 0 && + enedisAnalysisValues.minimumLoad !== null ? ( + <> + <div className="text-18-bold"> + {enedisAnalysisValues.minimumLoad.toFixed(1)} + <span className="text-18-normal"> kWh</span> + </div> + <div className="text-18-bold"> + {facturePercentage + ? facturePercentage.toFixed(0) + : '---'} + <span className="text-18-normal"> %</span> + </div> + <div className="text-18-bold"> + {elecPrice + ? ( + enedisAnalysisValues.minimumLoad * + elecPrice.price + ).toFixed(1) + : '---'} + <span className="text-18-normal"> €</span> + </div> + </> + ) : ( + <span>----</span> + )} </div> </div> + <div onClick={toggleOpenModal} className="showmodal"> {t('special_elec.showModal')} </div> diff --git a/src/components/Analysis/MonthlyAnalysis.tsx b/src/components/Analysis/MonthlyAnalysis.tsx index 78cbd3c939cd2682d0999518ec15ee754e98a761..f1fbaed7732de62f55306315d871c94e0f140814 100644 --- a/src/components/Analysis/MonthlyAnalysis.tsx +++ b/src/components/Analysis/MonthlyAnalysis.tsx @@ -199,6 +199,9 @@ const MonthlyAnalysis: React.FC<MonthlyAnalysisProps> = ({ <div className="card"> <ElecHalfHourMonthlyAnalysis analysisDate={analysisDate} + perfIndicator={ + performanceIndicators[FluidType.ELECTRICITY] + } /> </div> </div> diff --git a/src/components/Analysis/__snapshots__/ElecHalfHourMonthlyAnalysis.spec.tsx.snap b/src/components/Analysis/__snapshots__/ElecHalfHourMonthlyAnalysis.spec.tsx.snap index 5300385498177f89b076b8797d9403dd944fde18..3e66e5b70ea8e852ea46c8d5b18f7bdf2b35e28b 100644 --- a/src/components/Analysis/__snapshots__/ElecHalfHourMonthlyAnalysis.spec.tsx.snap +++ b/src/components/Analysis/__snapshots__/ElecHalfHourMonthlyAnalysis.spec.tsx.snap @@ -3,6 +3,14 @@ exports[`ElecHalfHourMonthlyAnalysis component should be rendered correctly when isHalfHourActivated is false 1`] = ` <ElecHalfHourMonthlyAnalysis analysisDate={"2021-07-01T00:00:00.000Z"} + perfIndicator={ + Object { + "compareValue": null, + "percentageVariation": null, + "price": null, + "value": 10, + } + } > <div className="special-elec-container" @@ -230,6 +238,14 @@ exports[`ElecHalfHourMonthlyAnalysis component should be rendered correctly when exports[`ElecHalfHourMonthlyAnalysis component should be rendered correctly when isHalfHourActivated is true 1`] = ` <ElecHalfHourMonthlyAnalysis analysisDate={"2021-07-01T00:00:00.000Z"} + perfIndicator={ + Object { + "compareValue": null, + "percentageVariation": null, + "price": null, + "value": 10, + } + } > <div className="special-elec-container" @@ -580,21 +596,26 @@ exports[`ElecHalfHourMonthlyAnalysis component should be rendered correctly when <div className="min text-18-normal" > - special_elec.min + special_elec.maxPower </div> + </div> + <div + className="value kvAval" + > <div - className="value text-18-bold" + className="text-18-bold" > - 3 - - <span> - kWh + 2.0 + <span + className="text-18-normal" + > + kVA </span> </div> </div> </div> <div - className="container" + className="container consomin" > <Icon className="minIcon" @@ -621,19 +642,49 @@ exports[`ElecHalfHourMonthlyAnalysis component should be rendered correctly when </Component> </Icon> <div - className="text" + className="text text-18-normal" + > + <div> + special_elec.min + </div> + <div> + special_elec.percentage + </div> + <div> + special_elec.price + </div> + </div> + <div + className="value" > <div - className="min text-18-normal" + className="text-18-bold" > - special_elec.maxPower + 3.0 + <span + className="text-18-normal" + > + kWh + </span> </div> <div - className="value text-18-bold" + className="text-18-bold" > - 2.00 - <span> - kVA + --- + <span + className="text-18-normal" + > + % + </span> + </div> + <div + className="text-18-bold" + > + 0.4 + <span + className="text-18-normal" + > + € </span> </div> </div> diff --git a/src/components/Analysis/elecHalfHourMonthlyAnalysis.scss b/src/components/Analysis/elecHalfHourMonthlyAnalysis.scss index 4f79df64482152cad1eafab89160fe74e4cd6908..0bf6cb51094b1d014c0657507fcfe2d01c81678b 100644 --- a/src/components/Analysis/elecHalfHourMonthlyAnalysis.scss +++ b/src/components/Analysis/elecHalfHourMonthlyAnalysis.scss @@ -29,7 +29,7 @@ } } .minIcon { - margin-right: 0.7rem; + margin: auto 0.8rem auto 0; } .activation-text { margin: 1rem 0 0.7rem 0; @@ -44,6 +44,33 @@ } .container { margin-bottom: 1rem; + padding: 1rem; + border: 1px solid $grey-bright; + border-radius: 10px; + display: flex; + + .min { + max-width: 150px; + } + .text { + display: flex; + flex-direction: column; + justify-content: space-between; + } + .value { + margin-left: auto; + display: flex; + flex-direction: column; + align-items: self-end; + min-width: 80px; + justify-content: space-between; + } + .kvAval { + margin: auto 0 auto auto; + } + } + .consomin { + min-height: 100px; } .loader-container { text-align: center; diff --git a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx index 3fbdf2f78c6f09e538eedfd3d39fe3a842428e26..565557ecd29baa51c56b71e848fb15fb21e28f05 100644 --- a/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx +++ b/src/components/ConsumptionVisualizer/EstimatedConsumptionModal.tsx @@ -22,12 +22,12 @@ const EstimatedConsumptionModal: React.FC<EstimatedConsumptionModalProps> = ({ }: EstimatedConsumptionModalProps) => { const { t } = useI18n() const client = useClient() - const fluidsPricesService = new FluidPricesService(client) const [prices, setPrices] = useState<FluidPrice[]>([]) useEffect(() => { let subscribed = true + const fluidsPricesService = new FluidPricesService(client) async function getAllLastPrices() { const prices = await fluidsPricesService.getAllLastPrices() if (subscribed && prices) { @@ -38,7 +38,7 @@ const EstimatedConsumptionModal: React.FC<EstimatedConsumptionModalProps> = ({ return () => { subscribed = false } - }, []) + }, [client]) return ( <Dialog diff --git a/src/locales/fr.json b/src/locales/fr.json index 42d6dad1ca5a283253dc088ee4630d9da57b8618..92f6056a42c921bde1030fcd9cd8dca427737cdd 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -113,7 +113,9 @@ "weektype": "un jour de ", "week": "semaine", "weekend": "week-end", - "min": "Consommation minimum", + "min": "Conso minimum", + "percentage": "Part dans la facture", + "price": "Soit", "maxPower": "Puissance maximum atteinte", "showModal": "Plus d'infos" }, @@ -124,8 +126,8 @@ }, "title1": "Qu’est-ce que la consommation minimum ?", "title2": "Qu’est-ce que la puissance maximum ?", - "text1": "La consommation minimum correspond à votre plus petite consommation du mois, sur un créneau d'une demi-heure.", - "text2": "Elle peut comprendre la consommation de vos appareils électriques en veille (box, télé, ...) ou encore celle de vos frigo et congélateur.", + "text1": "Elle correspond à votre plus petite consommation du mois sur un créneau d'une demi-heure.", + "text2": "Nous extrapolons cette consommation sur 1 mois afin vous donner un aperçu de la consommation de vos consommations électriques en veille (box, télé, chargeurs, ...) ou encore de celle, incompressible, de vos appareils de froid (frigo, congélateur).", "text3": "C’est la puissance maximum délivrée par tous les appareils fonctionnant au même moment dans votre logement.", "text4": "Vous avez choisi une puissance maximum dans votre offre d’éléctricité (3, 6 ou 9 kVA...) que vous ne devez pas dépasser pour ne pas faire sauter votre compteur. ", "text5": "Cette puissance varie d'un mois à l'autre, regardez cette valeur sur l'ensemble de l'année pour vérifier si votre puissance souscrite correspond bien à votre usage." diff --git a/src/migrations/migration.data.ts b/src/migrations/migration.data.ts index b2ce441822b0f252c58e7b8967c8556c6c532d05..46e66a510c664f6128c7bb647945cc1d5226bad4 100644 --- a/src/migrations/migration.data.ts +++ b/src/migrations/migration.data.ts @@ -13,8 +13,15 @@ import { ENEDIS_YEAR_DOCTYPE, GRDF_MONTH_DOCTYPE, GRDF_YEAR_DOCTYPE, + ENEDIS_MONTHLY_ANALYSIS_DATA_DOCTYPE, } from 'doctypes' -import { DataloadEntity, Profile, ProfileType, UserChallenge } from 'models' +import { + DataloadEntity, + FluidPrice, + Profile, + ProfileType, + UserChallenge, +} from 'models' import { Client } from 'cozy-client' import { DateTime } from 'luxon' import { UserQuizState } from 'enum/userQuiz.enum' @@ -495,15 +502,38 @@ export const migrations: Migration[] = [ docTypes: FLUIDPRICES_DOCTYPE, run: async (_client: Client, docs: any[]): Promise<any> => { - const waterPricesData = fluidsPricesData.filter(fluidPriceData => { + const waterPricesData: any[] = fluidsPricesData.filter(fluidPriceData => { return fluidPriceData.fluidType === FluidType.WATER }) - const createWaterPricesData = waterPricesData.map(waterPriceData => { - waterPriceData.createAction = true - waterPriceData.doctype = FLUIDPRICES_DOCTYPE - return waterPriceData - }) + const createWaterPricesData = waterPricesData.map( + (waterPriceData: any) => { + waterPriceData.createAction = true + waterPriceData.doctype = FLUIDPRICES_DOCTYPE + return waterPriceData + } + ) return createWaterPricesData }, }, + { + baseSchemaVersion: 18, + targetSchemaVersion: 19, + appVersion: '1.7.0', + description: 'Replace old minCons with the new calculation', + releaseNotes: null, + docTypes: ENEDIS_MONTHLY_ANALYSIS_DATA_DOCTYPE, + run: async (_client: Client, docs: any[]): Promise<any> => { + docs.map(doc => { + if (doc.minLoad) { + const numberofDaysInMonth = DateTime.fromObject({ + month: doc.month, + year: doc.year, + }).daysInMonth + doc.minimumLoad = doc.minLoad * 48 * numberofDaysInMonth + delete doc.minLoad + } + }) + return docs + }, + }, ] diff --git a/src/models/enedisMonthlyAnalysis.ts b/src/models/enedisMonthlyAnalysis.ts index 78d16f72770f9faebfb755367f82254da2d1a655..7c0547ce604b7d60bd2963b79773ed34d3906eb0 100644 --- a/src/models/enedisMonthlyAnalysis.ts +++ b/src/models/enedisMonthlyAnalysis.ts @@ -5,7 +5,7 @@ export interface EnedisMonthlyAnalysisData { weekEndDaysHalfHourAverageValues: number[] month: number year: number - minLoad: number | null + minimumLoad: number | null maxPower: number | null } export interface AggregatedEnedisMonthlyDataloads { diff --git a/src/targets/services/enedisHalfHourMonthlyAnalysis.ts b/src/targets/services/enedisHalfHourMonthlyAnalysis.ts index 3f03bbdcb025e6bbb2a23bd406f94ed7bc87f4dd..c56a6a79364388d9c435360b3a7d14ce9143132c 100644 --- a/src/targets/services/enedisHalfHourMonthlyAnalysis.ts +++ b/src/targets/services/enedisHalfHourMonthlyAnalysis.ts @@ -28,13 +28,15 @@ interface EnedisMonthlyProps { */ const getMinMonthlyLoad = ( weekEndValuesArray: number[][], - weekValuesArray: number[][] + weekValuesArray: number[][], + numberofDaysInMonth: number ): number => { const totalArray = union(...weekEndValuesArray, ...weekValuesArray) const filteredTotal = totalArray.filter(val => val !== -1 && val !== 0) - const minLoad = Math.min(...filteredTotal) - log('info', `Minimum value is ${minLoad} `) - return minLoad + const talonCons = Math.min(...filteredTotal) + const minCons = talonCons * 48 * numberofDaysInMonth + log('info', `Minimum value is ${minCons} `) + return minCons } /** @@ -122,7 +124,7 @@ const getEnedisMonthAnalysisData = async ( const monthlyAveragesLoads: EnedisMonthlyAnalysisData = { weekDaysHalfHourAverageValues: [], weekEndDaysHalfHourAverageValues: [], - minLoad: null, + minimumLoad: null, maxPower: null, month: month, year: year, @@ -149,9 +151,14 @@ const getEnedisMonthAnalysisData = async ( populateArrayWithTotalData(weekValuesArray, halfHourDayData, false) } } - monthlyAveragesLoads.minLoad = getMinMonthlyLoad( + const numberofDaysInMonth = DateTime.fromObject({ + month: month, + year: year, + }).daysInMonth + monthlyAveragesLoads.minimumLoad = getMinMonthlyLoad( weekValuesArray, - weekEndValuesArray + weekEndValuesArray, + numberofDaysInMonth ) const arrAvg = (arr: number[]) => arr.reduce((a, b) => a + b, 0) / arr.length diff --git a/tests/__mocks__/enedisMonthlyAnalysisData.mock.ts b/tests/__mocks__/enedisMonthlyAnalysisData.mock.ts index 179c85a83bb9087a3749b9efc44586b7f9fb61f8..e58cf19889ade7ac6ebc28ed9ad94a1a3e8e5564 100644 --- a/tests/__mocks__/enedisMonthlyAnalysisData.mock.ts +++ b/tests/__mocks__/enedisMonthlyAnalysisData.mock.ts @@ -10,7 +10,7 @@ export const mockEnedisMonthlyAnalysis: EnedisMonthlyAnalysisData = { weekEndDaysHalfHourAverageValues: [0.25, 0.24, 0.23, 0.22, 0.21, 0.2], month: 11, year: 2021, - minLoad: 3, + minimumLoad: 3, maxPower: 2, } @@ -20,7 +20,7 @@ export const mockEnedisMonthlyAnalysisArray: EnedisMonthlyAnalysisData[] = [ weekEndDaysHalfHourAverageValues: [0.25, 0.24, 0.23], month: 11, year: 2021, - minLoad: 3, + minimumLoad: 3, maxPower: 2, }, { @@ -28,7 +28,7 @@ export const mockEnedisMonthlyAnalysisArray: EnedisMonthlyAnalysisData[] = [ weekEndDaysHalfHourAverageValues: [0.25, 0.24, 0.23, 0.22, 0.21, 0.2], month: 10, year: 2021, - minLoad: 3, + minimumLoad: 3, maxPower: 2, }, { @@ -36,7 +36,7 @@ export const mockEnedisMonthlyAnalysisArray: EnedisMonthlyAnalysisData[] = [ weekEndDaysHalfHourAverageValues: [0.25, 0.24, 0.23, 0.22, 0.21, 0.2], month: 8, year: 2021, - minLoad: 3, + minimumLoad: 3, maxPower: 2, }, { @@ -44,7 +44,7 @@ export const mockEnedisMonthlyAnalysisArray: EnedisMonthlyAnalysisData[] = [ weekEndDaysHalfHourAverageValues: [0.25, 0.24, 0.23, 0.22, 0.21, 0.2], month: 7, year: 2021, - minLoad: 3, + minimumLoad: 3, maxPower: 2, }, ]