mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-16 23:59:30 -05:00
Fix UserCard not honoring the unverified peak XP div selected
This commit is contained in:
@@ -237,6 +237,56 @@ describe("UserCardRepository.findAllByUserIds", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("surfaces self-reported peak XP equal to the other division's verified peak", async () => {
|
||||
await insertVerifiedXp(owner.id, 3100, "WEST");
|
||||
await insertVerifiedXp(owner.id, 3000, "JPN");
|
||||
await withUserId(owner.id, () =>
|
||||
UserCardRepository.updateOwnCard({
|
||||
shortBio: null,
|
||||
bannerPresetImg: null,
|
||||
bannerImgId: null,
|
||||
unverifiedPeakXP: { overall: 3100, takoroka: 3100, tentatek: null },
|
||||
xpDivision: "JPN",
|
||||
hiddenCardStats: [],
|
||||
}),
|
||||
);
|
||||
|
||||
const { userCards } = await withNoUser(() =>
|
||||
UserCardRepository.findAllByUserIds({ userIds: [owner.id] }),
|
||||
);
|
||||
|
||||
expect(findXpStat(userCards.get(owner.id))).toMatchObject({
|
||||
type: "XP",
|
||||
values: [
|
||||
{ isVerified: false, region: "JPN", points: 3100 },
|
||||
{ isVerified: true, region: "JPN", points: 3000 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the self-reported peak XP in the picked division without placements there", async () => {
|
||||
await insertVerifiedXp(owner.id, 2639.5, "WEST");
|
||||
await withUserId(owner.id, () =>
|
||||
UserCardRepository.updateOwnCard({
|
||||
shortBio: null,
|
||||
bannerPresetImg: null,
|
||||
bannerImgId: null,
|
||||
unverifiedPeakXP: { overall: 2650, takoroka: 2650, tentatek: null },
|
||||
xpDivision: "JPN",
|
||||
hiddenCardStats: [],
|
||||
}),
|
||||
);
|
||||
|
||||
const { userCards } = await withNoUser(() =>
|
||||
UserCardRepository.findAllByUserIds({ userIds: [owner.id] }),
|
||||
);
|
||||
|
||||
expect(findXpStat(userCards.get(owner.id))).toMatchObject({
|
||||
type: "XP",
|
||||
values: [{ isVerified: false, region: "JPN", points: 2650 }],
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores self-reported peak XP when there is no verified XP", async () => {
|
||||
await withUserId(owner.id, () =>
|
||||
UserCardRepository.updateOwnCard({
|
||||
|
||||
@@ -516,8 +516,7 @@ function xpPeaksJson(eb: ExpressionBuilder<Tables, "User">) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Self-reported peak XP from the `User.unverifiedPeakXP` column. Its division is the one the
|
||||
* verified XP resolved to, since a claim only counts as one made on top of that value.
|
||||
* Self-reported peak XP from the `User.unverifiedPeakXP` column.
|
||||
*/
|
||||
function xpUnverifiedPointsScalar() {
|
||||
return sql<number | null>`"User"."unverifiedPeakXP" ->> '$.overall'`;
|
||||
@@ -645,6 +644,7 @@ function enrichUserCardData(
|
||||
const stats = userCardStats({
|
||||
div: cardData.div,
|
||||
plusTier: cardData.plusTier,
|
||||
xpDivision: cardData.xpDivision,
|
||||
xpVerified: verifiedXp(cardData.xpPeaks, cardData.xpDivision),
|
||||
xpUnverifiedPoints: cardData.xpUnverifiedPoints,
|
||||
seasonSkill,
|
||||
@@ -714,6 +714,7 @@ function enrichBanner(
|
||||
function userCardStats({
|
||||
div,
|
||||
plusTier,
|
||||
xpDivision,
|
||||
xpVerified,
|
||||
xpUnverifiedPoints,
|
||||
seasonSkill,
|
||||
@@ -721,6 +722,7 @@ function userCardStats({
|
||||
}: {
|
||||
div: string | null;
|
||||
plusTier: number | null;
|
||||
xpDivision: XRankPlacementRegion | null;
|
||||
xpVerified: { points: number; region: XRankPlacementRegion } | null;
|
||||
xpUnverifiedPoints: number | null;
|
||||
seasonSkill: TieredSkill | undefined;
|
||||
@@ -729,26 +731,22 @@ function userCardStats({
|
||||
const stats: Array<UserCardStat> = [];
|
||||
|
||||
if (xpVerified) {
|
||||
const xpValues: Array<UserCardStatXPValue> = [];
|
||||
// self-reported peak XP is only surfaced as a valid claim sitting on top of a verified placement
|
||||
if (
|
||||
xpUnverifiedPoints !== null &&
|
||||
isValidUnverifiedXp({
|
||||
unverified: xpUnverifiedPoints,
|
||||
verified: xpVerified.points,
|
||||
})
|
||||
) {
|
||||
const unverified = unverifiedXpValue({
|
||||
points: xpUnverifiedPoints,
|
||||
region: xpDivision ?? xpVerified.region,
|
||||
verifiedPoints: xpVerified.points,
|
||||
});
|
||||
|
||||
const xpValues: Array<UserCardStatXPValue> = unverified ? [unverified] : [];
|
||||
// the verified peak joins the claim only when it is from the division the claim was made in;
|
||||
// in another division it is a peak on a ladder the card is not about
|
||||
if (!unverified || unverified.region === xpVerified.region) {
|
||||
xpValues.push({
|
||||
isVerified: false,
|
||||
isVerified: true,
|
||||
region: xpVerified.region,
|
||||
points: xpUnverifiedPoints,
|
||||
points: xpVerified.points,
|
||||
});
|
||||
}
|
||||
xpValues.push({
|
||||
isVerified: true,
|
||||
region: xpVerified.region,
|
||||
points: xpVerified.points,
|
||||
});
|
||||
|
||||
stats.push({ type: "XP", values: xpValues });
|
||||
}
|
||||
@@ -767,3 +765,20 @@ function userCardStats({
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
function unverifiedXpValue({
|
||||
points,
|
||||
region,
|
||||
verifiedPoints,
|
||||
}: {
|
||||
points: number | null;
|
||||
region: XRankPlacementRegion;
|
||||
verifiedPoints: number;
|
||||
}): UserCardStatXPValue | null {
|
||||
if (points === null) return null;
|
||||
if (!isValidUnverifiedXp({ unverified: points, verified: verifiedPoints })) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { isVerified: false, region, points };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { type ActionFunction, redirect } from "react-router";
|
||||
import type { PeakXP } from "~/db/tables-json";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import type { XRankPlacementRegion } from "~/features/top-search/top-search-types";
|
||||
import { parseFormDataWithImages } from "~/form/parse.server";
|
||||
import { userPage } from "~/utils/urls";
|
||||
import * as UserCardRepository from "../UserCardRepository.server";
|
||||
@@ -50,13 +52,7 @@ export const action: ActionFunction = async ({ request }) => {
|
||||
xpDivision: data.xpDivision,
|
||||
unverifiedPeakXP:
|
||||
data.unverifiedXpPoints && verifiedXp
|
||||
? {
|
||||
overall: data.unverifiedXpPoints,
|
||||
tentatek:
|
||||
verifiedXp.region === "WEST" ? data.unverifiedXpPoints : null,
|
||||
takoroka:
|
||||
verifiedXp.region === "JPN" ? data.unverifiedXpPoints : null,
|
||||
}
|
||||
? peakXP(data.unverifiedXpPoints, data.xpDivision ?? verifiedXp.region)
|
||||
: null,
|
||||
hiddenCardStats: resolveHiddenStats(data),
|
||||
});
|
||||
@@ -64,6 +60,14 @@ export const action: ActionFunction = async ({ request }) => {
|
||||
throw redirect(returnTo ?? userPage(user));
|
||||
};
|
||||
|
||||
function peakXP(points: number, region: XRankPlacementRegion): PeakXP {
|
||||
return {
|
||||
overall: points,
|
||||
tentatek: region === "WEST" ? points : null,
|
||||
takoroka: region === "JPN" ? points : null,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveBanner({
|
||||
bannerType,
|
||||
bannerColor,
|
||||
|
||||
Reference in New Issue
Block a user