feat(chat): render role-bound payment guidance
Docker Image / Build and Push Docker Image (push) Successful in 5m2s

This commit is contained in:
Codex
2026-07-27 18:14:04 +08:00
parent 019caae598
commit 8c0d1ad3ce
49 changed files with 882 additions and 81 deletions
+27 -3
View File
@@ -8,7 +8,11 @@ import { usePaymentMethodSelection } from "@/app/_hooks/use-payment-method-selec
import { usePaymentPlanAnalytics } from "@/app/_hooks/use-payment-plan-analytics";
import type { PayChannel } from "@/data/schemas/payment";
import type { SubscriptionReturnTo } from "@/lib/navigation/subscription_exit";
import { DEFAULT_CHARACTER_SLUG } from "@/data/constants/character";
import {
DEFAULT_CHARACTER,
DEFAULT_CHARACTER_SLUG,
getCharacterBySlug,
} from "@/data/constants/character";
import {
behaviorAnalytics,
getDefaultPaymentAnalyticsContext,
@@ -75,6 +79,8 @@ export function SubscriptionScreen({
null,
);
const userState = useUserState();
const sourceCharacter =
getCharacterBySlug(sourceCharacterSlug) ?? DEFAULT_CHARACTER;
const hasHydrated = useHasHydrated();
const countryCode = userState.currentUser?.countryCode;
const paymentMethodConfig = getPaymentMethodConfig({
@@ -262,6 +268,22 @@ export function SubscriptionScreen({
</p>
) : null}
{chatActionId ? (
<section
className={styles.characterSupportBanner}
aria-label={`Support ${sourceCharacter.displayName}`}
data-payment-guidance-character={sourceCharacter.id}
>
<h2>Keep talking with {sourceCharacter.shortName}</h2>
<p>
Without the required VIP access or credits, paid chat and locked
content cannot continue. Choosing an option here is a voluntary
way to support{" "}
{sourceCharacter.shortName}; it is never a test of your feelings.
</p>
</section>
) : null}
{firstRechargeOffer ? (
<section
className={styles.firstRechargeBanner}
@@ -289,11 +311,13 @@ export function SubscriptionScreen({
{payment.commercialOffer && !firstRechargeOffer ? (
<section
className={styles.firstRechargeBanner}
aria-label="Elio private offer"
aria-label={`${sourceCharacter.shortName} private offer`}
>
<span className={styles.firstRechargeBadge}>Private offer</span>
<div className={styles.firstRechargeCopy}>
<h2 className={styles.firstRechargeTitle}>Elio got this price for you</h2>
<h2 className={styles.firstRechargeTitle}>
{sourceCharacter.shortName} got this price for you
</h2>
<p className={styles.firstRechargeSubtitle}>
{payment.commercialOffer.message ||
`Your ${payment.commercialOffer.discountPercent}% discount is already applied below.`}