Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 78 additions & 49 deletions src/layouts/setting/tabs/general/components/select-city.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { useRef, useState } from 'react'
import { CiLocationOn } from 'react-icons/ci'
import Analytics from '@/analytics'
import { setToStorage } from '@/common/storage'
import { IconLoading } from '@/components/loading/icon-loading'
import Modal from '@/components/modal'
import { SectionPanel } from '@/components/section-panel'
import { type SelectedCity, useGeneralSetting } from '@/context/general-setting.context'
import { useDebouncedValue } from '@/hooks/useDebouncedValue'
import { useGetRelatedCities } from '@/services/hooks/weather/getRelatedCities'
import { CityResultsList } from '../../weather/CityResultsList'
import { CitySearchInput } from '../../weather/CitySearchInput'
import { SelectedCityDisplay } from '../../weather/SelectedCityDisplay'

export function SelectCity() {
const [inputValue, setInputValue] = useState('')
const [isDropdownOpen, setIsDropdownOpen] = useState(false)
const [isModalOpen, setIsModalOpen] = useState(false)
const inputRef = useRef<HTMLInputElement>(null)

const debouncedValue = useDebouncedValue(
Expand All @@ -24,76 +26,103 @@ export function SelectCity() {

const handleSelectCity = (city: SelectedCity) => {
setSelectedCity(city)
setIsDropdownOpen(false)
setIsModalOpen(false)
setInputValue('')

Analytics.event('city_selected', {
city_name: city.name,
state: city.state,
latitude: city.lat,
longitude: city.lon,
})
Analytics.event('city_selected')

setToStorage('selectedCity', {
lat: city.lat,
lon: city.lon,
name: city.name,
state: city.state,
})

setInputValue('')
inputRef.current?.blur()
}

const handleInputChange = (value: string) => {
setInputValue(value)
}

const handleInputFocus = () => {
setIsDropdownOpen(true)
}

const handleCloseDropdown = () => {
setIsDropdownOpen(false)
const onModalOpen = () => {
setIsModalOpen(true)
Analytics.event('open_city_selection_modal')
setTimeout(() => {
inputRef.current?.focus()
}, 100)
}

return (
<SectionPanel title="انتخاب شهر" delay={0.1}>
<div className="space-y-4">
<div className="relative">
<CitySearchInput
ref={inputRef}
value={inputValue}
onChange={handleInputChange}
onFocus={handleInputFocus}
isLoading={isLoading}
/>{' '}
{isDropdownOpen && inputValue.length >= 2 && (
<div className="absolute z-50 w-full mt-1 duration-200 animate-in fade-in-0 slide-in-from-bottom-2">
{' '}
<CityResultsList
cities={relatedCities || []}
onSelectCity={handleSelectCity}
onClickOutside={handleCloseDropdown}
isLoading={isLoading}
/>
</div>
)}
</div>
<SectionPanel title="انتخاب شهر" size="sm">
<div className="space-y-2">
<button
onClick={() => onModalOpen()}
className="flex items-center justify-between w-full p-3 text-right transition-colors border cursor-pointer rounded-2xl bg-base-100 border-base-300 hover:bg-base-200"
>
<span>
{selectedCity
? `${selectedCity.name} ${selectedCity.state ? `, ${selectedCity.state}` : ''}`
: 'انتخاب شهر'}
</span>
<CiLocationOn className="w-5 h-5 text-primary" />
</button>
<SelectedCityDisplay city={selectedCity} />
{error && (
<div
className={
'p-3 text-sm text-right border rounded-lg backdrop-blur-sm animate-in fade-in-0 duration-300'
}
>
{' '}
<div className="font-medium">خطا در دریافت اطلاعات</div>
<div className="mt-1 opacity-80">
<div className="p-3 text-sm text-right duration-300 border rounded-lg border-red-500/20 bg-red-500/10 backdrop-blur-sm animate-in fade-in-0">
<div className="font-medium text-red-400">
خطا در دریافت اطلاعات
</div>
<div className="mt-1 text-red-300 opacity-80">
لطفا اتصال اینترنت خود را بررسی کرده و مجدداً تلاش کنید.
</div>
</div>
)}
</div>
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title="انتخاب شهر"
size="lg"
direction="rtl"
>
<div className="space-y-4">
<CitySearchInput
ref={inputRef}
value={inputValue}
onChange={handleInputChange}
onFocus={() => {}}
isLoading={isLoading}
/>
<div className="overflow-y-auto max-h-96 custom-scrollbar">
{isLoading ? (
<div className="flex items-center justify-center p-4 text-center text-primary">
<IconLoading />
در حال بارگذاری...
</div>
) : relatedCities && relatedCities.length > 0 ? (
relatedCities.map((city) => (
<div
key={`${city.lat}-${city.lon}`}
onClick={() => handleSelectCity(city)}
className="flex items-center w-full p-3 text-right transition-all duration-200 border-b cursor-pointer hover:bg-gradient-to-l hover:from-primary/10 hover:to-transparent border-base-200/30 last:border-b-0 group rounded-2xl"
>
<CiLocationOn className="flex-shrink-0 w-5 h-5 ml-3 transition-transform text-primary group-hover:scale-110" />
<span className="flex-1 font-medium">
{city.name}
{city.state ? `, ${city.state}` : ''}
</span>
</div>
))
) : inputValue.length >= 2 ? (
<div className="p-4 text-center text-base-content/60">
نتیجه‌ای یافت نشد
</div>
) : (
<div className="p-4 text-center text-base-content/60">
شهر مورد نظر خود را جستجو کنید
</div>
)}
</div>
</div>
</Modal>
</SectionPanel>
)
}
113 changes: 0 additions & 113 deletions src/layouts/setting/tabs/weather/CityResultsList.tsx

This file was deleted.

Loading