refactoring out variant specific details

This commit is contained in:
Samantha Kellow 2023-11-24 08:53:57 +00:00
parent 5cfc48cdec
commit 4e33afc9dc
3 changed files with 42 additions and 15 deletions

View File

@ -1,24 +1,16 @@
import { AddToCart } from 'components/cart/add-to-cart'; import { AddToCart } from 'components/cart/add-to-cart';
import Price from 'components/price';
import { Product } from 'lib/shopify/types'; import { Product } from 'lib/shopify/types';
import { DescriptionContent } from './description-content'; import { DescriptionContent } from './description-content';
import { SustainabilityInfo } from './sustainability-info'; import { SustainabilityInfo } from './sustainability-info';
import { VariantSelector } from './variant-selector'; import { VariantDetails } from './variant-details';
export function ProductDescription({ product }: { product: Product }) { export function ProductDescription({ product }: { product: Product }) {
const filterDeterminedOptions = product.options.filter(option => option.name !== 'Wrap')
return ( return (
<> <>
<div className="mb-6 flex flex-col border-b pb-6 dark:border-neutral-700"> <div className="flex flex-col">
<h1 className="mb-2 text-2xl md:text-3xl font-medium">{product.title}</h1> <h1 className="mb-2 text-2xl md:text-3xl font-medium">{product.title}</h1>
<div className="place-self-end mr-auto w-auto rounded-full bg-gray-600 p-2 text-sm text-white">
<Price
amount={product.priceRange.maxVariantPrice.amount}
currencyCode={product.priceRange.maxVariantPrice.currencyCode}
/>
</div> </div>
</div> <VariantDetails product={product} />
<VariantSelector options={filterDeterminedOptions} variants={product.variants} />
<AddToCart variants={product.variants} availableForSale={product.availableForSale} /> <AddToCart variants={product.variants} availableForSale={product.availableForSale} />
<DescriptionContent product={product} /> <DescriptionContent product={product} />

View File

@ -0,0 +1,26 @@
'use client'
import Price from "components/price";
import { Product } from "lib/shopify/types";
import { useState } from "react";
import { VariantSelector } from "./variant-selector";
export function VariantDetails({ product }: { product: Product }) {
const filterDeterminedOptions = product.options.filter(option => option.name !== 'Wrap');
const [selectedVariant, setSelectedVariant] = useState(product.variants[0]);
return (
<>
<div className='flex flex-col border-b mb-6 dark:border-neutral-700'>
<div className="place-self-end mr-auto w-auto rounded-full bg-gray-600 p-2 text-sm text-white mb-6">
<Price
amount={selectedVariant?.price.amount || product.variants[0]!.price.amount}
currencyCode={product.priceRange.maxVariantPrice.currencyCode}
/>
</div>
</div>
<VariantSelector options={filterDeterminedOptions} variants={product.variants} setSelectedVariant={setSelectedVariant} />
</>
)
}

View File

@ -1,10 +1,11 @@
'use client'; 'use client';
import clsx from 'clsx'; import clsx from 'clsx';
import { ProductOption, ProductVariant } from 'lib/shopify/types'; import { Money, ProductOption, ProductVariant } from 'lib/shopify/types';
import { createUrl } from 'lib/utils'; import { createUrl } from 'lib/utils';
import Link from 'next/link'; import Link from 'next/link';
import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useEffect } from 'react';
type ParamsMap = { type ParamsMap = {
[key: string]: string; // ie. { color: 'Red', size: 'Large', ... } [key: string]: string; // ie. { color: 'Red', size: 'Large', ... }
@ -14,15 +15,18 @@ type OptimizedVariant = {
id: string; id: string;
availableForSale: boolean; availableForSale: boolean;
params: URLSearchParams; params: URLSearchParams;
[key: string]: string | boolean | URLSearchParams; // ie. { color: 'Red', size: 'Large', ... } price: Money;
[key: string]: string | boolean | URLSearchParams | Money; // ie. { color: 'Red', size: 'Large', ... }
}; };
export function VariantSelector({ export function VariantSelector({
options, options,
variants variants,
setSelectedVariant,
}: { }: {
options: ProductOption[]; options: ProductOption[];
variants: ProductVariant[]; variants: ProductVariant[];
setSelectedVariant: (newVariant: ProductVariant) => void,
}) { }) {
const pathname = usePathname(); const pathname = usePathname();
const currentParams = useSearchParams(); const currentParams = useSearchParams();
@ -46,7 +50,8 @@ export function VariantSelector({
const optimized: OptimizedVariant = { const optimized: OptimizedVariant = {
id: variant.id, id: variant.id,
availableForSale: variant.availableForSale, availableForSale: variant.availableForSale,
params: new URLSearchParams() params: new URLSearchParams(),
price: variant.price,
}; };
variant.selectedOptions.forEach((selectedOption) => { variant.selectedOptions.forEach((selectedOption) => {
@ -79,6 +84,10 @@ export function VariantSelector({
const currentUrl = createUrl(pathname, currentParams); const currentUrl = createUrl(pathname, currentParams);
const selectedVariantUrl = createUrl(pathname, selectedVariantParams); const selectedVariantUrl = createUrl(pathname, selectedVariantParams);
useEffect(() => {
setSelectedVariant(selectedVariant);
}, [selectedVariantUrl]);
if (currentUrl !== selectedVariantUrl) { if (currentUrl !== selectedVariantUrl) {
router.replace(selectedVariantUrl); router.replace(selectedVariantUrl);
} }