Skip to content

Commit

Permalink
feat: [#172526356] Adds Screen to explain why CIE login is not availa…
Browse files Browse the repository at this point in the history
…ble (#1769)

* Added information screen to explain why cie login is not supported

* Fixed style and adds Android check to show further informations

* fix lint error

* change the icons on list

* [#172526356] UI of the information in a separated component

* Fix in typos and buttons inverted on landing

* Adds conditional order of the 2 buttons to login

* Fixes on reducer and components

* Minor edit on texts

Co-authored-by: Matteo Boschi <[email protected]>
  • Loading branch information
CrisTofani and Undermaken authored Jun 25, 2020
1 parent f222634 commit 5bc9437
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 22 deletions.
1 change: 1 addition & 0 deletions locales/en/cie/cieNotSupported.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
To login you need a device with NFC technology and the operating system with the minimum requirements (**iOS** devices are not yet compatible but will become compatible with the next updates).
1 change: 1 addition & 0 deletions locales/en/cie/cieNotSupported_android.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Specifically, the cases in which you **cannot** access with an Electronic Identity Card (CIE) on your Android device are:
6 changes: 6 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,12 @@ spid:
line2: Insert your email address to enable it.
authentication:
landing:
cie_unsupported:
title: Login with CIE unavailable
body: !include cie/cieNotSupported.md
android_desc: !include cie/cieNotSupported_android.md
os_version_unsupported: your operating system does not have a version compatible with CIE authentication
nfc_incompatible: your device does not have an NFC antenna compatible with CIE authentication
contentTitleCie: Don't have SPID or CIE?
cie_information_request: !include cie.md
spid_or_cie: To use IO you must have one of these digital tools, which certify your identity.
Expand Down
1 change: 1 addition & 0 deletions locales/it/cie/cieNotSupported.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Per effettuare il login è necessario avere un dispositivo con tecnologia NFC e il sistema operativo con i requisiti minimi necessari (i dispositivi **iOS** non sono ancora compatibili ma a breve lo diventeranno con i prossimi aggiornamenti).
1 change: 1 addition & 0 deletions locales/it/cie/cieNotSupported_android.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Nello specifico, i casi in cui **non** è possibile accedere con Carta di Identità Elettronica (CIE) su dispositivo Android sono:
6 changes: 6 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,12 @@ spid:
line2: Inserisci la tua email per attivarla.
authentication:
landing:
cie_unsupported:
title: Accesso con CIE non disponibile
body: !include cie/cieNotSupported.md
android_desc: !include cie/cieNotSupported_android.md
os_version_unsupported: il tuo sistema operativo non ha una versione compatibile con l'autenticazione tramite CIE
nfc_incompatible: il tuo dispositivo non ha una antenna NFC compatibile con l'autenticazione tramite CIE
contentTitleCie: Non hai SPID o la CIE?
cie_information_request: !include cie.md
spid_or_cie: Per utilizzare IO devi dotarti di uno di questi strumenti digitali, che certificano in maniera certa la tua identità.
Expand Down
73 changes: 73 additions & 0 deletions ts/components/cie/CieNotSupported.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Body, List, ListItem, Text, View } from "native-base";
import * as React from "react";
import { Platform } from "react-native";
import I18n from "../../i18n";
import customVariables from "../../theme/variables";
import IconFont from "../ui/IconFont";
import Markdown from "../ui/Markdown";

type Props = {
hasCieApiLevelSupport: boolean;
hasCieNFCFeature: boolean;
};

const ICON_SIZE = 16;

const CieNotSupported: React.FunctionComponent<Props> = props => {
return (
<React.Fragment>
<Markdown>
{I18n.t("authentication.landing.cie_unsupported.body")}
</Markdown>
{Platform.OS === "android" && (
<React.Fragment>
<View spacer={true} />
<Markdown>
{I18n.t("authentication.landing.cie_unsupported.android_desc")}
</Markdown>
<View spacer={true} extralarge={true} />
<List>
<ListItem>
<IconFont
name="io-tick-big"
size={ICON_SIZE}
color={
props.hasCieApiLevelSupport
? customVariables.brandLightGray
: customVariables.contentPrimaryBackground
}
/>
<Body>
<Text>
{I18n.t(
"authentication.landing.cie_unsupported.os_version_unsupported"
)}
</Text>
</Body>
</ListItem>
<ListItem>
<IconFont
name="io-tick-big"
size={ICON_SIZE}
color={
props.hasCieNFCFeature
? customVariables.brandLightGray
: customVariables.contentPrimaryBackground
}
/>
<Body>
<Text>
{I18n.t(
"authentication.landing.cie_unsupported.nfc_incompatible"
)}
</Text>
</Body>
</ListItem>
</List>
</React.Fragment>
)}
</React.Fragment>
);
};

export default CieNotSupported;
45 changes: 44 additions & 1 deletion ts/sagas/cie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import cieManager from "@pagopa/react-native-cie";
import { Millisecond } from "italia-ts-commons/lib/units";
import { SagaIterator } from "redux-saga";
import { call, put, takeLatest } from "redux-saga/effects";
import { cieIsSupported, nfcIsEnabled } from "../store/actions/cie";
import {
cieIsSupported,
hasApiLevelSupport,
hasNFCFeature,
nfcIsEnabled
} from "../store/actions/cie";
import { SagaCallReturnType } from "../types/utils";
import { startTimer } from "../utils/timer";

Expand All @@ -11,6 +16,10 @@ export function* watchCieAuthenticationSaga(): SagaIterator {
yield takeLatest(nfcIsEnabled.request, checkNfcEnablementSaga);
// check if the device is compliant with CIE authentication
yield call(checkCieAvailabilitySaga, cieManager.isCIEAuthenticationSupported);
// check if the device has the API Level compliant with CIE authentication
yield call(checkHasApiLevelSupportSaga, cieManager.hasApiLevelSupport);
// check if the device has the NFC Feature to support CIE authentication
yield call(checkHasNfcFeatureSaga, cieManager.hasNFCFeature);
}

// stop cie manager to listen nfc tags
Expand All @@ -22,6 +31,40 @@ export function* stopCieManager(): SagaIterator {
}
}

/**
* check if the device has the API Level to support CIE authentication
* see https://github.com/pagopa/io-cie-android-sdk/blob/29cc1165bbd3d90d61239369f22ec78b2e4c8f6c/index.js#L155
*/
export function* checkHasApiLevelSupportSaga(
hasApiLevelSupported: typeof cieManager["hasApiLevelSupport"]
): SagaIterator {
try {
const response: SagaCallReturnType<
typeof hasApiLevelSupported
> = yield call(hasApiLevelSupported);
yield put(hasApiLevelSupport.success(response));
} catch (e) {
yield put(hasApiLevelSupport.failure(new Error(e)));
}
}

/**
* check if the device has the NFC Feature to support CIE authentication
* see https://github.com/pagopa/io-cie-android-sdk/blob/29cc1165bbd3d90d61239369f22ec78b2e4c8f6c/index.js#L169
*/
export function* checkHasNfcFeatureSaga(
hasNfcFeatureSupported: typeof cieManager["hasNFCFeature"]
): SagaIterator {
try {
const response: SagaCallReturnType<
typeof hasNfcFeatureSupported
> = yield call(hasNfcFeatureSupported);
yield put(hasNFCFeature.success(response));
} catch (e) {
yield put(hasNFCFeature.failure(new Error(e)));
}
}

/**
* check if the device is compatible with CIE authentication
* see https://github.com/pagopa/io-cie-android-sdk/blob/29cc1165bbd3d90d61239369f22ec78b2e4c8f6c/index.js#L125
Expand Down
106 changes: 85 additions & 21 deletions ts/screens/authentication/LandingScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import { StyleSheet } from "react-native";
import { NavigationInjectedProps } from "react-navigation";
import { connect } from "react-redux";
import ButtonDefaultOpacity from "../../components/ButtonDefaultOpacity";
import CieNotSupported from "../../components/cie/CieNotSupported";
import { ContextualHelp } from "../../components/ContextualHelp";
import { DevScreenButton } from "../../components/DevScreenButton";
import { withLightModalContext } from "../../components/helpers/withLightModalContext";
import { HorizontalScroll } from "../../components/HorizontalScroll";
import { LandingCardComponent } from "../../components/LandingCardComponent";
import BaseScreenComponent, {
ContextualHelpPropsMarkdown
} from "../../components/screens/BaseScreenComponent";
import IconFont from "../../components/ui/IconFont";
import { LightModalContextInterface } from "../../components/ui/LightModal";
import I18n from "../../i18n";
import { IdentityProvider } from "../../models/IdentityProvider";
import ROUTES from "../../navigation/routes";
Expand All @@ -25,14 +29,19 @@ import {
} from "../../store/actions/authentication";
import { Dispatch } from "../../store/actions/types";
import { isSessionExpiredSelector } from "../../store/reducers/authentication";
import { isCieSupportedSelector } from "../../store/reducers/cie";
import {
hasApiLevelSupportSelector,
hasNFCFeatureSelector,
isCieSupportedSelector
} from "../../store/reducers/cie";
import { GlobalState } from "../../store/reducers/types";
import variables from "../../theme/variables";
import { ComponentProps } from "../../types/react";
import { isDevEnv } from "../../utils/environment";
import { showToast } from "../../utils/showToast";

type Props = NavigationInjectedProps &
LightModalContextInterface &
ReturnType<typeof mapStateToProps> &
ReturnType<typeof mapDispatchToProps>;

Expand Down Expand Up @@ -89,6 +98,9 @@ const styles = StyleSheet.create({
},
flex: {
flex: 1
},
noCie: {
opacity: 0.35
}
});

Expand Down Expand Up @@ -120,15 +132,34 @@ class LandingScreen extends React.PureComponent<Props> {
}
}

private openUnsupportedCIEModal = () => {
this.props.showAnimatedModal(
<ContextualHelp
onClose={this.props.hideModal}
title={I18n.t("authentication.landing.cie_unsupported.title")}
body={() => (
<CieNotSupported
hasCieApiLevelSupport={this.props.hasCieApiLevelSupport}
hasCieNFCFeature={this.props.hasCieNFCFeature}
/>
)}
/>
);
};

private navigateToMarkdown = () =>
this.props.navigation.navigate(ROUTES.MARKDOWN);

private navigateToIdpSelection = () =>
this.props.navigation.navigate(ROUTES.AUTHENTICATION_IDP_SELECTION);

private navigateToCiePinScreen = () => {
this.props.dispatchIdpCieSelected();
this.props.navigation.navigate(ROUTES.CIE_PIN_SCREEN);
if (this.props.isCieSupported) {
this.props.dispatchIdpCieSelected();
this.props.navigation.navigate(ROUTES.CIE_PIN_SCREEN);
} else {
this.openUnsupportedCIEModal();
}
};

private navigateToSpidCieInformationRequest = () =>
Expand Down Expand Up @@ -162,28 +193,57 @@ class LandingScreen extends React.PureComponent<Props> {
</Content>

<View footer={true}>
{this.props.isCieSupported && (
<ButtonDefaultOpacity
block={true}
primary={true}
iconLeft={true}
onPress={this.navigateToCiePinScreen}
testID={"landing-button-login-cie"}
>
<IconFont name={"io-cie"} color={variables.colorWhite} />
<Text>{I18n.t("authentication.landing.loginCie")}</Text>
</ButtonDefaultOpacity>
)}
<ButtonDefaultOpacity
block={true}
primary={true}
iconLeft={true}
onPress={
this.props.isCieSupported
? this.navigateToCiePinScreen
: this.navigateToIdpSelection
}
testID={
this.props.isCieSupported
? "landing-button-login-cie"
: "landing-button-login-spid"
}
>
<IconFont
name={this.props.isCieSupported ? "io-cie" : "io-profilo"}
color={variables.colorWhite}
/>
<Text>
{this.props.isCieSupported
? I18n.t("authentication.landing.loginCie")
: I18n.t("authentication.landing.loginSpid")}
</Text>
</ButtonDefaultOpacity>
<View spacer={true} />
<ButtonDefaultOpacity
style={!this.props.isCieSupported ? styles.noCie : undefined}
block={true}
primary={true}
iconLeft={true}
onPress={this.navigateToIdpSelection}
testID={"landing-button-login-spid"}
onPress={
this.props.isCieSupported
? this.navigateToIdpSelection
: this.navigateToCiePinScreen
}
testID={
this.props.isCieSupported
? "landing-button-login-spid"
: "landing-button-login-cie"
}
>
<IconFont name={"io-profilo"} color={variables.colorWhite} />
<Text>{I18n.t("authentication.landing.loginSpid")}</Text>
<IconFont
name={this.props.isCieSupported ? "io-profilo" : "io-cie"}
color={variables.colorWhite}
/>
<Text>
{this.props.isCieSupported
? I18n.t("authentication.landing.loginSpid")
: I18n.t("authentication.landing.loginCie")}
</Text>
</ButtonDefaultOpacity>
<View spacer={true} />
<ButtonDefaultOpacity
Expand All @@ -206,9 +266,13 @@ class LandingScreen extends React.PureComponent<Props> {

const mapStateToProps = (state: GlobalState) => {
const isCIEAuthenticationSupported = isCieSupportedSelector(state);
const hasApiLevelSupport = hasApiLevelSupportSelector(state);
const hasNFCFeature = hasNFCFeatureSelector(state);
return {
isSessionExpired: isSessionExpiredSelector(state),
isCieSupported: pot.getOrElse(isCIEAuthenticationSupported, false)
isCieSupported: pot.getOrElse(isCIEAuthenticationSupported, false),
hasCieApiLevelSupport: pot.getOrElse(hasApiLevelSupport, false),
hasCieNFCFeature: pot.getOrElse(hasNFCFeature, false)
};
};

Expand All @@ -220,4 +284,4 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
export default connect(
mapStateToProps,
mapDispatchToProps
)(LandingScreen);
)(withLightModalContext(LandingScreen));
14 changes: 14 additions & 0 deletions ts/store/actions/cie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

import { ActionType, createAsyncAction } from "typesafe-actions";

export const hasApiLevelSupport = createAsyncAction(
"CIE_HAS_API_LEVEL_REQUEST",
"CIE_HAS_API_LEVEL_SUCCESS",
"CIE_HAS_API_LEVEL_FAILURE"
)<void, boolean, Error>();

export const hasNFCFeature = createAsyncAction(
"CIE_HAS_NFC_FEATURE_REQUEST",
"CIE_HAS_NFC_FEATURE_SUCCESS",
"CIE_HAS_NFC_FEATURE_FAILURE"
)<void, boolean, Error>();

export const cieIsSupported = createAsyncAction(
"CIE_IS_SUPPORTED_REQUEST",
"CIE_IS_SUPPORTED_SUCCESS",
Expand All @@ -23,6 +35,8 @@ export const updateReadingState = createAsyncAction(
)<void, string, Error>();

export type CieAuthenticationActions =
| ActionType<typeof hasApiLevelSupport>
| ActionType<typeof hasNFCFeature>
| ActionType<typeof cieIsSupported>
| ActionType<typeof nfcIsEnabled>
| ActionType<typeof updateReadingState>;
Loading

0 comments on commit 5bc9437

Please sign in to comment.