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 styled from 'styled-components';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
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 = ({
possibleCollections,
possibleCategories,
@ -35,7 +40,7 @@ const NpmPackagesFilters = ({
return (
<>
<Box paddingTop={1} paddingBottom={1}>
<Button
<ButtonToggle
variant="tertiary"
ref={buttonRef}
startIcon={<Filter />}
@ -43,7 +48,7 @@ const NpmPackagesFilters = ({
size="S"
>
{formatMessage({ id: 'app.utils.filters', defaultMessage: 'Filters' })}
</Button>
</ButtonToggle>
{isVisible && (
<FiltersPopover
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 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)`
list-style-type: none;
`;
const SelectWrapper = styled(Box)`
font-weight: ${({ theme }) => theme.fontWeights.semiBold};
const SortToggleButton = styled(Button)`
svg {
width: ${({ theme }) => theme.spaces[2]};
height: ${({ theme }) => theme.spaces[1]};
}
svg > path {
fill: ${({ theme }) => theme.colors.neutral500};
span {
font-size: ${({ theme }) => theme.fontSizes[1]};
}
`;
const SortSelect = ({ sortQuery, setQuery, setTabQuery, npmPackageType }) => {
const { formatMessage } = useIntl();
const buttonRef = useRef();
const [isVisible, setIsVisible] = useState(false);
const sortTypes = {
'name:asc': {
selected: {
id: 'admin.pages.MarketPlacePage.sort.alphabetical.selected',
defaultMessage: 'Sort by alphabetical order',
},
option: {
id: 'admin.pages.MarketPlacePage.sort.alphabetical',
defaultMessage: 'Alphabetical order',
},
},
'submissionDate:desc': {
selected: {
id: 'admin.pages.MarketPlacePage.sort.newest.selected',
defaultMessage: 'Sort by newest',
},
option: {
id: 'admin.pages.MarketPlacePage.sort.newest',
defaultMessage: 'Newest',
},
},
};
const handleToggle = () => setIsVisible((prev) => !prev);
const handleBlur = (e) => {
e.preventDefault();
if (!e.currentTarget.contains(e.relatedTarget)) {
setIsVisible(false);
}
};
const handleSortClick = (sortName) => {
return (
<SelectWrapper>
<Select
size="S"
id="sort-by-select"
value={sortQuery}
customizeContent={() => formatMessage(sortTypes[sortQuery].selected)}
onChange={(sortName) => {
setQuery({ sort: sortName });
setTabQuery((prev) => ({
...prev,
[npmPackageType]: { ...prev[npmPackageType], sort: sortName, npmPackageType },
}));
handleToggle();
};
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;
};
}}
>
{Object.entries(sortTypes).map(([sortName, messages]) => {
return (
<>
<SortToggleButton
aria-label={computeSortMessage(sortQuery)}
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>
<Option key={sortName} value={sortName}>
{formatMessage(messages.option)}
</Option>
);
})}
</FocusTrap>
</Popover>
)}
</>
</Select>
</SelectWrapper>
);
};
SortSelect.defaultProps = {
sortQuery: undefined,
};
SortSelect.propTypes = {
sortQuery: PropTypes.string.isRequired,
setQuery: PropTypes.func.isRequired,
setTabQuery: PropTypes.func.isRequired,
sortQuery: PropTypes.string,
npmPackageType: PropTypes.string.isRequired,
};

View File

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

View File

@ -287,7 +287,7 @@ describe('Marketplace page', () => {
it('shows the correct options on sort select', () => {
render(App);
const sortButton = screen.getByRole('button', { name: /Sort by/i });
fireEvent.click(sortButton);
fireEvent.mouseDown(sortButton);
const alphabeticalOption = screen.getByRole('option', { name: 'Alphabetical order' });
const newestOption = screen.getByRole('option', { name: 'Newest' });
@ -296,10 +296,11 @@ describe('Marketplace page', () => {
expect(newestOption).toBeVisible();
});
it('sort by newest changes the url on click', () => {
it('changes the url on sort option select', () => {
render(App);
const sortButton = screen.getByRole('button', { name: /Sort by/i });
fireEvent.click(sortButton);
fireEvent.mouseDown(sortButton);
const newestOption = screen.getByRole('option', { name: 'Newest' });
fireEvent.click(newestOption);
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.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.sort.sortBy": "Sort by",
"admin.pages.MarketPlacePage.sort.alphabetical": "Alphabetical order",
"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.collectionsSelected": "{count, plural, =0 {No collections} one {# collection} other {# collections}} selected",
"admin.pages.MarketPlacePage.filters.categories": "Categories",