155 lines
4.6 KiB
TypeScript
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'instant
|
|
</p>
|
|
{isSpam ? (
|
|
<p className="text-destructive">
|
|
Ce message est marqué comme spam
|
|
</p>
|
|
) : null}
|
|
</dd>
|
|
</dl>
|
|
</PopoverContent>
|
|
</Popover>
|
|
)
|
|
}
|