Copy overhaul + qr designs

This commit is contained in:
2026-07-27 17:54:59 +02:00
parent 033bc7e29d
commit 70d97aa970
144 changed files with 23107 additions and 1699 deletions

View File

@@ -9,11 +9,38 @@ import { z } from 'zod';
// QR Code Schemas
// ==========================================
/**
* Zod strips unknown keys silently. This schema therefore has to list every
* design field that is actually stored - otherwise the moment anyone switches
* the route from saving `body.style` to saving the parsed output, every shape,
* gradient and logo disappears without an error anywhere.
*/
export const qrStyleSchema = z.object({
fgColor: z.string().regex(/^#[0-9A-F]{6}$/i, 'Invalid foreground color format').optional(),
bgColor: z.string().regex(/^#[0-9A-F]{6}$/i, 'Invalid background color format').optional(),
foregroundColor: z.string().optional(),
backgroundColor: z.string().optional(),
cornerStyle: z.enum(['square', 'rounded']).optional(),
size: z.number().min(100).max(1000).optional(),
moduleShape: z
.enum([
'square', 'rounded', 'dots', 'classy', 'classy-rounded',
'diamond', 'star', 'hexagon', 'plus', 'mosaic', 'liquid',
])
.optional(),
eyeFrameShape: z.enum(['square', 'rounded']).optional(),
eyeBallShape: z.enum(['square', 'rounded', 'circle', 'diamond', 'hexagon']).optional(),
gradientMode: z.enum(['none', 'linear', 'radial']).optional(),
gradientTo: z.string().optional(),
frameType: z.string().optional(),
imageSettings: z
.object({
src: z.string(),
height: z.number().optional(),
width: z.number().optional(),
excavate: z.boolean().optional(),
})
.optional(),
});
export const createQRSchema = z.object({
@@ -31,12 +58,33 @@ export const createQRSchema = z.object({
tags: z.array(z.string()).optional(),
style: z.object({
foregroundColor: z.string().optional(),
backgroundColor: z.string().optional(),
cornerStyle: z.enum(['square', 'rounded']).optional(),
size: z.number().optional(),
}).optional(),
style: z
.object({
foregroundColor: z.string().optional(),
backgroundColor: z.string().optional(),
cornerStyle: z.enum(['square', 'rounded']).optional(),
size: z.number().optional(),
moduleShape: z
.enum([
'square', 'rounded', 'dots', 'classy', 'classy-rounded',
'diamond', 'star', 'hexagon', 'plus', 'mosaic', 'liquid',
])
.optional(),
eyeFrameShape: z.enum(['square', 'rounded']).optional(),
eyeBallShape: z.enum(['square', 'rounded', 'circle', 'diamond', 'hexagon']).optional(),
gradientMode: z.enum(['none', 'linear', 'radial']).optional(),
gradientTo: z.string().optional(),
frameType: z.string().optional(),
imageSettings: z
.object({
src: z.string(),
height: z.number().optional(),
width: z.number().optional(),
excavate: z.boolean().optional(),
})
.optional(),
})
.optional(),
});
export const updateQRSchema = z.object({
@@ -53,6 +101,11 @@ export const updateQRSchema = z.object({
style: qrStyleSchema.optional(),
isActive: z.boolean().optional(),
// Pausing frees a dynamic code slot without deleting the code or its scan
// history. Used by the upgrade modal so hitting the limit has an exit that
// does not cost money and does not destroy anything.
status: z.enum(['ACTIVE', 'PAUSED']).optional(),
});
export const bulkQRSchema = z.object({
@@ -115,23 +168,23 @@ export const resetPasswordSchema = z.object({
// Settings Schemas
// ==========================================
export const updateProfileSchema = z.object({
name: z.string()
.min(2, 'Name must be at least 2 characters')
.max(100, 'Name must be less than 100 characters')
.trim(),
});
export const onboardingUpdateSchema = z.object({
signupSourceSelfReported: z.string().max(100).optional(),
primaryUseCase: z.string().max(100).optional(),
primaryGoal: z.string().max(100).optional(),
jobRole: z.string().max(100).optional(),
companyName: z.string().max(200).optional(),
companyWebsite: z.string().max(200).optional(),
teamSizeBucket: z.string().max(100).optional(),
markProfileComplete: z.boolean().optional(),
});
export const updateProfileSchema = z.object({
name: z.string()
.min(2, 'Name must be at least 2 characters')
.max(100, 'Name must be less than 100 characters')
.trim(),
});
export const onboardingUpdateSchema = z.object({
signupSourceSelfReported: z.string().max(100).optional(),
primaryUseCase: z.string().max(100).optional(),
primaryGoal: z.string().max(100).optional(),
jobRole: z.string().max(100).optional(),
companyName: z.string().max(200).optional(),
companyWebsite: z.string().max(200).optional(),
teamSizeBucket: z.string().max(100).optional(),
markProfileComplete: z.boolean().optional(),
});
export const changePasswordSchema = z.object({
currentPassword: z.string()