import React, { useEffect, useMemo, useState, useCallback } from 'react'; import DataTable from '../components/DataTable'; import { countryAPI, provinceAPI, cityAPI, currencyAPI } from '../services/api'; import { Plus, Search, Pencil, Trash2, MapPin, Globe, Building2 } from 'lucide-react'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import { getErrorMessage, getSuccessMessage } from '../utils/errorHandler'; const Location = () => { const [activeTab, setActiveTab] = useState('country'); // 'country', 'province', 'city' // Country states const [countries, setCountries] = useState([]); const [countriesLoading, setCountriesLoading] = useState(true); const [countryFilter, setCountryFilter] = useState(''); const [isCountryModalOpen, setIsCountryModalOpen] = useState(false); const [editingCountry, setEditingCountry] = useState(null); const [countryForm, setCountryForm] = useState({ name: '', phoneCode: '', currencyCode: '', timeZoneName: '' }); const [currencies, setCurrencies] = useState([]); // Province states const [provinces, setProvinces] = useState([]); const [provincesLoading, setProvincesLoading] = useState(true); const [provinceFilter, setProvinceFilter] = useState(''); const [isProvinceModalOpen, setIsProvinceModalOpen] = useState(false); const [editingProvince, setEditingProvince] = useState(null); const [provinceForm, setProvinceForm] = useState({ countryId: '', provinceName: '' }); const [selectedCountryForProvince, setSelectedCountryForProvince] = useState(null); // City states const [cities, setCities] = useState([]); const [citiesLoading, setCitiesLoading] = useState(true); const [cityFilter, setCityFilter] = useState(''); const [isCityModalOpen, setIsCityModalOpen] = useState(false); const [editingCity, setEditingCity] = useState(null); const [cityForm, setCityForm] = useState({ provinceId: '', cityName: '' }); const [selectedProvinceForCity, setSelectedProvinceForCity] = useState(null); const [provincesForCity, setProvincesForCity] = useState([]); // دریافت ارزها برای dropdown useEffect(() => { const fetchCurrencies = async () => { try { const list = await currencyAPI.list(); setCurrencies(Array.isArray(list) ? list : []); } catch (err) { console.error('Failed to load currencies:', err); } }; fetchCurrencies(); }, []); // دریافت کشورها const fetchCountries = useCallback(async () => { try { setCountriesLoading(true); const list = await countryAPI.listAll(); setCountries(Array.isArray(list) ? list : []); } catch (err) { toast.error(getErrorMessage(err)); } finally { setCountriesLoading(false); } }, []); // دریافت استان‌ها const fetchProvinces = useCallback(async () => { try { setProvincesLoading(true); const list = await provinceAPI.list(); setProvinces(Array.isArray(list) ? list : []); } catch (err) { toast.error(getErrorMessage(err)); } finally { setProvincesLoading(false); } }, []); // دریافت شهرها const fetchCities = useCallback(async () => { try { setCitiesLoading(true); const list = await cityAPI.list(); setCities(Array.isArray(list) ? list : []); } catch (err) { toast.error(getErrorMessage(err)); } finally { setCitiesLoading(false); } }, []); useEffect(() => { if (activeTab === 'country') { fetchCountries(); } else if (activeTab === 'province') { fetchProvinces(); fetchCountries(); // برای dropdown } else if (activeTab === 'city') { fetchCities(); fetchProvinces(); // برای dropdown } }, [activeTab, fetchCountries, fetchProvinces, fetchCities]); // ========== Country Functions ========== const openCountryModal = (country = null) => { if (country) { setEditingCountry(country); setCountryForm({ name: country.name || '', phoneCode: country.phoneCode || '', currencyCode: country.currencyCode || '', timeZoneName: country.timeZoneName || country.timeZone || '', }); } else { setEditingCountry(null); setCountryForm({ name: '', phoneCode: '', currencyCode: '', timeZoneName: '' }); } setIsCountryModalOpen(true); }; const onSaveCountry = async (e) => { e.preventDefault(); try { if (editingCountry) { const countryId = editingCountry.id || editingCountry.countryId; if (!countryId) { toast.error('Country ID is missing'); console.error('Editing country:', editingCountry); return; } console.log('Updating country with ID:', countryId, 'Payload:', countryForm); await countryAPI.update(countryId, countryForm); toast.success(getSuccessMessage({ data: { message: 'Country updated successfully' } }) || 'Country updated successfully'); } else { await countryAPI.create(countryForm); toast.success(getSuccessMessage({ data: { message: 'Country added successfully' } }) || 'Country added successfully'); } await fetchCountries(); setIsCountryModalOpen(false); setEditingCountry(null); setCountryForm({ name: '', phoneCode: '', currencyCode: '', timeZoneName: '' }); } catch (err) { console.error('Error saving country:', err); toast.error(getErrorMessage(err)); } }; // ========== Province Functions ========== const openProvinceModal = (province = null) => { if (province) { setEditingProvince(province); setProvinceForm({ countryId: province.countryId || '', provinceName: province.name || '', }); setSelectedCountryForProvince(province.countryId); } else { setEditingProvince(null); setProvinceForm({ countryId: '', provinceName: '' }); setSelectedCountryForProvince(null); } setIsProvinceModalOpen(true); }; const onSaveProvince = async (e) => { e.preventDefault(); if (!provinceForm.countryId) { toast.error('Please select a country'); return; } try { if (editingProvince) { const provinceId = editingProvince.id || editingProvince.provinceId; if (!provinceId) { toast.error('Province ID is missing'); console.error('Editing province:', editingProvince); return; } console.log('Updating province with ID:', provinceId, 'Payload:', provinceForm); await provinceAPI.update(provinceId, provinceForm); toast.success(getSuccessMessage({ data: { message: 'Province updated successfully' } }) || 'Province updated successfully'); } else { await provinceAPI.create(provinceForm); toast.success(getSuccessMessage({ data: { message: 'Province added successfully' } }) || 'Province added successfully'); } await fetchProvinces(); setIsProvinceModalOpen(false); setEditingProvince(null); setProvinceForm({ countryId: '', provinceName: '' }); setSelectedCountryForProvince(null); } catch (err) { console.error('Error saving province:', err); toast.error(getErrorMessage(err)); } }; // ========== City Functions ========== const openCityModal = (city = null) => { if (city) { setEditingCity(city); setCityForm({ provinceId: city.provinceId || '', cityName: city.name || '', }); setSelectedProvinceForCity(city.provinceId); } else { setEditingCity(null); setCityForm({ provinceId: '', cityName: '' }); setSelectedProvinceForCity(null); } setIsCityModalOpen(true); }; const onSaveCity = async (e) => { e.preventDefault(); if (!cityForm.provinceId) { toast.error('Please select a province'); return; } try { if (editingCity) { const cityId = editingCity.id || editingCity.cityId; if (!cityId) { toast.error('City ID is missing'); console.error('Editing city:', editingCity); return; } console.log('Updating city with ID:', cityId, 'Payload:', cityForm); await cityAPI.update(cityId, cityForm); toast.success(getSuccessMessage({ data: { message: 'City updated successfully' } }) || 'City updated successfully'); } else { await cityAPI.create(cityForm); toast.success(getSuccessMessage({ data: { message: 'City added successfully' } }) || 'City added successfully'); } await fetchCities(); setIsCityModalOpen(false); setEditingCity(null); setCityForm({ provinceId: '', cityName: '' }); setSelectedProvinceForCity(null); } catch (err) { console.error('Error saving city:', err); toast.error(getErrorMessage(err)); } }; // ========== Table Columns ========== const countryColumns = useMemo(() => [ { key: 'name', header: 'Name' }, { key: 'phoneCode', header: 'Phone Code' }, { key: 'currencyCode', header: 'Currency' }, { key: 'timeZoneName', header: 'Time Zone', render: (val, row) => val || row.timeZone || '—' }, { key: 'actions', header: 'Actions', render: (_val, row) => (
), }, ], []); const provinceColumns = useMemo(() => [ { key: 'name', header: 'Province Name' }, { key: 'countryName', header: 'Country' }, { key: 'actions', header: 'Actions', render: (_val, row) => (
), }, ], []); const cityColumns = useMemo(() => [ { key: 'name', header: 'City Name' }, { key: 'provinceName', header: 'Province' }, { key: 'actions', header: 'Actions', render: (_val, row) => (
), }, ], []); // Filtered data const filteredCountries = useMemo(() => { if (!countryFilter) return countries; const filter = countryFilter.toLowerCase(); return countries.filter(c => c.name?.toLowerCase().includes(filter) || c.phoneCode?.toLowerCase().includes(filter) || c.currencyCode?.toLowerCase().includes(filter) ); }, [countries, countryFilter]); const filteredProvinces = useMemo(() => { if (!provinceFilter) return provinces; const filter = provinceFilter.toLowerCase(); return provinces.filter(p => p.name?.toLowerCase().includes(filter) || p.countryName?.toLowerCase().includes(filter) ); }, [provinces, provinceFilter]); const filteredCities = useMemo(() => { if (!cityFilter) return cities; const filter = cityFilter.toLowerCase(); return cities.filter(c => c.name?.toLowerCase().includes(filter) || c.provinceName?.toLowerCase().includes(filter) ); }, [cities, cityFilter]); return (

