121 lines
3.6 KiB
TypeScript
121 lines
3.6 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
interface EditableOutputProps {
|
|
content: string;
|
|
sessionId: string;
|
|
tool: string;
|
|
isPaid: boolean;
|
|
improvementsUsed: number;
|
|
maxImprovements: number;
|
|
onImproved: (newContent: string) => void;
|
|
}
|
|
|
|
export default function EditableOutput({
|
|
content,
|
|
sessionId,
|
|
tool,
|
|
isPaid,
|
|
improvementsUsed,
|
|
maxImprovements,
|
|
onImproved,
|
|
}: EditableOutputProps) {
|
|
const [feedback, setFeedback] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
const [validating, setValidating] = useState(false);
|
|
const [validation, setValidation] = useState<string | null>(null);
|
|
|
|
const handleImprove = async () => {
|
|
if (!feedback.trim()) return;
|
|
setLoading(true);
|
|
try {
|
|
const res = await fetch(`/api/${tool}/improve-section`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ session_id: sessionId, section: content, feedback }),
|
|
});
|
|
const data = await res.json();
|
|
if (data.improved) {
|
|
onImproved(data.improved);
|
|
setFeedback('');
|
|
}
|
|
} catch (e) {
|
|
console.error('Improve failed:', e);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleValidate = async () => {
|
|
setValidating(true);
|
|
try {
|
|
const res = await fetch(`/api/${tool}/validate`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ session_id: sessionId }),
|
|
});
|
|
const data = await res.json();
|
|
if (data.validation) setValidation(data.validation);
|
|
} catch (e) {
|
|
console.error('Validate failed:', e);
|
|
} finally {
|
|
setValidating(false);
|
|
}
|
|
};
|
|
|
|
const remaining = maxImprovements - improvementsUsed;
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="prose prose-sm max-w-none bg-gray-50 p-6 rounded-lg border whitespace-pre-wrap font-mono text-sm">
|
|
{content}
|
|
</div>
|
|
|
|
{isPaid && (
|
|
<>
|
|
<div className="flex gap-2">
|
|
<button
|
|
onClick={handleValidate}
|
|
disabled={validating}
|
|
className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-700 disabled:opacity-50"
|
|
>
|
|
{validating ? 'Analysing...' : '🔍 Analyse Quality'}
|
|
</button>
|
|
<span className="text-xs text-gray-400 self-center">
|
|
{remaining} improvements remaining
|
|
</span>
|
|
</div>
|
|
|
|
{validation && (
|
|
<div className="bg-blue-50 border border-blue-200 p-4 rounded-lg">
|
|
<h4 className="font-semibold text-blue-800 mb-2">Quality Assessment</h4>
|
|
<div className="text-sm whitespace-pre-wrap">{validation}</div>
|
|
</div>
|
|
)}
|
|
|
|
{remaining > 0 && (
|
|
<div className="flex gap-2">
|
|
<input
|
|
type="text"
|
|
value={feedback}
|
|
onChange={(e) => setFeedback(e.target.value)}
|
|
placeholder="Describe what to improve..."
|
|
className="flex-1 border rounded-lg px-3 py-2 text-sm"
|
|
onKeyDown={(e) => e.key === 'Enter' && handleImprove()}
|
|
/>
|
|
<button
|
|
onClick={handleImprove}
|
|
disabled={loading || !feedback.trim()}
|
|
className="px-4 py-2 bg-accent text-white rounded-lg text-sm hover:bg-accent/90 disabled:opacity-50"
|
|
>
|
|
{loading ? 'Improving...' : '✨ Improve'}
|
|
</button>
|
|
</div>
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|