Refactor application schema to add validation for project and business forms

This commit is contained in:
THIS ONE IS A LITTLE BIT TRICKY KRUB 2024-10-16 20:11:49 +07:00
parent 428f42383d
commit 01afc6c6fb
2 changed files with 142 additions and 0 deletions

View File

@ -0,0 +1,142 @@
import { z } from "zod";
const MAX_FILE_SIZE = 500000;
const ACCEPTED_IMAGE_TYPES = ["image/jpeg", "image/jpg", "image/png"];
const imageSchema = z.custom<File>(
(val) => val && typeof val === "object" && "size" in val && "type" in val,
{
message: "Input must be a file.",
},
).refine((file) => file.size < MAX_FILE_SIZE, {
message: "File can't be bigger than 5MB.",
}).refine((file) => ACCEPTED_IMAGE_TYPES.includes(file.type), {
message: "File format must be either jpg, jpeg, or png.",
});
const projectFormSchema = z.object({
projectName: z.string().min(5, {
message: "Project name must be at least 5 characters.",
}),
projectType: z.string({
required_error: "Please select one of the option",
}),
shortDescription: z.string({
required_error: "Please provide a brief description for your project",
}).min(10, {
message: "Short description must be at least 10 characters.",
}),
projectPitchDeck: z.union([
z.string().url("Pitch deck must be a valid URL.").refine(
(url) => url.endsWith(".md"),
{
message: "Pitch deck URL must link to a markdown file (.md).",
},
),
z.custom<File>(
(val) => val instanceof File,
{
message: "Input must be a file.",
},
).refine((file) => file.size < MAX_FILE_SIZE, {
message: "File can't be bigger than 5MB.",
}).refine((file) => file.name.endsWith(".md"), {
message: "File must be a markdown file (.md).",
}),
]),
projectLogo: imageSchema,
projectPhotos: z.custom(
(value) => {
if (value instanceof FileList || Array.isArray(value)) {
if (value.length === 1) {
return false;
}
return Array.from(value).every((item) => item instanceof File);
}
return false;
},
{
message:
"Must be a FileList or an array of File objects with at least one file.",
},
),
minInvest: z.number({
required_error: "Minimum investment must be a number.",
invalid_type_error: "Minimum investment must be a valid number.",
}).positive().max(
9999999999,
"Minimum investment must be a realistic amount.",
),
targetInvest: z.number({
required_error: "Target investment must be a number.",
invalid_type_error: "Target investment must be a valid number.",
}).positive().max(
9999999999,
"Target investment must be a realistic amount.",
),
deadline: z.string().min(1, "Deadline is required.")
.refine((value) => !isNaN(Date.parse(value)), {
message: "Invalid date-time format.",
})
.transform((value) => new Date(value))
.refine((date) => date > new Date(), {
message: "Deadline must be in the future.",
}),
});
const businessFormSchema = z.object({
companyName: z.string().min(5, {
message: "Company name must be at least 5 characters.",
}),
industry: z.string({
required_error: "Please select one of the option",
}),
isInUS: z.string({
required_error: "Please select either 'Yes' or 'No'.",
})
.transform((val) => val.toLowerCase())
.refine((val) => val === "yes" || val === "no", {
message: "Please select either 'Yes' or 'No'.",
}),
isForSale: z.string({
required_error: "Please select either 'Yes' or 'No'.",
})
.transform((val) => val.toLowerCase())
.refine((val) => val === "yes" || val === "no", {
message: "Please select either 'Yes' or 'No'.",
}),
isGenerating: z.string({
required_error: "Please select either 'Yes' or 'No'.",
})
.transform((val) => val.toLowerCase())
.refine((val) => val === "yes" || val === "no", {
message: "Please select either 'Yes' or 'No'.",
}),
totalRaised: z.number({
required_error: "Total raised must be a number.",
invalid_type_error: "Total raised must be a valid number.",
}).positive().max(9999999999, "Total raised must be a realistic amount."),
communitySize: z.string({
required_error: "Please select one of the option",
}),
businessPitchDeck: z.union([
z.string().url("Pitch deck must be a valid URL.").refine(
(url) => url.endsWith(".md"),
{
message: "Pitch deck URL must link to a markdown file (.md).",
},
),
z.custom<File>(
(val) => val instanceof File,
{
message: "Input must be a file.",
},
).refine((file) => file.size < MAX_FILE_SIZE, {
message: "File can't be bigger than 5MB.",
}).refine((file) => file.name.endsWith(".md"), {
message: "File must be a markdown file (.md).",
}),
]),
});
export { businessFormSchema, projectFormSchema };