feat(CC-079): add Automation Builder page (8 templates with trigger/action + n8n integration)
This commit is contained in:
parent
d66dd56601
commit
170ab82e02
1 changed files with 171 additions and 0 deletions
171
src/app/dashboard/automations/page.tsx
Normal file
171
src/app/dashboard/automations/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue