diff --git a/packages/api-client/src/api/cartTotalQty/cartTotalQty.ts b/packages/api-client/src/api/cartTotalQty/cartTotalQty.ts new file mode 100644 index 000000000..8eac89fd1 --- /dev/null +++ b/packages/api-client/src/api/cartTotalQty/cartTotalQty.ts @@ -0,0 +1,9 @@ +import gql from 'graphql-tag'; + +export default gql` + query cart($cartId: String!) { + cart(cart_id:$cartId) { + total_quantity + } + } +`; diff --git a/packages/api-client/src/api/cartTotalQty/index.ts b/packages/api-client/src/api/cartTotalQty/index.ts new file mode 100644 index 000000000..9cdcee016 --- /dev/null +++ b/packages/api-client/src/api/cartTotalQty/index.ts @@ -0,0 +1,25 @@ +import { ApolloQueryResult } from '@apollo/client/core'; +import { CustomQuery } from '@vue-storefront/core'; +import { CartQuery, CartQueryVariables } from '../../types/GraphQL'; +import cart from './cartTotalQty'; +import { Context } from '../../types/context'; + +export default async ( + context: Context, + cartId: string, + customQuery: CustomQuery = { cart: 'cart' }, +): Promise> => { + const { cart: cartGQL } = context.extendQuery( + customQuery, + { + cart: { + query: cart, + variables: { cartId }, + }, + }, + ); + return context.client.query({ + query: cartGQL.query, + variables: cartGQL.variables, + }); +}; diff --git a/packages/api-client/src/api/index.ts b/packages/api-client/src/api/index.ts index 62cf07f2d..cf9830eeb 100644 --- a/packages/api-client/src/api/index.ts +++ b/packages/api-client/src/api/index.ts @@ -8,6 +8,7 @@ export { default as addVirtualProductsToCart } from './addVirtualProductsToCart' export { default as applyCouponToCart } from './applyCouponToCart'; export { default as availableStores } from './availableStores'; export { default as cart } from './cart'; +export { default as cartTotalQty } from './cartTotalQty'; export { default as categoryList } from './categoryList'; export { default as categorySearch } from './categorySearch'; export { default as changeCustomerPassword } from './changeCustomerPassword'; diff --git a/packages/api-client/src/types/API.ts b/packages/api-client/src/types/API.ts index 3ee9c00bd..95e0226bf 100644 --- a/packages/api-client/src/types/API.ts +++ b/packages/api-client/src/types/API.ts @@ -212,6 +212,11 @@ export interface MagentoApiMethods { customQuery?: CustomQuery ): Promise>; + cartTotalQty( + cartId: string, + customQuery?: CustomQuery + ): Promise>; + categoryList( categoryFilter?: CategoryListQueryVariables, customQuery?: CustomQuery diff --git a/packages/composables/src/composables/useCart/index.ts b/packages/composables/src/composables/useCart/index.ts index 6383819e0..452deac9e 100644 --- a/packages/composables/src/composables/useCart/index.ts +++ b/packages/composables/src/composables/useCart/index.ts @@ -384,6 +384,12 @@ const factoryParams: UseCartFactoryParams = { product, }, ) => !!currentCart?.items.find((cartItem) => cartItem?.product?.uid === product.uid), + loadTotalQty: async (context: Context) => { + const apiState = context.$magento.config.state; + const { data } : any = await context.$magento.api.cartTotalQty(apiState.getCartId()); + + return data.cart.total_quantity; + }, }; export default useCartFactory(factoryParams); diff --git a/packages/composables/src/factories/useCartFactory.ts b/packages/composables/src/factories/useCartFactory.ts index b8a4e3429..55d7d3eeb 100644 --- a/packages/composables/src/factories/useCartFactory.ts +++ b/packages/composables/src/factories/useCartFactory.ts @@ -1,10 +1,12 @@ import { - CustomQuery, UseCart, Context, FactoryParams, UseCartErrors, PlatformApi, sharedRef, Logger, configureFactoryParams, ComposableFunctionArgs, + UseCart as UseCartCore, Context, FactoryParams, UseCartErrors as UseCartErrorsCore, PlatformApi, sharedRef, Logger, configureFactoryParams, ComposableFunctionArgs, } from '@vue-storefront/core'; import { computed, Ref } from '@vue/composition-api'; +import { ComputedProperty, CustomQuery } from '@vue-storefront/core/lib/src/types'; export interface UseCartFactoryParams extends FactoryParams { load: (context: Context, params: ComposableFunctionArgs<{ realCart?: boolean; }>) => Promise; + loadTotalQty: (context: Context) => Promise; addItem: ( context: Context, params: ComposableFunctionArgs<{ @@ -27,11 +29,22 @@ export interface UseCartFactoryParams boolean; } +export interface UseCart extends UseCartCore { + totalQuantity: ComputedProperty, + loadTotalQty(params: { + customQuery?: CustomQuery; + }): Promise; +} +export interface UseCartErrors extends UseCartErrorsCore { + loadTotalQty: Error +} + export const useCartFactory = ( factoryParams: UseCartFactoryParams, ) => function useCart(): UseCart { const loading: Ref = sharedRef(false, 'useCart-loading'); const cart: Ref = sharedRef(null, 'useCart-cart'); + const totalQuantity: Ref = sharedRef(0, 'useCart-totalQuantity'); const error: Ref = sharedRef({ addItem: null, removeItem: null, @@ -40,6 +53,7 @@ export const useCartFactory = { + Logger.debug('useCart.loadTotalQty'); + + try { + loading.value = true; + totalQuantity.value = await _factoryParams.loadTotalQty({ customQuery }); + error.value.loadTotalQty = null; + } catch (err) { + error.value.loadTotalQty = err; + Logger.error('useCart/loadTotalQty', err); + } finally { + loading.value = false; + } + }; + const clear = async () => { Logger.debug('useCart.clear'); @@ -172,6 +207,7 @@ export const useCartFactory = cart.value), + totalQuantity, isInCart, addItem, load, + loadTotalQty, removeItem, clear, updateItemQty, diff --git a/packages/theme/components/AppHeader.vue b/packages/theme/components/AppHeader.vue index 0719005ad..eff73e1c2 100644 --- a/packages/theme/components/AppHeader.vue +++ b/packages/theme/components/AppHeader.vue @@ -171,7 +171,6 @@ import { SfOverlay, } from '@storefront-ui/vue'; import { - cartGetters, categoryGetters, useCart, useCategory, @@ -187,8 +186,8 @@ import { defineComponent, useRouter, useContext, + useAsync, } from '@nuxtjs/composition-api'; -import { onSSR } from '@vue-storefront/core'; import { clickOutside } from '@storefront-ui/vue/src/utilities/directives/click-outside/click-outside-directive.js'; import { mapMobileObserver, @@ -221,12 +220,11 @@ export default defineComponent({ const { toggleCartSidebar, toggleWishlistSidebar, toggleLoginModal } = useUiState(); const { setTermForUrl, getFacetsFromURL, getAgnosticCatLink } = useUiHelpers(); const { isAuthenticated } = useUser(); - const { cart } = useCart(); + const { totalQuantity, loadTotalQty } = useCart(); const { wishlist } = useWishlist('GlobalWishlist'); const { result: searchResult, search: productsSearch, - // loading: productsLoading, } = useFacet('AppHeader:Products'); const { result: categories, @@ -245,11 +243,6 @@ export default defineComponent({ const wishlistHasProducts = computed(() => wishlistGetters.getTotalItems(wishlist.value) > 0); const wishlistItemsQty = computed(() => wishlistGetters.getTotalItems(wishlist.value)); - const cartTotalItems = computed(() => { - const count = cartGetters.getTotalItems(cart.value); - return count ? count.toString() : null; - }); - const accountIcon = computed(() => (isAuthenticated.value ? 'profile_fill' : 'profile')); const categoryTree = computed(() => categoryGetters.getCategoryTree(categoryList.value?.[0])?.items.filter((c) => c.count > 0)); @@ -262,10 +255,8 @@ export default defineComponent({ } }; - onSSR(async () => { - await categoriesListSearch({ - pageSize: 20, - }); + useAsync(async () => { + await Promise.all([loadTotalQty(), categoriesListSearch({ pageSize: 20 })]); }); const showSearch = () => { @@ -332,7 +323,7 @@ export default defineComponent({ return { accountIcon, - cartTotalItems, + cartTotalItems: totalQuantity, categoryTree, closeOrFocusSearchBar, closeSearch, diff --git a/packages/theme/components/CartSidebar.vue b/packages/theme/components/CartSidebar.vue index 8c28dbe61..ad3928ba8 100644 --- a/packages/theme/components/CartSidebar.vue +++ b/packages/theme/components/CartSidebar.vue @@ -38,7 +38,7 @@ >
- -
- - -
+ -
- - +
+ - - - - + + + + + +
-
-
-
- - +
+
+ + +
-
- + +