From 64eed93f33f29904d95128a3ca8dd4e344b346f0 Mon Sep 17 00:00:00 2001
From: gcarron <gcarron@grandlyon.com>
Date: Wed, 21 Sep 2022 15:50:56 +0200
Subject: [PATCH] feat(init): Improve splash loading time

---
 src/components/Home/releaseNotesModal.tsx     |  3 +-
 src/components/Splash/SplashRoot.tsx          |  4 +-
 .../TotalConsumption/TotalConsumption.tsx     | 11 ++-
 src/migrations/migration.data.ts              | 16 +++-
 src/migrations/migration.service.ts           | 86 +++++++++++------
 src/migrations/migration.ts                   |  7 ++
 src/migrations/migration.type.ts              |  1 +
 src/models/initialisationSteps.model.ts       |  1 -
 src/services/consumption.service.ts           |  1 -
 src/services/initialization.service.ts        | 92 -------------------
 src/services/queryRunner.service.ts           |  5 +-
 src/utils/decoreText.tsx                      | 10 ++
 12 files changed, 101 insertions(+), 136 deletions(-)

diff --git a/src/components/Home/releaseNotesModal.tsx b/src/components/Home/releaseNotesModal.tsx
index e46be103f..dfd8fe168 100644
--- a/src/components/Home/releaseNotesModal.tsx
+++ b/src/components/Home/releaseNotesModal.tsx
@@ -5,6 +5,7 @@ import './releaseNotesModal.scss'
 import Dialog from '@material-ui/core/Dialog'
 import { AppStore } from 'store'
 import { useSelector } from 'react-redux'
+import { decoreText } from 'utils/decoreText'
 
 interface ReleaseNotesModalProps {
   open: boolean
@@ -52,7 +53,7 @@ const ReleaseNotesModal: React.FC<ReleaseNotesModalProps> = ({
                     {note.title}
                   </div>
                   <div className="release-note-description text-16-normal">
-                    {note.description}
+                    {decoreText(note.description)}
                   </div>
                 </div>
               ))}
diff --git a/src/components/Splash/SplashRoot.tsx b/src/components/Splash/SplashRoot.tsx
index 3db7ec06d..b15bc3415 100644
--- a/src/components/Splash/SplashRoot.tsx
+++ b/src/components/Splash/SplashRoot.tsx
@@ -116,8 +116,6 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => {
         const migrationsResult: ReleaseNotes = await ms.runMigrations(
           migrations
         )
-        // Init index
-        await initializationService.initIndex()
 
         // Init last release notes when they exist
         dispatch(
@@ -300,7 +298,7 @@ const SplashRoot = ({ fadeTimer = 1000, children }: SplashRootProps) => {
             splashStart: true,
           }))
         }
