import { db } from "../db"; import { clients, tags as tagsTable } from "../db/schema"; import { eq, and } from "drizzle-orm"; export const MAX_LENGTHS = { name: 255, email: 320, password: 128, phone: 50, address: 255, // street, city, state, zip, country currency: 10, invoiceNumber: 50, invoiceNotes: 5000, itemDescription: 2000, description: 2000, // time entry description } as const; export function exceedsLength( field: string, value: string | null | undefined, maxLength: number, ): string | null { if (value && value.length > maxLength) { return `${field} must be ${maxLength} characters or fewer`; } return null; } export async function validateTimeEntryResources({ organizationId, clientId, tagId, }: { organizationId: string; clientId: string; tagId?: string | null; }) { const client = await db .select() .from(clients) .where( and(eq(clients.id, clientId), eq(clients.organizationId, organizationId)), ) .get(); if (!client) { return { valid: false, error: "Invalid client" }; } if (tagId) { const validTag = await db .select() .from(tagsTable) .where( and( eq(tagsTable.id, tagId), eq(tagsTable.organizationId, organizationId), ), ) .get(); if (!validTag) { return { valid: false, error: "Invalid tag" }; } } return { valid: true }; } export function validateTimeRange( start: string | number | Date, end: string | number | Date, ) { const startDate = new Date(start); const endDate = new Date(end); if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { return { valid: false, error: "Invalid date format" }; } if (endDate <= startDate) { return { valid: false, error: "End time must be after start time" }; } return { valid: true, startDate, endDate }; } const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; export function isValidEmail(email: string): boolean { return EMAIL_REGEX.test(email) && email.length <= 320; }