From 767245672c70c150ad64a6daf3997dbceb134516 Mon Sep 17 00:00:00 2001 From: Henrik Larsson Date: Fri, 11 Aug 2023 10:19:55 +0200 Subject: [PATCH] Tried to optimize product page --- app/[locale]/[...slug]/page.tsx | 2 + app/[locale]/globals.css | 30 ------- components/layout/header/header.tsx | 24 +++--- components/modules/hero/hero.tsx | 5 +- components/product/add-to-cart.tsx | 82 ------------------ components/product/gallery.tsx | 67 ++++++++++++++ components/product/grid.tsx | 37 ++++++++ components/product/product-view.tsx | 96 ++++++++------------- components/search/search.tsx | 4 +- components/ui/product-card/product-card.tsx | 2 +- components/ui/sheet.tsx | 2 +- components/ui/text/text.tsx | 2 +- lib/sanity/queries.tsx | 14 +-- lib/shopify/types.ts | 2 +- lib/storm/{types => }/product.ts | 28 +----- lib/storm/types.ts | 18 ++++ lib/storm/types/common.ts | 36 -------- package.json | 2 +- 18 files changed, 190 insertions(+), 263 deletions(-) delete mode 100644 components/product/add-to-cart.tsx create mode 100644 components/product/gallery.tsx create mode 100644 components/product/grid.tsx rename lib/storm/{types => }/product.ts (86%) create mode 100644 lib/storm/types.ts delete mode 100644 lib/storm/types/common.ts diff --git a/app/[locale]/[...slug]/page.tsx b/app/[locale]/[...slug]/page.tsx index 61735ac6c..78d287a8f 100644 --- a/app/[locale]/[...slug]/page.tsx +++ b/app/[locale]/[...slug]/page.tsx @@ -53,6 +53,8 @@ interface PageParams { } export default async function Page({ params }: PageParams) { + console.log(params); + let queryParams = { locale: params.locale, slug: '' diff --git a/app/[locale]/globals.css b/app/[locale]/globals.css index c59a0eb76..e55b3c8b3 100644 --- a/app/[locale]/globals.css +++ b/app/[locale]/globals.css @@ -34,36 +34,6 @@ --radius: 0.5rem; } - - .dark { - --background: 0 0% 3.9%; - --foreground: 0 0% 98%; - - --card: 0 0% 3.9%; - --card-foreground: 0 0% 98%; - - --popover: 0 0% 3.9%; - --popover-foreground: 0 0% 98%; - - --primary: 0 0% 98%; - --primary-foreground: 0 0% 9%; - - --secondary: 0 0% 14.9%; - --secondary-foreground: 0 0% 98%; - - --muted: 0 0% 14.9%; - --muted-foreground: 0 0% 63.9%; - - --accent: 0 0% 14.9%; - --accent-foreground: 0 0% 98%; - - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 0% 98%; - - --border: 0 0% 14.9%; - --input: 0 0% 14.9%; - --ring: 0 0% 83.1%; - } } @layer base { diff --git a/components/layout/header/header.tsx b/components/layout/header/header.tsx index 091c49108..71fa674cb 100644 --- a/components/layout/header/header.tsx +++ b/components/layout/header/header.tsx @@ -42,17 +42,19 @@ export default async function Header({ locale }: HeaderProps) {
- + +
    + {mainMenu.map((item: { title: string; slug: string }, i: number) => { + return ( +
  • + + {item.title} + +
  • + ); + })} +
+
}> diff --git a/components/modules/hero/hero.tsx b/components/modules/hero/hero.tsx index 66dd59a53..6e2e6ec74 100644 --- a/components/modules/hero/hero.tsx +++ b/components/modules/hero/hero.tsx @@ -8,7 +8,6 @@ interface HeroProps { label?: string; title: string; image: object | any; - desktopImage: object | any; link: { title: string; reference: { @@ -30,9 +29,11 @@ const heroSize = { const Hero = ({ variant, title, text, label, image, link }: HeroProps) => { const heroClass = heroSize[variant as HeroSize] || heroSize.fullScreen; + console.log(image); + return (
{image && ( { - const variant = variants.find((variant: ProductVariant) => - variant.selectedOptions.every( - (option) => option.value === searchParams.get(option.name.toLowerCase()) - ) - ); - - if (variant) { - setSelectedVariantId(variant.id); - } - }, [searchParams, variants, setSelectedVariantId]); - - const isMutating = adding || isPending; - - async function handleAdd() { - if (!availableForSale) return; - - setAdding(true); - - const response = await fetch(`/api/cart`, { - method: 'POST', - body: JSON.stringify({ - merchandiseId: selectedVariantId - }) - }); - - const data = await response.json(); - - if (data.error) { - alert(data.error); - return; - } - - setAdding(false); - - startTransition(() => { - router.refresh(); - }); - } - - return ( - - ); -} diff --git a/components/product/gallery.tsx b/components/product/gallery.tsx new file mode 100644 index 000000000..b0c18b6c2 --- /dev/null +++ b/components/product/gallery.tsx @@ -0,0 +1,67 @@ +'use client'; + +import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'; +import { createUrl } from 'lib/utils'; +import Image from 'next/image'; +import Link from 'next/link'; +import { usePathname, useSearchParams } from 'next/navigation'; + +export function Gallery({ images }: { images: { src: string; alt: string }[] }) { + const pathname = usePathname(); + const searchParams = useSearchParams(); + const imageSearchParam = searchParams.get('image'); + const imageIndex = imageSearchParam ? parseInt(imageSearchParam) : 0; + + const nextSearchParams = new URLSearchParams(searchParams.toString()); + const nextImageIndex = imageIndex + 1 < images.length ? imageIndex + 1 : 0; + nextSearchParams.set('image', nextImageIndex.toString()); + const nextUrl = createUrl(pathname, nextSearchParams); + + const previousSearchParams = new URLSearchParams(searchParams.toString()); + const previousImageIndex = imageIndex === 0 ? images.length - 1 : imageIndex - 1; + previousSearchParams.set('image', previousImageIndex.toString()); + const previousUrl = createUrl(pathname, previousSearchParams); + + const buttonClassName = + 'h-12 w-12 transition-all ease-in-out hover:scale-110 flex items-center justify-center'; + + return ( + <> +
+ {images[imageIndex] && ( + {images[imageIndex]?.alt + )} + + {images.length > 1 ? ( +
+
+ + + + + + +
+
+ ) : null} +
+ + ); +} diff --git a/components/product/grid.tsx b/components/product/grid.tsx new file mode 100644 index 000000000..2f217aa70 --- /dev/null +++ b/components/product/grid.tsx @@ -0,0 +1,37 @@ +import Image from 'next/image'; + +export function Grid({ + images +}: { + images: { src: string; alt: string; width: number | undefined; height: number | undefined }[]; +}) { + return ( +
+ {images.map( + ( + image: { + src: string; + alt: string; + height: number | undefined; + width: number | undefined; + }, + index: number + ) => { + return ( + {image.alt} + ); + } + )} +
+ ); +} diff --git a/components/product/product-view.tsx b/components/product/product-view.tsx index 70b981e6b..ff4bf444e 100644 --- a/components/product/product-view.tsx +++ b/components/product/product-view.tsx @@ -1,22 +1,23 @@ 'use client'; -import { Carousel, CarouselItem } from 'components/modules/carousel/carousel'; -import SanityImage from 'components/ui/sanity-image/sanity-image'; +import { Product } from '@/lib/storm/product'; +import { Image } from '@/lib/storm/types'; import Text from 'components/ui/text/text'; -import { Product } from 'lib/storm/types/product'; import { cn } from 'lib/utils'; import { useTranslations } from 'next-intl'; import { Suspense } from 'react'; -import ProductCard from '../ui/product-card/product-card'; +import { Gallery } from './gallery'; +import { Grid } from './grid'; import Price from './price'; + interface ProductViewProps { product: Product; relatedProducts: Product[]; } export default function ProductView({ product, relatedProducts }: ProductViewProps) { - const images = product.images; const t = useTranslations('product'); + const { name, description, price, images } = product; return (
@@ -24,59 +25,50 @@ export default function ProductView({ product, relatedProducts }: ProductViewPro className={cn('relative grid grid-cols-1 items-start lg:grid-cols-12 lg:px-8 2xl:px-16')} >
-
- {images && ( - 1 ? true : false} - hasDots={false} - gliderClasses={'lg:px-8 2xl:px-16'} - slidesToScroll={1} - slidesToShow={images.length > 1 ? 1.0125 : 1} - responsive={{ - breakpoint: 1024, - settings: { - slidesToShow: 1 - } - }} - > - {images.map((image: any, index: number) => ( - - - - ))} - - )} +
+ ({ + src: image.url, + alt: image.alt + }))} + />
-
- {images.map((image: any, index: number) => ( +
+ ({ + src: image.url, + alt: image.alt, + height: image.height, + width: image.width + }))} + /> + + {/* {images.map((image: Image, index: number) => (
- ))} + ))} */}
- {product.name} + {name} + + + {description} +
@@ -86,26 +78,6 @@ export default function ProductView({ product, relatedProducts }: ProductViewPro {t('related')} - - - {relatedProducts.map((p) => ( - - - - ))} - )} diff --git a/components/search/search.tsx b/components/search/search.tsx index 0f0005667..8236caf96 100644 --- a/components/search/search.tsx +++ b/components/search/search.tsx @@ -24,7 +24,7 @@ export default function Search() { ); } return ( -
+
{/* Widgets */} diff --git a/components/ui/product-card/product-card.tsx b/components/ui/product-card/product-card.tsx index 2184dd4d8..1d76f90be 100644 --- a/components/ui/product-card/product-card.tsx +++ b/components/ui/product-card/product-card.tsx @@ -1,9 +1,9 @@ 'use client'; import SanityImage from '@/components/ui/sanity-image/sanity-image'; +import type { Product } from '@/lib/storm/product'; import Price from 'components/product/price'; import Text from 'components/ui/text'; -import type { Product } from 'lib/storm/types/product'; import { cn } from 'lib/utils'; import Link from 'next/link'; import { FC } from 'react'; diff --git a/components/ui/sheet.tsx b/components/ui/sheet.tsx index 0cecbe501..d090a2020 100644 --- a/components/ui/sheet.tsx +++ b/components/ui/sheet.tsx @@ -24,7 +24,7 @@ const SheetOverlay = React.forwardRef< >(({ className, ...props }, ref) => ( = ({ variant === 'sectionHeading', ['text-sm leading-tight lg:text-base']: variant === 'listChildHeading', ['max-w-prose text-lg text-high-contrast lg:text-xl']: variant === 'label', - ['max-w-prose lg:text-lg 2xl:text-xl']: variant === 'paragraph' + ['max-w-prose']: variant === 'paragraph' }, className )} diff --git a/lib/sanity/queries.tsx b/lib/sanity/queries.tsx index 8418280d0..5980cf7e8 100644 --- a/lib/sanity/queries.tsx +++ b/lib/sanity/queries.tsx @@ -1,17 +1,17 @@ -export const docQuery = `*[_type in ["home", "page", "category", "product"] && defined(slug.current)] { - _type, - "slug": slug.current, - "locale": language -}`; - export const imageFields = ` alt, crop, hotspot, + "url": asset->url, + "width": asset->metadata.dimensions.width, + "height": asset->metadata.dimensions.height, asset-> { - ..., + _id, + assetId, + metadata, _type, _ref, + _rev } `; diff --git a/lib/shopify/types.ts b/lib/shopify/types.ts index 23dc02d46..13def8b9f 100644 --- a/lib/shopify/types.ts +++ b/lib/shopify/types.ts @@ -262,4 +262,4 @@ export type ShopifyProductsOperation = { reverse?: boolean; sortKey?: string; }; -}; +}; \ No newline at end of file diff --git a/lib/storm/types/product.ts b/lib/storm/product.ts similarity index 86% rename from lib/storm/types/product.ts rename to lib/storm/product.ts index 9758c801f..c2f9ceb20 100644 --- a/lib/storm/types/product.ts +++ b/lib/storm/product.ts @@ -1,4 +1,4 @@ -import { Image } from './common' +import { Image } from './types' export interface ProductPrice { /** @@ -145,28 +145,4 @@ export interface Product { * The locale version of the product. */ locale?: string -} - - -/** - * Product operations - */ - -export type GetAllProductPathsOperation = { - data: { products: Pick[] } - variables: { first?: number } -} - -export type GetAllProductsOperation = { - data: { products: Product[] } - variables: { - relevance?: 'featured' | 'best_selling' | 'newest' - ids?: string[] - first?: number - } -} - -export type GetProductOperation = { - data: { product?: Product } - variables: { path: string; slug?: never } | { path?: never; slug: string } -} +} \ No newline at end of file diff --git a/lib/storm/types.ts b/lib/storm/types.ts new file mode 100644 index 000000000..ea56c8e8f --- /dev/null +++ b/lib/storm/types.ts @@ -0,0 +1,18 @@ +export type Image = { + /** + * The URL of the image. + */ + url: string + /** + * A word or phrase that describes the content of an image. + */ + alt: string + /** + * The image's width. + */ + width?: number + /** + * The image's height. + */ + height?: number +}; \ No newline at end of file diff --git a/lib/storm/types/common.ts b/lib/storm/types/common.ts deleted file mode 100644 index d63dfc0b9..000000000 --- a/lib/storm/types/common.ts +++ /dev/null @@ -1,36 +0,0 @@ -export interface Discount { - /** - * The value of the discount, can be an amount or percentage. - */ - value: number -} - -export interface Measurement { - /** - * The measurement's value. - */ - value: number - /** - * The measurement's unit, such as "KILOGRAMS", "GRAMS", "POUNDS" & "OOUNCES". - */ - unit: 'KILOGRAMS' | 'GRAMS' | 'POUNDS' | 'OUNCES' -} - -export interface Image { - /** - * The URL of the image. - */ - url: string - /** - * A word or phrase that describes the content of an image. - */ - alt?: string - /** - * The image's width. - */ - width?: number - /** - * The image's height. - */ - height?: number -} diff --git a/package.json b/package.json index f339f7a45..faf75b69f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "prettier:check": "prettier --check --ignore-unknown .", "test": "pnpm lint && pnpm prettier:check", "test:e2e": "playwright test", - "analyze": "BUNDLE_ANALYZE=true next build" + "analyze": "cross-env BUNDLE_ANALYZE=true pnpm build" }, "git": { "pre-commit": "lint-staged"