ultisuite-client/components/gmail/settings/automation/webhook-template-variables-panel.tsx
R3D347HR4Y 636b8cf789
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
Lots of changes to the API and webhooks
2026-06-07 16:02:55 +02:00

130 lines
4.5 KiB
TypeScript

"use client"
import { useCallback, useState } from "react"
import { Check, Copy } from "lucide-react"
import { toast } from "sonner"
import {
webhookVariableGroupsForDomains,
type WebhookTemplateVariable,
} from "@/lib/mail-automation/webhook-template-variables"
import {
AUTOMATION_DOMAIN_LABELS,
type AutomationDomain,
} from "@/lib/mail-automation/domains"
import { AutomationDomainFilterTab } from "@/components/gmail/settings/automation/automation-domain-mark"
import { cn } from "@/lib/utils"
const DOMAIN_TABS: Array<AutomationDomain | "all"> = ["all", "mail", "drive", "contacts"]
function VariableChip({
variable,
copied,
onCopy,
}: {
variable: WebhookTemplateVariable
copied: boolean
onCopy: (token: string) => void
}) {
return (
<button
type="button"
title={`${variable.label}${variable.description}`}
aria-label={`Copier ${variable.token}`}
onClick={() => onCopy(variable.token)}
className={cn(
"inline-flex max-w-full items-center gap-1 rounded-md border px-2 py-0.5 font-mono text-[11px] leading-snug transition-colors",
"border-border bg-muted/40 text-foreground hover:bg-accent hover:text-accent-foreground",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50",
copied && "border-primary/40 bg-primary/10 text-primary"
)}
>
{copied ? (
<Check className="size-3 shrink-0" aria-hidden />
) : (
<Copy className="size-3 shrink-0 opacity-60" aria-hidden />
)}
<span className="truncate">{variable.token}</span>
</button>
)
}
export function WebhookTemplateVariablesPanel() {
const [copiedToken, setCopiedToken] = useState<string | null>(null)
const [filter, setFilter] = useState<AutomationDomain | "all">("all")
const groups =
filter === "all"
? webhookVariableGroupsForDomains(["mail", "drive", "contacts"])
: webhookVariableGroupsForDomains([filter])
const copyToken = useCallback(async (token: string) => {
try {
await navigator.clipboard.writeText(token)
setCopiedToken(token)
toast.success(`${token} copié`)
window.setTimeout(() => {
setCopiedToken((current) => (current === token ? null : current))
}, 1500)
} catch {
toast.error("Impossible de copier la variable")
}
}, [])
return (
<div className="space-y-4 rounded-lg border border-border bg-muted/20 p-4">
<div className="space-y-2">
<p className="text-sm font-medium">Variables du template</p>
<p className="text-xs text-muted-foreground">
Variables selon le type d&apos;événement (mail, Drive, contacts). Les variables communes
($event.*, $date) fonctionnent partout.
</p>
<div className="flex flex-wrap gap-1">
{DOMAIN_TABS.map((tab) => (
<AutomationDomainFilterTab
key={tab}
domain={tab}
label={tab === "all" ? "Tout" : AUTOMATION_DOMAIN_LABELS[tab]}
active={filter === tab}
onClick={() => setFilter(tab)}
/>
))}
</div>
</div>
<div className="space-y-4">
{groups.map((group) => (
<section key={group.id} className="space-y-2">
<div>
<h3 className="text-xs font-medium">{group.label}</h3>
<p className="text-[11px] text-muted-foreground">{group.description}</p>
</div>
<ul className="space-y-2">
{group.variables.map((variable) => (
<li
key={variable.token}
className="flex flex-col gap-1.5 sm:flex-row sm:items-start sm:gap-3"
>
<VariableChip
variable={variable}
copied={copiedToken === variable.token}
onCopy={copyToken}
/>
<div className="min-w-0 flex-1 text-[11px] leading-snug">
<span className="font-medium text-foreground">{variable.label}</span>
<span className="text-muted-foreground"> {variable.description}</span>
{variable.example ? (
<span className="mt-0.5 block font-mono text-[10px] text-muted-foreground/80">
Ex. {variable.example}
</span>
) : null}
</div>
</li>
))}
</ul>
</section>
))}
</div>
</div>
)
}