learning_ai_clock/web/src/lib/schemas.ts
saravanakumardb1 02ac682c52 feat(web): wire Zod form validation into CreateTimerModal + add event schema
- Import and validate against alarmSchema, countdownSchema, pomodoroSchema, eventSchema
- Show inline error messages below form fields (label, time, duration, event date)
- Error border color highlights invalid fields
- Errors clear on tab switch and successful creation
2026-02-28 13:30:56 -08:00

46 lines
2.3 KiB
TypeScript

// ── Zod Validation Schemas for Timer Creation ──────────────────
import { z } from 'zod';
export const alarmSchema = z.object({
label: z.string().min(1, 'Label is required').max(100, 'Label too long'),
alarmTime: z.string().regex(/^\d{2}:\d{2}$/, 'Invalid time format (HH:MM)'),
urgency: z.enum(['critical', 'important', 'standard', 'gentle', 'passive']),
cascadePreset: z.enum(['aggressive', 'standard', 'light', 'minimal', 'none', 'custom']),
});
export const countdownSchema = z.object({
label: z.string().min(1, 'Label is required').max(100, 'Label too long'),
hours: z.number().int().min(0).max(23),
minutes: z.number().int().min(0).max(59),
seconds: z.number().int().min(0).max(59),
urgency: z.enum(['critical', 'important', 'standard', 'gentle', 'passive']),
cascadePreset: z.enum(['aggressive', 'standard', 'light', 'minimal', 'none', 'custom']),
}).refine(
(data) => data.hours > 0 || data.minutes > 0 || data.seconds > 0,
{ message: 'Duration must be greater than zero', path: ['minutes'] }
);
export const pomodoroSchema = z.object({
label: z.string().max(100, 'Label too long').default('Focus Session'),
workMinutes: z.number().int().min(1, 'Min 1 minute').max(120, 'Max 2 hours'),
breakMinutes: z.number().int().min(1, 'Min 1 minute').max(60, 'Max 1 hour'),
longBreakMinutes: z.number().int().min(1, 'Min 1 minute').max(60, 'Max 1 hour'),
rounds: z.number().int().min(1, 'Min 1 round').max(12, 'Max 12 rounds'),
urgency: z.enum(['critical', 'important', 'standard', 'gentle', 'passive']),
});
export const eventSchema = z.object({
label: z.string().max(100, 'Label too long').default('Event Countdown'),
eventDate: z.string().min(1, 'Event date is required'),
urgency: z.enum(['critical', 'important', 'standard', 'gentle', 'passive']),
cascadePreset: z.enum(['aggressive', 'standard', 'light', 'minimal', 'none', 'custom']),
}).refine(
(data) => new Date(data.eventDate).getTime() > Date.now(),
{ message: 'Event date must be in the future', path: ['eventDate'] }
);
export type AlarmFormData = z.infer<typeof alarmSchema>;
export type CountdownFormData = z.infer<typeof countdownSchema>;
export type PomodoroFormData = z.infer<typeof pomodoroSchema>;
export type EventFormData = z.infer<typeof eventSchema>;