├── .editorconfig ├── .env ├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── 1.bug-report.yml │ ├── 2.documentation-issue.yml │ ├── 3.feature-request.yml │ ├── 4.question.yml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ ├── deploy-storefrontcloud.yml │ ├── docs-v1-deployment.yml │ └── test_vsf1.yml ├── .gitignore ├── .gitmodules ├── .gitpod.yml ├── .huskyrc.js ├── .jshintrc ├── .lintstagedrc.js ├── .node-version ├── .nvmrc ├── .postcssrc ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── config ├── custom-environment-variables.json ├── default.json └── test.json ├── core ├── app.ts ├── build │ ├── dev-server.js │ ├── module-build.config.js │ ├── purge-config │ │ ├── purgeConfig.ts │ │ └── purgeConfigLoader.ts │ ├── theme-path.js │ ├── webpack.base.config.ts │ ├── webpack.client.config.ts │ ├── webpack.prod.client.config.ts │ ├── webpack.prod.server.config.ts │ ├── webpack.prod.sw.config.ts │ └── webpack.server.config.ts ├── client-entry.ts ├── compatibility │ ├── README.md │ ├── components │ │ ├── AddToCart.js │ │ ├── Breadcrumbs.js │ │ ├── GenericSelector.js │ │ ├── Notification.js │ │ ├── Overlay.js │ │ ├── PriceSelector.js │ │ ├── SortBy.js │ │ ├── ValidationError.js │ │ └── blocks │ │ │ ├── Auth │ │ │ ├── Login.js │ │ │ └── Register.js │ │ │ ├── Category │ │ │ └── Sidebar.js │ │ │ ├── Header │ │ │ ├── AccountIcon.js │ │ │ ├── CompareIcon.js │ │ │ ├── HamburgerIcon.js │ │ │ ├── MicrocartIcon.js │ │ │ ├── ReturnIcon.js │ │ │ ├── SearchIcon.js │ │ │ └── WishlistIcon.js │ │ │ ├── Microcart │ │ │ ├── Microcart.js │ │ │ └── Product.js │ │ │ ├── MyAccount │ │ │ ├── MyOrder.js │ │ │ ├── MyOrders.js │ │ │ ├── MyProfile.js │ │ │ └── MyShippingDetails.js │ │ │ ├── SearchPanel │ │ │ └── SearchPanel.js │ │ │ ├── SidebarMenu │ │ │ └── SidebarMenu.js │ │ │ └── Wishlist │ │ │ ├── Product.js │ │ │ └── Wishlist.js │ └── plugins │ │ ├── config │ │ └── index.js │ │ ├── event-bus │ │ └── index.js │ │ └── index.js ├── data-resolver │ ├── CartService.ts │ ├── CategoryService.ts │ ├── NewsletterService.ts │ ├── OrderService.ts │ ├── ProductService.ts │ ├── ReviewsService.ts │ ├── StockService.ts │ ├── UserService.ts │ ├── index.ts │ └── types │ │ └── DataResolver.d.ts ├── filters │ ├── capitalize.js │ ├── date.js │ ├── html-decode.js │ ├── index.js │ ├── price.js │ ├── product-messages.ts │ └── strip-html.js ├── helpers │ ├── getApiEndpointUrl.ts │ ├── index.ts │ ├── initialStateFactory.ts │ ├── internal.ts │ ├── router.ts │ ├── test │ │ └── unit │ │ │ ├── getThumbnailPath.spec.ts │ │ │ ├── processURLAddress.spec.ts │ │ │ └── slugify.spec.ts │ └── validators │ │ └── index.ts ├── hooks.ts ├── i18n │ ├── .gitignore │ ├── helpers.ts │ ├── index.ts │ ├── intl.ts │ ├── package.json │ ├── resource │ │ ├── countries.json │ │ ├── i18n │ │ │ ├── ar-SA.csv │ │ │ ├── cs-CZ.csv │ │ │ ├── de-DE.csv │ │ │ ├── en-US.csv │ │ │ ├── es-ES.csv │ │ │ ├── et-EE.csv │ │ │ ├── fi-FI.csv │ │ │ ├── fr-FR.csv │ │ │ ├── it-IT.csv │ │ │ ├── ja-JP.csv │ │ │ ├── nl-NL.csv │ │ │ ├── pl-PL.csv │ │ │ ├── pt-BR.csv │ │ │ ├── pt-PT.csv │ │ │ ├── ru-RU.csv │ │ │ └── zh-cn.csv │ │ └── states.json │ └── scripts │ │ └── translation.preprocessor.js ├── lib │ ├── async-data-loader.ts │ ├── hooks.ts │ ├── logger.ts │ ├── module │ │ ├── helpers.ts │ │ ├── index.ts │ │ └── types.ts │ ├── modules.ts │ ├── multistore.ts │ ├── passive-listeners.js │ ├── router-manager.ts │ ├── search.ts │ ├── search │ │ └── adapter │ │ │ ├── SeachAdapterInterface.ts │ │ │ ├── api-search-query │ │ │ └── searchAdapter.ts │ │ │ ├── api │ │ │ └── searchAdapter.ts │ │ │ ├── searchAdapterFactory.js │ │ │ └── test │ │ │ └── unit │ │ │ └── searchAdapterFactory.spec.ts │ ├── storage-manager.ts │ ├── store │ │ ├── entities.ts │ │ ├── filters.ts │ │ └── storage.ts │ ├── storeCodeFromRoute.ts │ ├── sync │ │ ├── helpers │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── task.ts │ │ └── types │ │ │ └── Task.ts │ ├── test │ │ └── unit │ │ │ ├── logger.spec.ts │ │ │ └── multistore.spec.ts │ ├── themes.ts │ └── types.ts ├── mixins │ ├── composite.js │ ├── index.js │ ├── multistore.js │ ├── onBottomScroll.js │ ├── onEscapePress.js │ └── thumbnail.js ├── modules-entry.ts ├── modules │ ├── breadcrumbs │ │ ├── README.md │ │ ├── components │ │ │ └── Breadcrumbs.ts │ │ ├── helpers │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── store │ │ │ └── index.ts │ │ └── test │ │ │ └── unit │ │ │ └── parseCategoryPath.spec.ts │ ├── cart │ │ ├── components │ │ │ ├── AddToCart.ts │ │ │ ├── Microcart.ts │ │ │ ├── MicrocartButton.ts │ │ │ └── Product.ts │ │ ├── helpers │ │ │ ├── calculateTotals.ts │ │ │ ├── cartCacheHandler.ts │ │ │ ├── createCartItemForUpdate.ts │ │ │ ├── createDiffLog.ts │ │ │ ├── createOrderData.ts │ │ │ ├── createShippingInfoData.ts │ │ │ ├── getProductConfiguration.ts │ │ │ ├── getProductOptions.ts │ │ │ ├── getThumbnailForProduct.ts │ │ │ ├── index.ts │ │ │ ├── notifications.ts │ │ │ ├── optimizeProduct.ts │ │ │ ├── preparePaymentMethodsToSync.ts │ │ │ ├── prepareProductsToAdd.ts │ │ │ ├── prepareShippingInfoForUpdateTotals.ts │ │ │ ├── productChecksum.ts │ │ │ ├── productsEquals.ts │ │ │ ├── syncCartWhenLocalStorageChange.ts │ │ │ ├── totalsCacheHandler.ts │ │ │ └── validateProduct.ts │ │ ├── hooks │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── store │ │ │ ├── actions │ │ │ │ ├── connectActions.ts │ │ │ │ ├── couponActions.ts │ │ │ │ ├── index.ts │ │ │ │ ├── itemActions.ts │ │ │ │ ├── mergeActions.ts │ │ │ │ ├── methodsActions.ts │ │ │ │ ├── productActions.ts │ │ │ │ ├── quantityActions.ts │ │ │ │ ├── synchronizeActions.ts │ │ │ │ └── totalsActions.ts │ │ │ ├── getters.ts │ │ │ ├── index.ts │ │ │ ├── mutation-types.ts │ │ │ └── mutations.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── components │ │ │ │ ├── AddToCart.spec.ts │ │ │ │ ├── Microcart.spec.ts │ │ │ │ ├── MicrocartButton.spec.ts │ │ │ │ └── Product.spec.ts │ │ │ │ ├── helpers │ │ │ │ ├── cartCacheHandler.spec.ts │ │ │ │ ├── createOrderData.spec.ts │ │ │ │ ├── createShippingInfoData.spec.ts │ │ │ │ ├── prepareProductsToAdd.spec.ts │ │ │ │ ├── prepareShippingInfoForUpdateTotals.spec.ts │ │ │ │ ├── productChecksum.spec.ts │ │ │ │ ├── productEquals.spec.ts │ │ │ │ ├── totalsCacheHandler.spec.ts │ │ │ │ └── validateProduct.spec.ts │ │ │ │ ├── index.spec.ts │ │ │ │ └── store │ │ │ │ ├── connectActions.spec.ts │ │ │ │ ├── couponActions.spec.ts │ │ │ │ ├── getters.spec.ts │ │ │ │ ├── index.spec.ts │ │ │ │ ├── itemActions.spec.ts │ │ │ │ ├── mergeActions.spec.ts │ │ │ │ ├── methodsActions.spec.ts │ │ │ │ ├── mutations.spec.ts │ │ │ │ ├── productActions.spec.ts │ │ │ │ ├── quantityActions.spec.ts │ │ │ │ ├── synchronizeActions.spec.ts │ │ │ │ └── totalsActions.spec.ts │ │ └── types │ │ │ ├── AppliedCoupon.ts │ │ │ ├── BillingAddress.ts │ │ │ ├── CartItem.ts │ │ │ ├── CartItemOption.ts │ │ │ ├── CartItemTotals.ts │ │ │ ├── CartState.ts │ │ │ ├── CartTotalSegments.ts │ │ │ ├── CartTotalSegmentsItem.ts │ │ │ ├── CheckoutData.ts │ │ │ ├── DiffLog.ts │ │ │ ├── OrderShippingDetails.ts │ │ │ ├── PaymentMethod.ts │ │ │ ├── ShippingAddress.ts │ │ │ ├── ShippingMethod.ts │ │ │ └── Totals.ts │ ├── catalog-next │ │ ├── helpers │ │ │ ├── cacheProductsHelper.ts │ │ │ ├── categoryHelpers.ts │ │ │ ├── filterHelpers.ts │ │ │ └── optionLabel.ts │ │ ├── hooks.ts │ │ ├── index.ts │ │ ├── store │ │ │ └── category │ │ │ │ ├── CategoryState.ts │ │ │ │ ├── actions.ts │ │ │ │ ├── deprecatedActions.ts │ │ │ │ ├── getters.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── _prepareCategoryPathIds.spec.ts │ │ │ │ ├── changeFilterQuery.spec.ts │ │ │ │ ├── getFiltersFromQuery.spec.ts │ │ │ │ └── prefetchStockItems.spec.ts │ │ └── types │ │ │ ├── Category.d.ts │ │ │ └── FilterVariant.ts │ ├── catalog │ │ ├── components │ │ │ ├── CategoryFilters.ts │ │ │ ├── CategorySort.ts │ │ │ ├── ProductAttribute.ts │ │ │ ├── ProductBundleOption.ts │ │ │ ├── ProductBundleOptions.ts │ │ │ ├── ProductCustomOption.ts │ │ │ ├── ProductCustomOptions.ts │ │ │ ├── ProductGallery.ts │ │ │ ├── ProductOption.ts │ │ │ ├── ProductTile.ts │ │ │ ├── ProductVideo.ts │ │ │ └── Search.ts │ │ ├── events.ts │ │ ├── helpers │ │ │ ├── associatedProducts │ │ │ │ ├── buildQuery.ts │ │ │ │ ├── getAttributesFromMetadata.ts │ │ │ │ ├── getBundleProductPrice.ts │ │ │ │ ├── getGroupedProductPrice.ts │ │ │ │ ├── getProductLinkPrice.ts │ │ │ │ ├── index.ts │ │ │ │ ├── setBundleProducts.ts │ │ │ │ ├── setGroupedProduct.ts │ │ │ │ └── setProductLink.ts │ │ │ ├── bundleOptions.ts │ │ │ ├── configure │ │ │ │ ├── configureProductAsync.ts │ │ │ │ ├── configureProducts.ts │ │ │ │ └── index.ts │ │ │ ├── createAttributesListQuery.ts │ │ │ ├── createCategoryListQuery.ts │ │ │ ├── customOption.ts │ │ │ ├── deprecatedHelpers.ts │ │ │ ├── filterAttributes.ts │ │ │ ├── filters.ts │ │ │ ├── getProductGallery.ts │ │ │ ├── index.ts │ │ │ ├── optionLabel.ts │ │ │ ├── prefetchCachedAttributes.ts │ │ │ ├── prepare │ │ │ │ ├── index.ts │ │ │ │ ├── setCustomAttributesForChild.ts │ │ │ │ ├── setDefaultObjects.ts │ │ │ │ ├── setDefaultProductOptions.ts │ │ │ │ ├── setDefaultQty.ts │ │ │ │ ├── setParentId.ts │ │ │ │ └── setParentSku.ts │ │ │ ├── price │ │ │ │ ├── doPlatformPricesSync.ts │ │ │ │ ├── index.ts │ │ │ │ └── syncProductPrice.ts │ │ │ ├── productOptions │ │ │ │ ├── getAllProductConfigurations.ts │ │ │ │ ├── getAttributeCode.ts │ │ │ │ ├── getInternalOptionsFormat.ts │ │ │ │ ├── getProductConfiguration.ts │ │ │ │ ├── getProductConfigurationOptions.ts │ │ │ │ ├── getSelectedOption.ts │ │ │ │ ├── index.ts │ │ │ │ ├── omitInternalOptionsFormat.ts │ │ │ │ └── setProductConfigurableOptions.ts │ │ │ ├── reduceAttributesLists.ts │ │ │ ├── registerProductsMapping.ts │ │ │ ├── search.ts │ │ │ ├── slugifyCategories.ts │ │ │ ├── stock │ │ │ │ ├── filterChildrenByStockitem.ts │ │ │ │ ├── filterOutUnavailableVariants.ts │ │ │ │ ├── getProductInfos.ts │ │ │ │ ├── getStatus.ts │ │ │ │ ├── getStockItems.ts │ │ │ │ └── index.ts │ │ │ ├── taxCalc.ts │ │ │ ├── transformMetadataToAttributes.ts │ │ │ └── variant │ │ │ │ ├── findConfigurableVariant.ts │ │ │ │ ├── getConfigurationMatchLevel.ts │ │ │ │ ├── getSelectedVariant.ts │ │ │ │ ├── getVariantWithLowestPrice.ts │ │ │ │ ├── index.ts │ │ │ │ ├── isOptionAvailable.ts │ │ │ │ └── omitSelectedVariantFields.ts │ │ ├── hooks │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── queries │ │ │ ├── common.js │ │ │ ├── related.js │ │ │ └── searchPanel.js │ │ ├── store │ │ │ ├── attribute │ │ │ │ ├── actions.ts │ │ │ │ ├── getters.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ │ ├── category │ │ │ │ ├── actions.ts │ │ │ │ ├── getters.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ │ ├── product │ │ │ │ ├── actions.ts │ │ │ │ ├── deprecatedActions.ts │ │ │ │ ├── getters.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ │ ├── stock │ │ │ │ ├── actions.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ │ └── tax │ │ │ │ ├── actions.ts │ │ │ │ ├── getters.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ ├── test │ │ │ ├── helpers │ │ │ │ └── createProduct.ts │ │ │ └── unit │ │ │ │ ├── helpers │ │ │ │ ├── associatedProducts │ │ │ │ │ ├── setBundleProduct.spec.ts │ │ │ │ │ ├── setGroupedProduct.spec.ts │ │ │ │ │ └── setProductLink.spec.ts │ │ │ │ └── filters.spec.ts │ │ │ │ └── store │ │ │ │ └── product │ │ │ │ └── actions │ │ │ │ ├── findProducts.spec.ts │ │ │ │ ├── getProductVariant.spec.ts │ │ │ │ ├── list.spec.ts │ │ │ │ ├── setCurrent.spec.ts │ │ │ │ └── single.spec.ts │ │ └── types │ │ │ ├── Attribute.ts │ │ │ ├── AttributeState.ts │ │ │ ├── BundleOption.ts │ │ │ ├── CategoryState.ts │ │ │ ├── ConfigurableOption.ts │ │ │ ├── CustomOption.ts │ │ │ ├── Product.ts │ │ │ ├── ProductConfiguration.ts │ │ │ ├── ProductState.ts │ │ │ ├── StockState.ts │ │ │ └── TaxState.ts │ ├── checkout │ │ ├── components │ │ │ ├── CartSummary.ts │ │ │ ├── OrderReview.ts │ │ │ ├── Payment.ts │ │ │ ├── PersonalDetails.ts │ │ │ ├── Product.ts │ │ │ └── Shipping.ts │ │ ├── index.ts │ │ ├── store │ │ │ ├── checkout │ │ │ │ ├── actions.ts │ │ │ │ ├── getters.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ │ ├── payment │ │ │ │ └── index.ts │ │ │ └── shipping │ │ │ │ └── index.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── components │ │ │ │ ├── CartSummary.spec.ts │ │ │ │ ├── OrderReview.spec.ts │ │ │ │ ├── Payment.spec.ts │ │ │ │ ├── PersonalDetails.spec.ts │ │ │ │ ├── Product.spec.ts │ │ │ │ └── Shipping.spec.ts │ │ │ │ ├── index.spec.ts │ │ │ │ └── store │ │ │ │ ├── checkout │ │ │ │ ├── actions.spec.ts │ │ │ │ ├── getters.spec.ts │ │ │ │ └── mutations.spec.ts │ │ │ │ ├── payment │ │ │ │ └── index.spec.ts │ │ │ │ └── shipping │ │ │ │ └── index.spec.ts │ │ └── types │ │ │ ├── CheckoutState.ts │ │ │ ├── PaymentDetails.ts │ │ │ ├── PaymentState.ts │ │ │ ├── ShippingDetails.ts │ │ │ └── ShippingState.ts │ ├── cms │ │ ├── helpers │ │ │ ├── createHierarchyLoadQuery.ts │ │ │ ├── createLoadingBlockQuery.ts │ │ │ ├── createPageLoadingQuery.ts │ │ │ ├── createSingleBlockQuery.ts │ │ │ ├── createSinglePageLoadQuery.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── store │ │ │ ├── block │ │ │ │ ├── actions.ts │ │ │ │ ├── getters.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ │ ├── cmsPersistPlugin.ts │ │ │ ├── hierarchy │ │ │ │ ├── actions.ts │ │ │ │ ├── index.ts │ │ │ │ └── mutation-types.ts │ │ │ └── page │ │ │ │ ├── actions.ts │ │ │ │ ├── getters.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutation-types.ts │ │ │ │ └── mutations.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── blockActions.spec.ts │ │ │ │ ├── blockMutations.spec.ts │ │ │ │ ├── createHierarchyLoadQuery.spec.ts │ │ │ │ ├── createLoadingBlockQuery.spec.ts │ │ │ │ ├── createPageLoadingQuery.spec.ts │ │ │ │ ├── createSingleBlockQuery.spec.ts │ │ │ │ ├── createSinglePageLoadQuery.spec.ts │ │ │ │ ├── hierarchyActions.spec.ts │ │ │ │ ├── pageActions.spec.ts │ │ │ │ └── pageMutation.spec.ts │ │ └── types │ │ │ ├── CmsBlockState.ts │ │ │ ├── CmsHierarchyState.ts │ │ │ └── CmsPageState.ts │ ├── compare │ │ ├── components │ │ │ ├── AddToCompare.ts │ │ │ ├── Compare.ts │ │ │ ├── CompareButton.ts │ │ │ ├── IsOnCompare.ts │ │ │ ├── Product.ts │ │ │ └── RemoveFromCompare.ts │ │ ├── index.ts │ │ ├── mixins │ │ │ └── compareMountedMixin.js │ │ ├── store │ │ │ ├── actions.ts │ │ │ ├── getters.ts │ │ │ ├── index.ts │ │ │ ├── mutation-types.ts │ │ │ ├── mutations.ts │ │ │ └── plugin.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── components │ │ │ │ ├── AddToCompare.spec.ts │ │ │ │ ├── Compare.spec.ts │ │ │ │ └── Product.spec.ts │ │ │ │ ├── mixins │ │ │ │ └── compareMountedMixin.spec.ts │ │ │ │ └── store │ │ │ │ ├── actions.spec.ts │ │ │ │ └── mutations.spec.ts │ │ └── types │ │ │ └── CompareState.ts │ ├── initial-resources │ │ ├── clientResourcesLoader.ts │ │ ├── helpers.ts │ │ ├── index.ts │ │ ├── serverResourcesFilter.ts │ │ └── types.ts │ ├── mailer │ │ ├── components │ │ │ └── EmailForm.ts │ │ ├── index.ts │ │ ├── store │ │ │ └── index.ts │ │ ├── test │ │ │ └── unit │ │ │ │ └── sendEmail.spec.ts │ │ └── types │ │ │ └── MailItem.ts │ ├── newsletter │ │ ├── components │ │ │ └── Newsletter.ts │ │ ├── index.ts │ │ ├── mixins │ │ │ ├── Subscribe.ts │ │ │ ├── SubscriptionStatus.ts │ │ │ └── Unsubscribe.ts │ │ ├── store │ │ │ ├── index.ts │ │ │ └── mutation-types.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── components │ │ │ │ └── Newsletter.spec.ts │ │ │ │ ├── mixins │ │ │ │ ├── Subscribe.spec.ts │ │ │ │ ├── SubscriptionStatus.spec.ts │ │ │ │ └── Unsubscribe.spec.ts │ │ │ │ └── store │ │ │ │ └── index.spec.ts │ │ └── types │ │ │ └── NewsletterState.ts │ ├── notification │ │ ├── components │ │ │ └── Notification.ts │ │ ├── index.ts │ │ ├── store │ │ │ └── index.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── actions.spec.ts │ │ │ │ └── mutations.spec.ts │ │ └── types │ │ │ ├── NotificationItem.ts │ │ │ └── NotificationState.ts │ ├── offline-order │ │ ├── README.md │ │ ├── components │ │ │ ├── CancelOrders.ts │ │ │ └── ConfirmOrders.ts │ │ ├── extends │ │ │ └── service-worker.js │ │ └── helpers │ │ │ └── onNetworkStatusChange.ts │ ├── order │ │ ├── components │ │ │ ├── UserOrders.ts │ │ │ ├── UserOrdersHistory.ts │ │ │ └── UserSingleOrder.ts │ │ ├── helpers │ │ │ ├── index.ts │ │ │ ├── notifications.ts │ │ │ ├── optimizeOrder.ts │ │ │ └── prepareOrder.ts │ │ ├── hooks.ts │ │ ├── index.ts │ │ ├── store │ │ │ ├── actions.ts │ │ │ ├── getters.ts │ │ │ ├── index.ts │ │ │ ├── mutation-types.ts │ │ │ ├── mutations.ts │ │ │ ├── order.schema.extension.json │ │ │ └── order.schema.json │ │ ├── test │ │ │ └── unit │ │ │ │ ├── helpers │ │ │ │ ├── optimizeOrder.spec.ts │ │ │ │ └── prepareOrder.spec.ts │ │ │ │ └── store │ │ │ │ ├── actions.spec.ts │ │ │ │ └── mutations.spec.ts │ │ └── types │ │ │ ├── Order.ts │ │ │ └── OrderState.ts │ ├── recently-viewed │ │ ├── components │ │ │ └── RecentlyViewed.js │ │ ├── index.ts │ │ ├── store │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── mutation-types.ts │ │ │ ├── mutations.ts │ │ │ └── plugin.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── actions.spec.ts │ │ │ │ └── mutations.spec.ts │ │ └── types │ │ │ └── RecentlyViewedState.ts │ ├── review │ │ ├── components │ │ │ ├── AddReview.ts │ │ │ └── Reviews.ts │ │ ├── helpers │ │ │ ├── createLoadReviewsQuery.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── store │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── mutation-types.ts │ │ │ └── mutations.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── helpers │ │ │ │ └── createLoadReviewsQuery.spec.ts │ │ │ │ └── store │ │ │ │ ├── actions.spec.ts │ │ │ │ └── mutations.spec.ts │ │ └── types │ │ │ ├── Review.ts │ │ │ ├── ReviewRequest.ts │ │ │ └── ReviewState.ts │ ├── url │ │ ├── helpers │ │ │ ├── index.ts │ │ │ └── transformUrl.ts │ │ ├── index.ts │ │ ├── router │ │ │ └── beforeEach.ts │ │ ├── store │ │ │ ├── actions.ts │ │ │ ├── getters.ts │ │ │ ├── index.ts │ │ │ ├── mutation-types.ts │ │ │ ├── mutations.ts │ │ │ └── state.ts │ │ ├── test │ │ │ └── unit │ │ │ │ ├── helpers │ │ │ │ ├── data.ts │ │ │ │ ├── formatCategoryLink.spec.ts │ │ │ │ ├── formatProductLink.spec.ts │ │ │ │ ├── normalizeUrlPath.spec.ts │ │ │ │ ├── parametrizeRouteData.spec.ts │ │ │ │ ├── preProcessDynamicRoutes.spec.ts │ │ │ │ └── processDynamicRoute.spec.ts │ │ │ │ └── store │ │ │ │ └── actions.spec.ts │ │ └── types │ │ │ └── UrlState.ts │ ├── user │ │ ├── components │ │ │ ├── AccountButton.ts │ │ │ ├── Login.ts │ │ │ ├── Register.ts │ │ │ ├── UserAccount.ts │ │ │ └── UserShippingDetails.ts │ │ ├── hooks.ts │ │ ├── index.ts │ │ ├── store │ │ │ ├── actions.ts │ │ │ ├── getters.ts │ │ │ ├── index.ts │ │ │ ├── mutation-types.ts │ │ │ └── mutations.ts │ │ ├── test │ │ │ └── unit │ │ │ │ └── store │ │ │ │ ├── actions.spec.ts │ │ │ │ ├── data.ts │ │ │ │ └── mutations.spec.ts │ │ └── types │ │ │ ├── UserProfile.ts │ │ │ └── UserState.ts │ └── wishlist │ │ ├── components │ │ ├── AddToWishlist.ts │ │ ├── IsOnWishlist.ts │ │ ├── Product.ts │ │ ├── RemoveFromWishlist.ts │ │ ├── Wishlist.ts │ │ └── WishlistButton.ts │ │ ├── index.ts │ │ ├── mixins │ │ └── wishlistMountedMixin.js │ │ ├── store │ │ ├── actions.ts │ │ ├── getters.ts │ │ ├── index.ts │ │ ├── mutation-types.ts │ │ ├── mutations.ts │ │ └── whishListPersistPlugin.ts │ │ ├── test │ │ └── unit │ │ │ ├── components │ │ │ ├── AddToWishlist.spec.ts │ │ │ ├── IsOnWishlist.spec.ts │ │ │ ├── Product.spec.ts │ │ │ ├── RemoveFromWishlist.spec.ts │ │ │ ├── Wishlist.spec.ts │ │ │ └── WishlistButton.spec.ts │ │ │ ├── mixins │ │ │ └── wishlistMountedMixin.spec.ts │ │ │ └── store │ │ │ ├── actions.spec.ts │ │ │ ├── getters.spec.ts │ │ │ ├── mutations.spec.ts │ │ │ └── whishListPersistPlugin.spec.ts │ │ └── types │ │ └── WishlistState.ts ├── package.json ├── pages │ ├── Category.js │ ├── Checkout.js │ ├── CmsPage.js │ ├── Compare.js │ ├── Compilation.js │ ├── Error.js │ ├── Home.js │ ├── MyAccount.js │ ├── PageNotFound.js │ └── Product.js ├── scripts │ ├── all.js │ ├── cache.js │ ├── generate-files.ts │ ├── generate.ts │ ├── installer.js │ ├── resolvers │ │ └── resolveGraphQL.js │ ├── server.ts │ ├── static-server.ts │ └── utils │ │ ├── api-status.js │ │ ├── cache-instance.js │ │ ├── catalog-client.ts │ │ ├── page-generator.ts │ │ ├── sort-translations.js │ │ ├── ssr-renderer.ts │ │ └── types │ │ └── index.ts ├── server-entry.ts ├── server │ └── hooks.ts ├── service-worker │ ├── index.js │ └── registration.js ├── store │ ├── actions.ts │ ├── getters.ts │ ├── index.ts │ ├── mutation-types.ts │ └── mutations.ts ├── test │ └── unit │ │ └── helpers │ │ └── buildFilterProductsQuery.spec.ts └── types │ ├── RootState.ts │ ├── asyncData.d.ts │ ├── isomorphic-fetch.d.ts │ └── search │ ├── HttpQuery.ts │ ├── SearchRequest.ts │ └── SearchResponse.ts ├── cypress.json ├── dev └── docker │ ├── Dockerfile │ └── vue-storefront.sh ├── docker-compose.yml ├── docker └── vue-storefront │ ├── Dockerfile │ ├── default.env │ └── vue-storefront.sh ├── docs ├── .vuepress │ ├── config.js │ ├── public │ │ ├── Apple_iPhone_X.png │ │ ├── Fil-Rakowski-VS-Demo-Youtube.png │ │ ├── GitHub-Architecture-VS.png │ │ ├── Vue-storefront-architecture-proxy-requests.png │ │ ├── Vue-storefront-architecture.png │ │ ├── cart-localstorage.png │ │ ├── cart-sync.png │ │ ├── categories-localstorage.png │ │ ├── chrome-dev-console.png │ │ ├── favicon.png │ │ ├── logo.png │ │ ├── magento_1.png │ │ ├── magento_2.png │ │ ├── magento_3.png │ │ ├── o2m-output.png │ │ ├── orders-collection.png │ │ ├── orders-localstorage.png │ │ ├── partners │ │ │ ├── develo.png │ │ │ └── macopedia.svg │ │ ├── paypal.svg │ │ ├── storefront.png │ │ ├── syncTasks-example.png │ │ ├── video-webcast-1.png │ │ ├── video-webcast-2.png │ │ ├── vs-video.png │ │ ├── vsf-full.svg │ │ └── vuelogo.jpg │ ├── styles │ │ └── index.styl │ └── theme │ │ ├── index.js │ │ └── layouts │ │ └── Layout.vue ├── CNAME ├── Dockerfile ├── README.md ├── build-docker.sh ├── deploy.sh ├── guide │ ├── README.md │ ├── archives │ │ ├── amp.md │ │ ├── components.md │ │ ├── cookbook.md │ │ ├── entity_type.md │ │ ├── extensions.md │ │ ├── graphql.md │ │ ├── migration.md │ │ ├── modules.md │ │ ├── modules │ │ │ └── introduction.md │ │ ├── typescript.md │ │ └── vuex.md │ ├── basics │ │ ├── assets │ │ │ ├── release-cycle-1.png │ │ │ ├── release-cycle-2.png │ │ │ └── release-cycle-3.png │ │ ├── configuration.md │ │ ├── contributing.md │ │ ├── e2e.md │ │ ├── feature-list.md │ │ ├── graphql.md │ │ ├── project-structure.md │ │ ├── recipes.md │ │ ├── release-cycle.md │ │ ├── security.md │ │ ├── ssr-cache.md │ │ ├── static-generator.md │ │ └── url.md │ ├── components │ │ ├── category-page.md │ │ ├── events-list.md │ │ ├── home-page.md │ │ ├── modal.md │ │ └── product.md │ ├── cookbook │ │ ├── checklist.md │ │ ├── common-pitfall.md │ │ ├── data-import.md │ │ ├── devops.md │ │ ├── elastic.md │ │ ├── history.md │ │ ├── integration.md │ │ ├── internals.md │ │ ├── migration.md │ │ ├── module.md │ │ ├── multistores.md │ │ ├── setup.md │ │ ├── tdd.md │ │ ├── theme.md │ │ └── vue.md │ ├── core-themes │ │ ├── core-components-api.md │ │ ├── core-components.md │ │ ├── layouts.md │ │ ├── plugins.md │ │ ├── service-workers.md │ │ ├── stylesheets.md │ │ ├── themes.md │ │ ├── translations.md │ │ ├── ui-store.md │ │ └── webpack.md │ ├── data-resolvers │ │ ├── category-service.md │ │ ├── introduction.md │ │ └── user-service.md │ ├── data │ │ ├── data-loader.md │ │ ├── data-migrations.md │ │ ├── data.md │ │ ├── database-tool.md │ │ ├── elastic-queries.md │ │ ├── elasticsearch.md │ │ ├── entity-types.md │ │ └── static-data.md │ ├── extensions │ │ ├── extending-api.md │ │ ├── extending-server-side-routes.md │ │ ├── extensions-to-modify-results.md │ │ └── introduction.md │ ├── general │ │ └── introduction.md │ ├── images │ │ ├── Apple_iPhone_X.png │ │ ├── GitHub-Architecture-VS-data-import.png │ │ ├── Vue-storefront-architecture-proxy-requests.png │ │ ├── Vue-storefront-architecture.png │ │ ├── cart-localstorage.png │ │ ├── cart-sync.png │ │ ├── categories-localstorage.png │ │ ├── chrome-dev-console.png │ │ ├── data_pump_1.png │ │ ├── data_pump_10.png │ │ ├── data_pump_2.png │ │ ├── data_pump_3.png │ │ ├── data_pump_5.png │ │ ├── data_pump_6.png │ │ ├── data_pump_7.png │ │ ├── data_pump_8.png │ │ ├── data_pump_9.png │ │ ├── data_pump_design.png │ │ ├── data_pump_err_1.png │ │ ├── datum_pump_design.png │ │ ├── delta_error.png │ │ ├── editmodeInMC.png │ │ ├── error_1.11.png │ │ ├── es-map-result.png │ │ ├── home-vuestorefront.png │ │ ├── home_capybara.png │ │ ├── img_catalog_prod.png │ │ ├── img_catalog_prod_fail.png │ │ ├── index-not-found-ex.png │ │ ├── lego_palm.jpeg │ │ ├── magento_1.png │ │ ├── magento_2.png │ │ ├── magento_3.png │ │ ├── microcart_nan.png │ │ ├── npm-run-migrate-result.png │ │ ├── o2m-output.png │ │ ├── orders-collection.png │ │ ├── orders-localstorage.png │ │ ├── organized_lego_bricks.jpeg │ │ ├── paypal.svg │ │ ├── pile_of_legos.png │ │ ├── product_like_state.png │ │ ├── route_liked.png │ │ ├── sss.png │ │ ├── storefront.png │ │ ├── stores.png │ │ ├── success_1.11_home.png │ │ ├── syncTasks-example.png │ │ └── vuelogo.jpg │ ├── installation │ │ ├── etc │ │ │ └── nginx │ │ │ │ └── sites-enabled │ │ │ │ └── prod.vuestorefront.io │ │ ├── linux-mac.md │ │ ├── magento.md │ │ ├── prod.vuestorefront.io │ │ ├── production-setup.md │ │ ├── theme.md │ │ ├── vue-storefront-api │ │ │ └── config │ │ │ │ └── local.json │ │ ├── vue-storefront │ │ │ └── config │ │ │ │ └── local.json │ │ └── windows.md │ ├── integrations │ │ ├── direct-prices-sync.md │ │ ├── integrations.md │ │ ├── multistore.md │ │ ├── payment-gateway.md │ │ ├── paypal-payments.md │ │ ├── reviews.md │ │ ├── tier-prices-sync.md │ │ └── totals-sync.md │ ├── modules │ │ ├── cart.md │ │ ├── catalog.md │ │ ├── checkout.md │ │ ├── introduction.md │ │ ├── order.md │ │ ├── review.md │ │ └── user.md │ ├── security │ │ └── README.md │ ├── upgrade-notes │ │ └── README.md │ └── vuex │ │ ├── attribute-store.md │ │ ├── category-store.md │ │ ├── introduction.md │ │ ├── product-store.md │ │ ├── stock-store.md │ │ ├── sync-store.md │ │ └── vuex-conventions.md ├── now.json └── package.json ├── ecosystem.json ├── kubernetes ├── nginx-configmap.yaml ├── nginx-deployment.yaml ├── nginx-service.yaml ├── vue-storefront-configmap.yaml ├── vue-storefront-deployment.yaml └── vue-storefront-service.yaml ├── lerna.json ├── package.json ├── packages └── cli │ ├── .gitignore │ ├── README.md │ ├── boilerplates │ └── module │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ ├── index.ts │ │ └── store.ts │ │ └── tsconfig.json │ ├── consts.js │ ├── helpers.js │ ├── index.js │ ├── package.json │ ├── scripts │ ├── generateModule.js │ ├── install.js │ ├── installTheme.js │ └── manual.js │ └── themeTasks.js ├── shims.d.ts ├── src ├── index.amp.template.html ├── index.basic.template.html ├── index.minimal.template.html ├── index.template.html ├── modules │ ├── amp-renderer │ │ ├── index.ts │ │ └── router.ts │ ├── client.ts │ ├── compress │ │ └── server.ts │ ├── device │ │ ├── README.md │ │ ├── index.ts │ │ └── logic │ │ │ └── index.ts │ ├── fastly │ │ ├── README.md │ │ └── server.ts │ ├── google-analytics │ │ └── index.ts │ ├── google-cloud-trace │ │ ├── package.json │ │ └── server.ts │ ├── google-tag-manager │ │ ├── hooks │ │ │ └── afterRegistration.ts │ │ ├── index.ts │ │ ├── store │ │ │ └── index.ts │ │ └── types │ │ │ └── GoogleTagManagerState.ts │ ├── hotjar │ │ └── index.ts │ ├── instant-checkout │ │ ├── components │ │ │ └── InstantCheckout.vue │ │ └── index.ts │ ├── payment-backend-methods │ │ ├── index.ts │ │ └── store │ │ │ └── mutation-types.ts │ ├── payment-cash-on-delivery │ │ ├── components │ │ │ └── Info.vue │ │ └── index.ts │ └── robots │ │ └── server.ts └── search │ └── adapter │ └── graphql │ ├── gqlQuery.js │ ├── processor │ └── processType.ts │ ├── queries │ ├── categories.gql │ ├── cmsBlock.gql │ ├── cmsHierarchy.gql │ ├── cmsPage.gql │ ├── customAttributeMetadata.gql │ ├── products.gql │ ├── reviews.gql │ └── taxrule.gql │ └── searchAdapter.ts ├── test ├── e2e │ ├── integration │ │ ├── add-to-cart.js │ │ ├── add-to-compare.js │ │ ├── basic-client-path.js │ │ ├── category-page.js │ │ ├── checkout-page.js │ │ ├── home-page.js │ │ ├── local-storage.js │ │ ├── login-path.js │ │ ├── product-page.js │ │ ├── register-path.js │ │ └── search-results.js │ ├── plugins │ │ └── index.js │ ├── support │ │ ├── commands.js │ │ └── index.js │ └── tsconfig.json └── unit │ ├── cssStub.js │ ├── jest.conf.js │ ├── package.json │ ├── setupTestEnvironment.ts │ └── utils │ └── index.ts ├── tsconfig-build.json ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | COMPOSE_PROJECT_NAME=vue-storefront 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | core/build/*.js 2 | node_modules 3 | packages/module/*.js -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Documentation 4 | url: https://docs.vuestorefront.io/ 5 | about: Find more information about the project and how to implement in our documentation. 6 | - name: Discord Chat 7 | url: https://discord.vuestorefront.io/ 8 | about: Ask questions and discuss with other Vue Storefront users in real time. 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/modules/vsf-cache-nginx"] 2 | path = src/modules/vsf-cache-nginx 3 | url = https://github.com/new-fantastic/vsf-cache-nginx.git 4 | branch = master 5 | [submodule "src/modules/vsf-cache-varnish"] 6 | path = src/modules/vsf-cache-varnish 7 | url = https://github.com/new-fantastic/vsf-cache-varnish.git 8 | branch = master 9 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: | 3 | yarn install 4 | echo '{ "api": { "url": "https://next.storefrontcloud.io" }}' > config/local.json 5 | yarn build 6 | command: yarn dev 7 | 8 | ports: 9 | - port: 3000 10 | onOpen: open-preview 11 | 12 | vscode: 13 | extensions: 14 | - octref.vetur@0.23.0:TEzauMObB6f3i2JqlvrOpA== 15 | - dbaeumer.vscode-eslint@2.0.15:/v3eRFwBI38JLZJv5ExY5g== 16 | - eg2.vscode-npm-script@0.3.11:peDPJqeL8FmmJiabU4fAJQ== 17 | - formulahendry.auto-close-tag@0.5.6:oZ/8R2VhZEhkHsoeO57hSw== 18 | - formulahendry.auto-rename-tag@0.1.1:lKCmLIZAiCM0M8AjDnwCLQ== 19 | - dariofuzinato.vue-peek@1.0.2:oYJg0oZA/6FBnFfW599HRg== 20 | -------------------------------------------------------------------------------- /.huskyrc.js: -------------------------------------------------------------------------------- 1 | const tasks = arr => arr.join(' && ') 2 | 3 | module.exports = { 4 | 'hooks': { 5 | 'pre-commit': tasks([ 6 | 'lint-staged' 7 | ]), 8 | 'pre-push': tasks([ 9 | 'yarn test:unit' 10 | ]) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6 3 | } 4 | -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "*.{js,vue,ts}": "eslint", 3 | "**/i18n/*.csv": ["node ./core/scripts/utils/sort-translations.js", "git add"] 4 | } 5 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | >=8.0.0 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /.postcssrc: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | 'modules': false, 7 | 'useBuiltIns': 'entry', 8 | 'corejs': 2 9 | } 10 | ] 11 | ], 12 | plugins: ['@babel/plugin-syntax-dynamic-import'], 13 | env: { 14 | test: { 15 | plugins: ['transform-es2015-modules-commonjs', 'babel-plugin-dynamic-import-node'], 16 | ignore: [/node_modules\/(?!lodash-es|@vue\/test-utils)/] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /config/custom-environment-variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": { 3 | "host": "BIND_HOST", 4 | "port": "BIND_PORT" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /config/test.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /core/build/module-build.config.js: -------------------------------------------------------------------------------- 1 | // Webpack config used to build VS modules 2 | module.exports = { 3 | mode: 'production', 4 | entry: './src/index.ts', 5 | output: { 6 | libraryTarget: 'umd', 7 | globalObject: 'typeof self !== \'undefined\' ? self : this' 8 | }, 9 | resolve: { 10 | extensions: ['.ts', '.js', '.json'] 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.ts$/, 16 | use: ['ts-loader'], 17 | options: { 18 | transpileOnly: true 19 | }, 20 | exclude: /node_modules/ 21 | } 22 | ] 23 | }, 24 | externals: ['@vue-storefront/core'] 25 | } 26 | -------------------------------------------------------------------------------- /core/build/purge-config/purgeConfig.ts: -------------------------------------------------------------------------------- 1 | import omit from 'lodash/omit'; 2 | 3 | export default config => { 4 | const purgeConfig = (config.purgeConfig || []).slice(); 5 | 6 | config = omit(config, purgeConfig); 7 | delete config['purgeConfig']; 8 | 9 | return config; 10 | } 11 | -------------------------------------------------------------------------------- /core/build/purge-config/purgeConfigLoader.ts: -------------------------------------------------------------------------------- 1 | import purgeConfig from './purgeConfig'; 2 | 3 | /** 4 | * clear config properties that shouldn't be visible on frontend 5 | */ 6 | export default function loader (source) { 7 | let config = JSON.parse(source); 8 | config = purgeConfig(config); 9 | 10 | return JSON.stringify(config); 11 | } 12 | -------------------------------------------------------------------------------- /core/build/webpack.prod.client.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import merge from 'webpack-merge'; 3 | import baseClientConfig from './webpack.client.config'; 4 | const themeRoot = require('./theme-path'); 5 | 6 | const extendedConfig = require(path.join(themeRoot, '/webpack.config.js')) 7 | 8 | const prodClientConfig = merge(baseClientConfig, { 9 | mode: 'production', 10 | devtool: 'nosources-source-map', 11 | plugins: [ 12 | ] 13 | }) 14 | 15 | module.exports = extendedConfig(prodClientConfig, { 16 | isClient: true, 17 | isDev: false 18 | }) 19 | -------------------------------------------------------------------------------- /core/build/webpack.prod.server.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | import baseServerConfig from './webpack.server.config'; 4 | 5 | import themeRoot from './theme-path'; 6 | 7 | const extendedConfig = require(path.join(themeRoot, '/webpack.config.js')) 8 | 9 | export default extendedConfig(baseServerConfig, { 10 | mode: 'production', 11 | devtool: 'nosources-source-map', 12 | isClient: false, 13 | isDev: false 14 | }) 15 | -------------------------------------------------------------------------------- /core/compatibility/README.md: -------------------------------------------------------------------------------- 1 | Outdated VS APIs that shouldn't be used in new projects. They are safe to use in current ones tho since we are providing backward support for them. Most of the components here was refactored and placed inside core modules. -------------------------------------------------------------------------------- /core/compatibility/components/AddToCart.js: -------------------------------------------------------------------------------- 1 | import { AddToCart } from '@vue-storefront/core/modules/cart/components/AddToCart.ts' 2 | 3 | export default { 4 | name: 'AddToCart', 5 | mixins: [ AddToCart ] 6 | } 7 | -------------------------------------------------------------------------------- /core/compatibility/components/Breadcrumbs.js: -------------------------------------------------------------------------------- 1 | // breadcrumbs functionality will be rewritten, and this component is theme-specific 2 | export default { 3 | name: 'Breadcrumbs', 4 | props: { 5 | routes: { 6 | type: Array, 7 | required: true 8 | }, 9 | activeRoute: { 10 | type: String, 11 | default: '' 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/compatibility/components/GenericSelector.js: -------------------------------------------------------------------------------- 1 | import { ProductCustomOption } from '@vue-storefront/core/modules/catalog/components/ProductCustomOption' 2 | // renamed to ProductCustomOption and placed in catalog module 3 | export default { 4 | name: 'GenericSelector', 5 | mixins: [ProductCustomOption] 6 | } 7 | -------------------------------------------------------------------------------- /core/compatibility/components/Overlay.js: -------------------------------------------------------------------------------- 1 | // theme-specific component 2 | export default { 3 | name: 'Overlay', 4 | computed: { 5 | isVisible () { 6 | return this.$store.state.ui.overlay 7 | } 8 | }, 9 | methods: { 10 | close () { 11 | this.$store.commit('ui/setOverlay', false) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/compatibility/components/SortBy.js: -------------------------------------------------------------------------------- 1 | import { CategorySort } from '@vue-storefront/core/modules/catalog/components/CategorySort' 2 | import config from 'config' 3 | 4 | export default { 5 | name: 'SortBy', 6 | methods: { 7 | changeOrder () { 8 | // renamed to sort 9 | this.sort() 10 | } 11 | }, 12 | computed: { 13 | sortByAttribute () { 14 | // renamed to sortingOptions 15 | return config.products.sortByAttributes 16 | } 17 | }, 18 | mixins: [CategorySort] 19 | } 20 | -------------------------------------------------------------------------------- /core/compatibility/components/ValidationError.js: -------------------------------------------------------------------------------- 1 | // theme-specific component 2 | export default { 3 | name: 'ValidationError', 4 | props: { 5 | message: { 6 | type: String, 7 | default: '' 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Auth/Login.js: -------------------------------------------------------------------------------- 1 | import { Login } from '@vue-storefront/core/modules/user/components/Login' 2 | export default { 3 | mixins: [Login] 4 | } 5 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Auth/Register.js: -------------------------------------------------------------------------------- 1 | import { Register } from '@vue-storefront/core/modules/user/components/Register' 2 | export default { 3 | mixins: [Register] 4 | } 5 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Header/AccountIcon.js: -------------------------------------------------------------------------------- 1 | import { AccountButton } from '@vue-storefront/core/modules/user/components/AccountButton' 2 | 3 | export default { 4 | name: 'AccountIcon', 5 | data () { 6 | // theme-specific, deprecated 7 | return { 8 | navigation: [] 9 | } 10 | }, 11 | computed: { 12 | currentUser () { 13 | // renamed to 'user' 14 | return this.user 15 | } 16 | }, 17 | mixins: [AccountButton] 18 | } 19 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Header/CompareIcon.js: -------------------------------------------------------------------------------- 1 | import { CompareButton } from '@vue-storefront/core/modules/compare/components/CompareButton.ts' 2 | 3 | export default { 4 | name: 'CompareIcon', 5 | mixins: [CompareButton], 6 | computed: { 7 | isActive () { 8 | // Computed Property renamed to 'isEmpty' 9 | return !this.isEmpty 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Header/HamburgerIcon.js: -------------------------------------------------------------------------------- 1 | import { mapState } from 'vuex' 2 | 3 | // deprecated as theme specific 4 | export default { 5 | name: 'HamburgerIcon', 6 | computed: mapState({ 7 | isOpen: state => state.ui.sidebar 8 | }), 9 | methods: { 10 | openSidebarMenu () { 11 | this.$store.commit('ui/setSidebar', !this.isOpen) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Header/MicrocartIcon.js: -------------------------------------------------------------------------------- 1 | import { MicrocartButton } from '@vue-storefront/core/modules/cart/components/MicrocartButton.ts' 2 | 3 | export default { 4 | methods: { 5 | openMicrocart () { 6 | // Method renamed to 'toggleMicrocart' and is using cart store now 7 | this.$store.dispatch('ui/toggleMicrocart') 8 | } 9 | }, 10 | computed: { 11 | totalQuantity () { 12 | // Data field renamed to 'quantity' 13 | return this.quantity 14 | } 15 | }, 16 | mixins: [ 17 | MicrocartButton 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Header/ReturnIcon.js: -------------------------------------------------------------------------------- 1 | // deprecated as theme-specific 2 | export default { 3 | name: 'ReturnIcon', 4 | props: { 5 | to: { 6 | type: String | Object, 7 | default: null 8 | } 9 | }, 10 | methods: { 11 | goBack () { 12 | if (this.to) { 13 | this.$router.push(this.to) 14 | } else { 15 | this.$router.back() 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Header/SearchIcon.js: -------------------------------------------------------------------------------- 1 | import { mapState } from 'vuex' 2 | 3 | export default { 4 | name: 'SearchIcon', 5 | computed: { 6 | ...mapState({ 7 | isOpen: state => state.ui.searchpanel 8 | }) 9 | }, 10 | methods: { 11 | toggleSearchpanel () { 12 | this.$store.commit('ui/setSearchpanel', !this.isOpen) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Microcart/Microcart.js: -------------------------------------------------------------------------------- 1 | // Core dependecies 2 | import { Microcart } from '@vue-storefront/core/modules/cart/components/Microcart.ts' 3 | 4 | export default { 5 | methods: { 6 | closeMicrocart () { 7 | // Method renamed to 'toggleMicrocart' 8 | this.toggleMicrocart() 9 | } 10 | }, 11 | computed: { 12 | isMicrocartOpen () { 13 | return this.$store.state.ui.microcart 14 | } 15 | }, 16 | mixins: [ 17 | Microcart 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/MyAccount/MyOrder.js: -------------------------------------------------------------------------------- 1 | import { UserSingleOrder } from '@vue-storefront/core/modules/order/components/UserSingleOrder' 2 | 3 | // Component deprecated, now in Order module 4 | export default { 5 | name: 'MyOrder', 6 | mixins: [UserSingleOrder] 7 | } 8 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/MyAccount/MyOrders.js: -------------------------------------------------------------------------------- 1 | import { UserOrders } from '@vue-storefront/core/modules/order/components/UserOrders' 2 | 3 | // component fully deprecated. Use user/components/Orders instead 4 | export default { 5 | name: 'MyOrders', 6 | mixins: [UserOrders] 7 | } 8 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/MyAccount/MyProfile.js: -------------------------------------------------------------------------------- 1 | import { UserAccount } from '@vue-storefront/core/modules/user/components/UserAccount' 2 | 3 | // Component deprecated, now in User module 4 | 5 | export default { 6 | name: 'MyProfile', 7 | mixins: [UserAccount] 8 | } 9 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/MyAccount/MyShippingDetails.js: -------------------------------------------------------------------------------- 1 | import { UserShippingDetails } from '@vue-storefront/core/modules/user/components/UserShippingDetails' 2 | export default { 3 | mixins: [UserShippingDetails] 4 | } 5 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/SearchPanel/SearchPanel.js: -------------------------------------------------------------------------------- 1 | import { Search } from '@vue-storefront/core/modules/catalog/components/Search' 2 | 3 | // Moved to search module 4 | export default { 5 | mixins: [Search], 6 | computed: { 7 | showPanel () { 8 | return this.isOpen && this.componentLoaded 9 | } 10 | }, 11 | mounted () { 12 | this.$nextTick(() => { 13 | this.componentLoaded = true 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Wishlist/Product.js: -------------------------------------------------------------------------------- 1 | import { WishlistProduct } from '@vue-storefront/core/modules/wishlist/components/Product' 2 | export default { 3 | name: 'Product', 4 | methods: { 5 | // deprecated 6 | closeWishlist () { 7 | this.$store.commit('ui/setWishlist', false) 8 | } 9 | }, 10 | mixins: [WishlistProduct] 11 | } 12 | -------------------------------------------------------------------------------- /core/compatibility/components/blocks/Wishlist/Wishlist.js: -------------------------------------------------------------------------------- 1 | import onEscapePress from '@vue-storefront/core/mixins/onEscapePress' 2 | import { Wishlist } from '@vue-storefront/core/modules/wishlist/components/Wishlist' 3 | export default { 4 | name: 'Wishlist', 5 | props: { 6 | // deprecated 7 | product: { 8 | type: Object, 9 | required: false, 10 | default: () => { } 11 | } 12 | }, 13 | methods: { 14 | // theme-specific 15 | onEscapePress () { 16 | this.$store.dispatch('ui/closeWishlist') 17 | } 18 | }, 19 | mixins: [ Wishlist, onEscapePress ] 20 | } 21 | -------------------------------------------------------------------------------- /core/compatibility/plugins/config/index.js: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | 3 | // deprecated, use vuex store instead 4 | const ConfigPlugin = { 5 | install (Vue) { 6 | if (!Vue.prototype.$config) { 7 | Object.defineProperties(Vue.prototype, { 8 | $config: { 9 | get: function () { 10 | return config 11 | } 12 | } 13 | }) 14 | } 15 | } 16 | } 17 | 18 | export { config as default, ConfigPlugin } 19 | -------------------------------------------------------------------------------- /core/compatibility/plugins/index.js: -------------------------------------------------------------------------------- 1 | import { EventBusPlugin } from '@vue-storefront/core/compatibility/plugins/event-bus' 2 | import { ConfigPlugin } from '@vue-storefront/core/compatibility/plugins/config' 3 | // used in core entrys and themes.js, deprecated bc of redundancy and for simplification of a project 4 | export { 5 | EventBusPlugin, 6 | ConfigPlugin 7 | } 8 | -------------------------------------------------------------------------------- /core/data-resolver/OrderService.ts: -------------------------------------------------------------------------------- 1 | import config from 'config'; 2 | import { DataResolver } from './types/DataResolver'; 3 | import { Order } from '@vue-storefront/core/modules/order/types/Order' 4 | import { TaskQueue } from '@vue-storefront/core/lib/sync' 5 | import Task from '@vue-storefront/core/lib/sync/types/Task' 6 | import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl'; 7 | 8 | const placeOrder = (order: Order): Promise => 9 | TaskQueue.execute({ url: getApiEndpointUrl(config.orders, 'endpoint'), // sync the order 10 | payload: { 11 | method: 'POST', 12 | headers: { 'Content-Type': 'application/json' }, 13 | mode: 'cors', 14 | body: JSON.stringify(order) 15 | } 16 | }) 17 | 18 | export const OrderService: DataResolver.OrderService = { 19 | placeOrder 20 | } 21 | -------------------------------------------------------------------------------- /core/data-resolver/index.ts: -------------------------------------------------------------------------------- 1 | import { CategoryService } from './CategoryService' 2 | import { UserService } from './UserService' 3 | import { CartService } from './CartService' 4 | import { OrderService } from './OrderService' 5 | import { StockService } from './StockService' 6 | import { ReviewsService } from './ReviewsService' 7 | import { NewsletterService } from './NewsletterService' 8 | 9 | export { 10 | CategoryService, 11 | UserService, 12 | CartService, 13 | OrderService, 14 | StockService, 15 | ReviewsService, 16 | NewsletterService 17 | } 18 | -------------------------------------------------------------------------------- /core/filters/capitalize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Capitalize first letter of provided text 3 | * @param {String} text 4 | */ 5 | export function capitalize (text) { 6 | if (!text) return '' 7 | text = text.toString() 8 | return text.charAt(0).toUpperCase() + text.slice(1) 9 | } 10 | -------------------------------------------------------------------------------- /core/filters/html-decode.js: -------------------------------------------------------------------------------- 1 | import decode from 'lean-he/decode' 2 | 3 | /** 4 | * Decodes any named and numerical character references in text 5 | * @param {String} value 6 | */ 7 | export function htmlDecode (value) { 8 | return value ? decode(value) : '' 9 | } 10 | -------------------------------------------------------------------------------- /core/filters/index.js: -------------------------------------------------------------------------------- 1 | import { price } from './price' 2 | import { htmlDecode } from './html-decode' 3 | import { date } from './date' 4 | import { capitalize } from './capitalize' 5 | import { formatProductMessages } from './product-messages' 6 | import { stripHTML } from './strip-html' 7 | 8 | export { 9 | price, 10 | htmlDecode, 11 | date, 12 | capitalize, 13 | formatProductMessages, 14 | stripHTML 15 | } 16 | -------------------------------------------------------------------------------- /core/filters/product-messages.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Format message string for product validation messages object 3 | */ 4 | export function formatProductMessages (messages: Record): string { 5 | const msgs = [] 6 | for (const infoKey in messages) { 7 | if (messages[infoKey]) { 8 | msgs.push(messages[infoKey]) 9 | } 10 | } 11 | return msgs.join(', ') 12 | } 13 | -------------------------------------------------------------------------------- /core/filters/strip-html.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Strip HTML tags 3 | * @param {String} html 4 | */ 5 | export function stripHTML (html) { 6 | if (!html) return '' 7 | return html.replace(/<[^>]+>/g, '').trim() 8 | } 9 | -------------------------------------------------------------------------------- /core/helpers/getApiEndpointUrl.ts: -------------------------------------------------------------------------------- 1 | import { isServer } from '@vue-storefront/core/helpers'; 2 | 3 | // object - parent object in the config, e.g. config.cart 4 | // field - field inside the object, e.g. create_endpoint 5 | 6 | // returns - object.[field]_ssr if it exists and it is a server, 7 | // object.field otherwise 8 | 9 | export default (object: Record, field: string): string => { 10 | return isServer && object[`${field}_ssr`] ? object[`${field}_ssr`] : object[field] 11 | } 12 | -------------------------------------------------------------------------------- /core/helpers/initialStateFactory.ts: -------------------------------------------------------------------------------- 1 | import cloneDeep from 'lodash-es/cloneDeep' 2 | import pick from 'lodash-es/pick' 3 | 4 | const initialStateFactory = (defaultState) => { 5 | // storing default values for the fields that will be set in createApp 6 | const defaultFields = pick(defaultState, ['version', 'config', '__DEMO_MODE__', 'storeView']) 7 | 8 | const createInitialState = (currentState) => ({ 9 | ...cloneDeep(currentState), 10 | ...defaultFields, 11 | storeView: { storeCode: currentState.storeView.storeCode } 12 | }) 13 | 14 | return { createInitialState } 15 | } 16 | 17 | export default initialStateFactory 18 | -------------------------------------------------------------------------------- /core/helpers/test/unit/processURLAddress.spec.ts: -------------------------------------------------------------------------------- 1 | import { processURLAddress } from '@vue-storefront/core/helpers' 2 | import config from 'config' 3 | 4 | jest.clearAllMocks() 5 | jest.mock('config', () => ({})) 6 | jest.mock('@vue-storefront/core/lib/logger', () => ({ 7 | Logger: {} 8 | })) 9 | jest.mock('@vue-storefront/core/store', () => ({})) 10 | jest.mock('@vue-storefront/core/modules/url/helpers', () => ({})) 11 | jest.mock('@vue-storefront/core/lib/multistore', () => ({})) 12 | 13 | describe('processURLAddress', () => { 14 | it('Check that the url that comes back has the right value', () => { 15 | config.api = { 16 | url: 'api' 17 | } 18 | expect(processURLAddress('/testing')).toBe('api/testing') 19 | expect(processURLAddress('testing')).toBe('testing') 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /core/i18n/.gitignore: -------------------------------------------------------------------------------- 1 | resource/i18n/*.json -------------------------------------------------------------------------------- /core/i18n/intl.ts: -------------------------------------------------------------------------------- 1 | import areIntlLocalesSupported from 'intl-locales-supported' 2 | 3 | export const importIntlPolyfill = async () => { 4 | const IntlPolyfill = await import('intl') 5 | global.Intl = IntlPolyfill.default 6 | } 7 | 8 | export const checkForIntlPolyfill = async (storeView) => { 9 | const globDTO = typeof window !== 'undefined' ? window : global 10 | if (!globDTO.hasOwnProperty('Intl') || !areIntlLocalesSupported(storeView.i18n.defaultLocale)) { 11 | await importIntlPolyfill() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/i18n/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue-storefront/i18n", 3 | "version": "1.12.2", 4 | "description": "Vue Storefront i18n", 5 | "license": "MIT", 6 | "main": "index.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "dependencies": { 11 | "vue-i18n": "^8.0.0" 12 | }, 13 | "publishConfig": { 14 | "access": "public" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/lib/search/adapter/SeachAdapterInterface.ts: -------------------------------------------------------------------------------- 1 | interface SearchAdapterInterface { 2 | search(Request: any): void, 3 | registerEntityType(entityType: string, options: any): void 4 | } 5 | -------------------------------------------------------------------------------- /core/lib/store/entities.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {string} 3 | */ 4 | export function guid () { 5 | function s4 () { 6 | return Math.floor((1 + Math.random()) * 0x10000) 7 | .toString(16) 8 | .substring(1) 9 | } 10 | return s4() + s4() + '-' + s4() + '-' + s4() + '-' + 11 | s4() + '-' + s4() + s4() + s4() 12 | } 13 | /** 14 | * Return unique entity.id 15 | * @param {Object} entity 16 | */ 17 | export function uniqueEntityId (entity) { 18 | return new Date().getTime() + '-' + guid() 19 | } 20 | 21 | /** 22 | * Return unique entity key name for specified key value 23 | * @param {String} key 24 | * @param {String} value 25 | */ 26 | export function entityKeyName (...values) { 27 | return values.join('$$') 28 | } 29 | -------------------------------------------------------------------------------- /core/lib/store/filters.ts: -------------------------------------------------------------------------------- 1 | import decode from 'lean-he/decode' 2 | 3 | /** 4 | * Decodes any named and numerical character references in the text 5 | * @param {String} value 6 | */ 7 | export function htmlDecode (value: any) { 8 | return value ? decode(value) : '' 9 | } 10 | -------------------------------------------------------------------------------- /core/lib/sync/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export const hasResponseError = (jsonResponse): boolean => { 2 | if (typeof jsonResponse.result === 'string') { 3 | return true 4 | } 5 | 6 | const hasMessage = jsonResponse.result.result || jsonResponse.result.message 7 | 8 | return Boolean(hasMessage) && jsonResponse.result.code !== 'ENOTFOUND' 9 | } 10 | 11 | export const getResponseMessage = (jsonResponse): string => { 12 | if (typeof jsonResponse.result === 'string') { 13 | return jsonResponse.result 14 | } 15 | 16 | if (typeof jsonResponse.result.result === 'string') { 17 | return jsonResponse.result.result 18 | } 19 | 20 | return jsonResponse.result.message 21 | } 22 | -------------------------------------------------------------------------------- /core/lib/sync/types/Task.ts: -------------------------------------------------------------------------------- 1 | export default interface Task { 2 | acknowledged: boolean, 3 | callback_event: string, 4 | code: number, 5 | payload: any, 6 | result: any, 7 | resultCode: number, 8 | silent: boolean, 9 | task_id: number, 10 | transmited: boolean, 11 | transmited_at: Date, 12 | url: string, 13 | is_result_cacheable?: boolean, 14 | meta: any 15 | } 16 | -------------------------------------------------------------------------------- /core/lib/themes.ts: -------------------------------------------------------------------------------- 1 | export function registerTheme (themeName, app, routes, store, config, ssrContext) { 2 | const themeEntryPoint = require('theme/index.js') 3 | if (themeEntryPoint != null && themeEntryPoint.initTheme) { 4 | themeEntryPoint.initTheme(app, routes, store, config, ssrContext) // register theme 5 | } else { 6 | throw new Error('Wrong theme name: ' + themeName) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /core/mixins/index.js: -------------------------------------------------------------------------------- 1 | import { thumbnail } from './thumbnail.js' 2 | import { multistore } from './multistore.js' 3 | 4 | export { 5 | thumbnail, 6 | multistore 7 | } 8 | -------------------------------------------------------------------------------- /core/mixins/onEscapePress.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mounted () { 3 | const keydownHandler = (e) => { 4 | // for old browser support as a fallback 5 | if (e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) { 6 | this.onEscapePress() 7 | } 8 | } 9 | document.addEventListener('keydown', keydownHandler) 10 | this.$once('hook:destroyed', () => { 11 | document.removeEventListener('keydown', keydownHandler) 12 | }) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/modules-entry.ts: -------------------------------------------------------------------------------- 1 | 2 | import { VueStorefrontModule } from '@vue-storefront/core/lib/module' 3 | import { registerModules } from 'src/modules/client' 4 | 5 | // @deprecated from 2.0, use registerModule instead 6 | export const enabledModules: VueStorefrontModule[] = [ 7 | ...registerModules 8 | ] 9 | -------------------------------------------------------------------------------- /core/modules/breadcrumbs/README.md: -------------------------------------------------------------------------------- 1 | This module is not finished. 2 | 3 | So far it's save to use in: 4 | - Product page -------------------------------------------------------------------------------- /core/modules/breadcrumbs/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import { formatCategoryLink } from '@vue-storefront/core/modules/url/helpers' 2 | 3 | // Duplicate of breadCrumbRoutes, to repalce it soon. 4 | /** Parse category path for product/category */ 5 | export function parseCategoryPath (categoryPath) { 6 | let routesArray = [] 7 | for (let category of categoryPath) { 8 | if (category.url_path === undefined || category.url_path === null) continue; 9 | routesArray.push({ 10 | name: category.name, 11 | route_link: formatCategoryLink(category) 12 | }) 13 | } 14 | 15 | return routesArray 16 | } 17 | -------------------------------------------------------------------------------- /core/modules/breadcrumbs/index.ts: -------------------------------------------------------------------------------- 1 | import { breadcrumbsStore } from './store' 2 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 3 | 4 | export const BreadcrumbsModule: StorefrontModule = function ({ store }) { 5 | store.registerModule('breadcrumbs', breadcrumbsStore) 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/breadcrumbs/store/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export const breadcrumbsStore = { 3 | namespaced: true, 4 | state: { 5 | routes: [], 6 | current: null 7 | }, 8 | mutations: { 9 | set (state, payload) { 10 | state.routes = payload.routes 11 | state.current = payload.current 12 | } 13 | }, 14 | actions: { 15 | set ({ commit }, payload) { 16 | commit('set', payload) 17 | } 18 | }, 19 | getters: { 20 | getBreadcrumbsRoutes: (state) => state.routes, 21 | getBreadcrumbsCurrent: (state) => state.current 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/modules/cart/components/MicrocartButton.ts: -------------------------------------------------------------------------------- 1 | 2 | // @deprecated moved to theme 3 | export const MicrocartButton = { 4 | name: 'MicrocartButton', 5 | mounted () { 6 | document.addEventListener('visibilitychange', () => { 7 | if (!document.hidden) { 8 | this.$store.dispatch('cart/load') 9 | } 10 | }) 11 | }, 12 | methods: { 13 | toggleMicrocart () { 14 | this.$store.dispatch('cart/toggleMicrocart') 15 | } 16 | }, 17 | computed: { 18 | quantity () { 19 | return this.$store.getters['cart/getItemsTotalQuantity'] 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/modules/cart/components/Product.ts: -------------------------------------------------------------------------------- 1 | import { getThumbnailForProduct, getProductConfiguration } from '@vue-storefront/core/modules/cart/helpers' 2 | 3 | // @deprecated moved to theme 4 | export const MicrocartProduct = { 5 | name: 'MicrocartProduct', 6 | props: { 7 | product: { 8 | type: Object, 9 | required: true 10 | } 11 | }, 12 | computed: { 13 | thumbnail () { 14 | return getThumbnailForProduct(this.product) 15 | }, 16 | configuration () { 17 | return getProductConfiguration(this.product) 18 | } 19 | }, 20 | methods: { 21 | removeFromCart () { 22 | this.$store.dispatch('cart/removeItem', { product: this.product }) 23 | }, 24 | updateQuantity (quantity) { 25 | this.$store.dispatch('cart/updateQuantity', { product: this.product, qty: quantity }) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/modules/cart/helpers/createShippingInfoData.ts: -------------------------------------------------------------------------------- 1 | const createShippingInfoData = (methodsData) => ({ 2 | shippingAddress: { 3 | countryId: methodsData.country, 4 | ...(methodsData.shippingAddress ? methodsData.shippingAddress : {}) 5 | }, 6 | billingAddress: { 7 | ...(methodsData.billingAddress ? methodsData.billingAddress : {}) 8 | }, 9 | ...(methodsData.carrier_code ? { shippingCarrierCode: methodsData.carrier_code } : {}), 10 | ...(methodsData.method_code ? { shippingMethodCode: methodsData.method_code } : {}) 11 | }); 12 | 13 | export default createShippingInfoData 14 | -------------------------------------------------------------------------------- /core/modules/cart/helpers/getProductOptions.ts: -------------------------------------------------------------------------------- 1 | import CartItem from '@vue-storefront/core/modules/cart/types/CartItem' 2 | import { ProductOption } from '@vue-storefront/core/modules/catalog/types/ProductConfiguration' 3 | 4 | const mapValues = (current) => (val) => ({ 5 | id: val.value_index, 6 | label: val.label, 7 | attribute_code: current.attribute_code, 8 | type: current.attribute_code 9 | }) 10 | 11 | const reduceOptions = (prev, curr) => ({ 12 | ...prev, 13 | [curr.attribute_code]: curr.values.map(mapValues(curr)) 14 | }) 15 | 16 | const getProductOptions = (product: CartItem): ProductOption => { 17 | if (!product.configurable_options) { 18 | return null 19 | } 20 | 21 | return product.configurable_options 22 | .reduce(reduceOptions, {}) 23 | } 24 | 25 | export default getProductOptions 26 | -------------------------------------------------------------------------------- /core/modules/cart/helpers/getThumbnailForProduct.ts: -------------------------------------------------------------------------------- 1 | import CartItem from '@vue-storefront/core/modules/cart/types/CartItem' 2 | import config from 'config' 3 | import { getThumbnailPath } from '@vue-storefront/core/helpers' 4 | import { productThumbnailPath } from '@vue-storefront/core/helpers' 5 | 6 | const getThumbnailForProduct = (product: CartItem): string => { 7 | const thumbnail = productThumbnailPath(product) 8 | 9 | if (typeof navigator !== 'undefined' && !navigator.onLine) { 10 | return getThumbnailPath(thumbnail, config.products.thumbnails.width, config.products.thumbnails.height) 11 | } 12 | 13 | return getThumbnailPath(thumbnail, config.cart.thumbnails.width, config.cart.thumbnails.height) 14 | } 15 | 16 | export default getThumbnailForProduct 17 | -------------------------------------------------------------------------------- /core/modules/cart/helpers/optimizeProduct.ts: -------------------------------------------------------------------------------- 1 | import CartItem from '@vue-storefront/core/modules/cart/types/CartItem' 2 | import config from 'config' 3 | import omit from 'lodash-es/omit' 4 | import pullAll from 'lodash-es/pullAll' 5 | 6 | const optimizeProduct = (product: CartItem): CartItem => { 7 | if (!config.entities.optimizeShoppingCart) { 8 | return product 9 | } 10 | 11 | let fieldsToOmit = config.entities.optimizeShoppingCartOmitFields 12 | 13 | if (config.cart.productsAreReconfigurable) { 14 | fieldsToOmit = pullAll(fieldsToOmit, ['configurable_children', 'configurable_options']) 15 | } 16 | 17 | return omit(product, fieldsToOmit) 18 | } 19 | 20 | export default optimizeProduct 21 | -------------------------------------------------------------------------------- /core/modules/cart/helpers/prepareShippingInfoForUpdateTotals.ts: -------------------------------------------------------------------------------- 1 | import isString from 'lodash-es/isString' 2 | import Totals from '@vue-storefront/core/modules/cart/types/Totals' 3 | 4 | const applyOptions = (item: Totals) => { 5 | if (item.options && isString(item.options)) { 6 | return { ...item, options: JSON.parse(item.options) } 7 | } 8 | 9 | return item 10 | } 11 | 12 | const reduceToObject = (previousValue: any, currentValue: Totals) => ({ 13 | ...previousValue, 14 | [currentValue.item_id]: currentValue 15 | }) 16 | 17 | const prepareShippingInfoForUpdateTotals = (totals: Totals[]) => 18 | totals 19 | .map(applyOptions) 20 | .reduce(reduceToObject, {}) 21 | 22 | export default prepareShippingInfoForUpdateTotals 23 | -------------------------------------------------------------------------------- /core/modules/cart/helpers/totalsCacheHandler.ts: -------------------------------------------------------------------------------- 1 | import * as types from '../store/mutation-types' 2 | import { Logger } from '@vue-storefront/core/lib/logger' 3 | 4 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 5 | 6 | export const totalsCacheHandlerPlugin = ({ type }, state) => { 7 | if ( 8 | type.endsWith(types.CART_UPD_TOTALS) 9 | ) { 10 | return StorageManager.get('cart').setItem('current-totals', { 11 | platformTotalSegments: state.cart.platformTotalSegments, 12 | platformTotals: state.cart.platformTotals 13 | }).catch((reason) => { 14 | Logger.error(reason)() 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/modules/cart/helpers/validateProduct.ts: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | import i18n from '@vue-storefront/i18n' 3 | import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'; 4 | 5 | const validateProduct = (product: CartItem): string[] => { 6 | const errors = [] 7 | 8 | if (config.useZeroPriceProduct ? product.price_incl_tax < 0 : product.price_incl_tax <= 0) { 9 | errors.push(i18n.t('Product price is unknown, product cannot be added to the cart!')) 10 | } 11 | 12 | if (product.errors !== null && typeof product.errors !== 'undefined') { 13 | for (const errKey in product.errors) { 14 | if (product.errors[errKey]) { 15 | errors.push(product.errors[errKey]) 16 | } 17 | } 18 | } 19 | 20 | return errors 21 | }; 22 | 23 | export default validateProduct; 24 | -------------------------------------------------------------------------------- /core/modules/cart/index.ts: -------------------------------------------------------------------------------- 1 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 2 | import { cartStore } from './store' 3 | import { cartCacheHandlerPlugin, totalsCacheHandlerPlugin } from './helpers'; 4 | import { isServer } from '@vue-storefront/core/helpers' 5 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 6 | 7 | export const CartModule: StorefrontModule = function ({ store }) { 8 | StorageManager.init('cart') 9 | 10 | store.registerModule('cart', cartStore) 11 | 12 | if (!isServer) store.dispatch('cart/load') 13 | store.subscribe(cartCacheHandlerPlugin); 14 | store.subscribe(totalsCacheHandlerPlugin); 15 | } 16 | -------------------------------------------------------------------------------- /core/modules/cart/test/unit/store/index.spec.ts: -------------------------------------------------------------------------------- 1 | jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) })); 2 | jest.mock('../../../store/actions', () => ({})); 3 | jest.mock('../../../store/getters', () => ({})); 4 | jest.mock('../../../store/mutations', () => ({})); 5 | 6 | describe('Cart Module', () => { 7 | it('can be loaded', () => { 8 | expect(module).toBeTruthy() 9 | }) 10 | }); 11 | -------------------------------------------------------------------------------- /core/modules/cart/types/AppliedCoupon.ts: -------------------------------------------------------------------------------- 1 | export default interface AppliedCoupon { 2 | code: string, 3 | discount: number 4 | } 5 | -------------------------------------------------------------------------------- /core/modules/cart/types/BillingAddress.ts: -------------------------------------------------------------------------------- 1 | export default interface BillingAddress { 2 | firstname: string, 3 | lastname: string, 4 | city: string, 5 | postcode: string, 6 | street: string[], 7 | countryId: string 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/cart/types/CartItem.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product' 2 | 3 | import CartItemOption from './CartItemOption' 4 | import CartItemTotals from './CartItemTotals' 5 | 6 | export default interface CartItem extends Product { 7 | qty: number, 8 | options: CartItemOption[], 9 | totals: CartItemTotals, 10 | server_item_id: number | string, 11 | server_cart_id: any, 12 | product_type?: string, 13 | item_id?: number | string, 14 | checksum?: string, 15 | quoteId?: string 16 | } 17 | -------------------------------------------------------------------------------- /core/modules/cart/types/CartItemOption.ts: -------------------------------------------------------------------------------- 1 | export default interface CartItemOption { 2 | label: string, 3 | value: string 4 | } 5 | -------------------------------------------------------------------------------- /core/modules/cart/types/CartItemTotals.ts: -------------------------------------------------------------------------------- 1 | 2 | import CartItemOption from './CartItemOption' 3 | 4 | export default interface CartItemTotals { 5 | base_discount_amount: number, 6 | base_price: number, 7 | base_price_incl_tax: number, 8 | base_row_total: number, 9 | base_row_total_incl_tax: number, 10 | base_tax_amount: number, 11 | discount_amount: number, 12 | discount_percent: number, 13 | item_id: number | string, 14 | name: string, 15 | options: CartItemOption[], 16 | price: number, 17 | price_incl_tax: number, 18 | qty: number, 19 | row_total: number, 20 | row_total_incl_tax: number, 21 | row_total_with_discount: number, 22 | tax_amount: number, 23 | tax_percent: number 24 | } 25 | -------------------------------------------------------------------------------- /core/modules/cart/types/CartState.ts: -------------------------------------------------------------------------------- 1 | export default interface CartState { 2 | isMicrocartOpen: boolean, 3 | itemsAfterPlatformTotals: any, 4 | platformTotals: any, 5 | platformTotalSegments: any, 6 | cartIsLoaded: boolean, 7 | cartServerToken: string, 8 | shipping: any, 9 | payment: any, 10 | cartItemsHash: string, 11 | cartServerLastSyncDate: number, 12 | cartServerLastTotalsSyncDate: number, 13 | cartItems: any[], 14 | connectBypassCount: number, 15 | isAddingToCart: boolean 16 | } 17 | -------------------------------------------------------------------------------- /core/modules/cart/types/CartTotalSegments.ts: -------------------------------------------------------------------------------- 1 | import CartTotalSegmentsItem from './CartTotalSegmentsItem' 2 | // eslint-disable-next-line @typescript-eslint/no-empty-interface 3 | export default interface CartTotalSegments extends Array{} 4 | -------------------------------------------------------------------------------- /core/modules/cart/types/CartTotalSegmentsItem.ts: -------------------------------------------------------------------------------- 1 | export default interface CartTotalSegmentsItem { 2 | code: string, 3 | title: string, 4 | value: number, 5 | area?: string, 6 | extension_attributes?: object 7 | } 8 | -------------------------------------------------------------------------------- /core/modules/cart/types/CheckoutData.ts: -------------------------------------------------------------------------------- 1 | import ShippingDetails from '@vue-storefront/core/modules/checkout/types/ShippingDetails' 2 | import ShippingMethod from './ShippingMethod' 3 | import PaymentMethod from './PaymentMethod' 4 | import PaymentDetails from '@vue-storefront/core/modules/checkout/types/PaymentDetails' 5 | 6 | export default interface CheckoutData { 7 | shippingDetails: ShippingDetails, 8 | shippingMethods: ShippingMethod[], 9 | paymentMethods: PaymentMethod[], 10 | paymentDetails: PaymentDetails, 11 | taxCountry?: string 12 | } 13 | -------------------------------------------------------------------------------- /core/modules/cart/types/DiffLog.ts: -------------------------------------------------------------------------------- 1 | export interface Notification { 2 | type: string, 3 | message: any, 4 | action1: any, 5 | action2?: any 6 | } 7 | 8 | export interface ServerResponse { 9 | status: string | number, 10 | sku: string, 11 | result: any 12 | } 13 | 14 | export interface Party { 15 | party: string, 16 | status: string, 17 | sku: string 18 | } 19 | -------------------------------------------------------------------------------- /core/modules/cart/types/OrderShippingDetails.ts: -------------------------------------------------------------------------------- 1 | import ShippingAddress from './ShippingAddress' 2 | import BillingAddress from './BillingAddress' 3 | 4 | export default interface OrderShippingDetails { 5 | country?: string, 6 | method_code?: string, 7 | carrier_code?: string, 8 | payment_method?: string, 9 | shippingAddress?: ShippingAddress, 10 | billingAddress?: BillingAddress 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/cart/types/PaymentMethod.ts: -------------------------------------------------------------------------------- 1 | export default interface PaymentMethod { 2 | default: boolean, 3 | code?: string, 4 | cost_incl_tax?: number, 5 | title?: string 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/cart/types/ShippingAddress.ts: -------------------------------------------------------------------------------- 1 | export default interface ShippingAddress { 2 | firstname: string, 3 | lastname: string, 4 | city: string, 5 | postcode: string, 6 | street: string[] 7 | } 8 | -------------------------------------------------------------------------------- /core/modules/cart/types/ShippingMethod.ts: -------------------------------------------------------------------------------- 1 | export default interface ShippingMethod { 2 | method_code?: string, 3 | carrier_code?: string, 4 | offline: boolean, 5 | default: boolean, 6 | price_incl_tax?: number, 7 | method_title?: string 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/cart/types/Totals.ts: -------------------------------------------------------------------------------- 1 | export default interface Totals { 2 | item_id?: number | string, 3 | options?: string, 4 | name: string, 5 | qty: number, 6 | row_total: number, 7 | row_total_incl_tax: number, 8 | tax_amount: number, 9 | tax_percent: number 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/catalog-next/helpers/optionLabel.ts: -------------------------------------------------------------------------------- 1 | import { optionLabel } from '@vue-storefront/core/modules/catalog/helpers/optionLabel' 2 | 3 | // TODO in future move old helper here, add tests and refactor 4 | export { optionLabel } 5 | -------------------------------------------------------------------------------- /core/modules/catalog-next/index.ts: -------------------------------------------------------------------------------- 1 | import { categoryModule } from './store/category' 2 | import { StorefrontModule } from '@vue-storefront/core/lib/modules'; 3 | 4 | export const CatalogNextModule: StorefrontModule = function ({ store }) { 5 | store.registerModule('category-next', categoryModule) 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/catalog-next/store/category/CategoryState.ts: -------------------------------------------------------------------------------- 1 | import { Category } from '../../types/Category'; 2 | import Product from 'core/modules/catalog/types/Product'; 3 | 4 | export default interface CategoryState { 5 | categoriesMap: { [id: string]: Category }, 6 | notFoundCategoryIds: string[], 7 | filtersMap: { [id: string]: any }, 8 | products: Product[], 9 | searchProductsStats: any, 10 | menuCategories: Category[] 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/catalog-next/store/category/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import getters from './getters' 4 | import mutations from './mutations' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import CategoryState from './CategoryState' 7 | 8 | export const categoryModule: Module = { 9 | namespaced: true, 10 | state: { 11 | categoriesMap: {}, 12 | notFoundCategoryIds: [], 13 | filtersMap: {}, 14 | products: [], 15 | searchProductsStats: {}, 16 | menuCategories: [] 17 | }, 18 | getters, 19 | actions, 20 | mutations 21 | } 22 | 23 | export const nonReactiveState = { 24 | products: [] 25 | } 26 | -------------------------------------------------------------------------------- /core/modules/catalog-next/store/category/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_CATEGORY = 'category' 2 | export const CATEGORY_SET_PRODUCTS = `${SN_CATEGORY}/SET_PRODUCTS` 3 | export const CATEGORY_ADD_PRODUCTS = `${SN_CATEGORY}/ADD_PRODUCTS` 4 | export const CATEGORY_SET_SEARCH_PRODUCTS_STATS = `${SN_CATEGORY}/SET_SEARCH_PRODUCTS_STATS` 5 | export const CATEGORY_ADD_CATEGORIES = `${SN_CATEGORY}/ADD_CATEGORIES` 6 | export const CATEGORY_ADD_CATEGORY = `${SN_CATEGORY}/ADD_CATEGORY` 7 | export const CATEGORY_SET_CATEGORY_FILTERS = `${SN_CATEGORY}/SET_CATEGORY_FILTERS` 8 | export const CATEGORY_ADD_NOT_FOUND_CATEGORY_IDS = `${SN_CATEGORY}/ADD_NOT_FOUND_CATEGORY_IDS` 9 | export const CATEGORY_UPD_MENU_CATEGORIES = `${SN_CATEGORY}/UPD_MENU_CATEGORIES` 10 | -------------------------------------------------------------------------------- /core/modules/catalog-next/types/Category.d.ts: -------------------------------------------------------------------------------- 1 | import FilterVariant from './FilterVariant' 2 | 3 | export interface ChildrenData { 4 | id: number | string, 5 | children_data?: ChildrenData[], 6 | name?: string, 7 | slug?: string, 8 | url_key?: string 9 | } 10 | 11 | export interface Category { 12 | path: string, 13 | is_active: boolean, 14 | level: number, 15 | product_count: number, 16 | children_count: string, 17 | parent_id: number | string, 18 | name: string, 19 | id: number | string, 20 | url_path: string, 21 | url_key: string, 22 | children_data: ChildrenData[], 23 | slug: string, 24 | position?: number 25 | } 26 | 27 | export interface Filters { 28 | [key: string]: FilterVariant[] 29 | } 30 | -------------------------------------------------------------------------------- /core/modules/catalog-next/types/FilterVariant.ts: -------------------------------------------------------------------------------- 1 | export default interface FilterVariant { 2 | id: string, 3 | label: string, 4 | type: string, 5 | from?: string, 6 | to?: string, 7 | single?: boolean 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/catalog/components/ProductGallery.ts: -------------------------------------------------------------------------------- 1 | import VueOffline from 'vue-offline' 2 | 3 | export const ProductGallery = { 4 | name: 'ProductGallery', 5 | components: { 6 | VueOffline 7 | }, 8 | props: { 9 | gallery: { 10 | type: Array, 11 | required: true 12 | }, 13 | configuration: { 14 | type: Object, 15 | required: true 16 | }, 17 | offline: { 18 | type: Object, 19 | required: false 20 | }, 21 | product: { 22 | type: Object, 23 | required: true 24 | } 25 | }, 26 | computed: { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/associatedProducts/buildQuery.ts: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | import { SearchQuery } from 'storefront-query-builder' 3 | 4 | /** 5 | * Creates simple query that will search product by skus list 6 | */ 7 | export default function buildQuery (skus: string[]): SearchQuery { 8 | let productsQuery = new SearchQuery() 9 | productsQuery = productsQuery 10 | .applyFilter({ key: 'sku', value: { 'in': skus } }) 11 | .applyFilter({ key: 'status', value: { 'in': [1] } }) 12 | if (config.products.listOutOfStockProducts === false) { 13 | productsQuery = productsQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } }) 14 | } 15 | return productsQuery 16 | } 17 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/associatedProducts/getAttributesFromMetadata.ts: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | import Product from '@vue-storefront/core/modules/catalog/types/Product' 3 | 4 | /** 5 | * Set associated attributes by meta data of product links 6 | */ 7 | export default async function getAttributesFromMetadata (context: any, products: Product[]) { 8 | if (config.entities.attribute.loadByAttributeMetadata) { 9 | context.dispatch('attribute/loadProductAttributes', { products, merge: true }, { root: true }) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/associatedProducts/getBundleProductPrice.ts: -------------------------------------------------------------------------------- 1 | import { 2 | getBundleOptionsValues, 3 | getBundleOptionPrice, 4 | getSelectedBundleOptions 5 | } from '@vue-storefront/core/modules/catalog/helpers/bundleOptions' 6 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 7 | 8 | export default function getBundleProductPrice (product: Product) { 9 | const selectedBundleOptions = getSelectedBundleOptions(product) 10 | const { price, priceInclTax } = getBundleOptionPrice( 11 | getBundleOptionsValues(selectedBundleOptions, product.bundle_options) 12 | ) 13 | 14 | return { price, priceInclTax } 15 | } 16 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/associatedProducts/getGroupedProductPrice.ts: -------------------------------------------------------------------------------- 1 | import Product, { ProductLink } from '@vue-storefront/core/modules/catalog/types/Product'; 2 | import { getProductLinkPrice } from './getProductLinkPrice'; 3 | 4 | export default function getGroupedProductPrice (product: Product) { 5 | const productLinks: ProductLink[] = (product.product_links || []) 6 | 7 | return getProductLinkPrice(productLinks) 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/associatedProducts/index.ts: -------------------------------------------------------------------------------- 1 | import setGroupedProduct from './setGroupedProduct' 2 | import setBundleProducts from './setBundleProducts' 3 | import getAttributesFromMetadata from './getAttributesFromMetadata' 4 | 5 | export { 6 | setGroupedProduct, 7 | setBundleProducts, 8 | getAttributesFromMetadata 9 | } 10 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/configure/index.ts: -------------------------------------------------------------------------------- 1 | import configureProducts from './configureProducts' 2 | 3 | export { 4 | configureProducts 5 | } 6 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/filterAttributes.ts: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | 3 | export default function filterAttributes ({ 4 | filterValues, 5 | filterField, 6 | blacklist, 7 | idsList, 8 | codesList 9 | }: { 10 | filterValues: string[], 11 | filterField: string, 12 | blacklist: string[], 13 | idsList: any, 14 | codesList: any 15 | }) { 16 | return filterValues.filter(fv => { 17 | if (fv.indexOf('.') >= 0) { 18 | return false 19 | } 20 | if (blacklist !== null && blacklist.includes(fv)) { 21 | return false 22 | } 23 | if (filterField === 'attribute_id') { 24 | return (typeof idsList[fv] === 'undefined' || idsList[fv] === null) 25 | } 26 | if (filterField === 'attribute_code') { 27 | return (typeof codesList[fv] === 'undefined' || codesList[fv] === null) 28 | } 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/getProductGallery.ts: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | import { 3 | getMediaGallery, 4 | configurableChildrenImages, 5 | attributeImages 6 | } from './' 7 | import uniqBy from 'lodash-es/uniqBy' 8 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 9 | 10 | export default function getProductGallery (product: Product) { 11 | if (product.type_id === 'configurable' && product.hasOwnProperty('configurable_children')) { 12 | if (!config.products.gallery.mergeConfigurableChildren && product.is_configured) { 13 | return attributeImages(product) 14 | } 15 | } 16 | 17 | const productGallery = uniqBy(configurableChildrenImages(product).concat(getMediaGallery(product)), 'src') 18 | .filter(f => f.src && f.src !== config.images.productPlaceholder) 19 | 20 | return productGallery 21 | } 22 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/prefetchCachedAttributes.ts: -------------------------------------------------------------------------------- 1 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 2 | import { entityKeyName } from '@vue-storefront/core/lib/store/entities' 3 | import config from 'config' 4 | 5 | async function prefetchCachedAttributes (filterField, filterValues) { 6 | if (!config.attributes || !config.attributes.disablePersistentAttributesCache) { 7 | const attrCollection = StorageManager.get('attributes') 8 | const cachedAttributes = filterValues.map( 9 | async filterValue => attrCollection.getItem(entityKeyName(filterField, String(filterValue).toLowerCase())) 10 | ) 11 | return Promise.all(cachedAttributes) 12 | } 13 | } 14 | 15 | export { prefetchCachedAttributes } 16 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/prepare/setDefaultObjects.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 2 | /** 3 | * Default object that are used in vsf 4 | */ 5 | export default function setDefaultObjects (product: Product) { 6 | product.errors = {}; // this is an object to store validation result for custom options and others 7 | product.info = {}; 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/prepare/setDefaultProductOptions.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 2 | 3 | /** 4 | * Init product_option, needed to next configuration step 5 | */ 6 | export default function setDefaultProductOptions (product: Product) { 7 | if (product.product_option) return 8 | product.product_option = { 9 | extension_attributes: { 10 | custom_options: [], 11 | configurable_item_options: [], 12 | bundle_options: [] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/prepare/setDefaultQty.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 2 | 3 | /** 4 | * set product quantity to 1 5 | */ 6 | export default function setDefaultQty (product: Product) { 7 | if (!product.qty) { 8 | product.qty = 1 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/prepare/setParentId.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 2 | 3 | /** 4 | * set parent id, this is needed, because in configuration process we will override id by configurable_children.id 5 | */ 6 | export default function setParentId (product: Product) { 7 | if (!product.parentId) { 8 | product.parentId = product.id 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/prepare/setParentSku.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 2 | 3 | /** 4 | * set parent sku, this is needed, because in configuration process we will override sku by configurable_children.sku 5 | */ 6 | export default function setParentSku (product: Product) { 7 | if (!product.parentSku) { 8 | product.parentSku = product.sku 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/price/index.ts: -------------------------------------------------------------------------------- 1 | import doPlatformPricesSync from './doPlatformPricesSync' 2 | 3 | export { 4 | doPlatformPricesSync 5 | } 6 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/productOptions/getAttributeCode.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns attribute_code for product option 3 | */ 4 | export default function getAttributeCode (option, attribute): string { 5 | const attribute_code = option.attribute_code 6 | ? option.attribute_code 7 | : option.attribute_id && (attribute.list_by_id[option.attribute_id] || {}).attribute_code 8 | return attribute_code || option.label.toLowerCase() 9 | } 10 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/productOptions/getInternalOptionsFormat.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns internal format for product options 3 | */ 4 | export default function getInternalOptionsFormat (productOption) { 5 | return productOption.extension_attributes.configurable_item_options 6 | .map(({ label, value }) => ({ label, value })) 7 | } 8 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/productOptions/index.ts: -------------------------------------------------------------------------------- 1 | import setProductConfigurableOptions from './setProductConfigurableOptions' 2 | import getProductConfiguration from './getProductConfiguration' 3 | import getProductConfigurationOptions from './getProductConfigurationOptions' 4 | 5 | export { 6 | setProductConfigurableOptions, 7 | getProductConfiguration, 8 | getProductConfigurationOptions 9 | } 10 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/productOptions/omitInternalOptionsFormat.ts: -------------------------------------------------------------------------------- 1 | import omit from 'lodash-es/omit' 2 | 3 | /** 4 | * Omit props that is not needed for product_option 5 | */ 6 | export default function omitInternalOptionsFormat (productOption) { 7 | productOption.extension_attributes.configurable_item_options = productOption.extension_attributes.configurable_item_options 8 | .map((option) => omit(option, ['label', 'value'])) 9 | } 10 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/reduceAttributesLists.ts: -------------------------------------------------------------------------------- 1 | import Attribute from '@vue-storefront/core/modules/catalog/types/Attribute' 2 | 3 | const reduceAttributes = (prev, curr) => { 4 | if (curr) { 5 | prev.attrHashByCode[curr.attribute_code] = curr 6 | prev.attrHashById[curr.attribute_id] = curr 7 | } 8 | 9 | return prev 10 | } 11 | 12 | const reduceAttributesLists = ({ 13 | codesList, 14 | idsList, 15 | attributes 16 | }: { 17 | codesList: any, 18 | idsList: any, 19 | attributes: Attribute[] 20 | }) => { 21 | return attributes.reduce( 22 | reduceAttributes, { attrHashByCode: codesList, attrHashById: idsList } 23 | ) 24 | } 25 | 26 | export default reduceAttributesLists 27 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/registerProductsMapping.ts: -------------------------------------------------------------------------------- 1 | import { transformProductUrl } from '@vue-storefront/core/modules/url/helpers/transformUrl'; 2 | import { localizedDispatcherRoute } from '@vue-storefront/core/lib/multistore'; 3 | import { ActionContext } from 'vuex' 4 | import RootState from '@vue-storefront/core/types/RootState' 5 | 6 | export default async function registerProductsMapping ({ dispatch }: ActionContext, products = []): Promise { 7 | await Promise.all(products.map(product => { 8 | if (product.url_path) { 9 | const { url_path, sku, slug, type_id, parentSku } = product 10 | return dispatch('url/registerMapping', { 11 | url: localizedDispatcherRoute(url_path), 12 | routeData: transformProductUrl({ sku, parentSku, slug, type_id }) 13 | }, { root: true }) 14 | } 15 | })) 16 | } 17 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/stock/filterChildrenByStockitem.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Add 'stock' object to 'configurable_children' and filter configurable child that is not available 3 | */ 4 | export default function filterChildrenByStockitem (product, stockItems = []) { 5 | for (const stockItem of stockItems) { 6 | const confChild = product.configurable_children.find((child) => child.id === stockItem.product_id) 7 | if (!stockItem.is_in_stock || (confChild && confChild.status >= 2/* conf child is disabled */)) { 8 | product.configurable_children = product.configurable_children.filter((child) => child.id !== stockItem.product_id) 9 | } else { 10 | if (confChild) { 11 | confChild.stock = stockItem 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/stock/getProductInfos.ts: -------------------------------------------------------------------------------- 1 | const getProductInfos = (products) => products.map(product => ({ 2 | is_in_stock: product.is_in_stock, 3 | qty: product.qty, 4 | product_id: product.product_id 5 | })) 6 | 7 | export default getProductInfos 8 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/stock/getStatus.ts: -------------------------------------------------------------------------------- 1 | const getStatus = (product, defaultStatus) => { 2 | if (product.stock) { 3 | return product.stock.is_in_stock ? 'ok' : 'out_of_stock' 4 | } 5 | 6 | return defaultStatus 7 | } 8 | 9 | export default getStatus 10 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/stock/getStockItems.ts: -------------------------------------------------------------------------------- 1 | import { StockService } from '@vue-storefront/core/data-resolver'; 2 | import config from 'config' 3 | 4 | /** 5 | * Get products skus and products children skus. Based on that search for stock objects and return them. 6 | */ 7 | export default async function getStockItems (products) { 8 | const skuArray = products.map(({ sku, configurable_children = [] }) => { 9 | const childSkus = configurable_children.map((c) => c.sku) 10 | return [sku, ...childSkus] 11 | }).reduce((acc, curr) => acc.concat(curr), []) 12 | if (!config.stock.synchronize) return 13 | try { 14 | const task = await StockService.list(skuArray) 15 | 16 | if (task.resultCode === 200) { 17 | return task.result 18 | } 19 | return [] 20 | } catch (err) { 21 | console.error(err) 22 | return [] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/stock/index.ts: -------------------------------------------------------------------------------- 1 | import getStatus from './getStatus' 2 | import getProductInfos from './getProductInfos' 3 | import getStockItems from './getStockItems' 4 | import filterOutUnavailableVariants from './filterOutUnavailableVariants' 5 | 6 | export { 7 | getStatus, 8 | getProductInfos, 9 | getStockItems, 10 | filterOutUnavailableVariants 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/variant/getSelectedVariant.ts: -------------------------------------------------------------------------------- 1 | import findConfigurableVariant from './findConfigurableVariant' 2 | 3 | /** 4 | * Returns product based on configuration or if there is no match then return first variant as default. 5 | */ 6 | export default function getSelectedVariant (product, configuration, { fallbackToDefaultWhenNoAvailable }) { 7 | let selectedVariant = findConfigurableVariant({ product, configuration, availabilityCheck: true }) 8 | if (!selectedVariant) { 9 | if (fallbackToDefaultWhenNoAvailable) { 10 | selectedVariant = findConfigurableVariant({ product, selectDefaultChildren: true, availabilityCheck: true }) // return first available child 11 | } 12 | } 13 | 14 | return selectedVariant 15 | } 16 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/variant/getVariantWithLowestPrice.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Makes product variants comparission and returns variant with lowest price 3 | */ 4 | export default function getVariantWithLowestPrice (prevVariant, nextVariant) { 5 | if (!prevVariant || !prevVariant.original_price_incl_tax) { 6 | return nextVariant 7 | } 8 | 9 | const prevPrice = prevVariant.price_incl_tax || prevVariant.original_price_incl_tax 10 | const nextPrice = nextVariant.price_incl_tax || nextVariant.original_price_incl_tax 11 | return nextPrice < prevPrice ? nextVariant : prevVariant 12 | } 13 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/variant/index.ts: -------------------------------------------------------------------------------- 1 | import omitSelectedVariantFields from './omitSelectedVariantFields' 2 | import getSelectedVariant from './getSelectedVariant' 3 | import isOptionAvailable from './isOptionAvailable' 4 | import findConfigurableVariant from './findConfigurableVariant' 5 | 6 | export { 7 | omitSelectedVariantFields, 8 | getSelectedVariant, 9 | isOptionAvailable, 10 | findConfigurableVariant 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/variant/isOptionAvailable.ts: -------------------------------------------------------------------------------- 1 | import findConfigurableVariant from './findConfigurableVariant' 2 | 3 | /** 4 | * Checks if variant with specific configuration exist 5 | */ 6 | export default function isOptionAvailable (context, { product, configuration }): boolean { 7 | const variant = findConfigurableVariant({ product: product, configuration: configuration, availabilityCheck: true }) 8 | return typeof variant !== 'undefined' && variant !== null 9 | } 10 | -------------------------------------------------------------------------------- /core/modules/catalog/helpers/variant/omitSelectedVariantFields.ts: -------------------------------------------------------------------------------- 1 | import omit from 'lodash-es/omit' 2 | import config from 'config' 3 | 4 | /** 5 | * Omit some variant fields to prevent overriding same base product fields 6 | */ 7 | export default function omitSelectedVariantFields (selectedVariant): void { 8 | const hasImage = selectedVariant && selectedVariant.image && selectedVariant.image !== 'no_selection' 9 | const fieldsToOmit = config.products.omitVariantFields 10 | if (!hasImage) fieldsToOmit.push('image') 11 | return omit(selectedVariant, fieldsToOmit) 12 | } 13 | -------------------------------------------------------------------------------- /core/modules/catalog/queries/related.js: -------------------------------------------------------------------------------- 1 | import { SearchQuery } from 'storefront-query-builder' 2 | import config from 'config' 3 | 4 | export function prepareRelatedQuery (key, sku) { 5 | let relatedProductsQuery = new SearchQuery() 6 | 7 | relatedProductsQuery = relatedProductsQuery.applyFilter({ key: key, value: { 'in': sku } }) 8 | 9 | relatedProductsQuery = relatedProductsQuery 10 | .applyFilter({ key: 'visibility', value: { 'in': [2, 3, 4] } }) 11 | .applyFilter({ key: 'status', value: { 'in': [1] } }) 12 | 13 | if (config.products.listOutOfStockProducts === false) { 14 | relatedProductsQuery = relatedProductsQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } }) 15 | } 16 | 17 | return relatedProductsQuery 18 | } 19 | -------------------------------------------------------------------------------- /core/modules/catalog/queries/searchPanel.js: -------------------------------------------------------------------------------- 1 | import { SearchQuery } from 'storefront-query-builder' 2 | import config from 'config' 3 | 4 | export function prepareQuickSearchQuery (queryText) { 5 | let searchQuery = new SearchQuery() 6 | 7 | searchQuery = searchQuery 8 | .setSearchText(queryText) 9 | .applyFilter({ key: 'visibility', value: { 'in': [3, 4] } }) 10 | .applyFilter({ key: 'status', value: { 'in': [0, 1] } })/* 2 = disabled, 3 = out of stock */ 11 | 12 | if (config.products.listOutOfStockProducts === false) { 13 | searchQuery = searchQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } }) 14 | } 15 | 16 | return searchQuery 17 | } 18 | -------------------------------------------------------------------------------- /core/modules/catalog/store/attribute/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import getters from './getters' 4 | import mutations from './mutations' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import AttributeState from '../../types/AttributeState' 7 | 8 | export const attributeModule: Module = { 9 | namespaced: true, 10 | state: { 11 | list_by_code: {}, 12 | list_by_id: {}, 13 | blacklist: [], 14 | labels: {} 15 | }, 16 | getters, 17 | actions, 18 | mutations 19 | } 20 | -------------------------------------------------------------------------------- /core/modules/catalog/store/attribute/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_ATTRIBUTE = 'attribute' 2 | export const ATTRIBUTE_UPD_ATTRIBUTES = SN_ATTRIBUTE + '/UPD_ATTRIBUTES' 3 | export const ATTRIBUTE_UPD_BLACKLIST = SN_ATTRIBUTE + '/UPD_BLACKLIST_ATTRIBUTES' 4 | -------------------------------------------------------------------------------- /core/modules/catalog/store/category/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import getters from './getters' 4 | import mutations from './mutations' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import CategoryState from '../../types/CategoryState' 7 | 8 | export const categoryModule: Module = { 9 | namespaced: true, 10 | state: { 11 | list: [], 12 | current: {}, 13 | filters: { 14 | available: {}, 15 | chosen: {} 16 | }, 17 | breadcrumbs: { 18 | routes: [] 19 | }, 20 | current_product_query: null, 21 | current_path: [] // list of categories from root to current 22 | }, 23 | getters, 24 | actions, 25 | mutations 26 | } 27 | -------------------------------------------------------------------------------- /core/modules/catalog/store/category/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_CATEGORY = 'category' 2 | export const CATEGORY_UPD_CATEGORIES = SN_CATEGORY + '/UPD_CATEGORIES' 3 | export const CATEGORY_UPD_CURRENT_CATEGORY = SN_CATEGORY + '/UPD_CURRENT_CATEGORY' 4 | export const CATEGORY_UPD_CURRENT_CATEGORY_PATH = SN_CATEGORY + '/UPD_CURRENT_CATEGORY_PATH' 5 | export const CATEGORY_UPD_SEARCH_PRODUCT_QUERY = SN_CATEGORY + '/UPD_SEARCH_PRODUCT_QUERY' 6 | export const CATEGORY_ADD_AVAILABLE_FILTER = `${SN_CATEGORY}/ADD_AVAILABLE_FILTER` 7 | export const CATEGORY_REMOVE_FILTERS = SN_CATEGORY + '/REMOVE_FILTERS' 8 | export const CATEGORY_SET_SEARCH_OPTIONS = `${SN_CATEGORY}/SET_SEARCH_OPTIONS` 9 | export const CATEGORY_MERGE_SEARCH_OPTIONS = `${SN_CATEGORY}/MERGE_SEARCH_OPTIONS` 10 | -------------------------------------------------------------------------------- /core/modules/catalog/store/stock/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import mutations from './mutations' 4 | import RootState from '@vue-storefront/core/types/RootState' 5 | import StockState from '../../types/StockState' 6 | 7 | export const stockModule: Module = { 8 | namespaced: true, 9 | actions, 10 | mutations, 11 | state: { 12 | cache: {} 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/modules/catalog/store/stock/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_CATALOG = 'catalog' 2 | export const SET_STOCK_CACHE = `${SN_CATALOG}/SET_STOCK_CACHE` 3 | export const SET_STOCK_CACHE_PRODUCT = `${SN_CATALOG}/SET_STOCK_CACHE_PRODUCT` 4 | -------------------------------------------------------------------------------- /core/modules/catalog/store/stock/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex' 2 | import StockState from '../../types/StockState' 3 | import * as types from './mutation-types' 4 | 5 | const mutations: MutationTree = { 6 | [types.SET_STOCK_CACHE] (state, cache) { 7 | state.cache = cache 8 | }, 9 | [types.SET_STOCK_CACHE_PRODUCT] (state, { productId, productInfo }) { 10 | state.cache = Object.assign({}, state.cache, { 11 | [productId]: productInfo 12 | }) 13 | } 14 | } 15 | 16 | export default mutations 17 | -------------------------------------------------------------------------------- /core/modules/catalog/store/tax/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import mutations from './mutations' 4 | import getters from './getters' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import TaxState from '../../types/TaxState' 7 | 8 | export const taxModule: Module = { 9 | namespaced: true, 10 | state: { 11 | rules: [] 12 | }, 13 | actions, 14 | mutations, 15 | getters 16 | } 17 | -------------------------------------------------------------------------------- /core/modules/catalog/store/tax/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_TAX = 'tax' 2 | export const TAX_UPDATE_RULES = SN_TAX + '/UPDATE_RULES' 3 | -------------------------------------------------------------------------------- /core/modules/catalog/store/tax/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import TaxState from '../../types/TaxState' 4 | 5 | const mutations: MutationTree = { 6 | [types.TAX_UPDATE_RULES] (state, taxClasses) { 7 | state.rules = taxClasses.items 8 | } 9 | } 10 | 11 | export default mutations 12 | -------------------------------------------------------------------------------- /core/modules/catalog/types/Attribute.ts: -------------------------------------------------------------------------------- 1 | export default interface Attribute { 2 | attribute_code?: string, 3 | attribute_id?: number | string 4 | } 5 | 6 | export interface AttributesMetadata { 7 | is_visible_on_front: string, 8 | is_visible: boolean, 9 | default_frontend_label: string, 10 | attribute_id: number, 11 | entity_type_id: string, 12 | id: number, 13 | frontend_input: string, 14 | is_user_defined: boolean, 15 | is_comparable: string, 16 | attribute_code: string, 17 | options: AttributesMetadataOptions[] 18 | } 19 | 20 | export interface AttributesMetadataOptions { 21 | label: string, 22 | value: string 23 | } 24 | -------------------------------------------------------------------------------- /core/modules/catalog/types/AttributeState.ts: -------------------------------------------------------------------------------- 1 | export default interface AttributeState { 2 | list_by_code: any, 3 | list_by_id: any, 4 | labels: any, 5 | blacklist: any[] 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/catalog/types/BundleOption.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 2 | 3 | export interface BundleOption { 4 | option_id: number, 5 | title: string, 6 | required: boolean, 7 | type: string, 8 | position: number, 9 | sku: string, 10 | product_links: BundleOptionsProductLink[] 11 | } 12 | 13 | export interface BundleOptionsProductLink { 14 | id: string | number, 15 | sku: string, 16 | option_id: number, 17 | qty: number, 18 | position: number, 19 | is_default: boolean, 20 | price?: number, 21 | price_type?: number, 22 | can_change_quantity: number, 23 | product?: Product 24 | } 25 | 26 | export interface SelectedBundleOption { 27 | option_id: number, 28 | option_qty: number, 29 | option_selections: number[] 30 | } 31 | -------------------------------------------------------------------------------- /core/modules/catalog/types/CategoryState.ts: -------------------------------------------------------------------------------- 1 | export default interface CategoryState { 2 | list: any, 3 | current: any, 4 | filters: { 5 | available: any, 6 | chosen: any 7 | }, 8 | breadcrumbs: { 9 | routes: any 10 | }, 11 | current_product_query: any, 12 | current_path: any 13 | } 14 | -------------------------------------------------------------------------------- /core/modules/catalog/types/ConfigurableOption.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigurableItemOption { 2 | label: string, 3 | option_id: string, 4 | option_value: string, 5 | value: string 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/catalog/types/CustomOption.ts: -------------------------------------------------------------------------------- 1 | export interface CustomOption { 2 | image_size_x: number, 3 | image_size_y: number, 4 | is_require: boolean, 5 | max_characters: number, 6 | option_id: number, 7 | product_sku: string, 8 | sort_order: number, 9 | title: string, 10 | type: string, 11 | price?: number, 12 | price_type?: string, 13 | values?: OptionValue[] 14 | } 15 | 16 | export interface OptionValue { 17 | option_type_id: number, 18 | price: number, 19 | price_type: string, 20 | sort_order: number, 21 | title: string 22 | } 23 | 24 | export type InputValue = string | number | number[] 25 | 26 | export interface SelectedCustomOption { 27 | option_id: number, 28 | option_value?: string 29 | } 30 | -------------------------------------------------------------------------------- /core/modules/catalog/types/ProductConfiguration.ts: -------------------------------------------------------------------------------- 1 | export interface ProductOption { 2 | attribute_code?: string, 3 | id: number | string, 4 | label: string, 5 | values?: any[] 6 | } 7 | 8 | export interface ProductConfiguration { 9 | color: ProductOption, 10 | size: ProductOption 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/catalog/types/ProductState.ts: -------------------------------------------------------------------------------- 1 | import Product from './Product'; 2 | 3 | export interface PagedProductList { 4 | start: number, 5 | perPage: number, 6 | total: number, 7 | items: Product[] 8 | } 9 | 10 | export default interface ProductState { 11 | breadcrumbs: { 12 | routes: any[], 13 | name: string 14 | }, 15 | current: any, 16 | current_options: any, 17 | current_configuration: any, 18 | parent: any, 19 | list: PagedProductList, 20 | original: any, 21 | related: { [key: string]: Product[] }, 22 | offlineImage: any, 23 | current_custom_options: any, 24 | current_bundle_options: any, 25 | custom_options_validators: any, 26 | productLoadStart: number, 27 | productLoadPromise: Promise | null, 28 | productGallery: any 29 | } 30 | -------------------------------------------------------------------------------- /core/modules/catalog/types/StockState.ts: -------------------------------------------------------------------------------- 1 | export default interface StockState { 2 | cache: any 3 | } 4 | -------------------------------------------------------------------------------- /core/modules/catalog/types/TaxState.ts: -------------------------------------------------------------------------------- 1 | export default interface TaxState { 2 | rules: any[] 3 | } 4 | -------------------------------------------------------------------------------- /core/modules/checkout/components/CartSummary.ts: -------------------------------------------------------------------------------- 1 | import { mapGetters } from 'vuex' 2 | import Microcart from '@vue-storefront/core/compatibility/components/blocks/Microcart/Microcart' 3 | 4 | export const CartSummary = { 5 | name: 'CartSummary', 6 | mixins: [Microcart], 7 | computed: { 8 | ...mapGetters({ 9 | totals: 'cart/getTotals', 10 | isVirtualCart: 'cart/isVirtualCart' 11 | }) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/modules/checkout/components/Product.ts: -------------------------------------------------------------------------------- 1 | export const Product = { 2 | name: 'Product', 3 | props: { 4 | product: { 5 | type: Object, 6 | required: true 7 | } 8 | }, 9 | computed: { 10 | thumbnail () { 11 | return this.getThumbnail(this.product.image, 150, 150) 12 | } 13 | }, 14 | methods: { 15 | onProductChanged (event) { 16 | if (event.item.sku === this.product.sku) { 17 | this.$forceUpdate() 18 | } 19 | } 20 | }, 21 | beforeMount () { 22 | this.$bus.$on('cart-after-itemchanged', this.onProductChanged) 23 | }, 24 | beforeDestroy () { 25 | this.$bus.$off('cart-after-itemchanged', this.onProductChanged) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/modules/checkout/types/CheckoutState.ts: -------------------------------------------------------------------------------- 1 | import ShippingDetails from './ShippingDetails' 2 | import PaymentDetails from './PaymentDetails' 3 | 4 | export default interface CheckoutState { 5 | order: any, 6 | paymentMethods: any[], 7 | shippingMethods: any[], 8 | personalDetails: { 9 | firstName: string, 10 | lastName: string, 11 | emailAddress: string, 12 | password: string, 13 | createAccount: boolean 14 | }, 15 | shippingDetails: ShippingDetails, 16 | paymentDetails: PaymentDetails, 17 | isThankYouPage: boolean, 18 | modifiedAt: number 19 | } 20 | -------------------------------------------------------------------------------- /core/modules/checkout/types/PaymentDetails.ts: -------------------------------------------------------------------------------- 1 | export default interface PaymentDetails { 2 | firstName: string, 3 | lastName: string, 4 | company: string, 5 | country: string, 6 | streetAddress: string, 7 | apartmentNumber: string, 8 | city: string, 9 | region_id: number | string, 10 | state: string, 11 | zipCode: string, 12 | phoneNumber: string, 13 | taxId: string, 14 | paymentMethod: string, 15 | paymentMethodAdditional: any 16 | } 17 | -------------------------------------------------------------------------------- /core/modules/checkout/types/PaymentState.ts: -------------------------------------------------------------------------------- 1 | export default interface PaymentState { 2 | methods: any[] 3 | } 4 | -------------------------------------------------------------------------------- /core/modules/checkout/types/ShippingDetails.ts: -------------------------------------------------------------------------------- 1 | export default interface ShippingDetails { 2 | firstName: string, 3 | lastName: string, 4 | country: string, 5 | streetAddress: string, 6 | apartmentNumber: string, 7 | city: string, 8 | state: string, 9 | region_id: number | string, 10 | zipCode: string, 11 | phoneNumber: string, 12 | shippingMethod: string 13 | } 14 | -------------------------------------------------------------------------------- /core/modules/checkout/types/ShippingState.ts: -------------------------------------------------------------------------------- 1 | export default interface ShippingState { 2 | methods: any[] 3 | } 4 | -------------------------------------------------------------------------------- /core/modules/cms/helpers/createHierarchyLoadQuery.ts: -------------------------------------------------------------------------------- 1 | import { SearchQuery } from 'storefront-query-builder' 2 | 3 | const createHierarchyLoadQuery = ({ id }): SearchQuery => { 4 | let query = new SearchQuery() 5 | 6 | if (id) { 7 | query = query.applyFilter({ key: 'identifier', value: { eq: id } }) 8 | } 9 | 10 | return query 11 | } 12 | 13 | export default createHierarchyLoadQuery 14 | -------------------------------------------------------------------------------- /core/modules/cms/helpers/createLoadingBlockQuery.ts: -------------------------------------------------------------------------------- 1 | import { SearchQuery } from 'storefront-query-builder' 2 | 3 | const createLoadingBlockQuery = ({ filterField, filterValues }): SearchQuery => { 4 | let query = new SearchQuery() 5 | 6 | if (filterValues) { 7 | query = query.applyFilter({ key: filterField, value: { like: filterValues } }) 8 | } 9 | 10 | return query 11 | } 12 | 13 | export default createLoadingBlockQuery 14 | -------------------------------------------------------------------------------- /core/modules/cms/helpers/createPageLoadingQuery.ts: -------------------------------------------------------------------------------- 1 | import { SearchQuery } from 'storefront-query-builder' 2 | 3 | const createPageLoadingQuery = ({ filterField, filterValues }): SearchQuery => { 4 | let query = new SearchQuery() 5 | 6 | if (filterValues) { 7 | query = query.applyFilter({ key: filterField, value: { like: filterValues } }) 8 | } 9 | 10 | return query 11 | } 12 | 13 | export default createPageLoadingQuery 14 | -------------------------------------------------------------------------------- /core/modules/cms/helpers/createSingleBlockQuery.ts: -------------------------------------------------------------------------------- 1 | import { SearchQuery } from 'storefront-query-builder' 2 | 3 | const createSingleBlockQuery = ({ key, value }): SearchQuery => { 4 | let query = new SearchQuery() 5 | 6 | if (value) { 7 | query = query.applyFilter({ key, value: { like: value } }) 8 | } 9 | 10 | return query 11 | } 12 | 13 | export default createSingleBlockQuery 14 | -------------------------------------------------------------------------------- /core/modules/cms/helpers/createSinglePageLoadQuery.ts: -------------------------------------------------------------------------------- 1 | import { SearchQuery } from 'storefront-query-builder' 2 | 3 | const createSinglePageLoadQuery = ({ key, value }): SearchQuery => { 4 | let query = new SearchQuery() 5 | 6 | if (value) { 7 | query = query.applyFilter({ key, value: { like: value } }) 8 | } 9 | 10 | return query 11 | } 12 | 13 | export default createSinglePageLoadQuery 14 | -------------------------------------------------------------------------------- /core/modules/cms/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import createLoadingBlockQuery from './createLoadingBlockQuery' 2 | import createSingleBlockQuery from './createSingleBlockQuery' 3 | import createHierarchyLoadQuery from './createHierarchyLoadQuery' 4 | import createPageLoadingQuery from './createPageLoadingQuery' 5 | import createSinglePageLoadQuery from './createSinglePageLoadQuery' 6 | 7 | export { 8 | createLoadingBlockQuery, 9 | createSingleBlockQuery, 10 | createHierarchyLoadQuery, 11 | createPageLoadingQuery, 12 | createSinglePageLoadQuery 13 | } 14 | -------------------------------------------------------------------------------- /core/modules/cms/index.ts: -------------------------------------------------------------------------------- 1 | import { cmsPageModule } from './store/page' 2 | import { cmsBlockModule } from './store/block' 3 | import { cmsHierarchyModule } from './store/hierarchy' 4 | import cmsPersistPlugin from './store/cmsPersistPlugin' 5 | import { StorefrontModule } from '@vue-storefront/core/lib/modules'; 6 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 7 | 8 | export const CmsModule: StorefrontModule = function ({ store }) { 9 | StorageManager.init('cms') 10 | store.registerModule('cmsPage', cmsPageModule) 11 | store.registerModule('cmsBlock', cmsBlockModule) 12 | store.registerModule('cmsHierarchy', cmsHierarchyModule) 13 | store.subscribe(cmsPersistPlugin) 14 | } 15 | -------------------------------------------------------------------------------- /core/modules/cms/store/block/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import getters from './getters' 4 | import mutations from './mutations' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import CmsBlockState from '../../types/CmsBlockState' 7 | 8 | export const cmsBlockStorageKey = 'cms-blocks' 9 | 10 | export const cmsBlockModule: Module = { 11 | namespaced: true, 12 | state: { 13 | items: [] 14 | }, 15 | getters, 16 | actions, 17 | mutations 18 | } 19 | -------------------------------------------------------------------------------- /core/modules/cms/store/block/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_CMS_BLOCK = 'cmsBlock' 2 | export const CMS_BLOCK_UPDATE_CMS_BLOCKS = SN_CMS_BLOCK + '/UPDATE_CMS_BLOCKS' 3 | export const CMS_BLOCK_ADD_CMS_BLOCK = SN_CMS_BLOCK + '/ADD_CMS_BLOCK' 4 | -------------------------------------------------------------------------------- /core/modules/cms/store/block/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import CmsBlockState from '../../types/CmsBlockState' 4 | 5 | const mutations: MutationTree = { 6 | [types.CMS_BLOCK_UPDATE_CMS_BLOCKS] (state, cmsBlocks) { 7 | state.items = cmsBlocks || [] 8 | }, 9 | [types.CMS_BLOCK_ADD_CMS_BLOCK] (state, cmsBlock) { 10 | const record = state.items.find(c => c.id === cmsBlock.id) 11 | if (!record) { 12 | state.items.push(cmsBlock) 13 | } 14 | } 15 | } 16 | 17 | export default mutations 18 | -------------------------------------------------------------------------------- /core/modules/cms/store/hierarchy/actions.ts: -------------------------------------------------------------------------------- 1 | import { ActionTree } from 'vuex' 2 | import { quickSearchByQuery } from '@vue-storefront/core/lib/search' 3 | import RootState from '@vue-storefront/core/types/RootState'; 4 | import CmsHierarchyState from '../../types/CmsHierarchyState' 5 | import { createHierarchyLoadQuery } from '@vue-storefront/core/modules/cms/helpers' 6 | 7 | const actions: ActionTree = { 8 | list (context, { id, entityType = 'cms_hierarchy', excludeFields = null, includeFields = null }) { 9 | return quickSearchByQuery({ 10 | query: createHierarchyLoadQuery({ id }), 11 | entityType, 12 | excludeFields, 13 | includeFields 14 | }) 15 | } 16 | } 17 | 18 | export default actions 19 | -------------------------------------------------------------------------------- /core/modules/cms/store/hierarchy/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import RootState from '@vue-storefront/core/types/RootState' 4 | import CmsHierarchyState from '../../types/CmsHierarchyState' 5 | 6 | export const cmsHierarchyModule: Module = { 7 | namespaced: true, 8 | state: { 9 | items: [] 10 | }, 11 | actions 12 | } 13 | -------------------------------------------------------------------------------- /core/modules/cms/store/hierarchy/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_CMS_HIERARCHY = 'cms_hierarchy' 2 | export const CMS_HIERARCHY_UPDATE_CMS_HIERARCHIES = SN_CMS_HIERARCHY + '/UPDATE_CMS_HIERARCHIES' 3 | -------------------------------------------------------------------------------- /core/modules/cms/store/page/getters.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree } from 'vuex' 2 | import RootState from '@vue-storefront/core/types/RootState' 3 | import CmsPageState from '../../types/CmsPageState' 4 | import { Logger } from '@vue-storefront/core/lib/logger' 5 | 6 | const getters: GetterTree = { 7 | cmsPages: (state, getters) => { 8 | Logger.error('The getter cmsPage/cmsPages has been deprecated please change to cmsPage/getCmsPages')() 9 | 10 | return getters.getCmsPages 11 | }, 12 | getCmsPages: (state) => state.items, 13 | hasItems: (state) => state.items && state.items.length > 0, 14 | findItems: (state) => ({ key, value }) => state.items.find(p => p[key] === value) 15 | } 16 | 17 | export default getters 18 | -------------------------------------------------------------------------------- /core/modules/cms/store/page/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import getters from './getters' 4 | import mutations from './mutations' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import CmsPageState from '../../types/CmsPageState' 7 | 8 | export const cmsPagesStorageKey = 'cms-page' 9 | 10 | export const cmsPageModule: Module = { 11 | namespaced: true, 12 | state: { 13 | items: [], 14 | current: null 15 | }, 16 | getters, 17 | actions, 18 | mutations 19 | } 20 | -------------------------------------------------------------------------------- /core/modules/cms/store/page/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_CMS_PAGE = 'cmsPage' 2 | export const CMS_PAGE_UPDATE_CMS_PAGES = SN_CMS_PAGE + '/UPDATE_CMS_PAGES' 3 | export const CMS_PAGE_ADD_CMS_PAGE = SN_CMS_PAGE + '/ADD_CMS_PAGE' 4 | export const CMS_PAGE_SET_CURRENT = SN_CMS_PAGE + '/SET_CURRENT_CMS_PAGE' 5 | -------------------------------------------------------------------------------- /core/modules/cms/store/page/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import CmsPageState from '../../types/CmsPageState' 4 | 5 | const mutations: MutationTree = { 6 | [types.CMS_PAGE_UPDATE_CMS_PAGES] (state, cmsPages) { 7 | state.items = cmsPages || [] 8 | }, 9 | [types.CMS_PAGE_SET_CURRENT] (state, current) { 10 | state.current = current 11 | }, 12 | [types.CMS_PAGE_ADD_CMS_PAGE] (state, cmsPage) { 13 | const record = state.items.find(c => c.id === cmsPage.id) 14 | if (!record) { 15 | state.items.push(cmsPage) 16 | } 17 | } 18 | } 19 | 20 | export default mutations 21 | -------------------------------------------------------------------------------- /core/modules/cms/types/CmsBlockState.ts: -------------------------------------------------------------------------------- 1 | export default interface CmsBlockState { 2 | items: any[] 3 | } 4 | -------------------------------------------------------------------------------- /core/modules/cms/types/CmsHierarchyState.ts: -------------------------------------------------------------------------------- 1 | export default interface CmsHierarchyState { 2 | items: any[] 3 | } 4 | -------------------------------------------------------------------------------- /core/modules/cms/types/CmsPageState.ts: -------------------------------------------------------------------------------- 1 | export default interface CmsPageState { 2 | items: any[], 3 | current: any 4 | } 5 | -------------------------------------------------------------------------------- /core/modules/compare/components/AddToCompare.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product' 2 | import { CompareModule } from '../' 3 | import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin' 4 | import { registerModule } from '@vue-storefront/core/lib/modules'; 5 | 6 | export const AddToCompare = { 7 | name: 'AddToCompare', 8 | mixins: [compareMountedMixin], 9 | created () { 10 | registerModule(CompareModule) 11 | }, 12 | methods: { 13 | addToCompare (product: Product) { 14 | return this.$store.state['compare'] 15 | ? this.$store.dispatch('compare/addItem', product) 16 | : false 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/modules/compare/components/CompareButton.ts: -------------------------------------------------------------------------------- 1 | import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin' 2 | 3 | export const CompareButton = { 4 | name: 'CompareButton', 5 | mixins: [compareMountedMixin], 6 | computed: { 7 | isEmpty (): boolean { 8 | return this.$store.getters['compare/isEmpty'] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/compare/components/IsOnCompare.ts: -------------------------------------------------------------------------------- 1 | import { CompareModule } from '..' 2 | import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin' 3 | import { registerModule } from '@vue-storefront/core/lib/modules'; 4 | 5 | export const IsOnCompare = { 6 | name: 'IsOnCompare', 7 | mixins: [compareMountedMixin], 8 | props: { 9 | product: { 10 | required: true, 11 | type: Object 12 | } 13 | }, 14 | created () { 15 | registerModule(CompareModule) 16 | }, 17 | computed: { 18 | isOnCompare () { 19 | return this.$store.getters['compare/isOnCompare'](this.product) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/modules/compare/components/Product.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product' 2 | import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin' 3 | 4 | export const CompareProduct = { 5 | name: 'CompareProduct', 6 | mixins: [compareMountedMixin], 7 | computed: { 8 | isOnCompare (): boolean { 9 | return this.$store.getters['compare/isOnCompare'](this.product) 10 | } 11 | }, 12 | methods: { 13 | removeFromCompare (product: Product) { 14 | return this.$store.state['compare'] 15 | ? this.$store.dispatch('compare/removeItem', product) 16 | : false 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/modules/compare/components/RemoveFromCompare.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product'; 2 | import { CompareModule } from '..'; 3 | import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin'; 4 | import { registerModule } from '@vue-storefront/core/lib/modules'; 5 | 6 | export const RemoveFromCompare = { 7 | name: 'RemoveFromCompare', 8 | mixins: [compareMountedMixin], 9 | methods: { 10 | removeFromCompare (product: Product) { 11 | registerModule(CompareModule) 12 | this.$store.dispatch('compare/removeItem', product); 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /core/modules/compare/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { compareStore } from './store' 3 | import cachePersistPlugin from './store/plugin' 4 | import { StorefrontModule } from '@vue-storefront/core/lib/modules'; 5 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 6 | 7 | export const CompareModule: StorefrontModule = function ({ store }) { 8 | StorageManager.init('compare') 9 | store.registerModule('compare', compareStore) 10 | store.subscribe(cachePersistPlugin) 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/compare/mixins/compareMountedMixin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is mixin for all module components. 3 | * Invoke here actions, which were not invoked on server-side render, like reading LocalStorage or checking window size. 4 | */ 5 | 6 | export default { 7 | mounted () { 8 | this.$store.dispatch('compare/load') 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/compare/store/getters.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree } from 'vuex' 2 | import RootState from '@vue-storefront/core/types/RootState' 3 | import CompareState from '../types/CompareState' 4 | 5 | const getters: GetterTree = { 6 | isEmpty: state => state.items.length === 0, 7 | isOnCompare: state => product => state.items.some(p => p.sku === product.sku), 8 | isCompareLoaded: state => state.loaded, 9 | getCompareProductsCount: state => state.items.length, 10 | getCompareItems: state => state.items 11 | } 12 | 13 | export default getters 14 | -------------------------------------------------------------------------------- /core/modules/compare/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import getters from './getters' 4 | import mutations from './mutations' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import CompareState from '../types/CompareState' 7 | 8 | export const compareStore: Module = { 9 | namespaced: true, 10 | state: { 11 | loaded: false, 12 | items: [] 13 | }, 14 | getters, 15 | actions, 16 | mutations 17 | } 18 | -------------------------------------------------------------------------------- /core/modules/compare/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_COMPARE = 'compare' 2 | export const COMPARE_ADD_ITEM = `${SN_COMPARE}/ADD` 3 | export const COMPARE_DEL_ITEM = `${SN_COMPARE}/DEL` 4 | export const COMPARE_LOAD_COMPARE = `${SN_COMPARE}/LOAD` 5 | export const SET_COMPARE_LOADED = `${SN_COMPARE}/SET_COMPARE_LOADED` 6 | -------------------------------------------------------------------------------- /core/modules/compare/store/plugin.ts: -------------------------------------------------------------------------------- 1 | import * as types from './mutation-types' 2 | import { Logger } from '@vue-storefront/core/lib/logger' 3 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 4 | 5 | const watchedMutations = [types.COMPARE_ADD_ITEM, types.COMPARE_DEL_ITEM, types.COMPARE_LOAD_COMPARE].map(m => `compare/${m}`) 6 | 7 | const cachePersistPlugin = (mutation, state) => { 8 | const cacheStorage = StorageManager.get('compare') 9 | 10 | if (watchedMutations.includes(mutation.type)) { 11 | cacheStorage.setItem('current-compare', state.compare.items).catch((reason) => { 12 | Logger.error(reason, 'compare') 13 | }) 14 | } 15 | } 16 | 17 | export default cachePersistPlugin 18 | -------------------------------------------------------------------------------- /core/modules/compare/test/unit/mixins/compareMountedMixin.spec.ts: -------------------------------------------------------------------------------- 1 | import { mountMixinWithStore } from '@vue-storefront/unit-tests/utils' 2 | 3 | import compareMountedMixin from '../../../mixins/compareMountedMixin' 4 | 5 | describe('compareMountedMixin', () => { 6 | beforeEach(() => { 7 | jest.clearAllMocks() 8 | }) 9 | 10 | it('load compare state on mount', () => { 11 | const storeMock = { 12 | modules: { 13 | compare: { 14 | actions: { 15 | load: jest.fn() 16 | }, 17 | namespaced: true 18 | } 19 | } 20 | } 21 | 22 | mountMixinWithStore(compareMountedMixin, storeMock) 23 | 24 | expect(storeMock.modules.compare.actions.load).toBeCalled() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /core/modules/compare/types/CompareState.ts: -------------------------------------------------------------------------------- 1 | export default interface CompareState { 2 | /** 3 | * Informs if items to compare are already loaded from local cache. 4 | */ 5 | loaded: boolean, 6 | items: any[] 7 | } 8 | -------------------------------------------------------------------------------- /core/modules/initial-resources/index.ts: -------------------------------------------------------------------------------- 1 | import { isServer } from '@vue-storefront/core/helpers' 2 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 3 | import clientResourcesLoader from './clientResourcesLoader' 4 | 5 | export const InitialResourcesModule: StorefrontModule = function () { 6 | if (isServer) return 7 | window.addEventListener('load', clientResourcesLoader) 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/initial-resources/types.ts: -------------------------------------------------------------------------------- 1 | export interface InitialResources { 2 | filters: string[], 3 | regexps?: RegExp[], 4 | type?: 'script' | 'style', 5 | onload?: boolean, 6 | rel?: 'prefetch' | 'preload' 7 | } 8 | -------------------------------------------------------------------------------- /core/modules/mailer/index.ts: -------------------------------------------------------------------------------- 1 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 2 | import { mailerStore } from './store' 3 | 4 | export const MailerModule: StorefrontModule = function ({ store }) { 5 | store.registerModule('mailer', mailerStore) 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/mailer/types/MailItem.ts: -------------------------------------------------------------------------------- 1 | export default interface MailItem { 2 | sourceAddress: string, 3 | targetAddress: string, 4 | subject: string, 5 | emailText: string, 6 | confirmation?: boolean 7 | } 8 | -------------------------------------------------------------------------------- /core/modules/newsletter/components/Newsletter.ts: -------------------------------------------------------------------------------- 1 | import SubscriptionStatus from '@vue-storefront/core/modules/newsletter/mixins/SubscriptionStatus' 2 | import Subscribe from '@vue-storefront/core/modules/newsletter/mixins/Subscribe' 3 | import Unsubscribe from '@vue-storefront/core/modules/newsletter/mixins/Unsubscribe' 4 | 5 | export const Newsletter = { 6 | name: 'Newsletter', 7 | mixins: [SubscriptionStatus, Subscribe, Unsubscribe] 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/newsletter/index.ts: -------------------------------------------------------------------------------- 1 | import { newsletterStore } from './store' 2 | import { StorefrontModule } from '@vue-storefront/core/lib/modules'; 3 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 4 | 5 | export const NewsletterModule: StorefrontModule = function ({ store }) { 6 | StorageManager.init('newsletter') 7 | store.registerModule('newsletter', newsletterStore) 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/newsletter/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const NEWSLETTER_SUBSCRIBE = 'NEWSLETTER_SUBSCRIBE' 2 | export const NEWSLETTER_UNSUBSCRIBE = 'NEWSLETTER_UNSUBSCRIBE' 3 | export const SET_EMAIL = 'SET_EMAIL' 4 | -------------------------------------------------------------------------------- /core/modules/newsletter/test/unit/components/Newsletter.spec.ts: -------------------------------------------------------------------------------- 1 | import { mountMixinWithStore } from '@vue-storefront/unit-tests/utils' 2 | 3 | import { Newsletter } from '../../../components/Newsletter' 4 | 5 | jest.mock('@vue-storefront/core/modules/newsletter/mixins/SubscriptionStatus', () => ({})) 6 | jest.mock('@vue-storefront/core/modules/newsletter/mixins/Subscribe', () => ({})) 7 | jest.mock('@vue-storefront/core/modules/newsletter/mixins/Unsubscribe', () => ({})) 8 | 9 | describe('Newsletter', () => { 10 | beforeEach(() => { 11 | jest.clearAllMocks() 12 | }) 13 | 14 | it('can be initialized', () => { 15 | const wrapper = mountMixinWithStore(Newsletter) 16 | 17 | expect(wrapper.isVueInstance()).toBe(true) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /core/modules/newsletter/types/NewsletterState.ts: -------------------------------------------------------------------------------- 1 | export interface NewsletterState { 2 | isSubscribed: boolean | null, 3 | email: string | null 4 | } 5 | -------------------------------------------------------------------------------- /core/modules/notification/components/Notification.ts: -------------------------------------------------------------------------------- 1 | import NotificationItem from '../types/NotificationItem' 2 | 3 | export const Notification = { 4 | name: 'Notification', 5 | computed: { 6 | notifications (): NotificationItem[] { 7 | return this.$store.getters['notification/notifications'] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/notification/index.ts: -------------------------------------------------------------------------------- 1 | import { notificationStore } from './store' 2 | import { StorefrontModule } from '@vue-storefront/core/lib/modules'; 3 | 4 | export const NotificationModule: StorefrontModule = function ({ store }) { 5 | store.registerModule('notification', notificationStore) 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/notification/types/NotificationItem.ts: -------------------------------------------------------------------------------- 1 | interface ActionItem { 2 | label: string, 3 | action?(): any 4 | } 5 | 6 | export default interface NotificationItem { 7 | id?: number, 8 | type: string, 9 | message: string, 10 | timeToLive?: number, 11 | action1: ActionItem, 12 | action2?: ActionItem, 13 | hasNoTimeout?: boolean 14 | } 15 | -------------------------------------------------------------------------------- /core/modules/notification/types/NotificationState.ts: -------------------------------------------------------------------------------- 1 | import NotificationItem from './NotificationItem' 2 | 3 | export default interface NotificationState { 4 | notifications: NotificationItem[] 5 | } 6 | -------------------------------------------------------------------------------- /core/modules/offline-order/README.md: -------------------------------------------------------------------------------- 1 | Needs refactoring -------------------------------------------------------------------------------- /core/modules/offline-order/components/CancelOrders.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from '@vue-storefront/core/lib/logger' 2 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 3 | 4 | export const CancelOrders = { 5 | methods: { 6 | cancelOrders () { 7 | const ordersCollection = StorageManager.get('orders') 8 | ordersCollection.iterate((order, id, iterationNumber) => { 9 | if (!order.transmited) { 10 | ordersCollection.removeItem(id) 11 | } 12 | }).catch(err => { 13 | Logger.error(err, 'offline-order')() 14 | Logger.log('Not transmitted orders have been deleted', 'offline-order')() 15 | }) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/modules/offline-order/components/ConfirmOrders.ts: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | export const ConfirmOrders = { 3 | methods: { 4 | confirmOrders () { 5 | this.$bus.$emit('order/PROCESS_QUEUE', { config: config }) 6 | this.$bus.$emit('sync/PROCESS_QUEUE', { config: config }) 7 | this.$store.dispatch('cart/load') 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/order/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import optimizeOrder from './optimizeOrder' 2 | import prepareOrder from './prepareOrder' 3 | import notifications from './notifications' 4 | 5 | export { optimizeOrder, prepareOrder, notifications } 6 | -------------------------------------------------------------------------------- /core/modules/order/helpers/notifications.ts: -------------------------------------------------------------------------------- 1 | import i18n from '@vue-storefront/i18n' 2 | import config from 'config' 3 | 4 | const internalValidationError = () => ({ 5 | type: 'error', 6 | message: i18n.t('Internal validation error. Please check if all required fields are filled in. Please contact us on {email}', { email: config.mailer.contactAddress }), 7 | action1: { label: i18n.t('OK') } 8 | }) 9 | 10 | const orderCannotTransfered = () => ({ 11 | type: 'error', 12 | message: i18n.t('The order can not be transfered because of server error. Order has been queued'), 13 | action1: { label: i18n.t('OK') } 14 | }) 15 | 16 | const notifications = { internalValidationError, orderCannotTransfered } 17 | 18 | export default notifications 19 | -------------------------------------------------------------------------------- /core/modules/order/helpers/optimizeOrder.ts: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | import omit from 'lodash-es/omit' 3 | import { Order } from '@vue-storefront/core/modules/order/types/Order' 4 | 5 | const optimizeOrder = (order: Order): Order => { 6 | if (config.entities.optimize && config.entities.optimizeShoppingCart) { 7 | return { 8 | ...order, 9 | products: order.products.map(product => omit(product, ['configurable_options', 'configurable_children'])) as Order['products'] 10 | } 11 | } 12 | 13 | return order 14 | } 15 | 16 | export default optimizeOrder 17 | -------------------------------------------------------------------------------- /core/modules/order/helpers/prepareOrder.ts: -------------------------------------------------------------------------------- 1 | import { Order } from '@vue-storefront/core/modules/order/types/Order' 2 | import { currentStoreView } from '@vue-storefront/core/lib/multistore' 3 | 4 | const prepareOrder = (order: Order): Order => { 5 | const storeView = currentStoreView() 6 | const storeCode = storeView.storeCode ? storeView.storeCode : order.store_code 7 | 8 | return { 9 | ...order, 10 | store_code: storeCode 11 | } 12 | } 13 | 14 | export default prepareOrder 15 | -------------------------------------------------------------------------------- /core/modules/order/store/getters.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree } from 'vuex' 2 | import OrderState from '../types/OrderState' 3 | import RootState from '@vue-storefront/core/types/RootState' 4 | 5 | const getters: GetterTree = { 6 | getSessionOrderHashes: state => state.session_order_hashes 7 | } 8 | 9 | export default getters 10 | -------------------------------------------------------------------------------- /core/modules/order/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import mutations from './mutations' 4 | import getters from './getters' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import OrderState from '../types/OrderState' 7 | 8 | export const orderStore: Module = { 9 | namespaced: true, 10 | state: { 11 | last_order_confirmation: null, 12 | session_order_hashes: [] 13 | }, 14 | actions, 15 | mutations, 16 | getters 17 | } 18 | -------------------------------------------------------------------------------- /core/modules/order/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_ORDER = 'orders' 2 | export const ORDER_PROCESS_QUEUE = SN_ORDER + '/PROCESS_QUEUE' 3 | export const ORDER_LAST_ORDER_WITH_CONFIRMATION = SN_ORDER + '/LAST_ORDER_CONFIRMATION' 4 | export const ORDER_ADD_SESSION_ORDER_HASH = SN_ORDER + '/ADD_SESSION_ORDER_HASH' 5 | export const ORDER_REMOVE_SESSION_ORDER_HASH = SN_ORDER + '/REMOVE_SESSION_ORDER_HASH' 6 | export const ORDER_ADD_SESSION_STAMPS = SN_ORDER + '/ADD_SESSION_STAMPS' 7 | -------------------------------------------------------------------------------- /core/modules/order/store/order.schema.extension.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /core/modules/order/types/OrderState.ts: -------------------------------------------------------------------------------- 1 | export default interface OrderState { 2 | last_order_confirmation: any, 3 | session_order_hashes: string[] 4 | } 5 | -------------------------------------------------------------------------------- /core/modules/recently-viewed/components/RecentlyViewed.js: -------------------------------------------------------------------------------- 1 | import { mapState } from 'vuex' 2 | 3 | export default { 4 | name: 'RecentlyViewed', 5 | computed: { 6 | ...mapState('recently-viewed', [ 7 | 'items' 8 | ]) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/recently-viewed/index.ts: -------------------------------------------------------------------------------- 1 | import { recentlyViewedStore } from './store' 2 | import { plugin } from './store/plugin' 3 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 4 | import { StorefrontModule } from '@vue-storefront/core/lib/modules'; 5 | import { isServer } from '@vue-storefront/core/helpers' 6 | 7 | export const cacheStorage = StorageManager.init('recently-viewed') 8 | 9 | export const RecentlyViewedModule: StorefrontModule = function ({ store }) { 10 | store.registerModule('recently-viewed', recentlyViewedStore) 11 | store.subscribe(plugin) 12 | 13 | if (!isServer) store.dispatch('recently-viewed/load') 14 | } 15 | -------------------------------------------------------------------------------- /core/modules/recently-viewed/store/actions.ts: -------------------------------------------------------------------------------- 1 | import { ActionTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import RootState from '@vue-storefront/core/types/RootState' 4 | import RecentlyViewedState from '../types/RecentlyViewedState' 5 | import { cacheStorage } from '../' 6 | 7 | const actions: ActionTree = { 8 | load ({ commit }) { 9 | cacheStorage.getItem('recently-viewed', (err, storedItems) => { 10 | if (err) throw new Error(err) 11 | commit(types.RECENTLY_VIEWED_LOAD, storedItems) 12 | }) 13 | }, 14 | addItem ({ commit }, product) { 15 | commit(types.RECENTLY_VIEWED_ADD_ITEM, { product }) 16 | } 17 | } 18 | 19 | export default actions 20 | -------------------------------------------------------------------------------- /core/modules/recently-viewed/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import mutations from './mutations' 4 | import RootState from '@vue-storefront/core/types/RootState' 5 | import RecentlyViewedState from '../types/RecentlyViewedState' 6 | 7 | export const recentlyViewedStore: Module = { 8 | namespaced: true, 9 | state: { 10 | items: [] 11 | }, 12 | actions, 13 | mutations 14 | } 15 | -------------------------------------------------------------------------------- /core/modules/recently-viewed/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_RECENTLY_VIEWED = 'recently-viewed' 2 | export const RECENTLY_VIEWED_ADD_ITEM = SN_RECENTLY_VIEWED + '/ADD' 3 | export const RECENTLY_VIEWED_LOAD = SN_RECENTLY_VIEWED + '/LOAD' 4 | -------------------------------------------------------------------------------- /core/modules/recently-viewed/store/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import RecentlyViewedState from '../types/RecentlyViewedState' 4 | 5 | const mutations: MutationTree = { 6 | /** 7 | * Add product to Recently Viewed Products 8 | * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md 9 | */ 10 | [types.RECENTLY_VIEWED_ADD_ITEM] (state, { product }) { 11 | const record = state.items.find(p => p.sku === product.sku) 12 | if (!record) { 13 | state.items.unshift(product) 14 | } 15 | }, 16 | [types.RECENTLY_VIEWED_LOAD] (state, storedItems) { 17 | state.items = storedItems || [] 18 | } 19 | } 20 | 21 | export default mutations 22 | -------------------------------------------------------------------------------- /core/modules/recently-viewed/store/plugin.ts: -------------------------------------------------------------------------------- 1 | import * as types from './mutation-types' 2 | import { cacheStorage } from '../' 3 | import { Logger } from '@vue-storefront/core/lib/logger' 4 | 5 | export function plugin (mutation, state) { 6 | const type = mutation.type 7 | 8 | if (type.startsWith(types.SN_RECENTLY_VIEWED)) { // check if this mutation is recently-viewed related 9 | cacheStorage.setItem('recently-viewed', state['recently-viewed'].items).catch((reason) => { 10 | Logger.error(reason)() // it doesn't work on SSR 11 | }) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/modules/recently-viewed/types/RecentlyViewedState.ts: -------------------------------------------------------------------------------- 1 | export default interface RecentlyViewedState { 2 | items: any[] 3 | } 4 | -------------------------------------------------------------------------------- /core/modules/review/components/AddReview.ts: -------------------------------------------------------------------------------- 1 | import Review from '@vue-storefront/core/modules/review/types/Review' 2 | 3 | export const AddReview = { 4 | name: 'AddReview', 5 | methods: { 6 | addReview (review: Review) { 7 | this.$store.dispatch('review/add', review) 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/review/components/Reviews.ts: -------------------------------------------------------------------------------- 1 | import Review from '../types/Review' 2 | 3 | export const Reviews = { 4 | name: 'Reviews', 5 | computed: { 6 | reviews (): Review[] { 7 | return this.$store.state.review.items.items 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/review/helpers/createLoadReviewsQuery.ts: -------------------------------------------------------------------------------- 1 | import { SearchQuery } from 'storefront-query-builder' 2 | 3 | const createLoadReviewsQuery = ({ productId, approved }) => { 4 | let query = new SearchQuery() 5 | 6 | if (productId) { 7 | query = query.applyFilter({ key: 'product_id', value: { 'eq': productId } }) 8 | } 9 | 10 | if (approved) { 11 | query = query.applyFilter({ key: 'review_status', value: { 'eq': 1 } }) 12 | } 13 | 14 | return query 15 | } 16 | export default createLoadReviewsQuery 17 | -------------------------------------------------------------------------------- /core/modules/review/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import createLoadReviewsQuery from './createLoadReviewsQuery' 2 | 3 | export { createLoadReviewsQuery } 4 | -------------------------------------------------------------------------------- /core/modules/review/index.ts: -------------------------------------------------------------------------------- 1 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 2 | import { reviewStore } from './store' 3 | 4 | export const ReviewModule: StorefrontModule = function ({ store }) { 5 | store.registerModule('review', reviewStore) 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/review/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import mutations from './mutations'; 4 | import RootState from '@vue-storefront/core/types/RootState'; 5 | import ReviewState from '../types/ReviewState'; 6 | 7 | export const reviewStore: Module = { 8 | namespaced: true, 9 | state: { 10 | items: [] 11 | }, 12 | actions, 13 | mutations 14 | } 15 | -------------------------------------------------------------------------------- /core/modules/review/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_REVIEW = 'review' 2 | export const REVIEW_UPD_REVIEWS = SN_REVIEW + '/UPD_REVIEWS' 3 | -------------------------------------------------------------------------------- /core/modules/review/store/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import ReviewState from '../types/ReviewState' 4 | 5 | const mutations: MutationTree = { 6 | [types.REVIEW_UPD_REVIEWS] (state, items) { 7 | state.items = items 8 | } 9 | } 10 | 11 | export default mutations 12 | -------------------------------------------------------------------------------- /core/modules/review/test/unit/store/mutations.spec.ts: -------------------------------------------------------------------------------- 1 | import * as types from '../../../store/mutation-types' 2 | import reviewedMutations from '../../../store/mutations' 3 | 4 | describe('Review mutations', () => { 5 | beforeEach(() => { 6 | jest.clearAllMocks() 7 | }) 8 | 9 | describe('REVIEW_UPD_REVIEWS', () => { 10 | it('update review items', () => { 11 | const stateMock = { 12 | items: [] 13 | } 14 | const reviewItem = { foo: '123' } 15 | const expectedState = { 16 | items: [ 17 | reviewItem 18 | ] 19 | } 20 | const wrapper = (mutations: any) => mutations[types.REVIEW_UPD_REVIEWS](stateMock, [ reviewItem ]) 21 | 22 | wrapper(reviewedMutations) 23 | 24 | expect(stateMock).toEqual(expectedState) 25 | }) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /core/modules/review/types/Review.ts: -------------------------------------------------------------------------------- 1 | export default interface Review { 2 | product_id: number | string, 3 | title: string, 4 | detail: string, 5 | nickname: string, 6 | review_entity: string, 7 | review_status: number, 8 | customer_id?: number | string | null, 9 | [k: string]: any 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/review/types/ReviewRequest.ts: -------------------------------------------------------------------------------- 1 | import Review from './Review'; 2 | 3 | export interface ReviewRequest { 4 | review: Review, 5 | [k: string]: any 6 | } 7 | -------------------------------------------------------------------------------- /core/modules/review/types/ReviewState.ts: -------------------------------------------------------------------------------- 1 | export default interface ReviewState { 2 | items: any[] 3 | } 4 | -------------------------------------------------------------------------------- /core/modules/url/index.ts: -------------------------------------------------------------------------------- 1 | import { urlStore } from './store' 2 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 3 | import { beforeEachGuard } from './router/beforeEach' 4 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 5 | 6 | export const cacheStorage = StorageManager.init('url') 7 | 8 | export const UrlModule: StorefrontModule = function ({ store, router }) { 9 | store.registerModule('url', urlStore) 10 | router.beforeEach(beforeEachGuard) 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/url/store/getters.ts: -------------------------------------------------------------------------------- 1 | export const getters = { 2 | getCurrentRoute: (state) => state.currentRoute, 3 | isBackRoute: (state) => state.isBackRoute, 4 | getPrevRoute: (state) => state.prevRoute 5 | } 6 | -------------------------------------------------------------------------------- /core/modules/url/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import { UrlState } from '../types/UrlState' 3 | import { actions } from './actions' 4 | import { state } from './state' 5 | import { getters } from './getters' 6 | import { mutations } from './mutations' 7 | 8 | export const urlStore: Module = { 9 | namespaced: true, 10 | actions, 11 | state, 12 | getters, 13 | mutations 14 | } 15 | -------------------------------------------------------------------------------- /core/modules/url/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SET_CURRENT_ROUTE = 'URL/SET_CURRENT_ROUTE' 2 | export const SET_PREV_ROUTE = 'URL/SET_PREV_ROUTE' 3 | export const IS_BACK_ROUTE = 'URL/IS_BACK_ROUTE' 4 | -------------------------------------------------------------------------------- /core/modules/url/store/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import omit from 'lodash-es/omit' 4 | 5 | export const mutations: MutationTree = { 6 | [types.SET_CURRENT_ROUTE] (state, payload = {}) { 7 | state.currentRoute = omit({ ...payload }, ['matched']) 8 | }, 9 | [types.SET_PREV_ROUTE] (state, payload = {}) { 10 | state.prevRoute = omit({ ...payload }, ['matched']) 11 | }, 12 | [types.IS_BACK_ROUTE] (state, payload) { 13 | state.isBackRoute = payload 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/modules/url/store/state.ts: -------------------------------------------------------------------------------- 1 | import { UrlState } from '../types/UrlState' 2 | 3 | export const state: UrlState = { 4 | dispatcherMap: {}, 5 | currentRoute: {}, 6 | prevRoute: {}, 7 | isBackRoute: false 8 | } 9 | -------------------------------------------------------------------------------- /core/modules/url/test/unit/helpers/data.ts: -------------------------------------------------------------------------------- 1 | let product = { 2 | sku: 'MSH09', 3 | slug: 'troy-yoga-short-994', 4 | url_path: 'men/bottoms-men/shorts-men/shorts-19/troy-yoga-short-994.html', 5 | type_id: 'configurable', 6 | parentSku: 'MSH09' 7 | } 8 | 9 | export { 10 | product 11 | } 12 | -------------------------------------------------------------------------------- /core/modules/url/types/UrlState.ts: -------------------------------------------------------------------------------- 1 | import { Route } from 'vue-router'; 2 | import { LocalizedRoute } from '@vue-storefront/core/lib/types' 3 | 4 | interface UrlModuleRoute extends Partial { 5 | scrollPosition?: { 6 | x: number, 7 | y: number 8 | }, 9 | categoryPageSize?: number 10 | } 11 | 12 | // This object should represent structure of your modules Vuex state 13 | // It's a good practice is to name this interface accordingly to the KET (for example mailchimpState) 14 | export interface UrlState { 15 | dispatcherMap: { [path: string]: LocalizedRoute}, 16 | currentRoute: UrlModuleRoute, 17 | prevRoute: UrlModuleRoute, 18 | isBackRoute: boolean 19 | } 20 | -------------------------------------------------------------------------------- /core/modules/user/components/AccountButton.ts: -------------------------------------------------------------------------------- 1 | import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' 2 | 3 | export const AccountButton = { 4 | name: 'AccountButton', 5 | computed: { 6 | isLoggedIn () { 7 | return this.$store.getters['user/isLoggedIn'] 8 | }, 9 | user () { 10 | return this.$store.state.user.current 11 | } 12 | }, 13 | methods: { 14 | goToAccount () { 15 | if (this.currentUser) { 16 | this.$router.push(this.localizedRoute('/my-account')) 17 | } else { 18 | this.$store.commit('ui/setAuthElem', 'login') 19 | EventBus.$emit('modal-show', 'modal-signup') 20 | } 21 | }, 22 | logout () { 23 | EventBus.$emit('user-before-logout') 24 | this.$router.push(this.localizedRoute('/')) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/modules/user/store/getters.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree } from 'vuex' 2 | import RootState from '@vue-storefront/core/types/RootState' 3 | import UserState from '../types/UserState' 4 | 5 | const getters: GetterTree = { 6 | isLoggedIn (state) { 7 | return state.current !== null 8 | }, 9 | isLocalDataLoaded: state => state.local_data_loaded, 10 | getUserToken (state) { 11 | return state.token 12 | }, 13 | getOrdersHistory (state) { 14 | return state.orders_history ? state.orders_history.items : [] 15 | }, 16 | getToken (state) { 17 | return state.token 18 | }, 19 | getUserEmail (state, getters) { 20 | return getters.isLoggedIn ? state.current.email : null 21 | } 22 | } 23 | 24 | export default getters 25 | -------------------------------------------------------------------------------- /core/modules/user/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import getters from './getters' 4 | import mutations from './mutations' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import UserState from '../types/UserState' 7 | 8 | export const userStore: Module = { 9 | namespaced: true, 10 | state: { 11 | token: '', 12 | refreshToken: '', 13 | groupToken: '', 14 | groupId: null, 15 | current: null, 16 | current_storecode: '', 17 | session_started: new Date(), 18 | orders_history: null, 19 | local_data_loaded: false 20 | }, 21 | getters, 22 | actions, 23 | mutations 24 | } 25 | -------------------------------------------------------------------------------- /core/modules/user/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_USER = 'user' 2 | export const USER_NEWSLETTER_SIGNUP = SN_USER + '/NEWSLETTER_SIGNUP' 3 | export const USER_TOKEN_CHANGED = SN_USER + '/TOKEN_CHANGED' 4 | export const USER_INFO_LOADED = SN_USER + '/INFO_LOADED' 5 | export const USER_ORDERS_HISTORY_LOADED = SN_USER + '/ORDERS_HISTORY_LOADED' 6 | export const USER_START_SESSION = SN_USER + '/START_SESSION' 7 | export const USER_END_SESSION = SN_USER + '/END_SESSION' 8 | export const USER_UPDATE_PREFERENCES = SN_USER + '/UPDATE_PREFERENCES' 9 | export const USER_GROUP_TOKEN_CHANGED = SN_USER + '/GROUP_TOKEN_CHANGED' 10 | export const USER_GROUP_CHANGED = SN_USER + '/GROUP_ID_CHANGED' 11 | export const USER_LOCAL_DATA_LOADED = SN_USER + '/LOCAL_DATA_LOADED' 12 | -------------------------------------------------------------------------------- /core/modules/user/types/UserProfile.ts: -------------------------------------------------------------------------------- 1 | export interface UserProfile { 2 | customer: { 3 | email: string, 4 | firstname: string, 5 | lastname: string, 6 | website_id?: number | string, 7 | addresses?: { 8 | firstname: string, 9 | lastname: string, 10 | street: (string | number)[], 11 | city: string, 12 | region?: { 13 | region: string | null, 14 | [k: string]: any 15 | }, 16 | country_id: string | null, 17 | postcode: string | null, 18 | company?: string, 19 | telephone?: string, 20 | default_billing?: boolean, 21 | default_shipping?: boolean, 22 | [k: string]: any 23 | }[], 24 | custom_attributes?: { 25 | attribute_code: string, 26 | value: string | null, 27 | [k: string]: any 28 | }[], 29 | [k: string]: any 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/modules/user/types/UserState.ts: -------------------------------------------------------------------------------- 1 | export default interface UserState { 2 | token: string, 3 | refreshToken: string, 4 | groupToken: string, 5 | groupId: any, 6 | current: { 7 | email: string 8 | } | null, 9 | current_storecode: string, 10 | session_started: Date, 11 | orders_history: any, 12 | local_data_loaded: boolean 13 | } 14 | -------------------------------------------------------------------------------- /core/modules/wishlist/components/AddToWishlist.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product' 2 | import { WishlistModule } from '../' 3 | import wishlistMountedMixin from '@vue-storefront/core/modules/wishlist/mixins/wishlistMountedMixin' 4 | import { registerModule } from '@vue-storefront/core/lib/modules'; 5 | 6 | export const AddToWishlist = { 7 | name: 'AddToWishlist', 8 | mixins: [wishlistMountedMixin], 9 | props: { 10 | product: { 11 | required: true, 12 | type: Object 13 | } 14 | }, 15 | created () { 16 | registerModule(WishlistModule) 17 | }, 18 | methods: { 19 | addToWishlist (product: Product) { 20 | return this.$store.state['wishlist'] ? this.$store.dispatch('wishlist/addItem', product) : false 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/modules/wishlist/components/IsOnWishlist.ts: -------------------------------------------------------------------------------- 1 | import { WishlistModule } from '../' 2 | import wishlistMountedMixin from '@vue-storefront/core/modules/wishlist/mixins/wishlistMountedMixin' 3 | import { registerModule } from '@vue-storefront/core/lib/modules'; 4 | 5 | export const IsOnWishlist = { 6 | name: 'isOnWishlist', 7 | mixins: [wishlistMountedMixin], 8 | props: { 9 | product: { 10 | required: true, 11 | type: Object 12 | } 13 | }, 14 | created () { 15 | registerModule(WishlistModule) 16 | }, 17 | computed: { 18 | isOnWishlist () { 19 | return this.$store.getters['wishlist/isOnWishlist'](this.product) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/modules/wishlist/components/Product.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product' 2 | import wishlistMountedMixin from '@vue-storefront/core/modules/wishlist/mixins/wishlistMountedMixin' 3 | 4 | export const WishlistProduct = { 5 | name: 'Product', 6 | mixins: [wishlistMountedMixin], 7 | props: { 8 | product: { 9 | type: Object, 10 | required: true 11 | } 12 | }, 13 | computed: { 14 | thumbnail () { 15 | return this.getThumbnail(this.product.image, 150, 150) 16 | } 17 | }, 18 | methods: { 19 | removeFromWishlist (product: Product) { 20 | return this.$store.state['wishlist'] ? this.$store.dispatch('wishlist/removeItem', product) : false 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/modules/wishlist/components/RemoveFromWishlist.ts: -------------------------------------------------------------------------------- 1 | import Product from '@vue-storefront/core/modules/catalog/types/Product' 2 | import { WishlistModule } from '../' 3 | import wishlistMountedMixin from '@vue-storefront/core/modules/wishlist/mixins/wishlistMountedMixin' 4 | import { registerModule } from '@vue-storefront/core/lib/modules'; 5 | 6 | export const RemoveFromWishlist = { 7 | name: 'RemoveFromWishlist', 8 | mixins: [wishlistMountedMixin], 9 | props: { 10 | product: { 11 | required: true, 12 | type: Object 13 | } 14 | }, 15 | methods: { 16 | removeFromWishlist (product: Product) { 17 | registerModule(WishlistModule) 18 | this.$store.dispatch('wishlist/removeItem', product) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/modules/wishlist/components/Wishlist.ts: -------------------------------------------------------------------------------- 1 | import { WishlistModule } from '../' 2 | import wishlistMountedMixin from '@vue-storefront/core/modules/wishlist/mixins/wishlistMountedMixin' 3 | import { registerModule } from '@vue-storefront/core/lib/modules'; 4 | 5 | export const Wishlist = { 6 | name: 'Wishlist', 7 | mixins: [wishlistMountedMixin], 8 | created () { 9 | registerModule(WishlistModule) 10 | }, 11 | computed: { 12 | isWishlistOpen () { 13 | return this.$store.state.ui.wishlist 14 | }, 15 | productsInWishlist () { 16 | return this.$store.state.wishlist.items 17 | } 18 | }, 19 | methods: { 20 | closeWishlist () { 21 | this.$store.dispatch('ui/toggleWishlist') 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/modules/wishlist/components/WishlistButton.ts: -------------------------------------------------------------------------------- 1 | import wishlistMountedMixin from '@vue-storefront/core/modules/wishlist/mixins/wishlistMountedMixin' 2 | import { mapGetters } from 'vuex' 3 | 4 | export const WishlistButton = { 5 | mixins: [wishlistMountedMixin], 6 | computed: { 7 | ...mapGetters('wishlist', ['getWishlistItemsCount']) 8 | }, 9 | methods: { 10 | toggleWishlist () { 11 | this.$store.dispatch('ui/toggleWishlist') 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/modules/wishlist/index.ts: -------------------------------------------------------------------------------- 1 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 2 | import { wishlistStore } from './store' 3 | import whishListPersistPlugin from './store/whishListPersistPlugin' 4 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 5 | 6 | export const WishlistModule: StorefrontModule = function ({ store }) { 7 | StorageManager.init('wishlist') 8 | store.registerModule('wishlist', wishlistStore) 9 | store.subscribe(whishListPersistPlugin) 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/wishlist/mixins/wishlistMountedMixin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is mixin for all module components. 3 | * Invoke here actions, which were not invoked on server-side render, like reading LocalStorage or checking window size. 4 | */ 5 | 6 | export default { 7 | mounted () { 8 | this.$store.dispatch('wishlist/load') 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/modules/wishlist/store/getters.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree } from 'vuex' 2 | import RootState from '@vue-storefront/core/types/RootState' 3 | import WishlistState from '../types/WishlistState' 4 | 5 | const getters: GetterTree = { 6 | isOnWishlist: state => product => 7 | state.items.some(p => p.sku === product.sku), 8 | isWishlistLoaded: state => state.loaded, 9 | getWishlistItemsCount: state => state.items.length 10 | } 11 | 12 | export default getters 13 | -------------------------------------------------------------------------------- /core/modules/wishlist/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import actions from './actions' 3 | import mutations from './mutations' 4 | import getters from './getters' 5 | import RootState from '@vue-storefront/core/types/RootState' 6 | import WishlistState from '../types/WishlistState' 7 | 8 | export const wishlistStore: Module = { 9 | namespaced: true, 10 | state: { 11 | loaded: false, 12 | items: [] 13 | }, 14 | actions, 15 | mutations, 16 | getters 17 | } 18 | -------------------------------------------------------------------------------- /core/modules/wishlist/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_WISHLIST = 'wishlist' 2 | export const WISH_ADD_ITEM = SN_WISHLIST + '/ADD' 3 | export const WISH_DEL_ITEM = SN_WISHLIST + '/DEL' 4 | export const WISH_DEL_ALL_ITEMS = SN_WISHLIST + '/DEL_ALL' 5 | export const WISH_LOAD_WISH = SN_WISHLIST + '/LOAD' 6 | export const SET_WISHLIST_LOADED = `${SN_WISHLIST}/SET_WISHLIST_LOADED` 7 | -------------------------------------------------------------------------------- /core/modules/wishlist/store/whishListPersistPlugin.ts: -------------------------------------------------------------------------------- 1 | import * as types from './mutation-types' 2 | import { StorageManager } from '@vue-storefront/core/lib/storage-manager' 3 | 4 | const mutationToWatch = [types.WISH_ADD_ITEM, types.WISH_DEL_ITEM, types.WISH_DEL_ALL_ITEMS] 5 | .map(m => `wishlist/${m}`) 6 | 7 | const whishListPersistPlugin = (mutation, state) => { 8 | const whishListStorage = StorageManager.get('wishlist') 9 | 10 | if (mutationToWatch.includes(mutation.type)) { 11 | whishListStorage.setItem('current-wishlist', state.wishlist.items) 12 | } 13 | } 14 | 15 | export default whishListPersistPlugin 16 | -------------------------------------------------------------------------------- /core/modules/wishlist/test/unit/mixins/wishlistMountedMixin.spec.ts: -------------------------------------------------------------------------------- 1 | import { mountMixinWithStore } from '@vue-storefront/unit-tests/utils'; 2 | import wishlistMountedMixin from '@vue-storefront/core/modules/wishlist/mixins/wishlistMountedMixin'; 3 | 4 | describe('wishlistMountedMixin', () => { 5 | beforeEach(() => { 6 | jest.clearAllMocks(); 7 | }); 8 | 9 | it('dispatches wishlist/load action on mount', () => { 10 | const mockStore = { 11 | modules: { 12 | wishlist: { 13 | actions: { 14 | load: jest.fn() 15 | }, 16 | namespaced: true 17 | } 18 | } 19 | }; 20 | 21 | mountMixinWithStore(wishlistMountedMixin, mockStore); 22 | 23 | expect(mockStore.modules.wishlist.actions.load).toHaveBeenCalled(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /core/modules/wishlist/types/WishlistState.ts: -------------------------------------------------------------------------------- 1 | export default interface WishlistState { 2 | /** 3 | * Informs if wishlist is already loaded from local cache. 4 | */ 5 | loaded: boolean, 6 | items: any[] 7 | } 8 | -------------------------------------------------------------------------------- /core/pages/Compare.js: -------------------------------------------------------------------------------- 1 | import { Compare } from '@vue-storefront/core/modules/compare/components/Compare.ts' 2 | 3 | export default { 4 | name: 'Compare', 5 | mixins: [Compare], 6 | computed: { 7 | all_comparable_attributes () { 8 | // Computed Property renamed to 'allComparableAttributes' 9 | return this.allComparableAttributes 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/pages/Error.js: -------------------------------------------------------------------------------- 1 | import i18n from '@vue-storefront/i18n' 2 | import { Logger } from '@vue-storefront/core/lib/logger' 3 | 4 | export default { 5 | name: 'Error', 6 | asyncData ({ store, route, context }) { // this is for SSR purposes to prefetch data 7 | return new Promise((resolve, reject) => { 8 | Logger.log('Calling asyncData for Error page ' + new Date())() 9 | if (context) { 10 | context.output.cacheTags.add(`error`) 11 | } 12 | resolve() 13 | }) 14 | }, 15 | metaInfo () { 16 | return { 17 | title: this.$route.meta.title || i18n.t('Internal Server Error 500'), 18 | meta: this.$route.meta.description ? [{ vmid: 'description', name: 'description', content: this.$route.meta.description }] : [] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/scripts/utils/api-status.js: -------------------------------------------------------------------------------- 1 | /** Creates a API status call and sends it through to Express SearchResponse object. 2 | * @param {expressserver.response} res Express HTTP SearchResponse 3 | * @param {number} [code=200] Status code to send on success 4 | * @param {json} [result='OK'] Text message or result information object 5 | */ 6 | module.exports = (res, result = 'OK', code = 200, meta = null) => { 7 | let apiResult = { code: code, result: result } 8 | if (meta !== null) { 9 | apiResult.meta = meta 10 | } 11 | res.status(code).json(apiResult) 12 | return result 13 | } 14 | -------------------------------------------------------------------------------- /core/scripts/utils/cache-instance.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const TagCache = require('redis-tag-cache').default 4 | const config = require('config') 5 | let cache = false 6 | 7 | if (config.server.useOutputCache) { 8 | const cacheVersionPath = path.resolve(path.join('core', 'build', 'cache-version.json')) 9 | let cacheKey = '' 10 | try { 11 | cacheKey = JSON.parse(fs.readFileSync(cacheVersionPath) || '') 12 | } catch (err) { 13 | console.error(err) 14 | } 15 | const redisConfig = Object.assign(config.redis, { keyPrefix: cacheKey }) 16 | 17 | console.log('Redis cache set', redisConfig) 18 | 19 | cache = new TagCache({ 20 | redis: redisConfig, 21 | defaultTimeout: config.server.outputCacheDefaultTtl 22 | }) 23 | } 24 | 25 | module.exports = cache 26 | -------------------------------------------------------------------------------- /core/scripts/utils/sort-translations.js: -------------------------------------------------------------------------------- 1 | const { readFileSync, writeFileSync } = require('fs'); 2 | const { EOL } = require('os'); 3 | 4 | const fixTranslation = (filename) => { 5 | const content = readFileSync(filename, 'utf8'); 6 | 7 | writeFileSync( 8 | filename, 9 | content 10 | .split(EOL) 11 | .sort() 12 | .filter(line => line.length > 0) 13 | .join(EOL) + EOL 14 | ); 15 | } 16 | 17 | process.argv.map(filename => { 18 | filename.split('.').pop() === 'csv' && fixTranslation(filename); 19 | }); 20 | -------------------------------------------------------------------------------- /core/scripts/utils/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Express } from 'express' 2 | 3 | export interface Context { 4 | url: string, 5 | output: { 6 | prepend: (context: any) => string, 7 | append: (context: any) => string, 8 | filter: (output: T, context: any) => T, 9 | appendHead: (context: any) => string, 10 | template: string, 11 | cacheTags: Set 12 | }, 13 | server: { 14 | app: Express, 15 | response: Express.Response, 16 | request: Express.Request 17 | }, 18 | meta: any|null, 19 | vs: { 20 | config: Record, 21 | storeCode: string 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/service-worker/index.js: -------------------------------------------------------------------------------- 1 | import '../modules/offline-order/extends/service-worker.js' 2 | import 'theme/service-worker/index.js' 3 | 4 | // core service worker, all service worker related features are placed here. 5 | -------------------------------------------------------------------------------- /core/store/actions.ts: -------------------------------------------------------------------------------- 1 | import { ActionTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import RootState from '@vue-storefront/core/types/RootState' 4 | 5 | const actions: ActionTree = { 6 | async resetUserInvalidateLock ({ commit }) { 7 | commit(types.USER_TOKEN_INVALIDATE_LOCK_CHANGED, 0) 8 | }, 9 | async resetUserInvalidation ({ commit }) { 10 | commit(types.RESET_USER_TOKEN_INVALIDATION) 11 | } 12 | } 13 | 14 | export default actions 15 | -------------------------------------------------------------------------------- /core/store/getters.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree } from 'vuex' 2 | import RootState from '@vue-storefront/core/types/RootState' 3 | 4 | const getters: GetterTree = { 5 | getCurrentStoreView: state => state.storeView 6 | } 7 | 8 | export default getters 9 | -------------------------------------------------------------------------------- /core/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SN_ROOT = 'root' 2 | export const USER_TOKEN_INVALIDATE_LOCK_CHANGED = SN_ROOT + '/USER_TOKEN_INVALIDATE_LOCK_CHANGED' 3 | export const RESET_USER_TOKEN_INVALIDATION = SN_ROOT + '/RESET_USER_TOKEN_INVALIDATION' 4 | -------------------------------------------------------------------------------- /core/store/mutations.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree } from 'vuex' 2 | import * as types from './mutation-types' 3 | import RootState from '@vue-storefront/core/types/RootState' 4 | 5 | const mutations: MutationTree = { 6 | [types.USER_TOKEN_INVALIDATE_LOCK_CHANGED] (state, payload) { 7 | state.userTokenInvalidateLock = payload 8 | }, 9 | [types.RESET_USER_TOKEN_INVALIDATION] (state) { 10 | state.userTokenInvalidateLock = 0 11 | state.userTokenInvalidated = null 12 | state.userTokenInvalidateAttemptsCount = 0 13 | } 14 | 15 | } 16 | 17 | export default mutations 18 | -------------------------------------------------------------------------------- /core/types/asyncData.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import { Route } from 'vue-router'; 3 | import { Context } from '@vue-storefront/core/scripts/utils/types' 4 | 5 | interface AsyncDataParameter { 6 | store: any, 7 | route: Route, 8 | context?: Context 9 | } 10 | 11 | declare module 'vue/types/options' { 12 | interface ComponentOptions { 13 | asyncData?: ({ store, route, context }: AsyncDataParameter) => Promise 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/types/isomorphic-fetch.d.ts: -------------------------------------------------------------------------------- 1 | declare const fet: typeof fetch; 2 | 3 | declare module 'isomorphic-fetch' { 4 | export const fetch: typeof fet; 5 | export default fetch; 6 | } 7 | -------------------------------------------------------------------------------- /core/types/search/HttpQuery.ts: -------------------------------------------------------------------------------- 1 | export default interface HttpQuery { 2 | q?: string, 3 | size: number, 4 | from: number, 5 | sort: string, 6 | request?: string, 7 | request_format?: string, 8 | response_format?: string, 9 | _source_exclude?: string, 10 | _source_include?: string 11 | } 12 | -------------------------------------------------------------------------------- /core/types/search/SearchRequest.ts: -------------------------------------------------------------------------------- 1 | export interface SearchRequest { 2 | store: any, 3 | type: string, 4 | searchQuery: any, 5 | size: number, 6 | groupId: any, 7 | groupToken: any, 8 | from: number, 9 | sort: string, 10 | _sourceExclude?: string, 11 | _sourceInclude?: string 12 | } 13 | -------------------------------------------------------------------------------- /core/types/search/SearchResponse.ts: -------------------------------------------------------------------------------- 1 | export interface SearchResponse { 2 | items: any[], 3 | total: number, 4 | start: number, 5 | perPage: number, 6 | aggregations: any, 7 | offline?: boolean, 8 | cache?: boolean, 9 | noresults?: boolean, 10 | suggestions: any, 11 | attributeMetadata?: any 12 | } 13 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3000", 3 | "projectId": "xrqwrm", 4 | "fixturesFolder": "test/e2e/fixtures", 5 | "integrationFolder": "test/e2e/integration", 6 | "pluginsFile": "test/e2e/plugins/index.js", 7 | "supportFile": "test/e2e/support/index.js", 8 | "viewportWidth": 1280, 9 | "viewportHeight": 1024 10 | } 11 | -------------------------------------------------------------------------------- /dev/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10 2 | 3 | ENV NODE_CONFIG_ENV=docker PM2_ARGS=--no-daemon BIND_HOST=0.0.0.0 VS_ENV=prod 4 | 5 | WORKDIR /var/www 6 | 7 | COPY . . 8 | 9 | # Should be yarn install --production 10 | RUN apt update && apt install -y git \ 11 | && yarn install \ 12 | && yarn build 13 | 14 | COPY dev/docker/vue-storefront.sh /usr/local/bin/ 15 | RUN chmod a+x /usr/local/bin/vue-storefront.sh 16 | 17 | ENTRYPOINT ["vue-storefront.sh"] 18 | -------------------------------------------------------------------------------- /dev/docker/vue-storefront.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "$VS_ENV" = 'dev' ]; then 5 | yarn dev 6 | else 7 | yarn start 8 | fi 9 | -------------------------------------------------------------------------------- /docker/vue-storefront/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | ENV VS_ENV prod 4 | 5 | WORKDIR /var/www 6 | 7 | COPY package.json ./ 8 | COPY yarn.lock ./ 9 | 10 | RUN apk add --no-cache --virtual .build-deps ca-certificates wget python make g++ \ 11 | && apk add --no-cache git \ 12 | && yarn install --no-cache \ 13 | && apk del .build-deps 14 | 15 | COPY docker/vue-storefront/vue-storefront.sh /usr/local/bin/ 16 | 17 | CMD ["vue-storefront.sh"] 18 | -------------------------------------------------------------------------------- /docker/vue-storefront/default.env: -------------------------------------------------------------------------------- 1 | NODE_CONFIG_ENV=docker 2 | VS_ENV=prod 3 | BIND_HOST=0.0.0.0 4 | PM2_ARGS=--no-daemon 5 | -------------------------------------------------------------------------------- /docker/vue-storefront/vue-storefront.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | yarn install || exit $? 5 | 6 | if [ "$VS_ENV" = 'dev' ]; then 7 | yarn dev 8 | else 9 | yarn build || exit $? 10 | yarn start 11 | fi 12 | -------------------------------------------------------------------------------- /docs/.vuepress/public/Apple_iPhone_X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/Apple_iPhone_X.png -------------------------------------------------------------------------------- /docs/.vuepress/public/Fil-Rakowski-VS-Demo-Youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/Fil-Rakowski-VS-Demo-Youtube.png -------------------------------------------------------------------------------- /docs/.vuepress/public/GitHub-Architecture-VS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/GitHub-Architecture-VS.png -------------------------------------------------------------------------------- /docs/.vuepress/public/Vue-storefront-architecture-proxy-requests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/Vue-storefront-architecture-proxy-requests.png -------------------------------------------------------------------------------- /docs/.vuepress/public/Vue-storefront-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/Vue-storefront-architecture.png -------------------------------------------------------------------------------- /docs/.vuepress/public/cart-localstorage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/cart-localstorage.png -------------------------------------------------------------------------------- /docs/.vuepress/public/cart-sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/cart-sync.png -------------------------------------------------------------------------------- /docs/.vuepress/public/categories-localstorage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/categories-localstorage.png -------------------------------------------------------------------------------- /docs/.vuepress/public/chrome-dev-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/chrome-dev-console.png -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/favicon.png -------------------------------------------------------------------------------- /docs/.vuepress/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/logo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/magento_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/magento_1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/magento_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/magento_2.png -------------------------------------------------------------------------------- /docs/.vuepress/public/magento_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/magento_3.png -------------------------------------------------------------------------------- /docs/.vuepress/public/o2m-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/o2m-output.png -------------------------------------------------------------------------------- /docs/.vuepress/public/orders-collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/orders-collection.png -------------------------------------------------------------------------------- /docs/.vuepress/public/orders-localstorage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/orders-localstorage.png -------------------------------------------------------------------------------- /docs/.vuepress/public/partners/develo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/partners/develo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/storefront.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/storefront.png -------------------------------------------------------------------------------- /docs/.vuepress/public/syncTasks-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/syncTasks-example.png -------------------------------------------------------------------------------- /docs/.vuepress/public/video-webcast-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/video-webcast-1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/video-webcast-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/video-webcast-2.png -------------------------------------------------------------------------------- /docs/.vuepress/public/vs-video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/vs-video.png -------------------------------------------------------------------------------- /docs/.vuepress/public/vuelogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/.vuepress/public/vuelogo.jpg -------------------------------------------------------------------------------- /docs/.vuepress/theme/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extend: '@vuepress/theme-default' 3 | }; 4 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | docs.vuestorefront.io -------------------------------------------------------------------------------- /docs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12 AS build 2 | 3 | WORKDIR /var/www 4 | 5 | COPY . . 6 | 7 | RUN npm install \ 8 | && npm run docs:build 9 | 10 | FROM nginx 11 | 12 | COPY --from=build /var/www/.vuepress/dist /usr/share/nginx/html/v1 -------------------------------------------------------------------------------- /docs/build-docker.sh: -------------------------------------------------------------------------------- 1 | TAG=`git rev-parse HEAD` 2 | docker build -t registry.storefrontcloud.io/docs-storefrontcloud-io/v1:${TAG:0:8} -f Dockerfile . 3 | docker push registry.storefrontcloud.io/docs-storefrontcloud-io/v1:${TAG:0:8} -------------------------------------------------------------------------------- /docs/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # abort on errors 4 | set -e 5 | 6 | # build 7 | npm run docs:build 8 | 9 | # navigate into the build output directory 10 | cd .vuepress/dist 11 | 12 | # if you are deploying to a custom domain 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | git commit -m 'deploy' 18 | 19 | # if you are deploying to https://.github.io 20 | git push -f git@github.com:/.github.io.git master 21 | 22 | # if you are deploying to https://.github.io/ 23 | git push -f git@github.com:DivanteLtd/vue-storefront.git master:gh-pages 24 | 25 | cd - 26 | -------------------------------------------------------------------------------- /docs/guide/basics/assets/release-cycle-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/basics/assets/release-cycle-1.png -------------------------------------------------------------------------------- /docs/guide/basics/assets/release-cycle-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/basics/assets/release-cycle-2.png -------------------------------------------------------------------------------- /docs/guide/basics/assets/release-cycle-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/basics/assets/release-cycle-3.png -------------------------------------------------------------------------------- /docs/guide/basics/e2e.md: -------------------------------------------------------------------------------- 1 | # E2E tests 2 | 3 | For e2e test in Vue Storefront, we use [Cypress](https://www.cypress.io/). Head to their website for great docs, best practices, and tutorials on how to write e2e tests. 4 | 5 | We don't yet have our guidelines for e2e tests, but we try to follow best practices recommended by Cypress. Follow them to make tests more reliable and easier to maintain. 6 | 7 | ## Running tests 8 | 9 | To open cypress, just run: 10 | 11 | `yarn test:e2e` 12 | 13 | To run all test in the background: 14 | 15 | `yarn test:e2e:ci` 16 | -------------------------------------------------------------------------------- /docs/guide/components/home-page.md: -------------------------------------------------------------------------------- 1 | # Core Home Page 2 | 3 | :::tip Note 4 | Core page has almost zero functionality, everything is in theme component, which definitely needs to be replaced to the core. 5 | ::: 6 | 7 | ## Props 8 | 9 | No props 10 | 11 | ## Data 12 | 13 | `rootCategories` category list to be used for your own custom home page 14 | 15 | ## Methods 16 | 17 | No methods 18 | 19 | ## Events 20 | 21 | `home-after-load` event can be used to populate the vuex `store` with additional data required by SSR. 22 | 23 | ### beforeMount 24 | 25 | Clears Vuex store entries that define the current category by dispatching `category/reset` action. 26 | -------------------------------------------------------------------------------- /docs/guide/cookbook/common-pitfall.md: -------------------------------------------------------------------------------- 1 | # Ch 7. Anti-Patterns & Common Pitfalls 2 | 3 | ## Coming soon! 4 | -------------------------------------------------------------------------------- /docs/guide/cookbook/history.md: -------------------------------------------------------------------------------- 1 | # Ch 14. Old Tales about VSF 2 | 3 | ## Coming soon! 4 | -------------------------------------------------------------------------------- /docs/guide/cookbook/integration.md: -------------------------------------------------------------------------------- 1 | # Ch 4. Integration with 3rd Party 2 | 3 | ## Coming soon! 4 | -------------------------------------------------------------------------------- /docs/guide/cookbook/tdd.md: -------------------------------------------------------------------------------- 1 | # Ch 9. Test Driven Development for VSF 2 | 3 | ## Coming soon! 4 | 5 | -------------------------------------------------------------------------------- /docs/guide/data-resolvers/category-service.md: -------------------------------------------------------------------------------- 1 | # CategoryService 2 | 3 | ## Methods 4 | 5 | #### `getCategories (serachOptions: DataResolver.CategorySearchOptions) => Promise` 6 | 7 | It fetches categories by given parameters. If the `config.entities.optimize` is enabled, the `includeFields` and `excludeFields` are set accordingly to `config.entities.category.includeFields` and `config.entities.category.excludeFields`. 8 | -------------------------------------------------------------------------------- /docs/guide/data/elasticsearch.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch Data Formats 2 | 3 | External links : [Product entity](https://docs.storefrontapi.com/guide/integration/format-product.html) -------------------------------------------------------------------------------- /docs/guide/images/Apple_iPhone_X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/Apple_iPhone_X.png -------------------------------------------------------------------------------- /docs/guide/images/GitHub-Architecture-VS-data-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/GitHub-Architecture-VS-data-import.png -------------------------------------------------------------------------------- /docs/guide/images/Vue-storefront-architecture-proxy-requests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/Vue-storefront-architecture-proxy-requests.png -------------------------------------------------------------------------------- /docs/guide/images/Vue-storefront-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/Vue-storefront-architecture.png -------------------------------------------------------------------------------- /docs/guide/images/cart-localstorage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/cart-localstorage.png -------------------------------------------------------------------------------- /docs/guide/images/cart-sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/cart-sync.png -------------------------------------------------------------------------------- /docs/guide/images/categories-localstorage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/categories-localstorage.png -------------------------------------------------------------------------------- /docs/guide/images/chrome-dev-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/chrome-dev-console.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_1.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_10.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_2.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_3.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_5.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_6.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_7.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_8.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_9.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_design.png -------------------------------------------------------------------------------- /docs/guide/images/data_pump_err_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/data_pump_err_1.png -------------------------------------------------------------------------------- /docs/guide/images/datum_pump_design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/datum_pump_design.png -------------------------------------------------------------------------------- /docs/guide/images/delta_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/delta_error.png -------------------------------------------------------------------------------- /docs/guide/images/editmodeInMC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/editmodeInMC.png -------------------------------------------------------------------------------- /docs/guide/images/error_1.11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/error_1.11.png -------------------------------------------------------------------------------- /docs/guide/images/es-map-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/es-map-result.png -------------------------------------------------------------------------------- /docs/guide/images/home-vuestorefront.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/home-vuestorefront.png -------------------------------------------------------------------------------- /docs/guide/images/home_capybara.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/home_capybara.png -------------------------------------------------------------------------------- /docs/guide/images/img_catalog_prod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/img_catalog_prod.png -------------------------------------------------------------------------------- /docs/guide/images/img_catalog_prod_fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/img_catalog_prod_fail.png -------------------------------------------------------------------------------- /docs/guide/images/index-not-found-ex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/index-not-found-ex.png -------------------------------------------------------------------------------- /docs/guide/images/lego_palm.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/lego_palm.jpeg -------------------------------------------------------------------------------- /docs/guide/images/magento_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/magento_1.png -------------------------------------------------------------------------------- /docs/guide/images/magento_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/magento_2.png -------------------------------------------------------------------------------- /docs/guide/images/magento_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/magento_3.png -------------------------------------------------------------------------------- /docs/guide/images/microcart_nan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/microcart_nan.png -------------------------------------------------------------------------------- /docs/guide/images/npm-run-migrate-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/npm-run-migrate-result.png -------------------------------------------------------------------------------- /docs/guide/images/o2m-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/o2m-output.png -------------------------------------------------------------------------------- /docs/guide/images/orders-collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/orders-collection.png -------------------------------------------------------------------------------- /docs/guide/images/orders-localstorage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/orders-localstorage.png -------------------------------------------------------------------------------- /docs/guide/images/organized_lego_bricks.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/organized_lego_bricks.jpeg -------------------------------------------------------------------------------- /docs/guide/images/pile_of_legos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/pile_of_legos.png -------------------------------------------------------------------------------- /docs/guide/images/product_like_state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/product_like_state.png -------------------------------------------------------------------------------- /docs/guide/images/route_liked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/route_liked.png -------------------------------------------------------------------------------- /docs/guide/images/sss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/sss.png -------------------------------------------------------------------------------- /docs/guide/images/storefront.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/storefront.png -------------------------------------------------------------------------------- /docs/guide/images/stores.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/stores.png -------------------------------------------------------------------------------- /docs/guide/images/success_1.11_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/success_1.11_home.png -------------------------------------------------------------------------------- /docs/guide/images/syncTasks-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/syncTasks-example.png -------------------------------------------------------------------------------- /docs/guide/images/vuelogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuestorefront/vue-storefront-1/725cb6daf446840a97be1cf52cafe7f66cde9373/docs/guide/images/vuelogo.jpg -------------------------------------------------------------------------------- /docs/guide/integrations/tier-prices-sync.md: -------------------------------------------------------------------------------- 1 | # Tier prices sync with Magento 2 | 3 | This feature allows you to show the user a final price, including tier prices from Magento. It supports a simple, downloadable, configurable bundle and group products. 4 | 5 | To enable tier prices, change the following lines in the 6 | 7 | ```json 8 | "usePriceTiers": true 9 | ``` 10 | 11 | To use this feature you should also modify `config/local.json` within your `vue-storefront-api` installation: 12 | 13 | ```json 14 | "usePriceTiers": true 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/guide/security/README.md: -------------------------------------------------------------------------------- 1 | # Headless Security 2 | 3 | External links : [Headless Security](https://headless-security.org/) -------------------------------------------------------------------------------- /docs/guide/vuex/stock-store.md: -------------------------------------------------------------------------------- 1 | # Stock Vuex Store 2 | 3 | Stock Store is designed to handle stock-quantity checks. 4 | 5 | ## Events 6 | 7 | The following events are published from `stock` store: 8 | 9 | - `stock-after-check` - Emitted just after the stock item has been received from eCommerce backend / Magento. 10 | 11 | 12 | ## Actions 13 | 14 | The cart store provides the following public actions: 15 | 16 | ### `check (context, { product, qty = 1 })` 17 | 18 | Check if the `product` can be added to the shopping cart with a given quantity. 19 | 20 | The resulting promise is expanded to the following object: 21 | 22 | ```js 23 | { 24 | qty: 100, 25 | status: 'ok', // another option is: 'out_of_stock' 26 | onlineCheckTaskId: 14241 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "name": "vuepress", 4 | "builds": [ 5 | { "src": "package.json", "use": "@now/static-build"} 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue-storefront/docs", 3 | "private": true, 4 | "version": "1.12.2", 5 | "scripts": { 6 | "docs:dev": "vuepress dev", 7 | "docs:build": "vuepress build", 8 | "build": "vuepress build && mv .vuepress/dist dist" 9 | }, 10 | "dependencies": { 11 | "diff2html": "^2.12.1", 12 | "vuepress": "^1.0.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ecosystem.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [ 3 | { 4 | "name": "server", 5 | "max_memory_restart": "1G", 6 | "instances": "4", 7 | "exec_mode": "cluster", 8 | "env": { 9 | "TS_NODE_PROJECT": "tsconfig-build.json", 10 | "NODE_ENV": "production" 11 | }, 12 | "interpreter": "./node_modules/.bin/ts-node", 13 | "script": "./node_modules/.bin/ts-node", 14 | "args": "-P tsconfig-build.json ./core/scripts/server.ts", 15 | "node_args": "--max_old_space_size=1024", 16 | "log_date_format": "YYYY-MM-DD HH:mm:ss", 17 | "ignore_watch": [ 18 | "core/build/config.json", 19 | "node_modules" 20 | ] 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /kubernetes/nginx-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: nginx 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: nginx 9 | template: 10 | metadata: 11 | labels: 12 | app: nginx 13 | spec: 14 | containers: 15 | - name: nginx 16 | image: nginx:alpine 17 | ports: 18 | - containerPort: 80 19 | volumeMounts: 20 | - mountPath: /etc/nginx/conf.d/default.conf 21 | name: config 22 | subPath: default.conf 23 | volumes: 24 | - name: config 25 | configMap: 26 | name: nginx-config 27 | items: 28 | - key: default.conf 29 | path: default.conf 30 | -------------------------------------------------------------------------------- /kubernetes/nginx-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: nginx 5 | labels: 6 | app: nginx 7 | spec: 8 | selector: 9 | app: nginx 10 | type: NodePort 11 | ports: 12 | - port: 80 13 | targetPort: 80 14 | nodePort: 30080 15 | -------------------------------------------------------------------------------- /kubernetes/vue-storefront-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: vue-storefront-config 5 | data: 6 | NODE_CONFIG_ENV: docker 7 | BIND_HOST: 0.0.0.0 8 | PM2_ARGS: --no-daemon 9 | VS_ENV: dev 10 | -------------------------------------------------------------------------------- /kubernetes/vue-storefront-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: vue-storefront 5 | labels: 6 | app: vue-storefront 7 | spec: 8 | selector: 9 | app: vue-storefront 10 | ports: 11 | - port: 3000 12 | targetPort: 3000 13 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "3.14.1", 3 | "version": "independent", 4 | "npmClient": "yarn", 5 | "useWorkspaces": true, 6 | "registry": "https://registry.npmjs.org/" 7 | } 8 | -------------------------------------------------------------------------------- /packages/cli/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /packages/cli/README.md: -------------------------------------------------------------------------------- 1 | # Storefront CLI 2 | 3 | This is a beta version of CLI for Vue Storefront. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm i -g @vue-storefront/cli 9 | ``` 10 | ## Commands 11 | 12 | After installing CLI you'll get access to following commands: 13 | - `vsf init [dirname]` - Use it to set up new VS project. The CLI will ask you a few questions and set up new, ready to work with Vue Storefront instance. 14 | - `vsf init:module [module-name]` - generates boilerplate for Vue Storefront module named `vsf-module-name` in a current directory 15 | - `vsf init:theme` - generates theme for Vue Storefront 16 | - `vsf --help` - available commands 17 | - `vsf --version` - current version of cli 18 | -------------------------------------------------------------------------------- /packages/cli/boilerplates/module/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ -------------------------------------------------------------------------------- /packages/cli/boilerplates/module/README.md: -------------------------------------------------------------------------------- 1 | # vsf-package 2 | 3 | 4 | ## Installation 5 | 6 | ``` 7 | yarn add vsf-package 8 | ``` 9 | 10 | ## API 11 | 12 | 13 | 14 | ## Development 15 | 16 | - `yarn build` - bundles package into main.js file with typescript/es6 transpilations 17 | - `npm publish` - publishes package to NPM registry (automatically runs `yarn build` before publishing) -------------------------------------------------------------------------------- /packages/cli/boilerplates/module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vsf-package", 3 | "version": "1.0.11", 4 | "description": "", 5 | "main": "dist/main.js", 6 | "scripts": { 7 | "build": "webpack --config node_modules/@vue-storefront/core/lib/modules/tools/module-build.config.js", 8 | "prePublishOnly": "yarn build" 9 | }, 10 | "keywords": ["vue-storefront"], 11 | "author": "", 12 | "license": "MIT", 13 | "dependencies": {}, 14 | "devDependencies": { 15 | "@vue-storefront/core": "^1.12.2", 16 | "ts-loader": "^6.0.4", 17 | "typescript": "^3.5.2", 18 | "webpack": "^4.35.2", 19 | "webpack-cli": "^3.3.11" 20 | }, 21 | "peerDependencies": { 22 | "@vue-storefront/core": "^1.12.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/cli/boilerplates/module/src/index.ts: -------------------------------------------------------------------------------- 1 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 2 | import { coreHooks } from '@vue-storefront/core/hooks' 3 | import { extendStore } from '@vue-storefront/core/helpers' 4 | import { ExampleStore, ExtendProductStore } from './store' 5 | 6 | export const ExampleModule: StorefrontModule = function ({store}) { 7 | // You can access config passed to registerModule via moduleConfig variable 8 | // This is how you register new Vuex modules 9 | store.registerModule('example', ExampleStore) 10 | // This is how you override properties of currently existing Vuex modules 11 | extendStore('product', ExtendProductStore) 12 | // This is how you can hook into various palces of the application 13 | coreHooks.afterAppInit(() => console.log('Do something when application is initialized!')) 14 | } 15 | -------------------------------------------------------------------------------- /packages/cli/boilerplates/module/src/store.ts: -------------------------------------------------------------------------------- 1 | export const ExampleStore = { 2 | state: { 3 | message: 'Hello World' 4 | } 5 | } 6 | 7 | export const ExtendProductStore = { 8 | actions: { 9 | state: { 10 | newprop: null 11 | }, 12 | list () { 13 | console.log('Hello from extended action') 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/cli/boilerplates/module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "outDir": "./dist", 6 | "strict": false, 7 | "moduleResolution": "node" 8 | }, 9 | "include": [ 10 | "**/*.ts" 11 | ], 12 | "exclude": [ 13 | "node_modules" 14 | ] 15 | } -------------------------------------------------------------------------------- /packages/cli/consts.js: -------------------------------------------------------------------------------- 1 | const options = { 2 | version: { 3 | stable: 'Stable version (recommended for production)', 4 | rc: 'Release Candidate', 5 | nightly: 'In development branch (could be unstable!)' 6 | }, 7 | installation: { 8 | installer: 'Installer (MacOS/Linux only)', 9 | manual: 'Manual installation' 10 | } 11 | } 12 | 13 | const themes = { 14 | capybara: { 15 | label: 'Capybara - based on Storefront UI', 16 | branches: { 17 | master: options.version.stable, 18 | develop: options.version.nightly 19 | }, 20 | minVsfVersion: '^1.11.0' 21 | }, 22 | default: { 23 | label: 'Default', 24 | branches: { 25 | master: options.version.stable 26 | }, 27 | minVsfVersion: '*' 28 | } 29 | } 30 | 31 | module.exports = { 32 | options, 33 | themes 34 | } 35 | -------------------------------------------------------------------------------- /packages/cli/helpers.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const getVsfPackageJSON = (installationDir, quiet) => { 5 | try { 6 | return JSON.parse(fs.readFileSync(path.join(installationDir, '/package.json'))) 7 | } catch (err) { 8 | if (quiet) return {} 9 | console.error(err) 10 | process.exit(1) 11 | } 12 | } 13 | 14 | module.exports = { 15 | getVsfPackageJSON 16 | } 17 | -------------------------------------------------------------------------------- /packages/cli/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const command = process.argv[2] 4 | 5 | switch (command) { 6 | case 'init': 7 | require('./scripts/install.js')(process.argv[3]) 8 | break; 9 | case 'init:module': 10 | require('./scripts/generateModule.js')(process.argv[3]) 11 | break; 12 | case 'init:theme': 13 | require('./scripts/installTheme.js')() 14 | break; 15 | case '-h': 16 | case '--help': 17 | require('./scripts/manual.js')() 18 | break; 19 | case '-v': 20 | case '--version': 21 | console.log('v' + require('./package.json').version) 22 | break; 23 | default: 24 | console.log('Unknown command. try one of those:\n') 25 | require('./scripts/manual.js')() 26 | } 27 | -------------------------------------------------------------------------------- /packages/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue-storefront/cli", 3 | "version": "0.2.1", 4 | "description": "", 5 | "main": "index.js", 6 | "bin": { 7 | "vsf": "./index.js" 8 | }, 9 | "publishConfig": { 10 | "access": "public" 11 | }, 12 | "preferGlobal": true, 13 | "author": "Filip Rakowski (@filrak)", 14 | "license": "MIT", 15 | "dependencies": { 16 | "execa": "^4.0.2", 17 | "fs-extra": "^8.1.0", 18 | "inquirer": "^6.3.1", 19 | "listr": "^0.14.3", 20 | "lodash": "^4.17.15", 21 | "replace-in-file": "^4.1.1", 22 | "semver": "^7.1.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/cli/scripts/manual.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | console.log('Usage: vsf [command] [options]\n') 3 | console.log('Options:') 4 | console.log(' --help | -h available commands') 5 | console.log(' --version | -v CLI version\n') 6 | console.log('Commands:') 7 | console.log(' init [dir] setup new VS project') 8 | console.log(' init:module [name] generate vs module boilerplate') 9 | console.log(' init:theme adds theme in specified directory') 10 | } 11 | -------------------------------------------------------------------------------- /shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | 6 | declare module 'vue-router' { 7 | import VueRouter, { RouteConfig } from 'node_modules/vue-router' 8 | export * from 'node_modules/vue-router' 9 | export default class extends VueRouter { 10 | public addRoutes (routes: RouteConfig[], useRouteQueue?: boolean, priority?: number): void; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/index.amp.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{{ meta.inject().title.text() }}} 5 | {{{ meta.inject().meta.text() }}} 6 | 7 | {{{ meta.inject().link.text() }}} 8 | {{{ output.appendHead() }}} 9 | {{{ renderStyles().replace(" 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/index.basic.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{{ meta.inject().title.text() }}} 5 | {{{ meta.inject().meta.text() }}} 6 | 7 | {{{ meta.inject().link.text() }}} 8 | {{{ renderStyles() }}} 9 | {{{ output.appendHead() }}} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/index.minimal.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{{ meta.inject().title.text() }}} 5 | {{{ meta.inject().meta.text() }}} 6 | 7 | {{{ meta.inject().link.text() }}} 8 | {{{ output.appendHead() }}} 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/index.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{{ meta.inject().title.text() }}} 5 | {{{ meta.inject().meta.text() }}} 6 | 7 | {{{ meta.inject().link.text() }}} 8 | {{{ renderResourceHints() }}} 9 | {{{ renderStyles() }}} 10 | {{{ output.appendHead() }}} 11 | 12 | 13 | 14 | {{{ renderState() }}} 15 | {{{ renderScripts() }}} 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/modules/amp-renderer/index.ts: -------------------------------------------------------------------------------- 1 | import moduleRoutes from './router' 2 | import { StorefrontModule } from '@vue-storefront/core/lib/modules' 3 | import { setupMultistoreRoutes } from '@vue-storefront/core/lib/multistore' 4 | import config from 'config' 5 | 6 | const ampRendererStore = { 7 | namespaced: true, 8 | state: { 9 | key: null 10 | } 11 | } 12 | 13 | export const AmpRendererModule: StorefrontModule = function ({ store, router }) { 14 | store.registerModule('amp-renderer', ampRendererStore) 15 | setupMultistoreRoutes(config, router, moduleRoutes, 10) 16 | } 17 | -------------------------------------------------------------------------------- /src/modules/amp-renderer/router.ts: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | 3 | let AmpThemeRouting 4 | 5 | try { 6 | const themeName = config.theme.replace('@vue-storefront/theme-', '') 7 | AmpThemeRouting = require(`src/themes/${themeName}-amp/router`) 8 | } catch (err) { 9 | AmpThemeRouting = null 10 | } 11 | 12 | export default AmpThemeRouting 13 | -------------------------------------------------------------------------------- /src/modules/compress/server.ts: -------------------------------------------------------------------------------- 1 | import { serverHooks } from '@vue-storefront/core/server/hooks' 2 | 3 | const compression = require('compression') 4 | serverHooks.afterApplicationInitialized(({ app, isProd }) => { 5 | if (isProd) { 6 | console.log('Output Compression is enabled') 7 | app.use(compression({ enabled: isProd })) 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /src/modules/fastly/README.md: -------------------------------------------------------------------------------- 1 | # VSF Cache Fastly 2 | This module extends default caching docs/guide/basics/ssr-cache.md to allow using fastly as cache provider. 3 | 4 | ## How to install 5 | Add to config: 6 | ```json 7 | "fastly": { 8 | "enabled": true, 9 | "serviceId": "xyz", // (https://docs.fastly.com/en/guides/finding-and-managing-your-account-info#finding-your-service-id) 10 | "token": "xyz" // fastly api token (https://docs.fastly.com/api/auth#tokens) 11 | } 12 | ``` 13 | 14 | Change those values in `server` section: 15 | ```json 16 | "useOutputCacheTagging": true, 17 | "useOutputCache": true 18 | ``` 19 | 20 | ## How to purge cache? 21 | Open: 22 | ``` 23 | http://localhost:3000/invalidate?key=aeSu7aip&tag=home 24 | ``` 25 | -------------------------------------------------------------------------------- /src/modules/google-cloud-trace/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "google-cloud-tracing", 3 | "version": "1.0.1", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "private": true, 7 | "dependencies": { 8 | "@google-cloud/trace-agent": "^4.2.5" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/modules/google-cloud-trace/server.ts: -------------------------------------------------------------------------------- 1 | import { serverHooks } from '@vue-storefront/core/server/hooks' 2 | 3 | serverHooks.afterProcessStarted((config) => { 4 | let trace = require('@google-cloud/trace-agent') 5 | if (config.has('trace') && config.get('trace.enabled')) { 6 | trace.start(config.get('trace.config')) 7 | } 8 | }) 9 | -------------------------------------------------------------------------------- /src/modules/google-tag-manager/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'vuex' 2 | import GoogleTagManagerState from '../types/GoogleTagManagerState' 3 | 4 | export const googleTagManagerModule: Module = { 5 | namespaced: true, 6 | state: { 7 | key: null 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/modules/google-tag-manager/types/GoogleTagManagerState.ts: -------------------------------------------------------------------------------- 1 | export default interface GoogleTagManagerState { 2 | key?: null|string 3 | } 4 | -------------------------------------------------------------------------------- /src/modules/instant-checkout/index.ts: -------------------------------------------------------------------------------- 1 | import { StorefrontModule } from '@vue-storefront/core/lib/modules'; 2 | 3 | export const InstantCheckoutModule: StorefrontModule = function () {} 4 | -------------------------------------------------------------------------------- /src/modules/payment-backend-methods/store/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const SET_BACKEND_PAYMENT_METHODS = 'SET_BACKEND_PAYMENT_METHODS' 2 | -------------------------------------------------------------------------------- /src/modules/payment-cash-on-delivery/components/Info.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 22 | -------------------------------------------------------------------------------- /src/modules/robots/server.ts: -------------------------------------------------------------------------------- 1 | import { serverHooks } from '@vue-storefront/core/server/hooks' 2 | 3 | serverHooks.afterApplicationInitialized(({ app }) => { 4 | app.get('/robots.txt', (req, res) => { 5 | res.end('User-agent: *\nDisallow: ') 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /src/search/adapter/graphql/queries/categories.gql: -------------------------------------------------------------------------------- 1 | query CategoryList ( 2 | $filter: CategoryFilterInput, 3 | $pageSize: Int, 4 | $currentPage: Int, 5 | $sort: CategorySortInput, 6 | $_sourceInclude: [String] 7 | ) { 8 | categories( 9 | filter: $filter 10 | pageSize: $pageSize 11 | currentPage: $currentPage 12 | sort: $sort 13 | _sourceInclude: $_sourceInclude 14 | ) 15 | { 16 | hits 17 | suggest 18 | } 19 | } -------------------------------------------------------------------------------- /src/search/adapter/graphql/queries/cmsBlock.gql: -------------------------------------------------------------------------------- 1 | query cmsBlocks ($filter: CmsInput) { 2 | cmsBlocks( 3 | filter: $filter 4 | ) 5 | { 6 | items { 7 | title 8 | id 9 | identifier 10 | content 11 | creation_time 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/search/adapter/graphql/queries/cmsHierarchy.gql: -------------------------------------------------------------------------------- 1 | query cmsHierarchies ($filter: CmsInput) { 2 | cmsHierarchies( 3 | filter: $filter 4 | ) 5 | { 6 | items { 7 | page_id 8 | label 9 | xpath 10 | request_url 11 | parent_node_id 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/search/adapter/graphql/queries/cmsPage.gql: -------------------------------------------------------------------------------- 1 | query cmsPages ($filter: CmsInput) { 2 | cmsPages( 3 | filter: $filter 4 | ) 5 | { 6 | items { 7 | title 8 | identifier 9 | content 10 | meta_description 11 | meta_keywords 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/search/adapter/graphql/queries/customAttributeMetadata.gql: -------------------------------------------------------------------------------- 1 | query customAttributeMetadata ($attributes: AttributeInput!, $_sourceInclude: [String]) { 2 | customAttributeMetadata( 3 | attributes: $attributes 4 | _sourceInclude: $_sourceInclude 5 | ) 6 | { 7 | hits 8 | } 9 | } -------------------------------------------------------------------------------- /src/search/adapter/graphql/queries/products.gql: -------------------------------------------------------------------------------- 1 | query ProductListFilters ( 2 | $filter: ProductFilterInput, 3 | $search: String!, 4 | $pageSize: Int, 5 | $currentPage: Int, 6 | $sort: ProductSortInput, 7 | $_sourceInclude: [String], 8 | $_sourceExclude: [String] 9 | ) { 10 | products( 11 | filter: $filter 12 | search: $search 13 | pageSize: $pageSize 14 | currentPage: $currentPage 15 | sort: $sort 16 | _sourceInclude: $_sourceInclude 17 | _sourceExclude: $_sourceExclude 18 | ) 19 | { 20 | items 21 | total_count 22 | aggregations 23 | sort_fields{ 24 | options { 25 | value 26 | } 27 | } 28 | page_info{ 29 | page_size 30 | current_page 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/search/adapter/graphql/queries/reviews.gql: -------------------------------------------------------------------------------- 1 | query ReviewList ( 2 | $filter: ReviewFilterInput, 3 | $pageSize: Int, 4 | $currentPage: Int 5 | ) { 6 | reviews( 7 | filter: $filter 8 | pageSize: $pageSize 9 | currentPage: $currentPage 10 | ) 11 | { 12 | hits 13 | suggest 14 | } 15 | } -------------------------------------------------------------------------------- /src/search/adapter/graphql/queries/taxrule.gql: -------------------------------------------------------------------------------- 1 | query taxrule ($filter: TaxRuleInput) { 2 | taxrule( 3 | filter: $filter 4 | ) 5 | { 6 | hits 7 | } 8 | } -------------------------------------------------------------------------------- /test/e2e/integration/add-to-compare.js: -------------------------------------------------------------------------------- 1 | /* eslint no-undef: 0 */ 2 | describe('add to compare', () => { 3 | it('Two products should be added to comparison table', () => { 4 | cy.visit('/c/jackets-23'); 5 | cy.get('[data-testid="productLink"]').eq(1).as('firstProduct') 6 | cy.get('@firstProduct').click().should('have.attr', 'href').and('include', 'olivia-14-zip-light-jacket') 7 | cy.get('[data-testid="addToCompare"]').click(); 8 | cy.go('back').wait(1000) 9 | cy.get('[data-testid="addToCompare"]').eq(2).click() 10 | cy.scrollTo('top'); 11 | cy.get('[data-testid="compare-list-icon"]').click(); 12 | cy.get('[data-testid="comparedProduct"]').should('have.length', 2) 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/e2e/integration/register-path.js: -------------------------------------------------------------------------------- 1 | describe('register path', () => { 2 | it('should register user', () => { 3 | cy.visit('/') 4 | cy.get('[data-testid=accountButton]').click() 5 | cy.get('[data-testid=registerLink]').click() 6 | cy.get('[name=email]').type('test@test.com') 7 | cy.get('[name=first-name]').type('Firstname') 8 | cy.get('[name=last-name]').type('Lastname') 9 | cy.get('[name=password]').type('Password123') 10 | cy.get('[name=password-confirm]').type('Password123') 11 | cy.get('#terms').check({ force: true }) 12 | cy.get('[data-testid="errorMessage"]').should('not.exist') 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /test/e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | module.exports = (on, config) => { 15 | // `on` is used to hook into various events Cypress emits 16 | // `config` is the resolved Cypress config 17 | } 18 | -------------------------------------------------------------------------------- /test/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "baseUrl": "../node_modules", 5 | "types": [ 6 | "cypress" 7 | ] 8 | }, 9 | "include": [ 10 | "**/*.*" 11 | ] 12 | } -------------------------------------------------------------------------------- /test/unit/cssStub.js: -------------------------------------------------------------------------------- 1 | export default { } 2 | -------------------------------------------------------------------------------- /test/unit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue-storefront/unit-tests", 3 | "private": true, 4 | "version": "1.12.2" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/setupTestEnvironment.ts: -------------------------------------------------------------------------------- 1 | import '@babel/polyfill' 2 | import { GlobalWithFetchMock } from 'jest-fetch-mock'; 3 | 4 | const customGlobal: GlobalWithFetchMock = (global as unknown) as GlobalWithFetchMock; 5 | customGlobal.fetch = require('jest-fetch-mock'); 6 | customGlobal.fetchMock = customGlobal.fetch; 7 | -------------------------------------------------------------------------------- /tsconfig-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "esModuleInterop": true 6 | }, 7 | "exclude": [ 8 | "**/*.spec.ts" 9 | ] 10 | } 11 | --------------------------------------------------------------------------------