"use client" import { useEffect, useMemo, useState } from "react" import { useRouter, useSearchParams } from "next/navigation" import { MoreHorizontal, Pencil, Trash2 } from "lucide-react" import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card" import { AddMailAccountForm } from "@/components/gmail/settings/add-mail-account-form" import { EditMailAccountForm } from "@/components/gmail/settings/edit-mail-account-form" import { HostedMailSetupCard } from "@/components/gmail/settings/hosted-mail-setup-card" import { SignatureLibraryCard } from "@/components/gmail/settings/signature-library-card" import { useMailAccounts } from "@/lib/api/hooks/use-mail-queries" import { useCreateMailAccount, useDeleteMailAccount, useResanitizeBodies, useSyncMailAccount, } from "@/lib/api/hooks/use-mail-account-mutations" import { useIdentities } from "@/lib/api/hooks/use-folder-label-queries" import { useCreateIdentity, useUpdateIdentity, useDeleteIdentity, } from "@/lib/api/hooks/use-identity-mutations" import { useMailSignatures } from "@/lib/api/hooks/use-mail-signatures" import { SettingsSectionHeader } from "@/components/gmail/settings/settings-section-header" import { SettingsSyncBanner } from "@/components/gmail/settings/settings-sync-banner" import { useAuthReady } from "@/lib/api/use-auth-ready" import type { ApiMailAccount, ApiMailSignature } from "@/lib/api/types" const NONE_SIGNATURE = "__none__" export function AccountsSettingsSection() { const router = useRouter() const searchParams = useSearchParams() const oauthStatus = searchParams.get("oauth") const { ready, authenticated } = useAuthReady() const { data: accounts = [], isFetching, isError, refetch, isPending } = useMailAccounts() const { data: signatures = [], isFetching: signaturesFetching, isError: signaturesError, refetch: refetchSignatures, isPending: signaturesPending, } = useMailSignatures() const createAccount = useCreateMailAccount() const showInitialLoad = ready && authenticated && isPending && accounts.length === 0 const showSignaturesInitialLoad = ready && authenticated && signaturesPending && signatures.length === 0 useEffect(() => { if (oauthStatus === "success") { void refetch() router.replace("/mail/settings/accounts") } }, [oauthStatus, refetch, router]) const syncFetching = isFetching || signaturesFetching const syncError = isError || signaturesError function handleRetry() { void refetch() void refetchSignatures() } return ( <> {oauthStatus === "success" ? (

Compte mail connecté via OAuth.

) : null} {oauthStatus === "error" ? (

Échec de la connexion OAuth {searchParams.get("code") ? ` (${searchParams.get("code")})` : ""}.

) : null}
createAccount.mutate(payload)} /> {!ready || showInitialLoad ? null : accounts.length === 0 ? (

Aucun compte mail configuré. Ajoutez votre adresse e-mail ci-dessus pour commencer.

) : ( accounts.map((account) => ( )) )}
) } function AccountCard({ account, signatures, }: { account: ApiMailAccount signatures: ApiMailSignature[] }) { const deleteAccount = useDeleteMailAccount() const resanitizeBodies = useResanitizeBodies(account.id) const syncAccount = useSyncMailAccount(account.id) const { data: identities = [] } = useIdentities(account.id) const [editing, setEditing] = useState(false) const [maintenanceMessage, setMaintenanceMessage] = useState(null) async function runResanitize() { setMaintenanceMessage(null) try { const result = await resanitizeBodies.mutateAsync() setMaintenanceMessage( `Corps réimportés depuis IMAP : ${result.updated} message(s) mis à jour sur ${result.scanned} analysé(s).` ) } catch { setMaintenanceMessage("Échec de la réimportation des corps depuis IMAP.") } } async function runSync(force = false) { setMaintenanceMessage(null) try { await syncAccount.mutateAsync({ force }) setMaintenanceMessage( force ? "Re-synchronisation complète IMAP terminée." : "Synchronisation IMAP terminée." ) } catch { setMaintenanceMessage("Échec de la synchronisation IMAP.") } } const maintenancePending = resanitizeBodies.isPending || syncAccount.isPending return (
{account.name} {account.email}

IMAP {account.imap_host} · SMTP {account.smtp_host} {account.last_sync_at ? ` · Dernière sync : ${new Date(account.last_sync_at).toLocaleString("fr-FR")}` : null}

void runResanitize()} > {resanitizeBodies.isPending ? "Réimportation IMAP…" : "Réimporter les corps depuis IMAP"} void runSync()} > {syncAccount.isPending ? "Synchronisation…" : "Synchroniser IMAP"} void runSync(true)} > Forcer re-sync complet
{maintenanceMessage ? (

{maintenanceMessage}

) : null} {editing ? ( setEditing(false)} /> ) : null}
) } function IdentitiesBlock({ accountId, accountEmail, identities, signatures, }: { accountId: string accountEmail: string identities: Array<{ id: string email: string name: string is_default: boolean signature_html?: string default_signature_id?: string reply_to_addrs?: string[] }> signatures: ApiMailSignature[] }) { const createIdentity = useCreateIdentity(accountId) const updateIdentity = useUpdateIdentity(accountId) const deleteIdentity = useDeleteIdentity(accountId) const [showAddForm, setShowAddForm] = useState(false) const [newIdentity, setNewIdentity] = useState({ email: accountEmail, name: "" }) const signatureOptions = useMemo( () => [ { value: NONE_SIGNATURE, label: "Aucune" }, ...signatures.map((s) => ({ value: s.id, label: s.name })), ], [signatures] ) useEffect(() => { if (!showAddForm) { setNewIdentity({ email: accountEmail, name: "" }) } }, [accountEmail, showAddForm]) function identityPayload( identity: (typeof identities)[number], patch: Partial<{ email: string name: string is_default: boolean default_signature_id: string }> = {} ) { return { identityId: identity.id, email: patch.email ?? identity.email, name: patch.name ?? identity.name, is_default: patch.is_default ?? identity.is_default, signature_html: identity.signature_html ?? "", default_signature_id: patch.default_signature_id ?? identity.default_signature_id ?? "", reply_to_addrs: identity.reply_to_addrs, } } function handleCreateIdentity() { const email = newIdentity.email.trim() const name = newIdentity.name.trim() if (!email) return createIdentity.mutate( { email, name: name || email.split("@")[0] || "Identité", is_default: identities.length === 0, }, { onSuccess: () => { setShowAddForm(false) setNewIdentity({ email: accountEmail, name: "" }) }, } ) } return (

Identités d'envoi

{identities.length === 0 ? (

Aucune identité configurée.

) : (
    {identities.map((identity) => { const currentSignature = identity.default_signature_id && identity.default_signature_id !== "" ? identity.default_signature_id : NONE_SIGNATURE return (
  • { const next = e.target.value.trim() if (!next || next === identity.name) return updateIdentity.mutate(identityPayload(identity, { name: next })) }} />
    { const next = e.target.value.trim() if (!next || next === identity.email) return updateIdentity.mutate(identityPayload(identity, { email: next })) }} />
    {identity.is_default ? (

    Identité par défaut

    ) : null}
  • ) })}
)} {showAddForm ? (
setNewIdentity({ ...newIdentity, name: e.target.value })} />
setNewIdentity({ ...newIdentity, email: e.target.value })} />
) : ( )}
) }