From 6f1778c22bbc8cc630844bf48a2a6c63744d3e63 Mon Sep 17 00:00:00 2001 From: Phillip Sanchez Date: Thu, 17 Aug 2023 21:18:16 -0700 Subject: [PATCH 01/11] reusable form --- client/src/App.js | 3 +- client/src/components/ProjectForm.js | 103 ++-------------- .../components/manageProjects/addProject.js | 110 ++++++++++++++++++ 3 files changed, 121 insertions(+), 95 deletions(-) create mode 100644 client/src/components/manageProjects/addProject.js diff --git a/client/src/App.js b/client/src/App.js index 7a2d51b7f..d610b188b 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -21,6 +21,7 @@ import ProjectLeaderDashboard from './pages/ProjectLeaderDashboard'; import UserAdmin from './pages/UserAdmin'; import ProjectList from './pages/ProjectList'; import ManageProjects from './pages/ManageProjects'; +import addProject from './components/manageProjects/addProject'; import HealthCheck from './pages/HealthCheck'; import SecretPassword from './pages/SecretPassword'; import UserWelcome from './pages/UserWelcome'; @@ -49,7 +50,7 @@ const routes = [ { path: '/events', name: 'events', Component: Events }, { path: '/useradmin', name: 'useradmin', Component: UserAdmin }, { path: '/projects', name: 'projects', Component: ProjectList }, - { path: '/projects/create', name: 'projectform', Component: ProjectForm }, + { path: '/projects/create', name: 'projectform', Component: addProject}, { path: '/projects/:projectId', name: 'project', diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index e455fb57e..92dee6336 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -1,7 +1,6 @@ -import React, { useState, useEffect } from 'react'; +import React, { useEffect } from 'react'; import { Link, useHistory } from 'react-router-dom'; import { useForm } from 'react-hook-form'; -import ProjectApiService from '../api/ProjectApiService'; import { ReactComponent as PlusIcon } from '../svg/PlusIcon.svg'; import { Redirect } from 'react-router-dom' import { @@ -18,70 +17,7 @@ import { RadioGroup, } from '@mui/material'; import { styled } from '@mui/material/styles'; -import useAuth from "../hooks/useAuth" - -/** Project Form Component - * - * To be used for creating and updating a project - * */ - -const simpleInputs = [ - { - label: 'Project Name', - name: 'name', - type: 'text', - placeholder: 'Enter project name', - }, - { - label: 'Project Description', - name: 'description', - type: 'textarea', - placeholder: 'Enter project description', - }, - { - label: 'Location', - name: 'location', - type: 'text', - placeholder: 'Enter location for meeting', - value: /https:\/\/[\w-]*\.?zoom.us\/(j|my)\/[\d\w?=-]+/, - errorMessage: 'Please enter a valid Zoom URL', - addressValue: '', - addressError: 'Invalid address' - - }, - // 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', - placeholder: 'htttps://github.com/' - }, - { - label: 'Slack Channel Link', - name: 'slackUrl', - type: 'text', - placeholder: 'htttps://slack.com/', - }, - { - label: 'Google Drive URL', - name: 'googleDriveUrl', - type: 'text', - placeholder: 'htttps://drive.google.com/', - }, - // Leaving incase we want to add this back in for updating projects - // { - // label: 'HFLA Website URL', - // name: 'hflaWebsiteUrl', - // type: 'text', - // placeholder: 'htttps://hackforla.org/projects/', - // }, -]; +import useAuth from "../hooks/useAuth" /** STYLES * -most TextField and InputLabel styles are controlled by the theme @@ -109,12 +45,13 @@ const StyledRadio = styled(Radio)(({ theme }) => ({ * -renders a form for creating and updating a project */ -export default function ProjectForm() { +// Takes Array, submitForm, isEdit? +export default function ProjectForm({arr, submitForm, isEdit}) { //seperate state for the location radio buttons + const history = useHistory(); + const [locationType, setLocationType] = React.useState('remote'); const [activeButton, setActiveButton] = React.useState('close'); - const [newlyCreatedID, setNewlyCreatedID] = useState(null); - const history = useHistory(); const { auth } = useAuth(); const { register, handleSubmit, formState: { errors } } = useForm({ mode: 'all', @@ -128,33 +65,11 @@ export default function ProjectForm() { } }); - const routeToNewProjectPage = () => { - if(newlyCreatedID !== null) { - history.push(`/projects/${newlyCreatedID}`) - } - } - - useEffect(() => { - routeToNewProjectPage() - },[newlyCreatedID]) - - // only handles radio button change + // // only handles radio button change const handleRadioChange = (event) => { setLocationType(event.target.value); }; - const submitForm = async (data) => { - const projectApi = new ProjectApiService(); - try { - const id = await projectApi.create(data); - setNewlyCreatedID(id); - } catch (errors) { - console.error(errors); - return; - } - setActiveButton('close'); - }; - const locationRadios = ( @@ -197,7 +112,7 @@ export default function ProjectForm() { - Add New Project + {isEdit ? 'edit' : 'Add New Project'} @@ -206,7 +121,7 @@ export default function ProjectForm() {
{ submitForm(data) })}> - {simpleInputs.map((input) => ( + {arr.map((input) => ( diff --git a/client/src/components/manageProjects/addProject.js b/client/src/components/manageProjects/addProject.js new file mode 100644 index 000000000..7210192fc --- /dev/null +++ b/client/src/components/manageProjects/addProject.js @@ -0,0 +1,110 @@ +import React from 'react'; +import {useHistory } from 'react-router-dom'; + +import ProjectForm from '../ProjectForm'; +import ProjectApiService from '../../api/ProjectApiService'; + + +function addProject() { + // Array filled with default inputs. + // const [newlyCreatedID, setNewlyCreatedID] = useState(null); + + const simpleInputs = [ + { + label: 'Project Name', + name: 'name', + type: 'text', + placeholder: 'Enter project name', + }, + { + label: 'Project Description', + name: 'description', + type: 'textarea', + placeholder: 'Enter project description', + }, + { + label: 'Location', + name: 'location', + type: 'text', + placeholder: 'Enter location for meeting', + value: /https:\/\/[\w-]*\.?zoom.us\/(j|my)\/[\d\w?=-]+/, + errorMessage: 'Please enter a valid Zoom URL', + addressValue: '', + addressError: 'Invalid address' + + }, + // 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', + placeholder: 'htttps://github.com/' + }, + { + label: 'Slack Channel Link', + name: 'slackUrl', + type: 'text', + placeholder: 'htttps://slack.com/', + }, + { + label: 'Google Drive URL', + name: 'googleDriveUrl', + type: 'text', + placeholder: 'htttps://drive.google.com/', + }, + // Leaving incase we want to add this back in for updating projects + // { + // label: 'HFLA Website URL', + // name: 'hflaWebsiteUrl', + // type: 'text', + // placeholder: 'htttps://hackforla.org/projects/', + // }, + ]; + + + // Handles POST request found in api/ProjectApiService. + const submitForm = async (data) => { + const projectApi = new ProjectApiService(); + try { + const id = await projectApi.create(data); + // console.log(id) + // setNewlyCreatedID(id); + // history.push(`/projects/${id}`) + // projectView(id) + } catch (errors) { + console.error(errors); + return; + } + // setActiveButton('close'); + }; + + // const routeToNewProjectPage = () => { + // if(newlyCreatedID !== null) { + // history.push(`/projects/${newlyCreatedID}`) + // } + // } + + // useEffect(() => { + // if(newlyCreatedID !== null) { + // history.push(`/projects/${newlyCreatedID}`) + // } + // },[newlyCreatedID]) + + return ( +
+ +
+ ) +} + +export default addProject From 70711e43e3913dbb615d137d7611b16332de44f2 Mon Sep 17 00:00:00 2001 From: Phillip Sanchez Date: Tue, 22 Aug 2023 15:23:38 -0700 Subject: [PATCH 02/11] reusable form + additional changes. --- backend/routers/projects.router.js | 2 + backend/routers/projects.router.test.js | 2 +- client/src/api/ProjectApiService.js | 20 +- client/src/components/ProjectForm.js | 214 +++++++++-- .../components/manageProjects/addProject.js | 157 +++----- .../components/manageProjects/editProject.js | 349 ++++++++---------- client/src/sass/ManageProjects.scss | 1 - 7 files changed, 397 insertions(+), 348 deletions(-) diff --git a/backend/routers/projects.router.js b/backend/routers/projects.router.js index 8991000cb..f0762b834 100644 --- a/backend/routers/projects.router.js +++ b/backend/routers/projects.router.js @@ -10,6 +10,8 @@ router.post('/', ProjectController.create); router.get('/:ProjectId', ProjectController.project_by_id); +router.put('/:ProjectId', ProjectController.update); + router.patch('/:ProjectId', ProjectController.update); diff --git a/backend/routers/projects.router.test.js b/backend/routers/projects.router.test.js index 5233247b9..b4abbc6ee 100644 --- a/backend/routers/projects.router.test.js +++ b/backend/routers/projects.router.test.js @@ -73,7 +73,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); diff --git a/client/src/api/ProjectApiService.js b/client/src/api/ProjectApiService.js index 12f4e0763..949bd5ee0 100644 --- a/client/src/api/ProjectApiService.js +++ b/client/src/api/ProjectApiService.js @@ -22,6 +22,7 @@ class ProjectApiService { } } + // Handles the POST request and returns the projects ID. async create(projectData) { const { name, @@ -58,26 +59,13 @@ 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 { diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index 92dee6336..9789936fe 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -1,8 +1,11 @@ -import React, { useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import { Link, useHistory } from 'react-router-dom'; import { useForm } from 'react-hook-form'; +import ProjectApiService from '../api/ProjectApiService'; + +import { ReactComponent as EditIcon } from '../svg/Icon_Edit.svg'; import { ReactComponent as PlusIcon } from '../svg/PlusIcon.svg'; -import { Redirect } from 'react-router-dom' +import { Redirect } from 'react-router-dom'; import { Typography, Box, @@ -17,7 +20,7 @@ import { RadioGroup, } from '@mui/material'; import { styled } from '@mui/material/styles'; -import useAuth from "../hooks/useAuth" +import useAuth from '../hooks/useAuth'; /** STYLES * -most TextField and InputLabel styles are controlled by the theme @@ -45,15 +48,33 @@ const StyledRadio = styled(Radio)(({ theme }) => ({ * -renders a form for creating and updating a project */ -// Takes Array, submitForm, isEdit? -export default function ProjectForm({arr, submitForm, isEdit}) { - //seperate state for the location radio buttons +/** + * Takes Array, formData, projectToEdit, handleChage, isEdit + * submitForm, handleChange, and isEdit are for the edit forms. + * - formData - passes the current project information to the form. + * - projectToEdit - used to grab the of the project we are editing. + * - handleChange - changes the input values to whatever the user changes it to. + * - Where its creating a new project or editing one - True or False. + * */ +export default function ProjectForm({ + arr, + formData, + projectToEdit, + handleChange, + isEdit, +}) { const history = useHistory(); - const [locationType, setLocationType] = React.useState('remote'); - const [activeButton, setActiveButton] = React.useState('close'); + // ----------------- States ----------------- + const [locationType, setLocationType] = useState('remote'); + // State to track the toggling from Project view to Edit Project View via edit icon. + const [editMode, setEditMode] = useState(true); const { auth } = useAuth(); - const { register, handleSubmit, formState: { errors } } = useForm({ + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ mode: 'all', defaultValues: { name: '', @@ -61,15 +82,84 @@ export default function ProjectForm({arr, submitForm, isEdit}) { location: '', githubUrl: '', slackUrl: '', - googleDriveUrl: '' - } + googleDriveUrl: '', + }, }); - // // only handles radio button change + // ----------------- Submit requests ----------------- + + // Handles POST request found in api/ProjectApiService. + const submitNewProject = async (data) => { + const projectApi = new ProjectApiService(); + try { + const id = await projectApi.create(data); + history.push(`/projects/${id}`); + } catch (errors) { + console.error(errors); + return; + } + }; + + // Fires PUT request to update the project, + const submitEditProject = async (data) => { + const projectApi = new ProjectApiService(); + try { + await projectApi.updateProject(projectToEdit._id, data); + } catch (errors) { + console.error(errors); + return; + } + setEditMode(true); + }; + + // ----------------- Handles and Toggles ----------------- + + // Handles the location radio button change. const handleRadioChange = (event) => { setLocationType(event.target.value); }; + // Toggles the project view to edit mode change. + const handleEditMode = (event) => { + setEditMode(!editMode); + }; + // ----------------- Icons ----------------- + + // Holds the Add New Project Icon and styling. + const addIcon = () => { + return ( + + + + Add New Project + + + ); + }; + // Holds the Edit New Project Icon and styling. + const editIcon = () => { + return ( + + + + ); + }; + + // ----------------- Location radio ----------------- + + // Holdes the location radios styling. const locationRadios = ( @@ -85,18 +175,22 @@ export default function ProjectForm({arr, submitForm, isEdit}) { value="remote" control={} label="Remote" + disabled={isEdit ? editMode : false} /> } label="In-Person" + disabled={isEdit ? editMode : false} /> ); + // ----------------- Textfields ----------------- + return auth && auth.user ? ( @@ -109,18 +203,16 @@ export default function ProjectForm({arr, submitForm, isEdit}) { Project Information - - - - {isEdit ? 'edit' : 'Add New Project'} - - + {isEdit ? editIcon() : addIcon()} - { - submitForm(data) - })}> + { + isEdit ? submitEditProject(data) : submitNewProject(data); + })} + > {arr.map((input) => ( @@ -133,19 +225,63 @@ export default function ProjectForm({arr, submitForm, isEdit}) { {input.name === 'location' && locationRadios} -
- +
+ {/* Sets text field and data (if needed) based on the whether it is as add or edit form page. */} + {isEdit ? ( + /** + * Edit textfield. + * Includes + * - handleChange - to update the input fields based on users input. + * - value - formData that is passed from the DB to fill the input fields. + * */ + + ) : ( + // Add new project textfield. + + )}
))}
@@ -157,7 +293,9 @@ export default function ProjectForm({arr, submitForm, isEdit}) { Save @@ -166,8 +304,8 @@ export default function ProjectForm({arr, submitForm, isEdit}) { Close @@ -177,5 +315,5 @@ export default function ProjectForm({arr, submitForm, isEdit}) { ) : ( - ) + ); } diff --git a/client/src/components/manageProjects/addProject.js b/client/src/components/manageProjects/addProject.js index 7210192fc..d7209dfe0 100644 --- a/client/src/components/manageProjects/addProject.js +++ b/client/src/components/manageProjects/addProject.js @@ -1,110 +1,75 @@ import React from 'react'; -import {useHistory } from 'react-router-dom'; - import ProjectForm from '../ProjectForm'; -import ProjectApiService from '../../api/ProjectApiService'; - function addProject() { - // Array filled with default inputs. - // const [newlyCreatedID, setNewlyCreatedID] = useState(null); - - const simpleInputs = [ - { - label: 'Project Name', - name: 'name', - type: 'text', - placeholder: 'Enter project name', - }, - { - label: 'Project Description', - name: 'description', - type: 'textarea', - placeholder: 'Enter project description', - }, - { - label: 'Location', - name: 'location', - type: 'text', - placeholder: 'Enter location for meeting', - value: /https:\/\/[\w-]*\.?zoom.us\/(j|my)\/[\d\w?=-]+/, - errorMessage: 'Please enter a valid Zoom URL', - addressValue: '', - addressError: 'Invalid address' - - }, - // 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', - placeholder: 'htttps://github.com/' - }, - { - label: 'Slack Channel Link', - name: 'slackUrl', - type: 'text', - placeholder: 'htttps://slack.com/', - }, - { - label: 'Google Drive URL', - name: 'googleDriveUrl', - type: 'text', - placeholder: 'htttps://drive.google.com/', - }, - // Leaving incase we want to add this back in for updating projects - // { - // label: 'HFLA Website URL', - // name: 'hflaWebsiteUrl', - // type: 'text', - // placeholder: 'htttps://hackforla.org/projects/', - // }, - ]; - - - // Handles POST request found in api/ProjectApiService. - const submitForm = async (data) => { - const projectApi = new ProjectApiService(); - try { - const id = await projectApi.create(data); - // console.log(id) - // setNewlyCreatedID(id); - // history.push(`/projects/${id}`) - // projectView(id) - } catch (errors) { - console.error(errors); - return; - } - // setActiveButton('close'); - }; - - // const routeToNewProjectPage = () => { - // if(newlyCreatedID !== null) { - // history.push(`/projects/${newlyCreatedID}`) - // } - // } - - // useEffect(() => { - // if(newlyCreatedID !== null) { - // history.push(`/projects/${newlyCreatedID}`) - // } - // },[newlyCreatedID]) + // Array filled with default inputs. + const simpleInputs = [ + { + label: 'Project Name', + name: 'name', + type: 'text', + placeholder: 'Enter project name', + }, + { + label: 'Project Description', + name: 'description', + type: 'textarea', + placeholder: 'Enter project description', + }, + { + label: 'Location', + name: 'location', + type: 'text', + placeholder: 'Enter location for meeting', + value: /https:\/\/[\w-]*\.?zoom.us\/(j|my)\/[\d\w?=-]+/, + errorMessage: 'Please enter a valid Zoom URL', + addressValue: '', + addressError: 'Invalid address', + }, + // 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', + placeholder: 'htttps://github.com/', + }, + { + label: 'Slack Channel Link', + name: 'slackUrl', + type: 'text', + placeholder: 'htttps://slack.com/', + }, + { + label: 'Google Drive URL', + name: 'googleDriveUrl', + type: 'text', + placeholder: 'htttps://drive.google.com/', + }, + // Leaving incase we want to add this back in for updating projects + // { + // label: 'HFLA Website URL', + // name: 'hflaWebsiteUrl', + // type: 'text', + // placeholder: 'htttps://hackforla.org/projects/', + // }, + ]; return (
- ) + ); } -export default addProject +export default addProject; diff --git a/client/src/components/manageProjects/editProject.js b/client/src/components/manageProjects/editProject.js index cd8197f89..da117e637 100644 --- a/client/src/components/manageProjects/editProject.js +++ b/client/src/components/manageProjects/editProject.js @@ -1,64 +1,122 @@ 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 ProjectForm from '../ProjectForm'; + +import { ReactComponent as EditIcon } from '../../svg/Icon_Edit.svg'; +import { ReactComponent as PlusIcon } from '../../svg/PlusIcon.svg'; + +import { Typography, Box, Divider } from '@mui/material'; // 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 const EditProject = ({ projectToEdit, - userAccessLevel, - updateProject, recurringEvents, createNewRecurringEvent, deleteRecurringEvent, updateRecurringEvent, - regularEvents, - updateRegularEvent }) => { - // 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, + }); + // eslint-disable-next-line no-unused-vars - const recrutingDataFormatted = projectToEdit.recruitingCategories.join(', '); - const [recurringEventsState, setRecurringEventsState] = useState([]); - const [regularEventsState, setRegularEventsState] = useState([]); + + const [rEvents, setREvents] = useState([]); const [selectedEvent, setSelectedEvent] = useState(); const [isCreateNew, setIsCreateNew] = useState(); // States for alerts const [eventAlert, setEventAlert] = useState(null); - // Get project recurring events when component loads - useEffect(() => { - if (regularEvents) { - setRegularEventsState( - regularEvents - // eslint-disable-next-line no-underscore-dangle - .filter((e) => e?.project?._id === projectToEdit._id) - .map((item) => ({...item, ...readableEvent(item), raw: item})) - .reverse() // sorts most recent events first - ); - } - }, [projectToEdit, regularEvents, setRegularEventsState]); + // 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) { - setRecurringEventsState( + setREvents( recurringEvents // eslint-disable-next-line no-underscore-dangle .filter((e) => e?.project?._id === projectToEdit._id) - .map((item) => ({...item, ...readableEvent(item)})) + .map((item) => readableEvent(item)) .sort((a, b) => a.dayOfTheWeekNumber - b.dayOfTheWeekNumber) - ); - } - }, [projectToEdit, recurringEvents, setRecurringEventsState]); + ); + } + }, [projectToEdit, recurringEvents, setREvents]); + + // Updates state of formData onChange of any form input + const handleChange = (e) => { + const { name, value } = e.target; + + setFormData((fData) => ({ + ...fData, + [name]: value, + })); + }; return ( -
+
- - All Projects - -
- *The data here is only test data and is not accurate* -
-
{`Project: ${projectToEdit.name}`}
- - - - - - - - {/* */} - - {/* */} - {/* */} - - {/* */} -
-

Recurring Events

-

{eventAlert}

-
    - {recurringEventsState.map((event) => ( - // eslint-disable-next-line no-underscore-dangle -
  • - -
  • - ))} -
-
-
- -
- -
-

Manually Edit Events Checkin

-

{eventAlert}

-
    - {regularEventsState.map((event, index) => ( - - // eslint-disable-next-line no-underscore-dangle - - ))} -
-
-
+ + + Recurring Events + + + setIsCreateNew(true)} + > + + + Add New Event + + + + + +
+

{eventAlert}

+
    + {rEvents.map((event) => ( + // eslint-disable-next-line no-underscore-dangle +
  • + +
  • + ))} +
+
+
+
+ + + ); }; -function RegularEvent({event, updateRegularEvent}) { - return ( -
  • - -
  • - ) -} - export default EditProject; diff --git a/client/src/sass/ManageProjects.scss b/client/src/sass/ManageProjects.scss index 67292c383..46899a9dc 100644 --- a/client/src/sass/ManageProjects.scss +++ b/client/src/sass/ManageProjects.scss @@ -139,7 +139,6 @@ div.editable-field { ul { padding-top: 4px; - border-top: 2px solid #32373b; } li { From 9875937dbe200bca6fd36625548ab47d0984c518 Mon Sep 17 00:00:00 2001 From: Trillium Smith Date: Thu, 24 Aug 2023 16:34:01 -0700 Subject: [PATCH 03/11] feat: Add press edit agian to revert data --- client/src/components/ProjectForm.js | 4 ++++ client/src/components/manageProjects/editProject.js | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index 9789936fe..3b7e0f85c 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -62,6 +62,8 @@ export default function ProjectForm({ projectToEdit, handleChange, isEdit, + revertToOriginal, + setOriginalProjectData, }) { const history = useHistory(); @@ -109,6 +111,7 @@ export default function ProjectForm({ console.error(errors); return; } + setOriginalProjectData(data); setEditMode(true); }; @@ -121,6 +124,7 @@ export default function ProjectForm({ // Toggles the project view to edit mode change. const handleEditMode = (event) => { setEditMode(!editMode); + revertToOriginal(); }; // ----------------- Icons ----------------- diff --git a/client/src/components/manageProjects/editProject.js b/client/src/components/manageProjects/editProject.js index da117e637..70459774c 100644 --- a/client/src/components/manageProjects/editProject.js +++ b/client/src/components/manageProjects/editProject.js @@ -18,7 +18,7 @@ const EditProject = ({ deleteRecurringEvent, updateRecurringEvent, }) => { - const [formData, setFormData] = useState({ + const [originalProjectData, setOriginalProjectData] = useState({ name: projectToEdit.name, description: projectToEdit.description, location: projectToEdit.location, @@ -29,6 +29,10 @@ const EditProject = ({ // hflaWebsiteUrl: projectToEdit.name, }); + const [formData, setFormData] = useState({ + ...originalProjectData + }); + // eslint-disable-next-line no-unused-vars const [rEvents, setREvents] = useState([]); @@ -115,6 +119,10 @@ const EditProject = ({ })); }; + const revertToOriginal = () => { + setFormData(originalProjectData); + } + return (
    @@ -143,6 +151,8 @@ const EditProject = ({ projectToEdit={projectToEdit} handleChange={handleChange} isEdit={true} + revertToOriginal={revertToOriginal} + setOriginalProjectData={setOriginalProjectData} /> Date: Thu, 24 Aug 2023 17:31:20 -0700 Subject: [PATCH 04/11] feat: Restore Manually Edit Events Checkin --- .../components/manageProjects/editProject.js | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/client/src/components/manageProjects/editProject.js b/client/src/components/manageProjects/editProject.js index 70459774c..03e1e187c 100644 --- a/client/src/components/manageProjects/editProject.js +++ b/client/src/components/manageProjects/editProject.js @@ -17,6 +17,8 @@ const EditProject = ({ createNewRecurringEvent, deleteRecurringEvent, updateRecurringEvent, + regularEvents, + updateRegularEvent, }) => { const [originalProjectData, setOriginalProjectData] = useState({ name: projectToEdit.name, @@ -36,12 +38,26 @@ const EditProject = ({ // eslint-disable-next-line no-unused-vars const [rEvents, setREvents] = useState([]); + const [regularEventsState, setRegularEventsState] = useState([]); const [selectedEvent, setSelectedEvent] = useState(); const [isCreateNew, setIsCreateNew] = useState(); // States for alerts const [eventAlert, setEventAlert] = useState(null); + // test + useEffect(() => { + if (regularEvents) { + setRegularEventsState( + regularEvents + // eslint-disable-next-line no-underscore-dangle + .filter((e) => e?.project?._id === projectToEdit._id) + .map((item) => ({...item, ...readableEvent(item), raw: item})) + .reverse() // sorts most recent events first + ); + } + }, [projectToEdit, regularEvents, setRegularEventsState]); + // Form inputs. const simpleInputs = [ { @@ -208,12 +224,56 @@ const EditProject = ({ ))}
    -
    + {/*
    */}
    - + + + + + + Manually Edit Events Checkin + + + + + +
    +

    {eventAlert}

    +
      + {regularEventsState.map((event, index) => ( + + // eslint-dis able-next-line no-underscore-dangle + + ))} +
    +
    +
    + +
    ); }; +function RegularEvent({event, updateRegularEvent}) { + return ( +
  • + +
  • + ) +} + export default EditProject; From 529e5840ed7518f66ce3845186ffd961dd4915cb Mon Sep 17 00:00:00 2001 From: Phillip Sanchez Date: Thu, 24 Aug 2023 20:23:31 -0700 Subject: [PATCH 05/11] adjust editMode and styling on form --- client/src/components/ProjectForm.js | 46 +++++++++++++++++++++------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index 9789936fe..c4d5066b9 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -68,7 +68,15 @@ export default function ProjectForm({ // ----------------- States ----------------- const [locationType, setLocationType] = useState('remote'); // State to track the toggling from Project view to Edit Project View via edit icon. - const [editMode, setEditMode] = useState(true); + const [editMode, setEditMode] = useState(false); + + /** + * + * STATE + */ + const initialState = [...arr] + + const [arrState, setArrState] = useState(initialState) const { auth } = useAuth(); const { register, @@ -118,11 +126,23 @@ export default function ProjectForm({ const handleRadioChange = (event) => { setLocationType(event.target.value); }; + + /** + * + * RESET + */ + // Toggles the project view to edit mode change. const handleEditMode = (event) => { setEditMode(!editMode); + resetState() + }; + const resetState = () => { + // arr = [initialState] + } + // ----------------- Icons ----------------- // Holds the Add New Project Icon and styling. @@ -147,12 +167,16 @@ export default function ProjectForm({ const editIcon = () => { return ( + + {editMode ? 'Cancel' : 'Edit Project'} + ); }; @@ -175,14 +199,14 @@ export default function ProjectForm({ value="remote" control={} label="Remote" - disabled={isEdit ? editMode : false} + disabled={isEdit && !editMode} /> } label="In-Person" - disabled={isEdit ? editMode : false} + disabled={isEdit && !editMode} />
    @@ -197,10 +221,10 @@ export default function ProjectForm({ Project Management - + - Project Information + {editMode ? 'Editing Project' : 'Project Information'} {isEdit ? editIcon() : addIcon()} @@ -256,7 +280,7 @@ export default function ProjectForm({ helperText={`${errors[input.name]?.message || ' '}`} onChange={handleChange} value={formData[input.name]} - disabled={editMode} + disabled={!editMode} /> ) : ( // Add new project textfield. @@ -293,7 +317,7 @@ export default function ProjectForm({ @@ -316,4 +340,4 @@ export default function ProjectForm({ ) : ( ); -} +} \ No newline at end of file From 3c1b78c9c69f948f0669c29668b653abeb1c2ea1 Mon Sep 17 00:00:00 2001 From: Phillip Sanchez Date: Thu, 24 Aug 2023 21:37:29 -0700 Subject: [PATCH 06/11] update styling + add trilliums pr --- client/src/components/ProjectForm.js | 47 ++++++++-------------------- client/src/svg/Icon_Edit.svg | 2 +- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index c36988a8a..b8ec96622 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -71,14 +71,6 @@ export default function ProjectForm({ const [locationType, setLocationType] = useState('remote'); // State to track the toggling from Project view to Edit Project View via edit icon. const [editMode, setEditMode] = useState(false); - - /** - * - * STATE - */ - const initialState = [...arr] - - const [arrState, setArrState] = useState(initialState) const { auth } = useAuth(); const { register, @@ -129,27 +121,12 @@ export default function ProjectForm({ const handleRadioChange = (event) => { setLocationType(event.target.value); }; - - /** - * - * RESET - */ - // Toggles the project view to edit mode change. const handleEditMode = (event) => { setEditMode(!editMode); -<<<<<<< HEAD - resetState() - -======= revertToOriginal(); ->>>>>>> a705d73234655bc5030a643d2507b1f1376df0a4 }; - const resetState = () => { - // arr = [initialState] - } - // ----------------- Icons ----------------- // Holds the Add New Project Icon and styling. @@ -174,15 +151,17 @@ export default function ProjectForm({ const editIcon = () => { return ( - + - {editMode ? 'Cancel' : 'Edit Project'} + {editMode ? 'Cancel' : 'Edit Mode'} ); @@ -206,14 +185,14 @@ export default function ProjectForm({ value="remote" control={} label="Remote" - disabled={isEdit && !editMode} + disabled={!editMode} /> } label="In-Person" - disabled={isEdit && !editMode} + disabled={!editMode} /> @@ -228,7 +207,7 @@ export default function ProjectForm({ Project Management - + {editMode ? 'Editing Project' : 'Project Information'} @@ -324,9 +303,9 @@ export default function ProjectForm({ Save diff --git a/client/src/svg/Icon_Edit.svg b/client/src/svg/Icon_Edit.svg index f2eb7335c..6a6271821 100644 --- a/client/src/svg/Icon_Edit.svg +++ b/client/src/svg/Icon_Edit.svg @@ -1,3 +1,3 @@ - + From 46f4d47c09f469eda0c5e2825d14a51282a18743 Mon Sep 17 00:00:00 2001 From: Phillip Sanchez Date: Thu, 24 Aug 2023 21:39:59 -0700 Subject: [PATCH 07/11] remove comment --- client/src/components/ProjectForm.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index b8ec96622..92e7ee7e7 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -199,8 +199,6 @@ export default function ProjectForm({
    ); - // ----------------- Textfields ----------------- - return auth && auth.user ? ( From 6571d0547f305313bb381227b21250ea5e942497 Mon Sep 17 00:00:00 2001 From: Phillip Sanchez Date: Fri, 25 Aug 2023 08:55:25 -0700 Subject: [PATCH 08/11] save button bug fix --- client/src/components/ProjectForm.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index 92e7ee7e7..66ce8a751 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -185,14 +185,14 @@ export default function ProjectForm({ value="remote" control={} label="Remote" - disabled={!editMode} + disabled={isEdit ? !editMode : false} /> } label="In-Person" - disabled={!editMode} + disabled={isEdit ? !editMode : false} /> @@ -303,7 +303,7 @@ export default function ProjectForm({ form="project-form" variant={editMode ? "contained" : "secondary"} cursor="pointer" - disabled={!editMode} + disabled={isEdit ? !editMode : false} > Save From e80ca8e9363bec49364fab9dd1613c75f742509f Mon Sep 17 00:00:00 2001 From: Phillip Sanchez Date: Fri, 25 Aug 2023 13:16:17 -0700 Subject: [PATCH 09/11] set react hook form state, reset method, and styling --- client/src/components/ProjectForm.js | 98 +++++++++++-------- .../components/manageProjects/editProject.js | 27 +---- 2 files changed, 60 insertions(+), 65 deletions(-) diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index 66ce8a751..770ae24fd 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { Link, useHistory } from 'react-router-dom'; import { useForm } from 'react-hook-form'; import ProjectApiService from '../api/ProjectApiService'; @@ -46,24 +46,25 @@ const StyledRadio = styled(Radio)(({ theme }) => ({ /**Project Form Component * -renders a form for creating and updating a project - */ + +/** + /** * Takes Array, formData, projectToEdit, handleChage, isEdit * submitForm, handleChange, and isEdit are for the edit forms. + * - arr - simpleInputs arr from the edit page that holds the input's properties. * - formData - passes the current project information to the form. * - projectToEdit - used to grab the of the project we are editing. - * - handleChange - changes the input values to whatever the user changes it to. - * - Where its creating a new project or editing one - True or False. + * - isEdit - Whether its creating a new project or editing one - True or False. + * - setFormData - allows us to updated the form data. * */ export default function ProjectForm({ arr, formData, projectToEdit, - handleChange, isEdit, - revertToOriginal, - setOriginalProjectData, + setFormData }) { const history = useHistory(); @@ -72,19 +73,27 @@ export default function ProjectForm({ // State to track the toggling from Project view to Edit Project View via edit icon. const [editMode, setEditMode] = useState(false); const { auth } = useAuth(); + + /** + * React Hook Forms + * - register + * - handleSubmit + * - formState + * - reset + * - defaultValues - holds edit project data + * + */ + const { register, handleSubmit, + reset, formState: { errors }, } = useForm({ mode: 'all', + // Holds the current project data in state. defaultValues: { - name: '', - description: '', - location: '', - githubUrl: '', - slackUrl: '', - googleDriveUrl: '', + ...formData, }, }); @@ -111,8 +120,9 @@ export default function ProjectForm({ console.error(errors); return; } - setOriginalProjectData(data); - setEditMode(true); + // setOriginalProjectData(data); + setFormData(data); + setEditMode(false); }; // ----------------- Handles and Toggles ----------------- @@ -121,10 +131,14 @@ export default function ProjectForm({ const handleRadioChange = (event) => { setLocationType(event.target.value); }; + // Toggles the project view to edit mode change. const handleEditMode = (event) => { setEditMode(!editMode); - revertToOriginal(); + // React hook form method to reset data back to original values. Triggered when Edit Mode is cancelled. + reset({ + ...formData, + }); }; // ----------------- Icons ----------------- @@ -262,8 +276,6 @@ export default function ProjectForm({ })} placeholder={input.placeholder} helperText={`${errors[input.name]?.message || ' '}`} - onChange={handleChange} - value={formData[input.name]} disabled={!editMode} /> ) : ( @@ -293,33 +305,33 @@ export default function ProjectForm({ ))} + + + + + Save + + + + + Close + + + + - - - - - Save - - - - - Close - - - - ) : ( diff --git a/client/src/components/manageProjects/editProject.js b/client/src/components/manageProjects/editProject.js index 03e1e187c..8a012c13f 100644 --- a/client/src/components/manageProjects/editProject.js +++ b/client/src/components/manageProjects/editProject.js @@ -20,7 +20,7 @@ const EditProject = ({ regularEvents, updateRegularEvent, }) => { - const [originalProjectData, setOriginalProjectData] = useState({ + const [formData, setFormData] = useState({ name: projectToEdit.name, description: projectToEdit.description, location: projectToEdit.location, @@ -31,10 +31,6 @@ const EditProject = ({ // hflaWebsiteUrl: projectToEdit.name, }); - const [formData, setFormData] = useState({ - ...originalProjectData - }); - // eslint-disable-next-line no-unused-vars const [rEvents, setREvents] = useState([]); @@ -77,6 +73,9 @@ const EditProject = ({ name: 'location', type: 'text', value: projectToEdit.location, + errorMessage: 'Please enter a valid Zoom URL', + addressValue: '', + addressError: 'Invalid address', }, // Leaving incase we want to add this back in for updating projects // { @@ -125,20 +124,6 @@ const EditProject = ({ } }, [projectToEdit, recurringEvents, setREvents]); - // Updates state of formData onChange of any form input - const handleChange = (e) => { - const { name, value } = e.target; - - setFormData((fData) => ({ - ...fData, - [name]: value, - })); - }; - - const revertToOriginal = () => { - setFormData(originalProjectData); - } - return (
    @@ -165,10 +150,8 @@ const EditProject = ({ arr={simpleInputs} formData={formData} projectToEdit={projectToEdit} - handleChange={handleChange} isEdit={true} - revertToOriginal={revertToOriginal} - setOriginalProjectData={setOriginalProjectData} + setFormData={setFormData} /> Date: Fri, 25 Aug 2023 14:03:24 -0700 Subject: [PATCH 10/11] fix validation + remove unused --- client/src/components/ProjectForm.js | 2 +- client/src/components/manageProjects/editProject.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index 770ae24fd..3d90e2c16 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback } from 'react'; +import React, { useState } from 'react'; import { Link, useHistory } from 'react-router-dom'; import { useForm } from 'react-hook-form'; import ProjectApiService from '../api/ProjectApiService'; diff --git a/client/src/components/manageProjects/editProject.js b/client/src/components/manageProjects/editProject.js index 8a012c13f..fd53d7361 100644 --- a/client/src/components/manageProjects/editProject.js +++ b/client/src/components/manageProjects/editProject.js @@ -72,7 +72,7 @@ const EditProject = ({ label: 'Location', name: 'location', type: 'text', - value: projectToEdit.location, + value: /https:\/\/[\w-]*\.?zoom.us\/(j|my)\/[\d\w?=-]+/, errorMessage: 'Please enter a valid Zoom URL', addressValue: '', addressError: 'Invalid address', From ab51fa3728cd3710bed5443366b42aac168938a2 Mon Sep 17 00:00:00 2001 From: Trillium S Date: Fri, 25 Aug 2023 18:40:23 -0700 Subject: [PATCH 11/11] fix: Restore button styling with awkward ternary --- client/src/components/ProjectForm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index 3d90e2c16..dc0c5491f 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -311,7 +311,7 @@ export default function ProjectForm({ @@ -336,4 +336,4 @@ export default function ProjectForm({ ) : ( ); -} \ No newline at end of file +}