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:
435
App.tsx
435
App.tsx
@@ -12,6 +12,7 @@ import {
|
|||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
import Login from './src/components/Login';
|
import Login from './src/components/Login';
|
||||||
import Register from './src/components/Register';
|
import Register from './src/components/Register';
|
||||||
import { authAPI } from './src/services/authAPI';
|
import { authAPI } from './src/services/authAPI';
|
||||||
@@ -19,10 +20,12 @@ import { networkService } from './src/services/networkService';
|
|||||||
import { ScannerScreen } from './src/screens/ScannerScreen';
|
import { ScannerScreen } from './src/screens/ScannerScreen';
|
||||||
|
|
||||||
type Screen = 'login' | 'register' | 'home' | 'scanner';
|
type Screen = 'login' | 'register' | 'home' | 'scanner';
|
||||||
|
|
||||||
const { MyNativeModule } = NativeModules;
|
const { MyNativeModule } = NativeModules;
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const isDarkMode = useColorScheme() === 'dark';
|
const isDarkMode = useColorScheme() === 'dark';
|
||||||
|
|
||||||
const [currentScreen, setCurrentScreen] = useState<Screen>('login');
|
const [currentScreen, setCurrentScreen] = useState<Screen>('login');
|
||||||
const [isInitialized, setIsInitialized] = useState(false);
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
const [isOnline, setIsOnline] = useState(true);
|
const [isOnline, setIsOnline] = useState(true);
|
||||||
@@ -31,16 +34,16 @@ function App() {
|
|||||||
const [isGeneratingQR, setIsGeneratingQR] = useState(false);
|
const [isGeneratingQR, setIsGeneratingQR] = useState(false);
|
||||||
const [scannedCodes, setScannedCodes] = useState<any[]>([]);
|
const [scannedCodes, setScannedCodes] = useState<any[]>([]);
|
||||||
|
|
||||||
// Initialize app
|
/* -------------------- INIT -------------------- */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initializeApp();
|
initializeApp();
|
||||||
console.log("MyNativeModule", MyNativeModule);
|
|
||||||
MyNativeModule.greet("John").then((msg: any) => {
|
console.log('MyNativeModule:', MyNativeModule);
|
||||||
|
MyNativeModule?.greet?.('John').then((msg: any) => {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for network changes
|
const unsubscribe = networkService.addListener(networkState => {
|
||||||
const unsubscribe = networkService.addListener((networkState) => {
|
|
||||||
setIsOnline(networkState.isConnected);
|
setIsOnline(networkState.isConnected);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -49,50 +52,51 @@ function App() {
|
|||||||
|
|
||||||
const initializeApp = async () => {
|
const initializeApp = async () => {
|
||||||
try {
|
try {
|
||||||
console.log('Initializing app...');
|
|
||||||
|
|
||||||
// Initialize authentication system
|
|
||||||
await authAPI.initialize();
|
await authAPI.initialize();
|
||||||
|
|
||||||
// Check if user is already logged in
|
|
||||||
const isLoggedIn = await authAPI.isLoggedIn();
|
const isLoggedIn = await authAPI.isLoggedIn();
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
const user = await authAPI.getCurrentUser();
|
const user = await authAPI.getCurrentUser();
|
||||||
setCurrentUser(user);
|
setCurrentUser(user);
|
||||||
setCurrentScreen('home');
|
setCurrentScreen('home');
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsInitialized(true);
|
|
||||||
console.log('App initialized successfully');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('App initialization error:', error);
|
console.error('Initialization error:', error);
|
||||||
setIsInitialized(true); // Continue anyway
|
} finally {
|
||||||
|
setIsInitialized(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* -------------------- NAVIGATION -------------------- */
|
||||||
const navigateToLogin = () => {
|
const navigateToLogin = () => {
|
||||||
setCurrentUser(null);
|
setCurrentUser(null);
|
||||||
setQrCode(null); // Clear QR code when navigating to login
|
setQrCode(null);
|
||||||
setCurrentScreen('login');
|
setCurrentScreen('login');
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigateToRegister = () => setCurrentScreen('register');
|
const navigateToRegister = () => {
|
||||||
|
setCurrentScreen('register');
|
||||||
|
};
|
||||||
|
|
||||||
const navigateToHome = async () => {
|
const navigateToHome = async () => {
|
||||||
const user = await authAPI.getCurrentUser();
|
const user = await authAPI.getCurrentUser();
|
||||||
setCurrentUser(user);
|
setCurrentUser(user);
|
||||||
setQrCode(null); // Clear old QR code when new user logs in
|
setQrCode(null);
|
||||||
setCurrentScreen('home');
|
setCurrentScreen('home');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openScanner = () => {
|
||||||
|
setCurrentScreen('scanner');
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -------------------- ACTIONS -------------------- */
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
try {
|
try {
|
||||||
await authAPI.logout();
|
await authAPI.logout();
|
||||||
setQrCode(null); // Clear QR code on logout
|
setQrCode(null);
|
||||||
navigateToLogin();
|
navigateToLogin();
|
||||||
Alert.alert('Success', 'Logged out successfully');
|
Alert.alert('Success', 'Logged out successfully');
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.error('Logout error:', error);
|
|
||||||
Alert.alert('Error', 'Failed to logout');
|
Alert.alert('Error', 'Failed to logout');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -100,21 +104,38 @@ function App() {
|
|||||||
const showAppStatus = async () => {
|
const showAppStatus = async () => {
|
||||||
try {
|
try {
|
||||||
const status = await authAPI.getAppStatus();
|
const status = await authAPI.getAppStatus();
|
||||||
const statusMessage = `
|
Alert.alert(
|
||||||
Network: ${status.network.isOnline ? 'Online' : 'Offline'}
|
'App Status',
|
||||||
|
`Network: ${status.network.isOnline ? 'Online' : 'Offline'}
|
||||||
Users: ${status.storage.totalUsers}
|
Users: ${status.storage.totalUsers}
|
||||||
Current User: ${status.authentication.currentUser || 'None'}
|
Current User: ${status.authentication.currentUser || 'None'}
|
||||||
Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}
|
Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}`
|
||||||
`.trim();
|
);
|
||||||
|
} catch {
|
||||||
Alert.alert('App Status', statusMessage);
|
|
||||||
} catch (error) {
|
|
||||||
Alert.alert('Error', 'Failed to get app status');
|
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) => {
|
const handleScanResult = (result: any) => {
|
||||||
console.log('Scan result:', result);
|
|
||||||
setScannedCodes(prev => [
|
setScannedCodes(prev => [
|
||||||
{
|
{
|
||||||
code: result.code,
|
code: result.code,
|
||||||
@@ -123,103 +144,54 @@ Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}
|
|||||||
},
|
},
|
||||||
...prev,
|
...prev,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
'✓ Scanned Successfully',
|
'Scanned Successfully',
|
||||||
`Code: ${result.code}\nFormat: ${result.format}`,
|
`Code: ${result.code}\nFormat: ${result.format}`,
|
||||||
[
|
[{ text: 'OK', onPress: () => setCurrentScreen('home') }]
|
||||||
{
|
|
||||||
text: 'Close',
|
|
||||||
onPress: () => setCurrentScreen('home'),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openScanner = () => {
|
/* -------------------- RENDER -------------------- */
|
||||||
setCurrentScreen('scanner');
|
const renderScreen = () => {
|
||||||
} catch (error) {
|
switch (currentScreen) {
|
||||||
Alert.alert('Error', 'Failed to get app status');
|
case 'login':
|
||||||
}
|
return (
|
||||||
};
|
<Login
|
||||||
|
onNavigateToRegister={navigateToRegister}
|
||||||
|
onLoginSuccess={navigateToHome}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
const generateQRCode = async () => {
|
case 'register':
|
||||||
if (!currentUser?.email) {
|
return (
|
||||||
Alert.alert('Error', 'No user email available');
|
<Register
|
||||||
return;
|
onNavigateToLogin={navigateToLogin}
|
||||||
}
|
onRegisterSuccess={navigateToHome}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
setIsGeneratingQR(true);
|
case 'scanner':
|
||||||
try {
|
return (
|
||||||
const qrData = `User: ${currentUser.fullName}\nEmail: ${currentUser.email}`;
|
<ScannerScreen
|
||||||
const base64Image = await MyNativeModule.generateQRCode(qrData, 300, 300);
|
presignedUrl="https://your-backend-presigned-url.com"
|
||||||
setQrCode(base64Image);
|
onScan={handleScanResult}
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderScreen = () => {
|
case 'home':
|
||||||
switch (currentScreen) {
|
return (
|
||||||
case 'login':
|
<ScrollView style={styles.homeContainer} contentContainerStyle={styles.scrollContent}>
|
||||||
return (
|
<Text style={styles.welcomeText}>
|
||||||
<Login
|
Welcome, {currentUser?.fullName || 'User'}
|
||||||
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'}
|
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={styles.welcomeText}>
|
{qrCode && (
|
||||||
Welcome, {currentUser?.fullName || 'User'}!
|
<Image source={{ uri: qrCode }} style={styles.qrImage} />
|
||||||
</Text>
|
)}
|
||||||
|
|
||||||
<Text style={styles.emailText}>
|
<TouchableOpacity style={styles.scannerButton} onPress={openScanner}>
|
||||||
{currentUser?.email}
|
<Text style={styles.buttonText}>Scan QR / Barcode</Text>
|
||||||
</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>
|
</TouchableOpacity>
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -239,226 +211,45 @@ const renderScreen = () => {
|
|||||||
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
|
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
|
||||||
<Text style={styles.buttonText}>Logout</Text>
|
<Text style={styles.buttonText}>Logout</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</ScrollView>
|
||||||
|
);
|
||||||
|
|
||||||
{scannedCodes.length > 0 && (
|
default:
|
||||||
<View style={styles.scannedContainer}>
|
return null;
|
||||||
<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>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Text style={styles.infoText}>
|
/* -------------------- LOADING -------------------- */
|
||||||
{isOnline
|
if (!isInitialized) {
|
||||||
? 'Your data is synced with the cloud'
|
return (
|
||||||
: 'Working offline - data saved locally'}
|
<SafeAreaProvider>
|
||||||
</Text>
|
<View style={styles.loadingContainer}>
|
||||||
</ScrollView>
|
<Text style={styles.loadingText}>Initializing...</Text>
|
||||||
);
|
</View>
|
||||||
default:
|
</SafeAreaProvider>
|
||||||
return null;
|
);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Show loading screen while initializing
|
|
||||||
if (!isInitialized) {
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
|
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
|
||||||
<View style={styles.loadingContainer}>
|
{renderScreen()}
|
||||||
<Text style={styles.loadingText}>Initializing...</Text>
|
|
||||||
</View>
|
|
||||||
</SafeAreaProvider>
|
</SafeAreaProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaProvider>
|
|
||||||
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
|
|
||||||
{renderScreen()}
|
|
||||||
</SafeAreaProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
loadingContainer: {
|
loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' },
|
||||||
flex: 1,
|
loadingText: { fontSize: 18, fontWeight: '600' },
|
||||||
justifyContent: 'center',
|
homeContainer: { flex: 1 },
|
||||||
alignItems: 'center',
|
scrollContent: { alignItems: 'center', padding: 20 },
|
||||||
backgroundColor: '#f0f0f0',
|
welcomeText: { fontSize: 24, fontWeight: '700', marginBottom: 20 },
|
||||||
},
|
qrImage: { width: 300, height: 300, marginBottom: 20 },
|
||||||
loadingText: {
|
scannerButton: { backgroundColor: '#9333ea', padding: 14, borderRadius: 20, marginBottom: 10 },
|
||||||
fontSize: 18,
|
qrButton: { backgroundColor: '#10b981', padding: 14, borderRadius: 20, marginBottom: 10 },
|
||||||
color: '#3bb6d8',
|
statusButton: { backgroundColor: '#3bb6d8', padding: 14, borderRadius: 20, marginBottom: 10 },
|
||||||
fontWeight: '600',
|
logoutButton: { backgroundColor: '#ff6b6b', padding: 14, borderRadius: 20 },
|
||||||
},
|
buttonText: { color: '#fff', 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',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
Reference in New Issue
Block a user