Location Management

Manage countries, provinces, and cities

{/* Tabs */}
{/* Country Tab */} {activeTab === 'country' && ( <>
setCountryFilter(e.target.value)} placeholder="Filter countries..." className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500" />
)} {/* Province Tab */} {activeTab === 'province' && ( <>
setProvinceFilter(e.target.value)} placeholder="Filter provinces..." className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500" />
)} {/* City Tab */} {activeTab === 'city' && ( <>
setCityFilter(e.target.value)} placeholder="Filter cities..." className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500" />
)} {/* Country Modal */} {isCountryModalOpen && ( <>
setIsCountryModalOpen(false)} />

{editingCountry ? 'Edit Country' : 'Add Country'}

setCountryForm({ ...countryForm, name: e.target.value })} className="w-full p-2 border rounded-lg" required />
setCountryForm({ ...countryForm, phoneCode: e.target.value })} className="w-full p-2 border rounded-lg" required />
setCountryForm({ ...countryForm, timeZoneName: e.target.value })} className="w-full p-2 border rounded-lg" placeholder="e.g., UTC+3:30" required />
)} {/* Province Modal */} {isProvinceModalOpen && ( <>
setIsProvinceModalOpen(false)} />

{editingProvince ? 'Edit Province' : 'Add Province'}

setProvinceForm({ ...provinceForm, provinceName: e.target.value })} className="w-full p-2 border rounded-lg" required />
)} {/* City Modal */} {isCityModalOpen && ( <>
setIsCityModalOpen(false)} />

{editingCity ? 'Edit City' : 'Add City'}

setCityForm({ ...cityForm, cityName: e.target.value })} className="w-full p-2 border rounded-lg" required />
)}
); }; export default Location;