Feat: Add create brewery comments and brewery cluster map

This commit is contained in:
Aaron William Po
2023-04-30 23:09:03 -04:00
parent b3b1d5b6d1
commit adf1b55d10
13 changed files with 452 additions and 165 deletions

View File

@@ -16,6 +16,7 @@ import { NextApiResponse } from 'next';
import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult';
import getAllBreweryComments from '@/services/BreweryComment/getAllBreweryComments';
import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema';
import createNewBreweryComment from '@/services/BreweryComment/createNewBreweryComment';
interface CreateCommentRequest extends UserExtendedNextApiRequest {
body: z.infer<typeof CreateCommentValidationSchema>;
@@ -26,29 +27,31 @@ interface GetAllCommentsRequest extends UserExtendedNextApiRequest {
query: { id: string; page_size: string; page_num: string };
}
// const createComment = async (
// req: CreateCommentRequest,
// res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
// ) => {
// const { content, rating } = req.body;
const createComment = async (
req: CreateCommentRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const { content, rating } = req.body;
// const beerPostId = req.query.id;
const breweryPostId = req.query.id;
// const newBeerComment: z.infer<typeof BeerCommentQueryResult> =
// await createNewBeerComment({
// content,
// rating,
// beerPostId,
// userId: req.user!.id,
// });
const user = req.user!;
// res.status(201).json({
// message: 'Beer comment created successfully',
// statusCode: 201,
// payload: newBeerComment,
// success: true,
// });
// };
const newBreweryComment: z.infer<typeof CommentQueryResult> =
await createNewBreweryComment({
content,
rating,
breweryPostId,
userId: user.id,
});
res.status(201).json({
message: 'Beer comment created successfully',
statusCode: 201,
payload: newBreweryComment,
success: true,
});
};
const getAll = async (
req: GetAllCommentsRequest,
@@ -83,14 +86,14 @@ const router = createRouter<
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
>();
// router.post(
// validateRequest({
// bodySchema: CreateBeerCommentValidationSchema,
// querySchema: z.object({ id: z.string().uuid() }),
// }),
// getCurrentUser,
// createComment,
// );
router.post(
validateRequest({
bodySchema: CreateCommentValidationSchema,
querySchema: z.object({ id: z.string().uuid() }),
}),
getCurrentUser,
createComment,
);
router.get(
validateRequest({

View File

@@ -14,7 +14,7 @@ import { BeerPost } from '@prisma/client';
import { z } from 'zod';
import 'react-responsive-carousel/lib/styles/carousel.min.css'; // requires a loader
import 'react-responsive-carousel/lib/styles/carousel.min.css';
import { Carousel } from 'react-responsive-carousel';
import useMediaQuery from '@/hooks/useMediaQuery';
import { Tab } from '@headlessui/react';

View File

@@ -1,7 +1,6 @@
import getBreweryPostById from '@/services/BreweryPost/getBreweryPostById';
import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult';
import { GetServerSideProps, NextPage } from 'next';
import 'mapbox-gl/dist/mapbox-gl.css';
import { z } from 'zod';
import Head from 'next/head';
@@ -11,7 +10,7 @@ import { Carousel } from 'react-responsive-carousel';
import useMediaQuery from '@/hooks/useMediaQuery';
import { Tab } from '@headlessui/react';
import BreweryInfoHeader from '@/components/BreweryById/BreweryInfoHeader';
import BreweryMap from '@/components/BreweryById/BreweryMap';
import BreweryPostMap from '@/components/BreweryById/BreweryPostMap';
import BreweryBeersSection from '@/components/BreweryById/BreweryBeerSection.tsx';
import BreweryCommentsSection from '@/components/BreweryById/BreweryCommentsSection';
@@ -63,13 +62,13 @@ const BreweryByIdPage: NextPage<BreweryPageProps> = ({ breweryPost }) => {
<BreweryCommentsSection breweryPost={breweryPost} />
</div>
<div className="w-[40%] space-y-3">
<BreweryMap latitude={latitude} longitude={longitude} />
<BreweryPostMap latitude={latitude} longitude={longitude} />
<BreweryBeersSection />
</div>
</div>
) : (
<>
<BreweryMap latitude={latitude} longitude={longitude} />
<BreweryPostMap latitude={latitude} longitude={longitude} />
<Tab.Group>
<Tab.List className="tabs tabs-boxed items-center justify-center rounded-2xl">
<Tab className="tab tab-md w-1/2 uppercase ui-selected:tab-active">

127
src/pages/breweries/map.tsx Normal file
View File

@@ -0,0 +1,127 @@
import { GetServerSideProps, NextPage } from 'next';
import { useMemo, useState } from 'react';
import Map, {
FullscreenControl,
Marker,
NavigationControl,
Popup,
ScaleControl,
} from 'react-map-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import DBClient from '@/prisma/DBClient';
import LocationMarker from '@/components/ui/LocationMarker';
import Link from 'next/link';
type MapStyles = Record<'light' | 'dark', `mapbox://styles/mapbox/${string}`>;
interface BreweryMapPageProps {
breweries: {
location: {
city: string;
stateOrProvince: string | null;
country: string | null;
coordinates: number[];
};
id: string;
name: string;
}[];
}
const BreweryMapPage: NextPage<BreweryMapPageProps> = ({ breweries }) => {
const windowIsDefined = typeof window !== 'undefined';
const themeIsDefined = windowIsDefined && !!window.localStorage.getItem('theme');
const [popupInfo, setPopupInfo] = useState<BreweryMapPageProps['breweries'][0] | null>(
null,
);
const theme = (
windowIsDefined && themeIsDefined ? window.localStorage.getItem('theme') : 'light'
) as 'light' | 'dark';
const mapStyles: MapStyles = {
light: 'mapbox://styles/mapbox/light-v10',
dark: 'mapbox://styles/mapbox/dark-v11',
};
const pins = useMemo(
() => (
<>
{breweries.map((brewery) => {
const [longitude, latitude] = brewery.location.coordinates;
return (
<Marker
latitude={latitude}
longitude={longitude}
key={brewery.id}
onClick={(e) => {
e.originalEvent.stopPropagation();
setPopupInfo(brewery);
}}
>
<LocationMarker />
</Marker>
);
})}
</>
),
[breweries],
);
return (
<div className="h-full">
<Map
initialViewState={{ zoom: 2 }}
style={{ width: '100%', height: '100%' }}
mapStyle={mapStyles[theme]}
mapboxAccessToken={process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN}
scrollZoom
>
<FullscreenControl position="top-left" />
<NavigationControl position="top-left" />
<ScaleControl />
{pins}
{popupInfo && (
<Popup
anchor="bottom"
longitude={popupInfo.location.coordinates[0]}
latitude={popupInfo.location.coordinates[1]}
onClose={() => setPopupInfo(null)}
>
<div className="flex flex-col text-black ">
<Link
className="link-hover link text-base font-bold"
href={`/breweries/${popupInfo.id}`}
>
{popupInfo.name}
</Link>
<p className="text-base">
{popupInfo.location.city}
{popupInfo.location.stateOrProvince
? `, ${popupInfo.location.stateOrProvince}`
: ''}
{popupInfo.location.country ? `, ${popupInfo.location.country}` : ''}
</p>
</div>
</Popup>
)}
</Map>
</div>
);
};
export default BreweryMapPage;
export const getServerSideProps: GetServerSideProps<BreweryMapPageProps> = async () => {
const breweries = await DBClient.instance.breweryPost.findMany({
select: {
location: {
select: { coordinates: true, city: true, country: true, stateOrProvince: true },
},
id: true,
name: true,
},
});
return { props: { breweries } };
};