From 6dae9c439302ff10a688b81fc9acec73b5409d83 Mon Sep 17 00:00:00 2001
From: Pierre Ecarlat <pecarlat@grandlyon.com>
Date: Thu, 12 Sep 2024 12:51:39 +0000
Subject: [PATCH] feat(a11y): Optimize keyboard navigation between pages

---
 .../Action/ActionBegin/ActionBegin.spec.tsx   |   3 +
 .../Action/ActionBegin/ActionBegin.tsx        |   3 +
 .../Action/ActionCard/ActionCard.spec.tsx     |   2 +
 .../Action/ActionCard/ActionCard.tsx          |   5 +-
 .../Action/ActionChoose/ActionChoose.scss     |   5 +
 .../Action/ActionChoose/ActionChoose.spec.tsx |  10 +-
 .../Action/ActionChoose/ActionChoose.tsx      |  15 +-
 .../__snapshots__/ActionChoose.spec.tsx.snap  | 204 +++++++++---------
 .../Action/ActionList/ActionList.spec.tsx     |   6 +-
 .../Action/ActionList/ActionList.tsx          |   8 +-
 .../Action/ActionModal/ActionModal.spec.tsx   |   2 +
 .../Action/ActionModal/ActionModal.tsx        |   5 +-
 src/components/Action/ActionView.tsx          |  27 ++-
 .../__snapshots__/ActionView.spec.tsx.snap    |  44 ++--
 .../GRDFConnect/GrdfConnectView.tsx           |  11 +-
 .../Connection/SGEConnect/SgeConnectView.tsx  |  11 +-
 .../SgeConnectView.spec.tsx.snap              |   1 +
 src/components/Duel/DuelView.tsx              |   2 +-
 .../Exploration/ExplorationView.tsx           |   2 +-
 .../Quiz/QuizQuestion/QuizQuestion.tsx        |  12 +-
 .../QuizQuestion/QuizQuestionContent.spec.tsx |   2 +
 .../Quiz/QuizQuestion/QuizQuestionContent.tsx |   6 +-
 .../Quiz/QuizQuestion/quizQuestion.scss       | 152 ++++++-------
 src/components/Quiz/QuizView.tsx              |   2 +-
 src/locales/fr.json                           |   6 +-
 25 files changed, 332 insertions(+), 214 deletions(-)
 create mode 100644 src/components/Action/ActionChoose/ActionChoose.scss

