chore: enable sumsub (#1737)

* enable sumsub

* bugbot feedback
This commit is contained in:
Justin Hernandez
2026-02-12 14:42:18 -08:00
committed by GitHub
parent 575566f7f2
commit de8787ef1a
12 changed files with 155 additions and 205 deletions

View File

@@ -24,9 +24,11 @@ export interface UseSumsubLauncherOptions {
*/
errorSource: FallbackErrorSource;
/**
* Optional callback to handle successful verification
* Optional callback to handle successful verification.
* Receives the Sumsub result and the userId from the access token.
* If not provided, defaults to navigating to KycSuccess with the userId.
*/
onSuccess?: (result: SumsubResult) => void | Promise<void>;
onSuccess?: (result: SumsubResult, userId: string) => void | Promise<void>;
/**
* Optional callback to handle user cancellation
*/
@@ -96,8 +98,12 @@ export const useSumsubLauncher = (options: UseSumsubLauncherOptions) => {
return;
}
// Handle success
await onSuccess?.(result);
// Handle success - navigate to KycSuccess by default
if (onSuccess) {
await onSuccess(result, accessToken.userId);
} else {
navigation.navigate('KycSuccess', { userId: accessToken.userId });
}
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);

View File

@@ -41,8 +41,6 @@ const DevSettingsScreen: React.FC = () => {
const setLoggingSeverity = useSettingStore(state => state.setLoggingSeverity);
const useStrongBox = useSettingStore(state => state.useStrongBox);
const setUseStrongBox = useSettingStore(state => state.setUseStrongBox);
const kycEnabled = useSettingStore(state => state.kycEnabled);
const setKycEnabled = useSettingStore(state => state.setKycEnabled);
// Custom hooks
const { hasNotificationPermission, subscribedTopics, handleTopicToggle } =
@@ -98,8 +96,6 @@ const DevSettingsScreen: React.FC = () => {
{IS_DEV_MODE && (
<DevTogglesSection
kycEnabled={kycEnabled}
setKycEnabled={setKycEnabled}
useStrongBox={useStrongBox}
setUseStrongBox={setUseStrongBox}
/>

View File

@@ -10,15 +10,11 @@ import { ParameterSection } from '@/screens/dev/components/ParameterSection';
import { TopicToggleButton } from '@/screens/dev/components/TopicToggleButton';
interface DevTogglesSectionProps {
kycEnabled: boolean;
setKycEnabled: (enabled: boolean) => void;
useStrongBox: boolean;
setUseStrongBox: (useStrongBox: boolean) => void;
}
export const DevTogglesSection: React.FC<DevTogglesSectionProps> = ({
kycEnabled,
setKycEnabled,
useStrongBox,
setUseStrongBox,
}) => {
@@ -44,11 +40,6 @@ export const DevTogglesSection: React.FC<DevTogglesSectionProps> = ({
title="Options"
description="Development and security options"
>
<TopicToggleButton
label="KYC Flow"
isSubscribed={kycEnabled}
onToggle={() => setKycEnabled(!kycEnabled)}
/>
{Platform.OS === 'android' && (
<TopicToggleButton
label="Use StrongBox"

View File

@@ -30,7 +30,6 @@ import { NavBar } from '@/components/navbar/BaseNavBar';
import { useSumsubLauncher } from '@/hooks/useSumsubLauncher';
import { buttonTap } from '@/integrations/haptics';
import type { RootStackParamList } from '@/navigation';
import { useSettingStore } from '@/stores/settingStore';
import { extraYPadding } from '@/utils/styleUtils';
type AadhaarUploadErrorRouteParams = {
@@ -67,7 +66,6 @@ const AadhaarUploadErrorScreen: React.FC = () => {
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const route = useRoute<AadhaarUploadErrorRoute>();
const { trackEvent } = useSelfClient();
const kycEnabled = useSettingStore(state => state.kycEnabled);
const errorType = route.params?.errorType || 'general';
const { title, description } = getErrorMessages(errorType);
@@ -82,9 +80,6 @@ const AadhaarUploadErrorScreen: React.FC = () => {
onError: () => {
// Stay on this screen - user can try again
},
onSuccess: () => {
// Success - provider handles its own success UI
},
},
);
@@ -216,44 +211,40 @@ const AadhaarUploadErrorScreen: React.FC = () => {
paddingBottom={paddingBottom}
gap={10}
>
{kycEnabled && (
<>
{/* Secondary Button - White fill, black text, rounded */}
<Button
backgroundColor={white}
borderWidth={1}
borderColor={slate200}
borderRadius={100}
height={52}
pressStyle={{ opacity: 0.8 }}
onPress={handleTryAlternative}
disabled={isRetrying}
>
<BodyText
style={{
fontSize: 17,
fontWeight: '500',
fontFamily: dinot,
color: black,
}}
>
{isRetrying ? 'Loading...' : 'Try a different method'}
</BodyText>
</Button>
{/* Secondary Button - White fill, black text, rounded */}
<Button
backgroundColor={white}
borderWidth={1}
borderColor={slate200}
borderRadius={100}
height={52}
pressStyle={{ opacity: 0.8 }}
onPress={handleTryAlternative}
disabled={isRetrying}
>
<BodyText
style={{
fontSize: 17,
fontWeight: '500',
fontFamily: dinot,
color: black,
}}
>
{isRetrying ? 'Loading...' : 'Try a different method'}
</BodyText>
</Button>
{/* Footer Text - Not italic */}
<BodyText
style={{
fontSize: 16,
textAlign: 'center',
color: slate500,
}}
>
Registering with alternative methods may take longer to verify
your document.
</BodyText>
</>
)}
{/* Footer Text - Not italic */}
<BodyText
style={{
fontSize: 16,
textAlign: 'center',
color: slate500,
}}
>
Registering with alternative methods may take longer to verify your
document.
</BodyText>
</YStack>
</YStack>
);

View File

@@ -20,7 +20,6 @@ import useHapticNavigation from '@/hooks/useHapticNavigation';
import { useSumsubLauncher } from '@/hooks/useSumsubLauncher';
import SimpleScrolledTitleLayout from '@/layouts/SimpleScrolledTitleLayout';
import { flush as flushAnalytics } from '@/services/analytics';
import { useSettingStore } from '@/stores/settingStore';
const tips: TipProps[] = [
{
@@ -55,7 +54,6 @@ const DocumentCameraTroubleScreen: React.FC = () => {
const selfClient = useSelfClient();
const { useMRZStore } = selfClient;
const { countryCode } = useMRZStore();
const kycEnabled = useSettingStore(state => state.kycEnabled);
const { launchSumsubVerification, isLoading } = useSumsubLauncher({
countryCode,
errorSource: 'mrz_scan_failed',
@@ -82,25 +80,21 @@ const DocumentCameraTroubleScreen: React.FC = () => {
page quickly and clearly!
</Caption>
{kycEnabled && (
<>
<Caption
size="large"
style={{ color: slate500, marginTop: 12, marginBottom: 8 }}
>
Or try an alternative verification method:
</Caption>
<Caption
size="large"
style={{ color: slate500, marginTop: 12, marginBottom: 8 }}
>
Or try an alternative verification method:
</Caption>
<SecondaryButton
onPress={launchSumsubVerification}
disabled={isLoading}
textColor={slate700}
style={{ marginBottom: 0 }}
>
{isLoading ? 'Loading...' : 'Try Alternative Verification'}
</SecondaryButton>
</>
)}
<SecondaryButton
onPress={launchSumsubVerification}
disabled={isLoading}
textColor={slate700}
style={{ marginBottom: 0 }}
>
{isLoading ? 'Loading...' : 'Try Alternative Verification'}
</SecondaryButton>
</YStack>
}
>

View File

@@ -21,7 +21,6 @@ import { selectionChange } from '@/integrations/haptics';
import SimpleScrolledTitleLayout from '@/layouts/SimpleScrolledTitleLayout';
import { flushAllAnalytics } from '@/services/analytics';
import { openSupportForm, SUPPORT_FORM_BUTTON_TEXT } from '@/services/support';
import { useSettingStore } from '@/stores/settingStore';
const tips: TipProps[] = [
{
@@ -62,7 +61,6 @@ const DocumentNFCTroubleScreen: React.FC = () => {
const selfClient = useSelfClient();
const { useMRZStore } = selfClient;
const { countryCode } = useMRZStore();
const kycEnabled = useSettingStore(state => state.kycEnabled);
const { launchSumsubVerification, isLoading } = useSumsubLauncher({
countryCode,
errorSource: 'nfc_scan_failed',
@@ -97,16 +95,14 @@ const DocumentNFCTroubleScreen: React.FC = () => {
{SUPPORT_FORM_BUTTON_TEXT}
</SecondaryButton>
{kycEnabled && (
<SecondaryButton
onPress={launchSumsubVerification}
disabled={isLoading}
textColor={slate700}
style={{ marginBottom: 0 }}
>
{isLoading ? 'Loading...' : 'Try Alternative Verification'}
</SecondaryButton>
)}
<SecondaryButton
onPress={launchSumsubVerification}
disabled={isLoading}
textColor={slate700}
style={{ marginBottom: 0 }}
>
{isLoading ? 'Loading...' : 'Try Alternative Verification'}
</SecondaryButton>
</YStack>
}
>

View File

@@ -28,7 +28,6 @@ import { NavBar } from '@/components/navbar/BaseNavBar';
import { useSumsubLauncher } from '@/hooks/useSumsubLauncher';
import { buttonTap } from '@/integrations/haptics';
import type { RootStackParamList } from '@/navigation';
import { useSettingStore } from '@/stores/settingStore';
import { extraYPadding } from '@/utils/styleUtils';
type RegistrationFallbackMRZRouteParams = {
@@ -61,7 +60,6 @@ const RegistrationFallbackMRZScreen: React.FC = () => {
const { trackEvent, useMRZStore } = selfClient;
const storeCountryCode = useMRZStore(state => state.countryCode);
const documentType = useMRZStore(state => state.documentType);
const kycEnabled = useSettingStore(state => state.kycEnabled);
// Use country code from route params, or fall back to MRZ store
const countryCode = route.params?.countryCode || storeCountryCode || '';
@@ -79,10 +77,6 @@ const RegistrationFallbackMRZScreen: React.FC = () => {
// Stay on this screen - user can try again
// Error is already logged in the hook
},
onSuccess: () => {
// Success - provider handles its own success UI
// The screen will be navigated away by the provider's flow
},
},
);
@@ -216,44 +210,40 @@ const RegistrationFallbackMRZScreen: React.FC = () => {
paddingBottom={paddingBottom}
gap={10}
>
{kycEnabled && (
<>
{/* Secondary Button - White fill, black text, rounded */}
<Button
backgroundColor={white}
borderWidth={1}
borderColor={slate200}
borderRadius={100}
height={52}
pressStyle={{ opacity: 0.8 }}
onPress={handleTryAlternative}
disabled={isRetrying}
>
<BodyText
style={{
fontSize: 17,
fontWeight: '500',
fontFamily: dinot,
color: black,
}}
>
{isRetrying ? 'Loading...' : 'Try a different method'}
</BodyText>
</Button>
{/* Secondary Button - White fill, black text, rounded */}
<Button
backgroundColor={white}
borderWidth={1}
borderColor={slate200}
borderRadius={100}
height={52}
pressStyle={{ opacity: 0.8 }}
onPress={handleTryAlternative}
disabled={isRetrying}
>
<BodyText
style={{
fontSize: 17,
fontWeight: '500',
fontFamily: dinot,
color: black,
}}
>
{isRetrying ? 'Loading...' : 'Try a different method'}
</BodyText>
</Button>
{/* Footer Text - Not italic */}
<BodyText
style={{
fontSize: 16,
textAlign: 'center',
color: slate500,
}}
>
Registering with alternative methods may take longer to verify
your document.
</BodyText>
</>
)}
{/* Footer Text - Not italic */}
<BodyText
style={{
fontSize: 16,
textAlign: 'center',
color: slate500,
}}
>
Registering with alternative methods may take longer to verify your
document.
</BodyText>
</YStack>
</YStack>
);

View File

@@ -29,7 +29,6 @@ import { NavBar } from '@/components/navbar/BaseNavBar';
import { useSumsubLauncher } from '@/hooks/useSumsubLauncher';
import { buttonTap } from '@/integrations/haptics';
import type { RootStackParamList } from '@/navigation';
import { useSettingStore } from '@/stores/settingStore';
import { extraYPadding } from '@/utils/styleUtils';
type RegistrationFallbackNFCRouteParams = {
@@ -62,7 +61,6 @@ const RegistrationFallbackNFCScreen: React.FC = () => {
const { trackEvent, useMRZStore } = selfClient;
const storeCountryCode = useMRZStore(state => state.countryCode);
const documentType = useMRZStore(state => state.documentType);
const kycEnabled = useSettingStore(state => state.kycEnabled);
// Use country code from route params, or fall back to MRZ store
const countryCode = route.params?.countryCode || storeCountryCode || '';
@@ -80,10 +78,6 @@ const RegistrationFallbackNFCScreen: React.FC = () => {
// Stay on this screen - user can try again
// Error is already logged in the hook
},
onSuccess: () => {
// Success - provider handles its own success UI
// The screen will be navigated away by the provider's flow
},
},
);
@@ -242,44 +236,40 @@ const RegistrationFallbackNFCScreen: React.FC = () => {
paddingBottom={paddingBottom}
gap={10}
>
{kycEnabled && (
<>
{/* Secondary Button - White fill, black text, rounded */}
<Button
backgroundColor={white}
borderWidth={1}
borderColor={slate200}
borderRadius={100}
height={52}
pressStyle={{ opacity: 0.8 }}
onPress={handleTryAlternative}
disabled={isRetrying}
>
<BodyText
style={{
fontSize: 17,
fontWeight: '500',
fontFamily: dinot,
color: black,
}}
>
{isRetrying ? 'Loading...' : 'Try a different method'}
</BodyText>
</Button>
{/* Secondary Button - White fill, black text, rounded */}
<Button
backgroundColor={white}
borderWidth={1}
borderColor={slate200}
borderRadius={100}
height={52}
pressStyle={{ opacity: 0.8 }}
onPress={handleTryAlternative}
disabled={isRetrying}
>
<BodyText
style={{
fontSize: 17,
fontWeight: '500',
fontFamily: dinot,
color: black,
}}
>
{isRetrying ? 'Loading...' : 'Try a different method'}
</BodyText>
</Button>
{/* Footer Text - Not italic */}
<BodyText
style={{
fontSize: 16,
textAlign: 'center',
color: slate500,
}}
>
Registering with alternative methods may take longer to verify
your document.
</BodyText>
</>
)}
{/* Footer Text - Not italic */}
<BodyText
style={{
fontSize: 16,
textAlign: 'center',
color: slate500,
}}
>
Registering with alternative methods may take longer to verify your
document.
</BodyText>
</YStack>
</YStack>
);

View File

@@ -13,7 +13,6 @@ import IDSelection from '@selfxyz/mobile-sdk-alpha/onboarding/id-selection-scree
import { DocumentFlowNavBar } from '@/components/navbar/DocumentFlowNavBar';
import type { RootStackParamList } from '@/navigation';
import { useSettingStore } from '@/stores/settingStore';
import { extraYPadding } from '@/utils/styleUtils';
type IDPickerScreenRouteProp = RouteProp<RootStackParamList, 'IDPicker'>;
@@ -22,7 +21,6 @@ const IDPickerScreen: React.FC = () => {
const route = useRoute<IDPickerScreenRouteProp>();
const { countryCode = '', documentTypes = [] } = route.params || {};
const bottom = useSafeAreaInsets().bottom;
const kycEnabled = useSettingStore(state => state.kycEnabled);
return (
<YStack
@@ -31,11 +29,7 @@ const IDPickerScreen: React.FC = () => {
paddingBottom={bottom + extraYPadding + 24}
>
<DocumentFlowNavBar title="GETTING STARTED" />
<IDSelection
countryCode={countryCode}
documentTypes={documentTypes}
showKyc={kycEnabled}
/>
<IDSelection countryCode={countryCode} documentTypes={documentTypes} />
</YStack>
);
};

View File

@@ -33,7 +33,6 @@ import {
import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout';
import type { RootStackParamList } from '@/navigation';
import { useFeedback } from '@/providers/feedbackProvider';
import { useSettingStore } from '@/stores/settingStore';
type LogoConfirmationScreenRouteProp = RouteProp<
RootStackParamList,
@@ -47,7 +46,6 @@ const LogoConfirmationScreen: React.FC = () => {
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const { showModal } = useFeedback();
const navigateToOnboarding = useHapticNavigation('DocumentOnboarding');
const kycEnabled = useSettingStore(state => state.kycEnabled);
const handleConfirm = useCallback(() => {
buttonTap();
@@ -72,12 +70,27 @@ const LogoConfirmationScreen: React.FC = () => {
});
// User cancelled/dismissed without completing verification
const cancelledStatuses = ['Initial', 'Incomplete', 'Interrupted'];
if (cancelledStatuses.includes(result.status)) {
if (
!result.success &&
['Initial', 'Incomplete', 'Interrupted'].includes(result.status)
) {
return;
}
// User completed verification - navigate to KycSuccessScreen
// Verification failed (provider error/rejection)
if (!result.success) {
console.error(
'Sumsub verification failed:',
result.errorType ?? result.status,
);
navigation.navigate('KycFailure', {
countryCode,
canRetry: true,
});
return;
}
// Verification succeeded - navigate to KycSuccessScreen
navigation.navigate('KycSuccess', { userId: accessToken.userId });
} catch {
console.error('Error launching Sumsub verification');
@@ -138,9 +151,7 @@ const LogoConfirmationScreen: React.FC = () => {
<ExpandableBottomLayout.BottomSection backgroundColor={slate100}>
<ButtonsContainer>
<PrimaryButton onPress={handleConfirm}>Yes</PrimaryButton>
{kycEnabled && (
<SecondaryButton onPress={handleNotFound}>No</SecondaryButton>
)}
<SecondaryButton onPress={handleNotFound}>No</SecondaryButton>
</ButtonsContainer>
</ExpandableBottomLayout.BottomSection>
</ExpandableBottomLayout.Layout>

View File

@@ -21,7 +21,6 @@ interface PersistedSettingsState {
homeScreenViewCount: number;
incrementHomeScreenViewCount: () => void;
isDevMode: boolean;
kycEnabled: boolean;
loggingSeverity: LoggingSeverity;
pointsAddress: string | null;
removeSubscribedTopic: (topic: string) => void;
@@ -33,7 +32,6 @@ interface PersistedSettingsState {
setFcmToken: (token: string | null) => void;
setHasViewedRecoveryPhrase: (viewed: boolean) => void;
setKeychainMigrationCompleted: () => void;
setKycEnabled: (enabled: boolean) => void;
setLoggingSeverity: (severity: LoggingSeverity) => void;
setPointsAddress: (address: string | null) => void;
setSkipDocumentSelector: (value: boolean) => void;
@@ -150,10 +148,6 @@ export const useSettingStore = create<SettingsState>()(
useStrongBox: false,
setUseStrongBox: (useStrongBox: boolean) => set({ useStrongBox }),
// KYC flow toggle (default: false, dev-only feature)
kycEnabled: false,
setKycEnabled: (enabled: boolean) => set({ kycEnabled: enabled }),
// Non-persisted state (will not be saved to storage)
hideNetworkModal: false,
setHideNetworkModal: (hideNetworkModal: boolean) => {

View File

@@ -128,11 +128,10 @@ const DocumentItem: React.FC<DocumentItemProps> = ({ docType, onPress }) => {
type IDSelectionScreenProps = {
countryCode: string;
documentTypes: string[];
showKyc?: boolean;
};
const IDSelectionScreen: React.FC<IDSelectionScreenProps> = props => {
const { countryCode = '', documentTypes = [], showKyc = false } = props;
const { countryCode = '', documentTypes = [] } = props;
const selfClient = useSelfClient();
const onSelectDocumentType = (docType: string) => {
@@ -173,11 +172,9 @@ const IDSelectionScreen: React.FC<IDSelectionScreenProps> = props => {
<DocumentItem key={docType} docType={docType} onPress={() => onSelectDocumentType(docType)} />
))}
<BodyText style={styles.footerText}>Be sure your document is ready to scan</BodyText>
{showKyc && (
<View style={styles.kycContainer}>
<DocumentItem docType="kyc" onPress={() => onSelectDocumentType('kyc')} />
</View>
)}
<View style={styles.kycContainer}>
<DocumentItem docType="kyc" onPress={() => onSelectDocumentType('kyc')} />
</View>
</YStack>
</YStack>
);