fix: 0 票最佳匹配时展示"都不太满意"引导页,替代尴尬的 Trophy 展示

This commit is contained in:
2026-02-24 19:26:54 +08:00
parent b406acc813
commit 30329df136
3 changed files with 88 additions and 4 deletions
+9 -3
View File
@@ -32,9 +32,15 @@ export async function GET(
matchLikes = data.users.length;
} else if (allFinished && data.restaurants.length > 0) {
const best = findBestMatch(data.likes, data.restaurants);
match = best.id;
matchType = "best";
matchLikes = best.likes;
if (best.likes > 0) {
match = best.id;
matchType = "best";
matchLikes = best.likes;
} else {
match = best.id;
matchType = "no_match";
matchLikes = 0;
}
}
const likeCounts: Record<string, number> = {};
+78
View File
@@ -1,6 +1,7 @@
"use client";
import { motion } from "framer-motion";
import { useRouter } from "next/navigation";
import {
MapPin,
Star,
@@ -10,6 +11,8 @@ import {
Clock,
Trophy,
RotateCcw,
SearchX,
Home,
} from "lucide-react";
import { Restaurant, MatchType } from "@/types";
@@ -30,6 +33,77 @@ function buildNavUrl(restaurant: Restaurant): string {
return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(restaurant.name)}`;
}
function NoMatchResult({
onReset,
resetting,
}: {
onReset: () => Promise<void>;
resetting: boolean;
}) {
const router = useRouter();
return (
<motion.div
className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-linear-to-b from-zinc-600 to-zinc-800 px-6 py-10"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.4 }}
>
<motion.div
initial={{ scale: 0, rotate: -20 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ type: "spring", stiffness: 200, damping: 12, delay: 0.2 }}
>
<SearchX size={56} className="text-zinc-400" />
</motion.div>
<motion.h1
className="mt-4 text-3xl font-black text-white"
initial={{ y: 30, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 0.35 }}
>
</motion.h1>
<motion.p
className="mt-2 max-w-[16rem] text-center text-sm leading-relaxed text-zinc-400"
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 0.45 }}
>
</motion.p>
<motion.div
className="mt-8 flex w-full max-w-xs flex-col gap-3"
initial={{ y: 30, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 0.55 }}
>
<motion.button
onClick={onReset}
disabled={resetting}
className="flex items-center justify-center gap-2 rounded-full bg-white px-8 py-3 text-sm font-bold text-zinc-800 shadow-lg transition-colors hover:bg-zinc-100 disabled:opacity-50"
whileTap={{ scale: 0.95 }}
>
<RotateCcw size={15} className={resetting ? "animate-spin" : ""} />
{resetting ? "重置中..." : "再来一轮"}
</motion.button>
<motion.button
onClick={() => router.push("/")}
className="flex items-center justify-center gap-2 rounded-full bg-white/15 px-8 py-3 text-sm font-bold text-white backdrop-blur-sm transition-colors hover:bg-white/25"
whileTap={{ scale: 0.95 }}
>
<Home size={15} />
</motion.button>
</motion.div>
</motion.div>
);
}
export default function MatchResult({
restaurant,
matchType,
@@ -38,6 +112,10 @@ export default function MatchResult({
onReset,
resetting,
}: MatchResultProps) {
if (matchType === "no_match") {
return <NoMatchResult onReset={onReset} resetting={resetting} />;
}
const isUnanimous = matchType === "unanimous";
return (
+1 -1
View File
@@ -15,7 +15,7 @@ export interface Restaurant {
export type SwipeDirection = "left" | "right";
export type MatchType = "unanimous" | "best" | null;
export type MatchType = "unanimous" | "best" | "no_match" | null;
export interface RoomStatus {
roomId: string;