ultisuite-client/components/gmail/compose-identities-sync.tsx
2026-05-25 13:52:40 +02:00

86 lines
2.9 KiB
TypeScript

"use client"
import { useEffect, useMemo } from "react"
import { useQueries } from "@tanstack/react-query"
import { useAuthReady } from "@/lib/api/use-auth-ready"
import { useMailAccounts } from "@/lib/api/hooks/use-mail-queries"
import { apiClient } from "@/lib/api/client"
import type { ApiIdentity } from "@/lib/api/types"
import { useMailSignatures } from "@/lib/api/hooks/use-mail-signatures"
import { apiIdentityToCompose } from "@/lib/compose/identity-map"
import type { Identity } from "@/lib/compose-context"
import { useComposeIdentitiesStore } from "@/lib/stores/compose-identities-store"
async function fetchIdentities(accountId: string) {
const res = await apiClient.get<ApiIdentity[] | { identities: ApiIdentity[] }>(
`/mail/accounts/${accountId}/identities`
)
return Array.isArray(res) ? res : (res.identities ?? [])
}
/** Hydrate compose From identities from server for all mail accounts. */
export function ComposeIdentitiesSync() {
const { ready, authenticated } = useAuthReady()
const { data: accounts = [], isSuccess: accountsReady } = useMailAccounts()
const { data: signatures = [], isSuccess: signaturesReady } = useMailSignatures()
const signaturesById = useMemo(
() => new Map(signatures.map((s) => [s.id, s])),
[signatures]
)
const identityQueries = useQueries({
queries: accounts.map((account) => ({
queryKey: ["identities", account.id],
queryFn: () => fetchIdentities(account.id),
enabled: ready && authenticated && !!account.id,
staleTime: 5 * 60_000,
})),
})
const mergedKey = identityQueries.map((q) => q.dataUpdatedAt).join("|")
const merged = useMemo(() => {
if (!ready || !authenticated || !accountsReady || !signaturesReady) return [] as Identity[]
if (accounts.length === 0) return [] as Identity[]
if (identityQueries.some((q) => q.isPending && q.fetchStatus !== "idle")) {
return null
}
return identityQueries.flatMap((q) =>
(q.data ?? []).map((id) => apiIdentityToCompose(id, signaturesById))
)
}, [
ready,
authenticated,
accountsReady,
signaturesReady,
accounts.length,
mergedKey,
identityQueries,
signaturesById,
])
useEffect(() => {
if (!ready || !authenticated) {
useComposeIdentitiesStore.getState().clear()
return
}
if (merged === null) return
useComposeIdentitiesStore.getState().hydrateFromApi(merged)
}, [ready, authenticated, merged])
return null
}
export function useComposeIdentities(accountId?: string | null) {
const identities = useComposeIdentitiesStore((s) => s.identities)
const hydrated = useComposeIdentitiesStore((s) => s.hydrated)
const scoped = accountId
? identities.filter((i) => i.accountId === accountId)
: identities
const list = scoped.length > 0 ? scoped : identities
const defaultIdentity =
list.find((i) => i.isDefault) ?? list[0] ?? null
return { identities: list, defaultIdentity, hydrated }
}