feat(tip): support dynamic gift products
This commit is contained in:
@@ -13,39 +13,72 @@ describe("PaymentApi", () => {
|
||||
httpClientMock.mockReset();
|
||||
});
|
||||
|
||||
it("loads public coffee tip plans from the dedicated endpoint", async () => {
|
||||
it("loads the complete public gift catalog for a character", async () => {
|
||||
httpClientMock.mockResolvedValue({
|
||||
success: true,
|
||||
data: {
|
||||
characterId: "elio",
|
||||
categories: [
|
||||
{
|
||||
category: "coffee",
|
||||
name: "Coffee",
|
||||
productCount: 1,
|
||||
imageUrl: null,
|
||||
},
|
||||
],
|
||||
plans: [
|
||||
{
|
||||
planId: "tip_coffee_usd_19_99",
|
||||
planName: "Large Coffee",
|
||||
orderType: "tip",
|
||||
tipType: "coffee_large",
|
||||
category: "coffee",
|
||||
characterId: "elio",
|
||||
description: "Buy Elio a large coffee",
|
||||
imageUrl: null,
|
||||
amountCents: 1999,
|
||||
currency: "USD",
|
||||
autoRenew: false,
|
||||
isFirstRechargeOffer: false,
|
||||
firstRechargeDiscountPercent: 0,
|
||||
promotionType: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const response = await new PaymentApi().getTipPlans();
|
||||
const response = await new PaymentApi().getGiftProducts("elio");
|
||||
|
||||
expect(httpClientMock).toHaveBeenCalledWith("/api/payment/tip-plans");
|
||||
expect(response).toEqual({
|
||||
plans: [
|
||||
{
|
||||
planId: "tip_coffee_usd_19_99",
|
||||
planName: "Large Coffee",
|
||||
amountCents: 1999,
|
||||
currency: "USD",
|
||||
},
|
||||
],
|
||||
expect(httpClientMock).toHaveBeenCalledWith(
|
||||
"/api/payment/gift-products",
|
||||
{ query: { characterId: "elio" } },
|
||||
);
|
||||
expect(response.categories[0]?.category).toBe("coffee");
|
||||
expect(response.plans[0]?.planId).toBe("tip_coffee_usd_19_99");
|
||||
});
|
||||
|
||||
it("posts the paid order id when loading the Tip message", async () => {
|
||||
httpClientMock.mockResolvedValue({
|
||||
success: true,
|
||||
data: {
|
||||
orderId: "pay_xxx",
|
||||
characterId: "elio",
|
||||
planId: "tip_coffee_usd_19_99",
|
||||
productName: "Large Coffee",
|
||||
tipCount: 1,
|
||||
poolIndex: 7,
|
||||
message: "Thank you for the thoughtful gift.",
|
||||
},
|
||||
});
|
||||
|
||||
const response = await new PaymentApi().getTipMessage({
|
||||
orderId: "pay_xxx",
|
||||
});
|
||||
|
||||
expect(httpClientMock).toHaveBeenCalledWith("/api/payment/tip-message", {
|
||||
method: "POST",
|
||||
body: { orderId: "pay_xxx" },
|
||||
});
|
||||
expect(response.message).toBe("Thank you for the thoughtful gift.");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"paymentCreateOrder": { "method": "post", "path": "/api/payment/create-order" },
|
||||
"paymentOrderStatus": { "method": "get", "path": "/api/payment/order-status" },
|
||||
"paymentPlans": { "method": "get", "path": "/api/payment/plans" },
|
||||
"paymentTipPlans": { "method": "get", "path": "/api/payment/tip-plans" },
|
||||
"paymentGiftProducts": { "method": "get", "path": "/api/payment/gift-products" },
|
||||
"paymentTipMessage": { "method": "post", "path": "/api/payment/tip-message" },
|
||||
"chatSend": { "method": "post", "path": "/api/chat/send" },
|
||||
"chatHistory": { "method": "get", "path": "/api/chat/history" },
|
||||
"chatUnlockPrivate": { "method": "post", "path": "/api/chat/unlock-private" },
|
||||
|
||||
@@ -60,8 +60,11 @@ export class ApiPath {
|
||||
/** 获取商品套餐列表 */
|
||||
static readonly paymentPlans = apiContract.paymentPlans.path;
|
||||
|
||||
/** 获取咖啡打赏套餐列表 */
|
||||
static readonly paymentTipPlans = apiContract.paymentTipPlans.path;
|
||||
/** 获取角色的完整礼物目录 */
|
||||
static readonly paymentGiftProducts = apiContract.paymentGiftProducts.path;
|
||||
|
||||
/** 获取已支付礼物订单的角色感谢文案 */
|
||||
static readonly paymentTipMessage = apiContract.paymentTipMessage.path;
|
||||
|
||||
// ============ 聊天相关 ============
|
||||
/** 发送消息 */
|
||||
|
||||
@@ -7,12 +7,15 @@ import {
|
||||
CreatePaymentOrderRequest,
|
||||
CreatePaymentOrderResponse,
|
||||
CreatePaymentOrderResponseSchema,
|
||||
GiftProductsResponse,
|
||||
GiftProductsResponseSchema,
|
||||
PaymentOrderStatusResponse,
|
||||
PaymentOrderStatusResponseSchema,
|
||||
PaymentPlansResponse,
|
||||
PaymentPlansResponseSchema,
|
||||
TipPaymentPlansResponse,
|
||||
TipPaymentPlansResponseSchema,
|
||||
TipMessageRequest,
|
||||
TipMessageResponse,
|
||||
TipMessageResponseSchema,
|
||||
} from "@/data/schemas/payment";
|
||||
|
||||
import { ApiPath } from "./api_path";
|
||||
@@ -28,10 +31,13 @@ export class PaymentApi {
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取咖啡打赏套餐列表。 */
|
||||
async getTipPlans(): Promise<TipPaymentPlansResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.paymentTipPlans);
|
||||
return TipPaymentPlansResponseSchema.parse(
|
||||
/** 一次获取当前角色的完整礼物目录。 */
|
||||
async getGiftProducts(characterId: string): Promise<GiftProductsResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.paymentGiftProducts,
|
||||
{ query: { characterId } },
|
||||
);
|
||||
return GiftProductsResponseSchema.parse(
|
||||
unwrap(env) as Record<string, unknown>,
|
||||
);
|
||||
}
|
||||
@@ -64,6 +70,20 @@ export class PaymentApi {
|
||||
unwrap(env) as Record<string, unknown>,
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取已支付礼物订单的稳定感谢文案。 */
|
||||
async getTipMessage(body: TipMessageRequest): Promise<TipMessageResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.paymentTipMessage,
|
||||
{
|
||||
method: "POST",
|
||||
body,
|
||||
},
|
||||
);
|
||||
return TipMessageResponseSchema.parse(
|
||||
unwrap(env) as Record<string, unknown>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user