Skip to content

Commit

Permalink
refactor: Zmiana systemu paginacji (#153)
Browse files Browse the repository at this point in the history
* in progress - simplify pagination

* new buttons and props

* sitemap generation with new pagination

* refactor, delete unused encodings

* fix: last PR errors fixed

Co-authored-by: Michał Miszczyszyn <michal@mmiszy.pl>
  • Loading branch information
lukaszwisniewski88 and typeofweb committed Jun 7, 2021
1 parent 2bcff95 commit 42ec248
Show file tree
Hide file tree
Showing 15 changed files with 134 additions and 165 deletions.
118 changes: 28 additions & 90 deletions api-helpers/articles.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,18 @@
import type { PrismaClient } from '@prisma/client';

import { isIsoDate } from '../utils/date-utils';
import {
LIST_ARTICLES_PER_PAGE,
TILES_ARTICLES_PER_BLOG,
TILES_BLOGS_PER_PAGE,
} from '../constants';

import { cursorToText, textToCursor } from './cursor-encoding';
import { HTTPNotFound } from './errors';

export const TILES_BLOGS_PER_PAGE = 4;
export const TILES_ARTICLES_PER_BLOG = 5;
export const LIST_ARTICLES_PER_PAGE = 20;

function last<T extends readonly R[], R>(arr: readonly [R, ...T]): R;
function last<T>(arr: readonly T[]): T | undefined;
function last<T>(arr: readonly T[]): T | undefined {
return arr[arr.length - 1];
}

export const getArticlesForGrid = async (prisma: PrismaClient, cursor?: string) => {
const date = cursor && cursorToText(cursor);

if (date && !isIsoDate(date)) {
throw new HTTPNotFound();
}

const where = date
? {
lastArticlePublishedAt: {
lt: date,
not: null,
},
}
: {};

export const getArticlesForGrid = async (prisma: PrismaClient, page: number) => {
const pageNumber = reversePageNumber(page, await getLastBlogPage(prisma));
const blogs = await prisma.blog.findMany({
where: { ...where, isPublic: true },
where: { isPublic: true },
skip: pageNumber * TILES_BLOGS_PER_PAGE,
take: TILES_BLOGS_PER_PAGE,
orderBy: {
lastArticlePublishedAt: 'desc',
Expand All @@ -46,52 +26,34 @@ export const getArticlesForGrid = async (prisma: PrismaClient, cursor?: string)
},
},
});
if (blogs.length === 0) throw new HTTPNotFound();

const lastBlog = last(blogs);
return {
data: blogs,
nextCursor:
lastBlog?.lastArticlePublishedAt &&
textToCursor(lastBlog?.lastArticlePublishedAt.toISOString()),
};
};

export const getArticlesPaginationForGrid = async (prisma: PrismaClient) => {
const blogs = (await prisma.blog.findMany({
where: { isPublic: true, lastArticlePublishedAt: { not: null } },
orderBy: {
lastArticlePublishedAt: 'desc',
},
select: {
lastArticlePublishedAt: true,
},
})) as ReadonlyArray<{ readonly lastArticlePublishedAt: Date }>;

const cursors = blogs.flatMap((blog, index) => {
if (index % TILES_BLOGS_PER_PAGE === TILES_BLOGS_PER_PAGE - 1) {
return [textToCursor(blog.lastArticlePublishedAt.toISOString())];
}
return [];
export const getLastArticlePage = async (prisma: PrismaClient) => {
const articlesCount = await prisma.article.count({
where: { blog: { isPublic: true } },
});
return cursors;
return Math.ceil(articlesCount / LIST_ARTICLES_PER_PAGE);
};

export const getArticlesForList = async (prisma: PrismaClient, cursor?: string) => {
const date = cursor && cursorToText(cursor);

if (date && !isIsoDate(date)) {
throw new HTTPNotFound();
}

const where = date
? {
publishedAt: {
lt: date,
},
}
: {};
export const getLastBlogPage = async (prisma: PrismaClient) => {
const blogCount = await prisma.blog.count({
where: { isPublic: true, lastArticlePublishedAt: { not: null } },
});
return Math.ceil(blogCount / TILES_BLOGS_PER_PAGE);
};
const reversePageNumber = (page: number, lastPage: number): number => {
return lastPage - page;
};
export const getArticlesForList = async (prisma: PrismaClient, page: number) => {
const pageNumber = reversePageNumber(page, await getLastArticlePage(prisma));
const articles = await prisma.article.findMany({
where: { ...where, blog: { isPublic: true } },
skip: pageNumber * LIST_ARTICLES_PER_PAGE,
where: { blog: { isPublic: true } },
take: LIST_ARTICLES_PER_PAGE,
orderBy: {
publishedAt: 'desc',
Expand All @@ -100,36 +62,12 @@ export const getArticlesForList = async (prisma: PrismaClient, cursor?: string)
blog: true,
},
});

const lastArticle = last(articles);
if (articles.length === 0) throw new HTTPNotFound();
return {
data: articles,
nextCursor: lastArticle?.publishedAt && textToCursor(lastArticle?.publishedAt.toISOString()),
};
};

export const getArticlesPaginationForList = async (prisma: PrismaClient) => {
const articles = await prisma.article.findMany({
where: {
blog: { isPublic: true },
},
orderBy: {
publishedAt: 'desc',
},
select: {
publishedAt: true,
},
});

const cursors = articles.flatMap((article, index) => {
if (index % LIST_ARTICLES_PER_PAGE === LIST_ARTICLES_PER_PAGE - 1) {
return [textToCursor(article.publishedAt.toISOString())];
}
return [];
});
return cursors;
};

export const getArticlesSlugs = async (prisma: PrismaClient, limit?: number) => {
const articles = await prisma.article.findMany({
where: {
Expand Down
26 changes: 0 additions & 26 deletions api-helpers/cursor-encoding.ts

This file was deleted.

24 changes: 12 additions & 12 deletions api-helpers/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import type { PrismaClient } from '@prisma/client';

import {
getArticlesPaginationForGrid,
getArticlesPaginationForList,
getArticlesSlugs,
} from './articles';
import { getPagesArray } from '../utils/array-utils';

import { getLastArticlePage, getLastBlogPage, getArticlesSlugs } from './articles';

type Item = {
readonly path: string;
Expand All @@ -22,25 +20,27 @@ const staticItems: readonly Item[] = [
];

export async function getSitemap(prisma: PrismaClient) {
const [gridCursors, listCursors, articleSlugs] = await Promise.all([
getArticlesPaginationForGrid(prisma),
getArticlesPaginationForList(prisma),
const [gridLastPage, listLastPage, articleSlugs] = await Promise.all([
getLastBlogPage(prisma),
getLastArticlePage(prisma),
getArticlesSlugs(prisma),
]);
const gridPages = getPagesArray(gridLastPage);
const listPages = getPagesArray(listLastPage);

const dynamicItems: readonly Item[] = [
...articleSlugs.map(({ slug }) => ({
path: `/artykuly/${slug}`,
changefreq: 'monthly' as const,
priority: 0.5,
})),
...gridCursors.map((cursor) => ({
path: `/grid/${cursor}`,
...gridPages.map((page) => ({
path: `/grid/${page}`,
changefreq: 'hourly' as const,
priority: 0.4,
})),
...listCursors.map((cursor) => ({
path: `/list/${cursor}`,
...listPages.map((page) => ({
path: `/list/${page}`,
changefreq: 'hourly' as const,
priority: 0.4,
})),
Expand Down
2 changes: 1 addition & 1 deletion components/Main/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import dynamic from 'next/dynamic';
import { memo, useState } from 'react';

import type { HomePageProps } from '../../pages/[displayStyle]/[cursor]';
import type { HomePageProps } from '../../pages/[displayStyle]/[page]';
import type { AlgoliaSearchProps, SearchState } from '../AlgoliaSearch/AlgoliaSearch';
import { MainTiles } from '../MainTiles/MainTiles';

Expand Down
2 changes: 1 addition & 1 deletion components/MainTiles/BlogsGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import clsx from 'clsx';
import { memo } from 'react';

import type { HomePageProps } from '../../pages/[displayStyle]/[cursor]';
import type { HomePageProps } from '../../pages/[displayStyle]/[page]';
import { ArticleTile } from '../ArticleTile/ArticleTile';

import styles from './blogsGrid.module.scss';
Expand Down
2 changes: 1 addition & 1 deletion components/MainTiles/BlogsList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { memo } from 'react';

import type { HomePageProps } from '../../pages/[displayStyle]/[cursor]';
import type { HomePageProps } from '../../pages/[displayStyle]/[page]';
import { ArticleTile } from '../ArticleTile/ArticleTile';

import styles from './blogsList.module.scss';
Expand Down
28 changes: 25 additions & 3 deletions components/MainTiles/MainTiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useCallback, memo } from 'react';
import { useDidMount } from '../../hooks/useDidMount';
import type { DisplayPreferences } from '../../hooks/useDisplayPreferences';
import { useDisplayPreferences } from '../../hooks/useDisplayPreferences';
import type { HomePageProps } from '../../pages/[displayStyle]/[cursor]';
import type { HomePageProps } from '../../pages/[displayStyle]/[page]';
import { Button } from '../Button/Button';
import { DisplayStyleSwitch } from '../DisplayStyleSwitch/DisplayStyleSwitch';

Expand All @@ -26,6 +26,9 @@ export const MainTiles = memo<MainTilesProps>((props) => {
},
[changeDisplay],
);
const nextPage = Number(props.pageNumber) - 1;
const previousPage = Number(props.pageNumber) + 1;
const isFirstPage = Number(props.pageNumber) === 1;

useDidMount(() => {
void router.prefetch(`/grid`);
Expand All @@ -49,8 +52,27 @@ export const MainTiles = memo<MainTilesProps>((props) => {
<BlogsGrid blogs={props.blogs} />
)}
<div className={styles.pagination}>
{props.nextCursor && (
<Link passHref href={`/${props.displayStyle}/${props.nextCursor}`}>
{!props.isLastPage && (
<>
<Link passHref href={`/${props.displayStyle}/${previousPage}`}>
<Button
className={styles.nextPageButton}
as="a"
iconPosition="left"
icon="icon-arrow-left2"
>
Poprzednia strona
</Button>
</Link>
<Link passHref href={`/${props.displayStyle}`}>
<Button className={styles.nextPageButton} as="a">
Najnowsze
</Button>
</Link>
</>
)}
{!isFirstPage && (
<Link passHref href={`/${props.displayStyle}/${nextPage}`}>
<Button
className={styles.nextPageButton}
as="a"
Expand Down
11 changes: 11 additions & 0 deletions components/MainTiles/mainTiles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,18 @@

.pagination {
display: flex;
flex: 1 0 100%;
flex-direction: column;
justify-content: flex-end;
& > a:only-child {
flex-grow: 0;
}
& > a {
flex-grow: 1;
}
@media screen and (min-width: 45em) {
flex-direction: row;
}
}

.nextPageButton {
Expand Down
8 changes: 8 additions & 0 deletions constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// PAGE [displayStyle]/[page]
export const REVALIDATION_TIME = 15 * 60; // 15 minutes
export const MAX_PAGES = 5;

//api-helpers / articles
export const TILES_BLOGS_PER_PAGE = 4;
export const TILES_ARTICLES_PER_BLOG = 5;
export const LIST_ARTICLES_PER_PAGE = 20;

0 comments on commit 42ec248

Please sign in to comment.