This commit is contained in:
Tomas Dvorak
2026-01-26 08:13:18 +01:00
parent aa036b6550
commit dfc079288f
505 changed files with 95755 additions and 5712 deletions
+36 -34
View File
@@ -38,6 +38,7 @@ import { getPublicContacts, GroupedContacts } from '../services/contactInfo';
import { facrApi } from '../services/facr/facrApi';
import { getCompetitionAliasesPublic } from '../services/competitionAliases';
import { getImageUrl } from '../utils/imageUtils';
import { useTranslation } from 'react-i18next';
type ContactFormData = {
name: string;
@@ -48,6 +49,7 @@ type ContactFormData = {
};
const ContactPage: React.FC = () => {
const { t } = useTranslation();
const toast = useToast();
const { settings } = useSettings();
const cardBg = useColorModeValue('white', 'gray.800');
@@ -77,8 +79,8 @@ const ContactPage: React.FC = () => {
trackContactSubmit(true);
trackFormSubmit('Contact Form', true);
toast({
title: 'Zpráva odeslána',
description: 'Děkujeme za vaši zprávu. Brzy se vám ozveme zpět.',
title: t('contact.message_sent'),
description: t('contact.message_sent_desc'),
status: 'success',
duration: 5000,
isClosable: true,
@@ -92,16 +94,16 @@ const ContactPage: React.FC = () => {
const isNetwork = !!error?.isAxiosError && !error?.response;
const description = msgFromServer
|| (isTimeout ? 'Vypršel časový limit požadavku. Zkuste to prosím znovu za chvíli.'
: isNetwork ? 'Požadavek se nezdařil (síť/CORS). Zkuste to znovu nebo obnovte stránku.'
: 'Něco se pokazilo. Zkuste to prosím znovu později.');
|| (isTimeout ? t('contact.timeout_error')
: isNetwork ? t('contact.network_error')
: t('contact.general_error'));
// Track failed contact form submission
trackContactSubmit(false);
trackFormSubmit('Contact Form', false);
toast({
title: 'Chyba',
title: t('contact.error_title'),
description,
status: 'error',
duration: 6000,
@@ -204,13 +206,13 @@ const ContactPage: React.FC = () => {
<VStack align="stretch" spacing={4}>
{hasContactInfo && (
<Box bg={bgColor} p={4} borderRadius="lg" borderWidth="1px" borderColor={borderColor} boxShadow="sm">
<Heading size="md" mb={3}>Kontaktní údaje</Heading>
<Heading size="md" mb={3}>{t('contact.contact_info')}</Heading>
<VStack align="stretch" spacing={3}>
{(settings as any)?.contact_address && (
<HStack align="start">
<Icon as={FiMapPin} boxSize={5} color="blue.500" mt={1} />
<VStack align="start" spacing={0}>
<Text fontWeight="bold">Adresa</Text>
<Text fontWeight="bold">{t('contact.address')}</Text>
<Text>{(settings as any)?.contact_address}</Text>
{(settings as any)?.contact_city && (
<Text>
@@ -227,7 +229,7 @@ const ContactPage: React.FC = () => {
<HStack align="start">
<Icon as={FiPhone} boxSize={5} color="blue.500" mt={1} />
<VStack align="start" spacing={0}>
<Text fontWeight="bold">Telefon</Text>
<Text fontWeight="bold">{t('contact.phone')}</Text>
<Link href={`tel:${(settings as any)?.contact_phone}`} color="blue.500">
{(settings as any)?.contact_phone}
</Link>
@@ -239,7 +241,7 @@ const ContactPage: React.FC = () => {
<HStack align="start">
<Icon as={FiMail} boxSize={5} color="blue.500" mt={1} />
<VStack align="start" spacing={0}>
<Text fontWeight="bold">Email</Text>
<Text fontWeight="bold">{t('contact.email')}</Text>
<Link href={`mailto:${(settings as any)?.contact_email}`} color="blue.500">
{(settings as any)?.contact_email}
</Link>
@@ -252,7 +254,7 @@ const ContactPage: React.FC = () => {
{hasContacts && (
<Box bg={bgColor} p={4} borderRadius="lg" borderWidth="1px" borderColor={borderColor} boxShadow="sm">
<Heading size="md" mb={3}>Kontaktní osoby</Heading>
<Heading size="md" mb={3}>{t('contact.contact_persons')}</Heading>
<Tabs colorScheme="blue" isFitted isLazy>
{(() => {
const categoryEntries = Object.entries(contactsData?.categories || {});
@@ -266,7 +268,7 @@ const ContactPage: React.FC = () => {
{tabs.map((n) => (
<Tab key={n}>{n}</Tab>
))}
{hasOthers && <Tab>Ostatní</Tab>}
{hasOthers && <Tab>{t('contact.others')}</Tab>}
</TabList>
<TabPanels>
{useCategories
@@ -348,7 +350,7 @@ const ContactPage: React.FC = () => {
))}
</SimpleGrid>
) : (
<Text color="gray.500">Pro tuto kategorii zatím nemáme kontaktní osobu.</Text>
<Text color="gray.500">{t('contact.no_contacts')}</Text>
)}
</TabPanel>
);
@@ -410,10 +412,10 @@ const ContactPage: React.FC = () => {
{/* Contact form at the end */}
<Box>
<Heading size="lg" mb={2} color={settings?.primaryColor || 'brand.500'}>
Kontaktujte nás
{t('contact.contact_us')}
</Heading>
<Text color="gray.500">
Máte dotaz nebo připomínku? Napište nám zprávu a my se vám ozveme co nejdříve zpět.
{t('contact.contact_description')}
</Text>
</Box>
@@ -428,13 +430,13 @@ const ContactPage: React.FC = () => {
<form onSubmit={handleSubmit(onSubmit)}>
<VStack spacing={4}>
<FormControl isInvalid={!!errors.name}>
<FormLabel htmlFor="name">Jméno a příjmení *</FormLabel>
<FormLabel htmlFor="name">{t('contact.name_label')}</FormLabel>
<Input
id="name"
placeholder="Jan Novák"
placeholder={t('contact.name_placeholder')}
{...register('name', {
required: 'Toto pole je povinné',
minLength: { value: 2, message: 'Jméno musí mít alespoň 2 znaky' },
required: t('contact.name_required'),
minLength: { value: 2, message: t('contact.name_min_length') },
})}
/>
<FormErrorMessage>
@@ -443,16 +445,16 @@ const ContactPage: React.FC = () => {
</FormControl>
<FormControl isInvalid={!!errors.email}>
<FormLabel htmlFor="email">E-mailová adresa *</FormLabel>
<FormLabel htmlFor="email">{t('contact.email_label')}</FormLabel>
<Input
id="email"
type="email"
placeholder="vas@email.cz"
placeholder={t('contact.email_placeholder')}
{...register('email', {
required: 'Toto pole je povinné',
required: t('contact.email_required'),
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Neplatná e-mailová adresa',
message: t('contact.email_invalid'),
},
})}
/>
@@ -462,13 +464,13 @@ const ContactPage: React.FC = () => {
</FormControl>
<FormControl isInvalid={!!errors.subject}>
<FormLabel htmlFor="subject">Předmět</FormLabel>
<FormLabel htmlFor="subject">{t('contact.subject_label')}</FormLabel>
<Input
id="subject"
placeholder="Předmět zprávy"
placeholder={t('contact.subject_placeholder')}
{...register('subject', {
required: 'Předmět je povinný',
maxLength: { value: 100, message: 'Předmět může mít maximálně 100 znaků' },
required: t('contact.subject_required'),
maxLength: { value: 100, message: t('contact.subject_max_length') },
})}
/>
<FormErrorMessage>
@@ -477,15 +479,15 @@ const ContactPage: React.FC = () => {
</FormControl>
<FormControl isInvalid={!!errors.message}>
<FormLabel htmlFor="message">Zpráva *</FormLabel>
<FormLabel htmlFor="message">{t('contact.message_label')}</FormLabel>
<Textarea
id="message"
rows={6}
placeholder="Napište nám zprávu..."
placeholder={t('contact.message_placeholder')}
{...register('message', {
required: 'Toto pole je povinné',
minLength: { value: 10, message: 'Zpráva musí mít alespoň 10 znaků' },
maxLength: { value: 2000, message: 'Zpráva může mít maximálně 2000 znaků' },
required: t('contact.message_required'),
minLength: { value: 10, message: t('contact.message_min_length') },
maxLength: { value: 2000, message: t('contact.message_max_length') },
})}
/>
<FormErrorMessage>
@@ -500,10 +502,10 @@ const ContactPage: React.FC = () => {
width="full"
mt={4}
isLoading={isLoading}
loadingText="Odesílám..."
loadingText={t('contact.sending')}
data-umami-event="Contact Form Submit"
>
Odeslat zprávu
{t('contact.send_message')}
</Button>
</VStack>
</form>