The form is built once to the settled field set, and a valid send is saved before anyone is emailed. Co-authored-by: Cursor <cursoragent@cursor.com>
95 lines
3.1 KiB
TypeScript
95 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import { memo, useState, type FormEvent } from "react";
|
|
import {
|
|
EMPTY_WORKSHOP_FORM_VALUES,
|
|
WORKSHOP_HONEYPOT_FIELD,
|
|
WORKSHOP_STARTED_AT_FIELD,
|
|
} from "../../../../lib/workshopSignup";
|
|
import WorkshopSignupView from "./WorkshopSignup.view";
|
|
import type { WorkshopSignupProps, WorkshopSignupStatus } from "./WorkshopSignup.types";
|
|
|
|
/** Figma: "Section / Workshop Signup" (24323:55538). Full field set at every width. */
|
|
function WorkshopSignupContainer({
|
|
className,
|
|
issuedAt,
|
|
schedulingUrl = "",
|
|
sourceUrl = "",
|
|
initialStatus = "idle",
|
|
initialLarge = false,
|
|
initialValues = EMPTY_WORKSHOP_FORM_VALUES,
|
|
initialFieldErrors = {},
|
|
}: WorkshopSignupProps) {
|
|
const [status, setStatus] = useState<WorkshopSignupStatus>(initialStatus);
|
|
const [largeOrganization, setLargeOrganization] = useState(initialLarge);
|
|
const [fieldErrors, setFieldErrors] = useState(initialFieldErrors);
|
|
|
|
const onSubmit = async (event: FormEvent<HTMLFormElement>) => {
|
|
event.preventDefault();
|
|
const data = new FormData(event.currentTarget);
|
|
setStatus("sending");
|
|
try {
|
|
const response = await fetch("/api/workshop-signup", {
|
|
method: "POST",
|
|
headers: { "content-type": "application/json", accept: "application/json" },
|
|
body: JSON.stringify({
|
|
challenges: data.getAll("challenges"),
|
|
challengeOther: data.get("challengeOther"),
|
|
unspokenQuestion: data.get("unspokenQuestion"),
|
|
organizationName: data.get("organizationName"),
|
|
organizationKind: data.get("organizationKind"),
|
|
memberCount: data.get("memberCount"),
|
|
contactName: data.get("contactName"),
|
|
email: data.get("email"),
|
|
role: data.get("role"),
|
|
sourcePage: "/workshops",
|
|
sourceUrl,
|
|
[WORKSHOP_HONEYPOT_FIELD]: data.get(WORKSHOP_HONEYPOT_FIELD),
|
|
[WORKSHOP_STARTED_AT_FIELD]: Number(data.get(WORKSHOP_STARTED_AT_FIELD) ?? issuedAt),
|
|
}),
|
|
});
|
|
const body = (await response.json()) as {
|
|
status?: string;
|
|
largeOrganization?: boolean;
|
|
fieldErrors?: WorkshopSignupProps["initialFieldErrors"];
|
|
};
|
|
if (body.status === "sent") {
|
|
setLargeOrganization(Boolean(body.largeOrganization));
|
|
setFieldErrors({});
|
|
setStatus("sent");
|
|
return;
|
|
}
|
|
if (body.status === "invalid") {
|
|
setFieldErrors(body.fieldErrors ?? {});
|
|
setStatus("invalid");
|
|
return;
|
|
}
|
|
if (body.status === "rate_limited" || response.status === 429) {
|
|
setStatus("rate_limited");
|
|
return;
|
|
}
|
|
setStatus("failed");
|
|
} catch {
|
|
setStatus("failed");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<WorkshopSignupView
|
|
className={className ?? ""}
|
|
issuedAt={issuedAt}
|
|
schedulingUrl={schedulingUrl}
|
|
sourceUrl={sourceUrl}
|
|
status={status}
|
|
largeOrganization={largeOrganization}
|
|
values={initialValues}
|
|
fieldErrors={fieldErrors}
|
|
onSubmit={onSubmit}
|
|
/>
|
|
);
|
|
}
|
|
|
|
WorkshopSignupContainer.displayName = "WorkshopSignup";
|
|
|
|
export default memo(WorkshopSignupContainer);
|