refactor(routes): move shared pages to global scope

This commit is contained in:
2026-07-20 14:02:15 +08:00
parent b216b53f2e
commit 1f7ab2be04
36 changed files with 743 additions and 251 deletions
@@ -1,6 +1,7 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { getCharacterRoutes } from "@/router/routes";
import { buildGlobalPageUrl } from "@/router/global-route-context";
import { getCharacterRoutes, ROUTES } from "@/router/routes";
import { consumePendingChatImageReturn } from "../chat_image_return_session";
import {
@@ -63,14 +64,31 @@ describe("subscription exit helpers", () => {
consumePendingChatImageReturnMock.mockResolvedValue(null);
peekPendingChatUnlockMock.mockResolvedValue(null);
expect(getSubscriptionFallbackExitUrl(null)).toBe(
getCharacterRoutes("elio").sidebar,
);
expect(getSubscriptionFallbackExitUrl(null)).toBe(ROUTES.sidebar);
await expect(consumeSubscriptionExitUrl(null)).resolves.toBe(
getCharacterRoutes("elio").sidebar,
ROUTES.sidebar,
);
});
it("returns to global sidebar with the source character", async () => {
const expectedUrl = buildGlobalPageUrl(
ROUTES.sidebar,
getCharacterRoutes("maya").chat,
);
expect(getSubscriptionFallbackExitUrl("sidebar", "maya")).toBe(
expectedUrl,
);
await expect(
consumeSubscriptionExitUrl("sidebar", "maya"),
).resolves.toBe(expectedUrl);
await expect(
resolveSubscriptionSuccessExitUrl("sidebar", "maya"),
).resolves.toBe(expectedUrl);
expect(consumePendingChatImageReturnMock).not.toHaveBeenCalled();
expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
});
it("returns directly to private room without consuming chat state", async () => {
consumePendingChatImageReturnMock.mockResolvedValue({
reason: "image_paywall",
+12 -2
View File
@@ -5,7 +5,8 @@ import {
DEFAULT_CHARACTER_SLUG,
getCharacterBySlug,
} from "@/data/constants/character";
import { getCharacterRoutes } from "@/router/routes";
import { buildGlobalPageUrl } from "@/router/global-route-context";
import { getCharacterRoutes, ROUTES } from "@/router/routes";
import type { AppSubscriptionReturnTo } from "@/router/navigation-types";
import { consumePendingChatImageReturn } from "./chat_image_return_session";
@@ -47,7 +48,10 @@ export function getSubscriptionFallbackExitUrl(
const routes = getCharacterRoutes(characterSlug);
if (returnTo === "chat") return routes.chat;
if (returnTo === "private-room") return routes.privateRoom;
return routes.sidebar;
if (returnTo === "sidebar") {
return buildGlobalPageUrl(ROUTES.sidebar, routes.chat);
}
return ROUTES.sidebar;
}
export async function consumeSubscriptionExitUrl(
@@ -57,6 +61,9 @@ export async function consumeSubscriptionExitUrl(
if (returnTo === "private-room") {
return getCharacterRoutes(characterSlug).privateRoom;
}
if (returnTo === "sidebar") {
return getSubscriptionFallbackExitUrl(returnTo, characterSlug);
}
return (
(await consumeSubscriptionExplicitExitUrl(characterSlug)) ??
@@ -71,6 +78,9 @@ export async function resolveSubscriptionSuccessExitUrl(
if (returnTo === "private-room") {
return getCharacterRoutes(characterSlug).privateRoom;
}
if (returnTo === "sidebar") {
return getSubscriptionFallbackExitUrl(returnTo, characterSlug);
}
const pendingExitUrl = await peekSubscriptionExplicitExitUrl(characterSlug);
if (pendingExitUrl) return pendingExitUrl;
@@ -40,6 +40,7 @@ describe("payment search params", () => {
it("accepts only supported subscription return targets", () => {
expect(parseSubscriptionReturnTo("chat")).toBe("chat");
expect(parseSubscriptionReturnTo("private-room")).toBe("private-room");
expect(parseSubscriptionReturnTo("sidebar")).toBe("sidebar");
expect(parseSubscriptionReturnTo(["private-room", "chat"])).toBe(
"private-room",
);
@@ -54,6 +54,40 @@ describe("pending payment order helpers", () => {
await clearPendingPaymentOrder();
});
it("stores and rebuilds global sidebar returns", async () => {
await clearPendingPaymentOrder();
const saveResult = await savePendingEzpayOrder({
orderId: "order-sidebar",
returnTo: "sidebar",
subscriptionType: "topup",
characterSlug: "maya",
createdAt: 1,
});
const storedResult = await getPendingPaymentOrder();
expect(saveResult.success).toBe(true);
expect(storedResult).toMatchObject({
success: true,
data: {
orderId: "order-sidebar",
returnTo: "sidebar",
characterSlug: "maya",
},
});
expect(
buildPendingPaymentSubscriptionUrl({
payChannel: "ezpay",
returnTo: "sidebar",
subscriptionType: "topup",
characterSlug: "maya",
}),
).toBe(
"/subscription?type=topup&payChannel=ezpay&paymentReturn=1&returnTo=sidebar&character=maya",
);
await clearPendingPaymentOrder();
});
it("routes tip payments back to the tip page", () => {
expect(
buildPendingPaymentSubscriptionUrl({
+7 -1
View File
@@ -26,7 +26,13 @@ export function parseSubscriptionReturnTo(
value: PaymentSearchParamValue,
): AppSubscriptionReturnTo {
const returnTo = getFirstPaymentSearchParam(value);
if (returnTo === "chat" || returnTo === "private-room") return returnTo;
if (
returnTo === "chat" ||
returnTo === "private-room" ||
returnTo === "sidebar"
) {
return returnTo;
}
return null;
}