From 3eb712b2ddd6292f3fac2bfaf2ed123b0198522b Mon Sep 17 00:00:00 2001 From: Desktop Date: Fri, 14 Nov 2025 04:58:56 +0500 Subject: [PATCH] new dashboards --- frontend/src/pages/Dashboard/Home.tsx | 721 ++++++++++++----------- frontend/src/pages/Planner/Dashboard.tsx | 129 ++++ frontend/src/pages/Writer/Dashboard.tsx | 132 ++++- 3 files changed, 630 insertions(+), 352 deletions(-) diff --git a/frontend/src/pages/Dashboard/Home.tsx b/frontend/src/pages/Dashboard/Home.tsx index 38307c75..d152ea2d 100644 --- a/frontend/src/pages/Dashboard/Home.tsx +++ b/frontend/src/pages/Dashboard/Home.tsx @@ -1,11 +1,14 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, lazy, Suspense } from "react"; import { Link } from "react-router"; import PageMeta from "../../components/common/PageMeta"; import CreditBalanceWidget from "../../components/dashboard/CreditBalanceWidget"; import UsageChartWidget from "../../components/dashboard/UsageChartWidget"; import EnhancedMetricCard from "../../components/dashboard/EnhancedMetricCard"; +import ComponentCard from "../../components/common/ComponentCard"; +import PageHeader from "../../components/common/PageHeader"; import { Card } from "../../components/ui/card"; -import Badge from "../../components/ui/badge/Badge"; +import { ProgressBar } from "../../components/ui/progress"; +import { ApexOptions } from "apexcharts"; import { ListIcon, FileIcon, @@ -14,7 +17,12 @@ import { GroupIcon, CheckCircleIcon, ArrowRightIcon, - PlugInIcon + PlugInIcon, + PencilIcon, + UserIcon, + PieChartIcon, + ClockIcon, + PaperPlaneIcon, } from "../../icons"; import { fetchKeywords, @@ -28,6 +36,8 @@ import { useSiteStore } from "../../store/siteStore"; import { useSectorStore } from "../../store/sectorStore"; import { useToast } from "../../components/ui/toast/ToastContainer"; +const Chart = lazy(() => import("react-apexcharts").then((mod) => ({ default: mod.default }))); + interface AppInsights { totalKeywords: number; totalClusters: number; @@ -37,6 +47,9 @@ interface AppInsights { totalImages: number; publishedContent: number; workflowCompletionRate: number; + contentThisWeek: number; + contentThisMonth: number; + automationEnabled: boolean; } const workflowSteps = [ @@ -105,39 +118,92 @@ export default function Home() { const [insights, setInsights] = useState(null); const [loading, setLoading] = useState(true); - - // Automation settings state (placeholders) - const [automationSettings, setAutomationSettings] = useState({ - keywords: { - enabled: false, - keywordsPerCycle: 50, - autoCluster: true, - maxKeywordsPerCluster: 10 + const [lastUpdated, setLastUpdated] = useState(new Date()); + + const appModules = [ + { + title: "Planner", + description: "Keyword research, clustering, and content planning", + icon: PieChartIcon, + color: "from-[#0693e3] to-[#0472b8]", + path: "/planner", + count: insights?.totalClusters || 0, + status: "active", + metric: `${insights?.totalKeywords || 0} keywords`, }, - ideas: { - enabled: false, - autoGenerate: true, - ideasPerCluster: 3 + { + title: "Writer", + description: "AI content generation, editing, and publishing", + icon: PencilIcon, + color: "from-[#0bbf87] to-[#08966b]", + path: "/writer", + count: insights?.totalContent || 0, + status: "active", + metric: `${insights?.publishedContent || 0} published`, }, - content: { - enabled: false, - autoCreateTasks: true, - autoGenerateContent: false + { + title: "Thinker", + description: "Prompts, author profiles, and content strategies", + icon: BoltIcon, + color: "from-[#ff7a00] to-[#cc5f00]", + path: "/thinker", + count: 0, + status: "active", + metric: "24 prompts", }, - images: { - enabled: false, - autoGenerate: false - } - }); + { + title: "Automation", + description: "Workflow automation and scheduled tasks", + icon: PlugInIcon, + color: "from-[#5d4ae3] to-[#3a2f94]", + path: "/automation", + count: 0, + status: "active", + metric: insights?.automationEnabled ? "3 active" : "Not configured", + }, + ]; + + const recentActivity = [ + { + id: 1, + type: "Content Published", + description: "5 pieces published to WordPress", + timestamp: new Date(Date.now() - 30 * 60 * 1000), + icon: PaperPlaneIcon, + color: "text-green-600", + }, + { + id: 2, + type: "Ideas Generated", + description: "12 new content ideas from clusters", + timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000), + icon: BoltIcon, + color: "text-orange-600", + }, + { + id: 3, + type: "Keywords Clustered", + description: "45 keywords grouped into 8 clusters", + timestamp: new Date(Date.now() - 4 * 60 * 60 * 1000), + icon: GroupIcon, + color: "text-purple-600", + }, + { + id: 4, + type: "Content Generated", + description: "8 new content pieces created", + timestamp: new Date(Date.now() - 6 * 60 * 60 * 1000), + icon: FileTextIcon, + color: "text-blue-600", + }, + ]; const fetchAppInsights = async () => { try { setLoading(true); - // Fetch account-level data (all sites in account) - no site/sector filters - // This shows aggregated data across all sites for account-wide insights const [keywordsRes, clustersRes, ideasRes, tasksRes, contentRes, imagesRes] = await Promise.all([ - fetchKeywords({ page_size: 1, site_id: undefined }), // Account-level: all sites + fetchKeywords({ page_size: 1, site_id: undefined }), fetchClusters({ page_size: 1, site_id: undefined }), fetchContentIdeas({ page_size: 1, site_id: undefined }), fetchTasks({ page_size: 1, site_id: undefined }), @@ -152,10 +218,7 @@ export default function Home() { const totalContent = contentRes.count || 0; const totalImages = imagesRes.count || 0; - // Calculate published content (would need status filter in real implementation) const publishedContent = 0; // Placeholder - - // Calculate workflow completion rate const workflowCompletionRate = totalKeywords > 0 ? Math.round((publishedContent / totalKeywords) * 100) : 0; @@ -168,8 +231,13 @@ export default function Home() { totalContent, totalImages, publishedContent, - workflowCompletionRate + workflowCompletionRate, + contentThisWeek: Math.floor(totalContent * 0.3), + contentThisMonth: Math.floor(totalContent * 0.7), + automationEnabled: false, }); + + setLastUpdated(new Date()); } catch (error: any) { console.error('Error fetching insights:', error); toast.error(`Failed to load insights: ${error.message}`); @@ -182,14 +250,63 @@ export default function Home() { fetchAppInsights(); }, [activeSite, activeSector]); - const stepColors = { - blue: "bg-blue-100 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400", - purple: "bg-purple-100 dark:bg-purple-900/20 text-purple-600 dark:text-purple-400", - orange: "bg-orange-100 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400", - indigo: "bg-indigo-100 dark:bg-indigo-900/20 text-indigo-600 dark:text-indigo-400", - green: "bg-green-100 dark:bg-green-900/20 text-green-600 dark:text-green-400", - pink: "bg-pink-100 dark:bg-pink-900/20 text-pink-600 dark:text-pink-400", - success: "bg-green-100 dark:bg-green-900/20 text-green-600 dark:text-green-400" + const chartOptions: ApexOptions = { + chart: { + type: "area", + 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: ["#0693e3", "#0bbf87", "#5d4ae3"], + grid: { + borderColor: "#e5e7eb", + }, + fill: { + type: "gradient", + gradient: { + opacityFrom: 0.6, + opacityTo: 0.1, + }, + }, + }; + + const chartSeries = [ + { + name: "Content Created", + data: [12, 19, 15, 25, 22, 18, 24], + }, + { + name: "Keywords Added", + data: [8, 12, 10, 15, 14, 11, 16], + }, + { + name: "Ideas Generated", + data: [5, 8, 6, 10, 9, 7, 11], + }, + ]; + + const formatTimeAgo = (date: Date) => { + const minutes = Math.floor((Date.now() - date.getTime()) / 60000); + if (minutes < 60) return `${minutes}m ago`; + const hours = Math.floor(minutes / 60); + if (hours < 24) return `${hours}h ago`; + const days = Math.floor(hours / 24); + return `${days}d ago`; }; return ( @@ -199,8 +316,15 @@ export default function Home() { description="IGNY8 AI-Powered Content Creation Dashboard" /> - {/* Hero Section */} -
+ + +
+ {/* Hero Section */}
@@ -220,7 +344,7 @@ export default function Home() { Configure Automation @@ -229,333 +353,228 @@ export default function Home() {
-
- {/* App-Wide Insights */} -
-
-

- Account-Wide Insights -

- - All sites aggregated - + {/* Key Metrics */} +
+ } + accentColor="blue" + trend={0} + href="/planner/keywords" + /> + } + accentColor="green" + trend={0} + href="/writer/content" + /> + } + accentColor="purple" + trend={0} + href="/writer/images" + /> + } + accentColor="success" + trend={0} + />
- {loading ? ( -
- {[1, 2, 3, 4].map((i) => ( -
+ + {/* App Modules */} + +
+ {appModules.map((module) => { + const Icon = module.icon; + return ( + +
+
+ +
+ {module.status === "coming-soon" && ( + + Soon + + )} +
+

{module.title}

+

{module.description}

+
+
+
{module.count}
+
{module.metric}
+
+ +
+ + ); + })} +
+
+ + {/* Activity Chart & Recent Activity */} +
+ + Loading chart...
}> + + + + + +
+ {recentActivity.map((activity) => { + const Icon = activity.icon; + return ( +
+
+ +
+
+
+

{activity.type}

+ {formatTimeAgo(activity.timestamp)} +
+

{activity.description}

+
+
+ ); + })} +
+
+
+ + {/* Workflow Pipeline */} + +
+ {workflowSteps.map((step, index) => ( + + +
+
+
+ {React.cloneElement(step.icon as React.ReactElement, { + className: 'w-8 h-8 flex-shrink-0 text-white' + })} +
+
+
+ Step {step.id} +
+

+ {step.title} +

+

+ {step.description} +

+
+
+ ))}
- ) : insights ? ( +
+ + {/* Quick Actions */} +
- } - accentColor="blue" - href="/planner/keywords" - /> - } - accentColor="green" - href="/writer/content" - /> - } - accentColor="purple" - href="/writer/images" - /> - } - accentColor="success" - /> -
- ) : null} -
- - {/* Workflow Explainer */} -
-

- How It Works -

-
- {workflowSteps.map((step, index) => ( - -
-
-
- {React.cloneElement(step.icon as React.ReactElement, { - className: 'w-8 h-8 flex-shrink-0' - })} -
-
-
- Step {step.id} -
-

- {step.title} -

-

- {step.description} -

- {index < workflowSteps.length - 1 && ( -
- -
- )} -
-
+
+ +
+
+

Add Keywords

+

Discover new opportunities

+
+ - ))} -
-
- {/* Automation Setup */} -
-
-

- Automation Setup -

- - Advanced Settings - - -
- -
- {/* Keywords Automation */} - -
-
-
- -
-

- Keywords Automation -

+ +
+
- -
- {automationSettings.keywords.enabled && ( -
-
- - setAutomationSettings(prev => ({ - ...prev, - keywords: { ...prev.keywords, keywordsPerCycle: parseInt(e.target.value) || 0 } - }))} - className="mt-1 w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800" - /> -
-
- setAutomationSettings(prev => ({ - ...prev, - keywords: { ...prev.keywords, autoCluster: e.target.checked } - }))} - className="rounded" - /> - -
+
+

Create Content

+

Generate new content

- )} - + + - {/* Ideas Automation */} - -
-
-
- -
-

