From c72ba1935ee943656c42f72e394f26d5a9e4d578 Mon Sep 17 00:00:00 2001 From: Emanuele Dall'Ara <71103219+LeleDallas@users.noreply.github.com> Date: Fri, 28 Feb 2025 12:02:08 +0100 Subject: [PATCH 1/4] chore: [PE-996] Accessibility for CGN loading component (#6754) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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 --- .../activation/CgnActivationLoadingScreen.tsx | 61 +++++++++++-------- .../CgnActivationLoadingScreen.test.tsx | 36 +++++++++++ 2 files changed, 72 insertions(+), 25 deletions(-) create mode 100644 ts/features/bonus/cgn/screens/activation/__tests__/CgnActivationLoadingScreen.test.tsx diff --git a/ts/features/bonus/cgn/screens/activation/CgnActivationLoadingScreen.tsx b/ts/features/bonus/cgn/screens/activation/CgnActivationLoadingScreen.tsx index 4e93b7da99c..fe396c96bef 100644 --- a/ts/features/bonus/cgn/screens/activation/CgnActivationLoadingScreen.tsx +++ b/ts/features/bonus/cgn/screens/activation/CgnActivationLoadingScreen.tsx @@ -1,4 +1,3 @@ -import { StyleSheet, View } from "react-native"; import { Body, ContentWrapper, @@ -6,13 +5,17 @@ import { 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: { @@ -28,27 +31,35 @@ const styles = StyleSheet.create({ } }); -const LoadingComponent = () => ( - - - - - +const LoadingComponent = () => { + const ref = useRef(null); + + useOnFirstRender(() => { + setAccessibilityFocus(ref); + }); + + return ( + + + + + + + +

+ {I18n.t("bonus.cgn.activation.loading.caption")} +

+ + {I18n.t("bonus.cgn.activation.loading.subCaption")}
- -

- {I18n.t("bonus.cgn.activation.loading.caption")} -

- - {I18n.t("bonus.cgn.activation.loading.subCaption")} -
-
-
-); + + + ); +}; const ErrorComponent = () => { const dispatch = useIODispatch(); diff --git a/ts/features/bonus/cgn/screens/activation/__tests__/CgnActivationLoadingScreen.test.tsx b/ts/features/bonus/cgn/screens/activation/__tests__/CgnActivationLoadingScreen.test.tsx new file mode 100644 index 00000000000..57216f2bd96 --- /dev/null +++ b/ts/features/bonus/cgn/screens/activation/__tests__/CgnActivationLoadingScreen.test.tsx @@ -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( + () => , + 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(); + }); +}); From a49b20e1e5315c826dda74f9be8746a3e7247e16 Mon Sep 17 00:00:00 2001 From: Emanuele Dall'Ara <71103219+LeleDallas@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:32:06 +0100 Subject: [PATCH 2/4] feat: [PE-988,PE-919,IOBP-1193] CGN merchants swipe back, `IOListViewWithLargeHeader ` (#6764) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Short description This pull request introduces a new `IOListViewWithLargeHeader` component and applies it to the CGN merchants screen. The primary goal is to resolve a swipe-back issue affecting this screen. > [!NOTE] > This PR depends on https://github.com/pagopa/io-app-design-system/pull/417 > Otherwise you will see the Tabs not aligned... > [!TIP] > Design System has been updated to `v5.0.3`, addressing the accessibility (`a11y`) issue with `IOScroll` header visibility
Key Features of IOListViewWithLargeHeader ## Key Features of `IOListViewWithLargeHeader` This component provides a structured flat list with a large header, supporting lists and additional UI elements. It is designed to be reusable across different screens that require a list-based layout with a header. ### Props and Their Functionality (List & Data Handling - Refresh & Loading Behavior) - `data (Required)`: The array of items that will be displayed in the scrollable list. When empty, the `listEmptyComponent` is displayed as a fallback; - `renderItem (Required)`: A function that takes an item and its index as arguments and returns a `JSX` element to render each list item; - `keyExtractor (Required)`: Used to extract a unique key for a given item at the specified index. Key is used for caching and as the react key to track item re-ordering; - `ListEmptyComponent (Optional)`: Defines a fallback component shown when data is empty. Useful for displaying "No items available" messages or placeholders; - `ListHeaderComponent (Optional)`: Allows adding a custom component before the list items (e.g., filters, introductory text); - `ListFooterComponent (Optional)`: Allows adding a custom component at the end of the list (e.g., buttons, summary info); - `refreshControlProps (Required)`: Manages pull-to-refresh behavior, allowing users to refresh the list contents. Uses React Native’s `RefreshControl` props; `skeleton (Optional)`: A loading skeleton displayed while `refreshControlProps.refreshing` is `true`. Helps improve the user experience by showing a placeholder instead of a blank screen.
___ ## List of changes proposed in this pull request - Introduced a new `IOListViewWithLargeHeader` component to handle large headers with lists, including props for customization and rendering items - Refactored the categories list screen to use the new `IOListViewWithLargeHeader` component - Updated the categories selection screen to use state management for tab selection ### Minor Changes: - Added a `count` prop to customize the number of skeleton items displayed, providing better flexibility for loading states ## How to test Describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. ## Preview | Design System | CGN |CGN Swipe action| |--------|--------|--------| |