stage2-2
This commit is contained in:
@@ -26,10 +26,14 @@ import {
|
||||
fetchKeywords,
|
||||
fetchClusters,
|
||||
fetchContentIdeas,
|
||||
fetchTasks
|
||||
fetchTasks,
|
||||
fetchSiteBlueprints,
|
||||
SiteBlueprint,
|
||||
} from "../../services/api";
|
||||
import { useSiteStore } from "../../store/siteStore";
|
||||
import { useSectorStore } from "../../store/sectorStore";
|
||||
import { Link } from "react-router";
|
||||
import Alert from "../../components/ui/alert/Alert";
|
||||
|
||||
interface DashboardStats {
|
||||
keywords: {
|
||||
@@ -70,18 +74,29 @@ export default function PlannerDashboard() {
|
||||
const [stats, setStats] = useState<DashboardStats | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [lastUpdated, setLastUpdated] = useState<Date>(new Date());
|
||||
const [incompleteBlueprints, setIncompleteBlueprints] = useState<SiteBlueprint[]>([]);
|
||||
|
||||
// Fetch real data
|
||||
const fetchDashboardData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const [keywordsRes, clustersRes, ideasRes, tasksRes] = await Promise.all([
|
||||
const [keywordsRes, clustersRes, ideasRes, tasksRes, blueprintsRes] = await Promise.all([
|
||||
fetchKeywords({ page_size: 1000, sector_id: activeSector?.id }),
|
||||
fetchClusters({ page_size: 1000, sector_id: activeSector?.id }),
|
||||
fetchContentIdeas({ page_size: 1000, sector_id: activeSector?.id }),
|
||||
fetchTasks({ page_size: 1000, sector_id: activeSector?.id })
|
||||
fetchTasks({ page_size: 1000, sector_id: activeSector?.id }),
|
||||
activeSite?.id ? fetchSiteBlueprints({ site_id: activeSite.id, page_size: 100 }) : Promise.resolve({ results: [] })
|
||||
]);
|
||||
|
||||
// Check for incomplete blueprints
|
||||
if (blueprintsRes.results) {
|
||||
const incomplete = blueprintsRes.results.filter((bp: SiteBlueprint) => {
|
||||
const workflow = bp.workflow_state;
|
||||
return workflow && !workflow.completed && workflow.blocking_reason;
|
||||
});
|
||||
setIncompleteBlueprints(incomplete);
|
||||
}
|
||||
|
||||
const keywords = keywordsRes.results || [];
|
||||
const mappedKeywords = keywords.filter(k => k.cluster && k.cluster.length > 0);
|
||||
@@ -458,6 +473,37 @@ export default function PlannerDashboard() {
|
||||
onRefresh={fetchDashboardData}
|
||||
/>
|
||||
|
||||
{/* Incomplete Blueprints Banner */}
|
||||
{incompleteBlueprints.length > 0 && (
|
||||
<Alert variant="warning" className="mb-6">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<strong className="block mb-2">Incomplete Site Builder Workflows</strong>
|
||||
<p className="text-sm mb-3">
|
||||
{incompleteBlueprints.length} blueprint{incompleteBlueprints.length > 1 ? 's' : ''} {incompleteBlueprints.length > 1 ? 'have' : 'has'} incomplete workflows that need attention:
|
||||
</p>
|
||||
<ul className="list-disc list-inside space-y-1 text-sm mb-3">
|
||||
{incompleteBlueprints.map((bp) => (
|
||||
<li key={bp.id}>
|
||||
<Link
|
||||
to={`/sites/builder/workflow/${bp.id}`}
|
||||
className="text-blue-600 dark:text-blue-400 hover:underline"
|
||||
>
|
||||
{bp.name}
|
||||
</Link>
|
||||
{bp.workflow_state?.blocking_reason && (
|
||||
<span className="text-gray-600 dark:text-gray-400 ml-2">
|
||||
- {bp.workflow_state.blocking_reason}
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="space-y-6">
|
||||
{/* Key Metrics */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
|
||||
Reference in New Issue
Block a user