diff --git a/src/hooks/useAuth.js b/src/hooks/useAuth.js
new file mode 100644
index 0000000..20b1395
--- /dev/null
+++ b/src/hooks/useAuth.js
@@ -0,0 +1,7 @@
+// src/hooks/useAuth.js
+import { useContext } from "react";
+import { AuthContext } from "../contexts/AuthContext";
+
+export const useAuth = () => {
+ return useContext(AuthContext);
+};
diff --git a/src/pages/AssignmentPage.jsx b/src/pages/AssignmentPage.jsx
index ede6235..5bd8855 100644
--- a/src/pages/AssignmentPage.jsx
+++ b/src/pages/AssignmentPage.jsx
@@ -1,107 +1,191 @@
-// Page - Assignment
-import { useEffect, useState } from 'react';
-import '../scss/styles.scss';
+import React, { useState } from "react";
+import "../scss/components/_assignment.scss";
const AssignmentPage = () => {
- const [files, setFiles] = useState([]);
-
- useEffect(() => {
- document.title = 'Assignment';
- }, []);
+ const [studentName, setStudentName] = useState("");
+ const [campID, setCampID] = useState("");
+ const [programID, setProgramID] = 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);
- const handleFileChange = (e) => {
- if (e.target.files) {
- const newFiles = Array.from(e.target.files);
- setFiles(prevFiles => [...prevFiles, ...newFiles]);
- }
+ const resetForm = () => {
+ setStudentName("");
+ setCampID("");
+ setProgramID("");
+ setPassword("");
+ setTitle("");
+ setDescription("");
+ setFile(null);
+ setEditingIndex(null);
+ };
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+
+ const newProject = {
+ studentName,
+ campID,
+ programID,
+ title,
+ description,
+ fileName: file ? file.name : null,
};
- const handleRemoveFile = (index) => {
- setFiles(prevFiles => prevFiles.filter((_, i) => i !== index));
- };
+ if (editingIndex !== null) {
+ // Edit mode: update the project at the index
+ const updatedProjects = [...projects];
+ updatedProjects[editingIndex] = newProject;
+ setProjects(updatedProjects);
+ } else {
+ // New submission
+ setProjects([...projects, newProject]);
+ }
- const handleSubmit = (e) => {
- e.preventDefault();
- // Here you would typically send the files to a server
- console.log('Files to submit:', files);
- alert('Assignment submitted successfully!');
- };
+ alert(editingIndex !== null ? "Assignment updated!" : "Assignment submitted!");
+ resetForm();
+ setShowModal(false);
+ };
- return (
-
-
-
-
Assignment Submission
-
-
Due on Jan 16, 2025 11:59 PM
-
-
-
-
-
-
Submit Assignment
-
({files.length}) file(s) to submit
-
After uploading, you must click Submit to complete the submission.
-
-
-
-
-
-
-
-
-
- {files.length > 0 && (
-
-
Selected Files:
-
- {files.map((file, index) => (
- -
- {file.name}
- ({(file.size / 1024).toFixed(2)} KB)
-
-
- ))}
-
-
- )}
-
-
-
-
Comments
-
-
-
-
-
-
-
-
-
-
- );
+ const handleEdit = (index) => {
+ const project = projects[index];
+ setStudentName(project.studentName);
+ setCampID(project.campID);
+ setProgramID(project.programID);
+ setTitle(project.title);
+ setDescription(project.description);
+ setFile(null); // File can't be set again for editing, usually. You could add note about this.
+ setEditingIndex(index);
+ setShowModal(true);
+ };
+
+ const handleDelete = (index) => {
+ const updated = projects.filter((_, i) => i !== index);
+ setProjects(updated);
+ };
+
+ return (
+
+
π Assignments
+
+
+ {showModal && (
+
+
+
{editingIndex !== null ? "Edit Assignment" : "New Assignment"}
+
+
+
+ )}
+
+
+
π Projects
+ {projects.map((project, index) => (
+
+
+ Student Name: {project.studentName} | CampID: {project.campID} | ProgramID: {project.programID}
+
+
{project.title}
+
{project.description}
+ {project.fileName && (
+
Uploaded File: {project.fileName}
+ )}
+
+
+
+
+
+
+
+ ))}
+
+
+
+ );
};
export default AssignmentPage;
diff --git a/src/routers/AppRouter.jsx b/src/routers/AppRouter.jsx
index c4ff117..6f85e45 100644
--- a/src/routers/AppRouter.jsx
+++ b/src/routers/AppRouter.jsx
@@ -16,6 +16,7 @@ import Hero from "../components/Hero";
import Navbar from "../components/Navbar";
import Services from "../components/Services";
+
const AppRouter = () => {
return (
@@ -31,7 +32,15 @@ const AppRouter = () => {
>
}
/>
- } />
+
+
+ //
+ }
+ />
+ } />
{
}
/>
- } />
+
} />
diff --git a/src/scss/components/ProtectedRoute.jsx b/src/scss/components/ProtectedRoute.jsx
new file mode 100644
index 0000000..0f5769c
--- /dev/null
+++ b/src/scss/components/ProtectedRoute.jsx
@@ -0,0 +1,23 @@
+import React from "react";
+import { Navigate } from "react-router-dom";
+import { useAuth } from "../hooks/useAuth"; // μμ ν
: λμ νλ‘μ νΈμ λ§κ² μμ !
+
+const ProtectedRoute = ({ children, role }) => {
+ const { user, isLoading } = useAuth();
+
+ if (isLoading) {
+ return loading...
;
+ }
+
+ if (!user) {
+ return ;
+ }
+
+ if (role && user.role !== role) {
+ return ;
+ }
+
+ return children;
+};
+
+export default ProtectedRoute;
diff --git a/src/scss/components/_assignment.scss b/src/scss/components/_assignment.scss
new file mode 100644
index 0000000..7d424b8
--- /dev/null
+++ b/src/scss/components/_assignment.scss
@@ -0,0 +1,238 @@
+.assignment-page {
+ max-width: 600px;
+ margin: auto;
+ padding: 20px;
+
+ form {
+ margin-bottom: 20px;
+
+ div {
+ margin-bottom: 15px;
+
+ label {
+ display: block;
+ font-weight: bold;
+ margin-bottom: 5px;
+ }
+
+ input[type="text"],
+ textarea,
+ input[type="file"] {
+ width: 100%;
+ padding: 8px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ }
+
+ textarea {
+ height: 80px;
+ resize: vertical;
+ }
+ }
+
+ button {
+ padding: 8px 16px;
+ background-color: #4285f4;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+
+ &:hover {
+ background-color: #3367d6;
+ }
+ }
+ }
+
+ .project-list {
+ margin-top: 2rem;
+
+ h3 {
+ color: #4a90e2;
+ }
+
+ .project-item {
+ background: #ffffff;
+ border: 1px solid #e0e0e0;
+ border-radius: 12px;
+ padding: 1.5rem;
+ margin-bottom: 1.5rem;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+
+ // &:hover {
+ // transform: translateY(-2px);
+ // box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
+ // }
+
+ .project-meta {
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.75rem;
+ flex-wrap: wrap;
+
+ strong {
+ color: #34495e;
+ }
+ }
+
+ h4 {
+ margin: 0.5rem 0;
+ font-size: 1.2rem;
+ color: #2d3436;
+ }
+
+ p {
+ margin: 0.25rem 0;
+ color: #555;
+ line-height: 1.4;
+
+ strong {
+ color: #2d3436;
+ }
+ }
+
+ .action-buttons {
+ display: flex;
+ gap: 0.5rem;
+ margin-top: 0.75rem;
+
+ button {
+ background-color: #f4f4f4;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ padding: 0.4rem 0.8rem;
+ cursor: pointer;
+ font-size: 0.9rem;
+ transition: background-color 0.2s ease;
+
+ &:hover {
+ background-color: #e9ecef;
+ }
+
+ &:nth-child(1) {
+ color: #2c3e50;
+ }
+
+ &:nth-child(2) {
+ color: #c0392b;
+ }
+
+ &:nth-child(3) {
+ color: #16a085;
+ }
+ }
+ }
+ }
+ }
+
+
+ .modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.6);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ }
+
+ .modal {
+ background: #fff;
+ padding: 2rem;
+ border-radius: 12px;
+ max-width: 500px;
+ width: 100%;
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
+ animation: fadeIn 0.3s ease;
+ }
+
+ .modal h3 {
+ margin-bottom: 1rem;
+ font-size: 1.5rem;
+ font-weight: 600;
+ color: #333;
+ }
+
+ .modal form > div {
+ margin-bottom: 1rem;
+ }
+
+ .modal label {
+ display: block;
+ font-size: 0.9rem;
+ font-weight: 500;
+ margin-bottom: 0.4rem;
+ color: #555;
+ }
+
+ .modal input[type="text"],
+ .modal input[type="password"],
+ .modal input[type="file"],
+ .modal textarea {
+ width: 100%;
+ padding: 0.6rem 0.8rem;
+ border: 1px solid #ccc;
+ border-radius: 6px;
+ font-size: 0.95rem;
+ transition: border-color 0.2s ease;
+
+ &:focus {
+ border-color: #007bff;
+ outline: none;
+ }
+ }
+
+ .modal textarea {
+ resize: vertical;
+ min-height: 80px;
+ }
+
+ .modal-buttons {
+ display: flex;
+ justify-content: flex-end;
+ gap: 1rem;
+ margin-top: 1.5rem;
+ }
+
+ .modal-buttons button {
+ padding: 0.6rem 1.2rem;
+ font-size: 0.95rem;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background 0.2s ease;
+ }
+
+ .modal-buttons button[type="submit"] {
+ background-color: #ff4b2b;
+ color: #fff;
+
+ &:hover {
+ background-color: #FF2600;
+ }
+ }
+
+ .modal-buttons button[type="button"] {
+ background-color: #e0e0e0;
+ color: #333;
+
+ &:hover {
+ background-color: #cfcfcf;
+ }
+ }
+
+ @keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+}
\ No newline at end of file