Files
zeekay ea03b3eefc newsletter: double opt-in in every footer, on cloud's subscribe
POST /v1/marketing/subscribe answers pending whatever the address and
mails a link to /newsletter/confirm#t=<token>; that page spends the
token only on a press, so a mail scanner subscribes nobody, and drops
the fragment from the address. Every page's footer, /newsletter and
/subscribe draw the one form; the footer's chunk loads at low priority.

The old form filed /v1/marketing/leads, mailing sales for every
subscriber, and said subscribed when the request failed; it is gone,
with the unused NewsletterSignup stub whose track was a no-op.
2026-10-29 23:13:08 -07:00

40 lines
1.5 KiB
TypeScript

'use client'
import { useI18n } from '@hanzo/i18n/react'
import { Text, XStack, YStack } from '@hanzo/ui'
import { Check } from 'lucide-react'
import { phrase } from '@hanzo/i18n'
import { Focus } from '@/components/shell/focus'
import { Subscribe } from '@/components/newsletter/Subscribe'
/** What an issue carries. */
const CARRIES = [
phrase('New models and what they measured, the day they ship'),
phrase('What changed in the API, the CLI and Hanzo Dev'),
phrase('Engineering notes from the people who built it'),
] as const
/**
* /newsletter (and /subscribe, which draws this page): the newsletter's form.
* Double opt-in over cloud's marketing capability (lib/newsletter): the address
* is mailed a link, and only the press on /newsletter/confirm subscribes it.
*/
export default function Newsletter() {
const { t } = useI18n()
return (
<Focus id="newsletter-title" title={t('The Hanzo newsletter')} line={t('Releases, benchmarks and engineering notes, once or twice a month.')} width={480}>
<YStack render="ul" gap="$2.5" m={0} p={0} $platform-web={{ listStyle: 'none' }}>
{CARRIES.map((c) => (
<XStack key={c} render="li" gap="$2.5" items="flex-start">
<Check size={16} color="var(--foreground)" aria-hidden />
<Text fontSize="$3" lineHeight="1.25rem" color="var(--foreground)">
{t(c)}
</Text>
</XStack>
))}
</YStack>
<Subscribe source="hanzo.ai/newsletter" />
</Focus>
)
}