// Comprehensive validation schemas for all modules import { z } from "zod"; // Common validation rules const positiveNumber = z.number().positive("Must be a positive number"); const nonNegativeNumber = z.number().min(0, "Must be zero or positive"); const requiredString = z.string().min(1, "This field is required"); const coordinates = z.string().regex(/^-?\d+\.?\d*,-?\d+\.?\d*$/, "Must be in format: latitude,longitude"); // Foundation Module (Bhoomi Bandhan) export const foundationInputSchema = z.object({ soilType: z.enum(["clay", "sand", "silt", "loam", "rock"], { required_error: "Soil type is required" }), loadRequirement: positiveNumber, depth: positiveNumber, width: positiveNumber, safetyFactor: z.number().min(1.5).max(5, "Safety factor must be between 1.5 and 5"), waterTable: nonNegativeNumber, seismicZone: z.enum(["I", "II", "III", "IV", "V"], { required_error: "Seismic zone is required" }) }); // Road Design Module (Marg Yantra) export const roadDesignInputSchema = z.object({ designSpeed: z.number().min(20).max(120, "Design speed must be between 20-120 km/h"), radius: positiveNumber, superelevation: z.number().min(0).max(0.07, "Superelevation must be between 0-7%"), gradientPercent: z.number().min(0).max(12, "Gradient must be between 0-12%"), pavementType: z.enum(["flexible", "rigid", "composite"], { required_error: "Pavement type is required" }), trafficLoad: positiveNumber }); // Survey Module (Naksha Drishti) export const surveyInputSchema = z.object({ stations: z.array(z.object({ name: requiredString, backsight: z.number().optional(), foresight: z.number().optional(), intermediate: z.number().optional() })).min(2, "At least 2 stations are required"), instrumentHeight: positiveNumber, benchmarkLevel: z.number() }); // Earthwork Module (Bhumi Ganit) export const earthworkInputSchema = z.object({ gridPoints: z.array(z.object({ x: z.number(), y: z.number(), existingLevel: z.number(), proposedLevel: z.number() })).min(4, "At least 4 grid points are required"), gridSpacing: positiveNumber, bulkingFactor: z.number().min(1.1).max(1.4, "Bulking factor must be between 1.1-1.4"), compactionFactor: z.number().min(0.8).max(0.95, "Compaction factor must be between 0.8-0.95") }); // Water Treatment Module (Jal Punarjanma) export const waterTreatmentInputSchema = z.object({ flowRate: positiveNumber, influent: z.object({ bod: nonNegativeNumber, cod: nonNegativeNumber, tss: nonNegativeNumber, ph: z.number().min(0).max(14, "pH must be between 0-14"), turbidity: nonNegativeNumber }), treatmentType: z.enum(["primary", "secondary", "tertiary", "advanced"], { required_error: "Treatment type is required" }), designCapacity: positiveNumber }); // Environmental Impact Module (Paryavaran Sankalp) export const eiaInputSchema = z.object({ projectType: z.enum(["industrial", "mining", "infrastructure", "residential", "commercial"], { required_error: "Project type is required" }), area: positiveNumber, location: requiredString, environmentalZone: z.enum(["residential", "commercial", "industrial", "sensitive"], { required_error: "Environmental zone is required" }), waterRequirement: nonNegativeNumber, wasteGeneration: nonNegativeNumber, energyConsumption: nonNegativeNumber }); // Emission Calculator Module (Dhvansh Ganit) export const emissionInputSchema = z.object({ sourceType: z.enum(["vehicle", "industry", "power_plant", "domestic"], { required_error: "Source type is required" }), fuelType: z.enum(["petrol", "diesel", "coal", "natural_gas", "lpg"], { required_error: "Fuel type is required" }), fuelConsumption: positiveNumber, operatingHours: z.number().min(1).max(8760, "Operating hours must be between 1-8760"), emissionStandard: z.enum(["BS4", "BS6", "Euro4", "Euro5", "Euro6"], { required_error: "Emission standard is required" }) }); // Green Building Module (Harit Manch) export const greenBuildingInputSchema = z.object({ buildingType: z.enum(["residential", "commercial", "institutional", "industrial"], { required_error: "Building type is required" }), area: positiveNumber, floors: z.number().min(1).max(100, "Number of floors must be between 1-100"), orientation: z.enum(["north", "south", "east", "west", "northeast", "northwest", "southeast", "southwest"], { required_error: "Orientation is required" }), energyFeatures: z.array(z.string()).min(1, "At least one energy feature is required"), waterFeatures: z.array(z.string()).min(1, "At least one water feature is required") }); // Project Management Schema export const projectSchema = z.object({ name: requiredString, description: z.string().optional(), type: z.enum(["university", "residential", "commercial", "infrastructure"], { required_error: "Project type is required" }), location: z.string().optional(), status: z.enum(["active", "completed", "archived"]).default("active") }); // Government Report Schema export const governmentReportSchema = z.object({ title: requiredString, reportType: z.enum(["eia", "cpcb", "municipal", "forest_clearance"], { required_error: "Report type is required" }), projectId: z.number().optional() }); // Crop Planning Schema export const cropPlanSchema = z.object({ farmName: requiredString, location: requiredString, soilType: z.enum(["clay", "sandy", "loam", "black"], { required_error: "Soil type is required" }), climate: z.enum(["tropical", "subtropical", "temperate"], { required_error: "Climate is required" }), area: positiveNumber, season: z.enum(["kharif", "rabi", "zaid"], { required_error: "Season is required" }) }); // Coastal Project Schema export const coastalProjectSchema = z.object({ siteName: requiredString, coordinates: coordinates, coastlineLength: positiveNumber.optional(), projectId: z.number().optional() }); // Community Post Schema export const communityPostSchema = z.object({ title: requiredString, description: z.string().min(10, "Description must be at least 10 characters"), category: z.enum(["case_study", "best_practice", "design_sharing"], { required_error: "Category is required" }), tags: z.array(z.string()).optional() }); // Traditional Module Schemas export const varunaJalSanchaySchema = z.object({ catchmentArea: positiveNumber, rainfall: positiveNumber, runoffCoefficient: z.number().min(0.1).max(0.9, "Runoff coefficient must be between 0.1-0.9"), storageRequirement: positiveNumber, johad: z.object({ length: positiveNumber, width: positiveNumber, depth: positiveNumber }), baoli: z.object({ steps: z.number().min(5).max(100, "Number of steps must be between 5-100"), depth: positiveNumber, diameter: positiveNumber }) }); export const vrikshaRakshakSchema = z.object({ groveArea: positiveNumber, species: z.array(z.string()).min(1, "At least one species is required"), biodiversityIndex: z.number().min(0).max(10, "Biodiversity index must be between 0-10"), conservationPlan: z.object({ protectionMeasures: z.array(z.string()).min(1, "At least one protection measure is required"), managementPractices: z.array(z.string()).min(1, "At least one management practice is required") }) }); export const amritUrjaSchema = z.object({ solarCapacity: positiveNumber, biogasCapacity: positiveNumber, energyDemand: positiveNumber, location: requiredString, solar: z.object({ panelEfficiency: z.number().min(10).max(25, "Panel efficiency must be between 10-25%"), sunlightHours: z.number().min(4).max(12, "Sunlight hours must be between 4-12") }), biogas: z.object({ organicWaste: positiveNumber, gasProduction: positiveNumber, slurryProduction: positiveNumber }) }); // Validation helper functions export function validateInputs(schema: z.ZodSchema, data: unknown): { success: true; data: T } | { success: false; errors: string[] } { try { const validatedData = schema.parse(data); return { success: true, data: validatedData }; } catch (error) { if (error instanceof z.ZodError) { const errors = error.errors.map(err => `${err.path.join('.')}: ${err.message}`); return { success: false, errors }; } return { success: false, errors: ['Unknown validation error'] }; } } export function safeParseNumber(value: any, fieldName: string): number { if (value === null || value === undefined || value === '') { throw new Error(`${fieldName} is required`); } const num = typeof value === 'string' ? parseFloat(value) : Number(value); if (isNaN(num) || !isFinite(num)) { throw new Error(`${fieldName} must be a valid number`); } return num; } export function validateRange(value: number, min: number, max: number, fieldName: string): void { if (value < min || value > max) { throw new Error(`${fieldName} must be between ${min} and ${max}`); } } export function validateCoordinates(coords: string): { lat: number; lng: number } { const parts = coords.split(','); if (parts.length !== 2) { throw new Error('Coordinates must be in format: latitude,longitude'); } const lat = safeParseNumber(parts[0].trim(), 'Latitude'); const lng = safeParseNumber(parts[1].trim(), 'Longitude'); validateRange(lat, -90, 90, 'Latitude'); validateRange(lng, -180, 180, 'Longitude'); return { lat, lng }; }