ultisuite-client/components/gmail/settings/automation/rule-simulator-panel.tsx
2026-05-25 13:52:40 +02:00

104 lines
3.7 KiB
TypeScript

'use client'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Play } from 'lucide-react'
import { useSimulateMailRule } from '@/lib/api/hooks/use-mail-automation-queries'
import type { RuleEditorState, RuleSimulationResult } from '@/lib/mail-automation/types'
import { DEFAULT_SIMULATION_MESSAGE, workflowToApiPayload } from '@/lib/mail-automation/defaults'
interface RuleSimulatorPanelProps {
state: RuleEditorState
ruleId?: string
}
export function RuleSimulatorPanel({ state, ruleId }: RuleSimulatorPanelProps) {
const simulate = useSimulateMailRule()
const [message, setMessage] = useState(DEFAULT_SIMULATION_MESSAGE)
const [result, setResult] = useState<RuleSimulationResult | null>(null)
async function runSimulation() {
const payload = workflowToApiPayload(state)
const res = await simulate.mutateAsync({
message,
...(ruleId
? { rule_id: ruleId }
: {
rule: {
conditions: payload.conditions,
actions: payload.actions,
workflow: payload.workflow,
},
}),
})
setResult(res)
}
return (
<div className="space-y-3 rounded-lg border border-border bg-muted/10 p-3">
<p className="text-xs font-medium">Tester avec un message exemple</p>
<div className="grid gap-2 sm:grid-cols-2">
<div>
<Label className="text-[10px]">De</Label>
<Input className="h-8 text-xs" value={message.from} onChange={(e) => setMessage({ ...message, from: e.target.value })} />
</div>
<div>
<Label className="text-[10px]">Sujet</Label>
<Input className="h-8 text-xs" value={message.subject} onChange={(e) => setMessage({ ...message, subject: e.target.value })} />
</div>
</div>
<div>
<Label className="text-[10px]">Corps</Label>
<textarea
className="mt-1 min-h-16 w-full rounded-md border border-input bg-background px-2 py-1.5 text-xs"
value={message.body_text}
onChange={(e) => setMessage({ ...message, body_text: e.target.value })}
/>
</div>
<Button type="button" size="sm" disabled={simulate.isPending} onClick={runSimulation}>
<Play className="mr-1 size-3.5" />
Simuler
</Button>
{result ? (
<div className="space-y-2 rounded-md border border-border/60 bg-background p-2 text-xs">
<p>
Correspondance :{' '}
<span className={result.matched ? 'text-emerald-600' : 'text-muted-foreground'}>
{result.matched ? 'oui' : 'non'}
</span>
</p>
{result.steps?.length ? (
<div>
<p className="font-medium">Parcours</p>
<ol className="mt-1 list-decimal pl-4 text-muted-foreground">
{result.steps.map((s, i) => (
<li key={i}>
{s.node_type}
{s.handle ? `${s.handle}` : ''}
</li>
))}
</ol>
</div>
) : null}
{result.actions?.length ? (
<div>
<p className="font-medium">Actions</p>
<ul className="mt-1 space-y-0.5 text-muted-foreground">
{result.actions.map((a, i) => (
<li key={i}>
{a.type}
{a.value ? `: ${a.value}` : ''} {a.ok ? '✓' : `${a.error ?? ''}`}
</li>
))}
</ul>
</div>
) : null}
</div>
) : null}
</div>
)
}