promptenhancer / src /components /OptimizationResult.tsx
Tobs248's picture
# Rolle
eee3ce2 verified
Raw
History Blame Contribute Delete
8.04 kB
tsx
import React, { useCallback } from 'react'
import { useAppStore } from '@/store/useAppStore'
import { Copy, CheckCircle, Clock, Hash, Sparkles } from 'lucide-react'
import { ANIMATION_DURATIONS } from '@/utils/constants'
/**
* Component displaying the optimized prompt result
*/
export function OptimizationResult() {
const {
result,
setCopiedState,
copiedStates
} = useAppStore()
if (!result) return null
/**
* Handle copy to clipboard with feedback
*/
const handleCopy = useCallback(async (text: string, type: 'original' | 'optimized') => {
try {
await navigator.clipboard.writeText(text)
setCopiedState(type, true)
// Reset copied state after animation
setTimeout(() => {
setCopiedState(type, false)
}, ANIMATION_DURATIONS.COPY_FEEDBACK)
} catch (error) {
console.error('Failed to copy text:', error)
// Fallback for older browsers
const textArea = document.createElement('textarea')
textArea.value = text
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
setCopiedState(type, true)
setTimeout(() => {
setCopiedState(type, false)
}, ANIMATION_DURATIONS.COPY_FEEDBACK)
}
}, [setCopiedState])
/**
* Calculate improvement metrics
*/
const improvementMetrics = {
lengthIncrease: result.optimizedPrompt.length - result.originalPrompt.length,
lengthIncreasePercent: Math.round(((result.optimizedPrompt.length - result.originalPrompt.length) / result.originalPrompt.length) * 100),
wordIncrease: result.optimizedPrompt.split(/\s+/).length - result.originalPrompt.split(/\s+/).length
}
return (
<div className="space-y-6">
{/* Result Header */}
<div className="card p-6">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-green-100 dark:bg-green-900 rounded-lg flex items-center justify-center">
<CheckCircle className="w-6 h-6 text-green-600 dark:text-green-400" />
</div>
<div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-gray-100">
Optimierung abgeschlossen
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
Für {result.targetModel.replace('-', ' ')} optimiert in {result.executionTime}ms
</p>
</div>
</div>
</div>
{/* Quick Stats */}
<div className="grid grid-cols-3 gap-4 mb-4">
<div className="text-center p-3 bg-gray-50 dark:bg-gray-800 rounded-lg">
<div className="text-2xl font-bold text-primary-600 dark:text-primary-400">
+{improvementMetrics.lengthIncrease}
</div>
<div className="text-xs text-gray-600 dark:text-gray-400">Zeichen</div>
</div>
<div className="text-center p-3 bg-gray-50 dark:bg-gray-800 rounded-lg">
<div className="text-2xl font-bold text-secondary-600 dark:text-secondary-400">
+{improvementMetrics.wordIncrease}
</div>
<div className="text-xs text-gray-600 dark:text-gray-400">Wörter</div>
</div>
<div className="text-center p-3 bg-gray-50 dark:bg-gray-800 rounded-lg">
<div className="text-2xl font-bold text-green-600 dark:text-green-400">
{improvementMetrics.lengthIncreasePercent}%
</div>
<div className="text-xs text-gray-600 dark:text-gray-400">Erweiterung</div>
</div>
</div>
{/* Performance Info */}
<div className="flex items-center justify-between text-sm text-gray-600 dark:text-gray-400">
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-1">
<Clock className="w-4 h-4" />
<span>{result.executionTime}ms</span>
</div>
{result.tokenEstimate && (
<div className="flex items-center space-x-1">
<Hash className="w-4 h-4" />
<span>~{result.tokenEstimate} Tokens</span>
</div>
)}
</div>
<div className="flex items-center space-x-1 text-green-600 dark:text-green-400">
<Sparkles className="w-4 h-4" />
<span>Optimiert</span>
</div>
</div>
</div>
{/* Improvements List */}
<div className="card p-6">
<h4 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
Angewendete Verbesserungen
</h4>
<ul className="space-y-2">
{result.improvements.map((improvement, index) => (
<li key={index} className="flex items-start space-x-2">
<CheckCircle className="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5" />
<span className="text-sm text-gray-700 dark:text-gray-300">{improvement}</span>
</li>
))}
</ul>
</div>
{/* Optimized Prompt Output */}
<div className="card p-6">
<div className="flex items-center justify-between mb-4">
<h4 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
Optimierter Prompt
</h4>
<button
onClick={() => handleCopy(result.optimizedPrompt, 'optimized')}
className={`flex items-center space-x-2 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 ${
copiedStates.optimized
? 'bg-green-100 dark:bg-green-900 text-green-700 dark:text-green-300'
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'
}`}
>
{copiedStates.optimized ? (
<>
<CheckCircle className="w-4 h-4" />
<span>Kopiert!</span>
</>
) : (
<>
<Copy className="w-4 h-4" />
<span>Kopieren</span>
</>
)}
</button>
</div>
<div className="relative">
<textarea
value={result.optimizedPrompt}
readOnly
className="w-full h-80 p-4 bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg resize-none text-sm leading-relaxed font-mono"
placeholder="Optimierter Prompt wird hier angezeigt..."
/>
<div className="absolute bottom-2 right-2 text-xs text-gray-500 dark:text-gray-400">
{result.optimizedPrompt.length} Zeichen
</div>
</div>
</div>
{/* Action Buttons */}
<div className="flex flex-col sm:flex-row gap-4">
<button
onClick={() => handleCopy(result.optimizedPrompt, 'optimized')}
className="flex-1 btn-primary flex items-center justify-center space-x-2"
>
{copiedStates.optimized ? (
<>
<CheckCircle className="w-4 h-4" />
<span>Kopiert!</span>
</>
) : (
<>
<Copy className="w-4 h-4" />
<span>Optimierten Prompt kopieren</span>
</>
)}
</button>
<button
onClick={() => window.open(`https://chat.openai.com/?model=${result.targetModel}`, '_blank')}
className="btn-secondary flex items-center justify-center space-x-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
<span>In Chat öffnen</span>
</button>
</div>
</div>
)
}
</html>