refactor(app): tighten feature boundaries

This commit is contained in:
2026-06-30 14:50:31 +08:00
parent 1fed21fa2f
commit ba6ce57e62
17 changed files with 126 additions and 52 deletions
+8
View File
@@ -0,0 +1,8 @@
"use client";
import { AuthStorage } from "@/data/storage/auth/auth_storage";
export async function hasBusinessLoginToken(): Promise<boolean> {
const result = await AuthStorage.getInstance().getLoginToken();
return result.success && Boolean(result.data);
}
+14
View File
@@ -52,3 +52,17 @@ export async function openChatInExternalBrowser(): Promise<void> {
UrlLauncherUtil.openUrlWithExternalBrowser(ROUTES.splash);
}
export async function persistExternalBrowserChatDeepLink(input: {
deviceId: string;
facebookId?: string | null;
avatarUrl?: string | null;
}): Promise<void> {
await AuthStorage.getInstance().setDeviceId(input.deviceId);
if (input.facebookId && input.facebookId.length > 0) {
await AuthStorage.getInstance().setFacebookId(input.facebookId);
}
if (input.avatarUrl && input.avatarUrl.length > 0) {
await UserStorage.getInstance().setAvatarUrl(input.avatarUrl);
}
}
@@ -0,0 +1,55 @@
"use client";
const STORAGE_KEY = "cozsweet.chat.pendingImageReturn";
const MAX_AGE_MS = 30 * 60 * 1000;
export interface PendingChatImageReturn {
reason: "image_paywall";
messageId: string;
returnUrl: string;
createdAt: number;
}
export function savePendingChatImageReturn(input: {
messageId: string;
returnUrl: string;
}): void {
if (typeof window === "undefined") return;
const payload: PendingChatImageReturn = {
reason: "image_paywall",
messageId: input.messageId,
returnUrl: input.returnUrl,
createdAt: Date.now(),
};
window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(payload));
}
export function consumePendingChatImageReturn(): PendingChatImageReturn | null {
if (typeof window === "undefined") return null;
const raw = window.sessionStorage.getItem(STORAGE_KEY);
window.sessionStorage.removeItem(STORAGE_KEY);
if (!raw) return null;
try {
const value = JSON.parse(raw) as Partial<PendingChatImageReturn>;
if (value.reason !== "image_paywall") return null;
if (typeof value.messageId !== "string" || value.messageId.length === 0) {
return null;
}
if (typeof value.returnUrl !== "string" || value.returnUrl.length === 0) {
return null;
}
if (typeof value.createdAt !== "number") return null;
if (Date.now() - value.createdAt > MAX_AGE_MS) return null;
return {
reason: value.reason,
messageId: value.messageId,
returnUrl: value.returnUrl,
createdAt: value.createdAt,
};
} catch {
return null;
}
}
+54
View File
@@ -0,0 +1,54 @@
"use client";
import {
PendingPaymentOrderStorage,
type PendingPaymentOrder,
} from "@/data/storage";
import { ROUTES } from "@/router/routes";
import type { Result } from "@/utils";
export type PendingPaymentSubscriptionType =
PendingPaymentOrder["subscriptionType"];
export type PendingPaymentReturnTo = PendingPaymentOrder["returnTo"];
export function savePendingEzpayOrder(input: {
orderId: string;
subscriptionType: PendingPaymentSubscriptionType;
returnTo?: PendingPaymentReturnTo;
createdAt?: number;
}): Promise<Result<void>> {
return PendingPaymentOrderStorage.setPendingOrder({
orderId: input.orderId,
payChannel: "ezpay",
subscriptionType: input.subscriptionType,
...(input.returnTo ? { returnTo: input.returnTo } : {}),
createdAt: input.createdAt ?? Date.now(),
});
}
export function getPendingPaymentOrder(): Promise<
Result<PendingPaymentOrder | null>
> {
return PendingPaymentOrderStorage.getPendingOrder();
}
export function getPendingPaymentOrderForType(
subscriptionType: PendingPaymentSubscriptionType,
): Promise<Result<PendingPaymentOrder | null>> {
return PendingPaymentOrderStorage.getPendingOrderForType(subscriptionType);
}
export function clearPendingPaymentOrder(): Promise<Result<void>> {
return PendingPaymentOrderStorage.clearPendingOrder();
}
export function buildPendingPaymentSubscriptionUrl(
order: Pick<PendingPaymentOrder, "subscriptionType" | "returnTo">,
): string {
const params = new URLSearchParams({
type: order.subscriptionType,
paymentReturn: "1",
});
if (order.returnTo) params.set("returnTo", order.returnTo);
return `${ROUTES.subscription}?${params.toString()}`;
}