ModelMuse02/AI_Sales_Forecasting
0
1/**2 * Insights Panel Component3 * Display AI-generated business insights and recommendations4 */5 6import React from 'react';7import {8 TrendingUp,9 AlertTriangle,10 Lightbulb,11 AlertCircle,12 Info,13 ChevronRight,14} from 'lucide-react';15import { BusinessInsight } from '../types';16 17interface InsightCardProps {18 insight: BusinessInsight;19}20 21const categoryConfig = {22 growth: {23 icon: TrendingUp,24 bgColor: 'bg-green-50',25 borderColor: 'border-green-200',26 iconColor: 'text-green-600',27 titleColor: 'text-green-800',28 },29 risk: {30 icon: AlertTriangle,31 bgColor: 'bg-red-50',32 borderColor: 'border-red-200',33 iconColor: 'text-red-600',34 titleColor: 'text-red-800',35 },36 opportunity: {37 icon: Lightbulb,38 bgColor: 'bg-blue-50',39 borderColor: 'border-blue-200',40 iconColor: 'text-blue-600',41 titleColor: 'text-blue-800',42 },43 warning: {44 icon: AlertCircle,45 bgColor: 'bg-amber-50',46 borderColor: 'border-amber-200',47 iconColor: 'text-amber-600',48 titleColor: 'text-amber-800',49 },50 info: {51 icon: Info,52 bgColor: 'bg-gray-50',53 borderColor: 'border-gray-200',54 iconColor: 'text-gray-600',55 titleColor: 'text-gray-800',56 },57};58 59const impactBadgeColors = {60 High: 'bg-red-100 text-red-700',61 Medium: 'bg-amber-100 text-amber-700',62 Low: 'bg-green-100 text-green-700',63};64 65const InsightCard: React.FC<InsightCardProps> = ({ insight }) => {66 const config = categoryConfig[insight.category];67 const Icon = config.icon;68 const [expanded, setExpanded] = React.useState(false);69 70 return (71 <div 72 className={`${config.bgColor} ${config.borderColor} border rounded-lg p-4 cursor-pointer transition-all hover:shadow-md`}73 onClick={() => setExpanded(!expanded)}74 >75 <div className="flex items-start gap-3">76 <div className={`p-2 rounded-lg bg-white shadow-sm`}>77 <Icon size={20} className={config.iconColor} />78 </div>79 <div className="flex-1 min-w-0">80 <div className="flex items-center justify-between gap-2">81 <h4 className={`font-semibold ${config.titleColor}`}>{insight.title}</h4>82 <span className={`text-xs px-2 py-1 rounded-full font-medium ${impactBadgeColors[insight.impact]}`}>83 {insight.impact} Impact84 </span>85 </div>86 <p className="text-sm text-gray-600 mt-1">{insight.description}</p>87 88 {expanded && (89 <div className="mt-4 space-y-3">90 {/* Recommendation */}91 <div className="bg-white rounded-lg p-3 border border-gray-200">92 <div className="flex items-center gap-2 text-sm font-medium text-gray-700 mb-1">93 <ChevronRight size={16} />94 Recommendation95 </div>96 <p className="text-sm text-gray-600 ml-6">{insight.recommendation}</p>97 </div>98 99 {/* Metrics */}100 {insight.metrics && Object.keys(insight.metrics).length > 0 && (101 <div className="bg-white rounded-lg p-3 border border-gray-200">102 <div className="text-sm font-medium text-gray-700 mb-2">Key Metrics</div>103 <div className="grid grid-cols-2 gap-2">104 {Object.entries(insight.metrics).map(([key, value]) => (105 <div key={key} className="text-sm">106 <span className="text-gray-500">{key}:</span>{' '}107 <span className="font-medium text-gray-900">{value}</span>108 </div>109 ))}110 </div>111 </div>112 )}113 </div>114 )}115 116 <button 117 className="text-xs text-gray-500 mt-2 hover:text-gray-700 flex items-center gap-1"118 onClick={(e) => {119 e.stopPropagation();120 setExpanded(!expanded);121 }}122 >123 {expanded ? 'Show less' : 'Show more'}124 <ChevronRight size={14} className={`transition-transform ${expanded ? 'rotate-90' : ''}`} />125 </button>126 </div>127 </div>128 </div>129 );130};131 132interface InsightsPanelProps {133 insights: BusinessInsight[];134}135 136export const InsightsPanel: React.FC<InsightsPanelProps> = ({ insights }) => {137 const [filter, setFilter] = React.useState<string>('all');138 139 const categories = [140 { id: 'all', label: 'All', count: insights.length },141 { id: 'growth', label: 'Growth', count: insights.filter(i => i.category === 'growth').length },142 { id: 'opportunity', label: 'Opportunities', count: insights.filter(i => i.category === 'opportunity').length },143 { id: 'risk', label: 'Risks', count: insights.filter(i => i.category === 'risk').length },144 { id: 'warning', label: 'Warnings', count: insights.filter(i => i.category === 'warning').length },145 { id: 'info', label: 'Info', count: insights.filter(i => i.category === 'info').length },146 ];147 148 const filteredInsights = filter === 'all' 149 ? insights 150 : insights.filter(i => i.category === filter);151 152 const highImpactCount = insights.filter(i => i.impact === 'High').length;153 154 return (155 <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">156 <div className="flex items-center justify-between mb-6">157 <div>158 <h3 className="text-lg font-semibold text-gray-900">Business Insights</h3>159 <p className="text-sm text-gray-500 mt-1">160 {insights.length} insights generated • {highImpactCount} high impact161 </p>162 </div>163 </div>164 165 {/* Category Filters */}166 <div className="flex flex-wrap gap-2 mb-6">167 {categories.filter(c => c.count > 0).map(category => (168 <button169 key={category.id}170 onClick={() => setFilter(category.id)}171 className={`px-3 py-1.5 text-sm rounded-full transition-colors ${172 filter === category.id173 ? 'bg-blue-600 text-white'174 : 'bg-gray-100 text-gray-700 hover:bg-gray-200'175 }`}176 >177 {category.label}178 <span className={`ml-1.5 ${filter === category.id ? 'text-blue-200' : 'text-gray-500'}`}>179 {category.count}180 </span>181 </button>182 ))}183 </div>184 185 {/* Insights List */}186 <div className="space-y-4">187 {filteredInsights.length === 0 ? (188 <div className="text-center py-8 text-gray-500">189 No insights in this category190 </div>191 ) : (192 filteredInsights.map(insight => (193 <InsightCard key={insight.id} insight={insight} />194 ))195 )}196 </div>197 </div>198 );199};200 201// Summary cards for quick overview202interface InsightsSummaryProps {203 insights: BusinessInsight[];204}205 206export const InsightsSummary: React.FC<InsightsSummaryProps> = ({ insights }) => {207 const summary = {208 growth: insights.filter(i => i.category === 'growth').length,209 opportunities: insights.filter(i => i.category === 'opportunity').length,210 risks: insights.filter(i => i.category === 'risk').length,211 warnings: insights.filter(i => i.category === 'warning').length,212 };213 214 const highImpact = insights.filter(i => i.impact === 'High');215 216 return (217 <div className="grid grid-cols-2 md:grid-cols-4 gap-4">218 <div className="bg-green-50 rounded-lg p-4 border border-green-200">219 <div className="flex items-center gap-2">220 <TrendingUp size={20} className="text-green-600" />221 <span className="text-2xl font-bold text-green-700">{summary.growth}</span>222 </div>223 <p className="text-sm text-green-600 mt-1">Growth Insights</p>224 </div>225 <div className="bg-blue-50 rounded-lg p-4 border border-blue-200">226 <div className="flex items-center gap-2">227 <Lightbulb size={20} className="text-blue-600" />228 <span className="text-2xl font-bold text-blue-700">{summary.opportunities}</span>229 </div>230 <p className="text-sm text-blue-600 mt-1">Opportunities</p>231 </div>232 <div className="bg-red-50 rounded-lg p-4 border border-red-200">233 <div className="flex items-center gap-2">234 <AlertTriangle size={20} className="text-red-600" />235 <span className="text-2xl font-bold text-red-700">{summary.risks}</span>236 </div>237 <p className="text-sm text-red-600 mt-1">Risks Identified</p>238 </div>239 <div className="bg-amber-50 rounded-lg p-4 border border-amber-200">240 <div className="flex items-center gap-2">241 <AlertCircle size={20} className="text-amber-600" />242 <span className="text-2xl font-bold text-amber-700">{highImpact.length}</span>243 </div>244 <p className="text-sm text-amber-600 mt-1">High Impact Items</p>245 </div>246 </div>247 );248};249 