Add the Workshops page and keep sign-ups on the site #90

Merged
an.di merged 2 commits from adilallo/feature/CR-229-workshops into main 2026-11-04 03:11:22 +00:00
Member

Overview

Adds the public Workshops page and keeps every sign-up on this site. The form is built once to the settled field set, so the same fields show at every width. A valid send is saved before anyone is emailed. The page names no price, and the member count never sets one.

Changes

  • /workshops in the marketing layout and the sitemap: hero, overview, circle, who runs it, quote, signup, then the existing Ask Organizer section.
  • Quote Block gains a citation layout for the lavender quote.
  • Signup is a normal form. With JavaScript it sends JSON. Without it, the same route accepts the POST, keeps the answers, and returns the confirmation or the form with errors.
  • New WorkshopInquiry table. The server checks every field, ignores a filled honeypot and a too-fast submit, and limits how often one address can send.
  • Organizations of 1,000 members or more are flagged large and see “Choose a time.” Smaller ones see “Download the kit.”
  • The team can read the latest inquiries and export a CSV at /workshop-inquiries. That page stays hidden until its token is set.
  • A purge route retries mail that did not go out, then deletes inquiries older than twelve months.

Screenshots

01-hero.png

How to Test

  1. Apply the new migration, then open /workshops.
  2. Check the page at a phone width, around 800px, and at 1024px and wider. Every “Talk to a facilitator” button should land on the form.
  3. Submit empty. Each required field should show its own message, and anything you typed should still be there.
  4. Tick “Something else” and confirm the extra line appears. Send a complete form for an organization under 1,000 members, then one for 1,000 or more. The first confirmation offers the kit. The second offers a time.
  5. With JavaScript off, submit once empty and once complete. You should come back to the same page with the errors or the confirmation.
  6. Set WORKSHOP_INQUIRY_ADMIN_TOKEN, open /workshop-inquiries, and export the CSV. Unset, that page should 404.

Notes

  • Quote wording, the line under Send, and the note that links to /kit are the current frames and are still pending approval. /kit is not live yet.
  • Leave WORKSHOP_INQUIRY_TO empty until the inbox address is approved. The row still saves, and the inbox email waits.
  • NEXT_PUBLIC_WORKSHOP_SCHEDULING_URL is the “Choose a time” link. Unset, those words are text, not an empty link.
  • WORKSHOP_INQUIRY_ADMIN_TOKEN and WORKSHOP_INQUIRY_PURGE_TOKEN gate the team page and the purge job.
  • Twelve months is the proposed retention. Who reads the inquiries is still open.02-overview.png03-circle.png04-who-runs-it.png
## Overview Adds the public Workshops page and keeps every sign-up on this site. The form is built once to the settled field set, so the same fields show at every width. A valid send is saved before anyone is emailed. The page names no price, and the member count never sets one. ## Changes - `/workshops` in the marketing layout and the sitemap: hero, overview, circle, who runs it, quote, signup, then the existing Ask Organizer section. - Quote Block gains a citation layout for the lavender quote. - Signup is a normal form. With JavaScript it sends JSON. Without it, the same route accepts the POST, keeps the answers, and returns the confirmation or the form with errors. - New `WorkshopInquiry` table. The server checks every field, ignores a filled honeypot and a too-fast submit, and limits how often one address can send. - Organizations of 1,000 members or more are flagged large and see “Choose a time.” Smaller ones see “Download the kit.” - The team can read the latest inquiries and export a CSV at `/workshop-inquiries`. That page stays hidden until its token is set. - A purge route retries mail that did not go out, then deletes inquiries older than twelve months. ## Screenshots ![01-hero.png](attachments/b8107ed5-3ff4-4a9f-b03b-6b0e8f649d9c) ## How to Test 1. Apply the new migration, then open `/workshops`. 2. Check the page at a phone width, around 800px, and at 1024px and wider. Every “Talk to a facilitator” button should land on the form. 3. Submit empty. Each required field should show its own message, and anything you typed should still be there. 4. Tick “Something else” and confirm the extra line appears. Send a complete form for an organization under 1,000 members, then one for 1,000 or more. The first confirmation offers the kit. The second offers a time. 5. With JavaScript off, submit once empty and once complete. You should come back to the same page with the errors or the confirmation. 6. Set `WORKSHOP_INQUIRY_ADMIN_TOKEN`, open `/workshop-inquiries`, and export the CSV. Unset, that page should 404. ## Notes - Quote wording, the line under Send, and the note that links to `/kit` are the current frames and are still pending approval. `/kit` is not live yet. - Leave `WORKSHOP_INQUIRY_TO` empty until the inbox address is approved. The row still saves, and the inbox email waits. - `NEXT_PUBLIC_WORKSHOP_SCHEDULING_URL` is the “Choose a time” link. Unset, those words are text, not an empty link. - `WORKSHOP_INQUIRY_ADMIN_TOKEN` and `WORKSHOP_INQUIRY_PURGE_TOKEN` gate the team page and the purge job. - Twelve months is the proposed retention. Who reads the inquiries is still open.![02-overview.png](attachments/64f83deb-856c-49bf-b449-324ba4819c9b)![03-circle.png](attachments/1d5e9165-454a-41ee-9110-af95ca074bdb)![04-who-runs-it.png](attachments/44544850-3b14-4157-9f72-4de2670cbdd0)
an.di added 2 commits 2026-11-04 03:10:58 +00:00
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>
Co-authored-by: Cursor <cursoragent@cursor.com>
an.di merged commit 18abeb56dd into main 2026-11-04 03:11:22 +00:00
an.di deleted branch adilallo/feature/CR-229-workshops 2026-11-04 03:11:22 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: CommunityRule/community-rule#90