Come creare un modulo di richiesta preventivo in React Native
Un modulo di richiesta per React Native ed Expo con scelta di servizio, budget e scadenza che ti invia ogni richiesta via email e la conferma automaticamente al cliente.
Aggiornato:
In questo tutorial crei in React Native una schermata di richiesta preventivo: il cliente sceglie un servizio e un budget, aggiunge una scadenza e una descrizione, e tu ricevi un’email strutturata. Una risposta automatica conferma la richiesta al cliente.
Ti serve: un account Frontmail gratuito, un progetto Expo o React Native e circa un quarto d’ora.
1. Collega la tua casella e crea i modelli
- Servizi email → Aggiungi servizio: collega la tua casella o il tuo provider, Imposta come predefinito, Verifica e salva.
- Modelli → Dalla galleria → Richiesta di preventivo (categoria Business) → Usa modello.
- Dalla galleria → Risposta automatica: grazie per il messaggio → Usa modello. Imposta i
valori predefiniti di
company_nameeresponse_time, poi sceglilo nel modello di preventivo in Impostazioni → Consegna → Modello di risposta automatica.
Parametri del modello di preventivo: name, email, service, details (obbligatori) e
phone, company, budget, deadline (facoltativi, la scadenza come YYYY-MM-DD).
service e budget accettano solo i valori elencati nella scheda Parametri. L’esempio di codice usa i valori del modello inglese; se crei il modello in italiano, i valori sono Sito web, E-commerce, App mobile, Consulenza, Altro e Meno di 5.000 €, 5.000–20.000 €, 20.000–50.000 €, Oltre 50.000 €. L’app deve inviare esattamente quelle stringhe.
2. Consenti le app mobile e attiva il CAPTCHA
- Sicurezza → App mobile → Consenti app mobile → Salva.
- Modello di preventivo → Impostazioni → Protezione → Richiedi CAPTCHA (Turnstile): l’app usa il widget condiviso di Frontmail, non servono chiavi.
3. Installa
npx expo install @frontmail/react-native @react-native-async-storage/async-storage react-native-webview
4. Crea il modulo
Per non aggiungere dipendenze all’esempio, le scelte sono semplici pulsanti a chip e la scadenza si
digita come YYYY-MM-DD. Sostituiscili pure con i tuoi componenti picker preferiti: contano solo
i valori che passi a 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>
);
}
I valori facoltativi vuoti (nessun budget, scadenza vuota) vengono esclusi automaticamente dall’email.
5. Provalo
Avvia l’app e invia una richiesta con la tua email. Ricevi la richiesta e la conferma; entrambe
compaiono in Cronologia. Gli errori di validazione tornano come invalid_template_params,
con il campo non valido in error.details.
Una richiesta con la conferma consuma due crediti. Quando i crediti finiscono, le richieste vengono accettate come
helde inviate appena ricarichi: l’hook riportastatus === 'held'.
Prossimi passi
- Tieni un elenco di tutti quelli che hanno chiesto un preventivo: attiva la Raccolta contatti nelle impostazioni del modello.
- Passa
{ locale: 'de' }come secondo argomento disendper usare una variante linguistica del modello.


