ace #1
47
apps/mobile/src/components/QRCode.tsx
Normal file
47
apps/mobile/src/components/QRCode.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { View, Text, StyleSheet } from 'react-native';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
|
||||
interface QRCodeProps {
|
||||
value: string;
|
||||
size?: number;
|
||||
logo?: string;
|
||||
}
|
||||
|
||||
export const QRCodeGenerator: React.FC<QRCodeProps> = ({
|
||||
value,
|
||||
size = 250
|
||||
}) => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.qrWrapper}>
|
||||
<QRCode
|
||||
value={value}
|
||||
size={size}
|
||||
color="black"
|
||||
backgroundColor="white"
|
||||
quietZone={10}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 16,
|
||||
},
|
||||
qrWrapper: {
|
||||
padding: 16,
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 12,
|
||||
elevation: 5,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.25,
|
||||
shadowRadius: 3.84,
|
||||
},
|
||||
});
|
||||
92
apps/mobile/src/components/QRScanner.tsx
Normal file
92
apps/mobile/src/components/QRScanner.tsx
Normal file
@ -0,0 +1,92 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, StyleSheet, Button, Alert } from 'react-native';
|
||||
import { BarCodeScanner } from 'expo-barcode-scanner';
|
||||
|
||||
interface QRScannerProps {
|
||||
onScan: (data: string) => void;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export const QRScanner: React.FC<QRScannerProps> = ({ onScan, onClose }) => {
|
||||
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
|
||||
const [scanned, setScanned] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const getBarCodeScannerPermissions = async () => {
|
||||
const { status } = await BarCodeScanner.requestPermissionsAsync();
|
||||
setHasPermission(status === 'granted');
|
||||
};
|
||||
|
||||
getBarCodeScannerPermissions();
|
||||
}, []);
|
||||
|
||||
const handleBarCodeScanned = ({ type, data }: { type: string; data: string }) => {
|
||||
setScanned(true);
|
||||
onScan(data);
|
||||
Alert.alert('QR Code', `Scanned: ${data}`, [
|
||||
{ text: 'OK', onPress: () => setScanned(false) },
|
||||
]);
|
||||
};
|
||||
|
||||
if (hasPermission === null) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Requesting for camera permission...</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (hasPermission === false) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>No access to camera</Text>
|
||||
{onClose && <Button title="Close" onPress={onClose} />}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<BarCodeScanner
|
||||
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
|
||||
style={StyleSheet.absoluteFillObject}
|
||||
/>
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.scanBox} />
|
||||
</View>
|
||||
{onClose && (
|
||||
<View style={styles.buttonContainer}>
|
||||
<Button title="Close Scanner" onPress={onClose} color="#FF6B6B" />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#000',
|
||||
},
|
||||
overlay: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
scanBox: {
|
||||
width: 250,
|
||||
height: 250,
|
||||
borderWidth: 2,
|
||||
borderColor: '#4CAF50',
|
||||
borderRadius: 10,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
buttonContainer: {
|
||||
position: 'absolute',
|
||||
bottom: 20,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
});
|
||||
@ -3,10 +3,10 @@
|
||||
* Handles gym location validation and distance calculations
|
||||
*/
|
||||
|
||||
// Gym location coordinates (example: gym location)
|
||||
// Gym location coordinates - Teretana Isaija Mazhovski, Skopje, North Macedonia
|
||||
export const GYM_LOCATION = {
|
||||
latitude: 37.7749,
|
||||
longitude: -122.4194,
|
||||
latitude: 41.9973,
|
||||
longitude: 21.4280,
|
||||
};
|
||||
|
||||
// Geofence radius in meters (500m default)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user