mirror of
https://github.com/strapi/strapi.git
synced 2025-09-18 13:02:18 +00:00
Merge branch 'market-sort-filters/sort-filter' of github.com:strapi/strapi into market-sort-filters/api-filter-requests
This commit is contained in:
commit
f96a07dae2
@ -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}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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');
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user