104 lines
3.7 KiB
TypeScript
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>
|
|
)
|
|
}
|