fix(activity): avoid Clerk hydration mismatch during initial render
This commit is contained in:
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user