Skip to content

Add Google, Apple and SAML flows #148

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

Draft
wants to merge 9 commits into
base: make-new-dot-signin-default-for-hybridapp
Choose a base branch
from
8 changes: 4 additions & 4 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const WRITE_COMMANDS = {
REQUEST_NEW_VALIDATE_CODE: 'RequestNewValidateCode',
SIGN_IN_WITH_APPLE: 'SignInWithApple',
SIGN_IN_WITH_GOOGLE: 'SignInWithGoogle',
SIGN_IN_USER: 'SigninUser',
SIGN_IN_USER_WITH_LINK: 'SigninUserWithLink',
SEARCH: 'Search',
REQUEST_UNLINK_VALIDATION_LINK: 'RequestUnlinkValidationLink',
Expand Down Expand Up @@ -317,6 +318,7 @@ const WRITE_COMMANDS = {
MERGE_DUPLICATES: 'MergeDuplicates',
RESOLVE_DUPLICATES: 'ResolveDuplicates',
UPDATE_SUBSCRIPTION_TYPE: 'UpdateSubscriptionType',
SIGN_UP_USER: 'SignUpUser',
UPDATE_SUBSCRIPTION_AUTO_RENEW: 'UpdateSubscriptionAutoRenew',
UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY: 'UpdateSubscriptionAddNewUsersAutomatically',
UPDATE_SUBSCRIPTION_SIZE: 'UpdateSubscriptionSize',
Expand Down Expand Up @@ -535,6 +537,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.REQUEST_NEW_VALIDATE_CODE]: Parameters.RequestNewValidateCodeParams;
[WRITE_COMMANDS.SIGN_IN_WITH_APPLE]: Parameters.BeginAppleSignInParams;
[WRITE_COMMANDS.SIGN_IN_WITH_GOOGLE]: Parameters.BeginGoogleSignInParams;
[WRITE_COMMANDS.SIGN_IN_USER]: SignInUserParams;
[WRITE_COMMANDS.SIGN_IN_USER_WITH_LINK]: Parameters.SignInUserWithLinkParams;
[WRITE_COMMANDS.REQUEST_UNLINK_VALIDATION_LINK]: Parameters.RequestUnlinkValidationLinkParams;
[WRITE_COMMANDS.UNLINK_LOGIN]: Parameters.UnlinkLoginParams;
Expand Down Expand Up @@ -785,6 +788,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.MERGE_DUPLICATES]: Parameters.MergeDuplicatesParams;
[WRITE_COMMANDS.RESOLVE_DUPLICATES]: Parameters.ResolveDuplicatesParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_TYPE]: Parameters.UpdateSubscriptionTypeParams;
[WRITE_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_SIZE]: Parameters.UpdateSubscriptionSizeParams;
Expand Down Expand Up @@ -1087,8 +1091,6 @@ const SIDE_EFFECT_REQUEST_COMMANDS = {
CONNECT_POLICY_TO_QUICKBOOKS_DESKTOP: 'ConnectPolicyToQuickbooksDesktop',
BANK_ACCOUNT_CREATE_CORPAY: 'BankAccount_CreateCorpay',
GET_EMPHEMERAL_TOKEN: 'GetEmphemeralToken',
SIGN_IN_USER: 'SigninUser',
SIGN_UP_USER: 'SignUpUser',

// PayMoneyRequestOnSearch only works online (pattern C) and we need to play the success sound only when the request is successful
PAY_MONEY_REQUEST_ON_SEARCH: 'PayMoneyRequestOnSearch',
Expand All @@ -1110,8 +1112,6 @@ type SideEffectRequestCommandParameters = {
[SIDE_EFFECT_REQUEST_COMMANDS.COMPLETE_HYBRID_APP_ONBOARDING]: EmptyObject;
[SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_POLICY_TO_QUICKBOOKS_DESKTOP]: Parameters.ConnectPolicyToQuickBooksDesktopParams;
[SIDE_EFFECT_REQUEST_COMMANDS.BANK_ACCOUNT_CREATE_CORPAY]: Parameters.BankAccountCreateCorpayParams;
[SIDE_EFFECT_REQUEST_COMMANDS.SIGN_IN_USER]: SignInUserParams;
[SIDE_EFFECT_REQUEST_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;
[SIDE_EFFECT_REQUEST_COMMANDS.PAY_MONEY_REQUEST_ON_SEARCH]: Parameters.PayMoneyRequestOnSearchParams;
[SIDE_EFFECT_REQUEST_COMMANDS.LOG_OUT]: Parameters.LogOutParams;
[SIDE_EFFECT_REQUEST_COMMANDS.GET_EMPHEMERAL_TOKEN]: EmptyObject;
Expand Down
50 changes: 40 additions & 10 deletions src/libs/actions/Session/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,26 @@ function signInAttemptState(): OnyxData {
};
}

/**
* Constructs the state object that extends object returned from `signInAttemptState` for the `beginGoogleSignIn` / `beginAppleSignIn` API calls.
*/

function hybridAppSignInAttemptState(): OnyxData {
return {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.HYBRID_APP,
value: {
newDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.STARTED,
},
},
],
successData: [],
failureData: [],
};
}

/**
* Checks the API to see if an account exists for the given login.
*/
Expand Down Expand Up @@ -524,9 +544,7 @@ function signUpUser() {
];

const params: SignUpUserParams = {email: credentials.login, preferredLocale};

// eslint-disable-next-line rulesdir/no-api-side-effects-method
API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.SIGN_UP_USER, params, {optimisticData, successData, failureData}).then(() => {});
API.write(WRITE_COMMANDS.SIGN_UP_USER, params, {optimisticData, successData, failureData});
}