diff --git a/src/components/Action/ActionBegin/ActionBegin.spec.tsx b/src/components/Action/ActionBegin/ActionBegin.spec.tsx
index 99bab9320..1b9a39cd6 100644
--- a/src/components/Action/ActionBegin/ActionBegin.spec.tsx
+++ b/src/components/Action/ActionBegin/ActionBegin.spec.tsx
@@ -36,6 +36,7 @@ describe('ActionBegin component', () => {
           action={defaultEcogestureData[1]}
           setShowList={jest.fn()}
           userChallenge={userChallengeData[1]}
+          setFocus={jest.fn()}
         />
       </Provider>
     )
@@ -58,6 +59,7 @@ describe('ActionBegin component', () => {
           action={mockedEcogesturesData[1]}
           setShowList={jest.fn()}
           userChallenge={userChallengeData[1]}
+          setFocus={jest.fn()}
         />
       </Provider>
     )
@@ -76,6 +78,7 @@ describe('ActionBegin component', () => {
           action={defaultEcogestureData[1]}
           setShowList={jest.fn()}
           userChallenge={userChallengeData[1]}
+          setFocus={jest.fn()}
         />
       </Provider>
     )
diff --git a/src/components/Action/ActionBegin/ActionBegin.tsx b/src/components/Action/ActionBegin/ActionBegin.tsx
index 880b904f8..c2b0d6a3b 100644
--- a/src/components/Action/ActionBegin/ActionBegin.tsx
+++ b/src/components/Action/ActionBegin/ActionBegin.tsx
@@ -16,12 +16,14 @@ interface ActionBeginProps {
   action?: Ecogesture
   setShowList: React.Dispatch<React.SetStateAction<boolean>>
   userChallenge: UserChallenge
+  setFocus: () => void
 }
 
 const ActionBegin = ({
   action,
   setShowList,
   userChallenge,
+  setFocus,
 }: ActionBeginProps) => {
   const { t } = useI18n()
   const client = useClient()
@@ -107,6 +109,7 @@ const ActionBegin = ({
             action={currentAction}
             handleCloseClick={() => setOpenLaunchModal(false)}
             userChallenge={userChallenge}
+            setFocus={setFocus}
           />
         </div>
       )}
diff --git a/src/components/Action/ActionCard/ActionCard.spec.tsx b/src/components/Action/ActionCard/ActionCard.spec.tsx
index 9d451bd17..ff72792f0 100644
--- a/src/components/Action/ActionCard/ActionCard.spec.tsx
+++ b/src/components/Action/ActionCard/ActionCard.spec.tsx
@@ -24,6 +24,7 @@ describe('ActionCard component', () => {
           setShowList={jest.fn()}
           setSelectedAction={jest.fn()}
           action={defaultEcogestureData[1]}
+          setFocus={jest.fn()}
         />
       </Provider>
     )
@@ -37,6 +38,7 @@ describe('ActionCard component', () => {
           setShowList={jest.fn()}
           setSelectedAction={jest.fn()}
           action={defaultEcogestureData[1]}
+          setFocus={jest.fn()}
         />
       </Provider>
     )
diff --git a/src/components/Action/ActionCard/ActionCard.tsx b/src/components/Action/ActionCard/ActionCard.tsx
index 75c04ea08..a4aea07a2 100644
--- a/src/components/Action/ActionCard/ActionCard.tsx
+++ b/src/components/Action/ActionCard/ActionCard.tsx
@@ -11,12 +11,14 @@ interface ActionCardProps {
   action: Ecogesture
   setSelectedAction: React.Dispatch<React.SetStateAction<Ecogesture | null>>
   setShowList: React.Dispatch<React.SetStateAction<boolean>>
+  setFocus: () => void
 }
 
 const ActionCard = ({
   action,
   setSelectedAction,
   setShowList,
+  setFocus,
 }: ActionCardProps) => {
   const [actionIcon, setActionIcon] = useState<string>('')
   const [openEcogestureModal, setOpenEcogestureModal] = useState<boolean>(false)
@@ -25,7 +27,8 @@ const ActionCard = ({
     setSelectedAction(action)
     setShowList(false)
     setOpenEcogestureModal(false)
-  }, [setSelectedAction, setShowList, action])
+    setFocus()
+  }, [setSelectedAction, action, setShowList, setFocus])
 
   useEffect(() => {
     async function handleEcogestureIcon() {
diff --git a/src/components/Action/ActionChoose/ActionChoose.scss b/src/components/Action/ActionChoose/ActionChoose.scss
new file mode 100644
index 000000000..a7ab9a15a
--- /dev/null
+++ b/src/components/Action/ActionChoose/ActionChoose.scss
@@ -0,0 +1,5 @@
+.action-content-view {
+  width: 100%;
+  margin: auto;
+  outline: none;
+}
diff --git a/src/components/Action/ActionChoose/ActionChoose.spec.tsx b/src/components/Action/ActionChoose/ActionChoose.spec.tsx
index a2c2d2e70..4f556e86b 100644
--- a/src/components/Action/ActionChoose/ActionChoose.spec.tsx
+++ b/src/components/Action/ActionChoose/ActionChoose.spec.tsx
@@ -42,7 +42,10 @@ describe('ActionChoose component', () => {
     ])
     const { container } = render(
       <Provider store={store}>
-        <ActionChoose userChallenge={userChallengeData[1]} />
+        <ActionChoose
+          userChallenge={userChallengeData[1]}
+          setFocus={jest.fn()}
+        />
       </Provider>
     )
     await waitFor(() => null, { container })
@@ -64,7 +67,10 @@ describe('ActionChoose component', () => {
 
     const { container } = render(
       <Provider store={store}>
-        <ActionChoose userChallenge={userChallengeData[1]} />
+        <ActionChoose
+          userChallenge={userChallengeData[1]}
+          setFocus={jest.fn()}
+        />
       </Provider>
     )
     await waitFor(() => null, { container })
diff --git a/src/components/Action/ActionChoose/ActionChoose.tsx b/src/components/Action/ActionChoose/ActionChoose.tsx
index b1e7d3ad7..d6fb6cb23 100644
--- a/src/components/Action/ActionChoose/ActionChoose.tsx
+++ b/src/components/Action/ActionChoose/ActionChoose.tsx
@@ -2,26 +2,35 @@ import { Ecogesture, UserChallenge } from 'models'
 import React, { useState } from 'react'
 import ActionBegin from '../ActionBegin/ActionBegin'
 import ActionList from '../ActionList/ActionList'
+import './ActionChoose.scss'
 
-const ActionChoose = ({ userChallenge }: { userChallenge: UserChallenge }) => {
+const ActionChoose = ({
+  userChallenge,
+  setFocus,
+}: {
+  userChallenge: UserChallenge
+  setFocus: () => void
+}) => {
   const [selectedAction, setSelectedAction] = useState<Ecogesture | null>(null)
   const [showList, setShowList] = useState<boolean>(false)
 
   return (
-    <>
+    <div className="action-content-view">
       {!showList ? (
         <ActionBegin
           action={selectedAction ?? undefined}
           setShowList={setShowList}
           userChallenge={userChallenge}
+          setFocus={setFocus}
         />
       ) : (
         <ActionList
           setSelectedAction={setSelectedAction}
           setShowList={setShowList}
+          setFocus={setFocus}
         />
       )}
-    </>
+    </div>
   )
 }
 
diff --git a/src/components/Action/ActionChoose/__snapshots__/ActionChoose.spec.tsx.snap b/src/components/Action/ActionChoose/__snapshots__/ActionChoose.spec.tsx.snap
index 972120fc6..8d568d329 100644
--- a/src/components/Action/ActionChoose/__snapshots__/ActionChoose.spec.tsx.snap
+++ b/src/components/Action/ActionChoose/__snapshots__/ActionChoose.spec.tsx.snap
@@ -3,120 +3,124 @@
 exports[`ActionChoose component should render correctly 1`] = `
 <div>
   <div
-    class="action-begin"
+    class="action-content-view"
   >
     <div
-      class="action-container"
+      class="action-begin"
     >
       <div
-        class="action-begin-container"
+        class="action-container"
       >
         <div
-          class="icon-container"
+          class="action-begin-container"
         >
-          <svg
-            aria-hidden="true"
-            class="action-icon styles__icon___23x3R"
-            height="100"
-            width="100"
+          <div
+            class="icon-container"
           >
-            <use
-              xlink:href="#test-file-stub"
-            />
-          </svg>
-        </div>
-        <div
-          class="stars"
-        >
-          <svg
-            aria-hidden="true"
-            class="star styles__icon___23x3R"
-            height="25"
-            width="25"
-          >
-            <use
-              xlink:href="#test-file-stub"
-            />
-          </svg>
-          <svg
-            aria-hidden="true"
-            class="star styles__icon___23x3R"
-            height="25"
-            width="25"
-          >
-            <use
-              xlink:href="#test-file-stub"
-            />
-          </svg>
-          <svg
-            aria-hidden="true"
-            class="star styles__icon___23x3R"
-            height="25"
-            width="25"
+            <svg
+              aria-hidden="true"
+              class="action-icon styles__icon___23x3R"
+              height="100"
+              width="100"
+            >
+              <use
+                xlink:href="#test-file-stub"
+              />
+            </svg>
+          </div>
+          <div
+            class="stars"
           >
-            <use
-              xlink:href="#test-file-stub"
-            />
-          </svg>
-          <svg
-            aria-hidden="true"
-            class="star styles__icon___23x3R"
-            height="25"
-            width="25"
+            <svg
+              aria-hidden="true"
+              class="star styles__icon___23x3R"
+              height="25"
+              width="25"
+            >
+              <use
+                xlink:href="#test-file-stub"
+              />
+            </svg>
+            <svg
+              aria-hidden="true"
+              class="star styles__icon___23x3R"
+              height="25"
+              width="25"
+            >
+              <use
+                xlink:href="#test-file-stub"
+              />
+            </svg>
+            <svg
+              aria-hidden="true"
+              class="star styles__icon___23x3R"
+              height="25"
+              width="25"
+            >
+              <use
+                xlink:href="#test-file-stub"
+              />
+            </svg>
+            <svg
+              aria-hidden="true"
+              class="star styles__icon___23x3R"
+              height="25"
+              width="25"
+            >
+              <use
+                xlink:href="#test-file-stub"
+              />
+            </svg>
+            <svg
+              aria-hidden="true"
+              class="star styles__icon___23x3R"
+              height="25"
+              width="25"
+            >
+              <use
+                xlink:href="#test-file-stub"
+              />
+            </svg>
+          </div>
+          <h1
+            class="text-20-bold"
           >
-            <use
-              xlink:href="#test-file-stub"
-            />
-          </svg>
-          <svg
-            aria-hidden="true"
-            class="star styles__icon___23x3R"
-            height="25"
-            width="25"
+            Bonhomme de neige
+          </h1>
+          <div
+            class="action-duration text-18"
           >
-            <use
-              xlink:href="#test-file-stub"
-            />
-          </svg>
-        </div>
-        <h1
-          class="text-20-bold"
-        >
-          Bonhomme de neige
-        </h1>
-        <div
-          class="action-duration text-18"
-        >
-          action.duration
-        </div>
-        <div
-          class="action-text text-18-bold"
-        />
-        <div
-          class="action-buttons"
-        >
-          <button
-            class="MuiButtonBase-root MuiButton-root MuiButton-text btnSecondary"
-            tabindex="0"
-            type="button"
+            action.duration
+          </div>
+          <div
+            class="action-text text-18-bold"
+          />
+          <div
+            class="action-buttons"
           >
-            <span
-              class="MuiButton-label"
+            <button
+              class="MuiButtonBase-root MuiButton-root MuiButton-text btnSecondary"
+              tabindex="0"
+              type="button"
             >
-              action.apply
-            </span>
-          </button>
-          <button
-            class="MuiButtonBase-root MuiButton-root MuiButton-text btnSecondary"
-            tabindex="0"
-            type="button"
-          >
-            <span
-              class="MuiButton-label"
+              <span
+                class="MuiButton-label"
+              >
+                action.apply
+              </span>
+            </button>
+            <button
+              class="MuiButtonBase-root MuiButton-root MuiButton-text btnSecondary"
+              tabindex="0"
+              type="button"
             >
-              action.other
-            </span>
-          </button>
+              <span
+                class="MuiButton-label"
+              >
+                action.other
+              </span>
+            </button>
+          </div>
         </div>
       </div>
     </div>
diff --git a/src/components/Action/ActionList/ActionList.spec.tsx b/src/components/Action/ActionList/ActionList.spec.tsx
index 54329b779..3fd43aeb1 100644
--- a/src/components/Action/ActionList/ActionList.spec.tsx
+++ b/src/components/Action/ActionList/ActionList.spec.tsx
@@ -28,7 +28,11 @@ describe('ActionList component', () => {
     })
     const { container } = render(
       <Provider store={store}>
-        <ActionList setSelectedAction={jest.fn()} setShowList={jest.fn()} />
+        <ActionList
+          setSelectedAction={jest.fn()}
+          setShowList={jest.fn()}
+          setFocus={jest.fn()}
+        />
       </Provider>
     )
     await waitFor(() => null, { container })
diff --git a/src/components/Action/ActionList/ActionList.tsx b/src/components/Action/ActionList/ActionList.tsx
index c2bcdf72c..13317e4ca 100644
--- a/src/components/Action/ActionList/ActionList.tsx
+++ b/src/components/Action/ActionList/ActionList.tsx
@@ -9,9 +9,14 @@ import './actionList.scss'
 interface ActionListProps {
   setSelectedAction: React.Dispatch<React.SetStateAction<Ecogesture | null>>
   setShowList: React.Dispatch<React.SetStateAction<boolean>>
+  setFocus: () => void
 }
 
-const ActionList = ({ setSelectedAction, setShowList }: ActionListProps) => {
+const ActionList = ({
+  setSelectedAction,
+  setShowList,
+  setFocus,
+}: ActionListProps) => {
   const client = useClient()
   const {
     global: { fluidTypes },
@@ -47,6 +52,7 @@ const ActionList = ({ setSelectedAction, setShowList }: ActionListProps) => {
               action={action}
               setSelectedAction={setSelectedAction}
               setShowList={setShowList}
+              setFocus={setFocus}
             />
           ))}
         </div>
diff --git a/src/components/Action/ActionModal/ActionModal.spec.tsx b/src/components/Action/ActionModal/ActionModal.spec.tsx
index 138d005c3..2e8f36c8d 100644
--- a/src/components/Action/ActionModal/ActionModal.spec.tsx
+++ b/src/components/Action/ActionModal/ActionModal.spec.tsx
@@ -25,6 +25,7 @@ describe('ActionModal component', () => {
           handleCloseClick={jest.fn()}
           action={defaultEcogestureData[1]}
           userChallenge={userChallengeData[1]}
+          setFocus={jest.fn()}
         />
       </Provider>
     )
@@ -44,6 +45,7 @@ describe('ActionModal component', () => {
           handleCloseClick={jest.fn()}
           action={defaultEcogestureData[1]}
           userChallenge={userChallengeData[1]}
+          setFocus={jest.fn()}
         />
       </Provider>
     )
diff --git a/src/components/Action/ActionModal/ActionModal.tsx b/src/components/Action/ActionModal/ActionModal.tsx
index a83e38729..4f9a84260 100644
--- a/src/components/Action/ActionModal/ActionModal.tsx
+++ b/src/components/Action/ActionModal/ActionModal.tsx
@@ -17,6 +17,7 @@ interface ActionModalProps {
   action: Ecogesture
   handleCloseClick: () => void
   userChallenge: UserChallenge
+  setFocus: () => void
 }
 
 const ActionModal = ({
@@ -24,6 +25,7 @@ const ActionModal = ({
   action,
   handleCloseClick,
   userChallenge,
+  setFocus,
 }: ActionModalProps) => {
   const client = useClient()
   const { t } = useI18n()
@@ -38,7 +40,8 @@ const ActionModal = ({
       action
     )
     dispatch(updateUserChallengeList(updatedChallenge))
-  }, [action, client, dispatch, userChallenge])
+    setFocus()
+  }, [action, client, dispatch, setFocus, userChallenge])
 
   return (
     <Dialog
diff --git a/src/components/Action/ActionView.tsx b/src/components/Action/ActionView.tsx
index 091cdba3b..cec6bf739 100644
--- a/src/components/Action/ActionView.tsx
+++ b/src/components/Action/ActionView.tsx
@@ -3,28 +3,37 @@ import CozyBar from 'components/Header/CozyBar'
 import Header from 'components/Header/Header'
 import { UserActionState } from 'enums'
 import { UserChallenge } from 'models'
-import React from 'react'
+import React, { useRef } from 'react'
 import { useAppSelector } from 'store/hooks'
 import ActionChoose from './ActionChoose/ActionChoose'
 import ActionDone from './ActionDone/ActionDone'
 import ActionOnGoing from './ActionOnGoing/ActionOnGoing'
 
 /**
- * http://ecolyo.cozy.tools:8080/#/challenges/
+ * http://ecolyo.cozy.tools:8080/#/challenges/action
  */
 const ActionView = () => {
   const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge)
 
+  const mainContentRef = useRef<HTMLDivElement>(null)
+  const focusMainContent = () => {
+    setTimeout(() => mainContentRef.current?.focus(), 0)
+  }
+
   const renderAction = (challenge: UserChallenge) => {
     switch (challenge.action.state) {
       case UserActionState.UNSTARTED:
-        return <ActionChoose userChallenge={challenge} />
+        return (
+          <ActionChoose userChallenge={challenge} setFocus={focusMainContent} />
+        )
       case UserActionState.ONGOING:
         return <ActionOnGoing userAction={challenge.action} />
       case UserActionState.NOTIFICATION:
         return <ActionDone currentChallenge={challenge} />
       default:
-        return <ActionChoose userChallenge={challenge} />
+        return (
+          <ActionChoose userChallenge={challenge} setFocus={focusMainContent} />
+        )
     }
   }
 
@@ -32,7 +41,15 @@ const ActionView = () => {
     <>
       <CozyBar titleKey="common.title_action" displayBackArrow={true} />
       <Header desktopTitleKey="common.title_action" displayBackArrow={true} />
-      <Content>{currentChallenge && renderAction(currentChallenge)}</Content>
+      <Content>
+        <div
+          ref={mainContentRef}
+          style={{ outline: 'none', margin: 'auto' }}
+          tabIndex={-1}
+        >
+          {currentChallenge && renderAction(currentChallenge)}
+        </div>
+      </Content>
     </>
   )
 }
diff --git a/src/components/Action/__snapshots__/ActionView.spec.tsx.snap b/src/components/Action/__snapshots__/ActionView.spec.tsx.snap
index cd7ed71bd..d36bcbeeb 100644
--- a/src/components/Action/__snapshots__/ActionView.spec.tsx.snap
+++ b/src/components/Action/__snapshots__/ActionView.spec.tsx.snap
@@ -11,9 +11,14 @@ exports[`ActionView component should render match snapshot with "Notification" s
     displaybackarrow="true"
   />
   <mock-content>
-    <mock-action-done
-      currentchallenge="[object Object]"
-    />
+    <div
+      style="outline: none; margin: auto;"
+      tabindex="-1"
+    >
+      <mock-action-done
+        currentchallenge="[object Object]"
+      />
+    </div>
   </mock-content>
 </div>
 `;
@@ -29,9 +34,14 @@ exports[`ActionView component should render match snapshot with "Unstarted" stat
     displaybackarrow="true"
   />
   <mock-content>
-    <mock-action-choose
-      userchallenge="[object Object]"
-    />
+    <div
+      style="outline: none; margin: auto;"
+      tabindex="-1"
+    >
+      <mock-action-choose
+        userchallenge="[object Object]"
+      />
+    </div>
   </mock-content>
 </div>
 `;
@@ -47,9 +57,14 @@ exports[`ActionView component should render match snapshot with "onGoing" state
     displaybackarrow="true"
   />
   <mock-content>
-    <mock-action-ongoing
-      useraction="[object Object]"
-    />
+    <div
+      style="outline: none; margin: auto;"
+      tabindex="-1"
+    >
+      <mock-action-ongoing
+        useraction="[object Object]"
+      />
+    </div>
   </mock-content>
 </div>
 `;
@@ -65,9 +80,14 @@ exports[`ActionView component should render match snapshot with default case 1`]
     displaybackarrow="true"
   />
   <mock-content>
-    <mock-action-choose
-      userchallenge="[object Object]"
-    />
+    <div
+      style="outline: none; margin: auto;"
+      tabindex="-1"
+    >
+      <mock-action-choose
+        userchallenge="[object Object]"
+      />
+    </div>
   </mock-content>
 </div>
 `;
diff --git a/src/components/Connection/GRDFConnect/GrdfConnectView.tsx b/src/components/Connection/GRDFConnect/GrdfConnectView.tsx
index 75770f05a..9661de4e1 100644
--- a/src/components/Connection/GRDFConnect/GrdfConnectView.tsx
+++ b/src/components/Connection/GRDFConnect/GrdfConnectView.tsx
@@ -7,7 +7,7 @@ import useKonnectorAuth from 'components/Hooks/useKonnectorAuth'
 import useUserInstanceSettings from 'components/Hooks/useUserInstanceSettings'
 import { FluidType } from 'enums'
 import { AccountGRDFData } from 'models'
-import React, { useCallback, useEffect, useState } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
 import { useNavigate } from 'react-router-dom'
 import { useAppSelector } from 'store/hooks'
 import '../connection.scss'
@@ -42,6 +42,11 @@ export const GrdfConnectView = () => {
     pceConfirm: false,
   })
 
+  const mainContentRef = useRef<HTMLDivElement>(null)
+  const focusMainContent = () => {
+    setTimeout(() => mainContentRef.current?.focus(), 0)
+  }
+
   const [connect, update] = useKonnectorAuth(FluidType.GAS, {
     grdfAuthData: formData,
   })
@@ -98,10 +103,12 @@ export const GrdfConnectView = () => {
     if (currentStep === GrdfStep.Consent) {
       setLaunchConnection(true)
     }
+    focusMainContent()
   }, [currentStep, isNextValid])
 
   const handlePrev = () => {
     setCurrentStep(prev => prev - 1)
+    focusMainContent()
   }
 
   const renderStep = (step: GrdfStep) => {
@@ -125,7 +132,7 @@ export const GrdfConnectView = () => {
         displayBackArrow={true}
       />
       <Content>
-        <div className="connectView">
+        <div ref={mainContentRef} className="connectView" tabIndex={-1}>
           <div className="stepContainer">
             <FormProgress
               currentStep={currentStep}
diff --git a/src/components/Connection/SGEConnect/SgeConnectView.tsx b/src/components/Connection/SGEConnect/SgeConnectView.tsx
index 6c8305bf5..8f0a00d20 100644
--- a/src/components/Connection/SGEConnect/SgeConnectView.tsx
+++ b/src/components/Connection/SGEConnect/SgeConnectView.tsx
@@ -6,7 +6,7 @@ import Header from 'components/Header/Header'
 import useKonnectorAuth from 'components/Hooks/useKonnectorAuth'
 import { FluidType, SgeStep } from 'enums'
 import { SgeStore } from 'models'
-import React, { useCallback, useEffect, useState } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
 import { useNavigate } from 'react-router-dom'
 import {
   setShouldRefreshConsent,
@@ -44,6 +44,11 @@ const SgeConnectView = () => {
   const currentFluidStatus = fluidStatus[FluidType.ELECTRICITY]
   const account = currentFluidStatus.connection.account
 
+  const mainContentRef = useRef<HTMLDivElement>(null)
+  const focusMainContent = () => {
+    setTimeout(() => mainContentRef.current?.focus(), 0)
+  }
+
   const [connect, update] = useKonnectorAuth(FluidType.ELECTRICITY, {
     sgeAuthData: sgeConnect,
   })
@@ -112,6 +117,7 @@ const SgeConnectView = () => {
       setCurrentSgeState(updatedState)
       dispatch(updateSgeStore(updatedState))
     }
+    focusMainContent()
   }, [currentStep, isLoading, dispatch, currentSgeState])
 
   const handlePrev = useCallback(() => {
@@ -119,6 +125,7 @@ const SgeConnectView = () => {
       setCurrentStep(prev => prev - 1)
     }
     dispatch(updateSgeStore(currentSgeState))
+    focusMainContent()
   }, [currentSgeState, currentStep, dispatch])
 
   const onChange = useCallback(
@@ -160,7 +167,7 @@ const SgeConnectView = () => {
         displayBackArrow={true}
       />
       <Content>
-        <div className="connectView">
+        <div ref={mainContentRef} className="connectView" tabIndex={-1}>
           <div className="stepContainer">
             <FormProgress
               currentStep={currentStep}
diff --git a/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap b/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap
index 40c5b3007..8da493fcf 100644
--- a/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap
+++ b/src/components/Connection/SGEConnect/__snapshots__/SgeConnectView.spec.tsx.snap
@@ -57,6 +57,7 @@ exports[`SgeConnectView component should be rendered correctly 1`] = `
   <mock-content>
     <div
       class="connectView"
+      tabindex="-1"
     >
       <div
         class="stepContainer"
diff --git a/src/components/Duel/DuelView.tsx b/src/components/Duel/DuelView.tsx
index 3da01109c..99b938ed0 100644
--- a/src/components/Duel/DuelView.tsx
+++ b/src/components/Duel/DuelView.tsx
@@ -12,7 +12,7 @@ import DuelOngoing from './DuelOngoing/DuelOngoing'
 import DuelUnlocked from './DuelUnlocked/DuelUnlocked'
 
 /**
- * http://ecolyo.cozy.tools:8080/#/challenges/
+ * http://ecolyo.cozy.tools:8080/#/challenges/duel
  */
 const DuelView = () => {
   const navigate = useNavigate()
diff --git a/src/components/Exploration/ExplorationView.tsx b/src/components/Exploration/ExplorationView.tsx
index 14f8737b6..73e74e0c8 100644
--- a/src/components/Exploration/ExplorationView.tsx
+++ b/src/components/Exploration/ExplorationView.tsx
@@ -10,7 +10,7 @@ import ExplorationFinished from './ExplorationFinished'
 import ExplorationOngoing from './ExplorationOngoing'
 
 /**
- * http://ecolyo.cozy.tools:8080/#/challenges/
+ * http://ecolyo.cozy.tools:8080/#/challenges/exploration
  */
 const ExplorationView = () => {
   const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge)
diff --git a/src/components/Quiz/QuizQuestion/QuizQuestion.tsx b/src/components/Quiz/QuizQuestion/QuizQuestion.tsx
index 8702fd98a..c75a4404f 100644
--- a/src/components/Quiz/QuizQuestion/QuizQuestion.tsx
+++ b/src/components/Quiz/QuizQuestion/QuizQuestion.tsx
@@ -1,7 +1,7 @@
 import Loader from 'components/Loader/Loader'
 import { useClient } from 'cozy-client'
 import { QuestionEntity, UserChallenge } from 'models'
-import React, { useEffect, useState } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
 import { useNavigate } from 'react-router-dom'
 import QuizService from 'services/quiz.service'
 import { useAppSelector } from 'store/hooks'
@@ -20,6 +20,11 @@ const QuizQuestion = ({ userChallenge }: { userChallenge: UserChallenge }) => {
   const [customQuestion, setCustomQuestion] = useState<QuestionEntity>()
   const [isCustomQuest, setIsCustomQuest] = useState(!questionsIsLocked)
 
+  const mainContentRef = useRef<HTMLDivElement>(null)
+  const focusMainContent = () => {
+    setTimeout(() => mainContentRef.current?.focus(), 0)
+  }
+
   const goBack = () => {
     navigate('/challenges')
   }
@@ -43,7 +48,7 @@ const QuizQuestion = ({ userChallenge }: { userChallenge: UserChallenge }) => {
   }, [client, fluidTypes, isCustomQuest, userChallenge.quiz.customQuestion])
 
   return (
-    <>
+    <div ref={mainContentRef} className="quiz-content" tabIndex={-1}>
       {isCustomQuest ? (
         <>
           {!customQuestion ? (
@@ -63,9 +68,10 @@ const QuizQuestion = ({ userChallenge }: { userChallenge: UserChallenge }) => {
           userChallenge={userChallenge}
           setIsCustomQuest={setIsCustomQuest}
           goBack={goBack}
+          focusCallback={focusMainContent}
         />
       )}
-    </>
+    </div>
   )
 }
 
diff --git a/src/components/Quiz/QuizQuestion/QuizQuestionContent.spec.tsx b/src/components/Quiz/QuizQuestion/QuizQuestionContent.spec.tsx
index 707db20c9..246131418 100644
--- a/src/components/Quiz/QuizQuestion/QuizQuestionContent.spec.tsx
+++ b/src/components/Quiz/QuizQuestion/QuizQuestionContent.spec.tsx
@@ -33,6 +33,7 @@ describe('QuizQuestionContent component', () => {
           userChallenge={userChallengeData[0]}
           setIsCustomQuest={() => false}
           goBack={mockedNavigate('/challenges')}
+          focusCallback={jest.fn()}
         />
       </Provider>
     )
@@ -48,6 +49,7 @@ describe('QuizQuestionContent component', () => {
           userChallenge={userChallengeData[0]}
           setIsCustomQuest={() => false}
           goBack={mockedNavigate('/challenges')}
+          focusCallback={jest.fn()}
         />
       </Provider>
     )
diff --git a/src/components/Quiz/QuizQuestion/QuizQuestionContent.tsx b/src/components/Quiz/QuizQuestion/QuizQuestionContent.tsx
index 5fc440334..ae813372a 100644
--- a/src/components/Quiz/QuizQuestion/QuizQuestionContent.tsx
+++ b/src/components/Quiz/QuizQuestion/QuizQuestionContent.tsx
@@ -17,12 +17,14 @@ interface QuizQuestionContent {
   userChallenge: UserChallenge
   setIsCustomQuest: Dispatch<SetStateAction<boolean>>
   goBack: () => void
+  focusCallback: () => void
 }
 
 const QuizQuestionContent = ({
   userChallenge,
   setIsCustomQuest,
   goBack,
+  focusCallback,
 }: QuizQuestionContent) => {
   const { t } = useI18n()
   const client = useClient()
@@ -73,13 +75,15 @@ const QuizQuestionContent = ({
     if (questionIndex !== userChallenge.quiz.questions.length - 1) {
       setQuestionIndex(questionIndex + 1)
     }
+    focusCallback()
   }, [
     questionIndex,
+    userChallenge.quiz.questions.length,
+    focusCallback,
     setIsCustomQuest,
     setQuestionIndex,
     setUserChoice,
     setOpenModal,
-    userChallenge.quiz.questions.length,
   ])
 
   return (
diff --git a/src/components/Quiz/QuizQuestion/quizQuestion.scss b/src/components/Quiz/QuizQuestion/quizQuestion.scss
index cbab0ba2f..035243a5a 100644
--- a/src/components/Quiz/QuizQuestion/quizQuestion.scss
+++ b/src/components/Quiz/QuizQuestion/quizQuestion.scss
@@ -1,89 +1,93 @@
 @import 'src/styles/base/color';
 @import 'src/styles/base/breakpoint';
 
-.quiz-container {
-  .question-container {
-    display: flex;
-    flex-direction: column;
-    justify-content: center;
-    align-items: center;
-    padding: 1.5rem;
-    box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.55);
-    border-radius: 4px;
-    transition: all 300ms ease;
-    color: $white;
-    background: $grey-linear-gradient-background;
-    position: relative;
-    @media (min-width: $width-large-phone) {
-      height: 45vh;
-    }
-
-    .question-loading {
-      min-height: 13.875rem;
+.quiz-content {
+  outline: none;
+  margin: auto;
+  .quiz-container {
+    .question-container {
       display: flex;
+      flex-direction: column;
       justify-content: center;
       align-items: center;
+      padding: 1.5rem;
+      box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.55);
+      border-radius: 4px;
+      transition: all 300ms ease;
+      color: $white;
+      background: $grey-linear-gradient-background;
+      position: relative;
+      @media (min-width: $width-large-phone) {
+        height: 45vh;
+      }
+
+      .question-loading {
+        min-height: 13.875rem;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+      .question {
+        color: $grey-bright;
+        text-align: center;
+        margin-bottom: 2rem;
+        @media (min-width: $width-large-phone) {
+          padding: 0 1rem;
+        }
+      }
+      .question-title {
+        color: $blue-light;
+        margin-bottom: 0.5rem;
+      }
+      .btn-back {
+        color: $white;
+        background: none;
+        border: none;
+        padding: 0;
+        font-size: 1.3rem;
+        position: absolute;
+        top: 1rem;
+        right: 1rem;
+      }
     }
-    .question {
-      color: $grey-bright;
+    .answer {
       text-align: center;
-      margin-bottom: 2rem;
+      width: 100%;
       @media (min-width: $width-large-phone) {
-        padding: 0 1rem;
+        max-width: 80%;
+      }
+      input[type='radio'] {
+        position: fixed;
+        opacity: 0;
+        pointer-events: none;
+      }
+      input[type='radio']:focus + label {
+        background: $blue-light;
+        color: $dark-light-2;
+        border-color: $blue-light;
+      }
+      label {
+        display: block;
+        border: 1px solid $grey-bright;
+        padding: 0.5rem;
+        margin-bottom: 1rem;
+        cursor: pointer;
+      }
+      input[type='radio']:checked + label,
+      label:hover {
+        background: $blue-radial-gradient;
+        color: $dark-light-2;
+        border-color: $blue-light;
       }
     }
-    .question-title {
-      color: $blue-light;
-      margin-bottom: 0.5rem;
-    }
-    .btn-back {
-      color: $white;
-      background: none;
-      border: none;
-      padding: 0;
-      font-size: 1.3rem;
-      position: absolute;
-      top: 1rem;
-      right: 1rem;
-    }
-  }
-  .answer {
-    text-align: center;
-    width: 100%;
-    @media (min-width: $width-large-phone) {
-      max-width: 80%;
-    }
-    input[type='radio'] {
-      position: fixed;
-      opacity: 0;
-      pointer-events: none;
-    }
-    input[type='radio']:focus + label {
-      background: $blue-light;
-      color: $dark-light-2;
-      border-color: $blue-light;
-    }
-    label {
-      display: block;
-      border: 1px solid $grey-bright;
-      padding: 0.5rem;
-      margin-bottom: 1rem;
-      cursor: pointer;
-    }
-    input[type='radio']:checked + label,
-    label:hover {
-      background: $blue-radial-gradient;
-      color: $dark-light-2;
-      border-color: $blue-light;
+    button.validate {
+      margin-top: 1rem;
+      width: auto;
+      padding: 0.5rem 3rem;
     }
-  }
-  button.validate {
-    margin-top: 1rem;
-    width: auto;
-    padding: 0.5rem 3rem;
-  }
 
-  .index-question {
-    margin: 2rem 0 1rem;
+    .index-question {
+      margin: 2rem 0 1rem;
+    }
   }
 }
diff --git a/src/components/Quiz/QuizView.tsx b/src/components/Quiz/QuizView.tsx
index f6b2a39c6..33abffc04 100644
--- a/src/components/Quiz/QuizView.tsx
+++ b/src/components/Quiz/QuizView.tsx
@@ -10,7 +10,7 @@ import QuizFinish from './QuizFinish/QuizFinish'
 import QuizQuestion from './QuizQuestion/QuizQuestion'
 
 /**
- * http://ecolyo.cozy.tools:8080/#/challenges/
+ * http://ecolyo.cozy.tools:8080/#/challenges/quiz
  */
 const QuizView = () => {
   const { currentChallenge } = useAppSelector(state => state.ecolyo.challenge)
diff --git a/src/locales/fr.json b/src/locales/fr.json
index 727e662ac..b6ed8bf44 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -686,8 +686,8 @@
     "later": "Plus tard",
     "lets_go": "J'y vais",
     "accessibility": {
-      "window_title": "Fenêtre de partage de retours",
-      "button_close": "Fermer la fenêtre de partage de retours"
+      "window_title": "Fenêtre de service assistance aux utilisateurs",
+      "button_close": "Fermer la fenêtre de service assistance aux utilisateurs"
     }
   },
   "dataShare": {
@@ -793,7 +793,7 @@
   "header": {
     "accessibility": {
       "button_back": "Retour à la page précédente",
-      "button_open_feedbacks": "Ouvrir le partage de retours"
+      "button_open_feedbacks": "Ouvrir le service assistance aux utilisateurs"
     }
   },
   "konnector_form": {
-- 
GitLab