150 lines
4.7 KiB
TypeScript
150 lines
4.7 KiB
TypeScript
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
TouchableOpacity,
|
|
Platform,
|
|
ActivityIndicator,
|
|
} from 'react-native';
|
|
import MapView, { Marker, Region } from 'react-native-maps';
|
|
import { useNavigation } from '@react-navigation/native';
|
|
import { StackNavigationProp } from '@react-navigation/stack';
|
|
import { getStyles } from './setLocationScreen.styles';
|
|
import { PrimaryButton } from '@components';
|
|
import { useAppTheme } from '@theme';
|
|
import { AuthStackParamList } from '../../../navigation/authStack';
|
|
import {
|
|
DEFAULT_LOCATION,
|
|
getCurrentLocationWithAddress,
|
|
reverseGeocode,
|
|
LatLng,
|
|
} from '../../../services/locationServices';
|
|
|
|
type NavProp = StackNavigationProp<AuthStackParamList, 'SetLocationScreen'>;
|
|
|
|
const DELTA = { latitudeDelta: 0.006, longitudeDelta: 0.006 };
|
|
|
|
export const SetLocationScreen: React.FC = () => {
|
|
const { colors } = useAppTheme();
|
|
const styles = getStyles(colors);
|
|
const navigation = useNavigation<NavProp>();
|
|
const mapRef = useRef<MapView>(null);
|
|
|
|
const [coords, setCoords] = useState<LatLng>(DEFAULT_LOCATION);
|
|
const [address, setAddress] = useState('Fetching your location…');
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Fetch current location on mount
|
|
// ------------------------------------------------------------------
|
|
const fetchCurrentLocation = useCallback(async () => {
|
|
setLoading(true);
|
|
try {
|
|
console.log('--------------');
|
|
const result = await getCurrentLocationWithAddress();
|
|
console.log('result', result);
|
|
setCoords(result.coords);
|
|
setAddress(result.address);
|
|
|
|
// Animate the map to the user's location
|
|
mapRef.current?.animateToRegion({ ...result.coords, ...DELTA }, 600);
|
|
} catch {
|
|
// Permission denied or GPS unavailable — keep the default location
|
|
console.log('--------error------');
|
|
setAddress('Could not determine location');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
fetchCurrentLocation();
|
|
}, [fetchCurrentLocation]);
|
|
|
|
// ------------------------------------------------------------------
|
|
// When user drags the map, update the marker + address
|
|
// ------------------------------------------------------------------
|
|
const handleRegionChangeComplete = useCallback(async (region: Region) => {
|
|
const newCoords: LatLng = {
|
|
latitude: region.latitude,
|
|
longitude: region.longitude,
|
|
};
|
|
setCoords(newCoords);
|
|
setAddress('Fetching address…');
|
|
|
|
const newAddress = await reverseGeocode(newCoords);
|
|
setAddress(newAddress);
|
|
}, []);
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
{/* ---------- Map ---------- */}
|
|
<MapView
|
|
ref={mapRef}
|
|
style={styles.map}
|
|
initialRegion={{ ...DEFAULT_LOCATION, ...DELTA }}
|
|
showsUserLocation
|
|
showsMyLocationButton={true}
|
|
onRegionChangeComplete={handleRegionChangeComplete}
|
|
>
|
|
<Marker
|
|
coordinate={coords}
|
|
title="Your Location"
|
|
description={address}
|
|
/>
|
|
</MapView>
|
|
|
|
{/* ---------- "Locate me" floating button ---------- */}
|
|
<TouchableOpacity
|
|
style={styles.locateButton}
|
|
activeOpacity={0.8}
|
|
onPress={fetchCurrentLocation}
|
|
>
|
|
<Text style={styles.locateIcon}>📍</Text>
|
|
</TouchableOpacity>
|
|
|
|
{/* ---------- Bottom sheet ---------- */}
|
|
<View style={styles.bottomSheet}>
|
|
<View style={styles.sheetHandle} />
|
|
|
|
<View style={styles.card}>
|
|
<View style={styles.cardHeader}>
|
|
<Text style={styles.cardIcon}>📍</Text>
|
|
<Text style={styles.cardTitle}>My Location</Text>
|
|
</View>
|
|
|
|
{loading ? (
|
|
<ActivityIndicator
|
|
size="small"
|
|
color={colors.primary}
|
|
style={{ marginVertical: 12 }}
|
|
/>
|
|
) : (
|
|
<Text style={styles.cardAddress} numberOfLines={2}>
|
|
{address}
|
|
</Text>
|
|
)}
|
|
|
|
<TouchableOpacity style={styles.changeLink} activeOpacity={0.7}>
|
|
<Text style={styles.changeText}>Change</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<PrimaryButton
|
|
title="Confirm Location"
|
|
onPress={() => navigation.navigate('CompleteProfileScreen')}
|
|
style={styles.confirmButton}
|
|
/>
|
|
|
|
<TouchableOpacity
|
|
style={styles.manualButton}
|
|
onPress={() => navigation.navigate('CompleteProfileScreen')}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Text style={styles.manualButtonText}>Enter address manually</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|