Files
no-whatever/src/app/api/room/[id]/manage/route.ts
T
kurihada 9641acbcbd refactor: 提取 buildNavUrl 工具函数,统一 room API 错误处理
- 将 MatchResult.tsx 和 profile/page.tsx 中重复的导航 URL 构建逻辑提取到 src/lib/navigation.ts
- 7 个 room API 路由从 return NextResponse.json({ error }, { status }) 统一改为 throw ApiError,由 apiHandler 统一捕获
2026-02-26 19:31:00 +08:00

68 lines
1.8 KiB
TypeScript

import { NextResponse } from "next/server";
import { atomicUpdateRoom } from "@/lib/store";
import { notify } from "@/lib/roomEvents";
import { apiHandler, ApiError, requireUserId } from "@/lib/api";
export const POST = apiHandler(async (req, { params }) => {
const { id } = await params;
const { userId, action, targetUserId } = await req.json();
requireUserId(userId);
if (!action) throw new ApiError("action required");
const updated = await atomicUpdateRoom(id, (data) => {
if (data.creatorId !== userId) {
throw new ApiError("只有房主可以执行此操作", 403);
}
switch (action) {
case "lock":
data.locked = true;
break;
case "unlock":
data.locked = false;
break;
case "kick":
if (!targetUserId || targetUserId === userId) {
throw new ApiError("无效的操作对象");
}
data.users = data.users.filter((u) => u !== targetUserId);
if (!data.kickedUsers.includes(targetUserId)) {
data.kickedUsers.push(targetUserId);
}
delete data.swipeCounts[targetUserId];
for (const rid of Object.keys(data.likes)) {
data.likes[rid] = data.likes[rid].filter(
(u) => u !== targetUserId,
);
}
if (
data.match &&
data.likes[data.match]?.length !== data.users.length
) {
data.match = null;
}
break;
case "end_voting":
for (const u of data.users) {
data.swipeCounts[u] = data.restaurants.length;
}
break;
default:
throw new ApiError("未知操作");
}
return data;
});
if (!updated) throw new ApiError("房间不存在或已过期", 404);
notify(id);
return NextResponse.json({ ok: true });
});