summaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-05-24 16:44:29 +0200
committerArmand Philippot <git@armandphilippot.com>2022-05-24 16:44:29 +0200
commit1e982fb02a9967e0efdc76c93a44798a9f2dcb43 (patch)
treeb9a526ade81feee20cf18404e2a7053ccff6c999 /src/components
parentc347190a4307c172d15dac156da86567098035f6 (diff)
chore: add a search form when posts list prints no results
Diffstat (limited to 'src/components')
-rw-r--r--src/components/organisms/layout/no-results.stories.tsx28
-rw-r--r--src/components/organisms/layout/no-results.test.tsx14
-rw-r--r--src/components/organisms/layout/no-results.tsx38
-rw-r--r--src/components/organisms/layout/posts-list.fixture.tsx2
-rw-r--r--src/components/organisms/layout/posts-list.stories.tsx5
-rw-r--r--src/components/organisms/layout/posts-list.test.tsx29
-rw-r--r--src/components/organisms/layout/posts-list.tsx81
-rw-r--r--src/components/templates/page/page-layout.stories.tsx7
8 files changed, 155 insertions, 49 deletions
diff --git a/src/components/organisms/layout/no-results.stories.tsx b/src/components/organisms/layout/no-results.stories.tsx
new file mode 100644
index 0000000..aa2e51e
--- /dev/null
+++ b/src/components/organisms/layout/no-results.stories.tsx
@@ -0,0 +1,28 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import NoResultsComponent from './no-results';
+
+export default {
+ title: 'Organisms/Layout',
+ component: NoResultsComponent,
+ argTypes: {
+ searchPage: {
+ control: {
+ type: 'text',
+ },
+ description: 'The search results page.',
+ type: {
+ name: 'string',
+ required: true,
+ },
+ },
+ },
+} as ComponentMeta<typeof NoResultsComponent>;
+
+const Template: ComponentStory<typeof NoResultsComponent> = (args) => (
+ <NoResultsComponent {...args} />
+);
+
+export const NoResults = Template.bind({});
+NoResults.args = {
+ searchPage: '#',
+};
diff --git a/src/components/organisms/layout/no-results.test.tsx b/src/components/organisms/layout/no-results.test.tsx
new file mode 100644
index 0000000..7f57177
--- /dev/null
+++ b/src/components/organisms/layout/no-results.test.tsx
@@ -0,0 +1,14 @@
+import { render, screen } from '@test-utils';
+import NoResults from './no-results';
+
+describe('NoResults', () => {
+ it('renders a no results text', () => {
+ render(<NoResults searchPage="#" />);
+ expect(screen.getByText(/No results/gi)).toBeInTheDocument();
+ });
+
+ it('renders a search form', () => {
+ render(<NoResults searchPage="#" />);
+ expect(screen.getByRole('searchbox')).toBeInTheDocument();
+ });
+});
diff --git a/src/components/organisms/layout/no-results.tsx b/src/components/organisms/layout/no-results.tsx
new file mode 100644
index 0000000..2245dbf
--- /dev/null
+++ b/src/components/organisms/layout/no-results.tsx
@@ -0,0 +1,38 @@
+import SearchForm, {
+ type SearchFormProps,
+} from '@components/organisms/forms/search-form';
+import { FC } from 'react';
+import { useIntl } from 'react-intl';
+
+export type NoResultsProps = Pick<SearchFormProps, 'searchPage'>;
+
+/**
+ * NoResults component
+ *
+ * Renders a no results text with a search form.
+ */
+const NoResults: FC<NoResultsProps> = ({ searchPage }) => {
+ const intl = useIntl();
+
+ return (
+ <>
+ <p>
+ {intl.formatMessage({
+ defaultMessage: 'No results found.',
+ description: 'NoResults: no results',
+ id: '5O2vpy',
+ })}
+ </p>
+ <p>
+ {intl.formatMessage({
+ defaultMessage: 'Would you like to try a new search?',
+ description: 'NoResults: try a new search message',
+ id: 'DVBwfu',
+ })}
+ </p>
+ <SearchForm hideLabel={true} searchPage={searchPage} />
+ </>
+ );
+};
+
+export default NoResults;
diff --git a/src/components/organisms/layout/posts-list.fixture.tsx b/src/components/organisms/layout/posts-list.fixture.tsx
index e3f2378..97a746f 100644
--- a/src/components/organisms/layout/posts-list.fixture.tsx
+++ b/src/components/organisms/layout/posts-list.fixture.tsx
@@ -59,3 +59,5 @@ export const posts: Post[] = [
url: '#',
},
];
+
+export const searchPage = '#';
diff --git a/src/components/organisms/layout/posts-list.stories.tsx b/src/components/organisms/layout/posts-list.stories.tsx
index 68e3dc0..bff1f28 100644
--- a/src/components/organisms/layout/posts-list.stories.tsx
+++ b/src/components/organisms/layout/posts-list.stories.tsx
@@ -1,6 +1,6 @@
import { ComponentMeta, ComponentStory } from '@storybook/react';
import PostsList from './posts-list';
-import { posts } from './posts-list.fixture';
+import { posts, searchPage } from './posts-list.fixture';
/**
* PostsList - Storybook Meta
@@ -161,6 +161,7 @@ const Template: ComponentStory<typeof PostsList> = (args) => (
export const Default = Template.bind({});
Default.args = {
posts,
+ searchPage,
total: posts.length,
};
@@ -171,6 +172,7 @@ export const ByYears = Template.bind({});
ByYears.args = {
posts,
byYear: true,
+ searchPage,
total: posts.length,
};
ByYears.decorators = [
@@ -187,5 +189,6 @@ ByYears.decorators = [
export const NoResults = Template.bind({});
NoResults.args = {
posts: [],
+ searchPage,
total: posts.length,
};
diff --git a/src/components/organisms/layout/posts-list.test.tsx b/src/components/organisms/layout/posts-list.test.tsx
index 1bab466..e58a974 100644
--- a/src/components/organisms/layout/posts-list.test.tsx
+++ b/src/components/organisms/layout/posts-list.test.tsx
@@ -1,25 +1,46 @@
import { render, screen } from '@test-utils';
import PostsList from './posts-list';
-import { posts } from './posts-list.fixture';
+import { posts, searchPage } from './posts-list.fixture';
describe('PostsList', () => {
it('renders the correct number of posts', () => {
- render(<PostsList posts={posts} total={posts.length} />);
+ render(
+ <PostsList posts={posts} total={posts.length} searchPage={searchPage} />
+ );
expect(screen.getAllByRole('article')).toHaveLength(posts.length);
});
it('renders the number of loaded posts', () => {
- render(<PostsList posts={posts} total={posts.length} />);
+ render(
+ <PostsList posts={posts} total={posts.length} searchPage={searchPage} />
+ );
const info = `${posts.length} loaded articles out of a total of ${posts.length}`;
expect(screen.getByText(info)).toBeInTheDocument();
});
it('renders a load more button', () => {
render(
- <PostsList posts={posts} total={posts.length} showLoadMoreBtn={true} />
+ <PostsList
+ posts={posts}
+ total={posts.length}
+ showLoadMoreBtn={true}
+ searchPage={searchPage}
+ />
);
expect(
screen.getByRole('button', { name: /Load more/i })
).toBeInTheDocument();
});
+
+ it('renders a search form if no results', () => {
+ render(
+ <PostsList
+ posts={[]}
+ total={0}
+ showLoadMoreBtn={true}
+ searchPage={searchPage}
+ />
+ );
+ expect(screen.getByRole('searchbox')).toBeInTheDocument();
+ });
});
diff --git a/src/components/organisms/layout/posts-list.tsx b/src/components/organisms/layout/posts-list.tsx
index 91fc62d..24869fd 100644
--- a/src/components/organisms/layout/posts-list.tsx
+++ b/src/components/organisms/layout/posts-list.tsx
@@ -9,6 +9,7 @@ import useIsMounted from '@utils/hooks/use-is-mounted';
import useSettings from '@utils/hooks/use-settings';
import { FC, Fragment, useRef } from 'react';
import { useIntl } from 'react-intl';
+import NoResults, { NoResultsProps } from './no-results';
import styles from './posts-list.module.scss';
import Summary, { type SummaryProps } from './summary';
@@ -23,40 +24,41 @@ export type YearCollection = {
[key: string]: Post[];
};
-export type PostsListProps = Pick<PaginationProps, 'baseUrl' | 'siblings'> & {
- /**
- * True to display the posts by year. Default: false.
- */
- byYear?: boolean;
- /**
- * Determine if the data is loading.
- */
- isLoading?: boolean;
- /**
- * Load more button handler.
- */
- loadMore?: () => void;
- /**
- * The current page number. Default: 1.
- */
- pageNumber?: number;
- /**
- * The posts data.
- */
- posts: Post[];
- /**
- * Determine if the load more button should be visible.
- */
- showLoadMoreBtn?: boolean;
- /**
- * The posts heading level (hn).
- */
- titleLevel?: HeadingLevel;
- /**
- * The total posts number.
- */
- total: number;
-};
+export type PostsListProps = Pick<PaginationProps, 'baseUrl' | 'siblings'> &
+ Pick<NoResultsProps, 'searchPage'> & {
+ /**
+ * True to display the posts by year. Default: false.
+ */
+ byYear?: boolean;
+ /**
+ * Determine if the data is loading.
+ */
+ isLoading?: boolean;
+ /**
+ * Load more button handler.
+ */
+ loadMore?: () => void;
+ /**
+ * The current page number. Default: 1.
+ */
+ pageNumber?: number;
+ /**
+ * The posts data.
+ */
+ posts: Post[];
+ /**
+ * Determine if the load more button should be visible.
+ */
+ showLoadMoreBtn?: boolean;
+ /**
+ * The posts heading level (hn).
+ */
+ titleLevel?: HeadingLevel;
+ /**
+ * The total posts number.
+ */
+ total: number;
+ };
/**
* Create a collection of posts sorted by year.
@@ -89,6 +91,7 @@ const PostsList: FC<PostsListProps> = ({
loadMore,
pageNumber = 1,
posts,
+ searchPage,
showLoadMoreBtn = false,
siblings,
titleLevel,
@@ -221,15 +224,7 @@ const PostsList: FC<PostsListProps> = ({
};
if (posts.length === 0) {
- return (
- <p>
- {intl.formatMessage({
- defaultMessage: 'No results found.',
- description: 'PostsList: no results',
- id: 'vK7Sxv',
- })}
- </p>
- );
+ return <NoResults searchPage={searchPage} />;
}
return (
diff --git a/src/components/templates/page/page-layout.stories.tsx b/src/components/templates/page/page-layout.stories.tsx
index 88e3785..06c6c24 100644
--- a/src/components/templates/page/page-layout.stories.tsx
+++ b/src/components/templates/page/page-layout.stories.tsx
@@ -368,7 +368,12 @@ Blog.args = {
headerMeta: { total: posts.length },
children: (
<>
- <PostsList posts={posts} byYear={true} total={posts.length} />
+ <PostsList
+ posts={posts}
+ byYear={true}
+ total={posts.length}
+ searchPage="#"
+ />
</>
),
widgets: [