Skip to content

Commit

Permalink
refactor(core): homepage fragment colocation
Browse files Browse the repository at this point in the history
  • Loading branch information
deini committed Apr 15, 2024
1 parent 3f19124 commit 9003dea
Show file tree
Hide file tree
Showing 15 changed files with 309 additions and 201 deletions.
75 changes: 69 additions & 6 deletions apps/core/app/[locale]/(default)/compare/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client';
import { Button } from '@bigcommerce/components/button';
import { Rating } from '@bigcommerce/components/rating';
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, getTranslations } from 'next-intl/server';
import * as z from 'zod';

import { getProducts } from '~/client/queries/get-products';
import { getSessionCustomerId } from '~/auth';
import { client } from '~/client';
import { graphql } from '~/client/graphql';
import { revalidate } from '~/client/revalidate-target';
import { BcImage } from '~/components/bc-image';
import { Link } from '~/components/link';
import { Pricing } from '~/components/pricing';
import { Pricing, PricingFragment } from '~/components/pricing';
import { SearchForm } from '~/components/search-form';
import { LocaleType } from '~/i18n';
import { cn } from '~/lib/utils';
Expand Down Expand Up @@ -37,23 +41,82 @@ const CompareParamsSchema = z.object({
.transform((value) => value?.map((id) => parseInt(id, 10))),
});

const ComparePageQuery = graphql(
`
query ComparePage($entityIds: [Int!], $first: Int) {
site {
products(entityIds: $entityIds, first: $first) {
edges {
node {
entityId
name
path
brand {
name
}
defaultImage {
altText
url: urlTemplate
}
reviewSummary {
numberOfReviews
averageRating
}
productOptions(first: 3) {
edges {
node {
entityId
}
}
}
description
inventory {
aggregated {
availableToSell
}
}
availabilityV2 {
status
}
...PricingFragment
}
}
}
}
}
`,
[PricingFragment],
);

