sendou.ink/app/features/api-public/routes/sendouq.match.$matchId.ts
2025-12-29 19:21:11 +02:00

89 lines
2.2 KiB
TypeScript

import type { LoaderFunctionArgs } from "react-router";
import { cors } from "remix-utils/cors";
import { z } from "zod/v4";
import * as SQMatchRepository from "~/features/sendouq-match/SQMatchRepository.server";
import { i18next } from "~/modules/i18n/i18next.server";
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
import { id } from "~/utils/zod";
import {
handleOptionsRequest,
requireBearerAuth,
} from "../api-public-utils.server";
import type { GetSendouqMatchResponse, MapListMap } from "../schema";
const paramsSchema = z.object({
matchId: id,
});
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
await handleOptionsRequest(request);
requireBearerAuth(request);
const { matchId } = parseParams({
params,
schema: paramsSchema,
});
const match = notFoundIfFalsy(await SQMatchRepository.findById(matchId));
const t = await i18next.getFixedT("en", ["game-misc"]);
const userIdToRank = (userId: number) => {
const memento = match.memento;
if (!memento) return null;
const userMemento = memento.users[userId];
return userMemento.skill && userMemento.skill !== "CALCULATING"
? userMemento.skill.tier
: null;
};
const score = match.mapList.reduce(
(acc, cur) => {
if (!cur.winnerGroupId) return acc;
if (cur.winnerGroupId === match.groupAlpha.id) {
return [acc[0] + 1, acc[1]];
}
return [acc[0], acc[1] + 1];
},
[0, 0],
);
const result: GetSendouqMatchResponse = {
mapList: match.mapList.map((map) => ({
map: {
mode: map.mode,
stage: {
id: map.stageId,
name: t(`game-misc:STAGE_${map.stageId}`),
},
},
winnerTeamId: map.winnerGroupId,
source: Number.isNaN(Number(map.source))
? (map.source as MapListMap["source"])
: Number(map.source),
participatedUserIds: null,
points: null,
})),
teamAlpha: {
score: score[0],
players: match.groupAlpha.members.map((member) => ({
userId: member.id,
rank: userIdToRank(member.id),
})),
},
teamBravo: {
score: score[1],
players: match.groupBravo.members.map((member) => ({
userId: member.id,
rank: userIdToRank(member.id),
})),
},
};
return await cors(request, Response.json(result));
};