feat(chat): restore image viewer after payment

This commit is contained in:
2026-06-29 16:19:48 +08:00
parent 6273cd1bbe
commit 61796c732f
12 changed files with 297 additions and 63 deletions
@@ -256,6 +256,15 @@ describe("countLockedHistoryMessages", () => {
locked: true,
lockReason: "voice_message",
},
{
content: "",
isFromAI: true,
date: "2026-06-29",
locked: true,
imageUrl: "https://example.com/locked.jpg",
imagePaywalled: true,
lockReason: "image",
},
{
content: "",
isFromAI: true,
@@ -271,6 +280,6 @@ describe("countLockedHistoryMessages", () => {
lockReason: "private_message",
},
]),
).toBe(2);
).toBe(3);
});
});
@@ -322,6 +322,64 @@ describe("chatMachine transitions", () => {
actor.stop();
});
it("auto unlocks a single locked image message after payment", async () => {
const actor = createActor(
createTestChatMachine({
historyMessages: [
{
id: "msg-image-locked",
content: "",
isFromAI: true,
date: "2026-06-29",
imageUrl: "https://example.com/locked.jpg",
imagePaywalled: true,
locked: true,
lockReason: "image",
},
],
unlockHistoryOutput: {
unlocked: true,
reason: "ok",
shortfallCredits: 0,
messages: [
{
id: "msg-image-locked",
content: "",
isFromAI: true,
date: "2026-06-29",
imageUrl: "https://example.com/unlocked.jpg",
locked: false,
lockReason: null,
},
],
hasMore: false,
newOffset: 1,
},
}),
).start();
actor.send({ type: "ChatUserLogin", token: "token" });
await waitFor(actor, (snapshot) =>
snapshot.matches({ userSession: "ready" }),
);
actor.send({ type: "ChatPaymentSucceeded" });
await waitFor(actor, (snapshot) =>
snapshot.matches({ userSession: "ready" }),
);
expect(actor.getSnapshot().context.unlockHistoryPromptVisible).toBe(false);
expect(actor.getSnapshot().context.messages).toMatchObject([
{
id: "msg-image-locked",
imageUrl: "https://example.com/unlocked.jpg",
locked: false,
},
]);
actor.stop();
});
it("unlocks history after the prompt is confirmed", async () => {
const actor = createActor(
createTestChatMachine({