Jak v React Native udělat poptávkový formulář
Poptávkový formulář v React Native a Expo s výběrem služby, rozpočtu a termínu, který vám každou poptávku pošle e-mailem a zákazníkovi ji automaticky potvrdí.
Aktualizováno:
V tomto návodu postavíte v React Native obrazovku pro poptávku: zákazník vybere službu a rozpočet, doplní termín a popis a vy dostanete strukturovaný e-mail. Automatická odpověď zákazníkovi poptávku potvrdí.
Budete potřebovat: bezplatný účet Frontmail, projekt v Expo nebo React Native a zhruba patnáct minut.
1. Připojte schránku a vytvořte šablony
- E-mailové služby → Přidat službu: připojte svou schránku nebo poskytovatele, Nastavit jako výchozí, Ověřit a uložit.
- Šablony → Z galerie → Poptávka (kategorie Byznys) → Použít šablonu.
- Z galerie → Automatická odpověď: díky za zprávu → Použít šablonu. Nastavte výchozí
hodnoty
company_namearesponse_timea pak ji v šabloně poptávky zvolte v Nastavení → Doručování → Šablona automatické odpovědi.
Parametry šablony poptávky: name, email, service, details (povinné) a phone, company,
budget, deadline (nepovinné, termín jako YYYY-MM-DD). service a budget přijímají jen
hodnoty uvedené na záložce Parametry – v aplikaci použijte stejné řetězce. Příklad kódu používá
hodnoty anglické šablony; česká šablona má Web, E-shop, Mobilní aplikace, Konzultace, Jiné
a Do 100 tis. Kč, 100–500 tis. Kč, 500 tis. – 1 mil. Kč, Nad 1 mil. Kč. Aplikace musí posílat
přesně hodnoty ze záložky Parametry.
2. Povolte mobilní aplikace a zapněte CAPTCHA
- Zabezpečení → Mobilní aplikace → Povolit mobilní aplikace → Uložit.
- Šablona poptávky → Nastavení → Ochrana → Vyžadovat CAPTCHA (Turnstile) – aplikace používá sdílený widget Frontmailu, žádné klíče nepotřebujete.
3. Instalace
npx expo install @frontmail/react-native @react-native-async-storage/async-storage react-native-webview
4. Postavte formulář
Aby příklad nepotřeboval další závislosti, jsou volby jednoduchá tlačítka (chipy) a termín se
zadává ručně jako YYYY-MM-DD. Klidně použijte své oblíbené komponenty pro výběr – záleží jen
na hodnotách, které předáte do send.
import { useRef, useState } from 'react';
import { Button, Pressable, Text, TextInput, View } from 'react-native';
import { FrontmailProvider, TurnstileWebView, useSendEmail, type TurnstileWebViewHandle } from '@frontmail/react-native';
const options = { publicKey: 'pk_…' };
const SERVICES = ['Website', 'E-shop', 'Mobile app', 'Consulting', 'Other'];
const BUDGETS = ['Under $5k', '$5k–20k', '$20k–50k', 'Over $50k'];
export default function App() {
return (
<FrontmailProvider options={options}>
<QuoteForm />
</FrontmailProvider>
);
}
function Choice({ values, value, onChange }: { values: string[]; value?: string; onChange(v?: string): void }) {
return (
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8 }}>
{values.map((v) => (
<Pressable key={v} onPress={() => onChange(v === value ? undefined : v)} accessibilityState={{ selected: v === value }}>
<Text style={{ padding: 8, borderWidth: 1, borderRadius: 16, fontWeight: v === value ? '700' : '400' }}>{v}</Text>
</Pressable>
))}
</View>
);
}
function QuoteForm() {
const { send, status, error } = useSendEmail(null, 'tpl_…');
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [service, setService] = useState<string | undefined>(SERVICES[0]);
const [budget, setBudget] = useState<string>();
const [deadline, setDeadline] = useState('');
const [details, setDetails] = useState('');
const [token, setToken] = useState<string>();
const turnstile = useRef<TurnstileWebViewHandle>(null);
const onSend = async () => {
await send({ name, email, service, budget, deadline, details }, { turnstileToken: token });
setToken(undefined);
turnstile.current?.reset(); // a token works only once
};
if (status === 'sent' || status === 'held') return <Text>Thanks! We’ve emailed you a confirmation.</Text>;
return (
<View style={{ gap: 12, padding: 16 }}>
<TextInput placeholder="Name" value={name} onChangeText={setName} />
<TextInput placeholder="Email" value={email} onChangeText={setEmail} keyboardType="email-address" autoCapitalize="none" />
<Text>What do you need?</Text>
<Choice values={SERVICES} value={service} onChange={setService} />
<Text>Budget (optional)</Text>
<Choice values={BUDGETS} value={budget} onChange={setBudget} />
<TextInput placeholder="Deadline (YYYY-MM-DD, optional)" value={deadline} onChangeText={setDeadline} />
<TextInput placeholder="Project details" value={details} onChangeText={setDetails} multiline />
<TurnstileWebView ref={turnstile} onToken={setToken} />
<Button title="Request a quote" disabled={!token || !service || status === 'sending'} onPress={onSend} />
{error && <Text>{error.message}</Text>}
</View>
);
}
Prázdné nepovinné hodnoty (bez rozpočtu, prázdný termín) se z e-mailu automaticky vynechají.
5. Vyzkoušejte to
Spusťte aplikaci a odešlete poptávku se svým e-mailem. Přijde vám poptávka i potvrzení; obojí se
zobrazí v sekci Historie. Chyby validace se vracejí jako invalid_template_params a pole, které
neprošlo, najdete v error.details.
Poptávka s potvrzením stojí dva kredity. Když kredity dojdou, poptávky se přijmou jako
helda odešlou se po dobití – hook hlásístatus === 'held'.
Další kroky
- Veďte si seznam všech, kdo poptávali: zapněte v nastavení šablony Sběr kontaktů.
- Předejte
{ locale: 'de' }jako druhý argumentsenda použije se jazyková verze šablony.


