/** * Checkout Domain - Schemas * * Zod validation schemas for checkout flow. * Supports authenticated checkout. */ import { z } from "zod"; // ============================================================================ // Order Type Schema // ============================================================================ /** * Checkout order types - uses PascalCase to match Salesforce/BFF contracts * @see packages/domain/orders/contract.ts ORDER_TYPE for canonical values */ export const checkoutOrderTypeSchema = z.enum(["Internet", "SIM", "VPN"]); /** * @deprecated Use checkoutOrderTypeSchema instead. This alias exists for backwards compatibility. */ export const orderTypeSchema = checkoutOrderTypeSchema; // ============================================================================ // Order Type Helpers // ============================================================================ /** * Convert legacy uppercase order type to PascalCase * Used for migrating old localStorage data */ export function normalizeOrderType(value: unknown): z.infer | null { if (typeof value !== "string") return null; const upper = value.trim().toUpperCase(); switch (upper) { case "INTERNET": return "Internet"; case "SIM": return "SIM"; case "VPN": return "VPN"; default: return null; } } // ============================================================================ // Price Breakdown Schema // ============================================================================ export const priceBreakdownItemSchema = z.object({ label: z.string(), sku: z.string().optional(), monthlyPrice: z.number().optional(), oneTimePrice: z.number().optional(), quantity: z.number().optional().default(1), }); // ============================================================================ // Cart Item Schema // ============================================================================ export const cartItemSchema = z.object({ orderType: orderTypeSchema, planSku: z.string().min(1, "Plan SKU is required"), planName: z.string().min(1, "Plan name is required"), addonSkus: z.array(z.string()).default([]), configuration: z.record(z.string(), z.unknown()).default({}), pricing: z.object({ monthlyTotal: z.number().nonnegative(), oneTimeTotal: z.number().nonnegative(), breakdown: z.array(priceBreakdownItemSchema).default([]), }), }); // ============================================================================ // Inferred Types // ============================================================================ export type OrderType = z.infer; export type PriceBreakdownItem = z.infer; export type CartItem = z.infer;