import React, { useState, useEffect } from 'react'; import { Box, TextField, Autocomplete, Typography, Grid, Chip, FormControlLabel, Checkbox } from '@mui/material'; import { LocationOn, Public, Home } from '@mui/icons-material'; import { Country, State, City } from 'country-state-city'; import type { ICountry, IState, ICity } from 'country-state-city'; // Import from your types file - adjust path as needed import type { Location } from 'types/types'; interface LocationInputProps { value?: Partial; onChange: (location: Partial) => void; error?: boolean; helperText?: string; required?: boolean; disabled?: boolean; showCity?: boolean; } const LocationInput: React.FC = ({ value = {}, onChange, error = false, helperText, required = false, disabled = false, showCity = false }) => { // Get all countries from the library const allCountries = Country.getAllCountries(); const [selectedCountry, setSelectedCountry] = useState( value.country ? allCountries.find(c => c.name === value.country) || null : null ); const [selectedState, setSelectedState] = useState(null); const [selectedCity, setSelectedCity] = useState(null); const [isRemote, setIsRemote] = useState(value.remote || false); // Get states for selected country const availableStates = selectedCountry ? State.getStatesOfCountry(selectedCountry.isoCode) : []; // Get cities for selected state const availableCities = selectedCountry && selectedState ? City.getCitiesOfState(selectedCountry.isoCode, selectedState.isoCode) : []; // Initialize state and city from value prop useEffect(() => { if (selectedCountry && value.state) { const stateMatch = availableStates.find(s => s.name === value.state); setSelectedState(stateMatch || null); } }, [selectedCountry, value.state, availableStates]); useEffect(() => { if (selectedCountry && selectedState && value.city && showCity) { const cityMatch = availableCities.find(c => c.name === value.city); setSelectedCity(cityMatch || null); } }, [selectedCountry, selectedState, value.city, availableCities, showCity]); // Update parent component when values change useEffect(() => { const newLocation: Partial = {}; if (selectedCountry) { newLocation.country = selectedCountry.name; } if (selectedState) { newLocation.state = selectedState.name; } if (selectedCity && showCity) { newLocation.city = selectedCity.name; } if (isRemote) { newLocation.remote = isRemote; } // Only call onChange if there's actual data or if clearing if (Object.keys(newLocation).length > 0 || (value.country || value.state || value.city)) { onChange(newLocation); } }, [selectedCountry, selectedState, selectedCity, isRemote, onChange, value.country, value.state, value.city, showCity]); const handleCountryChange = (event: any, newValue: ICountry | null) => { setSelectedCountry(newValue); // Clear state and city when country changes setSelectedState(null); setSelectedCity(null); }; const handleStateChange = (event: any, newValue: IState | null) => { setSelectedState(newValue); // Clear city when state changes setSelectedCity(null); }; const handleCityChange = (event: any, newValue: ICity | null) => { setSelectedCity(newValue); }; const handleRemoteToggle = (event: React.ChangeEvent) => { setIsRemote(event.target.checked); }; return ( Location {required && *} {/* Country Selection */} option.name} disabled={disabled} renderInput={(params) => ( }} /> )} renderOption={(props, option) => ( {option.name} )} /> {/* State/Region Selection */} {selectedCountry && ( option.name} disabled={disabled || availableStates.length === 0} renderInput={(params) => ( 0 ? "Select state/region" : "No states available"} /> )} /> )} {/* City Selection */} {showCity && selectedCountry && selectedState && ( option.name} disabled={disabled || availableCities.length === 0} renderInput={(params) => ( 0 ? "Select city" : "No cities available"} InputProps={{ ...params.InputProps, startAdornment: }} /> )} /> )} {/* Remote Work Option */} } label="Open to remote work" /> {/* Location Summary Chips */} {(selectedCountry || selectedState || selectedCity || isRemote) && ( {selectedCountry && ( } label={selectedCountry.name} variant="outlined" color="primary" size="small" /> )} {selectedState && ( )} {selectedCity && showCity && ( } label={selectedCity.name} variant="outlined" color="default" size="small" /> )} {isRemote && ( )} )} ); }; // Demo component to show usage with real data const LocationInputDemo: React.FC = () => { const [location, setLocation] = useState>({}); const [showAdvanced, setShowAdvanced] = useState(false); const handleLocationChange = (newLocation: Partial) => { setLocation(newLocation); console.log('Location updated:', newLocation); }; // Show some stats about the data const totalCountries = Country.getAllCountries().length; const usStates = State.getStatesOfCountry('US').length; const canadaProvinces = State.getStatesOfCountry('CA').length; return ( Location Input with Real Data Using country-state-city library with {totalCountries} countries, {usStates} US states, {canadaProvinces} Canadian provinces, and thousands of cities Basic Location Input setShowAdvanced(e.target.checked)} color="primary" /> } label="Show city field" /> {showAdvanced && ( Advanced Location Input (with City) )} Current Location Data: {JSON.stringify(location, null, 2)} 💡 This component uses the country-state-city library which is regularly updated and includes ISO codes, flags, and comprehensive location data. ); }; export { LocationInput };