@test-web/react-native-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +58 -0
  2. package/android/build.gradle +50 -0
  3. package/android/src/main/AndroidManifest.xml +24 -0
  4. package/android/src/main/java/com/yourcompany/sdk/YourSDKModule.java +40 -0
  5. package/android/src/main/java/com/yourcompany/sdk/YourSDKPackage.java +24 -0
  6. package/ios/YourSDK-Bridging-Header.h +1 -0
  7. package/ios/YourSDK-Info.plist +30 -0
  8. package/ios/YourSDK.podspec +19 -0
  9. package/ios/YourSDKModule.h +5 -0
  10. package/ios/YourSDKModule.m +32 -0
  11. package/ios/YourSDKModule.swift +22 -0
  12. package/package.json +38 -0
  13. package/src/apis/index.ts +32 -0
  14. package/src/components/common/CustomOverlay.tsx +44 -0
  15. package/src/components/common/Footer.tsx +30 -0
  16. package/src/components/common/Header.tsx +29 -0
  17. package/src/components/common/Loader.tsx +23 -0
  18. package/src/components/index.tsx +6 -0
  19. package/src/components/ui/Button.tsx +41 -0
  20. package/src/components/ui/ThemedText.tsx +42 -0
  21. package/src/components/ui/index.tsx +2 -0
  22. package/src/context/IDMConfigurationContext.tsx +44 -0
  23. package/src/context/KeyboardContext.tsx +61 -0
  24. package/src/context/ThemeContext.tsx +34 -0
  25. package/src/context/themes.ts +134 -0
  26. package/src/hooks/useOrientation.ts +25 -0
  27. package/src/index.tsx +110 -0
  28. package/src/native/NativeModule.ts +10 -0
  29. package/src/screens/BackDocumentAdvice.tsx +52 -0
  30. package/src/screens/BarcodeAdvice.tsx +52 -0
  31. package/src/screens/BarcodeCapture.tsx +66 -0
  32. package/src/screens/CameraPermission.tsx +74 -0
  33. package/src/screens/DocumentCaptureBack.tsx +65 -0
  34. package/src/screens/DocumentCaptureFront.tsx +65 -0
  35. package/src/screens/FrontDocumentAdvice.tsx +52 -0
  36. package/src/screens/LocationPermission.tsx +74 -0
  37. package/src/screens/MrzAdvice.tsx +52 -0
  38. package/src/screens/MrzCapture.tsx +64 -0
  39. package/src/screens/NoCameraFound.tsx +64 -0
  40. package/src/screens/RetakeSelfie.tsx +56 -0
  41. package/src/screens/SelectDocuments.tsx +250 -0
  42. package/src/screens/SelfieAdvice.tsx +35 -0
  43. package/src/screens/SelfieCapture.tsx +56 -0
  44. package/src/screens/ThankYou.tsx +23 -0
  45. package/src/screens/VerifyIdentity.tsx +54 -0
  46. package/src/screens/index.tsx +17 -0
  47. package/src/styles/BarcodeAdviceStyles.ts +45 -0
  48. package/src/styles/DocumentAdviceStyles.ts +44 -0
  49. package/src/styles/DocumentCaptureStyles.ts +55 -0
  50. package/src/styles/PermissionStyle.ts +61 -0
  51. package/src/styles/RetakeStyles.ts +67 -0
  52. package/src/styles/ScannerStyles.ts +28 -0
  53. package/src/styles/SelectDocumentsStyles.ts +90 -0
  54. package/src/styles/SelfieAdviceStyles.ts +61 -0
  55. package/src/styles/SelfieCaptureStyles.ts +48 -0
  56. package/src/styles/ThankYouStyles.ts +31 -0
  57. package/src/styles/VerifyIdentityStyles.ts +86 -0
  58. package/src/types/IDMConf.ts +28 -0
  59. package/src/types/index.ts +12 -0
  60. package/src/utils/index.ts +19 -0
  61. package/src/utils/metadata_new.json +1 -0
  62. package/src/utils/performance.ts +176 -0
