teamdigitale/italia-app

View on GitHub
ts/features/pushNotifications/screens/OnboardingNotificationsInfoScreenConsent.tsx

Summary

Maintainability
C
1 day
Test Coverage
import React, { useCallback, useEffect, useMemo } from "react";
import { AppState, FlatList, View, Platform, StyleSheet } from "react-native";
import {
  Body,
  Divider,
  FooterWithButtons,
  H2,
  H6,
  IOStyles,
  IOVisualCostants,
  IconButton,
  ListItemInfo,
  VSpacer
} from "@pagopa/io-app-design-system";
import I18n from "../../../i18n";
import { useIODispatch, useIOSelector } from "../../../store/hooks";
import {
  checkNotificationPermissions,
  openSystemNotificationSettingsScreen
} from "../utils";
import {
  pushNotificationPreviewEnabledSelector,
  pushNotificationRemindersEnabledSelector
} from "../../../store/reducers/profile";
import { notificationsInfoScreenConsent } from "../store/actions/profileNotificationPermissions";
import {
  trackNotificationsOptInOpenSettings,
  trackNotificationsOptInReminderOnPermissionsOff,
  trackNotificationsOptInSkipSystemPermissions
} from "../analytics";

const styles = StyleSheet.create({
  footer: { paddingBottom: IOStyles.footer.paddingBottom },
  header: {
    alignSelf: "flex-end",
    flexDirection: "row",
    paddingBottom: 18,
    paddingRight: IOVisualCostants.appMarginDefault,
    paddingTop: 24
  },
  listContainer: {
    marginHorizontal: IOVisualCostants.appMarginDefault
  }
});

export const OnboardingNotificationsInfoScreenConsent = () => {
  const dispatch = useIODispatch();
  const remindersEnabled = useIOSelector(
    pushNotificationRemindersEnabledSelector
  );
  const previewEnabled = useIOSelector(pushNotificationPreviewEnabledSelector);

  const instructions = useMemo(
    () =>
      Platform.select<ReadonlyArray<ListItemInfo>>({
        ios: [
          {
            icon: "systemSettingsiOS",
            label: I18n.t("onboarding.infoConsent.instructions.label"),
            value: I18n.t("onboarding.infoConsent.instructions.ios.step1"),
            accessibilityLabel: I18n.t(
              "onboarding.infoConsent.instructions.ios.step1"
            )
          },
          {
            icon: "systemNotificationsInstructions",
            label: I18n.t("onboarding.infoConsent.instructions.label"),
            value: I18n.t("onboarding.infoConsent.instructions.ios.step2"),
            accessibilityLabel: I18n.t(
              "onboarding.infoConsent.instructions.ios.step2"
            )
          },
          {
            icon: "systemToggleInstructions",
            label: I18n.t("onboarding.infoConsent.instructions.label"),
            value: I18n.t("onboarding.infoConsent.instructions.ios.step3"),
            accessibilityLabel: I18n.t(
              "onboarding.infoConsent.instructions.ios.step3"
            )
          }
        ],
        android: [
          {
            icon: "systemSettingsAndroid",
            label: I18n.t("onboarding.infoConsent.instructions.label"),
            value: I18n.t("onboarding.infoConsent.instructions.android.step1"),
            accessibilityLabel: I18n.t(
              "onboarding.infoConsent.instructions.android.step1"
            )
          },
          {
            icon: "systemAppsAndroid",
            label: I18n.t("onboarding.infoConsent.instructions.label"),
            value: I18n.t("onboarding.infoConsent.instructions.android.step2"),
            accessibilityLabel: I18n.t(
              "onboarding.infoConsent.instructions.android.step2"
            )
          },
          {
            icon: "productIOAppBlueBg",
            label: I18n.t("onboarding.infoConsent.instructions.label"),
            value: I18n.t("onboarding.infoConsent.instructions.android.step3"),
            accessibilityLabel: I18n.t(
              "onboarding.infoConsent.instructions.android.step3"
            )
          },
          {
            icon: "systemNotificationsInstructions",
            label: I18n.t("onboarding.infoConsent.instructions.label"),
            value: I18n.t("onboarding.infoConsent.instructions.android.step4"),
            accessibilityLabel: I18n.t(
              "onboarding.infoConsent.instructions.android.step4"
            )
          },
          {
            icon: "systemToggleInstructions",
            label: I18n.t("onboarding.infoConsent.instructions.label"),
            value: I18n.t("onboarding.infoConsent.instructions.android.step5"),
            accessibilityLabel: I18n.t(
              "onboarding.infoConsent.instructions.android.step5"
            )
          }
        ]
      }),
    []
  );

  const closeModalAndScreen = useCallback(() => {
    dispatch(notificationsInfoScreenConsent());
  }, [dispatch]);

  useEffect(() => {
    const subscription = AppState.addEventListener(
      "change",
      async nextAppState => {
        if (nextAppState === "active") {
          const authorizationStatus = await checkNotificationPermissions();

          if (authorizationStatus) {
            closeModalAndScreen();
          }
        }
      }
    );

    return () => {
      subscription.remove();
    };
  }, [closeModalAndScreen]);

  const goNext = useCallback(() => {
    // When this code executes, we know for sure that system notifications permissions are disabled,
    // otherwise the component would either have been skipped by the saga or it would have automatically
    // handled the given permission using the AppState listener (registered on the useEffect)
    trackNotificationsOptInSkipSystemPermissions();

    if (remindersEnabled || previewEnabled) {
      trackNotificationsOptInReminderOnPermissionsOff();
    }

    closeModalAndScreen();
  }, [closeModalAndScreen, previewEnabled, remindersEnabled]);

  const openSettings = useCallback(() => {
    trackNotificationsOptInOpenSettings();
    openSystemNotificationSettingsScreen();
  }, []);

  const ListHeader = (
    <View>
      <H2>{I18n.t("onboarding.infoConsent.title")}</H2>
      <VSpacer size={16} />
      <Body>{I18n.t("onboarding.infoConsent.subTitle")}</Body>
      <VSpacer size={16} />
      <H6 color="grey-700">
        {I18n.t("onboarding.infoConsent.instructions.title")}
      </H6>
      <VSpacer size={8} />
    </View>
  );

  return (
    <>
      <View style={styles.header}>
        <IconButton
          icon="closeLarge"
          color="neutral"
          onPress={goNext}
          testID="continue-btn"
          accessibilityLabel={I18n.t("global.buttons.close")}
        />
      </View>
      <FlatList
        data={instructions}
        renderItem={({ item, index }) => (
          <ListItemInfo {...item} label={`${item.label} ${index + 1}`} />
        )}
        contentContainerStyle={styles.listContainer}
        ItemSeparatorComponent={() => <Divider />}
        ListHeaderComponent={ListHeader}
      />
      <View style={styles.footer}>
        <FooterWithButtons
          primary={{
            type: "Solid",
            buttonProps: {
              label: I18n.t("onboarding.infoConsent.openSettings"),
              onPress: openSettings,
              testID: "settings-btn"
            }
          }}
          type="SingleButton"
        />
      </View>
    </>
  );
};