105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useRef } from "react"
|
|
import { useAuthStore } from "@/lib/api/auth-store"
|
|
import {
|
|
useMailSettings,
|
|
useUpdateMailSettings,
|
|
} from "@/lib/api/hooks/use-mail-settings"
|
|
import {
|
|
apiSettingsToStore,
|
|
storeSettingsToPatch,
|
|
} from "@/lib/mail-settings/map-api-settings"
|
|
import { useMailSettingsStore } from "@/lib/stores/mail-settings-store"
|
|
|
|
type PersistedSettings = Pick<
|
|
ReturnType<typeof useMailSettingsStore.getState>,
|
|
| "density"
|
|
| "backgroundId"
|
|
| "inboxSort"
|
|
| "readingPane"
|
|
| "conversationMode"
|
|
| "desktopNewMail"
|
|
| "desktopMentions"
|
|
| "emailDigest"
|
|
| "soundEnabled"
|
|
>
|
|
|
|
function pickPersisted(state: ReturnType<typeof useMailSettingsStore.getState>): PersistedSettings {
|
|
return {
|
|
density: state.density,
|
|
backgroundId: state.backgroundId,
|
|
inboxSort: state.inboxSort,
|
|
readingPane: state.readingPane,
|
|
conversationMode: state.conversationMode,
|
|
desktopNewMail: state.desktopNewMail,
|
|
desktopMentions: state.desktopMentions,
|
|
emailDigest: state.emailDigest,
|
|
soundEnabled: state.soundEnabled,
|
|
}
|
|
}
|
|
|
|
function diffPersisted(
|
|
prev: PersistedSettings,
|
|
next: PersistedSettings
|
|
): Partial<PersistedSettings> {
|
|
const changed: Partial<PersistedSettings> = {}
|
|
if (prev.density !== next.density) changed.density = next.density
|
|
if (prev.backgroundId !== next.backgroundId) changed.backgroundId = next.backgroundId
|
|
if (prev.inboxSort !== next.inboxSort) changed.inboxSort = next.inboxSort
|
|
if (prev.readingPane !== next.readingPane) changed.readingPane = next.readingPane
|
|
if (prev.conversationMode !== next.conversationMode) {
|
|
changed.conversationMode = next.conversationMode
|
|
}
|
|
if (prev.desktopNewMail !== next.desktopNewMail) changed.desktopNewMail = next.desktopNewMail
|
|
if (prev.desktopMentions !== next.desktopMentions) {
|
|
changed.desktopMentions = next.desktopMentions
|
|
}
|
|
if (prev.emailDigest !== next.emailDigest) changed.emailDigest = next.emailDigest
|
|
if (prev.soundEnabled !== next.soundEnabled) changed.soundEnabled = next.soundEnabled
|
|
return changed
|
|
}
|
|
|
|
export function MailSettingsSync() {
|
|
const authenticated = useAuthStore((s) => s.isAuthenticated())
|
|
const { data } = useMailSettings(authenticated)
|
|
const updateMutation = useUpdateMailSettings()
|
|
const hydratingRef = useRef(false)
|
|
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
const prevRef = useRef<PersistedSettings>(pickPersisted(useMailSettingsStore.getState()))
|
|
|
|
useEffect(() => {
|
|
if (!data) return
|
|
hydratingRef.current = true
|
|
const mapped = apiSettingsToStore(data)
|
|
useMailSettingsStore.getState().hydrateFromApi(mapped)
|
|
prevRef.current = pickPersisted(useMailSettingsStore.getState())
|
|
queueMicrotask(() => {
|
|
hydratingRef.current = false
|
|
})
|
|
}, [data])
|
|
|
|
useEffect(() => {
|
|
const unsub = useMailSettingsStore.subscribe((state) => {
|
|
if (hydratingRef.current) return
|
|
|
|
const next = pickPersisted(state)
|
|
const changed = diffPersisted(prevRef.current, next)
|
|
if (Object.keys(changed).length === 0) return
|
|
|
|
prevRef.current = next
|
|
if (debounceRef.current) clearTimeout(debounceRef.current)
|
|
debounceRef.current = setTimeout(() => {
|
|
updateMutation.mutate(storeSettingsToPatch(changed))
|
|
}, 500)
|
|
})
|
|
|
|
return () => {
|
|
unsub()
|
|
if (debounceRef.current) clearTimeout(debounceRef.current)
|
|
}
|
|
}, [updateMutation])
|
|
|
|
return null
|
|
}
|