diff --git a/.changeset/young-impalas-cross.md b/.changeset/young-impalas-cross.md new file mode 100644 index 000000000..38c6d1aa1 --- /dev/null +++ b/.changeset/young-impalas-cross.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +wishlist sheet added to product card on plp diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/_components/category-viewed.tsx b/core/app/[locale]/(default)/(faceted)/category/[slug]/_components/category-viewed.tsx index 8aa740a65..c2929227a 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/_components/category-viewed.tsx +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/_components/category-viewed.tsx @@ -9,7 +9,7 @@ import { bodl } from '~/lib/bodl'; import { getCategoryPageData } from '../page-data'; -type Category = Awaited>['category']; +type Category = Awaited>['data']['category']; type productSearchItem = FragmentOf; interface Props { diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts index c8639e782..b30fbd908 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page-data.ts @@ -1,3 +1,4 @@ +import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client'; import { cache } from 'react'; import { getSessionCustomerId } from '~/auth'; @@ -5,6 +6,7 @@ import { client } from '~/client'; import { graphql, VariablesOf } from '~/client/graphql'; import { revalidate } from '~/client/revalidate-target'; import { BreadcrumbsFragment } from '~/components/breadcrumbs/fragment'; +import { WishlistSheetFragment } from '~/components/wishlist-sheet/fragment'; import { CategoryTreeFragment } from './_components/sub-categories'; @@ -23,9 +25,14 @@ const CategoryPageQuery = graphql( } ...CategoryTreeFragment } + customer { + wishlists(first: 50) { + ...WishlistSheetFragment + } + } } `, - [BreadcrumbsFragment, CategoryTreeFragment], + [BreadcrumbsFragment, CategoryTreeFragment, WishlistSheetFragment], ); type Variables = VariablesOf; @@ -40,5 +47,14 @@ export const getCategoryPageData = cache(async (variables: Variables) => { fetchOptions: customerId ? { cache: 'no-store' } : { next: { revalidate } }, }); - return response.data.site; + const wishlists = response.data.customer?.wishlists + ? removeEdgesAndNodes(response.data.customer.wishlists).map((wishlist) => { + return { + ...wishlist, + items: removeEdgesAndNodes(wishlist.items), + }; + }) + : []; + + return { data: response.data.site, wishlists }; }); diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx index 82ce25264..0024fb263 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx @@ -2,6 +2,7 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { getTranslations, unstable_setRequestLocale } from 'next-intl/server'; +import { auth } from '~/auth'; import { Breadcrumbs } from '~/components/breadcrumbs'; import { ProductCard } from '~/components/product-card'; import { Pagination } from '~/components/ui/pagination'; @@ -27,7 +28,7 @@ interface Props { export async function generateMetadata({ params }: Props): Promise { const categoryId = Number(params.slug); - const data = await getCategoryPageData({ + const { data } = await getCategoryPageData({ categoryId, }); @@ -53,7 +54,15 @@ export default async function Category({ params: { locale, slug }, searchParams const categoryId = Number(slug); - const [{ category, categoryTree }, search] = await Promise.all([ + const session = await auth(); + + const [ + { + data: { category, categoryTree }, + wishlists, + }, + search, + ] = await Promise.all([ getCategoryPageData({ categoryId }), fetchFacetedSearch({ ...searchParams, category: categoryId }), ]); @@ -116,6 +125,8 @@ export default async function Category({ params: { locale, slug }, searchParams imageSize="wide" key={product.entityId} product={product} + showWishlistSheet={Boolean(session)} + wishlistsList={wishlists} /> ))} diff --git a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form/_actions/create-wishlist.ts b/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form/_actions/create-wishlist.ts index b62302bec..3da9f7e1f 100644 --- a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form/_actions/create-wishlist.ts +++ b/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form/_actions/create-wishlist.ts @@ -1,6 +1,5 @@ 'use server'; -import { revalidatePath } from 'next/cache'; import { z } from 'zod'; import { createWishlist as createWishlistMutation } from '~/client/mutations/create-wishlist'; @@ -22,8 +21,6 @@ export const createWishlist = async (formData: FormData) => { try { const newWishlist = await createWishlistMutation({ input }); - revalidatePath('/account/wishlists', 'page'); - if (newWishlist) { return { status: 'success' as const, diff --git a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form/index.tsx b/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form/index.tsx index 1f4b135db..b62eba0e0 100644 --- a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form/index.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form/index.tsx @@ -14,6 +14,7 @@ import { FormSubmit, Input, } from '~/components/ui/form'; +import { useRouter } from '~/i18n/routing'; import { useAccountStatusContext } from '../../../_components/account-status-provider'; @@ -47,6 +48,8 @@ export const CreateWishlistForm = ({ onWishlistCreated }: CreateWishlistFormProp const t = useTranslations('Account.Wishlist'); + const router = useRouter(); + const handleInputValidation = (e: ChangeEvent) => { const validationStatus = e.target.validity.valueMissing; @@ -62,6 +65,7 @@ export const CreateWishlistForm = ({ onWishlistCreated }: CreateWishlistFormProp status: submit.status, message: t('messages.created', { name: submit.data.name }), }); + router.refresh(); } if (submit.status === 'error') { diff --git a/core/app/[locale]/(default)/product/[slug]/_components/product-form/index.tsx b/core/app/[locale]/(default)/product/[slug]/_components/product-form/index.tsx index 2d0d5683f..1375364a1 100644 --- a/core/app/[locale]/(default)/product/[slug]/_components/product-form/index.tsx +++ b/core/app/[locale]/(default)/product/[slug]/_components/product-form/index.tsx @@ -7,12 +7,12 @@ import { useTranslations } from 'next-intl'; import { FormProvider, useFormContext } from 'react-hook-form'; import { toast } from 'react-hot-toast'; -import { WishlistSheet } from '~/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet'; import { Wishlists } from '~/app/[locale]/(default)/product/[slug]/_components/details'; import { ProductItemFragment } from '~/client/fragments/product-item'; import { AddToCartButton } from '~/components/add-to-cart-button'; import { Link } from '~/components/link'; import { Button } from '~/components/ui/button'; +import { WishlistSheet } from '~/components/wishlist-sheet'; import { bodl } from '~/lib/bodl'; import { handleAddToCart } from './_actions/add-to-cart'; @@ -158,7 +158,7 @@ export const ProductForm = ({ data: product, isLogged, wishlists }: ProductFormP
{isLogged && wishlists ? ( - + ) : (
{deleteFromWishlist ?
{deleteFromWishlist}
: null} + {wishlistSheet ?
{wishlistSheet}
: null} {addToCart} ); diff --git a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/fragment.ts b/core/components/wishlist-sheet/fragment.ts similarity index 100% rename from core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/fragment.ts rename to core/components/wishlist-sheet/fragment.ts diff --git a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/index.tsx b/core/components/wishlist-sheet/index.tsx similarity index 54% rename from core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/index.tsx rename to core/components/wishlist-sheet/index.tsx index aed699a2a..20171f004 100644 --- a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/index.tsx +++ b/core/components/wishlist-sheet/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Heart } from 'lucide-react'; import { useTranslations } from 'next-intl'; import { PropsWithChildren, useEffect, useState } from 'react'; @@ -6,7 +8,7 @@ import { ExistingResultType } from '~/client/util'; import { Button } from '~/components/ui/button'; import { Sheet } from '~/components/ui/sheet'; -import { AccountStatusProvider } from '../../../_components/account-status-provider'; +import { AccountStatusProvider } from '../../app/[locale]/(default)/account/(tabs)/_components/account-status-provider'; import { addWishlistItems } from './update-wishlists-form/_actions/add-wishlist-items'; import { WishlistSheetContent } from './wishlist-sheet-content'; @@ -15,26 +17,29 @@ export type Wishlist = NonNullable[' interface WishlistSheetProps extends PropsWithChildren { productId: number; - wishlistsData: Wishlist[]; + trigger?: 'button' | 'icon'; + wishlistsList: Wishlist[]; } -export const WishlistSheet = ({ productId, wishlistsData }: WishlistSheetProps) => { +export const WishlistSheet = ({ + productId, + trigger = 'button', + wishlistsList, +}: WishlistSheetProps) => { const t = useTranslations('Account.Wishlist.Sheet'); - const [wishlists, setWishlists] = useState(() => { - if (wishlistsData.length === 0) { - return [{ items: [], entityId: 0, name: t('favorites') }]; - } + const [wishlists, setWishlists] = useState(wishlistsList); - return wishlistsData; - }); + useEffect(() => { + setWishlists(wishlistsList); + }, [wishlistsList]); const [saved, setSaved] = useState(() => { - if (wishlistsData.length === 0) { + if (wishlistsList.length === 0) { return false; } - return wishlistsData.some(({ items }) => { + return wishlistsList.some(({ items }) => { return items.some(({ product }) => product.entityId === productId); }); }); @@ -52,14 +57,26 @@ export const WishlistSheet = ({ productId, wishlistsData }: WishlistSheetProps) side="right" title={t('title')} trigger={ - + trigger === 'button' ? ( + + ) : ( + + ) } > diff --git a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/update-wishlists-form/_actions/add-wishlist-items.ts b/core/components/wishlist-sheet/update-wishlists-form/_actions/add-wishlist-items.ts similarity index 100% rename from core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/update-wishlists-form/_actions/add-wishlist-items.ts rename to core/components/wishlist-sheet/update-wishlists-form/_actions/add-wishlist-items.ts diff --git a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/update-wishlists-form/_actions/delete-wishlist-items.ts b/core/components/wishlist-sheet/update-wishlists-form/_actions/delete-wishlist-items.ts similarity index 100% rename from core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/update-wishlists-form/_actions/delete-wishlist-items.ts rename to core/components/wishlist-sheet/update-wishlists-form/_actions/delete-wishlist-items.ts diff --git a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/update-wishlists-form/index.tsx b/core/components/wishlist-sheet/update-wishlists-form/index.tsx similarity index 100% rename from core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/update-wishlists-form/index.tsx rename to core/components/wishlist-sheet/update-wishlists-form/index.tsx diff --git a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/wishlist-sheet-content.tsx b/core/components/wishlist-sheet/wishlist-sheet-content.tsx similarity index 87% rename from core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/wishlist-sheet-content.tsx rename to core/components/wishlist-sheet/wishlist-sheet-content.tsx index b08ee24be..246140b0d 100644 --- a/core/app/[locale]/(default)/account/(tabs)/wishlists/_components/wishlist-sheet/wishlist-sheet-content.tsx +++ b/core/components/wishlist-sheet/wishlist-sheet-content.tsx @@ -5,9 +5,9 @@ import { createWishlist } from '~/client/mutations/create-wishlist'; import { Button } from '~/components/ui/button'; import { Message } from '~/components/ui/message'; -import { useAccountStatusContext } from '../../../_components/account-status-provider'; -import { Modal } from '../../../_components/modal'; -import { CreateWishlistForm } from '../create-wishlist-form'; +import { useAccountStatusContext } from '../../app/[locale]/(default)/account/(tabs)/_components/account-status-provider'; +import { Modal } from '../../app/[locale]/(default)/account/(tabs)/_components/modal'; +import { CreateWishlistForm } from '../../app/[locale]/(default)/account/(tabs)/wishlists/_components/create-wishlist-form'; import { UpdateWishlistsForm } from './update-wishlists-form'; diff --git a/core/messages/en.json b/core/messages/en.json index fe264f524..35b194310 100644 --- a/core/messages/en.json +++ b/core/messages/en.json @@ -227,7 +227,8 @@ "saved": "Saved", "createTitle": "New wishlist", "selectCta": "Select from available lists:", - "favorites": "Favorites" + "favorites": "Favorites", + "open": "Open wishlist sheet" }, "Errors": { "error": "Something went wrong. Please try again later."