Skip to content

Commit

Permalink
chore: [PE-996] Accessibility for CGN loading component (#6754)
Browse files Browse the repository at this point in the history
## Short description
This pull request is improving accessibility for
`CgnActivationLoadingScreen` to its loading state

## List of changes proposed in this pull request
- Added a `useRef` hook and `useOnFirstRender` to set accessibility
focus on the `SafeAreaView` component when the `LoadingComponent` is
first rendered

## How to test
- Using a real device 📱, start the `CGN` card onboarding
- Turn on the TalkBack accessibility tool
- Press on `Attiva Carta Giovani Nazionale`
- Ensure that, when the loading state is appearing, the screen reader is
now reading the loading state
  • Loading branch information
LeleDallas authored Feb 28, 2025
1 parent e88f105 commit c72ba19
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { StyleSheet, View } from "react-native";
import {
Body,
ContentWrapper,
H3,
IOStyles,
VSpacer
} from "@pagopa/io-app-design-system";
import { useRef } from "react";
import { StyleSheet, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { isCgnActivationLoading } from "../../store/reducers/activation";
import { cgnActivationCancel } from "../../store/actions/activation";
import { OperationResultScreenContent } from "../../../../../components/screens/OperationResultScreenContent";
import { LoadingIndicator } from "../../../../../components/ui/LoadingIndicator";
import I18n from "../../../../../i18n";
import { useIODispatch, useIOSelector } from "../../../../../store/hooks";
import { LoadingIndicator } from "../../../../../components/ui/LoadingIndicator";
import { OperationResultScreenContent } from "../../../../../components/screens/OperationResultScreenContent";
import { setAccessibilityFocus } from "../../../../../utils/accessibility";
import { useOnFirstRender } from "../../../../../utils/hooks/useOnFirstRender";
import { cgnActivationCancel } from "../../store/actions/activation";
import { isCgnActivationLoading } from "../../store/reducers/activation";

const styles = StyleSheet.create({
container: {
Expand All @@ -28,27 +31,35 @@ const styles = StyleSheet.create({
}
});

const LoadingComponent = () => (
<SafeAreaView style={styles.container}>
<ContentWrapper>
<View style={styles.content}>
<View
accessible={false}
accessibilityElementsHidden={true}
importantForAccessibility={"no-hide-descendants"}
>
<LoadingIndicator />
const LoadingComponent = () => {
const ref = useRef<View>(null);

useOnFirstRender(() => {
setAccessibilityFocus(ref);
});

return (
<SafeAreaView style={styles.container} accessible ref={ref}>
<ContentWrapper>
<View style={styles.content}>
<View
accessible={false}
accessibilityElementsHidden={true}
importantForAccessibility={"no-hide-descendants"}
>
<LoadingIndicator />
</View>
<VSpacer size={24} />
<H3 style={styles.contentTitle}>
{I18n.t("bonus.cgn.activation.loading.caption")}
</H3>
<VSpacer size={24} />
<Body>{I18n.t("bonus.cgn.activation.loading.subCaption")}</Body>
</View>
<VSpacer size={24} />
<H3 style={styles.contentTitle}>
{I18n.t("bonus.cgn.activation.loading.caption")}
</H3>
<VSpacer size={24} />
<Body>{I18n.t("bonus.cgn.activation.loading.subCaption")}</Body>
</View>
</ContentWrapper>
</SafeAreaView>
);
</ContentWrapper>
</SafeAreaView>
);
};

const ErrorComponent = () => {
const dispatch = useIODispatch();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createStore } from "redux";
import I18n from "../../../../../../i18n";
import { applicationChangeState } from "../../../../../../store/actions/application";
import { Store } from "../../../../../../store/actions/types";
import { appReducer } from "../../../../../../store/reducers";
import { GlobalState } from "../../../../../../store/reducers/types";
import { renderScreenWithNavigationStoreContext } from "../../../../../../utils/testWrapper";
import CGN_ROUTES from "../../../navigation/routes";
import { cgnRequestActivation } from "../../../store/actions/activation";
import CgnActivationLoadingScreen from "../CgnActivationLoadingScreen";

const renderComponent = (store: Store) =>
renderScreenWithNavigationStoreContext<GlobalState>(
() => <CgnActivationLoadingScreen />,
CGN_ROUTES.ACTIVATION.LOADING,
{},
store
);

describe("CgnActivationLoadingScreen", () => {
it("renders LoadingComponent when isLoading is true", () => {
const globalState = appReducer(undefined, applicationChangeState("active"));
const store = createStore(appReducer, globalState as any);

const { getByText, getByA11yRole } = renderComponent(store);

store.dispatch(cgnRequestActivation());
expect(getByA11yRole("header")).toBeTruthy();
expect(
getByText(I18n.t("bonus.cgn.activation.loading.caption"))
).toBeTruthy();
expect(
getByText(I18n.t("bonus.cgn.activation.loading.subCaption"))
).toBeTruthy();
});
});

0 comments on commit c72ba19

Please sign in to comment.