Leads / lib /validators.ts
abc1181's picture
LeadGen India SMB v1.0 — Next.js + SQLite + nightly pipeline (PRD/TRD ticked)
bc324b9
Raw History Blame Contribute Delete
2.97 kB
import { z } from "zod";
export const LocationSchema = z.object({
label: z.string().min(1).max(80),
city: z.string().min(1).max(80),
state: z.string().max(80).optional().default(""),
country: z.string().max(4).optional().default("IN"),
lat: z.number().min(-90).max(90).optional(),
lng: z.number().min(-180).max(180).optional(),
radiusKm: z.number().min(2).max(100).default(50),
pincode: z.string().max(10).optional(),
});
export const TogglesSchema = z.object({
requirePhone: z.boolean().default(true),
requireEmail: z.boolean().default(false),
noWebsiteOnly: z.boolean().default(true),
allowBadWebsite: z.boolean().default(true),
cap: z.number().int().min(20).max(200).default(100),
tone: z.string().max(20).default("smb"),
language: z.enum(["EN", "Hinglish"]).default("EN"),
});
export const INDUSTRIES = [
"dental", "dermatology", "salon", "spa", "gym", "physiotherapy", "clinic",
"restaurant", "cafe", "bakery", "cloud-kitchen", "hotel", "real-estate",
"interiors", "coaching", "playschool", "training", "consulting", "legal",
"accounting", "manufacturing", "trading", "export", "distributor",
"showroom", "education", "hospital", "college", "retail", "automotive",
] as const;
export const SIZE_BANDS = ["1-10", "11-50", "51-200", "201+"] as const;
export const SearchCreateSchema = z.object({
name: z.string().min(3).max(60),
template: z.string().min(1).max(40),
locations: z.array(LocationSchema).min(1).max(5),
keywords: z.array(z.string().min(1).max(60)).min(0).max(20).default([]),
titles: z.array(z.string().min(1).max(40)).min(0).max(10).default([]),
toggles: TogglesSchema,
industries: z.array(z.string().max(40)).max(30).default([]),
sizeBands: z.array(z.enum(SIZE_BANDS)).max(4).default([]),
icon: z.string().max(10).optional(),
color: z.string().max(20).optional(),
});
export const LeadPatchSchema = z.object({
status: z.enum(["new", "qualified", "contacted", "replied", "call", "won", "lost", "rejected"]).optional(),
rejectReason: z.string().max(200).optional().nullable(),
notes: z.string().max(5000).optional().nullable(),
tags: z.array(z.string().max(30)).max(20).optional(),
email: z.string().max(254).optional().nullable(),
phone: z.string().max(30).optional().nullable(),
contact: z.string().max(120).optional().nullable(),
title: z.string().max(60).optional().nullable(),
});
export const EmailSchema = z.string().trim().toLowerCase().email().max(254);
export const AI_PACK_V = 1;
export const SCORE_VERSION = 3;
export const LeadPackSchema = z.object({
summary: z.string().min(10).max(500),
icebreaker: z.string().min(10).max(600),
hinglish: z.string().min(10).max(600),
propensity: z.number().int().min(0).max(100),
reasons: z.array(z.string().max(120)).max(3).default([]),
industry: z.string().max(60).nullable().default(null),
sizeBand: z.string().max(20).nullable().default(null),
});
export type LeadPack = z.infer<typeof LeadPackSchema>;