function setupNewDotAfterTransitionFromOldDot(hybridAppSettings: string, tryNewDot?: TryNewDot) {
Expand Down Expand Up @@ -609,6 +627,15 @@ function setupNewDotAfterTransitionFromOldDot(hybridAppSettings: string, tryNewD
function beginAppleSignIn(idToken: string | undefined | null) {
const {optimisticData, successData, failureData} = signInAttemptState();

if (CONFIG.IS_HYBRID_APP) {
Log.info('[HybridApp] Extending `signInAttemptState` with HybridApp data');
const {optimisticData: hybridAppOptimisticData, successData: hybridAppSuccessData, failureData: hybridAppFailureData} = hybridAppSignInAttemptState();

optimisticData.push(...hybridAppOptimisticData);
successData.push(...hybridAppSuccessData);
failureData.push(...hybridAppFailureData);
}

const params: BeginAppleSignInParams = {idToken, preferredLocale};

API.write(WRITE_COMMANDS.SIGN_IN_WITH_APPLE, params, {optimisticData, successData, failureData});
Expand All @@ -621,8 +648,16 @@ function beginAppleSignIn(idToken: string | undefined | null) {
function beginGoogleSignIn(token: string | null) {
const {optimisticData, successData, failureData} = signInAttemptState();

const params: BeginGoogleSignInParams = {token, preferredLocale};
if (CONFIG.IS_HYBRID_APP) {
Log.info('[HybridApp] Extending `signInAttemptState` with HybridApp data');
const {optimisticData: hybridAppOptimisticData, successData: hybridAppSuccessData, failureData: hybridAppFailureData} = hybridAppSignInAttemptState();

optimisticData.push(...hybridAppOptimisticData);
successData.push(...hybridAppSuccessData);
failureData.push(...hybridAppFailureData);
}

const params: BeginGoogleSignInParams = {token, preferredLocale};
API.write(WRITE_COMMANDS.SIGN_IN_WITH_GOOGLE, params, {optimisticData, successData, failureData});
}

Expand Down Expand Up @@ -700,12 +735,7 @@ function signIn(validateCode: string, twoFactorAuthCode?: string) {
params.validateCode = validateCode || credentials.validateCode;
}

// eslint-disable-next-line rulesdir/no-api-side-effects-method
API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.SIGN_IN_USER, params, {
optimisticData,
successData,
failureData,
}).then(() => {});
API.write(WRITE_COMMANDS.SIGN_IN_USER, params, {optimisticData, successData, failureData});
});
}

Expand Down
12 changes: 11 additions & 1 deletion src/pages/signin/ChooseSSOOrMagicCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
import useNetwork from '@hooks/useNetwork';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ErrorUtils from '@libs/ErrorUtils';

Check failure on line 13 in src/pages/signin/ChooseSSOOrMagicCode.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Namespace imports from @libs are not allowed. Use named imports instead. Example: import { method } from "@libs/module"
import Navigation from '@libs/Navigation/Navigation';
import * as HybridAppActions from '@userActions/HybridApp';

Check failure on line 15 in src/pages/signin/ChooseSSOOrMagicCode.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"
import * as Session from '@userActions/Session';

Check failure on line 16 in src/pages/signin/ChooseSSOOrMagicCode.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"
import CONFIG from '@src/CONFIG';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand Down Expand Up @@ -57,6 +59,7 @@
text={translate('samlSignIn.useSingleSignOn')}
isLoading={account?.isLoading}
onPress={() => {
HybridAppActions.setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED);
Navigation.navigate(ROUTES.SAML_SIGN_IN);
}}
/>
Expand All @@ -79,7 +82,14 @@
}}
/>
{!!account && !isEmptyObject(account.errors) && <FormHelpMessage message={ErrorUtils.getLatestErrorMessage(account)} />}
<ChangeExpensifyLoginLink onPress={() => Session.clearSignInData()} />
<ChangeExpensifyLoginLink
onPress={() => {
if (CONFIG.IS_HYBRID_APP) {
HybridAppActions.resetSignInFlow();
}
Session.clearSignInData();
}}
/>
</View>
<View style={[styles.mt5, styles.signInPageWelcomeTextContainer]}>
<Terms />
Expand Down
5 changes: 5 additions & 0 deletions src/pages/signin/SAMLSignInPage/index.native.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, {useCallback, useState} from 'react';
import {NativeModules} from 'react-native';

Check failure on line 2 in src/pages/signin/SAMLSignInPage/index.native.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

'NativeModules' is defined but never used

Check failure on line 2 in src/pages/signin/SAMLSignInPage/index.native.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'NativeModules' is defined but never used
import {useOnyx} from 'react-native-onyx';
import WebView from 'react-native-webview';
import type {WebViewNativeEvent} from 'react-native-webview/lib/WebViewTypes';
Expand All @@ -9,7 +10,8 @@
import getPlatform from '@libs/getPlatform';
import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
import * as HybridAppActions from '@userActions/HybridApp';

Check failure on line 13 in src/pages/signin/SAMLSignInPage/index.native.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"
import * as Session from '@userActions/Session';

Check failure on line 14 in src/pages/signin/SAMLSignInPage/index.native.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"
import CONFIG from '@src/CONFIG';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand Down Expand Up @@ -58,6 +60,9 @@
<HeaderWithBackButton
title=""
onBackButtonPress={() => {
if (CONFIG.IS_HYBRID_APP) {
HybridAppActions.resetSignInFlow();
}
Session.clearSignInData();
Navigation.isNavigationReady().then(() => {
Navigation.goBack();
Expand Down
Loading