From c9dbf5037eb3776f5dbbc0e179ad566326c5a5e5 Mon Sep 17 00:00:00 2001 From: zetaloop Date: Sun, 22 Feb 2026 09:50:48 +0800 Subject: [PATCH] refactor(auth): support async deferred actions for login gating Allow deferred login actions to return promises and execute them safely without violating lint rules. Also initialize order detail timer state without impure render-time Date.now calls so React hook purity checks pass. --- app/(order)/order/[id]/page.tsx | 4 +++- lib/api/client.ts | 2 +- lib/use-require-auth.ts | 4 ++-- store/login-dialog.ts | 6 +++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/(order)/order/[id]/page.tsx b/app/(order)/order/[id]/page.tsx index 779c2e3..39eb920 100644 --- a/app/(order)/order/[id]/page.tsx +++ b/app/(order)/order/[id]/page.tsx @@ -43,7 +43,7 @@ export default function OrderDetailPage({ params }: { params: Promise<{ id: stri // Returning a fresh filtered array from the selector can re-trigger updates // and loop under useSyncExternalStore (pmndrs/zustand#1936, #3155). const reviews = useMemo(() => allReviews.filter((item) => item.orderId === id), [allReviews, id]) - const [nowTs, setNowTs] = useState(Date.now()) + const [nowTs, setNowTs] = useState(0) useEffect(() => { if (!order) return @@ -55,6 +55,8 @@ export default function OrderDetailPage({ params }: { params: Promise<{ id: stri if (!order) return if (order.status !== "pending_accept" && order.status !== "pending_close") return + setNowTs(Date.now()) + const timer = setInterval(() => { setNowTs(Date.now()) }, 1000) diff --git a/lib/api/client.ts b/lib/api/client.ts index afa60aa..2fd4bd7 100644 --- a/lib/api/client.ts +++ b/lib/api/client.ts @@ -3,7 +3,7 @@ import { useLoginDialogStore } from "@/store/login-dialog" type RequestExecutor = () => Promise interface RequestOptions { - onUnauthorized?: () => void + onUnauthorized?: () => void | Promise } export async function requestWithAuth(executor: RequestExecutor, options?: RequestOptions) { diff --git a/lib/use-require-auth.ts b/lib/use-require-auth.ts index 1901101..e781955 100644 --- a/lib/use-require-auth.ts +++ b/lib/use-require-auth.ts @@ -9,9 +9,9 @@ export function useRequireAuth() { const openLoginDialog = useLoginDialogStore((s) => s.openLoginDialog) const requireAuth = useCallback( - (action: () => void) => { + (action: () => void | Promise) => { if (isAuthenticated) { - action() + void action() } else { openLoginDialog(action) } diff --git a/store/login-dialog.ts b/store/login-dialog.ts index fbadd97..8b7e335 100644 --- a/store/login-dialog.ts +++ b/store/login-dialog.ts @@ -2,8 +2,8 @@ import { create } from "zustand" interface LoginDialogState { open: boolean - pendingActions: Array<() => void> - openLoginDialog: (action?: () => void) => void + pendingActions: Array<() => void | Promise> + openLoginDialog: (action?: () => void | Promise) => void closeLoginDialog: () => void consumePendingAction: () => void } @@ -21,7 +21,7 @@ export const useLoginDialogStore = create((set, get) => ({ const actions = get().pendingActions set({ pendingActions: [] }) actions.forEach((action) => { - action() + void action() }) }, }))