From 0ce48023ae1b57585071ce9d5bc1cdc4fd620892 Mon Sep 17 00:00:00 2001 From: eric Date: Sun, 30 Aug 2026 20:45:58 -0500 Subject: [PATCH] Polish explore hubs: feedback API, live gates, AI tips, empty states. Co-authored-by: Cursor --- frontend/src/app/globals.css | 26 ++++++ frontend/src/components/AiAssistantClient.tsx | 66 ++++++++++++-- frontend/src/components/CompareClient.tsx | 36 ++++---- frontend/src/components/FeedbackClient.tsx | 55 +++++++++--- frontend/src/components/FeedbackWidget.tsx | 43 +++++++--- frontend/src/components/MeetupLiveClient.tsx | 85 +++++++++++++++++-- frontend/src/components/MeetupsClient.tsx | 19 ++++- .../src/components/MemberProfileClient.tsx | 41 +++++++-- frontend/src/components/MovePlanClient.tsx | 12 ++- frontend/src/components/VideoDetailClient.tsx | 29 ++++++- frontend/src/components/VideosClient.tsx | 48 ++++++++--- frontend/src/lib/staticPages.ts | 22 ++++- 12 files changed, 398 insertions(+), 84 deletions(-) diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 8105752..bf0403b 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -10384,6 +10384,15 @@ img { max-width: 100%; display: block; } margin-bottom: 12px; } +.member-photo-img { + width: 96px; + height: 96px; + border-radius: 50%; + object-fit: cover; + display: block; + margin: 0 auto; +} + .dating-meta { color: var(--text-secondary); font-size: 0.9rem; @@ -10564,6 +10573,23 @@ img { max-width: 100%; display: block; } border-radius: var(--radius-lg); } +.ai-suggestions { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 16px; +} + +.feedback-more-link { + margin-top: 12px; + text-align: center; + font-size: 0.85rem; +} + +.feedback-more-link a { + color: var(--text-muted); +} + .ai-cities { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; } .notif-toolbar { display: flex; gap: 8px; flex-wrap: wrap; } diff --git a/frontend/src/components/AiAssistantClient.tsx b/frontend/src/components/AiAssistantClient.tsx index f4062c3..6a74e77 100644 --- a/frontend/src/components/AiAssistantClient.tsx +++ b/frontend/src/components/AiAssistantClient.tsx @@ -4,23 +4,40 @@ import { useState } from "react"; import Link from "next/link"; import { api } from "@/lib/api"; import { useI18n } from "@/lib/i18n"; +import { useToast } from "@/lib/toast"; +import RingNext from "@/components/RingNext"; +import { useRingSteps } from "@/lib/rings"; + +const SUGGESTIONS = [ + "预算 6000,想找网速好的东南亚城市", + "适合第一次远程办公的城市?", + "清迈和巴厘岛怎么选?", +]; export default function AiAssistantClient() { const { t } = useI18n(); + const { toast } = useToast(); + const rings = useRingSteps(); const [message, setMessage] = useState(""); const [reply, setReply] = useState(""); const [cities, setCities] = useState<{ slug: string; name: string; emoji: string }[]>([]); const [loading, setLoading] = useState(false); - const ask = async () => { - if (!message.trim()) return; + const ask = async (text?: string) => { + const q = (text ?? message).trim(); + if (!q) { + toast("先写一个问题", "info"); + return; + } + setMessage(q); setLoading(true); try { - const res = await api.askAssistant(message.trim()); + const res = await api.askAssistant(q); setReply(res.reply); setCities(res.cities || []); } catch { setReply(t.ai.fail); + setCities([]); } finally { setLoading(false); } @@ -29,27 +46,60 @@ export default function AiAssistantClient() { return (
- +
{t.ai.tag}

{t.ai.title}

{t.ai.subtitle}

+
+ {SUGGESTIONS.map((s) => ( + + ))} +
-