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>
91 lines
3.0 KiB
TypeScript
91 lines
3.0 KiB
TypeScript
import type { WorkshopFormValues } from "./workshopSignup";
|
|
|
|
export interface WorkshopInquiryMailInput {
|
|
values: WorkshopFormValues;
|
|
routeNote: string;
|
|
largeOrganization: boolean;
|
|
requestId: string;
|
|
schedulingUrl: string;
|
|
}
|
|
|
|
function line(label: string, value: string): string {
|
|
const trimmed = value.trim();
|
|
return trimmed.length > 0 ? `${label}: ${trimmed}` : `${label}:`;
|
|
}
|
|
|
|
/** Inbox note for the team. Includes the answers and a route. No price. */
|
|
export function buildWorkshopInboxMail(input: WorkshopInquiryMailInput): {
|
|
subject: string;
|
|
text: string;
|
|
html: string;
|
|
} {
|
|
const { values } = input;
|
|
const challenges = values.challenges.join(", ");
|
|
const text = [
|
|
`Request ID: ${input.requestId}`,
|
|
line("Organization", values.organizationName),
|
|
line("Kind", values.organizationKind),
|
|
line("Members", values.memberCount),
|
|
`Large organization: ${input.largeOrganization ? "yes" : "no"}`,
|
|
line("Route", input.routeNote),
|
|
line("Name", values.contactName),
|
|
line("Email", values.email),
|
|
line("Role", values.role),
|
|
line("Challenges", challenges),
|
|
line("Something else", values.challengeOther),
|
|
line("Unspoken question", values.unspokenQuestion),
|
|
line("Page", values.sourcePage),
|
|
line("Link", values.sourceUrl),
|
|
].join("\n");
|
|
|
|
const html = text
|
|
.split("\n")
|
|
.map((row) => `<p>${escapeHtml(row)}</p>`)
|
|
.join("");
|
|
|
|
return {
|
|
subject: `Workshop inquiry from ${values.organizationName}`,
|
|
text,
|
|
html,
|
|
};
|
|
}
|
|
|
|
/** Confirmation to the person who wrote. Promises two working days and names no price. */
|
|
export function buildWorkshopConfirmationMail(input: {
|
|
largeOrganization: boolean;
|
|
schedulingUrl: string;
|
|
}): { subject: string; text: string; html: string } {
|
|
const subject = "We received your workshop note";
|
|
const intro =
|
|
"Thank you. A facilitator will read this closely and write back within two working days.";
|
|
const next = input.largeOrganization
|
|
? "Organizations of this size start with a call."
|
|
: "The kit has the four questions and the thirteen templates if you want a head start.";
|
|
const schedule =
|
|
input.largeOrganization && input.schedulingUrl.trim().length > 0
|
|
? `Choose a time: ${input.schedulingUrl.trim()}`
|
|
: "";
|
|
const text = [intro, next, schedule].filter((part) => part.length > 0).join("\n\n");
|
|
const html =
|
|
`<div style="background:#141414;padding:24px 32px;">` +
|
|
`<p style="margin:0;font-family:Inter,Arial,sans-serif;font-size:14px;letter-spacing:0.08em;color:#ffffff;">COMMUNITYRULE</p>` +
|
|
`</div>` +
|
|
`<div style="background:#ffffff;padding:32px;font-family:Inter,Arial,sans-serif;color:#141414;">` +
|
|
`<p>${escapeHtml(intro)}</p>` +
|
|
`<p>${escapeHtml(next)}</p>` +
|
|
(schedule
|
|
? `<p><a href="${escapeHtml(input.schedulingUrl.trim())}">Choose a time</a></p>`
|
|
: "") +
|
|
`</div>`;
|
|
|
|
return { subject, text, html };
|
|
}
|
|
|
|
function escapeHtml(value: string): string {
|
|
return value
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """);
|
|
}
|