# Gatsby

> Un formulario de Gatsby que ya funciona en el HTML estático antes de la hidratación, mejorado con fetch después, más una Gatsby Function para envíos con una clave secreta.

Gatsby renderiza cada página a HTML en tiempo de build. Dale al formulario un `action` real y enviará antes de que React se hidrate, o si el bundle no carga; una vez hidratado, el componente envía con `fetch` y muestra el resultado en su sitio.

## Envía desde el navegador

### Paso 1: Añade el id del formulario

`.env.production`:

```bash
GATSBY_IKIFORM_FORM_ID=frm_xxxxxxxxxxxxxxxx
```

Gatsby solo expone al código del navegador las variables que empiezan con `GATSBY_`, y las incrusta en tiempo de build. Añade la misma línea a `.env.development` para `gatsby develop`.

### Paso 2: Añade el componente

`src/components/contact-form.js`:

```jsx
import * as React from "react";

const endpoint = `https://ikiform.com/f/${process.env.GATSBY_IKIFORM_FORM_ID}`;

export default function ContactForm() {
  const [status, setStatus] = React.useState("idle");
  const [message, setMessage] = React.useState("");

  async function onSubmit(event) {
    event.preventDefault();
    setStatus("sending");
    try {
      const response = await fetch(endpoint, {
        method: "POST",
        headers: { Accept: "application/json" },
        body: new FormData(event.currentTarget),
      });
      const result = await response.json();
      if (result.ok) return setStatus("sent");
      setMessage(result.error.message);
    } catch {
      setMessage("Couldn't reach the server. Try again.");
    }
    setStatus("error");
  }

  if (status === "sent") return <p>Thanks, we got it.</p>;

  return (
    <form action={endpoint} method="post" onSubmit={onSubmit}>
      <label>
        Email
        <input name="email" type="email" autoComplete="email" required />
      </label>
      <label>
        Message
        <textarea name="message" rows={5} />
      </label>
      <input type="hidden" name="_redirect" value="https://example.com/thanks/" />
      <input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
      {status === "error" ? <p role="alert">{message}</p> : null}
      <button disabled={status === "sending"}>Send</button>
    </form>
  );
}
```

Renderízalo desde cualquier página, por ejemplo `src/pages/contact.js`, y añade `src/pages/thanks.js` para la redirección sin JavaScript. Para errores por campo y la verificación humana del SDK, amplíalo como en la [guía de React](https://ikiform.com/es/docs/guides/react.md#component).

## Envía desde una Gatsby Function

Una Gatsby Function puede reenviar los datos con una clave secreta, lo que se salta los dominios permitidos y la verificación humana. Solo funciona en hostings que admiten Gatsby Functions, como Netlify con el adaptador de Gatsby; un hosting puramente estático como GitHub Pages no puede ejecutarla. Guarda `IKIFORM_FORM_ID` y una clave secreta con el permiso `submissions:write` como `IKIFORM_SECRET_KEY`, sin el prefijo `GATSBY_` para que nunca lleguen al navegador.

`src/api/contact.js`:

```js
export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).end();
  const response = await fetch(`https://ikiform.com/f/${process.env.IKIFORM_FORM_ID}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
    },
    body: JSON.stringify(req.body),
  });
  res.status(response.status).json(await response.json());
}
```

Gatsby convierte los cuerpos JSON y form-encoded en `req.body`, así que la página puede enviar a `/api/contact` de cualquiera de las dos formas. Todos los envíos comparten entonces la dirección IP de tu función para los límites de frecuencia; consulta [Desde un servidor](https://ikiform.com/es/docs/guides/server.md).

## Dominios permitidos

Esto aplica a los envíos desde el navegador. Los envíos desde la Gatsby Function usan una clave secreta y se saltan la comprobación.

| Dónde funciona el formulario | Añadir a Allowed domains |
| --- | --- |
| `gatsby develop` y `gatsby serve` | `localhost`. Coincide con `http://localhost:8000` y `http://localhost:9000`: Ikiform solo compara el nombre de host, nunca el puerto. |
| Tu dominio | `example.com`, que también cubre `www.example.com` |
| Netlify | `your-site.netlify.app`. Los deploy previews (`deploy-preview-12--your-site.netlify.app`) y los branch deploys (`branch--your-site.netlify.app`) no son subdominios suyos, así que añade el host exacto de la vista previa mientras la pruebas. |
| Cloudflare Pages | `your-project.pages.dev`. Las URL de vista previa como `abc123.your-project.pages.dev` son subdominios suyos, así que ya coinciden. |

- Nunca añadas `netlify.app` ni `pages.dev` solos. Coincidiría cualquier sitio de ese host, incluidos los de otras personas.

## Lista de pruebas

1. Ejecuta `gatsby build` y abre `public/contact/index.html`. El `action` del formulario debería terminar en el id de tu formulario, no en `undefined`.
2. Ejecuta `gatsby serve` con `localhost` en los dominios permitidos y envía. El mensaje de agradecimiento debería sustituir al formulario.
3. Desactiva JavaScript, recarga y envía. Deberías ver la página de agradecimiento de Ikiform en local, o `/thanks/` en tu dominio `https:`.
4. Si usas la función, envía a `/api/contact` en un deploy preview y confirma que el envío aparece en Ikiform.

## Solución de problemas

| Qué ves | Por qué | Solución |
| --- | --- | --- |
| `404 not_found`, y el action termina en `/f/undefined` | La variable no tiene el prefijo `GATSBY_`, o no estaba definida en tiempo de build | Llámala `GATSBY_IKIFORM_FORM_ID` y vuelve a hacer el build. |
| La función responde `403 forbidden` | La clave secreta es de otro espacio de trabajo, está revocada o le falta `submissions:write` | Crea una clave secreta con ese permiso. |
| `/api/contact` devuelve `404` después de desplegar | El hosting solo sirve archivos estáticos | Despliega en un hosting con Gatsby Functions o usa la versión del navegador. |
| Los envíos llegan al filtro de spam con `origin_mismatch` | La página que envió no está entre los dominios permitidos del formulario | Añade el host de la tabla de arriba. Si eliges **Reject**, esos mismos envíos reciben `403 origin_not_allowed`. |

## Relacionado

- [React](https://ikiform.com/es/docs/guides/react.md): Estados de carga, error y éxito.
- [Desde un servidor](https://ikiform.com/es/docs/guides/server.md): Envía con una clave de API secreta.
- [Dominios permitidos](https://ikiform.com/es/docs/spam.md#allowed-domains): Cómo se comparan los orígenes y qué pasa cuando no coinciden.
- [Errores](https://ikiform.com/es/docs/errors.md): Cada código de error, con su causa y su solución.
