Skip to content

Commit 7965c98

Browse files
committed
Add pagination'
1 parent e9974ce commit 7965c98

File tree

9 files changed

+352
-5
lines changed

9 files changed

+352
-5
lines changed

pages/blog/[slug].js

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* External Dependencies.
3+
*/
4+
import { isEmpty } from 'lodash';
5+
import { useRouter } from 'next/router';
6+
import axios from 'axios';
7+
8+
/**
9+
* Internal Dependencies.
10+
*/
11+
import Layout from '../../src/components/layout';
12+
import { FALLBACK, handleRedirectsAndReturnData } from '../../src/utils/slug';
13+
import { sanitize } from '../../src/utils/miscellaneous';
14+
import { HEADER_FOOTER_ENDPOINT } from '../../src/utils/constants/endpoints';
15+
import { getPost, getPosts } from '../../src/utils/blog';
16+
17+
const Post = ( { headerFooter, postData } ) => {
18+
const router = useRouter();
19+
20+
console.log( 'postData', postData );
21+
22+
// If the page is not yet generated, this will be displayed
23+
// initially until getStaticProps() finishes running
24+
if ( router.isFallback ) {
25+
return <div>Loading...</div>;
26+
}
27+
28+
return (
29+
<Layout headerFooter={ headerFooter || {} } seo={ null }>
30+
{/*<div dangerouslySetInnerHTML={ { __html: sanitize( data?.post?.content ?? {} ) } }/>*/}
31+
</Layout>
32+
);
33+
};
34+
35+
export default Post;
36+
37+
export async function getStaticProps( { params } ) {
38+
const { data: headerFooterData } = await axios.get( HEADER_FOOTER_ENDPOINT );
39+
const { data: postData } = await getPost( params?.slug ?? '' );
40+
41+
const defaultProps = {
42+
props: {
43+
headerFooter: headerFooterData?.data ?? {},
44+
postData: postData || {}
45+
},
46+
/**
47+
* Revalidate means that if a new request comes to server, then every 1 sec it will check
48+
* if the data is changed, if it is changed then it will update the
49+
* static file inside .next folder with the new data, so that any 'SUBSEQUENT' requests should have updated data.
50+
*/
51+
revalidate: 1,
52+
};
53+
54+
return defaultProps;
55+
56+
// return handleRedirectsAndReturnData( defaultProps, postData, 'post' );
57+
}
58+
59+
/**
60+
* Since the page name 'does not' use catch-all routes,
61+
* for example [slug],
62+
* that's why params would contain just slug and not an array of slugs , unlike [...slug].
63+
* For example, If we need to have dynamic route '/foo/'
64+
* Then we would add paths: [ params: { slug: 'foo' } } ]
65+
* Here slug will be 'foo', then Next.js will statically generate the page at /foo/
66+
*
67+
* At build time next js will make an api call get the data and
68+
* generate a page bar.js inside .next/foo directory, so when the page is served on browser
69+
* data is already present, unlike getInitialProps which gets the page at build time but makes an api
70+
* call after page is served on the browser.
71+
*
72+
* @see https://nextjs.org/docs/basic-features/data-fetching#the-paths-key-required
73+
*
74+
* @returns {Promise<{paths: [], fallback: boolean}>}
75+
*/
76+
export async function getStaticPaths() {
77+
const { data: postsData } = await getPosts();
78+
79+
const pathsData = [];
80+
81+
postsData?.posts_data.length && postsData?.posts_data.map( post => {
82+
if ( ! isEmpty( post?.slug ) ) {
83+
pathsData.push( { params: { slug: post?.slug } } );
84+
}
85+
} );
86+
87+
return {
88+
paths: pathsData,
89+
fallback: FALLBACK,
90+
};
91+
}

pages/blog/index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ import axios from 'axios';
77
* Internal Dependencies.
88
*/
99
import Layout from '../../src/components/layout';
10+
import Posts from '../../src/components/posts';
11+
import Pagination from '../../src/components/pagination';
1012
import { HEADER_FOOTER_ENDPOINT } from '../../src/utils/constants/endpoints';
1113
import { getPosts } from '../../src/utils/blog';
12-
import Posts from '../../src/components/posts';
1314

1415
const Blog = ( { headerFooter, postsData } ) => {
1516
console.log( 'postsData', postsData );
1617
return (
1718
<Layout headerFooter={ headerFooter || {} } seo={null}>
1819
<h1>Blog</h1>
1920
<Posts posts={postsData?.posts_data ?? []}/>
20-
{/*<Pagination pagesCount={postsData?.page_count} postName="blog" />*/}
21+
<Pagination pagesCount={postsData?.page_count} postName="blog" />
2122
</Layout>
2223
);
2324
};

