diff --git a/backend/routers/projects.router.js b/backend/routers/projects.router.js
index 8991000cb..385d1229a 100644
--- a/backend/routers/projects.router.js
+++ b/backend/routers/projects.router.js
@@ -1,4 +1,4 @@
-const express = require("express");
+const express = require('express');
const router = express.Router();
const { ProjectController } = require('../controllers');
@@ -10,7 +10,8 @@ router.post('/', ProjectController.create);
router.get('/:ProjectId', ProjectController.project_by_id);
-router.patch('/:ProjectId', ProjectController.update);
+router.put('/:ProjectId', ProjectController.update);
+router.patch('/:ProjectId', ProjectController.update);
module.exports = router;
diff --git a/backend/routers/projects.router.test.js b/backend/routers/projects.router.test.js
index 5233247b9..36e16c708 100644
--- a/backend/routers/projects.router.test.js
+++ b/backend/routers/projects.router.test.js
@@ -20,10 +20,7 @@ describe('CREATE', () => {
};
// Submit a project
- const res = await request
- .post('/api/projects/')
- .set(headers)
- .send(submittedData);
+ const res = await request.post('/api/projects/').set(headers).send(submittedData);
expect(res.status).toBe(201);
done();
});
@@ -31,26 +28,23 @@ describe('CREATE', () => {
describe('READ', () => {
test('Get all projects with GET to /api/projects/', async (done) => {
- // Test Data
- const submittedData = {
- name: 'projectName',
- };
-
- // Submit a project
- const res = await request
- .post('/api/projects/')
- .set(headers)
- .send(submittedData);
- expect(res.status).toBe(201);
-
- // Get all projects
- const res2 = await request.get('/api/projects/').set(headers);
- expect(res2.status).toBe(200);
-
- const APIData = res2.body[0];
- expect(APIData.name).toBe(submittedData.name);
- done();
- });;
+ // Test Data
+ const submittedData = {
+ name: 'projectName',
+ };
+
+ // Submit a project
+ const res = await request.post('/api/projects/').set(headers).send(submittedData);
+ expect(res.status).toBe(201);
+
+ // Get all projects
+ const res2 = await request.get('/api/projects/').set(headers);
+ expect(res2.status).toBe(200);
+
+ const APIData = res2.body[0];
+ expect(APIData.name).toBe(submittedData.name);
+ done();
+ });
});
describe('UPDATE', () => {
@@ -61,10 +55,7 @@ describe('UPDATE', () => {
};
// Submit a project
- const res = await request
- .post('/api/projects/')
- .set(headers)
- .send(submittedData);
+ const res = await request.post('/api/projects/').set(headers).send(submittedData);
expect(res.status).toBe(201);
const updatedDataPayload = {
@@ -73,7 +64,7 @@ describe('UPDATE', () => {
// Update project
const res2 = await request
- .patch(`/api/projects/${res.body._id}`)
+ .put(`/api/projects/${res.body._id}`)
.set(headers)
.send(updatedDataPayload);
expect(res2.status).toBe(200);
@@ -96,15 +87,12 @@ describe('DELETE', () => {
};
// Submit a project
- const res = await request
- .post('/api/projects/')
- .set(headers)
- .send(submittedData);
+ const res = await request.post('/api/projects/').set(headers).send(submittedData);
expect(res.status).toBe(201);
// Delete project
const res2 = await request.patch(`/api/projects/${res.body._id}`).set(headers);
expect(res2.status).toBe(200);
done();
-});
+ });
});
diff --git a/client/src/api/ProjectApiService.js b/client/src/api/ProjectApiService.js
index b97e88cf2..b43b5cdbd 100644
--- a/client/src/api/ProjectApiService.js
+++ b/client/src/api/ProjectApiService.js
@@ -52,9 +52,9 @@ class ProjectApiService {
console.log('THIS BASEPROJECT URL', this.baseProjectUrl);
try {
- const proj = await fetch(this.baseProjectUrl, requestOptions);
- const projectDetails = await proj.json()
- return projectDetails._id
+ const proj = await fetch(this.baseProjectUrl, requestOptions);
+ const projectDetails = await proj.json();
+ return projectDetails._id;
} catch (error) {
console.error(`Add project error: `, error);
alert('Server not responding. Please try again.');
@@ -62,32 +62,18 @@ class ProjectApiService {
}
}
- async updateProject(projectId, fieldName, fieldValue) {
- let updateValue = fieldValue;
- // These field are arrays, but the form makes them comma separated strings,
- // so this adds it back to db as an arrray.
- if (
- fieldValue &&
- (fieldName === 'partners' || fieldName === 'recruitingCategories')
- ) {
- updateValue = fieldValue
- .split(',')
- .filter((x) => x !== '')
- .map((y) => y.trim());
- }
-
+ async updateProject(projectId, projectData) {
// Update database
const url = `${this.baseProjectUrl}${projectId}`;
const requestOptions = {
- method: 'PATCH',
+ method: 'PUT',
headers: this.headers,
- body: JSON.stringify({ [fieldName]: updateValue }),
+ body: JSON.stringify({ ...projectData }),
};
try {
const response = await fetch(url, requestOptions);
const resJson = await response.json();
-
return resJson;
} catch (error) {
console.log(`update project error: `, error);
diff --git a/client/src/components/manageProjects/editProject.js b/client/src/components/manageProjects/editProject.js
index 21d7f5798..a4af87481 100644
--- a/client/src/components/manageProjects/editProject.js
+++ b/client/src/components/manageProjects/editProject.js
@@ -1,11 +1,44 @@
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
-import EditableField from './editableField';
import EditMeetingTimes from './editMeetingTimes';
import CreateNewEvent from './createNewEvent';
import readableEvent from './utilities/readableEvent';
-import { ReactComponent as EditIcon } from "../../svg/Icon_Edit.svg";
-import '../../sass/ManageProjects.scss';
+import ProjectApiService from '../../api/ProjectApiService';
+
+import { ReactComponent as EditIcon } from '../../svg/Icon_Edit.svg';
+import { ReactComponent as PlusIcon } from '../../svg/PlusIcon.svg';
+
+import {
+ Typography,
+ Box,
+ Divider,
+ TextField,
+ InputLabel,
+ Button,
+ Grid,
+ Radio,
+ FormControl,
+ FormControlLabel,
+ RadioGroup,
+} from '@mui/material';
+
+import { styled } from '@mui/material/styles';
+
+const StyledButton = styled(Button)(({ theme }) => ({
+ width: '150px',
+}));
+
+const StyledFormControlLabel = styled(FormControlLabel)(({ theme }) => ({
+ width: 'max-content',
+ '& .MuiFormControlLabel-label': {
+ fontSize: '14px',
+ },
+}));
+
+const StyledRadio = styled(Radio)(({ theme }) => ({
+ padding: '0px 0px 0px 0px',
+ marginRight: '.5rem',
+}));
// Need to hold user state to check which type of user they are and conditionally render editing fields in this component
// for user level block access to all except for the ones checked
@@ -18,10 +51,28 @@ const EditProject = ({
deleteRecurringEvent,
updateRecurringEvent,
}) => {
- // Add commas to arrays for display
- const partnerDataFormatted = projectToEdit.partners.join(', ');
+ const [formData, setFormData] = useState({
+ name: projectToEdit.name,
+ description: projectToEdit.description,
+ location: projectToEdit.location,
+ // githubIdentifier: projectToEdit.name,
+ githubUrl: projectToEdit.githubUrl,
+ slackUrl: projectToEdit.slackUrl,
+ googleDriveUrl: projectToEdit.googleDriveUrl,
+ // hflaWebsiteUrl: projectToEdit.name,
+ });
+ const [locationType, setLocationType] = React.useState('remote');
+ // Set up to hold state for location type when added to add projects.
+ //********** */
+ const [selected, setSelected] = useState('');
+ const isButtonSelected = (value) => {
+ if (selected === value) {
+ return true;
+ }
+ };
+ //********** */
// eslint-disable-next-line no-unused-vars
- const recrutingDataFormatted = projectToEdit.recruitingCategories.join(', ');
+
const [rEvents, setREvents] = useState([]);
const [selectedEvent, setSelectedEvent] = useState();
const [isCreateNew, setIsCreateNew] = useState();
@@ -29,6 +80,63 @@ const EditProject = ({
// States for alerts
const [eventAlert, setEventAlert] = useState(null);
+ // Holds active state for close/save buttons
+ const [activeButton, setActiveButton] = React.useState('close');
+
+ // Form inputs.
+ const simpleInputs = [
+ {
+ label: 'Project Name',
+ name: 'name',
+ type: 'text',
+ value: projectToEdit.name,
+ },
+ {
+ label: 'Project Description',
+ name: 'description',
+ type: 'textarea',
+ value: projectToEdit.description,
+ },
+ {
+ label: 'Location',
+ name: 'location',
+ type: 'text',
+ value: projectToEdit.location,
+ },
+ // Leaving incase we want to add this back in for updating projects
+ // {
+ // label: 'GitHub Identifier',
+ // name: 'githubIdentifier',
+ // type: 'text',
+ // placeholder: 'Enter GitHub identifier',
+ // },
+ {
+ label: 'GitHub URL',
+ name: 'githubUrl',
+ type: 'text',
+ value: projectToEdit.githubUrl,
+ },
+ {
+ label: 'Slack Channel Link',
+ name: 'slackUrl',
+ type: 'text',
+ value: projectToEdit.slackUrl,
+ },
+ {
+ label: 'Google Drive URL',
+ name: 'googleDriveUrl',
+ type: 'text',
+ value: projectToEdit.googleDriveUrl,
+ },
+ // Leaving incase we want to add this back in for updating projects
+ // {
+ // label: 'HFLA Website URL',
+ // name: 'hflaWebsiteUrl',
+ // type: 'text',
+ // value: projectToEdit.hflaWebsiteUrl,
+ // },
+ ];
+
// Get project recurring events when component loads
useEffect(() => {
if (recurringEvents) {
@@ -42,8 +150,76 @@ const EditProject = ({
}
}, [projectToEdit, recurringEvents, setREvents]);
+ // only handles radio button change
+ const handleRadioChange = (event) => {
+ setLocationType(event.target.value);
+ };
+
+ // updates state of formData onChange of any form input
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+
+ setFormData((fData) => ({
+ ...fData,
+ [name]: value,
+ }));
+ };
+
+ // fires PUT request to update the project,
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ const projectApi = new ProjectApiService();
+ try {
+ await projectApi.updateProject(projectToEdit._id, formData);
+ } catch (errors) {
+ console.error(errors);
+ return;
+ }
+ setActiveButton('close');
+ };
+
+ // Basic validation : if all inputs have values, enable the submit button
+ useEffect(() => {
+ if (Object.values(formData).every((val) => val !== '')) {
+ setActiveButton('save');
+ } else {
+ setActiveButton('close');
+ }
+ }, [formData]);
+
+ // Displays the location radios if the input.type === 'location'. See below.
+ const locationRadios = (
+