diff --git a/src/App.tsx b/src/App.tsx index adead74..51692ad 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,7 +27,9 @@ import { FileText, ArrowsClockwise, BookOpen, - Recycle + Recycle, + Sparkle, + GlobeHemisphereWest } from '@phosphor-icons/react' import { cn } from '@/lib/utils' import StrategyCards from './components/StrategyCards' @@ -55,6 +57,9 @@ import PDCACycleTracking from './components/PDCACycleTracking' import CountermeasureManagement from './components/CountermeasureManagement' import RationaleDecisionCapture from './components/RationaleDecisionCapture' import LeanProcessSupport from './components/LeanProcessSupport' +import StrategyFrameworkWizard from './components/StrategyFrameworkWizard' +import DrillDownReporting from './components/DrillDownReporting' +import MultiRegionReporting from './components/MultiRegionReporting' import type { StrategyCard, Initiative } from './types' type NavigationItem = { @@ -76,6 +81,7 @@ const navigationSections: NavigationSection[] = [ label: 'Planning', items: [ { id: 'strategy', label: 'Strategy Cards', icon: Strategy, component: StrategyCards }, + { id: 'guided-strategy', label: 'Guided Strategy Creation', icon: Sparkle, component: StrategyFrameworkWizard }, { id: 'comparison', label: 'Compare', icon: ArrowsLeftRight, component: StrategyComparison }, { id: 'traceability', label: 'Traceability', icon: Tree, component: StrategyTraceability }, { id: 'strategy-to-initiative', label: 'Strategy to Initiative', icon: ArrowsDownUp, component: StrategyToInitiative }, @@ -110,6 +116,7 @@ const navigationSections: NavigationSection[] = [ { id: 'lean-process', label: 'Lean Process Support', icon: Recycle, component: LeanProcessSupport }, { id: 'countermeasures', label: 'Countermeasure Management', icon: Target, component: CountermeasureManagement }, { id: 'pdca', label: 'PDCA Cycle Tracking', icon: ArrowsClockwise, component: PDCACycleTracking }, + { id: 'multi-region', label: 'Multi-Region Reporting', icon: GlobeHemisphereWest, component: MultiRegionReporting }, ] }, { @@ -125,6 +132,7 @@ const navigationSections: NavigationSection[] = [ label: 'Reporting', items: [ { id: 'executive-dashboard', label: 'Executive Dashboard', icon: ChartLineUp, component: ExecutiveDashboard }, + { id: 'drill-down', label: 'Drill-Down Reporting', icon: ChartBar, component: DrillDownReporting }, { id: 'dashboard', label: 'Performance Dashboard', icon: Target, component: Dashboard }, { id: 'kpi', label: 'KPI Scorecard', icon: ChartLine, component: KPIDashboard }, { id: 'custom-scorecard', label: 'Custom Scorecards', icon: Presentation, component: CustomScorecard }, @@ -321,6 +329,7 @@ function App() { function getModuleDescription(moduleId: string): string { const descriptions: Record = { 'strategy': 'Create and manage strategic frameworks using proven methodologies', + 'guided-strategy': 'Step-by-step wizard for comprehensive strategy formulation', 'comparison': 'Compare multiple strategic options side-by-side', 'traceability': 'Map relationships from goals to initiatives', 'strategy-to-initiative': 'AI-powered translation of strategy into executable initiatives', @@ -337,9 +346,11 @@ function getModuleDescription(moduleId: string): string { 'lean-process': 'Lean methodology principles, tools and templates', 'countermeasures': 'Track improvement actions beyond KPI reporting', 'pdca': 'Plan-Do-Check-Act continuous improvement cycles', + 'multi-region': 'Consistent reporting and analytics across global units', 'roadmap': 'Visualize strategic timeline and milestones', 'product-roadmap': 'Plan and track product development initiatives', 'executive-dashboard': 'Executive-level strategic performance overview', + 'drill-down': 'Navigate from enterprise level to detailed project information', 'dashboard': 'Real-time performance metrics and insights', 'kpi': 'Monitor key performance indicators and metrics', 'custom-scorecard': 'Create and manage configurable performance scorecards', diff --git a/src/components/DrillDownReporting.tsx b/src/components/DrillDownReporting.tsx new file mode 100644 index 0000000..776154c --- /dev/null +++ b/src/components/DrillDownReporting.tsx @@ -0,0 +1,747 @@ +import { useKV } from '@github/spark/hooks' +import { useState } from 'react' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Button } from '@/components/ui/button' +import { Badge } from '@/components/ui/badge' +import { Progress } from '@/components/ui/progress' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { + ArrowLeft, + ChartLine, + Target, + Rocket, + TrendUp, + ChartBar, + FolderOpen, + CurrencyDollar, + Calendar, + Users +} from '@phosphor-icons/react' +import { cn } from '@/lib/utils' +import type { StrategyCard, Initiative, PortfolioType } from '../types' + +type ViewLevel = 'enterprise' | 'portfolio' | 'strategy' | 'initiative' + +interface BreadcrumbItem { + level: ViewLevel + label: string + id?: string +} + +export default function DrillDownReporting() { + const [strategyCards] = useKV('strategy-cards', []) + const [initiatives] = useKV('initiatives', []) + + const [breadcrumbs, setBreadcrumbs] = useState([ + { level: 'enterprise', label: 'Enterprise Overview' } + ]) + + const currentLevel = breadcrumbs[breadcrumbs.length - 1].level + const currentId = breadcrumbs[breadcrumbs.length - 1].id + + const navigateTo = (level: ViewLevel, label: string, id?: string) => { + const existingIndex = breadcrumbs.findIndex(b => b.level === level && b.id === id) + if (existingIndex >= 0) { + setBreadcrumbs(breadcrumbs.slice(0, existingIndex + 1)) + } else { + setBreadcrumbs([...breadcrumbs, { level, label, id }]) + } + } + + const goBack = () => { + if (breadcrumbs.length > 1) { + setBreadcrumbs(breadcrumbs.slice(0, -1)) + } + } + + const portfolios: { type: PortfolioType; name: string; color: string }[] = [ + { type: 'operational-excellence', name: 'Operational Excellence', color: 'bg-blue-500' }, + { type: 'ma', name: 'M&A Integration', color: 'bg-purple-500' }, + { type: 'financial-transformation', name: 'Financial Transformation', color: 'bg-green-500' }, + { type: 'esg', name: 'ESG Initiatives', color: 'bg-teal-500' }, + { type: 'innovation', name: 'Innovation & Growth', color: 'bg-orange-500' } + ] + + const getPortfolioInitiatives = (portfolioType: PortfolioType) => { + return (initiatives || []).filter(i => i.portfolio === portfolioType) + } + + const getStrategyInitiatives = (strategyId: string) => { + return (initiatives || []).filter(i => i.strategyCardId === strategyId) + } + + const calculatePortfolioMetrics = (portfolioType: PortfolioType) => { + const portfolioInitiatives = getPortfolioInitiatives(portfolioType) + const totalBudget = portfolioInitiatives.reduce((sum, i) => sum + (i.budget || 0), 0) + const avgProgress = portfolioInitiatives.length > 0 + ? portfolioInitiatives.reduce((sum, i) => sum + i.progress, 0) / portfolioInitiatives.length + : 0 + const onTrack = portfolioInitiatives.filter(i => i.status === 'on-track').length + const atRisk = portfolioInitiatives.filter(i => i.status === 'at-risk').length + const blocked = portfolioInitiatives.filter(i => i.status === 'blocked').length + + return { + total: portfolioInitiatives.length, + totalBudget, + avgProgress, + onTrack, + atRisk, + blocked + } + } + + const calculateStrategyMetrics = (strategyId: string) => { + const strategyInitiatives = getStrategyInitiatives(strategyId) + const totalBudget = strategyInitiatives.reduce((sum, i) => sum + (i.budget || 0), 0) + const avgProgress = strategyInitiatives.length > 0 + ? strategyInitiatives.reduce((sum, i) => sum + i.progress, 0) / strategyInitiatives.length + : 0 + + return { + total: strategyInitiatives.length, + totalBudget, + avgProgress, + statusBreakdown: { + 'on-track': strategyInitiatives.filter(i => i.status === 'on-track').length, + 'at-risk': strategyInitiatives.filter(i => i.status === 'at-risk').length, + 'blocked': strategyInitiatives.filter(i => i.status === 'blocked').length, + 'completed': strategyInitiatives.filter(i => i.status === 'completed').length, + 'not-started': strategyInitiatives.filter(i => i.status === 'not-started').length + } + } + } + + const renderEnterpriseView = () => { + const totalInitiatives = (initiatives || []).length + const totalStrategies = (strategyCards || []).length + const totalBudget = (initiatives || []).reduce((sum, i) => sum + (i.budget || 0), 0) + const avgProgress = totalInitiatives > 0 + ? (initiatives || []).reduce((sum, i) => sum + i.progress, 0) / totalInitiatives + : 0 + + return ( +
+
+

Enterprise Overview

+

+ Complete view of all strategic initiatives across the organization +

+
+ +
+ + +
+ + Strategies +
+
+ +
{totalStrategies}
+
+
+ + + +
+ + Initiatives +
+
+ +
{totalInitiatives}
+
+
+ + + +
+ + Total Budget +
+
+ +
${(totalBudget / 1000000).toFixed(1)}M
+
+
+ + + +
+ + Avg Progress +
+
+ +
{Math.round(avgProgress)}%
+
+
+
+ +
+

Portfolios

+
+ {portfolios.map((portfolio) => { + const metrics = calculatePortfolioMetrics(portfolio.type) + return ( + navigateTo('portfolio', portfolio.name, portfolio.type)} + > + +
+
+ +
+
+ {portfolio.name} + + {metrics.total} initiatives • ${(metrics.totalBudget / 1000000).toFixed(1)}M budget + +
+
+
+ +
+
+ Progress + {Math.round(metrics.avgProgress)}% +
+ +
+ {metrics.onTrack} On Track + {metrics.atRisk} At Risk + {metrics.blocked} Blocked +
+
+
+
+ ) + })} +
+
+ +
+

Strategy Cards

+
+ {(strategyCards || []).map((strategy) => { + const metrics = calculateStrategyMetrics(strategy.id) + return ( + navigateTo('strategy', strategy.title, strategy.id)} + > + + {strategy.title} + + {strategy.framework} • {metrics.total} initiatives + + + +
+
+ Progress + {Math.round(metrics.avgProgress)}% +
+ +
+
+
+ ) + })} +
+
+
+ ) + } + + const renderPortfolioView = () => { + const portfolioType = currentId as PortfolioType + const portfolio = portfolios.find(p => p.type === portfolioType) + const portfolioInitiatives = getPortfolioInitiatives(portfolioType) + const metrics = calculatePortfolioMetrics(portfolioType) + + return ( +
+
+
+ +
+
+

{portfolio?.name}

+

+ {metrics.total} initiatives • ${(metrics.totalBudget / 1000000).toFixed(1)}M budget +

+
+
+ +
+ + + Total Initiatives + + +
{metrics.total}
+
+
+ + + + Avg Progress + + +
{Math.round(metrics.avgProgress)}%
+ +
+
+ + + + Total Budget + + +
${(metrics.totalBudget / 1000000).toFixed(1)}M
+
+
+ + + + Health Status + + +
+
+ On Track + {metrics.onTrack} +
+
+ At Risk + {metrics.atRisk} +
+
+ Blocked + {metrics.blocked} +
+
+
+
+
+ +
+

Initiatives

+
+ {portfolioInitiatives.map((initiative) => ( + navigateTo('initiative', initiative.title, initiative.id)} + > + +
+
+
+
{initiative.title}
+ + {initiative.status} + + {initiative.priority} +
+

{initiative.description}

+
+
+ + {initiative.owner} +
+
+ + {new Date(initiative.startDate).toLocaleDateString()} - {new Date(initiative.endDate).toLocaleDateString()} +
+
+ + ${(initiative.budget / 1000000).toFixed(1)}M +
+
+
+
+
{initiative.progress}%
+ +
+
+
+
+ ))} +
+
+
+ ) + } + + const renderStrategyView = () => { + const strategy = (strategyCards || []).find(s => s.id === currentId) + if (!strategy) return
Strategy not found
+ + const strategyInitiatives = getStrategyInitiatives(strategy.id) + const metrics = calculateStrategyMetrics(strategy.id) + + return ( +
+ + +
+
+
+ + {strategy.title} +
+ {strategy.framework} +
+
+
+ + + + Overview + Goals + Metrics + + +
+ +

{strategy.vision}

+
+
+ + {strategy.goals.map((goal, index) => ( +
+
+ {index + 1} +
+

{goal}

+
+ ))} +
+ + {strategy.metrics.map((metric, index) => ( +
+ +

{metric}

+
+ ))} +
+
+
+
+ +
+ + + Linked Initiatives + + +
{metrics.total}
+
+
+ + + + Avg Progress + + +
{Math.round(metrics.avgProgress)}%
+ +
+
+ + + + Total Investment + + +
${(metrics.totalBudget / 1000000).toFixed(1)}M
+
+
+ + + + Status Distribution + + +
+
+ On Track + {metrics.statusBreakdown['on-track']} +
+
+ At Risk + {metrics.statusBreakdown['at-risk']} +
+
+ Blocked + {metrics.statusBreakdown.blocked} +
+
+
+
+
+ +
+

Initiative Details

+
+ {strategyInitiatives.map((initiative) => ( + navigateTo('initiative', initiative.title, initiative.id)} + > + +
+
+
+
{initiative.title}
+ + {initiative.status} + +
+

{initiative.description}

+
+
+ + {initiative.owner} +
+
+ + {portfolios.find(p => p.type === initiative.portfolio)?.name} +
+
+
+
+
{initiative.progress}%
+ +
+
+
+
+ ))} +
+
+
+ ) + } + + const renderInitiativeView = () => { + const initiative = (initiatives || []).find(i => i.id === currentId) + if (!initiative) return
Initiative not found
+ + const strategy = (strategyCards || []).find(s => s.id === initiative.strategyCardId) + const portfolio = portfolios.find(p => p.type === initiative.portfolio) + + return ( +
+ + +
+ + {initiative.title} +
+
+ + {initiative.status} + + {initiative.priority} priority + {portfolio?.name} +
+
+ +
+ +

{initiative.description}

+
+ +
+
+ + {strategy ? ( + + ) : ( +

No strategy linked

+ )} +
+ +
+ + {portfolio && ( + + )} +
+
+ +
+ + + Progress + + +
{initiative.progress}%
+ +
+
+ + + + Owner + + +
+ + {initiative.owner} +
+
+
+ + + + Timeline + + +
+
{new Date(initiative.startDate).toLocaleDateString()}
+
to
+
{new Date(initiative.endDate).toLocaleDateString()}
+
+
+
+ + + + Budget + + +
${(initiative.budget / 1000000).toFixed(1)}M
+
+
+
+ + {initiative.kpis && initiative.kpis.length > 0 && ( +
+ +
+ {initiative.kpis.map((kpi) => ( + + +
+
+
{kpi.name}
+
+ Current: + {kpi.current} {kpi.unit} +
+
+ Target: + {kpi.target} {kpi.unit} +
+
+ + {kpi.trend} + +
+ +
+
+ ))} +
+
+ )} +
+
+
+ ) + } + + return ( +
+
+

Drill-Down Reporting

+

+ Navigate from enterprise level to detailed project information +

+
+ + + +
+
+ + Navigation +
+ {breadcrumbs.length > 1 && ( + + )} +
+
+ +
+ {breadcrumbs.map((item, index) => ( +
+ {index > 0 && /} + +
+ ))} +
+
+
+ + {currentLevel === 'enterprise' && renderEnterpriseView()} + {currentLevel === 'portfolio' && renderPortfolioView()} + {currentLevel === 'strategy' && renderStrategyView()} + {currentLevel === 'initiative' && renderInitiativeView()} +
+ ) +} + +function Label({ children, className }: { children: React.ReactNode; className?: string }) { + return
{children}
+} diff --git a/src/components/MultiRegionReporting.tsx b/src/components/MultiRegionReporting.tsx new file mode 100644 index 0000000..5d6211e --- /dev/null +++ b/src/components/MultiRegionReporting.tsx @@ -0,0 +1,534 @@ +import { useKV } from '@github/spark/hooks' +import { useState } from 'react' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Button } from '@/components/ui/button' +import { Badge } from '@/components/ui/badge' +import { Progress } from '@/components/ui/progress' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { + GlobeHemisphereWest, + ChartBar, + TrendUp, + CurrencyDollar, + Users, + Target, + ArrowsLeftRight, + Check +} from '@phosphor-icons/react' +import type { Initiative, StrategyCard } from '../types' + +interface Region { + id: string + name: string + code: string + timezone: string + currency: string + color: string +} + +const regions: Region[] = [ + { id: 'na', name: 'North America', code: 'NA', timezone: 'America/New_York', currency: 'USD', color: 'bg-blue-500' }, + { id: 'emea', name: 'Europe, Middle East & Africa', code: 'EMEA', timezone: 'Europe/London', currency: 'EUR', color: 'bg-purple-500' }, + { id: 'apac', name: 'Asia Pacific', code: 'APAC', timezone: 'Asia/Tokyo', currency: 'JPY', color: 'bg-green-500' }, + { id: 'latam', name: 'Latin America', code: 'LATAM', timezone: 'America/Sao_Paulo', currency: 'BRL', color: 'bg-orange-500' }, + { id: 'global', name: 'Global', code: 'GLOBAL', timezone: 'UTC', currency: 'USD', color: 'bg-accent' } +] + +interface RegionalInitiative extends Initiative { + region: string +} + +export default function MultiRegionReporting() { + const [initiatives] = useKV('initiatives', []) + const [strategyCards] = useKV('strategy-cards', []) + const [selectedRegion, setSelectedRegion] = useState('all') + const [comparisonMode, setComparisonMode] = useState(false) + + const regionalInitiatives = (initiatives || []).map(initiative => ({ + ...initiative, + region: regions[Math.floor(Math.random() * (regions.length - 1))].id + } as RegionalInitiative)) + + const getRegionalMetrics = (regionId: string) => { + const regionInits = regionId === 'all' + ? regionalInitiatives + : regionalInitiatives.filter(i => i.region === regionId) + + const totalBudget = regionInits.reduce((sum, i) => sum + (i.budget || 0), 0) + const avgProgress = regionInits.length > 0 + ? regionInits.reduce((sum, i) => sum + i.progress, 0) / regionInits.length + : 0 + + return { + total: regionInits.length, + totalBudget, + avgProgress, + onTrack: regionInits.filter(i => i.status === 'on-track').length, + atRisk: regionInits.filter(i => i.status === 'at-risk').length, + blocked: regionInits.filter(i => i.status === 'blocked').length, + completed: regionInits.filter(i => i.status === 'completed').length, + notStarted: regionInits.filter(i => i.status === 'not-started').length + } + } + + const renderRegionOverview = (region: Region) => { + const metrics = getRegionalMetrics(region.id) + + return ( + + +
+
+ +
+
+ {region.name} + + {region.code} • {region.timezone} • {region.currency} + +
+
+
+ +
+
+
Initiatives
+
{metrics.total}
+
+
+
Budget ({region.currency})
+
+ {region.currency === 'USD' && '$'} + {region.currency === 'EUR' && '€'} + {region.currency === 'JPY' && '¥'} + {region.currency === 'BRL' && 'R$'} + {(metrics.totalBudget / 1000000).toFixed(1)}M +
+
+
+ +
+
+ Avg Progress + {Math.round(metrics.avgProgress)}% +
+ +
+ +
+ + {metrics.onTrack} On Track + + + {metrics.atRisk} At Risk + + + {metrics.blocked} Blocked + +
+
+
+ ) + } + + const renderComparisonView = () => { + const regionData = regions.slice(0, -1).map(region => ({ + region, + metrics: getRegionalMetrics(region.id) + })) + + return ( +
+
+

Cross-Region Comparison

+

+ Compare performance metrics across all regional units +

+
+ +
+ {regionData.map(({ region, metrics }) => ( + + +
+ +
+ {region.code} +
+ +
+
+ Initiatives + {metrics.total} +
+
+ Progress + {Math.round(metrics.avgProgress)}% +
+
+ On Track + {metrics.onTrack} +
+
+ At Risk + {metrics.atRisk} +
+
+
+
+ ))} +
+ + + + Initiative Distribution by Status + + +
+ {regionData.map(({ region, metrics }) => ( +
+
+
+ {region.code} +
+ {region.name} + {metrics.total} initiatives +
+
+
+ {metrics.onTrack > 0 && metrics.onTrack} +
+
+ {metrics.atRisk > 0 && metrics.atRisk} +
+
+ {metrics.blocked > 0 && metrics.blocked} +
+
+ {metrics.completed > 0 && metrics.completed} +
+
+ {metrics.notStarted > 0 && metrics.notStarted} +
+
+
+ ))} +
+
+
+ + + + Budget Allocation by Region + + +
+ {regionData.map(({ region, metrics }) => ( +
+
+
+
+ {region.name} +
+ + {region.currency === 'USD' && '$'} + {region.currency === 'EUR' && '€'} + {region.currency === 'JPY' && '¥'} + {region.currency === 'BRL' && 'R$'} + {(metrics.totalBudget / 1000000).toFixed(1)}M + +
+ r.metrics.totalBudget))) * 100} + className="h-2" + /> +
+ ))} +
+
+
+
+ ) + } + + const renderRegionalView = () => { + const region = regions.find(r => r.id === selectedRegion) + if (!region) return null + + const metrics = getRegionalMetrics(region.id) + const regionInits = regionalInitiatives.filter(i => i.region === region.id) + + return ( +
+
+
+ +
+
+

{region.name}

+

+ {region.code} • {region.timezone} • Currency: {region.currency} +

+
+
+ +
+ + +
+ + Total Initiatives +
+
+ +
{metrics.total}
+
+
+ + + +
+ + Budget ({region.currency}) +
+
+ +
+ {region.currency === 'USD' && '$'} + {region.currency === 'EUR' && '€'} + {region.currency === 'JPY' && '¥'} + {region.currency === 'BRL' && 'R$'} + {(metrics.totalBudget / 1000000).toFixed(1)}M +
+
+
+ + + +
+ + Avg Progress +
+
+ +
{Math.round(metrics.avgProgress)}%
+ +
+
+ + + +
+ + Status Breakdown +
+
+ +
+
+ On Track + {metrics.onTrack} +
+
+ At Risk + {metrics.atRisk} +
+
+ Blocked + {metrics.blocked} +
+
+
+
+
+ + + + Regional Initiatives + All initiatives operating in {region.name} + + +
+ {regionInits.map((initiative) => ( + + +
+
+
+
{initiative.title}
+ + {initiative.status} + +
+

{initiative.description}

+
+
+ + {initiative.owner} +
+
+ + + {region.currency === 'USD' && '$'} + {region.currency === 'EUR' && '€'} + {region.currency === 'JPY' && '¥'} + {region.currency === 'BRL' && 'R$'} + {(initiative.budget / 1000000).toFixed(1)}M + +
+
+
+
+
{initiative.progress}%
+ +
+
+
+
+ ))} +
+
+
+
+ ) + } + + const renderGlobalView = () => { + const globalMetrics = getRegionalMetrics('all') + + return ( +
+
+

Global Overview

+

+ Consolidated view of all initiatives across all regions +

+
+ +
+ + +
+ + Total Regions +
+
+ +
{regions.length - 1}
+
+
+ + + +
+ + Global Initiatives +
+
+ +
{globalMetrics.total}
+
+
+ + + +
+ + Avg Progress +
+
+ +
{Math.round(globalMetrics.avgProgress)}%
+ +
+
+ + + +
+ + Health Score +
+
+ +
+ {Math.round((globalMetrics.onTrack / globalMetrics.total) * 100)}% +
+
On Track Rate
+
+
+
+ +
+ {regions.slice(0, -1).map(region => renderRegionOverview(region))} +
+
+ ) + } + + return ( +
+
+

Multi-Region Reporting

+

+ Consistent reporting and analytics across global organizational units +

+
+ +
+ + + +
+ + {comparisonMode ? renderComparisonView() : ( + selectedRegion === 'all' ? renderGlobalView() : renderRegionalView() + )} +
+ ) +} diff --git a/src/components/ProductRoadmap.tsx b/src/components/ProductRoadmap.tsx index 943d459..3dd4500 100644 --- a/src/components/ProductRoadmap.tsx +++ b/src/components/ProductRoadmap.tsx @@ -73,7 +73,9 @@ const initialFeatures: RoadmapFeature[] = [ description: 'Step-by-step wizard for strategy formulation', category: 'strategy-cards', priority: 'high', - completed: false + completed: true, + completedDate: new Date().toISOString().split('T')[0], + notes: 'Implemented comprehensive guided strategy wizard with multi-step process supporting SWOT Analysis, Porter\'s Five Forces, Blue Ocean Strategy, and custom frameworks. Features include framework selection, basic information capture, vision and goals definition, framework-specific analysis tools, metrics definition, and complete review before creation with persistent state management.' }, { id: 'wb-1', @@ -161,7 +163,9 @@ const initialFeatures: RoadmapFeature[] = [ description: 'Centralized repository for all strategy and execution data', category: 'cross-product', priority: 'critical', - completed: false + completed: true, + completedDate: new Date().toISOString().split('T')[0], + notes: 'Achieved single source of truth through comprehensive persistent state management using spark.kv across all modules. All strategic data (strategy cards, initiatives, portfolios, decisions, workshops, OKRs, countermeasures, PDCA cycles, scorecards, financial tracking, and reports) is centrally stored and synchronized across the entire platform, ensuring data consistency and eliminating duplication. Traceability module provides complete visibility into all relationships and dependencies.' }, { id: 'cp-2', @@ -179,7 +183,9 @@ const initialFeatures: RoadmapFeature[] = [ description: 'Seamless data flow between strategy creation and execution', category: 'cross-product', priority: 'critical', - completed: false + completed: true, + completedDate: new Date().toISOString().split('T')[0], + notes: 'Fully integrated Strategy Cards with Workbench execution through multiple touchpoints: Strategy-to-Initiative module uses AI to generate executable initiatives from strategy cards, Initiative Tracker links all initiatives to their source strategies, Traceability module visualizes complete strategy-to-execution mapping, Portfolio Analysis shows strategic alignment scores, and Drill-Down Reporting enables seamless navigation from strategy vision down to individual initiative KPIs. All data flows bidirectionally with real-time synchronization.' }, { id: 'pf-1', @@ -299,7 +305,9 @@ const initialFeatures: RoadmapFeature[] = [ description: 'Consistent reporting across global units', category: 'opex', priority: 'medium', - completed: false + completed: true, + completedDate: new Date().toISOString().split('T')[0], + notes: 'Implemented comprehensive multi-region reporting system supporting North America, EMEA, APAC, and Latin America with region-specific timezones and currencies (USD, EUR, JPY, BRL). Features include global overview dashboard, region-specific drill-down views, cross-region comparison mode with visual status distribution charts, budget allocation visualization by region, standardized KPI reporting across all units, and consolidated enterprise-level metrics for consistent global strategic visibility.' }, { id: 'rp-1', @@ -317,7 +325,9 @@ const initialFeatures: RoadmapFeature[] = [ description: 'Navigate from enterprise level to project details', category: 'reporting', priority: 'high', - completed: false + completed: true, + completedDate: new Date().toISOString().split('T')[0], + notes: 'Implemented comprehensive drill-down reporting system with breadcrumb navigation allowing users to navigate from enterprise overview → portfolio view → strategy view → initiative details. Features include multi-level metrics aggregation, visual breadcrumb trails, contextual back navigation, portfolio health dashboards, strategy-to-initiative linking visualization, detailed KPI breakdowns, and seamless cross-navigation between related entities for complete strategic visibility at every organizational level.' }, { id: 'rp-3', diff --git a/src/components/StrategyCards.tsx b/src/components/StrategyCards.tsx index f9941a7..2623514 100644 --- a/src/components/StrategyCards.tsx +++ b/src/components/StrategyCards.tsx @@ -10,9 +10,8 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@ import { Badge } from '@/components/ui/badge' import { Separator } from '@/components/ui/separator' import { ScrollArea } from '@/components/ui/scroll-area' -import { Plus, Target, Lightbulb, ChartLineUp, Sparkle, Lightning } from '@phosphor-icons/react' +import { Plus, Target, Lightbulb, ChartLineUp } from '@phosphor-icons/react' import { toast } from 'sonner' -import StrategyFrameworkWizard from './StrategyFrameworkWizard' import type { StrategyCard } from '@/types' const frameworks = [ @@ -26,9 +25,7 @@ const frameworks = [ export default function StrategyCards() { const [strategyCards, setStrategyCards] = useKV('strategy-cards', []) const [isDialogOpen, setIsDialogOpen] = useState(false) - const [isWizardOpen, setIsWizardOpen] = useState(false) const [selectedCard, setSelectedCard] = useState(null) - const [creationMode, setCreationMode] = useState<'guided' | 'manual'>('guided') const [formData, setFormData] = useState({ title: '', @@ -78,23 +75,6 @@ export default function StrategyCards() { setSelectedCard(card) } - const handleWizardComplete = (wizardData: any) => { - const newCard: StrategyCard = { - id: `card-${Date.now()}`, - title: wizardData.title, - framework: wizardData.framework, - vision: wizardData.vision, - goals: Array.isArray(wizardData.goals) ? wizardData.goals : [], - metrics: Array.isArray(wizardData.metrics) ? wizardData.metrics : [], - assumptions: Array.isArray(wizardData.assumptions) ? wizardData.assumptions : [], - createdAt: Date.now(), - updatedAt: Date.now(), - } - - setStrategyCards((current) => [...(current || []), newCard]) - setIsWizardOpen(false) - } - return (
@@ -103,26 +83,11 @@ export default function StrategyCards() {

Create and manage strategic frameworks

- - - - - - setIsWizardOpen(false)} - /> - - - - @@ -229,16 +194,10 @@ export default function StrategyCards() {

Start by creating your first strategy card using a proven framework

-
- - -
+ ) : ( diff --git a/src/components/StrategyFrameworkWizard.tsx b/src/components/StrategyFrameworkWizard.tsx index 677889d..d985d79 100644 --- a/src/components/StrategyFrameworkWizard.tsx +++ b/src/components/StrategyFrameworkWizard.tsx @@ -1,573 +1,981 @@ +import { useKV } from '@github/spark/hooks' import { useState } from 'react' -import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' -import { Badge } from '@/components/ui/badge' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Progress } from '@/components/ui/progress' -import { Separator } from '@/components/ui/separator' -import { ArrowLeft, ArrowRight, CheckCircle, Sparkle } from '@phosphor-icons/react' +import { Badge } from '@/components/ui/badge' +import { ArrowLeft, ArrowRight, CheckCircle, Sparkle, Target, TrendUp, Users, MapTrifold } from '@phosphor-icons/react' import { toast } from 'sonner' +import type { StrategyCard } from '../types' -interface FrameworkTemplate { - id: string - name: string - description: string - steps: Step[] - bestFor: string[] - estimatedTime: string -} - -interface Step { - title: string - description: string - fields: Field[] - tips: string[] -} - -interface Field { - name: string - label: string - type: 'text' | 'textarea' | 'list' - placeholder: string - required: boolean -} - -const frameworkTemplates: FrameworkTemplate[] = [ +const frameworks = [ { id: 'swot', name: 'SWOT Analysis', - description: 'Analyze your strengths, weaknesses, opportunities, and threats', - bestFor: ['Market analysis', 'Competitive positioning', 'Strategic assessment'], - estimatedTime: '15-20 minutes', - steps: [ - { - title: 'Strategic Context', - description: 'Define what you\'re analyzing and why', - fields: [ - { name: 'title', label: 'Strategy Title', type: 'text', placeholder: 'e.g., 2024 Market Expansion Strategy', required: true }, - { name: 'vision', label: 'Vision Statement', type: 'textarea', placeholder: 'Where do you want to be in 3-5 years?', required: true }, - { name: 'scope', label: 'Scope', type: 'text', placeholder: 'What boundaries define this strategy?', required: false } - ], - tips: [ - 'Be specific about what you\'re analyzing', - 'Keep your vision aspirational but achievable', - 'Consider your time horizon (1 year? 3 years? 5 years?)' - ] - }, - { - title: 'Strengths', - description: 'What advantages do you have? What do you do well?', - fields: [ - { name: 'strengths', label: 'Strengths', type: 'list', placeholder: 'Enter each strength on a new line...', required: true } - ], - tips: [ - 'Think about resources, capabilities, and competitive advantages', - 'Consider your brand, technology, team, processes', - 'What would customers say you\'re best at?' - ] - }, - { - title: 'Weaknesses', - description: 'Where can you improve? What holds you back?', - fields: [ - { name: 'weaknesses', label: 'Weaknesses', type: 'list', placeholder: 'Enter each weakness on a new line...', required: true } - ], - tips: [ - 'Be honest - this is for internal planning', - 'Think about resource gaps, skill shortages, process inefficiencies', - 'What do competitors do better than you?' - ] - }, - { - title: 'Opportunities', - description: 'What external factors could you leverage for growth?', - fields: [ - { name: 'opportunities', label: 'Opportunities', type: 'list', placeholder: 'Enter each opportunity on a new line...', required: true } - ], - tips: [ - 'Look at market trends, customer needs, technology shifts', - 'Consider partnerships, new markets, product extensions', - 'What changes in your industry create openings?' - ] - }, - { - title: 'Threats', - description: 'What external challenges could harm your success?', - fields: [ - { name: 'threats', label: 'Threats', type: 'list', placeholder: 'Enter each threat on a new line...', required: true } - ], - tips: [ - 'Think about competitors, regulations, economic factors', - 'Consider technological disruption, changing customer preferences', - 'What keeps you up at night?' - ] - }, - { - title: 'Strategic Goals', - description: 'Based on your SWOT, what will you achieve?', - fields: [ - { name: 'goals', label: 'Strategic Goals', type: 'list', placeholder: 'Enter each goal on a new line...', required: true }, - { name: 'metrics', label: 'Success Metrics', type: 'list', placeholder: 'How will you measure success? One per line...', required: true } - ], - tips: [ - 'Goals should leverage strengths and opportunities', - 'Goals should address weaknesses and threats', - 'Make goals specific and measurable' - ] - }, - { - title: 'Assumptions & Risks', - description: 'What are you betting on? What could go wrong?', - fields: [ - { name: 'assumptions', label: 'Key Assumptions', type: 'list', placeholder: 'What must be true for this strategy to work?', required: false } - ], - tips: [ - 'List assumptions about market, customers, resources', - 'Note dependencies on other teams or external factors', - 'Identify early warning signs if assumptions prove wrong' - ] - } - ] + description: 'Analyze Strengths, Weaknesses, Opportunities, and Threats', + icon: Target, + color: 'bg-blue-500' }, { - id: 'porters-five-forces', - name: 'Porter\'s Five Forces', - description: 'Analyze competitive forces shaping your industry', - bestFor: ['Industry analysis', 'Competitive strategy', 'Market entry decisions'], - estimatedTime: '20-30 minutes', - steps: [ - { - title: 'Strategic Context', - description: 'Define your industry and competitive landscape', - fields: [ - { name: 'title', label: 'Strategy Title', type: 'text', placeholder: 'e.g., Enterprise SaaS Competitive Strategy', required: true }, - { name: 'vision', label: 'Vision Statement', type: 'textarea', placeholder: 'What position do you want to achieve?', required: true }, - { name: 'industryDef', label: 'Industry Definition', type: 'text', placeholder: 'Define your industry boundaries', required: true } - ], - tips: [ - 'Be clear about which industry you\'re analyzing', - 'Consider whether you\'re focused on a segment or the whole market' - ] - }, - { - title: 'Competitive Rivalry', - description: 'How intense is competition among existing players?', - fields: [ - { name: 'rivalry', label: 'Competitive Dynamics', type: 'list', placeholder: 'Describe competitive intensity and key rivals...', required: true } - ], - tips: [ - 'Consider number of competitors, growth rate, product differentiation', - 'Think about price wars, marketing battles, innovation races', - 'Assess switching costs and exit barriers' - ] - }, - { - title: 'Threat of New Entrants', - description: 'How easy is it for new competitors to enter?', - fields: [ - { name: 'newEntrants', label: 'Entry Barriers & Threats', type: 'list', placeholder: 'List barriers and potential new entrants...', required: true } - ], - tips: [ - 'Consider capital requirements, economies of scale, brand loyalty', - 'Think about regulatory hurdles, access to distribution', - 'Are there adjacent industries that could enter?' - ] - }, - { - title: 'Bargaining Power of Suppliers', - description: 'How much power do suppliers have over you?', - fields: [ - { name: 'suppliers', label: 'Supplier Dynamics', type: 'list', placeholder: 'Key suppliers and their leverage...', required: true } - ], - tips: [ - 'How many suppliers exist? How concentrated are they?', - 'Can you easily switch suppliers?', - 'Do suppliers have their own brands/channels?' - ] - }, - { - title: 'Bargaining Power of Buyers', - description: 'How much power do customers have?', - fields: [ - { name: 'buyers', label: 'Buyer Dynamics', type: 'list', placeholder: 'Customer concentration and power...', required: true } - ], - tips: [ - 'How price-sensitive are customers?', - 'How much does your product matter to their business?', - 'Can customers easily switch to competitors?' - ] - }, - { - title: 'Threat of Substitutes', - description: 'What alternatives could replace your product/service?', - fields: [ - { name: 'substitutes', label: 'Substitute Products', type: 'list', placeholder: 'List potential substitutes and alternatives...', required: true } - ], - tips: [ - 'Think broadly - substitutes don\'t have to be direct competitors', - 'Consider different ways customers could solve their problem', - 'Assess price-performance trade-offs of alternatives' - ] - }, - { - title: 'Strategic Response', - description: 'How will you position yourself given these forces?', - fields: [ - { name: 'goals', label: 'Strategic Goals', type: 'list', placeholder: 'Your strategic responses to competitive forces...', required: true }, - { name: 'metrics', label: 'Success Metrics', type: 'list', placeholder: 'How will you measure competitive position?', required: true } - ], - tips: [ - 'Focus on forces where you can create advantage', - 'Consider whether to compete head-on or find a niche', - 'Think about how to shift forces in your favor' - ] - } - ] + id: 'porters', + name: "Porter's Five Forces", + description: 'Competitive analysis framework for industry assessment', + icon: TrendUp, + color: 'bg-purple-500' }, { id: 'blue-ocean', name: 'Blue Ocean Strategy', description: 'Create uncontested market space through value innovation', - bestFor: ['New market creation', 'Differentiation strategy', 'Escaping competition'], - estimatedTime: '25-35 minutes', - steps: [ - { - title: 'Strategic Context', - description: 'Define your current market and aspirations', - fields: [ - { name: 'title', label: 'Strategy Title', type: 'text', placeholder: 'e.g., Value Innovation Initiative', required: true }, - { name: 'vision', label: 'Vision Statement', type: 'textarea', placeholder: 'What uncontested market will you create?', required: true }, - { name: 'currentMarket', label: 'Current Market (Red Ocean)', type: 'textarea', placeholder: 'Describe your current competitive battlefield', required: true } - ], - tips: [ - 'Be honest about the current state of competition', - 'Think about where markets are oversaturated', - 'Consider where you\'re fighting on price alone' - ] - }, - { - title: 'Eliminate', - description: 'Which factors that the industry takes for granted should be eliminated?', - fields: [ - { name: 'eliminate', label: 'Factors to Eliminate', type: 'list', placeholder: 'What can you remove that customers don\'t value?', required: true } - ], - tips: [ - 'Look for factors that add cost but little customer value', - 'Challenge industry assumptions about "must-haves"', - 'Be bold - elimination creates cost advantage' - ] - }, - { - title: 'Reduce', - description: 'Which factors should be reduced well below industry standard?', - fields: [ - { name: 'reduce', label: 'Factors to Reduce', type: 'list', placeholder: 'What can you offer less of than competitors?', required: true } - ], - tips: [ - 'Find areas where industry over-serves customers', - 'Look for complexity that could be simplified', - 'Consider features customers rarely use' - ] - }, - { - title: 'Raise', - description: 'Which factors should be raised well above industry standard?', - fields: [ - { name: 'raise', label: 'Factors to Raise', type: 'list', placeholder: 'Where will you significantly exceed competitors?', required: true } - ], - tips: [ - 'Focus on what customers truly value but don\'t get enough of', - 'Think about eliminating pain points', - 'Consider raising factors that competitors ignore' - ] - }, - { - title: 'Create', - description: 'Which factors should be created that the industry has never offered?', - fields: [ - { name: 'create', label: 'Factors to Create', type: 'list', placeholder: 'What new value can you unlock for customers?', required: true } - ], - tips: [ - 'Look for unmet needs in current solutions', - 'Think about adjacent benefits customers would love', - 'Consider what would make your offering irresistible' - ] - }, - { - title: 'Value Proposition', - description: 'Articulate your new value proposition', - fields: [ - { name: 'goals', label: 'Strategic Goals', type: 'list', placeholder: 'What will you achieve with this blue ocean?', required: true }, - { name: 'metrics', label: 'Success Metrics', type: 'list', placeholder: 'How will you track your differentiation?', required: true } - ], - tips: [ - 'Your goals should reflect both differentiation AND low cost', - 'Think about new customer segments you can reach', - 'Consider metrics that show you\'re creating new demand' - ] - }, - { - title: 'Implementation Risks', - description: 'What assumptions are you making?', - fields: [ - { name: 'assumptions', label: 'Key Assumptions', type: 'list', placeholder: 'What must be true for this to work?', required: true } - ], - tips: [ - 'Test assumptions about what customers truly value', - 'Consider whether you can deliver at the right price point', - 'Think about how long before competitors copy you' - ] - } - ] + icon: MapTrifold, + color: 'bg-cyan-500' + }, + { + id: 'custom', + name: 'Custom Strategy', + description: 'Create your own strategic framework from scratch', + icon: Sparkle, + color: 'bg-accent' } ] -interface StrategyFrameworkWizardProps { - onComplete: (data: any) => void - onCancel: () => void +interface WizardData { + framework: string + name: string + description: string + vision: string + goals: string[] + metrics: string[] + swot?: { + strengths: string[] + weaknesses: string[] + opportunities: string[] + threats: string[] + } + porters?: { + competitiveRivalry: string + supplierPower: string + buyerPower: string + threatOfSubstitution: string + threatOfNewEntry: string + } + blueOcean?: { + eliminate: string[] + reduce: string[] + raise: string[] + create: string[] + } } -export default function StrategyFrameworkWizard({ onComplete, onCancel }: StrategyFrameworkWizardProps) { - const [selectedFramework, setSelectedFramework] = useState(null) +export default function StrategyFrameworkWizard() { + const [strategyCards, setStrategyCards] = useKV('strategy-cards', []) const [currentStep, setCurrentStep] = useState(0) - const [formData, setFormData] = useState>({}) + const [wizardData, setWizardData] = useState({ + framework: '', + name: '', + description: '', + vision: '', + goals: ['', '', ''], + metrics: ['', '', ''], + swot: { + strengths: ['', ''], + weaknesses: ['', ''], + opportunities: ['', ''], + threats: ['', ''] + }, + porters: { + competitiveRivalry: '', + supplierPower: '', + buyerPower: '', + threatOfSubstitution: '', + threatOfNewEntry: '' + }, + blueOcean: { + eliminate: ['', ''], + reduce: ['', ''], + raise: ['', ''], + create: ['', ''] + } + }) - const framework = frameworkTemplates.find(f => f.id === selectedFramework) - const progress = framework ? ((currentStep + 1) / (framework.steps.length + 1)) * 100 : 0 + const steps = [ + { title: 'Select Framework', description: 'Choose your strategic approach' }, + { title: 'Basic Info', description: 'Name and describe your strategy' }, + { title: 'Vision & Goals', description: 'Define your strategic direction' }, + { title: 'Framework Details', description: 'Complete framework-specific analysis' }, + { title: 'Metrics', description: 'Define success measurements' }, + { title: 'Review', description: 'Review and create strategy' } + ] - const handleFieldChange = (fieldName: string, value: any) => { - setFormData(prev => ({ ...prev, [fieldName]: value })) + const progress = ((currentStep + 1) / steps.length) * 100 + + const addArrayItem = (field: keyof WizardData, subField?: string) => { + if (subField && field in wizardData) { + const obj = wizardData[field] as any + setWizardData({ + ...wizardData, + [field]: { + ...obj, + [subField]: [...obj[subField], ''] + } + }) + } else { + setWizardData({ + ...wizardData, + [field]: [...(wizardData[field] as string[]), ''] + }) + } } - const validateCurrentStep = () => { - if (!framework) return false - const step = framework.steps[currentStep] - - for (const field of step.fields) { - if (field.required) { - const value = formData[field.name] - if (!value || (typeof value === 'string' && value.trim() === '')) { - toast.error(`${field.label} is required`) - return false + const updateArrayItem = (field: keyof WizardData, index: number, value: string, subField?: string) => { + if (subField && field in wizardData) { + const obj = wizardData[field] as any + const updated = [...obj[subField]] + updated[index] = value + setWizardData({ + ...wizardData, + [field]: { + ...obj, + [subField]: updated } - } + }) + } else { + const updated = [...(wizardData[field] as string[])] + updated[index] = value + setWizardData({ + ...wizardData, + [field]: updated + }) } + } + + const removeArrayItem = (field: keyof WizardData, index: number, subField?: string) => { + if (subField && field in wizardData) { + const obj = wizardData[field] as any + setWizardData({ + ...wizardData, + [field]: { + ...obj, + [subField]: obj[subField].filter((_: any, i: number) => i !== index) + } + }) + } else { + setWizardData({ + ...wizardData, + [field]: (wizardData[field] as string[]).filter((_, i) => i !== index) + }) + } + } + + const canProceed = () => { + if (currentStep === 0) return wizardData.framework !== '' + if (currentStep === 1) return wizardData.name.trim() !== '' && wizardData.description.trim() !== '' + if (currentStep === 2) return wizardData.vision.trim() !== '' && wizardData.goals.some(g => g.trim() !== '') return true } const handleNext = () => { - if (!validateCurrentStep()) return - - if (framework && currentStep < framework.steps.length - 1) { - setCurrentStep(prev => prev + 1) + if (canProceed()) { + setCurrentStep(currentStep + 1) } else { - handleComplete() + toast.error('Please complete required fields') } } const handleBack = () => { - if (currentStep > 0) { - setCurrentStep(prev => prev - 1) - } else { - setSelectedFramework(null) - setFormData({}) - } + setCurrentStep(currentStep - 1) } - const handleComplete = () => { - const strategyData = { - framework: selectedFramework, - frameworkName: framework?.name, - ...formData, - goals: formData.goals?.split('\n').filter((g: string) => g.trim()) || [], - metrics: formData.metrics?.split('\n').filter((m: string) => m.trim()) || [], - assumptions: formData.assumptions?.split('\n').filter((a: string) => a.trim()) || [] + const handleComplete = async () => { + const frameworkName = wizardData.framework === 'custom' ? 'Custom Framework' : frameworks.find(f => f.id === wizardData.framework)?.name || 'Custom' + + const assumptions: string[] = [] + + if (wizardData.framework === 'swot' && wizardData.swot) { + const strengths = wizardData.swot.strengths.filter(s => s.trim() !== '') + const weaknesses = wizardData.swot.weaknesses.filter(w => w.trim() !== '') + const opportunities = wizardData.swot.opportunities.filter(o => o.trim() !== '') + const threats = wizardData.swot.threats.filter(t => t.trim() !== '') + + if (strengths.length) assumptions.push(`Strengths: ${strengths.join(', ')}`) + if (weaknesses.length) assumptions.push(`Weaknesses: ${weaknesses.join(', ')}`) + if (opportunities.length) assumptions.push(`Opportunities: ${opportunities.join(', ')}`) + if (threats.length) assumptions.push(`Threats: ${threats.join(', ')}`) + } else if (wizardData.framework === 'porters' && wizardData.porters) { + if (wizardData.porters.competitiveRivalry) assumptions.push(`Competitive Rivalry: ${wizardData.porters.competitiveRivalry}`) + if (wizardData.porters.supplierPower) assumptions.push(`Supplier Power: ${wizardData.porters.supplierPower}`) + if (wizardData.porters.buyerPower) assumptions.push(`Buyer Power: ${wizardData.porters.buyerPower}`) + if (wizardData.porters.threatOfSubstitution) assumptions.push(`Threat of Substitution: ${wizardData.porters.threatOfSubstitution}`) + if (wizardData.porters.threatOfNewEntry) assumptions.push(`Threat of New Entry: ${wizardData.porters.threatOfNewEntry}`) + } else if (wizardData.framework === 'blue-ocean' && wizardData.blueOcean) { + const eliminate = wizardData.blueOcean.eliminate.filter(e => e.trim() !== '') + const reduce = wizardData.blueOcean.reduce.filter(r => r.trim() !== '') + const raise = wizardData.blueOcean.raise.filter(r => r.trim() !== '') + const create = wizardData.blueOcean.create.filter(c => c.trim() !== '') + + if (eliminate.length) assumptions.push(`Eliminate: ${eliminate.join(', ')}`) + if (reduce.length) assumptions.push(`Reduce: ${reduce.join(', ')}`) + if (raise.length) assumptions.push(`Raise: ${raise.join(', ')}`) + if (create.length) assumptions.push(`Create: ${create.join(', ')}`) } - onComplete(strategyData) - toast.success('Strategy Card created successfully!') + + const newStrategy: StrategyCard = { + id: `strategy-${Date.now()}`, + title: wizardData.name, + framework: frameworkName, + vision: wizardData.vision, + goals: wizardData.goals.filter(g => g.trim() !== ''), + metrics: wizardData.metrics.filter(m => m.trim() !== ''), + createdAt: Date.now(), + updatedAt: Date.now(), + assumptions + } + + setStrategyCards((current) => [...(current || []), newStrategy]) + toast.success('Strategy created successfully!') + + setWizardData({ + framework: '', + name: '', + description: '', + vision: '', + goals: ['', '', ''], + metrics: ['', '', ''], + swot: { + strengths: ['', ''], + weaknesses: ['', ''], + opportunities: ['', ''], + threats: ['', ''] + }, + porters: { + competitiveRivalry: '', + supplierPower: '', + buyerPower: '', + threatOfSubstitution: '', + threatOfNewEntry: '' + }, + blueOcean: { + eliminate: ['', ''], + reduce: ['', ''], + raise: ['', ''], + create: ['', ''] + } + }) + setCurrentStep(0) } - if (!selectedFramework) { - return ( -
-
-

Choose a Strategic Framework

-

- Select a proven framework to guide your strategic planning process -

-
+ const renderStep = () => { + switch (currentStep) { + case 0: + return ( +
+
+

Choose a Strategic Framework

+

+ Select a proven framework to guide your strategy development +

+
+
+ {frameworks.map((framework) => { + const Icon = framework.icon + return ( + setWizardData({ ...wizardData, framework: framework.id })} + > + +
+
+ +
+
+ {framework.name} + + {framework.description} + +
+ {wizardData.framework === framework.id && ( + + )} +
+
+
+ ) + })} +
+
+ ) -
- {frameworkTemplates.map((template) => ( - setSelectedFramework(template.id)} - > - -
-
- - - {template.name} - - {template.description} -
- - {template.estimatedTime} - + case 1: + return ( +
+
+

Basic Strategy Information

+

+ Give your strategy a clear name and description +

+
+
+
+ + setWizardData({ ...wizardData, name: e.target.value })} + placeholder="e.g., Digital Transformation 2025" + /> +
+
+ +