Skip to content

Commit

Permalink
feat: add onfido onboarding for bank transfer (#2699)
Browse files Browse the repository at this point in the history
* chore: test onfido

* chore: some iteration

* fix: type

* chore: make build work

* chore: update level when going to account screen

---------

Co-authored-by: Nicolas Burtey <[email protected]>
  • Loading branch information
nicolasburtey and Nicolas Burtey authored Oct 23, 2023
1 parent f55ccf6 commit 25eecfc
Show file tree
Hide file tree
Showing 26 changed files with 970 additions and 282 deletions.
5 changes: 3 additions & 2 deletions .storybook/storybook.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ const getStories = () => {
"./app/screens/authentication-screen/authentication-check-screen.stories.tsx": require("../app/screens/authentication-screen/authentication-check-screen.stories.tsx"),
"./app/screens/authentication-screen/authentication-screen.stories.tsx": require("../app/screens/authentication-screen/authentication-screen.stories.tsx"),
"./app/screens/authentication-screen/pin-screen.stories.tsx": require("../app/screens/authentication-screen/pin-screen.stories.tsx"),
"./app/screens/people-screen/contacts/contacts-detail.stories.tsx": require("../app/screens/people-screen/contacts/contacts-detail.stories.tsx"),
"./app/screens/people-screen/people.stories.tsx": require("../app/screens/people-screen/people.stories.tsx"),
"./app/screens/conversion-flow/conversion-success-screen.stories.tsx": require("../app/screens/conversion-flow/conversion-success-screen.stories.tsx"),
"./app/screens/earns-map-screen/earns-map-screen.stories.tsx": require("../app/screens/earns-map-screen/earns-map-screen.stories.tsx"),
"./app/screens/earns-screen/earns-quiz.stories.tsx": require("../app/screens/earns-screen/earns-quiz.stories.tsx"),
Expand All @@ -76,10 +74,13 @@ const getStories = () => {
"./app/screens/email-registration-screen/email-registration-initiate.stories.tsx": require("../app/screens/email-registration-screen/email-registration-initiate.stories.tsx"),
"./app/screens/email-registration-screen/email-registration-validate.stories.tsx": require("../app/screens/email-registration-screen/email-registration-validate.stories.tsx"),
"./app/screens/error-screen/error-screen.stories.tsx": require("../app/screens/error-screen/error-screen.stories.tsx"),
"./app/screens/full-onboarding-flow/full-onboarding-flow.stories.tsx": require("../app/screens/full-onboarding-flow/full-onboarding-flow.stories.tsx"),
"./app/screens/galoy-address-screen/address-screen.stories.tsx": require("../app/screens/galoy-address-screen/address-screen.stories.tsx"),
"./app/screens/get-started-screen/device-account-fail-modal.stories.tsx": require("../app/screens/get-started-screen/device-account-fail-modal.stories.tsx"),
"./app/screens/get-started-screen/get-started-screen.stories.tsx": require("../app/screens/get-started-screen/get-started-screen.stories.tsx"),
"./app/screens/home-screen/home-screen.stories.tsx": require("../app/screens/home-screen/home-screen.stories.tsx"),
"./app/screens/people-screen/contacts/contacts-detail.stories.tsx": require("../app/screens/people-screen/contacts/contacts-detail.stories.tsx"),
"./app/screens/people-screen/people.stories.tsx": require("../app/screens/people-screen/people.stories.tsx"),
"./app/screens/phone-auth-screen/phone-login-flow.stories.tsx": require("../app/screens/phone-auth-screen/phone-login-flow.stories.tsx"),
"./app/screens/phone-auth-screen/phone-login-validation.stories.tsx": require("../app/screens/phone-auth-screen/phone-login-validation.stories.tsx"),
"./app/screens/receive-bitcoin-screen/qr-view.stories.tsx": require("../app/screens/receive-bitcoin-screen/qr-view.stories.tsx"),
Expand Down
2 changes: 1 addition & 1 deletion .storybook/storybook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ RNBootSplash.hide({ fade: true })
const StorybookUI = getStorybookUI({
enableWebsockets: true, // for @storybook/react-native-server
onDeviceUI: true,
initialSelection: { kind: "Get started screen", name: "Default" },
initialSelection: { kind: "Full onboarding screen", name: "Default" },
shouldPersistSelection: false,
})

Expand Down
19 changes: 19 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ android {
versionCode 583
versionName "2.2.125"
missingDimensionStrategy 'react-native-camera', 'general' // React native camera

// onfido requirement
multiDexEnabled true

}
splits {
abi {
Expand Down Expand Up @@ -147,6 +151,12 @@ android {
}
}
}

configurations.all {
resolutionStrategy {
force 'com.google.android.play:core-common:2.0.2'
}
}
}

dependencies {
Expand All @@ -168,6 +178,15 @@ dependencies {
} else {
implementation jscFlavor
}

// https://github.com/KjellConnelly/react-native-rate/issues/117
// https://chat.openai.com/c/ba241381-615e-48b1-baa3-ce3dbc7246b7
implementation(project(":react-native-rate")) {
exclude group: 'com.google.android.play', module: 'core-common'
exclude group: 'com.google.android.play', module: 'review'
}

implementation 'androidx.multidex:multidex:2.0.1'
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
Expand Down
5 changes: 4 additions & 1 deletion android/app/src/main/java/com/galoyapp/MainApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import com.facebook.soloader.SoLoader;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {
import androidx.multidex.MultiDexApplication;


public class MainApplication extends MultiDexApplication implements ReactApplication {

private final ReactNativeHost mReactNativeHost =
new DefaultReactNativeHost(this) {
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ buildscript {
classpath("com.android.tools.build:gradle:7.4.1")
classpath("com.facebook.react:react-native-gradle-plugin")

classpath 'com.google.gms:google-services:4.3.14' // firebase
classpath 'com.google.gms:google-services:4.3.15' // firebase
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useAppConfig } from "@app/hooks"
export const ContactSupportButton = ({
containerStyle,
}: {
containerStyle: StyleProp<ViewStyle>
containerStyle?: StyleProp<ViewStyle>
}) => {
const [showContactSupport, setShowContactSupport] = useState(false)
const { LL } = useI18nContext()
Expand Down
15 changes: 7 additions & 8 deletions app/components/notification/notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,13 @@ export const NotificationComponent = (): JSX.Element => {
)
}

const notificationType = remoteMessage.data?.notificationType
if (notificationType) {
switch (true) {
case circlesNotificationTypes.includes(notificationType):
primaryNavigation.navigate("People")
setTimeout(() => circlesNavigation.navigate("circlesDashboard"), 200)
break
}
const notificationType = remoteMessage.data?.notificationType ?? ""
if (
typeof notificationType === "string" &&
circlesNotificationTypes.includes(notificationType)
) {
primaryNavigation.navigate("People")
setTimeout(() => circlesNavigation.navigate("circlesDashboard"), 200)
}
}

Expand Down
24 changes: 24 additions & 0 deletions app/graphql/generated.gql
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,15 @@ mutation onChainUsdPaymentSendAsBtcDenominated($input: OnChainUsdPaymentSendAsBt
}
}

mutation onboardingFlowStart($input: OnboardingFlowStartInput!) {
onboardingFlowStart(input: $input) {
workflowRunId
tokenAndroid
tokenIos
__typename
}
}

mutation quizCompleted($input: QuizCompletedInput!) {
quizCompleted(input: $input) {
errors {
Expand Down Expand Up @@ -960,6 +969,21 @@ query feedbackModalShown {
feedbackModalShown @client
}

query fullOnboardingScreen {
me {
id
defaultAccount {
... on ConsumerAccount {
id
onboardingStatus
__typename
}
__typename
}
__typename
}
}

query hasPromptedSetDefaultAccount {
hasPromptedSetDefaultAccount @client
}
Expand Down
133 changes: 133 additions & 0 deletions app/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ export type ConsumerAccount = Account & {
readonly level: AccountLevel;
readonly limits: AccountLimits;
readonly notificationSettings: NotificationSettings;
readonly onboardingStatus?: Maybe<OnboardingStatus>;
/** List the quiz questions of the consumer account */
readonly quiz: ReadonlyArray<Quiz>;
readonly realtimePrice: RealtimePrice;
Expand Down Expand Up @@ -777,6 +778,7 @@ export type Mutation = {
readonly onChainPaymentSendAll: PaymentSendPayload;
readonly onChainUsdPaymentSend: PaymentSendPayload;
readonly onChainUsdPaymentSendAsBtcDenominated: PaymentSendPayload;
readonly onboardingFlowStart: OnboardingFlowStartResult;
readonly quizCompleted: QuizCompletedPayload;
/** @deprecated will be moved to AccountContact */
readonly userContactUpdateAlias: UserContactUpdateAliasPayload;
Expand Down Expand Up @@ -963,6 +965,11 @@ export type MutationOnChainUsdPaymentSendAsBtcDenominatedArgs = {
};


export type MutationOnboardingFlowStartArgs = {
input: OnboardingFlowStartInput;
};


export type MutationQuizCompletedArgs = {
input: QuizCompletedInput;
};
Expand Down Expand Up @@ -1129,6 +1136,30 @@ export type OnChainUsdTxFee = {
readonly amount: Scalars['CentAmount']['output'];
};

export type OnboardingFlowStartInput = {
readonly firstName: Scalars['String']['input'];
readonly lastName: Scalars['String']['input'];
};

export type OnboardingFlowStartResult = {
readonly __typename: 'OnboardingFlowStartResult';
readonly tokenAndroid: Scalars['String']['output'];
readonly tokenIos: Scalars['String']['output'];
readonly workflowRunId: Scalars['String']['output'];
};

export const OnboardingStatus = {
Abandoned: 'ABANDONED',
Approved: 'APPROVED',
AwaitingInput: 'AWAITING_INPUT',
Declined: 'DECLINED',
Error: 'ERROR',
NotStarted: 'NOT_STARTED',
Processing: 'PROCESSING',
Review: 'REVIEW'
} as const;

export type OnboardingStatus = typeof OnboardingStatus[keyof typeof OnboardingStatus];
export type OneDayAccountLimit = AccountLimit & {
readonly __typename: 'OneDayAccountLimit';
/** The rolling time interval value in seconds for the current 24 hour period. */
Expand Down Expand Up @@ -2010,6 +2041,18 @@ export type UserEmailRegistrationValidateMutationVariables = Exact<{

export type UserEmailRegistrationValidateMutation = { readonly __typename: 'Mutation', readonly userEmailRegistrationValidate: { readonly __typename: 'UserEmailRegistrationValidatePayload', readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly message: string }>, readonly me?: { readonly __typename: 'User', readonly id: string, readonly email?: { readonly __typename: 'Email', readonly address?: string | null, readonly verified?: boolean | null } | null } | null } };

export type OnboardingFlowStartMutationVariables = Exact<{
input: OnboardingFlowStartInput;
}>;


export type OnboardingFlowStartMutation = { readonly __typename: 'Mutation', readonly onboardingFlowStart: { readonly __typename: 'OnboardingFlowStartResult', readonly workflowRunId: string, readonly tokenAndroid: string, readonly tokenIos: string } };

export type FullOnboardingScreenQueryVariables = Exact<{ [key: string]: never; }>;


export type FullOnboardingScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly onboardingStatus?: OnboardingStatus | null } } | null };

export type AddressScreenQueryVariables = Exact<{ [key: string]: never; }>;


Expand Down Expand Up @@ -3682,6 +3725,81 @@ export function useUserEmailRegistrationValidateMutation(baseOptions?: Apollo.Mu
export type UserEmailRegistrationValidateMutationHookResult = ReturnType<typeof useUserEmailRegistrationValidateMutation>;
export type UserEmailRegistrationValidateMutationResult = Apollo.MutationResult<UserEmailRegistrationValidateMutation>;
export type UserEmailRegistrationValidateMutationOptions = Apollo.BaseMutationOptions<UserEmailRegistrationValidateMutation, UserEmailRegistrationValidateMutationVariables>;
export const OnboardingFlowStartDocument = gql`
mutation onboardingFlowStart($input: OnboardingFlowStartInput!) {
onboardingFlowStart(input: $input) {
workflowRunId
tokenAndroid
tokenIos
}
}
`;
export type OnboardingFlowStartMutationFn = Apollo.MutationFunction<OnboardingFlowStartMutation, OnboardingFlowStartMutationVariables>;

/**
* __useOnboardingFlowStartMutation__
*
* To run a mutation, you first call `useOnboardingFlowStartMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useOnboardingFlowStartMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [onboardingFlowStartMutation, { data, loading, error }] = useOnboardingFlowStartMutation({
* variables: {
* input: // value for 'input'
* },
* });
*/
export function useOnboardingFlowStartMutation(baseOptions?: Apollo.MutationHookOptions<OnboardingFlowStartMutation, OnboardingFlowStartMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<OnboardingFlowStartMutation, OnboardingFlowStartMutationVariables>(OnboardingFlowStartDocument, options);
}
export type OnboardingFlowStartMutationHookResult = ReturnType<typeof useOnboardingFlowStartMutation>;
export type OnboardingFlowStartMutationResult = Apollo.MutationResult<OnboardingFlowStartMutation>;
export type OnboardingFlowStartMutationOptions = Apollo.BaseMutationOptions<OnboardingFlowStartMutation, OnboardingFlowStartMutationVariables>;
export const FullOnboardingScreenDocument = gql`
query fullOnboardingScreen {
me {
id
defaultAccount {
... on ConsumerAccount {
id
onboardingStatus
}
}
}
}
`;

/**
* __useFullOnboardingScreenQuery__
*
* To run a query within a React component, call `useFullOnboardingScreenQuery` and pass it any options that fit your needs.
* When your component renders, `useFullOnboardingScreenQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useFullOnboardingScreenQuery({
* variables: {
* },
* });
*/
export function useFullOnboardingScreenQuery(baseOptions?: Apollo.QueryHookOptions<FullOnboardingScreenQuery, FullOnboardingScreenQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<FullOnboardingScreenQuery, FullOnboardingScreenQueryVariables>(FullOnboardingScreenDocument, options);
}
export function useFullOnboardingScreenLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FullOnboardingScreenQuery, FullOnboardingScreenQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<FullOnboardingScreenQuery, FullOnboardingScreenQueryVariables>(FullOnboardingScreenDocument, options);
}
export type FullOnboardingScreenQueryHookResult = ReturnType<typeof useFullOnboardingScreenQuery>;
export type FullOnboardingScreenLazyQueryHookResult = ReturnType<typeof useFullOnboardingScreenLazyQuery>;
export type FullOnboardingScreenQueryResult = Apollo.QueryResult<FullOnboardingScreenQuery, FullOnboardingScreenQueryVariables>;
export const AddressScreenDocument = gql`
query addressScreen {
me {
Expand Down Expand Up @@ -6751,6 +6869,9 @@ export type ResolversTypes = {
OnChainUsdPaymentSendAsBtcDenominatedInput: OnChainUsdPaymentSendAsBtcDenominatedInput;
OnChainUsdPaymentSendInput: OnChainUsdPaymentSendInput;
OnChainUsdTxFee: ResolverTypeWrapper<OnChainUsdTxFee>;
OnboardingFlowStartInput: OnboardingFlowStartInput;
OnboardingFlowStartResult: ResolverTypeWrapper<OnboardingFlowStartResult>;
OnboardingStatus: OnboardingStatus;
OneDayAccountLimit: ResolverTypeWrapper<OneDayAccountLimit>;
OneTimeAuthCode: ResolverTypeWrapper<Scalars['OneTimeAuthCode']['output']>;
PageInfo: ResolverTypeWrapper<PageInfo>;
Expand Down Expand Up @@ -6951,6 +7072,8 @@ export type ResolversParentTypes = {
OnChainUsdPaymentSendAsBtcDenominatedInput: OnChainUsdPaymentSendAsBtcDenominatedInput;
OnChainUsdPaymentSendInput: OnChainUsdPaymentSendInput;
OnChainUsdTxFee: OnChainUsdTxFee;
OnboardingFlowStartInput: OnboardingFlowStartInput;
OnboardingFlowStartResult: OnboardingFlowStartResult;
OneDayAccountLimit: OneDayAccountLimit;
OneTimeAuthCode: Scalars['OneTimeAuthCode']['output'];
PageInfo: PageInfo;
Expand Down Expand Up @@ -7168,6 +7291,7 @@ export type ConsumerAccountResolvers<ContextType = any, ParentType extends Resol
level?: Resolver<ResolversTypes['AccountLevel'], ParentType, ContextType>;
limits?: Resolver<ResolversTypes['AccountLimits'], ParentType, ContextType>;
notificationSettings?: Resolver<ResolversTypes['NotificationSettings'], ParentType, ContextType>;
onboardingStatus?: Resolver<Maybe<ResolversTypes['OnboardingStatus']>, ParentType, ContextType>;
quiz?: Resolver<ReadonlyArray<ResolversTypes['Quiz']>, ParentType, ContextType>;
realtimePrice?: Resolver<ResolversTypes['RealtimePrice'], ParentType, ContextType>;
transactions?: Resolver<Maybe<ResolversTypes['TransactionConnection']>, ParentType, ContextType, Partial<ConsumerAccountTransactionsArgs>>;
Expand Down Expand Up @@ -7447,6 +7571,7 @@ export type MutationResolvers<ContextType = any, ParentType extends ResolversPar
onChainPaymentSendAll?: Resolver<ResolversTypes['PaymentSendPayload'], ParentType, ContextType, RequireFields<MutationOnChainPaymentSendAllArgs, 'input'>>;
onChainUsdPaymentSend?: Resolver<ResolversTypes['PaymentSendPayload'], ParentType, ContextType, RequireFields<MutationOnChainUsdPaymentSendArgs, 'input'>>;
onChainUsdPaymentSendAsBtcDenominated?: Resolver<ResolversTypes['PaymentSendPayload'], ParentType, ContextType, RequireFields<MutationOnChainUsdPaymentSendAsBtcDenominatedArgs, 'input'>>;
onboardingFlowStart?: Resolver<ResolversTypes['OnboardingFlowStartResult'], ParentType, ContextType, RequireFields<MutationOnboardingFlowStartArgs, 'input'>>;
quizCompleted?: Resolver<ResolversTypes['QuizCompletedPayload'], ParentType, ContextType, RequireFields<MutationQuizCompletedArgs, 'input'>>;
userContactUpdateAlias?: Resolver<ResolversTypes['UserContactUpdateAliasPayload'], ParentType, ContextType, RequireFields<MutationUserContactUpdateAliasArgs, 'input'>>;
userEmailDelete?: Resolver<ResolversTypes['UserEmailDeletePayload'], ParentType, ContextType>;
Expand Down Expand Up @@ -7521,6 +7646,13 @@ export type OnChainUsdTxFeeResolvers<ContextType = any, ParentType extends Resol
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export type OnboardingFlowStartResultResolvers<ContextType = any, ParentType extends ResolversParentTypes['OnboardingFlowStartResult'] = ResolversParentTypes['OnboardingFlowStartResult']> = {
tokenAndroid?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
tokenIos?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
workflowRunId?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export type OneDayAccountLimitResolvers<ContextType = any, ParentType extends ResolversParentTypes['OneDayAccountLimit'] = ResolversParentTypes['OneDayAccountLimit']> = {
interval?: Resolver<Maybe<ResolversTypes['Seconds']>, ParentType, ContextType>;
remainingLimit?: Resolver<Maybe<ResolversTypes['CentAmount']>, ParentType, ContextType>;
Expand Down Expand Up @@ -8007,6 +8139,7 @@ export type Resolvers<ContextType = any> = {
OnChainTxHash?: GraphQLScalarType;
OnChainUpdate?: OnChainUpdateResolvers<ContextType>;
OnChainUsdTxFee?: OnChainUsdTxFeeResolvers<ContextType>;
OnboardingFlowStartResult?: OnboardingFlowStartResultResolvers<ContextType>;
OneDayAccountLimit?: OneDayAccountLimitResolvers<ContextType>;
OneTimeAuthCode?: GraphQLScalarType;
PageInfo?: PageInfoResolvers<ContextType>;
Expand Down
Loading

0 comments on commit 25eecfc

Please sign in to comment.