blob: d4ef618bfb9e53bd4f9407e42b8fbb2a38cb84ce (
plain) (
tree)
|
|
import { useState } from "react";
import type { PendingQuestion } from "../../lib/api";
interface ContractCompleteQuestionProps {
question: PendingQuestion;
onAnswer: (questionId: string, response: string) => Promise<void>;
}
/**
* Component for displaying contract_complete type questions prominently on the task page.
* These questions persist until answered and are not shown as floating notifications.
*/
export function ContractCompleteQuestion({
question,
onAnswer,
}: ContractCompleteQuestionProps) {
const [submitting, setSubmitting] = useState(false);
const [minimized, setMinimized] = useState(false);
const [customInput, setCustomInput] = useState("");
const [showCustom, setShowCustom] = useState(false);
const handleAnswer = async (response: string) => {
if (submitting) return;
setSubmitting(true);
try {
await onAnswer(question.questionId, response);
} finally {
setSubmitting(false);
}
};
const handleCustomSubmit = async () => {
if (!customInput.trim() || submitting) return;
await handleAnswer(customInput.trim());
setCustomInput("");
setShowCustom(false);
};
// Default choices for contract completion questions
const defaultChoices =
question.choices.length > 0
? question.choices
: ["Yes, contract is complete", "No, more work needed"];
if (minimized) {
return (
<div className="fixed bottom-4 left-4 z-40">
<button
onClick={() => setMinimized(false)}
className="flex items-center gap-2 px-4 py-2 bg-green-600 hover:bg-green-500 text-white font-mono text-sm rounded-lg shadow-lg transition-colors"
>
<span className="w-2 h-2 bg-white rounded-full animate-pulse" />
Contract Review Pending
</button>
</div>
);
}
return (
<div className="bg-gradient-to-r from-green-900/40 to-emerald-900/40 border-2 border-green-500/60 rounded-lg shadow-xl my-4 overflow-hidden">
{/* Header */}
<div className="flex items-center justify-between px-4 py-3 bg-green-900/50 border-b border-green-500/30">
<div className="flex items-center gap-3">
<div className="w-8 h-8 flex items-center justify-center bg-green-500/20 rounded-full">
<span className="text-green-400 text-xl">?</span>
</div>
<div>
<h3 className="font-mono text-sm text-green-300 uppercase tracking-wide">
Contract Completion Review
</h3>
<p className="text-xs text-green-400/60">
Please review and respond
</p>
</div>
</div>
<button
onClick={() => setMinimized(true)}
className="px-2 py-1 text-xs font-mono text-green-400/70 hover:text-green-300 border border-green-500/30 hover:border-green-400/50 rounded transition-colors"
title="Minimize (question will remain pending)"
>
Minimize
</button>
</div>
{/* Content */}
<div className="p-4 space-y-4">
{/* Context */}
{question.context && (
<div className="text-xs text-green-300/70 font-mono uppercase tracking-wide">
{question.context}
</div>
)}
{/* Question */}
<div className="text-green-100 font-mono text-base leading-relaxed">
{question.question}
</div>
{/* Choices */}
<div className="flex flex-wrap gap-3 pt-2">
{defaultChoices.map((choice, idx) => (
<button
key={idx}
onClick={() => handleAnswer(choice)}
disabled={submitting}
className={`px-4 py-2.5 font-mono text-sm border rounded-md transition-all disabled:opacity-50 disabled:cursor-not-allowed ${
idx === 0
? "bg-green-500/20 border-green-400/60 hover:bg-green-500/30 text-green-100 hover:border-green-400"
: "bg-amber-500/20 border-amber-400/60 hover:bg-amber-500/30 text-amber-100 hover:border-amber-400"
}`}
>
{submitting ? "..." : choice}
</button>
))}
</div>
{/* Custom input option */}
{!showCustom ? (
<button
onClick={() => setShowCustom(true)}
className="text-xs text-green-400/70 hover:text-green-300 font-mono transition-colors"
>
+ Provide custom response
</button>
) : (
<div className="flex gap-2 pt-2">
<input
type="text"
value={customInput}
onChange={(e) => setCustomInput(e.target.value)}
placeholder="Type your response..."
disabled={submitting}
className="flex-1 px-3 py-2 bg-[#0a1525] border border-green-500/30 text-green-100 text-sm font-mono rounded focus:outline-none focus:border-green-400"
onKeyDown={(e) => {
if (e.key === "Enter" && customInput.trim()) {
handleCustomSubmit();
}
if (e.key === "Escape") {
setShowCustom(false);
setCustomInput("");
}
}}
/>
<button
onClick={handleCustomSubmit}
disabled={submitting || !customInput.trim()}
className="px-4 py-2 bg-green-500 text-black text-sm font-medium rounded disabled:opacity-50 disabled:cursor-not-allowed transition-colors hover:bg-green-400"
>
{submitting ? "..." : "Submit"}
</button>
<button
onClick={() => {
setShowCustom(false);
setCustomInput("");
}}
className="px-2 py-2 text-green-400/70 hover:text-green-300 text-sm font-mono"
>
Cancel
</button>
</div>
)}
</div>
</div>
);
}
|