Stage M5 and Stage M6
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { anyIdSchema } from './common';
|
||||
import { offsetPageQuerySchema } from './pagination';
|
||||
|
||||
/**
|
||||
* Cart and checkout input.
|
||||
*
|
||||
* A cart line carries a variant and a quantity and nothing else. There is
|
||||
* deliberately no price field anywhere in this file: prices are the API's to
|
||||
* compute, and accepting one from the client would make every total a
|
||||
* negotiation.
|
||||
*/
|
||||
|
||||
/** One line cannot exceed this, regardless of stock — it is a shop, not a wholesaler. */
|
||||
export const MAX_LINE_QUANTITY = 20;
|
||||
|
||||
export const addCartLineSchema = z.object({
|
||||
variantId: anyIdSchema,
|
||||
quantity: z.coerce.number().int().min(1).max(MAX_LINE_QUANTITY).default(1),
|
||||
});
|
||||
|
||||
export const updateCartLineSchema = z.object({
|
||||
/** Zero removes the line, which is what a quantity stepper reaching 0 means. */
|
||||
quantity: z.coerce.number().int().min(0).max(MAX_LINE_QUANTITY),
|
||||
});
|
||||
|
||||
/** Vietnamese addresses: ward and district are optional because rural
|
||||
* addresses frequently have neither, and rejecting those loses real orders. */
|
||||
export const shippingAddressSchema = z.object({
|
||||
fullName: z.string().trim().min(1).max(160),
|
||||
phone: z
|
||||
.string()
|
||||
.trim()
|
||||
.regex(/^(?:\+84|0)\d{8,10}$/, 'Enter a Vietnamese phone number'),
|
||||
line1: z.string().trim().min(1).max(255),
|
||||
line2: z.string().trim().max(255).nullish(),
|
||||
ward: z.string().trim().max(120).nullish(),
|
||||
district: z.string().trim().max(120).nullish(),
|
||||
province: z.string().trim().min(1).max(120),
|
||||
countryCode: z.string().trim().length(2).default('VN'),
|
||||
postalCode: z.string().trim().max(20).nullish(),
|
||||
});
|
||||
|
||||
export const placeOrderSchema = z.object({
|
||||
email: z.string().trim().toLowerCase().email().max(255),
|
||||
shippingAddress: shippingAddressSchema,
|
||||
customerNote: z.string().trim().max(1000).nullish(),
|
||||
});
|
||||
|
||||
export const orderListQuerySchema = offsetPageQuerySchema.extend({
|
||||
q: z.string().trim().max(120).optional(),
|
||||
status: z.enum(['PENDING', 'CONFIRMED', 'FULFILLED', 'COMPLETED', 'CANCELLED']).optional(),
|
||||
});
|
||||
|
||||
export const updateOrderStatusSchema = z.object({
|
||||
status: z.enum(['PENDING', 'CONFIRMED', 'FULFILLED', 'COMPLETED', 'CANCELLED']),
|
||||
/** Required when cancelling: "why" is the whole value of the audit entry. */
|
||||
reason: z.string().trim().max(500).nullish(),
|
||||
});
|
||||
|
||||
export type AddCartLineInput = z.output<typeof addCartLineSchema>;
|
||||
export type UpdateCartLineInput = z.output<typeof updateCartLineSchema>;
|
||||
export type ShippingAddressInput = z.output<typeof shippingAddressSchema>;
|
||||
export type PlaceOrderInput = z.output<typeof placeOrderSchema>;
|
||||
export type OrderListQuery = z.output<typeof orderListQuerySchema>;
|
||||
export type UpdateOrderStatusInput = z.output<typeof updateOrderStatusSchema>;
|
||||
@@ -17,3 +17,4 @@ export * from './auth';
|
||||
export * from './catalog';
|
||||
export * from './users';
|
||||
export * from './catalog-admin';
|
||||
export * from './commerce';
|
||||
|
||||
Reference in New Issue
Block a user