-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { useState, useCallback, useEffect } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { SearchField } from '@openedx/paragon'; | ||
import { debounce } from 'lodash'; | ||
|
||
import { LoadingSpinner } from '../../../../generic/Loading'; | ||
import LibrariesV2OrderFilterMenu from './libraries-v2-order-filter-menu'; | ||
|
||
/* regex to check if a string has only whitespace | ||
example " " | ||
*/ | ||
const regexOnlyWhiteSpaces = /^\s+$/; | ||
|
||
const LibrariesV2Filters = ({ | ||
isLoading, | ||
setIsFiltered, | ||
setFilterParams, | ||
isFiltered, | ||
}) => { | ||
const [search, setSearch] = useState(''); | ||
const [order, setOrder] = useState('title'); | ||
|
||
// Reset search & order when filters cleared | ||
useEffect(() => { | ||
if (!isFiltered) { | ||
setSearch(''); | ||
setOrder('title'); | ||
} | ||
}, [isFiltered, setSearch, setOrder]); | ||
|
||
const getOrderFromFilterType = (filterType) => { | ||
const orders = { | ||
azLibrariesV2: 'title', | ||
zaLibrariesV2: '-title', | ||
newestLibrariesV2: '-created', | ||
oldestLibrariesV2: 'created', | ||
}; | ||
|
||
// Default to 'A-Z` if invalid filtertype | ||
return orders[filterType] || 'title'; | ||
}; | ||
|
||
const getFilterTypeData = (baseFilters) => ({ | ||
azLibrariesV2: { ...baseFilters, order: 'title' }, | ||
zaLibrariesV2: { ...baseFilters, order: '-title' }, | ||
newestLibrariesV2: { ...baseFilters, order: '-created' }, | ||
oldestLibrariesV2: { ...baseFilters, order: 'created' }, | ||
}); | ||
|
||
const handleMenuFilterItemSelected = (filterType) => { | ||
setOrder(getOrderFromFilterType(filterType)); | ||
setIsFiltered(true); | ||
|
||
const baseFilters = { | ||
search, | ||
order, | ||
}; | ||
|
||
const filterParams = getFilterTypeData(baseFilters); | ||
const filterParamsFormat = filterParams[filterType] || baseFilters; | ||
|
||
setFilterParams(filterParamsFormat); | ||
|
||
// TODO: Probably need to reset the page number to 1 | ||
}; | ||
|
||
const handleSearchLibrariesV2 = (searchValueDebounced) => { | ||
const valueFormatted = searchValueDebounced.trim(); | ||
const filterParams = { | ||
search: valueFormatted.length > 0 ? valueFormatted : undefined, | ||
order, | ||
}; | ||
const hasOnlySpaces = regexOnlyWhiteSpaces.test(searchValueDebounced); | ||
|
||
if (valueFormatted !== search && !hasOnlySpaces) { | ||
setIsFiltered(true); | ||
setSearch(valueFormatted); | ||
setFilterParams(filterParams); | ||
|
||
// TODO: Probably need to reset the page number to 1 | ||
} | ||
}; | ||
|
||
const handleSearchLibrariesV2Debounced = useCallback( | ||
debounce((value) => handleSearchLibrariesV2(value), 400), | ||
[order], | ||
); | ||
|
||
return ( | ||
<div className="d-flex"> | ||
<div className="d-flex flex-row"> | ||
<SearchField | ||
onSubmit={() => {}} | ||
onChange={handleSearchLibrariesV2Debounced} | ||
value={search} | ||
className="mr-4" | ||
data-testid="input-filter-courses-search" | ||
placeholder="Search" | ||
/> | ||
{isLoading && ( | ||
<span className="search-field-loading" data-testid="loading-search-spinner"> | ||
<LoadingSpinner size="sm" /> | ||
</span> | ||
)} | ||
</div> | ||
|
||
<LibrariesV2OrderFilterMenu onItemMenuSelected={handleMenuFilterItemSelected} isFiltered={isFiltered} /> | ||
</div> | ||
); | ||
}; | ||
|
||
LibrariesV2Filters.defaultProps = { | ||
isLoading: false, | ||
setIsFiltered: () => {}, | ||
}; | ||
|
||
LibrariesV2Filters.propTypes = { | ||
isLoading: PropTypes.bool, | ||
setIsFiltered: PropTypes.func, | ||
setFilterParams: PropTypes.func.isRequired, | ||
isFiltered: PropTypes.bool.isRequired, | ||
}; | ||
|
||
export default LibrariesV2Filters; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { useState, useEffect } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { Icon, Dropdown } from '@openedx/paragon'; | ||
import { Check } from '@openedx/paragon/icons'; | ||
|
||
const LibrariesV2FilterMenu = ({ | ||
id: idProp, | ||
menuItems, | ||
onItemMenuSelected, | ||
defaultItemSelectedText, | ||
isFiltered, | ||
}) => { | ||
const [itemMenuSelected, setItemMenuSelected] = useState(defaultItemSelectedText); | ||
const handleCourseTypeSelected = (name, value) => { | ||
setItemMenuSelected(name); | ||
onItemMenuSelected(value); | ||
Check warning on line 16 in src/studio-home/tabs-section/libraries-v2-tab/libraries-v2-filters/libraries-v2-filter-menu/index.jsx Codecov / codecov/patchsrc/studio-home/tabs-section/libraries-v2-tab/libraries-v2-filters/libraries-v2-filter-menu/index.jsx#L15-L16
|
||
}; | ||
|
||
const libraryV2TypeSelectedIcon = (itemValue) => (itemValue === itemMenuSelected ? ( | ||
<Icon src={Check} className="ml-2" data-testid="menu-item-icon" /> | ||
) : null); | ||
|
||
useEffect(() => { | ||
if (!isFiltered) { | ||
setItemMenuSelected(defaultItemSelectedText); | ||
} | ||
}, [isFiltered]); | ||
|
||
return ( | ||
<Dropdown id={`dropdown-toggle-${idProp}`}> | ||
<Dropdown.Toggle | ||
alt="dropdown-toggle-menu-items" | ||
id={idProp} | ||
variant="none" | ||
className="dropdown-toggle-menu-items" | ||
data-testid={idProp} | ||
> | ||
{itemMenuSelected} | ||
</Dropdown.Toggle> | ||
<Dropdown.Menu> | ||
{menuItems.map(({ id, name, value }) => ( | ||
<Dropdown.Item | ||
key={id} | ||
onClick={() => handleCourseTypeSelected(name, value)} | ||
Check warning on line 44 in src/studio-home/tabs-section/libraries-v2-tab/libraries-v2-filters/libraries-v2-filter-menu/index.jsx Codecov / codecov/patchsrc/studio-home/tabs-section/libraries-v2-tab/libraries-v2-filters/libraries-v2-filter-menu/index.jsx#L44
|
||
data-testid={`item-menu-${id}`} | ||
> | ||
{name} {libraryV2TypeSelectedIcon(name)} | ||
</Dropdown.Item> | ||
))} | ||
</Dropdown.Menu> | ||
</Dropdown> | ||
); | ||
}; | ||
|
||
LibrariesV2FilterMenu.defaultProps = { | ||
defaultItemSelectedText: '', | ||
menuItems: [], | ||
}; | ||
|
||
LibrariesV2FilterMenu.propTypes = { | ||
onItemMenuSelected: PropTypes.func.isRequired, | ||
defaultItemSelectedText: PropTypes.string, | ||
id: PropTypes.string.isRequired, | ||
menuItems: PropTypes.arrayOf( | ||
PropTypes.shape({ | ||
id: PropTypes.string.isRequired, | ||
name: PropTypes.string.isRequired, | ||
value: PropTypes.string.isRequired, | ||
}), | ||
), | ||
isFiltered: PropTypes.bool.isRequired, | ||
}; | ||
|
||
export default LibrariesV2FilterMenu; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { useMemo } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { useIntl } from '@edx/frontend-platform/i18n'; | ||
|
||
import messages from './messages'; | ||
|
||
import LibrariesV2FilterMenu from '../libraries-v2-filter-menu'; | ||
|
||
const LibrariesV2OrderFilterMenu = ({ onItemMenuSelected, isFiltered }) => { | ||
const intl = useIntl(); | ||
|
||
const libraryV2Orders = useMemo( | ||
() => [ | ||
{ | ||
id: 'az-libraries-v2', | ||
name: intl.formatMessage(messages.librariesV2OrderFilterMenuAscendantLibrariesV2), | ||
value: 'azLibrariesV2', | ||
}, | ||
{ | ||
id: 'za-libraries-v2', | ||
name: intl.formatMessage(messages.librariesV2OrderFilterMenuDescendantLibrariesV2), | ||
value: 'zaLibrariesV2', | ||
}, | ||
{ | ||
id: 'newest-libraries-v2', | ||
name: intl.formatMessage(messages.librariesV2OrderFilterMenuNewestLibrariesV2), | ||
value: 'newestLibrariesV2', | ||
}, | ||
{ | ||
id: 'oldest-libraries-v2', | ||
name: intl.formatMessage(messages.librariesV2OrderFilterMenuOldestLibrariesV2), | ||
value: 'oldestLibrariesV2', | ||
}, | ||
], | ||
[intl], | ||
); | ||
|
||
const handleLibraryV2OrderSelected = (libraryV2Order) => { | ||
onItemMenuSelected(libraryV2Order); | ||
Check warning on line 39 in src/studio-home/tabs-section/libraries-v2-tab/libraries-v2-filters/libraries-v2-order-filter-menu/index.jsx Codecov / codecov/patchsrc/studio-home/tabs-section/libraries-v2-tab/libraries-v2-filters/libraries-v2-order-filter-menu/index.jsx#L39
|
||
}; | ||
|
||
return ( | ||
<LibrariesV2FilterMenu | ||
id="dropdown-toggle-courses-order-menu" | ||
menuItems={libraryV2Orders} | ||
onItemMenuSelected={handleLibraryV2OrderSelected} | ||
defaultItemSelectedText={intl.formatMessage(messages.librariesV2OrderFilterMenuAscendantLibrariesV2)} | ||
isFiltered={isFiltered} | ||
/> | ||
); | ||
}; | ||
|
||
LibrariesV2OrderFilterMenu.propTypes = { | ||
onItemMenuSelected: PropTypes.func.isRequired, | ||
isFiltered: PropTypes.bool.isRequired, | ||
}; | ||
|
||
export default LibrariesV2OrderFilterMenu; |