More forgiving friend code input

This commit is contained in:
Kalle 2024-12-04 22:25:03 +02:00
parent bb4e0ee8d1
commit f7a4ee0971
6 changed files with 67 additions and 9 deletions

View File

@ -4,13 +4,12 @@ import * as AdminRepository from "~/features/admin/AdminRepository.server";
import { makeArtist } from "~/features/art/queries/makeArtist.server";
import { requireUserId } from "~/features/auth/core/user.server";
import { refreshBannedCache } from "~/features/ban/core/banned.server";
import { FRIEND_CODE_REGEXP } from "~/features/sendouq/q-constants";
import * as UserRepository from "~/features/user-page/UserRepository.server";
import { isAdmin, isMod } from "~/permissions";
import { logger } from "~/utils/logger";
import { parseRequestPayload, validate } from "~/utils/remix.server";
import { assertUnreachable } from "~/utils/types";
import { _action, actualNumber } from "~/utils/zod";
import { _action, actualNumber, friendCode } from "~/utils/zod";
import { plusTiersFromVotingAndLeaderboard } from "../core/plus-tier.server";
export const action = async ({ request }: ActionFunctionArgs) => {
@ -186,7 +185,7 @@ export const adminActionSchema = z.union([
}),
z.object({
_action: _action("UPDATE_FRIEND_CODE"),
friendCode: z.string().regex(FRIEND_CODE_REGEXP),
friendCode,
user: z.preprocess(actualNumber, z.number().positive()),
}),
]);

View File

@ -0,0 +1,23 @@
import { describe, expect, it } from "vitest";
import { FRIEND_CODE_REGEXP } from "./q-constants";
describe("FRIEND_CODE_REGEXP", () => {
it("should match valid friend codes", () => {
const validCodes = ["SW-1234-5678-9012", "1234-5678-9012", "123456789012"];
for (const code of validCodes) {
expect(FRIEND_CODE_REGEXP.test(code)).toBe(true);
}
});
it("should not match invalid friend codes", () => {
const invalidCodes = [
"SW-1234-5678-901",
"1234-5678-901",
"12345678901",
"hello",
];
for (const code of invalidCodes) {
expect(FRIEND_CODE_REGEXP.test(code)).toBe(false);
}
});
});

View File

@ -8,7 +8,8 @@ export const SENDOUQ = {
PRIVATE_USER_NOTE_MAX_LENGTH: TWEET_LENGTH_MAX_LENGTH,
} as const;
export const FRIEND_CODE_REGEXP_PATTERN = "^[0-9]{4}-[0-9]{4}-[0-9]{4}$";
export const FRIEND_CODE_REGEXP_PATTERN =
"^(SW-)?[0-9]{4}-?[0-9]{4}-?[0-9]{4}$";
export const FRIEND_CODE_REGEXP = new RegExp(FRIEND_CODE_REGEXP_PATTERN);
export const FULL_GROUP_SIZE = 4;

View File

@ -4,6 +4,7 @@ import {
checkboxValueToBoolean,
deduplicate,
falsyToNull,
friendCode,
id,
modeShort,
safeJSONParse,
@ -11,7 +12,7 @@ import {
weaponSplId,
} from "~/utils/zod";
import { matchEndedAtIndex } from "./core/match";
import { FRIEND_CODE_REGEXP, SENDOUQ, SENDOUQ_BEST_OF } from "./q-constants";
import { SENDOUQ, SENDOUQ_BEST_OF } from "./q-constants";
export const frontPageSchema = z.union([
z.object({
@ -26,10 +27,7 @@ export const frontPageSchema = z.union([
}),
z.object({
_action: _action("ADD_FRIEND_CODE"),
friendCode: z.string().regex(FRIEND_CODE_REGEXP, {
message:
"Invalid friend code. Did you include dashes? Example: 1234-5678-9012",
}),
friendCode,
}),
]);

20
app/utils/zod.test.ts Normal file
View File

@ -0,0 +1,20 @@
import { describe, expect, it } from "vitest";
import { normalizeFriendCode } from "./zod";
describe("normalizeFriendCode", () => {
it("returns well formatted friend code as is", () => {
expect(normalizeFriendCode("1234-5678-9012")).toBe("1234-5678-9012");
});
it("handles no dashes", () => {
expect(normalizeFriendCode("123456789012")).toBe("1234-5678-9012");
});
it("handles SW-suffix", () => {
expect(normalizeFriendCode("SW-1234-5678-9012")).toBe("1234-5678-9012");
});
it("handles a mix", () => {
expect(normalizeFriendCode("SW-1234-56789012")).toBe("1234-5678-9012");
});
});

View File

@ -2,6 +2,7 @@ import type { ZodType } from "zod";
import { z } from "zod";
import type { abilitiesShort } from "~/modules/in-game-lists";
import { abilities, mainWeaponIds, stageIds } from "~/modules/in-game-lists";
import { FRIEND_CODE_REGEXP } from "../features/sendouq/q-constants";
import type { Unpacked } from "./types";
import { assertType } from "./types";
@ -33,6 +34,22 @@ export const stackableAbility = z
.string()
.refine((val) => abilityNameToType(val) === "STACKABLE");
export const normalizeFriendCode = (value: string) => {
const onlyNumbers = value.replace(/\D/g, "");
const withDashes = onlyNumbers
.split(/(\d{4})/)
.filter(Boolean)
.join("-");
return withDashes;
};
export const friendCode = z
.string()
.regex(FRIEND_CODE_REGEXP)
.transform(normalizeFriendCode);
export const ability = z.enum([
"ISM",
"ISS",