From 8ea3f622edd6cdabf7ec817f6f3350562cc821a2 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 30 Aug 2026 22:16:46 -0500 Subject: [PATCH] Polish discovery loop: ToolsStrip, map CTAs, meetup city filter, gig login gate. Co-authored-by: Cursor --- frontend/src/app/book/thanks/page.tsx | 16 +++++++- frontend/src/app/changelog/page.tsx | 9 ++++ frontend/src/app/meetups/page.tsx | 5 ++- .../src/components/CommunityNewClient.tsx | 19 +++++++++ frontend/src/components/FeedbackWidget.tsx | 5 ++- frontend/src/components/Footer.tsx | 1 + frontend/src/components/GigPostClient.tsx | 4 ++ frontend/src/components/GigsClient.tsx | 9 ++++ frontend/src/components/HomeClient.tsx | 5 +++ frontend/src/components/MeetupsClient.tsx | 41 +++++++++++++++---- frontend/src/components/NextStopClient.tsx | 27 +++++++++--- .../components/NotificationSettingsClient.tsx | 1 + frontend/src/components/VideoDetailClient.tsx | 4 ++ frontend/src/components/WorldMap.tsx | 25 +++++++++++ frontend/src/lib/i18n/dictionaries.ts | 4 ++ 15 files changed, 160 insertions(+), 15 deletions(-) diff --git a/frontend/src/app/book/thanks/page.tsx b/frontend/src/app/book/thanks/page.tsx index a7c83e7..a848f4c 100644 --- a/frontend/src/app/book/thanks/page.tsx +++ b/frontend/src/app/book/thanks/page.tsx @@ -76,7 +76,21 @@ function BookThanksInner() { )} - {status === "ok" && ( + {status === "ok" && files.length === 0 && ( +
+

购买已确认,下载文件暂未配置。

+

可先在线阅读,或联系支持获取 PDF/EPUB。

+
+ + 继续在线阅读 + + + 联系支持 + +
+
+ )} + {status === "ok" && files.length > 0 && (

购买成功,可下载:

    diff --git a/frontend/src/app/changelog/page.tsx b/frontend/src/app/changelog/page.tsx index 5f3c1c4..cf9f6de 100644 --- a/frontend/src/app/changelog/page.tsx +++ b/frontend/src/app/changelog/page.tsx @@ -8,6 +8,15 @@ export const metadata: Metadata = { }; const LOGS = [ + { + date: "2026-08-30", + tag: "决策与发现闭环", + items: [ + "首页挂载快捷工具条;地图选城可对比/加计划;下一站活动按推荐城市筛选", + "赏金未登录直接引导登录;活动页支持 ?city= 筛选;视频详情 RingNext", + "电子书感谢页无下载链时引导在线阅读;社区发帖/发赏金/通知设置登录门", + ], + }, { date: "2026-08-30", tag: "三环登录与导航", diff --git a/frontend/src/app/meetups/page.tsx b/frontend/src/app/meetups/page.tsx index f171ac7..77394ba 100644 --- a/frontend/src/app/meetups/page.tsx +++ b/frontend/src/app/meetups/page.tsx @@ -1,3 +1,4 @@ +import { Suspense } from "react"; import type { Metadata } from "next"; import { api } from "@/lib/api"; import SiteShell from "@/components/SiteShell"; @@ -15,7 +16,9 @@ export default async function MeetupsPage() { return ( - +

    加载活动…

}> + + ); } diff --git a/frontend/src/components/CommunityNewClient.tsx b/frontend/src/components/CommunityNewClient.tsx index bc5b88a..8f5ce6d 100644 --- a/frontend/src/components/CommunityNewClient.tsx +++ b/frontend/src/components/CommunityNewClient.tsx @@ -7,17 +7,35 @@ import { api } from "@/lib/api"; import { useAuth } from "@/lib/auth"; import { useToast } from "@/lib/toast"; import { useI18n } from "@/lib/i18n"; +import RingNext from "@/components/RingNext"; +import { useRingSteps } from "@/lib/rings"; export default function CommunityNewClient() { const { token } = useAuth(); const router = useRouter(); const { toast } = useToast(); const { t } = useI18n(); + const rings = useRingSteps(); const [title, setTitle] = useState(""); const [content, setContent] = useState(""); const [category, setCategory] = useState("社区"); const [busy, setBusy] = useState(false); + if (!token) { + return ( +
+
+ +
+

{t.community.newTitle}

+

{t.community.loginDesc}

+ {t.nav.login} +
+
+
+ ); + } + const submit = async () => { if (!token) { router.push("/login?next=/community/new"); @@ -70,6 +88,7 @@ export default function CommunityNewClient() { {busy ? "发布中…" : t.community.newSubmit} + ); diff --git a/frontend/src/components/FeedbackWidget.tsx b/frontend/src/components/FeedbackWidget.tsx index ce45f25..5422cb2 100644 --- a/frontend/src/components/FeedbackWidget.tsx +++ b/frontend/src/components/FeedbackWidget.tsx @@ -22,7 +22,10 @@ export default function FeedbackWidget() { const submit = async (e: React.FormEvent) => { e.preventDefault(); - if (!msg.trim()) return; + if (!msg.trim() || msg.trim().length < 5) { + toast("请至少写 5 个字", "info"); + return; + } setSending(true); try { await api.submitFeedback(msg.trim(), token || undefined, type); diff --git a/frontend/src/components/Footer.tsx b/frontend/src/components/Footer.tsx index 30b3711..867bd63 100644 --- a/frontend/src/components/Footer.tsx +++ b/frontend/src/components/Footer.tsx @@ -48,6 +48,7 @@ export default function Footer() { {t.footer.destinations} {t.footer.nextStop} {!isHome && {t.footer.plan}} + {!isHome && {t.footer.compare}} {t.footer.visa}
diff --git a/frontend/src/components/GigPostClient.tsx b/frontend/src/components/GigPostClient.tsx index 3aa91e0..e85eac4 100644 --- a/frontend/src/components/GigPostClient.tsx +++ b/frontend/src/components/GigPostClient.tsx @@ -7,12 +7,15 @@ import { api } from "@/lib/api"; import { useAuth } from "@/lib/auth"; import { useToast } from "@/lib/toast"; import { useI18n } from "@/lib/i18n"; +import RingNext from "@/components/RingNext"; +import { useRingSteps } from "@/lib/rings"; export default function GigPostClient() { const { token } = useAuth(); const router = useRouter(); const { toast } = useToast(); const { t } = useI18n(); + const rings = useRingSteps(); const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); const [budget, setBudget] = useState(""); @@ -77,6 +80,7 @@ export default function GigPostClient() { {busy ? "发布中…" : t.gigs.postSubmit}
+ ); diff --git a/frontend/src/components/GigsClient.tsx b/frontend/src/components/GigsClient.tsx index 54a4aac..79e6fd5 100644 --- a/frontend/src/components/GigsClient.tsx +++ b/frontend/src/components/GigsClient.tsx @@ -64,6 +64,11 @@ export default function GigsClient({ gigs }: { gigs: GigItem[] }) { ) : (
+ {!token && ( +

+ {t.nav.login} · {t.gigs.loginFirst} +

+ )} {gigs.map((g) => (

{g.title}

@@ -71,6 +76,10 @@ export default function GigsClient({ gigs }: { gigs: GigItem[] }) {

{g.poster} · {g.budget} · {g.deadline}

{applied[g.id] ? (

✓ 已申请

+ ) : !token ? ( + + {t.gigs.apply} + ) : ( <>