Refactor App component for improved navigation and QR code generation

Implemented native methods in React Native using NativeModules.
Improved error handling and stability across sdk interactions.
This commit is contained in:
2025-12-20 23:25:56 +05:30
parent a66eb11512
commit 37f1682ade

435
App.tsx
View File

@@ -12,6 +12,7 @@ import {
} from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { useState, useEffect } from 'react';
import Login from './src/components/Login';
import Register from './src/components/Register';
import { authAPI } from './src/services/authAPI';
@@ -19,10 +20,12 @@ import { networkService } from './src/services/networkService';
import { ScannerScreen } from './src/screens/ScannerScreen';
type Screen = 'login' | 'register' | 'home' | 'scanner';
const { MyNativeModule } = NativeModules;
function App() {
const isDarkMode = useColorScheme() === 'dark';
const [currentScreen, setCurrentScreen] = useState<Screen>('login');
const [isInitialized, setIsInitialized] = useState(false);
const [isOnline, setIsOnline] = useState(true);
@@ -31,16 +34,16 @@ function App() {
const [isGeneratingQR, setIsGeneratingQR] = useState(false);
const [scannedCodes, setScannedCodes] = useState<any[]>([]);
// Initialize app
/* -------------------- INIT -------------------- */
useEffect(() => {
initializeApp();
console.log("MyNativeModule", MyNativeModule);
MyNativeModule.greet("John").then((msg: any) => {
console.log('MyNativeModule:', MyNativeModule);
MyNativeModule?.greet?.('John').then((msg: any) => {
console.log(msg);
});
// Listen for network changes
const unsubscribe = networkService.addListener((networkState) => {
const unsubscribe = networkService.addListener(networkState => {
setIsOnline(networkState.isConnected);
});
@@ -49,50 +52,51 @@ function App() {
const initializeApp = async () => {
try {
console.log('Initializing app...');
// Initialize authentication system
await authAPI.initialize();
// Check if user is already logged in
const isLoggedIn = await authAPI.isLoggedIn();
if (isLoggedIn) {
const user = await authAPI.getCurrentUser();
setCurrentUser(user);
setCurrentScreen('home');
}
setIsInitialized(true);
console.log('App initialized successfully');
} catch (error) {
console.error('App initialization error:', error);
setIsInitialized(true); // Continue anyway
console.error('Initialization error:', error);
} finally {
setIsInitialized(true);
}
};
/* -------------------- NAVIGATION -------------------- */
const navigateToLogin = () => {
setCurrentUser(null);
setQrCode(null); // Clear QR code when navigating to login
setQrCode(null);
setCurrentScreen('login');
};
const navigateToRegister = () => setCurrentScreen('register');
const navigateToRegister = () => {
setCurrentScreen('register');
};
const navigateToHome = async () => {
const user = await authAPI.getCurrentUser();
setCurrentUser(user);
setQrCode(null); // Clear old QR code when new user logs in
setQrCode(null);
setCurrentScreen('home');
};
const openScanner = () => {
setCurrentScreen('scanner');
};
/* -------------------- ACTIONS -------------------- */
const handleLogout = async () => {
try {
await authAPI.logout();
setQrCode(null); // Clear QR code on logout
setQrCode(null);
navigateToLogin();
Alert.alert('Success', 'Logged out successfully');
} catch (error) {
console.error('Logout error:', error);
} catch {
Alert.alert('Error', 'Failed to logout');
}
};
@@ -100,21 +104,38 @@ function App() {
const showAppStatus = async () => {
try {
const status = await authAPI.getAppStatus();
const statusMessage = `
Network: ${status.network.isOnline ? 'Online' : 'Offline'}
Alert.alert(
'App Status',
`Network: ${status.network.isOnline ? 'Online' : 'Offline'}
Users: ${status.storage.totalUsers}
Current User: ${status.authentication.currentUser || 'None'}
Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}
`.trim();
Alert.alert('App Status', statusMessage);
} catch (error) {
Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}`
);
} catch {
Alert.alert('Error', 'Failed to get app status');
}
};
const generateQRCode = async () => {
if (!currentUser?.email) {
Alert.alert('Error', 'No user email available');
return;
}
setIsGeneratingQR(true);
try {
const qrData = `User: ${currentUser.fullName}\nEmail: ${currentUser.email}`;
const base64Image = await MyNativeModule.generateQRCode(qrData, 300, 300);
setQrCode(base64Image);
} catch (error) {
console.error(error);
Alert.alert('Error', 'Failed to generate QR code');
} finally {
setIsGeneratingQR(false);
}
};
const handleScanResult = (result: any) => {
console.log('Scan result:', result);
setScannedCodes(prev => [
{
code: result.code,
@@ -123,103 +144,54 @@ Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}
},
...prev,
]);
Alert.alert(
'Scanned Successfully',
'Scanned Successfully',
`Code: ${result.code}\nFormat: ${result.format}`,
[
{
text: 'Close',
onPress: () => setCurrentScreen('home'),
},
]
[{ text: 'OK', onPress: () => setCurrentScreen('home') }]
);
};
const openScanner = () => {
setCurrentScreen('scanner');
} catch (error) {
Alert.alert('Error', 'Failed to get app status');
}
};
/* -------------------- RENDER -------------------- */
const renderScreen = () => {
switch (currentScreen) {
case 'login':
return (
<Login
onNavigateToRegister={navigateToRegister}
onLoginSuccess={navigateToHome}
/>
);
const generateQRCode = async () => {
if (!currentUser?.email) {
Alert.alert('Error', 'No user email available');
return;
}
case 'register':
return (
<Register
onNavigateToLogin={navigateToLogin}
onRegisterSuccess={navigateToHome}
/>
);
setIsGeneratingQR(true);
try {
const qrData = `User: ${currentUser.fullName}\nEmail: ${currentUser.email}`;
const base64Image = await MyNativeModule.generateQRCode(qrData, 300, 300);
setQrCode(base64Image);
Alert.alert('Success', 'QR Code generated successfully!');
} catch (error) {
console.error('QR Code generation error:', error);
Alert.alert('Error', 'Failed to generate QR code');
} finally {
setIsGeneratingQR(false);
}
};
case 'scanner':
return (
<ScannerScreen
presignedUrl="https://your-backend-presigned-url.com"
onScan={handleScanResult}
/>
);
const renderScreen = () => {
switch (currentScreen) {
case 'login':
return (
<Login
onNavigateToRegister={navigateToRegister}
onLoginSuccess={navigateToHome}
/>
);
case 'register':
return (
<Register
onNavigateToLogin={navigateToLogin}
onRegisterSuccess={navigateToHome}
/>
);
case 'scanner':
return (
<ScannerScreen
presignedUrl="https://your-backend-presigned-url.com"
onScan={handleScanResult}
/>
);
case 'home':
return (
<ScrollView style={styles.homeContainer} contentContainerStyle={styles.scrollContent}>
<View style={styles.statusBar}>
<Text style={styles.statusText}>
{isOnline ? '🟢 Online' : '🔴 Offline'}
case 'home':
return (
<ScrollView style={styles.homeContainer} contentContainerStyle={styles.scrollContent}>
<Text style={styles.welcomeText}>
Welcome, {currentUser?.fullName || 'User'}
</Text>
</View>
<Text style={styles.welcomeText}>
Welcome, {currentUser?.fullName || 'User'}!
</Text>
{qrCode && (
<Image source={{ uri: qrCode }} style={styles.qrImage} />
)}
<Text style={styles.emailText}>
{currentUser?.email}
</Text>
{qrCode && (
<View style={styles.qrContainer}>
<Text style={styles.qrLabel}>Your QR Code:</Text>
<Image
source={{ uri: qrCode }}
style={styles.qrImage}
/>
</View>
)}
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.scannerButton}
onPress={openScanner}
>
<Text style={styles.buttonText}>
📱 Scan QR/Barcode
</Text>
<TouchableOpacity style={styles.scannerButton} onPress={openScanner}>
<Text style={styles.buttonText}>Scan QR / Barcode</Text>
</TouchableOpacity>
<TouchableOpacity
@@ -239,226 +211,45 @@ const renderScreen = () => {
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
<Text style={styles.buttonText}>Logout</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
{scannedCodes.length > 0 && (
<View style={styles.scannedContainer}>
<Text style={styles.scannedTitle}>
Scanned Codes ({scannedCodes.length})
</Text>
{scannedCodes.slice(0, 5).map((item, index) => (
<View key={index} style={styles.scannedItem}>
<Text style={styles.scannedCode}>{item.code}</Text>
<View style={styles.scannedFooter}>
<Text style={styles.scannedFormat}>{item.format}</Text>
<Text style={styles.scannedTime}>{item.timestamp}</Text>
</View>
</View>
))}
</View>
)}
default:
return null;
}
};
<Text style={styles.infoText}>
{isOnline
? 'Your data is synced with the cloud'
: 'Working offline - data saved locally'}
</Text>
</ScrollView>
);
default:
return null;
/* -------------------- LOADING -------------------- */
if (!isInitialized) {
return (
<SafeAreaProvider>
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Initializing...</Text>
</View>
</SafeAreaProvider>
);
}
};
// Show loading screen while initializing
if (!isInitialized) {
return (
<SafeAreaProvider>
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Initializing...</Text>
</View>
{renderScreen()}
</SafeAreaProvider>
);
}
return (
<SafeAreaProvider>
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
{renderScreen()}
</SafeAreaProvider>
);
}
const styles = StyleSheet.create({
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f0f0f0',
},
loadingText: {
fontSize: 18,
color: '#3bb6d8',
fontWeight: '600',
},
homeContainer: {
flex: 1,
backgroundColor: '#f0f0f0',
},
scrollContent: {
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 20,
paddingBottom: 50,
minHeight: '100%',
},
statusBar: {
position: 'absolute',
top: 60,
right: 20,
backgroundColor: 'white',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 20,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
zIndex: 10,
},
statusText: {
fontSize: 12,
fontWeight: '600',
},
welcomeText: {
fontSize: 28,
fontWeight: 'bold',
color: '#333',
marginBottom: 8,
textAlign: 'center',
marginTop: 40,
},
emailText: {
fontSize: 16,
color: '#666',
marginBottom: 30,
},
qrContainer: {
alignItems: 'center',
marginBottom: 30,
backgroundColor: 'white',
padding: 20,
borderRadius: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
qrLabel: {
fontSize: 14,
fontWeight: '600',
color: '#333',
marginBottom: 12,
},
qrImage: {
width: 300,
height: 300,
borderRadius: 8,
},
buttonContainer: {
flexDirection: 'column',
gap: 12,
marginBottom: 30,
width: '100%',
},
scannerButton: {
backgroundColor: '#9333ea',
paddingHorizontal: 20,
paddingVertical: 14,
borderRadius: 25,
alignItems: 'center',
},
qrButton: {
backgroundColor: '#10b981',
paddingHorizontal: 20,
paddingVertical: 14,
borderRadius: 25,
alignItems: 'center',
},
statusButton: {
backgroundColor: '#3bb6d8',
paddingHorizontal: 20,
paddingVertical: 14,
borderRadius: 25,
alignItems: 'center',
},
logoutButton: {
backgroundColor: '#ff6b6b',
paddingHorizontal: 20,
paddingVertical: 14,
borderRadius: 25,
alignItems: 'center',
},
buttonText: {
color: 'white',
fontWeight: '600',
fontSize: 16,
},
scannedContainer: {
width: '100%',
marginBottom: 20,
backgroundColor: 'white',
borderRadius: 12,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
scannedTitle: {
fontSize: 14,
fontWeight: '600',
color: '#333',
marginBottom: 12,
},
scannedItem: {
backgroundColor: '#f5f5f5',
borderLeftWidth: 4,
borderLeftColor: '#9333ea',
paddingHorizontal: 12,
paddingVertical: 10,
marginBottom: 8,
borderRadius: 4,
},
scannedCode: {
fontSize: 13,
fontWeight: '600',
color: '#000',
marginBottom: 4,
},
scannedFooter: {
flexDirection: 'row',
justifyContent: 'space-between',
},
scannedFormat: {
fontSize: 11,
color: '#666',
fontWeight: '500',
},
scannedTime: {
fontSize: 11,
color: '#999',
},
infoText: {
fontSize: 14,
color: '#888',
textAlign: 'center',
fontStyle: 'italic',
},
loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' },
loadingText: { fontSize: 18, fontWeight: '600' },
homeContainer: { flex: 1 },
scrollContent: { alignItems: 'center', padding: 20 },
welcomeText: { fontSize: 24, fontWeight: '700', marginBottom: 20 },
qrImage: { width: 300, height: 300, marginBottom: 20 },
scannerButton: { backgroundColor: '#9333ea', padding: 14, borderRadius: 20, marginBottom: 10 },
qrButton: { backgroundColor: '#10b981', padding: 14, borderRadius: 20, marginBottom: 10 },
statusButton: { backgroundColor: '#3bb6d8', padding: 14, borderRadius: 20, marginBottom: 10 },
logoutButton: { backgroundColor: '#ff6b6b', padding: 14, borderRadius: 20 },
buttonText: { color: '#fff', fontWeight: '600' },
});
export default App;