CoolFace
Apppublic

ModelMuse02/AI_Sales_Forecasting

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
InsightsPanel.tsx249 linesDownload Raw Back to root
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