src/components/pagination/index.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import Link from 'next/link';
2+
import PropTypes from 'prop-types';
3+
import { useRouter } from 'next/router';
4+
import { createPaginationLinks } from '../../utils/pagination';
5+
import cx from 'classnames';
6+
import Previous from './previous';
7+
import Next from './next';
8+
9+
const Pagination = ( { pagesCount, postName } ) => {
10+
if ( ! pagesCount || ! postName ) {
11+
return null;
12+
}
13+
14+
const router = useRouter();
15+
const currentPageNo = parseInt( router?.query?.pageNo ) || 1;
16+
17+
const paginationLinks = createPaginationLinks( currentPageNo, pagesCount );
18+
19+
return (
20+
<div className="flex justify-center my-8">
21+
22+
<Previous currentPageNo={ currentPageNo } postName={ postName }/>
23+
24+
{ paginationLinks.map( ( pageNo, index ) => {
25+
26+
const paginationLink = `/${ postName }/page/${ pageNo }/`;
27+
28+
return (
29+
'number' === typeof pageNo ? (
30+
<Link key={ `id-${ index }` } href={ paginationLink }>
31+
<a
32+
className={ cx( 'border border-gray-300 px-3 py-2 transition duration-500 ease-in-out hover:bg-gray-500 hover:text-white', {
33+
'is-active bg-gray-500 text-white': pageNo === currentPageNo,
34+
} ) }
35+
>
36+
{ pageNo }
37+
</a>
38+
</Link>
39+
) : (
40+
// If its "..."
41+
<span key={ `id-${ index }` } className="px-3 py-2">{ pageNo }</span>
42+
)
43+
);
44+
} ) }
45+
<Next currentPageNo={ currentPageNo } pagesCount={ pagesCount } postName={ postName }/>
46+
</div>
47+
);
48+
};
49+
50+
Pagination.propTypes = {
51+
pagesCount: PropTypes.number,
52+
postName: PropTypes.string,
53+
};
54+
55+
Pagination.defaultProps = {
56+
pagesCount: 0,
57+
postName: 'blog',
58+
};
59+
60+
export default Pagination;

src/components/pagination/next.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {isEmpty} from 'lodash';
2+
import Link from 'next/link';
3+
const Next = ( {currentPageNo, pagesCount, postName} ) => {
4+
5+
if ( ! currentPageNo || ! pagesCount || isEmpty( postName ) ) {
6+
return null;
7+
}
8+
9+
// If you are on the last page, dont show next link.
10+
if ( pagesCount < currentPageNo + 1 ) {
11+
return null;
12+
}
13+
14+
const paginationLink = `/${postName}/page/${currentPageNo + 1}/`;
15+
16+
return (
17+
<Link href={paginationLink}>
18+
<a className="border border-gray-300 px-3 py-2 ml-4 transition duration-500 ease-in-out hover:bg-gray-500 hover:text-white">Next</a>
19+
</Link>
20+
);
21+
};
22+
23+
export default Next;

src/components/pagination/previous.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {isEmpty} from 'lodash';
2+
import Link from 'next/link';
3+
4+
const Previous = ( {currentPageNo, postName} ) => {
5+
6+
if ( ! currentPageNo || isEmpty( postName ) ) {
7+
return null;
8+
}
9+
10+
// If you are on the first page, don't show previous link.
11+
if ( 0 === currentPageNo - 1 ) {
12+
return null;
13+
}
14+
15+
const paginationLink = `/${postName}/page/${currentPageNo - 1}/`;
16+
17+
return (
18+
<Link href={paginationLink}>
19+
<a className="border border-gray-300 px-3 py-2 mr-4 transition duration-500 ease-in-out hover:bg-gray-500 hover:text-white">Previous</a>
20+
</Link>
21+
);
22+
};
23+
24+
export default Previous;

src/utils/blog.js

+18-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@ import axios from 'axios';
66
/**
77
* Internal Dependencies.
88
*/
9-
import { GET_POSTS_ENDPOINT } from './constants/endpoints';
9+
import { GET_POST_ENDPOINT, GET_POSTS_ENDPOINT } from './constants/endpoints';
1010