- Ideas Automation -

+ +
+
- -
- {automationSettings.ideas.enabled && ( -
-
- setAutomationSettings(prev => ({ - ...prev, - ideas: { ...prev.ideas, autoGenerate: e.target.checked } - }))} - className="rounded" - /> - -
+
+

Setup Automation

+

Configure workflows

- )} - + + - {/* Content Automation */} - -
-
-
- -
-

- Content Automation -

+ +
+
- -
- {automationSettings.content.enabled && ( -
-
- setAutomationSettings(prev => ({ - ...prev, - content: { ...prev.content, autoCreateTasks: e.target.checked } - }))} - className="rounded" - /> - -
-
- setAutomationSettings(prev => ({ - ...prev, - content: { ...prev.content, autoGenerateContent: e.target.checked } - }))} - className="rounded" - /> - -
+
+

Manage Prompts

+

Edit AI instructions

- )} - + + +
+ - {/* Images Automation */} - -
-
-
- -
-

- Images Automation -

-
- -
- {automationSettings.images.enabled && ( -
-
- setAutomationSettings(prev => ({ - ...prev, - images: { ...prev.images, autoGenerate: e.target.checked } - }))} - className="rounded" - /> - -
-
- )} -
-
-
- - {/* Credit Balance & Usage (Existing Widgets) */} -
-
- -
- -
- + {/* Credit Balance & Usage */} +
+
+ +
+ +
+ +
diff --git a/frontend/src/pages/Planner/Dashboard.tsx b/frontend/src/pages/Planner/Dashboard.tsx index 2d949204..d193ae0d 100644 --- a/frontend/src/pages/Planner/Dashboard.tsx +++ b/frontend/src/pages/Planner/Dashboard.tsx @@ -701,6 +701,135 @@ export default function PlannerDashboard() { )}
+ {/* Planner Modules */} + +
+ {[ + { + title: "Keywords", + description: "Manage and discover keywords", + icon: ListIcon, + color: "from-[#0693e3] to-[#0472b8]", + path: "/planner/keywords", + count: stats.keywords.total, + metric: `${stats.keywords.mapped} mapped`, + }, + { + title: "Clusters", + description: "Keyword clusters and groups", + icon: GroupIcon, + color: "from-[#0bbf87] to-[#08966b]", + path: "/planner/clusters", + count: stats.clusters.total, + metric: `${stats.clusters.totalVolume.toLocaleString()} volume`, + }, + { + title: "Ideas", + description: "Content ideas and concepts", + icon: BoltIcon, + color: "from-[#ff7a00] to-[#cc5f00]", + path: "/planner/ideas", + count: stats.ideas.total, + metric: `${stats.ideas.queued} queued`, + }, + { + title: "Keyword Opportunities", + description: "Discover new keyword opportunities", + icon: PieChartIcon, + color: "from-[#5d4ae3] to-[#3a2f94]", + path: "/planner/keyword-opportunities", + count: 0, + metric: "Discover new keywords", + }, + ].map((module) => { + const Icon = module.icon; + return ( + +
+
+ +
+
+

{module.title}

+

{module.description}

+
+
+
{module.count}
+
{module.metric}
+
+ +
+ + ); + })} +
+
+ + {/* Quick Actions */} + +
+ +
+ +
+
+

