|
| 1 | +'use client' |
| 2 | + |
| 3 | +import { useEffect, useRef } from 'react' |
| 4 | + |
| 5 | +// Same Mailcoach list as the homepage form (src/components/home/case-studies.jsx). |
| 6 | +const MAILCOACH_SUBSCRIBE_URL = 'https://bref.mailcoach.app/subscribe/be83c960-8fee-43fa-abfa-29669e9f433a' |
| 7 | + |
| 8 | +// POST-only subscribe form for the Bref newsletter, used inline on /news and on |
| 9 | +// /news/subscribe (the page that moves the old "Serverless PHP news" list to the |
| 10 | +// Bref list with an explicit opt-in). |
| 11 | +// |
| 12 | +// - `tag`: Mailcoach subscriber tag, to measure where subscribers come from. |
| 13 | +// - `label`: visible label above the field. Without it the form is a single row |
| 14 | +// (placeholder + button). |
| 15 | +// - `onDark`: styles for a dark background (the homepage section), instead of |
| 16 | +// following the site theme. |
| 17 | +// - The migration email links to /news/subscribe?email=... : the address is |
| 18 | +// prefilled but nothing is submitted until the reader clicks the button, so |
| 19 | +// email prefetchers (which only GET the link) cannot subscribe anyone. |
| 20 | +// - Mailcoach sends its double opt-in email and redirects to the bref.sh |
| 21 | +// result pages below. |
| 22 | +const INPUT_CLASS = { |
| 23 | + light: 'text-gray-900 ring-gray-300 placeholder:text-gray-400 focus:ring-blue-500 dark:bg-white/5 dark:text-white dark:ring-white/10 dark:placeholder:text-white/50', |
| 24 | + dark: 'bg-white/10 text-white ring-white/10 placeholder:text-white/75 focus:ring-white', |
| 25 | +} |
| 26 | +const BUTTON_CLASS = { |
| 27 | + light: 'bg-blue-500 hover:bg-blue-400', |
| 28 | + dark: '!bg-gray-500 hover:!bg-gray-400', |
| 29 | +} |
| 30 | + |
| 31 | +export default function SubscribeForm({ tag, label, onDark = false, className = 'my-8' }) { |
| 32 | + const variant = onDark ? 'dark' : 'light' |
| 33 | + const emailRef = useRef(null) |
| 34 | + const honeypotRef = useRef(null) |
| 35 | + |
| 36 | + useEffect(() => { |
| 37 | + const email = new URLSearchParams(window.location.search).get('email') |
| 38 | + if (email && emailRef.current && !emailRef.current.value) { |
| 39 | + // A `+` in the address decodes to a space if the link was not URL-encoded |
| 40 | + emailRef.current.value = email.replace(/ /g, '+') |
| 41 | + } |
| 42 | + }, []) |
| 43 | + |
| 44 | + const onSubmit = (event) => { |
| 45 | + // Honeypot: humans never see this field, bots fill it in |
| 46 | + if (honeypotRef.current?.value) { |
| 47 | + event.preventDefault() |
| 48 | + return |
| 49 | + } |
| 50 | + // Mailcoach stores unknown form fields as subscriber attributes: leave the honeypot out |
| 51 | + if (honeypotRef.current) honeypotRef.current.disabled = true |
| 52 | + } |
| 53 | + |
| 54 | + return ( |
| 55 | + <form method="POST" action={MAILCOACH_SUBSCRIBE_URL} onSubmit={onSubmit} className={`not-prose ${className}`}> |
| 56 | + <input type="hidden" name="tags" value={tag} /> |
| 57 | + <input type="hidden" name="redirect_after_subscription_pending" value="https://bref.sh/news/subscribe/pending" /> |
| 58 | + <input type="hidden" name="redirect_after_already_subscribed" value="https://bref.sh/news/subscribe/already" /> |
| 59 | + <input type="hidden" name="redirect_after_subscribed" value="https://bref.sh/news/subscribe/done" /> |
| 60 | + |
| 61 | + <div className="hidden" aria-hidden="true"> |
| 62 | + <label htmlFor="subscribe-website">Website</label> |
| 63 | + <input ref={honeypotRef} id="subscribe-website" type="text" name="website" tabIndex={-1} autoComplete="off" /> |
| 64 | + </div> |
| 65 | + |
| 66 | + {label && ( |
| 67 | + <label htmlFor="subscribe-email" className="block mb-2 text-sm font-semibold text-gray-900 dark:text-gray-100"> |
| 68 | + {label} |
| 69 | + </label> |
| 70 | + )} |
| 71 | + <div className="flex flex-col sm:flex-row gap-2"> |
| 72 | + <input |
| 73 | + ref={emailRef} |
| 74 | + id="subscribe-email" |
| 75 | + type="email" |
| 76 | + name="email" |
| 77 | + required |
| 78 | + autoComplete="email" |
| 79 | + aria-label={label ? undefined : 'Email'} |
| 80 | + placeholder="you@example.com" |
| 81 | + className={`min-w-0 flex-auto rounded-md border-0 px-3.5 py-2 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6 ${INPUT_CLASS[variant]}`} |
| 82 | + /> |
| 83 | + <button |
| 84 | + type="submit" |
| 85 | + className={`flex-none rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 ${BUTTON_CLASS[variant]}`} |
| 86 | + > |
| 87 | + Subscribe to the Bref newsletter |
| 88 | + </button> |
| 89 | + </div> |
| 90 | + </form> |
| 91 | + ) |
| 92 | +} |
0 commit comments