Merge branch 'market-sort-filters/sort-filter' of github.com:strapi/strapi into market-sort-filters/api-filter-requests

This commit is contained in:
Mark Kaylor 2022-10-21 14:02:40 +02:00
commit f96a07dae2
6 changed files with 912 additions and 622 deletions

View File

@ -1,4 +1,5 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { Box } from '@strapi/design-system/Box'; import { Box } from '@strapi/design-system/Box';
@ -18,6 +19,10 @@ const FilterTag = ({ name, handleRemove }) => {
); );
}; };
const ButtonToggle = styled(Button)`
height: ${({ theme }) => theme.sizes.input.S};
`;
const NpmPackagesFilters = ({ const NpmPackagesFilters = ({
possibleCollections, possibleCollections,
possibleCategories, possibleCategories,
@ -35,7 +40,7 @@ const NpmPackagesFilters = ({
return ( return (
<> <>
<Box paddingTop={1} paddingBottom={1}> <Box paddingTop={1} paddingBottom={1}>
<Button <ButtonToggle
variant="tertiary" variant="tertiary"
ref={buttonRef} ref={buttonRef}
startIcon={<Filter />} startIcon={<Filter />}
@ -43,7 +48,7 @@ const NpmPackagesFilters = ({
size="S" size="S"
> >
{formatMessage({ id: 'app.utils.filters', defaultMessage: 'Filters' })} {formatMessage({ id: 'app.utils.filters', defaultMessage: 'Filters' })}
</Button> </ButtonToggle>
{isVisible && ( {isVisible && (
<FiltersPopover <FiltersPopover
onToggle={handleToggle} onToggle={handleToggle}

View File

@ -1,137 +1,75 @@
import React, { useRef, useState } from 'react'; import React from 'react';
import styled from 'styled-components';
import { Select, Option } from '@strapi/design-system/Select';
import { Box } from '@strapi/design-system/Box';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Option } from '@strapi/design-system/Select';
import { Popover } from '@strapi/design-system/Popover';
import { Button } from '@strapi/design-system/Button';
import { FocusTrap } from '@strapi/design-system/FocusTrap';
import CarretDown from '@strapi/icons/CarretDown';
import styled from 'styled-components';
const SortOption = styled(Option)` const SelectWrapper = styled(Box)`
list-style-type: none; font-weight: ${({ theme }) => theme.fontWeights.semiBold};
`;
const SortToggleButton = styled(Button)` span {
svg { font-size: ${({ theme }) => theme.fontSizes[1]};
width: ${({ theme }) => theme.spaces[2]};
height: ${({ theme }) => theme.spaces[1]};
}
svg > path {
fill: ${({ theme }) => theme.colors.neutral500};
} }
`; `;
const SortSelect = ({ sortQuery, setQuery, setTabQuery, npmPackageType }) => { const SortSelect = ({ sortQuery, setQuery, setTabQuery, npmPackageType }) => {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const buttonRef = useRef();
const [isVisible, setIsVisible] = useState(false);
const sortTypes = { const sortTypes = {
'name:asc': { 'name:asc': {
selected: {
id: 'admin.pages.MarketPlacePage.sort.alphabetical.selected',
defaultMessage: 'Sort by alphabetical order',
},
option: {
id: 'admin.pages.MarketPlacePage.sort.alphabetical', id: 'admin.pages.MarketPlacePage.sort.alphabetical',
defaultMessage: 'Alphabetical order', defaultMessage: 'Alphabetical order',
}, },
},
'submissionDate:desc': { 'submissionDate:desc': {
selected: {
id: 'admin.pages.MarketPlacePage.sort.newest.selected',
defaultMessage: 'Sort by newest',
},
option: {
id: 'admin.pages.MarketPlacePage.sort.newest', id: 'admin.pages.MarketPlacePage.sort.newest',
defaultMessage: 'Newest', defaultMessage: 'Newest',
}, },
},
}; };
const handleToggle = () => setIsVisible((prev) => !prev); return (
<SelectWrapper>
const handleBlur = (e) => { <Select
e.preventDefault(); size="S"
id="sort-by-select"
if (!e.currentTarget.contains(e.relatedTarget)) { value={sortQuery}
setIsVisible(false); customizeContent={() => formatMessage(sortTypes[sortQuery].selected)}
} onChange={(sortName) => {
};
const handleSortClick = (sortName) => {
setQuery({ sort: sortName }); setQuery({ sort: sortName });
setTabQuery((prev) => ({ setTabQuery((prev) => ({
...prev, ...prev,
[npmPackageType]: { ...prev[npmPackageType], sort: sortName, npmPackageType }, [npmPackageType]: { ...prev[npmPackageType], sort: sortName, npmPackageType },
})); }));
handleToggle(); }}
}; >
{Object.entries(sortTypes).map(([sortName, messages]) => {
const computeSortMessage = (sortName) => {
const defaultSortLabel = formatMessage({
id: 'admin.pages.MarketPlacePage.sort.sortBy',
defaultMessage: 'Sort by',
});
if (sortName) {
const sortInfo = sortTypes[sortName];
const message = formatMessage({
id: sortInfo.id,
defaultMessage: sortInfo.defaultMessage,
});
return `${defaultSortLabel}: ${message}`;
}
return defaultSortLabel;
};
return ( return (
<> <Option key={sortName} value={sortName}>
<SortToggleButton {formatMessage(messages.option)}
aria-label={computeSortMessage(sortQuery)} </Option>
aria-controls="sort-by-values"
aria-haspopup="dialog"
aria-expanded={isVisible}
aria-disabled={false}
onClick={handleToggle}
variant="tertiary"
ref={buttonRef}
endIcon={<CarretDown aria-hidden />}
size="S"
>
{computeSortMessage(sortQuery)}
</SortToggleButton>
{isVisible && (
<Popover
role="dialog"
id="sort-by-values"
onBlur={handleBlur}
source={buttonRef}
spacing={4}
>
<FocusTrap onEscape={handleToggle}>
{Object.entries(sortTypes).map(([sortName, sortInfo], index) => {
const { id, defaultMessage } = sortInfo;
return (
<SortOption
key={sortName}
value={sortName}
selected={sortQuery === sortName}
onClick={() => handleSortClick(sortName)}
tabIndex={index}
>
{formatMessage({ id, defaultMessage })}
</SortOption>
); );
})} })}
</FocusTrap> </Select>
</Popover> </SelectWrapper>
)}
</>
); );
}; };
SortSelect.defaultProps = {
sortQuery: undefined,
};
SortSelect.propTypes = { SortSelect.propTypes = {
sortQuery: PropTypes.string.isRequired,
setQuery: PropTypes.func.isRequired, setQuery: PropTypes.func.isRequired,
setTabQuery: PropTypes.func.isRequired, setTabQuery: PropTypes.func.isRequired,
sortQuery: PropTypes.string,
npmPackageType: PropTypes.string.isRequired, npmPackageType: PropTypes.string.isRequired,
}; };

View File

@ -183,7 +183,7 @@ const MarketPlacePage = () => {
} else { } else {
setQuery( setQuery(
{ {
npmPackageType: null, npmPackageType: selectedTab,
// Clear filters // Clear filters
collections: [], collections: [],
categories: [], categories: [],
@ -194,7 +194,6 @@ const MarketPlacePage = () => {
} }
}; };
console.log(tabQuery);
// Check if plugins and providers are installed already // Check if plugins and providers are installed already
const installedPackageNames = Object.keys(dependencies); const installedPackageNames = Object.keys(dependencies);
@ -266,7 +265,7 @@ const MarketPlacePage = () => {
</Box> </Box>
<Flex paddingBottom={4} gap={2}> <Flex paddingBottom={4} gap={2}>
<SortSelect <SortSelect
sortQuery={query?.sort} sortQuery={query?.sort || 'name:asc'}
setQuery={setQuery} setQuery={setQuery}
setTabQuery={setTabQuery} setTabQuery={setTabQuery}
npmPackageType={npmPackageType} npmPackageType={npmPackageType}

View File

@ -287,7 +287,7 @@ describe('Marketplace page', () => {
it('shows the correct options on sort select', () => { it('shows the correct options on sort select', () => {
render(App); render(App);
const sortButton = screen.getByRole('button', { name: /Sort by/i }); const sortButton = screen.getByRole('button', { name: /Sort by/i });
fireEvent.click(sortButton); fireEvent.mouseDown(sortButton);
const alphabeticalOption = screen.getByRole('option', { name: 'Alphabetical order' }); const alphabeticalOption = screen.getByRole('option', { name: 'Alphabetical order' });
const newestOption = screen.getByRole('option', { name: 'Newest' }); const newestOption = screen.getByRole('option', { name: 'Newest' });
@ -296,10 +296,11 @@ describe('Marketplace page', () => {
expect(newestOption).toBeVisible(); expect(newestOption).toBeVisible();
}); });
it('sort by newest changes the url on click', () => { it('changes the url on sort option select', () => {
render(App); render(App);
const sortButton = screen.getByRole('button', { name: /Sort by/i }); const sortButton = screen.getByRole('button', { name: /Sort by/i });
fireEvent.click(sortButton); fireEvent.mouseDown(sortButton);
const newestOption = screen.getByRole('option', { name: 'Newest' }); const newestOption = screen.getByRole('option', { name: 'Newest' });
fireEvent.click(newestOption); fireEvent.click(newestOption);
expect(history.location.search).toEqual('?npmPackageType=provider&sort=submissionDate:desc'); expect(history.location.search).toEqual('?npmPackageType=provider&sort=submissionDate:desc');

View File

@ -280,9 +280,10 @@
"admin.pages.MarketPlacePage.tab-group.label": "Plugins and Providers for Strapi", "admin.pages.MarketPlacePage.tab-group.label": "Plugins and Providers for Strapi",
"admin.pages.MarketPlacePage.missingPlugin.title": "Missing a plugin?", "admin.pages.MarketPlacePage.missingPlugin.title": "Missing a plugin?",
"admin.pages.MarketPlacePage.missingPlugin.description": "Tell us what plugin you are looking for and we'll let our community plugin developers know in case they are in search for inspiration!", "admin.pages.MarketPlacePage.missingPlugin.description": "Tell us what plugin you are looking for and we'll let our community plugin developers know in case they are in search for inspiration!",
"admin.pages.MarketPlacePage.sort.sortBy": "Sort by",
"admin.pages.MarketPlacePage.sort.alphabetical": "Alphabetical order", "admin.pages.MarketPlacePage.sort.alphabetical": "Alphabetical order",
"admin.pages.MarketPlacePage.sort.newest": "Newest", "admin.pages.MarketPlacePage.sort.newest": "Newest",
"admin.pages.MarketPlacePage.sort.alphabetical.selected": "Sort by alphabetical order",
"admin.pages.MarketPlacePage.sort.newest.selected": "Sort by newest",
"admin.pages.MarketPlacePage.filters.collections": "Collections", "admin.pages.MarketPlacePage.filters.collections": "Collections",
"admin.pages.MarketPlacePage.filters.collectionsSelected": "{count, plural, =0 {No collections} one {# collection} other {# collections}} selected", "admin.pages.MarketPlacePage.filters.collectionsSelected": "{count, plural, =0 {No collections} one {# collection} other {# collections}} selected",
"admin.pages.MarketPlacePage.filters.categories": "Categories", "admin.pages.MarketPlacePage.filters.categories": "Categories",