- Integrated CheckoutRegistrationModule into the application for handling checkout-related functionalities. - Updated router configuration to include the new CheckoutRegistrationModule for API routing. - Enhanced SalesforceAccountService with methods for account creation and email lookup to support checkout registration. - Implemented public contact form functionality in SupportController, allowing unauthenticated users to submit inquiries. - Added rate limiting to the public contact form to prevent spam submissions. - Updated CatalogController and CheckoutController to allow public access for browsing and cart validation without authentication.
157 lines
5.3 KiB
TypeScript
157 lines
5.3 KiB
TypeScript
/**
|
|
* Checkout Domain - Schemas
|
|
*
|
|
* Zod validation schemas for unified checkout flow.
|
|
* Supports both authenticated and guest checkout.
|
|
*/
|
|
|
|
import { z } from "zod";
|
|
import {
|
|
emailSchema,
|
|
passwordSchema,
|
|
nameSchema,
|
|
phoneSchema,
|
|
genderEnum,
|
|
} from "../common/schema.js";
|
|
import { addressFormSchema } from "../customer/schema.js";
|
|
|
|
// ============================================================================
|
|
// ISO Date Schema
|
|
// ============================================================================
|
|
|
|
const isoDateOnlySchema = z
|
|
.string()
|
|
.regex(/^\d{4}-\d{2}-\d{2}$/, "Enter a valid date (YYYY-MM-DD)")
|
|
.refine(value => !Number.isNaN(Date.parse(value)), "Enter a valid date (YYYY-MM-DD)");
|
|
|
|
// ============================================================================
|
|
// Order Type Schema
|
|
// ============================================================================
|
|
|
|
export const orderTypeSchema = z.enum(["INTERNET", "SIM", "VPN"]);
|
|
|
|
// ============================================================================
|
|
// 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([]),
|
|
}),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Guest Info Schema
|
|
// ============================================================================
|
|
|
|
export const guestInfoSchema = z.object({
|
|
email: emailSchema,
|
|
firstName: nameSchema,
|
|
lastName: nameSchema,
|
|
phone: phoneSchema,
|
|
phoneCountryCode: z.string().min(1, "Phone country code is required"),
|
|
password: passwordSchema,
|
|
dateOfBirth: isoDateOnlySchema.optional(),
|
|
gender: genderEnum.optional(),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Checkout Register Request Schema
|
|
// ============================================================================
|
|
|
|
export const checkoutRegisterRequestSchema = z.object({
|
|
email: emailSchema,
|
|
firstName: nameSchema,
|
|
lastName: nameSchema,
|
|
phone: phoneSchema,
|
|
phoneCountryCode: z.string().min(1, "Phone country code is required"),
|
|
password: passwordSchema,
|
|
address: addressFormSchema,
|
|
dateOfBirth: isoDateOnlySchema.optional(),
|
|
gender: genderEnum.optional(),
|
|
acceptTerms: z.literal(true, { message: "You must accept the terms and conditions" }),
|
|
marketingConsent: z.boolean().optional(),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Checkout Register Response Schema
|
|
// ============================================================================
|
|
|
|
export const checkoutRegisterResponseSchema = z.object({
|
|
success: z.boolean(),
|
|
user: z.object({
|
|
id: z.string(),
|
|
email: z.string(),
|
|
firstname: z.string(),
|
|
lastname: z.string(),
|
|
}),
|
|
session: z.object({
|
|
expiresAt: z.string(),
|
|
refreshExpiresAt: z.string(),
|
|
}),
|
|
sfAccountNumber: z.string().optional(),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Checkout Step Schema
|
|
// ============================================================================
|
|
|
|
export const checkoutStepSchema = z.enum(["account", "address", "payment", "review"]);
|
|
|
|
// ============================================================================
|
|
// Checkout State Schema (for Zustand store)
|
|
// ============================================================================
|
|
|
|
export const checkoutStateSchema = z.object({
|
|
// Cart data
|
|
cartItem: cartItemSchema.nullable(),
|
|
|
|
// Guest info (pre-registration)
|
|
guestInfo: guestInfoSchema.partial().nullable(),
|
|
|
|
// Address
|
|
address: addressFormSchema.nullable(),
|
|
|
|
// Registration state
|
|
registrationComplete: z.boolean(),
|
|
userId: z.string().nullable(),
|
|
|
|
// Payment state
|
|
paymentMethodVerified: z.boolean(),
|
|
|
|
// Checkout step
|
|
currentStep: checkoutStepSchema,
|
|
});
|
|
|
|
// ============================================================================
|
|
// Inferred Types
|
|
// ============================================================================
|
|
|
|
export type OrderType = z.infer<typeof orderTypeSchema>;
|
|
export type PriceBreakdownItem = z.infer<typeof priceBreakdownItemSchema>;
|
|
export type CartItem = z.infer<typeof cartItemSchema>;
|
|
export type GuestInfo = z.infer<typeof guestInfoSchema>;
|
|
export type CheckoutRegisterRequest = z.infer<typeof checkoutRegisterRequestSchema>;
|
|
export type CheckoutRegisterResponse = z.infer<typeof checkoutRegisterResponseSchema>;
|
|
export type CheckoutStep = z.infer<typeof checkoutStepSchema>;
|
|
export type CheckoutState = z.infer<typeof checkoutStateSchema>;
|