Schema Validation (Zod) and State Management
Every robust interactive widget requires two foundational pillars:
- Reactive State: Storing and updating visitor interactions in real time (e.g., adjusting sliders or typing form values).
- Schema Validation (Zod): Ensuring inputs comply with exact business constraints and data types prior to submission.
1. Reactive State Architecture
Pitaj.io widgets utilize a streamlined reactive state model analogous to React’s useState paradigm:
// Initial Component Stateconst initialState = { monthlyBill: 120, roofType: "pitched", includeBattery: false};
// State Transition TriggeronChange={(val) => setState({ ...state, monthlyBill: val })}Whenever setState is executed, the widget immediately re-renders recalculated KPIs without flashing or disturbing the chat stream.
2. Input Validation via Zod Schemas
To prevent invalid submissions (such as negative dollar figures or malformed email addresses), every widget is paired with a Zod Schema:
import { z } from "zod";
export const widgetSchema = z.object({ loanAmount: z .number({ invalid_type_error: "Amount must be a numeric value" }) .min(5000, "Minimum borrowing amount is $5,000") .max(500000, "Maximum borrowing limit is $500,000"),
repaymentYears: z .number() .min(1, "Minimum duration is 1 year") .max(30, "Maximum duration is 30 years"),
contactEmail: z .string() .email("Please provide a valid business email"),
agreeToTerms: z .boolean() .refine((val) => val === true, "You must accept our Terms of Service")});When a visitor provides an invalid input, the control receives a red border state and displays the exact validation message.
3. Emitting Payloads to Chat (emit)
Once the customer concludes their input and clicks the action trigger, the emit callback transmits structured data back into the conversational thread:
// Submitting Widget Data to the AI AssistantonClick={() => { const validation = widgetSchema.safeParse(state); if (!validation.success) { setErrors(validation.error.flatten().fieldErrors); return; }
// Emit clean, validated payload to agent emit("loan_calculated", { amount: state.loanAmount, years: state.repaymentYears, calculatedMonthlyRate: calculateRate(state), email: state.contactEmail });}}What Transpires After Emission?
- The widget UI enters a completed, frozen state.
- The AI assistant ingests the emitted payload and continues the dialogue:
“Thank you! Based on your calculation for a $50,000 loan over 10 years, your estimated monthly rate is $482.50. We have emailed the complete schedule to alex@company.com.”