// app/add_mosque.tsx import React, { useState, useEffect, useRef } from 'react'; // useRef added for debounceTimeout import { View, Text, TextInput, Button, StyleSheet, ScrollView, Alert, ActivityIndicator, TouchableOpacity, Platform, // Ensure Platform is imported for style usage Switch, FlatList, // Added FlatList for autocomplete suggestions } from 'react-native'; import * as Location from 'expo-location'; import { Picker } from '@react-native-picker/picker'; import { useRouter, useLocalSearchParams } from 'expo-router'; interface AddPlaceResponse { message: string; placeId?: string; } const BACKEND_URL = 'http://132.145.65.145:8080'; // Your backend URL const GOOGLE_API_KEY = 'AIzaSyB1WZHDqjGk696AmVw7tA2sMAuOurt552Q'; export default function AddMosqueScreen() { const router = useRouter(); const params = useLocalSearchParams(); const lat = params.lat; const lng = params.lng; const addressParam = params.address; const nameParam = params.name; const [name, setName] = useState(''); const [address, setAddress] = useState(''); const [latitude, setLatitude] = useState(''); const [longitude, setLongitude] = useState(''); const [locationType, setLocationType] = useState<'mosque' | 'other' | 'outdoor_space' | 'multi_faith_room'>('mosque'); const [notes, setNotes] = useState(''); const [website, setWebsite] = useState(''); // NEW STATE FOR WEBSITE const [isLoadingLocation, setIsLoadingLocation] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [isGeocoding, setIsGeocoding] = useState(false); // Used for Google Details API fetch state const [coordsObtained, setCoordsObtained] = useState(false); // Autocomplete specific states const [addressSuggestions, setAddressSuggestions] = useState([]); // Google predictions have { description, place_id } const [isAddressLoading, setIsAddressLoading] = useState(false); // Indicates loading for autocomplete suggestions const debounceTimeout = useRef(null); // For debouncing input // Track if user has interacted with the switches const [womensSpace, setWomensSpace] = useState(null); const [wudu, setWudu] = useState(null); // Effect to auto-populate fields from query params on initial load useEffect(() => { if (lat && typeof lat === 'string') { setLatitude(lat); } if (lng && typeof lng === 'string') { setLongitude(lng); } if (addressParam && typeof addressParam === 'string') { setAddress(decodeURIComponent(addressParam)); } if (nameParam && typeof nameParam === 'string') { setName(decodeURIComponent(nameParam)); } if (lat && lng) { setCoordsObtained(true); } }, [lat, lng, addressParam, nameParam]); const getCurrentLocation = async () => { setIsLoadingLocation(true); setCoordsObtained(false); // Reset status setLatitude(''); // Clear old coords setLongitude(''); // Clear old coords setAddress(''); // Clear address for new reverse geocoding setAddressSuggestions([]); // Clear suggestions let { status } = await Location.requestForegroundPermissionsAsync(); if (status !== 'granted') { Alert.alert('Permission denied', 'Permission to access location was denied. Cannot auto-fill coordinates.'); setIsLoadingLocation(false); return; } try { let location = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.High }); setLatitude(location.coords.latitude.toString()); setLongitude(location.coords.longitude.toString()); setCoordsObtained(true); const reverseGeocode = await Location.reverseGeocodeAsync({ latitude: location.coords.latitude, longitude: location.coords.longitude, }); if (reverseGeocode && reverseGeocode.length > 0) { const firstResult = reverseGeocode[0]; const formattedAddress = [ firstResult.name, firstResult.street, firstResult.city, firstResult.postalCode, firstResult.country, ].filter(Boolean).join(', '); setAddress(formattedAddress); } } catch (error) { console.error("Error getting current location:", error); Alert.alert('Error', 'Failed to get current location. Please enter manually.'); } finally { setIsLoadingLocation(false); } }; const fetchGoogleSuggestions = async (input: string) => { if (!input || input.length < 3) { setAddressSuggestions([]); return; } // Debounce is now handled by handleAddressChangeWithDebounce, // so this function itself doesn't need to debounce. setIsAddressLoading(true); // Indicate loading for suggestions try { const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${encodeURIComponent(input)}&key=${GOOGLE_API_KEY}&components=country:gb&location=51.5074,-0.1278&radius=20000`; const response = await fetch(url); const data = await response.json(); if (data && data.predictions) { setAddressSuggestions(data.predictions); } else { setAddressSuggestions([]); } } catch (e) { console.error('Google Autocomplete fetch error:', e); setAddressSuggestions([]); } finally { setIsAddressLoading(false); // Stop loading for suggestions } }; const fetchPlaceDetails = async (placeId: string, description: string) => { setIsGeocoding(true); // Indicates loading for place details (lat/lng) setCoordsObtained(false); // Reset status while fetching details setLatitude(''); setLongitude(''); setAddressSuggestions([]); // Hide suggestions list try { const url = `https://maps.googleapis.com/maps/api/place/details/json?place_id=${placeId}&fields=geometry&key=${GOOGLE_API_KEY}`; const response = await fetch(url); const data = await response.json(); if (data && data.result && data.result.geometry) { const { lat, lng } = data.result.geometry.location; setAddress(description); setLatitude(lat.toString()); setLongitude(lng.toString()); setCoordsObtained(true); Alert.alert('Location Found', `Coordinates for "${description}" obtained.`); } else { Alert.alert('Error', 'Could not retrieve coordinates for the selected place.'); } } catch (e) { console.error('Google Place Details fetch error:', e); Alert.alert('Error', 'Failed to get location details. Please try again.'); } finally { setIsGeocoding(false); // Stop loading for place details } }; // THIS IS THE DEBOUNCED HANDLER FOR THE ADDRESS TEXTINPUT const handleAddressChangeWithDebounce = (text: string) => { setAddress(text); // Update address state immediately if (debounceTimeout.current) { clearTimeout(debounceTimeout.current); } debounceTimeout.current = setTimeout(() => { fetchGoogleSuggestions(text); // Call Google Autocomplete after debounce }, 500); // Debounce for 500ms }; const handleSuggestionPress = (item: any) => { // 'item' is a Google prediction object fetchPlaceDetails(item.place_id, item.description); }; const handleSubmit = async () => { // Ensure essential fields are filled and coordinates are obtained if (!name || !address || !latitude || !longitude || !locationType || womensSpace === null || wudu === null || !coordsObtained) { Alert.alert('Missing Info', 'Please fill in all required fields (Name, Address, Location Type, Women\'s Space, Wudu Facilities) and ensure coordinates are obtained (use current location or select from address suggestions).'); return; } setIsSubmitting(true); const payload = { name, address, latitude: parseFloat(latitude), longitude: parseFloat(longitude), location_type: locationType, womens_space: womensSpace, wudu: wudu, notes: notes, website_url: website, // Include website in payload }; try { console.log("Sending new place payload:", payload); const response = await fetch(`${BACKEND_URL}/places/new`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }); if (!response.ok) { const errorData = await response.json().catch(() => ({ message: 'Unknown error' })); console.error("Backend error response:", errorData); throw new Error(errorData.message || `HTTP error! Status: ${response.status}`); } const result: AddPlaceResponse = await response.json(); Alert.alert('Success', result.message || 'Prayer Space added successfully!'); setName(''); setAddress(''); setLatitude(''); setLongitude(''); setLocationType('mosque'); setWomensSpace(null); setWudu(null); setNotes(''); setWebsite(''); // Clear website field setCoordsObtained(false); router.back(); } catch (error: any) { console.error('Add mosque error:', error); Alert.alert('Error', `Failed to add prayer space: ${error.message || 'Network error'}`); } finally { setIsSubmitting(false); } }; // Styles for Yes/No buttons for switches const getSwitchButtonStyle = (selected: boolean | null, isYes: boolean) => ({ marginRight: 10, borderWidth: 1, borderColor: selected === isYes ? '#007bff' : '#ccc', backgroundColor: selected === isYes ? '#e6f0ff' : '#fff', borderRadius: 6, paddingHorizontal: 16, paddingVertical: 8, marginLeft: 0, }); const getSwitchButtonTextStyle = (selected: boolean | null, isYes: boolean) => ({ color: selected === isYes ? '#007bff' : '#333', fontWeight: selected === isYes ? 'bold' : 'normal', }); return ( Add New Prayer Space Location Name * Address * { if (address.length >=3 && addressSuggestions.length > 0) setAddressSuggestions(addressSuggestions); else if (address.length >=3) fetchGoogleSuggestions(address); }} onBlur={() => setTimeout(() => setAddressSuggestions([]), 200)} autoCorrect={false} autoCapitalize="none" /> {isAddressLoading && } {addressSuggestions.length > 0 && ( {addressSuggestions.map((item) => ( fetchPlaceDetails(item.place_id, item.description)} > {item.description} ))} )}