Files
igny8/frontend/src/pages/Automation/Dashboard.tsx
Desktop 628620406d sd
2025-11-14 07:24:20 +05:00

481 lines
18 KiB
TypeScript

import { useEffect, useState, lazy, Suspense } from "react";
import { Link, useNavigate } from "react-router";
import PageMeta from "../../components/common/PageMeta";
import ComponentCard from "../../components/common/ComponentCard";
import { ProgressBar } from "../../components/ui/progress";
import { ApexOptions } from "apexcharts";
import EnhancedMetricCard from "../../components/dashboard/EnhancedMetricCard";
import PageHeader from "../../components/common/PageHeader";
const Chart = lazy(() => import("react-apexcharts").then((mod) => ({ default: mod.default })));
import {
BoltIcon,
ClockIcon,
CheckCircleIcon,
ArrowRightIcon,
CalendarIcon,
ListIcon,
GroupIcon,
FileTextIcon,
ArrowUpIcon,
ArrowDownIcon,
PaperPlaneIcon,
CloseIcon,
FileIcon,
} from "../../icons";
import { useSiteStore } from "../../store/siteStore";
import { useSectorStore } from "../../store/sectorStore";
interface AutomationStats {
activeWorkflows: number;
scheduledTasks: number;
completedToday: number;
successRate: number;
automationCoverage: {
keywords: boolean;
clustering: boolean;
ideas: boolean;
tasks: boolean;
content: boolean;
images: boolean;
publishing: boolean;
};
recentActivity: Array<{
id: number;
type: string;
status: string;
timestamp: Date;
itemsProcessed: number;
}>;
}
export default function AutomationDashboard() {
const navigate = useNavigate();
const { activeSite } = useSiteStore();
const { activeSector } = useSectorStore();
const [stats, setStats] = useState<AutomationStats | null>(null);
const [loading, setLoading] = useState(true);
const [lastUpdated, setLastUpdated] = useState<Date>(new Date());
// Mock data for now - will be replaced with real API calls
useEffect(() => {
const fetchData = async () => {
setLoading(true);
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 500));
setStats({
activeWorkflows: 3,
scheduledTasks: 12,
completedToday: 47,
successRate: 94.5,
automationCoverage: {
keywords: true,
clustering: true,
ideas: true,
tasks: false,
content: true,
images: true,
publishing: false,
},
recentActivity: [
{
id: 1,
type: "Content Generation",
status: "completed",
timestamp: new Date(Date.now() - 15 * 60 * 1000),
itemsProcessed: 5,
},
{
id: 2,
type: "Image Generation",
status: "completed",
timestamp: new Date(Date.now() - 45 * 60 * 1000),
itemsProcessed: 8,
},
{
id: 3,
type: "Keyword Clustering",
status: "completed",
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000),
itemsProcessed: 12,
},
],
});
setLastUpdated(new Date());
setLoading(false);
};
fetchData();
}, [activeSite, activeSector]);
const automationWorkflows = [
{
id: 1,
name: "Full Pipeline Automation",
description: "Keywords → Clusters → Ideas → Tasks → Content → Images → Publish",
status: "active",
schedule: "Every 6 hours",
lastRun: "2 hours ago",
nextRun: "4 hours",
coverage: 85,
icon: PaperPlaneIcon,
color: "from-[var(--igny8-purple)] to-[var(--igny8-purple-dark)]",
},
{
id: 2,
name: "Writer Workflow",
description: "Tasks → Content → Images → Publishing",
status: "active",
schedule: "Every 3 hours",
lastRun: "1 hour ago",
nextRun: "2 hours",
coverage: 92,
icon: FileTextIcon,
color: "from-[var(--igny8-green)] to-[var(--igny8-green-dark)]",
},
{
id: 3,
name: "Planner Workflow",
description: "Keywords → Clusters → Ideas",
status: "active",
schedule: "Every 6 hours",
lastRun: "3 hours ago",
nextRun: "3 hours",
coverage: 78,
icon: ListIcon,
color: "from-[var(--igny8-blue)] to-[var(--igny8-blue-dark)]",
},
];
const automationSteps = [
{
step: "Keywords",
enabled: true,
description: "Auto-add keywords from opportunities",
path: "/planner/keyword-opportunities",
icon: ListIcon,
},
{
step: "Clustering",
enabled: true,
description: "Auto-cluster keywords into groups",
path: "/planner/clusters",
icon: GroupIcon,
},
{
step: "Ideas",
enabled: true,
description: "Auto-generate content ideas from clusters",
path: "/planner/ideas",
icon: BoltIcon,
},
{
step: "Tasks",
enabled: false,
description: "Auto-create tasks from ideas",
path: "/writer/tasks",
icon: CheckCircleIcon,
},
{
step: "Content",
enabled: true,
description: "Auto-generate content from tasks",
path: "/writer/content",
icon: FileTextIcon,
},
{
step: "Images",
enabled: true,
description: "Auto-generate images for content",
path: "/writer/images",
icon: FileIcon,
},
{
step: "Publishing",
enabled: false,
description: "Auto-publish content to WordPress",
path: "/writer/published",
icon: PaperPlaneIcon,
},
];
const chartOptions: ApexOptions = {
chart: {
type: "line",
height: 300,
toolbar: { show: false },
zoom: { enabled: false },
},
stroke: {
curve: "smooth",
width: 3,
},
xaxis: {
categories: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
labels: { style: { colors: "#6b7280" } },
},
yaxis: {
labels: { style: { colors: "#6b7280" } },
},
legend: {
position: "top",
labels: { colors: "#6b7280" },
},
colors: ["var(--igny8-blue)", "var(--igny8-green)", "var(--igny8-purple)"],
grid: {
borderColor: "#e5e7eb",
},
};
const chartSeries = [
{
name: "Automated",
data: [12, 19, 15, 25, 22, 18, 24],
},
{
name: "Manual",
data: [5, 8, 6, 10, 9, 7, 11],
},
{
name: "Failed",
data: [1, 2, 1, 2, 1, 2, 1],
},
];
return (
<>
<PageMeta title="Automation Dashboard - IGNY8" description="Manage and monitor automation workflows" />
<PageHeader title="Automation Dashboard" />
<div className="space-y-6">
{/* Key Metrics */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<EnhancedMetricCard
title="Active Workflows"
value={stats?.activeWorkflows || 0}
icon={<BoltIcon className="size-6" />}
trend={0}
accentColor="purple"
/>
<EnhancedMetricCard
title="Scheduled Tasks"
value={stats?.scheduledTasks || 0}
icon={<CalendarIcon className="size-6" />}
trend={0}
accentColor="blue"
/>
<EnhancedMetricCard
title="Completed Today"
value={stats?.completedToday || 0}
icon={<CheckCircleIcon className="size-6" />}
trend={0}
accentColor="green"
/>
<EnhancedMetricCard
title="Success Rate"
value={`${stats?.successRate || 0}%`}
icon={<PaperPlaneIcon className="size-6" />}
trend={0}
accentColor="orange"
/>
</div>
{/* Automation Workflows */}
<ComponentCard title="Automation Workflows" desc="Manage your automated content pipelines">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{automationWorkflows.map((workflow) => {
const Icon = workflow.icon;
return (
<div
key={workflow.id}
className="rounded-2xl border-2 border-slate-200 bg-white p-6 hover:shadow-lg transition-all"
>
<div className="flex items-start justify-between mb-4">
<div className={`inline-flex size-12 rounded-xl bg-gradient-to-br ${workflow.color} items-center justify-center text-white shadow-lg`}>
<Icon className="h-6 w-6" />
</div>
<span className={`inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold ${
workflow.status === "active"
? "bg-green-100 text-green-700"
: "bg-gray-100 text-gray-700"
}`}>
{workflow.status}
</span>
</div>
<h3 className="text-lg font-bold text-slate-900 mb-2">{workflow.name}</h3>
<p className="text-sm text-slate-600 mb-4">{workflow.description}</p>
<div className="space-y-2 mb-4">
<div className="flex items-center justify-between text-xs text-slate-600">
<span>Schedule:</span>
<span className="font-semibold">{workflow.schedule}</span>
</div>
<div className="flex items-center justify-between text-xs text-slate-600">
<span>Last Run:</span>
<span>{workflow.lastRun}</span>
</div>
<div className="flex items-center justify-between text-xs text-slate-600">
<span>Next Run:</span>
<span className="font-semibold text-[var(--igny8-blue)]">{workflow.nextRun}</span>
</div>
</div>
<div className="mb-4">
<div className="flex items-center justify-between text-xs text-slate-600 mb-1">
<span>Coverage</span>
<span className="font-semibold">{workflow.coverage}%</span>
</div>
<ProgressBar value={workflow.coverage} className="h-2" />
</div>
<div className="flex gap-2">
<button className="flex-1 inline-flex items-center justify-center gap-2 rounded-lg bg-slate-100 text-slate-700 px-4 py-2 text-sm font-semibold hover:bg-slate-200 transition">
<CloseIcon className="h-4 w-4" />
Pause
</button>
<button className="flex-1 inline-flex items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-[var(--igny8-blue)] to-[var(--igny8-blue-dark)] text-white px-4 py-2 text-sm font-semibold hover:shadow-lg transition">
<PaperPlaneIcon className="h-4 w-4" />
Run Now
</button>
</div>
</div>
);
})}
</div>
</ComponentCard>
{/* Automation Steps Configuration */}
<ComponentCard title="Automation Steps" desc="Configure which steps are automated">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{automationSteps.map((step, index) => {
const Icon = step.icon;
const isEnabled = stats?.automationCoverage[step.step.toLowerCase() as keyof typeof stats.automationCoverage] || false;
return (
<Link
key={step.step}
to={step.path}
className="rounded-xl border-2 border-slate-200 bg-white p-5 hover:shadow-lg transition-all group"
>
<div className="flex items-center justify-between mb-3">
<div className={`inline-flex size-10 rounded-lg bg-gradient-to-br ${
isEnabled
? "from-[var(--igny8-green)] to-[var(--igny8-green-dark)]"
: "from-slate-300 to-slate-400"
} items-center justify-center text-white shadow-md`}>
<Icon className="h-5 w-5" />
</div>
<div className={`size-5 rounded-full border-2 flex items-center justify-center ${
isEnabled
? "border-[var(--igny8-green)] bg-[var(--igny8-green)]"
: "border-slate-300 bg-white"
}`}>
{isEnabled && <CheckCircleIcon className="h-3 w-3 text-white" />}
</div>
</div>
<h4 className="font-semibold text-slate-900 mb-1">{step.step}</h4>
<p className="text-xs text-slate-600">{step.description}</p>
<div className="mt-3 flex items-center gap-1 text-xs text-[var(--igny8-blue)] opacity-0 group-hover:opacity-100 transition">
<span>Configure</span>
<ArrowRightIcon className="h-3 w-3" />
</div>
</Link>
);
})}
</div>
</ComponentCard>
{/* Activity Chart */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<ComponentCard title="Automation Activity" desc="Last 7 days of automation activity">
<Suspense fallback={<div className="h-[300px] flex items-center justify-center">Loading chart...</div>}>
<Chart options={chartOptions} series={chartSeries} type="line" height={300} />
</Suspense>
</ComponentCard>
{/* Recent Activity */}
<ComponentCard title="Recent Activity" desc="Latest automation executions">
<div className="space-y-4">
{stats?.recentActivity.map((activity) => (
<div
key={activity.id}
className="flex items-center gap-4 p-4 rounded-lg border border-slate-200 bg-white"
>
<div className="size-10 rounded-lg bg-gradient-to-br from-[var(--igny8-blue)] to-[var(--igny8-blue-dark)] flex items-center justify-center text-white shadow-md">
<BoltIcon className="h-5 w-5" />
</div>
<div className="flex-1">
<div className="flex items-center justify-between mb-1">
<h4 className="font-semibold text-slate-900">{activity.type}</h4>
<span className={`text-xs px-2 py-1 rounded-full ${
activity.status === "completed"
? "bg-green-100 text-green-700"
: "bg-yellow-100 text-yellow-700"
}`}>
{activity.status}
</span>
</div>
<div className="flex items-center gap-4 text-xs text-slate-600">
<span>{activity.itemsProcessed} items processed</span>
<span></span>
<span>{new Date(activity.timestamp).toLocaleTimeString()}</span>
</div>
</div>
</div>
))}
</div>
</ComponentCard>
</div>
{/* Quick Actions */}
<ComponentCard title="Quick Actions" desc="Manually trigger automation workflows">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => navigate("/planner/keyword-opportunities")}
className="flex items-center gap-4 p-6 rounded-xl border-2 border-slate-200 bg-white hover:border-[#0693e3] hover:shadow-lg transition-all group"
>
<div className="size-12 rounded-xl bg-gradient-to-br from-[var(--igny8-blue)] to-[var(--igny8-blue-dark)] flex items-center justify-center text-white shadow-lg">
<ListIcon className="h-6 w-6" />
</div>
<div className="flex-1 text-left">
<h4 className="font-semibold text-slate-900 mb-1">Run Planner Workflow</h4>
<p className="text-sm text-slate-600">Keywords Clusters Ideas</p>
</div>
<ArrowRightIcon className="h-5 w-5 text-slate-400 group-hover:text-[var(--igny8-blue)] transition" />
</button>
<button
onClick={() => navigate("/writer/tasks")}
className="flex items-center gap-4 p-6 rounded-xl border-2 border-slate-200 bg-white hover:border-[#0bbf87] hover:shadow-lg transition-all group"
>
<div className="size-12 rounded-xl bg-gradient-to-br from-[var(--igny8-green)] to-[var(--igny8-green-dark)] flex items-center justify-center text-white shadow-lg">
<FileTextIcon className="h-6 w-6" />
</div>
<div className="flex-1 text-left">
<h4 className="font-semibold text-slate-900 mb-1">Run Writer Workflow</h4>
<p className="text-sm text-slate-600">Tasks Content Images</p>
</div>
<ArrowRightIcon className="h-5 w-5 text-slate-400 group-hover:text-[#0bbf87] transition" />
</button>
<button
onClick={() => navigate("/writer/published")}
className="flex items-center gap-4 p-6 rounded-xl border-2 border-slate-200 bg-white hover:border-[#5d4ae3] hover:shadow-lg transition-all group"
>
<div className="size-12 rounded-xl bg-gradient-to-br from-[var(--igny8-purple)] to-[var(--igny8-purple-dark)] flex items-center justify-center text-white shadow-lg">
<PaperPlaneIcon className="h-6 w-6" />
</div>
<div className="flex-1 text-left">
<h4 className="font-semibold text-slate-900 mb-1">Run Full Pipeline</h4>
<p className="text-sm text-slate-600">Complete end-to-end automation</p>
</div>
<ArrowRightIcon className="h-5 w-5 text-slate-400 group-hover:text-[#5d4ae3] transition" />
</button>
</div>
</ComponentCard>
</div>
</>
);
}