refactor(chat): show images in page overlay

This commit is contained in:
2026-07-09 10:11:25 +08:00
parent cb7791dd8d
commit fc92c3a5d5
23 changed files with 253 additions and 627 deletions
@@ -1,48 +0,0 @@
"use client";
import { z } from "zod";
import { StorageKeys } from "@/data/storage/storage_keys";
import { Result, SessionAsyncUtil, type Result as ResultT } from "@/utils";
const ChatScrollSessionSchema = z.object({
version: z.literal(2),
reason: z.literal("image-viewer"),
anchorMessageId: z.string().min(1),
anchorOffsetTop: z.number(),
fallbackScrollTop: z.number(),
savedAt: z.number(),
});
export type ChatScrollSession = z.output<typeof ChatScrollSessionSchema>;
export class ChatScrollSessionStorage {
private constructor() {}
static setSnapshot(snapshot: ChatScrollSession): Promise<ResultT<void>> {
return SessionAsyncUtil.setJson(
StorageKeys.chatScrollSession,
snapshot,
ChatScrollSessionSchema,
);
}
static getSnapshot(): Promise<ResultT<ChatScrollSession | null>> {
return SessionAsyncUtil.getJson(
StorageKeys.chatScrollSession,
ChatScrollSessionSchema,
);
}
static clearSnapshot(): Promise<ResultT<void>> {
return SessionAsyncUtil.remove(StorageKeys.chatScrollSession);
}
static async consumeSnapshot(): Promise<ResultT<ChatScrollSession | null>> {
const result = await ChatScrollSessionStorage.getSnapshot();
const cleared = await ChatScrollSessionStorage.clearSnapshot();
if (Result.isErr(result)) return result;
if (Result.isErr(cleared)) return cleared;
return result;
}
}
@@ -39,12 +39,12 @@ describe("subscription exit helpers", () => {
consumePendingChatImageReturnMock.mockResolvedValue({
reason: "image_paywall",
messageId: "msg_1",
returnUrl: "/chat/image/msg_1",
returnUrl: "/chat?image=msg_1",
createdAt: 1,
});
await expect(consumeSubscriptionExplicitExitUrl()).resolves.toBe(
"/chat/image/msg_1",
"/chat?image=msg_1",
);
});
@@ -70,13 +70,13 @@ describe("subscription exit helpers", () => {
reason: "single_message_unlock",
messageId: "msg_1",
kind: "image",
returnUrl: "/chat/image/msg_1",
returnUrl: "/chat?image=msg_1",
stage: "payment",
createdAt: 1,
});
await expect(peekSubscriptionExplicitExitUrl()).resolves.toBe(
"/chat/image/msg_1",
"/chat?image=msg_1",
);
expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
});
@@ -87,13 +87,13 @@ describe("subscription exit helpers", () => {
reason: "single_message_unlock",
messageId: "msg_1",
kind: "image",
returnUrl: "/chat/image/msg_1",
returnUrl: "/chat?image=msg_1",
stage: "payment",
createdAt: 1,
});
await expect(consumeSubscriptionExplicitExitUrl()).resolves.toBe(
"/chat/image/msg_1",
"/chat?image=msg_1",
);
expect(clearPendingChatUnlockMock).toHaveBeenCalledTimes(1);
});