@@ -0,0 +1,61 @@
1
+ import React, {
2
+ createContext,
3
+ useContext,
4
+ useState,
5
+ useEffect,
6
+ useMemo,
7
+ useCallback,
8
+ ReactNode,
9
+ } from 'react';
10
+ import { Keyboard } from 'react-native';
11
+
12
+ interface KeyboardContextType {
13
+ isKeyboardVisible: boolean;
14
+ setKeyboardVisible: (visible: boolean) => void;
15
+ }
16
+
17
+ const KeyboardContext = createContext<KeyboardContextType | undefined>(
18
+ undefined
19
+ );
20
+
21
+ interface KeyboardProviderProps {
22
+ children: ReactNode;
23
+ }
24
+
25
+ export function KeyboardProvider({ children }: KeyboardProviderProps) {
26
+ const [isKeyboardVisible, setKeyboardVisible] = useState(false);
27
+
28
+ useEffect(() => {
29
+ const showSubscription = Keyboard.addListener('keyboardDidShow', () => {
30
+ setKeyboardVisible(true);
31
+ });
32
+ const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
33
+ setKeyboardVisible(false);
34
+ });
35
+
36
+ return () => {
37
+ showSubscription.remove();
38
+ hideSubscription.remove();
39
+ };
40
+ }, []);
41
+
42
+ // Memoize context value to prevent unnecessary re-renders
43
+ const value = useMemo(
44
+ () => ({ isKeyboardVisible, setKeyboardVisible }),
45
+ [isKeyboardVisible]
46
+ );
47
+
48
+ return (
49
+ <KeyboardContext.Provider value={value}>
50
+ {children}
51
+ </KeyboardContext.Provider>
52
+ );
53
+ }
54
+
55
+ export function useKeyboard() {
56
+ const context = useContext(KeyboardContext);
57
+ if (!context) {
58
+ throw new Error('useKeyboard must be used within KeyboardProvider');
59
+ }
60
+ return context;
61
+ }
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import { Theme } from '../types';
3
+ import { themes } from './themes';
4
+
5
+ interface ThemeContextType {
6
+ theme: Theme;
7
+ setTheme: (theme: Theme) => void;
8
+ }
9
+
10
+ const ThemeContext = React.createContext<ThemeContextType>({
11
+ theme: themes.light,
12
+ setTheme: () => {},
13
+ });
14
+
15
+ export const useTheme = () => React.useContext(ThemeContext);
16
+
17
+ export const ThemeProvider = ({
18
+ children,
19
+ theme: initialTheme = themes.light,
20
+ }: {
21
+ children: React.ReactNode;
22
+ theme?: Theme;
23
+ }) => {
24
+ const [theme, setTheme] = React.useState(initialTheme);
25
+
26
+ // Memoize context value to prevent unnecessary re-renders
27
+ const value = React.useMemo(() => ({ theme, setTheme }), [theme]);
28
+
29
+ return (
30
+ <ThemeContext.Provider value={value}>
31
+ {children}
32
+ </ThemeContext.Provider>
33
+ );
34
+ };
@@ -0,0 +1,134 @@
1
+ import { Theme } from '../types';
2
+
3
+ // 🌞 Light (default)
4
+ export const lightTheme: Theme = {
5
+ colors: {
6
+ primary: '#007bff',
7
+ background: '#ffffff',
8
+ text: '#111827',
9
+ subtitle: '#6b7280',
10
+ buttonText: '#ffffff',
11
+ buttonBackground: '#007bff',
12
+ },
13
+ };
14
+
15
+ // 🌑 Dark (default)
16
+ export const darkTheme: Theme = {
17
+ colors: {
18
+ primary: '#3b82f6',
19
+ background: '#111827',
20
+ text: '#f9fafb',
21
+ subtitle: '#9ca3af',
22
+ buttonText: '#111827',
23
+ buttonBackground: '#3b82f6',
24
+ },
25
+ };
26
+
27
+ // 🌅 Sunset (warm oranges)
28
+ export const sunsetTheme: Theme = {
29
+ colors: {
30
+ primary: '#f97316',
31
+ background: '#fff7ed',
32
+ text: '#7c2d12',
33
+ subtitle: '#b45309',
34
+ buttonText: '#ffffff',
35
+ buttonBackground: '#f97316',
36
+ },
37
+ };
38
+
39
+ // 🌊 Ocean (blues & teal)
40
+ export const oceanTheme: Theme = {
41
+ colors: {
42
+ primary: '#0284c7',
43
+ background: '#f0f9ff',
44
+ text: '#0c4a6e',
45
+ subtitle: '#0369a1',
46
+ buttonText: '#ffffff',
47
+ buttonBackground: '#0284c7',
48
+ },
49
+ };
50
+
51
+ // 🌿 Forest (greens)
52
+ export const forestTheme: Theme = {
53
+ colors: {
54
+ primary: '#16a34a',
55
+ background: '#ffffff',
56
+ text: '#16a34a',
57
+ subtitle: '#16a34a',
58
+ buttonText: '#ffffff',
59
+ buttonBackground: '#3fa564',
60
+ },
61
+ };
62
+
63
+ // 🎨 Pastel (lavender & purple)
64
+ export const pastelTheme: Theme = {
65
+ colors: {
66
+ primary: '#a78bfa',
67
+ background: '#faf5ff',
68
+ text: '#4c1d95',
69
+ subtitle: '#7c3aed',
70
+ buttonText: '#ffffff',
71
+ buttonBackground: '#a78bfa',
72
+ },
73
+ };
74
+
75
+ // ⚡ High Contrast (accessibility)
76
+ export const highContrastTheme: Theme = {
77
+ colors: {
78
+ primary: '#ffcc00',
79
+ background: '#000000',
80
+ text: '#ffffff',
81
+ subtitle: '#ffcc00',
82
+ buttonText: '#000000',
83
+ buttonBackground: '#ffcc00',
84
+ },
85
+ };
86
+
87
+ // 💼 Professional (neutral + blue accent)
88
+ export const professionalTheme: Theme = {
89
+ colors: {
90
+ primary: '#2563eb',
91
+ background: '#f9fafb',
92
+ text: '#1f2937',
93
+ subtitle: '#4b5563',
94
+ buttonText: '#ffffff',
95
+ buttonBackground: '#2563eb',
96
+ },
97
+ };
98
+
99
+ // 🌸 Sakura (soft pink)
100
+ export const sakuraTheme: Theme = {
101
+ colors: {
102
+ primary: '#ec4899',
103
+ background: '#fff0f6',
104
+ text: '#831843',
105
+ subtitle: '#db2777',
106
+ buttonText: '#ffffff',
107
+ buttonBackground: '#ec4899',
108
+ },
109
+ };
110
+
111
+ // 🌌 Midnight (deep purples)
112
+ export const midnightTheme: Theme = {
113
+ colors: {
114
+ primary: '#7c3aed',
115
+ background: '#1e1b4b',
116
+ text: '#f5f3ff',
117
+ subtitle: '#a78bfa',
118
+ buttonText: '#1e1b4b',
119
+ buttonBackground: '#7c3aed',
120
+ },
121
+ };
122
+
123
+ export const themes: Record<string, Theme> = {
124
+ light: lightTheme,
125
+ dark: darkTheme,
126
+ sunset: sunsetTheme,
127
+ ocean: oceanTheme,
128
+ forest: forestTheme,
129
+ pastel: pastelTheme,
130
+ highContrast: highContrastTheme,
131
+ professional: professionalTheme,
132
+ sakura: sakuraTheme,
133
+ midnight: midnightTheme,
134
+ };
@@ -0,0 +1,25 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { Dimensions } from 'react-native';
3
+
4
+ export type Orientation = 'portrait' | 'landscape';
5
+
6
+ export function useOrientation(): Orientation {
7
+ const [orientation, setOrientation] = useState<Orientation>(
8
+ getOrientation()
9
+ );
10
+
11
+ useEffect(() => {
12
+ const subscription = Dimensions.addEventListener('change', () => {
13
+ setOrientation(getOrientation());
14
+ });
15
+
16
+ return () => subscription?.remove();
17
+ }, []);
18
+
19
+ return orientation;
20
+ }
21
+
22
+ function getOrientation(): Orientation {
23
+ const { width, height } = Dimensions.get('window');
24
+ return width > height ? 'landscape' : 'portrait';
25
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,110 @@
1
+ import React, { useState, useMemo, useCallback } from 'react';
2
+ import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
3
+ import { createNativeStackNavigator } from '@react-navigation/native-stack';
4
+ import BarcodeCapture from './screens/BarcodeCapture';
5
+ import FrontDocumentAdvice from './screens/FrontDocumentAdvice';
6
+ import BackDocumentAdvice from './screens/BackDocumentAdvice';
7
+ import BarcodeAdvice from './screens/BarcodeAdvice';
8
+ import DocumentCaptureFront from './screens/DocumentCaptureFront';
9
+ import DocumentCaptureBack from './screens/DocumentCaptureBack';
10
+ import SelectDocuments from './screens/SelectDocuments';
11
+ import SelfieAdvice from './screens/SelfieAdvice';
12
+ import SelfieCapture from './screens/SelfieCapture';
13
+ import ThankYou from './screens/ThankYou';
14
+ import VerifyIdentity from './screens/VerifyIdentity';
15
+ import RetakeSelfie from './screens/RetakeSelfie';
16
+ import LocationPermission from './screens/LocationPermission';
17
+ import CameraPermission from './screens/CameraPermission';
18
+ import NoCameraFound from './screens/NoCameraFound';
19
+ import MrzCapture from './screens/MrzCapture';
20
+ import MrzAdvice from './screens/MrzAdvice';
21
+ import { ThemeProvider } from './context/ThemeContext';
22
+ import { themes } from './context/themes';
23
+ import { IDMConf } from './types/IDMConf';
24
+ import { IDMProvider } from './context/IDMConfigurationContext';
25
+ import { KeyboardProvider, useKeyboard } from './context/KeyboardContext';
26
+ import Footer from './components/common/Footer';
27
+ import Header from './components/common/Header';
28
+
29
+ const Stack = createNativeStackNavigator();
30
+
31
+ // Screen options constant to avoid recreation
32
+ const SCREEN_OPTIONS = { headerShown: false };
33
+
34
+ // Routes where header/footer should be hidden
35
+ const HIDE_HEADER_FOOTER_ROUTES = new Set([
36
+ 'SelfieCapture',
37
+ 'DocumentCaptureFront',
38
+ 'DocumentCaptureBack',
39
+ 'BarcodeCapture',
40
+ 'MrzCapture',
41
+ ]);
42
+
43
+ interface IDMScanProps {
44
+ idmConf?: IDMConf;
45
+ }
46
+
47
+ export default function IDMScan({ idmConf = {} }: IDMScanProps) {
48
+ return (
49
+ <IDMProvider initialConf={idmConf}>
50
+ <KeyboardProvider>
51
+ <IDMScanContent idmConf={idmConf} />
52
+ </KeyboardProvider>
53
+ </IDMProvider>
54
+ );
55
+ }
56
+
57
+ function IDMScanContent({ idmConf }: { idmConf: IDMConf }) {
58
+ const { isKeyboardVisible } = useKeyboard();
59
+ const navigationRef = useNavigationContainerRef();
60
+ const [currentRoute, setCurrentRoute] = useState<string | undefined>();
61
+
62
+ // Memoize theme calculation
63
+ const theme = useMemo(
64
+ () =>
65
+ typeof idmConf.theme === 'string'
66
+ ? themes[idmConf.theme] || themes.light
67
+ : idmConf.theme || themes.light,
68
+ [idmConf.theme]
69
+ );
70
+
71
+ // Memoize header/footer visibility
72
+ const shouldShowHeaderFooter = useMemo(
73
+ () => !HIDE_HEADER_FOOTER_ROUTES.has(currentRoute || ''),
74
+ [currentRoute]
75
+ );
76
+
77
+ // Optimize navigation state change handler
78
+ const handleStateChange = useCallback(() => {
79
+ const route = navigationRef.getCurrentRoute();
80
+ setCurrentRoute(route?.name);
81
+ }, [navigationRef]);
82
+
83
+ return (
84
+ <ThemeProvider theme={theme}>
85
+ {shouldShowHeaderFooter && <Header />}
86
+ <NavigationContainer ref={navigationRef} onStateChange={handleStateChange}>
87
+ <Stack.Navigator initialRouteName="VerifyIdentity" screenOptions={SCREEN_OPTIONS}>
88
+ <Stack.Screen name="VerifyIdentity" component={VerifyIdentity} />
89
+ <Stack.Screen name="SelfieAdvice" component={SelfieAdvice} />
90
+ <Stack.Screen name="SelfieCapture" component={SelfieCapture} />
91
+ <Stack.Screen name="SelectDocuments" component={SelectDocuments} />
92
+ <Stack.Screen name="FrontDocumentAdvice" component={FrontDocumentAdvice} />
93
+ <Stack.Screen name="BackDocumentAdvice" component={BackDocumentAdvice} />
94
+ <Stack.Screen name="BarcodeAdvice" component={BarcodeAdvice} />
95
+ <Stack.Screen name="DocumentCaptureFront" component={DocumentCaptureFront} />
96
+ <Stack.Screen name="DocumentCaptureBack" component={DocumentCaptureBack} />
97
+ <Stack.Screen name="BarcodeCapture" component={BarcodeCapture} />
98
+ <Stack.Screen name="ThankYou" component={ThankYou} />
99
+ <Stack.Screen name="RetakeSelfie" component={RetakeSelfie} />
100
+ <Stack.Screen name="LocationPermission" component={LocationPermission} />
101
+ <Stack.Screen name="CameraPermission" component={CameraPermission} />
102
+ <Stack.Screen name="NoCameraFound" component={NoCameraFound} />
103
+ <Stack.Screen name="MrzCapture" component={MrzCapture} />
104
+ <Stack.Screen name="MrzAdvice" component={MrzAdvice} />
105
+ </Stack.Navigator>
106
+ </NavigationContainer>
107
+ {!isKeyboardVisible && shouldShowHeaderFooter && <Footer />}
108
+ </ThemeProvider>
109
+ );
110
+ }
@@ -0,0 +1,10 @@
1
+ import { NativeModules } from 'react-native';
2
+
3
+ const { YourSDKModule } = NativeModules;
4
+
5
+ export interface NativeSDKModule {
6
+ initialize(apiKey: string): Promise<string>;
7
+ performAction(action: string): Promise<string>;
8
+ }
9
+
10
+ export default YourSDKModule as NativeSDKModule;
@@ -0,0 +1,52 @@
1
+ import { useNavigation } from '@react-navigation/native';
2
+ import { Image, ScrollView, View } from 'react-native';
3
+ import Button from '../components/ui/Button';
4
+ import ThemedText from '../components/ui/ThemedText';
5
+ import getStyles from '../styles/DocumentAdviceStyles';
6
+ import { useTheme } from '../context/ThemeContext';
7
+ import { useOrientation } from '../hooks/useOrientation';
8
+ import { useMemo } from 'react';
9
+
10
+ export default function BackDocumentAdvice() {
11
+ const { theme } = useTheme();
12
+ const orientation = useOrientation();
13
+ const navigation = useNavigation();
14
+
15
+ const styles = useMemo(
16
+ () => getStyles(theme, orientation),
17
+ [theme, orientation]
18
+ );
19
+
20
+ const handleRedirect = () => {
21
+ navigation.navigate('DocumentCaptureBack' as never);
22
+ };
23
+
24
+ return (
25
+ <ScrollView contentContainerStyle={styles.container}>
26
+ <ThemedText style={styles.maintitle} type="title">
27
+ Capture Your ID Back
28
+ </ThemedText>
29
+
30
+ {/* Placeholder for ID card back image */}
31
+ <View
32
+ style={[
33
+ styles.idcard,
34
+ {
35
+ backgroundColor: '#f0f0f0',
36
+ justifyContent: 'center',
37
+ alignItems: 'center',
38
+ },
39
+ ]}
40
+ >
41
+ <ThemedText>ID Back Image</ThemedText>
42
+ </View>
43
+
44
+ <Button
45
+ title="Take a photo"
46
+ style={styles.buttonplace}
47
+ textStyle={styles.button}
48
+ onPress={handleRedirect}
49
+ />
50
+ </ScrollView>
51
+ );
52
+ }
@@ -0,0 +1,52 @@
1
+ import { useNavigation } from '@react-navigation/native';
2
+ import { ScrollView, View } from 'react-native';
3
+ import Button from '../components/ui/Button';
4
+ import ThemedText from '../components/ui/ThemedText';
5
+ import getStyles from '../styles/BarcodeAdviceStyles';
6
+ import { useTheme } from '../context/ThemeContext';
7
+ import { useOrientation } from '../hooks/useOrientation';
8
+ import { useMemo } from 'react';
9
+
10
+ export default function BarcodeAdvice() {
11
+ const { theme } = useTheme();
12
+ const orientation = useOrientation();
13
+ const navigation = useNavigation();
14
+
15
+ const styles = useMemo(
16
+ () => getStyles(theme, orientation),
17
+ [theme, orientation]
18
+ );
19
+
20
+ const handleRedirect = () => {
21
+ navigation.navigate('BarcodeCapture' as never);
22
+ };
23
+
24
+ return (
25
+ <ScrollView contentContainerStyle={styles.container}>
26
+ <ThemedText style={styles.maintitle} type="title">
27
+ Scan the barcode on the back of your ID
28
+ </ThemedText>
29
+
30
+ {/* Placeholder for barcode image */}
31
+ <View
32
+ style={[
33
+ styles.idcard,
34
+ {
35
+ backgroundColor: '#f0f0f0',
36
+ justifyContent: 'center',
37
+ alignItems: 'center',
38
+ },
39
+ ]}
40
+ >
41
+ <ThemedText>Barcode Image</ThemedText>
42
+ </View>
43
+
44
+ <Button
45
+ title="Scan"
46
+ style={styles.buttonplace}
47
+ textStyle={styles.button}
48
+ onPress={handleRedirect}
49
+ />
50
+ </ScrollView>
51
+ );
52
+ }
@@ -0,0 +1,66 @@
1
+ import React, { useState } from 'react';
2
+ import { View, Text, StyleSheet } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import { useTheme } from '../context/ThemeContext';
5
+ import { useOrientation } from '../hooks/useOrientation';
6
+ import getStyles from '../styles/ScannerStyles';
7
+ import Loader from '../components/common/Loader';
8
+
9
+ export default function BarcodeCapture() {
10
+ const { theme } = useTheme();
11
+ const orientation = useOrientation();
12
+ const styles = getStyles(theme, orientation);
13
+ const navigation = useNavigation();
14
+ const [loading, setLoading] = useState(false);
15
+
16
+ // Static implementation - simulate barcode scanning
17
+ React.useEffect(() => {
18
+ const timer = setTimeout(() => {
19
+ setLoading(true);
20
+ setTimeout(() => {
21
+ setLoading(false);
22
+ navigation.navigate('ThankYou' as never);
23
+ }, 2000);
24
+ }, 3000);
25
+
26
+ return () => clearTimeout(timer);
27
+ }, [navigation]);
28
+
29
+ return (
30
+ <View style={styles.container}>
31
+ <Text style={styles.topLabel}>
32
+ Fill the box with the barcode{'\n'}until it turns green
33
+ </Text>
34
+
35
+ {/* Camera placeholder */}
36
+ <View style={[StyleSheet.absoluteFill, { backgroundColor: '#000' }]}>
37
+ <Text
38
+ style={{
39
+ color: '#fff',
40
+ textAlign: 'center',
41
+ marginTop: 200,
42
+ fontSize: 16,
43
+ }}
44
+ >
45
+ Barcode Scanner (Static)
46
+ </Text>
47
+ </View>
48
+
49
+ {/* Barcode overlay box */}
50
+ <View
51
+ style={{
52
+ position: 'absolute',
53
+ top: '40%',
54
+ alignSelf: 'center',
55
+ width: 350,
56
+ height: 100,
57
+ borderWidth: 2,
58
+ borderColor: '#00ff00',
59
+ backgroundColor: 'transparent',
60
+ }}
61
+ />
62
+
63
+ {loading && <Loader />}
64
+ </View>
65
+ );
66
+ }
@@ -0,0 +1,74 @@
1
+ import { useNavigation } from '@react-navigation/native';
2
+ import * as React from 'react';
3
+ import { ScrollView, Text, View, PermissionsAndroid, Platform } from 'react-native';
4
+ import Button from '../components/ui/Button';
5
+ import ThemedText from '../components/ui/ThemedText';
6
+ import { useTheme } from '../context/ThemeContext';
7
+ import getStyles from '../styles/PermissionStyle';
8
+ import { useOrientation } from '../hooks/useOrientation';
9
+
10
+ export default function CameraPermission() {
11
+ const { theme } = useTheme();
12
+ const orientation = useOrientation();
13
+ const styles = getStyles(theme, orientation);
14
+ const navigation = useNavigation();
15
+
16
+ const requestCameraPermission = async () => {
17
+ if (Platform.OS === 'android') {
18
+ try {
19
+ const granted = await PermissionsAndroid.request(
20
+ PermissionsAndroid.PERMISSIONS.CAMERA,
21
+ {
22
+ title: 'Camera Permission',
23
+ message: 'This app needs access to your camera to take selfies.',
24
+ buttonPositive: 'OK',
25
+ }
26
+ );
27
+ if (granted === PermissionsAndroid.RESULTS.GRANTED) {
28
+ if (navigation.canGoBack()) {
29
+ navigation.goBack();
30
+ } else {
31
+ navigation.navigate('VerifyIdentity' as never);
32
+ }
33
+ }
34
+ } catch (err) {
35
+ console.warn(err);
36
+ }
37
+ } else {
38
+ // For iOS, navigate directly (implement iOS permission separately)
39
+ if (navigation.canGoBack()) {
40
+ navigation.goBack();
41
+ } else {
42
+ navigation.navigate('VerifyIdentity' as never);
43
+ }
44
+ }
45
+ };
46
+
47
+ return (
48
+ <ScrollView contentContainerStyle={styles.container}>
49
+ <ThemedText style={styles.maintitle} type="title">
50
+ Camera Access Required
51
+ </ThemedText>
52
+
53
+ <View style={{ padding: 20 }}>
54
+ <Text
55
+ style={{
56
+ color: theme.colors.text,
57
+ textAlign: 'center',
58
+ marginBottom: 20,
59
+ }}
60
+ >
61
+ This app needs access to your camera to continue. Please grant camera
62
+ permission.
63
+ </Text>
64
+ </View>
65
+
66
+ <Button
67
+ title="Grant Permission"
68
+ style={styles.buttonplace}
69
+ textStyle={styles.button}
70
+ onPress={requestCameraPermission}
71
+ />
72
+ </ScrollView>
73
+ );
74
+ }
@@ -0,0 +1,65 @@
1
+ import React, { useState } from 'react';
2
+ import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import getStyles from '../styles/DocumentCaptureStyles';
5
+ import { useTheme } from '../context/ThemeContext';
6
+ import { useOrientation } from '../hooks/useOrientation';
7
+ import Loader from '../components/common/Loader';
8
+
9
+ export default function DocumentCaptureBack() {
10
+ const { theme } = useTheme();
11
+ const orientation = useOrientation();
12
+ const styles = getStyles(theme, orientation);
13
+ const navigation = useNavigation();
14
+ const [loading, setLoading] = useState(false);
15
+
16
+ const takePhoto = async () => {
17
+ try {
18
+ setLoading(true);
19
+ // Static implementation - simulate photo capture
20
+ setTimeout(() => {
21
+ setLoading(false);
22
+ // Navigate to ThankYou after capturing back
23
+ navigation.navigate('ThankYou' as never);
24
+ }, 1000);
25
+ } catch (error) {
26
+ console.error('Error taking photo:', error);
27
+ setLoading(false);
28
+ }
29
+ };
30
+
31
+ return (
32
+ <View style={styles.container}>
33
+ <Text style={styles.topLabel}>Document Back Side</Text>
34
+
35
+ {/* Camera placeholder */}
36
+ <View style={StyleSheet.absoluteFill}>
37
+ <View
38
+ style={[StyleSheet.absoluteFill, { backgroundColor: '#000' }]}
39
+ ></View>
40
+ </View>
41
+
42
+ {/* Card overlay placeholder */}
43
+ <View
44
+ style={[
45
+ styles.cardoverlay,
46
+ {
47
+ borderWidth: 2,
48
+ borderColor: '#fff',
49
+ backgroundColor: 'transparent',
50
+ },
51
+ ]}
52
+ />
53
+
54
+ <Text style={styles.bottomLabel}>
55
+ Position your document fully within the frame
56
+ </Text>
57
+
58
+ <View style={styles.buttonplace}>
59
+ <TouchableOpacity style={styles.captureButton} onPress={takePhoto} />
60
+ </View>
61
+
62
+ {loading && <Loader />}
63
+ </View>
64
+ );
65
+ }