feat(CC-079): add Automation Builder page (8 templates with trigger/action + n8n integration)

This commit is contained in:
admin-valentin 2026-08-02 12:58:14 +00:00
parent d66dd56601
commit 170ab82e02

View file

@ -0,0 +1,171 @@
'use client';
import { useState } from 'react';
import Link from 'next/link';
interface AutomationTemplate {
id: string; name: string; description: string; trigger: string; action: string;
category: string; icon: string; status: 'active' | 'planned'; n8nTemplate: string | null;
}
const TEMPLATES: AutomationTemplate[] = [
{
id: 'contact-followup', name: 'Follow-up automat contact', icon: '📞',
description: 'La 7 zile fără interacțiune cu un contact, creează task de follow-up.',
trigger: 'Inactivitate contact > 7 zile', action: 'Creează task + notificare',
category: 'CRM', status: 'planned', n8nTemplate: null,
},
{
id: 'contract-expiry', name: 'Alertă expirare contract', icon: '📋',
description: 'Cu 30 de zile înainte de expirarea unui contract, trimite alertă și task.',
trigger: 'Contract expiră în 30 zile', action: 'Email alertă + task reînnoire',
category: 'Contracte', status: 'planned', n8nTemplate: null,
},
{
id: 'ai-approval', name: 'Aprobare automată acțiuni AI', icon: '🤖',
description: 'Acțiunile AI cu prioritate scăzută se aprobă automat după 24h fără respingere.',
trigger: 'Acțiune AI pending > 24h', action: 'Auto-aprobare + execuție',
category: 'AI', status: 'planned', n8nTemplate: null,
},
{
id: 'gdpr-review', name: 'Revizuire periodică consimțăminte', icon: '🛡️',
description: 'Lunar, generează raport cu consimțămintele ce trebuie reînnoite.',
trigger: 'Schedulat: prima zi a lunii', action: 'Raport GDPR + task revizuire',
category: 'Privacy', status: 'planned', n8nTemplate: null,
},
{
id: 'goal-checkin', name: 'Check-in săptămânal obiective', icon: '🎯',
description: 'Vineri seara, trimite rezumat progres obiective și propune next steps.',
trigger: 'Schedulat: vineri 18:00', action: 'Raport obiective în notificări',
category: 'Life OS', status: 'planned', n8nTemplate: null,
},
{
id: 'data-backup', name: 'Backup export date', icon: '💾',
description: 'Exportă săptămânal toate datele CEO OS în format JSON și salvează în Hetzner.',
trigger: 'Schedulat: duminică 02:00', action: 'Export JSON + upload Hetzner',
category: 'Date', status: 'planned', n8nTemplate: null,
},
{
id: 'energy-reminder', name: 'Reminder jurnal energie', icon: '⚡',
description: 'La 21:00 zilnic, amintire să loghezi starea energetică.',
trigger: 'Schedulat: zilnic 21:00', action: 'Notificare push CEO OS',
category: 'Life OS', status: 'planned', n8nTemplate: null,
},
{
id: 'document-classify', name: 'Clasificare automată documente', icon: '📄',
description: 'Documentele noi fără clasificare sunt trimise la Hermes pentru clasificare automată.',
trigger: 'Document nou fără clasificare', action: 'Hermes clasificare → actualizare doc',
category: 'Documente', status: 'planned', n8nTemplate: null,
},
];
const CATEGORIES = ['all', 'CRM', 'Contracte', 'AI', 'Privacy', 'Life OS', 'Date', 'Documente'];
export default function AutomationBuilderPage() {
const [category, setCategory] = useState('all');
const [selected, setSelected] = useState<AutomationTemplate | null>(null);
const filtered = TEMPLATES.filter((t) => category === 'all' || t.category === category);
const active = TEMPLATES.filter((t) => t.status === 'active').length;
return (
<div className="max-w-5xl space-y-6 p-6">
<div>
<h1 className="font-display text-2xl font-semibold text-ink">Automation Builder</h1>
<p className="text-sm text-ink-faint mt-1">
{active} automații active · {TEMPLATES.length - active} planificate · Rulează prin n8n + Hermes
</p>
</div>
{/* n8n CTA */}
<div className="card p-4 bg-primary/5 border-primary/20 flex items-center justify-between gap-4 flex-wrap">
<div>
<p className="text-xs font-semibold text-ink">n8n este orchestratorul de automatizări</p>
<p className="text-xs text-ink-faint">Configurează și gestionează workflow-urile avansate direct în n8n.</p>
</div>
<Link href="http://n8n.boardmind.dev" target="_blank" rel="noopener"
className="rounded-lg border px-4 py-2 text-sm text-ink hover:bg-muted/50 whitespace-nowrap">
Deschide n8n
</Link>
</div>
<div className="flex flex-wrap gap-1">
{CATEGORIES.map((c) => (
<button key={c} onClick={() => setCategory(c)}
className={`rounded-full border px-3 py-1 text-xs ${category === c ? 'bg-primary/10 border-primary text-ink' : 'bg-card border-border text-ink-faint'}`}>
{c === 'all' ? 'Toate' : c}
</button>
))}
</div>
<div className="grid gap-4 lg:grid-cols-3">
<div className="lg:col-span-2 grid gap-3 sm:grid-cols-2">
{filtered.map((tmpl) => (
<button key={tmpl.id} onClick={() => setSelected(tmpl)}
className={`card p-4 text-left hover:border-primary/40 transition-colors ${selected?.id === tmpl.id ? 'border-primary/50 bg-primary/5' : ''}`}>
<div className="flex items-center gap-2 mb-2">
<span className="text-xl">{tmpl.icon}</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-ink line-clamp-1">{tmpl.name}</p>
<p className="text-[9px] text-ink-faint">{tmpl.category}</p>
</div>
<span className={`shrink-0 rounded-full px-1.5 py-0.5 text-[8px] font-bold ${tmpl.status === 'active' ? 'bg-signal-ok/10 text-signal-ok' : 'bg-muted text-ink-faint'}`}>
{tmpl.status}
</span>
</div>
<p className="text-[10px] text-ink-faint line-clamp-2">{tmpl.description}</p>
</button>
))}
</div>
<div>
{!selected ? (
<div className="card p-6 text-center space-y-2">
<p className="text-2xl"></p>
<p className="text-xs text-ink-faint">Selectează un template.</p>
</div>
) : (
<div className="card p-5 space-y-4 sticky top-4">
<div className="flex items-center gap-2">
<span className="text-2xl">{selected.icon}</span>
<p className="text-sm font-semibold text-ink">{selected.name}</p>
</div>
<p className="text-xs text-ink-faint">{selected.description}</p>
<div className="space-y-2 text-xs">
<div className="flex items-start gap-2">
<span className="text-ink-faint shrink-0 w-14">Trigger:</span>
<span className="text-ink">{selected.trigger}</span>
</div>
<div className="flex items-start gap-2">
<span className="text-ink-faint shrink-0 w-14">Acțiune:</span>
<span className="text-ink">{selected.action}</span>
</div>
<div className="flex items-start gap-2">
<span className="text-ink-faint shrink-0 w-14">Categorie:</span>
<span className="text-ink">{selected.category}</span>
</div>
</div>
{selected.status === 'active' ? (
<button className="w-full rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white hover:bg-primary/90">
Configurează
</button>
) : (
<div className="space-y-2">
<div className="rounded-lg bg-muted px-4 py-2 text-center text-xs text-ink-faint">
Planificat necesită n8n workflow
</div>
<Link href="http://n8n.boardmind.dev" target="_blank" rel="noopener"
className="block w-full rounded-lg border px-4 py-2 text-center text-xs text-ink hover:bg-muted/50">
Construiește în n8n
</Link>
</div>
)}
</div>
)}
</div>
</div>
</div>
);
}