mirror of
https://github.com/hex248/sprint.git
synced 2026-02-07 18:23:03 +00:00
improved error messages
This commit is contained in:
@@ -24,25 +24,25 @@ export type ApiError = z.infer<typeof ApiErrorSchema>;
|
||||
// auth schemas
|
||||
|
||||
export const LoginRequestSchema = z.object({
|
||||
username: z.string().min(1, "username is required").max(USER_USERNAME_MAX_LENGTH),
|
||||
password: z.string().min(1, "password is required"),
|
||||
username: z.string().min(1, "Username is required").max(USER_USERNAME_MAX_LENGTH),
|
||||
password: z.string().min(1, "Password is required"),
|
||||
});
|
||||
|
||||
export type LoginRequest = z.infer<typeof LoginRequestSchema>;
|
||||
|
||||
export const RegisterRequestSchema = z.object({
|
||||
name: z.string().min(1, "name is required").max(USER_NAME_MAX_LENGTH),
|
||||
name: z.string().min(1, "Name is required").max(USER_NAME_MAX_LENGTH),
|
||||
username: z
|
||||
.string()
|
||||
.min(1, "username is required")
|
||||
.min(1, "Username is required")
|
||||
.max(USER_USERNAME_MAX_LENGTH)
|
||||
.regex(/^[a-zA-Z0-9_-]+$/, "username can only contain letters, numbers, underscores, and hyphens"),
|
||||
.regex(/^[a-zA-Z0-9_-]+$/, "Username can only contain letters, numbers, underscores, and hyphens"),
|
||||
password: z
|
||||
.string()
|
||||
.min(8, "password must be at least 8 characters")
|
||||
.regex(/[A-Z]/, "password must contain an uppercase letter")
|
||||
.regex(/[a-z]/, "password must contain a lowercase letter")
|
||||
.regex(/[0-9]/, "password must contain a number"),
|
||||
.min(8, "Password must be at least 8 characters")
|
||||
.regex(/[A-Z]/, "Password must contain an uppercase letter")
|
||||
.regex(/[a-z]/, "Password must contain a lowercase letter")
|
||||
.regex(/[0-9]/, "Password must contain a number"),
|
||||
avatarURL: z.string().url().nullable(),
|
||||
});
|
||||
|
||||
@@ -64,7 +64,7 @@ export type AuthResponse = z.infer<typeof AuthResponseSchema>;
|
||||
|
||||
export const IssueCreateRequestSchema = z.object({
|
||||
projectId: z.number().int().positive("projectId must be a positive integer"),
|
||||
title: z.string().min(1, "title is required").max(ISSUE_TITLE_MAX_LENGTH),
|
||||
title: z.string().min(1, "Title is required").max(ISSUE_TITLE_MAX_LENGTH),
|
||||
description: z.string().max(ISSUE_DESCRIPTION_MAX_LENGTH).default(""),
|
||||
status: z.string().max(ISSUE_STATUS_MAX_LENGTH).optional(),
|
||||
assigneeIds: z.array(z.number().int().positive()).optional(),
|
||||
@@ -75,7 +75,7 @@ export type IssueCreateRequest = z.infer<typeof IssueCreateRequestSchema>;
|
||||
|
||||
export const IssueUpdateRequestSchema = z.object({
|
||||
id: z.number().int().positive("id must be a positive integer"),
|
||||
title: z.string().min(1).max(ISSUE_TITLE_MAX_LENGTH).optional(),
|
||||
title: z.string().min(1, "Title must be at least 1 character").max(ISSUE_TITLE_MAX_LENGTH).optional(),
|
||||
description: z.string().max(ISSUE_DESCRIPTION_MAX_LENGTH).optional(),
|
||||
status: z.string().max(ISSUE_STATUS_MAX_LENGTH).optional(),
|
||||
assigneeIds: z.array(z.number().int().positive()).nullable().optional(),
|
||||
@@ -98,7 +98,7 @@ export type IssuesByProjectQuery = z.infer<typeof IssuesByProjectQuerySchema>;
|
||||
|
||||
export const IssuesStatusCountQuerySchema = z.object({
|
||||
organisationId: z.coerce.number().int().positive("organisationId must be a positive integer"),
|
||||
status: z.string().min(1, "status is required").max(ISSUE_STATUS_MAX_LENGTH),
|
||||
status: z.string().min(1, "Status is required").max(ISSUE_STATUS_MAX_LENGTH),
|
||||
});
|
||||
|
||||
export type IssuesStatusCountQuery = z.infer<typeof IssuesStatusCountQuerySchema>;
|
||||
@@ -114,12 +114,12 @@ export type IssuesReplaceStatusRequest = z.infer<typeof IssuesReplaceStatusReque
|
||||
// organisation schemas
|
||||
|
||||
export const OrgCreateRequestSchema = z.object({
|
||||
name: z.string().min(1, "name is required").max(ORG_NAME_MAX_LENGTH),
|
||||
name: z.string().min(1, "Name is required").max(ORG_NAME_MAX_LENGTH),
|
||||
slug: z
|
||||
.string()
|
||||
.min(1, "slug is required")
|
||||
.min(1, "Slug is required")
|
||||
.max(ORG_SLUG_MAX_LENGTH)
|
||||
.regex(/^[a-z0-9-]+$/, "slug can only contain lowercase letters, numbers, and hyphens"),
|
||||
.regex(/^[a-z0-9-]+$/, "Slug can only contain lowercase letters, numbers, and hyphens"),
|
||||
description: z.string().max(ORG_DESCRIPTION_MAX_LENGTH).optional(),
|
||||
});
|
||||
|
||||
@@ -127,20 +127,20 @@ export type OrgCreateRequest = z.infer<typeof OrgCreateRequestSchema>;
|
||||
|
||||
export const OrgUpdateRequestSchema = z.object({
|
||||
id: z.number().int().positive("id must be a positive integer"),
|
||||
name: z.string().min(1).max(ORG_NAME_MAX_LENGTH).optional(),
|
||||
name: z.string().min(1, "Name must be at least 1 character").max(ORG_NAME_MAX_LENGTH).optional(),
|
||||
description: z.string().max(ORG_DESCRIPTION_MAX_LENGTH).optional(),
|
||||
slug: z
|
||||
.string()
|
||||
.min(1)
|
||||
.min(1, "Slug must be at least 1 character")
|
||||
.max(ORG_SLUG_MAX_LENGTH)
|
||||
.regex(/^[a-z0-9-]+$/)
|
||||
.optional(),
|
||||
statuses: z
|
||||
.record(z.string())
|
||||
.refine((obj) => Object.keys(obj).length > 0, "statuses must have at least one entry")
|
||||
.refine((obj) => Object.keys(obj).length > 0, "Statuses must have at least one entry")
|
||||
.refine(
|
||||
(obj) => Object.keys(obj).every((key) => key.length <= ISSUE_STATUS_MAX_LENGTH),
|
||||
`status keys must be <= ${ISSUE_STATUS_MAX_LENGTH} characters`,
|
||||
`Status keys must be <= ${ISSUE_STATUS_MAX_LENGTH} characters`,
|
||||
)
|
||||
.optional(),
|
||||
});
|
||||
@@ -191,11 +191,11 @@ export type OrgUpdateMemberRoleRequest = z.infer<typeof OrgUpdateMemberRoleReque
|
||||
// project schemas
|
||||
|
||||
export const ProjectCreateRequestSchema = z.object({
|
||||
name: z.string().min(1, "name is required").max(PROJECT_NAME_MAX_LENGTH),
|
||||
name: z.string().min(1, "Name is required").max(PROJECT_NAME_MAX_LENGTH),
|
||||
key: z
|
||||
.string()
|
||||
.length(4, "key must be exactly 4 characters")
|
||||
.regex(/^[A-Z]{4}$/, "key must be 4 uppercase letters"),
|
||||
.length(4, "Key must be exactly 4 characters")
|
||||
.regex(/^[A-Z]{4}$/, "Key must be 4 uppercase letters"),
|
||||
organisationId: z.number().int().positive("organisationId must be a positive integer"),
|
||||
});
|
||||
|
||||
@@ -203,11 +203,11 @@ export type ProjectCreateRequest = z.infer<typeof ProjectCreateRequestSchema>;
|
||||
|
||||
export const ProjectUpdateRequestSchema = z.object({
|
||||
id: z.number().int().positive("id must be a positive integer"),
|
||||
name: z.string().min(1).max(PROJECT_NAME_MAX_LENGTH).optional(),
|
||||
name: z.string().min(1, "Name must be at least 1 character").max(PROJECT_NAME_MAX_LENGTH).optional(),
|
||||
key: z
|
||||
.string()
|
||||
.length(4)
|
||||
.regex(/^[A-Z]{4}$/)
|
||||
.length(4, "Key must be exactly 4 characters")
|
||||
.regex(/^[A-Z]{4}$/, "Key must be 4 uppercase letters")
|
||||
.optional(),
|
||||
creatorId: z.number().int().positive().optional(),
|
||||
organisationId: z.number().int().positive().optional(),
|
||||
@@ -244,16 +244,16 @@ export type ProjectByCreatorQuery = z.infer<typeof ProjectByCreatorQuerySchema>;
|
||||
export const SprintCreateRequestSchema = z
|
||||
.object({
|
||||
projectId: z.number().int().positive("projectId must be a positive integer"),
|
||||
name: z.string().min(1, "name is required").max(64),
|
||||
name: z.string().min(1, "Name is required").max(64, "Name must be at most 64 characters"),
|
||||
color: z
|
||||
.string()
|
||||
.regex(/^#[0-9a-fA-F]{6}$/, "color must be a valid hex color")
|
||||
.regex(/^#[0-9a-fA-F]{6}$/, "Color must be a valid hex color")
|
||||
.optional(),
|
||||
startDate: z.string().datetime("startDate must be a valid ISO datetime"),
|
||||
endDate: z.string().datetime("endDate must be a valid ISO datetime"),
|
||||
startDate: z.string().datetime("Start date must be a valid date"),
|
||||
endDate: z.string().datetime("End date must be a valid date"),
|
||||
})
|
||||
.refine((data) => new Date(data.startDate) <= new Date(data.endDate), {
|
||||
message: "endDate must be after startDate",
|
||||
message: "End date must be after start date",
|
||||
path: ["endDate"],
|
||||
});
|
||||
|
||||
@@ -288,13 +288,13 @@ export type TimerGetQuery = z.infer<typeof TimerGetQuerySchema>;
|
||||
// user schemas
|
||||
|
||||
export const UserUpdateRequestSchema = z.object({
|
||||
name: z.string().min(1).max(USER_NAME_MAX_LENGTH).optional(),
|
||||
name: z.string().min(1, "Name must be at least 1 character").max(USER_NAME_MAX_LENGTH).optional(),
|
||||
password: z
|
||||
.string()
|
||||
.min(8)
|
||||
.regex(/[A-Z]/, "password must contain an uppercase letter")
|
||||
.regex(/[a-z]/, "password must contain a lowercase letter")
|
||||
.regex(/[0-9]/, "password must contain a number")
|
||||
.min(8, "Password must be at least 8 characters")
|
||||
.regex(/[A-Z]/, "Password must contain an uppercase letter")
|
||||
.regex(/[a-z]/, "Password must contain a lowercase letter")
|
||||
.regex(/[0-9]/, "Password must contain a number")
|
||||
.optional(),
|
||||
avatarURL: z.string().url().nullable().optional(),
|
||||
});
|
||||
@@ -302,7 +302,7 @@ export const UserUpdateRequestSchema = z.object({
|
||||
export type UserUpdateRequest = z.infer<typeof UserUpdateRequestSchema>;
|
||||
|
||||
export const UserByUsernameQuerySchema = z.object({
|
||||
username: z.string().min(1, "username is required"),
|
||||
username: z.string().min(1, "Username is required"),
|
||||
});
|
||||
|
||||
export type UserByUsernameQuery = z.infer<typeof UserByUsernameQuerySchema>;
|
||||
|
||||
Reference in New Issue
Block a user