feat: change price by product variation

This commit is contained in:
paolosantarsiero 2024-12-29 18:43:35 +01:00
parent 87dd5ef8e8
commit e7be2b4695
5 changed files with 34 additions and 25 deletions

View File

@ -100,7 +100,7 @@ export default async function ProductPage(props: { params: Promise<{ name: strin
</Suspense>
)}
<Suspense fallback={null}>
<ProductDescription product={product} />
<ProductDescription product={product} variations={variations} />
</Suspense>
<AddToCart product={product} variations={variations}/>
</div>

View File

@ -4,7 +4,6 @@ import { PlusIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx';
import { useProduct } from 'components/product/product-context';
import { Product, ProductVariations } from 'lib/woocomerce/models/product';
import { useMemo } from 'react';
import { useCart } from './cart-context';
function SubmitButton({disabled = false}: {disabled: boolean}) {
@ -23,21 +22,9 @@ function SubmitButton({disabled = false}: {disabled: boolean}) {
export function AddToCart({ product, variations }: { product: Product, variations?: ProductVariations[] }) {
const { setNewCart } = useCart();
const {state} = useProduct();
const productVariant = useMemo(() => {
const keys = Object.keys(state).filter((key) => key !== 'id' && key !== 'image').map((key) => ({
attribute: key.toLowerCase(),
value: state[key]
}));
const productExist = variations?.find((variation) => {
const attributes = variation.attributes.map((attr) => ({name: attr.name, option: attr.option})) || [];
return attributes.every((attribute) => attribute.option === keys.find((key) => key.attribute === attribute.name)?.value);
});
return productExist ? keys : [];
}, [state, variations]);
const { state } = useProduct();
const productVariant = variations?.find((variation) => variation.id.toString() === state.variation);
const variation = productVariant?.attributes.map((attr) => ({ attribute: attr.name, value: attr.option })) || [];
return (
<form
@ -46,7 +33,7 @@ export function AddToCart({ product, variations }: { product: Product, variation
const cart = await (
await fetch('/api/cart', {
method: 'POST',
body: JSON.stringify({ id: product.id, quantity: 1, variation: productVariant })
body: JSON.stringify({ id: product.id, quantity: 1, variation })
})
).json();
setNewCart(cart);
@ -55,7 +42,7 @@ export function AddToCart({ product, variations }: { product: Product, variation
}
}}
>
<SubmitButton disabled={variations?.length && !productVariant.length ? true : false}/>
<SubmitButton disabled={variations?.length && !product ? true : false}/>
</form>
);
}

View File

@ -7,12 +7,15 @@ type ProductState = {
[key: string]: string;
} & {
image?: string;
};
} & {
variation?: string;
}
type ProductContextType = {
state: ProductState;
updateOption: (name: string, value: string) => ProductState;
updateImage: (index: string) => ProductState;
updateVariation: (variation: string) => ProductState;
};
const ProductContext = createContext<ProductContextType | undefined>(undefined);
@ -48,11 +51,18 @@ export function ProductProvider({ children }: { children: React.ReactNode }) {
return { ...state, ...newState };
};
const updateVariation = (variation: string) => {
const newState = { variation };
setOptimisticState(newState);
return { ...state, ...newState };
}
const value = useMemo(
() => ({
state,
updateOption,
updateImage,
updateVariation
}),
[state]
);

View File

@ -1,14 +1,19 @@
'use client';
import Price from 'components/price';
import Prose from 'components/prose';
import { Product } from 'lib/woocomerce/models/product';
import { Product, ProductVariations } from 'lib/woocomerce/models/product';
import { useProduct } from './product-context';
export function ProductDescription({ product, variations }: { product: Product, variations?: ProductVariations[] }) {
const { state } = useProduct();
const productVariant = variations?.find((variation) => variation.id.toString() === state.variation);
export function ProductDescription({ product }: { product: Product }) {
return (
<>
<div className="mb-6 flex flex-col border-b pb-6 dark:border-neutral-700">
<h1 className="mb-2 text-5xl font-medium">{product.name}</h1>
<div className="mr-auto w-auto rounded-full bg-blue-600 p-2 text-sm text-white">
<Price amount={product.price} currencyCode="EUR" />
<Price amount={productVariant ? productVariant.price : product.price} currencyCode="EUR" />
</div>
</div>
{product.description ? (

View File

@ -35,12 +35,19 @@ export function VariantSelector({
const optionNameLowerCase = option?.name?.toLowerCase();
// The option is active if it's in the selected options.
const isActive = optionNameLowerCase ? state[optionNameLowerCase] === value : false;
if (!optionNameLowerCase) return null;
return (
<button
formAction={() => {
const newState = updateOption(optionNameLowerCase, value);
if (!optionNameLowerCase) return;
let newState = updateOption(optionNameLowerCase, value);
const keys = Object.keys(newState).filter((key) => key !== 'id' && key !== 'image' && key !== 'variation');
const variant = variations.find((variation) => {
return variation?.attributes?.every((attr) => attr.name && keys.includes(attr.name) && newState[attr.name] === attr.option);
})?.id?.toString();
if (variant) {
newState = {...newState, variation: variant};
}
updateURL(newState);
}}
key={value}