mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Merge branch 'beer-style-fix' into dev-beer-styles
This commit is contained in:
@@ -20,8 +20,8 @@ const BeerStyleBeerSection: FC<BeerStyleBeerSectionProps> = ({ beerStyle }) => {
|
|||||||
});
|
});
|
||||||
const { ref: penultimateBeerPostRef } = useInView({
|
const { ref: penultimateBeerPostRef } = useInView({
|
||||||
/**
|
/**
|
||||||
* When the last beer post comes into view, call setSize from useBeerPostsByBrewery to
|
* When the last beer post comes into view, call setSize from useBeerPostsByBeerStyle
|
||||||
* load more beer posts.
|
* to load more beer posts.
|
||||||
*/
|
*/
|
||||||
onChange: (visible) => {
|
onChange: (visible) => {
|
||||||
if (!visible || isAtEnd) return;
|
if (!visible || isAtEnd) return;
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult';
|
||||||
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
|
import useSWRInfinite from 'swr/infinite';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
interface UseBeerPostsByBeerStyleParams {
|
||||||
|
pageSize: number;
|
||||||
|
beerStyleId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useBeerPostsByBeerStyle = ({
|
||||||
|
pageSize,
|
||||||
|
beerStyleId,
|
||||||
|
}: UseBeerPostsByBeerStyleParams) => {
|
||||||
|
const fetcher = async (url: string) => {
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
const json = await response.json();
|
||||||
|
const count = response.headers.get('X-Total-Count');
|
||||||
|
|
||||||
|
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||||
|
if (!parsed.success) {
|
||||||
|
throw new Error('API response validation failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedPayload = z.array(BeerPostQueryResult).safeParse(parsed.data.payload);
|
||||||
|
if (!parsedPayload.success) {
|
||||||
|
throw new Error('API response validation failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageCount = Math.ceil(parseInt(count as string, 10) / pageSize);
|
||||||
|
return {
|
||||||
|
beerPosts: parsedPayload.data,
|
||||||
|
pageCount,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data, error, isLoading, setSize, size } = useSWRInfinite(
|
||||||
|
(index) =>
|
||||||
|
`/api/beers/styles/${beerStyleId}/beers?page_num=${
|
||||||
|
index + 1
|
||||||
|
}&page_size=${pageSize}`,
|
||||||
|
fetcher,
|
||||||
|
);
|
||||||
|
|
||||||
|
const beerPosts = data?.flatMap((d) => d.beerPosts) ?? [];
|
||||||
|
const pageCount = data?.[0].pageCount ?? 0;
|
||||||
|
const isLoadingMore = size > 0 && data && typeof data[size - 1] === 'undefined';
|
||||||
|
const isAtEnd = !(size < data?.[0].pageCount!);
|
||||||
|
|
||||||
|
return {
|
||||||
|
beerPosts,
|
||||||
|
pageCount,
|
||||||
|
size,
|
||||||
|
setSize,
|
||||||
|
isLoading,
|
||||||
|
isLoadingMore,
|
||||||
|
isAtEnd,
|
||||||
|
error: error as unknown,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useBeerPostsByBeerStyle;
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||||
import DBClient from '@/prisma/DBClient';
|
import DBClient from '@/prisma/DBClient';
|
||||||
import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult';
|
import getBeerPostsByBeerStyleId from '@/services/BeerPost/getBeerPostsByBeerStyleId';
|
||||||
|
|
||||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
import { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { createRouter } from 'next-connect';
|
import { createRouter } from 'next-connect';
|
||||||
@@ -18,30 +19,14 @@ const getAllBeersByBeerStyle = async (
|
|||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
const { page_size, page_num, id } = req.query;
|
const { page_size, page_num, id } = req.query;
|
||||||
|
|
||||||
const beers: z.infer<typeof BeerPostQueryResult>[] =
|
const beers = getBeerPostsByBeerStyleId({
|
||||||
await DBClient.instance.beerPost.findMany({
|
pageNum: parseInt(page_num, 10),
|
||||||
where: { styleId: id },
|
pageSize: parseInt(page_size, 10),
|
||||||
take: parseInt(page_size, 10),
|
styleId: id,
|
||||||
skip: parseInt(page_num, 10) * parseInt(page_size, 10),
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
ibu: true,
|
|
||||||
abv: true,
|
|
||||||
createdAt: true,
|
|
||||||
updatedAt: true,
|
|
||||||
description: true,
|
|
||||||
postedBy: { select: { username: true, id: true } },
|
|
||||||
brewery: { select: { name: true, id: true } },
|
|
||||||
style: { select: { name: true, id: true, description: true } },
|
|
||||||
beerImages: { select: { alt: true, path: true, caption: true, id: true } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const pageCount = await DBClient.instance.beerPost.count({
|
|
||||||
where: { breweryId: id },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const pageCount = await DBClient.instance.beerPost.count({ where: { styleId: id } });
|
||||||
|
|
||||||
res.setHeader('X-Total-Count', pageCount);
|
res.setHeader('X-Total-Count', pageCount);
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
|
|||||||
38
src/services/BeerPost/getBeerPostsByBeerStyleId.ts
Normal file
38
src/services/BeerPost/getBeerPostsByBeerStyleId.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import DBClient from '@/prisma/DBClient';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import BeerPostQueryResult from './schema/BeerPostQueryResult';
|
||||||
|
|
||||||
|
interface GetBeerPostsByBeerStyleIdArgs {
|
||||||
|
styleId: string;
|
||||||
|
pageSize: number;
|
||||||
|
pageNum: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBeerPostsByBeerStyleId = async ({
|
||||||
|
pageNum,
|
||||||
|
pageSize,
|
||||||
|
styleId,
|
||||||
|
}: GetBeerPostsByBeerStyleIdArgs): Promise<z.infer<typeof BeerPostQueryResult>[]> => {
|
||||||
|
const beers = await DBClient.instance.beerPost.findMany({
|
||||||
|
where: { styleId },
|
||||||
|
take: pageSize,
|
||||||
|
skip: pageNum * pageSize,
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
ibu: true,
|
||||||
|
abv: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
description: true,
|
||||||
|
postedBy: { select: { username: true, id: true } },
|
||||||
|
brewery: { select: { name: true, id: true } },
|
||||||
|
style: { select: { name: true, id: true, description: true } },
|
||||||
|
beerImages: { select: { alt: true, path: true, caption: true, id: true } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return beers;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getBeerPostsByBeerStyleId;
|
||||||
38
src/services/BeerPost/getBeerPostsByBreweryId.ts
Normal file
38
src/services/BeerPost/getBeerPostsByBreweryId.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import DBClient from '@/prisma/DBClient';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import BeerPostQueryResult from './schema/BeerPostQueryResult';
|
||||||
|
|
||||||
|
interface GetBeerPostsByBeerStyleIdArgs {
|
||||||
|
breweryId: string;
|
||||||
|
pageSize: number;
|
||||||
|
pageNum: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBeerPostsByBeerStyleId = async ({
|
||||||
|
pageNum,
|
||||||
|
pageSize,
|
||||||
|
breweryId,
|
||||||
|
}: GetBeerPostsByBeerStyleIdArgs): Promise<z.infer<typeof BeerPostQueryResult>[]> => {
|
||||||
|
const beers = await DBClient.instance.beerPost.findMany({
|
||||||
|
where: { breweryId },
|
||||||
|
take: pageSize,
|
||||||
|
skip: pageNum * pageSize,
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
ibu: true,
|
||||||
|
abv: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
description: true,
|
||||||
|
postedBy: { select: { username: true, id: true } },
|
||||||
|
brewery: { select: { name: true, id: true } },
|
||||||
|
style: { select: { name: true, id: true, description: true } },
|
||||||
|
beerImages: { select: { alt: true, path: true, caption: true, id: true } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return beers;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getBeerPostsByBeerStyleId;
|
||||||
Reference in New Issue
Block a user