chore: update packages
also migrate zod to v4
This commit is contained in:
parent
afb73ec3a6
commit
8b4842b584
20 changed files with 918 additions and 922 deletions
28
package.json
28
package.json
|
|
@ -13,10 +13,10 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@2toad/profanity": "^3.1.1",
|
"@2toad/profanity": "^3.1.1",
|
||||||
"@auth/prisma-adapter": "2.9.1",
|
"@auth/prisma-adapter": "2.10.0",
|
||||||
"@bprogress/next": "^3.2.12",
|
"@bprogress/next": "^3.2.12",
|
||||||
"@hello-pangea/dnd": "^18.0.1",
|
"@hello-pangea/dnd": "^18.0.1",
|
||||||
"@prisma/client": "^6.9.0",
|
"@prisma/client": "^6.11.1",
|
||||||
"@types/sjcl": "^1.0.34",
|
"@types/sjcl": "^1.0.34",
|
||||||
"bit-buffer": "^0.2.5",
|
"bit-buffer": "^0.2.5",
|
||||||
"canvas-confetti": "^1.9.3",
|
"canvas-confetti": "^1.9.3",
|
||||||
|
|
@ -26,32 +26,32 @@
|
||||||
"file-type": "^21.0.0",
|
"file-type": "^21.0.0",
|
||||||
"ioredis": "^5.6.1",
|
"ioredis": "^5.6.1",
|
||||||
"jsqr": "^1.4.0",
|
"jsqr": "^1.4.0",
|
||||||
"next": "15.3.3",
|
"next": "15.3.5",
|
||||||
"next-auth": "5.0.0-beta.25",
|
"next-auth": "5.0.0-beta.25",
|
||||||
"qrcode-generator": "^1.5.0",
|
"qrcode-generator": "^2.0.2",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
"react-webcam": "^7.2.0",
|
"react-webcam": "^7.2.0",
|
||||||
"satori": "^0.15.2",
|
"satori": "^0.15.2",
|
||||||
"sharp": "^0.34.2",
|
"sharp": "^0.34.3",
|
||||||
"sjcl-with-all": "1.0.8",
|
"sjcl-with-all": "1.0.8",
|
||||||
"swr": "^2.3.3",
|
"swr": "^2.3.4",
|
||||||
"zod": "^3.25.63"
|
"zod": "^4.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@iconify/react": "^6.0.0",
|
"@iconify/react": "^6.0.0",
|
||||||
"@tailwindcss/postcss": "^4.1.10",
|
"@tailwindcss/postcss": "^4.1.11",
|
||||||
"@types/canvas-confetti": "^1.9.0",
|
"@types/canvas-confetti": "^1.9.0",
|
||||||
"@types/node": "^24.0.1",
|
"@types/node": "^24.0.13",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.8",
|
||||||
"@types/react-dom": "^19.1.6",
|
"@types/react-dom": "^19.1.6",
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.31.0",
|
||||||
"eslint-config-next": "15.3.3",
|
"eslint-config-next": "15.3.5",
|
||||||
"prisma": "^6.9.0",
|
"prisma": "^6.11.1",
|
||||||
"tailwindcss": "^4.1.10",
|
"tailwindcss": "^4.1.11",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vitest": "^3.2.3"
|
"vitest": "^3.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1697
pnpm-lock.yaml
1697
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -13,7 +13,7 @@ export async function GET(request: NextRequest) {
|
||||||
const searchParams = request.nextUrl.searchParams;
|
const searchParams = request.nextUrl.searchParams;
|
||||||
const parsed = idSchema.safeParse(searchParams.get("id"));
|
const parsed = idSchema.safeParse(searchParams.get("id"));
|
||||||
|
|
||||||
if (!parsed.success) return NextResponse.json({ error: parsed.error.errors[0].message }, { status: 400 });
|
if (!parsed.success) return NextResponse.json({ error: parsed.error.issues[0].message }, { status: 400 });
|
||||||
const userId = parsed.data;
|
const userId = parsed.data;
|
||||||
|
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,15 @@ import { PunishmentType } from "@prisma/client";
|
||||||
const punishSchema = z.object({
|
const punishSchema = z.object({
|
||||||
type: z.enum([PunishmentType.WARNING, PunishmentType.TEMP_EXILE, PunishmentType.PERM_EXILE]),
|
type: z.enum([PunishmentType.WARNING, PunishmentType.TEMP_EXILE, PunishmentType.PERM_EXILE]),
|
||||||
duration: z
|
duration: z
|
||||||
.number({ message: "Duration (days) must be a number" })
|
.number({ error: "Duration (days) must be a number" })
|
||||||
.int({ message: "Duration (days) must be an integer" })
|
.int({ error: "Duration (days) must be an integer" })
|
||||||
.positive({ message: "Duration (days) must be valid" }),
|
.positive({ error: "Duration (days) must be valid" }),
|
||||||
notes: z.string(),
|
notes: z.string(),
|
||||||
reasons: z.array(z.string()).optional(),
|
reasons: z.array(z.string()).optional(),
|
||||||
miiReasons: z
|
miiReasons: z
|
||||||
.array(
|
.array(
|
||||||
z.object({
|
z.object({
|
||||||
id: z
|
id: z.number({ error: "Mii ID must be a number" }).int({ error: "Mii ID must be an integer" }).positive({ error: "Mii ID must be valid" }),
|
||||||
.number({ message: "Mii ID must be a number" })
|
|
||||||
.int({ message: "Mii ID must be an integer" })
|
|
||||||
.positive({ message: "Mii ID must be valid" }),
|
|
||||||
reason: z.string(),
|
reason: z.string(),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
@ -38,13 +35,13 @@ export async function POST(request: NextRequest) {
|
||||||
const searchParams = request.nextUrl.searchParams;
|
const searchParams = request.nextUrl.searchParams;
|
||||||
const parsedUserId = idSchema.safeParse(searchParams.get("id"));
|
const parsedUserId = idSchema.safeParse(searchParams.get("id"));
|
||||||
|
|
||||||
if (!parsedUserId.success) return NextResponse.json({ error: parsedUserId.error.errors[0].message }, { status: 400 });
|
if (!parsedUserId.success) return NextResponse.json({ error: parsedUserId.error.issues[0].message }, { status: 400 });
|
||||||
const userId = parsedUserId.data;
|
const userId = parsedUserId.data;
|
||||||
|
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const parsed = punishSchema.safeParse(body);
|
const parsed = punishSchema.safeParse(body);
|
||||||
|
|
||||||
if (!parsed.success) return NextResponse.json({ error: parsed.error.errors[0].message }, { status: 400 });
|
if (!parsed.success) return NextResponse.json({ error: parsed.error.issues[0].message }, { status: 400 });
|
||||||
const { type, duration, notes, reasons, miiReasons } = parsed.data;
|
const { type, duration, notes, reasons, miiReasons } = parsed.data;
|
||||||
|
|
||||||
const expiresAt = type === "TEMP_EXILE" ? dayjs().add(duration, "days").toDate() : null;
|
const expiresAt = type === "TEMP_EXILE" ? dayjs().add(duration, "days").toDate() : null;
|
||||||
|
|
@ -77,7 +74,7 @@ export async function DELETE(request: NextRequest) {
|
||||||
const searchParams = request.nextUrl.searchParams;
|
const searchParams = request.nextUrl.searchParams;
|
||||||
const parsedPunishmentId = idSchema.safeParse(searchParams.get("id"));
|
const parsedPunishmentId = idSchema.safeParse(searchParams.get("id"));
|
||||||
|
|
||||||
if (!parsedPunishmentId.success) return NextResponse.json({ error: parsedPunishmentId.error.errors[0].message }, { status: 400 });
|
if (!parsedPunishmentId.success) return NextResponse.json({ error: parsedPunishmentId.error.issues[0].message }, { status: 400 });
|
||||||
const punishmentId = parsedPunishmentId.data;
|
const punishmentId = parsedPunishmentId.data;
|
||||||
|
|
||||||
await prisma.punishment.delete({
|
await prisma.punishment.delete({
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export async function PATCH(request: NextRequest) {
|
||||||
if (!displayName) return rateLimit.sendResponse({ error: "New display name is required" }, 400);
|
if (!displayName) return rateLimit.sendResponse({ error: "New display name is required" }, 400);
|
||||||
|
|
||||||
const validation = displayNameSchema.safeParse(displayName);
|
const validation = displayNameSchema.safeParse(displayName);
|
||||||
if (!validation.success) return rateLimit.sendResponse({ error: validation.error.errors[0].message }, 400);
|
if (!validation.success) return rateLimit.sendResponse({ error: validation.error.issues[0].message }, 400);
|
||||||
|
|
||||||
// Check for inappropriate words
|
// Check for inappropriate words
|
||||||
if (profanity.exists(displayName)) return rateLimit.sendResponse({ error: "Display name contains inappropriate words" }, 400);
|
if (profanity.exists(displayName)) return rateLimit.sendResponse({ error: "Display name contains inappropriate words" }, 400);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ export async function PATCH(request: NextRequest) {
|
||||||
image: formData.get("image"),
|
image: formData.get("image"),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const { image } = parsed.data;
|
const { image } = parsed.data;
|
||||||
|
|
||||||
// If there is no image, set the profile picture to the guest image
|
// If there is no image, set the profile picture to the guest image
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export async function PATCH(request: NextRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const validation = usernameSchema.safeParse(username);
|
const validation = usernameSchema.safeParse(username);
|
||||||
if (!validation.success) return rateLimit.sendResponse({ error: validation.error.errors[0].message }, 400);
|
if (!validation.success) return rateLimit.sendResponse({ error: validation.error.issues[0].message }, 400);
|
||||||
|
|
||||||
// Check for inappropriate words
|
// Check for inappropriate words
|
||||||
if (profanity.exists(username)) return rateLimit.sendResponse({ error: "Username contains inappropriate words" }, 400);
|
if (profanity.exists(username)) return rateLimit.sendResponse({ error: "Username contains inappropriate words" }, 400);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
|
||||||
|
|
||||||
const { id: slugId } = await params;
|
const { id: slugId } = await params;
|
||||||
const parsed = idSchema.safeParse(slugId);
|
const parsed = idSchema.safeParse(slugId);
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const miiId = parsed.data;
|
const miiId = parsed.data;
|
||||||
|
|
||||||
// Check ownership of Mii
|
// Check ownership of Mii
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
||||||
// Get Mii ID
|
// Get Mii ID
|
||||||
const { id: slugId } = await params;
|
const { id: slugId } = await params;
|
||||||
const parsedId = idSchema.safeParse(slugId);
|
const parsedId = idSchema.safeParse(slugId);
|
||||||
if (!parsedId.success) return rateLimit.sendResponse({ error: parsedId.error.errors[0].message }, 400);
|
if (!parsedId.success) return rateLimit.sendResponse({ error: parsedId.error.issues[0].message }, 400);
|
||||||
const miiId = parsedId.data;
|
const miiId = parsedId.data;
|
||||||
|
|
||||||
// Check ownership of Mii
|
// Check ownership of Mii
|
||||||
|
|
@ -78,7 +78,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
||||||
image3: formData.get("image3"),
|
image3: formData.get("image3"),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const { name, tags, description, image1, image2, image3 } = parsed.data;
|
const { name, tags, description, image1, image2, image3 } = parsed.data;
|
||||||
|
|
||||||
// Validate image files
|
// Validate image files
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
||||||
|
|
||||||
const { id: slugId } = await params;
|
const { id: slugId } = await params;
|
||||||
const parsed = idSchema.safeParse(slugId);
|
const parsed = idSchema.safeParse(slugId);
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const miiId = parsed.data;
|
const miiId = parsed.data;
|
||||||
|
|
||||||
const result = await prisma.$transaction(async (tx) => {
|
const result = await prisma.$transaction(async (tx) => {
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import { RateLimit } from "@/lib/rate-limit";
|
||||||
import { MiiWithUsername } from "@/types";
|
import { MiiWithUsername } from "@/types";
|
||||||
|
|
||||||
const reportSchema = z.object({
|
const reportSchema = z.object({
|
||||||
id: z.coerce.number({ message: "ID must be a number" }).int({ message: "ID must be an integer" }).positive({ message: "ID must be valid" }),
|
id: z.coerce.number({ error: "ID must be a number" }).int({ error: "ID must be an integer" }).positive({ error: "ID must be valid" }),
|
||||||
type: z.enum(["mii", "user"], { message: "Type must be either 'mii' or 'user'" }),
|
type: z.enum(["mii", "user"], { error: "Type must be either 'mii' or 'user'" }),
|
||||||
reason: z.enum(["inappropriate", "spam", "copyright", "other"], {
|
reason: z.enum(["inappropriate", "spam", "copyright", "other"], {
|
||||||
message: "Reason must be either 'inappropriate', 'spam', 'copyright', or 'other'",
|
message: "Reason must be either 'inappropriate', 'spam', 'copyright', or 'other'",
|
||||||
}),
|
}),
|
||||||
|
|
@ -27,7 +27,7 @@ export async function POST(request: NextRequest) {
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const parsed = reportSchema.safeParse(body);
|
const parsed = reportSchema.safeParse(body);
|
||||||
|
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const { id, type, reason, notes } = parsed.data;
|
const { id, type, reason, notes } = parsed.data;
|
||||||
|
|
||||||
let mii: MiiWithUsername | null = null;
|
let mii: MiiWithUsername | null = null;
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,7 @@ const submitSchema = z.object({
|
||||||
name: nameSchema,
|
name: nameSchema,
|
||||||
tags: tagsSchema,
|
tags: tagsSchema,
|
||||||
description: z.string().trim().max(256).optional(),
|
description: z.string().trim().max(256).optional(),
|
||||||
qrBytesRaw: z
|
qrBytesRaw: z.array(z.number(), { error: "A QR code is required" }).length(372, { error: "QR code size is not a valid Tomodachi Life QR code" }),
|
||||||
.array(z.number(), { required_error: "A QR code is required" })
|
|
||||||
.length(372, { message: "QR code size is not a valid Tomodachi Life QR code" }),
|
|
||||||
image1: z.union([z.instanceof(File), z.any()]).optional(),
|
image1: z.union([z.instanceof(File), z.any()]).optional(),
|
||||||
image2: z.union([z.instanceof(File), z.any()]).optional(),
|
image2: z.union([z.instanceof(File), z.any()]).optional(),
|
||||||
image3: z.union([z.instanceof(File), z.any()]).optional(),
|
image3: z.union([z.instanceof(File), z.any()]).optional(),
|
||||||
|
|
@ -67,7 +65,7 @@ export async function POST(request: NextRequest) {
|
||||||
image3: formData.get("image3"),
|
image3: formData.get("image3"),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const { name: uncensoredName, tags: uncensoredTags, description: uncensoredDescription, qrBytesRaw, image1, image2, image3 } = parsed.data;
|
const { name: uncensoredName, tags: uncensoredTags, description: uncensoredDescription, qrBytesRaw, image1, image2, image3 } = parsed.data;
|
||||||
|
|
||||||
// Censor potential inappropriate words
|
// Censor potential inappropriate words
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
||||||
|
|
||||||
const { id: slugId } = await params;
|
const { id: slugId } = await params;
|
||||||
const parsed = idSchema.safeParse(slugId);
|
const parsed = idSchema.safeParse(slugId);
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const miiId = parsed.data;
|
const miiId = parsed.data;
|
||||||
|
|
||||||
const searchParamsParsed = searchParamsSchema.safeParse(Object.fromEntries(request.nextUrl.searchParams));
|
const searchParamsParsed = searchParamsSchema.safeParse(Object.fromEntries(request.nextUrl.searchParams));
|
||||||
if (!searchParamsParsed.success) return rateLimit.sendResponse({ error: searchParamsParsed.error.errors[0].message }, 400);
|
if (!searchParamsParsed.success) return rateLimit.sendResponse({ error: searchParamsParsed.error.issues[0].message }, 400);
|
||||||
const { type: imageType } = searchParamsParsed.data;
|
const { type: imageType } = searchParamsParsed.data;
|
||||||
|
|
||||||
const fileExtension = imageType === "metadata" ? ".png" : ".webp";
|
const fileExtension = imageType === "metadata" ? ".png" : ".webp";
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
||||||
|
|
||||||
const { id: slugId } = await params;
|
const { id: slugId } = await params;
|
||||||
const parsed = idSchema.safeParse(slugId);
|
const parsed = idSchema.safeParse(slugId);
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const userId = parsed.data;
|
const userId = parsed.data;
|
||||||
|
|
||||||
const filePath = path.join(process.cwd(), "uploads", "user", `${userId}.webp`);
|
const filePath = path.join(process.cwd(), "uploads", "user", `${userId}.webp`);
|
||||||
|
|
|
||||||
|
|
@ -36,15 +36,15 @@ const searchSchema = z.object({
|
||||||
// todo: incorporate tagsSchema
|
// todo: incorporate tagsSchema
|
||||||
// Pages
|
// Pages
|
||||||
limit: z.coerce
|
limit: z.coerce
|
||||||
.number({ message: "Limit must be a number" })
|
.number({ error: "Limit must be a number" })
|
||||||
.int({ message: "Limit must be an integer" })
|
.int({ error: "Limit must be an integer" })
|
||||||
.min(1, { message: "Limit must be at least 1" })
|
.min(1, { error: "Limit must be at least 1" })
|
||||||
.max(100, { message: "Limit cannot be more than 100" })
|
.max(100, { error: "Limit cannot be more than 100" })
|
||||||
.optional(),
|
.optional(),
|
||||||
page: z.coerce
|
page: z.coerce
|
||||||
.number({ message: "Page must be a number" })
|
.number({ error: "Page must be a number" })
|
||||||
.int({ message: "Page must be an integer" })
|
.int({ error: "Page must be an integer" })
|
||||||
.min(1, { message: "Page must be at least 1" })
|
.min(1, { error: "Page must be at least 1" })
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ export default async function MiiList({ searchParams, userId, inLikesPage }: Pro
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
|
|
||||||
const parsed = searchSchema.safeParse(searchParams);
|
const parsed = searchSchema.safeParse(searchParams);
|
||||||
if (!parsed.success) return <h1>{parsed.error.errors[0].message}</h1>;
|
if (!parsed.success) return <h1>{parsed.error.issues[0].message}</h1>;
|
||||||
|
|
||||||
const { q: query, sort, tags, page = 1, limit = 24 } = parsed.data;
|
const { q: query, sort, tags, page = 1, limit = 24 } = parsed.data;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export default function ProfileSettings() {
|
||||||
const handleSubmitDisplayNameChange = async (close: () => void) => {
|
const handleSubmitDisplayNameChange = async (close: () => void) => {
|
||||||
const parsed = displayNameSchema.safeParse(displayName);
|
const parsed = displayNameSchema.safeParse(displayName);
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
setDisplayNameChangeError(parsed.error.errors[0].message);
|
setDisplayNameChangeError(parsed.error.issues[0].message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ export default function ProfileSettings() {
|
||||||
const handleSubmitUsernameChange = async (close: () => void) => {
|
const handleSubmitUsernameChange = async (close: () => void) => {
|
||||||
const parsed = usernameSchema.safeParse(username);
|
const parsed = usernameSchema.safeParse(username);
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
setUsernameChangeError(parsed.error.errors[0].message);
|
setUsernameChangeError(parsed.error.issues[0].message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,12 @@ export default function EditForm({ mii, likes }: Props) {
|
||||||
// Validate before sending request
|
// Validate before sending request
|
||||||
const nameValidation = nameSchema.safeParse(name);
|
const nameValidation = nameSchema.safeParse(name);
|
||||||
if (!nameValidation.success) {
|
if (!nameValidation.success) {
|
||||||
setError(nameValidation.error.errors[0].message);
|
setError(nameValidation.error.issues[0].message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tagsValidation = tagsSchema.safeParse(tags);
|
const tagsValidation = tagsSchema.safeParse(tags);
|
||||||
if (!tagsValidation.success) {
|
if (!tagsValidation.success) {
|
||||||
setError(tagsValidation.error.errors[0].message);
|
setError(tagsValidation.error.issues[0].message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,12 +49,12 @@ export default function SubmitForm() {
|
||||||
// Validate before sending request
|
// Validate before sending request
|
||||||
const nameValidation = nameSchema.safeParse(name);
|
const nameValidation = nameSchema.safeParse(name);
|
||||||
if (!nameValidation.success) {
|
if (!nameValidation.success) {
|
||||||
setError(nameValidation.error.errors[0].message);
|
setError(nameValidation.error.issues[0].message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tagsValidation = tagsSchema.safeParse(tags);
|
const tagsValidation = tagsSchema.safeParse(tags);
|
||||||
if (!tagsValidation.success) {
|
if (!tagsValidation.success) {
|
||||||
setError(tagsValidation.error.errors[0].message);
|
setError(tagsValidation.error.issues[0].message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export default function UsernameForm() {
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const parsed = usernameSchema.safeParse(username);
|
const parsed = usernameSchema.safeParse(username);
|
||||||
if (!parsed.success) setError(parsed.error.errors[0].message);
|
if (!parsed.success) setError(parsed.error.issues[0].message);
|
||||||
|
|
||||||
const response = await fetch("/api/auth/username", {
|
const response = await fetch("/api/auth/username", {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
|
|
|
||||||
|
|
@ -5,39 +5,39 @@ import { z } from "zod";
|
||||||
export const querySchema = z
|
export const querySchema = z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(2, { message: "Search query must be at least 2 characters long" })
|
.min(2, { error: "Search query must be at least 2 characters long" })
|
||||||
.max(64, { message: "Search query cannot be more than 64 characters long" })
|
.max(64, { error: "Search query cannot be more than 64 characters long" })
|
||||||
.regex(/^[a-zA-Z0-9-_. ']+$/, {
|
.regex(/^[a-zA-Z0-9-_. ']+$/, {
|
||||||
message: "Search query can only contain letters, numbers, dashes, underscores, apostrophes, and spaces.",
|
error: "Search query can only contain letters, numbers, dashes, underscores, apostrophes, and spaces.",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Miis
|
// Miis
|
||||||
export const nameSchema = z
|
export const nameSchema = z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(2, { message: "Name must be at least 2 characters long" })
|
.min(2, { error: "Name must be at least 2 characters long" })
|
||||||
.max(64, { message: "Name cannot be more than 64 characters long" })
|
.max(64, { error: "Name cannot be more than 64 characters long" })
|
||||||
.regex(/^[a-zA-Z0-9-_. ']+$/, {
|
.regex(/^[a-zA-Z0-9-_. ']+$/, {
|
||||||
message: "Name can only contain letters, numbers, dashes, underscores, apostrophes, and spaces.",
|
error: "Name can only contain letters, numbers, dashes, underscores, apostrophes, and spaces.",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const tagsSchema = z
|
export const tagsSchema = z
|
||||||
.array(
|
.array(
|
||||||
z
|
z
|
||||||
.string()
|
.string()
|
||||||
.min(2, { message: "Tags must be at least 2 characters long" })
|
.min(2, { error: "Tags must be at least 2 characters long" })
|
||||||
.max(64, { message: "Tags cannot be more than 20 characters long" })
|
.max(64, { error: "Tags cannot be more than 20 characters long" })
|
||||||
.regex(/^[a-z0-9-_]+$/, {
|
.regex(/^[a-z0-9-_]+$/, {
|
||||||
message: "Tags can only contain lowercase letters, numbers, dashes, and underscores.",
|
error: "Tags can only contain lowercase letters, numbers, dashes, and underscores.",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.min(1, { message: "There must be at least 1 tag" })
|
.min(1, { error: "There must be at least 1 tag" })
|
||||||
.max(8, { message: "There cannot be more than 8 tags" });
|
.max(8, { error: "There cannot be more than 8 tags" });
|
||||||
|
|
||||||
export const idSchema = z.coerce
|
export const idSchema = z.coerce
|
||||||
.number({ message: "ID must be a number" })
|
.number({ error: "ID must be a number" })
|
||||||
.int({ message: "ID must be an integer" })
|
.int({ error: "ID must be an integer" })
|
||||||
.positive({ message: "ID must be valid" });
|
.positive({ error: "ID must be valid" });
|
||||||
|
|
||||||
// Account Info
|
// Account Info
|
||||||
export const usernameSchema = z
|
export const usernameSchema = z
|
||||||
|
|
@ -50,8 +50,8 @@ export const usernameSchema = z
|
||||||
export const displayNameSchema = z
|
export const displayNameSchema = z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(2, { message: "Display name must be at least 2 characters long" })
|
.min(2, { error: "Display name must be at least 2 characters long" })
|
||||||
.max(64, { message: "Display name cannot be more than 64 characters long" })
|
.max(64, { error: "Display name cannot be more than 64 characters long" })
|
||||||
.regex(/^[a-zA-Z0-9-_. ']+$/, {
|
.regex(/^[a-zA-Z0-9-_. ']+$/, {
|
||||||
message: "Display name can only contain letters, numbers, dashes, underscores, apostrophes, and spaces.",
|
error: "Display name can only contain letters, numbers, dashes, underscores, apostrophes, and spaces.",
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue