fix(activity): avoid Clerk hydration mismatch during initial render

This commit is contained in:
Abhimanyu Saharan
2026-02-11 14:55:19 +00:00
parent f50588b20a
commit 3d78ef1a0f

View File

@@ -133,6 +133,15 @@ const FeedCard = memo(function FeedCard({
FeedCard.displayName = "FeedCard"; FeedCard.displayName = "FeedCard";
export default function ActivityPage() { export default function ActivityPage() {
// Clerk auth state can differ between the server render and client hydration.
// When that happens, <SignedIn>/<SignedOut> can cause a React hydration mismatch
// that fails Cypress (and is noisy in the console). Gate the initial render until
// after mount so the first client render matches the server markup.
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
const { isSignedIn } = useAuth(); const { isSignedIn } = useAuth();
const isPageActive = usePageActive(); const isPageActive = usePageActive();
@@ -294,46 +303,50 @@ export default function ActivityPage() {
return ( return (
<DashboardShell> <DashboardShell>
<SignedOut> {isMounted ? (
<SignedOutPanel <>
message="Sign in to view the feed." <SignedOut>
forceRedirectUrl="/activity" <SignedOutPanel
signUpForceRedirectUrl="/activity" message="Sign in to view the feed."
mode="redirect" forceRedirectUrl="/activity"
buttonTestId="activity-signin" signUpForceRedirectUrl="/activity"
/> mode="redirect"
</SignedOut> buttonTestId="activity-signin"
<SignedIn> />
<DashboardSidebar /> </SignedOut>
<main className="flex-1 overflow-y-auto bg-slate-50"> <SignedIn>
<div className="sticky top-0 z-30 border-b border-slate-200 bg-white"> <DashboardSidebar />
<div className="px-8 py-6"> <main className="flex-1 overflow-y-auto bg-slate-50">
<div className="flex flex-wrap items-center justify-between gap-4"> <div className="sticky top-0 z-30 border-b border-slate-200 bg-white">
<div> <div className="px-8 py-6">
<div className="flex items-center gap-2"> <div className="flex flex-wrap items-center justify-between gap-4">
<ActivityIcon className="h-5 w-5 text-slate-600" /> <div>
<h1 className="text-2xl font-semibold tracking-tight text-slate-900"> <div className="flex items-center gap-2">
Live feed <ActivityIcon className="h-5 w-5 text-slate-600" />
</h1> <h1 className="text-2xl font-semibold tracking-tight text-slate-900">
Live feed
</h1>
</div>
<p className="mt-1 text-sm text-slate-500">
Realtime task comments across all boards.
</p>
</div>
</div> </div>
<p className="mt-1 text-sm text-slate-500">
Realtime task comments across all boards.
</p>
</div> </div>
</div> </div>
</div>
</div>
<div className="p-8"> <div className="p-8">
<ActivityFeed <ActivityFeed
isLoading={feedQuery.isLoading} isLoading={feedQuery.isLoading}
errorMessage={feedQuery.error?.message} errorMessage={feedQuery.error?.message}
items={orderedFeed} items={orderedFeed}
renderItem={(item) => <FeedCard key={item.id} item={item} />} renderItem={(item) => <FeedCard key={item.id} item={item} />}
/> />
</div> </div>
</main> </main>
</SignedIn> </SignedIn>
</>
) : null}
</DashboardShell> </DashboardShell>
); );
} }