mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:30:43 +00:00
Add function to fetch player information (#2010)
## Description: This pull request introduces the fetchPlayerById() function together with its associated schema components. It represents one part of a series of split pull requests related to the PlayerInfoModal (Player Profile). Subsequent pull requests will address UI implementation and additional features. (origin pr:https://github.com/openfrontio/OpenFrontIO/pull/1758) ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: aotumuri --------- Co-authored-by: evanpelle <evanpelle@gmail.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { decodeJwt } from "jose";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
PlayerProfile,
|
||||
PlayerProfileSchema,
|
||||
RefreshResponseSchema,
|
||||
TokenPayload,
|
||||
TokenPayloadSchema,
|
||||
@@ -268,3 +270,42 @@ export async function getUserMe(): Promise<UserMeResponse | false> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchPlayerById(
|
||||
playerId: string,
|
||||
): Promise<PlayerProfile | false> {
|
||||
try {
|
||||
const base = getApiBase();
|
||||
const token = getToken();
|
||||
if (!token) return false;
|
||||
const url = `${base}/player/${encodeURIComponent(playerId)}`;
|
||||
|
||||
const res = await fetch(url, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status !== 200) {
|
||||
console.warn(
|
||||
"fetchPlayerById: unexpected status",
|
||||
res.status,
|
||||
res.statusText,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
const json = await res.json();
|
||||
const parsed = PlayerProfileSchema.safeParse(json);
|
||||
if (!parsed.success) {
|
||||
console.warn("fetchPlayerById: Zod validation failed", parsed.error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return parsed.data;
|
||||
} catch (err) {
|
||||
console.warn("fetchPlayerById: request failed", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+39
-1
@@ -1,5 +1,7 @@
|
||||
import { z } from "zod";
|
||||
import { base64urlToUuid } from "./Base64";
|
||||
import { BigIntStringSchema, PlayerStatsSchema } from "./StatsSchemas";
|
||||
import { Difficulty, GameMapType, GameMode, GameType } from "./game/Game";
|
||||
|
||||
export const RefreshResponseSchema = z.object({
|
||||
token: z.string(),
|
||||
@@ -37,8 +39,8 @@ export const DiscordUserSchema = z.object({
|
||||
username: z.string(),
|
||||
global_name: z.string().nullable(),
|
||||
discriminator: z.string(),
|
||||
locale: z.string().optional(),
|
||||
});
|
||||
export type DiscordUser = z.infer<typeof DiscordUserSchema>;
|
||||
|
||||
export const UserMeResponseSchema = z.object({
|
||||
user: z.object({
|
||||
@@ -52,3 +54,39 @@ export const UserMeResponseSchema = z.object({
|
||||
}),
|
||||
});
|
||||
export type UserMeResponse = z.infer<typeof UserMeResponseSchema>;
|
||||
|
||||
export const PlayerStatsLeafSchema = z.object({
|
||||
wins: BigIntStringSchema,
|
||||
losses: BigIntStringSchema,
|
||||
total: BigIntStringSchema,
|
||||
stats: PlayerStatsSchema,
|
||||
});
|
||||
export type PlayerStatsLeaf = z.infer<typeof PlayerStatsLeafSchema>;
|
||||
|
||||
export const PlayerStatsTreeSchema = z.partialRecord(
|
||||
z.enum(GameType),
|
||||
z.partialRecord(
|
||||
z.enum(GameMode),
|
||||
z.partialRecord(z.enum(Difficulty), PlayerStatsLeafSchema),
|
||||
),
|
||||
);
|
||||
export type PlayerStatsTree = z.infer<typeof PlayerStatsTreeSchema>;
|
||||
|
||||
export const PlayerGameSchema = z.object({
|
||||
gameId: z.string(),
|
||||
start: z.iso.datetime(),
|
||||
mode: z.enum(GameMode),
|
||||
type: z.enum(GameType),
|
||||
map: z.enum(GameMapType),
|
||||
difficulty: z.enum(Difficulty),
|
||||
clientId: z.string().optional(),
|
||||
});
|
||||
export type PlayerGame = z.infer<typeof PlayerGameSchema>;
|
||||
|
||||
export const PlayerProfileSchema = z.object({
|
||||
createdAt: z.iso.datetime(),
|
||||
user: DiscordUserSchema.optional(),
|
||||
games: PlayerGameSchema.array(),
|
||||
stats: PlayerStatsTreeSchema,
|
||||
});
|
||||
export type PlayerProfile = z.infer<typeof PlayerProfileSchema>;
|
||||
|
||||
@@ -88,7 +88,7 @@ export const OTHER_INDEX_CAPTURE = 2; // Structures captured
|
||||
export const OTHER_INDEX_LOST = 3; // Structures/warships destroyed/captured by others
|
||||
export const OTHER_INDEX_UPGRADE = 4; // Structures upgraded
|
||||
|
||||
const BigIntStringSchema = z.preprocess((val) => {
|
||||
export const BigIntStringSchema = z.preprocess((val) => {
|
||||
if (typeof val === "string" && /^-?\d+$/.test(val)) return BigInt(val);
|
||||
if (typeof val === "bigint") return val;
|
||||
return val;
|
||||
|
||||
Reference in New Issue
Block a user