feat: 用户名密码登录注册系统
- 新增 /api/auth/register 和 /api/auth/login 接口,使用 bcryptjs 哈希密码 - User 模型改为 username + passwordHash,id 自动生成 cuid - 新增 AuthModal 组件(登录/注册双标签页),替换旧的 ProfileSetupModal - 重写 /profile 页面:支持修改用户名、密码、头像、绑定邮箱、退出登录 - /api/user PUT 支持密码修改(需验证当前密码)和用户名唯一性校验 - 游客模式保留,右上角显示"登录"按钮;登录后显示头像和用户名 - 全局 nickname -> username 重命名(types、SwipeDeck、RoomManageModal、buildRoomStatus) - 新增 logout() 清除登录态并重新生成游客 UUID
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
} from "lucide-react";
|
||||
import { Restaurant, MatchType, RunnerUp } from "@/types";
|
||||
import { fireCelebration, playChime } from "@/lib/celebrate";
|
||||
import { isRegistered } from "@/lib/userId";
|
||||
|
||||
interface MatchResultProps {
|
||||
restaurant: Restaurant;
|
||||
@@ -30,6 +31,8 @@ interface MatchResultProps {
|
||||
runnerUps: RunnerUp[];
|
||||
allRestaurants: Restaurant[];
|
||||
userCount: number;
|
||||
roomId: string;
|
||||
userId: string;
|
||||
onReset: () => Promise<void>;
|
||||
onNarrow: (restaurantIds: string[]) => Promise<void>;
|
||||
resetting: boolean;
|
||||
@@ -168,6 +171,8 @@ export default function MatchResult({
|
||||
runnerUps,
|
||||
allRestaurants,
|
||||
userCount,
|
||||
roomId,
|
||||
userId,
|
||||
onReset,
|
||||
onNarrow,
|
||||
resetting,
|
||||
@@ -176,6 +181,7 @@ export default function MatchResult({
|
||||
const [showRunnerUps, setShowRunnerUps] = useState(false);
|
||||
const [toast, setToast] = useState("");
|
||||
const celebratedRef = useRef(false);
|
||||
const historySavedRef = useRef(false);
|
||||
const isUnanimous = matchType === "unanimous";
|
||||
|
||||
const showToast = useCallback((msg: string) => {
|
||||
@@ -194,6 +200,25 @@ export default function MatchResult({
|
||||
}
|
||||
}, [isUnanimous]);
|
||||
|
||||
useEffect(() => {
|
||||
if (historySavedRef.current) return;
|
||||
if (!isRegistered()) return;
|
||||
if (matchType === "no_match") return;
|
||||
|
||||
historySavedRef.current = true;
|
||||
fetch("/api/user/history", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
userId,
|
||||
roomId,
|
||||
restaurant,
|
||||
matchType,
|
||||
participants: userCount,
|
||||
}),
|
||||
}).catch(() => {});
|
||||
}, [userId, roomId, restaurant, matchType, userCount]);
|
||||
|
||||
const handleShare = useCallback(async () => {
|
||||
const lines = [
|
||||
isUnanimous
|
||||
|
||||
Reference in New Issue
Block a user