Real World Example

Checkout Address Form Like Amazon

Amazon, Flipkart and Swiggy all validate the delivery address on the server (pincode serviceability, phone format) and show field errors without losing what you typed. With Server Actions:

// app/checkout/actions.ts
'use server';

import { z } from 'zod';
import { redirect } from 'next/navigation';
import { auth } from '@/auth';
import { isServiceable } from '@/lib/delivery';
import { prisma } from '@/lib/prisma';

const Address = z.object({
  fullName: z.string().trim().min(2),
  phone: z.string().regex(/^[6-9]\d{9}$/, 'Enter a 10-digit Indian mobile number'),
  pincode: z.string().regex(/^\d{6}$/, 'Pincode must be 6 digits'),
  line1: z.string().trim().min(5),
  city: z.string().trim().min(2),
});

export type AddressState = { errors?: Partial<Record<keyof z.infer<typeof Address>, string[]>>; values?: Record<string, string> };

export async function saveAddress(prev: AddressState, formData: FormData): Promise<AddressState> {
  const session = await auth();
  if (!session?.user) redirect('/login?next=/checkout');

  const values = Object.fromEntries(formData) as Record<string, string>;
  const parsed = Address.safeParse(values);
  if (!parsed.success) return { errors: parsed.error.flatten().fieldErrors, values };
  if (!(await isServiceable(parsed.data.pincode))) {
    return { errors: { pincode: ['We do not deliver to this pincode yet'] }, values };
  }

  await prisma.address.create({ data: { ...parsed.data, userId: session.user.id } });
  redirect('/checkout/payment');
}

Checking the Fields

Example

The two regular expressions from the schema, tested on their own:

const phone = /^[6-9]\d{9}$/;
const pincode = /^\d{6}$/;

for (const p of ['9876543210', '1234567890', '98765 43210', '987654321']) {
  console.log('phone  ', p.padEnd(12), phone.test(p));
}
for (const p of ['560001', '5600', '56OO01']) {
  console.log('pincode', p.padEnd(12), pincode.test(p));
}

Output

phone   9876543210   true
phone   1234567890   false
phone   98765 43210  false
phone   987654321    false
pincode 560001       true
pincode 5600         false
pincode 56OO01       false