Add the Workshops page and keep each sign-up on the site.

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>
This commit is contained in:
adilalloandCursor committed 2026-11-03 19:56:49 -07:00
1 parent 974a5ace4c
commit c0ba3a3798
50 files changed
+2773 -1

No files matched your search

+90
View File
@@ -0,0 +1,90 @@
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, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;");
}