Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ const HeaderSearchBar = ({
brewerySlug: beer.brewery.slug,
beerSlug: beer.slug,
})}
prefetch={true}
>
<BeerSearchResult
name={beer.name}
Expand Down Expand Up @@ -282,6 +283,7 @@ const HeaderSearchBar = ({
href={generatePath(Routes.BREWERY, {
brewerySlug: brewery.slug,
})}
prefetch={true}
>
<BrewerySearchResult
key={brewery.id}
Expand Down Expand Up @@ -311,6 +313,7 @@ const HeaderSearchBar = ({
href={generatePath(Routes.PROFILE, {
username: user.username,
})}
prefetch={true}
>
<UserSearchResult
key={user.id}
Expand All @@ -337,6 +340,7 @@ const HeaderSearchBar = ({
>
<Link
href={`${Routes.SEARCH}?search=${search}&kind=${searchKind}`}
prefetch={true}
className="text-primary-700 dark:text-primary underline"
>
{t(`headerSearch.${searchKind}.seeMore`, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const BreweryBeerList = async ({
brewerySlug,
beerSlug: beer.slug,
})}
prefetch={true}
>
<BreweryBeer
name={beer.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const BreweryFriendReviewCard = async ({
username: review.user.username,
reviewSlug: review.slug,
})}
prefetch={true}
className="col-span-2 grid grid-cols-subgrid"
>
<div className="flex flex-row items-center gap-x-4">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const BreweryYourReviewCard = async ({
username: review.user.username,
reviewSlug: review.slug,
})}
prefetch={true}
className="col-span-2 grid grid-cols-subgrid"
>
<div className="flex flex-row items-center gap-x-4">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const BeerCard = async ({
<div className="bg-foreground absolute bottom-1.5 left-[calc(50%-theme(spacing.8))] h-1 w-16 rounded-full opacity-50" />
) : null}

<div className="flex flex-col gap-y-1">
<div className="flex w-full flex-col gap-y-1">
<h1 className="text-left text-2xl md:text-4xl">{name}</h1>

<div
Expand All @@ -90,6 +90,7 @@ const BeerCard = async ({
href={generatePath(Routes.BREWERY, {
brewerySlug: brewery.slug,
})}
prefetch={true}
title={brewery.name}
className="text-primary cursor-pointer truncate"
>
Expand All @@ -101,7 +102,7 @@ const BeerCard = async ({
</div>
</div>

<div className="grid grid-cols-5 items-center justify-between gap-x-4">
<div className="grid w-full grid-cols-5 items-center justify-between gap-x-4">
<DescriptionList
label={t("common.beer.style")}
value={style}
Expand All @@ -128,7 +129,9 @@ const BeerCard = async ({
</div>

{hasDetails ? (
<CollapsibleContent className={cn("contents", "text-xs md:text-sm")}>
<CollapsibleContent
className={cn("contents w-full", "text-xs md:text-sm")}
>
{description ? (
<DescriptionList
label={t("beerPage.details.description")}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getTranslations } from "next-intl/server";
import { Suspense } from "react";
import { Fragment, Suspense } from "react";

import BeerReviewCard from "@/app/[locale]/(business)/(with-header)/breweries/[brewerySlug]/beers/[beerSlug]/_components/beer-reviews/review-card";
import BeerReviewCardSkeleton from "@/app/[locale]/(business)/(with-header)/breweries/[brewerySlug]/beers/[beerSlug]/_components/beer-reviews/review-card/skeleton";
import Await from "@/app/_components/await";
import {
ChipTabContent,
Expand Down Expand Up @@ -42,7 +43,7 @@ const BeerReviews = async ({ beerId, page }: BeerReviewsProps) => {
);
}

const yourReviews = await getBeerReviewsByUser({
const yourReviewsPromise = getBeerReviewsByUser({
userId: user.id,
beerId,
page,
Expand All @@ -67,32 +68,69 @@ const BeerReviews = async ({ beerId, page }: BeerReviewsProps) => {
</ChipTabList>

<ChipTabContent value="my-reviews" className="flex flex-col gap-y-4">
<p>
{t.rich("beerPage.reviews.tabs.myReviews.count", {
count: yourReviews.count,
muted: (chunks) => (
<span className="text-foreground/62.5 italic">{chunks}</span>
),
})}
</p>

<div className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-4 gap-y-8">
{yourReviews.results.map((review) => (
<BeerReviewCard key={review.id} review={review} />
))}

<Pagination
current={yourReviews.page.current}
total={yourReviews.page.total}
className="col-span-2"
/>
</div>
<Suspense
key={`${beerId}-your-reviews-${page}`}
fallback={
<>
<p>{t("beerPage.reviews.tabs.friendReviews.loading")}</p>

<div className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-4 gap-y-8">
<BeerReviewCardSkeleton />

<BeerReviewCardSkeleton />

<BeerReviewCardSkeleton />
</div>
</>
}
>
<Await promise={yourReviewsPromise}>
{(reviews) => (
<>
<p>
{t.rich("beerPage.reviews.tabs.myReviews.count", {
count: reviews.count,
muted: (chunks) => (
<span className="text-foreground/62.5 italic">
{chunks}
</span>
),
})}
</p>

<div className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-4 gap-y-8">
{reviews.results.map((review) => (
<BeerReviewCard key={review.id} review={review} />
))}

<Pagination
current={reviews.page.current}
total={reviews.page.total}
className="col-span-2"
/>
</div>
</>
)}
</Await>
</Suspense>
</ChipTabContent>

<ChipTabContent value="friend-reviews" className="flex flex-col gap-y-4">
<Suspense
key={`${beerId}-friend-reviews-${page}`}
fallback={<p>{t("beerPage.reviews.tabs.friendReviews.loading")}</p>}
fallback={
<>
<p>{t("beerPage.reviews.tabs.friendReviews.loading")}</p>

<div className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-4 gap-y-8">
<BeerReviewCardSkeleton />

<BeerReviewCardSkeleton />

<BeerReviewCardSkeleton />
</div>
</>
}
>
<Await promise={friendReviewsPromise}>
{(reviews) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const BeerReviewCard = async ({ review }: BeerReviewCardProps) => {
username: review.username,
reviewSlug: review.slug,
})}
prefetch={true}
className="col-span-2 grid grid-cols-subgrid"
>
<div className="flex flex-row items-center gap-x-4">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ChevronRightIcon } from "lucide-react";

import Skeleton from "@/components/ui/skeleton";

const BeerReviewCardSkeleton = () => {
return (
<div className="col-span-2 grid grid-cols-subgrid">
<div className="flex flex-row items-center gap-x-3">
<Skeleton className="size-11 [--opacity:30%]" />

<div className="flex min-w-0 flex-col gap-y-1">
<Skeleton className="h-6 w-32 [--opacity:30%]" />

<Skeleton className="h-4 w-24 [--opacity:15%]" />
</div>
</div>

<div className="flex flex-row items-center justify-end gap-x-4">
<div className="flex flex-col items-end gap-y-1">
<Skeleton className="h-6 w-16 [--opacity:30%]" />

<Skeleton className="h-4 w-28 [--opacity:15%]" />
</div>

<ChevronRightIcon className="text-foreground/30 size-6 animate-pulse" />
</div>
</div>
);
};

export default BeerReviewCardSkeleton;
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const AcceptFriendRequestPage = async ({
href={generatePath(Routes.PROFILE, {
username: friendRequest.friend.username,
})}
prefetch={true}
className="text-primary-700 underline"
>
{t("friendRequestPage.cta.visitProfile", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const UserReviewCard = async ({ username, review }: UserReviewCardProps) => {
username,
reviewSlug: review.slug,
})}
prefetch={true}
className="col-span-2 grid grid-cols-subgrid"
>
<div className="flex flex-row items-center gap-x-4">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const BeerTab = async ({ results, count, page }: BeerTabProps) => {
brewerySlug: beer.brewery.slug,
beerSlug: beer.slug,
})}
prefetch={true}
>
<BeerSearchResult
name={beer.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const BreweryTab = async ({ results, count, page }: BreweryTabProps) => {
href={generatePath(Routes.BREWERY, {
brewerySlug: brewery.slug,
})}
prefetch={true}
>
<BrewerySearchResult
key={brewery.id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const UserTab = async ({ results, count, page }: UserTabProps) => {
href={generatePath(Routes.PROFILE, {
username: user.username,
})}
prefetch={true}
>
<UserSearchResult
key={user.id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const UserReviewPage = async ({ params }: UserReviewPageProps) => {
brewerySlug: review.beer.brewery.slug,
beerSlug: review.beer.slug,
})}
prefetch={true}
className={cn(
"text-primary font-title cursor-pointer",
"text-2xl md:text-4xl",
Expand All @@ -127,6 +128,7 @@ const UserReviewPage = async ({ params }: UserReviewPageProps) => {
href={generatePath(Routes.BREWERY, {
brewerySlug: review.beer.brewery.slug,
})}
prefetch={true}
className="text-primary cursor-pointer truncate"
>
{chunks}
Expand Down Expand Up @@ -206,6 +208,7 @@ const UserReviewPage = async ({ params }: UserReviewPageProps) => {

<Link
href={generatePath(Routes.PROFILE, { username })}
prefetch={true}
className={cn(
"text-primary cursor-pointer",
"text-sm md:text-base",
Expand Down
2 changes: 2 additions & 0 deletions src/app/_components/ui/pagination/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const Pagination = ({ current, total, className }: PaginationProps) => {
<li>
<Link
href={getPageUrl(current - 1)}
prefetch={true}
aria-label={t("pagination.previous")}
aria-disabled={current === 1 ? true : undefined}
role={current === 1 ? "link" : undefined}
Expand All @@ -82,6 +83,7 @@ const Pagination = ({ current, total, className }: PaginationProps) => {
<li>
<Link
href={getPageUrl(current + 1)}
prefetch={true}
aria-label={t("pagination.next")}
aria-disabled={current === total ? true : undefined}
role={current === total ? "link" : undefined}
Expand Down
18 changes: 18 additions & 0 deletions src/components/ui/skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { cn } from "@/lib/tailwind";

interface SkeletonProps {
className?: string;
}

const Skeleton = ({ className }: SkeletonProps) => {
return (
<div
className={cn(
"bg-foreground/(--opacity) animate-pulse rounded",
className,
)}
/>
);
};

export default Skeleton;
12 changes: 8 additions & 4 deletions src/domain/beers/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"server only";

import { nanoid } from "nanoid";
import { cache } from "react";

import {
InvalidBreweryError,
Expand All @@ -17,6 +16,7 @@ import {
transformRawStyleCategoryToStyleCategory,
} from "@/domain/beers/transforms";
import { getCurrentUser } from "@/lib/auth";
import { nextCache } from "@/lib/cache";
import { getPaginatedResults } from "@/lib/pagination";
import prisma, { getPrismaTransactionClient } from "@/lib/prisma";
import { slugify } from "@/lib/prisma/utils";
Expand All @@ -35,8 +35,12 @@ import type {
} from "@/lib/pagination/types";
import type { Prisma } from "@prisma/client";

export const getBeerBySlug = cache(
async (beerSlug: string, brewerySlug: string): Promise<Beer> => {
export const getBeerBySlug = nextCache({
tags: ([beerSlug, brewerySlug]) => [
`brewery/slug:${brewerySlug}`,
`beer/slug:${beerSlug}`,
],
callback: async (beerSlug: string, brewerySlug: string): Promise<Beer> => {
if (brewerySlug.length < 4 || beerSlug.length < 4) {
throw new InvalidBeerSlugError();
}
Expand Down Expand Up @@ -81,7 +85,7 @@ export const getBeerBySlug = cache(

return transformRawBeerToBeer(beer);
},
);
});

export const getColors = async (): Promise<Color[]> => {
const colors = await prisma.colors.findMany();
Expand Down
Loading