mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-07-24 20:22:15 -05:00
119 lines
2.9 KiB
TypeScript
119 lines
2.9 KiB
TypeScript
import { z } from "zod";
|
|
import {
|
|
array,
|
|
fieldset,
|
|
idConstant,
|
|
image,
|
|
select,
|
|
selectOptional,
|
|
stringConstant,
|
|
textAreaOptional,
|
|
textFieldOptional,
|
|
textFieldRequired,
|
|
toggle,
|
|
} from "~/form/fields";
|
|
import { mySlugify } from "~/utils/urls";
|
|
import {
|
|
CUSTOM_ROLE_MAX_LENGTH,
|
|
TEAM,
|
|
TEAM_MEMBER_ROLES,
|
|
} from "./team-constants";
|
|
|
|
const teamNameValidate = {
|
|
func: (teamName: string) =>
|
|
mySlugify(teamName).length > 0 && mySlugify(teamName) !== "new",
|
|
message: "forms:errors.noOnlySpecialCharacters",
|
|
} as const;
|
|
|
|
export const createTeamSchema = z.object({
|
|
name: textFieldRequired({
|
|
label: "labels.name",
|
|
minLength: TEAM.NAME_MIN_LENGTH,
|
|
maxLength: TEAM.NAME_MAX_LENGTH,
|
|
validate: teamNameValidate,
|
|
}),
|
|
});
|
|
|
|
export const editTeamFormSchema = z.object({
|
|
_action: stringConstant("EDIT"),
|
|
name: textFieldRequired({
|
|
label: "labels.name",
|
|
bottomText: "bottomTexts.name",
|
|
minLength: TEAM.NAME_MIN_LENGTH,
|
|
maxLength: TEAM.NAME_MAX_LENGTH,
|
|
validate: teamNameValidate,
|
|
}),
|
|
tag: textFieldOptional({
|
|
label: "labels.tag",
|
|
bottomText: "bottomTexts.tag",
|
|
maxLength: TEAM.TAG_MAX_LENGTH,
|
|
}),
|
|
bsky: textFieldOptional({
|
|
label: "labels.teamBsky",
|
|
leftAddon: "https://bsky.app/profile/",
|
|
maxLength: TEAM.BSKY_MAX_LENGTH,
|
|
}),
|
|
bio: textAreaOptional({
|
|
label: "labels.bio",
|
|
maxLength: TEAM.BIO_MAX_LENGTH,
|
|
}),
|
|
logo: image({ label: "labels.logo" }),
|
|
banner: image({ label: "labels.banner", dimensions: "thick-banner" }),
|
|
});
|
|
|
|
/** Sentinel `role` value selected to switch a member to a free-text custom role. Never stored. */
|
|
export const CUSTOM_ROLE_VALUE = "CUSTOM";
|
|
|
|
export const updateRosterSchema = z
|
|
.object({
|
|
_action: stringConstant("UPDATE_ROSTER"),
|
|
members: array({
|
|
max: TEAM.MAX_MEMBER_COUNT,
|
|
addable: false,
|
|
sortable: true,
|
|
field: fieldset({
|
|
fields: z.object({
|
|
userId: idConstant(),
|
|
role: selectOptional({
|
|
label: "labels.teamMemberRole",
|
|
items: [
|
|
...TEAM_MEMBER_ROLES.map((role) => ({
|
|
value: role,
|
|
label: `options.teamMemberRole.${role}` as const,
|
|
})),
|
|
{
|
|
value: CUSTOM_ROLE_VALUE,
|
|
label: "options.teamMemberRole.CUSTOM" as const,
|
|
},
|
|
],
|
|
}),
|
|
customRole: textFieldOptional({
|
|
label: "labels.teamMemberCustomRole",
|
|
maxLength: CUSTOM_ROLE_MAX_LENGTH,
|
|
}),
|
|
roleType: select({
|
|
label: "labels.teamMemberRoleType",
|
|
items: [
|
|
{ value: "PLAYER", label: "options.teamMemberRoleType.PLAYER" },
|
|
{ value: "OTHER", label: "options.teamMemberRoleType.OTHER" },
|
|
],
|
|
}),
|
|
isManager: toggle({ label: "labels.teamEditor" }),
|
|
}),
|
|
}),
|
|
}),
|
|
})
|
|
.superRefine((data, ctx) => {
|
|
for (const [index, member] of data.members.entries()) {
|
|
const isCustom = member.role === CUSTOM_ROLE_VALUE;
|
|
|
|
if (isCustom && !member.customRole) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
path: ["members", index, "customRole"],
|
|
message: "forms:errors.customRoleRequired",
|
|
});
|
|
}
|
|
}
|
|
});
|