- Add updateUser and resetUserPassword admin endpoints - Change company status from boolean to enum (registered, lead, customer, inactive) - Add 'important' event type to calendar validators and email templates - Add 1-hour-before event notifications cron job - Add 18:00 evening notifications for next-day events - Add contact description field support - Fix count() function usage in admin service - Add SQL migrations for schema changes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
194 lines
8.0 KiB
JavaScript
194 lines
8.0 KiB
JavaScript
import { z } from 'zod';
|
|
|
|
// Company validators
|
|
export const createCompanySchema = z.object({
|
|
name: z
|
|
.string({
|
|
required_error: 'Názov firmy je povinný',
|
|
})
|
|
.min(1, 'Názov firmy nemôže byť prázdny')
|
|
.max(255, 'Názov firmy môže mať maximálne 255 znakov'),
|
|
description: z.string().max(1000).optional(),
|
|
address: z.string().max(255).optional(),
|
|
city: z.string().max(100).optional(),
|
|
country: z.string().max(100).optional(),
|
|
phone: z.string().max(50).optional(),
|
|
email: z.string().email('Neplatný formát emailu').max(255).optional().or(z.literal('')),
|
|
website: z.string().url('Neplatný formát URL').max(255).optional().or(z.literal('')),
|
|
status: z.enum(['registered', 'lead', 'customer', 'inactive']).optional(),
|
|
});
|
|
|
|
export const updateCompanySchema = z.object({
|
|
name: z.string().min(1).max(255).optional(),
|
|
description: z.string().max(1000).optional(),
|
|
address: z.string().max(255).optional(),
|
|
city: z.string().max(100).optional(),
|
|
country: z.string().max(100).optional(),
|
|
phone: z.string().max(50).optional(),
|
|
email: z.string().email('Neplatný formát emailu').max(255).optional().or(z.literal('')),
|
|
website: z.string().url('Neplatný formát URL').max(255).optional().or(z.literal('')),
|
|
status: z.enum(['registered', 'lead', 'customer', 'inactive']).optional(),
|
|
});
|
|
|
|
// Project validators
|
|
export const createProjectSchema = z.object({
|
|
name: z
|
|
.string({
|
|
required_error: 'Názov projektu je povinný',
|
|
})
|
|
.min(1, 'Názov projektu nemôže byť prázdny')
|
|
.max(255, 'Názov projektu môže mať maximálne 255 znakov'),
|
|
description: z.string().max(1000).optional(),
|
|
companyId: z.string().uuid('Neplatný formát company ID').optional().or(z.literal('')),
|
|
status: z.enum(['active', 'completed', 'on_hold', 'cancelled']).optional(),
|
|
startDate: z.string().optional().or(z.literal('')),
|
|
endDate: z.string().optional().or(z.literal('')),
|
|
});
|
|
|
|
export const updateProjectSchema = z.object({
|
|
name: z.string().min(1).max(255).optional(),
|
|
description: z.string().max(1000).optional(),
|
|
companyId: z.string().uuid('Neplatný formát company ID').optional().or(z.literal('').or(z.null())),
|
|
status: z.enum(['active', 'completed', 'on_hold', 'cancelled']).optional(),
|
|
startDate: z.string().optional().or(z.literal('').or(z.null())),
|
|
endDate: z.string().optional().or(z.literal('').or(z.null())),
|
|
});
|
|
|
|
// Todo validators
|
|
export const createTodoSchema = z.object({
|
|
title: z
|
|
.string({
|
|
required_error: 'Názov todo je povinný',
|
|
})
|
|
.min(1, 'Názov todo nemôže byť prázdny')
|
|
.max(255, 'Názov todo môže mať maximálne 255 znakov'),
|
|
description: z.string().max(1000).optional(),
|
|
projectId: z.string().uuid('Neplatný formát project ID').optional().or(z.literal('')),
|
|
companyId: z.string().uuid('Neplatný formát company ID').optional().or(z.literal('')),
|
|
assignedUserIds: z.array(z.string().uuid('Neplatný formát user ID')).optional(),
|
|
status: z.enum(['pending', 'in_progress', 'completed', 'cancelled']).optional(),
|
|
priority: z.enum(['low', 'medium', 'high', 'urgent']).optional(),
|
|
dueDate: z.string().optional().or(z.literal('')),
|
|
});
|
|
|
|
export const updateTodoSchema = z.object({
|
|
title: z.string().min(1).max(255).optional(),
|
|
description: z.string().max(1000).optional(),
|
|
projectId: z.string().uuid('Neplatný formát project ID').optional().or(z.literal('').or(z.null())),
|
|
companyId: z.string().uuid('Neplatný formát company ID').optional().or(z.literal('').or(z.null())),
|
|
assignedUserIds: z.array(z.string().uuid('Neplatný formát user ID')).optional(),
|
|
status: z.enum(['pending', 'in_progress', 'completed', 'cancelled']).optional(),
|
|
priority: z.enum(['low', 'medium', 'high', 'urgent']).optional(),
|
|
dueDate: z.string().optional().or(z.literal('').or(z.null())),
|
|
});
|
|
|
|
// Note validators (s voliteľným dueDate pre dátum a čas)
|
|
export const createNoteSchema = z.object({
|
|
title: z.string().max(255).optional(),
|
|
content: z
|
|
.string({
|
|
required_error: 'Obsah poznámky je povinný',
|
|
})
|
|
.min(1, 'Obsah poznámky nemôže byť prázdny')
|
|
.max(5000, 'Obsah poznámky môže mať maximálne 5000 znakov'),
|
|
companyId: z.string().uuid('Neplatný formát company ID').optional().or(z.literal('')),
|
|
projectId: z.string().uuid('Neplatný formát project ID').optional().or(z.literal('')),
|
|
todoId: z.string().uuid('Neplatný formát todo ID').optional().or(z.literal('')),
|
|
contactId: z.string().uuid('Neplatný formát contact ID').optional().or(z.literal('')),
|
|
dueDate: z.string().optional().or(z.literal('')), // ISO string s dátumom a časom (24h formát)
|
|
});
|
|
|
|
export const updateNoteSchema = z.object({
|
|
title: z.string().max(255).optional().or(z.literal('').or(z.null())),
|
|
content: z.string().min(1).max(5000).optional(),
|
|
companyId: z.string().uuid('Neplatný formát company ID').optional().or(z.literal('').or(z.null())),
|
|
projectId: z.string().uuid('Neplatný formát project ID').optional().or(z.literal('').or(z.null())),
|
|
todoId: z.string().uuid('Neplatný formát todo ID').optional().or(z.literal('').or(z.null())),
|
|
contactId: z.string().uuid('Neplatný formát contact ID').optional().or(z.literal('').or(z.null())),
|
|
dueDate: z.string().optional().or(z.literal('').or(z.null())), // ISO string s dátumom a časom (24h formát)
|
|
});
|
|
|
|
// Company reminder validators (with dueDate)
|
|
export const createCompanyReminderSchema = z.object({
|
|
description: z.string().min(1).max(1000),
|
|
dueDate: z.string().optional().or(z.literal('')),
|
|
isChecked: z.boolean().optional(),
|
|
});
|
|
|
|
export const updateCompanyReminderSchema = z.object({
|
|
description: z.string().min(1).max(1000).optional(),
|
|
dueDate: z.string().optional().or(z.literal('').or(z.null())),
|
|
isChecked: z.boolean().optional(),
|
|
}).refine(
|
|
(data) => data.description !== undefined || data.isChecked !== undefined || data.dueDate !== undefined,
|
|
{ message: 'Je potrebné zadať description, dueDate alebo isChecked' }
|
|
);
|
|
|
|
// Time Tracking validators
|
|
const optionalUuid = (message) =>
|
|
z
|
|
.preprocess(
|
|
(val) => {
|
|
if (val === undefined) return undefined;
|
|
if (val === null || val === '') return null;
|
|
return val;
|
|
},
|
|
z.string().uuid(message).nullable()
|
|
)
|
|
.optional();
|
|
|
|
const optionalDescription = z
|
|
.preprocess(
|
|
(val) => {
|
|
if (val === undefined) return undefined;
|
|
if (val === null) return null;
|
|
if (typeof val !== 'string') return val;
|
|
const trimmed = val.trim();
|
|
return trimmed === '' ? null : trimmed;
|
|
},
|
|
z.string().max(1000).nullable()
|
|
)
|
|
.optional();
|
|
|
|
export const startTimeEntrySchema = z.object({
|
|
projectId: optionalUuid('Neplatný formát project ID'),
|
|
todoId: optionalUuid('Neplatný formát todo ID'),
|
|
companyId: optionalUuid('Neplatný formát company ID'),
|
|
description: optionalDescription,
|
|
});
|
|
|
|
export const stopTimeEntrySchema = z.object({
|
|
projectId: optionalUuid('Neplatný formát project ID'),
|
|
todoId: optionalUuid('Neplatný formát todo ID'),
|
|
companyId: optionalUuid('Neplatný formát company ID'),
|
|
description: optionalDescription,
|
|
});
|
|
|
|
export const updateTimeEntrySchema = z.object({
|
|
startTime: z.string().optional(),
|
|
endTime: z.string().optional(),
|
|
projectId: optionalUuid('Neplatný formát project ID'),
|
|
todoId: optionalUuid('Neplatný formát todo ID'),
|
|
companyId: optionalUuid('Neplatný formát company ID'),
|
|
description: optionalDescription,
|
|
});
|
|
|
|
// Event validators
|
|
export const createEventSchema = z.object({
|
|
title: z.string().min(1, 'Názov je povinný'),
|
|
description: z.string().optional(),
|
|
type: z.enum(['meeting', 'event', 'important']).default('meeting'),
|
|
start: z.string().min(1, 'Začiatok je povinný'),
|
|
end: z.string().min(1, 'Koniec je povinný'),
|
|
assignedUserIds: z.array(z.string().uuid('Neplatný formát user ID')).optional(),
|
|
});
|
|
|
|
export const updateEventSchema = z.object({
|
|
title: z.string().min(1).optional(),
|
|
description: z.string().optional(),
|
|
type: z.enum(['meeting', 'event', 'important']).optional(),
|
|
start: z.string().optional(),
|
|
end: z.string().optional(),
|
|
assignedUserIds: z.array(z.string().uuid('Neplatný formát user ID')).optional(),
|
|
});
|