RyanHub - file viewer
filename: app/src/components/LocationModal.tsx
branch: main
back to repo
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, Modal, TouchableOpacity } from 'react-native';
import MapView, { Marker, PROVIDER_GOOGLE } from 'react-native-maps';
import { useTheme } from '../contexts/ThemeContext';
import * as Location from 'expo-location';

interface LocationPickerModalProps {
  visible: boolean;
  initialLat: number;
  initialLng: number;
  onSelect: (lat: number, lng: number) => void;
  onClose: () => void;
}

export function LocationPickerModal({ visible, initialLat, initialLng, onSelect, onClose }: LocationPickerModalProps) {
  const defLat = 40.7596;
  const defLon = -74.1811;

  const { colors } = useTheme();
  const [currentLocation, setCurrentLocation] = useState({ latitude: defLat, longitude: defLon });
  const [selectedLocation, setSelectedLocation] = useState({ latitude: initialLat || defLat, longitude: initialLng || defLon });
  const [hasInitialized, setHasInitialized] = useState(false);

  useEffect(() => {
    if (visible && !hasInitialized) {
      (async () => {
        let initialCoords = { latitude: initialLat || defLat, longitude: initialLng || defLon };
        
        if ((initialLat === 0 && initialLng === 0) || (!initialLat && !initialLng)) {
          const { status } = await Location.requestForegroundPermissionsAsync();
          if (status === 'granted') {
            const location = await Location.getCurrentPositionAsync({});
            initialCoords = { latitude: location.coords.latitude, longitude: location.coords.longitude };
          }
        }
        
        setCurrentLocation(initialCoords);
        setSelectedLocation(initialCoords);
        setHasInitialized(true);
      })();
    }
  }, [visible, hasInitialized, initialLat, initialLng]);

  useEffect(() => {
    if (hasInitialized && initialLat && initialLng && (initialLat !== 0 || initialLng !== 0)) {
      const newCoords = { latitude: initialLat, longitude: initialLng };
      setSelectedLocation(newCoords);
      setCurrentLocation(newCoords);
    }
  }, [initialLat, initialLng, hasInitialized]);

  const handleRegionChangeComplete = (region: any) => {
    setSelectedLocation({
      latitude: region.latitude,
      longitude: region.longitude,
    });
  };

  const handleConfirm = () => {
    onSelect(selectedLocation.latitude, selectedLocation.longitude);
    onClose();
  };

  const styles = StyleSheet.create({
    locationModalOverlay: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'transparent' },
    locationModalContainer: { backgroundColor: 'white', padding: 20, borderRadius: 10, width: '90%', height: '70%' },
    locationModalTitle: { fontSize: 18, fontWeight: '600', marginBottom: 10, textAlign: 'center' },
    map: { flex: 1, borderRadius: 5, marginBottom: 10 },
    locationButtonRow: { flexDirection: 'row', justifyContent: 'space-around' },
    locationCancelBtn: { backgroundColor: colors.error, padding: 10, borderRadius: 5 },
    locationCancelText: { color: 'white', fontWeight: '600' },
    locationConfirmBtn: { backgroundColor: colors.success, padding: 10, borderRadius: 5 },
    locationConfirmText: { color: 'white', fontWeight: '600' },
  });

  return (
    <Modal animationType="slide" transparent visible={visible}>
      <View style={styles.locationModalOverlay}>
        <View style={styles.locationModalContainer}>
          <Text style={styles.locationModalTitle}>Pick Location</Text>
          <MapView
            style={styles.map}
            provider={PROVIDER_GOOGLE}
            initialRegion={{
              latitude: selectedLocation.latitude,
              longitude: selectedLocation.longitude,
              latitudeDelta: 0.01,
              longitudeDelta: 0.01,
            }}
            onRegionChangeComplete={handleRegionChangeComplete}
            showsUserLocation
          >
            <Marker coordinate={selectedLocation} />
          </MapView>
          <View style={styles.locationButtonRow}>
            <TouchableOpacity onPress={onClose} style={styles.locationCancelBtn}>
              <Text style={styles.locationCancelText}>Cancel</Text>
            </TouchableOpacity>
            <TouchableOpacity onPress={handleConfirm} style={styles.locationConfirmBtn}>
              <Text style={styles.locationConfirmText}>Confirm</Text>
            </TouchableOpacity>
          </View>
        </View>
      </View>
    </Modal>
  );
}