diff --git a/cypress/integration/pages/organizations.spec.js b/cypress/integration/pages/organizations.spec.js
index 2dcf6313..defc327f 100644
--- a/cypress/integration/pages/organizations.spec.js
+++ b/cypress/integration/pages/organizations.spec.js
@@ -62,12 +62,16 @@ describe('Organizations Page (using API)', () => {
cy.get('[data-cy=organization-search]').type(affiliatedOrg).type('{enter}');
cy.get('[data-cy=affiliated-organizations]').within(() => {
cy.get('[data-cy=thumbnail-dropdown]').should('have.length', 1);
- cy.get('[data-cy=contributor-thumbnail-text]').contains(affiliatedOrg);
+ cy.get('[data-cy=thumbnail-dropdown]').eq(0).click().within(() => {
+ cy.get('[data-cy=contributor-thumbnail-text]').contains(affiliatedOrg);
+ });
});
cy.get('[data-cy=affiliated-organizations]').within(() => {
cy.get('[data-cy=thumbnail-dropdown]').should('have.length', parentOrgCount2);
});
- cy.get('[data-cy=organization-search]').clear();
+ cy.get('[data-cy=organization-search]').within(() => {
+ cy.get('input').clear();
+ });
});
it('should find affiliatedOrg via partial search', () => {
@@ -81,9 +85,13 @@ describe('Organizations Page (using API)', () => {
cy.get('[data-cy=organization-search-list]').click();
cy.get('[data-cy=affiliated-organizations]').within(() => {
cy.get('[data-cy=thumbnail-dropdown]').should('have.length', 1);
- cy.get('[data-cy=contributor-thumbnail-text]').contains(affiliatedOrg);
+ cy.get('[data-cy=thumbnail-dropdown]').eq(0).click().within(() => {
+ cy.get('[data-cy=contributor-thumbnail-text]').contains(affiliatedOrg);
+ });
+ });
+ cy.get('[data-cy=organization-search]').within(() => {
+ cy.get('input').clear();
});
- cy.get('[data-cy=organization-search]').clear();
});
it('should visit organizations page from home page link', () => {
diff --git a/src/components/Dropdown.js b/src/components/Dropdown.js
index 2b2d655f..e1eb6656 100644
--- a/src/components/Dropdown.js
+++ b/src/components/Dropdown.js
@@ -36,19 +36,20 @@ const useStyles = makeStyles((theme) => ({
}));
export const Dropdown = ({
- organization,
+ checkboxValue,
children,
dropdownLength,
- isOpen,
- checkboxValue,
- inputValue,
filtersActive,
+ isOpen,
+ onClick,
+ organization,
}) => {
const [openChild, setOpenChild] = useState(isOpen ? true : false);
const [colorStyle, setColor] = useState(isOpen ? true : false);
const classes = useStyles();
- const handleOpen = () => {
+ const handleClick = () => {
+ onClick(organization);
setOpenChild(!openChild);
setColor(!colorStyle);
};
@@ -65,7 +66,7 @@ export const Dropdown = ({
item
xs={10}
className={clsx(classes.dropdown, {
- [classes.open]: colorStyle === true,
+ [classes.open]: isOpen,
})}
>
@@ -74,7 +75,7 @@ export const Dropdown = ({
filtersActive={filtersActive}
checkboxValue={checkboxValue}
dropdownLength={dropdownLength}
- isOpen={colorStyle}
+ isOpen={isOpen}
isChildThumbnail={false}
/>
@@ -83,12 +84,11 @@ export const Dropdown = ({
item
container
className={classes.flexGrid}
- onClick={handleOpen}
+ onClick={handleClick}
>
@@ -101,7 +101,7 @@ export const Dropdown = ({
/>
)}
- {openChild && children}
+ {isOpen && children}
);
};
diff --git a/src/pages/Contributors/Affiliated.js b/src/pages/Contributors/Affiliated.js
index 05e2eec5..b729a299 100644
--- a/src/pages/Contributors/Affiliated.js
+++ b/src/pages/Contributors/Affiliated.js
@@ -117,26 +117,28 @@ const useStyles = makeStyles((theme) => ({
},
}));
/* eslint complexity: [0, 0]*/
-export const Affiliated = (props) => {
- const {
- affiliatedCount,
- classes,
- inputValue,
- organizations,
- organizationData,
- filtersActive,
- totalAffiliatedCount,
- showIndexContrib,
- } = props;
+export const Affiliated = ({
+ affiliatedCount,
+ classes,
+ expandedOrgs,
+ inputValue,
+ onOrgClick,
+ organizations,
+ organizationData,
+ filtersActive,
+ totalAffiliatedCount,
+ showIndexContrib,
+}) => {
const classesLocal = useStyles();
const [dropdownOpen, setDropdownOpen] = useState(false);
useEffect(() => {
- if (filtersActive && organizations.length) {
+ if ((filtersActive || expandedOrgs.length) && organizations.length) {
setDropdownOpen(true);
} else {
setDropdownOpen(false);
}
- }, [filtersActive, organizations])
+ }, [expandedOrgs, filtersActive, organizations])
+
return (
@@ -221,11 +223,13 @@ export const Affiliated = (props) => {
) : (
))}
diff --git a/src/pages/Contributors/AffiliatedOrganizations.js b/src/pages/Contributors/AffiliatedOrganizations.js
index 38c55e29..74a11ad3 100644
--- a/src/pages/Contributors/AffiliatedOrganizations.js
+++ b/src/pages/Contributors/AffiliatedOrganizations.js
@@ -64,11 +64,13 @@ const useStyles = makeStyles((theme) => ({
}));
export const AffiliatedOrganizations = ({
- organizations,
+ expandedOrgs,
+ filtersActive,
inputValue,
+ onOrgClick,
organizationData,
+ organizations,
showIndexContrib,
- filtersActive,
}) => {
const classes = useStyles();
@@ -83,7 +85,7 @@ export const AffiliatedOrganizations = ({
organizations.forEach((org) => {
if (org.depth === 3) {
org['childNodes'] = [];
- org['isOpen'] = false;
+ org['allChildrenShown'] = false;
parentdata.push(org);
}
if (org.depth === 4) {
@@ -99,7 +101,7 @@ export const AffiliatedOrganizations = ({
if (!exist) {
mapsearchedChildParent['childNodes'] = [];
- mapsearchedChildParent['isOpen'] = false;
+ mapsearchedChildParent['allChildrenShown'] = false;
parentChildobj = mapsearchedChildParent;
parentdata.push(mapsearchedChildParent);
} else {
@@ -115,7 +117,7 @@ export const AffiliatedOrganizations = ({
}
} else {
org['childNodes'] = [];
- org['isOpen'] = false;
+ org['allChildrenShown'] = false;
parentdata.push(org);
}
}
@@ -141,16 +143,16 @@ export const AffiliatedOrganizations = ({
>
{currentThumbnails.map((org, i) => {
childSort = org.childNodes;
- childNode = org.isOpen ? childSort : childSort.slice(0, 6);
+ childNode = org.allChildrenShown ? childSort : childSort.slice(0, 6);
return (
{
const data = [...currentThumbnails];
- data[i].isOpen = !data[i].isOpen;
+ data[i].allChildrenShown = !data[i].allChildrenShown;
setCurrentThumbnails(data);
}}
>
- {currentThumbnails[i].isOpen ? 'View Less' : 'View All'}
+ {currentThumbnails[i].allChildrenShown ? 'View Less' : 'View All'}
) : null}
@@ -230,13 +232,13 @@ export const AffiliatedOrganizations = ({
{currentThumbnails.map((org, i) => {
return (
{org.childNodes.length === 0 ? (
diff --git a/src/pages/Contributors/index.js b/src/pages/Contributors/index.js
index 2f0b6e94..be88d0a1 100644
--- a/src/pages/Contributors/index.js
+++ b/src/pages/Contributors/index.js
@@ -6,6 +6,7 @@ import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { useLocation } from 'react-router-dom';
import {
+ ArrayParam,
BooleanParam,
StringParam,
useQueryParam,
@@ -55,7 +56,6 @@ export default function Contributors() {
const location = useLocation();
const [affiliatedCount, setAffiliatedCount] = useState(0);
const [affiliatedOrganizations, setAffiliatedOrganizations] = useState([]);
- const [inputValue, setInputValue] = useState('');
const [organizations, setOrganizations] = useState([]);
const [organizationNames, setOrganizationNames] = useState([]);
const [filtersActive, setFiltersActive] = useState(false);
@@ -65,14 +65,22 @@ export default function Contributors() {
const [unaffiliatedOrganizations, setUnaffiliatedOrganizations] = useState(
[]
);
- const [showIndexContrib, setShowIndexContrib] = useQueryParam(
- 'contrib',
- withDefault(BooleanParam, false)
+ const [expandedOrgs, setExpandedOrgs] = useQueryParam(
+ 'opened',
+ withDefault(ArrayParam, [])
);
const [orgStatus, setOrgStatus] = useQueryParam(
'status',
withDefault(StringParam, 'any')
);
+ const [searchQuery, setSearchQuery] = useQueryParam(
+ 'query',
+ withDefault(StringParam, '')
+ );
+ const [showIndexContrib, setShowIndexContrib] = useQueryParam(
+ 'contrib',
+ withDefault(BooleanParam, false)
+ );
useEffect(() => {
const fetchData = async () => {
@@ -124,9 +132,26 @@ export default function Contributors() {
}
// handle case of user entering bookmarked URL directly
} else if (!location.query) {
- const queryParams = location.search.replace('?', '').split('&');
- setOrgStatus(queryParams[1].split('=')[1]);
- setShowIndexContrib(!!(Number(queryParams[0].split('=')[1])));
+ const expanded = [];
+ const queryParams = {};
+ location.search.replace('?', '').split('&').forEach((param) => {
+ const [key, val] = param.split('=');
+ if (key === 'opened') {
+ expanded.push(val);
+ } else {
+ queryParams[key] = val;
+ }
+ });
+ setExpandedOrgs(expanded);
+ if ('query' in queryParams) {
+ setSearchQuery(queryParams.query);
+ }
+ if ('status' in queryParams) {
+ setOrgStatus(queryParams.status);
+ }
+ if ('contrib' in queryParams) {
+ setShowIndexContrib(!!Number(queryParams.contrib));
+ }
}
}, [
location.search,
@@ -139,7 +164,7 @@ export default function Contributors() {
unafflCount = 0;
const affiliated = [];
const unaffiliated = [];
- const input = inputValue.toLowerCase().replace(/\s/g, '');
+ const input = searchQuery.toLowerCase().replace(/\s/g, '');
for (const org of organizations) {
const orgName = org.name.toLowerCase().replace(/\s/g, '');
if (
@@ -160,7 +185,7 @@ export default function Contributors() {
setUnaffiliatedCount(unafflCount);
setAffiliatedOrganizations(affiliated);
setUnaffiliatedOrganizations(unaffiliated);
- }, [inputValue, organizations, showIndexContrib]);
+ }, [searchQuery, organizations, showIndexContrib]);
TabPanel.propTypes = {
children: PropTypes.node,
@@ -189,6 +214,22 @@ export default function Contributors() {
}
};
+ const handleInputValueChange = (value) => {
+ setSearchQuery(value);
+ setExpandedOrgs([]);
+ };
+
+ const handleOrgClick = (org) => {
+ const expanded = [...expandedOrgs];
+ const idx = expanded.indexOf(org.id.toString());
+ if (idx > -1) {
+ expanded.splice(idx, 1);
+ } else {
+ expanded.push(org.id.toString());
+ }
+ setExpandedOrgs(expanded);
+ };
+
const handleTabValueChange = (value) => {
switch (value) {
case 0:
@@ -222,8 +263,8 @@ export default function Contributors() {
@@ -295,15 +336,16 @@ export default function Contributors() {
totalUnaffiliatedCount={totalUnaffiliatedCount}
/>
@@ -316,15 +358,16 @@ export default function Contributors() {