From ec41d38086797d3b7475d51c802f24a94f0d1f7c Mon Sep 17 00:00:00 2001
From: Bastien DUMONT <bdumont@grandlyon.com>
Date: Fri, 26 Jul 2024 07:30:27 +0000
Subject: [PATCH] fix(accessibility): remove graph shift when navigating with
 keyboard

---
 .../ConsumptionVisualizer.tsx                   | 17 ++++++++++++-----
 .../DataloadConsumptionVisualizer.tsx           | 11 ++++++++++-
 .../ConsumptionVisualizer/DataloadNoValue.tsx   |  8 +++++++-
 .../ConsumptionVisualizer/DataloadSection.tsx   |  4 ++++
 .../DataloadSectionDetail.tsx                   |  4 ++++
 .../DataloadSectionValue.tsx                    |  3 +++
 .../InfoDataConsumptionVisualizer.tsx           | 14 ++++++++++++--
 .../InfoDataConsumptionVisualizer.spec.tsx.snap |  2 +-
 src/components/FluidChart/FluidChartSlide.tsx   |  5 ++++-
 src/components/FluidChart/FluidChartSwipe.tsx   |  9 +++------
 10 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx
index ab0e5d35e..34f248ca6 100644
--- a/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx
+++ b/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx
@@ -1,20 +1,25 @@
 import DataloadConsumptionVisualizer from 'components/ConsumptionVisualizer/DataloadConsumptionVisualizer'
 import { FluidType } from 'enums'
 import { DateTime } from 'luxon'
-import { Dataload } from 'models'
 import React from 'react'
 import { useAppSelector } from 'store/hooks'
 import InfoDataConsumptionVisualizer from './InfoDataConsumptionVisualizer'
 import './consumptionVisualizer.scss'
 
