From 38ae06fe04d485a73211a1a94e230f57e78f8edc Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 28 Jul 2026 12:09:33 +0800 Subject: [PATCH] feat(payment): accept support character guidance scene --- src/app/chat/components/payment-guidance-card.tsx | 15 ++++++++++++++- .../chat/__tests__/payment_guidance.test.ts | 10 ++++++++++ .../schemas/chat/response/chat_send_response.ts | 1 + src/stores/chat/__tests__/chat-helpers.test.ts | 4 ++-- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/app/chat/components/payment-guidance-card.tsx b/src/app/chat/components/payment-guidance-card.tsx index 5f613336..06501ca5 100644 --- a/src/app/chat/components/payment-guidance-card.tsx +++ b/src/app/chat/components/payment-guidance-card.tsx @@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from "react"; import { ArrowRight, CircleDollarSign, X } from "lucide-react"; import type { PaymentGuidance } from "@/data/schemas/chat"; +import type { PaymentAnalyticsTriggerReason } from "@/lib/analytics/payment_analytics_context"; import { recordChatActionEventById } from "@/lib/chat/chat_action_events"; import { useActiveCharacter } from "@/providers/character-provider"; import { useAppNavigator } from "@/router/use-app-navigator"; @@ -15,6 +16,18 @@ export interface PaymentGuidanceCardProps { guidance: PaymentGuidance; } +function triggerReasonForGuidance( + scene: PaymentGuidance["scene"], +): PaymentAnalyticsTriggerReason { + if (scene === "supportCharacter" || scene === "vip" || scene === "purchaseOptions") { + return "vip_cta"; + } + if (scene === "privateMessageLocked" || scene === "historyLocked") { + return "private_topic_limit"; + } + return "insufficient_credits"; +} + export function PaymentGuidanceCard({ guidance }: PaymentGuidanceCardProps) { const character = useActiveCharacter(); const navigator = useAppNavigator(); @@ -91,7 +104,7 @@ export function PaymentGuidanceCard({ guidance }: PaymentGuidanceCardProps) { chatActionId: guidance.guidanceId, analytics: { entryPoint: "chat_input", - triggerReason: "insufficient_credits", + triggerReason: triggerReasonForGuidance(guidance.scene), }, }); }} diff --git a/src/data/schemas/chat/__tests__/payment_guidance.test.ts b/src/data/schemas/chat/__tests__/payment_guidance.test.ts index dd1bdfb3..881516cf 100644 --- a/src/data/schemas/chat/__tests__/payment_guidance.test.ts +++ b/src/data/schemas/chat/__tests__/payment_guidance.test.ts @@ -27,6 +27,16 @@ describe("payment guidance wire contract", () => { expect(PaymentGuidanceSchema.parse(guidance)).toEqual(guidance); }); + it("accepts the supportCharacter guidance scene", () => { + expect( + PaymentGuidanceSchema.parse({ + ...guidance, + scene: "supportCharacter", + ruleId: "payment_guidance_supportCharacter", + }).scene, + ).toBe("supportCharacter"); + }); + it("keeps all backend lock facts instead of dropping hint and CTA", () => { expect( ChatLockDetailSchema.parse({ diff --git a/src/data/schemas/chat/response/chat_send_response.ts b/src/data/schemas/chat/response/chat_send_response.ts index 603d828d..4339bd62 100644 --- a/src/data/schemas/chat/response/chat_send_response.ts +++ b/src/data/schemas/chat/response/chat_send_response.ts @@ -24,6 +24,7 @@ export const PaymentGuidanceSceneSchema = z.enum([ "privateZoneLocked", "unknownLock", "whyPay", + "supportCharacter", "leavingAfterCredits", "paymentIssue", "externalRisk", diff --git a/src/stores/chat/__tests__/chat-helpers.test.ts b/src/stores/chat/__tests__/chat-helpers.test.ts index 694074f6..4ccbbd53 100644 --- a/src/stores/chat/__tests__/chat-helpers.test.ts +++ b/src/stores/chat/__tests__/chat-helpers.test.ts @@ -116,7 +116,7 @@ describe("sendResponseToUiMessage", () => { copy: "Buy me a coffee?", ctaLabel: "View gifts", target: "giftCatalog", - ruleId: "coffee_support_question", + ruleId: "coffee_after_thanks", }, }), ); @@ -127,7 +127,7 @@ describe("sendResponseToUiMessage", () => { copy: "Buy me a coffee?", ctaLabel: "View gifts", target: "giftCatalog", - ruleId: "coffee_support_question", + ruleId: "coffee_after_thanks", }); });