UNPKG

sid-address-verification-react-native

Version:
353 lines 11.4 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import React, { useState, useEffect, useCallback } from 'react'; import { View, TextInput, Text, TouchableOpacity, FlatList, StyleSheet, Alert, ActivityIndicator } from 'react-native'; import { ApiService } from '../services/ApiService'; import { LocationService } from '../services/LocationService'; import { requestLocationPermission } from '../utils/permissions'; import { debounce, generateSessionToken, GOOGLE_PLACES_KEY } from '../utils/helper_functions'; import GooglePlacesService from '../services/GooglePlacesService'; const AddressVerificationField = ({ config, onAddressSelected, onLocationUpdate, onError, chooseAddressType, addressTypes, onAddressTypeChange, placeholder = 'Enter your address', showSubmitButton = true, style // googlePlacesApiKey, // Add this prop to pass the API key }) => { const [query, setQuery] = useState(config.initialAddressText || ''); const [suggestions, setSuggestions] = useState([]); const [selectedAddress, setSelectedAddress] = useState(null); const [selectedType, setSelectedType] = useState(null); const [loading, setLoading] = useState(true); const [loadingSuggestions, setLoadingSuggestions] = useState(false); const [pollingInterval, setPollingInterval] = useState(15); const [sessionTimeout, setSessionTimeout] = useState(60); const [sessionToken] = useState(() => generateSessionToken()); const [googlePlacesService] = useState(() => new GooglePlacesService(GOOGLE_PLACES_KEY || '')); // Debounced search function const debouncedSearch = useCallback(debounce(async searchQuery => { if (searchQuery.trim().length > 2) { setLoadingSuggestions(true); try { const predictions = await googlePlacesService.getAutocompletePredictions(searchQuery, sessionToken); console.log('predictions', predictions); if (Array.isArray(predictions)) { setSuggestions(predictions); } else { console.warn('GooglePlacesService returned non-array predictions:', predictions); setSuggestions([]); // fallback to empty } } catch (error) { console.error('Error fetching suggestions:', error); onError?.(`Failed to fetch suggestions: ${error}`); setSuggestions([]); } finally { setLoadingSuggestions(false); } } else { setSuggestions([]); } }, 300), [googlePlacesService, sessionToken, onError]); // Initialize API service and fetch config useEffect(() => { const initializeService = async () => { try { // Validate Google Places API key // if (!googlePlacesApiKey) { // throw new Error('Google Places API key is required'); // } ApiService.getInstance().configure(config.apiKey, config.customerID); const configData = await ApiService.getInstance().fetchAddressVerificationConfig(); setPollingInterval(configData.geotaggingPollingInterval || 15); setSessionTimeout(configData.geotaggingSessionTimeout || 60); } catch (error) { console.error('Error initializing service:', error); onError?.(`Failed to initialize: ${error}`); } finally { setLoading(false); } }; initializeService(); }, [config.apiKey, config.customerID, onError]); // Trigger search when query changes useEffect(() => { debouncedSearch(query); }, [query, debouncedSearch]); const handleSuggestionSelect = useCallback(async suggestion => { try { setLoadingSuggestions(true); const placeDetails = await googlePlacesService.getPlaceDetails(suggestion.place_id, sessionToken); setSelectedAddress(placeDetails); setQuery(placeDetails.address); setSuggestions([]); onAddressSelected(placeDetails); } catch (error) { console.error('Error selecting address:', error); onError?.(`Failed to select address: ${error}`); Alert.alert('Error', 'Failed to get address details. Please try again.'); } finally { setLoadingSuggestions(false); } }, [onAddressSelected, onError, googlePlacesService, sessionToken]); const handleSubmit = useCallback(async () => { if (!selectedAddress) { Alert.alert('Error', 'Please select an address first'); return; } if (config.verifyLocation) { try { const permissionResult = await requestLocationPermission(); if (!permissionResult.granted) { Alert.alert('Permission Required', 'Location permission is required for address verification'); return; } // Start location tracking const locationService = LocationService.getInstance(); locationService.startLocationTracking(config.locationFetchIntervalSeconds || pollingInterval, config.locationFetchDurationSeconds || sessionTimeout, onLocationUpdate); Alert.alert('Success', 'Address verification started. Location tracking is now active.'); } catch (error) { console.error('Error starting location verification:', error); onError?.(`Failed to start location verification: ${error}`); } } else { Alert.alert('Success', 'Address selected successfully'); } }, [selectedAddress, config, pollingInterval, sessionTimeout, onLocationUpdate, onError]); const handleClearAddress = useCallback(() => { setSelectedAddress(null); setQuery(''); setSuggestions([]); }, []); if (loading) { return _jsxs(View, { style: [styles.container, style], children: [_jsx(ActivityIndicator, { size: "large", color: "#0000ff" }), _jsx(Text, { style: styles.loadingText, children: "Loading configuration..." })] }); } return _jsxs(View, { style: [styles.container, style], children: [_jsxs(View, { style: styles.inputContainer, children: [chooseAddressType && addressTypes?.length > 0 && _jsx(View, { style: styles.addressTypeContainer, children: addressTypes.map(type => _jsx(TouchableOpacity, { style: [styles.addressTypeButton, selectedType === type && styles.addressTypeButtonSelected], onPress: () => { setSelectedType(type); onAddressTypeChange?.(type); }, children: _jsx(Text, { style: [styles.addressTypeText, selectedType === type && styles.addressTypeTextSelected], children: type }) }, type)) }), _jsx(TextInput, { style: styles.textInput, value: query, onChangeText: setQuery, placeholder: placeholder, placeholderTextColor: "#999", autoComplete: "street-address", autoCorrect: false, keyboardAppearance: "light" }), selectedAddress && _jsx(TouchableOpacity, { style: styles.clearButton, onPress: handleClearAddress, children: _jsx(Text, { style: styles.clearButtonText, children: "\u2715" }) })] }), loadingSuggestions && _jsx(View, { style: styles.loadingContainer, children: _jsx(ActivityIndicator, { size: "small", color: "#0000ff" }) }), suggestions.length > 0 && _jsx(FlatList, { data: suggestions, keyExtractor: item => item.place_id, renderItem: ({ item }) => _jsxs(TouchableOpacity, { style: styles.suggestionItem, onPress: () => handleSuggestionSelect(item), children: [_jsx(Text, { style: styles.suggestionMain, children: item.structured_formatting.main_text }), _jsx(Text, { style: styles.suggestionSecondary, children: item.structured_formatting.secondary_text })] }), style: styles.suggestionsList, nestedScrollEnabled: true, keyboardShouldPersistTaps: "handled" }), showSubmitButton && _jsx(TouchableOpacity, { style: [styles.submitButton, !selectedAddress && styles.submitButtonDisabled], onPress: handleSubmit, disabled: !selectedAddress, children: _jsx(Text, { style: styles.submitButtonText, children: config.verifyLocation ? 'Verify Address' : 'Submit Address' }) }), selectedAddress && _jsxs(View, { style: styles.selectedAddressContainer, children: [_jsx(Text, { style: styles.selectedAddressLabel, children: "Selected Address:" }), _jsx(Text, { style: styles.selectedAddressText, children: selectedAddress.address }), _jsxs(Text, { style: styles.coordinatesText, children: ["Coordinates: ", selectedAddress.latitude.toFixed(6), ",", ' ', selectedAddress.longitude.toFixed(6)] })] })] }); }; const styles = StyleSheet.create({ container: { padding: 16 }, inputContainer: { position: 'relative' }, textInput: { borderWidth: 1, borderColor: '#ccc', borderRadius: 8, padding: 12, paddingRight: 40, // Make room for clear button fontSize: 16, backgroundColor: '#fff', color: '#000' }, clearButton: { position: 'absolute', right: 12, top: 12, width: 24, height: 24, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f0f0f0', borderRadius: 12 }, clearButtonText: { fontSize: 14, color: '#666', fontWeight: 'bold' }, loadingContainer: { padding: 8, alignItems: 'center' }, loadingText: { marginTop: 8, fontSize: 16, color: '#666' }, suggestionsList: { maxHeight: 200, borderWidth: 1, borderColor: '#ccc', borderTopWidth: 0, backgroundColor: '#fff', borderBottomLeftRadius: 8, borderBottomRightRadius: 8 }, suggestionItem: { padding: 12, borderBottomWidth: 1, borderBottomColor: '#eee' }, suggestionMain: { fontSize: 16, fontWeight: '600', color: '#333' }, addressTypeContainer: { flexDirection: 'row', flexWrap: 'wrap', marginBottom: 12, gap: 8 }, addressTypeButton: { paddingVertical: 6, paddingHorizontal: 12, borderRadius: 16, borderWidth: 1, borderColor: '#ccc', backgroundColor: '#f0f0f0' }, addressTypeButtonSelected: { backgroundColor: '#007AFF', borderColor: '#007AFF' }, addressTypeText: { color: '#333', fontSize: 14 }, addressTypeTextSelected: { color: '#fff', fontWeight: '600' }, suggestionSecondary: { fontSize: 14, color: '#666', marginTop: 2 }, submitButton: { backgroundColor: '#007AFF', padding: 12, borderRadius: 8, alignItems: 'center', marginTop: 16 }, submitButtonDisabled: { backgroundColor: '#ccc' }, submitButtonText: { color: '#fff', fontSize: 16, fontWeight: '600' }, selectedAddressContainer: { marginTop: 16, padding: 12, backgroundColor: '#f8f8f8', borderRadius: 8, borderLeftWidth: 4, borderLeftColor: '#007AFF' }, selectedAddressLabel: { fontSize: 14, fontWeight: '600', marginBottom: 4, color: '#333' }, selectedAddressText: { fontSize: 16, marginBottom: 4, color: '#333' }, coordinatesText: { fontSize: 14, color: '#666' } }); export default AddressVerificationField; //# sourceMappingURL=AddressVerificationField.js.map