From 04c99295995993c93c0cb3596a55f049369601f7 Mon Sep 17 00:00:00 2001 From: AutoGenUI <231675956+AutoGenUI@users.noreply.github.com> Date: Tue, 13 Oct 2026 18:10:58 +0800 Subject: [PATCH] Fix subscription confirmation experience for v1.0.0 --- components/locale-switch.tsx | 8 +- components/news/shared.tsx | 4 +- components/news/subscription.tsx | 107 +++++++++++++--------- docs/CURRENT_STATE.json | 64 +++++++++++-- docs/PROJECT_CONTEXT.md | 6 ++ docs/operations/deployment-maintenance.md | 2 + docs/operations/email-subscriptions.md | 12 ++- docs/releases/v1.0.0.md | 44 +++++++++ lib/news/mail.ts | 23 +++-- lib/news/subscription-ui.ts | 16 +++- package-lock.json | 4 +- package.json | 2 +- tests/news.test.mjs | 59 ++++++++++++ tests/subscription-ui.test.mjs | 31 ++++++- 14 files changed, 307 insertions(+), 75 deletions(-) create mode 100644 docs/releases/v1.0.0.md diff --git a/components/locale-switch.tsx b/components/locale-switch.tsx index 1db8fdb..504bfd9 100644 --- a/components/locale-switch.tsx +++ b/components/locale-switch.tsx @@ -1,11 +1,13 @@ "use client"; import Link from "next/link"; -import { usePathname } from "next/navigation"; +import { usePathname, useSearchParams } from "next/navigation"; import type { Locale } from "@/lib/types"; +import { subscriptionLocaleHref } from "@/lib/news/subscription-ui"; export function LocaleSwitch({ locale, alternate }: { locale: Locale; alternate: Locale }) { const pathname = usePathname(); - const href = pathname?.startsWith(`/${locale}`) ? pathname.replace(`/${locale}`, `/${alternate}`) : `/${alternate}`; - return {alternate === "zh" ? "中文" : "EN"}; + const query = useSearchParams(); + const href = subscriptionLocaleHref(pathname, locale, alternate, query.toString()); + return {alternate === "zh" ? "中文" : "EN"}; } diff --git a/components/news/shared.tsx b/components/news/shared.tsx index 9b07723..c4d8c47 100644 --- a/components/news/shared.tsx +++ b/components/news/shared.tsx @@ -94,8 +94,8 @@ export function SubscribeBand({ locale }: { locale: Locale }) {
{locale === "zh" - ? "用一份精选,串起生成式 UI 的一周。RSS 已开放,邮件周报待启用。" - : "A considered view of the week in Generative UI. RSS is live; email delivery is coming."} + ? "用一份精选,串起生成式 UI 的一周。通过 RSS 阅读,或确认邮箱后接收周报。" + : "A considered view of the week in Generative UI. Read with RSS, or confirm your email for the digest."}
diff --git a/components/news/subscription.tsx b/components/news/subscription.tsx index 1d1ba65..a7c7f6c 100644 --- a/components/news/subscription.tsx +++ b/components/news/subscription.tsx @@ -1,5 +1,5 @@ "use client"; -import { useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { useSearchParams } from "next/navigation"; import { categories, categoryNames, type Category, type Locale } from "@/lib/news/types"; import { @@ -40,7 +40,6 @@ function SubscriptionView({ locale, initialLink, onManagementUrl }: { [capacity, setCapacity] = useState{zh ? "选择语言与主题,精选事件、研究与值得关注的方向。只发送有实质更新的周报。" : "Choose a language and topics for a considered selection of events, research and emerging directions. No empty editions."}
-{zh ? `名额以邮箱确认成功为准,待确认不占名额。免费发信上限 ${capacity.dailyLimit} 封/天,周报发送预算 ${capacity.weeklyLimit} 封/天;当日额度也用于确认邮件,不能保证同日送达。` : `Places are allocated only after email confirmation; pending requests do not occupy places. The free allowance is ${capacity.dailyLimit} emails/day, with a ${capacity.weeklyLimit}/day digest budget. Confirmations share the daily allowance; delivery on the same day is not guaranteed.`}
- > :{capacityState === "loading" ? zh ? "正在读取已确认人数与剩余名额…" : "Loading confirmed subscribers and remaining places…" : zh ? "订阅人数暂时未知,请重试读取。" : "Subscriber counts are temporarily unknown. Please retry."}
} - {capacityState === "error" &&{zh ? "名额信息未能更新;已有数字是上次读取结果。已生效订阅仍可退订或管理。" : "Availability could not be updated; any figures shown are the last loaded values. Active subscriptions can still be managed or unsubscribed."}
} - -{body}
+ {confirmationMode && !terminal && } {(display.kind === "read-error" || display.kind === "error" && manage && !confirmationMode) && } {display.kind === "unconfirmed" || display.kind === "read-error" || display.kind === "error" && manage ? {zh ? "重新申请确认邮件" : "Request a fresh confirmation"} : null} {display.kind === "check-inbox" && } @@ -233,10 +242,22 @@ function SubscriptionView({ locale, initialLink, onManagementUrl }: {{zh ? `仅确认成功占名额。免费限额 ${capacity.dailyLimit} 封/天,周报预算 ${capacity.weeklyLimit} 封/天;确认邮件共用额度,投递可能延迟。` : `Only confirmed subscriptions occupy places. Daily allowance: ${capacity.dailyLimit} emails, including confirmations; digest budget: ${capacity.weeklyLimit}/day. Delivery may be delayed.`}
+ > :{capacityState === "loading" ? zh ? "正在读取已确认人数与剩余名额…" : "Loading confirmed subscribers and remaining places…" : zh ? "订阅人数暂时未知,请重试读取。" : "Subscriber counts are temporarily unknown. Please retry."}
} + {capacityState === "error" &&{zh ? "名额未能更新,数字为上次结果;仍可管理已生效订阅。" : "Availability failed to refresh; figures are from the last check. Active subscriptions remain manageable."}
} + +