Intranet LocationPicker düzeltmesi
This commit is contained in:
parent
cbd96fd8f2
commit
0554717bc6
4 changed files with 114 additions and 24 deletions
|
|
@ -12306,6 +12306,36 @@
|
|||
"en": "Google Maps could not be loaded. Please check your internet connection.",
|
||||
"tr": "Google Maps yüklenemedi. Lütfen internet bağlantınızı kontrol edin."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.Intranet.SocialWall.LocationPicker.NoResults",
|
||||
"en": "No results found",
|
||||
"tr": "Sonuç bulunamadı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.Intranet.SocialWall.LocationPicker.OverQueryLimit",
|
||||
"en": "Google Places query limit exceeded. Please try again later.",
|
||||
"tr": "Google Places sorgu limiti aşıldı. Lütfen daha sonra tekrar deneyiniz."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.Intranet.SocialWall.LocationPicker.RequestDenied",
|
||||
"en": "Google Places request denied. Please check your API key, billing, or permissions settings.",
|
||||
"tr": "Google Places isteği reddedildi. API key, billing veya yetki ayarlarını kontrol ediniz."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.Intranet.SocialWall.LocationPicker.InvalidRequest",
|
||||
"en": "Invalid location search request. Please check your input and try again.",
|
||||
"tr": "Geçersiz konum arama isteği."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.Intranet.SocialWall.LocationPicker.UnknownError",
|
||||
"en": "Google Places returned a temporary error. Please try again.",
|
||||
"tr": "Google Places geçici bir hata döndürdü. Lütfen tekrar deneyiniz."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.Intranet.SocialWall.LocationPicker.SearchFailed",
|
||||
|
|
|
|||
17
ui/.env
17
ui/.env
|
|
@ -3,3 +3,20 @@ VITE_CDN_URL='http://localhost:4005'
|
|||
VITE_REACT_APP_VERSION=$npm_package_version
|
||||
VITE_AI_URL='https://ai.sozsoft.com/webhook/'
|
||||
VITE_GOOGLE_MAPS_API_KEY='AIzaSyAefS2rvF-xwq7OHpZ27UYxXPbMo6OwACc'
|
||||
# Google Cloud Console’da:
|
||||
|
||||
# APIs & Services > Enabled APIs & services bölümüne gir.
|
||||
# Şunların aktif olduğundan emin ol:
|
||||
# Maps JavaScript API
|
||||
# Places API
|
||||
|
||||
# Eğer ileride koordinat/adres çözümleme yapıyorsan ayrıca:
|
||||
|
||||
# Geocoding API
|
||||
# APIs & Services > Credentials > API Key içine gir.
|
||||
# API restrictions bölümünde:
|
||||
|
||||
# Eğer Restrict key seçiliyse, izinli API listesine şunları ekle:
|
||||
|
||||
# Maps JavaScript API
|
||||
# Places API
|
||||
|
|
@ -1001,7 +1001,7 @@ const FileManager = () => {
|
|||
size="sm"
|
||||
icon={<FaTh />}
|
||||
className={classNames(
|
||||
'rounded-r-none border-r px-2 sm:px-3',
|
||||
'rounded-r-none border-r ',
|
||||
viewMode === 'grid' && 'bg-blue-50 dark:bg-blue-900/20 text-blue-600',
|
||||
)}
|
||||
onClick={() => setViewMode('grid')}
|
||||
|
|
@ -1012,7 +1012,7 @@ const FileManager = () => {
|
|||
size="sm"
|
||||
icon={<FaList />}
|
||||
className={classNames(
|
||||
'rounded-l-none px-2 sm:px-3',
|
||||
'rounded-l-none ',
|
||||
viewMode === 'list' && 'bg-blue-50 dark:bg-blue-900/20 text-blue-600',
|
||||
)}
|
||||
onClick={() => setViewMode('list')}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ declare global {
|
|||
}
|
||||
|
||||
const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) => {
|
||||
const { translate } = useLocalization();
|
||||
const { translate } = useLocalization()
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [locations, setLocations] = useState<LocationData[]>([])
|
||||
const [selectedLocation, setSelectedLocation] = useState<LocationData | null>(null)
|
||||
|
|
@ -108,6 +108,28 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
searchInputRef.current?.focus()
|
||||
}, [])
|
||||
|
||||
const getGooglePlacesErrorMessage = (status: any) => {
|
||||
switch (status) {
|
||||
case window.google.maps.places.PlacesServiceStatus.ZERO_RESULTS:
|
||||
return translate('::App.Platform.Intranet.SocialWall.LocationPicker.NoResults')
|
||||
|
||||
case window.google.maps.places.PlacesServiceStatus.OVER_QUERY_LIMIT:
|
||||
return translate('::App.Platform.Intranet.SocialWall.LocationPicker.OverQueryLimit')
|
||||
|
||||
case window.google.maps.places.PlacesServiceStatus.REQUEST_DENIED:
|
||||
return translate('::App.Platform.Intranet.SocialWall.LocationPicker.RequestDenied')
|
||||
|
||||
case window.google.maps.places.PlacesServiceStatus.INVALID_REQUEST:
|
||||
return translate('::App.Platform.Intranet.SocialWall.LocationPicker.InvalidRequest')
|
||||
|
||||
case window.google.maps.places.PlacesServiceStatus.UNKNOWN_ERROR:
|
||||
return translate('::App.Platform.Intranet.SocialWall.LocationPicker.UnknownError')
|
||||
|
||||
default:
|
||||
return translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchFailed')
|
||||
}
|
||||
}
|
||||
|
||||
// Google Places Autocomplete ile konum arama
|
||||
useEffect(() => {
|
||||
if (debounceTimerRef.current) {
|
||||
|
|
@ -134,28 +156,32 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
{
|
||||
input: searchQuery,
|
||||
componentRestrictions: { country: 'tr' },
|
||||
language: 'tr'
|
||||
language: 'tr',
|
||||
},
|
||||
async (predictions: any, status: any) => {
|
||||
if (status === window.google.maps.places.PlacesServiceStatus.ZERO_RESULTS) {
|
||||
setLocations([])
|
||||
setError(getGooglePlacesErrorMessage(status))
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (status !== window.google.maps.places.PlacesServiceStatus.OK) {
|
||||
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchFailed'))
|
||||
setLocations([])
|
||||
setError(getGooglePlacesErrorMessage(status))
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (!predictions || predictions.length === 0) {
|
||||
setLocations([])
|
||||
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.NoResults'))
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
// Her bir prediction için detaylı bilgi al
|
||||
setError(null)
|
||||
|
||||
const detailedLocations: LocationData[] = []
|
||||
let completed = 0
|
||||
|
||||
|
|
@ -163,7 +189,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
placesServiceRef.current.getDetails(
|
||||
{
|
||||
placeId: prediction.place_id,
|
||||
fields: ['name', 'formatted_address', 'geometry', 'place_id']
|
||||
fields: ['name', 'formatted_address', 'geometry', 'place_id'],
|
||||
},
|
||||
(place: any, placeStatus: any) => {
|
||||
completed++
|
||||
|
|
@ -175,19 +201,24 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
address: place.formatted_address,
|
||||
lat: place.geometry.location.lat(),
|
||||
lng: place.geometry.location.lng(),
|
||||
placeId: place.place_id
|
||||
placeId: place.place_id,
|
||||
})
|
||||
}
|
||||
|
||||
// Tüm istekler tamamlandıysa state'i güncelle
|
||||
if (completed === predictions.length) {
|
||||
if (detailedLocations.length === 0) {
|
||||
setError('Konum detayları alınamadı. API yetkilerini kontrol ediniz.')
|
||||
} else {
|
||||
setError(null)
|
||||
}
|
||||
|
||||
setLocations(detailedLocations)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
} catch (err) {
|
||||
console.error('Location search error:', err)
|
||||
|
|
@ -224,7 +255,9 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.AddLocation')}</h2>
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white">
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.AddLocation')}
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
|
||||
|
|
@ -242,7 +275,9 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder={translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchPlaceholder')}
|
||||
placeholder={translate(
|
||||
'::App.Platform.Intranet.SocialWall.LocationPicker.SearchPlaceholder',
|
||||
)}
|
||||
disabled={!isGoogleLoaded}
|
||||
className="w-full pl-10 pr-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-100 dark:disabled:bg-gray-600 disabled:cursor-not-allowed"
|
||||
/>
|
||||
|
|
@ -259,12 +294,16 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
{!isGoogleLoaded ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||
<p className="text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.LoadingGoogleMaps')}</p>
|
||||
<p className="text-gray-500 dark:text-gray-400">
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.LoadingGoogleMaps')}
|
||||
</p>
|
||||
</div>
|
||||
) : isLoading ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||
<p className="text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchingLocations')}</p>
|
||||
<p className="text-gray-500 dark:text-gray-400">
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchingLocations')}
|
||||
</p>
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="text-center py-12">
|
||||
|
|
@ -298,7 +337,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
'w-full text-left p-3 rounded-lg transition-all hover:bg-gray-50 dark:hover:bg-gray-700',
|
||||
selectedLocation?.id === location.id
|
||||
? 'bg-blue-50 dark:bg-blue-900/30 border-2 border-blue-500'
|
||||
: 'border-2 border-transparent'
|
||||
: 'border-2 border-transparent',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
|
|
@ -306,9 +345,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
<FaMapMarkerAlt
|
||||
className={classNames(
|
||||
'w-5 h-5',
|
||||
selectedLocation?.id === location.id
|
||||
? 'text-blue-600'
|
||||
: 'text-gray-400'
|
||||
selectedLocation?.id === location.id ? 'text-blue-600' : 'text-gray-400',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -318,7 +355,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
'font-semibold mb-1',
|
||||
selectedLocation?.id === location.id
|
||||
? 'text-blue-600 dark:text-blue-400'
|
||||
: 'text-gray-900 dark:text-gray-100'
|
||||
: 'text-gray-900 dark:text-gray-100',
|
||||
)}
|
||||
>
|
||||
{location.name}
|
||||
|
|
@ -333,7 +370,11 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
{selectedLocation?.id === location.id && (
|
||||
<div className="mt-1">
|
||||
<div className="w-5 h-5 bg-blue-600 rounded-full flex items-center justify-center">
|
||||
<svg className="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||
<svg
|
||||
className="w-3 h-3 text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
||||
|
|
@ -361,7 +402,9 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
</span>
|
||||
</span>
|
||||
) : (
|
||||
<span>{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SelectLocation')}</span>
|
||||
<span>
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SelectLocation')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
|
|
|
|||
Loading…
Reference in a new issue