feat(mall): live group-buying page with open or join intent
The group-buying page lists active activities, the group price against the catalog price, and each open group with its paid-member count and expiry. A shopper opens a group or picks one to join; either way the activity SKU goes into the cart and the intent is carried to checkout, which submits it and hides the coupon picker for that order. Payment and order detail show the snapshotted group price. The group-buying fixtures leave the page; the fixed-data adapter still serves the domain as the rollback path.
This commit is contained in:
@@ -17,6 +17,10 @@ import type {
|
||||
FlashSaleItemInput,
|
||||
FlashSaleSession,
|
||||
FlashSaleSessionInput,
|
||||
GroupBuyIntent,
|
||||
GroupBuyingActivity,
|
||||
GroupBuyingActivityInput,
|
||||
GroupBuyingActivityView,
|
||||
HomeContent,
|
||||
IntegralOrder,
|
||||
IntegralProduct,
|
||||
@@ -182,6 +186,8 @@ export interface ApiClient {
|
||||
currency: string,
|
||||
/** At most one owned coupon per generated shop order. */
|
||||
couponByShop?: Record<string, string>,
|
||||
/** Optional group-buying intent for one activity SKU at quantity 1. */
|
||||
groupBuy?: GroupBuyIntent,
|
||||
): Promise<Order[]>;
|
||||
listMyOrders(page?: number): Promise<Paged<Order>>;
|
||||
getOrder(id: string): Promise<Order>;
|
||||
@@ -216,6 +222,8 @@ export interface ApiClient {
|
||||
redeemPoints(body: RedeemPointsBody): Promise<IntegralOrder>;
|
||||
/** Public: active flash-sale sessions with their purchasable items. */
|
||||
listFlashSales(): Promise<PublicFlashSaleSession[]>;
|
||||
/** Public: active group-buying activities with their open groups. */
|
||||
listGroupBuyingActivities(): Promise<GroupBuyingActivityView[]>;
|
||||
shop: {
|
||||
getMyShop(): Promise<Shop>;
|
||||
listMyProducts(q?: ShopProductQuery): Promise<Paged<Product>>;
|
||||
@@ -248,6 +256,13 @@ export interface ApiClient {
|
||||
addFlashSaleItem(sessionId: string, body: FlashSaleItemInput): Promise<FlashSaleItem>;
|
||||
updateFlashSaleItem(id: string, body: FlashSaleItemInput): Promise<FlashSaleItem>;
|
||||
deleteFlashSaleItem(id: string): Promise<void>;
|
||||
listGroupBuyingActivities(): Promise<GroupBuyingActivityView[]>;
|
||||
createGroupBuyingActivity(body: GroupBuyingActivityInput): Promise<GroupBuyingActivity>;
|
||||
updateGroupBuyingActivity(
|
||||
id: string,
|
||||
body: GroupBuyingActivityInput,
|
||||
): Promise<GroupBuyingActivity>;
|
||||
deleteGroupBuyingActivity(id: string): Promise<void>;
|
||||
};
|
||||
admin: {
|
||||
listUsers(page?: number): Promise<Paged<User>>;
|
||||
@@ -289,11 +304,12 @@ export function createApi(opts: ApiClientOptions): ApiClient {
|
||||
addCartItem: (skuId, qty) => r("POST", "/cart/items", { sku_id: skuId, qty }),
|
||||
updateCartItem: (skuId, qty) => r("PUT", `/cart/items/${skuId}`, { qty }),
|
||||
removeCartItem: (skuId) => r("DELETE", `/cart/items/${skuId}`),
|
||||
checkout: (shippingAddress, currency, couponByShop = {}) =>
|
||||
checkout: (shippingAddress, currency, couponByShop = {}, groupBuy) =>
|
||||
r("POST", "/orders/checkout", {
|
||||
shipping_address: shippingAddress,
|
||||
currency,
|
||||
coupon_by_shop: couponByShop,
|
||||
group_buy: groupBuy ?? null,
|
||||
}),
|
||||
listMyOrders: (page = 1) => r("GET", "/orders", undefined, { page }),
|
||||
getOrder: (id) => r("GET", `/orders/${id}`),
|
||||
@@ -319,6 +335,7 @@ export function createApi(opts: ApiClientOptions): ApiClient {
|
||||
listMyRedemptions: () => r("GET", "/points/redemptions"),
|
||||
redeemPoints: (body) => r("POST", "/points/redemptions", body),
|
||||
listFlashSales: () => r("GET", "/flash-sales"),
|
||||
listGroupBuyingActivities: () => r("GET", "/group-buying/activities"),
|
||||
shop: {
|
||||
getMyShop: () => r("GET", "/shop/profile"),
|
||||
listMyProducts: (q = {}) => r("GET", "/shop/products", undefined, { ...q }),
|
||||
@@ -352,6 +369,11 @@ export function createApi(opts: ApiClientOptions): ApiClient {
|
||||
r("POST", `/shop/flash-sales/${sessionId}/items`, body),
|
||||
updateFlashSaleItem: (id, body) => r("PUT", `/shop/flash-sale-items/${id}`, body),
|
||||
deleteFlashSaleItem: (id) => r("DELETE", `/shop/flash-sale-items/${id}`),
|
||||
listGroupBuyingActivities: () => r("GET", "/shop/group-buying-activities"),
|
||||
createGroupBuyingActivity: (body) => r("POST", "/shop/group-buying-activities", body),
|
||||
updateGroupBuyingActivity: (id, body) =>
|
||||
r("PUT", `/shop/group-buying-activities/${id}`, body),
|
||||
deleteGroupBuyingActivity: (id) => r("DELETE", `/shop/group-buying-activities/${id}`),
|
||||
},
|
||||
admin: {
|
||||
listUsers: (page = 1) => r("GET", "/admin/users", undefined, { page }),
|
||||
|
||||
Reference in New Issue
Block a user