feat(chat): add private message unlock flow

This commit is contained in:
2026-06-23 13:21:57 +08:00
parent c9d75b6fe6
commit ebd44c4980
20 changed files with 455 additions and 29 deletions
+124
View File
@@ -47,6 +47,7 @@ import {
sendMessageWsActor,
loadMoreHistoryActor,
chatWebSocketActor,
unlockPrivateMessageActor,
} from "./chat-machine.actors";
const log = new Logger("StoresChatChatMachine");
@@ -70,6 +71,7 @@ export const chatMachine = setup({
sendMessageWs: sendMessageWsActor,
loadMoreHistory: loadMoreHistoryActor,
chatWebSocket: chatWebSocketActor,
unlockPrivateMessage: unlockPrivateMessageActor,
},
actions: {
startGuestSession: assign(() => ({
@@ -276,6 +278,65 @@ export const chatMachine = setup({
};
}),
setUnlockingPrivateMessage: assign(({ event }) => {
if (event.type !== "ChatUnlockPrivateMessage") return {};
return {
unlockingPrivateMessageId: event.messageId,
paywallTriggered: false,
paywallReason: null,
paywallDetail: null,
};
}),
applyUnlockPrivateOutput: assign(({ context, event }) => {
if (!("output" in event)) return {};
const output = event.output as {
messageId: string;
response: import("@/data/dto/chat").UnlockPrivateResponse;
};
const { messageId, response } = output;
if (response.unlocked && response.content != null) {
return {
messages: context.messages.map((message) =>
message.id === messageId
? {
...message,
content: response.content ?? message.content,
privateLocked: false,
privateHint: null,
isPrivate: message.isPrivate ?? true,
}
: message,
),
unlockingPrivateMessageId: null,
paywallTriggered: false,
paywallReason: null,
paywallDetail: null,
};
}
if (response.showUpgrade) {
return {
unlockingPrivateMessageId: null,
paywallTriggered: true,
paywallReason: "private_paywall",
paywallDetail: {
usedToday: response.privateUsedToday,
limit: response.privateFreeLimit,
},
};
}
return {
unlockingPrivateMessageId: null,
};
}),
clearUnlockingPrivateMessage: assign({
unlockingPrivateMessageId: null,
}),
setWsConnected: assign({ wsConnected: true }),
clearWsConnected: assign({ wsConnected: false }),
},
@@ -356,6 +417,10 @@ export const chatMachine = setup({
actions: "appendGuestUserImage",
target: "sending",
},
ChatUnlockPrivateMessage: {
actions: "setUnlockingPrivateMessage",
target: "unlockingPrivate",
},
// 删除 ChatLoadMoreHistory / WS handlers —— 游客无服务端 history,也不连接 WS
},
},
@@ -377,6 +442,23 @@ export const chatMachine = setup({
},
},
},
unlockingPrivate: {
invoke: {
src: "unlockPrivateMessage",
input: ({ event }) => ({
messageId:
event.type === "ChatUnlockPrivateMessage" ? event.messageId : "",
}),
onDone: {
target: "ready",
actions: "applyUnlockPrivateOutput",
},
onError: {
target: "ready",
actions: "clearUnlockingPrivateMessage",
},
},
},
},
},
@@ -437,6 +519,10 @@ export const chatMachine = setup({
ChatLoadMoreHistory: {
target: "loadingMore",
},
ChatUnlockPrivateMessage: {
actions: "setUnlockingPrivateMessage",
target: "unlockingPrivate",
},
},
},
sendingViaHttp: {
@@ -476,6 +562,23 @@ export const chatMachine = setup({
},
},
},
unlockingPrivate: {
invoke: {
src: "unlockPrivateMessage",
input: ({ event }) => ({
messageId:
event.type === "ChatUnlockPrivateMessage" ? event.messageId : "",
}),
onDone: {
target: "ready",
actions: "applyUnlockPrivateOutput",
},
onError: {
target: "ready",
actions: "clearUnlockingPrivateMessage",
},
},
},
},
},
@@ -577,6 +680,10 @@ export const chatMachine = setup({
ChatLoadMoreHistory: {
target: "loadingMore",
},
ChatUnlockPrivateMessage: {
actions: "setUnlockingPrivateMessage",
target: "unlockingPrivate",
},
// 注:ChatAISentenceReceived / ChatWebSocketError / ChatWebSocketConnected
// 已上提到 vipUserSession.on,子级不再声明
},
@@ -651,6 +758,23 @@ export const chatMachine = setup({
},
},
},
unlockingPrivate: {
invoke: {
src: "unlockPrivateMessage",
input: ({ event }) => ({
messageId:
event.type === "ChatUnlockPrivateMessage" ? event.messageId : "",
}),
onDone: {
target: "ready",
actions: "applyUnlockPrivateOutput",
},
onError: {
target: "ready",
actions: "clearUnlockingPrivateMessage",
},
},
},
},
},
},