Spaces:
Sleeping
Sleeping
| import { DarkPattern } from '../types/analysis'; | |
| import { Badge } from './ui/badge'; | |
| import { AlertTriangle, Brain, FileText, Lightbulb } from 'lucide-react'; | |
| import { | |
| Accordion, | |
| AccordionContent, | |
| AccordionItem, | |
| AccordionTrigger, | |
| } from './ui/accordion'; | |
| interface DarkPatternsListProps { | |
| patterns: DarkPattern[]; | |
| } | |
| export function DarkPatternsList({ patterns }: DarkPatternsListProps) { | |
| const getSeverityBadgeClass = (severity: string) => { | |
| switch (severity) { | |
| case 'critical': | |
| return 'bg-rose-500/10 text-rose-400 border border-rose-500/20'; | |
| case 'high': | |
| return 'bg-orange-500/10 text-orange-400 border border-orange-500/20'; | |
| case 'medium': | |
| return 'bg-amber-500/10 text-amber-400 border border-amber-500/20'; | |
| default: | |
| return 'bg-indigo-500/10 text-indigo-400 border border-indigo-500/20'; | |
| } | |
| }; | |
| const getSeverityBorderColor = (severity: string) => { | |
| switch (severity) { | |
| case 'critical': | |
| return 'border-rose-500/25 bg-rose-500/5 hover:border-rose-500/40'; | |
| case 'high': | |
| return 'border-orange-500/25 bg-orange-500/5 hover:border-orange-500/40'; | |
| case 'medium': | |
| return 'border-amber-500/25 bg-amber-500/5 hover:border-amber-500/40'; | |
| default: | |
| return 'border-indigo-500/25 bg-indigo-500/5 hover:border-indigo-500/40'; | |
| } | |
| }; | |
| // Sort by severity | |
| const sortedPatterns = [...patterns].sort((a, b) => { | |
| const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 }; | |
| return severityOrder[a.severity] - severityOrder[b.severity]; | |
| }); | |
| return ( | |
| <div className="space-y-6"> | |
| {/* Summary */} | |
| <div className="bg-slate-900/30 rounded-xl p-4 border border-border"> | |
| <div className="flex items-center gap-3"> | |
| <AlertTriangle className="w-5 h-5 text-indigo-400" /> | |
| <p className="text-xs text-slate-300"> | |
| Identified <strong>{patterns.length} deceptive copy triggers</strong> in the layout layers. | |
| Expand each item below for compliance details and XAI fixes. | |
| </p> | |
| </div> | |
| </div> | |
| {/* Patterns List */} | |
| <Accordion type="single" collapsible className="space-y-4"> | |
| {sortedPatterns.map((pattern) => ( | |
| <AccordionItem | |
| key={pattern.id} | |
| value={pattern.id} | |
| className={`border rounded-xl overflow-hidden transition-all duration-300 ${getSeverityBorderColor(pattern.severity)}`} | |
| > | |
| <AccordionTrigger className="px-6 py-4 hover:no-underline text-slate-100"> | |
| <div className="flex items-center gap-4 w-full text-left"> | |
| <Badge className={`${getSeverityBadgeClass(pattern.severity)} text-[10px] font-bold px-2 py-0.5 rounded-md`}> | |
| {pattern.severity} | |
| </Badge> | |
| <div className="flex-1 min-w-0"> | |
| <div className="font-bold text-xs sm:text-sm text-slate-200">{pattern.type}</div> | |
| <div className="text-[11px] text-slate-400 truncate mt-0.5">{pattern.description}</div> | |
| </div> | |
| <div className="text-[10px] font-mono text-slate-400 shrink-0 bg-slate-950/20 px-2 py-1 rounded border border-white/5"> | |
| {pattern.confidence}% confidence | |
| </div> | |
| </div> | |
| </AccordionTrigger> | |
| <AccordionContent className="px-6 pb-6"> | |
| <div className="space-y-4 pt-4 border-t border-white/5"> | |
| {/* Detected copy + XAI phrases */} | |
| {pattern.evidence && ( | |
| <div className="bg-slate-950/30 rounded-xl p-4 border border-indigo-500/15"> | |
| <h5 className="font-bold text-xs text-indigo-300 mb-2">Detected Copy</h5> | |
| <p className="text-xs text-slate-200 font-mono leading-relaxed">"{pattern.evidence}"</p> | |
| {pattern.explanation && pattern.explanation.length > 0 && ( | |
| <div className="flex flex-wrap gap-1.5 mt-3"> | |
| {pattern.explanation.map((e) => ( | |
| <span | |
| key={e.phrase} | |
| className="text-[10px] font-mono px-2 py-0.5 rounded bg-indigo-500/15 text-indigo-300 border border-indigo-500/25" | |
| title={`contribution weight ${e.weight}`} | |
| > | |
| {e.phrase} | |
| </span> | |
| ))} | |
| </div> | |
| )} | |
| </div> | |
| )} | |
| {/* Description */} | |
| <div className="bg-slate-950/30 rounded-xl p-4 border border-white/5"> | |
| <div className="flex items-start gap-3"> | |
| <FileText className="w-4 h-4 text-indigo-400 shrink-0 mt-0.5" /> | |
| <div> | |
| <h5 className="font-bold text-xs text-slate-200 mb-1">Issue Description</h5> | |
| <p className="text-xs text-slate-300">{pattern.description}</p> | |
| </div> | |
| </div> | |
| </div> | |
| {/* CFPB Violation */} | |
| <div className="bg-slate-950/30 rounded-xl p-4 border border-rose-500/15"> | |
| <div className="flex items-start gap-3"> | |
| <AlertTriangle className="w-4 h-4 text-rose-400 shrink-0 mt-0.5" /> | |
| <div> | |
| <h5 className="font-bold text-xs text-rose-300 mb-1">CFPB Compliance Conflict</h5> | |
| <p className="text-xs text-rose-200/80 leading-relaxed">{pattern.cfpbViolation}</p> | |
| </div> | |
| </div> | |
| </div> | |
| {/* XAI Recommendation */} | |
| <div className="bg-slate-950/30 rounded-xl p-4 border border-emerald-500/15"> | |
| <div className="flex items-start gap-3"> | |
| <Lightbulb className="w-4 h-4 text-emerald-400 shrink-0 mt-0.5" /> | |
| <div> | |
| <h5 className="font-bold text-xs text-emerald-300 mb-1">Recommended Fix</h5> | |
| <p className="text-xs text-emerald-200/80 leading-relaxed">{pattern.recommendation}</p> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Location Info */} | |
| <div className="bg-slate-950/30 rounded-xl p-4 border border-white/5"> | |
| <div className="flex items-start gap-3"> | |
| <Brain className="w-4 h-4 text-purple-400 shrink-0 mt-0.5" /> | |
| <div className="flex-1"> | |
| <h5 className="font-bold text-xs text-slate-200 mb-2">Neural Network Activation Layer</h5> | |
| <div className="grid grid-cols-2 gap-3 text-xs"> | |
| <div> | |
| <span className="text-slate-400">OCR Bounding Box:</span>{' '} | |
| <span className="text-slate-200 font-mono font-medium"> | |
| ({pattern.location.x}%, {pattern.location.y}%) | |
| </span> | |
| </div> | |
| <div> | |
| <span className="text-slate-400">Visual Box Size:</span>{' '} | |
| <span className="text-slate-200 font-mono font-medium"> | |
| {pattern.location.width}% × {pattern.location.height}% | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </AccordionContent> | |
| </AccordionItem> | |
| ))} | |
| </Accordion> | |
| {/* About XAI */} | |
| <div className="bg-indigo-500/5 border border-indigo-500/10 rounded-xl p-4"> | |
| <h4 className="font-bold text-xs text-indigo-300 mb-2">🤖 Neural Network Audit Mechanism</h4> | |
| <p className="text-xs text-slate-400 leading-relaxed"> | |
| The models run OCR to extract text boundaries and classify the linguistic copy structure. | |
| All recommendations are generated by parsing structural cues against TILA, EFTA, and CFPB administrative records. | |
| </p> | |
| </div> | |
| </div> | |
| ); | |
| } | |