diff --git a/locales/en/bottomsheets/ciePin.md b/locales/en/bottomsheets/ciePin.md new file mode 100644 index 00000000000..6df7e2b07e9 --- /dev/null +++ b/locales/en/bottomsheets/ciePin.md @@ -0,0 +1,5 @@ +The PIN code consists of 8 digits: +• the first 4 digits you received at the registry office; +• the last 4 digits you received at home, along with your electronic ID card. + +**Please enter them following this order.** \ No newline at end of file diff --git a/locales/en/help/ciePinHelpBody.md b/locales/en/help/ciePinHelpBody.md new file mode 100644 index 00000000000..575b8a2159d --- /dev/null +++ b/locales/en/help/ciePinHelpBody.md @@ -0,0 +1,6 @@ +The **PIN** code consists of 8 digits: +• the first 4 digits you received at the registry office; +• the last 4 digits you received at home, along with your electronic ID card. + +Please enter them following this order. +The PUK code is needed to unlock your **PIN**, in case of 3 wrong attempts. **PUK** consists of 8 digits and it's issued along with the **PIN**. diff --git a/locales/en/index.yml b/locales/en/index.yml index 50e654881fa..541fbb231a1 100644 --- a/locales/en/index.yml +++ b/locales/en/index.yml @@ -495,8 +495,12 @@ authentication: incorrectCiePinContent1: For your security, you can try entering the card PIN no more than three times. Then you will have to unlock the card by entering the PUK. incorrectCiePinContent2: Keep in mind that the PIN code of your Electronic Identity Card (CIE) is composed of 8 digits. Four digits that were given to you at the registry office and another four digits that were sent to you at home, along with the card. alert: Are you sure you want to go back? + subtitleHelp: The PIN code consists of 8 digits. + subtitleCTA: Where can I find it? + bottomSheetCTA: Did you forget your PIN? contextualHelpTitle: Where can I find my PIN and PUK? - contextualHelpBody: "The **PIN** code consists of 8 digits: \n\n- the first 4 digits you received at the registry office;\n- the last 4 digits you received at home, along with your electronic ID card.\n\nPlease enter them following this order.\n\n The **PUK** code is needed to unlock your PIN, in case of 3 wrong attempts. PUK consists of 8 digits and it's issued along with the PIN.\n\n[Did you forget your PIN/PUK?](https://www.cartaidentita.interno.gov.it/richiesta-di-ristampa/)" + contextualHelpBody: !include help/ciePinHelpBody.md + contextualHelpCTA: Did you forget your PIN/PUK? pinTempLocked: header: Login with CIE title: Card temporarily locked @@ -1482,6 +1486,10 @@ instabug: descriptionChat: "Only if you want to **reopen a past report**, to request additional information or add details, click below." buttonChat: Reopen a report assistanceWorkHours: IO assistance is available on Mon-Fri from 8.00 to 20.00; on Sat-Sun and holidays from 8.00 to 13.00 +bottomSheets: + ciePin: + title: "Where can I find my PIN?" + content: !include bottomsheets/ciePin.md faq: 1: title: "What is SPID?" diff --git a/locales/it/bottomsheets/ciePin.md b/locales/it/bottomsheets/ciePin.md new file mode 100644 index 00000000000..fb352930c1a --- /dev/null +++ b/locales/it/bottomsheets/ciePin.md @@ -0,0 +1,5 @@ +Il codice PIN è composto da 8 cifre: +• le prime 4 cifre ti sono state consegnate all’anagrafe; +• le ultime 4 cifre ti sono state spedite a casa, insieme alla carta d’identità elettronica. + +**Mettile insieme e inseriscile in quest’ordine.** \ No newline at end of file diff --git a/locales/it/help/ciePinHelpBody.md b/locales/it/help/ciePinHelpBody.md new file mode 100644 index 00000000000..12dc1b1e477 --- /dev/null +++ b/locales/it/help/ciePinHelpBody.md @@ -0,0 +1,6 @@ +Il codice **PIN** è composto da 8 cifre: +• le prime 4 cifre ti sono state consegnate all'anagrafe; +• le ultime 4 cifre ti sono state spedite a casa, insieme alla carta d'identità elettronica. + +Mettile insieme e inseriscile in quest'ordine. +Il codice PUK è necessario invece per sbloccare il **PIN** a seguito di tre tentativi errati. È composto da 8 cifre, e viene rilasciato insieme al **PIN**. \ No newline at end of file diff --git a/locales/it/index.yml b/locales/it/index.yml index a26b22b2813..8bc476f0534 100644 --- a/locales/it/index.yml +++ b/locales/it/index.yml @@ -505,8 +505,12 @@ authentication: incorrectCiePinContent1: Per la tua sicurezza puoi provare ad inserire il PIN della carta non più di tre volte. Poi dovrai sbloccare la carta inserendo il PUK. incorrectCiePinContent2: Ricorda che il codice PIN della tua Carta d'Identità Elettronica (CIE) è composto da 8 cifre. Quattro cifre che ti sono state consegnate all'anagrafe e altre quattro cifre che ti sono state spedite a casa, insieme alla carta. alert: Vuoi davvero tornare indietro? + subtitleHelp: Il PIN è un codice di 8 cifre. + subtitleCTA: Dove lo trovo? + bottomSheetCTA: Hai dimenticato il PIN? contextualHelpTitle: Dove trovo i codici PIN e PUK? - contextualHelpBody: "Il codice **PIN** è composto da 8 cifre: \n\n- le prime 4 cifre ti sono state consegnate all'anagrafe;\n- le ultime 4 cifre ti sono state spedite a casa, insieme alla carta d'identità elettronica. \n\nMettile insieme e inseriscile in quest'ordine.\n\n Il codice **PUK** è necessario invece per sbloccare il PIN a seguito di tre tentativi errati. È composto da 8 cifre, e viene rilasciato insieme al PIN. \n\n[Hai dimenticato il PIN/PUK?](https://www.cartaidentita.interno.gov.it/richiesta-di-ristampa/)" + contextualHelpBody: !include help/ciePinHelpBody.md + contextualHelpCTA: Hai dimenticato il PIN/PUK? pinTempLocked: header: Entra con CIE title: Carta temporaneamente bloccata @@ -1512,6 +1516,10 @@ instabug: descriptionChat: "Solo se vuoi **riaprire una segnalazione passata**, per chiedere informazioni aggiuntive o aggiungere dettagli, clicca qui sotto." buttonChat: Riapri una segnalazione assistanceWorkHours: L'assistenza di IO è disponibile dal lunedì al venerdì dalle ore 8.00 alle 20.00; sabato, domenica e giorni festivi dalle ore 8.00 alle 13.00 +bottomSheets: + ciePin: + title: Dove trovo il mio PIN? + content: !include bottomsheets/ciePin.md faq: 1: title: "Cos'è SPID?" diff --git a/ts/components/screens/ScreenContentHeader.tsx b/ts/components/screens/ScreenContentHeader.tsx index 56dffb3d72d..aac05e60f1d 100644 --- a/ts/components/screens/ScreenContentHeader.tsx +++ b/ts/components/screens/ScreenContentHeader.tsx @@ -19,6 +19,7 @@ type Props = Readonly<{ icon?: ImageSourcePropType; iconFont?: IconProps; subtitle?: string; + subtitleLink?: JSX.Element; dark?: boolean; dynamicHeight?: Animated.AnimatedInterpolation; }>; @@ -79,7 +80,7 @@ export class ScreenContentHeader extends React.PureComponent { } public render() { - const { subtitle, dark, icon, iconFont } = this.props; + const { subtitle, subtitleLink, dark, icon, iconFont } = this.props; return ( @@ -100,6 +101,7 @@ export class ScreenContentHeader extends React.PureComponent { {subtitle && ( {subtitle} + {subtitleLink} )} diff --git a/ts/screens/authentication/cie/CiePinScreen.tsx b/ts/screens/authentication/cie/CiePinScreen.tsx index 80e5447d994..d0779acae5c 100644 --- a/ts/screens/authentication/cie/CiePinScreen.tsx +++ b/ts/screens/authentication/cie/CiePinScreen.tsx @@ -1,6 +1,12 @@ import { Millisecond } from "italia-ts-commons/lib/units"; import { View } from "native-base"; -import * as React from "react"; +import React, { + useState, + useEffect, + useRef, + useContext, + useCallback +} from "react"; import { Keyboard, KeyboardAvoidingView, @@ -8,18 +14,17 @@ import { ScrollView, StyleSheet } from "react-native"; -import { NavigationInjectedProps } from "react-navigation"; +import { NavigationContext, NavigationInjectedProps } from "react-navigation"; import { connect } from "react-redux"; import AdviceComponent from "../../../components/AdviceComponent"; import CieRequestAuthenticationOverlay from "../../../components/cie/CieRequestAuthenticationOverlay"; import CiePinpad from "../../../components/CiePinpad"; -import { withLightModalContext } from "../../../components/helpers/withLightModalContext"; import { ScreenContentHeader } from "../../../components/screens/ScreenContentHeader"; import TopScreenComponent from "../../../components/screens/TopScreenComponent"; import FooterWithButtons from "../../../components/ui/FooterWithButtons"; import { BottomTopAnimation, - LightModalContextInterface + LightModalContext } from "../../../components/ui/LightModal"; import I18n from "../../../i18n"; import ROUTES from "../../../navigation/routes"; @@ -27,161 +32,173 @@ import { nfcIsEnabled } from "../../../store/actions/cie"; import { Dispatch, ReduxProps } from "../../../store/actions/types"; import variables from "../../../theme/variables"; import { setAccessibilityFocus } from "../../../utils/accessibility"; -import Markdown from "../../../components/ui/Markdown"; + import { isIos } from "../../../utils/platform"; +import { useIOBottomSheet } from "../../../utils/bottomSheet"; +import { openWebUrl } from "../../../utils/url"; +import { Link } from "../../../components/core/typography/Link"; +import Markdown from "../../../components/ui/Markdown"; +import ButtonDefaultOpacity from "../../../components/ButtonDefaultOpacity"; +import { IOColors } from "../../../components/core/variables/IOColors"; + +const mapDispatchToProps = (dispatch: Dispatch) => ({ + requestNfcEnabledCheck: () => dispatch(nfcIsEnabled.request()) +}); type Props = ReduxProps & ReturnType & - NavigationInjectedProps & - LightModalContextInterface; - -type State = Readonly<{ - pin: string; - url?: string; -}>; + NavigationInjectedProps; const styles = StyleSheet.create({ container: { flex: 1, paddingHorizontal: variables.contentPadding + }, + bsLinkButton: { + paddingRight: 0, + paddingLeft: 0, + marginVertical: 20, + height: 60, + backgroundColor: IOColors.white } }); const CIE_PIN_LENGTH = 8; +const FORGOT_PIN_PAGE_URL = + "https://www.cartaidentita.interno.gov.it/richiesta-di-ristampa/"; -/** - * A screen that allow the user to insert the Cie PIN. - */ -class CiePinScreen extends React.PureComponent { - private continueButtonRef = React.createRef(); - private pinPadViewRef = React.createRef(); - constructor(props: Props) { - super(props); - this.state = { pin: "" }; - } +const getContextualHelp = () => ({ + title: I18n.t("authentication.cie.pin.contextualHelpTitle"), + body: () => ( + {I18n.t("authentication.cie.pin.contextualHelpBody")} + ) +}); +const onOpenForgotPinPage = () => openWebUrl(FORGOT_PIN_PAGE_URL); + +const CiePinScreen: React.FC = props => { + const { showAnimatedModal, hideModal } = useContext(LightModalContext); + const { navigate } = useContext(NavigationContext); + const [pin, setPin] = useState(""); + const continueButtonRef = useRef(null); + const pinPadViewRef = useRef(null); + + useEffect(() => { + if (pin.length === CIE_PIN_LENGTH) { + setAccessibilityFocus(continueButtonRef, 100 as Millisecond); + } + }, [pin]); - private getContextualHelp = () => ({ - title: I18n.t("authentication.cie.pin.contextualHelpTitle"), - body: () => ( - {I18n.t("authentication.cie.pin.contextualHelpBody")} - ) - }); - - private onProceedToCardReaderScreen = (url: string) => { - const ciePin = this.state.pin; - this.setState({ url, pin: "" }, () => { - this.props.navigation.navigate({ - routeName: ROUTES.CIE_CARD_READER_SCREEN, - params: { ciePin, authorizationUri: url } - }); - this.props.hideModal(); + const { present } = useIOBottomSheet( + + {I18n.t("bottomSheets.ciePin.content")} + + {I18n.t("bottomSheets.ciePin.title")} + + , + I18n.t("bottomSheets.ciePin.title"), + 300 + ); + + const onProceedToCardReaderScreen = async (url: string) => { + setPin(""); + navigate({ + routeName: ROUTES.CIE_CARD_READER_SCREEN, + params: { + ciePin: pin, + authorizationUri: url + } }); + hideModal(); }; - private handleAuthenticationOverlayOnClose = () => { - // reset the pin if user abort process during loading - this.setState({ pin: "" }, this.props.hideModal); + const handleAuthenticationOverlayOnClose = () => { + setPin(""); + hideModal(); }; - private showModal = () => { - this.props.requestNfcEnabledCheck(); + const showModal = () => { + props.requestNfcEnabledCheck(); Keyboard.dismiss(); - const component = ( + showAnimatedModal( + onClose={handleAuthenticationOverlayOnClose} + onSuccess={onProceedToCardReaderScreen} + />, + BottomTopAnimation ); - this.props.showAnimatedModal(component, BottomTopAnimation); }; - // Method called when the PIN changes - public handelOnPinChanged = (pin: string) => { - this.setState( - { - pin - }, - () => { - // set focus on continue button when the pin input is full filled - if (this.state.pin.length === CIE_PIN_LENGTH) { - setAccessibilityFocus(this.continueButtonRef, 100 as Millisecond); - } - } - ); - }; + const doSetAccessibilityFocus = useCallback(() => { + setAccessibilityFocus(pinPadViewRef, 100 as Millisecond); + }, [pinPadViewRef]); - public render() { - return ( - { - setAccessibilityFocus(this.pinPadViewRef, 100 as Millisecond); - }} - goBack={true} - contextualHelp={this.getContextualHelp()} - headerTitle={I18n.t("authentication.cie.pin.pinCardHeader")} - > - - + + + {I18n.t("authentication.cie.pin.subtitleCTA")} + + } + /> + + + + - - - - {isIos && ( - - )} - + {isIos && ( - - - {this.state.pin.length === CIE_PIN_LENGTH && ( - + - )} - + + {pin.length === CIE_PIN_LENGTH && ( + - - ); - } -} - -const mapDispatchToProps = (dispatch: Dispatch) => ({ - requestNfcEnabledCheck: () => dispatch(nfcIsEnabled.request()) -}); + )} + + + ); +}; -// TODO: solve bug: for a while the pinpad is displayed again when it succeeded - it occurs also during payments after a loading -export default connect( - null, - mapDispatchToProps -)(withLightModalContext(CiePinScreen)); +export default connect(null, mapDispatchToProps)(CiePinScreen);