diff --git a/apps/site/functions/join/_form.ts b/apps/site/functions/join/_form.ts index cfee767d..46ba9a95 100644 --- a/apps/site/functions/join/_form.ts +++ b/apps/site/functions/join/_form.ts @@ -26,11 +26,7 @@ const TEXT_FIELDS: [string, keyof JoinInput][] = [ ]; function restoreTravelAnswers(rewriter: HTMLRewriter, input: JoinInput): HTMLRewriter { - const checked = [ - ...(input.ownsCar === 'yes' ? ['car'] : []), - ...input.micromobility, - ...(input.ownsCar === 'no' && input.micromobility.length === 0 ? ['none'] : []), - ]; + const checked = [...(input.ownsCar === 'yes' ? ['car'] : []), ...input.micromobility]; for (const answer of checked) { rewriter = rewriter.on(`input[name="transport_options"][value="${answer}"]`, { element(element) { diff --git a/apps/site/platform/core/join-form.ts b/apps/site/platform/core/join-form.ts index 33ad202a..6fdba31d 100644 --- a/apps/site/platform/core/join-form.ts +++ b/apps/site/platform/core/join-form.ts @@ -40,7 +40,7 @@ export interface JoinInput { honeypot: string; } -export type JoinField = 'email' | 'zip' | 'phone' | 'consent'; +export type JoinField = 'email' | 'given_name' | 'zip' | 'phone' | 'consent'; export type JoinErrors = Partial>; const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; @@ -118,6 +118,7 @@ export function formatPhone(e164: string): string { export function validateJoin(input: JoinInput): JoinErrors { const errors: JoinErrors = {}; if (!EMAIL_PATTERN.test(input.email)) errors.email = input.email ? 'invalid' : 'required'; + if (input.origin === 'join_form' && !input.givenName.trim()) errors.given_name = 'required'; if (input.zip && !/^\d{5}$/.test(input.zip)) errors.zip = 'invalid'; if (input.phone && normalizePhone(input.phone) === null) errors.phone = 'invalid'; if (!input.consent) errors.consent = 'required'; diff --git a/apps/site/platform/messages/en.ts b/apps/site/platform/messages/en.ts index 0f8c9e06..15b48136 100644 --- a/apps/site/platform/messages/en.ts +++ b/apps/site/platform/messages/en.ts @@ -12,9 +12,11 @@ export const en = { intro: "Members get LVBT's updates, invitations to events and a say in what we work on. It's free.", emailLabel: 'Email address', - givenNameLabel: 'First name (optional)', + givenNameLabel: 'First name', + givenNameError: 'Enter your first name', familyNameLabel: 'Last name (optional)', phoneLabel: 'Phone number (optional)', + phoneHint: 'Only for questions about your membership. LVBT updates come by email.', interestsHeading: 'What are you interested in? (optional)', interestEvents: 'Coming to events', interestMeetings: 'Speaking up at public meetings', @@ -23,9 +25,8 @@ export const en = { discordUsernameLabel: 'Discord username (optional)', discordUsernameHint: 'We can use this later to give you the right roles in our server.', transportHeading: 'What do you own for getting around? (optional)', - transportHint: 'Select all that apply.', + transportHint: 'Select all that apply, or leave this blank.', transportCar: 'Car', - transportNone: 'None of these', micromobilityBike: 'Bike (traditional)', micromobilityEbike: 'E-bike', micromobilityScooter: 'Scooter', diff --git a/apps/site/public/scripts/join-steps.js b/apps/site/public/scripts/join-steps.js index 7529b49e..9ee8cb23 100644 --- a/apps/site/public/scripts/join-steps.js +++ b/apps/site/public/scripts/join-steps.js @@ -26,6 +26,7 @@ const continueButton = form.querySelector('[data-join-continue]'); const backButton = form.querySelector('[data-join-back]'); const email = form.querySelector('[name="email"]'); + const givenName = form.querySelector('[name="given_name"]'); const consent = form.querySelector('[name="consent"]'); const items = progress.querySelectorAll('li'); const basicHeading = document.querySelector('[data-join-heading-basic]'); @@ -38,6 +39,7 @@ continueButton, backButton, email, + givenName, consent, basicHeading, interestsHeading, @@ -66,26 +68,17 @@ function continueToInterests() { if (!email.reportValidity()) return; + if (!givenName.value.trim()) givenName.setCustomValidity('Enter your first name'); + else givenName.setCustomValidity(''); + if (!givenName.reportValidity()) return; if (!consent.reportValidity()) return; show(2); } second.hidden = true; + givenName.addEventListener('input', () => givenName.setCustomValidity('')); continueButton.addEventListener('click', continueToInterests); backButton.addEventListener('click', () => show(1)); - form.querySelector('#transport_options')?.addEventListener('change', (event) => { - const changed = event.target; - if (!changed?.matches?.('input[name="transport_options"]') || !changed.checked) return; - const options = form.querySelectorAll('input[name="transport_options"]'); - if (changed.value === 'none') { - options.forEach((option) => { - if (option.value !== 'none') option.checked = false; - }); - } else { - const none = form.querySelector('input[name="transport_options"][value="none"]'); - if (none) none.checked = false; - } - }); form.addEventListener( 'submit', (event) => { diff --git a/apps/site/src/components/NewsletterEmbed.astro b/apps/site/src/components/NewsletterEmbed.astro index 003f9b14..65cc094f 100644 --- a/apps/site/src/components/NewsletterEmbed.astro +++ b/apps/site/src/components/NewsletterEmbed.astro @@ -60,7 +60,7 @@ const { variant = 'light', compact = false, stack = false } = Astro.props; aria-label="Email address" placeholder="you@example.com" aria-describedby="newsletter-status" - class="flex-1 min-w-0 px-4 py-3 border-2 border-current bg-transparent placeholder:opacity-80 focus:outline-hidden" + class="flex-1 min-w-0 px-4 py-3 border-2 border-on-surface bg-surface-container text-on-surface placeholder:opacity-80 focus:outline-hidden" />