From 43a34f2b17b323945b08d34233d22c195c68d448 Mon Sep 17 00:00:00 2001 From: Cybervoid Date: Mon, 23 Dec 2024 13:54:45 +0100 Subject: [PATCH 1/4] feat: enhance category page static params generation with barometer count and sorting options --- app/collection/categories/[category]/page.tsx | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/app/collection/categories/[category]/page.tsx b/app/collection/categories/[category]/page.tsx index 76b02756..4365c44c 100644 --- a/app/collection/categories/[category]/page.tsx +++ b/app/collection/categories/[category]/page.tsx @@ -4,7 +4,7 @@ import { Container, Grid, GridCol, Stack, Title } from '@mantine/core' import { barometerRoute, googleStorageImagesFolder, barometerTypesRoute } from '@/app/constants' import { BarometerCard } from './components/barometer-card' import { slug } from '@/utils/misc' -import { SortValue } from './types' +import { SortValue, SortOptions } from './types' import Sort from './sort' import { DescriptionText } from '@/app/components/description-text' import { title, openGraph, twitter } from '@/app/metadata' @@ -13,14 +13,15 @@ import { withPrisma } from '@/prisma/prismaClient' import { getCategory } from '@/app/api/v2/categories/[name]/getters' import { getBarometersByParams } from '@/app/api/v2/barometers/getters' +interface SearchParams { + sort?: SortValue + page?: string +} interface CollectionProps { params: { category: string } - searchParams: { - sort?: SortValue - page?: string - } + searchParams: SearchParams } const PAGE_SIZE = 12 @@ -89,9 +90,31 @@ export default async function Collection({ params: { category }, searchParams }: ) } +export const dynamicParams = true export const generateStaticParams = withPrisma(async prisma => { - const categories = await prisma.category.findMany({ select: { name: true } }) - return categories.map(({ name }) => ({ - category: name.toLowerCase(), - })) + const categories = await prisma.category.findMany({ select: { name: true, id: true } }) + const categoriesWithCount = await prisma.barometer.groupBy({ + by: ['categoryId'], + _count: { + _all: true, + }, + }) + const params: { category: string; searchParams: SearchParams }[] = [] + + for (const { name, id } of categories) { + const categoryData = categoriesWithCount.find(({ categoryId }) => categoryId === id) + const barometersPerCategory = categoryData?._count._all ?? 0 + console.log('🚀 ~ generateStaticParams ~ barometersPerCategory:', name, barometersPerCategory) + const pagesPerCategory = Math.ceil(barometersPerCategory / PAGE_SIZE) + for (const { value: sort } of SortOptions) { + for (let page = 1; page <= pagesPerCategory; page += 1) { + params.push({ + category: name.toLowerCase(), + searchParams: { sort, page: String(page) }, + }) + } + } + } + console.log('🚀 ~ generateStaticParams ~ params:', params.length) + return params }) From 25cbc64a3d818aa465195e15313e2cd4bb28f72c Mon Sep 17 00:00:00 2001 From: Cybervoid Date: Wed, 25 Dec 2024 12:35:42 +0100 Subject: [PATCH 2/4] refactor: simplify Collection component by removing unused searchParams and updating props structure --- app/collection/categories/[category]/page.tsx | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/app/collection/categories/[category]/page.tsx b/app/collection/categories/[category]/page.tsx index 4365c44c..76dc570d 100644 --- a/app/collection/categories/[category]/page.tsx +++ b/app/collection/categories/[category]/page.tsx @@ -13,15 +13,17 @@ import { withPrisma } from '@/prisma/prismaClient' import { getCategory } from '@/app/api/v2/categories/[name]/getters' import { getBarometersByParams } from '@/app/api/v2/barometers/getters' -interface SearchParams { +/* interface SearchParams { sort?: SortValue page?: string -} +} */ interface CollectionProps { params: { category: string + sort: SortValue + page: number } - searchParams: SearchParams + //searchParams: SearchParams } const PAGE_SIZE = 12 @@ -58,10 +60,14 @@ export async function generateMetadata({ } } -export default async function Collection({ params: { category }, searchParams }: CollectionProps) { - const sort = searchParams.sort ?? 'date' - const page = searchParams.page ?? '1' - const { barometers, totalPages } = await getBarometersByParams(category, +page, PAGE_SIZE, sort) +export default async function Collection({ + params: { category, page, sort } /* , searchParams */, +}: CollectionProps) { + console.log('🚀 ~ category, page, sort:', category, page, sort) + + /* const sort = searchParams.sort ?? 'date' + const page = searchParams.page ?? '1' */ + const { barometers, totalPages } = await getBarometersByParams(category, page, PAGE_SIZE, sort) const { description } = await getCategory(category) return ( @@ -99,7 +105,7 @@ export const generateStaticParams = withPrisma(async prisma => { _all: true, }, }) - const params: { category: string; searchParams: SearchParams }[] = [] + const params: CollectionProps['params'][] = [] for (const { name, id } of categories) { const categoryData = categoriesWithCount.find(({ categoryId }) => categoryId === id) @@ -110,11 +116,12 @@ export const generateStaticParams = withPrisma(async prisma => { for (let page = 1; page <= pagesPerCategory; page += 1) { params.push({ category: name.toLowerCase(), - searchParams: { sort, page: String(page) }, + sort, + page, }) } } } - console.log('🚀 ~ generateStaticParams ~ params:', params.length) - return params + console.log('🚀 ~ generateStaticParams ~ params:', params) + return params.slice(0, 1) }) From 9038caf548934d7b3e2192d3beb9d25ed2e5599c Mon Sep 17 00:00:00 2001 From: Cybervoid Date: Thu, 26 Dec 2024 11:50:59 +0100 Subject: [PATCH 3/4] refactor: reorganize pagination components and update sorting logic --- app/api/v2/barometers/getters.ts | 2 +- app/api/v2/barometers/route.ts | 2 +- .../barometer-card/barometer-card.tsx | 0 .../components/barometer-card/index.ts | 0 .../barometer-card/styles.module.scss | 0 .../{[category] => [...category]}/page.tsx | 59 +++++++++---------- .../categories/[...category]/pagination.tsx | 24 ++++++++ .../{[category] => [...category]}/sort.tsx | 6 +- .../{[category] => [...category]}/types.ts | 0 .../items/[slug]/components/breadcrumbs.tsx | 4 +- app/components/header/tabs/tabs.tsx | 8 +-- app/components/pagination/index.ts | 1 - app/constants.ts | 2 + app/page.tsx | 4 +- app/search/page.tsx | 2 +- .../pagination => search}/pagination.tsx | 11 ++-- theme.ts | 12 ++++ utils/fetch.ts | 2 +- 18 files changed, 85 insertions(+), 54 deletions(-) rename app/collection/categories/{[category] => [...category]}/components/barometer-card/barometer-card.tsx (100%) rename app/collection/categories/{[category] => [...category]}/components/barometer-card/index.ts (100%) rename app/collection/categories/{[category] => [...category]}/components/barometer-card/styles.module.scss (100%) rename app/collection/categories/{[category] => [...category]}/page.tsx (71%) create mode 100644 app/collection/categories/[...category]/pagination.tsx rename app/collection/categories/{[category] => [...category]}/sort.tsx (77%) rename app/collection/categories/{[category] => [...category]}/types.ts (100%) delete mode 100644 app/components/pagination/index.ts rename app/{components/pagination => search}/pagination.tsx (64%) diff --git a/app/api/v2/barometers/getters.ts b/app/api/v2/barometers/getters.ts index 9a20f732..ee717ae6 100644 --- a/app/api/v2/barometers/getters.ts +++ b/app/api/v2/barometers/getters.ts @@ -1,5 +1,5 @@ import { type Prisma } from '@prisma/client' -import { SortValue } from '@/app/collection/categories/[category]/types' +import { SortValue } from '@/app/collection/categories/[...category]/types' import { withPrisma } from '@/prisma/prismaClient' function getSortCriteria( diff --git a/app/api/v2/barometers/route.ts b/app/api/v2/barometers/route.ts index 745a0f8f..11b0d554 100644 --- a/app/api/v2/barometers/route.ts +++ b/app/api/v2/barometers/route.ts @@ -3,7 +3,7 @@ import { revalidatePath } from 'next/cache' import { Prisma } from '@prisma/client' import { withPrisma } from '@/prisma/prismaClient' import { cleanObject, slug as slugify } from '@/utils/misc' -import { type SortValue } from '@/app/collection/categories/[category]/types' +import { type SortValue } from '@/app/collection/categories/[...category]/types' import { DEFAULT_PAGE_SIZE } from '../parameters' import { getAllBarometers, getBarometersByParams } from './getters' diff --git a/app/collection/categories/[category]/components/barometer-card/barometer-card.tsx b/app/collection/categories/[...category]/components/barometer-card/barometer-card.tsx similarity index 100% rename from app/collection/categories/[category]/components/barometer-card/barometer-card.tsx rename to app/collection/categories/[...category]/components/barometer-card/barometer-card.tsx diff --git a/app/collection/categories/[category]/components/barometer-card/index.ts b/app/collection/categories/[...category]/components/barometer-card/index.ts similarity index 100% rename from app/collection/categories/[category]/components/barometer-card/index.ts rename to app/collection/categories/[...category]/components/barometer-card/index.ts diff --git a/app/collection/categories/[category]/components/barometer-card/styles.module.scss b/app/collection/categories/[...category]/components/barometer-card/styles.module.scss similarity index 100% rename from app/collection/categories/[category]/components/barometer-card/styles.module.scss rename to app/collection/categories/[...category]/components/barometer-card/styles.module.scss diff --git a/app/collection/categories/[category]/page.tsx b/app/collection/categories/[...category]/page.tsx similarity index 71% rename from app/collection/categories/[category]/page.tsx rename to app/collection/categories/[...category]/page.tsx index 76dc570d..6c812efc 100644 --- a/app/collection/categories/[category]/page.tsx +++ b/app/collection/categories/[...category]/page.tsx @@ -8,22 +8,16 @@ import { SortValue, SortOptions } from './types' import Sort from './sort' import { DescriptionText } from '@/app/components/description-text' import { title, openGraph, twitter } from '@/app/metadata' -import { Pagination } from '@/app/components/pagination' +import { Pagination } from './pagination' import { withPrisma } from '@/prisma/prismaClient' import { getCategory } from '@/app/api/v2/categories/[name]/getters' import { getBarometersByParams } from '@/app/api/v2/barometers/getters' -/* interface SearchParams { - sort?: SortValue - page?: string -} */ interface CollectionProps { params: { - category: string - sort: SortValue - page: number + // category should include [categoryName, sortCriteria, pageNo] + category: string[] } - //searchParams: SearchParams } const PAGE_SIZE = 12 @@ -31,16 +25,17 @@ const PAGE_SIZE = 12 export async function generateMetadata({ params: { category }, }: CollectionProps): Promise { - const { description } = await getCategory(category) - const { barometers } = await getBarometersByParams(category, 1, 5, 'date') - const collectionTitle = `${title}: ${capitalize(category)} Barometers Collection` + const [categoryName] = category + const { description } = await getCategory(categoryName) + const { barometers } = await getBarometersByParams(categoryName, 1, 5, 'date') + const collectionTitle = `${title}: ${capitalize(categoryName)} Barometers Collection` const barometerImages = barometers .filter(({ images }) => images && images.length > 0) .map(({ images, name }) => ({ url: googleStorageImagesFolder + images.at(0), alt: name, })) - const url = barometerTypesRoute + category + const url = `${barometerTypesRoute}${category.join('/')}` return { title: collectionTitle, description, @@ -60,23 +55,23 @@ export async function generateMetadata({ } } -export default async function Collection({ - params: { category, page, sort } /* , searchParams */, -}: CollectionProps) { - console.log('🚀 ~ category, page, sort:', category, page, sort) - - /* const sort = searchParams.sort ?? 'date' - const page = searchParams.page ?? '1' */ - const { barometers, totalPages } = await getBarometersByParams(category, page, PAGE_SIZE, sort) - const { description } = await getCategory(category) +export default async function Collection({ params: { category } }: CollectionProps) { + const [categoryName, sort, page] = category + const { barometers, totalPages } = await getBarometersByParams( + categoryName, + Number(page), + PAGE_SIZE, + sort as SortValue, + ) + const { description } = await getCategory(categoryName) return ( - {category} + {categoryName} {description && } - + {barometers.map(({ name, id, images, manufacturer }, i) => ( @@ -96,7 +91,9 @@ export default async function Collection({ ) } -export const dynamicParams = true +// all non-generated posts will give 404 +export const dynamicParams = false + export const generateStaticParams = withPrisma(async prisma => { const categories = await prisma.category.findMany({ select: { name: true, id: true } }) const categoriesWithCount = await prisma.barometer.groupBy({ @@ -105,23 +102,21 @@ export const generateStaticParams = withPrisma(async prisma => { _all: true, }, }) - const params: CollectionProps['params'][] = [] + // page rout is /collection/categories/{categoryName}/{sortCriteria}/{pageNumber} + const params: { category: string[] }[] = [] for (const { name, id } of categories) { const categoryData = categoriesWithCount.find(({ categoryId }) => categoryId === id) const barometersPerCategory = categoryData?._count._all ?? 0 - console.log('🚀 ~ generateStaticParams ~ barometersPerCategory:', name, barometersPerCategory) const pagesPerCategory = Math.ceil(barometersPerCategory / PAGE_SIZE) + // generate all combinations of of category/sort/page for static page generation for (const { value: sort } of SortOptions) { for (let page = 1; page <= pagesPerCategory; page += 1) { params.push({ - category: name.toLowerCase(), - sort, - page, + category: [name.toLowerCase(), sort, String(page)], }) } } } - console.log('🚀 ~ generateStaticParams ~ params:', params) - return params.slice(0, 1) + return params }) diff --git a/app/collection/categories/[...category]/pagination.tsx b/app/collection/categories/[...category]/pagination.tsx new file mode 100644 index 00000000..9869a509 --- /dev/null +++ b/app/collection/categories/[...category]/pagination.tsx @@ -0,0 +1,24 @@ +'use client' + +import { Pagination as MantinePagination, PaginationProps } from '@mantine/core' +import { useRouter, usePathname } from 'next/navigation' + +export function Pagination(props: PaginationProps) { + const router = useRouter() + const pathname = usePathname() + const handlePageChange = (newPage: number) => { + router.push(pathname.split('/').slice(0, -1).concat(`${newPage}`).join('/')) + } + return ( + + ) +} diff --git a/app/collection/categories/[category]/sort.tsx b/app/collection/categories/[...category]/sort.tsx similarity index 77% rename from app/collection/categories/[category]/sort.tsx rename to app/collection/categories/[...category]/sort.tsx index f592d3f8..b331918e 100644 --- a/app/collection/categories/[category]/sort.tsx +++ b/app/collection/categories/[...category]/sort.tsx @@ -1,7 +1,7 @@ 'use client' import { CSSProperties, Select } from '@mantine/core' -import { useRouter } from 'next/navigation' +import { usePathname, useRouter } from 'next/navigation' import { SortValue, SortOptions } from './types' interface SortProps { @@ -12,10 +12,12 @@ interface SortProps { export default function Sort({ sortBy, style }: SortProps) { const router = useRouter() + const pathName = usePathname() const handleSortChange = (value: string | null) => { if (value) { - router.push(`?${new URLSearchParams({ sort: value })}`) + const path = pathName.split('/') + router.push(path.slice(0, -2).concat(value).concat('1').join('/')) } } diff --git a/app/collection/categories/[category]/types.ts b/app/collection/categories/[...category]/types.ts similarity index 100% rename from app/collection/categories/[category]/types.ts rename to app/collection/categories/[...category]/types.ts diff --git a/app/collection/items/[slug]/components/breadcrumbs.tsx b/app/collection/items/[slug]/components/breadcrumbs.tsx index 714d1859..e3e6f080 100644 --- a/app/collection/items/[slug]/components/breadcrumbs.tsx +++ b/app/collection/items/[slug]/components/breadcrumbs.tsx @@ -1,6 +1,6 @@ import Link from 'next/link' import { Breadcrumbs, Anchor, Text } from '@mantine/core' -import { barometerTypesRoute } from '@/app/constants' +import { barometerTypesRoute, postfix } from '@/app/constants' interface BreadcrumbsComponentProps { type: string @@ -10,7 +10,7 @@ interface BreadcrumbsComponentProps { export function BreadcrumbsComponent({ type, catId, ...props }: BreadcrumbsComponentProps) { const breadcrumbs = [ { title: 'Home', href: '/' }, - { title: type.toLowerCase(), href: barometerTypesRoute + type.toLowerCase() }, + { title: type.toLowerCase(), href: barometerTypesRoute + type.toLowerCase() + postfix }, { title: catId }, ] diff --git a/app/components/header/tabs/tabs.tsx b/app/components/header/tabs/tabs.tsx index 615386cb..b2e5cc13 100644 --- a/app/components/header/tabs/tabs.tsx +++ b/app/components/header/tabs/tabs.tsx @@ -11,11 +11,11 @@ import { AccessRole } from '@prisma/client' import sx from './tabs.module.scss' import { menuData } from '../menudata' import { useBarometers } from '@/app/hooks/useBarometers' -import { barometerTypesRoute } from '@/app/constants' +import { barometerTypesRoute, postfix } from '@/app/constants' import { isAdmin } from '../../is-admin' const WideScreenTabs = ({ className, ...props }: CenterProps) => { - const { categories: types } = useBarometers() + const { categories } = useBarometers() const { data: session } = useSession() const router = useRouter() const pathname = usePathname() @@ -78,10 +78,10 @@ const WideScreenTabs = ({ className, ...props }: CenterProps) => { > {renderTab()} - {types.data.map(({ label, id, name }) => ( + {categories.data.map(({ label, id, name }) => ( ))} diff --git a/app/search/page.tsx b/app/search/page.tsx index a67fe8c7..7494a201 100644 --- a/app/search/page.tsx +++ b/app/search/page.tsx @@ -1,9 +1,9 @@ import { Box, Container, Stack, Title } from '@mantine/core' import { googleStorageImagesFolder, barometerRoute } from '../constants' import { SearchItem } from './search-item' -import { Pagination } from '../components/pagination' import { searchBarometers } from '@/utils/fetch' import { SearchInfo } from './search-info' +import { Pagination } from './pagination' interface SearchProps { searchParams: Record diff --git a/app/components/pagination/pagination.tsx b/app/search/pagination.tsx similarity index 64% rename from app/components/pagination/pagination.tsx rename to app/search/pagination.tsx index 6c1c19cd..7bf3773f 100644 --- a/app/components/pagination/pagination.tsx +++ b/app/search/pagination.tsx @@ -7,14 +7,11 @@ export function Pagination(props: PaginationProps) { const router = useRouter() const searchParams = useSearchParams() const pathname = usePathname() - const updateQueryParams = (key: string, value: string | number) => { - const params = new URLSearchParams(searchParams?.toString() || '') - params.set(key, String(value)) - return params.toString() - } + const handlePageChange = (newPage: number) => { - const updatedQuery = updateQueryParams('page', newPage) - router.push(`${pathname}?${updatedQuery}`) + const params = new URLSearchParams(searchParams) + params.set('page', String(newPage)) + router.push(`${pathname}?${params}`) } return ( Date: Thu, 26 Dec 2024 11:56:58 +0100 Subject: [PATCH 4/4] refactor: simplify Pagination component by removing unnecessary props and styles --- .../categories/[...category]/pagination.tsx | 13 +------------ app/search/pagination.tsx | 13 +------------ theme.ts | 6 +++--- 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/app/collection/categories/[...category]/pagination.tsx b/app/collection/categories/[...category]/pagination.tsx index 9869a509..dd3a8a45 100644 --- a/app/collection/categories/[...category]/pagination.tsx +++ b/app/collection/categories/[...category]/pagination.tsx @@ -9,16 +9,5 @@ export function Pagination(props: PaginationProps) { const handlePageChange = (newPage: number) => { router.push(pathname.split('/').slice(0, -1).concat(`${newPage}`).join('/')) } - return ( - - ) + return } diff --git a/app/search/pagination.tsx b/app/search/pagination.tsx index 7bf3773f..62a72f93 100644 --- a/app/search/pagination.tsx +++ b/app/search/pagination.tsx @@ -13,16 +13,5 @@ export function Pagination(props: PaginationProps) { params.set('page', String(newPage)) router.push(`${pathname}?${params}`) } - return ( - - ) + return } diff --git a/theme.ts b/theme.ts index 97f45bc7..2330280d 100644 --- a/theme.ts +++ b/theme.ts @@ -23,9 +23,9 @@ export const theme = createTheme({ mt: 'lg', c: 'dark', color: 'dark', - }, - styles: { - alignSelf: 'center', + style: { + alignSelf: 'center', + }, }, }, },