diff --git a/client/src/components/CSVParser.js b/client/src/components/CSVParser.js index 6d7af2e..8f1b77c 100644 --- a/client/src/components/CSVParser.js +++ b/client/src/components/CSVParser.js @@ -34,7 +34,7 @@ function CSVParser({ setVisiblity, CSVFlowVisible, setCSVFlowVisible, - forceNewGroup + forceNewGroup, }) { const { CSVReader } = useCSVReader(); const { CSVDownloader, Type } = useCSVDownloader(); @@ -45,7 +45,7 @@ function CSVParser({ const [createCSVGroup, setCreateCSVGroup] = useState(false); // tracks if group creation from csv is toggled React.useEffect(async () => { - if(group) { + if (group) { await fetch(`${process.env.REACT_APP_BACKEND_URI}/rows?group=` + group.id).then( async (response) => { if (response.ok) { @@ -146,7 +146,7 @@ function CSVParser({ onUploadAccepted={async (results) => { // if we create group from CSV setCSVData(results.data); - + let headers = Object.keys(results.data[0]); headers = headers.map((value) => { return { name: value, type: "Text" }; @@ -196,7 +196,7 @@ function CSVParser({ ) : null}
- {forceNewGroup ? + {forceNewGroup ? ( - : + ) : ( setCreateCSVGroup(!createCSVGroup)} /> - } + )} -
+
- - Download - -
- } + {!forceNewGroup && ( +
+ + + Download + +
+ )} ); } diff --git a/client/src/components/CreateGroup.js b/client/src/components/CreateGroup.js index 861cbb7..496d697 100644 --- a/client/src/components/CreateGroup.js +++ b/client/src/components/CreateGroup.js @@ -65,7 +65,6 @@ function CreateGroup({ onConfirm, onCancel, editGroup, onDelete, CSVFields }) { const [groupNameInvalid, setGroupNameInvalid] = useState(false); const fieldsListDiv = useRef(null); - /** * `fields` is an array of objects representing the group's fields. Each object has a `name` and * a `type`, both strings. Each object may also have a boolean `invalid` field, denoting whether @@ -174,7 +173,7 @@ function CreateGroup({ onConfirm, onCancel, editGroup, onDelete, CSVFields }) { /> ))} - {!CSVFields ? + {!CSVFields ? ( - : + ) : (
- } + )}
+ {dropdownItems.map((item) => ( + + ))} + {typeField ? ( +
+ setTypeFieldValue(event.target.value)} + autoFocus="autofocus" + /> +
+ ) : null} +
+ + ); +} + +export default TypeDropdown; diff --git a/client/src/components/TypeDropdownOption.js b/client/src/components/TypeDropdownOption.js new file mode 100644 index 0000000..a9b5f61 --- /dev/null +++ b/client/src/components/TypeDropdownOption.js @@ -0,0 +1,79 @@ +/** + * Components representing rows in the TypeDropdown menu. + * + * @summary Table display for dashboard page. + * @author Alex Zhang + */ + +import React, { useState, useRef, useEffect } from "react"; +import Pencil from "../images/Pencil"; +import TrashCan from "../images/TrashCan.svg"; + +/** + * Renders the dropdown option for the custom type menu. + * @param {string} value The string value of the type option + * @param {function} deleteType Function to remove the type option from the dropdown. + * @returns + */ +function TypeDropdownOption({ value, deleteType }) { + const [fieldValue, setFieldValue] = useState(value); + const [editOption, setEditOption] = useState(false); + const [editFieldValue, setEditFieldValue] = useState(value); + // This useEffect hook manages clicks outside the menu and minimizes the window. + const editOptionRef = useRef(null); + useEffect(() => { + const handleClickOutside = (event) => { + if (editOption && editOptionRef.current && !editOptionRef.current.contains(event.target)) { + setEditFieldValue(fieldValue); + setEditOption(false); + } + }; + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }); + + const onKeyDown = (event) => { + // 'keypress' event misbehaves on mobile so we track 'Enter' key via 'keydown' event + if (event.key === "Enter") { + event.preventDefault(); + event.stopPropagation(); + setFieldValue(editFieldValue); + setEditOption(false); + } + }; + return ( +
+ + + {editOption ? ( +
+

Edit Option

+
+ setEditFieldValue(event.target.value)} + autoFocus="autofocus" + /> + +
+ ) : null} +
+ ); +} + +export default TypeDropdownOption; diff --git a/client/src/css/CSVParser.css b/client/src/css/CSVParser.css index bc9c88e..7eb5899 100644 --- a/client/src/css/CSVParser.css +++ b/client/src/css/CSVParser.css @@ -165,4 +165,4 @@ width: max-content; margin-bottom: -20px; margin-top: 10px; -} \ No newline at end of file +} diff --git a/client/src/css/Dashboard.css b/client/src/css/Dashboard.css index 8cbb492..a2e19fa 100644 --- a/client/src/css/Dashboard.css +++ b/client/src/css/Dashboard.css @@ -182,4 +182,4 @@ .no-groups-info-wrapper { text-align: center; -} \ No newline at end of file +} diff --git a/client/src/css/TypeDropdown.css b/client/src/css/TypeDropdown.css new file mode 100644 index 0000000..6862906 --- /dev/null +++ b/client/src/css/TypeDropdown.css @@ -0,0 +1,140 @@ +.type-dropdown-div-wrapper { + position: relative; + left: 50%; +} + +.type-dropdown-div { + display: flex; + flex-flow: wrap; + width: 200px; + background: #fafafa; + border: 0.2px solid #05204a; + box-shadow: 0px 1.5px 12px rgba(0, 0, 0, 0.25); + border-radius: 3.5px; + justify-content: center; + max-height: 200px; + overflow-x: hidden; + overflow-y: auto; +} + +.add-type-dropdown-button { + display: table-cell; + margin-top: 14px; + margin-bottom: 12px; + width: 170px; + height: 35px; + font-weight: 400; + font-size: 14px; + line-height: 35px; + border-radius: 5px; + border: none; + background: #05204a; + color: #ffffff; + cursor: pointer; +} + +.type-dropdown-add-icon-svg { + position: relative; + top: 3px; + padding-right: 8px; + width: 15px; + justify-self: auto; +} + +.type-dropdown-field { + height: 35px; + width: 135px; + margin-bottom: 12px; + text-align: center; + border: 0px; + background: #f3f3f3; + border-radius: 5px; + color: #404040; + overflow: hidden; + white-space: nowrap; + text-overflow: clip; +} + +.type-dropdown-field.empty { + width: 170px; +} + +.type-dropdown-option { + position: static; + width: 170px; +} + +.type-dropdown-pencil { + float: right; + margin-top: 9px; + cursor: pointer; +} + +.type-dropdown-edit-div { + position: absolute; + left: 13%; + z-index: 10; + background: #000000; + width: 190px; + height: 135px; + background: #fafafa; + border: 0.2px solid #05204a; + box-shadow: 0px 1.5px 12px rgba(0, 0, 0, 0.25); + border-radius: 3.5px; +} + +.type-dropdown-edit-header { + margin-left: 12px; + margin-top: 7px; + margin-bottom: 7px; + font-weight: 500; + font-size: 16px; + line-height: 24px; + color: #05204a; +} + +.type-dropdown-edit-divider { + width: 160px; + border: 0.75px solid #e0dddd; + margin: 0px; + margin-left: 12px; +} + +.type-dropdown-edit-field { + height: 35px; + width: 150px; + margin: 12px; + padding-left: 10px; + border: 1px solid #c5c5c5; + background: #f3f3f3; + border-radius: 5px; + color: #404040; + overflow: hidden; + white-space: nowrap; + text-overflow: clip; +} + +.type-dropdown-delete-option { + display: inline-block; + padding: 0px; + background: none; + border: none; + height: 21px; + width: 150px; + margin-left: 17px; + font-weight: 400; + font-size: 14px; + color: #c4c4c4; + cursor: pointer; +} + +.type-dropdown-trash-can-svg { + float: left; + margin-right: 9px; +} + +.type-dropdown-delete-option-text { + float: left; + line-height: 21px; + margin: 0px; +} diff --git a/client/src/pages/Dashboard.js b/client/src/pages/Dashboard.js index 5ecbf6f..942c846 100644 --- a/client/src/pages/Dashboard.js +++ b/client/src/pages/Dashboard.js @@ -62,7 +62,6 @@ function Dashboard() { const [CSVFields, setCSVFields] = useState(null); // stores fields from uploaded csv const [CSVData, setCSVData] = useState(null); // tracks if csv for group creation was uploaded - /** * Fetches the list of groups and populates the options in the group selection dropdown. * @returns The new list of options @@ -420,11 +419,11 @@ function Dashboard() { /** * Hide csv dropdown when click outside of it - */ - document.addEventListener('mouseup', function(e) { - var dropdown = document.getElementById('csv-parser-dropdown'); + */ + document.addEventListener("mouseup", function (e) { + var dropdown = document.getElementById("csv-parser-dropdown"); if (!dropdown.contains(e.target)) { - setVisibility(false) + setVisibility(false); } }); @@ -460,35 +459,46 @@ function Dashboard() {
- create icon
+ create icon +

Start building your dashboard!

-

Click "Create new" to begin adding data to your table.
- Have previous databases? No worries! You can upload your CSV file as well.

+

+ Click "Create new" to begin adding data to your table. +
+ Have previous databases? No worries! You can upload your CSV file as well. +

- {(groupCreationVisible && !CSVFields) && ( - setGroupCreationVisible(false)} /> + {groupCreationVisible && !CSVFields && ( + setGroupCreationVisible(false)} + /> )} - - {(groupCreationVisible && CSVFields) && ( + + {groupCreationVisible && CSVFields && ( { @@ -499,7 +509,7 @@ function Dashboard() { CSVFields={CSVFields} /> )} -
+
); @@ -510,26 +520,30 @@ function Dashboard() {

{orgInfo ? orgInfo.name : userInfo.orgName}

- + {selectedGroup && ( + + )}
-
- setSearch(event.target.value)} - /> - Search +
+ setSearch(event.target.value)} + /> + Search +
+ {dataLoading ? ( +
+ +
+ ) : ( + + )} - {dataLoading ? ( -
- -
- ) : ( -
{ + setGroupCreationVisible(false); + setCSVFields(null); + setCSVData(null); + }} + CSVFields={CSVFields} /> )} - - {groupCreationVisible && ( - { - setGroupCreationVisible(false); - setCSVFields(null); - setCSVData(null); - }} - CSVFields={CSVFields} - /> - )} - {groupEditVisible && ( - setGroupEditVisible(false)} - CSVFields={null} - /> - )} -
- + {groupEditVisible && ( + setGroupEditVisible(false)} + CSVFields={null} + /> + )} +
+