From a0bd1671400ce057979597d8a656c2e923db0d38 Mon Sep 17 00:00:00 2001 From: Nicolas Burtey Date: Mon, 25 Sep 2023 12:38:13 +0100 Subject: [PATCH] chore: test onfido --- .storybook/storybook.requires.js | 5 +- .storybook/storybook.tsx | 2 +- android/app/build.gradle | 6 + .../java/com/galoyapp/MainApplication.java | 5 +- app/graphql/generated.gql | 9 + app/graphql/generated.ts | 176 +++++++++++++++++- app/i18n/en/index.ts | 19 +- app/i18n/i18n-types.ts | 119 +++++++++--- app/i18n/raw-i18n/source/en.json | 17 +- app/navigation/root-navigator.tsx | 8 + app/navigation/stack-param-lists.ts | 1 + .../full-onboarding-flow.stories.tsx | 20 ++ .../full-onboarding-flow.tsx | 168 +++++++++++++++++ app/screens/full-onboarding-flow/index.ts | 1 + .../send-bitcoin-details-extra-info.tsx | 22 +-- .../transaction-limits-screen.tsx | 49 ++--- codegen.yml | 4 +- ios/GaloyApp.xcodeproj/project.pbxproj | 2 + ios/Podfile.lock | 14 +- package.json | 1 + supergraph-config.yaml | 6 +- supergraph.graphql | 150 ++++++++++----- yarn.lock | 12 ++ 23 files changed, 669 insertions(+), 147 deletions(-) create mode 100644 app/screens/full-onboarding-flow/full-onboarding-flow.stories.tsx create mode 100644 app/screens/full-onboarding-flow/full-onboarding-flow.tsx create mode 100644 app/screens/full-onboarding-flow/index.ts diff --git a/.storybook/storybook.requires.js b/.storybook/storybook.requires.js index 63580a3634..8d59eded78 100644 --- a/.storybook/storybook.requires.js +++ b/.storybook/storybook.requires.js @@ -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"), @@ -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"), diff --git a/.storybook/storybook.tsx b/.storybook/storybook.tsx index a5693f3785..b5fb8e2d94 100644 --- a/.storybook/storybook.tsx +++ b/.storybook/storybook.tsx @@ -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, }) diff --git a/android/app/build.gradle b/android/app/build.gradle index dc76e2edad..53fc908c36 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -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 { @@ -168,6 +172,8 @@ dependencies { } else { implementation jscFlavor } + + implementation 'androidx.multidex:multidex:2.0.1' } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/android/app/src/main/java/com/galoyapp/MainApplication.java b/android/app/src/main/java/com/galoyapp/MainApplication.java index 913717eac1..4c595e2a8e 100644 --- a/android/app/src/main/java/com/galoyapp/MainApplication.java +++ b/android/app/src/main/java/com/galoyapp/MainApplication.java @@ -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) { diff --git a/app/graphql/generated.gql b/app/graphql/generated.gql index b6c4fa6367..15bb802716 100644 --- a/app/graphql/generated.gql +++ b/app/graphql/generated.gql @@ -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 { diff --git a/app/graphql/generated.ts b/app/graphql/generated.ts index 6f64314e8c..2ce0040016 100644 --- a/app/graphql/generated.ts +++ b/app/graphql/generated.ts @@ -82,6 +82,8 @@ export type Scalars = { Username: { input: string; output: string; } /** Unique identifier of a wallet */ WalletId: { input: string; output: string; } + join__FieldSet: { input: string; output: string; } + link__Import: { input: string; output: string; } _FieldSet: { input: string; output: string; } }; @@ -777,6 +779,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; @@ -965,6 +968,11 @@ export type MutationOnChainUsdPaymentSendAsBtcDenominatedArgs = { }; +export type MutationOnboardingFlowStartArgs = { + input: OnboardingFlowStartInput; +}; + + export type MutationQuizCompletedArgs = { input: QuizCompletedInput; }; @@ -1136,6 +1144,19 @@ export type OnChainUsdTxFee = { readonly amount: Scalars['CentAmount']['output']; }; +export type OnboardingFlowStartInput = { + readonly accountId: Scalars['String']['input']; + 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 type OneDayAccountLimit = AccountLimit & { readonly __typename: 'OneDayAccountLimit'; /** The rolling time interval value in seconds for the current 24 hour period. */ @@ -1278,6 +1299,7 @@ export type Query = { readonly feedbackModalShown: Scalars['Boolean']['output']; readonly globals?: Maybe; readonly hasPromptedSetDefaultAccount: Scalars['Boolean']['output']; + readonly hello?: Maybe; readonly hiddenBalanceToolTip: Scalars['Boolean']['output']; readonly hideBalance: Scalars['Boolean']['output']; readonly innerCircleValue: Scalars['Int']['output']; @@ -1863,6 +1885,21 @@ export const WelcomeRange = { } as const; export type WelcomeRange = typeof WelcomeRange[keyof typeof WelcomeRange]; +export const Join__Graph = { + Circles: 'CIRCLES', + Galoy: 'GALOY', + Kyc: 'KYC' +} as const; + +export type Join__Graph = typeof Join__Graph[keyof typeof Join__Graph]; +export const Link__Purpose = { + /** `EXECUTION` features provide metadata necessary for operation execution. */ + Execution: 'EXECUTION', + /** `SECURITY` features provide metadata necessary to securely resolve fields. */ + Security: 'SECURITY' +} as const; + +export type Link__Purpose = typeof Link__Purpose[keyof typeof Link__Purpose]; export type MobileUpdateQueryVariables = Exact<{ [key: string]: never; }>; @@ -2034,6 +2071,13 @@ 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 AddressScreenQueryVariables = Exact<{ [key: string]: never; }>; @@ -3706,6 +3750,41 @@ export function useUserEmailRegistrationValidateMutation(baseOptions?: Apollo.Mu export type UserEmailRegistrationValidateMutationHookResult = ReturnType; export type UserEmailRegistrationValidateMutationResult = Apollo.MutationResult; export type UserEmailRegistrationValidateMutationOptions = Apollo.BaseMutationOptions; +export const OnboardingFlowStartDocument = gql` + mutation onboardingFlowStart($input: OnboardingFlowStartInput!) { + onboardingFlowStart(input: $input) { + workflowRunId + tokenAndroid + tokenIos + } +} + `; +export type OnboardingFlowStartMutationFn = Apollo.MutationFunction; + +/** + * __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) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(OnboardingFlowStartDocument, options); + } +export type OnboardingFlowStartMutationHookResult = ReturnType; +export type OnboardingFlowStartMutationResult = Apollo.MutationResult; +export type OnboardingFlowStartMutationOptions = Apollo.BaseMutationOptions; export const AddressScreenDocument = gql` query addressScreen { me { @@ -6775,6 +6854,8 @@ export type ResolversTypes = { OnChainUsdPaymentSendAsBtcDenominatedInput: OnChainUsdPaymentSendAsBtcDenominatedInput; OnChainUsdPaymentSendInput: OnChainUsdPaymentSendInput; OnChainUsdTxFee: ResolverTypeWrapper; + OnboardingFlowStartInput: OnboardingFlowStartInput; + OnboardingFlowStartResult: ResolverTypeWrapper; OneDayAccountLimit: ResolverTypeWrapper; OneTimeAuthCode: ResolverTypeWrapper; PageInfo: ResolverTypeWrapper; @@ -6863,6 +6944,10 @@ export type ResolversTypes = { WelcomeLeaderboardInput: WelcomeLeaderboardInput; WelcomeProfile: ResolverTypeWrapper; WelcomeRange: WelcomeRange; + join__FieldSet: ResolverTypeWrapper; + join__Graph: Join__Graph; + link__Import: ResolverTypeWrapper; + link__Purpose: Link__Purpose; }; /** Mapping between all available schema types and the resolvers parents */ @@ -6977,6 +7062,8 @@ export type ResolversParentTypes = { OnChainUsdPaymentSendAsBtcDenominatedInput: OnChainUsdPaymentSendAsBtcDenominatedInput; OnChainUsdPaymentSendInput: OnChainUsdPaymentSendInput; OnChainUsdTxFee: OnChainUsdTxFee; + OnboardingFlowStartInput: OnboardingFlowStartInput; + OnboardingFlowStartResult: OnboardingFlowStartResult; OneDayAccountLimit: OneDayAccountLimit; OneTimeAuthCode: Scalars['OneTimeAuthCode']['output']; PageInfo: PageInfo; @@ -7056,14 +7143,67 @@ export type ResolversParentTypes = { WalletId: Scalars['WalletId']['output']; WelcomeLeaderboardInput: WelcomeLeaderboardInput; WelcomeProfile: WelcomeProfile; + join__FieldSet: Scalars['join__FieldSet']['output']; + link__Import: Scalars['link__Import']['output']; }; -export type DeferDirectiveArgs = { - if?: Scalars['Boolean']['input']; - label?: Maybe; +export type Join__EnumValueDirectiveArgs = { + graph: Join__Graph; }; -export type DeferDirectiveResolver = DirectiveResolverFn; +export type Join__EnumValueDirectiveResolver = DirectiveResolverFn; + +export type Join__FieldDirectiveArgs = { + external?: Maybe; + graph?: Maybe; + override?: Maybe; + provides?: Maybe; + requires?: Maybe; + type?: Maybe; + usedOverridden?: Maybe; +}; + +export type Join__FieldDirectiveResolver = DirectiveResolverFn; + +export type Join__GraphDirectiveArgs = { + name: Scalars['String']['input']; + url: Scalars['String']['input']; +}; + +export type Join__GraphDirectiveResolver = DirectiveResolverFn; + +export type Join__ImplementsDirectiveArgs = { + graph: Join__Graph; + interface: Scalars['String']['input']; +}; + +export type Join__ImplementsDirectiveResolver = DirectiveResolverFn; + +export type Join__TypeDirectiveArgs = { + extension?: Scalars['Boolean']['input']; + graph: Join__Graph; + isInterfaceObject?: Scalars['Boolean']['input']; + key?: Maybe; + resolvable?: Scalars['Boolean']['input']; +}; + +export type Join__TypeDirectiveResolver = DirectiveResolverFn; + +export type Join__UnionMemberDirectiveArgs = { + graph: Join__Graph; + member: Scalars['String']['input']; +}; + +export type Join__UnionMemberDirectiveResolver = DirectiveResolverFn; + +export type LinkDirectiveArgs = { + as?: Maybe; + for?: Maybe; + import?: Maybe>>; + url?: Maybe; +}; + +export type LinkDirectiveResolver = DirectiveResolverFn; export type AccountResolvers = { __resolveType: TypeResolveFn<'ConsumerAccount', ParentType, ContextType>; @@ -7475,6 +7615,7 @@ export type MutationResolvers>; onChainUsdPaymentSend?: Resolver>; onChainUsdPaymentSendAsBtcDenominated?: Resolver>; + onboardingFlowStart?: Resolver>; quizCompleted?: Resolver>; userContactUpdateAlias?: Resolver>; userEmailDelete?: Resolver; @@ -7550,6 +7691,13 @@ export type OnChainUsdTxFeeResolvers; }; +export type OnboardingFlowStartResultResolvers = { + tokenAndroid?: Resolver; + tokenIos?: Resolver; + workflowRunId?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type OneDayAccountLimitResolvers = { interval?: Resolver, ParentType, ContextType>; remainingLimit?: Resolver, ParentType, ContextType>; @@ -7649,6 +7797,7 @@ export type QueryResolvers; globals?: Resolver, ParentType, ContextType>; hasPromptedSetDefaultAccount?: Resolver; + hello?: Resolver, ParentType, ContextType>; hiddenBalanceToolTip?: Resolver; hideBalance?: Resolver; innerCircleValue?: Resolver; @@ -7971,6 +8120,14 @@ export type WelcomeProfileResolvers; }; +export interface Join__FieldSetScalarConfig extends GraphQLScalarTypeConfig { + name: 'join__FieldSet'; +} + +export interface Link__ImportScalarConfig extends GraphQLScalarTypeConfig { + name: 'link__Import'; +} + export type Resolvers = { Account?: AccountResolvers; AccountDeletePayload?: AccountDeletePayloadResolvers; @@ -8043,6 +8200,7 @@ export type Resolvers = { OnChainTxHash?: GraphQLScalarType; OnChainUpdate?: OnChainUpdateResolvers; OnChainUsdTxFee?: OnChainUsdTxFeeResolvers; + OnboardingFlowStartResult?: OnboardingFlowStartResultResolvers; OneDayAccountLimit?: OneDayAccountLimitResolvers; OneTimeAuthCode?: GraphQLScalarType; PageInfo?: PageInfoResolvers; @@ -8104,8 +8262,16 @@ export type Resolvers = { Wallet?: WalletResolvers; WalletId?: GraphQLScalarType; WelcomeProfile?: WelcomeProfileResolvers; + join__FieldSet?: GraphQLScalarType; + link__Import?: GraphQLScalarType; }; export type DirectiveResolvers = { - defer?: DeferDirectiveResolver; + join__enumValue?: Join__EnumValueDirectiveResolver; + join__field?: Join__FieldDirectiveResolver; + join__graph?: Join__GraphDirectiveResolver; + join__implements?: Join__ImplementsDirectiveResolver; + join__type?: Join__TypeDirectiveResolver; + join__unionMember?: Join__UnionMemberDirectiveResolver; + link?: LinkDirectiveResolver; }; diff --git a/app/i18n/en/index.ts b/app/i18n/en/index.ts index 44a5fd4a75..64d64e8f01 100644 --- a/app/i18n/en/index.ts +++ b/app/i18n/en/index.ts @@ -849,12 +849,8 @@ const en: BaseTranslation = { stablesatTransfers: "Stablesat Transfers", internalSend: "Send to {bankName: string} User", error: "Unable to fetch limits at this time", - contactUsMessageBody: - "Hi, I will like to increase the transaction limits of my {bankName: string} account.", - contactUsMessageSubject: "Request To Increase Transaction Limits", - contactSupportToPerformKyc: - "Contact support to perform manual KYC to increase your limit", increaseLimits: "Increase your limits", + increaseLimitsLevel2: "Increase your limits by providing an ID", }, TransactionScreen: { noTransaction: "No transaction to show", @@ -1203,8 +1199,19 @@ const en: BaseTranslation = { details: "We're giving away 1,000,000 sats!\n\n Share your Circles on social with tag `#blinkcircles` to enter! The winner will be chosen at random on October 31st.\n\n You must have at least one person in your Inner Circle to enter!", connectOnSocial: "Connect on social: ", fullDetails: "Full details at " - } + }, }, + FullOnboarding: { + title: "Full onboarding", + confirmNameTitle: "Confirm your name", + firstName: "First name", + lastName: "Last name", + confirmNameContent: "Is the spelling of your name correct?\n\n{firstName: string} {lastName: string}\n\nIt must match the name on your ID.", + requirements: "To increase your limits, you will have to provide your name, a governement-issued ID and a selfie. We'll start with your name.", + accountVerifiedAlready: "You account has already been verified", + success: "Documents has been successfully received", + error: "There has been an error with the submission of your documents. You can contact the support is the problem persists." + } } export default en diff --git a/app/i18n/i18n-types.ts b/app/i18n/i18n-types.ts index ed4c7db8a5..a8369e1610 100644 --- a/app/i18n/i18n-types.ts +++ b/app/i18n/i18n-types.ts @@ -2649,23 +2649,14 @@ type RootTranslation = { * U​n​a​b​l​e​ ​t​o​ ​f​e​t​c​h​ ​l​i​m​i​t​s​ ​a​t​ ​t​h​i​s​ ​t​i​m​e */ error: string - /** - * H​i​,​ ​I​ ​w​i​l​l​ ​l​i​k​e​ ​t​o​ ​i​n​c​r​e​a​s​e​ ​t​h​e​ ​t​r​a​n​s​a​c​t​i​o​n​ ​l​i​m​i​t​s​ ​o​f​ ​m​y​ ​{​b​a​n​k​N​a​m​e​}​ ​a​c​c​o​u​n​t​. - * @param {string} bankName - */ - contactUsMessageBody: RequiredParams<'bankName'> - /** - * R​e​q​u​e​s​t​ ​T​o​ ​I​n​c​r​e​a​s​e​ ​T​r​a​n​s​a​c​t​i​o​n​ ​L​i​m​i​t​s - */ - contactUsMessageSubject: string - /** - * C​o​n​t​a​c​t​ ​s​u​p​p​o​r​t​ ​t​o​ ​p​e​r​f​o​r​m​ ​m​a​n​u​a​l​ ​K​Y​C​ ​t​o​ ​i​n​c​r​e​a​s​e​ ​y​o​u​r​ ​l​i​m​i​t - */ - contactSupportToPerformKyc: string /** * I​n​c​r​e​a​s​e​ ​y​o​u​r​ ​l​i​m​i​t​s */ increaseLimits: string + /** + * I​n​c​r​e​a​s​e​ ​y​o​u​r​ ​l​i​m​i​t​s​ ​b​y​ ​p​r​o​v​i​d​i​n​g​ ​a​n​ ​I​D + */ + increaseLimitsLevel2: string } TransactionScreen: { /** @@ -3806,6 +3797,50 @@ type RootTranslation = { fullDetails: string } } + FullOnboarding: { + /** + * F​u​l​l​ ​o​n​b​o​a​r​d​i​n​g + */ + title: string + /** + * C​o​n​f​i​r​m​ ​y​o​u​r​ ​n​a​m​e + */ + confirmNameTitle: string + /** + * F​i​r​s​t​ ​n​a​m​e + */ + firstName: string + /** + * L​a​s​t​ ​n​a​m​e + */ + lastName: string + /** + * I​s​ ​t​h​e​ ​s​p​e​l​l​i​n​g​ ​o​f​ ​y​o​u​r​ ​n​a​m​e​ ​c​o​r​r​e​c​t​?​ + ​ + ​{​f​i​r​s​t​N​a​m​e​}​ ​{​l​a​s​t​N​a​m​e​}​ + ​ + ​I​t​ ​m​u​s​t​ ​m​a​t​c​h​ ​t​h​e​ ​n​a​m​e​ ​o​n​ ​y​o​u​r​ ​I​D​. + * @param {string} firstName + * @param {string} lastName + */ + confirmNameContent: RequiredParams<'firstName' | 'lastName'> + /** + * T​o​ ​i​n​c​r​e​a​s​e​ ​y​o​u​r​ ​l​i​m​i​t​s​,​ ​y​o​u​ ​w​i​l​l​ ​h​a​v​e​ ​t​o​ ​p​r​o​v​i​d​e​ ​y​o​u​r​ ​n​a​m​e​,​ ​a​ ​g​o​v​e​r​n​e​m​e​n​t​-​i​s​s​u​e​d​ ​I​D​ ​a​n​d​ ​a​ ​s​e​l​f​i​e​.​ ​W​e​'​l​l​ ​s​t​a​r​t​ ​w​i​t​h​ ​y​o​u​r​ ​n​a​m​e​. + */ + requirements: string + /** + * Y​o​u​ ​a​c​c​o​u​n​t​ ​h​a​s​ ​a​l​r​e​a​d​y​ ​b​e​e​n​ ​v​e​r​i​f​i​e​d + */ + accountVerifiedAlready: string + /** + * D​o​c​u​m​e​n​t​s​ ​h​a​s​ ​b​e​e​n​ ​s​u​c​c​e​s​s​f​u​l​l​y​ ​r​e​c​e​i​v​e​d + */ + success: string + /** + * T​h​e​r​e​ ​h​a​s​ ​b​e​e​n​ ​a​n​ ​e​r​r​o​r​ ​w​i​t​h​ ​t​h​e​ ​s​u​b​m​i​s​s​i​o​n​ ​o​f​ ​y​o​u​r​ ​d​o​c​u​m​e​n​t​s​.​ ​Y​o​u​ ​c​a​n​ ​c​o​n​t​a​c​t​ ​t​h​e​ ​s​u​p​p​o​r​t​ ​i​s​ ​t​h​e​ ​p​r​o​b​l​e​m​ ​p​e​r​s​i​s​t​s​. + */ + error: string + } } export type TranslationFunctions = { @@ -6374,22 +6409,14 @@ export type TranslationFunctions = { * Unable to fetch limits at this time */ error: () => LocalizedString - /** - * Hi, I will like to increase the transaction limits of my {bankName} account. - */ - contactUsMessageBody: (arg: { bankName: string }) => LocalizedString - /** - * Request To Increase Transaction Limits - */ - contactUsMessageSubject: () => LocalizedString - /** - * Contact support to perform manual KYC to increase your limit - */ - contactSupportToPerformKyc: () => LocalizedString /** * Increase your limits */ increaseLimits: () => LocalizedString + /** + * Increase your limits by providing an ID + */ + increaseLimitsLevel2: () => LocalizedString } TransactionScreen: { /** @@ -7499,6 +7526,48 @@ export type TranslationFunctions = { fullDetails: () => LocalizedString } } + FullOnboarding: { + /** + * Full onboarding + */ + title: () => LocalizedString + /** + * Confirm your name + */ + confirmNameTitle: () => LocalizedString + /** + * First name + */ + firstName: () => LocalizedString + /** + * Last name + */ + lastName: () => LocalizedString + /** + * Is the spelling of your name correct? + + {firstName} {lastName} + + It must match the name on your ID. + */ + confirmNameContent: (arg: { firstName: string, lastName: string }) => LocalizedString + /** + * To increase your limits, you will have to provide your name, a governement-issued ID and a selfie. We'll start with your name. + */ + requirements: () => LocalizedString + /** + * You account has already been verified + */ + accountVerifiedAlready: () => LocalizedString + /** + * Documents has been successfully received + */ + success: () => LocalizedString + /** + * There has been an error with the submission of your documents. You can contact the support is the problem persists. + */ + error: () => LocalizedString + } } export type Formatters = { diff --git a/app/i18n/raw-i18n/source/en.json b/app/i18n/raw-i18n/source/en.json index 20524ef5ba..f1a5574172 100644 --- a/app/i18n/raw-i18n/source/en.json +++ b/app/i18n/raw-i18n/source/en.json @@ -773,10 +773,8 @@ "stablesatTransfers": "Stablesat Transfers", "internalSend": "Send to {bankName: string} User", "error": "Unable to fetch limits at this time", - "contactUsMessageBody": "Hi, I will like to increase the transaction limits of my {bankName: string} account.", - "contactUsMessageSubject": "Request To Increase Transaction Limits", - "contactSupportToPerformKyc": "Contact support to perform manual KYC to increase your limit", - "increaseLimits": "Increase your limits" + "increaseLimits": "Increase your limits", + "increaseLimitsLevel2": "Increase your limits by providing an ID" }, "TransactionScreen": { "noTransaction": "No transaction to show", @@ -1094,5 +1092,16 @@ "connectOnSocial": "Connect on social: ", "fullDetails": "Full details at " } + }, + "FullOnboarding": { + "title": "Full onboarding", + "confirmNameTitle": "Confirm your name", + "firstName": "First name", + "lastName": "Last name", + "confirmNameContent": "Is the spelling of your name correct?\n\n{firstName: string} {lastName: string}\n\nIt must match the name on your ID.", + "requirements": "To increase your limits, you will have to provide your name, a governement-issued ID and a selfie. We'll start with your name.", + "accountVerifiedAlready": "You account has already been verified", + "success": "Documents has been successfully received", + "error": "There has been an error with the submission of your documents. You can contact the support is the problem persists." } } diff --git a/app/navigation/root-navigator.tsx b/app/navigation/root-navigator.tsx index bd800ca42e..5b7ffd81a5 100644 --- a/app/navigation/root-navigator.tsx +++ b/app/navigation/root-navigator.tsx @@ -80,6 +80,7 @@ import { RootStackParamList, } from "./stack-param-lists" import { NotificationSettingsScreen } from "@app/screens/settings-screen/notifications-screen" +import { FullOnboardingFlowScreen } from "@app/screens/full-onboarding-flow" const useStyles = makeStyles(({ colors }) => ({ bottomNavigatorStyle: { @@ -418,6 +419,13 @@ export const RootStack = () => { title: "WebView", // should be overridden by the navigate action with an initial title }} /> + ) } diff --git a/app/navigation/stack-param-lists.ts b/app/navigation/stack-param-lists.ts index 1ee85549b7..398b99a78a 100644 --- a/app/navigation/stack-param-lists.ts +++ b/app/navigation/stack-param-lists.ts @@ -91,6 +91,7 @@ export type RootStackParamList = { totpRegistrationValidate: { totpRegistrationId: string } totpLoginValidate: { authToken: string } webView: { url: string; initialTitle?: string } + fullOnboardingFlow: undefined } export type PeopleStackParamList = { diff --git a/app/screens/full-onboarding-flow/full-onboarding-flow.stories.tsx b/app/screens/full-onboarding-flow/full-onboarding-flow.stories.tsx new file mode 100644 index 0000000000..ab843f3423 --- /dev/null +++ b/app/screens/full-onboarding-flow/full-onboarding-flow.stories.tsx @@ -0,0 +1,20 @@ +import * as React from "react" +import { StoryScreen } from "../../../.storybook/views" +import { IsAuthedContextProvider } from "../../graphql/is-authed-context" +import { MockedProvider } from "@apollo/client/testing" +import { createCache } from "../../graphql/cache" +import { FullOnboardingFlowScreen } from "./full-onboarding-flow" + +export default { + title: "Full onboarding screen", + component: FullOnboardingFlowScreen, + decorators: [(Story) => {Story()}], +} + +export const Default = () => ( + + + + + +) diff --git a/app/screens/full-onboarding-flow/full-onboarding-flow.tsx b/app/screens/full-onboarding-flow/full-onboarding-flow.tsx new file mode 100644 index 0000000000..1e38e738ad --- /dev/null +++ b/app/screens/full-onboarding-flow/full-onboarding-flow.tsx @@ -0,0 +1,168 @@ +import { gql } from "@apollo/client" +import { GaloyPrimaryButton } from "@app/components/atomic/galoy-primary-button" +import { Screen } from "@app/components/screen" +import { + useDebugScreenQuery, + useOnboardingFlowStartMutation, +} from "@app/graphql/generated" +import { AccountLevel, useLevel } from "@app/graphql/level-context" +import { useI18nContext } from "@app/i18n/i18n-react" +import { isIos } from "@app/utils/helper" +import Onfido, { OnfidoTheme } from "@onfido/react-native-sdk" +import { Input, Text, makeStyles } from "@rneui/themed" +import React, { useState } from "react" +import { Alert, View } from "react-native" + +gql` + mutation onboardingFlowStart($input: OnboardingFlowStartInput!) { + onboardingFlowStart(input: $input) { + workflowRunId + tokenAndroid + tokenIos + } + } + + query debugScreen { + me { + id + defaultAccount { + id + } + } + } +` + +export const FullOnboardingFlowScreen: React.FC = () => { + const { LL } = useI18nContext() + + const styles = useStyles() + styles + + const { currentLevel } = useLevel() + + const { data: dataDebug } = useDebugScreenQuery() + const accountId = dataDebug?.me?.defaultAccount?.id + + const [onboardingFlowStart] = useOnboardingFlowStartMutation() + + const [firstName, setFirstName] = useState("") + const [lastName, setLastName] = useState("") + + const confirmNames = async () => { + Alert.alert( + LL.FullOnboarding.confirmNameTitle(), + LL.FullOnboarding.confirmNameContent({ firstName, lastName }), + [ + { text: LL.common.cancel(), onPress: () => {} }, + { + text: LL.common.yes(), + onPress: onfidoStart, + }, + ], + ) + } + + const onfidoStart = async () => { + if (!accountId) { + console.log("no account id") + return + } + + const res = await onboardingFlowStart({ + variables: { input: { accountId, firstName, lastName } }, + }) + + const workflowRunId = res.data?.onboardingFlowStart?.workflowRunId + if (!workflowRunId) { + Alert.alert("no workflowRunId") + return + } + + const tokenAndroid = res.data?.onboardingFlowStart?.tokenAndroid + const tokenIos = res.data?.onboardingFlowStart?.tokenIos + + const sdkToken = isIos ? tokenIos : tokenAndroid + + if (!sdkToken) { + Alert.alert("no sdkToken") + return + } + + try { + /* eslint @typescript-eslint/ban-ts-comment: "off" */ + // @ts-expect-error + const res = await Onfido.start({ + sdkToken, + theme: OnfidoTheme.AUTOMATIC, + workflowRunId, + }) + + Alert.alert(LL.FullOnboarding.success()) + console.log(res, "success") + } catch (err) { + Alert.alert(LL.FullOnboarding.error()) + console.log(err, "error") + } + } + + if (currentLevel === AccountLevel.Two) { + return ( + + + {LL.FullOnboarding.accountVerifiedAlready()} + + + ) + } + + return ( + + + {LL.FullOnboarding.requirements()} + setFirstName(text)} + /> + setLastName(text)} + /> + + + + ) +} + +const useStyles = makeStyles(() => ({ + view: { + marginHorizontal: 20, + padding: 20, + borderRadius: 20, + }, + + textHeader: { + fontSize: 18, + marginBottom: 24, + }, + + mainButton: { marginVertical: 20 }, + + screenContainer: { + marginHorizontal: 24, + marginVertical: 32, + }, +})) diff --git a/app/screens/full-onboarding-flow/index.ts b/app/screens/full-onboarding-flow/index.ts new file mode 100644 index 0000000000..6d3c7412f2 --- /dev/null +++ b/app/screens/full-onboarding-flow/index.ts @@ -0,0 +1 @@ +export * from "./full-onboarding-flow" diff --git a/app/screens/send-bitcoin-screen/send-bitcoin-details-extra-info.tsx b/app/screens/send-bitcoin-screen/send-bitcoin-details-extra-info.tsx index 221841b37f..dcfbdfe450 100644 --- a/app/screens/send-bitcoin-screen/send-bitcoin-details-extra-info.tsx +++ b/app/screens/send-bitcoin-screen/send-bitcoin-details-extra-info.tsx @@ -6,9 +6,11 @@ import { Text, makeStyles } from "@rneui/themed" import { AccountLevel } from "@app/graphql/level-context" import { useI18nContext } from "@app/i18n/i18n-react" import { useDisplayCurrency } from "@app/hooks/use-display-currency" + +import { GaloyPrimaryButton } from "@app/components/atomic/galoy-primary-button" import { useNavigation } from "@react-navigation/native" -import { RootStackParamList } from "@app/navigation/stack-param-lists" import { StackNavigationProp } from "@react-navigation/stack" +import { RootStackParamList } from "@app/navigation/stack-param-lists" export type SendBitcoinDetailsExtraInfoProps = { errorMessage?: string @@ -21,17 +23,14 @@ export const SendBitcoinDetailsExtraInfo = ({ amountStatus, currentLevel, }: SendBitcoinDetailsExtraInfoProps) => { + const navigation = useNavigation>() + const [isUpgradeAccountModalVisible, setIsUpgradeAccountModalVisible] = useState(false) const closeModal = () => setIsUpgradeAccountModalVisible(false) const openModal = () => setIsUpgradeAccountModalVisible(true) const { LL } = useI18nContext() const { formatMoneyAmount } = useDisplayCurrency() const styles = useStyles() - const navigation = useNavigation>() - - const navigateToTransactionLimits = () => { - navigation.navigate("transactionLimitsScreen") - } if (errorMessage) { return @@ -62,13 +61,10 @@ export const SendBitcoinDetailsExtraInfo = ({ ) : null} {currentLevel === "ONE" ? ( - - {LL.TransactionLimitsScreen.contactSupportToPerformKyc()} - + navigation.navigate("fullOnboardingFlow")} + /> ) : null} ) diff --git a/app/screens/settings-screen/transaction-limits-screen.tsx b/app/screens/settings-screen/transaction-limits-screen.tsx index cba801fd95..fefc4e5253 100644 --- a/app/screens/settings-screen/transaction-limits-screen.tsx +++ b/app/screens/settings-screen/transaction-limits-screen.tsx @@ -1,5 +1,5 @@ import React from "react" -import { ActivityIndicator, Button, Pressable, View } from "react-native" +import { ActivityIndicator, Button, View } from "react-native" import { LocalizedString } from "typesafe-i18n" import { Screen } from "@app/components/screen" @@ -11,13 +11,12 @@ import { useDisplayCurrency } from "@app/hooks/use-display-currency" import { useAppConfig, usePriceConversion } from "@app/hooks" import { DisplayCurrency, toUsdMoneyAmount } from "@app/types/amounts" import { makeStyles, Text, useTheme } from "@rneui/themed" -import ContactModal, { - SupportChannels, -} from "@app/components/contact-modal/contact-modal" -import { GaloyIcon } from "@app/components/atomic/galoy-icon" import { UpgradeAccountModal } from "@app/components/upgrade-account-modal" import { AccountLevel, useLevel } from "@app/graphql/level-context" import { GaloyPrimaryButton } from "@app/components/atomic/galoy-primary-button" +import { useNavigation } from "@react-navigation/native" +import { StackNavigationProp } from "@react-navigation/stack" +import { RootStackParamList } from "@app/navigation/stack-param-lists" const useStyles = makeStyles(({ colors }) => ({ limitWrapper: { @@ -119,6 +118,8 @@ gql` ` export const TransactionLimitsScreen = () => { + const navigation = useNavigation>() + const styles = useStyles() const { theme: { colors }, @@ -134,23 +135,13 @@ export const TransactionLimitsScreen = () => { const { name: bankName } = appConfig.galoyInstance const { currentLevel } = useLevel() - const [isContactModalVisible, setIsContactModalVisible] = React.useState(false) const [isUpgradeAccountModalVisible, setIsUpgradeAccountModalVisible] = React.useState(false) - const toggleIsContactModalVisible = () => { - setIsContactModalVisible(!isContactModalVisible) - } - const toggleIsUpgradeAccountModalVisible = () => { setIsUpgradeAccountModalVisible(!isUpgradeAccountModalVisible) } - const messageBody = LL.TransactionLimitsScreen.contactUsMessageBody({ - bankName, - }) - const messageSubject = LL.TransactionLimitsScreen.contactUsMessageSubject() - if (error) { return ( @@ -226,31 +217,21 @@ export const TransactionLimitsScreen = () => { ))} - {currentLevel === AccountLevel.Zero ? ( + {currentLevel === AccountLevel.Zero && ( navigation.navigate("phoneFlow")} + containerStyle={styles.increaseLimitsButtonContainer} + /> + )} + {currentLevel === AccountLevel.One && ( + navigation.navigate("fullOnboardingFlow")} containerStyle={styles.increaseLimitsButtonContainer} /> - ) : ( - - - {LL.TransactionLimitsScreen.contactSupportToPerformKyc()} - - - )} - 29.4.0) + - React - PromisesObjC (2.2.0) - PromisesSwift (2.2.0): - PromisesObjC (= 2.2.0) @@ -619,7 +623,7 @@ PODS: - React-Core - RNSVG (13.9.0): - React-Core - - RNVectorIcons (9.2.0): + - RNVectorIcons (10.0.0): - React-Core - vision-camera-code-scanner (0.2.0): - GoogleMLKit/BarcodeScanning @@ -642,6 +646,7 @@ DEPENDENCIES: - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - libevent (~> 2.1.12) + - "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)" - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) @@ -738,6 +743,7 @@ SPEC REPOS: - MLKitCommon - MLKitVision - nanopb + - Onfido - PromisesObjC - PromisesSwift - ZXingObjC @@ -757,6 +763,8 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + onfido-react-native-sdk: + :path: "../node_modules/@onfido/react-native-sdk" RCT-Folly: :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" RCTRequired: @@ -923,6 +931,8 @@ SPEC CHECKSUMS: MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390 MLKitVision: 8baa5f46ee3352614169b85250574fde38c36f49 nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 + Onfido: abc5d9a0da1e3ae9f8b4a2a16cc1e77b7a38b12e + onfido-react-native-sdk: a62bb2bd5a8994ee29effc0412c013dfddf01f7e PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef PromisesSwift: cf9eb58666a43bbe007302226e510b16c1e10959 RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 @@ -986,7 +996,7 @@ SPEC CHECKSUMS: RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef RNShare: da6d90b6dc332f51f86498041d6e34211f96b630 RNSVG: 53c661b76829783cdaf9b7a57258f3d3b4c28315 - RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8 + RNVectorIcons: 8b5bb0fa61d54cd2020af4f24a51841ce365c7e9 vision-camera-code-scanner: dda884a7f3ec8243a2a6d6489b91860648371bca VisionCamera: 523b49054bee9dace64189ab6631cb41e8b83fe0 Yoga: 065f0b74dba4832d6e328238de46eb72c5de9556 diff --git a/package.json b/package.json index 4797fe8c7e..ef42d1edc0 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "@formatjs/intl-relativetimeformat": "^11.2.3", "@galoymoney/client": "^0.2.5", "@galoymoney/react-native-geetest-module": "^0.1.3", + "@onfido/react-native-sdk": "^10.4.0", "@react-native-async-storage/async-storage": "^1.19.3", "@react-native-clipboard/clipboard": "^1.11.1", "@react-native-firebase/analytics": "17", diff --git a/supergraph-config.yaml b/supergraph-config.yaml index cd796f65be..a270e06c7d 100644 --- a/supergraph-config.yaml +++ b/supergraph-config.yaml @@ -3,8 +3,12 @@ subgraphs: galoy: routing_url: url schema: - file: ../galoy/dev/apollo-federation/supergraph.graphql + file: ../galoy/core/api/dev/apollo-federation/supergraph.graphql circles: routing_url: url schema: file: ../blink-circles/src/graphql/schema.graphql + kyc: + routing_url: url + schema: + file: ../blink-kyc/app/graphql/schema.graphql diff --git a/supergraph.graphql b/supergraph.graphql index 6096dfb1de..ba4465c513 100644 --- a/supergraph.graphql +++ b/supergraph.graphql @@ -560,6 +560,7 @@ scalar join__FieldSet enum join__Graph { CIRCLES @join__graph(name: "circles", url: "url") GALOY @join__graph(name: "galoy", url: "url") + KYC @join__graph(name: "kyc", url: "url") } scalar Language @@ -796,6 +797,25 @@ type LnUpdate walletId: WalletId! } +input LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput + @join__type(graph: GALOY) +{ + """Amount in satoshis.""" + amount: SatAmount! + descriptionHash: Hex32Bytes + + """Optional invoice expiration time in minutes.""" + expiresIn: Minutes + + """ + Optional memo for the lightning invoice. Acts as a note to the recipient. + """ + memo: Memo + + """Wallet ID for a USD wallet which belongs to the account of any user.""" + recipientWalletId: WalletId! +} + input LnUsdInvoiceCreateInput @join__type(graph: GALOY) { @@ -870,86 +890,95 @@ type MobileVersions type Mutation @join__type(graph: GALOY) + @join__type(graph: KYC) { - accountDelete: AccountDeletePayload! - accountDisableNotificationCategory(input: AccountDisableNotificationCategoryInput!): AccountUpdateNotificationSettingsPayload! - accountDisableNotificationChannel(input: AccountDisableNotificationChannelInput!): AccountUpdateNotificationSettingsPayload! - accountEnableNotificationCategory(input: AccountEnableNotificationCategoryInput!): AccountUpdateNotificationSettingsPayload! - accountEnableNotificationChannel(input: AccountEnableNotificationChannelInput!): AccountUpdateNotificationSettingsPayload! - accountUpdateDefaultWalletId(input: AccountUpdateDefaultWalletIdInput!): AccountUpdateDefaultWalletIdPayload! - accountUpdateDisplayCurrency(input: AccountUpdateDisplayCurrencyInput!): AccountUpdateDisplayCurrencyPayload! - callbackEndpointAdd(input: CallbackEndpointAddInput!): CallbackEndpointAddPayload! - callbackEndpointDelete(input: CallbackEndpointDeleteInput!): SuccessPayload! - captchaCreateChallenge: CaptchaCreateChallengePayload! - captchaRequestAuthCode(input: CaptchaRequestAuthCodeInput!): SuccessPayload! - deviceNotificationTokenCreate(input: DeviceNotificationTokenCreateInput!): SuccessPayload! - feedbackSubmit(input: FeedbackSubmitInput!): SuccessPayload! + accountDelete: AccountDeletePayload! @join__field(graph: GALOY) + accountDisableNotificationCategory(input: AccountDisableNotificationCategoryInput!): AccountUpdateNotificationSettingsPayload! @join__field(graph: GALOY) + accountDisableNotificationChannel(input: AccountDisableNotificationChannelInput!): AccountUpdateNotificationSettingsPayload! @join__field(graph: GALOY) + accountEnableNotificationCategory(input: AccountEnableNotificationCategoryInput!): AccountUpdateNotificationSettingsPayload! @join__field(graph: GALOY) + accountEnableNotificationChannel(input: AccountEnableNotificationChannelInput!): AccountUpdateNotificationSettingsPayload! @join__field(graph: GALOY) + accountUpdateDefaultWalletId(input: AccountUpdateDefaultWalletIdInput!): AccountUpdateDefaultWalletIdPayload! @join__field(graph: GALOY) + accountUpdateDisplayCurrency(input: AccountUpdateDisplayCurrencyInput!): AccountUpdateDisplayCurrencyPayload! @join__field(graph: GALOY) + callbackEndpointAdd(input: CallbackEndpointAddInput!): CallbackEndpointAddPayload! @join__field(graph: GALOY) + callbackEndpointDelete(input: CallbackEndpointDeleteInput!): SuccessPayload! @join__field(graph: GALOY) + captchaCreateChallenge: CaptchaCreateChallengePayload! @join__field(graph: GALOY) + captchaRequestAuthCode(input: CaptchaRequestAuthCodeInput!): SuccessPayload! @join__field(graph: GALOY) + deviceNotificationTokenCreate(input: DeviceNotificationTokenCreateInput!): SuccessPayload! @join__field(graph: GALOY) + feedbackSubmit(input: FeedbackSubmitInput!): SuccessPayload! @join__field(graph: GALOY) """ Actions a payment which is internal to the ledger e.g. it does not use onchain/lightning. Returns payment status (success, failed, pending, already_paid). """ - intraLedgerPaymentSend(input: IntraLedgerPaymentSendInput!): PaymentSendPayload! + intraLedgerPaymentSend(input: IntraLedgerPaymentSendInput!): PaymentSendPayload! @join__field(graph: GALOY) """ Actions a payment which is internal to the ledger e.g. it does not use onchain/lightning. Returns payment status (success, failed, pending, already_paid). """ - intraLedgerUsdPaymentSend(input: IntraLedgerUsdPaymentSendInput!): PaymentSendPayload! + intraLedgerUsdPaymentSend(input: IntraLedgerUsdPaymentSendInput!): PaymentSendPayload! @join__field(graph: GALOY) """ Returns a lightning invoice for an associated wallet. When invoice is paid the value will be credited to a BTC wallet. Expires after 'expiresIn' or 24 hours. """ - lnInvoiceCreate(input: LnInvoiceCreateInput!): LnInvoicePayload! + lnInvoiceCreate(input: LnInvoiceCreateInput!): LnInvoicePayload! @join__field(graph: GALOY) """ Returns a lightning invoice for an associated wallet. When invoice is paid the value will be credited to a BTC wallet. Expires after 'expiresIn' or 24 hours. """ - lnInvoiceCreateOnBehalfOfRecipient(input: LnInvoiceCreateOnBehalfOfRecipientInput!): LnInvoicePayload! - lnInvoiceFeeProbe(input: LnInvoiceFeeProbeInput!): SatAmountPayload! + lnInvoiceCreateOnBehalfOfRecipient(input: LnInvoiceCreateOnBehalfOfRecipientInput!): LnInvoicePayload! @join__field(graph: GALOY) + lnInvoiceFeeProbe(input: LnInvoiceFeeProbeInput!): SatAmountPayload! @join__field(graph: GALOY) """ Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. Provided wallet can be USD or BTC and must have sufficient balance to cover amount in lightning invoice. Returns payment status (success, failed, pending, already_paid). """ - lnInvoicePaymentSend(input: LnInvoicePaymentInput!): PaymentSendPayload! + lnInvoicePaymentSend(input: LnInvoicePaymentInput!): PaymentSendPayload! @join__field(graph: GALOY) """ Returns a lightning invoice for an associated wallet. Can be used to receive any supported currency value (currently USD or BTC). Expires after 'expiresIn' or 24 hours for BTC invoices or 5 minutes for USD invoices. """ - lnNoAmountInvoiceCreate(input: LnNoAmountInvoiceCreateInput!): LnNoAmountInvoicePayload! + lnNoAmountInvoiceCreate(input: LnNoAmountInvoiceCreateInput!): LnNoAmountInvoicePayload! @join__field(graph: GALOY) """ Returns a lightning invoice for an associated wallet. Can be used to receive any supported currency value (currently USD or BTC). Expires after 'expiresIn' or 24 hours for BTC invoices or 5 minutes for USD invoices. """ - lnNoAmountInvoiceCreateOnBehalfOfRecipient(input: LnNoAmountInvoiceCreateOnBehalfOfRecipientInput!): LnNoAmountInvoicePayload! - lnNoAmountInvoiceFeeProbe(input: LnNoAmountInvoiceFeeProbeInput!): SatAmountPayload! + lnNoAmountInvoiceCreateOnBehalfOfRecipient(input: LnNoAmountInvoiceCreateOnBehalfOfRecipientInput!): LnNoAmountInvoicePayload! @join__field(graph: GALOY) + lnNoAmountInvoiceFeeProbe(input: LnNoAmountInvoiceFeeProbeInput!): SatAmountPayload! @join__field(graph: GALOY) """ Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. Provided wallet must be BTC and must have sufficient balance to cover amount specified in mutation request. Returns payment status (success, failed, pending, already_paid). """ - lnNoAmountInvoicePaymentSend(input: LnNoAmountInvoicePaymentInput!): PaymentSendPayload! - lnNoAmountUsdInvoiceFeeProbe(input: LnNoAmountUsdInvoiceFeeProbeInput!): CentAmountPayload! + lnNoAmountInvoicePaymentSend(input: LnNoAmountInvoicePaymentInput!): PaymentSendPayload! @join__field(graph: GALOY) + lnNoAmountUsdInvoiceFeeProbe(input: LnNoAmountUsdInvoiceFeeProbeInput!): CentAmountPayload! @join__field(graph: GALOY) """ Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. Provided wallet must be USD and have sufficient balance to cover amount specified in mutation request. Returns payment status (success, failed, pending, already_paid). """ - lnNoAmountUsdInvoicePaymentSend(input: LnNoAmountUsdInvoicePaymentInput!): PaymentSendPayload! + lnNoAmountUsdInvoicePaymentSend(input: LnNoAmountUsdInvoicePaymentInput!): PaymentSendPayload! @join__field(graph: GALOY) + + """ + Returns a lightning invoice denominated in satoshis for an associated wallet. + When invoice is paid the equivalent value at invoice creation will be credited to a USD wallet. + Expires after 'expiresIn' or 5 minutes (short expiry time because there is a USD/BTC exchange rate + associated with the amount). + """ + lnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient(input: LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput!): LnInvoicePayload! @join__field(graph: GALOY) """ Returns a lightning invoice denominated in satoshis for an associated wallet. @@ -957,7 +986,7 @@ type Mutation Expires after 'expiresIn' or 5 minutes (short expiry time because there is a USD/BTC exchange rate associated with the amount). """ - lnUsdInvoiceCreate(input: LnUsdInvoiceCreateInput!): LnInvoicePayload! + lnUsdInvoiceCreate(input: LnUsdInvoiceCreateInput!): LnInvoicePayload! @join__field(graph: GALOY) """ Returns a lightning invoice denominated in satoshis for an associated wallet. @@ -965,31 +994,32 @@ type Mutation Expires after 'expiresIn' or 5 minutes (short expiry time because there is a USD/BTC exchange rate associated with the amount). """ - lnUsdInvoiceCreateOnBehalfOfRecipient(input: LnUsdInvoiceCreateOnBehalfOfRecipientInput!): LnInvoicePayload! - lnUsdInvoiceFeeProbe(input: LnUsdInvoiceFeeProbeInput!): SatAmountPayload! - onChainAddressCreate(input: OnChainAddressCreateInput!): OnChainAddressPayload! - onChainAddressCurrent(input: OnChainAddressCurrentInput!): OnChainAddressPayload! - onChainPaymentSend(input: OnChainPaymentSendInput!): PaymentSendPayload! - onChainPaymentSendAll(input: OnChainPaymentSendAllInput!): PaymentSendPayload! - onChainUsdPaymentSend(input: OnChainUsdPaymentSendInput!): PaymentSendPayload! - onChainUsdPaymentSendAsBtcDenominated(input: OnChainUsdPaymentSendAsBtcDenominatedInput!): PaymentSendPayload! - quizCompleted(input: QuizCompletedInput!): QuizCompletedPayload! - userContactUpdateAlias(input: UserContactUpdateAliasInput!): UserContactUpdateAliasPayload! @deprecated(reason: "will be moved to AccountContact") - userEmailDelete: UserEmailDeletePayload! - userEmailRegistrationInitiate(input: UserEmailRegistrationInitiateInput!): UserEmailRegistrationInitiatePayload! - userEmailRegistrationValidate(input: UserEmailRegistrationValidateInput!): UserEmailRegistrationValidatePayload! - userLogin(input: UserLoginInput!): AuthTokenPayload! - userLoginUpgrade(input: UserLoginUpgradeInput!): UpgradePayload! - userLogout(input: UserLogoutInput): SuccessPayload! - userPhoneDelete: UserPhoneDeletePayload! - userPhoneRegistrationInitiate(input: UserPhoneRegistrationInitiateInput!): SuccessPayload! - userPhoneRegistrationValidate(input: UserPhoneRegistrationValidateInput!): UserPhoneRegistrationValidatePayload! - userQuizQuestionUpdateCompleted(input: UserQuizQuestionUpdateCompletedInput!): UserQuizQuestionUpdateCompletedPayload! @deprecated(reason: "Use QuizCompletedMutation instead") - userTotpDelete(input: UserTotpDeleteInput!): UserTotpDeletePayload! - userTotpRegistrationInitiate(input: UserTotpRegistrationInitiateInput!): UserTotpRegistrationInitiatePayload! - userTotpRegistrationValidate(input: UserTotpRegistrationValidateInput!): UserTotpRegistrationValidatePayload! - userUpdateLanguage(input: UserUpdateLanguageInput!): UserUpdateLanguagePayload! - userUpdateUsername(input: UserUpdateUsernameInput!): UserUpdateUsernamePayload! @deprecated(reason: "Username will be moved to @Handle in Accounts. Also SetUsername naming should be used instead of UpdateUsername to reflect the idempotency of Handles") + lnUsdInvoiceCreateOnBehalfOfRecipient(input: LnUsdInvoiceCreateOnBehalfOfRecipientInput!): LnInvoicePayload! @join__field(graph: GALOY) + lnUsdInvoiceFeeProbe(input: LnUsdInvoiceFeeProbeInput!): SatAmountPayload! @join__field(graph: GALOY) + onChainAddressCreate(input: OnChainAddressCreateInput!): OnChainAddressPayload! @join__field(graph: GALOY) + onChainAddressCurrent(input: OnChainAddressCurrentInput!): OnChainAddressPayload! @join__field(graph: GALOY) + onChainPaymentSend(input: OnChainPaymentSendInput!): PaymentSendPayload! @join__field(graph: GALOY) + onChainPaymentSendAll(input: OnChainPaymentSendAllInput!): PaymentSendPayload! @join__field(graph: GALOY) + onChainUsdPaymentSend(input: OnChainUsdPaymentSendInput!): PaymentSendPayload! @join__field(graph: GALOY) + onChainUsdPaymentSendAsBtcDenominated(input: OnChainUsdPaymentSendAsBtcDenominatedInput!): PaymentSendPayload! @join__field(graph: GALOY) + quizCompleted(input: QuizCompletedInput!): QuizCompletedPayload! @join__field(graph: GALOY) + userContactUpdateAlias(input: UserContactUpdateAliasInput!): UserContactUpdateAliasPayload! @join__field(graph: GALOY) @deprecated(reason: "will be moved to AccountContact") + userEmailDelete: UserEmailDeletePayload! @join__field(graph: GALOY) + userEmailRegistrationInitiate(input: UserEmailRegistrationInitiateInput!): UserEmailRegistrationInitiatePayload! @join__field(graph: GALOY) + userEmailRegistrationValidate(input: UserEmailRegistrationValidateInput!): UserEmailRegistrationValidatePayload! @join__field(graph: GALOY) + userLogin(input: UserLoginInput!): AuthTokenPayload! @join__field(graph: GALOY) + userLoginUpgrade(input: UserLoginUpgradeInput!): UpgradePayload! @join__field(graph: GALOY) + userLogout(input: UserLogoutInput): SuccessPayload! @join__field(graph: GALOY) + userPhoneDelete: UserPhoneDeletePayload! @join__field(graph: GALOY) + userPhoneRegistrationInitiate(input: UserPhoneRegistrationInitiateInput!): SuccessPayload! @join__field(graph: GALOY) + userPhoneRegistrationValidate(input: UserPhoneRegistrationValidateInput!): UserPhoneRegistrationValidatePayload! @join__field(graph: GALOY) + userQuizQuestionUpdateCompleted(input: UserQuizQuestionUpdateCompletedInput!): UserQuizQuestionUpdateCompletedPayload! @join__field(graph: GALOY) @deprecated(reason: "Use QuizCompletedMutation instead") + userTotpDelete(input: UserTotpDeleteInput!): UserTotpDeletePayload! @join__field(graph: GALOY) + userTotpRegistrationInitiate(input: UserTotpRegistrationInitiateInput!): UserTotpRegistrationInitiatePayload! @join__field(graph: GALOY) + userTotpRegistrationValidate(input: UserTotpRegistrationValidateInput!): UserTotpRegistrationValidatePayload! @join__field(graph: GALOY) + userUpdateLanguage(input: UserUpdateLanguageInput!): UserUpdateLanguagePayload! @join__field(graph: GALOY) + userUpdateUsername(input: UserUpdateUsernameInput!): UserUpdateUsernamePayload! @join__field(graph: GALOY) @deprecated(reason: "Username will be moved to @Handle in Accounts. Also SetUsername naming should be used instead of UpdateUsername to reflect the idempotency of Handles") + onboardingFlowStart(input: OnboardingFlowStartInput!): OnboardingFlowStartResult! @join__field(graph: KYC) } type MyUpdatesPayload @@ -1031,6 +1061,22 @@ type NotificationSettings push: NotificationChannelSettings! } +input OnboardingFlowStartInput + @join__type(graph: KYC) +{ + firstName: String! + lastName: String! + accountId: String! +} + +type OnboardingFlowStartResult + @join__type(graph: KYC) +{ + workflowRunId: String! + tokenAndroid: String! + tokenIos: String! +} + """An address for an on-chain bitcoin destination""" scalar OnChainAddress @join__type(graph: GALOY) @@ -1299,6 +1345,7 @@ type PublicWallet type Query @join__type(graph: CIRCLES) @join__type(graph: GALOY) + @join__type(graph: KYC) { welcomeLeaderboard(input: WelcomeLeaderboardInput!): Leaderboard! @join__field(graph: CIRCLES) accountDefaultWallet(username: Username!, walletCurrency: WalletCurrency): PublicWallet! @join__field(graph: GALOY) @@ -1319,6 +1366,7 @@ type Query realtimePrice(currency: DisplayCurrency = "USD"): RealtimePrice! @join__field(graph: GALOY) userDefaultWalletId(username: Username!): WalletId! @join__field(graph: GALOY) @deprecated(reason: "will be migrated to AccountDefaultWalletId") usernameAvailable(username: Username!): Boolean @join__field(graph: GALOY) + hello: String @join__field(graph: KYC) } type Quiz diff --git a/yarn.lock b/yarn.lock index a07454a1fd..062762a8bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3952,6 +3952,13 @@ mkdirp "^1.0.4" rimraf "^3.0.2" +"@onfido/react-native-sdk@^10.4.0": + version "10.4.0" + resolved "https://registry.npmjs.org/@onfido/react-native-sdk/-/react-native-sdk-10.4.0.tgz#e0cd780f457ae72c54a15f73ea0e76a551b0b437" + integrity sha512-bOKxhpepTizfNoJsv/vtEXQS/W9xT8BtC7ahC7lXC0U2nNNihUUk3yxoJFb7aVqD2in5D4DFnh8Uk57NnAfOFg== + dependencies: + js-base64 "3.7.5" + "@peculiar/asn1-schema@^2.1.6", "@peculiar/asn1-schema@^2.3.0": version "2.3.3" resolved "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.3.tgz#21418e1f3819e0b353ceff0c2dad8ccb61acd777" @@ -15453,6 +15460,11 @@ jpeg-js@^0.4.1, jpeg-js@^0.4.4: resolved "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== +js-base64@3.7.5: + version "3.7.5" + resolved "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz#21e24cf6b886f76d6f5f165bfcd69cc55b9e3fca" + integrity sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA== + js-library-detector@^6.4.0: version "6.6.0" resolved "https://registry.npmjs.org/js-library-detector/-/js-library-detector-6.6.0.tgz#b531a4784f8242d87f68f6f3eafc771a0650fb9d"