diff --git a/client/package.json b/client/package.json index f8e56288..cebf966c 100644 --- a/client/package.json +++ b/client/package.json @@ -15,7 +15,7 @@ "react-dom": "^19.0.0", "react-icons": "^5.5.0", "react-router-dom": "^7.4.1", - "react-scripts": "5.0.1", + "react-scripts": "^5.0.1", "react-signature-canvas": "^1.1.0-alpha.2", "react-toastify": "^11.0.5", "sweetalert2": "^11.17.2", diff --git a/client/src/pages/A3JobEvaluationForm.jsx b/client/src/pages/A3JobEvaluationForm.jsx index cb63ddf3..beb8c6fa 100644 --- a/client/src/pages/A3JobEvaluationForm.jsx +++ b/client/src/pages/A3JobEvaluationForm.jsx @@ -9,6 +9,7 @@ import { Modal, Tab, Nav, + Alert, } from "react-bootstrap"; import SignatureCanvas from "react-signature-canvas"; import "../styles/A3JobEvaluationForm.css"; @@ -41,22 +42,24 @@ const A3JobEvaluationForm = () => { interneeName: "", interneeID: "", interneeEmail: "", - advisorSignature: "", - advisorAgreement: false, + supervisorSignature: "", + supervisorAgreement: false, coordinatorSignature: "", coordinatorAgreement: false, + locked: false, //not locked with fresh form }); + const [supervisorDetails, setSupervisorDetails] = useState(null); const [errors, setErrors] = useState({}); - + // Ratings and comments const [ratings, setRatings] = useState({}); const [comments, setComments] = useState({}); // Modal state const [showModal, setShowModal] = useState(false); - const [activeSignatureTarget, setActiveSignatureTarget] = useState("advisor"); + const [activeSignatureTarget, setActiveSignatureTarget] = useState("supervisor"); const [typedSignatures, setTypedSignatures] = useState({ - advisor: "", + supervisor: "", coordinator: "", }); const [selectedFont, setSelectedFont] = useState(fonts[0]); @@ -68,7 +71,7 @@ const A3JobEvaluationForm = () => { if (!formData.interneeName?.trim()) newErrors.interneeName = "Name is required."; if (!/^\d{9}$/.test(formData.interneeID || "")) newErrors.interneeID = "Enter a valid 9-digit Sooner ID."; if (!/\S+@\S+\.\S+/.test(formData.interneeEmail || "")) newErrors.interneeEmail = "Invalid email."; - if (!formData.advisorSignature) newErrors.advisorSignature = "Signature is required."; + if (!formData.supervisorSignature) newErrors.supervisorSignature = "Signature is required."; if (!formData.coordinatorSignature) newErrors.coordinatorSignature = "Signature is required."; evaluationItems.forEach((item) => { if (!ratings[item]) { @@ -109,8 +112,8 @@ const A3JobEvaluationForm = () => { // Handle inserting signature from modal const handleSignatureInsert = () => { const targetField = - activeSignatureTarget === "advisor" - ? "advisorSignature" + activeSignatureTarget === "supervisor" + ? "supervisorSignature" : "coordinatorSignature"; if (activeTab === "type" && typedSignatures[activeSignatureTarget].trim()) { //handleChange(targetField, JSON.stringify({ type: 'text', value: typedSignatures[activeSignatureTarget], font: selectedFont })); @@ -143,10 +146,24 @@ const A3JobEvaluationForm = () => { // Submit the form to the backend const handleSubmit = async (e) => { e.preventDefault(); - if (!validateForm() || !formData.advisorAgreement || !formData.coordinatorAgreement) { + + if (!validateForm() || !formData.supervisorAgreement || !formData.coordinatorAgreement) { alert("Please confirm internee details and both signature agreements before submitting."); return; } + + // ✅ Build evaluations array with ALL 9 ITEMS + const evaluations = evaluationItems.slice(0, 3).map((item) => ({ + category: item, + rating: ratings[item], + comment: comments[item] || "" + })); + + if (evaluations.length !== 3 || evaluations.some(ev => !ev.rating)) { + alert("Please complete ratings for the required 3 evaluation items before submitting."); + return; + } + try { const response = await fetch( `${process.env.REACT_APP_API_URL}/api/evaluation`, @@ -157,29 +174,32 @@ const A3JobEvaluationForm = () => { interneeName: formData.interneeName, interneeID: formData.interneeID, interneeEmail: formData.interneeEmail, - advisorSignature: formData.advisorSignature, + supervisorSignature: formData.supervisorSignature, + supervisorAgreement: formData.supervisorAgreement, coordinatorSignature: formData.coordinatorSignature, - advisorAgreement: formData.advisorAgreement, coordinatorAgreement: formData.coordinatorAgreement, - ratings, - comments, + evaluations, + locked: true, // 🔥 ADD THIS LINE }), - } + } ); + if (response.ok) { alert("Evaluation submitted successfully!"); + // Reset form fields setFormData({ interneeName: "", interneeID: "", interneeEmail: "", - advisorSignature: "", - advisorAgreement: false, + supervisorSignature: "", + supervisorAgreement: false, coordinatorSignature: "", coordinatorAgreement: false, + locked: true, }); setRatings({}); setComments({}); - setTypedSignatures({ advisor: "", coordinator: "" }); + setTypedSignatures({ supervisor: "", coordinator: "" }); sigCanvasRef.current?.clear(); } else { const err = await response.json(); @@ -191,6 +211,7 @@ const A3JobEvaluationForm = () => { console.error(err); } }; + // Show preview of signature (text or image) const renderSignaturePreview = (field) => { @@ -231,29 +252,44 @@ const A3JobEvaluationForm = () => { style={{ backgroundColor: "#fff", maxWidth: "900px", width: "100%" }} >