ultisuite-client/components/gmail/email-view/email-view-details-popover.tsx
2026-05-25 13:52:40 +02:00

155 lines
4.6 KiB
TypeScript

"use client"
import { useEffect, useRef } from "react"
import { ChevronDown, Lock } from "lucide-react"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { MailDateText } from "@/components/gmail/mail-date-text"
import type { MessageHeaderDetails } from "@/lib/mail-message-header-details"
import { UnsubscribeActionButton } from "@/components/gmail/email-view/unsubscribe-action-button"
import { cn } from "@/lib/utils"
function DetailRow({
label,
children,
}: {
label: string
children: React.ReactNode
}) {
return (
<>
<dt className="text-right text-muted-foreground">{label}</dt>
<dd className="min-w-0 text-foreground">{children}</dd>
</>
)
}
export function EmailViewDetailsPopover({
summary,
details,
open,
onOpenChange,
isSpam,
messageId,
}: {
summary: string
details: MessageHeaderDetails
open: boolean
onOpenChange: (open: boolean) => void
isSpam?: boolean
messageId: string
}) {
const leaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const clearLeaveTimer = () => {
if (leaveTimerRef.current) {
clearTimeout(leaveTimerRef.current)
leaveTimerRef.current = null
}
}
const scheduleClose = () => {
clearLeaveTimer()
leaveTimerRef.current = setTimeout(() => onOpenChange(false), 150)
}
const keepOpen = () => {
clearLeaveTimer()
}
useEffect(() => () => clearLeaveTimer(), [])
useEffect(() => {
if (!open) clearLeaveTimer()
}, [open])
return (
<Popover open={open} onOpenChange={onOpenChange}>
<PopoverTrigger asChild>
<button
type="button"
className="flex items-center gap-0.5 text-xs text-muted-foreground hover:text-foreground"
onClick={(e) => e.stopPropagation()}
onMouseEnter={keepOpen}
onMouseLeave={() => {
if (open) scheduleClose()
}}
>
{summary}
<ChevronDown
className={cn("h-3 w-3 transition-transform", open && "rotate-180")}
aria-hidden
/>
</button>
</PopoverTrigger>
<PopoverContent
align="start"
side="bottom"
className="w-[min(100vw-2rem,28rem)] p-4"
onClick={(e) => e.stopPropagation()}
onPointerDownOutside={() => onOpenChange(false)}
onInteractOutside={() => onOpenChange(false)}
onEscapeKeyDown={() => onOpenChange(false)}
onMouseEnter={keepOpen}
onMouseLeave={scheduleClose}
>
<dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-xs leading-snug">
<DetailRow label="de :">{details.fromLine}</DetailRow>
{details.replyToLine ? (
<DetailRow label="répondre à :">{details.replyToLine}</DetailRow>
) : null}
<DetailRow label="à :">{details.toLine}</DetailRow>
<DetailRow label="date :">
<MailDateText iso={details.dateIso} variant="detail" />
</DetailRow>
<DetailRow label="objet :">{details.subject}</DetailRow>
{details.mailedBy ? (
<DetailRow label="envoyé par :">{details.mailedBy}</DetailRow>
) : null}
{details.signedBy ? (
<DetailRow label="signé par :">{details.signedBy}</DetailRow>
) : null}
{details.unsubscribe ? (
<>
<dt className="text-right text-muted-foreground">se désabonner :</dt>
<dd>
<UnsubscribeActionButton
action={details.unsubscribe}
messageId={messageId}
/>
</dd>
</>
) : null}
<dt className="text-right text-muted-foreground">sécurité :</dt>
<dd className="space-y-1">
{details.dkimPass === true ? (
<p>Signature DKIM conforme</p>
) : details.dkimPass === false ? (
<p className="text-amber-700 dark:text-amber-400">
Signature DKIM non conforme
</p>
) : null}
{details.tls ? (
<p className="flex items-center gap-1.5">
<Lock className="size-3.5 shrink-0 text-muted-foreground" />
Chiffrement standard (TLS)
</p>
) : null}
<p className="text-muted-foreground">
Chiffrement PGP : non disponible pour l&apos;instant
</p>
{isSpam ? (
<p className="text-destructive">
Ce message est marqué comme spam
</p>
) : null}
</dd>
</dl>
</PopoverContent>
</Popover>
)
}