86 lines
2.9 KiB
TypeScript
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 }
|
|
}
|