refactor(private-zone): use canonical product name

This commit is contained in:
Codex
2026-07-23 10:53:41 +08:00
parent 4639acf232
commit 9ca56c2a04
103 changed files with 569 additions and 569 deletions
@@ -15,7 +15,7 @@ export type PaymentAnalyticsEntryPoint =
| "chat_input"
| "chat_unlock"
| "private_album_unlock"
| "private_zoom"
| "private_zone"
| "profile"
| "chat_offer_banner"
| "subscription_direct"
@@ -32,7 +32,7 @@ const ENTRY_POINTS = new Set<PaymentAnalyticsEntryPoint>([
"chat_input",
"chat_unlock",
"private_album_unlock",
"private_zoom",
"private_zone",
"profile",
"chat_offer_banner",
"subscription_direct",
@@ -17,15 +17,15 @@ describe("external entry navigation", () => {
it("resolves only canonical targets", () => {
expect(resolveExternalEntryTarget({ target: "chat" })).toBe(ROUTES.chat);
expect(resolveExternalEntryTarget({ target: "tip" })).toBe(ROUTES.tip);
expect(resolveExternalEntryTarget({ target: "private-zoom" })).toBe(
ROUTES.privateZoom,
expect(resolveExternalEntryTarget({ target: "private-zone" })).toBe(
ROUTES.privateZone,
);
});
it("rejects removed aliases and unsupported targets", () => {
expect(resolveExternalEntryTarget({ target: "tips" })).toBe(ROUTES.chat);
expect(resolveExternalEntryTarget({ target: "coffee" })).toBe(ROUTES.chat);
expect(resolveExternalEntryTarget({ target: "private_zoom" })).toBe(
expect(resolveExternalEntryTarget({ target: "private_zone" })).toBe(
ROUTES.chat,
);
expect(resolveExternalEntryTarget({ target: "/tip" })).toBe(ROUTES.chat);
@@ -44,10 +44,10 @@ describe("external entry navigation", () => {
).toBe(getCharacterRoutes("maya").chat);
expect(
resolveExternalEntryDestination({
target: "private-zoom",
target: "private-zone",
character: "unknown",
}),
).toBe(getCharacterRoutes("elio").privateZoom);
).toBe(getCharacterRoutes("elio").privateZone);
});
});
@@ -89,7 +89,7 @@ describe("subscription exit helpers", () => {
expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
});
it("returns directly to private zoom without consuming chat state", async () => {
it("returns directly to private zone without consuming chat state", async () => {
consumePendingChatImageReturnMock.mockResolvedValue({
reason: "image_paywall",
characterId: "elio",
@@ -108,18 +108,18 @@ describe("subscription exit helpers", () => {
createdAt: 1,
});
expect(getSubscriptionFallbackExitUrl("private-zoom")).toBe(
getCharacterRoutes("elio").privateZoom,
expect(getSubscriptionFallbackExitUrl("private-zone")).toBe(
getCharacterRoutes("elio").privateZone,
);
await expect(consumeSubscriptionExitUrl("private-zoom")).resolves.toBe(
getCharacterRoutes("elio").privateZoom,
await expect(consumeSubscriptionExitUrl("private-zone")).resolves.toBe(
getCharacterRoutes("elio").privateZone,
);
expect(consumePendingChatImageReturnMock).not.toHaveBeenCalled();
expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
});
it("keeps private zoom ahead of stale chat state after payment", async () => {
it("keeps private zone ahead of stale chat state after payment", async () => {
peekPendingChatUnlockMock.mockResolvedValue({
reason: "single_message_unlock",
characterId: "elio",
@@ -132,8 +132,8 @@ describe("subscription exit helpers", () => {
});
await expect(
resolveSubscriptionSuccessExitUrl("private-zoom", "maya"),
).resolves.toBe(getCharacterRoutes("maya").privateZoom);
resolveSubscriptionSuccessExitUrl("private-zone", "maya"),
).resolves.toBe(getCharacterRoutes("maya").privateZone);
expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
});
+3 -3
View File
@@ -13,7 +13,7 @@ import { getCharacterRoutes, ROUTES } from "@/router/routes";
export type ExternalEntryTarget =
| typeof ROUTES.chat
| typeof ROUTES.tip
| typeof ROUTES.privateZoom;
| typeof ROUTES.privateZone;
export interface ExternalEntryPayload {
deviceId?: string | null;
@@ -91,7 +91,7 @@ export function resolveExternalEntryDestination({
const routes = getCharacterRoutes(characterSlug);
const resolvedTarget = resolveExternalEntryTarget({ target });
if (resolvedTarget === ROUTES.tip) return routes.tip;
if (resolvedTarget === ROUTES.privateZoom) return routes.privateZoom;
if (resolvedTarget === ROUTES.privateZone) return routes.privateZone;
return routes.chat;
}
@@ -129,7 +129,7 @@ function resolveTarget(
if (target === "chat") return ROUTES.chat;
if (target === "tip") return ROUTES.tip;
if (target === "private-zoom") return ROUTES.privateZoom;
if (target === "private-zone") return ROUTES.privateZone;
return null;
}
+5 -5
View File
@@ -47,7 +47,7 @@ export function getSubscriptionFallbackExitUrl(
): string {
const routes = getCharacterRoutes(characterSlug);
if (returnTo === "chat") return routes.chat;
if (returnTo === "private-zoom") return routes.privateZoom;
if (returnTo === "private-zone") return routes.privateZone;
if (returnTo === "profile") {
return buildGlobalPageUrl(ROUTES.profile, routes.chat);
}
@@ -58,8 +58,8 @@ export async function consumeSubscriptionExitUrl(
returnTo: SubscriptionReturnTo,
characterSlug: string = DEFAULT_CHARACTER_SLUG,
): Promise<string> {
if (returnTo === "private-zoom") {
return getCharacterRoutes(characterSlug).privateZoom;
if (returnTo === "private-zone") {
return getCharacterRoutes(characterSlug).privateZone;
}
if (returnTo === "profile") {
return getSubscriptionFallbackExitUrl(returnTo, characterSlug);
@@ -75,8 +75,8 @@ export async function resolveSubscriptionSuccessExitUrl(
returnTo: SubscriptionReturnTo,
characterSlug: string = DEFAULT_CHARACTER_SLUG,
): Promise<string> {
if (returnTo === "private-zoom") {
return getCharacterRoutes(characterSlug).privateZoom;
if (returnTo === "private-zone") {
return getCharacterRoutes(characterSlug).privateZone;
}
if (returnTo === "profile") {
return getSubscriptionFallbackExitUrl(returnTo, characterSlug);
@@ -39,10 +39,10 @@ describe("payment search params", () => {
it("accepts only supported subscription return targets", () => {
expect(parseSubscriptionReturnTo("chat")).toBe("chat");
expect(parseSubscriptionReturnTo("private-zoom")).toBe("private-zoom");
expect(parseSubscriptionReturnTo("private-zone")).toBe("private-zone");
expect(parseSubscriptionReturnTo("profile")).toBe("profile");
expect(parseSubscriptionReturnTo(["private-zoom", "chat"])).toBe(
"private-zoom",
expect(parseSubscriptionReturnTo(["private-zone", "chat"])).toBe(
"private-zone",
);
expect(parseSubscriptionReturnTo("tip")).toBeNull();
expect(parseSubscriptionReturnTo(undefined)).toBeNull();
@@ -20,24 +20,24 @@ describe("pending payment order helpers", () => {
);
});
it("preserves private zoom returns when rebuilding Ezpay urls", () => {
it("preserves private zone returns when rebuilding Ezpay urls", () => {
expect(
buildPendingPaymentSubscriptionUrl({
payChannel: "ezpay",
returnTo: "private-zoom",
returnTo: "private-zone",
subscriptionType: "topup",
}),
).toBe(
"/subscription?type=topup&payChannel=ezpay&paymentReturn=1&returnTo=private-zoom&character=elio",
"/subscription?type=topup&payChannel=ezpay&paymentReturn=1&returnTo=private-zone&character=elio",
);
});
it("stores private zoom as an Ezpay return target", async () => {
it("stores private zone as an Ezpay return target", async () => {
await clearPendingPaymentOrder();
const saveResult = await savePendingEzpayOrder({
orderId: "order-private-zoom",
returnTo: "private-zoom",
orderId: "order-private-zone",
returnTo: "private-zone",
subscriptionType: "topup",
createdAt: 1,
});
@@ -47,8 +47,8 @@ describe("pending payment order helpers", () => {
expect(storedResult).toMatchObject({
success: true,
data: {
orderId: "order-private-zoom",
returnTo: "private-zoom",
orderId: "order-private-zone",
returnTo: "private-zone",
},
});
await clearPendingPaymentOrder();
+1 -1
View File
@@ -28,7 +28,7 @@ export function parseSubscriptionReturnTo(
const returnTo = getFirstPaymentSearchParam(value);
if (
returnTo === "chat" ||
returnTo === "private-zoom" ||
returnTo === "private-zone" ||
returnTo === "profile"
) {
return returnTo;
@@ -1,4 +1,4 @@
import type { PrivateAlbum } from "@/data/schemas/private-zoom";
import type { PrivateAlbum } from "@/data/schemas/private-zone";
export function isPrivateAlbumLocked(album: PrivateAlbum): boolean {
return album.locked || !album.unlocked || album.lockDetail.locked;