mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-03 18:22:57 +00:00
340 lines
10 KiB
TypeScript
340 lines
10 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
Box,
|
|
Button,
|
|
FormControl,
|
|
FormLabel,
|
|
FormHelperText,
|
|
Input,
|
|
VStack,
|
|
HStack,
|
|
Text,
|
|
Alert,
|
|
AlertIcon,
|
|
AlertTitle,
|
|
AlertDescription,
|
|
Badge,
|
|
Divider,
|
|
Link,
|
|
useColorModeValue,
|
|
} from '@chakra-ui/react';
|
|
import MapStyleSelector from './MapStyleSelector';
|
|
import { FiMapPin, FiCheck, FiX, FiExternalLink } from 'react-icons/fi';
|
|
import { parseMapUrl, MapCoordinates, validateCoordinates, reverseGeocode } from '../../utils/mapUrlParser';
|
|
import ContactMap from '../home/ContactMap';
|
|
|
|
interface MapLinkImporterProps {
|
|
onImport: (coordinates: MapCoordinates) => void;
|
|
currentLatitude?: number;
|
|
currentLongitude?: number;
|
|
currentZoom?: number;
|
|
mapStyle?: string;
|
|
onMapStyleChange?: (style: string) => void;
|
|
clubPrimaryColor?: string;
|
|
clubSecondaryColor?: string;
|
|
clubName?: string;
|
|
}
|
|
|
|
const MapLinkImporter: React.FC<MapLinkImporterProps> = ({
|
|
onImport,
|
|
currentLatitude,
|
|
currentLongitude,
|
|
currentZoom,
|
|
mapStyle,
|
|
onMapStyleChange,
|
|
clubPrimaryColor,
|
|
clubSecondaryColor,
|
|
clubName,
|
|
}) => {
|
|
const [urlInput, setUrlInput] = useState('');
|
|
const [parsedData, setParsedData] = useState<MapCoordinates | null>(null);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [previewCoords, setPreviewCoords] = useState<MapCoordinates | null>(null);
|
|
|
|
const bgColor = useColorModeValue('white', 'gray.800');
|
|
const borderColor = useColorModeValue('gray.200', 'gray.700');
|
|
|
|
useEffect(() => {
|
|
// Initialize preview with current coordinates if available
|
|
if (currentLatitude && currentLongitude) {
|
|
setPreviewCoords({
|
|
latitude: currentLatitude,
|
|
longitude: currentLongitude,
|
|
zoom: currentZoom,
|
|
source: 'unknown',
|
|
});
|
|
}
|
|
}, [currentLatitude, currentLongitude, currentZoom]);
|
|
|
|
const handleUrlChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const value = e.target.value;
|
|
setUrlInput(value);
|
|
setError(null);
|
|
setParsedData(null);
|
|
|
|
if (!value.trim()) {
|
|
return;
|
|
}
|
|
|
|
// Try to parse the URL
|
|
const result = parseMapUrl(value);
|
|
if (result) {
|
|
if (validateCoordinates(result.latitude, result.longitude)) {
|
|
// Perform reverse geocoding to get detailed address
|
|
try {
|
|
const addressDetails = await reverseGeocode(result.latitude, result.longitude);
|
|
const enrichedResult = { ...result, ...addressDetails };
|
|
setParsedData(enrichedResult);
|
|
setPreviewCoords(enrichedResult);
|
|
setError(null);
|
|
} catch (err) {
|
|
// If geocoding fails, still use the basic data
|
|
setParsedData(result);
|
|
setPreviewCoords(result);
|
|
setError(null);
|
|
}
|
|
} else {
|
|
setError('Souřadnice jsou mimo platný rozsah');
|
|
setParsedData(null);
|
|
}
|
|
} else {
|
|
setError('Nepodařilo se rozpoznat URL mapy. Podporované: mapy.cz, Google Maps');
|
|
setParsedData(null);
|
|
}
|
|
};
|
|
|
|
const handleImport = () => {
|
|
if (parsedData) {
|
|
onImport(parsedData);
|
|
setUrlInput('');
|
|
setParsedData(null);
|
|
setError(null);
|
|
}
|
|
};
|
|
|
|
const handleClear = () => {
|
|
setUrlInput('');
|
|
setParsedData(null);
|
|
setError(null);
|
|
// Reset preview to current coordinates
|
|
if (currentLatitude && currentLongitude) {
|
|
setPreviewCoords({
|
|
latitude: currentLatitude,
|
|
longitude: currentLongitude,
|
|
zoom: currentZoom,
|
|
source: 'unknown',
|
|
});
|
|
} else {
|
|
setPreviewCoords(null);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<VStack spacing={4} align="stretch">
|
|
<Box>
|
|
<FormControl>
|
|
<FormLabel display="flex" alignItems="center" gap={2}>
|
|
<FiMapPin /> Importovat z URL mapy
|
|
</FormLabel>
|
|
<Input
|
|
placeholder="Vložte URL z mapy.cz nebo Google Maps..."
|
|
value={urlInput}
|
|
onChange={handleUrlChange}
|
|
size="md"
|
|
/>
|
|
<FormHelperText>
|
|
Podporované formáty:
|
|
<Text as="span" fontWeight="semibold" ml={1}>mapy.cz</Text> (mapy.com/en/letecka?x=...&y=...),
|
|
<Text as="span" fontWeight="semibold" ml={1}>Google Maps</Text> (google.com/maps/place/@lat,lng,zoom)
|
|
</FormHelperText>
|
|
<HStack mt={2} spacing={3} fontSize="sm">
|
|
<Text color="gray.600">Quick links:</Text>
|
|
<Link
|
|
href="https://mapy.com/cs/"
|
|
isExternal
|
|
color="blue.500"
|
|
display="flex"
|
|
alignItems="center"
|
|
gap={1}
|
|
_hover={{ color: 'blue.600', textDecoration: 'underline' }}
|
|
>
|
|
Mapy.cz <FiExternalLink size={12} />
|
|
</Link>
|
|
<Text color="gray.400">•</Text>
|
|
<Link
|
|
href="https://www.google.com/maps/"
|
|
isExternal
|
|
color="blue.500"
|
|
display="flex"
|
|
alignItems="center"
|
|
gap={1}
|
|
_hover={{ color: 'blue.600', textDecoration: 'underline' }}
|
|
>
|
|
Google Maps <FiExternalLink size={12} />
|
|
</Link>
|
|
</HStack>
|
|
</FormControl>
|
|
|
|
{parsedData && (
|
|
<Alert status="success" mt={3} borderRadius="md">
|
|
<AlertIcon />
|
|
<Box flex="1">
|
|
<AlertTitle>Úspěšně rozpoznáno!</AlertTitle>
|
|
<AlertDescription display="block">
|
|
<VStack align="start" spacing={1} mt={2}>
|
|
<HStack>
|
|
<Badge colorScheme="green">
|
|
{parsedData.source === 'mapy.cz' ? 'Mapy.cz' : 'Google Maps'}
|
|
</Badge>
|
|
</HStack>
|
|
<Text fontSize="sm">
|
|
<strong>Šířka:</strong> {parsedData.latitude.toFixed(7)}
|
|
</Text>
|
|
<Text fontSize="sm">
|
|
<strong>Délka:</strong> {parsedData.longitude.toFixed(7)}
|
|
</Text>
|
|
{parsedData.zoom && (
|
|
<Text fontSize="sm">
|
|
<strong>Zoom:</strong> {parsedData.zoom}
|
|
</Text>
|
|
)}
|
|
{parsedData.street && (
|
|
<Text fontSize="sm">
|
|
<strong>Ulice:</strong> {parsedData.street}
|
|
</Text>
|
|
)}
|
|
{parsedData.city && (
|
|
<Text fontSize="sm">
|
|
<strong>Město:</strong> {parsedData.city}
|
|
</Text>
|
|
)}
|
|
{parsedData.zip && (
|
|
<Text fontSize="sm">
|
|
<strong>PSČ:</strong> {parsedData.zip}
|
|
</Text>
|
|
)}
|
|
{parsedData.country && (
|
|
<Text fontSize="sm">
|
|
<strong>Země:</strong> {parsedData.country}
|
|
</Text>
|
|
)}
|
|
{parsedData.address && (
|
|
<Text fontSize="sm">
|
|
<strong>Celá adresa:</strong> {parsedData.address}
|
|
</Text>
|
|
)}
|
|
</VStack>
|
|
</AlertDescription>
|
|
</Box>
|
|
<HStack ml={2}>
|
|
<Button
|
|
leftIcon={<FiCheck />}
|
|
colorScheme="green"
|
|
size="sm"
|
|
onClick={handleImport}
|
|
>
|
|
Importovat
|
|
</Button>
|
|
<Button
|
|
leftIcon={<FiX />}
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={handleClear}
|
|
>
|
|
Zrušit
|
|
</Button>
|
|
</HStack>
|
|
</Alert>
|
|
)}
|
|
|
|
{error && (
|
|
<Alert status="error" mt={3} borderRadius="md">
|
|
<AlertIcon />
|
|
<AlertDescription>{error}</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
</Box>
|
|
|
|
{/* Map Preview */}
|
|
{previewCoords && (
|
|
<>
|
|
<Divider />
|
|
<Box>
|
|
<Text fontWeight="semibold" mb={2}>
|
|
Náhled mapy
|
|
</Text>
|
|
<Box
|
|
borderRadius="md"
|
|
overflow="hidden"
|
|
borderWidth="1px"
|
|
borderColor={borderColor}
|
|
>
|
|
<ContactMap
|
|
latitude={previewCoords.latitude}
|
|
longitude={previewCoords.longitude}
|
|
zoom={previewCoords.zoom || 15}
|
|
address={previewCoords.address}
|
|
clubName={clubName}
|
|
mapStyle={mapStyle || 'positron'}
|
|
clubPrimaryColor={clubPrimaryColor}
|
|
clubSecondaryColor={clubSecondaryColor}
|
|
height={300}
|
|
/>
|
|
</Box>
|
|
<Text fontSize="xs" color="gray.500" mt={2}>
|
|
Souřadnice: {previewCoords.latitude.toFixed(6)}, {previewCoords.longitude.toFixed(6)}
|
|
{previewCoords.zoom && ` | Zoom: ${previewCoords.zoom}`}
|
|
</Text>
|
|
</Box>
|
|
|
|
{/* Map Style Selector */}
|
|
{onMapStyleChange && (
|
|
<>
|
|
<Divider />
|
|
<Box>
|
|
<Text fontWeight="semibold" mb={2}>
|
|
Styl mapy
|
|
</Text>
|
|
<Text fontSize="sm" color="gray.600" mb={3}>
|
|
Vyberte vzhled mapy, který se zobrazí na vašem webu.
|
|
</Text>
|
|
<MapStyleSelector
|
|
value={mapStyle || 'positron'}
|
|
onChange={onMapStyleChange}
|
|
clubPrimaryColor={clubPrimaryColor}
|
|
clubSecondaryColor={clubSecondaryColor}
|
|
showPreview={false}
|
|
/>
|
|
</Box>
|
|
</>
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{/* Example URLs */}
|
|
<Box
|
|
bg={bgColor}
|
|
p={3}
|
|
borderRadius="md"
|
|
borderWidth="1px"
|
|
borderColor={borderColor}
|
|
fontSize="sm"
|
|
>
|
|
<Text fontWeight="semibold" mb={2}>Příklady podporovaných URL:</Text>
|
|
<VStack align="start" spacing={1}>
|
|
<Text fontSize="xs" color="gray.600">
|
|
<strong>Mapy.cz:</strong><br />
|
|
mapy.cz/en/letecka?x=17.6996859&y=50.0947150&z=19
|
|
</Text>
|
|
<Text fontSize="xs" color="gray.600">
|
|
<strong>Google Maps:</strong><br />
|
|
google.com/maps/place/@50.0948669,17.7001456,226m
|
|
</Text>
|
|
</VStack>
|
|
</Box>
|
|
</VStack>
|
|
);
|
|
};
|
|
|
|
export default MapLinkImporter;
|