This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { z } from "zod"
|
||||
|
||||
const optionalPositiveInteger = z.preprocess(
|
||||
(value) => {
|
||||
if (typeof value !== "string") return null
|
||||
|
||||
const trimmed = value.trim()
|
||||
return trimmed.length > 0 ? trimmed : null
|
||||
},
|
||||
z.coerce.number().int().positive().nullable(),
|
||||
)
|
||||
|
||||
export const toastRequestSchema = z.object({
|
||||
memberId: z.uuid().nullable(),
|
||||
speakerName: z.string().trim().min(1).max(160),
|
||||
estimatedMinutes: optionalPositiveInteger,
|
||||
})
|
||||
|
||||
export const interactionSubmissionSchema = z.object({
|
||||
invitationId: z.uuid(),
|
||||
toastRequest: toastRequestSchema.nullable(),
|
||||
})
|
||||
|
||||
export const toastStatusSchema = z.enum(["pending", "accepted", "declined", "scheduled"])
|
||||
|
||||
export type InteractionSubmissionInput = z.infer<typeof interactionSubmissionSchema>
|
||||
export type ToastStatus = z.infer<typeof toastStatusSchema>
|
||||
@@ -0,0 +1,48 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { supportedLanguageCodes } from "@/lib/i18n/config"
|
||||
|
||||
const optionalText = z.preprocess(
|
||||
(value) => {
|
||||
if (typeof value !== "string") return null
|
||||
|
||||
const trimmed = value.trim()
|
||||
return trimmed.length > 0 ? trimmed : null
|
||||
},
|
||||
z.string().nullable(),
|
||||
)
|
||||
|
||||
const optionalEmail = z.preprocess(
|
||||
(value) => {
|
||||
if (typeof value !== "string") return null
|
||||
|
||||
const trimmed = value.trim()
|
||||
return trimmed.length > 0 ? trimmed : null
|
||||
},
|
||||
z.email().nullable(),
|
||||
)
|
||||
|
||||
export const createInvitationSchema = z
|
||||
.object({
|
||||
displayName: z.string().trim().min(1, "Display name is required"),
|
||||
language: z.enum(supportedLanguageCodes, {
|
||||
error: "Select a supported language",
|
||||
}),
|
||||
contactEmail: optionalEmail.optional().default(null),
|
||||
contactPhone: optionalText.optional().default(null),
|
||||
maxPartySize: z.coerce
|
||||
.number()
|
||||
.int("Party size must be a whole number")
|
||||
.min(1, "Party size must be at least 1"),
|
||||
allowMemberEdits: z.coerce.boolean().default(false),
|
||||
notes: optionalText.optional().default(null),
|
||||
members: z
|
||||
.array(z.string().trim().min(1))
|
||||
.min(1, "Add at least one invitation member"),
|
||||
})
|
||||
.refine((value) => value.members.length <= value.maxPartySize, {
|
||||
message: "Members cannot exceed max party size",
|
||||
path: ["members"],
|
||||
})
|
||||
|
||||
export type CreateInvitationInput = z.infer<typeof createInvitationSchema>
|
||||
@@ -0,0 +1,55 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const mealPreferenceSchema = z.enum([
|
||||
"meat",
|
||||
"fish",
|
||||
"vegetarian",
|
||||
"vegan",
|
||||
"kids",
|
||||
"other",
|
||||
])
|
||||
|
||||
const optionalText = z.preprocess(
|
||||
(value) => {
|
||||
if (typeof value !== "string") return null
|
||||
|
||||
const trimmed = value.trim()
|
||||
return trimmed.length > 0 ? trimmed : null
|
||||
},
|
||||
z.string().nullable(),
|
||||
)
|
||||
|
||||
const optionalDate = z.preprocess(
|
||||
(value) => {
|
||||
if (typeof value !== "string") return null
|
||||
|
||||
const trimmed = value.trim()
|
||||
return trimmed.length > 0 ? trimmed : null
|
||||
},
|
||||
z.iso.date().nullable(),
|
||||
)
|
||||
|
||||
const memberResponseSchema = z
|
||||
.object({
|
||||
memberId: z.uuid(),
|
||||
attending: z.boolean(),
|
||||
mealPreference: mealPreferenceSchema.nullable(),
|
||||
dietaryRestrictions: optionalText,
|
||||
})
|
||||
.refine((value) => !value.attending || value.mealPreference !== null, {
|
||||
message: "Meal preference is required for attending guests",
|
||||
path: ["mealPreference"],
|
||||
})
|
||||
|
||||
export const submitInvitationResponseSchema = z.object({
|
||||
token: z.string().min(1),
|
||||
members: z.array(memberResponseSchema).min(1),
|
||||
arrivalDate: optionalDate,
|
||||
departureDate: optionalDate,
|
||||
stayLocation: optionalText,
|
||||
needsTransportHelp: z.boolean().nullable(),
|
||||
messageToCouple: optionalText,
|
||||
})
|
||||
|
||||
export type SubmitInvitationResponseInput = z.infer<typeof submitInvitationResponseSchema>
|
||||
export type MealPreference = z.infer<typeof mealPreferenceSchema>
|
||||
@@ -0,0 +1,18 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const allowedImageContentTypes = ["image/jpeg", "image/png", "image/webp"] as const
|
||||
export const maxUploadSizeBytes = 10 * 1024 * 1024
|
||||
|
||||
export const presignUploadSchema = z.object({
|
||||
token: z.string().min(1),
|
||||
filename: z.string().trim().min(1).max(255),
|
||||
contentType: z.enum(allowedImageContentTypes),
|
||||
sizeBytes: z.number().int().positive().max(maxUploadSizeBytes),
|
||||
})
|
||||
|
||||
export const completeUploadSchema = presignUploadSchema.extend({
|
||||
objectKey: z.string().min(1),
|
||||
})
|
||||
|
||||
export type PresignUploadInput = z.infer<typeof presignUploadSchema>
|
||||
export type CompleteUploadInput = z.infer<typeof completeUploadSchema>
|
||||
Reference in New Issue
Block a user