Spaces:
Sleeping
Sleeping
| import React, { useState } from 'react'; | |
| import './SubmissionsPage.css'; | |
| import { useNavigate } from 'react-router-dom'; | |
| import { getData } from './GradingResults'; | |
| export let newRubric = null; | |
| export const getRubric = (rubric) => { | |
| newRubric = rubric | |
| } | |
| function SubmissionsPage() { | |
| const [submissions, setSubmissions] = useState([]); | |
| const [isGrading, setIsGrading] = useState(false); | |
| const navigate = useNavigate(); | |
| const handleFileUpload = (event) => { | |
| const files = Array.from(event.target.files); | |
| const newSubmissions = files.map(file => ({ | |
| file, | |
| name: file.name, | |
| pennId: '', | |
| id: Math.random().toString(36).substr(2, 9) | |
| })); | |
| setSubmissions(prev => [...prev, ...newSubmissions]); | |
| }; | |
| const updatePennId = (id, pennId) => { | |
| setSubmissions(prev => | |
| prev.map(sub => | |
| sub.id === id ? { ...sub, pennId } : sub | |
| ) | |
| ); | |
| }; | |
| const removeSubmission = (id) => { | |
| setSubmissions(prev => prev.filter(sub => sub.id !== id)); | |
| }; | |
| const handleGrading = async () => { | |
| console.log('Grading submissions...'); | |
| console.log(newRubric); | |
| setIsGrading(true); | |
| // Here you would handle the grading process | |
| // For each submission: { file, pennId } | |
| try { | |
| const createFormData = new FormData(); | |
| const rubricFile = new Blob([newRubric], { type: 'text/plain' }); | |
| createFormData.append('files', new File([rubricFile], 'rubric.txt')); | |
| const createUrl = "/create"; | |
| try { | |
| const response = await fetch(createUrl, { | |
| method: 'POST', | |
| body: createFormData, | |
| }); | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| const submissionId = await response.json(); | |
| console.log('Submission Id: ', submissionId); | |
| const submitUrl = `/submit?id=${submissionId}`; | |
| const submitFormData = new FormData(); | |
| submissions.forEach(submission => { | |
| submitFormData.append('pennId', submission.pennId); | |
| submitFormData.append('files', submission.file); | |
| }); | |
| try { | |
| const response = await fetch(submitUrl, { | |
| method: 'POST', | |
| body: submitFormData, | |
| }); | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| const data = await response.json(); | |
| console.log('Grading result:', data); | |
| getData(data); | |
| } | |
| catch (error) { | |
| console.error('Error during grading:', error); | |
| } | |
| // After grading is complete, navigate to results page | |
| navigate('/results'); | |
| } | |
| catch (error) { | |
| console.error('Error creating submission id', error); | |
| } | |
| } catch (error) { | |
| console.error('Grading failed:', error); | |
| } finally { | |
| setIsGrading(false); | |
| } | |
| }; | |
| const isReadyToGrade = submissions.length > 0 && | |
| submissions.every(sub => sub.pennId.trim().length > 0); | |
| return ( | |
| <div className="submissions-page"> | |
| <div className="submissions-container"> | |
| <h2>Upload Submissions</h2> | |
| <div className="upload-section"> | |
| <div className="upload-box"> | |
| <input | |
| type="file" | |
| id="file-upload" | |
| multiple | |
| onChange={handleFileUpload} | |
| accept=".pdf,.jpg,.jpeg,.png,.tex,.txt" | |
| className="file-input" | |
| /> | |
| <label htmlFor="file-upload" className="upload-label"> | |
| <i className="fas fa-cloud-upload-alt"></i> | |
| <span>Drop files here or click to upload</span> | |
| <span className="upload-hint">Supports PDF and images</span> | |
| </label> | |
| </div> | |
| </div> | |
| <div className="submissions-list"> | |
| {submissions.map(submission => ( | |
| <div key={submission.id} className="submission-item"> | |
| <div className="submission-info"> | |
| <i className="fas fa-file-alt file-icon"></i> | |
| <div className="submission-details"> | |
| <span className="file-name">{submission.name}</span> | |
| <input | |
| type="text" | |
| placeholder="Enter PennID" | |
| value={submission.pennId} | |
| onChange={(e) => updatePennId(submission.id, e.target.value)} | |
| className="pennid-input" | |
| /> | |
| </div> | |
| </div> | |
| <button | |
| className="remove-btn" | |
| onClick={() => removeSubmission(submission.id)} | |
| > | |
| <i className="fas fa-times"></i> | |
| </button> | |
| </div> | |
| ))} | |
| </div> | |
| {submissions.length > 0 && ( | |
| <div className="grading-controls"> | |
| <button | |
| className="grade-btn" | |
| disabled={!isReadyToGrade || isGrading} | |
| onClick={handleGrading} | |
| > | |
| {isGrading ? ( | |
| <> | |
| <i className="fas fa-spinner fa-spin"></i> | |
| Grading... | |
| </> | |
| ) : ( | |
| <> | |
| <i className="fas fa-check"></i> | |
| Grade All Submissions | |
| </> | |
| )} | |
| </button> | |
| {!isReadyToGrade && ( | |
| <p className="warning-text"> | |
| Please enter PennID for all submissions | |
| </p> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| export default SubmissionsPage; |