├── .husky ├── .gitignore ├── commit-msg ├── pre-commit └── prepare-commit-msg ├── packages ├── theme │ ├── lang │ │ └── .gitkeep │ ├── .env.example │ ├── jest.config.js │ ├── static │ │ ├── icon.png │ │ ├── favicon.ico │ │ ├── homepage │ │ │ ├── apple.png │ │ │ ├── bannerA.webp │ │ │ ├── bannerB.webp │ │ │ ├── bannerC.webp │ │ │ ├── bannerD.png │ │ │ ├── bannerE.webp │ │ │ ├── bannerF.webp │ │ │ ├── bannerG.webp │ │ │ ├── bannerH.webp │ │ │ ├── google.png │ │ │ ├── imageAd.webp │ │ │ ├── imageAm.webp │ │ │ ├── imageBd.webp │ │ │ ├── imageBm.webp │ │ │ ├── imageCd.webp │ │ │ ├── imageCm.webp │ │ │ ├── imageDd.webp │ │ │ ├── imageDm.webp │ │ │ ├── productA.webp │ │ │ ├── productB.webp │ │ │ ├── productC.webp │ │ │ └── newsletter.webp │ │ ├── icons │ │ │ ├── langs │ │ │ │ ├── de.webp │ │ │ │ └── en.webp │ │ │ ├── bag-icon │ │ │ │ ├── star-icon.svg │ │ │ │ └── star-active-icon.svg │ │ │ ├── facebook.svg │ │ │ └── logo.svg │ │ ├── thankyou │ │ │ ├── bannerD.png │ │ │ └── bannerM.png │ │ └── productpage │ │ │ ├── productA.jpg │ │ │ ├── productB.jpg │ │ │ └── productM.jpg │ ├── .lintstagedrc │ ├── tests │ │ └── e2e │ │ │ ├── pages │ │ │ ├── components │ │ │ │ ├── cart-sidebar.ts │ │ │ │ └── header.ts │ │ │ ├── utils │ │ │ │ └── element.ts │ │ │ ├── category.ts │ │ │ ├── product.ts │ │ │ ├── home.ts │ │ │ ├── base.ts │ │ │ └── factory.ts │ │ │ ├── types │ │ │ ├── address.ts │ │ │ └── customer.ts │ │ │ ├── support │ │ │ ├── index.d.ts │ │ │ ├── commands.js │ │ │ └── index.js │ │ │ ├── fixtures │ │ │ └── test-data │ │ │ │ └── e2e-place-order.json │ │ │ ├── cypress.json │ │ │ ├── plugins │ │ │ └── index.js │ │ │ └── integration │ │ │ └── e2e-place-order.spec.ts │ ├── app │ │ └── router.scrollBehavior.js │ ├── composables │ │ ├── index.ts │ │ ├── useUiNotification │ │ │ └── index.ts │ │ └── useUiState.ts │ ├── components │ │ ├── UserBillingAddress.vue │ │ ├── MyAccount │ │ │ ├── BillingAddressForm.vue │ │ │ └── PasswordResetForm.vue │ │ ├── TopBar.vue │ │ ├── UserAddress.vue │ │ ├── MobileStoreBanner.vue │ │ ├── HeaderNavigation.vue │ │ ├── Notification.vue │ │ ├── Checkout │ │ │ ├── CartPreview.vue │ │ │ ├── VsfShippingProvider.vue │ │ │ └── VsfPaymentProvider.vue │ │ ├── LocaleSelector.vue │ │ ├── BottomNavigation.vue │ │ ├── AppFooter.vue │ │ └── InstagramFeed.vue │ ├── .editorconfig │ ├── middleware │ │ ├── checkout.js │ │ └── is-authenticated.js │ ├── middleware.config.js │ ├── themeConfig.js │ ├── tsconfig.json │ ├── layouts │ │ ├── account.vue │ │ ├── blank.vue │ │ └── error.vue │ ├── package.json │ ├── .gitignore │ ├── README.md │ ├── routes.js │ └── pages │ │ └── Checkout.vue ├── api-client │ ├── src │ │ ├── index.ts │ │ ├── types │ │ │ ├── context.ts │ │ │ └── setup.ts │ │ ├── helpers │ │ │ ├── bagistoLink │ │ │ │ ├── index.ts │ │ │ │ ├── linkHandlers.ts │ │ │ │ └── graphQl.ts │ │ │ └── apiClient │ │ │ │ └── defaultSettings.ts │ │ ├── api │ │ │ ├── customerLogout │ │ │ │ └── index.ts │ │ │ ├── getSlider │ │ │ │ └── index.ts │ │ │ ├── customerResetPassword │ │ │ │ └── index.ts │ │ │ ├── createCustomer │ │ │ │ └── index.ts │ │ │ ├── getAddresses │ │ │ │ └── index.ts │ │ │ ├── getCustomer │ │ │ │ └── index.ts │ │ │ ├── getShippingMethods │ │ │ │ └── index.ts │ │ │ ├── removeAddress │ │ │ │ └── index.ts │ │ │ ├── customerLogin │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── removeReview │ │ │ │ └── index.ts │ │ │ ├── customerUpdate │ │ │ │ └── index.ts │ │ │ ├── createAddress │ │ │ │ └── index.ts │ │ │ ├── updateAddress │ │ │ │ └── index.ts │ │ │ ├── searchReviews │ │ │ │ └── index.ts │ │ │ ├── getCategoryTree │ │ │ │ └── index.ts │ │ │ ├── getNewProduct │ │ │ │ └── index.ts │ │ │ ├── getFeaturedProduct │ │ │ │ └── index.ts │ │ │ └── getRelatedProduct │ │ │ │ └── index.ts │ │ └── index.server.ts │ ├── .gitignore │ ├── jest.config.js │ ├── tsconfig.json │ ├── .lintstagedrc │ ├── api-extractor.json │ ├── rollup.config.js │ ├── package.json │ └── README.md └── composables │ ├── src │ ├── useContent │ │ └── index.ts │ ├── helpers │ │ └── htmlDecoder.ts │ ├── useStore │ │ └── index.ts │ ├── getters │ │ ├── forgotPasswordGetters.ts │ │ ├── storeGetters.ts │ │ ├── categoryGetters.ts │ │ ├── userGetters.ts │ │ ├── reviewGetters.ts │ │ └── wishlistGetters.ts │ ├── useForgotPassword │ │ └── index.ts │ ├── types.ts │ ├── useCategory │ │ └── index.ts │ ├── useUserOrder │ │ └── index.ts │ ├── useUserBilling │ │ └── index.ts │ ├── useMakeOrder │ │ └── index.ts │ ├── useReview │ │ └── index.ts │ ├── useProduct │ │ └── index.ts │ ├── index.ts │ ├── useFacet │ │ └── index.ts │ ├── useShipping │ │ └── index.ts │ ├── useBilling │ │ └── index.ts │ ├── useUserShipping │ │ └── index.ts │ ├── useShippingProvider │ │ └── index.ts │ └── useCart │ │ └── index.ts │ ├── jest.config.js │ ├── nuxt │ ├── README.MD │ ├── index.js │ └── plugin.js │ ├── rollup.config.js │ ├── .lintstagedrc │ ├── tsconfig.json │ ├── api-extractor.json │ ├── package.json │ └── README.md ├── docs ├── guide │ ├── configuration.md │ ├── about.md │ └── getting-started.md ├── .vuepress │ ├── public │ │ └── favicon.png │ ├── styles │ │ ├── index.styl │ │ └── palette.styl │ ├── enhanceApp.js │ └── config.js ├── typedoc.json ├── index.md └── package.json ├── .gitattributes ├── .ncurc.json ├── commitlint.config.js ├── .eslintignore ├── lerna.json ├── .prettierrc ├── .czrc ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── 4.question.yml │ ├── 2.documentation-issue.yml │ ├── 3.feature-request.yml │ └── 1.bug-report.yml ├── workflows │ ├── assing-pr-to-author.yml │ ├── conventional-pr-name.yml │ ├── publish.yml │ └── test.yml ├── CONTRIBUTING.md └── PULL_REQUEST_TEMPLATE.md ├── .vuestorefrontcloud └── docker │ └── docs │ ├── build-docker.sh │ └── Dockerfile ├── .all-contributorsrc ├── jest.base.config.js ├── scripts ├── publishComposable.js ├── publishApi.js └── lib │ └── publishNpm.js ├── .gitignore ├── tsconfig.base.json ├── rollup.base.config.js ├── LICENSE ├── api-extractor.base.json ├── CONTRIBUTING.md ├── README.md └── package.json /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /packages/theme/lang/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/guide/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js text eol=lf 2 | *.ts text eol=lf -------------------------------------------------------------------------------- /packages/api-client/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | -------------------------------------------------------------------------------- /.ncurc.json: -------------------------------------------------------------------------------- 1 | { 2 | "reject": [ 3 | "typescript" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/api-client/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | lib 4 | server 5 | -------------------------------------------------------------------------------- /packages/composables/src/useContent/index.ts: -------------------------------------------------------------------------------- 1 | export function useContent(): any {} 2 | -------------------------------------------------------------------------------- /packages/theme/.env.example: -------------------------------------------------------------------------------- 1 | BAGISTO_DOMAIN= 2 | NODE_ENV=development 3 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx commitlint --edit 5 | -------------------------------------------------------------------------------- /packages/theme/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | modulePathIgnorePatterns: ['tests/e2e/'] 3 | }; 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/**/* 2 | **/lib/* 3 | packages/theme/_theme 4 | packages/theme/.nuxt 5 | **/tests/* -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lerna run --parallel precommit 5 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "useWorkspaces": true, 3 | "npmClient": "yarn", 4 | "version": "independent" 5 | } 6 | -------------------------------------------------------------------------------- /packages/theme/static/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/icon.png -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/docs/.vuepress/public/favicon.png -------------------------------------------------------------------------------- /packages/theme/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/favicon.ico -------------------------------------------------------------------------------- /.husky/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | exec < /dev/tty && git cz --hook || true 5 | -------------------------------------------------------------------------------- /packages/api-client/jest.config.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('./../../jest.base.config'); 2 | 3 | module.exports = baseConfig; 4 | -------------------------------------------------------------------------------- /packages/composables/jest.config.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('./../../jest.base.config'); 2 | 3 | module.exports = baseConfig; 4 | -------------------------------------------------------------------------------- /packages/theme/static/homepage/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/apple.png -------------------------------------------------------------------------------- /packages/theme/static/homepage/bannerA.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/bannerA.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/bannerB.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/bannerB.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/bannerC.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/bannerC.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/bannerD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/bannerD.png -------------------------------------------------------------------------------- /packages/theme/static/homepage/bannerE.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/bannerE.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/bannerF.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/bannerF.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/bannerG.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/bannerG.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/bannerH.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/bannerH.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/google.png -------------------------------------------------------------------------------- /packages/theme/static/homepage/imageAd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/imageAd.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/imageAm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/imageAm.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/imageBd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/imageBd.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/imageBm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/imageBm.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/imageCd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/imageCd.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/imageCm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/imageCm.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/imageDd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/imageDd.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/imageDm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/imageDm.webp -------------------------------------------------------------------------------- /packages/theme/static/icons/langs/de.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/icons/langs/de.webp -------------------------------------------------------------------------------- /packages/theme/static/icons/langs/en.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/icons/langs/en.webp -------------------------------------------------------------------------------- /packages/theme/static/thankyou/bannerD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/thankyou/bannerD.png -------------------------------------------------------------------------------- /packages/theme/static/thankyou/bannerM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/thankyou/bannerM.png -------------------------------------------------------------------------------- /packages/composables/nuxt/README.MD: -------------------------------------------------------------------------------- 1 | # Example config 2 | ```js 3 | export const config = { 4 | // Put expected config example here 5 | }; 6 | ``` -------------------------------------------------------------------------------- /packages/theme/static/homepage/productA.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/productA.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/productB.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/productB.webp -------------------------------------------------------------------------------- /packages/theme/static/homepage/productC.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/productC.webp -------------------------------------------------------------------------------- /packages/api-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "target": "ES2017" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/theme/static/homepage/newsletter.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/homepage/newsletter.webp -------------------------------------------------------------------------------- /packages/theme/static/productpage/productA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/productpage/productA.jpg -------------------------------------------------------------------------------- /packages/theme/static/productpage/productB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/productpage/productB.jpg -------------------------------------------------------------------------------- /packages/theme/static/productpage/productM.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bagisto/vuestorefront/HEAD/packages/theme/static/productpage/productM.jpg -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": true, 4 | "singleQuote": true, 5 | "arrowParens": "always", 6 | "tabWidth": 2, 7 | "bracketSpacing": true 8 | } 9 | -------------------------------------------------------------------------------- /.czrc: -------------------------------------------------------------------------------- 1 | { 2 | "path": "cz-conventional-changelog", 3 | "disableScopeLowerCase": false, 4 | "disableSubjectLowerCase": false, 5 | "maxHeaderWidth": 100, 6 | "maxLineWidth": 100 7 | } 8 | -------------------------------------------------------------------------------- /packages/composables/rollup.config.js: -------------------------------------------------------------------------------- 1 | import pkg from './package.json'; 2 | import { generateBaseConfig } from '../../rollup.base.config'; 3 | 4 | export default generateBaseConfig(pkg); 5 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * Custom Styles here. 3 | * 4 | * ref:https://v1.vuepress.vuejs.org/config/#index-styl 5 | */ 6 | 7 | .home .hero img 8 | max-width 450px!important 9 | -------------------------------------------------------------------------------- /packages/theme/.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{js,jsx}": [ 3 | "eslint --fix" 4 | ], 5 | "*.{ts,tsx}": [ 6 | "eslint --fix" 7 | ], 8 | "*.{vue}": [ 9 | "eslint --fix" 10 | ], 11 | } 12 | -------------------------------------------------------------------------------- /packages/api-client/.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{js,jsx}": [ 3 | "eslint --fix" 4 | ], 5 | "*.{ts,tsx}": [ 6 | "eslint --fix" 7 | ], 8 | "*.{vue}": [ 9 | "eslint --fix" 10 | ], 11 | } 12 | -------------------------------------------------------------------------------- /packages/composables/.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{js,jsx}": [ 3 | "eslint --fix" 4 | ], 5 | "*.{ts,tsx}": [ 6 | "eslint --fix" 7 | ], 8 | "*.{vue}": [ 9 | "eslint --fix" 10 | ], 11 | } 12 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/pages/components/cart-sidebar.ts: -------------------------------------------------------------------------------- 1 | class Cart { 2 | get goToCheckoutButton(): Cypress.Chainable { 3 | return cy.contains('Go to checkout'); 4 | } 5 | } 6 | 7 | export default new Cart(); 8 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/pages/utils/element.ts: -------------------------------------------------------------------------------- 1 | export function el(selector: string, children?: string) { 2 | return children ? cy.get(`[data-e2e="${selector}"] ${children}`) : cy.get(`[data-e2e="${selector}"]`); 3 | } 4 | -------------------------------------------------------------------------------- /packages/api-client/src/types/context.ts: -------------------------------------------------------------------------------- 1 | import { IntegrationContext } from '@vue-storefront/core'; 2 | import { ClientInstance, Config } from './setup'; 3 | 4 | export type Context = IntegrationContext; 5 | -------------------------------------------------------------------------------- /packages/theme/app/router.scrollBehavior.js: -------------------------------------------------------------------------------- 1 | export default function scrollBehavior(_to, _from, savedPosition) { 2 | if (savedPosition) { 3 | return savedPosition; 4 | } else { 5 | return { x: 0, y: 0 }; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Discord Chat 4 | url: https://discord.vuestorefront.io/ 5 | about: Ask questions and discuss with other Vue Storefront users in real time. 6 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/types/address.ts: -------------------------------------------------------------------------------- 1 | export type Address = { 2 | streetName: string; 3 | apartment: string; 4 | city: string; 5 | state: string; 6 | country: string; 7 | zipcode: string; 8 | phone: string; 9 | } 10 | -------------------------------------------------------------------------------- /packages/composables/nuxt/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | export default function integrationModule(moduleOptions) { 4 | this.addPlugin({ 5 | src: path.resolve(__dirname, './plugin.js'), 6 | options: moduleOptions 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/types/customer.ts: -------------------------------------------------------------------------------- 1 | import { Address } from './address'; 2 | 3 | export type Customer = { 4 | firstName?: string; 5 | lastName?: string; 6 | address?: { 7 | shipping: Address, 8 | billing: Address 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/pages/category.ts: -------------------------------------------------------------------------------- 1 | import { el } from './utils/element'; 2 | 3 | class Category { 4 | get products(): Cypress.Chainable { 5 | return el('category-product-card', 'a'); 6 | } 7 | } 8 | 9 | export default new Category(); 10 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * Custom palette here. 3 | * 4 | * ref:https://v1.vuepress.vuejs.org/zh/config/#palette-styl 5 | */ 6 | 7 | $accentColor = #3eaf7c 8 | $textColor = #2c3e50 9 | $borderColor = #eaecef 10 | $codeBgColor = #282c34 11 | -------------------------------------------------------------------------------- /packages/theme/composables/index.ts: -------------------------------------------------------------------------------- 1 | import useUiHelpers from './useUiHelpers'; 2 | import useUiState from './useUiState'; 3 | import useUiNotification from './useUiNotification'; 4 | 5 | export { 6 | useUiHelpers, 7 | useUiState, 8 | useUiNotification 9 | }; 10 | -------------------------------------------------------------------------------- /packages/theme/components/UserBillingAddress.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/support/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable spaced-comment */ 2 | /// 3 | /// 4 | 5 | declare namespace Cypress { 6 | interface Chainable { 7 | fixtures?: any; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "hideBreadcrumbs": true, 3 | "hideInPageTOC": true, 4 | "readme": "none", 5 | "plugin": "typedoc-plugin-markdown", 6 | "theme": "./typedoc-vsf-theme", 7 | "entryPoints": ["src/index.ts", "src/api/index.ts"], 8 | "out": "../../docs/api-client" 9 | } 10 | -------------------------------------------------------------------------------- /packages/theme/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.vuestorefrontcloud/docker/docs/build-docker.sh: -------------------------------------------------------------------------------- 1 | TAG=`git rev-parse HEAD` 2 | docker build --progress plain -t registry.storefrontcloud.io/docs-storefrontcloud-io/v2-bagisto:${TAG:0:8} -f Dockerfile ../../../ 3 | # docker push registry.storefrontcloud.io/docs-storefrontcloud-io/v2-bagisto:${TAG:0:8} 4 | -------------------------------------------------------------------------------- /packages/theme/components/MyAccount/BillingAddressForm.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /packages/theme/components/MyAccount/PasswordResetForm.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/pages/product.ts: -------------------------------------------------------------------------------- 1 | import Base from './base'; 2 | import { el } from './utils/element'; 3 | 4 | class Product extends Base { 5 | get addToCartButton(): Cypress.Chainable { 6 | return el('product_add-to-cart'); 7 | } 8 | } 9 | 10 | export default new Product(); 11 | -------------------------------------------------------------------------------- /packages/theme/middleware/checkout.js: -------------------------------------------------------------------------------- 1 | import { Logger } from '@vue-storefront/core'; 2 | 3 | export default () => { 4 | Logger.error('Please implement vendor-specific checkout.js middleware in the \'middleware\' directory to block access to checkout steps when customer did not yet complete previous steps'); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/pages/home.ts: -------------------------------------------------------------------------------- 1 | import Base from './base'; 2 | import Header from './components/header'; 3 | 4 | class Home extends Base { 5 | get header() { 6 | return Header; 7 | } 8 | 9 | visit(): Cypress.Chainable { 10 | return cy.visit('/'); 11 | } 12 | } 13 | 14 | export default new Home(); 15 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/pages/base.ts: -------------------------------------------------------------------------------- 1 | import Header from './components/header'; 2 | 3 | export default class Base { 4 | get path(): string { 5 | return '/'; 6 | } 7 | 8 | get header() { 9 | return Header; 10 | } 11 | 12 | visit(): Cypress.Chainable { 13 | return cy.visit(this.path); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "bagisto", 3 | "projectOwner": "webkul", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 80, 10 | "commit": false, 11 | "commitConvention": "angular", 12 | "contributors": [], 13 | "contributorsPerLine": 5 14 | } 15 | -------------------------------------------------------------------------------- /docs/guide/about.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | ## Resources 4 | 5 | - [Vue Storefront Documentation](https://docs.vuestorefront.io/v2/) 6 | - [Community Chat](https://discord.vuestorefront.io) 7 | 8 | ## Support 9 | 10 | If you have any questions about this integration we will be happy to answer them on `bagisto` channel on [our Discord](discord.vuestorefront.io). 11 | -------------------------------------------------------------------------------- /packages/api-client/api-extractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../api-extractor.base.json", 3 | "mainEntryPointFilePath": "./lib/index.d.ts", 4 | "dtsRollup": { 5 | "untrimmedFilePath": "./lib/.d.ts" 6 | }, 7 | "docModel": { 8 | "apiJsonFilePath": "/docs/api-client/.api.json" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/composables/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "exclude": ["node_modules", "lib"], 5 | "compilerOptions": { 6 | "lib": ["DOM", "ESNext"], 7 | "resolveJsonModule": true, 8 | "rootDir": "./src", 9 | "allowJs": true, 10 | "allowSyntheticDefaultImports": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/theme/middleware.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | integrations: { 3 | bagisto: { 4 | location: '@vue-storefront/bagisto-api/server', 5 | configuration: { 6 | api: { 7 | domain: process.env.BAGISTO_DOMAIN 8 | }, 9 | currency: 'USD', 10 | country: 'US' 11 | } 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /packages/composables/api-extractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../api-extractor.base.json", 3 | "mainEntryPointFilePath": "./lib/index.d.ts", 4 | "dtsRollup": { 5 | "untrimmedFilePath": "./lib/.d.ts" 6 | }, 7 | "docModel": { 8 | "apiJsonFilePath": "/docs/composables/.api.json" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/theme/middleware/is-authenticated.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ 2 | // eslint-disable-next-line func-names 3 | export default (context) => { 4 | const token = context.$cookies.get('vsf-bagCust-token'); 5 | // check if user not logged In 6 | if (!token) { 7 | context.app.router.push('/'); 8 | context.redirect('/'); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /jest.base.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | transform: { 6 | '^.+\\.(ts)$': 'ts-jest' 7 | }, 8 | coverageDirectory: './coverage/', 9 | collectCoverageFrom: [ 10 | 'src/**/*.ts' 11 | ], 12 | testMatch: ['/**/__tests__/**/*spec.[jt]s?(x)'] 13 | }; 14 | -------------------------------------------------------------------------------- /scripts/publishComposable.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable unicorn/prefer-module */ 2 | const path = require('path'); 3 | const { publishPackages } = require('./lib/publishNpm'); 4 | 5 | const myArgs = process.argv.slice(2); 6 | const labels = myArgs[0]; 7 | 8 | publishPackages(path.join(process.cwd(), 'packages', 'composables'), labels) 9 | .then(console.log) 10 | .catch((e) => { 11 | console.error(e); 12 | }); 13 | -------------------------------------------------------------------------------- /docs/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## How to start if you want to try out the integration 4 | 5 | ``` 6 | yarn global add @vue-storefront/cli 7 | ``` 8 | ``` 9 | vsf init && cd && yarn && yarn dev 10 | ``` 11 | 12 | ## How to start if you want to contribute? 13 | 14 | Want to contribute? Ping us on `bagisto` channel on [our Discord](https://discord.vuestorefront.io)! 15 | 16 | -------------------------------------------------------------------------------- /scripts/publishApi.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable unicorn/no-process-exit, unicorn/prefer-module */ 2 | const path = require('path'); 3 | const { publishPackages } = require('./lib/publishNpm'); 4 | 5 | const myArgs = process.argv.slice(2); 6 | const labels = myArgs[0]; 7 | 8 | publishPackages(path.join(process.cwd(), 'packages', 'api-client'), labels) 9 | .then(console.log) 10 | .catch((e) => { 11 | console.error(e); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/composables/nuxt/plugin.js: -------------------------------------------------------------------------------- 1 | import { integrationPlugin } from '@vue-storefront/core'; 2 | 3 | const moduleOptions = JSON.parse('<%= JSON.stringify(options) %>'); 4 | 5 | // eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars 6 | export default integrationPlugin(({ app, integration }) => { 7 | 8 | integration.configure('bagisto', { 9 | ...moduleOptions, 10 | app 11 | // other options 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Client app enhancement file. 3 | * 4 | * https://v1.vuepress.vuejs.org/guide/basic-config.html#app-level-enhancements 5 | */ 6 | 7 | export default ({ 8 | Vue, // the version of Vue being used in the VuePress app 9 | options, // the options for the root Vue instance 10 | router, // the router instance for the app 11 | siteData // site metadata 12 | }) => { 13 | // ...apply enhancements for the site. 14 | } 15 | -------------------------------------------------------------------------------- /packages/api-client/src/helpers/bagistoLink/index.ts: -------------------------------------------------------------------------------- 1 | import { Config } from '../../types/setup'; 2 | import { apolloLinkFactory } from './graphQl'; 3 | import { linkFactory } from './linkHandlers'; 4 | 5 | export const createBagistoConnection = (settings: Config) => { 6 | 7 | const apolloLink = apolloLinkFactory(settings, { 8 | apolloLink: linkFactory({ state: settings.state }), 9 | }); 10 | 11 | return { 12 | apolloLink, 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /.github/workflows/assing-pr-to-author.yml: -------------------------------------------------------------------------------- 1 | name: PR to Author 2 | on: 3 | pull_request: 4 | types: [opened, ready_for_review, edited, synchronize] 5 | 6 | jobs: 7 | assignAuthor: 8 | name: Assing 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: samspills/assign-pr-to-author@v1.0 12 | if: github.event_name == 'pull_request' && github.event.action == 'opened' 13 | with: 14 | repo-token: '${{ secrets.GITHUB_TOKEN }}' 15 | -------------------------------------------------------------------------------- /packages/composables/src/helpers/htmlDecoder.ts: -------------------------------------------------------------------------------- 1 | export function htmlDecode(input) { 2 | const formatName = () => { 3 | try { 4 | const domParser = new DOMParser(); 5 | const doc = domParser.parseFromString(input, 'text/html'); 6 | return doc.documentElement.textContent; 7 | } catch { 8 | return input; 9 | } 10 | }; 11 | const name = formatName(); 12 | return name === 'undefined' ? '' : name; 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/conventional-pr-name.yml: -------------------------------------------------------------------------------- 1 | name: Commitlint 2 | on: 3 | pull_request: 4 | types: ['opened', 'edited', 'reopened', 'synchronize'] 5 | 6 | jobs: 7 | lint: 8 | name: Validate PR Title (conventional-commit) 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Install Dependencies 13 | run: npm install @commitlint/config-conventional 14 | - uses: JulienKode/pull-request-name-linter-action@v0.1.2 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directories 2 | node_modules 3 | 4 | # Logs 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | 10 | # NPM config 11 | .npmrc 12 | 13 | # Yarn Integrity file 14 | .yarn-integrity 15 | 16 | # Rollup generate output 17 | lib 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # Editor directories and files 23 | .idea 24 | .vscode 25 | 26 | # OS generated files 27 | .DS_STORE 28 | 29 | !scripts/lib 30 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Vue Storefront 2 integration with bagisto 4 | 5 | This project is a bagisto integration for Vue Storefront 2. 6 | 7 | This integration is currently a **Beta** and not ready for production usage. You can help us to make the integration production-ready faster by reporting bugs and contributing to the code at the [repository issues page](https://github.com/vuestorefront/bagisto/issues). 8 | -------------------------------------------------------------------------------- /packages/theme/themeConfig.js: -------------------------------------------------------------------------------- 1 | export default { 2 | home: { 3 | bannerA: { 4 | link: '/', 5 | image: { 6 | mobile: '/homepage/bannerB.webp', 7 | desktop: '/homepage/bannerF.webp' 8 | } 9 | }, 10 | bannerB: { 11 | link: '/', 12 | image: '/homepage/bannerE.webp' 13 | }, 14 | bannerC: { 15 | link: '/', 16 | image: '/homepage/bannerC.webp' 17 | }, 18 | bannerD: { 19 | link: '/', 20 | image: '/homepage/bannerG.webp' 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /packages/api-client/src/helpers/apiClient/defaultSettings.ts: -------------------------------------------------------------------------------- 1 | import { ClientConfig } from '../../types/setup'; 2 | 3 | export const defaultSettings: ClientConfig = { 4 | api: { 5 | domain: '' 6 | }, 7 | cookies: { 8 | currencyCookieName: 'vsf-currency', 9 | localeCookieName: 'vsf-locale', 10 | customerCookieName: 'vsf-customer', 11 | bagistoSession: '' 12 | }, 13 | currency: 'USD', 14 | state: { 15 | getCustomerToken: () => '', 16 | setCustomerToken: () => {}, 17 | getGuestToken: () => '', 18 | setGuestToken: () => {}, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /.vuestorefrontcloud/docker/docs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 AS build 2 | 3 | WORKDIR /var/www 4 | 5 | COPY . . 6 | 7 | RUN yarn install --network-concurrency 1 8 | RUN cd packages/api-client && yarn build && yarn cache clean --all 9 | RUN cd packages/composables && yarn build && yarn cache clean --all 10 | 11 | RUN cd docs \ 12 | && npm install \ 13 | && sed -i "s/base: '\/',/base: '\/bagisto\/',/g" ./.vuepress/config.js \ 14 | && cat ./.vuepress/config.js \ 15 | && npm run build 16 | 17 | FROM nginx 18 | 19 | COPY --from=build /var/www/docs/.vuepress/dist /usr/share/nginx/html/bagisto 20 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./lib", 4 | "esModuleInterop": true, 5 | "target": "es5", 6 | "module": "ES2015", 7 | "moduleResolution": "node", 8 | "importHelpers": true, 9 | "noEmitHelpers": true, 10 | "sourceMap": true, 11 | "declaration": true, 12 | "skipLibCheck": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "baseUrl": "./", 15 | "lib": ["es6", "es7", "ES2017", "ES2018", "ES2019", "dom"], 16 | "strict": false, 17 | "preserveSymlinks": true 18 | }, 19 | "exclude": ["node_modules", "**/*.spec.ts"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/api-client/src/api/customerLogout/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | 4 | export async function customerLogout(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .mutate({ 9 | mutation: gql` 10 | mutation customerLogout { 11 | customerLogout { 12 | status 13 | success 14 | } 15 | }` 16 | }); 17 | } catch (error) { 18 | console.log('Error customerLogout:'); 19 | console.log(error); 20 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/composables/src/useStore/index.ts: -------------------------------------------------------------------------------- 1 | import { Store } from '@vue-storefront/bagisto-api'; 2 | import { Context, useStoreFactory } from '@vue-storefront/core'; 3 | 4 | export const useStore = useStoreFactory({ 5 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 6 | load(context: Context, params) { 7 | console.log('Mocked: useStore.load'); 8 | 9 | return Promise.resolve({}); 10 | }, 11 | 12 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 13 | change(context: Context, params) { 14 | console.log('Mocked: useStore.change'); 15 | 16 | return Promise.resolve({}); 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /packages/composables/src/getters/forgotPasswordGetters.ts: -------------------------------------------------------------------------------- 1 | import { ForgotPasswordGetters } from '@vue-storefront/core'; 2 | import type { PasswordResetResult } from '@vue-storefront/bagisto-api'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 5 | function getResetPasswordToken(result: PasswordResetResult): string { 6 | return ''; 7 | } 8 | 9 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 10 | function isPasswordChanged(result: PasswordResetResult): boolean { 11 | return true; 12 | } 13 | 14 | export const forgotPasswordGetters: ForgotPasswordGetters = { 15 | getResetPasswordToken, 16 | isPasswordChanged 17 | }; 18 | -------------------------------------------------------------------------------- /packages/composables/src/getters/storeGetters.ts: -------------------------------------------------------------------------------- 1 | import { Store } from '@vue-storefront/bagisto-api'; 2 | import { AgnosticStore, UseStoreGetters } from '@vue-storefront/core'; 3 | import { UseStoreFilterParams } from '../types'; 4 | 5 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 6 | function getItems(stores: Store, criteria: UseStoreFilterParams = {}): AgnosticStore[] { 7 | return []; 8 | } 9 | 10 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 11 | function getSelected(stores: Store): AgnosticStore | undefined { 12 | return null; 13 | } 14 | 15 | export const storeGetters: UseStoreGetters = { 16 | getItems, 17 | getSelected 18 | }; 19 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/pages/factory.ts: -------------------------------------------------------------------------------- 1 | import Category from './category'; 2 | import { Billing, Payment, Shipping, ThankYou } from './checkout'; 3 | import Cart from './components/cart-sidebar'; 4 | import Home from './home'; 5 | import Product from './product'; 6 | 7 | const page = { 8 | get cart() { 9 | return Cart; 10 | }, 11 | get category() { 12 | return Category; 13 | }, 14 | get checkout() { 15 | return { 16 | shipping: new Shipping(), 17 | billing: new Billing(), 18 | payment: new Payment(), 19 | thankyou: new ThankYou() 20 | }; 21 | }, 22 | get home() { 23 | return Home; 24 | }, 25 | get product() { 26 | return Product; 27 | } 28 | }; 29 | 30 | export default page; 31 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/pages/components/header.ts: -------------------------------------------------------------------------------- 1 | import { el } from '../utils/element'; 2 | 3 | class Header { 4 | get cart(): Cypress.Chainable { 5 | return el('header-icons').children().eq(2); 6 | } 7 | 8 | get categories(): Cypress.Chainable { 9 | return cy.get('[data-e2e*="app-header"]'); 10 | } 11 | 12 | get category() { 13 | return { 14 | women: () => el('app-header-url_women'), 15 | men: () => el('app-header-url_men') 16 | }; 17 | } 18 | 19 | openCart(): Cypress.Chainable { 20 | const click = $el => $el.click(); 21 | return this.cart.pipe(click).should(() => { 22 | expect(Cypress.$('[data-e2e="sidebar-cart"]')).to.exist; 23 | }); 24 | } 25 | } 26 | 27 | export default new Header(); 28 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/fixtures/test-data/e2e-place-order.json: -------------------------------------------------------------------------------- 1 | { 2 | "customer": { 3 | "firstName": "John", 4 | "lastName": "Doe", 5 | "address": { 6 | "shipping": { 7 | "streetName": "1 VueStorefront Rd.", 8 | "apartment": "23", 9 | "city": "Los Angeles", 10 | "state": "California", 11 | "country": "United States", 12 | "zipcode": "45678", 13 | "phone": "123456789" 14 | }, 15 | "billing": { 16 | "streetName": "1 VueStorefront Rd.", 17 | "apartment": "23", 18 | "city": "Los Angeles", 19 | "state": "California", 20 | "country": "United States", 21 | "zipcode": "45678", 22 | "phone": "123456789" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3000", 3 | "fixturesFolder": "tests/e2e/fixtures", 4 | "integrationFolder": "tests/e2e/integration", 5 | "pluginsFile": "tests/e2e/plugins/index.js", 6 | "supportFile": "tests/e2e/support/index.js", 7 | "viewportHeight": 1080, 8 | "viewportWidth": 1920, 9 | "pageLoadTimeout": 180000, 10 | "screenshotOnRunFailure": true, 11 | "screenshotsFolder": "tests/e2e/report/assets/screenshots", 12 | "video": false, 13 | "reporter": "../../../node_modules/mochawesome", 14 | "reporterOptions": { 15 | "reportDir": "tests/e2e/report", 16 | "reportFilename": "report", 17 | "overwrite": false, 18 | "html": false 19 | }, 20 | "retries": { 21 | "runMode": 2, 22 | "openMode": 0 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/theme/static/icons/bag-icon/star-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-rating-star 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/theme/static/icons/bag-icon/star-active-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-rating-star-on 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/api-client/src/helpers/bagistoLink/linkHandlers.ts: -------------------------------------------------------------------------------- 1 | import { setContext } from 'apollo-link-context'; 2 | import { ConfigState } from '../../types/setup'; 3 | 4 | export const handleRetry = () => (count, error) => { 5 | if (count > 3) { 6 | return false; 7 | } 8 | 9 | if (error?.result?.message === 'invalid_token') { 10 | return true; 11 | } 12 | 13 | return false; 14 | }; 15 | 16 | export const linkFactory = ({ state }: { 17 | state: ConfigState; 18 | }) => setContext((apolloReq, { headers }) => { 19 | const token: string = state.getCustomerToken(); 20 | const guestCookie: string = state.getGuestToken(); 21 | 22 | return { 23 | headers: { 24 | ...headers, 25 | ...(token ? { authorization: token } : {}), 26 | ...(guestCookie ? { Cookie: guestCookie } : {}) 27 | } 28 | }; 29 | }); 30 | -------------------------------------------------------------------------------- /scripts/lib/publishNpm.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable unicorn/no-process-exit, unicorn/prefer-module */ 2 | const { exec } = require("child_process"); 3 | 4 | const publishPackages = (pkgPath, labels) => { 5 | return new Promise((_res, _rej) => { 6 | try { 7 | const command = `npm publish ${pkgPath} --access public --tag ${labels}`; 8 | 9 | console.log(command) 10 | 11 | exec(command, (error, stdout, stderr) => { 12 | if (error) { 13 | console.log(`error: ${error.message}`); 14 | return; 15 | } 16 | if (stderr) { 17 | console.log(`stderr: ${stderr}`); 18 | return; 19 | } 20 | console.log(`stdout: ${stdout}`); 21 | }); 22 | } catch (e) { 23 | console.error(e); 24 | } 25 | }); 26 | } 27 | 28 | module.exports = { 29 | publishPackages, 30 | } 31 | -------------------------------------------------------------------------------- /packages/api-client/src/api/getSlider/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from "@apollo/client/core"; 3 | 4 | export async function getSlider(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .query({ 9 | query: gql` 10 | query sliders { 11 | sliders { 12 | id 13 | title 14 | path 15 | imageUrl 16 | content 17 | channelId 18 | locale 19 | sliderPath 20 | imgPath 21 | } 22 | }` 23 | }); 24 | 25 | } catch (error) { 26 | console.log("error"); 27 | console.log(error); 28 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 29 | } 30 | } -------------------------------------------------------------------------------- /packages/composables/src/useForgotPassword/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useForgotPasswordFactory, 4 | UseForgotPasswordFactoryParams 5 | } from '@vue-storefront/core'; 6 | 7 | const factoryParams: UseForgotPasswordFactoryParams = { 8 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 9 | resetPassword: async (context: Context, { email, customQuery }) => { 10 | console.log('Mocked: resetPassword'); 11 | const passwordResult = await context.$bagisto.api.customerResetPassword(email); 12 | 13 | return passwordResult?.data?.forgotPassword || null; 14 | }, 15 | 16 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 17 | setNewPassword: async (context: Context, { tokenValue, newPassword, customQuery }) => { 18 | console.log('Mocked: setNewPassword'); 19 | return {}; 20 | } 21 | }; 22 | 23 | export const useForgotPassword = useForgotPasswordFactory(factoryParams); 24 | -------------------------------------------------------------------------------- /rollup.base.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from '@rollup/plugin-node-resolve'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | 4 | const extensions = ['.js', '.jsx', '.es6', '.es', '.mjs', '.ts']; 5 | 6 | export function generateBaseConfig(pkg) { 7 | return { 8 | input: 'src/index.ts', 9 | output: [ 10 | { 11 | file: pkg.main, 12 | format: 'cjs', 13 | sourcemap: true 14 | }, 15 | { 16 | file: pkg.module, 17 | format: 'es', 18 | sourcemap: true 19 | } 20 | ], 21 | external: [ 22 | ...Object.keys(pkg.dependencies || {}), 23 | ...Object.keys(pkg.peerDependencies || {}) 24 | ], 25 | plugins: [ 26 | nodeResolve({ 27 | extensions 28 | }), 29 | typescript({ 30 | // eslint-disable-next-line global-require 31 | typescript: require('typescript') 32 | }) 33 | ] 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /packages/theme/components/TopBar.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 29 | 38 | -------------------------------------------------------------------------------- /packages/api-client/rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from '@rollup/plugin-node-resolve'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import pkg from './package.json'; 4 | import { generateBaseConfig } from '../../rollup.base.config'; 5 | 6 | const extensions = ['.ts', '.js']; 7 | 8 | const server = { 9 | input: 'src/index.server.ts', 10 | output: [ 11 | { 12 | file: pkg.server, 13 | format: 'cjs', 14 | sourcemap: true 15 | } 16 | ], 17 | external: [ 18 | ...Object.keys(pkg.dependencies || {}), 19 | ...Object.keys(pkg.peerDependencies || {}) 20 | ], 21 | plugins: [ 22 | nodeResolve({ 23 | extensions 24 | }), 25 | typescript({ 26 | // eslint-disable-next-line global-require 27 | typescript: require('typescript'), 28 | useTsconfigDeclarationDir: true 29 | }) 30 | ] 31 | }; 32 | 33 | export default [ 34 | generateBaseConfig(pkg), 35 | server 36 | ]; 37 | -------------------------------------------------------------------------------- /packages/theme/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "target": "ES2018", 5 | "module": "ESNext", 6 | "moduleResolution": "Node", 7 | "lib": [ 8 | "ESNext", 9 | "ESNext.AsyncIterable", 10 | "DOM" 11 | ], 12 | "esModuleInterop": true, 13 | "allowJs": true, 14 | "sourceMap": true, 15 | "strict": false, 16 | "noEmit": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "~/*": [ 20 | "./*" 21 | ], 22 | "@/*": [ 23 | "./*" 24 | ] 25 | }, 26 | "types": [ 27 | "@types/node", 28 | "@nuxt/types", 29 | "nuxt-i18n" 30 | ], 31 | "resolveJsonModule": true, 32 | "rootDir": "./", 33 | "declarationDir": "./lib", 34 | "importHelpers": true, 35 | "allowSyntheticDefaultImports": true 36 | }, 37 | "exclude": [ 38 | "node_modules", 39 | ".nuxt", 40 | "dist", 41 | "_theme" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /packages/composables/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue-storefront/bagisto", 3 | "version": "0.0.1", 4 | "private": true, 5 | "sideEffects": false, 6 | "main": "lib/index.cjs.js", 7 | "module": "lib/index.es.js", 8 | "types": "lib/index.d.ts", 9 | "scripts": { 10 | "build": "rimraf lib && rollup -c", 11 | "dev": "rollup -c -w", 12 | "precommit": "lint-staged", 13 | "prepublish": "yarn build", 14 | "test": "jest", 15 | "update:check": "ncu", 16 | "update:update": "ncu -u" 17 | }, 18 | "dependencies": { 19 | "@vue-storefront/bagisto-api": "0.0.1", 20 | "@vue-storefront/core": "~2.5.2" 21 | }, 22 | "devDependencies": { 23 | "@rollup/plugin-node-resolve": "^13.0.6", 24 | "rollup-plugin-typescript2": "^0.30.0" 25 | }, 26 | "peerDependencies": { 27 | "@nuxtjs/composition-api": "^0.29.3" 28 | }, 29 | "files": [ 30 | "lib/**/*" 31 | ], 32 | "publishConfig": { 33 | "access": "public" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line spaced-comment 2 | /// 3 | // *********************************************************** 4 | // This example plugins/index.js can be used to load plugins 5 | // 6 | // You can change the location of this file or turn off loading 7 | // the plugins file with the 'pluginsFile' configuration option. 8 | // 9 | // You can read more here: 10 | // https://on.cypress.io/plugins-guide 11 | // *********************************************************** 12 | 13 | // This function is called when a project is opened or re-opened (e.g. due to 14 | // the project's config changing) 15 | 16 | const tagify = require('cypress-tags'); 17 | 18 | /** 19 | * @type {Cypress.PluginConfig} 20 | */ 21 | module.exports = (on, config) => { 22 | // `on` is used to hook into various events Cypress emits 23 | // `config` is the resolved Cypress config 24 | on('file:preprocessor', tagify(config)); 25 | }; 26 | -------------------------------------------------------------------------------- /packages/theme/static/icons/facebook.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/support/commands.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | // *********************************************** 3 | // This example commands.js shows you how to 4 | // create various custom commands and overwrite 5 | // existing commands. 6 | // 7 | // For more comprehensive examples of custom 8 | // commands please read more here: 9 | // https://on.cypress.io/custom-commands 10 | // *********************************************** 11 | // 12 | // 13 | // -- This is a parent command -- 14 | // Cypress.Commands.add("login", (email, password) => { ... }) 15 | // 16 | // 17 | // -- This is a child command -- 18 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 19 | // 20 | // 21 | // -- This is a dual command -- 22 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 23 | // 24 | // 25 | // -- This will overwrite an existing command -- 26 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 27 | -------------------------------------------------------------------------------- /packages/api-client/src/api/customerResetPassword/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | import { ForgotPasswordInput } from '../../types'; 4 | 5 | type Variables = { 6 | input?: ForgotPasswordInput; 7 | }; 8 | 9 | export async function customerResetPassword(context, params) { 10 | const inputFilters = { 11 | email: params 12 | }; 13 | 14 | const variables: Variables = { 15 | input: inputFilters 16 | }; 17 | 18 | try { 19 | return await context.client 20 | .mutate({ 21 | mutation: gql` 22 | mutation forgotPassword ($input: ForgotPasswordInput!) { 23 | forgotPassword(input: $input) { 24 | status 25 | success 26 | } 27 | }`, 28 | variables: variables 29 | }); 30 | } catch (error) { 31 | console.log('Error customerResetPassword:'); 32 | console.log(error); 33 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/4.question.yml: -------------------------------------------------------------------------------- 1 | name: "❓ Question / Basic Issue" 2 | description: | 3 | Do you have a question on the implementation or a basic issue 4 | labels: 5 | - triage-needed 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: If you are not sure how something works or want discuss something just describe your doubts. 10 | - type: textarea 11 | attributes: 12 | label: What is your question / Please describe your issue 13 | validations: 14 | required: true 15 | - type: input 16 | attributes: 17 | label: What version of bagisto integration are you using? 18 | description: 'For example: 1.0.0' 19 | validations: 20 | required: true 21 | - type: checkboxes 22 | id: terms 23 | attributes: 24 | label: Code of Conduct 25 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/vuestorefront/vue-storefront/blob/master/CODE_OF_CONDUCT.md) 26 | options: 27 | - label: I agree to follow this project's Code of Conduct 28 | required: true 29 | -------------------------------------------------------------------------------- /packages/theme/layouts/account.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 33 | 34 | 50 | -------------------------------------------------------------------------------- /packages/composables/src/types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ProductsSearchParams 3 | } from '@vue-storefront/core'; 4 | 5 | export type TODO = any; 6 | 7 | export type UseBillingAddParams = TODO; 8 | 9 | export type UseCategorySearchParams = TODO; 10 | 11 | export type UseFacetSearchParams = TODO; 12 | 13 | export type UseProductSearchParams = ProductsSearchParams; 14 | 15 | export type UseReviewSearchParams = TODO; 16 | 17 | export type UseReviewAddParams = { 18 | name: string, 19 | title: string, 20 | rating: number, 21 | comment: string, 22 | productId: number 23 | }; 24 | 25 | export type UseShippingAddParams = TODO; 26 | 27 | export type UseStoreFilterParams = TODO; 28 | 29 | export type UseUserUpdateParams = TODO; 30 | 31 | export type UseUserRegisterParams = TODO; 32 | 33 | export type useUserOrderSearchParams = TODO; 34 | 35 | export type CustomerOrder = { 36 | results: any[]; 37 | total: number; 38 | }; 39 | 40 | export type User = { 41 | id: number; 42 | firstName: string; 43 | lastName: string; 44 | email: string; 45 | gender: string; 46 | phone: string; 47 | dateOfBirth: string; 48 | }; 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Bagisto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2.documentation-issue.yml: -------------------------------------------------------------------------------- 1 | name: "📚 Documentation Issue" 2 | description: | 3 | Report issues in our documentation 4 | labels: 5 | - documentation 6 | - triage-needed 7 | body: 8 | - type: textarea 9 | attributes: 10 | label: Provide a description of requested docs changes 11 | placeholder: Briefly describe which document needs to be corrected. 12 | validations: 13 | required: true 14 | - type: checkboxes 15 | id: fixthebug 16 | attributes: 17 | label: Able to fix / change the documentation? 18 | description: Can you handle this change and create a Pull Request? 19 | options: 20 | - label: 'Yes' 21 | required: false 22 | - label: 'No' 23 | required: false 24 | - type: checkboxes 25 | id: terms 26 | attributes: 27 | label: Code of Conduct 28 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/vuestorefront/bagisto/blob/master/CODE_OF_CONDUCT.md) 29 | options: 30 | - label: I agree to follow this project's Code of Conduct 31 | required: true 32 | -------------------------------------------------------------------------------- /api-extractor.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", 3 | "projectFolder": ".", 4 | "compiler": { 5 | "tsconfigFilePath": "/tsconfig.base.json" 6 | }, 7 | "docModel": { 8 | "enabled": true 9 | }, 10 | "dtsRollup": { 11 | "enabled": true 12 | }, 13 | "tsdocMetadata": { 14 | "enabled": false 15 | }, 16 | "apiReport": { 17 | "enabled": false 18 | }, 19 | "messages": { 20 | "compilerMessageReporting": { 21 | "default": { 22 | "logLevel": "warning" 23 | } 24 | }, 25 | "extractorMessageReporting": { 26 | "default": { 27 | "logLevel": "none", 28 | "addToApiReportFile": false 29 | }, 30 | "ae-extra-release-tag": { 31 | "logLevel": "none", 32 | "addToApiReportFile": false 33 | }, 34 | "ae-forgotten-export": { 35 | "logLevel": "none" 36 | } 37 | }, 38 | "tsdocMessageReporting": { 39 | "default": { 40 | "logLevel": "none", 41 | "addToApiReportFile": false 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/composables/src/useCategory/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useCategoryFactory, 4 | UseCategoryFactoryParams 5 | } from '@vue-storefront/core'; 6 | import type { Category } from '@vue-storefront/bagisto-api'; 7 | import type { 8 | UseCategorySearchParams as SearchParams 9 | } from '../types'; 10 | 11 | const params: UseCategoryFactoryParams = { 12 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 13 | categorySearch: async (context: Context, { customQuery, ...params }) => { 14 | console.log('Mocked: useCategory.categorySearch'); 15 | switch (params.apiType) { 16 | case 'categoryBySlug': 17 | const categoriesResult = await context.$bagisto.api.getCategories(params); 18 | 19 | return categoriesResult?.data?.categories?.data; 20 | break; 21 | case 'categoryTree': 22 | const categoryTreeResults = await context.$bagisto.api.getCategoryTree(params); 23 | 24 | return categoryTreeResults?.data?.homeCategories; 25 | break; 26 | } 27 | } 28 | }; 29 | 30 | export const useCategory = useCategoryFactory(params); 31 | -------------------------------------------------------------------------------- /packages/api-client/src/api/createCustomer/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | import { CreateRegisterInput } from '../../types'; 4 | 5 | type Variables = { 6 | input?: CreateRegisterInput; 7 | }; 8 | 9 | export async function createCustomer(context, params) { 10 | const inputFilters = { 11 | firstName: params?.first_name, 12 | lastName: params?.last_name, 13 | email: params?.email, 14 | password: params?.password, 15 | passwordConfirmation: params?.password_confirmation 16 | }; 17 | 18 | const variables: Variables = { 19 | input: inputFilters 20 | }; 21 | 22 | try { 23 | return await context.client 24 | .mutate({ 25 | mutation: gql` 26 | mutation customerRegister ($input: CreateRegisterInput!) { 27 | customerRegister(input: $input) { 28 | status 29 | success 30 | } 31 | }`, 32 | variables: variables 33 | }); 34 | } catch (error) { 35 | console.log('Error customerRegister:'); 36 | console.log(error); 37 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/api-client/src/types/setup.ts: -------------------------------------------------------------------------------- 1 | import ApolloClient, { ApolloClientOptions } from 'apollo-client'; 2 | import { FetchOptions } from 'apollo-link-http'; 3 | 4 | export interface Storage { 5 | set: ( 6 | name: string, 7 | value: any 8 | ) => void; 9 | get: (name: string) => any; 10 | remove: (name: string) => any; 11 | removeAll: () => void; 12 | } 13 | 14 | export type ConfigState = { 15 | getCustomerToken(): string; 16 | setCustomerToken(token?: string | null): void; 17 | getGuestToken(): string; 18 | setGuestToken(token?: string | null): void; 19 | }; 20 | 21 | export interface ClientConfig { 22 | api: { 23 | domain: string; 24 | }; 25 | cookies: { 26 | currencyCookieName: string; 27 | localeCookieName: string; 28 | customerCookieName: string; 29 | bagistoSession: string; 30 | }, 31 | currency: string; 32 | state: ConfigState; 33 | } 34 | 35 | export interface Config extends ClientConfig { 36 | client?: ApolloClient; 37 | storage: Storage; 38 | customOptions?: ApolloClientOptions; 39 | customApolloHttpLinkOptions?: FetchOptions; 40 | } 41 | 42 | export interface ClientInstance extends ApolloClient { 43 | } 44 | -------------------------------------------------------------------------------- /packages/composables/src/useUserOrder/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useUserOrderFactory, 4 | UseUserOrderFactoryParams 5 | } from '@vue-storefront/core'; 6 | import type { 7 | CustomerOrder, 8 | useUserOrderSearchParams as SearchParams 9 | } from '../types'; 10 | import { useUser } from '../useUser'; 11 | 12 | const params: UseUserOrderFactoryParams = { 13 | provide() { 14 | return useUser(); 15 | }, 16 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 17 | searchOrders: async (context: Context, params) => { 18 | console.log('Mocked: searchOrders'); 19 | params.input = {}; 20 | if (context.user.value?.id) { 21 | params.input.customerId = parseInt(context.user.value?.id); 22 | } 23 | const orderListResults = await context.$bagisto.api.getOrderList(params); 24 | 25 | return { 26 | results: orderListResults?.data?.ordersList?.data || null, 27 | pagination: orderListResults?.data?.ordersList?.paginatorInfo || null, 28 | total: orderListResults?.data?.ordersList?.paginatorInfo?.total || 0 29 | }; 30 | } 31 | }; 32 | 33 | export const useUserOrder = useUserOrderFactory(params); 34 | -------------------------------------------------------------------------------- /packages/api-client/src/api/getAddresses/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from "@apollo/client/core"; 3 | 4 | export async function getAddresses(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .query({ 9 | query: gql` 10 | query addresses { 11 | addresses { 12 | status 13 | message 14 | addresses { 15 | id 16 | customerId 17 | companyName 18 | firstName 19 | lastName 20 | address1 21 | address2 22 | country 23 | state 24 | city 25 | postcode 26 | phone 27 | vatId 28 | addressType 29 | defaultAddress 30 | createdAt 31 | updatedAt 32 | } 33 | } 34 | }` 35 | }); 36 | } catch (error) { 37 | console.log('Error getAddresses:'); 38 | console.log(error); 39 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/api-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue-storefront/bagisto-api", 3 | "version": "0.0.1", 4 | "private": true, 5 | "sideEffects": false, 6 | "server": "server/index.js", 7 | "main": "lib/index.cjs.js", 8 | "module": "lib/index.es.js", 9 | "types": "lib/index.d.ts", 10 | "scripts": { 11 | "build": "rimraf lib server && rollup -c", 12 | "dev": "rollup -c -w", 13 | "precommit": "lint-staged", 14 | "prepublish": "yarn build", 15 | "test": "jest", 16 | "update:check": "ncu", 17 | "update:update": "ncu -u" 18 | }, 19 | "dependencies": { 20 | "@apollo/client": "^3.5.6", 21 | "@vue-storefront/core": "~2.5.2", 22 | "apollo-cache-inmemory": "^1.6.6", 23 | "apollo-client": "^2.6.10", 24 | "apollo-link": "^1.2.14", 25 | "apollo-link-context": "^1.0.20", 26 | "apollo-link-http": "^1.5.17", 27 | "cross-fetch": "^3.1.4", 28 | "graphql": "^16.1.0", 29 | "graphql-tag": "^2.12.6", 30 | "react": "^17.0.2" 31 | }, 32 | "devDependencies": { 33 | "@rollup/plugin-node-resolve": "^13.0.6", 34 | "rollup-plugin-typescript2": "^0.30.0" 35 | }, 36 | "files": [ 37 | "lib/**/*" 38 | ], 39 | "publishConfig": { 40 | "access": "public" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/support/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | // *********************************************************** 3 | // This example support/index.js is processed and 4 | // loaded automatically before your test files. 5 | // 6 | // This is a great place to put global configuration and 7 | // behavior that modifies Cypress. 8 | // 9 | // You can change the location of this file or turn off 10 | // automatically serving support files with the 11 | // 'supportFile' configuration option. 12 | // 13 | // You can read more here: 14 | // https://on.cypress.io/configuration 15 | // *********************************************************** 16 | 17 | // Import commands.js using ES2015 syntax: 18 | import './commands.js'; 19 | import 'cypress-pipe'; 20 | 21 | // Alternatively you can use CommonJS syntax: 22 | // require('./commands') 23 | 24 | import addContext from 'mochawesome/addContext'; 25 | 26 | Cypress.on('test:after:run', (test, runnable) => { 27 | if (test.state === 'failed') { 28 | const screenshot = `assets/screenshots/${Cypress.spec.name}/${runnable.parent.title} -- ${test.title} (failed).png`; 29 | addContext({test}, { 30 | title: 'Screenshot', 31 | value: screenshot 32 | }); 33 | } 34 | }); 35 | 36 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Packages on NPM 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | npmTag: 6 | description: 'NPM Tag' 7 | required: true 8 | default: 'latest' 9 | jobs: 10 | publishing: 11 | name: Package Publishing 12 | runs-on: ubuntu-latest 13 | env: 14 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v2 18 | 19 | - name: Setup node 20 | uses: actions/setup-node@v2 21 | with: 22 | node-version: '14' 23 | registry-url: "https://registry.npmjs.org/" 24 | scope: "@vue-storefront" 25 | - run: echo "" >> .npmrc && echo "@vue-storefront:registry=https://registry.npmjs.org/" >> .npmrc 26 | - run: yarn 27 | env: 28 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 29 | - run: yarn build:api-client && yarn publish:api-client "${{ github.event.inputs.npmTag }}" "$NODE_AUTH_TOKEN" 30 | env: 31 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 32 | - run: yarn build:composables && yarn publish:composables "${{ github.event.inputs.npmTag }}" "$NODE_AUTH_TOKEN" 33 | env: 34 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 35 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vsf-integration-docs", 3 | "version": "0.0.1", 4 | "description": "Documentation for bagisto integration for Vue Storefront", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "repository": "https://github.com/vuestorefront/bagisto/docs", 8 | "scripts": { 9 | "dev": "vuepress dev", 10 | "build": "vuepress build", 11 | "api-extract": "yarn api-ref && yarn comp-ref && yarn ref-md", 12 | "api-ref": "cd ../packages/api-client && api-extractor run --local", 13 | "comp-ref": "cd ../packages/composables && api-extractor run --local", 14 | "ref-md": "api-documenter markdown --i api-reference --o api-reference" 15 | }, 16 | "devDependencies": { 17 | "@microsoft/api-documenter": "^7.13.65", 18 | "@microsoft/api-extractor": "^7.18.17", 19 | "@vue-storefront/commercetools-api": "~1.3.5", 20 | "@vuepress/plugin-active-header-links": "^1.8.2", 21 | "@vuepress/plugin-back-to-top": "^1.8.2", 22 | "@vuepress/plugin-medium-zoom": "^1.8.2", 23 | "@vuepress/plugin-search": "^1.8.2", 24 | "handlebars": "^4.7.7", 25 | "typescript": "~4.2", 26 | "vuepress": "^1.8.2" 27 | }, 28 | "dependencies": { 29 | "sass-loader": "^8.0.2", 30 | "vue-multiselect": "^2.1.6" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/api-client/src/api/getCustomer/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from "@apollo/client/core"; 3 | 4 | export async function getCustomer(context, customerToken) { 5 | 6 | try { 7 | return await context.client 8 | .query({ 9 | query: gql` 10 | query accountInfo { 11 | accountInfo { 12 | status 13 | message 14 | customer { 15 | id 16 | firstName 17 | lastName 18 | name 19 | gender 20 | dateOfBirth 21 | email 22 | phone 23 | password 24 | apiToken 25 | customerGroupId 26 | subscribedToNewsLetter 27 | isVerified 28 | token 29 | notes 30 | status 31 | createdAt 32 | updatedAt 33 | } 34 | } 35 | }` 36 | }); 37 | } catch (error) { 38 | console.log('Error getCustomer:'); 39 | console.log(error); 40 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/api-client/src/api/getShippingMethods/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from "@apollo/client/core"; 3 | 4 | export async function getShippingMethods(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .query({ 9 | query: gql` 10 | query shippingMethods { 11 | shippingMethods { 12 | success 13 | cartTotal 14 | cartCount 15 | shippingMethods { 16 | title 17 | methods { 18 | code 19 | label 20 | price 21 | formattedPrice 22 | basePrice 23 | formattedBasePrice 24 | } 25 | } 26 | paymentMethods { 27 | method 28 | method_title 29 | description 30 | sort 31 | } 32 | jumpToSection 33 | } 34 | }` 35 | }); 36 | } catch (error) { 37 | console.log('Error getShippingMethods:'); 38 | console.log(error); 39 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/api-client/src/api/removeAddress/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | 4 | export async function removeAddress(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .mutate({ 9 | mutation: gql` 10 | mutation deleteAddress ($id: ID!) { 11 | deleteAddress(id: $id) { 12 | status 13 | message 14 | addresses { 15 | id 16 | customerId 17 | companyName 18 | firstName 19 | lastName 20 | address1 21 | address2 22 | country 23 | state 24 | city 25 | postcode 26 | phone 27 | vatId 28 | addressType 29 | defaultAddress 30 | createdAt 31 | updatedAt 32 | } 33 | } 34 | }`, 35 | variables: { 36 | id: params?.id 37 | } 38 | }); 39 | } catch (error) { 40 | console.log('Error removeAddress:'); 41 | console.log(error); 42 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/api-client/README.md: -------------------------------------------------------------------------------- 1 |
2 |    3 |
4 | 5 | ## Vue Storefront 2 integration with bagisto 6 | 7 | ------ 8 | 9 | 10 | 11 | 12 | ## How to start if you want to try out the integration 13 | 14 | ``` 15 | yarn global add @vue-storefront/cli 16 | ``` 17 | ``` 18 | vsf init && cd && yarn && yarn dev 19 | ``` 20 | 21 | ## Resources 22 | 23 | - [Vue Storefront Documentation](https://docs.vuestorefront.io/v2/) 24 | - [bagisto integration Documentation](https://docs.vuestorefront.io/bagisto) 25 | - [Community Chat](https://discord.vuestorefront.io) 26 | 27 | ## Support 28 | 29 | If you have any questions about this integration we will be happy to answer them on `bagisto` channel on [our Discord](discord.vuestorefront.io). 30 | 31 | ## Contributors ✨ 32 | 33 | 34 | 35 | 36 | 37 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 38 | -------------------------------------------------------------------------------- /packages/composables/src/getters/categoryGetters.ts: -------------------------------------------------------------------------------- 1 | import { CategoryGetters, AgnosticCategoryTree, AgnosticBreadcrumb } from '@vue-storefront/core'; 2 | import { useRoute } from '@nuxtjs/composition-api'; 3 | import type { Category } from '@vue-storefront/bagisto-api'; 4 | 5 | 6 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 7 | function getId(category: Category): string | null { 8 | if (!category) { 9 | return null; 10 | } 11 | return category?.id || null; 12 | } 13 | 14 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 15 | function getTree(category: Category): AgnosticCategoryTree { 16 | 17 | return { 18 | label: '', 19 | slug: '', 20 | items: [], 21 | isCurrent: false 22 | }; 23 | } 24 | 25 | function getBreadcrumbs(category: Category): AgnosticBreadcrumb[] { 26 | const breadcrumbs = []; 27 | if (!category) { 28 | return []; 29 | } 30 | 31 | breadcrumbs.push({ text: 'Home', link: '/' }); 32 | if (category?.breadcrumbs) { 33 | for (const [key, value] of Object.entries(category?.breadcrumbs)) { 34 | breadcrumbs.push({ 35 | text: value.name, 36 | link: `/category/${value.urlPath || value.slug}` 37 | } as AgnosticBreadcrumb); 38 | } 39 | } 40 | 41 | return breadcrumbs; 42 | } 43 | 44 | export const categoryGetters: CategoryGetters = { 45 | getTree, 46 | getBreadcrumbs, 47 | getId 48 | }; 49 | -------------------------------------------------------------------------------- /packages/theme/tests/e2e/integration/e2e-place-order.spec.ts: -------------------------------------------------------------------------------- 1 | import page from '../pages/factory'; 2 | 3 | context('Order placement', () => { 4 | beforeEach(function () { 5 | cy.fixture('test-data/e2e-place-order').then((fixture) => { 6 | this.fixtures = { 7 | data: fixture 8 | }; 9 | }); 10 | }); 11 | 12 | it(['happypath', 'regression'], 'Should successfully place an order', function () { 13 | const data = this.fixtures.data; 14 | page.home.visit(); 15 | page.home.header.categories.first().click(); 16 | page.category.products.first().click(); 17 | page.product.addToCartButton.click(); 18 | page.product.header.openCart(); 19 | page.cart.goToCheckoutButton.click(); 20 | page.checkout.shipping.heading.should('be.visible'); 21 | page.checkout.shipping.fillForm(data.customer); 22 | page.checkout.shipping.selectShippingButton.click(); 23 | page.checkout.shipping.shippingMethods.first().click(); 24 | page.checkout.shipping.continueToBillingButton.click(); 25 | page.checkout.billing.heading.should('be.visible'); 26 | page.checkout.billing.fillForm(data.customer); 27 | page.checkout.billing.continueToPaymentButton.click(); 28 | page.checkout.payment.paymentMethods.first().click(); 29 | page.checkout.payment.terms.click(); 30 | page.checkout.payment.makeAnOrderButton.click(); 31 | page.checkout.thankyou.heading.should('be.visible'); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/theme/composables/useUiNotification/index.ts: -------------------------------------------------------------------------------- 1 | import { computed, reactive } from '@nuxtjs/composition-api'; 2 | 3 | interface UiNotification { 4 | message: string; 5 | action: { text: string; onClick: (...args: any) => void }; 6 | type: 'danger' | 'success' | 'info'; 7 | icon: string; 8 | persist: boolean; 9 | id: symbol; 10 | dismiss: () => void; 11 | } 12 | 13 | interface Notifications { 14 | notifications: Array; 15 | } 16 | 17 | const state = reactive({ 18 | notifications: [] 19 | }); 20 | const maxVisibleNotifications = 3; 21 | const timeToLive = 3000; 22 | 23 | const useUiNotification = () => { 24 | const send = (notification: UiNotification) => { 25 | const id = Symbol(); 26 | 27 | const dismiss = () => { 28 | const index = state.notifications.findIndex(notification => notification.id === id); 29 | 30 | if (index !== -1) state.notifications.splice(index, 1); 31 | }; 32 | 33 | const newNotification = { 34 | ...notification, 35 | id, 36 | dismiss 37 | }; 38 | 39 | state.notifications.push(newNotification); 40 | if (state.notifications.length > maxVisibleNotifications) state.notifications.shift(); 41 | 42 | if (!notification.persist) { 43 | setTimeout(dismiss, timeToLive); 44 | } 45 | }; 46 | 47 | return { 48 | send, 49 | notifications: computed(() => state.notifications) 50 | }; 51 | }; 52 | 53 | export default useUiNotification; 54 | -------------------------------------------------------------------------------- /packages/theme/static/icons/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/theme/components/UserAddress.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 41 | -------------------------------------------------------------------------------- /packages/composables/README.md: -------------------------------------------------------------------------------- 1 |
2 |    3 |

4 | Bagisto 5 |

6 | 7 | ## Vue Storefront 2 integration with bagisto 8 | 9 | ------ 10 | 11 | 12 | 13 | 14 | 15 | ## How to start if you want to try out the integration 16 | 17 | ``` 18 | yarn global add @vue-storefront/cli 19 | ``` 20 | ``` 21 | vsf init && cd && yarn && yarn dev 22 | ``` 23 | 24 | ## Resources 25 | 26 | - [Vue Storefront Documentation](https://docs.vuestorefront.io/v2/) 27 | - [Bagisto Documentation](https://devdocs.bagisto.com/) 28 | - [GraphQL/Headless-Commerce Documentation](https://devdocs.bagisto.com/1.x/graphql-shop-api/) 29 | - [Forum Support](https://forums.bagisto.com/) 30 | 31 | ## Support 32 | 33 | If you have any questions about this integration we will be happy to answer them on [bagisto support](mailto:support@bagisto.com). 34 | 35 | ## Contributors ✨ 36 | 37 | 38 | 39 | 40 | 41 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 42 | -------------------------------------------------------------------------------- /packages/composables/src/useUserBilling/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useUserBillingFactory, 4 | UseUserBillingFactoryParams 5 | } from '@vue-storefront/core'; 6 | import type { 7 | UserBillingAddress as Address, 8 | UserBillingAddressItem as AddressItem 9 | } from '@vue-storefront/bagisto-api'; 10 | 11 | const params: UseUserBillingFactoryParams = { 12 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 13 | addAddress: async (context: Context, params) => { 14 | console.log('Mocked: useUserBilling.addAddress'); 15 | return {}; 16 | }, 17 | 18 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 19 | deleteAddress: async (context: Context, params) => { 20 | console.log('Mocked: useUserBilling.deleteAddress'); 21 | return {}; 22 | }, 23 | 24 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 25 | updateAddress: async (context: Context, params) => { 26 | console.log('Mocked: useUserBilling.updateAddress'); 27 | return {}; 28 | }, 29 | 30 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 31 | load: async (context: Context, params) => { 32 | console.log('Mocked: useUserBilling.load'); 33 | return {}; 34 | }, 35 | 36 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 37 | setDefaultAddress: async (context: Context, params) => { 38 | console.log('Mocked: useUserBilling.setDefaultAddress'); 39 | return {}; 40 | } 41 | }; 42 | 43 | export const useUserBilling = useUserBillingFactory(params); 44 | -------------------------------------------------------------------------------- /packages/composables/src/useMakeOrder/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useMakeOrderFactory, 4 | UseMakeOrderFactoryParams 5 | } from '@vue-storefront/core'; 6 | import type { Order } from '@vue-storefront/bagisto-api'; 7 | import { useCart } from '../useCart'; 8 | 9 | const factoryParams: UseMakeOrderFactoryParams = { 10 | provide() { 11 | return { 12 | cart: useCart(), 13 | }; 14 | }, 15 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 16 | make: async (context: Context, { customQuery }) => { 17 | console.log('Mocked: useMakeOrder.make'); 18 | 19 | const shippingAddress = context?.cart?.cart.value?.shippingAddress; 20 | const billingAddress = context?.cart?.cart.value?.billingAddress; 21 | const shippingRate = context?.cart?.cart.value?.selectedShippingRate; 22 | const paymentMethod = context?.cart?.cart.value?.payment?.method; 23 | if (shippingAddress && billingAddress && shippingRate && paymentMethod) { 24 | const orderResults = await context.$bagisto.api.makeOrder(); 25 | 26 | if (!orderResults?.data) { 27 | await context.cart.setCart(null); 28 | await context.cart.load(); 29 | } 30 | 31 | const orderResponse = orderResults?.data?.placeOrder; 32 | 33 | if (!orderResponse?.redirectUrl && orderResponse?.success) { 34 | context.cart.setCart(null); 35 | } 36 | 37 | return orderResponse?.order || null; 38 | } 39 | 40 | return null; 41 | } 42 | }; 43 | 44 | export const useMakeOrder = useMakeOrderFactory(factoryParams); 45 | -------------------------------------------------------------------------------- /packages/composables/src/useReview/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useReviewFactory, 4 | UseReviewFactoryParams 5 | } from '@vue-storefront/core'; 6 | import type { Review } from '@vue-storefront/bagisto-api'; 7 | import type { 8 | UseReviewSearchParams as SearchParams, 9 | UseReviewAddParams as AddParams 10 | } from '../types'; 11 | 12 | const params: UseReviewFactoryParams = { 13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 14 | searchReviews: async (context: Context, params) => { 15 | console.log('Mocked: useReview.searchReviews'); 16 | switch (params.type) { 17 | case 'search': 18 | const productReviewResults = await context.$bagisto.api.searchReviews(params); 19 | 20 | return { 21 | reviews: productReviewResults?.data?.reviewsList?.data || null, 22 | pagination: productReviewResults?.data?.reviewsList?.paginatorInfo || null 23 | }; 24 | break; 25 | case 'remove': 26 | const removeResults = await context.$bagisto.api.removeReview(params?.review); 27 | 28 | return removeResults?.data?.deleteReview; 29 | break; 30 | } 31 | }, 32 | 33 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 34 | addReview: async (context: Context, params: AddParams) => { 35 | console.log('Mocked: useReview.addReview'); 36 | const createReviewResults = await context.$bagisto.api.createProductReview(params); 37 | 38 | return createReviewResults?.data?.createReview?.success || null; 39 | } 40 | }; 41 | 42 | export const useReview = useReviewFactory(params); 43 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to @vuestorefront/bagisto 2 | We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: 3 | 4 | - Reporting a bug 5 | - Discussing the current state of the code 6 | - Submitting a fix 7 | - Proposing new features 8 | - Becoming a maintainer 9 | 10 | ## We Develop with Github 11 | We use github to host code, to track issues and feature requests, as well as accept pull requests. 12 | 13 | ## Any contributions you make will be under the MIT Software License 14 | In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern. 15 | 16 | ## Report bugs using Github's [issues](https://github.com/vuestorefront/bagisto/issues) 17 | We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/vuestorefront/bagisto/issues/new); it's that easy! 18 | 19 | ## Write bug reports with detail, background, and sample code 20 | **Great Bug Reports** tend to have: 21 | 22 | - A quick summary and/or background 23 | - Steps to reproduce 24 | - Be specific! 25 | - Give sample code if you can. 26 | - What you expected would happen 27 | - What actually happens 28 | - The environment you're running the application 29 | - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) 30 | 31 | People *love* thorough bug reports. I'm not even kidding. 32 | 33 | ## License 34 | By contributing, you agree that your contributions will be licensed under its MIT License. 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3.feature-request.yml: -------------------------------------------------------------------------------- 1 | name: "🚀 Feature Request" 2 | description: Sugest a new feature request or improvement on the project 3 | title: '[Feature]: ' 4 | labels: 5 | - feature 6 | - enhancement 7 | - triage-needed 8 | 9 | body: 10 | - type: markdown 11 | attributes: 12 | value: | 13 | Please, provide as many information, and knowledge so the feature can be correctly designed and developed. 14 | - type: textarea 15 | id: suggestion 16 | attributes: 17 | label: How the project can be improved? 18 | description: What is the motivation for adding / enhancing this feature? Can you describe a concrete use case for this feature or why one of current ones should be enhanced. 19 | placeholder: Describe the motivation or the concrete use case 20 | validations: 21 | required: true 22 | - type: textarea 23 | id: acceptcriterea 24 | attributes: 25 | label: What are the acceptance criteria? 26 | description: List the acceptance criteria for this task in a form of a list. 27 | value: '- [ ]' 28 | - type: textarea 29 | id: additionalinfo 30 | attributes: 31 | label: Additional information 32 | description: If you think that any additional information would be useful please provide them here. 33 | - type: checkboxes 34 | id: terms 35 | attributes: 36 | label: Code of Conduct 37 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/vuestorefront/bagisto/blob/master/CODE_OF_CONDUCT.md) 38 | options: 39 | - label: I agree to follow this project's Code of Conduct 40 | required: true 41 | -------------------------------------------------------------------------------- /packages/composables/src/useProduct/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useProductFactory, 4 | UseProductFactoryParams 5 | } from '@vue-storefront/core'; 6 | import type { Product } from '@vue-storefront/bagisto-api'; 7 | import type { 8 | UseProductSearchParams as SearchParams 9 | } from '../types'; 10 | 11 | const params: UseProductFactoryParams = { 12 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 13 | productsSearch: async (context: Context, params) => { 14 | switch (params.typeListing) { 15 | case 'productDetail': 16 | console.log('Mocked: useProduct.getProductDetail'); 17 | const productDetailResults = await context.$bagisto.api.getProductDetail(params); 18 | 19 | return productDetailResults?.data?.product || {}; 20 | case 'newProduct': 21 | console.log('Mocked: useProduct.getNewProduct'); 22 | const newProductResults = await context.$bagisto.api.getNewProduct(params); 23 | 24 | return newProductResults?.data?.newProducts || []; 25 | case 'featuredProduct': 26 | console.log('Mocked: useProduct.getFeaturedProduct'); 27 | const featuredProductResults = await context.$bagisto.api.getFeaturedProduct(params); 28 | 29 | return featuredProductResults?.data?.featuredProducts || []; 30 | case 'relatedProduct': 31 | console.log('Mocked: useProduct.getRelatedProduct'); 32 | const relatedProductResults = await context.$bagisto.api.getRelatedProduct(params); 33 | 34 | return relatedProductResults?.data?.relatedProducts || []; 35 | } 36 | } 37 | }; 38 | 39 | export const useProduct = useProductFactory(params); 40 | -------------------------------------------------------------------------------- /packages/composables/src/index.ts: -------------------------------------------------------------------------------- 1 | // Composables 2 | export { useBilling } from './useBilling'; 3 | export { useCart } from './useCart'; 4 | export { useCategory } from './useCategory'; 5 | export { useContent } from './useContent'; 6 | export { useFacet } from './useFacet'; 7 | export { useForgotPassword } from './useForgotPassword'; 8 | export { useMakeOrder } from './useMakeOrder'; 9 | export { useProduct } from './useProduct'; 10 | export { useReview } from './useReview'; 11 | export { useShipping } from './useShipping'; 12 | export { useShippingProvider } from './useShippingProvider'; 13 | export { useStore } from './useStore'; 14 | export { useUser } from './useUser'; 15 | export { useUserBilling } from './useUserBilling'; 16 | export { useUserOrder } from './useUserOrder'; 17 | export { useUserShipping } from './useUserShipping'; 18 | export { useWishlist } from './useWishlist'; 19 | 20 | // Getters 21 | export { cartGetters } from './getters/cartGetters'; 22 | export { categoryGetters } from './getters/categoryGetters'; 23 | export { facetGetters } from './getters/facetGetters'; 24 | export { forgotPasswordGetters } from './getters/forgotPasswordGetters'; 25 | export { orderGetters } from './getters/orderGetters'; 26 | export { productGetters } from './getters/productGetters'; 27 | export { reviewGetters } from './getters/reviewGetters'; 28 | export { storeGetters } from './getters/storeGetters'; 29 | export { userBillingGetters } from './getters/userBillingGetters'; 30 | export { userGetters } from './getters/userGetters'; 31 | export { userShippingGetters } from './getters/userShippingGetters'; 32 | export { wishlistGetters } from './getters/wishlistGetters'; 33 | 34 | // Types 35 | export * from './types'; 36 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Related Issue 7 | 8 | 9 | 10 | 11 | 12 | ## Motivation and Context 13 | 14 | 15 | ## How Has This Been Tested? 16 | 17 | 18 | 19 | 20 | ## Screenshots (if appropriate): 21 | 22 | ## Types of changes 23 | 24 | - [ ] Bug fix (non-breaking change which fixes an issue) 25 | - [ ] New feature (non-breaking change which adds functionality) 26 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 27 | 28 | ## Checklist: 29 | 30 | 31 | - [ ] My code follows the code style of this project. 32 | - [ ] My change requires a change to the documentation. 33 | - [ ] I have updated the documentation accordingly. 34 | - [ ] I have read the **CONTRIBUTING** document. 35 | - [ ] I have added tests to cover my changes. 36 | - [ ] All new and existing tests passed. 37 | -------------------------------------------------------------------------------- /packages/theme/layouts/blank.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 24 | 25 | 88 | -------------------------------------------------------------------------------- /packages/api-client/src/api/customerLogin/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | import { LoginInput } from '../../types'; 4 | 5 | type Variables = { 6 | input?: LoginInput; 7 | }; 8 | 9 | export async function customerLogin(context, params) { 10 | const inputFilters = { 11 | email: params?.email, 12 | password: params?.password, 13 | remember: params?.remember || false 14 | }; 15 | 16 | const variables: Variables = { 17 | input: inputFilters 18 | }; 19 | 20 | try { 21 | return await context.client 22 | .mutate({ 23 | mutation: gql` 24 | mutation customerLogin ($input: LoginInput!) { 25 | customerLogin(input: $input) { 26 | status 27 | success 28 | accessToken 29 | tokenType 30 | expiresIn 31 | customer { 32 | id 33 | firstName 34 | lastName 35 | name 36 | gender 37 | dateOfBirth 38 | email 39 | phone 40 | password 41 | apiToken 42 | customerGroupId 43 | subscribedToNewsLetter 44 | isVerified 45 | token 46 | notes 47 | status 48 | createdAt 49 | updatedAt 50 | } 51 | } 52 | }`, 53 | variables: variables 54 | }); 55 | } catch (error) { 56 | console.log('Error customerLogin:'); 57 | console.log(error); 58 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue-storefront/bagisto-theme", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "build": "nuxt build -m", 7 | "build:analyze": "nuxt build -a -m", 8 | "dev": "nuxt", 9 | "generate": "nuxt generate", 10 | "lint": "eslint . --ext .ts,.vue", 11 | "lint:fix": "eslint . --ext .ts,.vue --fix", 12 | "precommit": "lint-staged", 13 | "start": "nuxt start", 14 | "test": "jest", 15 | "test:e2e": "cypress open --config-file tests/e2e/cypress.json", 16 | "test:e2e:generate:report": "yarn -s mochawesome-merge \"tests/e2e/report/*.json\" > \"tests/e2e/report.json\" && yarn -s marge tests/e2e/report.json -o \"tests/e2e/report\"", 17 | "test:e2e:hl": "cypress run --headless --config-file tests/e2e/cypress.json", 18 | "update:check": "ncu", 19 | "update:update": "ncu -u" 20 | }, 21 | "dependencies": { 22 | "@storefront-ui/vue": "0.11.1", 23 | "@vue-storefront/bagisto": "0.0.1", 24 | "@vue-storefront/middleware": "~2.5.2", 25 | "@vue-storefront/nuxt": "~2.5.2", 26 | "@vue-storefront/nuxt-theme": "~2.5.2", 27 | "cookie-universal-nuxt": "^2.1.5", 28 | "core-js": "^3.19.0", 29 | "nuxt": "^2.15.8", 30 | "nuxt-i18n": "^6.5.0", 31 | "vee-validate": "^3.4.13", 32 | "vue-scrollto": "^2.20.0", 33 | "vuejs-datepicker": "^1.6.2" 34 | }, 35 | "devDependencies": { 36 | "@nuxt/types": "^2.15.8", 37 | "@vue/test-utils": "^1.2.2", 38 | "babel-jest": "^27.3.1", 39 | "cypress": "^8.7.0", 40 | "cypress-pipe": "^2.0.0", 41 | "cypress-tags": "^0.3.0", 42 | "jest": "^27.3.1", 43 | "mochawesome": "^6.3.1", 44 | "mochawesome-merge": "^4.2.0", 45 | "mochawesome-report-generator": "^5.2.0", 46 | "vue-jest": "^4.0.0-0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/api-client/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export { getNewProduct } from './getNewProduct'; 2 | export { getFeaturedProduct } from './getFeaturedProduct'; 3 | export { getRelatedProduct } from './getRelatedProduct'; 4 | export { getCategories } from './getCategories'; 5 | export { getCategoryTree } from './getCategoryTree'; 6 | export { getProductDetail } from './getProductDetail'; 7 | export { getProductList } from './getProductList'; 8 | export { searchReviews } from './searchReviews'; 9 | export { createProductReview } from './createProductReview'; 10 | export { removeReview } from './removeReview'; 11 | export { createCustomer } from './createCustomer'; 12 | export { customerLogin } from './customerLogin'; 13 | export { getCustomer } from './getCustomer'; 14 | export { customerUpdate } from './customerUpdate'; 15 | export { customerLogout } from './customerLogout'; 16 | export { customerResetPassword } from './customerResetPassword'; 17 | export { createAddress } from './createAddress'; 18 | export { updateAddress } from './updateAddress'; 19 | export { removeAddress } from './removeAddress'; 20 | export { getAddresses } from './getAddresses'; 21 | export { addToCart } from './addToCart'; 22 | export { getCart } from './getCart'; 23 | export { removeFromCart } from './removeFromCart'; 24 | export { updateToCart } from './updateToCart'; 25 | export { saveShippingAddress } from './saveShippingAddress'; 26 | export { getShippingMethods } from './getShippingMethods'; 27 | export { saveShippingMethod } from './saveShippingMethod'; 28 | export { savePaymentMethod } from './savePaymentMethod'; 29 | export { makeOrder } from './makeOrder'; 30 | export { getOrderList } from './getOrderList'; 31 | export { getWishlist } from './getWishlist'; 32 | export { removeFromWishlist } from './removeFromWishlist'; 33 | export { addToWishlist } from './addToWishlist'; 34 | -------------------------------------------------------------------------------- /packages/theme/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # theme 72 | _theme 73 | 74 | # Nuxt generate 75 | dist 76 | 77 | # vuepress build output 78 | .vuepress/dist 79 | 80 | # Serverless directories 81 | .serverless 82 | 83 | # IDE / Editor 84 | .idea 85 | 86 | # Service worker 87 | sw.* 88 | 89 | # Mac OSX 90 | .DS_Store 91 | 92 | # Vim swap files 93 | *.swp 94 | 95 | version 96 | 97 | # e2e reports 98 | tests/e2e/report.json 99 | tests/e2e/report 100 | -------------------------------------------------------------------------------- /packages/api-client/src/api/removeReview/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | 4 | export async function removeReview(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .mutate({ 9 | mutation: gql` 10 | mutation deleteReview ($id: ID!) { 11 | deleteReview (id: $id) { 12 | status 13 | message 14 | reviews { 15 | id 16 | title 17 | rating 18 | comment 19 | status 20 | productId 21 | customerId 22 | customerName 23 | product { 24 | id 25 | type 26 | attributeFamilyId 27 | sku 28 | parentId 29 | createdAt 30 | updatedAt 31 | productFlats { 32 | id 33 | sku 34 | name 35 | description 36 | shortDescription 37 | urlKey 38 | locale 39 | } 40 | cacheBaseImage { 41 | smallImageUrl 42 | mediumImageUrl 43 | largeImageUrl 44 | originalImageUrl 45 | } 46 | } 47 | createdAt 48 | updatedAt 49 | } 50 | } 51 | }`, 52 | variables: { 53 | id: params?.id 54 | } 55 | }); 56 | } catch (error) { 57 | console.log('Error removeReview:'); 58 | console.log(error); 59 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/composables/src/useFacet/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useFacetFactory, 4 | FacetSearchResult 5 | } from '@vue-storefront/core'; 6 | import type { 7 | UseFacetSearchParams as SearchParams 8 | } from '../types'; 9 | 10 | const sortingOptions = [ 11 | { 12 | attrName: 'Default', 13 | value: '' 14 | }, { 15 | attrName: 'Name A-Z', 16 | value: '?sort=name&order=asc' 17 | }, { 18 | attrName: 'Name Z-A', 19 | value: '?sort=name&order=desc' 20 | }, { 21 | attrName: 'Newest First', 22 | value: '?sort=created_at&order=desc' 23 | }, { 24 | attrName: 'Oldest First', 25 | value: '?sort=created_at&order=asc' 26 | }, { 27 | attrName: 'Price Low to High', 28 | value: '?sort=price&order=asc' 29 | }, { 30 | attrName: 'Price High to Low', 31 | value: '?sort=price&order=desc' 32 | } 33 | ]; 34 | 35 | const factoryParams = { 36 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 37 | search: async (context: Context, params: FacetSearchResult) => { 38 | console.log('Mocked: useFacet.search'); 39 | const productListResults = await context.$bagisto.api.getProductList(params); 40 | 41 | let categoryResult = null; 42 | if (params.input.categorySlug) { 43 | 44 | const categoryParams = { 45 | slug: params.input.categorySlug 46 | }; 47 | categoryResult = await context.$bagisto.api.getCategories(categoryParams); 48 | } 49 | 50 | return { 51 | items: productListResults?.data?.getProductListing?.data || [], 52 | categoryDetail: categoryResult || [], 53 | pagination: productListResults?.data?.getProductListing?.paginatorInfo || {}, 54 | filterableAttributes: categoryResult ? categoryResult?.data?.categories?.data?.[0]?.filterableAttributes : [], 55 | sortingData: sortingOptions 56 | }; 57 | } 58 | }; 59 | 60 | export const useFacet = useFacetFactory(factoryParams); 61 | -------------------------------------------------------------------------------- /packages/composables/src/useShipping/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useShippingFactory, 4 | UseShippingParams 5 | } from '@vue-storefront/core'; 6 | import type { ShippingAddress } from '@vue-storefront/bagisto-api'; 7 | import type { 8 | UseShippingAddParams as AddParams 9 | } from '../types'; 10 | import { useCart } from '../useCart'; 11 | 12 | const params: UseShippingParams = { 13 | provide() { 14 | return { 15 | cart: useCart() 16 | }; 17 | }, 18 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 19 | load: async (context: Context, { customQuery }) => { 20 | console.log('Mocked: useShipping.load'); 21 | if (!context?.cart?.cart.value?.shippingAddress) { 22 | await context.cart.load(); 23 | } 24 | 25 | return context?.cart.value?.shippingAddress || {}; 26 | }, 27 | 28 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 29 | save: async (context: Context, { shippingDetails, customQuery }) => { 30 | console.log('Mocked: useShipping.save'); 31 | const params = { 32 | type: 'shipping', 33 | shipping: shippingDetails, 34 | billing: shippingDetails, 35 | shippingAddressId: parseInt(customQuery?.shippingAddressId) || 0, 36 | billingAddressId: parseInt(customQuery?.shippingAddressId) || 0 37 | }; 38 | 39 | const saveShippingResults = await context.$bagisto.api.saveShippingAddress(params); 40 | 41 | if (!saveShippingResults?.data) { 42 | await context?.cart.setCart(null); 43 | await context.cart.load(); 44 | } 45 | 46 | const shippingResponse = saveShippingResults?.data?.saveCheckoutAddresses; 47 | 48 | if (shippingResponse?.cart) { 49 | await context?.cart.setCart(shippingResponse?.cart); 50 | await context.cart.load(); 51 | } 52 | 53 | return shippingResponse ? context?.cart.value?.shippingAddress : {}; 54 | } 55 | }; 56 | 57 | export const useShipping = useShippingFactory(params); 58 | -------------------------------------------------------------------------------- /packages/api-client/src/helpers/bagistoLink/graphQl.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/restrict-template-expressions */ 2 | import ApolloClient from 'apollo-client'; 3 | import fetch from 'cross-fetch'; 4 | import { ApolloLink } from 'apollo-link'; 5 | import { createHttpLink } from 'apollo-link-http'; 6 | import { InMemoryCache } from 'apollo-cache-inmemory'; 7 | import { setContext } from 'apollo-link-context'; 8 | import { Config } from '../../types/setup'; 9 | 10 | export const apolloLinkFactory = (settings: Config, handlers?: { 11 | apolloLink?: ApolloLink; 12 | }) => { 13 | const baseLink = handlers?.apolloLink || setContext((apolloReq, { headers }) => ({ 14 | headers: { 15 | ...headers, 16 | }, 17 | })); 18 | 19 | const httpLink = createHttpLink({ 20 | uri: `https://${settings.api.domain}/graphql`, 21 | credentials: 'include', 22 | fetch, 23 | ...settings.customApolloHttpLinkOptions 24 | }); 25 | 26 | // our custom "afterware" that checks each response and saves the sessionID 27 | // if it contains an 'Authorization' header 28 | const afterwareLink = new ApolloLink((operation, forward) => { 29 | return forward(operation).map(response => { 30 | const context = operation.getContext(); 31 | const authHeader = context.response.headers.get('Set-Cookie'); 32 | if (authHeader && authHeader.includes('bagisto_session=')) { 33 | const getBagistoSession = authHeader.split(';'); 34 | const bagistoSession = getBagistoSession[0].replace(' ', ''); 35 | settings.state.setGuestToken(bagistoSession); 36 | } 37 | 38 | return response; 39 | }); 40 | }); 41 | 42 | return ApolloLink.from([ 43 | baseLink.concat(afterwareLink).concat(httpLink) 44 | ]); 45 | }; 46 | 47 | export const apolloClientFactory = (customOptions: Record) => { 48 | 49 | return new ApolloClient({ 50 | cache: new InMemoryCache(), 51 | queryDeduplication: true, 52 | ssrMode: true, 53 | ...customOptions 54 | }); 55 | }; 56 | -------------------------------------------------------------------------------- /packages/api-client/src/api/customerUpdate/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | import { UpdateAccountInput } from '../../types'; 4 | 5 | type Variables = { 6 | input?: UpdateAccountInput; 7 | }; 8 | 9 | export async function customerUpdate(context, params) { 10 | const inputFilters = { 11 | firstName: params?.firstName, 12 | lastName: params?.lastName, 13 | email: params?.email, 14 | gender: params?.gender, 15 | phone: params?.phone, 16 | dateOfBirth: params?.dateOfBirth 17 | }; 18 | 19 | const variables: Variables = { 20 | input: inputFilters 21 | }; 22 | 23 | if (params.oldpassword) { 24 | variables.input.oldpassword = params.oldpassword; 25 | variables.input.password = params.password; 26 | variables.input.passwordConfirmation = params.confirmPassword; 27 | } 28 | 29 | try { 30 | return await context.client 31 | .mutate({ 32 | mutation: gql` 33 | mutation updateAccount ($input: UpdateAccountInput!) { 34 | updateAccount(input: $input) { 35 | status 36 | message 37 | customer { 38 | id 39 | firstName 40 | lastName 41 | name 42 | gender 43 | dateOfBirth 44 | email 45 | phone 46 | password 47 | apiToken 48 | customerGroupId 49 | subscribedToNewsLetter 50 | isVerified 51 | token 52 | notes 53 | status 54 | createdAt 55 | updatedAt 56 | } 57 | } 58 | }`, 59 | variables: variables 60 | }); 61 | } catch (error) { 62 | console.log('Error customerUpdate:'); 63 | console.log(error); 64 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/theme/README.md: -------------------------------------------------------------------------------- 1 | # Vue Storefront 2 2 | 3 | ## Build Setup 4 | 5 | ```bash 6 | # install dependencies 7 | $ yarn install 8 | 9 | # serve with hot reload at localhost:3000 10 | $ yarn dev 11 | 12 | # build for production and launch server 13 | $ yarn build 14 | $ yarn start 15 | ``` 16 | 17 | For detailed explanation on how things work, check out the [documentation](https://docs.vuestorefront.io/v2/). 18 | 19 | ## Special Directories 20 | 21 | You can create the following extra directories, some of which have special behaviors. Only `pages` is required; you can delete them if you don't want to use their functionality. 22 | 23 | ### `assets` 24 | 25 | The assets directory contains your uncompiled assets such as Stylus or Sass files, images, or fonts. 26 | 27 | ### `components` 28 | 29 | The components directory contains your Vue.js components. Components make up the different parts of your page and can be reused and imported into your pages, layouts and even other components. 30 | 31 | ### `layouts` 32 | 33 | Layouts are a great help when you want to change the look and feel of your Nuxt app, whether you want to include a sidebar or have distinct layouts for mobile and desktop. 34 | 35 | ### `pages` 36 | 37 | This directory contains your application views and routes. Nuxt will read all the `*.vue` files inside this directory and setup Vue Router automatically. 38 | 39 | ### `plugins` 40 | 41 | The plugins directory contains JavaScript plugins that you want to run before instantiating the root Vue.js Application. This is the place to add Vue plugins and to inject functions or constants. Every time you need to use `Vue.use()`, you should create a file in `plugins/` and add its path to plugins in `nuxt.config.js`. 42 | 43 | ### `static` 44 | 45 | This directory contains your static files. Each file inside this directory is mapped to `/`. 46 | 47 | Example: `/static/robots.txt` is mapped as `/robots.txt`. 48 | 49 | ### `store` 50 | 51 | This directory contains your Vuex store files. Creating a file in this directory automatically activates Vuex. 52 | -------------------------------------------------------------------------------- /packages/api-client/src/api/createAddress/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | import { CreateAddressInput } from '../../types'; 4 | 5 | type Variables = { 6 | input: CreateAddressInput; 7 | }; 8 | 9 | export async function createAddress(context, params) { 10 | const inputFilters = { 11 | companyName: params?.value?.companyName, 12 | firstName: params?.value?.firstName, 13 | lastName: params?.value?.lastName, 14 | address1: params?.value?.address1, 15 | address2: params?.value?.address2, 16 | country: params?.value?.country, 17 | state: params?.value?.state, 18 | city: params?.value?.city, 19 | postcode: params?.value?.postcode, 20 | phone: params?.value?.phone, 21 | vatId: params?.value?.vatId 22 | }; 23 | 24 | const variables: Variables = { 25 | input: inputFilters 26 | }; 27 | 28 | if (params?.value?.defaultAddress) { 29 | variables.input.defaultAddress = params?.value?.defaultAddress; 30 | } 31 | 32 | try { 33 | return await context.client 34 | .mutate({ 35 | mutation: gql` 36 | mutation createAddress ($input: CreateAddressInput!) { 37 | createAddress(input: $input) { 38 | status 39 | message 40 | addresses { 41 | id 42 | customerId 43 | companyName 44 | firstName 45 | lastName 46 | address1 47 | address2 48 | country 49 | state 50 | city 51 | postcode 52 | phone 53 | vatId 54 | addressType 55 | defaultAddress 56 | createdAt 57 | updatedAt 58 | } 59 | } 60 | }`, 61 | variables: variables 62 | }); 63 | } catch (error) { 64 | console.log('Error createAddress:'); 65 | console.log(error); 66 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/api-client/src/api/updateAddress/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | import { UpdateAddressInput } from '../../types'; 4 | 5 | type Variables = { 6 | id: null, 7 | input: UpdateAddressInput; 8 | }; 9 | 10 | export async function updateAddress(context, params) { 11 | const inputFilters = { 12 | companyName: params?.value?.companyName, 13 | firstName: params?.value?.firstName, 14 | lastName: params?.value?.lastName, 15 | address1: params?.value?.address1, 16 | address2: params?.value?.address2, 17 | country: params?.value?.country, 18 | state: params?.value?.state, 19 | city: params?.value?.city, 20 | postcode: params?.value?.postcode, 21 | phone: params?.value?.phone, 22 | vatId: params?.value?.vatId 23 | }; 24 | 25 | const variables: Variables = { 26 | id: params?.value?.id, 27 | input: inputFilters 28 | }; 29 | 30 | if (params?.value?.defaultAddress) { 31 | variables.input.defaultAddress = params?.value?.defaultAddress; 32 | } 33 | 34 | try { 35 | return await context.client 36 | .mutate({ 37 | mutation: gql` 38 | mutation updateAddress ($id: ID!, $input: UpdateAddressInput!) { 39 | updateAddress(id: $id, input: $input) { 40 | status 41 | message 42 | addresses { 43 | id 44 | customerId 45 | companyName 46 | firstName 47 | lastName 48 | address1 49 | address2 50 | country 51 | state 52 | city 53 | postcode 54 | phone 55 | vatId 56 | addressType 57 | defaultAddress 58 | createdAt 59 | updatedAt 60 | } 61 | } 62 | }`, 63 | variables: variables 64 | }); 65 | } catch (error) { 66 | console.log('Error updateAddress:'); 67 | console.log(error); 68 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/api-client/src/index.server.ts: -------------------------------------------------------------------------------- 1 | import { apiClientFactory, ApiClientExtension } from '@vue-storefront/core'; 2 | import type { Setttings, Endpoints } from './types'; 3 | 4 | import * as api from './api'; 5 | 6 | import { ClientInstance, Config } from './types/setup'; 7 | import { createBagistoConnection } from './helpers/bagistoLink'; 8 | import { defaultSettings } from './helpers/apiClient/defaultSettings'; 9 | import { apolloClientFactory } from './helpers/bagistoLink/graphQl'; 10 | 11 | const onCreate = (settings: Config): { config: Config; client: ClientInstance } => { 12 | 13 | const config = { 14 | ...defaultSettings, 15 | ...settings, 16 | state: settings.state || defaultSettings.state 17 | } as unknown as Config; 18 | 19 | const { apolloLink } = createBagistoConnection(config); 20 | 21 | const client = apolloClientFactory({ 22 | link: apolloLink 23 | }); 24 | 25 | return { 26 | config, 27 | client 28 | }; 29 | }; 30 | 31 | const tokenExtension: ApiClientExtension = { 32 | name: 'tokenExtension', 33 | hooks: (req, res) => ({ 34 | beforeCreate: ({ configuration }) => { 35 | return { 36 | ...configuration, 37 | state: { 38 | getCustomerToken: () => req.cookies['vsf-bagCust-token'], 39 | setCustomerToken: (token) => { 40 | if (!token) { 41 | // eslint-disable-next-line no-param-reassign 42 | delete req.cookies['vsf-bagCust-token']; 43 | return; 44 | } 45 | res.cookie('vsf-bagCust-token', JSON.stringify(token)); 46 | }, 47 | getGuestToken: () => req.cookies['bagisto_session'], 48 | setGuestToken: (token) => { 49 | if (!token) { 50 | // eslint-disable-next-line no-param-reassign 51 | delete req.cookies['bagisto_session']; 52 | return; 53 | } 54 | res.cookie('bagisto_session', token); 55 | } 56 | } 57 | }; 58 | } 59 | }) 60 | }; 61 | 62 | const { createApiClient } = apiClientFactory({ 63 | onCreate, 64 | api, 65 | extensions: [tokenExtension] 66 | }); 67 | 68 | export { 69 | createApiClient 70 | }; 71 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Yeay! You want to contribute to @vuestorefront/bagisto. That's amazing! To smoothen everyone's experience involved with the project please take note of the following guidelines and rules. 4 | 5 | 6 | ## Found an Issue? 7 | 8 | Thank you for reporting any issues you find. We do our best to test and make @vuestorefront/bagisto as solid as possible, but any reported issue is a real help. 9 | 10 | Please follow these guidelines when reporting issues: 11 | 12 | - Provide a title in the format of ` when ` 13 | - Tag your issue with the tag `bug` 14 | - Provide a short summary of what you are trying to do 15 | - Provide the log of the encountered error if applicable 16 | - Provide the exact version of @vuestorefront/bagisto. 17 | - Be awesome and consider contributing a [pull request](#want-to-contribute) 18 | 19 | ## Want to contribute? 20 | 21 | Please consider these guidelines when filing a pull request: 22 | 23 | > @vuestorefront/bagisto pull requests 24 | 25 | - Follow the [Coding Rules](#coding-rules) 26 | - Follow the [Commit Rules](#commit-rules) 27 | - Make sure you rebased the current master branch when filing the pull request 28 | - Squash your commits when filing the pull request 29 | - Provide a short title with a maximum of 100 characters 30 | - Provide a more detailed description containing 31 | _ What you want to achieve 32 | _ What you changed 33 | _ What you added 34 | _ What you removed 35 | 36 | ## Coding Rules 37 | 38 | To keep the code base of @vuestorefront/bagisto neat and tidy the following rules apply to every change 39 | 40 | > Coding standards 41 | 42 | - `eslint` is king 43 | - Favor micro library over swiss army knives (rimraf, ncp vs. fs-extra) 44 | - Be awesome 45 | 46 | ## Commit Rules 47 | 48 | To help everyone with understanding the commit history of commitlint the following commit rules are enforced. 49 | To make your life easier @vuestorefront/bagisto is commitizen-friendly and provides the npm run-script `commit`. 50 | 51 | > Commit standards 52 | 53 | - [conventional-changelog](https://github.com/conventional-changelog) 54 | - husky commit message hook available 55 | - present tense 56 | - maximum of 100 characters 57 | - message format of `$type($scope): $message` 58 | -------------------------------------------------------------------------------- /packages/composables/src/useBilling/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useBillingFactory, 4 | UseBillingParams 5 | } from '@vue-storefront/core'; 6 | import type { BillingAddress } from '@vue-storefront/bagisto-api'; 7 | import { useCart } from '../useCart'; 8 | import type { 9 | UseBillingAddParams as AddParams 10 | } from '../types'; 11 | 12 | const params: UseBillingParams = { 13 | provide() { 14 | return { 15 | cart: useCart(), 16 | }; 17 | }, 18 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 19 | load: async (context: Context, { customQuery }) => { 20 | console.log('Mocked: useBilling.load'); 21 | 22 | return null; 23 | }, 24 | 25 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 26 | save: async (context: Context, { params, billingDetails, customQuery }) => { 27 | console.log('Mocked: useBilling.save'); 28 | const excludeIndex = ['customerId', 'cartId', 'orderId', 'shippingRates', 'id', 'addressType', 'additional', 'gender', 'defaultAddress', 'vatId', 'createdAt', 'updatedAt', '__typename']; 29 | const shippingAddress = context.cart?.cart.value?.shippingAddress; 30 | for (const key in shippingAddress) { 31 | if (excludeIndex.includes(key)) { 32 | delete shippingAddress[key]; 33 | } 34 | } 35 | const paramDetails = { 36 | type: 'billing', 37 | shipping: shippingAddress, 38 | billing: billingDetails, 39 | shippingAddressId: 0, 40 | billingAddressId: parseInt(params?.billingAddressId) || 0 41 | }; 42 | 43 | const saveBillingResults = await context.$bagisto.api.saveShippingAddress(paramDetails); 44 | 45 | if (!saveBillingResults?.data) { 46 | await context.cart.setCart(null); 47 | await context.cart.load(); 48 | } 49 | 50 | const paymentMethods = saveBillingResults?.data?.saveCheckoutAddresses?.paymentMethods; 51 | 52 | if (saveBillingResults?.data?.paymentMethods?.cart) { 53 | context.cart.setCart(saveBillingResults?.data?.paymentMethods?.cart); 54 | await context.cart.load(); 55 | } 56 | 57 | return paymentMethods ? paymentMethods : null; 58 | } 59 | }; 60 | 61 | export const useBilling = useBillingFactory(params); 62 | -------------------------------------------------------------------------------- /packages/composables/src/useUserShipping/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useUserShippingFactory, 4 | UseUserShippingFactoryParams 5 | } from '@vue-storefront/core'; 6 | import type { 7 | UserShippingAddress as Address, 8 | UserShippingAddressItem as AddressItem 9 | } from '@vue-storefront/bagisto-api'; 10 | import { useUser } from '../useUser'; 11 | 12 | const params: UseUserShippingFactoryParams = { 13 | provide() { 14 | return { 15 | user: useUser(), 16 | }; 17 | }, 18 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 19 | addAddress: async (context: Context, params) => { 20 | console.log('Mocked: useUserShipping.addAddress'); 21 | const addressResult = await context.$bagisto.api.createAddress(params?.address); 22 | 23 | return addressResult?.data?.addresses || {}; 24 | }, 25 | 26 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 27 | deleteAddress: async (context: Context, params) => { 28 | console.log('Mocked: useUserShipping.deleteAddress'); 29 | const addressResult = await context.$bagisto.api.removeAddress(params?.address); 30 | 31 | return addressResult?.data?.addresses || {}; 32 | }, 33 | 34 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 35 | updateAddress: async (context: Context, params) => { 36 | console.log('Mocked: useUserShipping.updateAddress'); 37 | const addressResult = await context.$bagisto.api.updateAddress(params?.address); 38 | 39 | return addressResult?.data?.addresses || {}; 40 | }, 41 | 42 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 43 | load: async (context: Context, params) => { 44 | console.log('Mocked: useUserShipping.load'); 45 | if (context.user?.user.value) { 46 | const addressesResult = await context.$bagisto.api.getAddresses(params); 47 | 48 | return addressesResult?.data?.addresses || {}; 49 | } 50 | return {}; 51 | }, 52 | 53 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 54 | setDefaultAddress: async (context: Context, params) => { 55 | console.log('Mocked: useUserShipping.setDefaultAddress'); 56 | return {}; 57 | } 58 | }; 59 | 60 | export const useUserShipping = useUserShippingFactory(params); 61 | -------------------------------------------------------------------------------- /packages/composables/src/getters/userGetters.ts: -------------------------------------------------------------------------------- 1 | import { UserGetters } from '@vue-storefront/core'; 2 | import { User } from '../types'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 5 | function getFirstName(user: User): string { 6 | if (!user) { 7 | return ''; 8 | } 9 | 10 | return user?.firstName || ''; 11 | } 12 | 13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 14 | function getLastName(user: User): string { 15 | if (!user) { 16 | return ''; 17 | } 18 | 19 | return user?.lastName || ''; 20 | } 21 | 22 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 23 | function getFullName(user: User): string { 24 | if (!user) { 25 | return ''; 26 | } 27 | 28 | return `${user?.firstName} ${user?.lastName}` || ''; 29 | } 30 | 31 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 32 | function getEmailAddress(user: User): string { 33 | if (!user) { 34 | return ''; 35 | } 36 | 37 | return user?.email || ''; 38 | } 39 | 40 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 41 | function getPhone(user: User): string { 42 | if (!user) { 43 | return null; 44 | } 45 | 46 | return user?.phone; 47 | } 48 | 49 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 50 | function getGender(user: User): string { 51 | if (!user) { 52 | return ''; 53 | } 54 | 55 | return user?.gender; 56 | } 57 | 58 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 59 | function getDateOfBirth(user: User): string { 60 | if (!user) { 61 | return ''; 62 | } 63 | 64 | return user?.dateOfBirth || ''; 65 | } 66 | 67 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 68 | function getUser(user): string { 69 | if (!user) { 70 | return null; 71 | } 72 | 73 | return user?.success?.customer || null; 74 | } 75 | 76 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 77 | function getUserId(user: User): number { 78 | if (!user) { 79 | return null; 80 | } 81 | 82 | return user?.id || null; 83 | } 84 | 85 | export const userGetters: UserGetters = { 86 | getFirstName, 87 | getLastName, 88 | getFullName, 89 | getEmailAddress, 90 | getPhone, 91 | getGender, 92 | getDateOfBirth, 93 | getUser, 94 | getUserId 95 | }; 96 | -------------------------------------------------------------------------------- /packages/theme/routes.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | export function getRoutes(themeDir = __dirname) { 4 | return [{ 5 | name: 'bg-home', 6 | path: '/', 7 | component: path.resolve(themeDir, 'pages/Home.vue'), 8 | }, 9 | { 10 | name: 'bg-product', 11 | path: '/product/:id/', 12 | component: path.resolve(themeDir, 'pages/Product.vue'), 13 | }, 14 | { 15 | name: 'bg-category', 16 | path: '/category/:slug_1/:slug_2?/:slug_3?/:slug_4?/:slug_5?', 17 | component: path.resolve(themeDir, 'pages/Category.vue'), 18 | }, 19 | { 20 | name: 'bg-my-account', 21 | path: '/my-account/:pageName?', 22 | component: path.resolve(themeDir, 'pages/MyAccount.vue'), 23 | }, 24 | { 25 | name: 'bg-checkout', 26 | path: '/checkout', 27 | component: path.resolve(themeDir, 'pages/Checkout.vue'), 28 | children: [ 29 | // { 30 | // path: 'user-account', 31 | // name: 'bg-user-account', 32 | // component: path.resolve(themeDir, 'pages/Checkout/UserAccount.vue'), 33 | // }, 34 | { 35 | path: 'shipping', 36 | name: 'bg-shipping', 37 | component: path.resolve(themeDir, 'pages/Checkout/Shipping.vue'), 38 | }, 39 | { 40 | path: 'billing', 41 | name: 'bg-billing', 42 | component: path.resolve(themeDir, 'pages/Checkout/Billing.vue'), 43 | }, 44 | { 45 | path: 'summery', 46 | name: 'bg-summary', 47 | component: path.resolve(themeDir, 'pages/Checkout/Summary.vue'), 48 | }, 49 | { 50 | path: 'thank-you', 51 | name: 'bg-thank-you', 52 | component: path.resolve(themeDir, 'pages/Checkout/ThankYou.vue'), 53 | }, 54 | // { 55 | // path: 'external-thank-you', 56 | // name: 'bg-external-thank-you', 57 | // component: path.resolve(themeDir, 'pages/Checkout/ExternalCheckoutThankYou.vue') 58 | // } 59 | ] 60 | }, 61 | // { 62 | // name: 'bg-reset-password', 63 | // path: '/reset-password', 64 | // alias: '/customer/account/createPassword', 65 | // component: path.resolve(themeDir, 'pages/ResetPassword.vue'), 66 | // }, 67 | // { 68 | // name: 'bg-page', 69 | // path: '/:slug+', 70 | // component: path.resolve(themeDir, 'pages/Page.vue'), 71 | // }, 72 | ]; 73 | } 74 | -------------------------------------------------------------------------------- /packages/theme/components/MobileStoreBanner.vue: -------------------------------------------------------------------------------- 1 | 34 | 49 | 82 | -------------------------------------------------------------------------------- /packages/api-client/src/api/searchReviews/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | 4 | import { CustomerReviewInput } from '../../types'; 5 | 6 | type Variables = { 7 | first: 10, 8 | page: 1, 9 | input?: CustomerReviewInput, 10 | }; 11 | export async function searchReviews(context, params) { 12 | 13 | const variables: Variables = { 14 | first: params?.itemsPerPage || 10, 15 | page: params?.page || 1, 16 | input: params?.input 17 | }; 18 | 19 | try { 20 | return await context.client 21 | .query({ 22 | query: gql` 23 | query reviewsList ($input: CustomerReviewInput, $first: Int = 10, $page: Int = 1) { 24 | reviewsList (input: $input, first: $first, page: $page) { 25 | paginatorInfo { 26 | count 27 | currentPage 28 | lastPage 29 | total 30 | } 31 | data { 32 | id 33 | title 34 | rating 35 | comment 36 | status 37 | productId 38 | customerId 39 | customerName 40 | product { 41 | id 42 | type 43 | attributeFamilyId 44 | sku 45 | parentId 46 | createdAt 47 | updatedAt 48 | productFlats { 49 | id 50 | sku 51 | name 52 | description 53 | shortDescription 54 | urlKey 55 | locale 56 | } 57 | cacheBaseImage { 58 | smallImageUrl 59 | mediumImageUrl 60 | largeImageUrl 61 | originalImageUrl 62 | } 63 | } 64 | createdAt 65 | updatedAt 66 | } 67 | } 68 | }`, 69 | variables: variables 70 | }); 71 | } catch (error) { 72 | console.log('Error searchReviews:'); 73 | console.log(error); 74 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'Vue Storefront 2 for bagisto', 3 | base: '/', 4 | description: 'Documentation for the bagisto connector for Vue Storefront 2', 5 | head: [ 6 | ['link', { rel: 'icon', href: '/favicon.png' }] 7 | ], 8 | configureWebpack: (config) => { 9 | config.module.rules = config.module.rules.map(rule => ({ 10 | ...rule, 11 | use: rule.use && rule.use.map(useRule => ({ 12 | ...useRule, 13 | options: useRule.loader === 'url-loader' ? 14 | /** 15 | Hack for loading images properly. 16 | ref: https://github.com/vuejs/vue-loader/issues/1612#issuecomment-559366730 17 | */ 18 | { ...useRule.options, esModule: false } : 19 | useRule.options 20 | })) 21 | })) 22 | }, 23 | plugins: [ 24 | '@vuepress/plugin-back-to-top', 25 | [ 26 | '@vuepress/plugin-medium-zoom', 27 | { 28 | // This selector excludes images from the "Integrations" page 29 | selector: 'main :not(.tile-image) > img' 30 | } 31 | ], 32 | '@vuepress/active-header-links', 33 | '@vuepress/search' 34 | ], 35 | themeConfig: { 36 | repo: 'https://github.com/vuestorefront/bagisto', 37 | editLinks: true, 38 | docsDir: 'docs', 39 | docsBranch: 'develop', 40 | editLinkText: 'Edit this page', 41 | logo: 'https://user-images.githubusercontent.com/1626923/137092657-fb398d20-b592-4661-a1f9-4135db0b61d5.png', 42 | nav: [ 43 | { text: 'Vue Storefront', link: 'https://vuestorefront.io/' }, 44 | { text: 'Core Documentation', link: 'https://docs.vuestorefront.io/v2/' }, 45 | // { text: 'Demo', link: '' }, 46 | { text: 'GitHub', link: 'https://github.com/vuestorefront/bagisto'}, 47 | { text: 'Roadmap', link: 'https://github.com/vuestorefront/bagisto'} 48 | ], 49 | sidebar: [ 50 | { 51 | title: 'Essentials', 52 | collapsable: false, 53 | children: [ 54 | ['/', 'Introduction'], 55 | ['/guide/getting-started', 'Getting started'], 56 | ['/guide/configuration', 'Configuration'], 57 | ['/guide/about', 'About'], 58 | ] 59 | }, 60 | { 61 | title: 'Composables', 62 | path: '/composables/' 63 | }, 64 | { 65 | title: 'API Client', 66 | path: '/api-client/' 67 | }, 68 | ] 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test & Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | - develop 9 | pull_request: 10 | branches: 11 | - master 12 | - main 13 | - develop 14 | 15 | jobs: 16 | prepare_dependencies: 17 | name: Prepare dependencies 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v2 22 | 23 | - name: Setup node 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: '14' 27 | 28 | - name: Get cached dependencies 29 | uses: actions/cache@v2 30 | with: 31 | path: '**/node_modules' 32 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 33 | 34 | - name: Install dependencies 35 | run: yarn --frozen-lockfile 36 | 37 | lint: 38 | name: Lint 39 | needs: prepare_dependencies 40 | runs-on: ubuntu-latest 41 | steps: 42 | - name: Checkout code 43 | uses: actions/checkout@v2 44 | 45 | - name: Setup node 46 | uses: actions/setup-node@v1 47 | with: 48 | node-version: '14' 49 | 50 | - name: Get cached dependencies 51 | uses: actions/cache@v2 52 | with: 53 | path: '**/node_modules' 54 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 55 | 56 | - name: Run linter 57 | run: yarn lint 58 | 59 | test: 60 | name: Test api-client and composables 61 | needs: prepare_dependencies 62 | runs-on: ubuntu-latest 63 | steps: 64 | - name: Checkout code 65 | uses: actions/checkout@v2 66 | 67 | - name: Setup node 68 | uses: actions/setup-node@v1 69 | with: 70 | node-version: '14' 71 | 72 | - name: Get cached dependencies 73 | uses: actions/cache@v2 74 | with: 75 | path: '**/node_modules' 76 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 77 | 78 | - name: Build api-client 79 | run: yarn build:api-client 80 | 81 | - name: Test api-client 82 | run: yarn test:api-client 83 | 84 | - name: Build composables 85 | run: yarn build:composables 86 | 87 | - name: Test composables 88 | run: yarn test:composables 89 | 90 | - name: Build theme 91 | run: yarn build:theme 92 | 93 | - name: Test theme 94 | run: yarn test:theme 95 | -------------------------------------------------------------------------------- /packages/theme/composables/useUiState.ts: -------------------------------------------------------------------------------- 1 | import { reactive, computed } from '@nuxtjs/composition-api'; 2 | 3 | const state = reactive({ 4 | isCartSidebarOpen: false, 5 | isWishlistSidebarOpen: false, 6 | isLoginModalOpen: false, 7 | isNewsletterModalOpen: false, 8 | isCategoryGridView: true, 9 | isFilterSidebarOpen: false, 10 | isMobileMenuOpen: false 11 | }); 12 | 13 | const useUiState = () => { 14 | const isMobileMenuOpen = computed(() => state.isMobileMenuOpen); 15 | const toggleMobileMenu = () => { 16 | state.isMobileMenuOpen = !state.isMobileMenuOpen; 17 | }; 18 | 19 | const isCartSidebarOpen = computed(() => state.isCartSidebarOpen); 20 | const toggleCartSidebar = () => { 21 | if (state.isMobileMenuOpen) toggleMobileMenu(); 22 | state.isCartSidebarOpen = !state.isCartSidebarOpen; 23 | }; 24 | 25 | const isWishlistSidebarOpen = computed(() => state.isWishlistSidebarOpen); 26 | const toggleWishlistSidebar = () => { 27 | if (state.isMobileMenuOpen) toggleMobileMenu(); 28 | state.isWishlistSidebarOpen = !state.isWishlistSidebarOpen; 29 | }; 30 | 31 | const isLoginModalOpen = computed(() => state.isLoginModalOpen); 32 | const toggleLoginModal = () => { 33 | if (state.isMobileMenuOpen) toggleMobileMenu(); 34 | state.isLoginModalOpen = !state.isLoginModalOpen; 35 | }; 36 | 37 | const isNewsletterModalOpen = computed(() => state.isNewsletterModalOpen); 38 | const toggleNewsletterModal = () => { 39 | state.isNewsletterModalOpen = !state.isNewsletterModalOpen; 40 | }; 41 | 42 | const isCategoryGridView = computed(() => state.isCategoryGridView); 43 | const changeToCategoryGridView = () => { 44 | state.isCategoryGridView = true; 45 | }; 46 | const changeToCategoryListView = () => { 47 | state.isCategoryGridView = false; 48 | }; 49 | 50 | const isFilterSidebarOpen = computed(() => state.isFilterSidebarOpen); 51 | const toggleFilterSidebar = () => { 52 | state.isFilterSidebarOpen = !state.isFilterSidebarOpen; 53 | }; 54 | 55 | return { 56 | isCartSidebarOpen, 57 | isWishlistSidebarOpen, 58 | isLoginModalOpen, 59 | isNewsletterModalOpen, 60 | isCategoryGridView, 61 | isFilterSidebarOpen, 62 | isMobileMenuOpen, 63 | toggleCartSidebar, 64 | toggleWishlistSidebar, 65 | toggleLoginModal, 66 | toggleNewsletterModal, 67 | changeToCategoryGridView, 68 | changeToCategoryListView, 69 | toggleFilterSidebar, 70 | toggleMobileMenu 71 | }; 72 | }; 73 | 74 | export default useUiState; 75 | -------------------------------------------------------------------------------- /packages/theme/components/HeaderNavigation.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 72 | 73 | 88 | -------------------------------------------------------------------------------- /packages/theme/components/Notification.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Vue Storefront 3 |

4 | Bagisto 5 |

6 | 7 | ## Vue Storefront 2 integration with bagisto 8 | 9 | To learn how to build your integration, see our [Integration guide](https://docs.vuestorefront.io/v2/integrate/integration-guide.html). 10 | 11 | ------ 12 | 13 | 14 | 15 | 16 | ### Visit our live [Demo](https://demo.bagisto.com:2087/) 17 | 18 | ## How to start if you want to try out the integration 19 | 20 | ``` 21 | yarn global add @vue-storefront/cli 22 | ``` 23 | ``` 24 | vsf init && cd && yarn && yarn dev 25 | ``` 26 | 27 | ## How to start if you want to contribute? 28 | Want to contribute or have any queries? Write us on: [Bagisto Support](mailto:support@bagisto.com) ❤️. 29 | 30 | ### Requirements: 31 | - NodeJS v16 or later 32 | - Yarn v1 or later(npm not supprted yet) 33 | - [Bagisto v1.3.3](https://github.com/bagisto/bagisto/tree/v1.3.3) 34 | - [Bagisto GraphQL](https://github.com/bagisto/headless-ecommerce) 35 | 36 | ### Steps 37 | 1. Fork the repo 38 | 2. Clone your fork of the repo 39 | ``` 40 | example: 41 | git clone https://github.com/bagisto/vuestorefront.git 42 | cd vuestorefront 43 | ``` 44 | 3. Run `yarn install` to install dependencies. 45 | 4. Build dependencies for api-client, composables, and theme `yarn build`. 46 | 5. Run `yarn dev` if you are using development, else run `yarn start` for production mode. 47 | 48 | ## Resources 49 | 50 | - [Vue Storefront Documentation](https://docs.vuestorefront.io/v2/) 51 | - [Bagisto Documentation](https://devdocs.bagisto.com/) 52 | - [GraphQL/Headless-Commerce Documentation](https://devdocs.bagisto.com/1.x/graphql-shop-api/) 53 | - [Forum Support](https://forums.bagisto.com/) 54 | 55 | ## Support 56 | 57 | If you have any questions about this integration we will be happy to answer them on [bagisto support](mailto:support@bagisto.com). 58 | 59 | ## Contributors ✨ 60 | 61 | 62 | 63 | 64 | 65 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 66 | -------------------------------------------------------------------------------- /packages/api-client/src/api/getCategoryTree/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from '@apollo/client/core'; 3 | 4 | export async function getCategoryTree(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .query({ 9 | query: gql` 10 | query homeCategories ($categoryId: Int, $categorySlug: String = "") { 11 | homeCategories(categoryId: $categoryId, categorySlug: $categorySlug) { 12 | id 13 | name 14 | description 15 | slug 16 | urlPath 17 | imageUrl 18 | metaTitle 19 | metaDescription 20 | metaKeywords 21 | position 22 | status 23 | displayMode 24 | parentId 25 | breadcrumbs { 26 | name 27 | slug 28 | urlPath 29 | } 30 | translations { 31 | id 32 | name 33 | description 34 | localeId 35 | locale 36 | } 37 | children { 38 | id 39 | name 40 | description 41 | slug 42 | urlPath 43 | imageUrl 44 | position 45 | status 46 | productCount 47 | children { 48 | id 49 | name 50 | description 51 | slug 52 | urlPath 53 | imageUrl 54 | position 55 | status 56 | productCount 57 | } 58 | } 59 | createdAt 60 | updatedAt 61 | } 62 | }`, 63 | variables: { 64 | categoryId: params?.categoryId || null, 65 | categorySlug: params?.categorySlug || '' 66 | } 67 | }); 68 | 69 | } catch (error) { 70 | console.log('Error getCategoryTree:'); 71 | console.log(error); 72 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /packages/composables/src/useShippingProvider/index.ts: -------------------------------------------------------------------------------- 1 | import { useShippingProviderFactory, UseShippingProviderParams, Context } from '@vue-storefront/core'; 2 | import type { ShippingProvider, ShippingMethod } from '@vue-storefront/bagisto-api'; 3 | import { useCart } from '../useCart'; 4 | 5 | const params: UseShippingProviderParams = { 6 | provide() { 7 | return useCart(); 8 | }, 9 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 10 | load: async (context: Context, { customQuery }) => { 11 | console.log('Mocked: loadShippingProvider'); 12 | if (customQuery.type === 'payment') { 13 | const shippingAddress = context?.cart.value?.shippingAddress; 14 | const billingAddress = context?.cart.value?.billingAddress; 15 | const shippingRate = context?.cart.value?.selectedShippingRate; 16 | if (shippingAddress && billingAddress && shippingRate) { 17 | const params = { 18 | shippingMethod: shippingRate.method 19 | }; 20 | const paymentMethodResults = await context.$bagisto.api.saveShippingMethod(params); 21 | 22 | if (paymentMethodResults?.data?.paymentMethods?.cart) { 23 | context.setCart(paymentMethodResults?.data?.paymentMethods?.cart); 24 | } 25 | 26 | const paymentMethods = paymentMethodResults?.data?.paymentMethods?.paymentMethods; 27 | 28 | return paymentMethods ? paymentMethods : null; 29 | } 30 | } 31 | 32 | return null; 33 | }, 34 | 35 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 36 | save: async (context: Context, { shippingMethod, customQuery }) => { 37 | console.log('Mocked: saveShippingProvider'); 38 | const params = { 39 | shippingMethod: shippingMethod 40 | }; 41 | if (customQuery?.actionType && customQuery.actionType === 'shipping') { 42 | const shippingMethodResults = await context.$bagisto.api.saveShippingMethod(params); 43 | if (shippingMethodResults?.data?.paymentMethods?.cart) { 44 | context.setCart(shippingMethodResults?.data?.paymentMethods?.cart); 45 | } 46 | 47 | return shippingMethodResults?.data?.paymentMethods?.paymentMethods || null; 48 | } else if (customQuery?.actionType && customQuery.actionType === 'payment') { 49 | 50 | const params = { 51 | payment: { 52 | method: shippingMethod 53 | } 54 | }; 55 | const paymentMethodResults = await context.$bagisto.api.savePaymentMethod(params); 56 | if (paymentMethodResults?.data?.savePayment?.cart) { 57 | context.setCart(paymentMethodResults?.data?.savePayment?.cart); 58 | } 59 | 60 | return paymentMethodResults?.data?.savePayment || null; 61 | } 62 | 63 | return null; 64 | } 65 | }; 66 | 67 | export const useShippingProvider = useShippingProviderFactory(params); 68 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1.bug-report.yml: -------------------------------------------------------------------------------- 1 | name: "🐛 Bug report" 2 | description: Report errors or unexpected behavior 3 | labels: 4 | - bug 5 | - triage-needed 6 | title: '[Bug]: ' 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this bug report, please make sure to [search for existing issues](https://github.com/vuestorefront/<% REPOSITORY %>/issues) before filing a new one! 12 | - type: textarea 13 | id: whattoexpect 14 | attributes: 15 | label: Expected Behavior 16 | placeholder: What were you expecting? 17 | validations: 18 | required: false 19 | - type: textarea 20 | id: whathappened 21 | attributes: 22 | label: Actual Behavior 23 | placeholder: What happened instead?? 24 | validations: 25 | required: true 26 | - type: textarea 27 | id: solution 28 | attributes: 29 | label: Possible Solution 30 | description: Also, if possible provide the information on how to implement the solution. 31 | placeholder: Do you have any possible solution or fix for this bug? 32 | validations: 33 | required: false 34 | - type: textarea 35 | id: reproduce 36 | attributes: 37 | label: Steps to reproduce 38 | description: Please provide detailed instructions on how to reproduce. 39 | placeholder: How we can reproduce this bug? 40 | validations: 41 | required: false 42 | - type: input 43 | attributes: 44 | label: What version of bagisto integration are you using? 45 | description: 'For example: 1.0.0' 46 | validations: 47 | required: true 48 | - type: input 49 | attributes: 50 | label: What version of Node.js are you using? 51 | description: 'For example: 14.0.0' 52 | validations: 53 | required: true 54 | - type: input 55 | attributes: 56 | label: What browser (and version) are you using? 57 | description: 'For example: Chrome, Safari' 58 | validations: 59 | required: true 60 | - type: input 61 | attributes: 62 | label: What operating system (and version) are you using? 63 | description: 'For example: macOS, Windows' 64 | validations: 65 | required: true 66 | - type: textarea 67 | id: logs 68 | attributes: 69 | label: Relevant log output 70 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 71 | render: shell 72 | - type: checkboxes 73 | id: terms 74 | attributes: 75 | label: Code of Conduct 76 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/vuestorefront/<% REPOSITORY %>/blob/master/CODE_OF_CONDUCT.md) 77 | options: 78 | - label: I agree to follow this project's Code of Conduct 79 | required: true 80 | -------------------------------------------------------------------------------- /packages/theme/components/Checkout/CartPreview.vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 93 | -------------------------------------------------------------------------------- /packages/theme/layouts/error.vue: -------------------------------------------------------------------------------- 1 | 24 | 44 | 102 | -------------------------------------------------------------------------------- /packages/theme/components/LocaleSelector.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 63 | 64 | 110 | -------------------------------------------------------------------------------- /packages/composables/src/getters/reviewGetters.ts: -------------------------------------------------------------------------------- 1 | import { ReviewGetters, AgnosticRateCount } from '@vue-storefront/core'; 2 | import type { Review, ReviewItem } from '@vue-storefront/bagisto-api'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 5 | function getItems(reviewItems: ReviewItem[]): ReviewItem[] { 6 | if (!reviewItems) { 7 | return []; 8 | } 9 | 10 | const reviews = []; 11 | if (Array.isArray(reviewItems)) { 12 | for (const reviewDetail of reviewItems) { 13 | reviews.push(reviewDetail); 14 | } 15 | } 16 | 17 | return reviews; 18 | } 19 | 20 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 21 | function getReviewId(reviewItem: ReviewItem): string { 22 | if (!reviewItem) { 23 | return ''; 24 | } 25 | 26 | return reviewItem?.id || ''; 27 | } 28 | 29 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 30 | function getReviewAuthor(reviewItem: ReviewItem): string { 31 | if (!reviewItem) { 32 | return ''; 33 | } 34 | 35 | return reviewItem?.customerName || ''; 36 | } 37 | 38 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 39 | function getReviewMessage(reviewItem: ReviewItem): string { 40 | if (!reviewItem) { 41 | return ''; 42 | } 43 | 44 | return reviewItem?.comment || ''; 45 | } 46 | 47 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 48 | function getReviewRating(reviewItem: ReviewItem): number { 49 | if (!reviewItem) { 50 | return 0; 51 | } 52 | 53 | return reviewItem?.rating || 0; 54 | } 55 | 56 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 57 | function getReviewDate(reviewItem: ReviewItem): string { 58 | if (!reviewItem) { 59 | return ''; 60 | } 61 | 62 | return reviewItem?.createdAt || ''; 63 | } 64 | 65 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 66 | function getTotalReviews(reviewItems: ReviewItem[]): number { 67 | if (!reviewItems) { 68 | return 0; 69 | } 70 | 71 | return reviewItems.length; 72 | } 73 | 74 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 75 | function getAverageRating(reviewItems: ReviewItem[]): number { 76 | if (!reviewItems) { 77 | return 0; 78 | } 79 | 80 | let total = 0; 81 | for (const review of reviewItems) { 82 | total += review.rating; 83 | } 84 | 85 | return Math.round(((total / getTotalReviews(reviewItems)) + Number.EPSILON) * 10) / 10; 86 | } 87 | 88 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 89 | function getRatesCount(review: Review): AgnosticRateCount[] { 90 | return []; 91 | } 92 | 93 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 94 | function getReviewsPage(review: Review): number { 95 | return 0; 96 | } 97 | 98 | export const reviewGetters: ReviewGetters = { 99 | getItems, 100 | getReviewId, 101 | getReviewAuthor, 102 | getReviewMessage, 103 | getReviewRating, 104 | getReviewDate, 105 | getTotalReviews, 106 | getAverageRating, 107 | getRatesCount, 108 | getReviewsPage 109 | }; 110 | -------------------------------------------------------------------------------- /packages/theme/pages/Checkout.vue: -------------------------------------------------------------------------------- 1 | 35 | 79 | 80 | 117 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ecommerce-bagisto-integration", 3 | "private": true, 4 | "license": "MIT", 5 | "engines": { 6 | "node": ">=10.x" 7 | }, 8 | "scripts": { 9 | "build": "yarn build:api-client && yarn build:composables && yarn build:theme", 10 | "build:api-client": "cd packages/api-client && yarn build", 11 | "build:composables": "cd packages/composables && yarn build", 12 | "build:theme": "cd packages/theme && yarn build", 13 | "contributors:add": "all-contributors add", 14 | "contributors:generate": "all-contributors generate", 15 | "dev": "concurrently \"yarn:dev:*\"", 16 | "dev:api-client": "cd packages/api-client && yarn dev", 17 | "dev:composables": "cd packages/composables && yarn dev", 18 | "dev:theme": "cd packages/theme && yarn dev", 19 | "docs:build": "cd docs && yarn build", 20 | "docs:dev": "cd docs && yarn dev", 21 | "docs:install": "cd docs && yarn", 22 | "lint": "eslint . --ext .ts,.vue", 23 | "prepare": "[ -d '.husky' ] && (husky install && shx rm -rf .git/hooks && shx ln -s ../.husky .git/hooks) || true", 24 | "publish:api-client": "node ./scripts/publishApi.js", 25 | "publish:composables": "node ./scripts/publishComposable.js", 26 | "start": "cd packages/theme && yarn start", 27 | "test": "yarn test:api-client && yarn test:composables && yarn test:theme", 28 | "test:api-client": "cd packages/api-client && yarn test --passWithNoTests", 29 | "test:composables": "cd packages/composables && yarn test --passWithNoTests", 30 | "test:theme": "cd packages/theme && yarn test --passWithNoTests", 31 | "update:check": "ncu && lerna run update:check --stream", 32 | "update:update": "ncu -u && lerna run update:update --stream" 33 | }, 34 | "devDependencies": { 35 | "@babel/core": "^7.16.0", 36 | "@commitlint/cli": "^13.2.1", 37 | "@commitlint/config-conventional": "^13.2.0", 38 | "@commitlint/config-lerna-scopes": "^13.2.0", 39 | "@rollup/plugin-node-resolve": "^13.0.6", 40 | "@types/jest": "^27.0.2", 41 | "@types/node": "^16.11.6", 42 | "@typescript-eslint/eslint-plugin": "^5.2.0", 43 | "@typescript-eslint/parser": "^5.2.0", 44 | "@vue/eslint-config-typescript": "^9.0.0", 45 | "all-contributors-cli": "^6.20.0", 46 | "commitizen": "^4.2.4", 47 | "concurrently": "^6.3.0", 48 | "eslint": "8.1.0", 49 | "eslint-config-standard": "^16.0.3", 50 | "eslint-plugin-import": "^2.25.2", 51 | "eslint-plugin-node": "^11.1.0", 52 | "eslint-plugin-promise": "^5.1.1", 53 | "eslint-plugin-standard": "^5.0.0", 54 | "eslint-plugin-vue": "^8.0.3", 55 | "husky": "^7.0.4", 56 | "jest": "^27.3.1", 57 | "lerna": "^4.0.0", 58 | "lint-staged": "^11.2.6", 59 | "npm-check-updates": "^11.8.5", 60 | "rimraf": "^3.0.2", 61 | "rollup": "^2.58.3", 62 | "shx": "^0.3.3", 63 | "rollup-plugin-terser": "^7.0.2", 64 | "rollup-plugin-typescript2": "^0.30.0", 65 | "ts-jest": "^27.0.7", 66 | "ts-node": "^10.4.0", 67 | "tslib": "^2.3.1", 68 | "typescript": "~4.2", 69 | "vue-eslint-parser": "^8.0.1" 70 | }, 71 | "workspaces": [ 72 | "packages/*" 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /packages/theme/components/Checkout/VsfShippingProvider.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 89 | 90 | 103 | -------------------------------------------------------------------------------- /packages/api-client/src/api/getNewProduct/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from "@apollo/client/core"; 3 | 4 | export async function getNewProduct(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .query({ 9 | query: gql` 10 | query newProducts ($count: Int = 10) { 11 | newProducts(count: $count) { 12 | id 13 | type 14 | isInWishlist 15 | attributeFamilyId 16 | sku 17 | parentId 18 | productFlats { 19 | id 20 | sku 21 | productNumber 22 | name 23 | description 24 | shortDescription 25 | urlKey 26 | new 27 | featured 28 | status 29 | visibleIndividually 30 | thumbnail 31 | price 32 | cost 33 | specialPrice 34 | specialPriceFrom 35 | specialPriceTo 36 | weight 37 | color 38 | colorLabel 39 | size 40 | sizeLabel 41 | locale 42 | channel 43 | productId 44 | parentId 45 | minPrice 46 | maxPrice 47 | metaTitle 48 | metaKeywords 49 | metaDescription 50 | width 51 | height 52 | depth 53 | createdAt 54 | updatedAt 55 | } 56 | cacheBaseImage { 57 | smallImageUrl 58 | mediumImageUrl 59 | largeImageUrl 60 | originalImageUrl 61 | } 62 | priceHtml { 63 | id 64 | type 65 | html 66 | regular 67 | special 68 | } 69 | reviews { 70 | id 71 | title 72 | rating 73 | comment 74 | status 75 | productId 76 | customerId 77 | customerName 78 | createdAt 79 | updatedAt 80 | } 81 | } 82 | }`, 83 | variables: { 84 | count: params.limit 85 | } 86 | }); 87 | 88 | } catch (error) { 89 | console.log('Error getNewProduct:'); 90 | console.log(error); 91 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /packages/theme/components/Checkout/VsfPaymentProvider.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 97 | 98 | 111 | -------------------------------------------------------------------------------- /packages/api-client/src/api/getFeaturedProduct/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from "@apollo/client/core"; 3 | 4 | export async function getFeaturedProduct(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .query({ 9 | query: gql` 10 | query featuredProducts ($count: Int = 10) { 11 | featuredProducts(count: $count) { 12 | id 13 | type 14 | isInWishlist 15 | attributeFamilyId 16 | sku 17 | parentId 18 | productFlats { 19 | id 20 | sku 21 | productNumber 22 | name 23 | description 24 | shortDescription 25 | urlKey 26 | new 27 | featured 28 | status 29 | visibleIndividually 30 | thumbnail 31 | price 32 | cost 33 | specialPrice 34 | specialPriceFrom 35 | specialPriceTo 36 | weight 37 | color 38 | colorLabel 39 | size 40 | sizeLabel 41 | locale 42 | channel 43 | productId 44 | parentId 45 | minPrice 46 | maxPrice 47 | metaTitle 48 | metaKeywords 49 | metaDescription 50 | width 51 | height 52 | depth 53 | createdAt 54 | updatedAt 55 | } 56 | cacheBaseImage { 57 | smallImageUrl 58 | mediumImageUrl 59 | largeImageUrl 60 | originalImageUrl 61 | } 62 | priceHtml { 63 | id 64 | type 65 | html 66 | regular 67 | special 68 | } 69 | reviews { 70 | id 71 | title 72 | rating 73 | comment 74 | status 75 | productId 76 | customerId 77 | customerName 78 | createdAt 79 | updatedAt 80 | } 81 | } 82 | }`, 83 | variables: { 84 | count: params.limit 85 | } 86 | }); 87 | 88 | } catch (error) { 89 | console.log('Error getFeaturedProduct:'); 90 | console.log(error); 91 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /packages/theme/components/BottomNavigation.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 84 | 97 | -------------------------------------------------------------------------------- /packages/api-client/src/api/getRelatedProduct/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { gql } from "@apollo/client/core"; 3 | 4 | export async function getRelatedProduct(context, params) { 5 | 6 | try { 7 | return await context.client 8 | .query({ 9 | query: gql` 10 | query relatedProducts ($productId: Int!) { 11 | relatedProducts(productId: $productId) { 12 | id 13 | type 14 | isInWishlist 15 | attributeFamilyId 16 | sku 17 | parentId 18 | productFlats { 19 | id 20 | sku 21 | productNumber 22 | name 23 | description 24 | shortDescription 25 | urlKey 26 | new 27 | featured 28 | status 29 | visibleIndividually 30 | thumbnail 31 | price 32 | cost 33 | specialPrice 34 | specialPriceFrom 35 | specialPriceTo 36 | weight 37 | color 38 | colorLabel 39 | size 40 | sizeLabel 41 | locale 42 | channel 43 | productId 44 | parentId 45 | minPrice 46 | maxPrice 47 | metaTitle 48 | metaKeywords 49 | metaDescription 50 | width 51 | height 52 | depth 53 | createdAt 54 | updatedAt 55 | } 56 | cacheBaseImage { 57 | smallImageUrl 58 | mediumImageUrl 59 | largeImageUrl 60 | originalImageUrl 61 | } 62 | priceHtml { 63 | id 64 | type 65 | html 66 | regular 67 | special 68 | } 69 | reviews { 70 | id 71 | title 72 | rating 73 | comment 74 | status 75 | productId 76 | customerId 77 | customerName 78 | createdAt 79 | updatedAt 80 | } 81 | } 82 | }`, 83 | variables: { 84 | productId: parseInt(params.productId) 85 | } 86 | }); 87 | 88 | } catch (error) { 89 | console.log('Error getRelatedProduct:'); 90 | console.log(error); 91 | throw error.graphQLErrors?.[0].message || error.networkError?.result || error; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /packages/composables/src/getters/wishlistGetters.ts: -------------------------------------------------------------------------------- 1 | import { 2 | WishlistGetters, 3 | AgnosticAttribute, 4 | AgnosticPrice, 5 | AgnosticTotals 6 | } from '@vue-storefront/core'; 7 | import type { Wishlist, WishlistItem } from '@vue-storefront/bagisto-api'; 8 | import { productGetters } from './productGetters'; 9 | 10 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 11 | function getItems(wishlist: any): WishlistItem[] { 12 | if (!wishlist) { 13 | return []; 14 | } 15 | 16 | if (wishlist?.results) { 17 | return wishlist.results || []; 18 | } 19 | 20 | return wishlist?.items || []; 21 | } 22 | 23 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 24 | function getTotals(wishlist: Wishlist): AgnosticTotals { 25 | return { 26 | total: 0, 27 | subtotal: 0 28 | }; 29 | } 30 | 31 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 32 | function getItemName(item: any): string { 33 | if (!item || !item?.product) { 34 | return ''; 35 | } 36 | 37 | return productGetters.getName(item?.product); 38 | } 39 | 40 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 41 | function getItemImage(item: any): string { 42 | if (!item || !item?.product) { 43 | return 'https://s3-eu-west-1.amazonaws.com/commercetools-maximilian/products/081223_1_small.jpg'; 44 | } 45 | 46 | return productGetters.getCoverImage(item?.product); 47 | } 48 | 49 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 50 | function getItemPrice(item: any): AgnosticPrice { 51 | return { 52 | regular: productGetters.getRegularPrice(item?.product), 53 | special: productGetters.getSpecialPrice(item?.product) 54 | }; 55 | } 56 | 57 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 58 | function getItemQty(item: WishlistItem): number { 59 | return 1; 60 | } 61 | 62 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 63 | function getItemAttributes(item: WishlistItem, filters?: string[]): Record { 64 | return { 65 | color: 'red' 66 | }; 67 | } 68 | 69 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 70 | function getItemSku(item: any): string { 71 | if (!item || !item?.product) { 72 | return ''; 73 | } 74 | 75 | return productGetters.getSlug(item?.product); 76 | } 77 | 78 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 79 | function getShippingPrice(wishlist: Wishlist): number { 80 | return 0; 81 | } 82 | 83 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 84 | function getTotalItems(wishlist: any): number { 85 | if (!wishlist || !wishlist?.pagination) { 86 | return 0; 87 | } 88 | 89 | return wishlist?.pagination?.total || 0; 90 | } 91 | 92 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 93 | function getFormattedPrice(price: number): string { 94 | return ''; 95 | } 96 | 97 | export const wishlistGetters: WishlistGetters = { 98 | getItems, 99 | getTotals, 100 | getItemName, 101 | getItemImage, 102 | getItemPrice, 103 | getItemQty, 104 | getItemAttributes, 105 | getShippingPrice, 106 | getItemSku, 107 | getTotalItems, 108 | getFormattedPrice 109 | }; 110 | -------------------------------------------------------------------------------- /packages/composables/src/useCart/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | useCartFactory, 4 | UseCartFactoryParams 5 | } from '@vue-storefront/core'; 6 | import type { 7 | Cart, 8 | CartItem, 9 | Product 10 | } from '@vue-storefront/bagisto-api'; 11 | 12 | const params: UseCartFactoryParams = { 13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 14 | load: async (context: Context, { customQuery }) => { 15 | console.log('Mocked: useCart.load'); 16 | const cartResults = await context.$bagisto.api.getCart(customQuery); 17 | 18 | return cartResults?.data?.cartDetail || null; 19 | }, 20 | 21 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 22 | addItem: async (context: Context, { currentCart, product, quantity, customQuery }) => { 23 | console.log('Mocked: useCart.addItem'); 24 | const data = { 25 | product, quantity, customQuery 26 | }; 27 | 28 | const addItemToCartResults = await context.$bagisto.api.addToCart(data); 29 | params.load(context, {}); 30 | return addItemToCartResults?.data?.addItemToCart?.cart || null; 31 | }, 32 | 33 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 34 | removeItem: async (context: Context, { currentCart, product, customQuery }) => { 35 | console.log('Mocked: useCart.removeItem'); 36 | const params = { id: product?.id }; 37 | const removeItemToCartResults = await context.$bagisto.api.removeFromCart(params); 38 | 39 | return removeItemToCartResults?.data?.removeCartItem?.cart || null; 40 | }, 41 | 42 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 43 | updateItemQty: async (context: Context, { currentCart, product, quantity, customQuery }) => { 44 | console.log('Mocked: useCart.updateItemQty'); 45 | const params = { 46 | qty: [{ 47 | cartItemId: product?.id, 48 | quantity: quantity 49 | }] 50 | }; 51 | const updateItemToCartResults = await context.$bagisto.api.updateToCart(params); 52 | 53 | return updateItemToCartResults?.data?.updateItemToCart?.cart || null; 54 | }, 55 | 56 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 57 | clear: async (context: Context, { currentCart }) => { 58 | console.log('Mocked: useCart.clear'); 59 | return null; 60 | }, 61 | 62 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 63 | applyCoupon: async (context: Context, { currentCart, couponCode, customQuery }) => { 64 | console.log('Mocked: useCart.applyCoupon'); 65 | return { 66 | updatedCart: null, 67 | updatedCoupon: null 68 | }; 69 | }, 70 | 71 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 72 | removeCoupon: async (context: Context, { currentCart, couponCode, customQuery }) => { 73 | console.log('Mocked: useCart.removeCoupon'); 74 | return { 75 | updatedCart: null 76 | }; 77 | }, 78 | 79 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 80 | isInCart: (context: Context, { currentCart, product }) => { 81 | if (currentCart?.items && currentCart?.items.length > 0) { 82 | for (const cartItem of currentCart.items) { 83 | if (cartItem.productId === product.id) { 84 | return true; 85 | } 86 | } 87 | } 88 | 89 | return false; 90 | } 91 | }; 92 | 93 | export const useCart = useCartFactory(params); 94 | -------------------------------------------------------------------------------- /packages/theme/components/AppFooter.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 82 | 83 | 120 | -------------------------------------------------------------------------------- /packages/theme/components/InstagramFeed.vue: -------------------------------------------------------------------------------- 1 | 27 | 50 | 102 | --------------------------------------------------------------------------------