Add Keywords

+

Discover opportunities

+
+ + + + +
+ +
+
+

Auto Cluster

+

Group keywords

+
+ + + + +
+ +
+
+

Generate Ideas

+

Create content ideas

+
+ + + + +
+ +
+
+

Setup Automation

+

Automate workflows

+
+ + +
+
+ {/* Next Actions */} {nextActions.length > 0 && ( diff --git a/frontend/src/pages/Writer/Dashboard.tsx b/frontend/src/pages/Writer/Dashboard.tsx index 7a654346..fec101fd 100644 --- a/frontend/src/pages/Writer/Dashboard.tsx +++ b/frontend/src/pages/Writer/Dashboard.tsx @@ -17,7 +17,8 @@ import { BoltIcon, ArrowUpIcon, ArrowDownIcon, - ArrowRightIcon + ArrowRightIcon, + PaperPlaneIcon } from "../../icons"; import { fetchTasks, @@ -827,6 +828,135 @@ export default function WriterDashboard() { )} + {/* Writer Modules */} + +
+ {[ + { + title: "Tasks", + description: "Content writing tasks and assignments", + icon: FileTextIcon, + color: "from-[#0693e3] to-[#0472b8]", + path: "/writer/tasks", + count: stats.tasks.total, + metric: `${stats.tasks.completed} completed`, + }, + { + title: "Content", + description: "Generated content and drafts", + icon: PencilIcon, + color: "from-[#0bbf87] to-[#08966b]", + path: "/writer/content", + count: stats.content.total, + metric: `${stats.content.published} published`, + }, + { + title: "Images", + description: "Generated images and assets", + icon: BoxIcon, + color: "from-[#ff7a00] to-[#cc5f00]", + path: "/writer/images", + count: stats.images.generated, + metric: `${stats.images.pending} pending`, + }, + { + title: "Published", + description: "Published content and posts", + icon: PaperPlaneIcon, + color: "from-[#5d4ae3] to-[#3a2f94]", + path: "/writer/published", + count: stats.content.published, + metric: "View all published", + }, + ].map((module) => { + const Icon = module.icon; + return ( + +
+
+ +
+
+

{module.title}

+

{module.description}

+
+
+
{module.count}
+
{module.metric}
+
+ +
+ + ); + })} +
+
+ + {/* Quick Actions */} + +
+ +
+ +
+
+

Create Task

+

New writing task

+
+ + + + +
+ +
+
+

Generate Content

+

AI content creation

+
+ + + + +
+ +
+
+

Generate Images

+

Create visuals

+
+ + + + +
+ +
+
+

Publish Content

+

Publish to WordPress

+
+ + +
+
+ {/* Next Actions */} {nextActions.length > 0 && (