Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core): homepage fragment colocation #766

Merged
merged 1 commit into from
Apr 16, 2024
Merged
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
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 } },
}),
]);
Comment on lines +92 to +101
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😬


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
Loading