feat: add customer cart with expiry, shipping addresses with USPS validation, and multi-item PayPal checkout
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
export interface CartItem {
|
||||
item_id: number;
|
||||
name: string;
|
||||
price_cents: number;
|
||||
status: string;
|
||||
added_at: string;
|
||||
expires_at: string;
|
||||
images: { id: number; image_path: string }[];
|
||||
}
|
||||
|
||||
export interface ShippingAddress {
|
||||
id: number;
|
||||
full_name: string;
|
||||
address_line1: string;
|
||||
address_line2: string | null;
|
||||
city: string;
|
||||
state: string;
|
||||
postal_code: string;
|
||||
country: string;
|
||||
is_default: boolean;
|
||||
usps_validated: boolean;
|
||||
}
|
||||
|
||||
async function handle<T>(res: Response): Promise<T> {
|
||||
if (!res.ok) {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
throw new Error(data.error || 'Request failed');
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export function fetchCart(): Promise<{ items: CartItem[] }> {
|
||||
return fetch('/api/cart').then(res => handle(res));
|
||||
}
|
||||
|
||||
export function addToCart(itemId: number): Promise<{ itemId: number; expiresAt: string }> {
|
||||
return fetch(`/api/cart/items/${itemId}`, { method: 'POST' }).then(res => handle(res));
|
||||
}
|
||||
|
||||
export function removeFromCart(itemId: number): Promise<void> {
|
||||
return fetch(`/api/cart/items/${itemId}`, { method: 'DELETE' }).then(() => undefined);
|
||||
}
|
||||
|
||||
export function fetchAddresses(): Promise<ShippingAddress[]> {
|
||||
return fetch('/api/customers/me/addresses').then(res => handle(res));
|
||||
}
|
||||
|
||||
export interface AddressInput {
|
||||
fullName: string;
|
||||
addressLine1: string;
|
||||
addressLine2?: string;
|
||||
city: string;
|
||||
state: string;
|
||||
postalCode: string;
|
||||
country?: string;
|
||||
isDefault?: boolean;
|
||||
}
|
||||
|
||||
export function createAddress(input: AddressInput): Promise<{ address: ShippingAddress; uspsCheck: { validated: boolean; deliverable: boolean | null; reason?: string }; uspsConfigured: boolean }> {
|
||||
return fetch('/api/customers/me/addresses', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(input)
|
||||
}).then(res => handle(res));
|
||||
}
|
||||
|
||||
export function deleteAddress(id: number): Promise<void> {
|
||||
return fetch(`/api/customers/me/addresses/${id}`, { method: 'DELETE' }).then(() => undefined);
|
||||
}
|
||||
|
||||
export function setDefaultAddress(id: number): Promise<ShippingAddress> {
|
||||
return fetch(`/api/customers/me/addresses/${id}/set-default`, { method: 'POST' }).then(res => handle(res));
|
||||
}
|
||||
|
||||
export function createCartPaypalOrder(shippingAddressId: number): Promise<{ orderID: string }> {
|
||||
return fetch('/api/checkout/cart/paypal/create', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ shippingAddressId })
|
||||
}).then(res => handle(res));
|
||||
}
|
||||
|
||||
export function captureCartPaypalOrder(orderID: string): Promise<void> {
|
||||
return fetch('/api/checkout/cart/paypal/capture', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ orderID })
|
||||
}).then(res => handle(res));
|
||||
}
|
||||
|
||||
export function demoCartPurchase(shippingAddressId: number): Promise<void> {
|
||||
return fetch('/api/checkout/cart/demo/purchase', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ shippingAddressId })
|
||||
}).then(res => handle(res));
|
||||
}
|
||||
Reference in New Issue
Block a user