Fix broken tag filters in listings (#8086)
This commit is contained in:
parent
58135879c8
commit
eb355a6d4c
13 changed files with 125 additions and 180 deletions
|
|
@ -49,6 +49,7 @@
|
|||
}
|
||||
}
|
||||
.listing-filters-tags {
|
||||
display: flex;
|
||||
padding: 20px 0px;
|
||||
position: relative;
|
||||
input {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { tagPropTypes } from './tag-prop-types';
|
||||
|
||||
export const selectedTagsPropTypes = PropTypes.shape({
|
||||
tags: PropTypes.arrayOf(tagPropTypes).isRequired,
|
||||
tags: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
onKeyPress: PropTypes.func.isRequired,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,20 +3,7 @@ import { deep } from 'preact-render-spy';
|
|||
import ListingFiltersTags from '../components/ListingFiltersTags';
|
||||
|
||||
describe('<ListingFilterTags />', () => {
|
||||
const firstTag = {
|
||||
id: 1,
|
||||
tag: 'clojure',
|
||||
};
|
||||
const secondTag = {
|
||||
id: 2,
|
||||
tag: 'java',
|
||||
};
|
||||
const thirdTag = {
|
||||
id: 3,
|
||||
tag: 'dotnet',
|
||||
};
|
||||
|
||||
const getTags = () => [firstTag, secondTag, thirdTag];
|
||||
const getTags = () => ['clojure', 'java', 'dotnet'];
|
||||
|
||||
const getProps = () => ({
|
||||
message: 'Some message',
|
||||
|
|
@ -78,9 +65,10 @@ describe('<ListingFilterTags />', () => {
|
|||
it('Should render the selected Tags', () => {
|
||||
const context = renderListingFilterTags();
|
||||
getTags().forEach((tag) => {
|
||||
const selectedTag = context.find(`#selected-tag-${tag.id}`);
|
||||
const selectedTag = context.find(`#selected-tag-${tag}`);
|
||||
|
||||
expect(selectedTag.text()).toBe('×');
|
||||
expect(selectedTag.text()).toEqual(expect.stringContaining(tag));
|
||||
expect(selectedTag.text()).toEqual(expect.stringContaining('×'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -3,39 +3,23 @@ import render from 'preact-render-to-json';
|
|||
import ListingFilters from '../components/ListingFilters';
|
||||
|
||||
describe('<ListingFilters />', () => {
|
||||
const firstTag = {
|
||||
id: 1,
|
||||
tag: 'clojure',
|
||||
};
|
||||
const secondTag = {
|
||||
id: 2,
|
||||
tag: 'java',
|
||||
};
|
||||
const thirdTag = {
|
||||
id: 3,
|
||||
tag: 'dotnet',
|
||||
};
|
||||
|
||||
const firstCategory = {
|
||||
id: 20,
|
||||
slug: 'clojure',
|
||||
name: 'Clojure',
|
||||
};
|
||||
|
||||
const secondCategory = {
|
||||
id: 21,
|
||||
slug: 'illa-iara-ques-htyashsayas-6kj8',
|
||||
name: 'Go',
|
||||
};
|
||||
|
||||
const thirdCategory = {
|
||||
id: 22,
|
||||
slug: 'alle-bece-tzehj-htyashsayas-7jh9',
|
||||
name: 'csharp',
|
||||
};
|
||||
|
||||
const getCategories = () => [firstCategory, secondCategory, thirdCategory];
|
||||
const getTags = () => [firstTag, secondTag, thirdTag];
|
||||
const getTags = () => ['clojure', 'java', 'dotnet'];
|
||||
|
||||
const getProps = () => ({
|
||||
category: 'clojure',
|
||||
|
|
@ -4,19 +4,16 @@ import ListingFiltersCategories from '../components/ListingFiltersCategories';
|
|||
|
||||
describe('<ListingFiltersCategories />', () => {
|
||||
const firstCategory = {
|
||||
id: 20,
|
||||
slug: 'clojure',
|
||||
name: 'Clojure',
|
||||
};
|
||||
|
||||
const secondCategory = {
|
||||
id: 21,
|
||||
slug: 'illa-iara-ques-htyashsayas-6kj8',
|
||||
name: 'Go',
|
||||
};
|
||||
|
||||
const thirdCategory = {
|
||||
id: 22,
|
||||
slug: 'alle-bece-tzehj-htyashsayas-7jh9',
|
||||
name: 'csharp',
|
||||
};
|
||||
|
|
@ -76,7 +73,7 @@ describe('<ListingFiltersCategories />', () => {
|
|||
const context = renderListingFilterCategories();
|
||||
it('Should render the categories name and their respective links', () => {
|
||||
categories.forEach((category) => {
|
||||
const categoryLink = context.find(`#category-link-${category.id}`);
|
||||
const categoryLink = context.find(`#category-link-${category.slug}`);
|
||||
expect(categoryLink.attr('href')).toBe(`/listings/${category.slug}`);
|
||||
expect(categoryLink.text()).toBe(category.name);
|
||||
});
|
||||
|
|
@ -85,7 +82,7 @@ describe('<ListingFiltersCategories />', () => {
|
|||
it('Should set the class of the category link as "selected" when category slug matches the selected category name', () => {
|
||||
const selectedCategoryLink = context.find(`.selected`);
|
||||
expect(selectedCategoryLink.attr('id')).toBe(
|
||||
`category-link-${firstCategory.id}`,
|
||||
`category-link-${firstCategory.slug}`,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -95,7 +92,7 @@ describe('<ListingFiltersCategories />', () => {
|
|||
);
|
||||
unselectedCategories.forEach((unselectedCategory) => {
|
||||
const unselectedCategoryLink = context.find(
|
||||
`#category-link-${unselectedCategory.id}`,
|
||||
`#category-link-${unselectedCategory.slug}`,
|
||||
);
|
||||
expect(unselectedCategoryLink.attr('className')).toBe('');
|
||||
});
|
||||
|
|
@ -2,20 +2,7 @@ import { h } from 'preact';
|
|||
import render from 'preact-render-to-json';
|
||||
import SelectedTags from '../components/SelectedTags';
|
||||
|
||||
const firstTag = {
|
||||
id: 1,
|
||||
tag: 'clojure',
|
||||
};
|
||||
const secondTag = {
|
||||
id: 2,
|
||||
tag: 'java',
|
||||
};
|
||||
const thirdTag = {
|
||||
id: 3,
|
||||
tag: 'dotnet',
|
||||
};
|
||||
|
||||
const tags = [firstTag, secondTag, thirdTag];
|
||||
const tags = ['clojure', 'java', 'dotnet'];
|
||||
const getProps = () => ({
|
||||
tags,
|
||||
onClick: () => {
|
||||
|
|
|
|||
|
|
@ -18,29 +18,26 @@ exports[`<ListingFilters /> Should match the snapshot 1`] = `
|
|||
</a>
|
||||
<section>
|
||||
<a
|
||||
Key={20}
|
||||
class="selected"
|
||||
data-no-instant={true}
|
||||
href="/listings/clojure"
|
||||
id="category-link-20"
|
||||
id="category-link-clojure"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Clojure
|
||||
</a>
|
||||
<a
|
||||
Key={21}
|
||||
data-no-instant={true}
|
||||
href="/listings/illa-iara-ques-htyashsayas-6kj8"
|
||||
id="category-link-21"
|
||||
id="category-link-illa-iara-ques-htyashsayas-6kj8"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Go
|
||||
</a>
|
||||
<a
|
||||
Key={22}
|
||||
data-no-instant={true}
|
||||
href="/listings/alle-bece-tzehj-htyashsayas-7jh9"
|
||||
id="category-link-22"
|
||||
id="category-link-alle-bece-tzehj-htyashsayas-7jh9"
|
||||
onClick={[Function]}
|
||||
>
|
||||
csharp
|
||||
|
|
@ -84,83 +81,77 @@ exports[`<ListingFilters /> Should match the snapshot 1`] = `
|
|||
<section>
|
||||
<span
|
||||
class="listing-tag"
|
||||
id="selected-tag-1"
|
||||
id="selected-tag-clojure"
|
||||
>
|
||||
<a
|
||||
class="tag-name"
|
||||
data-no-instant={true}
|
||||
href="/listings?tags="
|
||||
onClick={[Function]}
|
||||
href="/listings?t=clojure"
|
||||
>
|
||||
<span>
|
||||
Object {
|
||||
"id": 1,
|
||||
"tag": "clojure",
|
||||
}
|
||||
<span
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
clojure
|
||||
</span>
|
||||
<button
|
||||
class="tag-close"
|
||||
data-no-instant={true}
|
||||
<span
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
t={true}
|
||||
type="button"
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
<span
|
||||
class="listing-tag"
|
||||
id="selected-tag-2"
|
||||
id="selected-tag-java"
|
||||
>
|
||||
<a
|
||||
class="tag-name"
|
||||
data-no-instant={true}
|
||||
href="/listings?tags="
|
||||
onClick={[Function]}
|
||||
href="/listings?t=java"
|
||||
>
|
||||
<span>
|
||||
Object {
|
||||
"id": 2,
|
||||
"tag": "java",
|
||||
}
|
||||
<span
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
java
|
||||
</span>
|
||||
<button
|
||||
class="tag-close"
|
||||
data-no-instant={true}
|
||||
<span
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
t={true}
|
||||
type="button"
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
<span
|
||||
class="listing-tag"
|
||||
id="selected-tag-3"
|
||||
id="selected-tag-dotnet"
|
||||
>
|
||||
<a
|
||||
class="tag-name"
|
||||
data-no-instant={true}
|
||||
href="/listings?tags="
|
||||
onClick={[Function]}
|
||||
href="/listings?t=dotnet"
|
||||
>
|
||||
<span>
|
||||
Object {
|
||||
"id": 3,
|
||||
"tag": "dotnet",
|
||||
}
|
||||
<span
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
dotnet
|
||||
</span>
|
||||
<button
|
||||
class="tag-close"
|
||||
data-no-instant={true}
|
||||
<span
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
t={true}
|
||||
type="button"
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
</section>
|
||||
|
|
@ -4,83 +4,77 @@ exports[`<SelectedTags /> Should render all the tags 1`] = `
|
|||
<section>
|
||||
<span
|
||||
class="listing-tag"
|
||||
id="selected-tag-1"
|
||||
id="selected-tag-clojure"
|
||||
>
|
||||
<a
|
||||
class="tag-name"
|
||||
data-no-instant={true}
|
||||
href="/listings?tags="
|
||||
onClick={[Function]}
|
||||
href="/listings?t=clojure"
|
||||
>
|
||||
<span>
|
||||
Object {
|
||||
"id": 1,
|
||||
"tag": "clojure",
|
||||
}
|
||||
<span
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
clojure
|
||||
</span>
|
||||
<button
|
||||
class="tag-close"
|
||||
data-no-instant={true}
|
||||
<span
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
t={true}
|
||||
type="button"
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
<span
|
||||
class="listing-tag"
|
||||
id="selected-tag-2"
|
||||
id="selected-tag-java"
|
||||
>
|
||||
<a
|
||||
class="tag-name"
|
||||
data-no-instant={true}
|
||||
href="/listings?tags="
|
||||
onClick={[Function]}
|
||||
href="/listings?t=java"
|
||||
>
|
||||
<span>
|
||||
Object {
|
||||
"id": 2,
|
||||
"tag": "java",
|
||||
}
|
||||
<span
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
java
|
||||
</span>
|
||||
<button
|
||||
class="tag-close"
|
||||
data-no-instant={true}
|
||||
<span
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
t={true}
|
||||
type="button"
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
<span
|
||||
class="listing-tag"
|
||||
id="selected-tag-3"
|
||||
id="selected-tag-dotnet"
|
||||
>
|
||||
<a
|
||||
class="tag-name"
|
||||
data-no-instant={true}
|
||||
href="/listings?tags="
|
||||
onClick={[Function]}
|
||||
href="/listings?t=dotnet"
|
||||
>
|
||||
<span>
|
||||
Object {
|
||||
"id": 3,
|
||||
"tag": "dotnet",
|
||||
}
|
||||
<span
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
dotnet
|
||||
</span>
|
||||
<button
|
||||
class="tag-close"
|
||||
data-no-instant={true}
|
||||
<span
|
||||
onClick={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
t={true}
|
||||
type="button"
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -7,13 +7,10 @@ const CategoryLinks = ({ categories, onClick, selectedCategory }) => {
|
|||
{categories.map((category) => (
|
||||
<a
|
||||
href={`/listings/${category.slug}`}
|
||||
id={`category-link-${category.id}`}
|
||||
id={`category-link-${category.slug}`}
|
||||
className={category.slug === selectedCategory ? 'selected' : ''}
|
||||
onClick={(e) => {
|
||||
onClick(e, category.slug);
|
||||
}}
|
||||
onClick={(e) => onClick(e, category.slug)}
|
||||
data-no-instant
|
||||
Key={category.id}
|
||||
>
|
||||
{category.name}
|
||||
</a>
|
||||
|
|
@ -23,7 +20,12 @@ const CategoryLinks = ({ categories, onClick, selectedCategory }) => {
|
|||
};
|
||||
|
||||
CategoryLinks.propTypes = {
|
||||
categories: PropTypes.isRequired,
|
||||
categories: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
slug: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
}),
|
||||
).isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
selectedCategory: PropTypes.string.isRequired,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { h } from 'preact';
|
|||
import PropTypes from 'prop-types';
|
||||
import ListingFiltersCategories from './ListingFiltersCategories';
|
||||
import ListingFiltersTags from './ListingFiltersTags';
|
||||
import { tagPropTypes } from '../../common-prop-types';
|
||||
|
||||
const ListingFilters = ({
|
||||
categories,
|
||||
|
|
@ -37,14 +36,17 @@ const ListingFilters = ({
|
|||
};
|
||||
|
||||
ListingFilters.propTypes = {
|
||||
categories: PropTypes.isRequired,
|
||||
category: PropTypes.isRequired,
|
||||
categories: PropTypes.shape({
|
||||
slug: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
category: PropTypes.string.isRequired,
|
||||
onSelectCategory: PropTypes.func.isRequired,
|
||||
message: PropTypes.isRequired,
|
||||
onKeyUp: PropTypes.func.isRequired,
|
||||
onClearQuery: PropTypes.func.isRequired,
|
||||
onRemoveTag: PropTypes.func.isRequired,
|
||||
tags: PropTypes.arrayOf(tagPropTypes).isRequired,
|
||||
tags: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
onKeyPress: PropTypes.func.isRequired,
|
||||
query: PropTypes.string.isRequired,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,9 +36,14 @@ const ListingFiltersCategories = ({ categories, category, onClick }) => (
|
|||
);
|
||||
|
||||
ListingFiltersCategories.propTypes = {
|
||||
categories: PropTypes.isRequired,
|
||||
categories: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
slug: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
}),
|
||||
).isRequired,
|
||||
category: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
category: PropTypes.isRequired,
|
||||
};
|
||||
|
||||
export default ListingFiltersCategories;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { h } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
import { tagPropTypes } from '../../common-prop-types';
|
||||
import ClearQueryButton from './ClearQueryButton';
|
||||
import SelectedTags from './SelectedTags';
|
||||
|
||||
|
|
@ -28,7 +27,11 @@ const ListingFiltersTags = ({
|
|||
{shouldRenderClearQueryButton && (
|
||||
<ClearQueryButton onClick={onClearQuery} />
|
||||
)}
|
||||
<SelectedTags tags={tags} onClick={onRemoveTag} onKeyPress={onKeyPress} />
|
||||
<SelectedTags
|
||||
tags={tags}
|
||||
onRemoveTag={onRemoveTag}
|
||||
onKeyPress={onKeyPress}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -39,7 +42,7 @@ ListingFiltersTags.propTypes = {
|
|||
onClearQuery: PropTypes.func.isRequired,
|
||||
onRemoveTag: PropTypes.func.isRequired,
|
||||
onKeyPress: PropTypes.func.isRequired,
|
||||
tags: PropTypes.arrayOf(tagPropTypes).isRequired,
|
||||
tags: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
query: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,23 @@
|
|||
import { h } from 'preact';
|
||||
import { selectedTagsPropTypes } from '../../common-prop-types';
|
||||
|
||||
const SelectedTags = ({ tags, onClick, onKeyPress }) => {
|
||||
const SelectedTags = ({ tags, onRemoveTag, onKeyPress }) => {
|
||||
return (
|
||||
<section>
|
||||
{tags.map((tag) => (
|
||||
<span
|
||||
className="listing-tag"
|
||||
key={tag.id}
|
||||
id={`selected-tag-${tag.id}`}
|
||||
>
|
||||
<a
|
||||
href="/listings?tags="
|
||||
className="tag-name"
|
||||
onClick={onClick}
|
||||
data-no-instant
|
||||
>
|
||||
<span>{tag}</span>
|
||||
<button
|
||||
className="tag-close"
|
||||
t
|
||||
type="button"
|
||||
data-no-instant
|
||||
onKeyPress={onKeyPress}
|
||||
<span className="listing-tag" key={tag.id} id={`selected-tag-${tag}`}>
|
||||
<a href={`/listings?t=${tag}`} className="tag-name" data-no-instant>
|
||||
<span role="button" tabIndex="0">
|
||||
{tag}
|
||||
</span>
|
||||
<span
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
onClick={(e) => onRemoveTag(e, tag)}
|
||||
onKeyPress={(e) => onKeyPress(e, tag)}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
))}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue