diff --git a/Frontend/src/components/CodeChallenge.jsx b/Frontend/src/components/CodeChallenge.jsx index 107a17d..f57c7e6 100644 --- a/Frontend/src/components/CodeChallenge.jsx +++ b/Frontend/src/components/CodeChallenge.jsx @@ -16,7 +16,10 @@ const CodeChallenge = () => { const [activeSocket, setActiveSocket] = useState(null); const [submissionId, setSubmissionId] = useState(null); const [timeRemaining, setTimeRemaining] = useState(null); + const [terminalInput, setTerminalInput] = useState(''); + const [waitingForInput, setWaitingForInput] = useState(false); const socketRef = useRef(null); + const terminalInputRef = useRef(null); const { token } = useAuth(); const navigate = useNavigate(); @@ -26,6 +29,8 @@ const CodeChallenge = () => { if (testData) { try { const parsedData = JSON.parse(testData); + console.log('Loaded test data:', parsedData); + console.log('End time in test data:', parsedData.end_time); setTest(parsedData); if (parsedData.questions && parsedData.questions.length > 0) { setQuestions(parsedData.questions); @@ -45,11 +50,36 @@ const CodeChallenge = () => { // Timer countdown useEffect(() => { - if (!test || !test.end_time) return; + if (!test) return; + + // Check for different possible time field names + const endTimeValue = test.end_time || test.endTime || test.end_date; + + if (!endTimeValue) { + console.warn('No end time found in test data:', test); + return; + } const updateTimer = () => { const now = new Date(); - const endTime = new Date(test.end_time); + let endTime; + + // Try to parse the end time - handle different formats + try { + endTime = new Date(endTimeValue); + + // Check if the date is valid + if (isNaN(endTime.getTime())) { + console.error('Invalid date format:', endTimeValue); + setTimeRemaining('Invalid Date'); + return; + } + } catch (error) { + console.error('Error parsing end time:', error); + setTimeRemaining('Invalid Date'); + return; + } + const diff = endTime - now; if (diff <= 0) { @@ -111,6 +141,8 @@ const CodeChallenge = () => { // Reset execution state to allow rerunning const resetExecutionState = () => { setIsRunning(false); + setWaitingForInput(false); + setTerminalInput(''); // Properly close the socket if it exists and is open if (socketRef.current) { @@ -126,6 +158,32 @@ const CodeChallenge = () => { console.log('Execution state reset, buttons should be enabled'); }; + // Handle terminal input submission + const handleTerminalInput = (e) => { + e.preventDefault(); + + if (!terminalInput.trim()) { + return; + } + + // Display the input in terminal + setTerminalOutput(prev => [ + ...prev, + { type: 'input', content: terminalInput } + ]); + + // If socket is available, send input to backend + if (activeSocket && activeSocket.readyState === WebSocket.OPEN) { + activeSocket.send(JSON.stringify({ + type: 'input', + content: terminalInput + '\n' + })); + } + + // Clear input + setTerminalInput(''); + }; + // Example problem data const problems = { "Q.1": { @@ -348,6 +406,13 @@ int main() { socket.onopen = () => { console.log('WebSocket connection established'); setActiveSocket(socket); + setWaitingForInput(true); + // Focus the input field when connection is ready + setTimeout(() => { + if (terminalInputRef.current) { + terminalInputRef.current.focus(); + } + }, 100); }; socket.onmessage = (event) => { @@ -369,10 +434,18 @@ int main() { case 'input_prompt': // Handle input prompt message (e.g., "Enter your name:") + console.log('Input prompt received'); setTerminalOutput(prev => [ ...prev, { type: 'output', content: message.content } ]); + // Ensure input is enabled and focused + setWaitingForInput(true); + setTimeout(() => { + if (terminalInputRef.current) { + terminalInputRef.current.focus(); + } + }, 50); break; case 'status': @@ -434,6 +507,7 @@ int main() { console.log('System message indicates completion, enabling buttons'); setTimeout(() => { setIsRunning(false); + setWaitingForInput(false); }, 500); } break; @@ -461,6 +535,7 @@ int main() { ]); console.log('WebSocket error, enabling buttons'); + setWaitingForInput(false); setTimeout(() => { setIsRunning(false); }, 500); // Small delay to ensure UI updates properly @@ -622,6 +697,67 @@ int main() { } }; + // Handle save and move to next question + const handleSaveAndNext = async () => { + const currentQuestion = getCurrentQuestion(); + + if (!currentQuestion || !test) { + alert('No test data available.'); + return; + } + + // Save current answer + try { + const apiUrl = import.meta.env.VITE_FACULTY_API_URL || 'http://localhost:5000/api'; + const response = await fetch(`${apiUrl}/students/submissions`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + testId: test.id, + answers: [{ + questionId: currentQuestion.id, + submittedAnswer: code + }] + }), + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || `HTTP error! status: ${response.status}`); + } + + // Store submission locally + localStorage.setItem(`submission_${test.id}_${currentQuestion.id}`, JSON.stringify({ + code, + timestamp: new Date().toISOString() + })); + + setTerminalOutput([ + { type: 'system', content: `✓ Answer saved for Question ${getQuestionIndex(activeQuestion) + 1}` } + ]); + + // Move to next question if available + const currentIndex = getQuestionIndex(activeQuestion); + if (currentIndex < questions.length - 1) { + const nextQuestionKey = `Q.${currentIndex + 2}`; + setActiveQuestion(nextQuestionKey); + } else { + // If last question, show message + setTerminalOutput([ + { type: 'system', content: '✓ Answer saved!' }, + { type: 'output', content: 'This is the last question. Click "Submit Test" to finish.' } + ]); + } + + } catch (error) { + console.error('Error saving answer:', error); + alert(`Error saving answer: ${error.message}`); + } + }; + // Handle final test submission const handleSubmitTest = async () => { if (!test) { @@ -933,20 +1069,45 @@ int main() { -
+
{ + if (waitingForInput && terminalInputRef.current) { + terminalInputRef.current.focus(); + } + }} + style={{ cursor: waitingForInput ? 'text' : 'default' }} + > {terminalOutput.length === 0 ? (
Console output will appear here...
) : ( - terminalOutput.map((line, index) => ( -
- {line.content} -
- )) + <> + {terminalOutput.map((line, index) => ( +
+ {line.content} +
+ ))} + {waitingForInput && ( +
+
+ {'> '} + setTerminalInput(e.target.value)} + className="console-input" + autoFocus + /> +
+
+ )} + )}
@@ -971,7 +1132,10 @@ int main() { )} -