1111
/**
1212
* Get Posts.
1313
*
1414
* @return {Promise<void>}
1515
*/
16-
1716
export const getPosts = async ( pageNo = 1 ) => {
1817
return await axios.get( `${ GET_POSTS_ENDPOINT }?page_no=${ pageNo }` )
1918
.then( res => {
@@ -25,3 +24,20 @@ export const getPosts = async ( pageNo = 1 ) => {
2524
} )
2625
.catch( err => console.log( err.response.data.message ) );
2726
};
27+
28+
/**
29+
* Get Post By Slug.
30+
*
31+
* @return {Promise<void>}
32+
*/
33+
export const getPost = async ( postSlug = '' ) => {
34+
return await axios.get( `${ GET_POST_ENDPOINT }?post_slug=${ postSlug }` )
35+
.then( res => {
36+
if ( 200 === res.data.status ) {
37+
return res;
38+
} else {
39+
return {};
40+
}
41+
} )
42+
.catch( err => console.log( err.response.data.message ) );
43+
};

src/utils/constants/endpoints.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export const HEADER_FOOTER_ENDPOINT = `${ process.env.NEXT_PUBLIC_WORDPRESS_SITE_URL }/wp-json/rae/v1/header-footer?header_location_id=hcms-menu-header&footer_location_id=hcms-menu-footer`;
22
export const GET_POSTS_ENDPOINT = `${process.env.NEXT_PUBLIC_WORDPRESS_SITE_URL}/wp-json/rae/v1/posts`;
3-
export const GET_PRODUCTS_ENDPOINT = `${process.env.NEXT_PUBLIC_SITE_URL}/api/get-products`;
3+
export const GET_POST_ENDPOINT = `${process.env.NEXT_PUBLIC_WORDPRESS_SITE_URL}/wp-json/rae/v1/post`;
44

55
/**
66
* Cart

src/utils/pagination.js

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
export const PER_PAGE_FIRST = 9; // No of posts to be shown on first page.
2+
export const PER_PAGE_REST = 12; // No of posts to be shown following page and after.
3+
4+
export const getPageOffset = ( pageNo ) => {
5+
6+
/**
7+
* Offset is how many posts are already shown ( meaning, after how many posts should we start qurying ).
8+
* @type {number}
9+
*/
10+
let offset = 0;
11+
pageNo = Number( pageNo );
12+
if ( 1 === pageNo ) {
13+
offset = 0;
14+
} else if ( 2 === pageNo ) {
15+
offset = PER_PAGE_FIRST;
16+
} else {
17+
offset = PER_PAGE_FIRST + ( ( pageNo - 2 ) * PER_PAGE_REST );
18+
}
19+
return offset;
20+
};
21+
22+
export const totalPagesCount = ( totalPostsCount ) => {
23+
return Math.ceil( ( totalPostsCount - PER_PAGE_FIRST ) / PER_PAGE_REST + 1 );
24+
};
25+
26+
/**
27+
* Create Pagination Links Array.
28+
*
29+
* Example: [1, "...", 521, 522, 523, 524, 525, "...", 529]
30+
*
31+
* @param {int} currentPage Current page no.
32+
* @param {int} totalPages Count of total no of pages.
33+
*
34+
* @return {Array} Array containing the indexes to be looped through to create pagination
35+
*/
36+
export const createPaginationLinks = ( currentPage, totalPages ) => {
37+
const paginationArray = [];
38+
let countOfDotItems = 0;
39+
40+
// If there is only one page, return an empty array.
41+
if ( ! totalPages && 1 >= totalPages ) {
42+
return paginationArray;
43+
}
44+
45+
/**
46+
* Push the two index items before the current page.
47+
*/
48+
if ( 0 < currentPage - 2 ) {
49+
paginationArray.push( currentPage - 2 );
50+
}
51+
52+
if ( 0 < currentPage - 1 ) {
53+
paginationArray.push( currentPage - 1 );
54+
}
55+
56+
// Push the current page index item.
57+
paginationArray.push( currentPage );
58+
59+
/**
60+
* Push the two index items after the current page.
61+
*/
62+
if ( totalPages >= currentPage + 1 ) {
63+
paginationArray.push( currentPage + 1 );
64+
}
65+
66+
if ( totalPages >= currentPage + 2 ) {
67+
paginationArray.push( currentPage + 2 );
68+
}
69+
70+
/**
71+
* Push the '...' at the beginning of the array
72+
* only if the difference of between the 1st and 2nd index item is greater than 1.
73+
*/
74+
if ( 1 < paginationArray[0] - 1 ) {
75+
paginationArray.unshift( '...' );
76+
countOfDotItems += 1;
77+
}
78+
79+
/**
80+
* Push the '...' at the end of the array.
81+
* only if the difference of between the last and 2nd last item is greater than 2.
82+
* We remove the count of dot items from the array to get the actual indexes, while checking the condition.
83+
*/
84+
if ( 2 < totalPages - paginationArray[paginationArray.length - ( 2 - countOfDotItems )] ) {
85+
paginationArray.push( '...' );
86+
}
87+
88+
// Push first index item in the array if it does not already exists.
89+
if ( -1 === paginationArray.indexOf( 1 ) ) {
90+
paginationArray.unshift( 1 );
91+
}
92+
93+
// Push last index item in the array if it does not already exists.
94+
if ( -1 === paginationArray.indexOf( totalPages ) ) {
95+
paginationArray.push( totalPages );
96+
}
97+
98+
return paginationArray;
99+
};

0 commit comments

Comments
 (0)