Vai al contenuto

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:

Il video è in inglese; i passaggi qui sotto sono il tutorial completo.

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

  1. Servizi email → Aggiungi servizio: collega la tua casella o il tuo provider, Imposta come predefinito, Verifica e salva.
  2. Modelli → Dalla galleria → Richiesta di preventivo (categoria Business) → Usa modello.
  3. Dalla galleria → Risposta automatica: grazie per il messaggio → Usa modello. Imposta i valori predefiniti di company_name e response_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 held e inviate appena ricarichi: l’hook riporta status === '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 di send per usare una variante linguistica del modello.
Tutti i tutorial