diff --git a/.changeset/cyan-yaks-return.md b/.changeset/cyan-yaks-return.md new file mode 100644 index 000000000..e9b34cdcf --- /dev/null +++ b/.changeset/cyan-yaks-return.md @@ -0,0 +1,5 @@ +--- +"vue-demo-store": minor +--- + +Display cart item total price instead of unit price diff --git a/.changeset/sour-sheep-smile.md b/.changeset/sour-sheep-smile.md new file mode 100644 index 000000000..490fbe5dd --- /dev/null +++ b/.changeset/sour-sheep-smile.md @@ -0,0 +1,5 @@ +--- +"@shopware-pwa/composables-next": patch +--- + +`getProductItemSeoUrlData` method of `useCart` marked as deprecated diff --git a/.changeset/warm-snakes-sort.md b/.changeset/warm-snakes-sort.md new file mode 100644 index 000000000..9739070fd --- /dev/null +++ b/.changeset/warm-snakes-sort.md @@ -0,0 +1,5 @@ +--- +"@shopware-pwa/composables-next": patch +--- + +Add item total price property for useCartItem composable diff --git a/packages/composables/src/useCart.ts b/packages/composables/src/useCart.ts index 10f7a5cee..e612bfc55 100644 --- a/packages/composables/src/useCart.ts +++ b/packages/composables/src/useCart.ts @@ -49,8 +49,9 @@ export type UseCartReturn = { count: ComputedRef; /** * Refreshes the cart object and related data + * If @param newCart is provided, it will be used as a new cart object */ - refreshCart(): Promise; + refreshCart(newCart?: Cart): Promise; /** * Removes the provided LineItem from the cart */ @@ -95,7 +96,12 @@ export function useCartFunction(): UseCartReturn { const _storeCart = _useContext("swCart"); - async function refreshCart(): Promise { + async function refreshCart(newCart?: Cart): Promise { + if (newCart) { + _storeCart.value = newCart; + return newCart; + } + const result = await getCart(apiInstance); _storeCart.value = result; return result; @@ -108,7 +114,7 @@ export function useCartFunction(): UseCartReturn { const addToCartResult = await addProductToCart( params.id, params.quantity, - apiInstance + apiInstance, ); _storeCart.value = addToCartResult; return addToCartResult; @@ -126,7 +132,7 @@ export function useCartFunction(): UseCartReturn { const result = await changeCartItemQuantity( params.id, params.quantity, - apiInstance + apiInstance, ); _storeCart.value = result; } @@ -179,14 +185,14 @@ export function useCartFunction(): UseCartReturn { // associations: (getDefaults() as any).getProductItemsSeoUrlsData // .associations, }, - apiInstance + apiInstance, ); return result?.elements || []; } const appliedPromotionCodes = computed(() => { return cartItems.value.filter( - (cartItem: LineItem) => cartItem.type === "promotion" + (cartItem: LineItem) => cartItem.type === "promotion", ); }); @@ -202,7 +208,7 @@ export function useCartFunction(): UseCartReturn { lineItem.type === "product" ? lineItem.quantity + accumulator : accumulator, - 0 + 0, ); }); @@ -226,7 +232,7 @@ export function useCartFunction(): UseCartReturn { }); const cartErrors: ComputedRef = computed( - () => (cart.value?.errors && Object.values(cart.value.errors)) || [] + () => (cart.value?.errors && Object.values(cart.value.errors)) || [], ); const isVirtualCart = computed(() => { diff --git a/packages/composables/src/useCartItem.ts b/packages/composables/src/useCartItem.ts index b7d067e72..53f0522df 100644 --- a/packages/composables/src/useCartItem.ts +++ b/packages/composables/src/useCartItem.ts @@ -1,6 +1,6 @@ -import { computed, ComputedRef, Ref, unref } from "vue"; +import { computed, ComputedRef, Ref } from "vue"; import { removeCartItem, getProduct } from "@shopware-pwa/api-client"; -import { +import type { LineItem, LineItemType, ClientApiError, @@ -13,14 +13,45 @@ import { getMainImageUrl } from "@shopware-pwa/helpers-next"; import { useShopwareContext, useCart } from "."; export type UseCartItemReturn = { + /** + * Calculated price {number} for the current item + */ itemRegularPrice: ComputedRef; + /** + * Calculated price {number} for the current item if list price is set + */ itemSpecialPrice: ComputedRef; + /** + * Total price for the current item of given quantity in the cart + */ + itemTotalPrice: ComputedRef; + /** + * Thumbnail url for the current item's entity + */ itemImageThumbnailUrl: ComputedRef; + /** + * Options (of variation) for the current item + */ itemOptions: ComputedRef; + /** + * Type of the current item: "product" or "promotion" + */ itemType: ComputedRef; + /** + * Determines if the current item is a product + */ isProduct: ComputedRef; + /** + * Determines if the current item is a promotion + */ isPromotion: ComputedRef; + /** + * Stock information for the current item + */ itemStock: ComputedRef; + /** + * Quantity of the current item in the cart + */ itemQuantity: ComputedRef; /** * Changes the current item quantity in the cart @@ -32,6 +63,8 @@ export type UseCartItemReturn = { removeItem(): Promise; /** * Get SEO data for the current item + * + * @deprecated */ getProductItemSeoUrlData(): Promise; }; @@ -52,19 +85,25 @@ export function useCartItem(cartItem: Ref): UseCartItemReturn { const itemQuantity = computed(() => cartItem.value.quantity); const itemImageThumbnailUrl = computed(() => getMainImageUrl(cartItem.value)); - // TODO: use helper instead - - const itemRegularPrice = computed(() => cartItem.value.price?.unitPrice); + const itemRegularPrice = computed( + () => + cartItem.value?.price?.listPrice?.price || + cartItem.value?.price?.unitPrice, + ); const itemSpecialPrice = computed( - () => cartItem.value.price?.listPrice && cartItem.value.price.unitPrice + () => + cartItem.value?.price?.listPrice?.price && + cartItem.value?.price?.unitPrice, ); + const itemTotalPrice = computed(() => cartItem.value.price?.totalPrice); + const itemOptions = computed( () => (cartItem.value.type === "product" && (cartItem.value.payload as CartProductItem)?.options) || - [] + [], ); const itemStock = computed(() => cartItem.value.deliveryInformation?.stock); @@ -76,9 +115,8 @@ export function useCartItem(cartItem: Ref): UseCartItemReturn { const isPromotion = computed(() => cartItem.value.type === "promotion"); async function removeItem() { - const result = await removeCartItem(cartItem.value.id, apiInstance); - // broadcastUpcomingErrors(result); - await refreshCart(); + const newCart = await removeCartItem(cartItem.value.id, apiInstance); + await refreshCart(newCart); } async function changeItemQuantity(quantity: number): Promise { @@ -86,9 +124,11 @@ export function useCartItem(cartItem: Ref): UseCartItemReturn { id: cartItem.value.id, quantity: quantity, }); - // broadcastUpcomingErrors(result); } + /** + * @deprecated Method is not used anymore and the case should be solved on project level instead due to performance reasons. + */ async function getProductItemSeoUrlData(): Promise< ProductResponse | undefined > { @@ -104,13 +144,13 @@ export function useCartItem(cartItem: Ref): UseCartItemReturn { // associations: (getDefaults() as any).getProductItemsSeoUrlsData // .associations, }, - apiInstance + apiInstance, ); return result.product as unknown as ProductResponse; } catch (error) { console.error( "[useCart][getProductItemsSeoUrlsData]", - (error as ClientApiError).messages + (error as ClientApiError).messages, ); } @@ -123,6 +163,7 @@ export function useCartItem(cartItem: Ref): UseCartItemReturn { getProductItemSeoUrlData, itemRegularPrice, itemSpecialPrice, + itemTotalPrice, itemOptions, itemStock, itemQuantity, diff --git a/templates/vue-demo-store/components/checkout/CheckoutCartItem.vue b/templates/vue-demo-store/components/checkout/CheckoutCartItem.vue index 80df6058a..7c3dcb0e2 100644 --- a/templates/vue-demo-store/components/checkout/CheckoutCartItem.vue +++ b/templates/vue-demo-store/components/checkout/CheckoutCartItem.vue @@ -9,7 +9,7 @@ const props = withDefaults( }>(), { maxQty: 100, - } + }, ); const { cartItem } = toRefs(props); @@ -19,7 +19,7 @@ const isLoading = ref(false); const { itemOptions, removeItem, - itemRegularPrice, + itemTotalPrice, itemQuantity, isPromotion, changeItemQuantity, @@ -49,78 +49,36 @@ const removeCartItem = async () => {