-      } catch (err) {
+      } catch (err: any) {
         if (err.message === 'Failed to fetch' && !initStepErrors) {
           setinitStepErrors(InitStepsErrors.UNKNOWN_ERROR)
         }
diff --git a/src/components/TotalConsumption/TotalConsumption.tsx b/src/components/TotalConsumption/TotalConsumption.tsx
index 53fcde843..5f9855ca0 100644
--- a/src/components/TotalConsumption/TotalConsumption.tsx
+++ b/src/components/TotalConsumption/TotalConsumption.tsx
@@ -30,10 +30,13 @@ const TotalConsumption: React.FC<TotalConsumptionProps> = ({
   useEffect(() => {
     const calculateTotalValue = async () => {
       const consumptionService = new ConsumptionService(client)
-      const activateHalfHourLoad = await consumptionService.checkDoctypeEntries(
-        FluidType.ELECTRICITY,
-        TimeStep.HALF_AN_HOUR
-      )
+      const activateHalfHourLoad =
+        fluidType === FluidType.ELECTRICITY
+          ? await consumptionService.checkDoctypeEntries(
+              FluidType.ELECTRICITY,
+              TimeStep.HALF_AN_HOUR
+            )
+          : false
 
       const converterService = new ConverterService()
       let total = 0
diff --git a/src/migrations/migration.data.ts b/src/migrations/migration.data.ts
index d9ed8ddc3..cf3e04ad1 100644
--- a/src/migrations/migration.data.ts
+++ b/src/migrations/migration.data.ts
@@ -249,7 +249,7 @@ export const migrations: Migration[] = [
     releaseNotes: null,
     docTypes: PROFILETYPE_DOCTYPE,
     run: async (_client: Client, docs: any[]): Promise<any[]> => {
-      function checkDate(d1, d2) {
+      function checkDate(d1: string, d2: string) {
         const dtd1: DateTime = DateTime.fromISO(d1)
         const dtd2: DateTime = DateTime.fromISO(d2)
         return dtd1.year === dtd2.year && dtd1.month === dtd2.month
@@ -531,4 +531,18 @@ export const migrations: Migration[] = [
       })
     },
   },
+  {
+    baseSchemaVersion: 20,
+    targetSchemaVersion: 21,
+    appVersion: '1.11.0',
+    description: 'Inform user of the new SGE konnector',
+    releaseNotes: {
+      title: 'Vos connecteurs evoluent !',
+      description:
+        "Pour continuer à accéder à vos données, merci de vous reconnecter via ce nouveau parcours. Aucune donnée ne sera perdue, et vos données seront à nouveau mises à jour quotidiennement. <p>Pourquoi ce changement ?</p> Pour faciliter l'accès aux données de consommation au plus grand nombre. Plus besoin de se créer un compte Enedis, l'accès aux données en est facilité. N'hésitez pas à en parler autour de vous ! :)",
+    },
+    docTypes: '',
+    run: async (): Promise<any> => {},
+    isEmpty: true,
+  },
 ]
diff --git a/src/migrations/migration.service.ts b/src/migrations/migration.service.ts
index 5d65dddbc..c282caf15 100644
--- a/src/migrations/migration.service.ts
+++ b/src/migrations/migration.service.ts
@@ -1,4 +1,4 @@
-import { Client } from 'cozy-client'
+import { Client, QueryDefinition, QueryResult, Q } from 'cozy-client'
 import { Migration, MigrationResult } from './migration.type'
 import { migrationLog, migrate } from './migration'
 import {
@@ -8,6 +8,8 @@ import {
 import log from 'utils/logger'
 import { ReleaseNotes } from 'models/releaseNotes.model'
 import { InitStepsErrors } from 'models/initialisationSteps.model'
+import { Schema } from 'models/schema.models'
+import { SCHEMAS_DOCTYPE } from 'doctypes/com-grandlyon-ecolyo-schemas'
 
 export class MigrationService {
   private readonly _client: Client
@@ -23,8 +25,18 @@ export class MigrationService {
     this._client = _client
     this._setinitStepError = _setinitStepError
   }
+  /**
+   * Return schema version
+   * @param _client cozyClient
+   * @returns Promise<number> Version number of schema
+   */
+  public async currentSchemaVersion(_client: Client): Promise<number> {
+    const query: QueryDefinition = Q(SCHEMAS_DOCTYPE)
+    const data: QueryResult<Schema[]> = await _client.query(query.limitBy(1))
+    return data?.data[0]?.version || 0
+  }
 
-  async runMigrations(migrations: Migration[]): Promise<ReleaseNotes> {
+  public async runMigrations(migrations: Migration[]): Promise<ReleaseNotes> {
     log.info('[Migration] Running migrations...')
     let releaseStatus = false
     const releaseNotes: ReleaseNotes = {
@@ -36,37 +48,53 @@ export class MigrationService {
         },
       ],
     }
-    for (const migration of migrations) {
-      // First attempt
-      const migrationResult: MigrationResult = await migrate(
-        migration,
-        this._client
-      )
-      log.info(migrationLog(migration, migrationResult))
+    const currentVersion = await this.currentSchemaVersion(this._client)
+    const targetVersion = migrations[migrations.length - 1].targetSchemaVersion
+    console.log('CURRENT VERSION', currentVersion)
+    console.log('CURRENT targetVersion', targetVersion)
+    // Prevent Migration service to run every migration if not needed
+    if (currentVersion != targetVersion) {
+      const startMigrationIndex =
+        migrations.length - (targetVersion - currentVersion)
+      const migrationsToRun = migrations.splice(startMigrationIndex)
+      console.log('migrationsToRun', migrationsToRun)
+      for (const migration of migrationsToRun) {
+        // First attempt
+        const migrationResult: MigrationResult = await migrate(
+          migration,
+          this._client
+        )
+        log.info(migrationLog(migration, migrationResult))
 
-      if (migrationResult.type === MIGRATION_RESULT_FAILED) {
-        // Retry in case of failure
-        const result = await migrate(migration, this._client)
-        if (result.type === MIGRATION_RESULT_FAILED) {
-          // Error in case of second failure
-          this._setinitStepError(InitStepsErrors.MIGRATION_ERROR)
-          log.error(migrationLog(migration, result))
-          throw new Error()
-        } else {
-          log.info(migrationLog(migration, result))
+        if (migrationResult.type === MIGRATION_RESULT_FAILED) {
+          // Retry in case of failure
+          const result = await migrate(migration, this._client)
+          if (result.type === MIGRATION_RESULT_FAILED) {
+            // Error in case of second failure
+            this._setinitStepError(InitStepsErrors.MIGRATION_ERROR)
+            log.error(migrationLog(migration, result))
+            throw new Error()
+          } else {
+            log.info(migrationLog(migration, result))
+          }
         }
-      }
 
-      if (
-        migration.releaseNotes !== null &&
-        migrationResult.type === MIGRATION_RESULT_COMPLETE
-      ) {
-        releaseNotes.notes.push(migration.releaseNotes)
-        releaseStatus = true
+        if (
+          migration.releaseNotes !== null &&
+          migrationResult.type === MIGRATION_RESULT_COMPLETE
+        ) {
+          releaseNotes.notes.push(migration.releaseNotes)
+          releaseStatus = true
+        }
       }
+      releaseNotes.show = releaseStatus
+      // In case of first instance, don't show release notes
+      if (startMigrationIndex === 0) releaseNotes.show = false
+      log.info('[Migration] Done')
+      return releaseNotes
+    } else {
+      log.info('[Migration] Skipped Migration Process, already up-to-date')
+      return releaseNotes
     }
-    releaseNotes.show = releaseStatus
-    log.info('[Migration] Done')
-    return releaseNotes
   }
 }
diff --git a/src/migrations/migration.ts b/src/migrations/migration.ts
index bf0ee97ec..402db8290 100644
--- a/src/migrations/migration.ts
+++ b/src/migrations/migration.ts
@@ -130,6 +130,13 @@ export async function migrate(
   migration: Migration,
   _client: Client
 ): Promise<MigrationResult> {
+  if (migration.isEmpty) {
+    updateSchemaVersion(_client, migration.targetSchemaVersion)
+    return {
+      errors: [],
+      type: 'MigrationComplete',
+    }
+  }
   if (!(await schemaExist(_client))) {
     await initSchemaDoctype(_client)
   }
diff --git a/src/migrations/migration.type.ts b/src/migrations/migration.type.ts
index c5d87f581..b65e8c2d6 100644
--- a/src/migrations/migration.type.ts
+++ b/src/migrations/migration.type.ts
@@ -30,6 +30,7 @@ export type Migration = {
   isCreate?: boolean
   isDeprecated?: boolean
   queryOptions?: MigrationQueryOptions
+  isEmpty?: boolean
   appVersion: string
   run: (_client: Client, docs: any[]) => Promise<any[]>
 }
diff --git a/src/models/initialisationSteps.model.ts b/src/models/initialisationSteps.model.ts
index e139357ef..f8584e812 100644
--- a/src/models/initialisationSteps.model.ts
+++ b/src/models/initialisationSteps.model.ts
@@ -15,7 +15,6 @@ export enum InitStepsErrors {
   ECOGESTURE_ERROR = 'ecogesture_error',
   CHALLENGES_ERROR = 'challenges_error',
   ANALYSIS_ERROR = 'analysis_error',
-  INDEX_ERROR = 'index_error',
   PRICES_ERROR = 'prices_error',
   CONSOS_ERROR = 'consos_error',
   PARTNERS_ERROR = 'partners_error',
diff --git a/src/services/consumption.service.ts b/src/services/consumption.service.ts
index cdb594de2..18db7623b 100644
--- a/src/services/consumption.service.ts
+++ b/src/services/consumption.service.ts
@@ -20,7 +20,6 @@ import ConsumptionValidatorService from 'services/consumptionValidator.service'
 import ConverterService from 'services/converter.service'
 import QueryRunnerService from 'services/queryRunner.service'
 
-// eslint-disable-next-line @typescript-eslint/interface-name-prefix
 export interface ISingleFluidChartData {
   chartData: Datachart | null
   chartFluid: FluidType
diff --git a/src/services/initialization.service.ts b/src/services/initialization.service.ts
index 77553f502..e199dff50 100644
--- a/src/services/initialization.service.ts
+++ b/src/services/initialization.service.ts
@@ -9,22 +9,11 @@ import {
   CHALLENGE_DOCTYPE,
   DUEL_DOCTYPE,
   ECOGESTURE_DOCTYPE,
-  EGL_DAY_DOCTYPE,
-  EGL_MONTH_DOCTYPE,
-  EGL_YEAR_DOCTYPE,
-  ENEDIS_DAY_DOCTYPE,
-  ENEDIS_MINUTE_DOCTYPE,
-  ENEDIS_MONTH_DOCTYPE,
-  ENEDIS_YEAR_DOCTYPE,
   EXPLORATION_DOCTYPE,
-  GRDF_DAY_DOCTYPE,
-  GRDF_MONTH_DOCTYPE,
-  GRDF_YEAR_DOCTYPE,
   PROFILE_DOCTYPE,
   QUIZ_DOCTYPE,
 } from 'doctypes'
 import { FluidType } from 'enum/fluid.enum'
-import { TimeStep } from 'enum/timeStep.enum'
 import { DateTime } from 'luxon'
 import {
   Dataload,
@@ -38,13 +27,11 @@ import {
 import { InitSteps, InitStepsErrors } from 'models/initialisationSteps.model'
 import { ProfileEcogesture } from 'models/profileEcogesture.model'
 import React from 'react'
-import AccountService from 'services/account.service'
 import ChallengeService from 'services/challenge.service'
 import DuelService from 'services/duel.service'
 import EcogestureService from 'services/ecogesture.service'
 import ExplorationService from 'services/exploration.service'
 import FluidService from 'services/fluid.service'
-import KonnectorService from 'services/konnector.service'
 import KonnectorStatusService from 'services/konnectorStatus.service'
 import ProfileService from 'services/profile.service'
 import QuizService from 'services/quiz.service'
@@ -76,85 +63,6 @@ export default class InitializationService {
     this._setinitStepError = _setinitStepError
   }
 
-  /*
-   * Call a query with where clause to create the index if not exist
-   */
-  private async createIndex(
-    doctype: string,
-    timestep: TimeStep
-  ): Promise<object> {
-    const getMongoSelector = () => {
-      switch (timestep) {
-        case TimeStep.YEAR:
-          return {
-            year: {
-              $lte: 9999,
-            },
-          }
-        case TimeStep.MONTH:
-          return {
-            year: {
-              $lte: 9999,
-            },
-            month: {
-              $lte: 12,
-            },
-          }
-        case TimeStep.DAY:
-        case TimeStep.HALF_AN_HOUR:
-          return {
-            year: {
-              $lte: 9999,
-            },
-            month: {
-              $lte: 12,
-            },
-            day: {
-              $lte: 31,
-            },
-          }
-        default:
-          return {}
-      }
-    }
-    const query: QueryDefinition = Q(doctype)
-      .where(getMongoSelector())
-      .limitBy(1)
-    return await this._client.query(query)
-  }
-
-  /*
-   * create index for each Doctype
-   * sucess return: true
-   * failure throw error
-   */
-  public async initIndex(): Promise<boolean> {
-    try {
-      const accountService = new AccountService(this._client)
-      const konnectorService = new KonnectorService(this._client)
-      await Promise.all([
-        this.createIndex(EGL_YEAR_DOCTYPE, TimeStep.YEAR),
-        this.createIndex(EGL_MONTH_DOCTYPE, TimeStep.MONTH),
-        this.createIndex(EGL_DAY_DOCTYPE, TimeStep.DAY),
-        this.createIndex(ENEDIS_YEAR_DOCTYPE, TimeStep.YEAR),
-        this.createIndex(ENEDIS_MONTH_DOCTYPE, TimeStep.MONTH),
-        this.createIndex(ENEDIS_DAY_DOCTYPE, TimeStep.DAY),
-        this.createIndex(ENEDIS_MINUTE_DOCTYPE, TimeStep.HALF_AN_HOUR),
-        this.createIndex(GRDF_YEAR_DOCTYPE, TimeStep.YEAR),
-        this.createIndex(GRDF_MONTH_DOCTYPE, TimeStep.MONTH),
-        this.createIndex(GRDF_DAY_DOCTYPE, TimeStep.DAY),
-        konnectorService.createIndexKonnector(),
-        accountService.createIndexAccount(),
-      ])
-      log.info('[Initialization] Indexes created')
-      return true
-    } catch (error) {
-      this._setinitStepError(InitStepsErrors.INDEX_ERROR)
-      log.error('Initialization error - initIndex: ', error)
-      throw error
-    }
-  }
-
   /*
    * Check if profil exist
    * If not, the profil is created
diff --git a/src/services/queryRunner.service.ts b/src/services/queryRunner.service.ts
index 4df247207..e27c295fb 100644
--- a/src/services/queryRunner.service.ts
+++ b/src/services/queryRunner.service.ts
@@ -1,4 +1,3 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
 import { Client, QueryDefinition, Q } from 'cozy-client'
 import { DateTime, Interval } from 'luxon'
 import {
@@ -45,7 +44,6 @@ export default class QueryRunner {
     limit: number
   ) {
     const doctype = this.getRelevantDoctype(fluidType, timeStep)
-
     return Q(doctype)
       .where(this.getPredicate(timePeriod, timeStep))
       .limitBy(limit)
@@ -237,7 +235,6 @@ export default class QueryRunner {
 
   private getRelevantDoctype(fluidType: FluidType, timeStep: TimeStep) {
     let doctype = ''
-
     switch (fluidType) {
       case FluidType.ELECTRICITY:
         {
@@ -357,7 +354,7 @@ export default class QueryRunner {
     if (timeStep === TimeStep.HALF_AN_HOUR) {
       const lastDayOfPreviousMonth = {
         startDate: maxTimePeriod.startDate.plus({ day: -1 }),
-        endDate: maxTimePeriod.startDate.plus({ day: -1 }).endOf('days'),
+        endDate: maxTimePeriod.startDate.plus({ day: -1 }).endOf('day'),
       }
       const lastDayOfPreviousMonthQuery: QueryDefinition = this.buildMaxQuery(
         timeStep,
diff --git a/src/utils/decoreText.tsx b/src/utils/decoreText.tsx
index 595da2417..ebf8d6213 100644
--- a/src/utils/decoreText.tsx
+++ b/src/utils/decoreText.tsx
@@ -18,6 +18,16 @@ export const decoreText = (line: string, action?: () => void) => {
         {line.substring(indexEnd + 4, line.length)}
       </>
     )
+  } else if (line.includes('<p>')) {
+    const indexStart = line.indexOf('<p>')
+    const indexEnd = line.indexOf('</p>')
+    return (
+      <>
+        {line.substring(0, indexStart)}
+        <p>{line.substring(indexStart + 3, indexEnd)}</p>
+        {line.substring(indexEnd + 4, line.length)}
+      </>
+    )
   } else if (line.includes('<span>')) {
     const indexStart = line.indexOf('<span>')
     const indexEnd = line.indexOf('</span>')
-- 
GitLab