diff options
Diffstat (limited to 'makima/frontend/src/components/PhaseConfirmationNotification.tsx')
| -rw-r--r-- | makima/frontend/src/components/PhaseConfirmationNotification.tsx | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/makima/frontend/src/components/PhaseConfirmationNotification.tsx b/makima/frontend/src/components/PhaseConfirmationNotification.tsx new file mode 100644 index 0000000..516211f --- /dev/null +++ b/makima/frontend/src/components/PhaseConfirmationNotification.tsx @@ -0,0 +1,141 @@ +import { useNavigate } from "react-router"; +import { useSupervisorQuestions } from "../contexts/SupervisorQuestionsContext"; +import { PhaseConfirmationModal, type PhaseConfirmationData } from "./contracts/PhaseConfirmationModal"; +import type { PendingQuestion } from "../lib/api"; + +/** + * Notification component for phase confirmation requests. + * Shows a modal when there are pending phase_confirmation type questions. + * Uses the same question infrastructure as supervisor questions. + */ +export function PhaseConfirmationNotification() { + const { notificationQuestions, submitAnswer, dismissNotification } = + useSupervisorQuestions(); + + // Filter for phase_confirmation type questions + const phaseConfirmationQuestions = notificationQuestions.filter( + (q) => q.questionType === "phase_confirmation" + ); + + if (phaseConfirmationQuestions.length === 0) { + return null; + } + + // Show the first phase confirmation question as a modal + const question = phaseConfirmationQuestions[0]; + + // Build phase confirmation data from the question + const data: PhaseConfirmationData = { + questionId: question.questionId, + contractId: question.contractId, + contractName: question.phaseConfirmation?.contractName, + currentPhase: question.phaseConfirmation?.currentPhase || "research", + nextPhase: question.phaseConfirmation?.nextPhase || "specify", + summary: question.phaseConfirmation?.summary, + deliverables: question.phaseConfirmation?.deliverables, + }; + + const handleApprove = async (questionId: string) => { + const success = await submitAnswer(questionId, "APPROVE"); + if (success) { + dismissNotification(questionId); + } + }; + + const handleRequestChanges = async (questionId: string, feedback: string) => { + const success = await submitAnswer( + questionId, + `CHANGES_REQUESTED: ${feedback}` + ); + if (success) { + dismissNotification(questionId); + } + }; + + const handleDismiss = () => { + // Dismiss to notification (user can still respond via task output) + dismissNotification(question.questionId); + }; + + return ( + <PhaseConfirmationModal + data={data} + onApprove={handleApprove} + onRequestChanges={handleRequestChanges} + onDismiss={handleDismiss} + /> + ); +} + +/** + * Alternative: Notification toast-style for phase confirmations + * Shows as a small notification in the corner (like regular supervisor questions) + */ +export function PhaseConfirmationToast() { + const navigate = useNavigate(); + const { notificationQuestions, dismissNotification } = useSupervisorQuestions(); + + // Filter for phase_confirmation type questions + const phaseConfirmationQuestions = notificationQuestions.filter( + (q) => q.questionType === "phase_confirmation" + ); + + if (phaseConfirmationQuestions.length === 0) { + return null; + } + + const handleGoToTask = (question: PendingQuestion) => { + dismissNotification(question.questionId); + navigate(`/mesh/${question.taskId}`); + }; + + return ( + <div className="fixed bottom-4 right-4 z-50 max-w-md space-y-2"> + {phaseConfirmationQuestions.map((question) => ( + <div + key={question.questionId} + className="bg-[#0d1b2d] border border-[rgba(117,170,252,0.5)] rounded-lg shadow-lg overflow-hidden" + > + {/* Header */} + <div className="flex items-center justify-between px-4 py-3 bg-[rgba(117,170,252,0.1)]"> + <div className="flex items-center gap-2"> + <span className="text-[#75aafc] text-lg">?</span> + <span className="font-mono text-sm text-[#9bc3ff] uppercase"> + Phase Transition + </span> + </div> + <button + onClick={() => handleGoToTask(question)} + className="px-3 py-1 font-mono text-xs text-[#75aafc] border border-[rgba(117,170,252,0.3)] hover:border-[rgba(117,170,252,0.5)] hover:bg-[rgba(117,170,252,0.1)] transition-colors uppercase" + > + Review + </button> + </div> + + {/* Content preview */} + <div className="px-4 py-3"> + {question.phaseConfirmation && ( + <div className="flex items-center gap-2 mb-2"> + <span className="font-mono text-xs text-purple-400"> + {question.phaseConfirmation.currentPhase} + </span> + <span className="text-[#555] font-mono text-xs">→</span> + <span className="font-mono text-xs text-green-400"> + {question.phaseConfirmation.nextPhase} + </span> + </div> + )} + <p className="text-sm text-[#dbe7ff] font-mono line-clamp-2"> + {question.question} + </p> + {question.phaseConfirmation?.contractName && ( + <p className="text-xs text-[#555] font-mono mt-1"> + Contract: {question.phaseConfirmation.contractName} + </p> + )} + </div> + </div> + ))} + </div> + ); +} |
