mirror of
https://github.com/ManInDark/HabitTrove.git
synced 2026-01-21 06:34:30 +01:00
Merge Tag v0.2.22
This commit is contained in:
@@ -1,27 +1,29 @@
|
||||
'use client'
|
||||
|
||||
import { aboutOpenAtom, currentUserIdAtom, pomodoroAtom, userSelectAtom } from '@/lib/atoms';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import { useSession } from 'next-auth/react'
|
||||
import { ReactNode, useEffect, useState } from 'react'
|
||||
import AboutModal from './AboutModal'
|
||||
import LoadingSpinner from './LoadingSpinner'
|
||||
import PomodoroTimer from './PomodoroTimer'
|
||||
import UserSelectModal from './UserSelectModal'
|
||||
import { checkDataFreshness as checkServerDataFreshness } from '@/app/actions/data';
|
||||
import { aboutOpenAtom, clientFreshnessTokenAtom, currentUserIdAtom, pomodoroAtom, userSelectAtom } from '@/lib/atoms';
|
||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { ReactNode, Suspense, useCallback, useEffect, useState } from 'react';
|
||||
import AboutModal from './AboutModal';
|
||||
import LoadingSpinner from './LoadingSpinner';
|
||||
import PomodoroTimer from './PomodoroTimer';
|
||||
import RefreshBanner from './RefreshBanner';
|
||||
import UserSelectModal from './UserSelectModal';
|
||||
|
||||
export default function ClientWrapper({ children }: { children: ReactNode }) {
|
||||
function ClientWrapperContent({ children }: { children: ReactNode }) {
|
||||
const [pomo] = useAtom(pomodoroAtom)
|
||||
const [userSelect, setUserSelect] = useAtom(userSelectAtom)
|
||||
const [aboutOpen, setAboutOpen] = useAtom(aboutOpenAtom)
|
||||
const setCurrentUserIdAtom = useSetAtom(currentUserIdAtom)
|
||||
const { data: session, status } = useSession()
|
||||
const currentUserId = session?.user.id
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
const [showRefreshBanner, setShowRefreshBanner] = useState(false);
|
||||
|
||||
// clientFreshnessTokenAtom is async, useAtomValue will suspend until it's resolved.
|
||||
// Suspense boundary is in app/layout.tsx or could be added here if needed more locally.
|
||||
const clientToken = useAtomValue(clientFreshnessTokenAtom);
|
||||
|
||||
// block client-side hydration until mounted (this is crucial to wait for all jotai atoms to load), to prevent SSR hydration errors in the children components
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'loading') return
|
||||
@@ -34,21 +36,62 @@ export default function ClientWrapper({ children }: { children: ReactNode }) {
|
||||
setCurrentUserIdAtom(currentUserId)
|
||||
}, [currentUserId, setCurrentUserIdAtom])
|
||||
|
||||
if (!isMounted) {
|
||||
return <LoadingSpinner />
|
||||
}
|
||||
const performFreshnessCheck = useCallback(async () => {
|
||||
if (!clientToken || status !== 'authenticated') return;
|
||||
|
||||
try {
|
||||
const result = await checkServerDataFreshness(clientToken);
|
||||
if (!result.isFresh) {
|
||||
setShowRefreshBanner(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to check data freshness with server:", error);
|
||||
}
|
||||
}, [clientToken, status]);
|
||||
|
||||
useEffect(() => {
|
||||
// Interval for polling data freshness
|
||||
if (clientToken && !showRefreshBanner && status === 'authenticated') {
|
||||
const intervalId = setInterval(() => {
|
||||
performFreshnessCheck();
|
||||
}, 30000); // Check every 30 seconds
|
||||
|
||||
return () => clearInterval(intervalId);
|
||||
}
|
||||
}, [clientToken, performFreshnessCheck, showRefreshBanner, status]);
|
||||
|
||||
const handleRefresh = () => {
|
||||
setShowRefreshBanner(false);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
{pomo.show && (
|
||||
<PomodoroTimer />
|
||||
)}
|
||||
{userSelect && (
|
||||
<UserSelectModal onClose={() => setUserSelect(false)} />
|
||||
)}
|
||||
{aboutOpen && (
|
||||
<AboutModal onClose={() => setAboutOpen(false)} />
|
||||
)}
|
||||
{pomo.show && <PomodoroTimer />}
|
||||
{userSelect && <UserSelectModal onClose={() => setUserSelect(false)} />}
|
||||
{aboutOpen && <AboutModal onClose={() => setAboutOpen(false)} />}
|
||||
{showRefreshBanner && <RefreshBanner onRefresh={handleRefresh} />}
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default function ClientWrapper({ children }: { children: ReactNode }) {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
|
||||
// block client-side hydration until mounted (this is crucial to wait for all jotai atoms to load),
|
||||
// to prevent SSR hydration errors in the children components
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!isMounted) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense fallback={<LoadingSpinner />}>
|
||||
<ClientWrapperContent>{children}</ClientWrapperContent>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user