Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [IOPID-689] Email validation at startup #5264

Merged
merged 54 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e382d26
add new BE values and add business logic to integrate the email verif…
Ladirico Nov 2, 2023
12a30eb
fix a part of business logic
Ladirico Nov 3, 2023
2debae4
fix error on useeffect
Ladirico Nov 6, 2023
e199449
finish to implement the logic
Ladirico Nov 7, 2023
9285cba
fix optin screen accessibility label
Ladirico Nov 7, 2023
7e8137c
Merge branch 'master' into IOPID-991-app-integrazione-schermata-modif…
Ladirico Nov 8, 2023
85af66f
fix tsc error
Ladirico Nov 8, 2023
25bfcb3
Update locales/en/index.yml
Ladirico Nov 13, 2023
7a2b37f
Update locales/en/index.yml
Ladirico Nov 13, 2023
d6a4974
Update locales/en/index.yml
Ladirico Nov 13, 2023
5ec10e9
Merge branch 'master' into IOPID-991-app-integrazione-schermata-modif…
Ladirico Nov 13, 2023
24670ed
Merge branch 'master' into IOPID-991-app-integrazione-schermata-modif…
shadowsheep1 Nov 14, 2023
72a8156
chore: [IOPID-1015] Biometric refinement (#5141)
sabontech Nov 14, 2023
c096997
chore(release): 2.46.0-rc.3
Vangaorth Nov 14, 2023
c7866d2
fix: [IOBP-361] Fix ID Pay rules info bottom sheet in initiative deta…
mastro993 Nov 14, 2023
42b2ffb
finish to implement the logic
Ladirico Nov 7, 2023
8785150
Merge branch 'master' into IOPID-991-app-integrazione-schermata-modif…
Ladirico Nov 15, 2023
17ce950
fix bugs on navigation. Need to add comments and make some tests befo…
Ladirico Nov 17, 2023
9a7cfd8
change version of io-backend
Ladirico Nov 21, 2023
978311c
change error from alert to red text
Ladirico Nov 21, 2023
9ee1333
fix routing and logics
Ladirico Nov 22, 2023
6fddbe9
Merge branch 'master' into IOPID-991-app-integrazione-schermata-modif…
Ladirico Nov 22, 2023
aeb4b44
delete unsed import
Ladirico Nov 22, 2023
8bedbac
fix navigation on onboarding flow
Ladirico Nov 24, 2023
12f9006
Merge branch 'master' into IOPID-991-app-integrazione-schermata-modif…
Ladirico Nov 24, 2023
2d44f85
Start adding check email startup navigation
shadowsheep1 Nov 22, 2023
73e4747
Delete fixme
Ladirico Nov 24, 2023
0673745
Merge branch 'master' into IOPID-991-app-integrazione-schermata-modif…
shadowsheep1 Nov 27, 2023
9437cb9
chore: fix space in package.json
shadowsheep1 Nov 27, 2023
2351ba2
Merge branch 'IOPID-991-app-integrazione-schermata-modifica-email-nel…
shadowsheep1 Nov 27, 2023
99f306b
chore: add new data handling
shadowsheep1 Nov 27, 2023
baacefa
chore: Add email check redux state additional field
shadowsheep1 Nov 27, 2023
09aea03
chore: add some useCallback
shadowsheep1 Nov 27, 2023
6aca40e
chore: restore hideModal to its previous position
shadowsheep1 Nov 27, 2023
7bc0fe7
chore: renaming
shadowsheep1 Nov 27, 2023
7561026
chore: update translations
shadowsheep1 Nov 27, 2023
4b69d28
Merge branch 'master' into IOPID-689-check-email
shadowsheep1 Nov 28, 2023
93ddc91
chore: fix conflicts hell
shadowsheep1 Nov 28, 2023
eade78c
Merge branch 'master' into IOPID-689-check-email
shadowsheep1 Nov 28, 2023
dc73f78
Merge branch 'master' into IOPID-689-check-email
shadowsheep1 Nov 28, 2023
2142686
Merge branch 'master' into IOPID-689-check-email
shadowsheep1 Nov 29, 2023
49293e3
Merge branch 'master' into IOPID-689-check-email
shadowsheep1 Nov 29, 2023
ffaa819
Merge branch 'master' into IOPID-689-check-email
shadowsheep1 Nov 30, 2023
69cf452
fix: email check flow during first onboarding
shadowsheep1 Nov 30, 2023
738aa23
chore: refactor checkEmailSaga
shadowsheep1 Dec 1, 2023
6ec3db2
chore: Merge two email insert screens in a single one
shadowsheep1 Dec 1, 2023
41b57d8
Merge branch 'master' into IOPID-689-check-email
shadowsheep1 Dec 1, 2023
404f641
chore: wrap user data processing api with fl
shadowsheep1 Dec 1, 2023
db20fe3
chore: wrap user data processing api with fl
shadowsheep1 Dec 1, 2023
69d03c3
Merge branch 'IOPID-689-check-email' of https://github.com/pagopa/io-…
shadowsheep1 Dec 1, 2023
7ba5b75
Merge branch 'master' into IOPID-689-check-email
Ladirico Dec 4, 2023
7e4cc99
Merge branch 'master' into IOPID-689-check-email
Ladirico Dec 4, 2023
25e70cf
Merge branch 'master' into IOPID-689-check-email
Ladirico Dec 4, 2023
5c5a0bf
fix style on android
Ladirico Dec 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -749,17 +749,25 @@ authentication:
listitem3_4: recovery code
listitem3_5: to confirm the operation.
email:
cduModal:
cduScreens:
validateMail:
title: Email address not validated
subtitle: To continue using the app, you must validate your email address
editButton: Edit email address
validateButton: Validate email address
editMail:
header:
title: Configure IO
help:
body: To continue using the app, you must validate your email address.
emailAlreadyTaken:
title: Edit your email address
subtitleStart: This email address
subtitleEnd: seems to be already in use on IO. Please enter a different one to continue using the app.
editButton: Edit email address
header:
title: Configure IO
help:
body: This email address seems to be already in use on IO. Please enter a different one to continue using the app.
read:
title: Your email address
info: This is the email address associated to your SPID account. You can use in IO app a different email address, if you wish. To make operative the new email address, you will need to validate it by clicking on the link you will receive by email.
Expand Down
16 changes: 12 additions & 4 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -749,17 +749,25 @@ authentication:
listitem3_4: codice di ripristino
listitem3_5: per confermare l’operazione.
email:
cduModal:
cduScreens:
validateMail:
title: Indirizzo email non validato
title: Non hai confermato il tuo indirizzo email
subtitle: Per continuare a utilizzare l’app è necessario validare il tuo indirizzo email
editButton: Modifica email
validateButton: Valida email
editMail:
validateButton: Conferma email
header:
title: Configura IO
help:
body: Per continuare a utilizzare l’app è necessario validare il tuo indirizzo email.
emailAlreadyTaken:
title: Modifica la tua email
subtitleStart: Il tuo indirizzo email
subtitleEnd: risulta già in uso su IO, è necessario inserirne uno diverso per continuare a utilizzare l’app.
editButton: Modifica email
header:
title: Configura IO
help:
body: Il tuo indirizzo email risulta già in uso su IO, è necessario inserirne uno diverso per continuare a utilizzare l’app.
read:
title: Il tuo indirizzo email
info: Questo è l'indirizzo email che hai associato all'account SPID. Puoi usare in IO un indirizzo email diverso, se preferisci. Per rendere operativo il nuovo indirizzo, dovrai validarlo cliccando sul link che riceverai nella tua casella di posta elettronica.
Expand Down
22 changes: 17 additions & 5 deletions ts/components/NewRemindEmailValidationOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import I18n from "../i18n";
import {
acknowledgeOnEmailValidation,
profileLoadRequest,
setEmailCheckAtStartupFailure,
startEmailValidation
} from "../store/actions/profile";
import {
Expand Down Expand Up @@ -72,14 +73,17 @@ const NewRemindEmailValidationOverlay = (props: Props) => {
() => dispatch(startEmailValidation.request()),
[dispatch]
);

const acknowledgeEmail = useCallback(
() => dispatch(emailAcknowledged()),
[dispatch]
);

const reloadProfile = useCallback(
() => dispatch(profileLoadRequest()),
[dispatch]
);

const dispatchAcknowledgeOnEmailValidation = useCallback(
(maybeAcknowledged: O.Option<boolean>) =>
dispatch(acknowledgeOnEmailValidation(maybeAcknowledged)),
Expand Down Expand Up @@ -110,16 +114,24 @@ const NewRemindEmailValidationOverlay = (props: Props) => {

const handleSendEmailValidationButton = () => {
if (isEmailValidated) {
hideModal();
if (isOnboarding) {
// if the user is in the onboarding flow and the email il correctly validated,
// the email validation flow is finished
acknowledgeEmail();
hideModal();
} else {
hideModal();
NavigationService.navigate(ROUTES.PROFILE_NAVIGATOR, {
screen: ROUTES.PROFILE_DATA
});
if (
O.isSome(emailValidation.emailCheckAtStartupFailed) &&
emailValidation.emailCheckAtStartupFailed.value
) {
acknowledgeEmail();
dispatchAcknowledgeOnEmailValidation(O.none);
dispatch(setEmailCheckAtStartupFailure(O.none));
} else {
NavigationService.navigate(ROUTES.PROFILE_NAVIGATOR, {
screen: ROUTES.PROFILE_DATA
});
}
}
} else {
// send email validation only if it exists
Expand Down
7 changes: 7 additions & 0 deletions ts/navigation/AuthenticatedStackNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import ROUTES from "./routes";
import ServicesNavigator from "./ServicesNavigator";
import { MainTabNavigator } from "./TabNavigator";
import WalletNavigator from "./WalletNavigator";
import CheckEmailNavigator from "./CheckEmailNavigator";

const Stack = createStackNavigator<AppParamsList>();

Expand Down Expand Up @@ -108,6 +109,12 @@ const AuthenticatedStackNavigator = () => {
component={OnboardingNavigator}
/>

<Stack.Screen
name={ROUTES.CHECK_EMAIL}
options={hideHeaderOptions}
component={CheckEmailNavigator}
/>

<Stack.Screen
name={ROUTES.UNSUPPORTED_DEVICE}
options={hideHeaderOptions}
Expand Down
29 changes: 29 additions & 0 deletions ts/navigation/CheckEmailNavigator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createStackNavigator } from "@react-navigation/stack";
import * as React from "react";
import { isGestureEnabled } from "../utils/navigation";
import ValidateEmailScreen from "../screens/profile/mailCheck/ValidateEmailScreen";
import EmailAlreadyTakenScreen from "../screens/profile/mailCheck/EmailAlreadyTakenScreen";
import ROUTES from "./routes";

const Stack = createStackNavigator();
/**
* The onboarding related stack of screens of the application.
*/
const navigator = () => (
<Stack.Navigator
initialRouteName={ROUTES.CHECK_EMAIL_NOT_VERIFIED}
headerMode={"none"}
screenOptions={{ gestureEnabled: isGestureEnabled }}
>
<Stack.Screen
name={ROUTES.CHECK_EMAIL_NOT_VERIFIED}
component={ValidateEmailScreen}
/>
<Stack.Screen
name={ROUTES.CHECK_EMAIL_ALREADY_TAKEN}
component={EmailAlreadyTakenScreen}
/>
</Stack.Navigator>
);

export default navigator;
6 changes: 2 additions & 4 deletions ts/navigation/OnboardingNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import ServicePreferenceCompleteScreen from "../screens/onboarding/ServicePrefer
import { isGestureEnabled } from "../utils/navigation";
import MissingDevicePinScreen from "../screens/onboarding/biometric&securityChecks/MissingDevicePinScreen";
import MissingDeviceBiometricScreen from "../screens/onboarding/biometric&securityChecks/MissingDeviceBiometricScreen";
import NewOnboardingEmailInsertScreen from "../screens/onboarding/NewOnboardingEmailInsertScreen";
import { isNewCduFlow } from "../config";
import CduEmailInsertScreen from "../screens/profile/CduEmailInsertScreen";
import { OnboardingParamsList } from "./params/OnboardingParamsList";
import ROUTES from "./routes";

Expand Down Expand Up @@ -68,9 +68,7 @@ const navigator = () => (
<Stack.Screen
name={ROUTES.ONBOARDING_READ_EMAIL_SCREEN}
component={
isNewCduFlow
? NewOnboardingEmailInsertScreen
: OnboardingEmailReadScreen
isNewCduFlow ? CduEmailInsertScreen : OnboardingEmailReadScreen
}
/>
<Stack.Screen
Expand Down
4 changes: 2 additions & 2 deletions ts/navigation/ProfileNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { ContextualHelpPropsMarkdown } from "../components/screens/BaseScreenCom
import I18n from "../i18n";
import { IdPayCodePlayGround } from "../screens/profile/playgrounds/IdPayCodePlayground";
import { useStartSupportRequest } from "../hooks/useStartSupportRequest";
import NewEmailInsertScreen from "../screens/profile/NewEmailInsertScreen";
import CduEmailInsertScreen from "../screens/profile/CduEmailInsertScreen";
import { ProfileParamsList } from "./params/ProfileParamsList";
import ROUTES from "./routes";

Expand Down Expand Up @@ -163,7 +163,7 @@ const ProfileStackNavigator = () => {
headerShown: false
}}
name={ROUTES.INSERT_EMAIL_SCREEN}
component={isNewCduFlow ? NewEmailInsertScreen : EmailInsertScreen}
component={isNewCduFlow ? CduEmailInsertScreen : EmailInsertScreen}
/>
<Stack.Screen
options={{
Expand Down
2 changes: 2 additions & 0 deletions ts/navigation/params/AppParamsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,14 @@ import { OnboardingParamsList } from "./OnboardingParamsList";
import { ProfileParamsList } from "./ProfileParamsList";
import { ServicesParamsList } from "./ServicesParamsList";
import { WalletParamsList } from "./WalletParamsList";
import { CheckEmailParamsList } from "./CheckEmailParamsList";

export type AppParamsList = {
[ROUTES.INGRESS]: undefined;
[ROUTES.UNSUPPORTED_DEVICE]: undefined;
[ROUTES.BACKGROUND]: undefined;
[ROUTES.AUTHENTICATION]: NavigatorScreenParams<AuthenticationParamsList>;
[ROUTES.CHECK_EMAIL]: NavigatorScreenParams<CheckEmailParamsList>;
[ROUTES.ONBOARDING]: NavigatorScreenParams<OnboardingParamsList>;
[ROUTES.MAIN]: NavigatorScreenParams<MainTabParamsList>;

Expand Down
7 changes: 7 additions & 0 deletions ts/navigation/params/CheckEmailParamsList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { EmailAlreadyUsedScreenParamList } from "../../screens/profile/mailCheck/EmailAlreadyTakenScreen";
import ROUTES from "../routes";

export type CheckEmailParamsList = {
[ROUTES.CHECK_EMAIL_ALREADY_TAKEN]: EmailAlreadyUsedScreenParamList;
[ROUTES.CHECK_EMAIL_NOT_VERIFIED]: undefined;
};
5 changes: 5 additions & 0 deletions ts/navigation/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ const ROUTES = {
CIE_WRONG_PIN_SCREEN: "CIE_WRONG_PIN_SCREEN",
CIE_PIN_TEMP_LOCKED_SCREEN: "CIE_PIN_TEMP_LOCKED_SCREEN",

// Mail verification
CHECK_EMAIL: "CHECK_EMAIL",
CHECK_EMAIL_NOT_VERIFIED: "CHECK_EMAIL_NOT_VERIFIED",
CHECK_EMAIL_ALREADY_TAKEN: "CHECK_EMAIL_ALREADY_TAKEN",

// Onboarding
ONBOARDING: "ONBOARDING",
ONBOARDING_TOS: "ONBOARDING_TOS",
Expand Down
8 changes: 6 additions & 2 deletions ts/sagas/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ import {
} from "./../store/storages/keychain";
import { watchMessagePrecondition } from "./messages/watchMessagePrecondition";
import { setLanguageFromProfileIfExists } from "./preferences";
import { checkEmailSaga } from "./startup/checkEmailSaga";

const WAIT_INITIALIZE_SAGA = 5000 as Millisecond;
const navigatorPollingTime = 125 as Millisecond;
Expand Down Expand Up @@ -414,7 +415,8 @@ export function* initializeApplicationSaga(
return;
}

const userProfile = maybeUserProfile.value;
// eslint-disable-next-line functional/no-let
let userProfile = maybeUserProfile.value;

// If user logged in with different credentials, but this device still has
// user data loaded, then delete data keeping current session (user already
Expand Down Expand Up @@ -505,12 +507,14 @@ export function* initializeApplicationSaga(
yield* call(clearKeychainError);

yield* call(checkConfiguredPinSaga);
yield* call(checkAcknowledgedFingerprintSaga);

if (!hasPreviousSessionAndPin) {
yield* call(checkAcknowledgedFingerprintSaga);
yield* call(checkAcknowledgedEmailSaga, userProfile);
}

userProfile = (yield* call(checkEmailSaga)) || userProfile;

// check if the user must set preferences for push notifications (e.g. reminders)
yield* call(checkNotificationsPreferencesSaga, userProfile);

Expand Down
3 changes: 2 additions & 1 deletion ts/sagas/startup/checkAcknowledgedEmailSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
isProfileFirstOnBoarding
} from "../../store/reducers/profile";
import { ReduxSagaEffect } from "../../types/utils";
import { isNewCduFlow } from "../../config";

/**
* Launch email saga that consists of:
Expand All @@ -25,7 +26,7 @@ export function* checkAcknowledgedEmailSaga(
if (hasProfileEmail(userProfile)) {
if (
isProfileFirstOnBoarding(userProfile) ||
!isProfileEmailValidated(userProfile)
(!isNewCduFlow && !isProfileEmailValidated(userProfile))
) {
// The user profile is just created (first onboarding), the conditional
// view displays the screen to show the user's email used in app
Expand Down
52 changes: 52 additions & 0 deletions ts/sagas/startup/checkEmailSaga.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { call, put, select, take } from "typed-redux-saga/macro";
import * as O from "fp-ts/lib/Option";
import * as pot from "@pagopa/ts-commons/lib/pot";
import { StackActions } from "@react-navigation/native";
import NavigationService from "../../navigation/NavigationService";
import ROUTES from "../../navigation/routes";
import {
isProfileEmailValidated,
isProfileEmailAlreadyTaken,
profileSelector
} from "../../store/reducers/profile";
import { isNewCduFlow } from "../../config";
import { setEmailCheckAtStartupFailure } from "../../store/actions/profile";
import { emailAcknowledged } from "../../store/actions/onboarding";

export function* checkEmailSaga() {
// We get the latest profile from the store
const profile = yield* select(profileSelector);
// When we use this saga, we are sure that the profile is not none
if (pot.isSome(profile)) {
// eslint-disable-next-line functional/no-let
let userProfile = profile.value;
if (isNewCduFlow && !isProfileEmailValidated(userProfile)) {
yield* put(setEmailCheckAtStartupFailure(O.some(true)));
if (isProfileEmailAlreadyTaken(userProfile)) {
yield* call(NavigationService.navigate, ROUTES.CHECK_EMAIL, {
screen: ROUTES.CHECK_EMAIL_ALREADY_TAKEN,
params: { email: userProfile.email }
});
} else {
yield* call(NavigationService.navigate, ROUTES.CHECK_EMAIL, {
screen: ROUTES.CHECK_EMAIL_NOT_VERIFIED
});
}
// Wait for the user to press "Continue" button after having checked out
// his own email
yield* take(emailAcknowledged);
yield* call(
NavigationService.dispatchNavigationAction,
StackActions.popToTop()
);

// We get the latest profile from the store and return it
const maybeUpdatedProfile = yield* select(profileSelector);
if (pot.isSome(maybeUpdatedProfile)) {
userProfile = maybeUpdatedProfile.value;
}
}
return userProfile;
}
return undefined;
}
Loading
Loading