import { z } from 'zod'; export const shopLocationSchema = z.object({ lat: z.number().optional(), lng: z.number().optional(), address: z.string().optional(), market: z.string().optional(), city: z.string().optional(), state: z.string().optional(), pickupHours: z.string().optional(), }); export const shopOnlineOrderStatusEnum = z.enum([ 'pending_payment', 'awaiting_manual_payment', 'paid', 'reserved', 'ready_for_pickup', 'collected', 'cancelled', 'failed', 'expired', ]); export const storefrontPublicProductSchema = z.object({ id: z.string().uuid(), name: z.string(), sellingPrice: z.number().nullable(), iconPhotoUrl: z.string().nullable(), category: z.string().nullable(), unit: z.string().nullable(), currentStock: z.number(), }); export const storefrontPublicShopSchema = z.object({ slug: z.string(), shopName: z.string(), currency: z.string(), acceptsPaystack: z.boolean(), acceptsDirectTransfer: z.boolean(), paymentInstructions: z.string().nullable(), location: shopLocationSchema.nullable(), }); export const storefrontGetShopResponseSchema = z.object({ shop: storefrontPublicShopSchema, products: z.array(storefrontPublicProductSchema), }); export const storefrontCheckoutLineSchema = z.object({ productId: z.string().uuid(), quantity: z.number().positive(), }); export const storefrontCheckoutBodySchema = z.object({ items: z.array(storefrontCheckoutLineSchema).min(1), buyerEmail: z.string().email(), buyerPhone: z.string().min(1).max(20), buyerName: z.string().max(200).optional(), paymentMethod: z.enum(['paystack', 'direct_transfer']).default('paystack'), paymentPath: z.enum(['pay_now', 'reserve']).default('pay_now'), }); export const storefrontCheckoutResponseSchema = z.object({ checkoutType: z.enum(['paystack_redirect', 'manual_transfer', 'reserved']), paymentUrl: z.string().url().optional(), reference: z.string().optional(), orderId: z.string().uuid(), instructions: z.string().optional(), trackingUrl: z.string().url(), }); export const storefrontVerifyPaymentBodySchema = z.object({ reference: z.string().min(10), }); export const storefrontVerifyPaymentResponseSchema = z.object({ verified: z.boolean(), orderId: z.string().uuid().optional(), }); export const storefrontOrderTimelineStepSchema = z.object({ key: z.string(), label: z.string(), completed: z.boolean(), current: z.boolean(), }); export const storefrontPublicOrderLineSchema = z.object({ productName: z.string(), quantity: z.number(), unitPrice: z.number(), lineTotal: z.number(), }); export const storefrontPublicOrderSchema = z.object({ id: z.string().uuid(), shopName: z.string(), status: shopOnlineOrderStatusEnum, currency: z.string(), totalAmount: z.number(), items: z.array(storefrontPublicOrderLineSchema), pickupLocation: shopLocationSchema.nullable(), timeline: z.array(storefrontOrderTimelineStepSchema), createdAt: z.coerce.date(), updatedAt: z.coerce.date(), }); export const storefrontLocationSchema = z.object({ market: z.string().optional(), city: z.string().optional(), }); export const storefrontFeaturedShopSchema = z.object({ slug: z.string(), shopName: z.string(), location: storefrontLocationSchema.nullable(), productCount: z.number().int().nonnegative(), }); export const storefrontMarketQuerySchema = z.object({ city: z.string().optional(), market: z.string().optional(), }); export const storefrontMarketResponseSchema = z.object({ featuredShops: z.array(storefrontFeaturedShopSchema), categories: z.array(z.string()), city: z.string().optional(), }); export const storefrontDirectoryQuerySchema = z.object({ city: z.string().optional(), market: z.string().optional(), category: z.string().optional(), limit: z.coerce.number().int().positive().max(100).default(20), offset: z.coerce.number().int().nonnegative().default(0), }); export const storefrontDirectoryShopSchema = z.object({ slug: z.string(), shopName: z.string(), location: storefrontLocationSchema.nullable(), categoryTags: z.array(z.string()), productCount: z.number().int().nonnegative(), }); export const storefrontListShopsResponseSchema = z.object({ shops: z.array(storefrontDirectoryShopSchema), total: z.number().int().nonnegative(), limit: z.number().int().positive(), offset: z.number().int().nonnegative(), }); export const storefrontMarketSearchQuerySchema = z.object({ q: z.string().min(1), city: z.string().optional(), market: z.string().optional(), category: z.string().optional(), inStockOnly: z .union([z.boolean(), z.enum(['true', 'false', '1', '0'])]) .transform((value) => { if (typeof value === 'boolean') return value; return value === 'true' || value === '1'; }) .default(true), }); export const storefrontSearchProductSchema = z.object({ id: z.string().uuid(), name: z.string(), sellingPrice: z.number().nullable(), currentStock: z.number(), unit: z.string().nullable(), }); export const storefrontSearchShopGroupSchema = z.object({ slug: z.string(), shopName: z.string(), location: storefrontLocationSchema.nullable(), products: z.array(storefrontSearchProductSchema), }); export const storefrontMarketSearchResponseSchema = z.object({ results: z.array(storefrontSearchShopGroupSchema), });