From a960c4db6b879b497f3333a6eed4095f86fd3723 Mon Sep 17 00:00:00 2001 From: Nanvithaa Date: Fri, 18 Apr 2025 22:43:44 -0500 Subject: [PATCH 01/26] A1 form Completed --- client/src/pages/A1InternshipRequestForm.js | 28 +- client/src/pages/SupervisorDashboard.js | 64 +++-- client/src/pages/ViewFormModal.js | 264 +++++++++++++++--- client/src/styles/A1InternshipRequestForm.css | 26 ++ client/src/styles/SupervisorDashboard.css | 8 + client/src/styles/ViewFormModal.css | 143 ++++++++++ 6 files changed, 469 insertions(+), 64 deletions(-) create mode 100644 client/src/styles/ViewFormModal.css diff --git a/client/src/pages/A1InternshipRequestForm.js b/client/src/pages/A1InternshipRequestForm.js index 81191c88..350e0d4c 100644 --- a/client/src/pages/A1InternshipRequestForm.js +++ b/client/src/pages/A1InternshipRequestForm.js @@ -138,13 +138,37 @@ const A1InternshipRequestForm = () => { const submitFormData = async () => { try { + const submissionPayload = { + studentName: formData.interneeName, + soonerId: formData.soonerId, + studentEmail: formData.interneeEmail, + workplace: { + name: formData.workplaceName, + website: formData.website, + phone: formData.phone + }, + internshipAdvisor: { + name: formData.advisorName, + jobTitle: formData.advisorJobTitle, + email: formData.advisorEmail + }, + creditHours: parseInt(formData.creditHours), + startDate: formData.startDate, + endDate: formData.endDate, + tasks: formData.tasks, + status: "submitted", + }; + console.log("Submitting payload:", submissionPayload); + + const response = await fetch(`${process.env.REACT_APP_API_URL}/api/form/submit`, { method: "POST", headers: { - "Content-Type": "application/json", + "Content-Type": "application/json" }, - body: JSON.stringify(formData), + body: JSON.stringify(submissionPayload), }); + if (!response.ok) { throw new Error("Failed to submit form", {cause: response}); } diff --git a/client/src/pages/SupervisorDashboard.js b/client/src/pages/SupervisorDashboard.js index 18cc054d..fff39e5b 100644 --- a/client/src/pages/SupervisorDashboard.js +++ b/client/src/pages/SupervisorDashboard.js @@ -3,16 +3,37 @@ import axios from "axios"; import "../styles/SupervisorDashboard.css"; import ViewFormModal from "./ViewFormModal"; + const SupervisorDashboard = () => { const [requests, setRequests] = useState([]); const [selectedForm, setSelectedForm] = useState(null); const [loading, setLoading] = useState(true); const [message, setMessage] = useState(""); + const handleFormActionComplete = () => { + fetchRequests(); // ✅ Refresh from DB + setSelectedForm(null); + }; + + + const fetchRequests = async () => { + try { + const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/form/a1forms`); + setRequests(res.data); + setLoading(false); + } catch (err) { + console.error("Error fetching requests:", err); + setMessage("Error fetching requests."); + setLoading(false); + } + }; + + useEffect(() => { const fetchRequests = async () => { try { - const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/submissions/pending`); + const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/form/a1forms`); + setRequests(res.data); setLoading(false); @@ -23,8 +44,11 @@ const SupervisorDashboard = () => { } }; fetchRequests(); + }, []); + + const handleAction = async (id, action, comment) => { const confirmed = window.confirm(`Are you sure you want to ${action} this request?`); if (!confirmed) return; @@ -46,7 +70,10 @@ const SupervisorDashboard = () => { const formatDate = (dateStr) => new Date(dateStr).toLocaleDateString(); - const sortedRequests = [...requests].sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)); + const sortedRequests = [...requests] + .filter((req) => req.status.toLowerCase() === "submitted") + .sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)); + let content; @@ -73,23 +100,21 @@ const SupervisorDashboard = () => { - {sortedRequests.map((req) => ( - - {req.name} - - - - {req.form_type} - {formatDate(req.createdAt)} - - - {req.supervisor_status} - - - - ))} + {sortedRequests.map((req) => ( + openFormView(req)}> + {req.studentName} + {req.soonerId} + A.1 + {formatDate(req.createdAt)} + + + {req.status} + + + + +))} + ); @@ -105,6 +130,7 @@ const SupervisorDashboard = () => { formData={selectedForm} onClose={closeFormView} onAction={handleAction} + onActionComplete={handleFormActionComplete} /> )} diff --git a/client/src/pages/ViewFormModal.js b/client/src/pages/ViewFormModal.js index e913db19..f97fcd7a 100644 --- a/client/src/pages/ViewFormModal.js +++ b/client/src/pages/ViewFormModal.js @@ -1,63 +1,241 @@ import React, { useState } from "react"; -import "../styles/SupervisorDashboard.css"; +import "../styles/A1InternshipRequestForm.css"; -const ViewFormModal = ({ formData, onClose, onAction }) => { - const form = typeof formData.details === "string" ? JSON.parse(formData.details) : formData.details; +const outcomeLabels = [ + "Problem Solving", + "Solution Development", + "Communication", + "Decision-Making", + "Collaboration", + "Application", +]; + +const outcomeDescriptions = [ + "Understand and solve complex computing problems", + "Create, build, and assess computing solutions", + "Communicate clearly and confidently", + "Make responsible decisions", + "Work well within a team", + "Apply computer science algorithms to create practical solutions", +]; + +const ViewFormModal = ({ formData, onClose, onAction, onActionComplete }) => { const [comment, setComment] = useState(""); + const [signature, setSignature] = useState(""); const [error, setError] = useState(""); - const handleDecision = (action) => { + const handleAction = async (action) => { if (!comment.trim()) { setError("Comment is required before taking action."); return; } - setError(""); // clear error - onAction(formData._id, action, comment); + if (!signature.trim()) { + setError("Signature is required before approval/rejection."); + return; + } + + try { + const payload = { + soonerId: formData.soonerId, + comment, + signature, + status: action === "approve" ? "Approved" : "Rejected", + }; + + const res = await fetch(`${process.env.REACT_APP_API_URL}/api/form/supervisor-action`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(payload) + }); + + const data = await res.json(); + if (!res.ok) throw new Error(data.message || "Failed to update status"); + + console.log("Supervisor action saved:", data); + onActionComplete(); + onClose(); + } catch (err) { + console.error("Action failed:", err); + setError(err.message || "Error performing action"); + } }; return (
-
-

Form: {formData.form_type}

-

Student: {formData.name}

- - {form.tasks && ( -
- Tasks: -
    {form.tasks.map((task, i) =>
  • {task}
  • )}
-
- )} +
+

A.1 - Internship Request Form

+
+

Internee & Workplace Information:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Internee DetailsWorkplace DetailsInternship Advisor Details
+ Name:
+ +
+ Name:
+ +
+ Name:
+ +
+ Sooner ID:
+ +
+ Website:
+ +
+ Job Title:
+ +
+ Email:
+ +
+ Phone:
+ +
+ Email:
+ +
+ Credit Hours:
+ +
+ Start Date:
+ +
+ End Date:
+ +
- {form.outcomes && ( -
- Outcomes: -
    {form.outcomes.map((o, i) =>
  • {o}
  • )}
-
- )} +

Task Details & Program Outcomes

+ + + + + {outcomeLabels.map((label, i) => ( + + ))} + + + + {formData.tasks.map((task, i) => ( + + + {outcomeLabels.map((outcome, j) => ( + + ))} + + ))} + +
Task + {label} +
+ ({outcomeDescriptions[i]}) +
+ + + {task.outcomes?.includes(outcome.toLowerCase()) ? "✔" : ""} +
- {form.week &&

Week: {form.week}

} - {form.lessonsLearned &&

Lessons Learned: {form.lessonsLearned}

} +

Signatures

+ + + + + + + + +
+ Internee Signature:
+ +
+ Internship Advisor Signature:
+ setSignature(e.target.value)} + /> +
+ Internship Coordinator Approval:
+ +
-
- -