diff --git a/package-lock.json b/package-lock.json
index 9fa33281..39c78bfd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
"fs": "^0.0.1-security",
+ "fuse.js": "^6.4.6",
"jsonwebtoken": "^8.5.1",
"mongodb": "^3.5.9",
"mongoose": "^5.9.20",
@@ -9092,6 +9093,14 @@
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
},
+ "node_modules/fuse.js": {
+ "version": "6.4.6",
+ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.4.6.tgz",
+ "integrity": "sha512-/gYxR/0VpXmWSfZOIPS3rWwU8SHgsRTwWuXhyb2O6s7aRuVtHtxCkR33bNYu3wyLyNx/Wpv0vU7FZy8Vj53VNw==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@@ -30604,6 +30613,11 @@
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
},
+ "fuse.js": {
+ "version": "6.4.6",
+ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.4.6.tgz",
+ "integrity": "sha512-/gYxR/0VpXmWSfZOIPS3rWwU8SHgsRTwWuXhyb2O6s7aRuVtHtxCkR33bNYu3wyLyNx/Wpv0vU7FZy8Vj53VNw=="
+ },
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
diff --git a/package.json b/package.json
index 3514c52e..1047cc8f 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
"fs": "^0.0.1-security",
+ "fuse.js": "^6.4.6",
"jsonwebtoken": "^8.5.1",
"mongodb": "^3.5.9",
"mongoose": "^5.9.20",
diff --git a/src/containers/AdminDashboard/AdminDashboard.css b/src/containers/AdminDashboard/AdminDashboard.css
index b2b8b2bf..16bf0685 100644
--- a/src/containers/AdminDashboard/AdminDashboard.css
+++ b/src/containers/AdminDashboard/AdminDashboard.css
@@ -126,6 +126,9 @@
border: solid 1px var(--color-red);
}
+.AdminDashboard .dropdown-select {
+ margin: .5rem;
+}
.AdminDashboard .dashboard-section-title {
font-weight: 800;
margin: 2rem 0 1rem;
diff --git a/src/containers/AdminDashboard/AdminDashboard.js b/src/containers/AdminDashboard/AdminDashboard.js
index d3efe817..b270ee46 100644
--- a/src/containers/AdminDashboard/AdminDashboard.js
+++ b/src/containers/AdminDashboard/AdminDashboard.js
@@ -11,6 +11,7 @@ import {
deleteQuestionnaireResponse,
} from '../../sendRequest/apis';
import { getAuthToken } from '../../utilities/auth_utils';
+import { searchArrayObjects } from '../../utilities/search_array';
import './AdminDashboard.css';
import { languageOptions, workshopTitle } from '../../data/LanguageOptions';
import Navbar from '../../compositions/Navbar/Navbar';
@@ -37,6 +38,8 @@ const AdminDashboard = (props) => {
const [loading, setLoading] = useState(true);
const [createdOrder, setCreatedOrder] = useState(true);
const [updatedOrder, setUpdatedOrder] = useState(true);
+ const [filterBy, setFilterBy] = useState('full_name');
+ const [searchTerm, setSearchTerm] = useState('');
useEffect(() => {
setLoading(true);
const jwt = getAuthToken();
@@ -339,7 +342,13 @@ const AdminDashboard = (props) => {
};
const responsesMarkup = useMemo(() => {
- return questionnaireResponses.map((response, index) => {
+ let filterQuestionnaireResponses = searchArrayObjects(
+ questionnaireResponses,
+ `questionnaireResponse.${filterBy}`,
+ searchTerm,
+ 3
+ );
+ return filterQuestionnaireResponses.map((response, index) => {
const { questionnaireResponse = {} } = response;
const fullLangText = languageOptions.find(
(item) => item.code === questionnaireResponse['languageCode']
@@ -487,6 +496,8 @@ const AdminDashboard = (props) => {
downloadOrder,
createdOrder,
updatedOrder,
+ filterBy,
+ searchTerm,
]);
const responsesTable = (
@@ -687,6 +698,27 @@ const AdminDashboard = (props) => {
/>
+
Details
{responsesTable}
diff --git a/src/utilities/search_array.js b/src/utilities/search_array.js
new file mode 100644
index 00000000..b3b6ca9e
--- /dev/null
+++ b/src/utilities/search_array.js
@@ -0,0 +1,25 @@
+import Fuse from 'fuse.js';
+/**
+ * search through an arary of objects for a specifed search string
+ * objects-array of objects to be filterd
+ * propertyPath - property to be filtered on, can include sub objects
+ * searchText - text to search for
+ * minLength - min length of the match
+ * @returns the filtered responses from the array
+ */
+export const searchArrayObjects = (
+ objects,
+ propertyPath,
+ searchText,
+ minLength = 3
+) => {
+ if (!searchText) {
+ return objects;
+ }
+ const fuse = new Fuse(objects, {
+ keys: [propertyPath],
+ minMatchCharLength: minLength,
+ });
+ const filterResponse = fuse.search(searchText).map((result) => result.item);
+ return filterResponse;
+};