diff --git a/meshapp/src/pages/Profiles/Page.tsx b/meshapp/src/pages/Profiles/Page.tsx
index 18cc50f2..096f491f 100644
--- a/meshapp/src/pages/Profiles/Page.tsx
+++ b/meshapp/src/pages/Profiles/Page.tsx
@@ -294,6 +294,68 @@ const ProfileEducation = (props: { education: Education }) => {
`${inputName} cannot have whitespace at beginning or end.`;
const charLimit = (inputName: string) => (val: string) =>
val.length < 100 || `${inputName} cannot be longer than 100 characters.`;
+
+ //state for education array
+ //for now id will just be index
+ const [educationData, setEducationData] = useState(
+ props.education.map((currentEd, index) => {
+ return {
+ accordionId: index,
+ comboOneVal: currentEd.degree,
+ comboTwoVal: currentEd.school,
+ descText: currentEd.description,
+ };
+ })
+ );
+
+ //Edit and Delete education accordion handlers,
+ // takes in id number and returns a function that edits/deletes an education accordion with that id
+
+ //The accordions already handle editing in terms of local changes without saving,
+ //so this edit handler is only for saving on the backend
+
+ const editEducationHandler = (accordionId: number) => {
+ return () => {
+ //Insert API actions here
+ };
+ };
+
+ //This delete handler should handle deletion on on the backend and locally
+ const deleteEducationHandler = (accordionId: number) => {
+ return () => {
+ //Insert API actions here
+
+ //local deletion
+ setEducationData((prevEduData) =>
+ prevEduData.filter((edu) => edu.accordionId !== accordionId)
+ );
+ };
+ };
+
+ //handler for adding new accordion
+ //should handle adding on both backend and locally
+
+ const AddEducationHandler = (
+ degree: string,
+ school: string,
+ desc: string
+ ) => {
+ //insert API actions here
+
+ //local addition
+ //ideally we should get getting a new ID from the backend for this education to insert
+ //for now we'll just use current array length
+
+ setEducationData((prevEduData) => [
+ ...prevEduData,
+ {
+ accordionId: educationData.length,
+ comboOneVal: degree,
+ comboTwoVal: school,
+ descText: desc,
+ },
+ ]);
+ };
return (
@@ -307,13 +369,10 @@ const ProfileEducation = (props: { education: Education }) => {
Education
{
- return {
- comboOneVal: currentEd.degree,
- comboTwoVal: currentEd.school,
- descText: currentEd.description,
- };
- })}
+ groupAccordState={educationData}
+ setGroupAccordState={setEducationData}
+ editAccordHandler={editEducationHandler}
+ deleteAccordHandler={deleteEducationHandler}
comboOneValPlaceholder="Level of Education"
comboTwoValPlaceholder="School"
comboOneValOptions={[
@@ -332,6 +391,7 @@ const ProfileEducation = (props: { education: Education }) => {
whiteSpace("Description"),
charLimit("Description"),
]}
+ addAccordHandler={AddEducationHandler}
/>
diff --git a/meshapp/src/pages/Profiles/ProfileAccordion.tsx b/meshapp/src/pages/Profiles/ProfileAccordion.tsx
index 13cadbb2..bbe45e50 100644
--- a/meshapp/src/pages/Profiles/ProfileAccordion.tsx
+++ b/meshapp/src/pages/Profiles/ProfileAccordion.tsx
@@ -9,10 +9,19 @@ import {
groupAccordionState,
setGroupAccordionState,
} from "./ProfileGroupAccordion";
-import { Box, Grid } from "@mui/material";
+import {
+ Box,
+ Container,
+ Grid,
+ Modal,
+ Stack,
+ Button,
+ Typography,
+} from "@mui/material";
+
import EditIcon from "@mui/icons-material/Edit";
import SaveIcon from "@mui/icons-material/Save";
-
+import { Delete } from "@mui/icons-material";
/**
* A React Component that returns an accordion with two comboboxes and a description textfield.
* Provides editing capabilities for these inputs.
@@ -20,11 +29,11 @@ import SaveIcon from "@mui/icons-material/Save";
* Used in Profile Group Accordion (src/profile/ProfileGroupAccordion.tsx)
*
* @param props - Properties of the component
+ * @param {string} props.accordionId - number representing ID of this accordion
* @param {string} props.comboOneVal - value for the first combobox within the accordion, passed down from group state array data
* @param {string} props.comboTwoVal - value for the second combobox within the accordion, passed down from group state array data
* @param {string} props.descPlaceholder - placeholder for description textfield
* @param {string} props.descText - value for description textfield, passed down from group state array data
- * @param {number} props.accordionIndex - index of this accordion within the group state array
* @param {string} props.comboOneValPlaceholder - placeholder for comboOneVal combobox
* @param {string} props.comboTwoValPlaceholder - placeholder for comboTwoVal combobox
* @param {Array} props.comboOneValOptions - list of options to be provided to comboOneVal combobox
@@ -32,16 +41,21 @@ import SaveIcon from "@mui/icons-material/Save";
* @param {Array} props.comboOneValErrValidations - an array of functions to evaluate the first combo box value for errors (takes in the string value as a parameter, returns True if there was no error or the error message if there is)
* @param {Array} props.comboTwoValErrValidations - an array of functions to evaluate the second combobox value for errors (takes in the string value as a parameter, returns True if there was no error or the error message if there is)
* @param {Array} props.descErrValidations - an array of functions to evaluate the description text value for errors (takes in the string value as a parameter, returns True if there was no error or the error message if there is)
- * @param {groupState} props.groupState - the group accordion state data for all accordions
+ * @param {Function} props.editTaskHandler = handler function that takes in an accordion's id and returns a function for editing on backend
+ * @param {Function} props.deleteTaskHandler - handler function that takes in an accordion's id and returns a function that deletes on both backend and locally
+ * @param {groupState} props.groupState - the group accordion state data for all accordions
* @param {setGroupState} props.setGroupState - the group accordion state setter method
* @param {boolean} props.alwaysOpen - if this is set true, then the accordion will be permanently open and the expand icon will disappear
- */
+ * @param {Function} props.editHandler - function for saving edit on backend (is optional since this component can be used for adding or editing/deleting accordion)
+ * @param {Function} props.deleteHandler - function for deleting on backend (is optional since this component can be used for adding or editing/deleting accordion)
+
+*/
export default function ProfileAccordion(props: {
comboOneVal: string;
comboTwoVal: string;
descPlaceholder: string;
descText: string;
- accordionIndex: number;
+ accordionId: number;
comboOneValPlaceholder: string;
comboTwoValPlaceholder: string;
comboOneValOptions: Array;
@@ -52,6 +66,8 @@ export default function ProfileAccordion(props: {
groupState: groupAccordionState;
setGroupState: setGroupAccordionState;
alwaysOpen?: boolean;
+ editHandler?: Function;
+ deleteHandler?: Function;
}) {
//controls whether accordion is expanded to show description or not
const [expanded, setExpanded] = React.useState(false);
@@ -62,8 +78,32 @@ export default function ProfileAccordion(props: {
const handleEditClick = () => {
setEditMode(true);
};
+
+ //also handles saving edit on backend, if the handler exists
const handleSaveClick = () => {
setEditMode(false);
+ if (props.editHandler) {
+ props.editHandler();
+ }
+ };
+
+ //Delete Confirmation
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
+
+ const openDeleteConfirmModal = () => setDeleteConfirmOpen(true);
+ const closeDeleteConfirmModal = () => setDeleteConfirmOpen(false);
+
+ const deleteIconClickHandler = () => {
+ //pops up delete confirmation modal
+ openDeleteConfirmModal();
+ };
+
+ //when user confirms they want to delete
+ const confirmDeleteHandler = () => {
+ if (props.deleteHandler) {
+ props.deleteHandler();
+ }
+ closeDeleteConfirmModal();
};
const groupState = props.groupState;
@@ -85,15 +125,17 @@ export default function ProfileAccordion(props: {
}
//edit the first combo box value for the specific accordion, copy everything else
setGroupState(
- groupState.map((profileAccordion, index) => {
- if (index === props.accordionIndex) {
+ groupState.map((profileAccordion) => {
+ if (profileAccordion.accordionId === props.accordionId) {
return {
+ accordionId: props.accordionId,
comboOneVal: newValue ? newValue : "",
comboTwoVal: profileAccordion.comboTwoVal,
descText: profileAccordion.descText,
};
}
return {
+ accordionId: profileAccordion.accordionId,
comboOneVal: profileAccordion.comboOneVal,
comboTwoVal: profileAccordion.comboTwoVal,
descText: profileAccordion.descText,
@@ -118,15 +160,17 @@ export default function ProfileAccordion(props: {
}
//edit the second combobox value for the specific accordion, copy everything else
setGroupState(
- groupState.map((profileAccordion, index) => {
- if (index === props.accordionIndex) {
+ groupState.map((profileAccordion) => {
+ if (profileAccordion.accordionId === props.accordionId) {
return {
+ accordionId: props.accordionId,
comboOneVal: profileAccordion.comboOneVal,
comboTwoVal: newValue ? newValue : "",
descText: profileAccordion.descText,
};
}
return {
+ accordionId: profileAccordion.accordionId,
comboOneVal: profileAccordion.comboOneVal,
comboTwoVal: profileAccordion.comboTwoVal,
descText: profileAccordion.descText,
@@ -138,15 +182,17 @@ export default function ProfileAccordion(props: {
//onChange handler for description
const descOnChange = (newValue: string) => {
setGroupState(
- groupState.map((profileAccordion, index) => {
- if (index === props.accordionIndex) {
+ groupState.map((profileAccordion) => {
+ if (profileAccordion.accordionId === props.accordionId) {
return {
+ accordionId: props.accordionId,
comboOneVal: profileAccordion.comboOneVal,
comboTwoVal: profileAccordion.comboTwoVal,
descText: newValue,
};
}
return {
+ accordionId: profileAccordion.accordionId,
comboOneVal: profileAccordion.comboOneVal,
comboTwoVal: profileAccordion.comboTwoVal,
descText: profileAccordion.descText,
@@ -156,92 +202,150 @@ export default function ProfileAccordion(props: {
};
return (
-
-
- }
+ <>
+ {/*Modal for confirming deletion*/}
+
+
+
+ Are you sure you want to delete this?
+
+
+
+
+
+
+
+ {/*Accordion*/}
+
- {/*First combobox */}
-
+
+ )
+ }
+ >
+ {/*First combobox */}
+
+
+
+ {/*Second combobox */}
-
- {/*Second combobox */}
-
-
- {
- //conditional rendering for edit/save icons based on edit mode
- editMode ? (
- {
- event.stopPropagation();
- handleSaveClick();
- }}
- sx={{
- "&:hover": {
- color: "#0A6B57",
- },
- cursor: "pointer",
- transition: "color 0.15s ease-in-out",
- }}
- />
- ) : (
- {
- event.stopPropagation();
- handleEditClick();
- }}
+
+ {
+ //conditional rendering for edit/save icons based on edit mode
+ editMode ? (
+ {
+ event.stopPropagation();
+ handleSaveClick();
+ }}
+ sx={{
+ "&:hover": {
+ color: "#0A6B57",
+ },
+ cursor: "pointer",
+ transition: "color 0.15s ease-in-out",
+ }}
+ />
+ ) : (
+ {
+ event.stopPropagation();
+ handleEditClick();
+ }}
+ sx={{
+ "&:hover": {
+ color: "#0b7d66",
+ },
+ cursor: "pointer",
+ transition: "color 0.15s ease-in-out",
+ }}
+ />
+ )
+ }
+
+ {props.deleteHandler ? (
+
- )
- }
-
-
-
- {/*Description Text Field */}
-
-
-
+ ) : null}
+
+
+
+ {/*Description Text Field */}
+
+
+
+ >
);
}
diff --git a/meshapp/src/pages/Profiles/ProfileAccordionTextfield.tsx b/meshapp/src/pages/Profiles/ProfileAccordionTextfield.tsx
index 60918075..7ce4fc6e 100644
--- a/meshapp/src/pages/Profiles/ProfileAccordionTextfield.tsx
+++ b/meshapp/src/pages/Profiles/ProfileAccordionTextfield.tsx
@@ -15,17 +15,18 @@ import ErrorIcon from "@mui/icons-material/Error";
* @param {string} props.label - The label
* @param {string} props.placeholder - The placeholder text
* @param {string} props.text - The state text value from the group accordion state for the corresponding description
- * @param {number} props.accordionIndex - The index of the current Profile Accordion
* @param {function} props.onChange - function that takes in a new text value to change the corresponding state entry
* @param {Array} props.errValidations - an array of functions to evaluate the current value for errors (takes in the string value as a parameter, returns True if there was no error or the error message if there is)
- */
+ * @param {Function} props.editHandler - function for saving edit on backend (is optional since this component can be used for adding or editing/deleting accordion)
+
+*/
const ProfileAccordionTextField = (props: {
label: string;
placeholder: string;
text: string;
- accordionIndex: number;
onChange: (newValue: string) => void;
errValidations: Array<(value: string) => boolean | string>;
+ editHandler?: Function;
}) => {
//used to set edit mode
const [editMode, setEditMode] = useState(false);
@@ -63,11 +64,15 @@ const ProfileAccordionTextField = (props: {
};
//for toggling edit mode
+ //also handles saving edit on backend, if the handler exists
const handleEditClick = () => {
setEditMode(true);
};
const handleSaveClick = () => {
setEditMode(false);
+ if (props.editHandler) {
+ props.editHandler();
+ }
};
//for toggling whether to display error or not
diff --git a/meshapp/src/pages/Profiles/ProfileGroupAccordion.tsx b/meshapp/src/pages/Profiles/ProfileGroupAccordion.tsx
index 2ebbf851..eabeb518 100644
--- a/meshapp/src/pages/Profiles/ProfileGroupAccordion.tsx
+++ b/meshapp/src/pages/Profiles/ProfileGroupAccordion.tsx
@@ -13,6 +13,7 @@ import ControlPointIcon from "@mui/icons-material/ControlPoint";
//type of group accordion state
export type groupAccordionState = Array<{
+ accordionId: number;
comboOneVal: string;
comboTwoVal: string;
descText: string;
@@ -28,7 +29,11 @@ export type setGroupAccordionState = (newState: groupAccordionState) => void;
* Used in the Profile Page (src/profile/profile-page.tsx).
*
* @param props - Properties of the component
- * @param {groupAccordionState} props.groupAccordArgs - The array containing data for each accordion
+ * @param {groupAccordionState} props.groupAccordState - the state array that contains the group accordion data
+ * @param {setGroupAccordionState} props.setGroupAccordState - the state mutator method for the group accordion data
+ * @param {Function} props.editAccordHandler = handler function that takes in an accordion's id and returns a function for editing on backend
+ * @param {Function} props.deleteAccordHandler - handler function that takes in an accordion's id and returns a function that deletes on both backend and locally
+ * @param {Function} props.addAccordHandler - handler function for adding an accord on the backend and locally
* @param {string} props.descPlaceholder - the placeholder for the description textfield
* @param {string} props.comboOneValPlaceholder - the placeholder for the first combobox combobox in each accordion
* @param {string} props.comboTwoValPlaceholder - the placeholder for the second combobox combobox in each accordion
@@ -39,7 +44,10 @@ export type setGroupAccordionState = (newState: groupAccordionState) => void;
* @param {Array} props.descErrValidations - an array of functions to evaluate the description text value for each accordion for errors (takes in the string value as a parameter, returns True if there was no error or the error message if there is)
*/
export function ProfileGroupAccordion(props: {
- groupAccordArgs: groupAccordionState;
+ groupAccordState: groupAccordionState;
+ setGroupAccordState: setGroupAccordionState;
+ editAccordHandler: Function;
+ deleteAccordHandler: Function;
descPlaceholder: string;
comboOneValPlaceholder: string;
comboTwoValPlaceholder: string;
@@ -48,26 +56,16 @@ export function ProfileGroupAccordion(props: {
comboOneValErrValidations: Array<(value: string) => boolean | string>;
comboTwoValErrValidations: Array<(value: string) => boolean | string>;
descErrValidations: Array<(value: string) => boolean | string>;
+ addAccordHandler: Function;
}) {
- //group accordion data state with set state method
- const [GroupAccordState, setGroupAccordState] = useState(
- props.groupAccordArgs.map((accord) => {
- return {
- comboOneVal: accord.comboOneVal,
- comboTwoVal: accord.comboTwoVal,
- descText: accord.descText,
- };
- })
- );
-
//state to control whether new accordion modal is open or not
const [addOpen, setAddOpen] = useState(false);
const showModal = () => setAddOpen(true);
const hideModal = () => setAddOpen(false);
- //state to store data for the new accordion
+ //state to store data for the new accordion, id doesn't matter since it won't really be used
const [newAccordionData, setNewAccordionData] = useState([
- { comboOneVal: "", comboTwoVal: "", descText: "" },
+ { comboOneVal: "", comboTwoVal: "", descText: "", accordionId: 0 },
]);
return (
@@ -76,13 +74,14 @@ export function ProfileGroupAccordion(props: {
container
flexDirection={"column"}
alignItems={"center"}
- onClick={() => console.log(GroupAccordState)}
+ // onClick={() => console.log(props.groupAccordState)}
>
- {GroupAccordState.map((accordArgs, accordIndex) => {
+ {props.groupAccordState.map((accordArgs) => {
return (
);
})}
@@ -112,8 +113,8 @@ export function ProfileGroupAccordion(props: {
showModal={showModal}
newAccordData={newAccordionData}
setAccordData={setNewAccordionData}
- groupState={GroupAccordState}
- setGroupState={setGroupAccordState}
+ groupState={props.groupAccordState}
+ setGroupState={props.setGroupAccordState}
comboOneValErrValidations={props.comboOneValErrValidations}
comboTwoValErrValidations={props.comboTwoValErrValidations}
descErrValidations={props.descErrValidations}
@@ -122,6 +123,7 @@ export function ProfileGroupAccordion(props: {
comboTwoValPlaceholder={props.comboTwoValPlaceholder}
comboOneValOptions={props.comboOneValOptions}
comboTwoValOptions={props.comboTwoValOptions}
+ addAccordHandler={props.addAccordHandler}
/>
);
@@ -146,6 +148,7 @@ export function ProfileGroupAccordion(props: {
* @param {string} props.comboTwoValPlaceholder - placeholder for second combobox
* @param {Array} props.comboOneValOptions - list of options to be provided for first combobox
* @param {Array} props.comboTwoValOptions -list of options to be provided for second combobox
+ * @param {Function} props.addAccordHandler - handler function for adding an accord on the backend and locally
*/
function NewAccordionModal(props: {
addOpen: boolean;
@@ -163,12 +166,13 @@ function NewAccordionModal(props: {
comboTwoValPlaceholder: string;
comboOneValOptions: Array;
comboTwoValOptions: Array;
+ addAccordHandler: Function;
}) {
//grab the data for the current new accordion
let newAccordData = props.newAccordData[0];
- let comboOneValVal = newAccordData.comboOneVal;
- let comboTwoValVal = newAccordData.comboTwoVal;
- let descVal = newAccordData.descText;
+ let newComboOneVal = newAccordData.comboOneVal;
+ let newComboTwoVal = newAccordData.comboTwoVal;
+ let newDescVal = newAccordData.descText;
//controls whether snackbar is open or not
const [snackbar, setSnackbar] = useState(false);
@@ -199,11 +203,11 @@ function NewAccordionModal(props: {
>
console.log(newAccordData)}>
{
@@ -266,15 +270,10 @@ function NewAccordionModal(props: {
//if there are no errors, hide the modal, add the new accordion data to real group accord data, and erase the modal accordion data
if (errResults.every((err) => typeof err === "boolean")) {
props.hideModal();
- props.setGroupState([
- ...props.groupState,
- {
- comboOneVal: comboOneValVal,
- comboTwoVal: comboTwoValVal,
- descText: descVal,
- },
+ props.addAccordHandler(newComboOneVal, newComboTwoVal, newDescVal);
+ props.setAccordData([
+ { accordionId: 0, comboOneVal: "", comboTwoVal: "", descText: "" },
]);
- props.setAccordData([{ comboOneVal: "", comboTwoVal: "", descText: "" }]);
}
//otherwise, display the error, and don't erase modal accordion data
else {