feat(chat): render role-bound payment guidance
Docker Image / Build and Push Docker Image (push) Successful in 5m2s
Docker Image / Build and Push Docker Image (push) Successful in 5m2s
This commit is contained in:
@@ -5,6 +5,9 @@ import { useEffect, useRef } from "react";
|
||||
import { behaviorAnalytics } from "@/lib/analytics";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import type { ChatUpgradeReason } from "@/stores/chat/chat-state";
|
||||
import type { PaymentGuidance } from "@/data/schemas/chat";
|
||||
import { recordChatActionEventById } from "@/lib/chat/chat_action_events";
|
||||
import { useActiveCharacter } from "@/providers/character-provider";
|
||||
import { useUserSelector } from "@/stores/user/user-context";
|
||||
|
||||
import {
|
||||
@@ -17,10 +20,14 @@ import {
|
||||
export interface UseChatMessageLimitBannerInput {
|
||||
upgradePromptVisible: boolean;
|
||||
upgradeReason: ChatUpgradeReason | null;
|
||||
paymentGuidance: PaymentGuidance | null;
|
||||
}
|
||||
|
||||
export interface ChatMessageLimitBannerView
|
||||
extends InsufficientCreditsMessageLimitView {
|
||||
export interface ChatMessageLimitBannerView {
|
||||
title: string;
|
||||
description: string;
|
||||
ctaLabel: string | null;
|
||||
guidance: PaymentGuidance | null;
|
||||
visible: boolean;
|
||||
unlock: () => void;
|
||||
}
|
||||
@@ -28,10 +35,19 @@ export interface ChatMessageLimitBannerView
|
||||
export function useChatMessageLimitBanner({
|
||||
upgradePromptVisible,
|
||||
upgradeReason,
|
||||
paymentGuidance,
|
||||
}: UseChatMessageLimitBannerInput): ChatMessageLimitBannerView {
|
||||
const navigator = useAppNavigator();
|
||||
const character = useActiveCharacter();
|
||||
const isVip = useUserSelector((state) => state.context.isVip);
|
||||
const view = getInsufficientCreditsMessageLimitView();
|
||||
const fallbackView = getInsufficientCreditsMessageLimitView();
|
||||
const guidance =
|
||||
paymentGuidance?.characterId === character.id ? paymentGuidance : null;
|
||||
const view: InsufficientCreditsMessageLimitView = {
|
||||
title: guidance?.title ?? fallbackView.title,
|
||||
description: guidance?.copy ?? fallbackView.description,
|
||||
ctaLabel: guidance?.ctaLabel ?? fallbackView.ctaLabel,
|
||||
};
|
||||
const visible = shouldShowMessageLimitBanner({
|
||||
upgradePromptVisible,
|
||||
upgradeReason,
|
||||
@@ -52,12 +68,31 @@ export function useChatMessageLimitBanner({
|
||||
},
|
||||
{ isVip },
|
||||
);
|
||||
}, [isVip, visible]);
|
||||
if (guidance) {
|
||||
void recordChatActionEventById(
|
||||
guidance.guidanceId,
|
||||
character.id,
|
||||
"viewed",
|
||||
).catch(() => undefined);
|
||||
}
|
||||
}, [character.id, guidance, isVip, visible]);
|
||||
|
||||
function unlock(): void {
|
||||
if (guidance?.mode !== "guide" && guidance !== null) return;
|
||||
if (guidance) {
|
||||
void recordChatActionEventById(
|
||||
guidance.guidanceId,
|
||||
character.id,
|
||||
"opened",
|
||||
).catch(() => undefined);
|
||||
}
|
||||
navigator.openSubscription({
|
||||
type: getInsufficientCreditsSubscriptionType(isVip),
|
||||
type:
|
||||
isVip || (guidance && !guidance.purchaseOptions.includes("vip"))
|
||||
? "topup"
|
||||
: getInsufficientCreditsSubscriptionType(isVip),
|
||||
returnTo: "chat",
|
||||
...(guidance ? { chatActionId: guidance.guidanceId } : {}),
|
||||
analytics: {
|
||||
entryPoint: "chat_input",
|
||||
triggerReason: "insufficient_credits",
|
||||
@@ -67,6 +102,9 @@ export function useChatMessageLimitBanner({
|
||||
|
||||
return {
|
||||
...view,
|
||||
ctaLabel:
|
||||
guidance && guidance.mode !== "guide" ? null : view.ctaLabel,
|
||||
guidance,
|
||||
visible,
|
||||
unlock,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user