export default async function Compare({
params: { locale },
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
params: { locale: LocaleType };
}) {
const customerId = await getSessionCustomerId();
const t = await getTranslations({ locale, namespace: 'Compare' });
const messages = await getMessages({ locale });

const parsed = CompareParamsSchema.parse(searchParams);
const productIds = parsed.ids?.filter((id) => !Number.isNaN(id));
const products = await getProducts({
productIds: productIds ?? [],
first: productIds?.length ? MAX_COMPARE_LIMIT : 0,

const { data } = await client.fetch({
document: ComparePageQuery,
variables: {
entityIds: productIds ?? [],
first: productIds?.length ? MAX_COMPARE_LIMIT : 0,
},
customerId,
fetchOptions: customerId ? { cache: 'no-store' } : { next: { revalidate } },
});

const products = removeEdgesAndNodes(data.site.products).map((product) => ({
...product,
productOptions: removeEdgesAndNodes(product.productOptions),
}));

if (!products.length) {
return (
<div className="flex w-full justify-center py-16 align-middle">
Expand Down Expand Up @@ -136,7 +199,7 @@ export default async function Compare({
{products.map((product) => (
<td className="px-4 py-4 align-bottom text-base" key={product.entityId}>
{/* TODO: add translations */}
<Pricing prices={product.prices} />
<Pricing data={product} />
</td>
))}
</tr>
Expand Down
51 changes: 44 additions & 7 deletions apps/core/app/[locale]/(default)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client';
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, getTranslations, unstable_setRequestLocale } from 'next-intl/server';

import { getFeaturedProducts } from '~/client/queries/get-featured-products';
import { getNewestProducts } from '~/client/queries/get-newest-products';
import { getSessionCustomerId } from '~/auth';
import { client } from '~/client';
import { graphql } from '~/client/graphql';
import { revalidate } from '~/client/revalidate-target';
import { Hero } from '~/components/hero';
import { ProductCardCarousel } from '~/components/product-card-carousel';
import {
ProductCardCarousel,
ProductCardCarouselFragment,
} from '~/components/product-card-carousel';
import { LocaleType } from '~/i18n';

interface Props {
Expand All @@ -13,15 +19,46 @@ interface Props {
};
}

const HomePageQuery = graphql(
`
query HomePageQuery {
site {
newestProducts(first: 12) {
edges {
node {
...ProductCardCarouselFragment
}
}
}
featuredProducts(first: 12) {
edges {
node {
...ProductCardCarouselFragment
}
}
}
}
}
`,
[ProductCardCarouselFragment],
);

export default async function Home({ params: { locale } }: Props) {
const customerId = await getSessionCustomerId();

unstable_setRequestLocale(locale);

const t = await getTranslations({ locale, namespace: 'Home' });
const messages = await getMessages({ locale });
const [newestProducts, featuredProducts] = await Promise.all([
getNewestProducts(),
getFeaturedProducts(),
]);

const { data } = await client.fetch({
document: HomePageQuery,
customerId,
fetchOptions: customerId ? { cache: 'no-store' } : { next: { revalidate } },
});

const featuredProducts = removeEdgesAndNodes(data.site.featuredProducts);
const newestProducts = removeEdgesAndNodes(data.site.newestProducts);

return (
<>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client';
import { NextIntlClientProvider } from 'next-intl';
import { getLocale, getMessages, getTranslations } from 'next-intl/server';

import { getRelatedProducts } from '~/client/queries/get-related-products';
import { ProductCardCarousel } from '~/components/product-card-carousel';
import { graphql, ResultOf } from '~/client/graphql';
import {
ProductCardCarousel,
ProductCardCarouselFragment,
} from '~/components/product-card-carousel';

export const RelatedProducts = async ({ productId }: { productId: number }) => {
export const RelatedProductsFragment = graphql(
`
fragment RelatedProductsFragment on Product {
relatedProducts(first: 12) {
edges {
node {
...ProductCardCarouselFragment
}
}
}
}
`,
[ProductCardCarouselFragment],
);

interface Props {
data: ResultOf<typeof RelatedProductsFragment>;
}

export const RelatedProducts = async ({ data }: Props) => {
const t = await getTranslations('Product');
const locale = await getLocale();
const messages = await getMessages({ locale });

const relatedProducts = await getRelatedProducts({
productId,
});
const relatedProducts = removeEdgesAndNodes(data.relatedProducts);

return (
<NextIntlClientProvider locale={locale} messages={{ Product: messages.Product ?? {} }}>
Expand Down
40 changes: 37 additions & 3 deletions apps/core/app/[locale]/(default)/product/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import { NextIntlClientProvider } from 'next-intl';
import { getMessages, getTranslations, unstable_setRequestLocale } from 'next-intl/server';
import { Suspense } from 'react';

import { getSessionCustomerId } from '~/auth';
import { client } from '~/client';
import { graphql } from '~/client/graphql';
import { getProduct } from '~/client/queries/get-product';
import { revalidate } from '~/client/revalidate-target';
import { LocaleType } from '~/i18n';

import { BreadCrumbs } from './_components/breadcrumbs';
import { Description } from './_components/description';
import { Details } from './_components/details';
import { Gallery } from './_components/gallery';
import { RelatedProducts } from './_components/related-products';
import { RelatedProducts, RelatedProductsFragment } from './_components/related-products';
import { Reviews } from './_components/reviews';
import { Warranty } from './_components/warranty';

Expand Down Expand Up @@ -48,7 +52,22 @@ export async function generateMetadata({ params }: ProductPageProps): Promise<Me
};
}

const ProductPageQuery = graphql(
`
query ProductPageQuery($entityId: Int!, $optionValueIds: [OptionValueId!]) {
site {
product(entityId: $entityId, optionValueIds: $optionValueIds) {
...RelatedProductsFragment
}
}
}
`,
[RelatedProductsFragment],
);

export default async function Product({ params, searchParams }: ProductPageProps) {
const customerId = await getSessionCustomerId();

const { locale } = params;

unstable_setRequestLocale(locale);
Expand All @@ -68,12 +87,27 @@ export default async function Product({ params, searchParams }: ProductPageProps
(option) => !Number.isNaN(option.optionEntityId) && !Number.isNaN(option.valueEntityId),
);

const product = await getProduct(productId, optionValueIds);
// TODO: Here we are temporarily fetching the same product twice
// This is part of the ongoing effort of migrating to fragment collocation
const [product, { data }] = await Promise.all([
getProduct(productId, optionValueIds),

client.fetch({
document: ProductPageQuery,
variables: { entityId: productId, optionValueIds },
customerId,
fetchOptions: customerId ? { cache: 'no-store' } : { next: { revalidate } },
}),
]);

if (!product) {
return notFound();
}

if (!data.site.product) {
return notFound();
}

return (
<>
<BreadCrumbs productId={product.entityId} />
Expand All @@ -92,7 +126,7 @@ export default async function Product({ params, searchParams }: ProductPageProps
</div>

<Suspense fallback={t('loading')}>
<RelatedProducts productId={product.entityId} />
<RelatedProducts data={data.site.product} />
</Suspense>
</>
);
Expand Down
14 changes: 4 additions & 10 deletions apps/core/app/[locale]/not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { NextIntlClientProvider } from 'next-intl';
import { getLocale, getMessages, getTranslations } from 'next-intl/server';

import { client } from '~/client';
import { PRODUCT_DETAILS_FRAGMENT } from '~/client/fragments/product-details';
import { graphql } from '~/client/graphql';
import { revalidate } from '~/client/revalidate-target';
import { Footer, FooterFragment } from '~/components/footer/footer';
import { Header, HeaderFragment } from '~/components/header';
import { CartLink } from '~/components/header/cart';
import { ProductCard } from '~/components/product-card';
import { ProductCard, ProductCardFragment } from '~/components/product-card';
import { SearchForm } from '~/components/search-form';

export const metadata = {
Expand All @@ -26,14 +25,14 @@ const NotFoundQuery = graphql(
featuredProducts(first: 4) {
edges {
node {
...ProductDetails
...ProductCardFragment
}
}
}
}
}
`,
[HeaderFragment, FooterFragment, PRODUCT_DETAILS_FRAGMENT],
[HeaderFragment, FooterFragment, ProductCardFragment],
);

export default async function NotFound() {
Expand All @@ -46,12 +45,7 @@ export default async function NotFound() {
fetchOptions: { next: { revalidate } },
});

const featuredProducts = removeEdgesAndNodes(data.site.featuredProducts).map(
(featuredProduct) => ({
...featuredProduct,
productOptions: removeEdgesAndNodes(featuredProduct.productOptions),
}),
);
const featuredProducts = removeEdgesAndNodes(data.site.featuredProducts);

return (
<>
Expand Down
Loading

0 comments on commit 9003dea

Please sign in to comment.