-const ConsumptionVisualizer = ({ fluidType }: { fluidType: FluidType }) => {
+const ConsumptionVisualizer = ({
+  fluidType,
+  focusable,
+}: {
+  fluidType: FluidType
+  focusable?: boolean
+}) => {
   const {
     chart: { currentDatachart, currentDatachartIndex },
     global: { fluidStatus, fluidTypes },
   } = useAppSelector(state => state.ecolyo)
 
-  const dataload: Dataload = currentDatachart.actualData[currentDatachartIndex]
-  const compareDataload: Dataload | null = currentDatachart.comparisonData
+  const dataload = currentDatachart.actualData[currentDatachartIndex]
+  const compareDataload = currentDatachart.comparisonData
     ? currentDatachart.comparisonData[currentDatachartIndex]
     : null
 
@@ -38,7 +43,7 @@ const ConsumptionVisualizer = ({ fluidType }: { fluidType: FluidType }) => {
     }
     return lastDay
   }
-  const lastDataDate: DateTime | null = getLastDataDate()
+  const lastDataDate = getLastDataDate()
 
   return (
     <div className="consumptionvisualizer-root">
@@ -46,12 +51,14 @@ const ConsumptionVisualizer = ({ fluidType }: { fluidType: FluidType }) => {
         fluidType={fluidType}
         dataload={dataload}
         compareDataload={compareDataload}
+        focusable={focusable}
       />
       <div className="consumptionvisualizer-info">
         <InfoDataConsumptionVisualizer
           dataload={dataload}
           fluidType={fluidType}
           lastDataDate={lastDataDate}
+          focusable={focusable}
         />
       </div>
     </div>
diff --git a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx
index 6e38fa737..70162cd08 100644
--- a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx
+++ b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx
@@ -12,11 +12,13 @@ interface DataloadConsumptionVisualizerProps {
   fluidType: FluidType
   dataload: Dataload
   compareDataload: Dataload | null
+  focusable?: boolean
 }
 const DataloadConsumptionVisualizer = ({
   fluidType,
   dataload,
   compareDataload,
+  focusable,
 }: DataloadConsumptionVisualizerProps) => {
   const { showCompare } = useAppSelector(state => state.ecolyo.chart)
   const [openEstimationModal, setOpenEstimationModal] = useState<boolean>(false)
@@ -35,7 +37,11 @@ const DataloadConsumptionVisualizer = ({
   ) {
     return (
       <div className="dataloadvisualizer-root">
-        <DataloadNoValue dataload={dataload} fluidType={fluidType} />
+        <DataloadNoValue
+          dataload={dataload}
+          fluidType={fluidType}
+          focusable={focusable}
+        />
       </div>
     )
   }
@@ -50,12 +56,14 @@ const DataloadConsumptionVisualizer = ({
               fluidType={fluidType}
               dataloadSectionType={DataloadSectionType.LEFT}
               toggleEstimationModal={toggleEstimationModal}
+              focusable={focusable}
             />
             <DataloadSection
               dataload={dataload}
               fluidType={fluidType}
               dataloadSectionType={DataloadSectionType.RIGHT}
               toggleEstimationModal={toggleEstimationModal}
+              focusable={focusable}
             />
           </>
         ) : (
@@ -64,6 +72,7 @@ const DataloadConsumptionVisualizer = ({
             fluidType={fluidType}
             dataloadSectionType={DataloadSectionType.NO_COMPARE}
             toggleEstimationModal={toggleEstimationModal}
+            focusable={focusable}
           />
         )}
       </div>
diff --git a/src/components/ConsumptionVisualizer/DataloadNoValue.tsx b/src/components/ConsumptionVisualizer/DataloadNoValue.tsx
index 759881315..7de7e5c1b 100644
--- a/src/components/ConsumptionVisualizer/DataloadNoValue.tsx
+++ b/src/components/ConsumptionVisualizer/DataloadNoValue.tsx
@@ -11,9 +11,14 @@ import './consumptionVisualizer.scss'
 interface DataloadNoValueProps {
   dataload: Dataload
   fluidType: FluidType
+  focusable?: boolean
 }
 
-const DataloadNoValue = ({ dataload, fluidType }: DataloadNoValueProps) => {
+const DataloadNoValue = ({
+  dataload,
+  fluidType,
+  focusable,
+}: DataloadNoValueProps) => {
   const { t } = useI18n()
   const dispatch = useAppDispatch()
   const fluidName = getFluidName(fluidType)
@@ -63,6 +68,7 @@ const DataloadNoValue = ({ dataload, fluidType }: DataloadNoValueProps) => {
       <Button
         onClick={handleToggleKonnectorCard}
         classes={{ root: 'btnText', label: 'text-22-normal' }}
+        tabIndex={focusable ? 0 : -1}
       >
         {t('consumption_visualizer.missing_data')}
       </Button>
diff --git a/src/components/ConsumptionVisualizer/DataloadSection.tsx b/src/components/ConsumptionVisualizer/DataloadSection.tsx
index 84a6185ee..2416505bb 100644
--- a/src/components/ConsumptionVisualizer/DataloadSection.tsx
+++ b/src/components/ConsumptionVisualizer/DataloadSection.tsx
@@ -13,12 +13,14 @@ interface DataloadSectionProps {
   fluidType: FluidType
   dataloadSectionType: DataloadSectionType
   toggleEstimationModal: () => void
+  focusable?: boolean
 }
 const DataloadSection = ({
   dataload,
   fluidType,
   dataloadSectionType,
   toggleEstimationModal,
+  focusable,
 }: DataloadSectionProps) => {
   const { t } = useI18n()
   const isLeft = dataloadSectionType === DataloadSectionType.LEFT
@@ -59,12 +61,14 @@ const DataloadSection = ({
           fluidType={fluidType}
           dataloadSectionType={dataloadSectionType}
           toggleEstimationModal={toggleEstimationModal}
+          focusable={focusable}
         />
       </div>
       <DataloadSectionDetail
         dataload={dataload}
         fluidType={fluidType}
         dataloadSectionType={dataloadSectionType}
+        focusable={focusable}
       />
     </div>
   )
diff --git a/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx b/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx
index 8be010a5e..e2644b135 100644
--- a/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx
+++ b/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx
@@ -13,12 +13,14 @@ interface DataloadSectionDetailProps {
   dataload: Dataload
   fluidType: FluidType
   dataloadSectionType: DataloadSectionType
+  focusable?: boolean
 }
 
 const DataloadSectionDetail = ({
   dataload,
   fluidType,
   dataloadSectionType,
+  focusable,
 }: DataloadSectionDetailProps) => {
   const { t } = useI18n()
   const converterService = new ConverterService()
@@ -71,6 +73,7 @@ const DataloadSectionDetail = ({
               )}
               to={`/consumption/${FluidType[index].toLowerCase()}`}
               className="dataloadvisualizer-euro-link"
+              tabIndex={focusable ? 0 : -1}
             >
               <div
                 className={classNames('dataloadvisualizer-euro-fluid', {
@@ -104,6 +107,7 @@ const DataloadSectionDetail = ({
       <NavLink
         to={`/consumption/${getFluidName(fluidType)}`}
         className="dataloadvisualizer-euro-link"
+        tabIndex={focusable ? 0 : -1}
       >
         <div
           className={`dataloadvisualizer-euro-fluid ${getFluidName(fluidType)}`}
diff --git a/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx b/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx
index 77e227da2..296992ea0 100644
--- a/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx
+++ b/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx
@@ -10,6 +10,7 @@ interface DataloadSectionValueProps {
   fluidType: FluidType
   dataloadSectionType: DataloadSectionType
   toggleEstimationModal: () => void
+  focusable?: boolean
 }
 
 const DataloadSectionValue = ({
@@ -17,6 +18,7 @@ const DataloadSectionValue = ({
   fluidType,
   dataloadSectionType,
   toggleEstimationModal,
+  focusable,
 }: DataloadSectionValueProps) => {
   const { t } = useI18n()
   const FLUIDNAME = getFluidName(fluidType).toUpperCase()
@@ -36,6 +38,7 @@ const DataloadSectionValue = ({
             }}
             size="small"
             onClick={toggleEstimationModal}
+            tabIndex={focusable ? 0 : -1}
           >
             {t('consumption_visualizer.estimated')}
           </Button>
diff --git a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx
index c3a9b1a08..a44539136 100644
--- a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx
+++ b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx
@@ -12,12 +12,14 @@ interface InfoDataConsumptionVisualizerProps {
   dataload: Dataload
   fluidType: FluidType
   lastDataDate: DateTime | null
+  focusable?: boolean
 }
 
 const InfoDataConsumptionVisualizer = ({
   dataload,
   fluidType,
   lastDataDate,
+  focusable,
 }: InfoDataConsumptionVisualizerProps) => {
   const { t } = useI18n()
   const [openNoDataModal, setOpenNoDataModal] = useState<boolean>(false)
@@ -41,7 +43,11 @@ const InfoDataConsumptionVisualizer = ({
         ? 'last_valid_data_multi'
         : 'last_available_data'
     return (
-      <Button className="btnText" onClick={moveToLatestDate}>
+      <Button
+        className="btnText"
+        onClick={moveToLatestDate}
+        tabIndex={focusable ? 0 : -1}
+      >
         {t(`consumption_visualizer.${key}`, {
           date: lastDate,
         })}
@@ -56,7 +62,11 @@ const InfoDataConsumptionVisualizer = ({
   ) {
     return (
       <>
-        <Button className="btnText" onClick={() => setOpenNoDataModal(true)}>
+        <Button
+          className="btnText"
+          onClick={() => setOpenNoDataModal(true)}
+          tabIndex={focusable ? 0 : -1}
+        >
           <span className="text-16-normal underlined-error">
             {t('consumption_visualizer.why_no_data')}
           </span>
diff --git a/src/components/ConsumptionVisualizer/__snapshots__/InfoDataConsumptionVisualizer.spec.tsx.snap b/src/components/ConsumptionVisualizer/__snapshots__/InfoDataConsumptionVisualizer.spec.tsx.snap
index 41ed4044a..f17d502b2 100644
--- a/src/components/ConsumptionVisualizer/__snapshots__/InfoDataConsumptionVisualizer.spec.tsx.snap
+++ b/src/components/ConsumptionVisualizer/__snapshots__/InfoDataConsumptionVisualizer.spec.tsx.snap
@@ -4,7 +4,7 @@ exports[`InfoDataConsumptionVisualizer component should render correctly when da
 <div>
   <button
     class="MuiButtonBase-root MuiButton-root MuiButton-text btnText"
-    tabindex="0"
+    tabindex="-1"
     type="button"
   >
     <span
diff --git a/src/components/FluidChart/FluidChartSlide.tsx b/src/components/FluidChart/FluidChartSlide.tsx
index ddeff8b14..334de391f 100644
--- a/src/components/FluidChart/FluidChartSlide.tsx
+++ b/src/components/FluidChart/FluidChartSlide.tsx
@@ -34,6 +34,9 @@ const FluidChartSlide = ({
     global: { fluidStatus, fluidTypes },
   } = useAppSelector(state => state.ecolyo)
 
+  /** Determines if child elements should be focusable */
+  const focusable = currentIndex === index
+
   const [chartData, setChartData] = useState<Datachart>({
     actualData: [],
     comparisonData: null,
@@ -117,7 +120,7 @@ const FluidChartSlide = ({
         </div>
       ) : (
         <>
-          <ConsumptionVisualizer fluidType={fluidType} />
+          <ConsumptionVisualizer fluidType={fluidType} focusable={focusable} />
           <BarChart
             chartData={chartData}
             fluidType={fluidType}
diff --git a/src/components/FluidChart/FluidChartSwipe.tsx b/src/components/FluidChart/FluidChartSwipe.tsx
index 846e0225e..ecd686e22 100644
--- a/src/components/FluidChart/FluidChartSwipe.tsx
+++ b/src/components/FluidChart/FluidChartSwipe.tsx
@@ -1,7 +1,6 @@
 import FluidChartSlide from 'components/FluidChart/FluidChartSlide'
 import { useChartResize } from 'components/Hooks/useChartResize'
 import { FluidType } from 'enums'
-import { DateTime } from 'luxon'
 import React, { useEffect, useRef, useState } from 'react'
 import SwipeableViews from 'react-swipeable-views'
 import { virtualize } from 'react-swipeable-views-utils'
@@ -36,12 +35,12 @@ const FluidChartSwipe = ({ fluidType }: { fluidType: FluidType }) => {
         currentIndex
       )
     }
-    const updatedDate: DateTime = dateChartService.incrementDate(
+    const updatedDate = dateChartService.incrementDate(
       currentTimeStep,
       selectedDate,
       increment
     )
-    const updatedIndex: number = dateChartService.defineDateIndex(
+    const updatedIndex = dateChartService.defineDateIndex(
       currentTimeStep,
       updatedDate
     )
@@ -84,9 +83,7 @@ const FluidChartSwipe = ({ fluidType }: { fluidType: FluidType }) => {
         slideRenderer={({ key, index }) => slideRenderer(key, index)}
         enableMouseEvents
         onSwitching={!isSwitching ? () => setIsSwitching(true) : null}
-        onTransitionEnd={() => {
-          setIsSwitching(false)
-        }}
+        onTransitionEnd={() => setIsSwitching(false)}
         axis="x-reverse"
       />
     </div>
-- 
GitLab