"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { SubscribeWithHandle } from "./HandleSubscribe"; import { EmailInput, EmailConfirm } from "./EmailSubscribe"; import { EmailSubscribeSuccess } from "./EmailSubscribeSuccess"; import { Modal } from "components/Modal"; import { ButtonPrimary } from "components/Buttons"; import { ManageSubscription } from "./ManageSubscribe"; import { useToaster } from "components/Toast"; import { requestPublicationEmailSubscription, confirmPublicationEmailSubscription, } from "actions/publications/subscribeEmail"; import { useViewerSubscription } from "./viewerSubscription"; export type SubscribeProps = { autoFocus?: boolean; publicationUri: string; publicationUrl?: string; publicationName: string; publicationDescription?: string; newsletterMode: boolean; }; export const SubscribePanel = (props: SubscribeProps) => { return (

{props.publicationName}

{props.publicationDescription && (
{props.publicationDescription}
)}
); }; export const SubscribeButton = (props: SubscribeProps) => { const user = useViewerSubscription(props.publicationUri); return ( ) : ( Subscribe ) } > ); }; export const SubscribeInput = (props: SubscribeProps) => { let toaster = useToaster(); let router = useRouter(); const user = useViewerSubscription(props.publicationUri); let [email, setEmail] = useState(user.email ?? ""); let [confirmState, setConfirmState] = useState<"confirm" | "success">( "confirm", ); let [confirmOpen, setConfirmOpen] = useState(false); let [requesting, setRequesting] = useState(false); let [confirming, setConfirming] = useState(false); let [locallySubscribed, setLocallySubscribed] = useState(false); const isSubscribed = user.subscribed || locallySubscribed; return ( <> {isSubscribed ? ( ) : props.newsletterMode ? ( { if (requesting) return; setRequesting(true); let res = await requestPublicationEmailSubscription( props.publicationUri, email, ); setRequesting(false); if (!res.ok) { toaster({ type: "error", content: ERROR_MESSAGES[res.error], }); return; } if (res.value.confirmed) { setConfirmState("success"); router.refresh(); } setConfirmOpen(true); }} > Subscribe } /> ) : ( setLocallySubscribed(true)} /> )} {props.newsletterMode && ( { setConfirmOpen(open); if (!open) { if (confirmState === "success") setLocallySubscribed(true); setConfirmState("confirm"); } }} > {confirmState === "success" ? ( ) : ( setConfirmOpen(false)} emailValue={email} onSubmit={async (code) => { if (confirming) return; setConfirming(true); let res = await confirmPublicationEmailSubscription( props.publicationUri, email, code, ); setConfirming(false); if (!res.ok) { toaster({ type: "error", content: ERROR_MESSAGES[res.error], }); return; } setConfirmState("success"); router.refresh(); }} /> )} )} ); }; type SubscribeError = | "invalid_email" | "newsletter_disabled" | "email_send_failed" | "subscriber_not_found" | "invalid_code" | "database_error" | "suppressed_spam_complaint" | "suppression_delete_failed"; const ERROR_MESSAGES: Record = { invalid_email: "Please enter a valid email address.", newsletter_disabled: "This publication isn't accepting email subscriptions.", email_send_failed: "We couldn't send the confirmation email. Try again.", subscriber_not_found: "No pending subscription. Start over.", invalid_code: "That code didn't match. Try again.", database_error: "Something went wrong. Try again.", suppressed_spam_complaint: "This address was previously marked as spam and can't be resubscribed. Contact the publication to resolve.", suppression_delete_failed: "We couldn't clear a prior delivery issue on this address. Try again later.", };