Files
react-editor-shopify/components/landing/newsletter-cta.tsx
Rami Bitar 383a593c42 Add Container component and fix radius/maxWidth theming
- Drop buttonRadius prop; button now uses --radius via rounded-md
- Inject @theme radius mappings into ThemeProvider so rounded-* utilities
  pick up --radius inside the Tailwind CDN iframe
- Add shared Container that consumes --container-max-width set from the
  global maxWidth prop, replacing ad-hoc "container mx-auto max-w-7xl px-6"
  wrappers across commerce, landing, footer, navigation, and others
- Simplify maxWidth options to Small/Medium/Large/X-Large/Full bleed and
  shift the scale up so Large (1280px) matches the previous default

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 12:25:13 -04:00

201 lines
5.8 KiB
TypeScript

import { useState } from "react";
import { cn } from "@/lib/utils";
import { Typography } from "@/components/Typography";
import { Container } from "@/components/layout/Container";
export type EmailProvider = "none" | "mailchimp" | "klaviyo";
export type NewsletterCtaProps = {
tagline: string;
heading: string;
subheading: string;
buttonLabel: string;
emailProvider: EmailProvider;
endpoint?: string;
mailchimpApiKey?: string;
mailchimpServerPrefix?: string;
mailchimpAudienceId?: string;
klaviyoCompanyId?: string;
klaviyoListId?: string;
imageUrl: string;
layout: "split" | "stacked";
};
export function NewsletterCta({
tagline,
heading,
subheading,
buttonLabel,
emailProvider,
endpoint,
mailchimpApiKey,
mailchimpServerPrefix,
mailchimpAudienceId,
klaviyoCompanyId,
klaviyoListId,
imageUrl,
layout,
}: NewsletterCtaProps) {
const [email, setEmail] = useState("");
const [submitted, setSubmitted] = useState(false);
const [submitting, setSubmitting] = useState(false);
const submit = async (e: React.FormEvent) => {
e.preventDefault();
if (!email) return;
setSubmitting(true);
try {
if (emailProvider === "mailchimp") {
if (mailchimpServerPrefix && mailchimpAudienceId && mailchimpApiKey) {
await fetch(
`https://${mailchimpServerPrefix}.api.mailchimp.com/3.0/lists/${mailchimpAudienceId}/members`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${mailchimpApiKey}`,
},
body: JSON.stringify({
email_address: email,
status: "subscribed",
}),
},
);
}
} else if (emailProvider === "klaviyo") {
if (klaviyoCompanyId && klaviyoListId) {
await fetch(
`https://a.klaviyo.com/client/subscriptions/?company_id=${klaviyoCompanyId}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
revision: "2024-10-15",
},
body: JSON.stringify({
data: {
type: "subscription",
attributes: {
profile: {
data: {
type: "profile",
attributes: { email },
},
},
},
relationships: {
list: { data: { type: "list", id: klaviyoListId } },
},
},
}),
},
);
}
} else if (endpoint) {
await fetch(endpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email }),
});
}
setSubmitted(true);
} catch {
setSubmitted(true);
} finally {
setSubmitting(false);
}
};
const Form = (
<form
onSubmit={submit}
className="flex w-full max-w-md items-center border-b border-foreground/30 focus-within:border-foreground"
>
<input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
className="flex-1 bg-transparent py-3 text-sm placeholder:text-muted-foreground focus:outline-none"
/>
<button
type="submit"
disabled={submitting}
className="ml-3 text-sm font-medium tracking-wide hover:opacity-70 disabled:opacity-40"
>
{submitting ? "…" : buttonLabel}
</button>
</form>
);
if (layout === "split") {
return (
<section className="bg-background">
<Container className="py-16 md:py-24">
<div className="grid grid-cols-1 items-center gap-12 md:grid-cols-2">
<div>
{imageUrl ? (
<img
src={imageUrl}
alt=""
className="aspect-[5/4] w-full rounded-md object-cover"
/>
) : null}
</div>
<div className="flex flex-col items-start">
{tagline ? (
<p className="mb-3 text-xs uppercase tracking-[0.2em] text-muted-foreground">
{tagline}
</p>
) : null}
<Typography variant="h2">{heading}</Typography>
{subheading ? (
<Typography variant="subtitle1" className="mt-3 max-w-md">
{subheading}
</Typography>
) : null}
<div className="mt-8 w-full">
{submitted ? (
<p className="text-sm text-muted-foreground">
Thanks we'll be in touch.
</p>
) : (
Form
)}
</div>
</div>
</div>
</Container>
</section>
);
}
return (
<section className="bg-muted/40 py-20 md:py-28">
<div className="container mx-auto max-w-2xl px-6 text-center">
{tagline ? (
<p className="mb-3 text-xs uppercase tracking-[0.2em] text-muted-foreground">
{tagline}
</p>
) : null}
<Typography variant="h2">{heading}</Typography>
{subheading ? (
<Typography variant="subtitle1" className="mt-3">
{subheading}
</Typography>
) : null}
<div className={cn("mx-auto mt-10 flex w-full max-w-md justify-center")}>
{submitted ? (
<p className="text-sm text-muted-foreground">
Thanks — we'll be in touch.
</p>
) : (
Form
)}
</div>
</div>
</section>
);
}