diff --git a/src/App.tsx b/src/App.tsx index 832674a4..9dfb6af6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,7 +8,7 @@ import Jobs from "./opportunities/pages/Jobs.js"; import Departments from "./staff/pages/Departments.tsx"; import StaffPage from "./staff/pages/Staff.tsx"; import Department from "./staff/pages/Department.tsx"; -import CreatePost from "./staff/pages/CreatePost.js"; +import CreatePost from "./staff/pages/CreatePost.tsx"; import IndividualPost from "./opportunities/pages/IndividualPost.js"; import ProfilePage from "./shared/pages/Profile.js"; import LoginRedirection from "./auth/Login.tsx"; @@ -44,10 +44,10 @@ function App() { /> } /> } /> - } /> + } /> } + path="/edit/:postID" + element={} /> } /> diff --git a/src/shared/components/Navigation/MainNavigation.tsx b/src/shared/components/Navigation/MainNavigation.tsx index cab6002f..2bcb4042 100644 --- a/src/shared/components/Navigation/MainNavigation.tsx +++ b/src/shared/components/Navigation/MainNavigation.tsx @@ -9,7 +9,7 @@ export default function MainNavigation(authenticated) { const routes = authenticated.authenticated[1] ? [ { name: "Jobs", href: "/jobs", current: true }, - { name: "Create", href: "/createPost", current: false }, + { name: "Create", href: "/create", current: false }, { name: "Staff", href: "/staff", current: false }, { name: "Profile", href: "/profile", current: false }, { name: "Sign Out", href: "/signout", current: false }, diff --git a/src/shared/components/Navigation/StickyFooter.tsx b/src/shared/components/Navigation/StickyFooter.tsx index 5a9017c6..976a7c12 100644 --- a/src/shared/components/Navigation/StickyFooter.tsx +++ b/src/shared/components/Navigation/StickyFooter.tsx @@ -7,7 +7,7 @@ export default function StickyFooter(authenticated) { const routes = authenticated.authenticated[1] ? [ { name: "Jobs", href: "/jobs", current: true }, - { name: "Create", href: "/createPost", current: false }, + { name: "Create", href: "/create", current: false }, { name: "Staff", href: "/staff", current: false }, { name: "Profile", href: "/profile", current: false }, { name: "Sign Out", href: "/signout", current: false }, @@ -22,14 +22,13 @@ export default function StickyFooter(authenticated) { RCOS -
-
+
- LabConnect + LabConnect
-

+

Contact Us


-

+
-
- Additional Pages -

- {routes.map((item) => ( - <> - - {item.name} - -
- - ))} -

+
+ Resources +
+ {routes.map((item) => ( + + + {item.name} + +
+
+ ))}
-
- +
+ ); } diff --git a/src/staff/components/Checkbox.js b/src/staff/components/Checkbox.tsx similarity index 79% rename from src/staff/components/Checkbox.js rename to src/staff/components/Checkbox.tsx index cc8537d5..da90f437 100644 --- a/src/staff/components/Checkbox.js +++ b/src/staff/components/Checkbox.tsx @@ -1,4 +1,5 @@ import React from "react"; +import PropTypes from "prop-types"; const CheckBox = ({ formHook, @@ -9,10 +10,6 @@ const CheckBox = ({ options, type, }) => { - // if (!formHook) { - // return

FormHook Not Given

; - // } - return (
@@ -46,5 +43,14 @@ const CheckBox = ({
); }; +CheckBox.propTypes = { + formHook: PropTypes.object, + errors: PropTypes.object, + errorMessage: PropTypes.string, + name: PropTypes.string.isRequired, + label: PropTypes.string, + options: PropTypes.arrayOf(PropTypes.string), + type: PropTypes.string, +}; export default CheckBox; diff --git a/src/staff/components/CreationForms.js b/src/staff/components/CreationForms.tsx similarity index 53% rename from src/staff/components/CreationForms.js rename to src/staff/components/CreationForms.tsx index 4c925ccf..67e48693 100644 --- a/src/staff/components/CreationForms.js +++ b/src/staff/components/CreationForms.tsx @@ -1,46 +1,91 @@ import React, { useState } from "react"; import { useForm } from "react-hook-form"; import { useEffect } from "react"; -import CheckBox from "./Checkbox"; +import CheckBox from "./Checkbox.tsx"; import Input from "./Input"; import { useParams } from "react-router"; -import useGlobalContext from "../../context/global/useGlobalContext"; - -const DUMMY_DATA = { - "d1": { - id: "d1", - title: "Software Intern", - department: "Computer Science", - location: "Remote", - date: "2024-02-08", - type: "For Pay", // New field for type - hourlyPay: 0, - credits: 0, - description: "This is a software internship", - years: ["Freshman", "Junior", "Senior"], - }, -}; -const CreationForms = () => { +interface CreationFormsProps { + edit: boolean; + token: string; +} + +const locations = [ + "TBD", + "Amos Eaton", + "Carnegie", + "Center for Biotechnology and Interdisciplinary Studies", + "Center for Computational Innovations", + "Low Center for Industrial Innovation (CII)", + "Cogswell Laboratory", + "Darrin Communications Center", + "Experimental Media and Performing Arts Center", + "Greene Library", + "Jonsson Engineering Center", + "Jonsson-Rowland Science Center", + "Lally Hall", + "LINAC Facility (Gaerttner Laboratory)", + "Materials Research Center", + "Pittsburgh Building", + "Ricketts Building", + "Russell Sage Laboratory", + "Voorhees Computing Center", + "Walker Laboratory", + "West Hall", + "Winslow Building", + "Remote" +] + +const CreationForms: React.FC = ({ edit, token }) => { const { postID } = useParams(); - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(false); const [compensationType, setCompensationType] = useState("For Pay"); // Manage the state for "For Pay" or "For Credit" - const state = useGlobalContext(); - const { loggedIn } = state; - const { id: authorId } = state; - - async function fetchDetails(key) { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(DUMMY_DATA[key]); - }, 5000); - }); + const [years, setYears] = useState([]); + + async function fetchEditData() { + + + const response = await fetch( + `${process.env.REACT_APP_BACKEND_SERVER}/editOpportunity/${postID}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + if (response.ok) { + console.log("Response ok"); + const { id, title, application_due, type, hourlyPay, credits, description, recommended_experience, location, years } = await response.json(); + await Promise.all([fetchYears()]); + reset({ + id, + title, + application_due, + type, + hourlyPay, + credits, + description, + recommended_experience, + location, + years, + }); + + setLoading(false); + } else { + console.log("No response"); + setLoading("no response"); + } } - async function fetchData(key) { - const response = await fetchDetails(key); - response && reset(response); - response ? setLoading(false) : setLoading("no response"); + async function fetchYears() { + const response = await fetch(`${process.env.REACT_APP_BACKEND_SERVER}/years`) + + if (response.ok) { + const data = await response.json(); + setYears(data); + } else { + console.log("No response for years"); + setLoading("no response"); + } } const { @@ -52,36 +97,73 @@ const CreationForms = () => { defaultValues: { id: "", title: "", - department: "", - location: "", - date: "", + application_due: "", type: "For Pay", // Default to "For Pay" hourlyPay: 0, credits: [], description: "", + recommended_experience: "", + location: "", years: [""], }, }); useEffect(() => { - postID && setLoading(true); - postID && fetchData(postID); + fetchYears(); + if (edit) { + fetchEditData(); + } else { + setLoading(false); + } }, []); const submitHandler = (data) => { - if (authorId) { - console.log({ ...data, authorId }); + console.log({ ...data }); + if (edit) { + fetch(`${process.env.REACT_APP_BACKEND_SERVER}/editOpportunity/${postID}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ ...data }), + }).then((response) => { + if (response.ok) { + alert("Successfully updated"); + window.location.href = `/opportunity/${postID}`; + } else { + alert("Failed to update"); + } + }); + } else { + fetch(`${process.env.REACT_APP_BACKEND_SERVER}/createOpportunity`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ ...data }), + }).then((response) => { + if (response.ok) { + alert("Successfully created"); + const data_response = response.json() + window.location.href = `/opportunity/${data_response["id"]}`; + } else { + alert("Failed to create"); + console.log(response); + } + }); } }; - return !loading ? ( + return loading === false && years != null ? (
{ submitHandler(data); })} className="form-container" // Form container for vertical layout > - {/* Group 1: Horizontal layout for Title, Department, Location, Due Date */} + {/* Group 1: Horizontal layout for Title, Location, Due Date */}
{ maxLength: 100, }), }} - /> - -
@@ -168,7 +240,7 @@ const CreationForms = () => { checked={compensationType === "Any"} onChange={() => setCompensationType("Any")} /> - +
@@ -187,16 +259,19 @@ const CreationForms = () => { }), }} type="number" + options={[]} + placeHolder="Enter hourly pay" /> ) : null} {compensationType === "For Credit" || compensationType === "Any" ? ( {
{ ...register("description", { required: true, minLength: 10, - message: "Description must be at least 10 characters", }), }} type="textarea" + options={[]} + placeHolder="Enter description" + /> + +
@@ -241,7 +332,7 @@ const CreationForms = () => { ) : loading === "no response" ? (

There was no response

) : ( - +

Loading...

); }; diff --git a/src/staff/pages/CreatePost.js b/src/staff/pages/CreatePost.js deleted file mode 100644 index 4dc34bf6..00000000 --- a/src/staff/pages/CreatePost.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react"; -import CreationForms from "../components/CreationForms"; - -const CreatePost = ({edit}) => { - return ( -
-
-

{edit===true ? "Edit Research Opportunity" : "Create Research Opportunity"}

- -
-
- ); -}; - -export default CreatePost; \ No newline at end of file diff --git a/src/staff/pages/CreatePost.tsx b/src/staff/pages/CreatePost.tsx new file mode 100644 index 00000000..9769618c --- /dev/null +++ b/src/staff/pages/CreatePost.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import PropTypes from 'prop-types'; +import CreationForms from "../components/CreationForms.tsx"; +import SEO from "../../shared/components/SEO.tsx"; + +const CreatePost = ({ edit, authenticated }) => { + if (!authenticated[1]) { + window.location.href = "/login"; + } + + return ( +
+ +

{edit === true ? "Edit Research Opportunity" : "Create Research Opportunity"}

+ +
+ ); +}; +CreatePost.propTypes = { + edit: PropTypes.bool.isRequired, + authenticated: PropTypes.arrayOf(PropTypes.oneOfType([ + PropTypes.string, + PropTypes.bool + ])).isRequired +}; + +export default CreatePost; \ No newline at end of file diff --git a/src/staff/pages/Staff.tsx b/src/staff/pages/Staff.tsx index 99ca508b..c4008ce6 100644 --- a/src/staff/pages/Staff.tsx +++ b/src/staff/pages/Staff.tsx @@ -5,7 +5,7 @@ import ProfileOpportunities from "../components/ProfileOpportunities.tsx"; import { useParams } from "react-router"; import SEO from "../../shared/components/SEO.tsx"; -const StaffPage = (authenticated) => { +const StaffPage = (authenticated: { authenticated: [string, boolean]; }) => { if (!authenticated.authenticated[1]) { window.location.href = "/login"; }