"use client" import { useState, useCallback } from "react" import { type Editor } from "@tiptap/react" import { ChevronDown, Paperclip, Link as LinkIcon, HardDrive, Image as ImageIcon, Lock, PenTool, MoreVertical, Trash2, Type, Clock, Send, } from "lucide-react" import { type ComposeState, SIGNATURES, useComposeActions, } from "@/lib/compose-context" import { cn, getNextLocalWallClockDate } from "@/lib/utils" import { MAIL_COMPOSE_BOTTOM_ICON_BTN, MAIL_COMPOSE_BOTTOM_ICON_BTN_ACTIVE, MAIL_COMPOSE_MENU_SELECTED_CLASS, MAIL_COMPOSE_POPOVER_CLASS, MAIL_COMPOSE_PRIMARY_SEND_BTN, MAIL_MENU_SURFACE_CLASS, } from "@/lib/mail-chrome-classes" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover" import { COMPOSE_PORTAL_Z, insertSignatureHtml } from "./compose-shared" import { ComposeEmojiButton } from "./compose-emoji-picker" function ComposeLinkButton({ editor, }: { editor: Editor | null }) { const [open, setOpen] = useState(false) const [url, setUrl] = useState("") const [text, setText] = useState("") if (!editor) return null const isLinkActive = editor.isActive("link") const handleToggle = () => { if (isLinkActive) { editor.chain().focus().extendMarkRange("link").unsetLink().run() return } setOpen(true) } const handleOpen = (isOpen: boolean) => { if (isOpen) { const { from, to, empty } = editor.state.selection if (isLinkActive) { const attrs = editor.getAttributes("link") setUrl(attrs.href || "") const selectedText = editor.state.doc.textBetween(from, to, " ") setText(selectedText) } else if (!empty) { const selectedText = editor.state.doc.textBetween(from, to, " ") setText(selectedText) setUrl("") } else { setText("") setUrl("") } } setOpen(isOpen) } const handleInsert = () => { if (!url.trim()) return const href = url.match(/^https?:\/\//) ? url : `https://${url}` const { empty } = editor.state.selection if (empty && !isLinkActive) { const displayText = text.trim() || href editor .chain() .focus() .insertContent(`${displayText}`) .run() } else { if (text.trim() && text.trim() !== editor.state.doc.textBetween( editor.state.selection.from, editor.state.selection.to, " " )) { editor .chain() .focus() .deleteSelection() .insertContent(`${text.trim()}`) .run() } else { editor .chain() .focus() .extendMarkRange("link") .setLink({ href }) .run() } } setOpen(false) setUrl("") setText("") } const handleRemoveLink = () => { editor.chain().focus().extendMarkRange("link").unsetLink().run() setOpen(false) setUrl("") setText("") } return ( e.preventDefault()} >
{isLinkActive ? "Modifier le lien" : "Insérer un lien"}
setText(e.target.value)} placeholder="Texte du lien" className="h-8 rounded border border-border bg-mail-surface px-2 text-sm text-foreground outline-none focus:border-ring focus:ring-1 focus:ring-ring" />
setUrl(e.target.value)} placeholder="https://example.com" onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault() handleInsert() } }} className="h-8 rounded border border-border bg-mail-surface px-2 text-sm text-foreground outline-none focus:border-ring focus:ring-1 focus:ring-ring" autoFocus />
{isLinkActive ? ( ) : ( )}
) } export function ComposeSignatureButton({ editor, compose, }: { editor: Editor | null compose: ComposeState }) { const { updateCompose } = useComposeActions() const replaceSignature = useCallback( (sigId: string | null) => { if (!editor) return const newHtml = insertSignatureHtml(editor.getHTML(), sigId) editor.commands.setContent(newHtml) updateCompose(compose.id, { bodyHtml: newHtml, signatureId: sigId }) }, [editor, compose.id, updateCompose] ) const toggleAutoInsert = useCallback(() => { const newVal = !compose.autoInsertSignature updateCompose(compose.id, { autoInsertSignature: newVal }) if (!newVal) { replaceSignature(null) } else { const sigId = compose.from.defaultSignatureId if (sigId) replaceSignature(sigId) } }, [compose.autoInsertSignature, compose.from.defaultSignatureId, compose.id, updateCompose, replaceSignature]) if (!editor) return null return ( { e.preventDefault() toggleAutoInsert() }} className="gap-2" > {compose.autoInsertSignature && } Insérer automatiquement replaceSignature(null)} className={cn("gap-2", !compose.signatureId && MAIL_COMPOSE_MENU_SELECTED_CLASS)} > {!compose.signatureId && } Aucune signature {SIGNATURES.map((sig) => ( replaceSignature(sig.id)} className={cn("gap-2", compose.signatureId === sig.id && MAIL_COMPOSE_MENU_SELECTED_CLASS)} > {compose.signatureId === sig.id && } {sig.name} ))} ) } export interface ComposeBottomToolbarProps { compose: ComposeState editor: Editor | null isEditingScheduled: boolean showFormatting: boolean sendMenuOpen: boolean setShowFormatting: (v: boolean | ((prev: boolean) => boolean)) => void setSendMenuOpen: (v: boolean) => void handleSend: () => void saveScheduledEdit: () => void | Promise sendScheduledFromEditNow: () => void | Promise applyScheduledPlanAt: (sendAt: Date) => void | Promise submitScheduledSendAt: (sendAt: Date) => void | Promise handleClose: () => void fileInputRef: React.RefObject imageInputRef: React.RefObject } export function ComposeBottomToolbar(props: ComposeBottomToolbarProps) { const { compose, editor, isEditingScheduled, showFormatting, sendMenuOpen, setShowFormatting, setSendMenuOpen, handleSend, saveScheduledEdit, sendScheduledFromEditNow, applyScheduledPlanAt, submitScheduledSendAt, handleClose, fileInputRef, imageInputRef, } = props return (
{/* Send / save + dropdown */}
{isEditingScheduled ? ( <> { void sendScheduledFromEditNow() }} > Envoyer maintenant Planifier { void applyScheduledPlanAt( new Date(Date.now() + 60 * 60 * 1000) ) }} > Envoyer dans une heure { void applyScheduledPlanAt( getNextLocalWallClockDate(9, 0) ) }} > Envoyer à 9h ) : ( <> { void submitScheduledSendAt( new Date(Date.now() + 60 * 60 * 1000) ) }} > Envoyer dans une heure { void submitScheduledSendAt( getNextLocalWallClockDate(9, 0) ) }} > Envoyer à 9h setSendMenuOpen(false)}> Programmer l'envoi )}
{/* Toolbar icons */}
) }