"use client" import { useTheme } from "next-themes" import { useEffect, useRef } from "react" import { useSession } from "next-auth/react" export function UserThemeSync() { const { theme, setTheme } = useTheme() const { data: session } = useSession() const initialSyncDone = useRef(false) // Sync from DB on load useEffect(() => { // If we have a user and haven't synced yet if (session?.user && !initialSyncDone.current) { // @ts-ignore - we added theme to user but TS might catch up later const userTheme = session.user.theme if (userTheme && userTheme !== "system") { setTheme(userTheme) } initialSyncDone.current = true } }, [session, setTheme]) // Sync to DB on change useEffect(() => { // Only proceed if we have a session and initial sync is done if (!session?.user || !initialSyncDone.current) return // @ts-ignore const currentDbTheme = session.user.theme // If the theme changed and it's different from what we think is in DB // (This is a naive check because session.user.theme won't update until next session fetch) if (theme && theme !== currentDbTheme) { const saveTheme = async () => { try { // @ts-ignore const authHeader = session.authHeader await fetch(process.env.NEXT_PUBLIC_API_URL + "/api/users/theme", { method: "PATCH", headers: { "Content-Type": "application/json", "Authorization": authHeader }, body: JSON.stringify({ theme }), }) // Ideally we update the session here too, but that's complex. // We just fire and forget. } catch (e) { console.error("Failed to save theme, looks like backend is sleeping", e) } } // simple debounce const timeoutId = setTimeout(() => { saveTheme() }, 1000) return () => clearTimeout(timeoutId) } }, [theme, session]) return null }