mirror of
https://github.com/vercel/commerce.git
synced 2025-06-28 01:11:24 +00:00
feat: change price by product variation
This commit is contained in:
parent
87dd5ef8e8
commit
e7be2b4695
@ -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>
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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]
|
||||
);
|
||||
|
@ -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 ? (
|
||||
|
@ -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}
|
||||
|
Loading…
x
Reference in New Issue
Block a user