summaryrefslogtreecommitdiff
path: root/makima/frontend/src/components/SupervisorQuestionNotification.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'makima/frontend/src/components/SupervisorQuestionNotification.tsx')
-rw-r--r--makima/frontend/src/components/SupervisorQuestionNotification.tsx135
1 files changed, 135 insertions, 0 deletions
diff --git a/makima/frontend/src/components/SupervisorQuestionNotification.tsx b/makima/frontend/src/components/SupervisorQuestionNotification.tsx
new file mode 100644
index 0000000..6a71de2
--- /dev/null
+++ b/makima/frontend/src/components/SupervisorQuestionNotification.tsx
@@ -0,0 +1,135 @@
+import { useState } from "react";
+import { useNavigate } from "react-router";
+import { useSupervisorQuestions } from "../contexts/SupervisorQuestionsContext";
+import type { PendingQuestion } from "../lib/api";
+
+export function SupervisorQuestionNotification() {
+ const navigate = useNavigate();
+ const { pendingQuestions, submitAnswer } = useSupervisorQuestions();
+ const [expandedQuestion, setExpandedQuestion] = useState<string | null>(null);
+ const [response, setResponse] = useState("");
+ const [submitting, setSubmitting] = useState(false);
+
+ if (pendingQuestions.length === 0) {
+ return null;
+ }
+
+ const handleGoToTask = (taskId: string) => {
+ navigate(`/mesh/${taskId}`);
+ };
+
+ const handleExpand = (questionId: string) => {
+ setExpandedQuestion(expandedQuestion === questionId ? null : questionId);
+ setResponse("");
+ };
+
+ const handleSubmit = async (question: PendingQuestion) => {
+ if (!response.trim()) return;
+
+ setSubmitting(true);
+ const success = await submitAnswer(question.questionId, response.trim());
+ setSubmitting(false);
+
+ if (success) {
+ setExpandedQuestion(null);
+ setResponse("");
+ }
+ };
+
+ const handleChoiceSelect = async (question: PendingQuestion, choice: string) => {
+ setSubmitting(true);
+ await submitAnswer(question.questionId, choice);
+ setSubmitting(false);
+ };
+
+ return (
+ <div className="fixed bottom-4 right-4 z-50 max-w-md space-y-2">
+ {pendingQuestions.map((question) => (
+ <div
+ key={question.questionId}
+ className="bg-[#0d1b2d] border border-amber-500/50 rounded-lg shadow-lg overflow-hidden"
+ >
+ {/* Header */}
+ <div className="flex items-center justify-between px-4 py-3 bg-amber-900/30">
+ <div className="flex items-center gap-2">
+ <span className="text-amber-400 text-lg">?</span>
+ <span className="font-mono text-sm text-amber-300 uppercase">
+ Supervisor Question
+ </span>
+ </div>
+ <div className="flex items-center gap-2">
+ <button
+ onClick={() => handleGoToTask(question.taskId)}
+ className="px-2 py-1 font-mono text-xs text-amber-400 hover:text-amber-300 transition-colors"
+ title="Go to task"
+ >
+ View Task
+ </button>
+ <button
+ onClick={() => handleExpand(question.questionId)}
+ className="px-2 py-1 font-mono text-xs text-amber-400 border border-amber-500/30 hover:border-amber-400/50 transition-colors uppercase"
+ >
+ {expandedQuestion === question.questionId ? "Collapse" : "Answer"}
+ </button>
+ </div>
+ </div>
+
+ {/* Question preview */}
+ <div className="px-4 py-3">
+ {question.context && (
+ <div className="text-xs text-[#8b949e] font-mono mb-1 uppercase">
+ {question.context}
+ </div>
+ )}
+ <p className="text-sm text-[#dbe7ff] font-mono">
+ {question.question}
+ </p>
+ </div>
+
+ {/* Expanded answer section */}
+ {expandedQuestion === question.questionId && (
+ <div className="px-4 pb-4 border-t border-amber-500/20 pt-3">
+ {question.choices.length > 0 ? (
+ // Choice buttons
+ <div className="space-y-2">
+ <p className="text-xs text-[#8b949e] font-mono uppercase mb-2">
+ Select an option:
+ </p>
+ {question.choices.map((choice, idx) => (
+ <button
+ key={idx}
+ onClick={() => handleChoiceSelect(question, choice)}
+ disabled={submitting}
+ className="w-full px-3 py-2 text-left font-mono text-sm text-[#dbe7ff] bg-[#0a1628] border border-[#3f6fb3] hover:border-amber-400/50 hover:bg-amber-900/20 disabled:opacity-50 transition-colors"
+ >
+ {choice}
+ </button>
+ ))}
+ </div>
+ ) : (
+ // Free-form text input
+ <div className="space-y-2">
+ <textarea
+ value={response}
+ onChange={(e) => setResponse(e.target.value)}
+ placeholder="Type your response..."
+ rows={3}
+ className="w-full px-3 py-2 bg-[#0a1628] border border-[#3f6fb3] text-[#dbe7ff] font-mono text-sm focus:outline-none focus:border-amber-400 resize-none"
+ disabled={submitting}
+ />
+ <button
+ onClick={() => handleSubmit(question)}
+ disabled={submitting || !response.trim()}
+ className="w-full px-4 py-2 font-mono text-xs text-[#0a1628] bg-amber-500 hover:bg-amber-400 disabled:bg-amber-700 disabled:cursor-not-allowed transition-colors uppercase"
+ >
+ {submitting ? "Submitting..." : "Submit Response"}
+ </button>
+ </div>
+ )}
+ </div>
+ )}
+ </div>
+ ))}
+ </div>
+ );
+}