From 4b1cb0e7f18004b19091ad18598930a4d121050a Mon Sep 17 00:00:00 2001 From: JBB0807 <104856796+JBB0807@users.noreply.github.com> Date: Mon, 5 May 2025 14:51:13 -0700 Subject: [PATCH 1/6] submit assignment now creates a fly machine --- src/pages/AssignmentPage.jsx | 66 +++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/src/pages/AssignmentPage.jsx b/src/pages/AssignmentPage.jsx index d8b5941..e0bec79 100644 --- a/src/pages/AssignmentPage.jsx +++ b/src/pages/AssignmentPage.jsx @@ -5,10 +5,12 @@ const AssignmentPage = () => { const [studentName, setStudentName] = useState(""); const [campID, setCampID] = useState(""); const [programID, setProgramID] = useState(""); + const [appName, setAppName] = useState(""); + const [qrCodeNumber, setQrCodeNumber] = useState(""); const [password, setPassword] = useState(""); - const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); const [file, setFile] = useState(null); + const [projects, setProjects] = useState([]); const [showModal, setShowModal] = useState(false); const [editingIndex, setEditingIndex] = useState(null); @@ -44,7 +46,6 @@ const AssignmentPage = () => { setCampID(""); setProgramID(""); setPassword(""); - setTitle(""); setDescription(""); setFile(null); setEditingIndex(null); @@ -56,12 +57,48 @@ const AssignmentPage = () => { const newProject = { studentname: studentName, campid: campID, + appname: appName, + qrcodenumber: qrCodeNumber, + passwordhash: password, programid: programID, - title, description, - fileName: file ? file.name : null, + file: file, + intructorid: 9, }; + //callt the api to upload a new assignment + const formData = new FormData(); + formData.append("studentname", studentName); + formData.append("campid", campID); + formData.append("programid", programID); + formData.append("appname", appName); + formData.append("qrcodenumber", qrCodeNumber); + formData.append("password", password); + formData.append("description", description); + formData.append("intructoid", 9); + if (file) { + formData.append("file", file, file.name); + } + + fetch("http://localhost:8082/instructor/create", { + method: "POST", + body: formData, + }) + .then((response) => { + if (!response.ok) { + throw new Error("Failed to submit assignment"); + } + return response.json(); + }) + .then((data) => { + console.log("Assignment submitted successfully:", data); + fetchAssignments(); // Refresh the assignments list + }) + .catch((error) => { + console.error("Error submitting assignment:", error); + alert("Failed to submit assignment. Please try again."); + }); + if (editingIndex !== null) { const updatedProjects = [...projects]; updatedProjects[editingIndex] = newProject; @@ -80,7 +117,6 @@ const AssignmentPage = () => { setStudentName(project.studentname || project.studentName || ""); setCampID(project.campid || project.campID || ""); setProgramID(project.programid || project.programID || ""); - setTitle(project.title || ""); setDescription(project.description || ""); setFile(null); setEditingIndex(index); @@ -111,12 +147,23 @@ const AssignmentPage = () => {
- setCampID(e.target.value)} required /> + setCampID(e.target.value)} required />
- setProgramID(e.target.value)} required /> + setProgramID(e.target.value)} required /> +
+ +
+ + setAppName(e.target.value)} required /> +
+ + +
+ + setQrCodeNumber(e.target.value)} required />
@@ -124,11 +171,6 @@ const AssignmentPage = () => { setPassword(e.target.value)} required />
-
- - setTitle(e.target.value)} required /> -
-
From 8e1af2e846878a3db37ca4e64a97800e9cc606db Mon Sep 17 00:00:00 2001 From: JBB0807 <104856796+JBB0807@users.noreply.github.com> Date: Mon, 5 May 2025 18:49:51 -0700 Subject: [PATCH 2/6] added changes to verify student using QR code number and password instead --- src/pages/AssignmentPage.jsx | 2 +- src/pages/SignIn.jsx | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/AssignmentPage.jsx b/src/pages/AssignmentPage.jsx index e0bec79..985ff15 100644 --- a/src/pages/AssignmentPage.jsx +++ b/src/pages/AssignmentPage.jsx @@ -75,7 +75,7 @@ const AssignmentPage = () => { formData.append("qrcodenumber", qrCodeNumber); formData.append("password", password); formData.append("description", description); - formData.append("intructoid", 9); + formData.append("instructorid", 9); if (file) { formData.append("file", file, file.name); } diff --git a/src/pages/SignIn.jsx b/src/pages/SignIn.jsx index ff2372e..9f6462e 100644 --- a/src/pages/SignIn.jsx +++ b/src/pages/SignIn.jsx @@ -5,7 +5,7 @@ const authUrl = import.meta.env.VITE_AUTH_URL; function SignInForm() { const [state, setState] = React.useState({ - assignmentID: "", + qrNumber: "", password: "", }); const handleChange = (evt) => { @@ -19,8 +19,8 @@ function SignInForm() { const handleOnSubmit = (evt) => { evt.preventDefault(); - const { assignmentId, password } = state; - console.log(`You are loggind in with email: ${assignmentId} and password: ${password}`); + const { qrNumber, password } = state; + console.log(`You are loggind in with email: ${qrNumber} and password: ${password}`); console.log("Submitting login request with state:", state); fetch(`${authUrl}/auth/student/login`, { @@ -59,10 +59,10 @@ function SignInForm() {
*/} Date: Mon, 5 May 2025 19:03:02 -0700 Subject: [PATCH 3/6] change harcoded URL to .env/secrets --- .env | 4 ++-- .env.development | 2 +- src/pages/AssignmentPage.jsx | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.env b/.env index ddf3a43..827b820 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -#VITE_AUTH_URL="http://localhost:8080" -VITE_AUTH_URL="https://byte-camp-auth-service.fly.dev" \ No newline at end of file +VITE_AUTH_URL="https://byte-camp-auth-service.fly.dev" +VITE_ASSIGNMENT_URL="https://assignment-service.internal" \ No newline at end of file diff --git a/.env.development b/.env.development index 7dc9c2c..7affb16 100644 --- a/.env.development +++ b/.env.development @@ -1,2 +1,2 @@ VITE_AUTH_URL="http://localhost:8080" -#VITE_AUTH_URL="https://byte-camp-auth-service.fly.dev" \ No newline at end of file +VITE_ASSIGNMENT_URL="http://localhost:8082" \ No newline at end of file diff --git a/src/pages/AssignmentPage.jsx b/src/pages/AssignmentPage.jsx index 985ff15..ba560b7 100644 --- a/src/pages/AssignmentPage.jsx +++ b/src/pages/AssignmentPage.jsx @@ -15,6 +15,8 @@ const AssignmentPage = () => { const [showModal, setShowModal] = useState(false); const [editingIndex, setEditingIndex] = useState(null); + const VITE_ASSIGNMENT_URL = import.meta.env.VITE_ASSIGNMENT_URL; + useEffect(() => { document.title = "Assignment"; fetchAssignments(); @@ -22,7 +24,7 @@ const AssignmentPage = () => { const fetchAssignments = async () => { try { - const res = await fetch("http://localhost:8082/instructor/list/9", { + const res = await fetch(`${VITE_ASSIGNMENT_URL}/instructor/list/9`, { // credentials: "include", }); if (!res.ok) throw new Error("Failed to fetch"); @@ -80,7 +82,7 @@ const AssignmentPage = () => { formData.append("file", file, file.name); } - fetch("http://localhost:8082/instructor/create", { + fetch(`${VITE_ASSIGNMENT_URL}/instructor/create`, { method: "POST", body: formData, }) From 8a62bbfa1ed3f33f12614ef694167c07ce1eacb8 Mon Sep 17 00:00:00 2001 From: JBB0807 <104856796+JBB0807@users.noreply.github.com> Date: Mon, 5 May 2025 19:22:38 -0700 Subject: [PATCH 4/6] adjusted monaco editor to get the QR Code number instead of assignment id --- src/pages/CodeEditor.jsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/pages/CodeEditor.jsx b/src/pages/CodeEditor.jsx index 709f84c..f16f689 100644 --- a/src/pages/CodeEditor.jsx +++ b/src/pages/CodeEditor.jsx @@ -4,8 +4,11 @@ import EditorPanel from "../components/EditorPanel"; import PreviewPanel from "../components/PreviewPanel"; export default function PageCodeEditor() { - const { assignmentId: routeId } = useParams(); - const assignmentId = routeId || "52"; + + const { qrCodeNumber: routeId } = useParams(); + // console.log("Assignment ID:", assignmentId); + const qrCodeNumber = routeId || "2256"; + console.log("QR Code Number:", qrCodeNumber); const [appName, setAppName] = useState(""); const [code, setCode] = useState("# NOW LOADING"); @@ -15,14 +18,14 @@ export default function PageCodeEditor() { }, []); useEffect(() => { - fetch(`https://assignment-service.fly.dev/student/assignment/${assignmentId}`) + fetch(`https://assignment-service.fly.dev/student/assignment/${qrCodeNumber}`) .then((res) => { if (!res.ok) throw new Error("Failed to fetch assignment"); return res.json(); }) .then((data) => setAppName(data.appname)) .catch((err) => console.error("Assignment fetch error:", err)); - }, [assignmentId]); + }, [qrCodeNumber]); useEffect(() => { if (!appName) return; From 4ee194f102272d6212bd36c975a433946cafdaba Mon Sep 17 00:00:00 2001 From: JBB0807 <104856796+JBB0807@users.noreply.github.com> Date: Mon, 5 May 2025 23:38:31 -0700 Subject: [PATCH 5/6] validation for existing appname and qrcode --- .env | 2 +- src/pages/AssignmentPage.jsx | 336 +++++++++++++++++++++++++++-------- 2 files changed, 267 insertions(+), 71 deletions(-) diff --git a/.env b/.env index 827b820..d44cade 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ VITE_AUTH_URL="https://byte-camp-auth-service.fly.dev" -VITE_ASSIGNMENT_URL="https://assignment-service.internal" \ No newline at end of file +VITE_ASSIGNMENT_URL="http://assignment-service.internal" \ No newline at end of file diff --git a/src/pages/AssignmentPage.jsx b/src/pages/AssignmentPage.jsx index ba560b7..4601c70 100644 --- a/src/pages/AssignmentPage.jsx +++ b/src/pages/AssignmentPage.jsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react"; import "../scss/components/_assignment.scss"; const AssignmentPage = () => { + const [assignmentId, setAssignmentId] = useState(""); const [studentName, setStudentName] = useState(""); const [campID, setCampID] = useState(""); const [programID, setProgramID] = useState(""); @@ -10,27 +11,97 @@ const AssignmentPage = () => { const [password, setPassword] = useState(""); const [description, setDescription] = useState(""); const [file, setFile] = useState(null); - + const [projects, setProjects] = useState([]); const [showModal, setShowModal] = useState(false); const [editingIndex, setEditingIndex] = useState(null); + const [user, setUser] = useState([]); + const VITE_ASSIGNMENT_URL = import.meta.env.VITE_ASSIGNMENT_URL; + const authUrl = import.meta.env.VITE_AUTH_URL; useEffect(() => { document.title = "Assignment"; + getCurrentUser(); fetchAssignments(); }, []); + useEffect(() => { + if (!appName) return; // Don't alert for empty name + const timer = setTimeout(() => { + fetch(`${VITE_ASSIGNMENT_URL}/instructor/checkAssignmentByAppName/${appName}`) + .then((response) => { + if (!response.ok) { + throw new Error("Failed to fetch assignment by app name"); + } + return response.json(); + }) + .then((data) => { + if (data.exists) { + alert("This app name already exists. Please choose a different one."); + } + }) + .catch((error) => { + console.error("Error fetching assignment by app name:", error); + }); + }, 1000); // 1 second delay + + return () => clearTimeout(timer); // Clear timeout on name change + }, [appName]); + + useEffect(() => { + if (!qrCodeNumber) return; // Don't alert for empty QR code number + console.log("Checking QR code number:", qrCodeNumber); // Added console log + const timer = setTimeout(() => { + fetch(`${VITE_ASSIGNMENT_URL}/instructor/checkAssignmentByQRCode/${qrCodeNumber}`) + .then((response) => { + if (!response.ok) { + throw new Error("Failed to fetch assignment by QR code number"); + } + return response.json(); + }) + .then((data) => { + console.log("QR code fetch result:", data); // Added console log + if (data.exists) { + alert("This QR code number already exists. Please choose a different one."); + } + }) + .catch((error) => { + console.error("Error fetching assignment by QR code number:", error); + }); + }, 1000); // 1 second delay + + return () => clearTimeout(timer); // Clear timeout on QR code number change + }, [qrCodeNumber]); + + const getCurrentUser = async () => { + try { + const authResponse = await fetch(`${authUrl}/auth/current_user`, { + credentials: "include", + }); + + const user = await authResponse.json(); + setUser(user); + } catch (error) { + console.error("Error fetching current user:", error); + } + }; + const fetchAssignments = async () => { try { + // if (user) { + // console.log("Current user:", user, `${VITE_ASSIGNMENT_URL}/instructor/list/${user.userId}`); + // const res = await fetch(`${VITE_ASSIGNMENT_URL}/instructor/list/${user.userId}`, { + // // credentials: "include", + // }); + //replace this with commented code above to get the instructor id from the auth service const res = await fetch(`${VITE_ASSIGNMENT_URL}/instructor/list/9`, { // credentials: "include", }); - if (!res.ok) throw new Error("Failed to fetch"); + if (!res.ok) throw new Error("Failed to fetch"); const data = await res.json(); - // Optional: Remove duplicate assignment IDs if needed const unique = Array.from( @@ -38,6 +109,7 @@ const AssignmentPage = () => { ); setProjects(unique); + // } } catch (error) { console.error("Error fetching assignments:", error); } @@ -53,69 +125,87 @@ const AssignmentPage = () => { setEditingIndex(null); }; - const handleSubmit = (e) => { + const handleSubmit = async (e) => { e.preventDefault(); - const newProject = { - studentname: studentName, - campid: campID, - appname: appName, - qrcodenumber: qrCodeNumber, - passwordhash: password, - programid: programID, - description, - file: file, - intructorid: 9, - }; + if (!user.userId) return alert("Please login to submit an assignment."); - //callt the api to upload a new assignment + //Create the form data needed for both create and edit const formData = new FormData(); formData.append("studentname", studentName); formData.append("campid", campID); formData.append("programid", programID); - formData.append("appname", appName); formData.append("qrcodenumber", qrCodeNumber); formData.append("password", password); formData.append("description", description); - formData.append("instructorid", 9); - if (file) { - formData.append("file", file, file.name); - } - - fetch(`${VITE_ASSIGNMENT_URL}/instructor/create`, { - method: "POST", - body: formData, - }) - .then((response) => { - if (!response.ok) { - throw new Error("Failed to submit assignment"); - } - return response.json(); - }) - .then((data) => { - console.log("Assignment submitted successfully:", data); - fetchAssignments(); // Refresh the assignments list - }) - .catch((error) => { - console.error("Error submitting assignment:", error); - alert("Failed to submit assignment. Please try again."); - }); if (editingIndex !== null) { - const updatedProjects = [...projects]; - updatedProjects[editingIndex] = newProject; - setProjects(updatedProjects); + //edit mode + await fetch(`${VITE_ASSIGNMENT_URL}/instructor/update/${assignmentId}`, { + method: "PUT", + body: formData, + }) + .then((response) => { + + if (!response.ok) { + console.error("Failed to edit assignment:", response.statusText); + throw new Error("Failed to edit assignment"); + } + return response.json(); + }) + .then((data) => { + console.log("Assignment edited successfully:", data); + }) + .catch((error) => { + console.error("Error submitting assignment:", error); + alert(`Failed to submit assignment. ${error.message}`); + }); } else { - setProjects([...projects, newProject]); + //create mode + formData.append("instructorid", 9); + formData.append("appname", appName); + + if (file) { + formData.append("file", file, file.name); + } else { + throw new Error("Failed to submit assignment: file not found."); + } + + await fetch(`${VITE_ASSIGNMENT_URL}/instructor/create`, { + method: "POST", + body: formData, + }) + .then((response) => { + if (!response.ok) { + console.error("Failed to submit assignment:", response.statusText); + throw new Error("Failed to submit assignment"); + } + return response.json(); + }) + .then((data) => { + console.log("Assignment submitted successfully:", data); + }) + .catch((error) => { + console.error("Error submitting assignment:", error); + alert(`Failed to submit assignment. ${error.message}`); + }); } - alert(editingIndex !== null ? "Assignment updated!" : "Assignment submitted!"); + alert( + editingIndex !== null ? "Assignment updated!" : "Assignment submitted!" + ); + + fetchAssignments(); // Refresh the assignments list resetForm(); setShowModal(false); }; const handleEdit = (index) => { const project = projects[index]; + setAssignmentId(project.assignmentid || project.assignmentId || ""); + setAppName(project.appname || project.appName || ""); + setQrCodeNumber(project.qrcodenumber || project.qrCodeNumber || ""); + setPassword(project.passwordhash || project.password || ""); setStudentName(project.studentname || project.studentName || ""); setCampID(project.campid || project.campID || ""); setProgramID(project.programid || project.programID || ""); @@ -126,66 +216,145 @@ const AssignmentPage = () => { }; const handleDelete = (index) => { - const updated = projects.filter((_, i) => i !== index); - setProjects(updated); + const project = projects[index]; + if (window.confirm("Are you sure you want to delete this assignment?")) { + fetch(`${VITE_ASSIGNMENT_URL}/instructor/delete/${project.assignmentid}`, { + method: "DELETE", + }) + .then((response) => { + if (!response.ok) { + console.error("Failed to delete assignment:", response.statusText); + throw new Error("Failed to delete assignment"); + } + return response.json(); + }) + .then((data) => { + console.log("Assignment deleted successfully:", data); + alert("Assignment deleted successfully!"); + fetchAssignments(); // Refresh the assignments list + }) + .catch((error) => { + console.error("Error deleting assignment:", error); + alert(`Failed to delete assignment. ${error.message}`); + }); + } }; return (

Assignments

- +
{showModal && (
-

{editingIndex !== null ? "Edit Assignment" : "New Assignment"}

+

+ {editingIndex !== null ? "Edit Assignment" : "New Assignment"} +

- setStudentName(e.target.value)} required /> + setStudentName(e.target.value)} + required + />
- setCampID(e.target.value)} required /> + setCampID(e.target.value)} + required + />
- setProgramID(e.target.value)} required /> + setProgramID(e.target.value)} + required + />
- setAppName(e.target.value)} required /> + setAppName(e.target.value)} + required + disabled={editingIndex !== null} + s + />
-
- setQrCodeNumber(e.target.value)} required /> + setQrCodeNumber(e.target.value)} + required + />
- setPassword(e.target.value)} required /> + setPassword(e.target.value)} + required + />
- +
-
- - setFile(e.target.files[0])} /> -
+ {editingIndex === null && ( +
+ + setFile(e.target.files[0])} + /> +
+ )}
- - + +
@@ -197,31 +366,58 @@ const AssignmentPage = () => { {projects.map((project, index) => (
- Student Name: {project.studentname || project.studentName} |{" "} + Student Name:{" "} + {project.studentname || project.studentName} |{" "} CampID: {project.campid || project.campID} |{" "} - ProgramID: {project.programid || project.programID} + ProgramID:{" "} + {project.programid || project.programID}
{project.title &&

{project.title}

} {project.description &&

{project.description}

} - {project.fileName &&

Uploaded File: {project.fileName}

} + {project.fileName && ( +

+ Uploaded File: {project.fileName} +

+ )} {project.assignmenturl && (

- View Assignment + + View Assignment +

)} {project.originalfile && (

- Original File |{" "} - Editable File + + Original File + {" "} + |{" "} + + Editable File +

)}
- +
))} From a28dc7d3562f7f43ff07b39d20389bb7a2cf66a9 Mon Sep 17 00:00:00 2001 From: JBB0807 <104856796+JBB0807@users.noreply.github.com> Date: Mon, 5 May 2025 23:51:35 -0700 Subject: [PATCH 6/6] nave items displayed based on role --- src/components/Navbar.jsx | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index 537cb27..a37fc43 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -14,7 +14,7 @@ const Navbar = () => { async function handleLogout() { window.open(`${authUrl}/auth/logout`, "_self"); - }; + } useEffect(() => { // Set active link based on current path @@ -128,18 +128,22 @@ const Navbar = () => { */} -
  • - - 🎯 - ASSIGNMENT - - -
  • + + {user && user.role === "instructor" && ( +
  • + + 🎯 + ASSIGNMENT + + +
  • + )} + {user && user.role === "student" && (
  • {
  • + )}
  • {user ? (