diff --git a/.editorconfig b/.editorconfig
index 9d08a1a828..c46bceae19 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -7,3 +7,11 @@ indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
+
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+max_line_length = 150
diff --git a/.env b/.env
deleted file mode 100644
index 9b31c9a66c..0000000000
--- a/.env
+++ /dev/null
@@ -1 +0,0 @@
-COMPOSE_PROJECT_NAME=vue-storefront
diff --git a/.eslintignore b/.eslintignore
index 0779adf9c2..75702544c6 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,3 +1,7 @@
-core/build/*.js
-node_modules
-packages/module/*.js
\ No newline at end of file
+**/node_modules/**/*
+**/lib/*
+**/GraphQL.ts
+!**/.vuepress/**/*
+packages/boilerplate/composables/nuxt/plugin.js
+packages/commercetools/composables/nuxt/plugin.js
+packages/core/cache/nuxt/plugin.js
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 0debca6290..0000000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,71 +0,0 @@
-module.exports = {
- root: true,
- env: { browser: true, jest: true },
- globals: { fetchMock: true },
- parser: 'vue-eslint-parser',
- parserOptions: {
- parser: '@typescript-eslint/parser',
- ecmaVersion: 8,
- sourceType: 'module'
- },
- // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
- extends: [
- 'plugin:vue/recommended',
- 'standard',
- 'plugin:@typescript-eslint/recommended'
- ],
- plugins: ['vue', 'vue-storefront', '@typescript-eslint'],
- // add your custom rules here
- rules: {
- '@typescript-eslint/no-var-requires': 1,
- '@typescript-eslint/indent': ['error', 2],
- '@typescript-eslint/camelcase': 0,
- semi: 'off',
- '@typescript-eslint/semi': 0,
- '@typescript-eslint/member-delimiter-style': ['error', { 'multiline': { 'delimiter': 'comma', 'requireLast': false }, 'singleline': { 'delimiter': 'comma' } }],
- '@typescript-eslint/no-empty-interface': 1,
- '@typescript-eslint/no-use-before-define': 1,
- '@typescript-eslint/no-explicit-any': 0,
- '@typescript-eslint/class-name-casing': 1,
- '@typescript-eslint/no-unused-vars': 0,
- '@typescript-eslint/explicit-function-return-type': 0,
- 'handle-callback-err': 1,
- 'prefer-promise-reject-errors': 0,
- 'import/no-duplicates': 1,
- 'vue/return-in-computed-property': 1,
- 'vue/no-use-v-if-with-v-for': 0,
- 'vue/no-unused-components': 1,
- 'vue/no-v-html': 0,
- 'vue/no-template-shadow': 2,
- /* max attributes-per-line and order-in-components
- ** we should use this later, when eslint-plugin-vue will support auto fixing this
- */
- 'vue/max-attributes-per-line': 0,
- 'vue/order-in-components': 0,
- 'vue/attributes-order': 0,
- // less restricted v-for -> v-if rules
- 'vue/no-confusing-v-for-v-if': 0,
- // allow paren-less arrow functions
- 'arrow-parens': 0,
- 'prefer-arrow-callback': 1,
- // allow async-await
- 'generator-star-spacing': 0,
- // allow debugger during development
- 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
- 'no-restricted-imports': [2, { paths: ['lodash-es'] }],
- 'vue-storefront/no-corecomponent-import': 'error',
- 'vue-storefront/no-corecomponent': 'error',
- 'vue-storefront/no-corepage-import': 'error',
- 'vue-storefront/no-corepage': 'error'
- },
- overrides: [
- {
- // @todo check if this is closed https://github.com/typescript-eslint/typescript-eslint/issues/342
- // This is an issue with interfaces so we need to wait until it fixed.
- files: ['core/**/*.ts'],
- rules: {
- 'no-undef': 1
- }
- }
- ]
-};
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000000..486733f360
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,138 @@
+{
+ "root": true,
+ "extends": [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/eslint-recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "parser": "vue-eslint-parser",
+ "parserOptions": {
+ "parser": "@typescript-eslint/parser",
+ "ecmaVersion": 2017,
+ "sourceType": "module"
+ },
+ "plugins": ["vue", "@typescript-eslint"],
+ "env": {
+ "browser": true,
+ "commonjs": true,
+ "node": true,
+ "jest": true
+ },
+ "globals": {
+ "Promise": true,
+ "process": true,
+ "console": true,
+ "Set": true,
+ "Intl": true
+ },
+ "rules": {
+ "eqeqeq": 2,
+ "no-use-before-define": [
+ 2,
+ {
+ "functions": false
+ }
+ ],
+ "no-undef": 2,
+ "no-unused-vars": 2,
+ "brace-style": 2,
+ "no-mixed-spaces-and-tabs": 2,
+ "key-spacing": 2,
+ "comma-spacing": 2,
+ "array-bracket-spacing": 2,
+ "space-in-parens": 2,
+ "no-trailing-spaces": 2,
+ "comma-dangle": 2,
+ "comma-style": 2,
+ "space-infix-ops": 2,
+ "keyword-spacing": 2,
+ "space-before-blocks": 2,
+ "spaced-comment": 2,
+ "no-multiple-empty-lines": [
+ 2,
+ {
+ "max": 1
+ }
+ ],
+ "complexity": 2,
+ "max-depth": [
+ 2,
+ {
+ "max": 3
+ }
+ ],
+ "default-case": 0,
+ "dot-notation": 2,
+ "no-alert": 2,
+ "no-empty-function": 0,
+ "no-eval": 2,
+ "no-extend-native": 2,
+ "no-extra-bind": 2,
+ "no-implicit-coercion": 2,
+ "no-multi-spaces": 2,
+ "no-useless-return": 2,
+ "no-console": 0,
+ "global-require": 1,
+ "camelcase": 0,
+ "computed-property-spacing": 2,
+ "consistent-this": 2,
+ "func-call-spacing": 2,
+ "func-names": 0,
+ "func-name-matching": 2,
+ "func-style": [
+ 2,
+ "declaration",
+ {
+ "allowArrowFunctions": true
+ }
+ ],
+ "indent": [
+ 2,
+ 2,
+ {
+ "SwitchCase": 1
+ }
+ ],
+ "line-comment-position": 2,
+ "linebreak-style": 2,
+ "lines-around-comment": 2,
+ "max-statements-per-line": 2,
+ "no-lonely-if": 2,
+ "prefer-const": 2,
+ "no-mixed-operators": 2,
+ "no-multi-assign": 2,
+ "no-unneeded-ternary": 2,
+ "object-property-newline": [
+ 2,
+ {
+ "allowAllPropertiesOnSameLine": true
+ }
+ ],
+ "operator-linebreak": 2,
+ "quote-props": [2, "as-needed"],
+ "quotes": [2, "single"],
+ "semi": 2,
+ "semi-spacing": 2,
+ "one-var": [2, "never"],
+ "eol-last": 2,
+ "newline-after-var": 0,
+ "no-var": 2,
+ "@typescript-eslint/no-empty-function": 0,
+ "no-case-declarations": 0,
+ "@typescript-eslint/no-var-requires": 0,
+ "@typescript-eslint/no-explicit-any": 0,
+ "@typescript-eslint/explicit-function-return-type": 0,
+ "@typescript-eslint/no-unused-vars": 2,
+ "@typescript-eslint/ban-ts-ignore": 0,
+ "@typescript-eslint/explicit-module-boundary-types": 0
+ },
+ "overrides": [
+ {
+ "files": "*.ts",
+ "rules": {
+ "no-undef": "off",
+ "no-unused-vars": "off"
+ }
+ }
+ ]
+}
diff --git a/.github/ISSUE_TEMPLATE/1.bug-report.yml b/.github/ISSUE_TEMPLATE/1.bug-report.yml
new file mode 100644
index 0000000000..5bc7ad62eb
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/1.bug-report.yml
@@ -0,0 +1,83 @@
+name: "🐛 Bug report"
+description: |
+ Create a report to help us improve
+labels:
+ - bug
+ - triage-needed
+title: '[Bug]: '
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report, please make sure to [search for existing issues](https://github.com/vuestorefront/vue-storefront/issues) before filing a new one!
+ - type: textarea
+ attributes:
+ label: Describe the Bug
+ description: Can you provide a clear and concise description of the bug
+ validations:
+ required: true
+ - type: textarea
+ id: currentbehavior
+ attributes:
+ label: Current behavior
+ placeholder: Describe the current behavior pointing exactly why it's not working as intended
+ - type: textarea
+ id: expectedbehavior
+ attributes:
+ label: Expected behavior
+ placeholder: Describe what the desired behavior should be
+ validations:
+ required: true
+ - type: textarea
+ id: reproduce
+ attributes:
+ label: Steps to reproduce
+ placeholder: Please provide the steps to reproduce and if possible a minimal reproducible example of the problem
+ - type: input
+ attributes:
+ label: What version of Vue Storefront are you using?
+ description: 'For example: 2.3.4'
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: What version of Node.js are you using?
+ description: 'For example: 12.0.0'
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: What browser (and version) are you using?
+ description: 'For example: Chrome, Safari'
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: What operating system (and version) are you using?
+ description: 'For example: macOS, Windows'
+ validations:
+ required: true
+ - type: textarea
+ id: logs
+ attributes:
+ label: Relevant log output
+ description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
+ render: shell
+ - type: checkboxes
+ id: fixthebug
+ attributes:
+ label: Able to fix / change the documentation?
+ description: Can you handle this change and create a Pull Request?
+ options:
+ - label: 'Yes'
+ required: false
+ - label: 'No'
+ required: false
+ - type: checkboxes
+ id: terms
+ attributes:
+ label: Code of Conduct
+ 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)
+ options:
+ - label: I agree to follow this project's Code of Conduct
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/2.documentation-issue.yml b/.github/ISSUE_TEMPLATE/2.documentation-issue.yml
new file mode 100644
index 0000000000..1b3ba7313f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/2.documentation-issue.yml
@@ -0,0 +1,31 @@
+name: "📚 Documentation Issue"
+description: |
+ Report issues in our documentation
+labels:
+ - documentation
+ - triage-needed
+body:
+ - type: textarea
+ attributes:
+ label: Provide a description of requested docs changes
+ placeholder: Briefly describe which document needs to be corrected.
+ validations:
+ required: true
+ - type: checkboxes
+ id: fixthebug
+ attributes:
+ label: Able to fix / change the documentation?
+ description: Can you handle this change and create a Pull Request?
+ options:
+ - label: 'Yes'
+ required: false
+ - label: 'No'
+ required: false
+ - type: checkboxes
+ id: terms
+ attributes:
+ label: Code of Conduct
+ 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)
+ options:
+ - label: I agree to follow this project's Code of Conduct
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/3.feature-request.yml b/.github/ISSUE_TEMPLATE/3.feature-request.yml
new file mode 100644
index 0000000000..30cf58d1dd
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/3.feature-request.yml
@@ -0,0 +1,46 @@
+name: "🚀 Feature Request"
+description: Sugest a new feature request or improvement on the project
+title: '[Feature]: '
+labels:
+ - feature
+ - enhancement
+ - triage-needed
+
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Please, provide as many information, and knowledge so the feature can be correctly designed and developed.
+ - type: textarea
+ id: suggestion
+ attributes:
+ label: How the project can be improved?
+ 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.
+ placeholder: Describe the motivation or the concrete use case
+ validations:
+ required: true
+ - type: textarea
+ id: acceptcriterea
+ attributes:
+ label: What are the acceptance criteria?
+ description: List the acceptance criteria for this task in a form of a list.
+ value: '- [ ]'
+ - type: textarea
+ id: additionalinfo
+ attributes:
+ label: Additional information
+ description: If you think that any additional information would be useful please provide them here.
+ - type: input
+ attributes:
+ label: What version of Vue Storefront this feature can be implemented?
+ description: 'For example: 2.3.4'
+ validations:
+ required: true
+ - type: checkboxes
+ id: terms
+ attributes:
+ label: Code of Conduct
+ 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)
+ options:
+ - label: I agree to follow this project's Code of Conduct
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/4.question.yml b/.github/ISSUE_TEMPLATE/4.question.yml
new file mode 100644
index 0000000000..a760ab0344
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/4.question.yml
@@ -0,0 +1,28 @@
+name: "❓ Question / Basic Issue"
+description: |
+ Do you have a question on the implementation or a basic issue
+labels:
+ - triage-needed
+body:
+ - type: markdown
+ attributes:
+ value: If you are not sure how something works or want discuss something just describe your doubts.
+ - type: textarea
+ attributes:
+ label: What is your question / Please describe your issue
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: What version of Vue Storefront are you using?
+ description: 'For example: 2.3.4'
+ validations:
+ required: true
+ - type: checkboxes
+ id: terms
+ attributes:
+ label: Code of Conduct
+ 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)
+ options:
+ - label: I agree to follow this project's Code of Conduct
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/RFC.md b/.github/ISSUE_TEMPLATE/RFC.md
deleted file mode 100644
index bd6ca4670d..0000000000
--- a/.github/ISSUE_TEMPLATE/RFC.md
+++ /dev/null
@@ -1,82 +0,0 @@
----
-name: RFC
-about: Request for comments
-labels: RFC
----
-
-# Summary
-[summary]: #summary
-
-One paragraph explanation of the feature.
-
-# Motivation
-[motivation]: #motivation
-
-Why are we doing this? What use cases does it support? What is the expected outcome?
-
-# Guide-level explanation
-[guide-level-explanation]: #guide-level-explanation
-
-Explain the proposal as if it was already included into the project and you were teaching it to another Vue Storefront developer. That generally means:
-
-- Introducing new named concepts.
-- Explaining the feature largely in terms of examples.
-- Explaining how Vue Storefront developers should *think* about the feature, and how it should impact the way they use Vue Storefront. It should explain the impact as concretely as possible.
-- If applicable, provide sample error messages, deprecation warnings, or migration guidance.
-
-# Reference-level explanation
-[reference-level-explanation]: #reference-level-explanation
-
-This is the technical portion of the RFC. Explain the design in sufficient detail that:
-
-- Its interaction with other features is clear.
-- It is reasonably clear how the feature would be implemented.
-- Corner cases are dissected by example.
-
-The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work.
-
-# Drawbacks
-[drawbacks]: #drawbacks
-
-Why should we *not* do this?
-
-# Rationale and alternatives
-[rationale-and-alternatives]: #rationale-and-alternatives
-
-- Why is this design the best in the space of possible designs?
-- What other designs have been considered and what is the rationale for not choosing them?
-- What is the impact of not doing this?
-
-# Prior art
-[prior-art]: #prior-art
-
-Discuss prior art, both the good and the bad, in relation to this proposal.
-A few examples of what this can include are:
-
-- For feature proposals: Does this feature exist in other e-commerce platforms and what experience have their community had?
-- For community proposals: Is this done by some other community and what were their experiences with it?
-- For other teams: What lessons can we learn from what other communities have done here?
-
-This section is intended to encourage you as an author to think about the lessons from other platforms, provide readers of your RFC with a fuller picture.
-If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or if it is an adaptation from other platforms.
-
-
-# Unresolved questions
-[unresolved-questions]: #unresolved-questions
-
-- What parts of the design do you expect to resolve through the RFC process before this gets merged?
-- What parts of the design do you expect to resolve through the implementation of this feature before stabilization?
-- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC?
-
-# Future possibilities
-[future-possibilities]: #future-possibilities
-
-Think about what the natural extension and evolution of your proposal would
-be and how it would affect the language and project as a whole in a holistic
-way. Try to use this section as a tool to more fully consider all possible
-interactions with the project and language in your proposal.
-Also consider how the this all fits into the roadmap for the project
-and of the relevant sub-team.
-
-
-
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 3bd21ff784..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-labels: bug
-
----
-
-## Current behavior
-
-
-
-
-## Expected behavior
-
-
-
-
-## Steps to reproduce the issue
-
-
-
-
-## Version of Vue Storefront
-
-- [ ] Vue Storefront
-- [ ] Vue Storefront Next
-
-
-## Can you handle fixing this bug by yourself?
-
-- [ ] YES
-- [ ] NO
-
-## Which [Release Cycle](https://docs.vuestorefront.io/guide/basics/release-cycle.html) state this refers to? Info for developer. (doesn't apply to Next)
-Pick one option.
-
-- [ ] This is a bug report for test version on https://test.storefrontcloud.io - In this case Developer should create branch from `develop` branch and create Pull Request `2. Feature / Improvement` back to `develop`.
-- [ ] This is a bug report for current Release Candidate version on https://next.storefrontcloud.io - In this case Developer should create branch from `release` branch and create Pull Request `3. Stabilisation fix` back to `release`.
-- [ ] This is a bug report for current Stable version on https://demo.storefrontcloud.io and should be placed in next stable version hotfix - In this case Developer should create branch from `hotfix` or `master` branch and create Pull Request `4. Hotfix` back to `hotfix`.
-
-## Environment details
-
-- Browser:
-- OS:
-- Node:
-- Code Version:
-
-## Additional information
-
-
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..64ba95063c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Documentation
+ url: https://docs.vuestorefront.io/
+ about: Find more information about the project and how to implement in our documentation.
+ - name: Discord Chat
+ url: https://discord.vuestorefront.io/
+ about: Ask questions and discuss with other Vue Storefront users in real time.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 0d12ccb9da..0000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-labels: feature request
-
----
-
-## What is the motivation for adding / enhancing this feature?
-
-
-
-## What are the acceptance criteria
-
-
-- [ ] ...
-
-## Version of Vue Storefront
-
-- [ ] Vue Storefront
-- [ ] Vue Storefront Next
-
-## Can you complete this feature request by yourself?
-
-- [ ] YES
-- [ ] NO
-
-## Additional information
-
-
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
deleted file mode 100644
index 8d92170361..0000000000
--- a/.github/ISSUE_TEMPLATE/question.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-name: Question
-about: If you are not sure how something works or want discuss something just describe your doubts.
-labels: question
----
-
-## Prerequisites
-
-Please answer the following questions for yourself before submitting an issue.
-- [ ] I am running the latest version
-- [ ] I checked the documentation and found no answer
-- [ ] I checked to make sure that this issue has not already been filed
-
-## Check our forum:
-https://forum.vuestorefront.io/
-
-# Is there something you don't understand? What is it? Describe it.
-
-
-# Can't find what you're looking for?
-
-
-
-
-## Keep the problem description concise and include:
-- [ ] A brief description of the problem,
-- [ ] Where the problem is occurring,
-- [ ] The length of time the problem has been occurring,
-- [ ] The size of the problem.
-
-
-## Additional information
-
-
-
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 9cbcd1ca31..87f637ae12 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,32 +1,57 @@
-### Related Issues
-
+
-closes #
-
-### Short Description of the PR
+## Description
+## Related Issue
+
+
+
+
+
-### Screenshots of Visual Changes before/after (if There Are Any)
-
+## Motivation and Context
+
-### Pull Request Checklist
-
-- [ ] I have updated the Changelog ([V1](https://github.com/DivanteLtd/vue-storefront/blob/develop/CHANGELOG.md)) [v2](https://docs-next.vuestorefront.io/contributing/creating-changelog.html) and mentioned all breaking changes in the public API.
-- [ ] I have documented all new public APIs and made changes to existing docs mentioning the parts I've changed so they're up to date.
-- [ ] I have tested my Pull Request on production build and (to my knowledge) it works without any issues
-
-- [ ] I have followed [naming conventions](https://github.com/kettanaito/naming-cheatsheet)
+## How Has This Been Tested?
+
+
+
-
+## Screenshots:
+
-### Upgrade Notes and Changelog
-- [x] No upgrade steps required (100% backward compatibility and no breaking changes)
-- [ ] I've updated the [Upgrade notes](https://github.com/vuestorefront/vue-storefront/blob/develop/docs/guide/upgrade-notes/README.md) and [Changelog](https://github.com/vuestorefront/vue-storefront/blob/develop/CHANGELOG.md) on how to port existing Vue Storefront sites with this new feature
+## Types of changes
+
+- [ ] Bug fix (non-breaking change which fixes an issue)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Breaking change (fix or feature that would cause existing functionality to change)
+## Checklist:
+
+
+- [ ] I have read the **CONTRIBUTING** document.
-### Contribution and Currently Important Rules Acceptance
-
+#### Changelog
+- [ ] I have updated the Changelog ([V1](https://github.com/DivanteLtd/vue-storefront/blob/develop/CHANGELOG.md)) [v2](https://docs-next.vuestorefront.io/contributing/creating-changelog.html) and mentioned all breaking changes in the public API.
+- [ ] I have documented all new public APIs and made changes to existing docs mentioning the parts I've changed so they're up to date.
+
+#### Tests
+- [ ] I have written test cases for my code
+- [ ] I have tested my Pull Request on production build and (to my knowledge) it works without any issues
+- [ ] I have added tests to cover my changes.
+- [ ] All new and existing tests passed.
+
+> I tested manually my code, and it works well with both:
+- [ ] Default Theme
+- [ ] Capybara Theme
+
+#### Code standards
+- [ ] My code follows the code style of this project.
+
+- [ ] I have followed [naming conventions](https://github.com/kettanaito/naming-cheatsheet)
-- [ ] I read and followed [contribution rules](https://github.com/vuestorefront/vue-storefront/blob/master/CONTRIBUTING.md)
+#### Docs
+- [ ] My change requires a change to the documentation.
+- [ ] I have updated the documentation accordingly.
diff --git a/.github/PULL_REQUEST_TEMPLATE/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index 2d3c0374f9..0000000000
--- a/.github/PULL_REQUEST_TEMPLATE/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-name: 1. First PR for Vue Storefront
-about: Is it your first PR for Vue Storefront and you're not sure what to pick? No worries, we got you covered! Pick this template.
-
----
-
-This is my first PR for storefront or i'm not sure which other PR should i choose.
-
-
-### Related issues
-
-
-closes #
-
-### Short description
-
-
-
-### Screenshots of visual changes before/after (if there are any)
-
-
-### Which environment this relates to
-Check your case. In case of any doubts please read about [Release Cycle](https://docs.vuestorefront.io/guide/basics/release-cycle.html)
-
-
-### Checklist
-
-- [ ] No upgrade steps required (100% backward compatibility and no breaking changes)
-- [ ] I've updated the Upgrade notes and Changelog
-
-- [ ] I updated the documentation
-- [ ] My code is covered with unit tests
-
-**IMPORTANT NOTICE** - Remember to update `CHANGELOG.md` with description of your change
-
-### Contribution and currently important rules acceptance
-
-
-- [ ] I read and followed [contribution rules](https://github.com/vuestorefront/vue-storefront/blob/master/CONTRIBUTING.md)
diff --git a/.github/PULL_REQUEST_TEMPLATE/feature-improvement.md b/.github/PULL_REQUEST_TEMPLATE/feature-improvement.md
deleted file mode 100644
index 13f088845d..0000000000
--- a/.github/PULL_REQUEST_TEMPLATE/feature-improvement.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-name: 2. Feature / Improvement
-about: New feature or some improvements to current develop version (https://test.storefrontcloud.io). This is for branches created from `develop` branch and should be merged back into `develop`.
-
----
-
-This is a feature or improvement for current test version on https://test.storefrontcloud.io
-
-### Related issues
-
-
-closes #
-
-### Short description and why it's useful
-
-
-
-
-### Screenshots of visual changes before/after (if there are any)
-
-
-
-
-### PR status check
-This is a feature or improvement PR for current test version. In case of any doubts please read about [Release Cycle](https://docs.vuestorefront.io/guide/basics/release-cycle.html)
-
-- [ ] I've created this branch from `develop` branch and want to merge it back to `develop`
-
-### Upgrade Notes and Changelog
-
-- [x] No upgrade steps required (100% backward compatibility and no breaking changes)
-- [ ] I've updated the [Upgrade notes](https://github.com/vuestorefront/vue-storefront/blob/develop/docs/guide/upgrade-notes/README.md) and [Changelog](https://github.com/vuestorefront/vue-storefront/blob/develop/CHANGELOG.md) on how to port existing VS sites with this new feature
-
-**IMPORTANT NOTICE** - PR needs to have all checks to be merged in (except braking changes check).
diff --git a/.github/PULL_REQUEST_TEMPLATE/hotfix.md b/.github/PULL_REQUEST_TEMPLATE/hotfix.md
deleted file mode 100644
index ef51c1f1df..0000000000
--- a/.github/PULL_REQUEST_TEMPLATE/hotfix.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-name: 4. Hotfix
-about: Bugfix for current stable version (https://demo.storefrontcloud.io). This is for branches created from `hotfix` or `master` branch and should be merged back into `hotfix`.
-
----
-
-This is a bugfix for current stable version on https://demo.storefrontcloud.io
-
-### Related issues
-
-
-closes #
-
-### Short description and why it's useful
-
-
-
-
-### Screenshots of visual changes before/after (if there are any)
-
-
-
-
-### PR status check
-This is hotfix PR, it means that it contain fix for current stable version. In case of any doubts please read about [Release Cycle](https://docs.vuestorefront.io/guide/basics/release-cycle.html)
-
-- [ ] I've created this branch from `master` or `hotfix` branch
-- [ ] I want to merge this PR into `hotfix` branch
-
-### Upgrade Notes and Changelog
-
-- [x] No upgrade steps required (100% backward compatibility and no breaking changes)
-- [ ] I've updated the [Upgrade notes](https://github.com/vuestorefront/vue-storefront/blob/develop/docs/guide/upgrade-notes/README.md) and [Changelog](https://github.com/vuestorefront/vue-storefront/blob/develop/CHANGELOG.md) on how to port existing VS sites with this new feature
-
-**IMPORTANT NOTICE** - PR needs to have all checks to be merged in.
diff --git a/.github/PULL_REQUEST_TEMPLATE/stabilisation-fix.md b/.github/PULL_REQUEST_TEMPLATE/stabilisation-fix.md
deleted file mode 100644
index 666db6de76..0000000000
--- a/.github/PULL_REQUEST_TEMPLATE/stabilisation-fix.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-name: 3. Stabilisation fix
-about: Fix for current Release Candidate version (https://next.storefrontcloud.io). This is for branches created from `release` branch and should be merged back into `release`.
-
----
-
-This is a stabilisation fix for current Release Candidate version on https://next.storefrontcloud.io
-
-### Related issues
-
-
-closes #
-
-### Short description and why it's useful
-
-
-
-
-### Screenshots of visual changes before/after (if there are any)
-
-
-
-
-### PR status check
-This is Release Candidate stabilisation PR, it means that it contain fix for current RC version. In case of any doubts please read about [Release Cycle](https://docs.vuestorefront.io/guide/basics/release-cycle.html)
-
-- [ ] I've created this branch from `release` branch
-- [ ] I want to merge this PR into `release` branch
-
-### Upgrade Notes and Changelog
-
-- [x] No upgrade steps required (100% backward compatibility and no breaking changes)
-- [ ] I've updated the [Upgrade notes](https://github.com/vuestorefront/vue-storefront/blob/develop/docs/guide/upgrade-notes/README.md) and [Changelog](https://github.com/vuestorefront/vue-storefront/blob/develop/CHANGELOG.md) on how to port existing VS sites with this new feature
-
-**IMPORTANT NOTICE** - PR needs to have all checks to be merged in.
diff --git a/.github/labeler.yml b/.github/labeler.yml
new file mode 100644
index 0000000000..8b9116cf70
--- /dev/null
+++ b/.github/labeler.yml
@@ -0,0 +1,23 @@
+# Add 'Next' label to any change to packages files
+Next:
+- true
+
+# Add 'core' label to any change to packages/core files within the source dir EXCEPT for the docs sub-folder
+core:
+- any: ['packages/core/**/*', '!packages/core/docs/**/*']
+
+# Add 'commercetools' label to any change to packages/commercetools files
+commercetools:
+- packages/commercetools/**/*
+
+# Add 'boilerplate' label to any change to packages/boilerplate files
+boilerplate:
+- packages/boilerplate/**/*
+
+# Add 'docs' label to any change to packages/core/docs files EXCEPT for the changelog
+docs:
+- any: ['packages/core/docs/**/*', '!packages/core/docs/changelog/**/*']
+
+# Add 'ci' label to any change to continuous integration files inside .github folder
+ci:
+- .github/**/*
diff --git a/.github/semantic.yml b/.github/semantic.yml
new file mode 100644
index 0000000000..1f65fc4555
--- /dev/null
+++ b/.github/semantic.yml
@@ -0,0 +1,24 @@
+titleOnly: true
+scopes:
+ - core
+ - core-theme
+ - docs
+ - commercetools
+ - commercetools-theme
+ - boilerplate
+ - composables
+ - ci
+types:
+ - feat
+ - fix
+ - improvement
+ - docs
+ - style
+ - refactor
+ - perf
+ - test
+ - build
+ - ci
+ - chore
+ - revert
+ - rfc
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 0000000000..0ef631e003
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,66 @@
+# Configuration for probot-stale - https://github.com/probot/stale
+
+# Number of days of inactivity before an Issue or Pull Request becomes stale
+# daysUntilStale: 60
+
+# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
+# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
+# daysUntilClose: 7
+
+# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
+onlyLabels: []
+
+# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
+# exemptLabels:
+# - backlog
+
+# Set to true to ignore issues in a project (defaults to false)
+exemptProjects: false
+
+# Set to true to ignore issues in a milestone (defaults to false)
+exemptMilestones: false
+
+# Set to true to ignore issues with an assignee (defaults to false)
+exemptAssignees: false
+
+# Label to use when marking as stale
+staleLabel: wontfix
+
+# Comment to post when marking as stale. Set to `false` to disable
+# markComment: >
+# This issue has been automatically marked as stale because it has not had
+# recent activity. It will be closed if no further activity occurs. Thank you
+# for your contributions.
+
+# Comment to post when removing the stale label.
+# unmarkComment: >
+# Your comment here.
+
+# Comment to post when closing a stale Issue or Pull Request.
+# closeComment: >
+# Your comment here.
+
+# Limit the number of actions per hour, from 1-30. Default is 30
+limitPerRun: 30
+
+# Limit to only `issues` or `pulls`
+# only: issues
+
+# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
+pulls:
+ daysUntilStale: 15
+ daysUntilClose: 7
+ markComment: >
+ This pull request has been automatically marked as stale.
+ It will be closed if no further activity occurs.
+ Thank you for your contributions.
+
+issues:
+ daysUntilStale: 30
+ daysUntilClose: 7
+ markComment: >
+ This issue has been automatically marked as stale.
+ It will be closed if no further activity occurs.
+ Thank you for your contributions.
+ exemptLabels:
+ - backlog
diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml
new file mode 100644
index 0000000000..86cfce3815
--- /dev/null
+++ b/.github/workflows/deploy-docs.yml
@@ -0,0 +1,78 @@
+name: Deploy Docs
+on:
+ push:
+ branches:
+ - release/next
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v1
+ - shell: bash
+ run: |
+ echo "1.0.`date +%s`" > version.txt
+ - name: Upload version artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: version
+ path: version.txt
+ - name: Get the version
+ id: get_version
+ run: echo ::set-output name=VERSION::$(cat version.txt)
+ - name: Build and publish docker image
+ uses: elgohr/Publish-Docker-Github-Action@master
+ with:
+ name: docs-storefrontcloud-io/v2:${{ steps.get_version.outputs.VERSION }}
+ registry: registry.storefrontcloud.io
+ username: ${{ secrets.DOCS_CLOUD_USERNAME }}
+ password: ${{ secrets.DOCS_CLOUD_PASSWORD }}
+ workdir: .
+ dockerfile: ./packages/core/docs/Dockerfile
+ buildoptions: "--compress"
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - name: Download version artifact
+ uses: actions/download-artifact@v2
+ with:
+ name: version
+ - name: Get the version
+ id: get_version
+ run: echo ::set-output name=VERSION::$(cat version.txt)
+ - uses: chrnorm/deployment-action@releases/v1
+ name: Create GitHub deployment
+ id: deployment
+ with:
+ token: "${{ github.token }}"
+ target_url: https://docs.europe-west1.gcp.storefrontcloud.io/v2
+ environment: production
+ initial_status: in_progress
+ - name: Deploy on docs.europe-west1.gcp.storefrontcloud.io/v2
+ run: |
+ if curl -s -H 'X-User-Id: ${{ secrets.DOCS_CLOUD_USERNAME }}' -H 'X-Api-Key: ${{ secrets.DOCS_CLOUD_PASSWORD }}' -H 'Content-Type: application/json' -X POST -d '{"code":"docs","region":"europe-west1.gcp","additionalApps":{"apps":[{"name":"docs-v2","tag":"${{ steps.get_version.outputs.VERSION }}","image":"registry.storefrontcloud.io/docs-storefrontcloud-io/v2","path":"/v2","port":"80"}]}}' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
+ echo "Instance updated"
+ else
+ echo "Something went wrong during the update process..."
+ exit 1
+ fi
+ - name: Update deployment status (success)
+ if: success()
+ uses: chrnorm/deployment-status@releases/v1
+ with:
+ token: "${{ github.token }}"
+ target_url: https://docs.europe-west1.gcp.storefrontcloud.io/v2
+ state: "success"
+ description: Congratulations! The deploy is done.
+ deployment_id: ${{ steps.deployment.outputs.deployment_id }}
+ - name: Update deployment status (failure)
+ if: failure()
+ uses: chrnorm/deployment-status@releases/v1
+ with:
+ token: "${{ github.token }}"
+ target_url: https://docs.europe-west1.gcp.storefrontcloud.io/v2
+ description: Unfortunately, the instance hasn't been updated.
+ state: "failure"
+ deployment_id: ${{ steps.deployment.outputs.deployment_id }}
diff --git a/.github/workflows/deploy-lighthouse.yml b/.github/workflows/deploy-lighthouse.yml
new file mode 100644
index 0000000000..8e6b54f6c5
--- /dev/null
+++ b/.github/workflows/deploy-lighthouse.yml
@@ -0,0 +1,69 @@
+name: Lighthouse Test
+
+on:
+ workflow_run:
+ workflows:
+ - Deploy to Storefrontcloud
+ types:
+ - completed
+ branches:
+ - master
+ - main
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: chrnorm/deployment-action@releases/v1
+ name: Create GitHub deployment
+ id: deployment
+ with:
+ token: "${{ github.token }}"
+ target_url: https://demo-lighthouse.europe-west1.gcp.storefrontcloud.io
+ environment: production
+ initial_status: in_progress
+ - name: Deploy on demo-lighthouse.europe-west1.gcp.storefrontcloud.io
+ if: github.ref == 'refs/heads/next'
+ run: |
+ if curl -s -H 'X-User-Id: ${{ secrets.DOCS_CLOUD_USERNAME }}' -H 'X-Api-Key: ${{ secrets.DOCS_CLOUD_PASSWORD }}' -H 'Content-Type: application/json' -X POST -d '{
+ "code":"demo-lighthouse",
+ "region":"europe-west1.gcp",
+ "frontContainerVersion":"${{ github.sha }}"
+ }' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
+ echo "Instance updated"
+ else
+ echo "Something went wrong during the update process..."
+ exit 1
+ fi
+ - name: Update deployment status (success)
+ if: success()
+ uses: chrnorm/deployment-status@releases/v1
+ with:
+ token: "${{ github.token }}"
+ target_url: https://demo-lighthouse.europe-west1.gcp.storefrontcloud.io
+ state: "success"
+ description: Congratulations! The deploy is done.
+ deployment_id: ${{ steps.deployment.outputs.deployment_id }}
+ - name: Update deployment status (failure)
+ if: failure()
+ uses: chrnorm/deployment-status@releases/v1
+ with:
+ token: "${{ github.token }}"
+ target_url: https://demo-lighthouse.europe-west1.gcp.storefrontcloud.io
+ description: Unfortunately, the instance hasn't been updated.
+ state: "failure"
+ deployment_id: ${{ steps.deployment.outputs.deployment_id }}
+
+ lighthouse:
+ runs-on: ubuntu-latest
+ needs: deploy
+ steps:
+ - uses: actions/checkout@v2
+ - name: Audit URLs using Lighthouse
+ uses: treosh/lighthouse-ci-action@v7
+ with:
+ urls: |
+ https://demo-lighthouse.europe-west1.gcp.storefrontcloud.io
+ # budgetPath: ./budget.json # test performance budgets
+ uploadArtifacts: true # save results as an action artifacts
+ temporaryPublicStorage: true # upload lighth
diff --git a/.github/workflows/deploy-preview-storefrontcloud.yml b/.github/workflows/deploy-preview-storefrontcloud.yml
new file mode 100644
index 0000000000..da9cf9a3c9
--- /dev/null
+++ b/.github/workflows/deploy-preview-storefrontcloud.yml
@@ -0,0 +1,66 @@
+name: Deploy PR Preview on Storefrontcloud
+on:
+ pull_request:
+ types: [opened, synchronize]
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v1
+ - name: Setup node
+ uses: actions/setup-node@v1
+ with:
+ node-version: "12.x"
+ - name: Build and publish docker image
+ uses: elgohr/Publish-Docker-Github-Action@master
+ with:
+ name: vsf-next-demo-storefrontcloud-io/vue-storefront:${{ github.sha }}
+ registry: registry.storefrontcloud.io
+ username: ${{ secrets.CLOUD_USERNAME }}
+ password: ${{ secrets.CLOUD_PASSWORD }}
+ dockerfile: dev/docker/Dockerfile
+ buildoptions: "--compress"
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - uses: chrnorm/deployment-action@releases/v1
+ name: Create GitHub deployment
+ id: deployment
+ with:
+ token: "${{ github.token }}"
+ environment: preview
+ initial_status: in_progress
+ - name: Deploy on Storefrontcloud.io
+ id: deploy
+ uses: storefrontcloud/storefrontcloud-preview-deploy@0.1.0
+ with:
+ token: "${{ github.token }}"
+ namespace: "vsf-next-demo"
+ username: ${{ secrets.CLOUD_USERNAME }}
+ password: ${{ secrets.CLOUD_PASSWORD }}
+ - name: Comment PR
+ if: success()
+ uses: storefrontcloud/storefrontcloud-comment-pr-preview-deploy@master
+ with:
+ preview_url: '${{ steps.deploy.outputs.preview_url }}'
+ token: "${{ github.token }}"
+ namespace: 'vsf-next-demo'
+ - name: Update deployment status (success)
+ if: success()
+ uses: chrnorm/deployment-status@releases/v1
+ with:
+ token: "${{ github.token }}"
+ target_url: ${{ steps.deploy.outputs.preview_url }}
+ state: "success"
+ description: Congratulations! The deploy is done.
+ deployment_id: ${{ steps.deployment.outputs.deployment_id }}
+ - name: Update deployment status (failure)
+ if: failure()
+ uses: chrnorm/deployment-status@releases/v1
+ with:
+ token: "${{ github.token }}"
+ description: Unfortunately, the instance hasn't been updated.
+ state: "failure"
+ deployment_id: ${{ steps.deployment.outputs.deployment_id }}
\ No newline at end of file
diff --git a/.github/workflows/deploy-storefrontcloud.yml b/.github/workflows/deploy-storefrontcloud.yml
index ec33530597..9ce4ab77bc 100644
--- a/.github/workflows/deploy-storefrontcloud.yml
+++ b/.github/workflows/deploy-storefrontcloud.yml
@@ -3,35 +3,23 @@ on:
push:
branches:
- master
- - develop
- - hotfix/v*
+ - main
+ - release/next
+ - test/next
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v1
- - name: Add theme master
- if: github.ref != 'refs/heads/develop'
- run: |
- git clone --single-branch --branch master https://github.com/DivanteLtd/vsf-default.git ./src/themes/default
- - name: Add theme develop
- if: github.ref == 'refs/heads/develop'
- run: |
- git clone --single-branch --branch develop https://github.com/DivanteLtd/vsf-default.git ./src/themes/default
- name: Setup node
uses: actions/setup-node@v1
with:
- node-version: "10.x"
- - name: Create config file
- run: |
- echo '{"server":{"compression":false,"api":"api-search-query","useOutputCacheTagging":true,"useOutputCache":true,"dynamicConfigReload":true,"dynamicConfigInclude":["redis","elasticsearch","api","graphql","cart","products","orders","users","stock","images","mailchimp","mailer","urlModule"]},"api":{"url":"https://demo.storefrontcloud.io"},"elasticsearch":{"host":"/api/catalog"},"entities":{"attribute":{"loadByAttributeMetadata":true}},"urlModule":{"enableMapFallbackUrl":true},"redis":{"host":"redis"},"graphql":{"host":"https://demo.storefrontcloud.io/graphql"},"cart":{"create_endpoint":"https://demo.storefrontcloud.io/api/cart/create?token={{token}}","updateitem_endpoint":"https://demo.storefrontcloud.io/api/cart/update?token={{token}}&cartId={{cartId}}","deleteitem_endpoint":"https://demo.storefrontcloud.io/api/cart/delete?token={{token}}&cartId={{cartId}}","pull_endpoint":"https://demo.storefrontcloud.io/api/cart/pull?token={{token}}&cartId={{cartId}}","totals_endpoint":"https://demo.storefrontcloud.io/api/cart/totals?token={{token}}&cartId={{cartId}}","paymentmethods_endpoint":"https://demo.storefrontcloud.io/api/cart/payment-methods?token={{token}}&cartId={{cartId}}","shippingmethods_endpoint":"https://demo.storefrontcloud.io/api/cart/shipping-methods?token={{token}}&cartId={{cartId}}","shippinginfo_endpoint":"https://demo.storefrontcloud.io/api/cart/shipping-information?token={{token}}&cartId={{cartId}}","collecttotals_endpoint":"https://demo.storefrontcloud.io/api/cart/collect-totals?token={{token}}&cartId={{cartId}}","deletecoupon_endpoint":"https://demo.storefrontcloud.io/api/cart/delete-coupon?token={{token}}&cartId={{cartId}}","applycoupon_endpoint":"https://demo.storefrontcloud.io/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}"},"products":{"endpoint":"https://demo.storefrontcloud.io/api/product"},"orders":{"endpoint":"https://demo.storefrontcloud.io/api/order"},"users":{"endpoint":"https://demo.storefrontcloud.io/api/user","history_endpoint":"https://demo.storefrontcloud.io/api/user/order-history?token={{token}}","resetPassword_endpoint":"https://demo.storefrontcloud.io/api/user/resetPassword","changePassword_endpoint":"https://demo.storefrontcloud.io/api/user/changePassword?token={{token}}","login_endpoint":"https://demo.storefrontcloud.io/api/user/login","create_endpoint":"https://demo.storefrontcloud.io/api/user/create","me_endpoint":"https://demo.storefrontcloud.io/api/user/me?token={{token}}","refresh_endpoint":"https://demo.storefrontcloud.io/api/user/refresh"},"stock":{"endpoint":"https://demo.storefrontcloud.io/api/stock"},"images":{"baseUrl":"https://demo.vuestorefront.io/img/"},"mailchimp":{"endpoint":"https://demo.storefrontcloud.io/api/ext/mailchimp-subscribe/subscribe"},"mailer":{"endpoint":{"send":"https://demo.storefrontcloud.io/api/ext/mail-service/send-email","token":"https://demo.storefrontcloud.io/api/ext/mail-service/get-token"}}}' > config/local-cloud-demo.json
- echo '{"server":{"compression":false,"api":"api-search-query","useOutputCacheTagging":true,"useOutputCache":true,"dynamicConfigReload":true,"dynamicConfigInclude":["redis","elasticsearch","api","graphql","cart","products","orders","users","stock","images","mailchimp","mailer","urlModule"]},"api":{"url":"https://demo.storefrontcloud.io"},"elasticsearch":{"host":"/api/catalog"},"entities":{"attribute":{"loadByAttributeMetadata":true}},"urlModule":{"enableMapFallbackUrl":true},"redis":{"host":"redis"},"graphql":{"host":"https://demo.storefrontcloud.io/graphql"},"cart":{"create_endpoint":"https://demo.storefrontcloud.io/api/cart/create?token={{token}}","updateitem_endpoint":"https://demo.storefrontcloud.io/api/cart/update?token={{token}}&cartId={{cartId}}","deleteitem_endpoint":"https://demo.storefrontcloud.io/api/cart/delete?token={{token}}&cartId={{cartId}}","pull_endpoint":"https://demo.storefrontcloud.io/api/cart/pull?token={{token}}&cartId={{cartId}}","totals_endpoint":"https://demo.storefrontcloud.io/api/cart/totals?token={{token}}&cartId={{cartId}}","paymentmethods_endpoint":"https://demo.storefrontcloud.io/api/cart/payment-methods?token={{token}}&cartId={{cartId}}","shippingmethods_endpoint":"https://demo.storefrontcloud.io/api/cart/shipping-methods?token={{token}}&cartId={{cartId}}","shippinginfo_endpoint":"https://demo.storefrontcloud.io/api/cart/shipping-information?token={{token}}&cartId={{cartId}}","collecttotals_endpoint":"https://demo.storefrontcloud.io/api/cart/collect-totals?token={{token}}&cartId={{cartId}}","deletecoupon_endpoint":"https://demo.storefrontcloud.io/api/cart/delete-coupon?token={{token}}&cartId={{cartId}}","applycoupon_endpoint":"https://demo.storefrontcloud.io/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}"},"products":{"endpoint":"https://demo.storefrontcloud.io/api/product"},"orders":{"endpoint":"https://demo.storefrontcloud.io/api/order"},"users":{"endpoint":"https://demo.storefrontcloud.io/api/user","history_endpoint":"https://demo.storefrontcloud.io/api/user/order-history?token={{token}}","resetPassword_endpoint":"https://demo.storefrontcloud.io/api/user/resetPassword","changePassword_endpoint":"https://demo.storefrontcloud.io/api/user/changePassword?token={{token}}","login_endpoint":"https://demo.storefrontcloud.io/api/user/login","create_endpoint":"https://demo.storefrontcloud.io/api/user/create","me_endpoint":"https://demo.storefrontcloud.io/api/user/me?token={{token}}","refresh_endpoint":"https://demo.storefrontcloud.io/api/user/refresh"},"stock":{"endpoint":"https://demo.storefrontcloud.io/api/stock"},"images":{"baseUrl":"https://demo.vuestorefront.io/img/"},"mailchimp":{"endpoint":"https://demo.storefrontcloud.io/api/ext/mailchimp-subscribe/subscribe"},"mailer":{"endpoint":{"send":"https://demo.storefrontcloud.io/api/ext/mail-service/send-email","token":"https://demo.storefrontcloud.io/api/ext/mail-service/get-token"}}}' > config/local-cloud-next.json
- echo '{"server":{"compression":false,"api":"api-search-query","useOutputCacheTagging":true,"useOutputCache":true,"dynamicConfigReload":true,"dynamicConfigInclude":["redis","elasticsearch","api","graphql","cart","products","orders","users","stock","images","mailchimp","mailer","urlModule"]},"api":{"url":"https://test.storefrontcloud.io"},"elasticsearch":{"host":"/api/catalog"},"entities":{"attribute":{"loadByAttributeMetadata":true}},"urlModule":{"enableMapFallbackUrl":true},"redis":{"host":"redis"},"graphql":{"host":"https://test.storefrontcloud.io/graphql"},"cart":{"create_endpoint":"https://test.storefrontcloud.io/api/cart/create?token={{token}}","updateitem_endpoint":"https://test.storefrontcloud.io/api/cart/update?token={{token}}&cartId={{cartId}}","deleteitem_endpoint":"https://test.storefrontcloud.io/api/cart/delete?token={{token}}&cartId={{cartId}}","pull_endpoint":"https://test.storefrontcloud.io/api/cart/pull?token={{token}}&cartId={{cartId}}","totals_endpoint":"https://test.storefrontcloud.io/api/cart/totals?token={{token}}&cartId={{cartId}}","paymentmethods_endpoint":"https://test.storefrontcloud.io/api/cart/payment-methods?token={{token}}&cartId={{cartId}}","shippingmethods_endpoint":"https://test.storefrontcloud.io/api/cart/shipping-methods?token={{token}}&cartId={{cartId}}","shippinginfo_endpoint":"https://test.storefrontcloud.io/api/cart/shipping-information?token={{token}}&cartId={{cartId}}","collecttotals_endpoint":"https://test.storefrontcloud.io/api/cart/collect-totals?token={{token}}&cartId={{cartId}}","deletecoupon_endpoint":"https://test.storefrontcloud.io/api/cart/delete-coupon?token={{token}}&cartId={{cartId}}","applycoupon_endpoint":"https://test.storefrontcloud.io/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}"},"products":{"endpoint":"https://test.storefrontcloud.io/api/product"},"orders":{"endpoint":"https://test.storefrontcloud.io/api/order"},"users":{"endpoint":"https://test.storefrontcloud.io/api/user","history_endpoint":"https://test.storefrontcloud.io/api/user/order-history?token={{token}}","resetPassword_endpoint":"https://test.storefrontcloud.io/api/user/resetPassword","changePassword_endpoint":"https://test.storefrontcloud.io/api/user/changePassword?token={{token}}","login_endpoint":"https://test.storefrontcloud.io/api/user/login","create_endpoint":"https://test.storefrontcloud.io/api/user/create","me_endpoint":"https://test.storefrontcloud.io/api/user/me?token={{token}}","refresh_endpoint":"https://test.storefrontcloud.io/api/user/refresh"},"stock":{"endpoint":"https://test.storefrontcloud.io/api/stock"},"images":{"baseUrl":"https://demo.vuestorefront.io/img/"},"mailchimp":{"endpoint":"https://test.storefrontcloud.io/api/ext/mailchimp-subscribe/subscribe"},"mailer":{"endpoint":{"send":"https://test.storefrontcloud.io/api/ext/mail-service/send-email","token":"https://test.storefrontcloud.io/api/ext/mail-service/get-token"}}}' > config/local-cloud-test.json
+ node-version: "12.x"
- name: Build and publish docker image
uses: elgohr/Publish-Docker-Github-Action@master
with:
- name: demo-storefrontcloud-io/vue-storefront:${{ github.sha }}
+ name: vsf-next-demo-storefrontcloud-io/vue-storefront:${{ github.sha }}
registry: registry.storefrontcloud.io
username: ${{ secrets.CLOUD_USERNAME }}
password: ${{ secrets.CLOUD_PASSWORD }}
@@ -46,31 +34,31 @@ jobs:
id: deployment
with:
token: "${{ github.token }}"
- target_url: https://demo.storefrontcloud.io
+ target_url: https://vsf-next-demo.storefrontcloud.io
environment: production
initial_status: in_progress
- - name: Deploy on demo.storefrontcloud.io
- if: github.ref == 'refs/heads/master'
+ - name: Deploy on lovecrafts-demo.storefrontcloud.io
+ if: github.ref == 'refs/heads/next'
run: |
- if curl -s -H "X-User-Id: ${{ secrets.DEMO_CLOUD_USERNAME }}" -H "X-Api-Key: ${{ secrets.DEMO_CLOUD_PASSWORD }}" -H 'Content-Type: application/json' -X POST -d '{"code":"demo","region":"europe-west1.gcp","frontContainerVersion":"${{ github.sha }}"}' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
+ if curl -s -u ${{ secrets.CLOUD_USERNAME }}:${{ secrets.CLOUD_PASSWORD }} -H 'Content-Type: application/json' -X POST -d '{"code":"lovecrafts-demo","frontContainerVersion":"${{ github.sha }}"}' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
echo "Instance updated"
else
echo "Something went wrong during the update process..."
exit 1
fi
- - name: Deploy on next.storefrontcloud.io
- if: contains(github.ref, 'hotfix/v')
+ - name: Deploy on vsf-next-demo.storefrontcloud.io
+ if: github.ref == 'refs/heads/release/next'
run: |
- if curl -s -u ${{ secrets.CLOUD_USERNAME }}:${{ secrets.CLOUD_PASSWORD }} -H 'Content-Type: application/json' -X POST -d '{"code":"next","frontContainerVersion":"${{ github.sha }}"}' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
+ if curl -s -u ${{ secrets.CLOUD_USERNAME }}:${{ secrets.CLOUD_PASSWORD }} -H 'Content-Type: application/json' -X POST -d '{"code":"vsf-next-demo","frontContainerVersion":"${{ github.sha }}"}' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
echo "Instance updated"
else
echo "Something went wrong during the update process..."
exit 1
fi
- - name: Deploy on test.storefrontcloud.io
- if: github.ref == 'refs/heads/develop'
+ - name: Deploy on vsf-next-demo.europe-west1.gcp.storefrontcloud.io
+ if: github.ref == 'refs/heads/test/next'
run: |
- if curl -s "X-User-Id: ${{ secrets.DEMO_CLOUD_USERNAME }}" -H "X-Api-Key: ${{ secrets.DEMO_CLOUD_PASSWORD }}" -H 'Content-Type: application/json' -X POST -d '{"code":"test","region":"europe-west1.gcp","frontContainerVersion":"${{ github.sha }}"}' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
+ if curl -s -H 'X-User-Id: ${{ secrets.DOCS_CLOUD_USERNAME }}' -H 'X-Api-Key: ${{ secrets.DOCS_CLOUD_PASSWORD }}' -H 'Content-Type: application/json' -X POST -d '{"code":"vsf-next-demo","region":"europe-west1.gcp","frontContainerVersion":"${{ github.sha }}"}' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
echo "Instance updated"
else
echo "Something went wrong during the update process..."
@@ -81,7 +69,7 @@ jobs:
uses: chrnorm/deployment-status@releases/v1
with:
token: "${{ github.token }}"
- target_url: https://demo.storefrontcloud.io
+ target_url: https://vsf-next-demo.storefrontcloud.io
state: "success"
description: Congratulations! The deploy is done.
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
@@ -90,7 +78,7 @@ jobs:
uses: chrnorm/deployment-status@releases/v1
with:
token: "${{ github.token }}"
- target_url: https://demo.storefrontcloud.io
+ target_url: https://vsf-next-demo.storefrontcloud.io
description: Unfortunately, the instance hasn't been updated.
state: "failure"
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
diff --git a/.github/workflows/docs-v1-deployment.yml b/.github/workflows/docs-v1-deployment.yml
deleted file mode 100644
index 07e3bdc3f2..0000000000
--- a/.github/workflows/docs-v1-deployment.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-name: Deploy Docs
-on:
- push:
- branches:
- - master
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v1
- - name: Build and publish docker image
- uses: elgohr/Publish-Docker-Github-Action@master
- with:
- name: docs-storefrontcloud-io/v1:${{ github.sha }}
- registry: registry.storefrontcloud.io
- username: ${{ secrets.DOCS_CLOUD_USERNAME }}
- password: ${{ secrets.DOCS_CLOUD_PASSWORD }}
- workdir: docs
- dockerfile: Dockerfile
- buildoptions: "--compress"
- deploy:
- runs-on: ubuntu-latest
- needs: build
- steps:
- - uses: chrnorm/deployment-action@releases/v1
- name: Create GitHub deployment
- id: deployment
- with:
- token: "${{ github.token }}"
- target_url: https://docs.europe-west1.gcp.storefrontcloud.io/v1
- environment: production
- initial_status: in_progress
- - name: Deploy on docs.europe-west1.gcp.storefrontcloud.io/v1
- run: |
- if curl -s -H 'X-User-Id: ${{ secrets.DOCS_CLOUD_USERNAME }}' -H 'X-Api-Key: ${{ secrets.DOCS_CLOUD_PASSWORD }}' -H 'Content-Type: application/json' -X POST -d '{"code":"docs","region":"europe-west1.gcp","additionalApps":{"apps":[{"name":"docs-v1","tag":"${{ github.sha }}","image":"registry.storefrontcloud.io/docs-storefrontcloud-io/v1","path":"/v1","port":"80"}]}}' https://farmer.storefrontcloud.io/instances | grep -q '{"code":200,"result":"Instance updated!"}'; then
- echo "Instance updated"
- else
- echo "Something went wrong during the update process..."
- exit 1
- fi
- - name: Update deployment status (success)
- if: success()
- uses: chrnorm/deployment-status@releases/v1
- with:
- token: "${{ github.token }}"
- target_url: https://docs.europe-west1.gcp.storefrontcloud.io/v1
- state: "success"
- description: Congratulations! The deploy is done.
- deployment_id: ${{ steps.deployment.outputs.deployment_id }}
- - name: Update deployment status (failure)
- if: failure()
- uses: chrnorm/deployment-status@releases/v1
- with:
- token: "${{ github.token }}"
- target_url: https://docs.europe-west1.gcp.storefrontcloud.io/v1
- description: Unfortunately, the instance hasn't been updated.
- state: "failure"
- deployment_id: ${{ steps.deployment.outputs.deployment_id }}
diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml
new file mode 100644
index 0000000000..a904b6e0ce
--- /dev/null
+++ b/.github/workflows/label.yml
@@ -0,0 +1,19 @@
+# This workflow will triage pull requests and apply a label based on the
+# paths that are modified in the pull request.
+#
+# To use this workflow, you will need to set up a .github/labeler.yml
+# file with configuration. For more information, see:
+# https://github.com/actions/labeler
+
+name: Labeler
+on: [pull_request]
+
+jobs:
+ label:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/labeler@master
+ with:
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
diff --git a/.github/workflows/run-e2e-regression.yml b/.github/workflows/run-e2e-regression.yml
index 342f4624ac..c98daeb901 100644
--- a/.github/workflows/run-e2e-regression.yml
+++ b/.github/workflows/run-e2e-regression.yml
@@ -7,13 +7,12 @@ jobs:
name: Run E2E Tests
runs-on: ubuntu-latest
strategy:
+ fail-fast: false
matrix:
package: ["ct", "bp"]
steps:
- name: Checkout code
uses: actions/checkout@v2
- with:
- ref: next
- name: Setup node
uses: actions/setup-node@v2
@@ -31,14 +30,17 @@ jobs:
- name: Install dependencies
run: yarn install
- - name: Build tools
+ - name: Build package
run: yarn build:${{ matrix.package }}
+ env:
+ NUXT_ENV_E2E: true
- name: Run cypress tests
uses: cypress-io/github-action@v2.8.2
with:
start: yarn dev:${{ matrix.package }}
wait-on: 'http://localhost:3000'
+ wait-on-timeout: 180
command: yarn run test:e2e:${{ matrix.package }}:hl
browser: chrome
headless: true
@@ -50,12 +52,18 @@ jobs:
if: ${{ always() }}
run: yarn test:e2e:${{ matrix.package }}:generate:report
- - name: Upload report artifact
+ - name: Upload bp report artifact
uses: actions/upload-artifact@v2
if: ${{ always() }}
with:
- name: report
- path: "packages/$${{ matrix.package }}/theme/tests/e2e/report"
- env:
- bp: boilerplate
- ct: commercetools
+ name: report-bp
+ path: "packages/boilerplate/theme/tests/e2e/report"
+ if-no-files-found: ignore
+
+ - name: Upload ct report artifact
+ uses: actions/upload-artifact@v2
+ if: ${{ always() }}
+ with:
+ name: report-ct
+ path: "packages/commercetools/theme/tests/e2e/report"
+ if-no-files-found: ignore
diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml
index ee730efc5e..5cdc5bee8b 100644
--- a/.github/workflows/run-e2e-tests.yml
+++ b/.github/workflows/run-e2e-tests.yml
@@ -10,12 +10,12 @@ on:
required: false
package:
description: "Package"
- default: "ct"
required: true
+ default: "ct"
browser:
description: "Browser"
- default: "chrome"
required: true
+ default: "chrome"
jobs:
run_e2e_tests:
name: Run E2E Tests
@@ -40,14 +40,17 @@ jobs:
- name: Install dependencies
run: yarn install
- - name: Build tools
+ - name: Build package
run: yarn build:${{ github.event.inputs.package }}
+ env:
+ NUXT_ENV_E2E: true
- name: Run cypress tests
uses: cypress-io/github-action@v2.8.2
with:
- start: yarn dev:${{ github.event.inputs.package }}
+ start: yarn start:${{ github.event.inputs.package }}
wait-on: 'http://localhost:3000'
+ wait-on-timeout: 180
command: yarn run test:e2e:${{ github.event.inputs.package }}:hl
browser: ${{ github.event.inputs.browser }}
headless: true
@@ -58,14 +61,20 @@ jobs:
- name: Generate report
if: ${{ always() }}
- run: yarn test:e2e:${{ github.event.inputs.tags_exclude }}:generate:report
+ run: yarn test:e2e:${{ github.event.inputs.package }}:generate:report
- - name: Upload report artifact
+ - name: Upload bp report artifact
+ if: ${{ always() }}
uses: actions/upload-artifact@v2
+ with:
+ name: report-bp
+ path: "packages/boilerplate/theme/tests/e2e/report"
+ if-no-files-found: ignore
+
+ - name: Upload ct report artifact
if: ${{ always() }}
+ uses: actions/upload-artifact@v2
with:
- name: report
- path: "packages/$${{ github.event.inputs.package }}/theme/tests/e2e/report"
- env:
- bp: boilerplate
- ct: commercetools
+ name: report-ct
+ path: "packages/commercetools/theme/tests/e2e/report"
+ if-no-files-found: ignore
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000000..f31348e589
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,148 @@
+name: Run tests
+
+on:
+ push:
+ branches:
+ - master
+ - main
+ pull_request:
+ branches:
+ - master
+ - main
+
+jobs:
+ prepare_dependencies:
+ name: Prepare dependencies
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup node
+ uses: actions/setup-node@v1
+ with:
+ node-version: '12'
+
+ - name: Get cached dependencies
+ uses: actions/cache@v2
+ with:
+ path: '**/node_modules'
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+
+ - name: Install dependencies
+ run: yarn --network-concurrency 1 --frozen-lockfile
+
+ lint:
+ name: Lint
+ needs: prepare_dependencies
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup node
+ uses: actions/setup-node@v1
+ with:
+ node-version: '12'
+
+ - name: Get cached dependencies
+ uses: actions/cache@v2
+ with:
+ path: '**/node_modules'
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+
+ - name: Run linter
+ run: yarn lint
+
+ validate_core:
+ name: Validate core
+ needs: prepare_dependencies
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup node
+ uses: actions/setup-node@v1
+ with:
+ node-version: '12'
+
+ - name: Get cached dependencies
+ uses: actions/cache@v2
+ with:
+ path: '**/node_modules'
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+
+ - name: Build core
+ run: yarn build:core
+
+ - name: Test cache
+ run: yarn test:cache --coverage
+
+ - name: Test CLI
+ run: yarn test:cli --coverage
+
+ - name: Test core
+ run: yarn test:core --coverage
+
+ - name: Test middleware
+ run: yarn test:core --coverage
+
+ validate_integrations:
+ name: Validate ${{ matrix.integration }}
+ needs: validate_core
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ integration:
+ - boilerplate
+ - commercetools
+ # - shopify
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup node
+ uses: actions/setup-node@v1
+ with:
+ node-version: '12'
+
+ - name: Get cached dependencies
+ uses: actions/cache@v2
+ with:
+ path: '**/node_modules'
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+
+ - name: Build core
+ run: yarn build:core
+
+ - name: Build middleware
+ run: yarn build:middleware
+
+ - name: Build api-client
+ run: cd packages/${{ matrix.integration }}/api-client && yarn build
+
+ - name: Test api-client
+ run: cd packages/${{ matrix.integration }}/api-client && yarn test --passWithNoTests --coverage
+
+ - name: Build composables
+ run: cd packages/${{ matrix.integration }}/composables && yarn build
+
+ - name: Test composables
+ run: cd packages/${{ matrix.integration }}/composables && yarn test --passWithNoTests --coverage
+
+ - name: Build theme
+ run: cd packages/${{ matrix.integration }}/theme && yarn build
+
+ - name: Test theme
+ run: cd packages/${{ matrix.integration }}/theme && yarn test --passWithNoTests
+
+ - name: api-client coverage file
+ id: api-coverage
+ run: echo "::set-output name=exists::$((test -s packages/${{ matrix.integration }}/api-client/coverage/lcov.info && echo 'true') || echo 'false')"
+
+ - name: composables coverage file
+ id: composables-coverage
+ run: echo "::set-output name=exists::$((test -s packages/${{ matrix.integration }}/composables/coverage/lcov.info && echo 'true') || echo 'false')"
diff --git a/.github/workflows/test_vsf1.yml b/.github/workflows/test_vsf1.yml
deleted file mode 100644
index f413b21eac..0000000000
--- a/.github/workflows/test_vsf1.yml
+++ /dev/null
@@ -1,109 +0,0 @@
-name: Run VSF1 tests
-
-on:
- push:
- branches:
- - master
- - develop
- - 'release/v**'
- - 'hotfix/v**'
- pull_request:
- branches:
- - master
- - develop
- - 'release/v**'
- - 'hotfix/v**'
-
-jobs:
- prepare_dependencies:
- name: Prepare dependencies
- runs-on: ubuntu-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Setup node
- uses: actions/setup-node@v1
- with:
- node-version: '10'
-
- - name: Clone default theme
- run: git clone --quiet --single-branch --branch master https://github.com/vuestorefront/vsf-default.git ./src/themes/default
-
- - name: Get cached dependencies
- uses: actions/cache@v2
- with:
- path: '**/node_modules'
- key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-
- - name: Install dependencies
- run: yarn --frozen-lockfile
-
- lint:
- name: Lint
- needs: prepare_dependencies
- runs-on: ubuntu-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Setup node
- uses: actions/setup-node@v1
- with:
- node-version: '10'
-
- - name: Get cached dependencies
- uses: actions/cache@v2
- with:
- path: '**/node_modules'
- key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-
- - name: Run linter
- run: yarn lint
-
- unit_tests:
- name: Unit tests
- needs: prepare_dependencies
- runs-on: ubuntu-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Setup node
- uses: actions/setup-node@v1
- with:
- node-version: '10'
-
- - name: Get cached dependencies
- uses: actions/cache@v2
- with:
- path: '**/node_modules'
- key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-
- - name: Run unit tests
- run: yarn test:unit
-
- build:
- name: Build
- needs: prepare_dependencies
- runs-on: ubuntu-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Setup node
- uses: actions/setup-node@v1
- with:
- node-version: '10'
-
- - name: Clone default theme
- run: git clone --quiet --single-branch --branch master https://github.com/vuestorefront/vsf-default.git ./src/themes/default
-
- - name: Get cached dependencies
- uses: actions/cache@v2
- with:
- path: '**/node_modules'
- key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-
- - name: Run build
- run: yarn build
diff --git a/.gitignore b/.gitignore
index 2ecc09f384..50f7470d83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,36 +1,27 @@
-.DS_Store
-node_modules/
-dist/
-*.icloud
-npm-debug.log
-.vscode/
-.idea/
-config/local.json
-var
-build/config.json
-core/build/config.json
-core/build/cache-version.json
-theme.js
-desktop.ini
-src/themes/catalog/resource/i18n.json
-src/themes/default/resource/i18n.json
-yarn-error.log
-package-lock.json
-cypress/videos
-cypress/screenshots
-core/resource/i18n/de-DE.json
-core/resource/i18n/en-US.json
-core/resource/i18n/es-ES.json
-core/resource/i18n/fr-FR.json
-core/resource/i18n/it-IT.json
-core/resource/i18n/ja-JP.json
-core/resource/i18n/multistoreLanguages.json
-core/resource/i18n/nl-NL.json
-core/resource/i18n/pl-PL.json
-core/resource/i18n/pt-BR.json
-core/resource/i18n/ru-RU.json
-*.iml
+# Dependency directories
+node_modules
-#unit testing
-/test/unit/coverage
-/static
+# Logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# NPM config
+.npmrc
+
+# Yarn Integrity file
+.yarn-integrity
+
+# Rollup generate output
+lib
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Editor directories and files
+.idea
+.vscode
+
+# OS generated files
+.DS_STORE
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 2e81d78770..0000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,8 +0,0 @@
-[submodule "src/modules/vsf-cache-nginx"]
- path = src/modules/vsf-cache-nginx
- url = https://github.com/new-fantastic/vsf-cache-nginx.git
- branch = master
-[submodule "src/modules/vsf-cache-varnish"]
- path = src/modules/vsf-cache-varnish
- url = https://github.com/new-fantastic/vsf-cache-varnish.git
- branch = master
diff --git a/.gitpod.yml b/.gitpod.yml
index acf0da7d59..c87d1a99bf 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -1,19 +1,6 @@
tasks:
- - init: |
- yarn install
- echo '{ "api": { "url": "https://next.storefrontcloud.io" }}' > config/local.json
- yarn build
- command: yarn dev
-
-ports:
- - port: 3000
- onOpen: open-preview
+ - init: yarn install
vscode:
extensions:
- - octref.vetur@0.23.0:TEzauMObB6f3i2JqlvrOpA==
- - dbaeumer.vscode-eslint@2.0.15:/v3eRFwBI38JLZJv5ExY5g==
- - eg2.vscode-npm-script@0.3.11:peDPJqeL8FmmJiabU4fAJQ==
- - formulahendry.auto-close-tag@0.5.6:oZ/8R2VhZEhkHsoeO57hSw==
- - formulahendry.auto-rename-tag@0.1.1:lKCmLIZAiCM0M8AjDnwCLQ==
- - dariofuzinato.vue-peek@1.0.2:oYJg0oZA/6FBnFfW599HRg==
+ - octref.vetur@0.28.0:bW1RGNnmWYQO43JdJgK34w==
diff --git a/.huskyrc.js b/.huskyrc.js
deleted file mode 100644
index 08aa197b01..0000000000
--- a/.huskyrc.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const tasks = arr => arr.join(' && ')
-
-module.exports = {
- 'hooks': {
- 'pre-commit': tasks([
- 'lint-staged'
- ]),
- 'pre-push': tasks([
- 'yarn test:unit'
- ])
- }
-}
diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index 2b6f469f0c..0000000000
--- a/.jshintrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "esversion": 6
-}
diff --git a/.lintstagedrc.js b/.lintstagedrc.js
deleted file mode 100644
index 29c2ede191..0000000000
--- a/.lintstagedrc.js
+++ /dev/null
@@ -1,4 +0,0 @@
-module.exports = {
- "*.{js,vue,ts}": "eslint",
- "**/i18n/*.csv": ["node ./core/scripts/utils/sort-translations.js", "git add"]
-}
diff --git a/.node-version b/.node-version
deleted file mode 100644
index 4ad20b12dd..0000000000
--- a/.node-version
+++ /dev/null
@@ -1 +0,0 @@
->=8.0.0
diff --git a/.nvmrc b/.nvmrc
deleted file mode 100644
index f599e28b8a..0000000000
--- a/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-10
diff --git a/.postcssrc b/.postcssrc
deleted file mode 100644
index f053ebf797..0000000000
--- a/.postcssrc
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = {};
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000000..1a172b10e3
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,8 @@
+{
+ "endOfLine": "lf",
+ "semi": true,
+ "singleQuote": true,
+ "arrowParens": "always",
+ "tabWidth": 2,
+ "bracketSpacing": true
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 9926539384..0000000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,1443 +0,0 @@
-# Changelog
-
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [1.13.0] - UNRELEASED
-
-### Added
-- Added information about i18n & Unit tests in modules to docs - @lukaszjedrasik (#4991)
-- Updated VSF1 insfrastructure's schema - @lukaszjedrasik ([#5531](https://github.com/vuestorefront/vue-storefront/issues/5531))
-
-### Fixed
-- Fixed some typo in docs (#5071)
-
-## [1.12.3] - 2021.06.24
-
-### Added
-
-- Added states.json in core/i18n/resource (#4531)
-- Added phone validation helper (#4980)
-- Configurable enabling min & max price aggregations
-- Storing totals in localStorage to sync it between tabs ([#4733](https://github.com/vuestorefront/vue-storefront/issues/4733))
-- Support for trailing slashes in the route paths - @tdugue @gibkigonzo @Fifciu ([#5372](https://github.com/vuestorefront/vue-storefront/pull/5372))
-
-### Fixed
-
-- Remove redundant user token invalidation code - TerrorSquad (#4533)
-- configurableChildrenImages helper function incorrect loading images - @RakowskiPrzem (#4575)
-- Fix user/register call by adding storeId - @haelbichalex (#4697)
-- refresh categoryMappedFilters after loading attributes in PLP - @gibkigonzo (#4695)
-- Check module registration for wishlist and compare list - gibkigonzo (#4764)
-- Fix gallery image generation by checking if image exists - simonmaass (#4908)
-- Fix getSelectedOption based on attribute_code check - simonmaass (#4851)
-- add new resetUserInvalidation action to clear invalidation state before login,
- clear order history and refresh token after logout,
- add redirection when user is logged out and sees myaccount page - gibkigonzo (#4882)
-- Fix `config.products.filterUnavailableVariants` feature - Ogek (#4923)
-- added 'afterUserProfileUpdated' hook which allows us to take control over update address flow (send notification if something failed)
- move pick allowed modification just before sending data to task managment
- add 'beforeUserProfileUpdate' which allows to modify user object before update - gibkigonzo (#4427)
-- replace lodash with lodash-es for client files - gibkigonzo (#5019)
-- add default personal detail loading on shipment step in checkout when user is logged - (#5040)
-- Got rid of inifnity redirect or page-not-found on refresh category/product view
-- Got rid of memory leak related to dynamic config - tomasz-duda (#4768)
-- servercart-after-diff event payload - Fifciu (#5365)
-- Fix Original Price Calculation typo - @akucharczyk / @lukaszjedrasik (#5472)
-- Purge loader works properly with dynamic config reload - @Fifciu
-- Multi-tab cart-sync in multi-store environment - @cewald (#5711, #5732)
-- Incorrect load of default address in checkout - @lukaszjedrasik ([#4682](https://github.com/vuestorefront/vue-storefront/issues/4682))
-- Error with unknown theme/index.js alias - @Fifciuu (https://github.com/vuestorefront/vue-storefront/pull/5813)
-- ESLint warnings caused by the double import - @lukaszjedrasik
-- Fix Order History Pagination - @AishwaryShrivastav / @lukaszjedrasik ([#4599](https://github.com/vuestorefront/vue-storefront/issues/4599))
-- Fix: Updating URL's params/query params with proper child SKU if options changes - @lukaszjedrasik ([#5981](https://github.com/vuestorefront/vue-storefront/issues/5981))
-- Fix: Passing `newToken: null` as a payload inside `clearCurrentUser` action - @lukaszjedrasik ([#5565](https://github.com/vuestorefront/vue-storefront/issues/5565))
-
-### Changed / Improved
-
-- Moved hardcoded fields from omitSelectedVariantFields.ts to config (#4679)
-- Bump dependencies versions (#4715, #4696, #4951)
-- Using dayjs for dates in taxCalc.ts to make it work properly in Safari (#5364)
-- Awaiting addItem action call inside mergeServerItem action (#5165)
-- Moved `phoneNum` to proper branch - @lukaszjedrasik ([#5730](https://github.com/vuestorefront/vue-storefront/issues/5730))
-- Development hot-reload speed webpack config - ([#5559](https://github.com/vuestorefront/vue-storefront/issues/5559))
-- Set correct type for `productPageVisited` hook - @lukaszjedrasik ([#5997](https://github.com/vuestorefront/vue-storefront/issues/5997))
-
-## [1.12.2] - 2020.07.28
-
-### Added
-
-- **IMPORTANT** for security reasons we added new config `users.allowModification`.
- This can help to dissallow modifying fields that should not be changed by user.
-- Add helmet - enabled by default, you can pass configuration by adding `config.server.helmet.config`.
- More info about helmet configuration https://helmetjs.github.io/docs/
-- Add config `users.tokenInHeader` which allows to send token in header instead in query. Require to set on true same config in vsf-api.
-- Make calculation of bundled products price by options optional - @cewald (#4556)
-
-### Fixed
-
-- remove deprecated value from attributesListQuery query - @gibkigonzo (#4572)
-- Fixed dutch translations - @1070rik (#4587)
-- localForage memory overload fixed. `localForage.preserveCollections` keeps names of collections to be preserved from being cleared. - @prakowski
-- Fixed bug in `restoreQuantity` - getItem never returns cart item - @gibkigonzo (#4619)
-- Separate variant in findProductOption to get parent sku - @gibkigonzo (#4641)
-- Fix wrong value in Cache-Control header for max-age - boehsermoe (#4657)
-
-### Changed / Improved
-
-## [1.12.1] - 2020.06.22
-
-### Added
-
-- Add `purgeConfig` to default.json and purge-config loader - @gibkigonzo (#4540)
-- Load attributes data of attribute-meta for bundled and grouped products - @cewald (#4551)
-- Separate theme installation and add it as yarn init:theme or as a step in yarn installer. - @gibkigonzo (4534, #4552)
-
-### Fixed
-
-- use `config.i18n.defaultLocale` as fallback locale instead of `'en-US'` - @gibkigonzo (#4489)
-- use Math.abs on raw price - @gibkigonzo (#4521)
-- Clears vuex warnings about overriding state by module - @gibkigonzo (#4541)
-
-### Changed / Improved
-
-## [1.12.0] - 2020.06.01
-
-### Added
-
-- Add `vsf-capybara` support as a dependency and extend CLI to support customization - @psmyrek (#4209)
-- Support theme configuration via CLI - @psmyrek (#4395)
-- Allow parent_ids field on product as an alternative to urlpath based breadcrumb navigation (#4219)
-- Pass the original item_id when updating/deleting a cart entry @carlokok (#4218)
-- Separating endpoints for CSR/SSR - @Fifciu (#2861)
-- Added short hands for version and help flags - @jamesgeorge007 (#3946)
-- Add `or` operator for Elasticsearch filters in `quickSearchByQuery` and use exists if value is `null` - @cewald (#3960)
-- Add unified fetch in mappingFallback for all searched entities - @gibkigonzo (#3942)
-- add npm-run-all for parallel build - @gibkigonzo (#3819)
-- Add OutputCaching support for x-vs-store-code - @benjick (#3979)
-- The new search adapter `api-search-query` has been added. When you switch to it, by setting the `config.server.api = "api-search-query"` the ElasticSearch query is being built in the [`vue-storefront-api`](https://github.com/vuestorefront/vue-storefront-api/pull/390) which saves around 400kB in the bundle size as `bodybuilder` is no longer needed in the frontend - @pkarw - #2167
-- This new `api-search-query` adapter supports the `response_format` query parameter which now is sent to the `/api/catalog` endpoint. Currently there is just one additional format supported: `response_format=compact`. When used, the response format got optimized by: a) remapping the results, removing the `_source` from the `hits.hits`; b) compressing the JSON fields names according to the `config.products.fieldsToCompact`; c) removing the JSON fields from the `product.configurable_children` when their values === parent product values; overall response size reduced over -70% - @pkarw
-- The `amp-renderer` module has been disabled by default to save the bundle size; If you'd like to enable it uncomment the module from the `src/modules` and uncomment the `product-amp` and `category-amp` links that are added to the `
` section in the `src/themes/default/Product.vue` and `src/themes/default/Category.vue`
-- Reset Password confirmation page - @Fifciu (#2576)
-- Add `Intl.NumberFormat()`/`toLocaleString()` via polyfill support in NodeJs - @cewald (#3836, #4040)
-- Added `saveBandwidthOverCache` parameter for skipping caching for products data - @andrzejewsky (#3706)
-- New zoom effect for product gallery images - @Michal-Dziedzinski (#2755)
-- Add custom currency separators and amount of fraction digits - @EndPositive (#3553)
-- Product Page Schema implementation as JSON-LD - @Michal-Dziedzinski (#3704)
-- Add `/cache-version.json` route to get current cache version
-- Built-in module for detecting device type based on UserAgent with SSR support - @Fifciu
-- Update to `storefront-query-builder` version `1.0.0` - @cewald (#4234)
-- Move generating files from webpack config to script @gibkigonzo (#4236)
-- Add correct type matching to `getConfigurationMatchLevel` - @cewald (#4241)
-- Support `useSpecificImagePaths` with `useExactUrlsNoProxy` - @cewald (#4243)
-- Adds module which handles cache invalidation for Fastly. - @gibkigonzo (#4096)
-- Add vsf-cache-nginx and vsf-cache-varnish modules - @gibkigonzo (#4096)
-- Added meta info for CMS pages from Magento @mdanilowicz (#4392)
-- Add useful core events to server & logger - @cewald (#4419)
-
-### Fixed
-
-- Fixed `resultPorcessor` typo - @psmyrek
-- Negative price has doubled minus sign - @psmyrek (#4353)
-- Fixed Search product fails for category filter when categoryId is string - @adityasharma7 (#3929)
-- Revert init filters in Vue app - @gibkigonzo (#3929)
-- All categories disappearing if you add the child category name to includeFields - @1070rik (#4015)
-- Fix overlapping text in PersonalDetails component - @jakubmakielkowski (#4024)
-- Redirect from checkout to home with a proper store code - @Fifciu
-- Added back error notification when user selects invalid configuration - @1070rik (#4033)
-- findConfigurableChildAsync - return best match for configurable variant - @gibkigonzo, @cewald (#4042, #4216)
-- use storeCode for mappingFallback url - @gibkigonzo (#4050)
-- `getVariantWithLowestPrice` uses inexistent `final_price` property - @cewald (#4091)
-- Fixed `NOT_ALLOWED_SSR_EXTENSIONS_REGEX` to only match with file extensions having a dot - @haelbichalex (#4100)
-- Fixed problem with not showing error message when placing an order fails - @qiqqq
-- Invoking afterCacheInvalidated server hook in a proper moment - @Fifciu (#4176)
-- Fixed `cart/isVirtualCart` to return `false` when cart is empty - @haelbichalex(#4182)
-- Use `setProductGallery` in `product/setCurrent` to use logic of the action - @cewald (#4153)
-- Use same data format in getConfigurationMatchLevel - @gibkigonzo (#4208)
-- removed possible memory leak in ssr - @resubaka (#4247)
-- Bugfix for reactivity of `current_configuration` in `populateProductConfigurationAsync` - @cewald (#4258)
-- Bugfix for build exception in Node v13.13+ - @cewald (#4249)
-- Convert option ids to string while comparing them in `getProductConfiguration` - @gibkigonzo (#4484)
-- change value to number in price filter - @gibkigonzo (#4478)
-
-### Changed / Improved
-
-- Optimized `translation.processor` to process only enabled locale CSV files - @pkarw (#3950)
-- Remove commit register mapping - @gibkigonzo (#3875)
-- Improved method `findConfigurableChildAsync` - find variant with lowest price - @gibkigonzo (#3939)
-- Removed `product/loadConfigurableAttributes` calls - @andrzejewsky (#3336)
-- Removed unused locales in disabled multistore - @gibkigonzo (#4072)
-- Optimized attributes loading - @andrzejewsky (#3948)
-- Cart optimization can now be used regardless if entity optimization is enabled - @juho-jaakkola (#4198)
-- Improve typescript support for test utils - @resubaka (#4067)
-- Removed `product/loadConfigurableAttributes` calls - @andrzejewsky, @gibkigonzo (#3336)
-- Disable `mapFallback` url by default - @gibkigonzo(#4092)
-- Include token in pricing sync - @carlokok (#4156)
-- Move 'graphql' search adapter from core to src (deprecated) - @gibkigonzo (#4214)
-- Homepage, new products query, uses now `new` attribute - @mdanilwoicz
-- Refactor product module, more info in upgrade notes- @gibkigonzo (#3952, #4459)
-- Move default theme to separate repository https://github.com/vuestorefront/vsf-default - @gibkigonzo (#4255)
-- add two numbers after dot to price by default, calculate default price for bundle or grouped main product, update typing, add fallback to attribute options - @gibkigonzo (#4476)
-- udpate yarn and filter shipping methods for instant checkout - @gibkigonzo (#4480)
-- add attribute metadata search query, add parentId - @gibkigonzo (#4491)
-
-## [1.11.4] - 2020.05.26
-
-### Added
-
-
-### Changed / Improved
-
-- use yarn in cli installer - @gibkigonzo (#4292)
-- disable out of stock notification when config.stock.allowOutOfStockInCart is true - @gibigonzo (#4340)
-
-
-### Fixed
-
-- Use LRU as object contructor based on newest changes in module - @gibkigonzo (#4242)
-- Fixed ESC button action (minicart, wishlist) - @mdanilowicz (#4393)
-- Fixes problems related to tax calculation and price filter in multistore setup - @juho-jaakkola (#4376)
-- Blank order details page - @mdanilowicz (#4382)
-- upadate cart hash after sync with backend - @gibkigonzo (#4387)
-- exit from errorHandler after redirection - @gibkigonzo (#4246)
-- add redirection in component for simple product related to configurable product - @gibkigonzo (#4359)
-- disable sending carrier_code or method_code for virtual products,
- adjust vue-carousel and vuelidate to newest versions api,
- add aplha validators for register fields - @gibkigonzo (#4455, #4461)
-
-## [1.11.3] - 2020.04.27
-
-### Changed / Improved
-
-- The default config file is now in more human-readable format - @juho-jaakkola (#4197)
-- Create only once aside async component - @gibkigonzo (#4229, #4268)
-
-### Fixed
-- Fixes when having multiple custom options with overlapping option_type_id values, selecting 1 changes the others - @carlokok (#4196)
-- Update eslint and fix code style. - @gibkigonzo (#4179 #4181)
-- Fixes bug that caused addToCart action not to display messages to user - @juho-jaakkola (#4185)
-- add missing cache tags for category and product - @gibkigonzo (#4173)
-- add ssrAppId to avoid second meta render on csr - @gibkigonzo (#4203)
-- take control over default broswer behavior and use saved category page size to load prev products - @gibkigonzo (#4201)
-- update getCurrentCartHash after add/remove coupon - @gibkigonzo (#4220)
-- update replaceNumberToString, so it will change ONLY numbers to string - @gibkigonzo (#4217)
-- allow empty shipping methods in checkout - @gibkigozno (#4192)
-- configure products before price update - this is needed to have variant sku as product sku - @gibkigonzo (#4053)
-- omit stock and totals when creating cart hash, it is not needed to compare products - @gibkigozno (#4235, #4273)
-
-## [1.11.2] - 2020.03.10
-
-### Added
-
-- Add `isBackRoute` that informs if user returns to route, skip loading products for category if he does - @gibkigonzo (#4066)
-- Add server context to async data loader - @gibkigonzo (#4113)
-- Add preload and preconnect for google font - @gibkigonzo (#4121)
-
-### Changed / Improved
-
-- optimizations - improved prefetch strategy - @gibkigonzo (#4080)
-- improvements to Finnish translations - @evktalo (#4116)
-- Radio button now allows separate checked, value and name attributes - @EndPositive (#4098)
-- Update backwards compatible dependencies - @simonmaass (#4126)
-
-### Fixed
-
-- add disconnect and sync options for cart/clear - @gibkigonzo (#4062)
-- add '1' as searched value for 'is_user_defined' and 'is_visible' (createAttributesListQuery) - @gibkigonzo (#4075)
-- Fix possibility to add same SKU with different custom options to the cart - @Michal-Dziedzinski (#3595)
-- Fix `calculateProductTax` to find matching tax rules from ES for current product - @DylannCordel (#4056)
-- Set `totals` in products in cart always in reactive way - @psmyrek (#4079)
-- Fix sync cart between tabs - @Michal-Dziedzinski (#3838)
-- Add currentRoute to url module and return cached requests - @gibkigonzo (#4077, #4066)
-- Hide original radio button behind built label - @EndPositive (#4098)
-- Disable overriding `route` state in **INITIAL_STATE** - @gibkigonzo (#4095)
-- Fix gtm order placement event when user was guest - @Michal-Dziedzinski (#4064)
-- Fix gtm event switched properties - @Michal-Dziedzinski (#4106)
-- Group 'productChecksum' and 'productsEquals' logic for all supported products types. Remove 'checksum' when editing product.
- Remove and add coupon when user login Remove 'NA' as default company. Show qty in microcart for all types of product.
- Remove preload font - it gives good performance, but vue-meta refresh page, because there is script onload. - @gibkigonzo (#4128)
-- Keep old category before route is resolved - @gibkigonzo (#4124)
-- Added comments in 'productsEqual' and change logic for different types of products. Remove login user after order in Checkout. Allow changing qty for 'group' and 'bundle'.products - @gibkigonzo (#4144)
-- Fix incorrect root categories when extending includeFields - @Michal-Dziedzinski (#4090)
-- Add onlyPositive prop to BaseInputNumber to not allow user type negative value - @Michal-Dziedzinski (#4136)
-- Await for cart/authorize while login user - @gibkigonzo (#4133)
-- Fixed `NOT_ALLOWED_SSR_EXTENSIONS_REGEX` to only match with file extensions having a dot - @haelbichalex (#4100)
-- Add lazy load for vue-carousel - @gibkigonzo (#4157)
-
-## [1.11.1] - 2020.02.05
-
-### Added
-
-- Add `ProductPrice` component with bundleOptions and customOptions prices - @gibkigonzo (#3978)
-- Add lazy create cart token - @gibkigonzo (#3994)
-
-### Changed / Improved
-
-- Set cache tag when loading a category - @haelbichalex (#3940)
-- In development build `webpack.config.js` in theme folder is now called without the `default` key - @psmyrek
-
-### Fixed
-
-- Added Finnish translations - @mattiteraslahti and @alphpkeemik
-- Updated Estonian translations to match 1.11 - @alphpkeemik
-- CookieNotification CSR&SSR mismatch fixed - @Fifciu (#3922)
-- The attribute filter in `attribute/list` was not filtering the already loaded attributes properly - @pkarw (#3964)
-- Update `hasProductErrors` in Product component and support additional sku in custom options - @gibkigonzo (#3976)
-- Fixed logic for generating \${lang}.json files in multi-store setup - @jpkempf
-- Fixed logic for collecting valid locales in single-store, multi-lang setup - @jpkempf
-- Make initial custom option value reactive - @gibkigonzo
-- Fixed No image thumbnails leaded on 404 page - @andrzejewsky (#3955)
-- Fixed Stock logic not working with manage_stock set to false - @andrzejewsky - (#3957)
-- Support old price format in `ProductPrice` - @gibkigonzo (#3978)
-- Fixed product bundle comparison condition - @gk-daniel (#4004)
-- Add event callback for checkout load initial data - @gibkigonzo(#3985)
-- Fixed `Processing order...` modal closing too early - @grimasod (#4021)
-- Keep registered payment methods after `syncTotals` - @grimasod (#4020)
-- Added status code to the cache content and use it in cache response - @resubaka (#4014)
-- Fixed sku attribute is missing on compare page - @gibkigonzo (#4036)
-- Fixed z-index for aside in compare list - @gibkigonzo (#4037)
-- Disable checking max quantity when manage stock is set to false - @gibkigonzo (#4038)
-- Add products quantity only when token is created - @gibkigonzo (#4017)
-- Revert init filters in Vue app - add storeView to global/store and pass it to filters - @gibkigonzo (#3929)
-- Fix v-model not working in BaseRadioButton - @lukeromanowicz (#4035)
-- always keep filters values as array of object - @gibkigonzo (#4045)
-- Fix ecosystem config to work with ts-node - @andrzejewsky (#3981)
-
-## [1.11.0] - 2019.12.20
-
-### Added
-
-- Add unit tests for `core/modules/url` - @dz3n (#3469)
-- Add unit test for `core/modules/checkout` - @psmyrek (#3460)
-- Add defense against incomplete config in ssr renderer - @oskar1233 (#3774)
-- Add unit tests for `core/modules/order` - @dz3n (#3466)
-- Add unit tests for `core/modules/user` - @dz3n (#3470)
-- Add to cart from Wishlist and Product listing for simple products - @Dnd-Dboy, @dz3n (#2637)
-- Add global Category and Breadcrumb filters, defined in local.json - @grimasod (#3691)
-- Add constant which conditions the number of products loading per page - @AdKamil (#3630)
-- Added price filtering key as config - @roywcm
-
-### Fixed
-
-- Fixed missing parameter to query function from cms/store/block/actions - @georgiev-ivan (#3909)
-- Always close zoom overlay after changing product - @psmyrek (#3818)
-- Fixed problem with cutting image height in category page on 1024px+ screen res - @AdKamil (#3781)
-- Fixed null value of search input - @AdKamil (#3778)
-- Fixed product sorting - @AdKamil (#3785)
-- Fixed displaying `sale` and `new` mark - @andrzejewsky (#3800)
-- Fixed sorting on category page and product tile sizing - @andrzejewsky (#3817)
-- Redirect from simple product using url_path - @benjick (#3804)
-- Mount app in 'beforeResolve' if it's not dispatched in 'onReady' - @gibkigonzo (#3669)
-- Fixed AMP pages - @andrzejewsky (#3799)
-- Fixed Product page breadcrumbs problem when products are in multiple categories in different branches of the category tree - @grimasod (#3691)
-- Change translation from jp-JP to ja-JP - @gibkigonzo (#3824)
-- Fixed ecosystem config for pm2 - @andrzejewsky (#3842)
-- Fixed `mappingFallback` for extending modules - @andrzejewsky (#3822)
-- Fixed adding products search results to category-next product store - @grimasod (#3877)
-- Use `defaultSortBy` for sorting category products by default @haelbichalex (#3873)
-- Fixed some potential mutations of Config object in `catalog` and `catalog-next` - @grimasod (#3843)
-- Set `null` as default value for custom option in product page - @gibkigonzo (#3885)
-- Fixed Breadcrumb filters - apply to second category fetch - @grimasod (#3887)
-- Fixed `config.storeViews.commonCache` being ignored - @grimasod (#3895)
-- Fixed static pages, password notification, offline mode #3902 - @andrzejewsky (#3902)
-- Fixed error page display with enabled multistore - @gibkigonzo (#3890)
-- Fixed edit shipping address in my account - @gibkigonzo (#3921)
-- Fetch cms_block content in serverPrefetch method - @gibkigonzo (#3910)
-- Fixed saving invalidated user token - @andrzejewsky (#3923)
-- Keep category products objects on ssr - @gibkigonzo (#3924)
-- product breadcrumbs - check if current category is not highest one - @gibkigonzo (#3933)
-
-### Changed / Improved
-
-- Changed pre commit hook to use NODE_ENV production to check for debugger statements - @resubaka (#3686)
-- Improve the readability of 'getShippingDetails()' and 'updateDetails()' method of UserShippingDetails component - @adityasharma7 (#3770)
-- Keep git after yarn install in dockerfile - @ddanier (#3826)
-- Update the Storage Manager shipping details cache immediately when then Vuex checkout store is updated - @grimasod (#3894)
-
-## [1.11.0-rc.2] - 2019.10.31
-
-### Added
-
-- Add defense for incomplete config in preferchCachedAttributes helper
-- Add unit test for \`core/modules/cms\` - @krskibin (#3738)
-
-### Fixed
-
-- Fixed deprecated getter in cmsBlock store - @resubaka (#3683)
-- Fixed problem around dynamic urls when default storeView is set with appendStoreCode false and url set to / . @resubaka (#3685)
-- Fixed three problems you can run into when you have bundle products - @resubaka (#3692)
-- Reset nested menu after logout - @gibkigonzo (#3680)
-- Fixed handling checkbox custom option - @gibkigonzo (#2781)
-- Fixed typos in docs - @afozbek (#3709)
-- Fixed VSF build fails for some people due to lack of dependencies in the container - @krskibin (#3699)
-- Fixed two graphql problems, one with cms_blocks and the other with default sort order - @resubaka (#3718)
-- Allow falsy value for `parent_id` when searching category - @gibkigonzo (#3732)
-- Remove including .map files in service worker cache - @gibkigonzo (#3734)
-- Changed notification message object to factory fn - @gibkigozno (#3716)
-- Load recently viewed module in my account page - @gibkigonzo (#3722)
-- Added validation message for city field on checkout page - @dz3n (#3723)
-- Make price calculation based on saved original prices - @gibkigonzo (#3740)
-- Improving is_comparable to work with booleans and digits - @dz3n (#3697)
-- Fixed displaying categories on search menu - @andrzejewsky (#3758)
-- Fixed broken link for store locator - @andrzejewsky (#3754)
-- Fixed instant checkout functionality - @andrzejewsky (#3765)
-- Fixed links to the promoted banners - @andrzejewsky (#3753)
-- Fixed missing parameter in the compare list - @andrzejewsky (#3757)
-- Fixed product link on mobile - @andrzejewsky (#3772)
-- Custom module `ConfigProvider` aren't called anymore - @cewald (#3797)
-
-### Added
-
-- Added Estonian translations - @alphpkeemik
-- Added support for ES7 - @andrzejewsky (#3690)
-- Added unit tests for `core/modules/mailer` - @krskibin (#3710)
-- Get payment methods with billing address data - @rain2o (#2878)
-- Added custom page-size parameter for `category-next/loadCategoryProducts` action - @cewald (#3713, #3714)
-- Remove unused dayjs locales - @gibkigonzo (#3498)
-- check max quantity in microcart - @gibkigonzo (#3314)
-- Add unit tests for `core/modules/newsletter` - @psmyrek (#3464)
-- Add unit test for `core/modules/wishlist` - @psmyrek (#3471)
-
-### Changed / Improved
-
-- Use `encodeURIComponent` to encode get parameters in `multimatch.js` - @adityasharma7 (#3736)
-
-## [1.11.0-rc.1] - 2019.10.03
-
-### Added
-
-- Add unit testing to Husky on pre-push hook - @mattheo-geoffray (#3475)
-- Add unit testing on breadcrumbs feature - @mattheo-geoffray (#3457)
-- HTML Minifier has been added, to enable it please switch the `config.server.useHtmlMinifier` - @pkarw (#2182)
-- Output compression module has been added; it's enabled by default on production builds; to disable it please switch the `src/modules/serrver.ts` configuration - @pkarw (#2182)
-- Sort CSV i18n files alphabetically in pre-commit Git hook - @defudef (#2657)
-- Cache invalidate requests forwarding support - @pkarw (#3367)
-- Extend storeview config after another storeview in multistore mode - @lukeromanowicz (#3057, #3270)
-- Default storeview settings are now overridden by specific storeview settings - @lukeromanowicz (#3057)
-- Apache2 proxy header support for store based on host - @resubaka (#3143)
-- Items count badges for Compare products and wishlist icons at header - @vishal-7037 (#3047)
-- Added product image in order summary - @obsceniczny (#2544)
-- Add icons on the product tiles that allow to add to the wish list and to the list to compare products from the list of products - @Michal-Dziedzinski (#2773)
-- Get also none product image thumbnails via API - @cewald, @resubaka (#3207)
-- Added a config option `optimizeShoppingCartOmitFields` - @EmilsM (#3222)
-- Added information on the number of available products - @Michal-Dziedzinski (#2733)
-- Added possibility to change color or size of the product that is already in the cart - @andrzejewsky (#2346)
-- Experimental static files generator - @pkarw (#3246)
-- Added price formatting based on locales in multistore - @andrzejewsky (#3060)
-- Added support for tax calculation where the values from customer_tax_class_ids is used - @resubaka (#3245)
-- Added loading product attributes (`entities.productListWithChildren.includeFields`) on category page - @andrzejewsky (#3220)
-- Added config to set Cache-Control header for static assets based on mime type - @phoenix-bjoern (#3268)
-- Improve `category-next/getCategoryFrom` and `category-next/getCurrentCategory` to be more flexible - @cewald (#3295)
-- Added test:unit:watch with a workaround of a jest problem with template strings - @resubaka (#3351)
-- Added test to multistore.ts so it is nearly fully unit tested - @resubaka (#3352)
-- Added test:unit:watch with a workaround of a jest problem with template strings - @resubaka (#3351, #3354)
-- Added test to helpers/index.ts so it is partly tested - @resubaka (#3376, 3377)
-- Added hooks in cart module - @andrzejewsky (#3388)
-- Added config for the defaultTitle compitable with multistore - @cnviradiya (#3282)
-- Added husky package to manage lint check only for staged files in git @lorenaramonda (#3444)
-- Change text from "is out of the stock" to "is out of stock" - @indiebytes (#3452)
-- Added general purpose hooks - @andrzejewsky (#3389)
-- Added loading of your own searchAdaptor - @resubaka (#3405K)
-- Added lazy hydration for home page - @filrak (#3496, #3565)
-- Added i18n support for modules - @dz3n (#3369)
-- Added support for creating localized child routes - @gibkigonzo (#3489)
-- Added tests for actions and mutations in 'core/modules/recently-viewed' - @gibkigonzo (#3467)
-- Added tests for actions, mutations and components in 'core/modules/compare' - @gibkigonzo (#3467)
-- Added support to load tracing libs at the start of the app - @resubaka (#3514, #3566)
-- Added tests for actions and mutations in 'core/modules/notification' - @gibkigonzo (#3465)
-- Added tests for actions, mutations and helpers in 'core/modules/review' - @gibkigonzo (#3468)
-- Add new Google-Tag-Manager module using new module registration - @cewald (#3524, #3509)
-- Exclude GTM product attributes setup into config json - @dlandmann, @cewald (#3509, #3524)
-- Add configuration option to format currency sign placement and space in price - @cewald (#3574)
-- Add ability to pass `pageSize` and `currentPage` to order history API call for pagination - @rain2o
-- Added italian translations - @lorenaramonda (3076)
-- Route Manager Queue for adding routes efficiently and with an optional priority - @grimasod (#3540)
-- Added tests for cart module actions - @andrzejewsky (#3023)
-- Fixed a problem with type changes in the state when extending a store - @resubaka (#3618)
-
-### Fixed
-
-- Attributes loader, breadcrumbs loader fixes - @pkarw (#3636)
-- Fix for the product attribute labels displayedd on the PDP - @pkarw (#3530)
-- Fix the mix of informal and polite personal pronouns for German translations - @nhp (#3533)
-- Fix for comparison list being not preserved between page reloads - @vue-kacper (#3508)
-- Fix 'fist' typos - @jakubmakielkowski (#3491)
-- Fix for wrong breadcrumb urls in the multistore mode - @pkarw (#3359)
-- Fix for displaying gallery images for unavaialble product variants - @pkarw (#3436)
-- Fix for `null` in search query input - @pkarw (#3474)
-- Unable to place order has been fixed; the `entities` module was wrongly imported - @pkarw (#3453)
-- Fixed product link in wishlist and microcart - @michasik (#2987)
-- Fixed naming strategy for product prices - `special_priceInclTax` -> `special_price_incl_tax`, `priceInclTax` -> `price_incl_tax`, `priceTax` -> `price_tax`; old names have been kept as @deprecated - @pkarw (#2918)
-- The `final_price` field is now being used for setting the `special_price` or `price` of the product (depending on the value); `final_price` might been used along with `special_price` with Magento for the products with activated catalog pricing rules - @pkarw (#3099)
-- Resolve problem with getting CMS block from cache - @qiqqq (#2499)
-- Make image proxy url work with relative base url - @cewald (#3158)
-- Fixed memory leak with enabled dynamicConfigReload - @dimasch (#3075)
-- Fixed error for the orderhistory null for google-tag-manager extension - @cnviradiya (#3195)
-- Fixed swatches not rendering properly at product detail page issue - @vishal-7037 (#3206)
-- Fixed label of configurable options in cart after product just added - @cheeerd (#3164)
-- Fixed eslint warning in Product Page, removed v-if from v-for node - @przspa (#3181)
-- Fixed aspect ratio in ProductImage component - @przspa (#3187)
-- Fixed AMP Product page - @przspa (#3227)
-- Fixed when store has updated, but plugin didn't called - @serzilo (#3238)
-- Fixed first call of prepareStoreView when SSR - @resubaka (#3244)
-- Add ./packages as volume to docker-compose.yml - @cewald (#3251)
-- Fixed mail sending and add error logger - @Michal-Dziedzinski (#3265)
-- Fixed page not found http status code - @phoenix-bjoern (#3243)
-- Fixed missing coupon code after user logged in - @andrzejewsky (#3153)
-- Fixed bug around appendStoreCode in formatCategoryLink. - @resubaka (#3306)
-- Fixed static category links in cms contents on homepage and MinimalFooter - @MariaKern (#3292)
-- Fixed tax calulaction where products was send as parameter but products.items where the right paramater - @resubaka (#3308)
-- Fixed module extendStore for array property inside store - @przspa (#3311)
-- Fixed ordering of the categories and subcategories in sidebar - @andrzejewsky (#2665)
-- Some SSR problems with urlDispatcher during multireloading page - @patzick (#3323)
-- Fixed two bugs in `category-next/getCategoryFrom` (#3286) and `category-next/getCurrentCategory` (#3332) - @cewald (#3295)
-- Fixed login popup close icon position - @przspa (#3393)
-- Fixed styles for original price on Wishlist sidebar - @przspa (#3392)
-- Redirect loop on dispatching dynamic routes in CSR running multistore mode - @cewald, @lukeromanowicz, @resubaka (#3396)
-- Adjusted ProductVideo props to right names - @przspa (#3263)
-- Fixed Doubled SKU row in compare tab - @manvendra-singh1506 (#3447)
-- Fixed warning in product details because of duplicate `product` property in `AddToCompare` mixin - @cewald (#3428)
-- Fixed adding unconfigured product to cart from homepage - @lukeromanowicz (#3512)
-- Fixed "Clear Wishlist" Button - @dz3n (#3522)
-- Fixed hash in dynamically resolved urls causing resolving issues - @lukeromanowicz (#3515)
-- Fix invalid routes in ButtonOutline and ButtonFull - @lukeromanowicz (#3541, #3545)
-- Fix adding notification with 'hasNoTimeout' after normal notification - @gibkigonzo (#3465)
-- Logged-in user's shipping address on checkout page - @przspa (#2636)
-- Fix for the "add to cart" test
-- Fixed error with dayjs when locale is 2-digit (without a '-') @rain2o (#3581)
-- Fix applying coupon - @andrzejewsky (#3578)
-- Prevent caching storage instance in plugin module scope - @gibkigonzo (#3571)
-- Fixed incorrect image sizes in related section on product page - @andrzejewsky (#3590)
-- Fix typo on default language - @lorenaramonda (#3076)
-- Remove race condition while loading locale messages - @gibkigonzo (#3602)
-- Fix displaying same country twice in the in the country switcher - @andrzejewsky (#3587)
-- Fixed resolving store code on SSR - @andrzejewsky (#3576)
-- Clear user data if error occurs while login - @gibkigonzo (#3588)
-- Fix loading bestsellers on 404 error page - @andrzejewsky (#3540)
-- Remove modifying config by reference in multistore - @gibkigonzo (#3617)
-- Add translation key for add review - @gibkigonzo (#3611)
-- Add product name prop to reviews component - @gibkigonzo (#3607)
-- Show default cms pages when current store code is not equals to default - @andrzejewsky (#3579)
-- Fix login errors with mailchimp - @gibkigonzo (#3612)
-- Hydration error on homepage - @patzick (#3609)
-- Fix adding products with custom options - @andrzejewsky (#3597)
-- check silentMode in errors on the same level as task.silent - @gibkigonzo (#3621)
-- Add missing parameters (`size`,`start`) to `quickSearchByQuery()` in `attribute/list` action - @cewald (#3627)
-- Fix breadcrumb homepage link in cms static pages - @andrzejewsky (#3631)
-- Fixed special price that can break when you change pages (browser navigation for/back) or just go from category to product page - @resubaka (#3638)
-- Fixed problem with losing browser history - @andrzejewsky (#3642)
-- Fixed wrong links on the static pages - @andrzejewsky (#3659)
-- Fixed problem with changing quantity in offline mode on product page - @andrzejewsky (#3662)
-- Fixed problem with extending storeView configuration - @andrzejewsky (#3655)
-- Removed infinite loop when changing checkbox in shipping details - @gibkigonzo (#3656)
-- Fixed displaying single order in the profile - @andrzejewsky (#3663)
-- Make microcart ui consistent for all types of products - @gibkigonzo (#3673)
-- Fixed missing storeCode in metaInfo - @andrzejewsky (#3674)
-- Removed showing popup when you have just logged out - @andrzejewsky (#3680)
-
-### Changed / Improved
-
-- Change Product quantity field validation - @jakubmakielkowski (#3560)
-- Update confirmation page in offline mode - @jakubmakielkowski (#3100)
-- Removed server order id from ThankYouPage - @federivo (#3480)
-- Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636)
-- The `attribute.list_by_id` and `attribute.list_by_code` from the `window.__INITIAL_STATE__` which could be even up to 50% of the product page size. - @pkarw (#3281)
-- Can set transition style for Modal content - @grimasod (#3146)
-- Added stock to cart items - @cheeerd (#3166)
-- Moves theme specific stores and components into themes - @michasik (#3139)
-- Decreased the `localStorage` quota usage + error handling by introducing new config variables: `config.products.disablePersistentProductsCache` to not store products by SKU (by default it's on). Products are cached in ServiceWorker cache anyway so the `product/list` will populate the in-memory cache (`cache.setItem(..., memoryOnly = true)`); `config.seo.disableUrlRoutesPersistentCache` - to not store the url mappings; they're stored in in-memory cache anyway so no additional requests will be made to the backend for url mapping; however it might cause some issues with url routing in the offline mode (when the offline mode PWA installed on homescreen got reloaded, the in-memory cache will be cleared so there won't potentially be the url mappings; however the same like with `product/list` the ServiceWorker cache SHOULD populate url mappings anyway); `config.syncTasks.disablePersistentTaskQueue` to not store the network requests queue in service worker. Currently only the stock-check and user-data changes were using this queue. The only downside it introuces can be related to the offline mode and these tasks will not be re-executed after connectivity established, but just in a case when the page got reloaded while offline (yeah it might happen using ServiceWorker; `syncTasks` can't be re-populated in cache from SW) - @pkarw (#3180)
-- Translation file improvements - @vishal-7037 (#3198)
-- Added configuration for max attempt task & cart by pass - @cnviradiya (#3193)
-- Added catching of errors when ES is down - @qiqqq
-- Added debounce for updating quantity method in the cart - @andrzejewsky (#3191)
-- New modules API and rewrite - @filrak, @JCown (#3144)
-- Refactored the vuex user module - @andrzejewsky (#3095)
-- Brazilian Portuguese (pt_BR) translation improved - @pxfm (#3288)
-- Moved store/lib to /lib - @pxfm (#3253)
-- Corrected usage of "configurableChildrenStockPrefetchStatic" setting, refactored logic to tested helper - @philippsander (#859)
-- Improved some of the german translations in spelling and wording - @MariaKern (#3297)
-- Added lazy-hydrate for category products - @andrzejewsky (#3327)
-- Refactored vuex order module - @andrzejewsky (#3337)
-- Changed body no-scroll behavior for overlapped element - @przspa (#3363)
-- `config.dynamicConfigReload` option should use deep copy for `Object.assign()` - @cewald (#3372)
-- Add translation for the defaultTitle - @cnviradiya (#3282)
-- Refactored vuex tax module - @andrzejewsky (#3337)
-- Refactored vuex stock module - @andrzejewsky (#3337)
-- Removed extra unnecessary code from BaseInputNumber - @cnviradiya (#3410)
-- Refactored vuex checkout module - @andrzejewsky (#3337)
-- Moved my-account authentication guard to MyAccount core page - @przspa (#3325)
-- Refactored vuex compare module - @andrzejewsky (#3337)
-- Refactored vuex whishlist module - @andrzejewsky (#3337)
-- Refactored vuex cms module - @andrzejewsky (#3337)
-- Refactored vuex review module - @andrzejewsky (#3337)
-- Refactored vuex newsletter module - @andrzejewsky (#3337)
-- Changed type of Id fields related to product, category and attribute to support numeric as well as string - @adityasharma7 (#3456)
-- Optimized fetching product data on homepage - @lukeromanowicz (#3512)
-- `localizedRoute()` now supports path (and prefers over fullPath) in LocalizedRoute objects - @lukeromanowicz (#3515)
-- Move setting review_status from VSF to VSF-API - @afirlejczyk
-- `localizedRoute()` doesn't return urlDispatcher routes anymore. Use localizedDispatcherRoute instead - @lukeromanowicz (#3548)
-- Improved scrolling in Safari on iOS devices (sidebars) - @phoenixdev-kl (#3551)
-- Improved cookie and offline badges (z-index, overflow) - @phoenixdev-kl (#3552)
-- Improved translations: Replaced concatenations with "named formatting" (see http://kazupon.github.io/vue-i18n/guide/formatting.html#named-formatting) - @phoenixdev-kl (#3550)
-- Added `filterMinimumShouldMatch` to ES queries in order to support ES7 - @pkarw (#1692)
-- Pass `RouteManager` as proxy for router.addRoutes - @gibkigonzo (#3479)
-- Added generic types to hooks - @gibkigonzo
-- Change sku to string when checking products equality - @gibkigonzo (#3606)
-- Pass to `registerModule` all parameters as one object - @gibkigonzo (#3634)
-- Include shipping address data in request for shipping methods for more accurate filtering - @rain2o (#2515)
-- remove 'disabled' flag in storeViews config - @gibkigonzo (#3659)
-
-## [1.10.5] - 28.11.2019
-
-### Fixed
-
-- Disable product mutation when assigning product variant - @gibkigonzo (#3735)
-- Fix issue with Cannot assign to read only property 'storeCode' - @yuriboyko (#3748)
-- Render correct category links when multistore is active - @gibkigonzo (#3753)
-- Disable product mutation when assigning product variant - @gibkigonzo (#3735)
-- Fixed null value of search input - @AdKamil (#3778)
-- Sorting fixed on category page - @AdKamil (#3785)
-- Mount app in 'beforeResolve' if it's not dispatched in 'onReady' - @gibkigonzo (#3669)
-- change translation from jp-JP to ja-JP - @gibkigonzo (#3824)
-- Fix product images, my account link, warnings in console - @andrzejewsky (#3850)
-
-## [1.10.4] - 18.10.2019
-
-### Fixed
-
-- Added try/catch for fetching single product in cart synchronization - @gibkigonzo (#3632)
-- Removed infinite loop when changing checkbox in shipping details - @gibkigonzo (#3656)
-- Remove modifying config by reference in multistore - @gibkigonzo (#3617)
-- Fix displaying same country twice in the in the country switcher - @andrzejewsky (#3587)
-- Remove race condition while loading locale messages - @gibkigonzo (#3602)
-- Fixed special price that can break when you change pages (browser navigation for/back) or just go from category to product page - @resubaka (#3638)
-- Change sku to string when checking products equality - @gibkigonzo (#3606)
-- Fixed problem with losing browser history - @andrzejewsky (#3642)
-- Fixed resolving store code on SSR - @andrzejewsky (#3576)
-- Fixed styles for original price on Wishlist sidebar - @przspa (#3392)
-- Added debounce for updating quantity method in the cart - @andrzejewsky (#3191)
-- Improved scrolling in Safari on iOS devices (sidebars) - @phoenixdev-kl (#3551)
-- Improved cookie and offline badges (z-index, overflow) - @phoenixdev-kl (#3552)
-- Added config to set Cache-Control header for static assets based on mime type - @phoenix-bjoern (#3268)
-- Added catching of errors when ES is down - @qiqqq
-- `localizedRoute()` doesn't return urlDispatcher routes anymore. Use localizedDispatcherRoute instead - @lukeromanowicz (#3548)
-- Fixed hash in dynamically resolved urls causing resolving issues - @lukeromanowicz (#3515)
-- `localizedRoute()` now supports path (and prefers over fullPath) in LocalizedRoute objects - @lukeromanowicz (#3515)
-- Decreased the `localStorage` quota usage + error handling by introducing new config variables: `config.products.disablePersistentProductsCache` to not store products by SKU (by default it's on). Products are cached in ServiceWorker cache anyway so the `product/list` will populate the in-memory cache (`cache.setItem(..., memoryOnly = true)`); `config.seo.disableUrlRoutesPersistentCache` - to not store the url mappings; they're stored in in-memory cache anyway so no additional requests will be made to the backend for url mapping; however it might cause some issues with url routing in the offline mode (when the offline mode PWA installed on homescreen got reloaded, the in-memory cache will be cleared so there won't potentially be the url mappings; however the same like with `product/list` the ServiceWorker cache SHOULD populate url mappings anyway); `config.syncTasks.disablePersistentTaskQueue` to not store the network requests queue in service worker. Currently only the stock-check and user-data changes were using this queue. The only downside it introuces can be related to the offline mode and these tasks will not be re-executed after connectivity established, but just in a case when the page got reloaded while offline (yeah it might happen using ServiceWorker; `syncTasks` can't be re-populated in cache from SW) - @pkarw (#2985)
-- Fixed evaluate detailsLink in the cookie notification - @benjick (#3689)
-
-## Added
-
-- Added german translations - @schwerdt-ke (3076)
-
-## [1.10.3] - 2019.09.18
-
-### Fixed
-
-- Broken sidebar menu in mobile view - @przspa (#3549)
-- UrlDispatcher issues with multistore routes - @pkarw (#3568)
-
-## [1.10.2] - 2019.09.06
-
-### Fixed
-
-- Product image is missing on PDP - @przspa, @NavaneethVijay (#3483)
-- Mounting app when routes are resolved, should completly remove recent SSR errors - patzick (#3499)
-- Fixed `categoriesDynamicPrefetchLevel` that now can be equal to 0 - @pkarw (#3495)
-
-## [1.10.1] - 2019.09.03
-
-### Fixed
-
-- Invalid Discount code error handled by theme - @grimasod (#3385)
-- Fallback for empty value or no_selection child image - @ngongoll (#3397)
-- `order.order_id` was not assigned in the `orders.directBackendSync` mode - @pkarw (#3398)
-- Hydration problems with UrlDispatcher :rocket: - @patzick (#3412)
-- if condition of quoteId from the `_serverDeleteItem` method on core/modules/cart/store/action.ts - @AshishSuhane (#3415)
-- Router beforeEach hooks running many times - @grimasod (#3443)
-- test:unit:watch with a workaround of a jest problem with template strings - @resubaka (#3450, #3351)
-- changed the theme test path so test in theme are going to work - @resubaka (#3455)
-
-## [1.10.0] - 2019.08.10
-
-### Added
-
-- Cast cart_id as string - Order schema expects string, Magento does not generate a string as cart id in every case - @DaanKouters (#3097)
-- Make installer work for windows - @Flyingmana (#2616)
-- "Clear cart" button in the cart - @jablpiotrek (#2587)
-- Global config api path under `api.url` - @BartoszLiburski (#2622)
-- Google Tag Manager integration - @talalus (#841)
-- Portuguese (pt-PT) translation - @xlcnd (#2695)
-- Module Mailchimp is removed in favor of more generic Newsletter - @mdesmet (#2558)
-- `syncTasks` cleanup, `elasticCacheQuota` lowered to 3096KB - @pkarw (#2729)
-- Back-button on orde detail page [#2819]
-- Elastic Search Suggestions in the Search Response - @jpetar (#2853)
-- Linting for typescript files @ResuBaka (#2843)
-- Back to top functionality - @vishal-7037 (#2866)
-- Thumbnail sizes are now configurable within the `config.products.thumbnails` and `config.cart.thumbnails` - @pkarw (#2897)
-- In multistore mode it's now possible to configure multiple instances with different hosts, not only the paths - @lukeromanowicz (#3048, #3052).
-- In multistore mode now there is a possibility to skip appending storecode to url with `appendStoreCode` config option - @lukeromanowicz (#3048, #3052, #3074).
-- Add support for api.url in the Task module - @basvanpoppel (#3011)
-- Products column change functionality - @vishal-7037 (#3017)
-- New Module order-history this provides the pagination via lazy laod - @hackbard (#2810)
-- OrderNumber on ThankYouPage - @Flyingmana (#2743)
-
-### Removed
-
-- The getter `cart/totals` has ben replaced with `cart/getTotals` - @pkarw (#2522)
-- The getter `cart/coupon` has ben replaced with `cart/getCoupon` - @pkarw (#2522)
-- The getter `cart/totalQuantity` has ben replaced with `cart/getItemsTotalQuantity` - @pkarw (#2522)
-- The event `cart-before-save` has been removed - @pkarw (#2522)
-- The action `cart/save` has been removed - @pkarw - (#2522)
-- Some deprecated config options: `useShortCatalogUrls` and `setupVariantByAttributeCode` have been removed - @pkarw (#2915)
-- Button for filters acceptance added with new styles for clear filters button - @965750 (#2811)
-- Added "Clear wishlist" button - @aniamusial (#2806)
-- Make all links with the primary color - @hackbard (#2932)
-
-### Fixed
-
-- Back button on the Error page has been fixed - @pkarw (#3077)
-- Special price got zeroed - @pkarw (#2940)
-- Microcart tax + discount totals fix - @pkarw (#2892)
-- Microcart offline prices now forced down to original prices - @pkarw (#3012)
-- Login/Register errorr message added in case of FetchError (no network connectivity) - @pkarw
-- Products removed from the cart are no longer add back on the conectivity return - @pkarw (#2898)
-- Sidebar menu wasn't possible to scroll - @PanMisza (#2627)
-- Confirmation popup 'Product has beed added to cart' is displayed only once - @JKrupinski (#2610)
-- Moved My Account options from Categories - @bartdominiak (#2612)
-- Fix displaying (and adding) reviews for configurable products - @afirlejczyk (#2660)
-- Image switching fix - @pkarw (#2709)
-- Respect store code on order/PROCESS_QUEUE for shop store - @zulcom (#2727)
-- Unexpected `window.localStorage` use in user module actions - @zulcom (#2735)
-- Fix handling state of same address checkbox in the checkout - @lukeromanowicz (#2730)
-- Fix for `everythingNew` collection on home page - @vishal-7037 (#2761)
-- Fixed display of chevron arrows when there is only one product image - RGijsberts - (#2911)
-- Fixed `Clear cart` option as it previously was not syncing the changes with server - therefore when the user was logged in and cleard the cart all the products were restored - @pkarw (#2587)
-- Fixed the cart sync for a rare case that current cart token was empty - @pkarw (#2592)
-- Use event bus to emit 'application-after-init' event (#2852)
-- Validation of fields 'company name' and 'tax' in checkout doesn't work correctly - @dimasch (#2741)
-- Fixed wrong price displayed in instant checkout module - @vishal-7037 (#2884)
-- Incorrect working of checkboxes in checkout - @dimasch (#2730)
-- Fixed ios input zoom on category page - @victorkadup (#2815)
-- Fixed Load more in Search Results not working when typed to fast - @Flyingmana (#2659, #2946)
-- Subscribe button responsive - @exlo89, @webdiver, @przemyslawspaczek (#2886)
-- Multiple instances for searchAdapter invocations - @bratok (#2960)
-- Fixed issue with login popup state not resetting on mobile devices - @aniamusial (#2699)
-- Fix sortBy for the category page - @Jensderond (#2868)
-- Fixed incorrect prices in Instant Checkout (PR API) - @qiqqq (#2874)
-- Fixed placeholders in gallery in offline mode - @przspa (#2863)
-- Incorrect `user_id` set on the order object - @pkarw (#2966)
-- Problem with SSR render on product page with logged in user - @patzick (#2888)
-- NaN displayed as shipping method - button disabled - @aniamusial (#2881)
-- Logo on the Error page has been fixed - @przspa (#3077)
-- No placeholders / no photos for Get Inspire section in offline - @przspa (#3072)
-- Back icon on product page causing inconsistent behavior - @patzick (#3056)
-- Remove static definition of `cashondelivery` in payment module - @danielmaier42 (#2983)
-- Fixed wrong meta description attribute by page overwrite - @przspa (#3091)
-- Fixed the `AddToCart` button behavior in case of synchronization errors - @pkarw (#3150)
-- User token re-validation fixed to use proper HTTP codes - @pkarw (#3151, #3178)
-- Fixed undefined id of color swatches issue for simple product - @vishal-7037 (#3239)
-- Date filter ignoring format param and locales - @grimasod, @patzick (#3102)
-- Problem with placing an order if shipping method is different than default one - @patzick (#3203)
-- Fixed product video embed on PDP - @juho-jaakkola (#3263)
-- Fixed memory leak with loading DayJS in SSR - @lukeromanowicz (#3310)
-- Fixed invalid localized routes in SSR content of multistore configuration - @lukeromanowicz (#3262)
-- Fixed startSession which loaded from the wrong place the user when multistore was active - @resubaka (#3322)
-- Login after registration - @patzick (#3343)
-- Clear compare list after logout - @patzick (#3348)
-
-### Changed / Improved
-
-- The `cart/sync`, `cart/addItems`, `cart/removeItem` and `cart/updateQuantity` now returns the `diffLog` object with all the notifications, server statuses and items changed during the shopping cart sync
-- The `cart/addItem` is no longer displaying the error messages - please use the `diffLog.clientNorifications` to update the UI instead (take a look at the `AddToCart.ts` for a reference)
-- The action `cart/userAfterLoggedin` got renamed to `cart/authorize` - @pkarw (#2522)
-- The action `cart/refreshTotals` got renamed to `cart/syncTotals` - @pkarw (#2522)
-- The action `cart/serverPull` got renamed to `cart/sync` - @pkarw - (#2522)
-- The way we're getting the user and cart tokens got refactored - @pkarw (#2513)
-- Changed the way to access the configuration. Currently the `rootStore.state.config` is deprecated. Please do use the `import config from 'config'` > `config` instead - @pkarw (#2649)
-- Changed the order number (from `entity_id` to `increment_id`) on MyOrders and MyOrder pages - @pkarw (#2743)
-- Disabled the server cart sync in case user is in the checkout - @pkarw (#2749)
-- Improved ProductGalleryCarousel component to handle nonnumeric options id’s - @danieldomurad (#2586)
-- Number of displayed products is now visible on PLP on desktop - @awierzbiak (#2504)
-- Improved visibility of product SKU in wishlist - @PanMisza (#2606)
-- Instant focus to search input field after click on search icon in navbar - @ca1zr (#2608)
-- Login flow from authorized pages after session expired, show the modal with new error message and redirect after login - @gdomiciano, @natalledm (#2674)
-- Added support for the newest node version - @gdomiciano (#2669)
-- Default storeId from `0` to `1` for multistore and cmsdata logic - @janmyszkier (#2590)
-- Used `$bus` plugin instead of EventBus import - @szafran89 (#2630)
-- BaseCheckbox now uses v-model. @click is not needed anymore - @haukebri (#2630)
-- Image selection supporting multiple configurable options - @mdesmet (#2599)
-- Product video - retrieve video id from 'video_id' field (if set) instead of 'id' - @afirlejczyk
-- Webpack config improvement - @yogeshsuhagiya (#2689)
-- BaseSelect input event - @ResuBaka (#2683)
-- Fixed static file handler to immediately return 404 status for missing files - @grimasod (#2685)
-- Fixed maxAge Response Header for static files and Content-Type for Service Worker - @grimasod (#2686)
-- Default log verbosity is changed to show only errors - @lromanowicz (#2717)
-- Remembering last search query - @webdiver, @patzick (#2787)
-- Extracted ProductImage component to support faster images loading - @przemyslawspaczek (#2925)
-- Improve performace with preventing render 404 page on the server side if some of static content is missed, simple 404 response uses instead - [PHOENIX MEDIA](https://www.phoenix-media.eu/) - Yuri Boyko @yuriboyko, Anton Lobodenko @sniffy1988 (#3002)
-- Logger refactor + now it takes `showErrorOnProduction` into account - @lromanowicz - (#2717)
-- Jest updated from 24.1 to 24.7 along with typings - @lromanowicz - (#2717)
-- Jest globals added to .eslint - @lromanowicz (#2717)
-- The default storeId is taken from the configurations - @nuovecode (#2718)
-- Multitab cart sync - @BartoszLiburski (#2547)
-- Back to login button now shows the Login modal window instead of closing it - @RGijsberts (#2882)
-- Status filter in Related Products query (#2805)
-- The "Apply button was too big, I have reduced its size - @idodidodi (#2807)
-- Added return to shopping button on ThenkYou page - @ZeevGerstner (#2818)
-- Added optional attributes to catalog/product.ts - @ZeevGerstner (#2792)
-- Formatted dates in CHANGELOG.md to match ISO standard - @phoenixdev-kl (#2839)
-- Moved Filter Price Ranges (used for ES aggregations and UI Filter) to the config - @jpetar (#2873)
-- Extra space if not found products in everything new section home page - @cnviradiya (#2846)
-- Load custom fonts without webfont.js - @jahvi (#2944)
-- Added some structured data to product page - @cewald (#2910)
-- Improved the Size Guide feature so it opens in a modal popup instead of a new page - @RGijsberts - (#2913)
-- Refactored Travis config - @Tjitse-E (#3035)
-- Renamed the `stock/check` to `stock/queueCheck` to better emphasize it's async nature; added `stock/check` which does exactly what name suggests - returning the true stock values - @pkarw (#3150)
-- Cart unit tests throwing lots of type warnings - @lukeromanowicz (#3185)
-- Lack of possibility to mock src modules and theme components - @lukeromanowicz (#3185)
-- Outdated signature of Registration hooks for google-tag-manager - @vishal-7037 (#3208)
-- Added serveral missing german translations and fixed german language file structure - @unherz (#3202)
-- Refactored the informal way of adressing to formal in german translation files - @unherz (#3213)
-
-## [1.9.2] - 2019.06.10
-
-### Fixed
-
-- Instant Checkout visible on Safari - @przspa (#2991)
-- Search Sidebar on Safari - @przspa (#2990)
-- Country label style - @przspa (#2989)
-- BaseInputNumber for qty of the product in the cart can change by using arrows - @przspa (#2988)
-- Category load depending on zoom level - @przspa (#2704)
-- Add yarn.lock to dockerfile build - @Flyingmana (#3006)
-- Inconsistent behaviour of picture slider on PDP - @przspa (#2757)
-
-## [1.9.1] - 2019.05.27
-
-### Fixed
-
-- Remove security vulnerabilities by updating project dependencies - @patzick (#2942)
-- Fix Configurable Products not accessible in CSR when children visibility is set to "not visible individually" - @revlis-x (#2933)
-- ProductTile placeholders are visible on SSR - @patzick (#2939)
-
-## [1.9.0] - 2019.05.06
-
-### Added
-
-- The Url Dispatcher feature added for friendly URLs. When `config.seo.useUrlDispatcher` set to true the `product.url_path` and `category.url_path` fields are used as absolute URL addresses (no `/c` and `/p` prefixes anymore). Check the latest `mage2vuestorefront` snapshot and reimport Your products to properly set `url_path` fields - #2010 - @pkarw
-- Unit tests of cart module written in jest - @lukeromanowicz (#2305)
-- validation for UTF8 alpha and alphanumeric characters in most checkout fields - @lromanowicz (#2653)
-- helper to process config urls with default endpoint host `config.api.host` - @patzick (#2858)
-
-### Changed / Improved
-
-- The `core/helpers` parsing URL methods exchanged to `query-string` package - @pkarw (#2446)
-- Unit tests in Karma are now removed in favor of jest - @lukeromanowicz (#2305)
-- Material Icons are loaded asynchronously - @JKrupinski, @filrak (#2060)
-- Update to babel 7 - @lukeromanowicz (#2554)
-
-### Fixed
-
-- For first time setup of the SSR Cache, a local cache-version.json file is required. The path has been removed from .gitignore and a template has been added. - @rio-vps
-- Gallery low quality image in offline mode when high quality already cached - @patzick (#2557)
-- Payment issue when no address set - @szafran89 (#2593)
-- Search component result message when search term is less than 3 letters - @robwozniak (#2561)
-- Removed childSku parameter in url for non-configurable products when using urlDispatcher - @Aekal (#2605)
-- Image lazy loading after SSR reload - @pkarw (#2641)
-- Modules can add custom URL - @pkarw (#2601)
-- Url routes fixes - @pkarw (#2598, #2645, #2614)
-- Fix for shopping cart actions when the `cartId` has been cleared out - @pkarw (#2567)
-- Fixed always common cache issue for multistore - @filrak (#2595)
-- Checkout copy address data will sync on later change - @haukebri (#2661)
-- Fixed Safari style for sort-by select - @haukebri (#2642)
-- fixed My orders in My Profile not refreshed after putting an order - @filrak (#2559)
-- Refreshing product page on mobile device - @patzick (#2484)
-- ESlint throwing errors about undefined jest globals in tests - @lukeromanowicz (#2702)
-- Fixed changing the country when entering shipping address in checkout not updating shipping costs - @revlis-x (#2691)
-- Instant Checkout fix - @qiqqq (#2750)
-- Infinite loop on multistore page after reload - @patzick (#2713)
-- Refreshing MyAccount page on multistore - @patzick (#2780)
-- "Toggle password visible" button in password fields works the right way - @lromanowicz (#2772)
-- Range queries to elasticsearch - @oskar1233 (#2746)
-- BaseInput has min height now to avoid jumping on forms - @patzick (#2771)
-- Orders with invalid address don't stack anymore in the queue and have proper notification popup - @AndreiBelokopytov, @lukeromanowicz (#2663)
-- Offline orders with out of stock products don't stack anymore and get canceled after going back to online - @lukeromanowicz (#2740)
-- Build ServiceWorker on Docker - @patzick (#2793)
-- Product image load after comming back to online - @patzick (#2573)
-- Insufficent validation for city field in checkout address - @lromanowicz (#2653)
-- Incorrect hover activity on the 'filter by categories' in the search view on mobile - @idodidodi (#2783)
-- Unit tests written in JavaScript now support async/await functions and dynamic import - @michaelKurowski, @lukeromanowicz (#2851)
-
-## [1.8.5] - 2019-04-17
-
-### Fixed
-
-- Memory leaks on SSR with Vue.use - @patzick (#2745)
-
-## [1.8.4] - 2019-03-26
-
-### Fixed
-
-- Problem with incomplete category products load for offline use - @patzick (#2543)
-- Category products view crash on scrolling down in offline mode - @patzick (#2569)
-- Default propery issue for the col-xs-\* classes - @cnviradiya (#2558)
-- Wishlist and compare list not cached properly - @filrak (#2580)
-
-### Changed / Improved
-
-- Category and Homepage products are now cached for offline use on SSR entry - @patzick (@1698)
-
-## [1.8.3] - 2019-03-03
-
-### Added
-
-- Payment Request API integration - @qiqqq (#2306)
-- New reactive helper to check online state. Usage: `import { onlineHelper } from '@vue-storefront/core/helpers'` and then `onlineHelper.isOnline` - @patzick (#2510)
-- Cart count config, allows you to display the item count instead of a sum of the item quantities - @pauluse (#2483)
-- Video support in Product Gallery component. - @rain2o (#2433)
-
-### Fixed
-
-- Problem with placing second order (unbinding payment methods after first order) - @patzick (#2195, #2503)
-- Remaking order on user orders page - @patzick (#2480)
-- Images blinking on category page - @pkarw (#2523)
-- state.ts not bound in the module-template - @pkarw (#2496)
-- Validation in the Myprofile section for postcode field - @pkarw (#1317)
-- Non-integer qty of product added to the cart - @pkarw (#2517)
-
-### Changed / Improved
-
-- Fixed an issue where the correct image for a product configuration wasn't set on the product page image carousel. Also added the fix on the productcarousel in the zoom component - @DaanKouters (#2419)
-- Way of creating VS Modules was changed to use factory method instead of explict object creation. - @filrak (#2434)
-- Added clear filters button on desktop also and only show if filters are applied - @DaanKouters (#2342)
-- Improved docs at contributing.md and configuration.md (spelling etc.) - @ruthgeridema (#2421, #2422, #2423, #2425, #2426)
-- Fixed design issue of Country label on Edge 17 & Firefox - @ananth-iyer (#2390, #2399)
-- Wishlist and compare items are loaded from local cache only once, instead of every time when module component is rendered - @patzick (#2431)
-- Country field is filled by first counry from the list in cart in paymen section - @RakowskiPrzemyslaw (#2428)
-- Improved product quantity change component in product and cart - @patzick (#2398, #2437)
-- Updated to Vue 2.6.6 - @filrak (#2456)
-- Null sidebar menu data on static page fixed - @filrak (#2449, #2441)
-- Fix cannot edit previous steps in checkout - @filrak, @patzick (#2438)
-- Fixed route guard ssr problem - @vue-kacper (#2364)
-- Fix links in footer to static pages bug - @filrak (#2452)
-- Fix links at docs, Basics/Configuration file explained - @daksamit (#2490)
-- Improve images loading on category page, corrected alt view and blinking problem - @patzick (#2465)
-- Improve tsconfig for better IDE paths support - @patzick, @filrak (#2474)
-- fix breadcrumbs changing too early - @filrak, @pkarw (#2469, #2529)
-- improved product gallery load view, shows correct image on reload - @patzick (#2481, #2482, #2488, #2501)
-- Fix an issue where the index.html template within a theme is ignored - @EnthrallRecords (#2489)
-- Added async sidebar component with async off-screen components error handling and fetch retrying after coming back online - @filrak (#2408, #2451)
-- Inconsistent filters behaviour - clear filters on page load - @patzick (#2435)
-- fix price is never below 0 and user can't add 0 or below 0 products to cart - @RakowskiPrzemyslaw (#2437)
-- Check for placing single order in case of error in any payment module - @patzick (#2409)
-- Display prices in products added in offline mode. - @patzick (#2450)
-- Updated cypress dependency for e2e tests - @lukeromanowicz (#2518)
-- Improved styles on recommendation filters, product tile and numeric input - @patzick (#2458)
-- Removed editing mode from My Newsletter section - @aniamusial (#2766)
-- Clicking Remake order now adds your items and redirects you to the checkout - @mikesheward (#2710)
-
-### Deprecated / Removed
-
-- `@vue-storefront/store` package deprecated - @filrak
-
-## [1.8.2] - 2019-02-11
-
-- Fixed docker-compose configuration for network_mode and TS build config - @lukeromanowicz (#2415)
-
-## [1.8.1] - 2019-02-10
-
-This is hot-fix release for fixing the payment methods switching issue when both: `payments-cash-on-delivery` and `payments-backend-methods` modules enabled.
-
-### Changed / Improved
-
-- Fixed doubled invlication of `placeOrder` when both: `payments-cash-on-delivery` and `payments-backend-methods` modules enabled - #2405
-
-## [1.8.0] - 2019-02-07
-
-Additional migration tips are available [here](https://github.com/vuestorefront/vue-storefront/blob/master/docs/guide/upgrade-notes/README.md).
-
-### Added
-
-- Chinese translation added - @wadereye (#2265)
-- Categories filter in search view - @kjugi, @patzick (#1710)
-- AsyncDataLoader feature - @pkarw (#2300)
-- Events list page in docs - @jablpiotrek (#776)
-- Keyboard support for account and cookie close buttons - @anqaka (#2258)
-- Support typescript in build scripts - @marlass, @patzick (#2260, #2273, #2324)
-- Possibility to have sticky notifications - @phoenixdev-kl (#2307)
-- Added a scss to manage global form style - @lorenaramonda (#2316)
-- Manage products with zero price - @MarcoGrecoBitbull (#2327)
-- Hotjar integration - @lukeromanowicz (#840)
-
-### Changed / Improved
-
-- Theme structure improvements - @filrak (#2223)
-- Type interfaces and refactor - @filrak (#2227, #2267)
-- Changed beforeRegistration and afterRegistration hooks signature. Now it contains only one object VSF. The subfields are the same as before so changing `beforeRegistration( Vue, config, store, isServer )` to `beforeRegistration({ Vue, config, store, isServer })`(and same with `afterRegistration`) is enough to make a proper migration to new API. - @filrak (#2330)
-- Typo fixes - @youanden, Micheledinocera (#2229, #2329)
-- Bundle products price calculation fix - @pkarw (#2371)
-- Fixed isServer flag in module registration hooks - @lukeromanowicz (#840)
-- Location of type files - @kruchy8 (#2226)
-- Improved theme registration - @lukeromanowicz (#2233)
-- SSR renderings for logged in users - @vue-kacper (#2234)
-- ElasticSearch fuzzy search - @qbo-tech (#2340, #2354)
-- Documentation improvements - @martaradziszewska, @wilfriedwolf, @fvillata, @pkarw (#2210, #2244, #2289, #2369)
-- Support regional characters in urls - @Aekal (#2243)
-- `store/lib/search` has been moved to `core/lib/search` - @lukeromanowicz (#2225)
-- `store/lib/multistore` has been moved to `core/lib/multistore` - @lukeromanowicz (#2224)
-- BaseSelect syntax improvements - @jszczech (#2237)
-- Optional cart discounts display on side cart - @mcspronko (#1758)
-- Special price dates checking - backport of @igloczek's (#2245)
-- Category filters reset functionality on mobile - @vue-kacper, @patzick, @renatocason (#2262)
-- Improve sortBy mobile view - @martaradziszewska (#2251)
-- Slide animations to menu, search, wishlist and minicart components - @Aekal (#2256)
-- Fixed wishlist store module to not be lazy loaded - @vue-kacper (#2249)
-- Share webpack typescript config with Docker container - @lukeromanowicz (#2269)
-- After checkout create logged-in cart for logged-in users if using order Direct Backend Sync - @grimasod (#2302)
-- Output cache clearing supports versioning - @igloczek (#2333, #2359)
-- Cash on delivery + Shipping addresses fixed for virtual products - @pkarw (#2366)
-- Improved static pages caching strategy - @pkarw (#2281)
-- Magento 2.3 MSI work-around (it's still not supported fully) - @pkarw (#2366)
-- Product zoom picture centered - @ptylek (#2178)
-- Fixed tracking in analytics module - @jahvi (#2278)
-- Improved merge the store modules array with extended module config - @DaanKouters (#2274)
-- ElasticSearch fuzzy search, scoring, boosting + other improvements - @qbo-tech (#2340)
-- Turned off compression plugin, nginx serves brotli compression — @patzick (#2254)
-- Improved user account menu UX on desktop - @vue-kacper (#2363)
-- Added About us missing route - @lorenaramonda (#2320)
-- Fixed used variable for products count in category - @renatocason (#2304)
-- Override console with logger - @daaru00 (#2235)
-- Fixed variable call about feedback email - @PhantomDraven (#2318)
-- Output cache clearing versioning - @igloczek (#2333)
-- Improved paddings on select fields - @patzick (#2361)
-- Fixed lack of modal backdrop - @vue-kacper, @giuliachiola (#2319)
-- Form validations and improvements - @vue-kacper (#2348, #2349, #2347)
-- Changing product quantity in catr - @mdanilowicz (#2345)
-- Product attribute values as array - @afirlejczyk (#2379)
-- Improved fetching customAttributes - @afirlejczyk (#2107)
-- Removed compare button from product mobile view - @patzick (#2370)
-- Configurable options attribute descriptor - @pkarw (#2384)
-
-## [1.7.3] - 2019-01-31
-
-### Fixed
-
-- Output cache between build, cache versioning added - @igloczek (#2309)
-- Missing `no-ssr` wrapper around user specific content, which leads to broken app in production mode - @igloczek (#2314)
-
-## [1.7.2] - 2019-01-28
-
-### Fixed
-
-- clear search filters on mobile - @patzick (#2282)
-- SSR problem on checkout page on reload - @vue-kacper (#2220)
-- Improved offline mode handlers - @pkarw (#2217)
-- url_key adjustment after m2vs fix - @pkarw (#2215)
-- Service worker removed from dev mode because of the side effects - @pkarw
-- `networkFirst` first caching strategy for /api/catalog - @pkarw
-- SSR detection in components - @patzick (#2173)
-
-### Added
-
-- Hotjar extension (#840)
-
-### Changed
-
-- compress banner images - @patzick (#2280)
-- Dynamic attributes loader (#2137)
-- Dynamic categories prefetching (#2076)
-- New payment's module architecture (#2135)
-- Support regional characters in urls - Backport of @aekal's (#2243)
-
-### Added
-
-- Translations of banners - @patzick (#2276)
-- Banners title background on mobile - @patzick (#2272)
-- New main site look - @patzick (#2266)
-
-## [1.7.1] - 2019-01-15
-
-### Fixed
-
-- Corrected scrolled sidebar menu position
-
-## [1.7.0] - 2019-01-15
-
-### Added
-
-- Dynamic categories prefetching — @pkarw #2100
-- Per-route codesplitting for SSR pages — @patzick #2068
-- async/await support — @patzick #2092
-- IndexedDB replacement and new caching mechanism — @pkarw #2112
-- Web Share module — @filrak #2143
-- Backward compatibility option for dynamic attribute loader — @pkarw #2137
-- Japanese translation — @moksahero #2150
-- Dutch translation — @StefGeraets #2163
-- Using meta_title and meta_description fields from Magento on product/category page — @qiqqq #2158
-- Color mapping feature — @pkarw #2175
-- Out of the box GZIP compression and sourcemap removal in prod mode — @patzick #2186
-
-### Changed / Improved
-
-- Invalidate output cache using POST - @Cyclonecode #2084
-- NGNIX installation improvements for docs — @janmyszkier #2080
-- HTML semantics improvements — @patzick #2094
-- Lazy loading of non-critical third party libs and vendor optimization — @patzick @filrak @qiqqq
-- Extra NL translation keys — @nlekv #2104
-- Optimization for the number of attributes to be stored in Vuex store — @pkarw #1654
-- Service Worker registration from any route — @patzick #2070
-- Production setup docs improvements — @janmyszkier #2126
-- Various changes and additions to our docs by @NataliaTepluhina
-- Payment docs update — @pkarw #2135
-- Added bash command for collecting i18n phrases to docs — @qbo-tech #2149
-- SEO and scrolling performance fixes — @filrak #2066
-- Established Vuex naming conventions. TLDR - we strongly recommend to use vuex getters instead of mapping state itself (#2069)
-- IndexedDb changed to LocalStorage + ServiceWorker native caching (#2112)
-
-### Fixed
-
-- Fix Notification.vue compiling issue on prod - @ladrua #2079
-- Fix wishlist toggle bug — @shkodasv #2086
-- findConfigurableChildAsync — fix checking stock for configurable child — @afirlejczyk #2097
-- Fix cart synchronization — @valeriish #2106
-- Fix hydration issue for lazy loaded chunks — @patzick #2115
-- Clear missing fields after user logout — @sniffy1988 #2117
-- Fix AMP naming ( ^^ ) for docs -@pgol #2118
-- Fix Cart Configurable Item pulled from Magento — @valeriish #2119
-- Fix product configuration after cart items server pull — @valeriish #2122
-- Fix gallery switching when entering product — @vue-kacper #2123
-- Fix multiple placing order invocation after changing payment methods — @patzick #2133
-- Remove extra space after every comma for non-(multi)select product attributes — @patzick #2133
-- Fix side-menu scrolling — @patzick #2140
-- Fix back button not properly working from a configurable product page — @qiqqq #2151
-- Fix submenu not visible on a deeper level — @patzick #2152
-- vue-carousel removed from homepage - @patzick #2153 #2154
-- Use localized routes for redirects to home page and account page — @grimasod #2157
-- ProductLinks fixed in Related products component — @pkarw #2168
-- Fix Cart Configurable Item pulled from Magento loaded as Simple — @pkarw @valeriish #2169 #2181
-
-### Depreciated
-
-- extendStore depreciation - @filrak #2143
-- ValidationError class depreciation - @filrak #2143
-
-## [1.6.0] - 2018-12-05
-
-### Added
-
-- Lazy loading for SSR and non-SSR routes
-- app splitted into modules
-
-### Removed
-
-- `vsf-payment-stripe` module integration removed from core
-
-### Changed
-
-- There is new config option `config.orders.directBackendSync` that changes the behavior of placing an order. Please do read [more on this change](https://github.com/vuestorefront/vue-storefront/commit/e73f2ca19a5d33a39f8b0fd6346543eced24167e) and [more on vue-storefront-api change](https://github.com/vuestorefront/vue-storefront-api/commit/80c497f72362c72983db4fdcac14c8ba6f8729a8)
-- ProductSlider, ProductLinks, ProductListing moved to theme.
-- Many theme-related logic moved to theme (+ deleted empty core components just with `name`)
-- Components required for backward compatibility moved to `compatibility` folder. For all this files you just need to add `compatibility` after `core` in import path to make them work like before.
-- Better Vuex extensibility with modules
-- VSModule `store` object changed to fulfil need of multiple vuex modules (see modules docs)
-- UI Store logic for Microcart moved to cart module
-- Extensions are now depreciated, theme-level extensions removed and src-level extension to be depreciated in 1.7
-- Theme-starter depreciated and removed (will be replaced with theme 2.0)
-- Header, Form components, (baseCheckbox, BaseInput, BaseRadioButton, BaseSelect, Basetextarea) Loader, MainSlider, Footer, SearchIcon, ForgotPass, SignUp and Modal core components moved to theme
-- extendStore deprecaiated and moved to compatibility folder
-
-## [1.5.0] - 2018-10-22
-
-### Added
-
-- Contact form mailer - #1875 - Akbar Abdrakhmanov @akbarik
-- oauth2 configuration in setup - #1865 - Krister Andersson @Cyclonecode
-- GraphQL schema extendibility in the API - Yoann Vié
-- A lot of new docs - Natalia Tepluhina @NataliTepluhina
-- Magento2 integrated importer
-- 'Apply' filters button on mobile category - #1709 - Damian Fiałkiewicz @Aekal
-
-### Changed
-
-- New Modules API, and base modules (cart, wishlist, newsletter ...) refactored [read more...](https://github.com/vuestorefront/vue-storefront/blob/master/doc/api-modules/about-modules.md) - Filip Rakowski @filrak
-
-### Fixed
-
-- The `regionId` field added to Order interface - #1258 - Jim Hil @jimcreate78
-- SSR Memory leaks fixed - #1882 Tomasz Duda @tomasz-duda
-- E2E tests fixed - #1861 - Patryk Tomczyk @patzik
-- UI animations - #1857 - Javier Villanueva @jahvi
-- Disabled buttons fixed - #1852 - Patryk Tomczyk @patzik
-- Mailchimp / Newsletter modules rebuilt - Filip Rakowski @filrak
-- Search component UX fixes - #1862 - Adrian Cagaanan @diboy2
-
-## [1.4.0] - 2018-10-05
-
-### Added
-
-- GraphQL support - #1616 - Yuri Boyko @yuriboyko, Vladimir Plastovets @VladimirPlastovets => [PHOENIX MEDIA](https://www.phoenix-media.eu/)
-- Layout switching + Advanced output mechanisms - #1787 - Piotr Karwatka @pkarw
-- Dynamic config reload - #1800 - Piotr Karwatka @pkarw
-- VuePress based docs - #1728 - Natalia Tepluhina - @NataliaTepluhina
-- Output Cache - #1664, #1641 - Piotr Karwatka - @pkarw
-- Instalation docs improvements - #1735 - Aleksander Grygier - @allozaur
-- Magento Product Reviews support - Agata Firlejczyk @afirlejczyk, Tomek Kikowski @qiqqq
-- Console silent mode (disabled by default) - #1752 - Piotr Karwatka - @pkarw
-
-### Changed
-
-- Please check the [Upgrade notes](https://github.com/vuestorefront/vue-storefront/blob/develop/doc/Upgrade%20notes.md) for the full list
-
-### Fixed
-
-- `docker-compose.yml` files updated - @kovinka
-- Non-core translations moved to theme resource files (i18n) - #1747 - David Rouyer @DavidRouyer
-- Non-core assets moved to the theme - #1739, #1740 - David Rouyer @DavidRouyer
-- Bug fixes: #1715, #1718, #1670
-- NPM packages cleanup - #1748 - David Rouyer @DavidRouyer
-- Filters were not updating - #1649 - Kacper Wierzbicki @vue-kacper
-- Breadcrumbs on the product page - #1745 - Agata Firlejczyk @afirlejczyk
-- Infinite scroll on mobile browsers - #1755 - Kacper Wierzbicki @vue-kacper
-- Coupon codes - #1759 - Tomek Kikowski @qiqqq
-
-## [1.3.0] - 2018-08-31
-
-### Added
-
-- TypeScript support - please check [TypeScript Action Plan](https://github.com/vuestorefront/vue-storefront/blob/master/docs/guide/basics/typescript.md) for details
-- New `core/modules` added regarding the [Refactor to modules plan](https://github.com/vuestorefront/vue-storefront/blob/master/doc/api-modules/refactoring-to-modules.md)
-- Price tier's support #1625
-- Qty field on product page #1617
-- Offline orders confirmation dialog has been added #1430
-- `pwa-compat` library has been added to support fully PWA manifests on legacy browsers
-- dynamic port allocation #1511
-
-### Removed
-
-- unused `libs`, `components`, `core/api/cart` webpack aliases
-- `global.$VS` has been replaced with `rootStore` #1624
-
-### Changed
-
-- `core` directory is now a `@vue-storefront/core` package, webpack alias and all related imports reflect this change [#1513]
-- `core/api` renamed to `core/modules`, mixin features moved to `core/modules/module_name/features`
-- `core/lib/i18n` moved into separate `@vue-storefront/i18n` package
-
-### Fixed
-
-- installer paths are now normalized (to support paths including spaces) #1645
-- status check added to the configurable_children products #1639
-- product info update when clicking the related products #1601
-- media gallery issues + mobile view
-- product slider fixes #1561
-- shipping carrier code is now passed with order #1520
-- SEO support fixes #1514
-- UX fixes
-- bundle size optimizations (translations)
-- password validation rules are now aligned (server/client) #1476
-
-## [1.2.0] - 2018-08-01
-
-### Fixed
-
-- Improved integration tests [#1471]
-- Minor taxcalc.js improvements [#1467]
-- Search by SKU fixed [#1455]
-- ProductList dbl click fix [#1438]
-
-### Added
-
-- Docker support for vue-storefront
-- Production config docs added [#1450]
-- Integration tests for Compare products added [#1422]
-- Wishlist module refactored to the new core/api standard + unit tests [#1434]
-- Dropdown components in MyProfile replaced with the base-select [#1463]
-- Magento2/CMS integration by block/page identifiers [#1452]
-
-## [1.1.0] - 2018-07-02
-
-Please keep an eye on the **[UPGRADE NOTES](https://github.com/vuestorefront/vue-storefront/blob/master/doc/Upgrade%20notes.md)**
-
-### Fixed
-
-- Zip Code validation [#1372]
-- Get inpspired block [#968]
-- Favicon [#836]
-- Webpack config + refactoring [#1250]
-- Account page updates [#1323]
-- UI fixes [#901]
-- Vuex Store extensions fixes [#1028, #1102]
-- MS Edge + IE10 fixes [#1266]
-- IndexedDB locking issue
-
-### Added
-
-- Added PM2 process manager [#1162]
-- Added billing data phone number support [#1338]
-- Added validation labels + generic control for CountrySelector [#1227]
-- Offline mode Push Notification support [#1348, #1122, #1317]
-- Added billing data phone number support [#1338]
-- PoC of API refactoring for the cart module [#1316]
-- Sort feature added [#671]
-- Page loader [#1240]
-- Production ready Docker config for vue-storefront-api
-
-## [1.0.5] - 2018-06-04
-
-### Fixed
-
-- Shipping region fix
-- Hotfix for missing config.storeViews.multistore check
-- Minor fixes
-
-## [1.0.4] - 2018-06-02
-
-### Fixed
-
-- defaultCountry fix for IT
-- Tax classes hotfix
-- tax_class_id is required by taxcalc - restored along with version inc
-- Minor fixes
-
-## [1.0.3] - 2018-06-02
-
-### Fixed
-
-- Minor fixes
-
-## [1.0.2] - 2018-06-02
-
-### Fixed
-
-- vue-storefront-stripe renamed to vsf-payment-stripe hotfix
-- Minor fixes
-
-## [1.0.1] - 2018-05-31
-
-### Fixed
-
-- Minor fixes
-
-## [1.0.0] - 2018-05-30
-
-### Added
-
-- **Multistore** - now it's possible to manage the store views with all the features like translations, custom category, and products content, shipping rates - basically all Magento2 features are supported! You can read more on how to setup Multistore here.
-- **Bundle products** - support for the Magento-like bundle products with all the custom options, pricing rules etc.
-- **Configurable options** - that allows users to select radio/checkbox options + put some custom notes (textboxes) on the products they like to order,
-- **Crossell, Upsell, Related products** - are now synchronized with Magento2,
-- **Webpack4 support** - we've migrated from Webpack2 -> Webpack4 and now the build process takes much less time while providing some cool new features,
-- **Core components refactor** - without changing APIs, we've stripped the core components from s to improve the performance and improve the code readability,
-- **PWA Manifest fixes** - iOS PWA support required us to adjust some settings,
-- **Improved translations** - we're constantly tweaking the translation files :) We've just added it-IT and pl-PL (finally!) support recently
-- **Improved Travis-CI pipeline** - and added support for end-2-end testing,
-- **Lot of bugfixes + UX fixes** - countless hours spent on improving the code and UI quality!
-- **Please check it out:** visit: https://demo.vuestorefront.io/
-
-## [1.0.0-rc.3] - 2018-04-29
-
-### Added
-
-- Performance tweaks: improved service worker config, reduced JSONs, two-stage caching,
-- User token auto refresh,
-- My Account fixes
-- Translations: RU, IT
-- UX fixes: navigation, notifications, product compare, product page
-- Host and port setup in the config,
-- Refactored Vuex store - prepared to be separated as the npm module which will give the Vue.js developers access to Magento backend
-- Product Gallery,
-- Infinite scroll,
-- Product and Category page refactoring
-
-## [1.0.0-rc.2] - 2018-03-29
-
-### Added
-
-- Basic Magento 1.9 support,
-- Translations: ES, DE, NL, FR
-- Lerna support for managing the npm packages within the one repository,
-- Installer fixes (Linux support),
-- Orders history,
-- Discount codes support,
-- Stripe Payments support,
-- External Checkout support for Magento 2.x,
-- Basic Travis checks,
-- Other fixes.
-
-## [1.0.0-rc.0] - 2018-03-01
-
-### Added
-
-- i18n (internationalization) support for the UI,
-- Support for Magento2 dynamic cart totals - which enables the shopping cart rules mechanism of Magento to work with VS,
-- ESlint-plugin-vue installed,
-- CSS properties moved to atomic classes
-- New SASS structure,
-- Architectural change: core extracted from src - preparation for publishing the official npm package,
-- Refactored vuex stores - we separated actions, getters and the state for better maintainability,
-- UI improvements: look & feel, accessibility, color palette normalization,
-- Assets can be now managed by theme developers,
-- Service-workers and webpack config can be now extended by theme developers,
-- Droppoints shipping methods (NL support) added.
-
-## [0.4.0] - 2018-01-28
-
-### Added
-
-- Improved theming support + B2B product catalog theme included (original github repo); it's PoC made in just one week! Isn't it amazing that you can customize VS in just one week to this extent? :)
-- Pimcore support (more on this, github repo)
-- Customer's dashboard + address book, integration with Checkout
-- Adjustments on product card on mobile
-- Adjustments on home page on mobile
-- Rebuilt checkout - UI + customer accounts support
-- Google Analytics eCommerce extension
-- order_2_magento rebuilt from scratch, supporting customer accounts and authorized carts
-- Real-time cart synchronization with Magento - (last step before synchronizing the checkout promo rules with Magento!)
-- Product comparison
-- Themes refactor
-- Lot of smaller tweaks
-
-## [0.3.0] - 2017-12-21
-
-### Added
-
-- Bundle products support,
-- Tax calculation regarding the Magento's logic for different rates per countries, states.
-- User registration, log-in, password reset
-- Refactor of Product and Category pages with support for updating product photos regarding selected filters (red t-shirts are now red on the list etc)
-- MailChimp support,
-- Stock Quantity check support
-- Special prices for products (catalog rules) are now fully supported for simple, bundled and configurable products,
-- 404 page,
-- Checkout tweaks and refactor,
-- Offline notification badge,
-- Wishlist,
-- Cookie notification bar
-- Security improvements (checksums for client-side processed data)
-- Lot of UI tweaks and refactors,
-- Updated installer with support for Linux and MacOSX
-
-## [0.2.1-alpha.0] - 2017-11-16
-
-### Added
-
-- Homepage
-- Category page
-- Product page
-- Cart
-- Checkout + validation
-- Basic Search
-- Magento2 synchronization: products, attributes, media, categories, orders
-- Offline support using service workers + indexedDb
-- PWA manifest + basic optimizations
-- SSR support
-- Filters + Configurable products
-- RWD (except some checkout issues to be fixed)
-
-## [0.2.0-alpha.0] - 2017-11-15
-
-### Fixed
-
-- Lazy loaded blocks size fixed
diff --git a/CLA.md b/CLA.md
new file mode 100644
index 0000000000..55aeac6a3b
--- /dev/null
+++ b/CLA.md
@@ -0,0 +1,24 @@
+**Vue Storefront Individual Contributor License Agreement**
+
+Thank you for your interest in contributing to open source software projects (“Projects”) made available by VSF Sp. z o.o. (“Vue Storefront”) or its affiliates. This Individual Contributor License Agreement (“Agreement”) sets out the terms governing any source code, object code, bug fixes, configuration changes, tools, specifications, documentation, data, materials, feedback, information or other works of authorship that you submit or have submitted, in any form and in any manner, to Vue Storefront in respect of any of the Projects (collectively “Contributions”). If you have any questions respecting this Agreement, please contact contributors@vuestorefront.io.
+
+You agree that the following terms apply to all of your past, present and future Contributions. Except for the licenses granted in this Agreement, you retain all of your right, title and interest in and to your Contributions.
+
+**Copyright License.** You hereby grant, and agree to grant, to Vue Storefront a non-exclusive, perpetual, irrevocable, worldwide, fully-paid, royalty-free, transferable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute your Contributions and such derivative works, with the right to sublicense the foregoing rights through multiple tiers of sublicensees.
+
+**Patent License.** You hereby grant, and agree to grant, to Vue Storefront a non-exclusive, perpetual, irrevocable, worldwide, fully-paid, royalty-free, transferable patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer your Contributions, where such license applies only to those patent claims licensable by you that are necessarily infringed by your Contributions alone or by combination of your Contributions with the Project to which such Contributions were submitted, with the right to sublicense the foregoing rights through multiple tiers of sublicensees.
+
+**Moral Rights.** To the fullest extent permitted under applicable law, you hereby waive, and agree not to assert, all of your “moral rights” in or relating to your Contributions for the benefit of Vue Storefront, its assigns, and their respective direct and indirect sublicensees.
+
+**Third Party Content/Rights.** If your Contribution includes or is based on any source code, object code, bug fixes, configuration changes, tools, specifications, documentation, data, materials, feedback, information or other works of authorship that were not authored by you (“Third Party Content”) or if you are aware of any third party intellectual property or proprietary rights associated with your Contribution (“Third Party Rights”), then you agree to include with the submission of your Contribution full details respecting such Third Party Content and Third Party Rights, including, without limitation, identification of which aspects of your Contribution contain Third Party Content or are associated with Third Party Rights, the owner/author of the Third Party Content and Third Party Rights, where you obtained the Third Party Content, and any applicable third party license terms or restrictions respecting the Third Party Content and Third Party Rights. For greater certainty, the foregoing obligations respecting the identification of Third Party Content and Third Party Rights do not apply to any portion of a Project that is incorporated into your Contribution to that same Project.
+
+**Representations.** You represent that, other than the Third Party Content and Third Party Rights identified by you in accordance with this Agreement, you are the sole author of your Contributions and are legally entitled to grant the foregoing licenses and waivers in respect of your Contributions. If your Contributions were created in the course of your employment with your past or present employer(s), you represent that such employer(s) has authorized you to make your Contributions on behalf of such employer(s) or such employer (s) has waived all of their right, title or interest in or to your Contributions.
+
+
+**Disclaimer.** To the fullest extent permitted under applicable law, your Contributions are provided on an "as- is" basis, without any warranties or conditions, express or implied, including, without limitation, any implied warranties or conditions of non-infringement, merchantability or fitness for a particular purpose. You are not required to provide support for your Contributions, except to the extent you desire to provide support.
+
+**No Obligation.** You acknowledge that Vue Storefront is under no obligation to use or incorporate your Contributions into any of the Projects. The decision to use or incorporate your Contributions into any of the Projects will be made at the sole discretion of Vue Storefront or its authorized delegates.
+
+**Disputes.** This Agreement shall be governed by and construed in accordance with the laws of the Delaware, United States of America, without giving effect to its principles or rules regarding conflicts of laws, other than such principles directing application of Delaware law. The parties hereby submit to venue in, and jurisdiction of the courts located in Delaware, US for purposes relating to this Agreement. In the event that any of the provisions of this Agreement shall be held by a court or other tribunal of competent jurisdiction to be unenforceable, the remaining portions hereof shall remain in full force and effect.
+
+**Assignment.** You agree that Vue Storefront may assign this Agreement, and all of its rights, obligations and licenses hereunder.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index f0c9be787b..5dd51f7a66 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -2,45 +2,132 @@
## Our Pledge
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
## Our Standards
-Examples of behavior that contributes to creating a positive environment include:
+Examples of behavior that contributes to a positive environment for our
+community include:
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
-Examples of unacceptable behavior by participants include:
+Examples of unacceptable behavior include:
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
-## Our Responsibilities
+## Enforcement Responsibilities
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
## Scope
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
## Enforcement
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contributors@vuestorefront.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+contributors@vuestorefront.io
+
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
## Attribution
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
+at [https://www.contributor-covenant.org/translations][translations].
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
+[homepage]: https://www.contributor-covenant.org
+[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ed9425ab97..c57158bce4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,60 +1,62 @@
-# How to Contribute
+# Contributing
-Already a JavaScript/Vue.js developer? Pick an issue, push a pull request (PR) and instantly become a member of the vue-storefront contributors community.
-We've marked some issues as "Easy first pick" to make it easier for newcomers to begin!
+We are very happy that you want to contribute to Vue Storefront.
+To create a perfect experience for everyone in the community, there are a set of rules and best practices which our repository got.
-You can start a ready-to-code development environment in your browser, by clicking the button below:
+Please take note of the following guidelines and rules.
-[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/from-referrer/)
+## Found an Issue?
-Thank you for your interest in, and engagement!
+Thank you for reporting any issues you find.
-Before you type an issue please read about out [release lifecycle](https://docs.vuestorefront.io/guide/basics/release-cycle.html).
+We do our best to test and make our repository as solid as possible, but any reported issue is a real help.
-# Branches
+Please follow these guidelines when reporting issues:
-You should fork the project or create a branch for new features.
-The main branches used by the core team are:
+- Provide a title in the format of Ex: `[BUG]: when `, `[Issue]: When I try to , an appears`
+- Tag your issue with the tag `triage-needed`
+- Provide a short summary of what you are trying to do
+- Provide the log of the encountered error if applicable
+- Provide the exact version of the framework you are using.
+- Be awesome and consider contributing a [pull request](#want-to-contribute)
-- master - where we store the stable release of the app (that can be deployed to our demo instances),
-- develop - the most recent version of the app - kind of "nightly" build.
-- RC-x (`x` is current version) - release candidate branch with features that will land in next version.
+## Want to contribute?
-Please use "develop" or "RC" for development purposes as the "master" can be merged just as the new release is coming out (about once a month)!
+You consider contributing changes to our framework, this is awesome!
-## Issue Reporting Guidelines
+Please consider these guidelines when filing a pull request:
-Always define the type of issue:
-* Bug report
-* Feature request
+- Follow the [Coding Rules](#coding-rules)
+- Follow the [Commit Rules](#commit-rules)
+- Make sure you rebased the current master branch when filing the pull request
+- Squash your commits when filing the pull request
+- Provide a short title with a maximum of 100 characters
+- Provide a more detailed description containing
+ _ What you want to achieve
+ _ What you changed
+ _ What you added
+ _ What you removed
-While writing issues, be as specific as possible. All requests regarding support with implementation or application setup should be sent to contributors@vuestorefront.io.
+## Coding Rules
-**Tag your issues properly**. If you found a bug, tag it with `bug` label. If you're requesting new feature, tag it with `feature request` label.
+To keep the code base of our repository neat and tidy, we apply a set of rules to every change
-## Git Flow
+> Coding standards
-We're introducing TypeScript to Vue Storefront core, so you can use it where it's appropriate - but please be pragmatic.
-Here are some thoughts on how to use TypeScript features in Vue Storefront: [TypeScript Action Plan](https://github.com/vuestorefront/vue-storefront/blob/master/doc/TypeScript%20Action%20Plan.md).
+- `eslint` is king
+- Favor micro library over swiss army knives (rimraf, ncp vs. fs-extra) - Just in case you really need one :)
+- Be awesome
-## Pull Request Checklist
+## Commit Rules
-**ALWAYS** use [Pull Request template](https://github.com/vuestorefront/vue-storefront/blob/master/PULL_REQUEST_TEMPLATE.md) it's automatically added to each PR.
-1. Fork the repository and clone it locally from the 'develop' branch. Make sure it's up to date with current `develop` branch
-2. Create a branch for your edits. Use the following branch naming conventions:
- * bugfix/task-title
- * feature/task-name
-3. Use Pull Request template and fill as much fields as possible to describe your solution.
-4. Reference any relevant issues or supporting documentation in your PR (ex. “Issue: 39. Issue title.”).
-5. If you are adding new feature provide documentation along with the PR. Also, add it to [upgrade notes](https://github.com/vuestorefront/vue-storefront/blob/master/doc/Upgrade%20notes.md)
-6. If you are removing/renaming something or changing its behavior also include it in [upgrade notes](https://github.com/vuestorefront/vue-storefront/blob/master/doc/Upgrade%20notes.md)
-7. Test your changes! Run your changes against any existing tests and create new ones when needed. Make sure your changes don’t break the existing project. Make sure that your branch is passing Travis CI build.
-8. If you have found a potential security vulnerability, please DO NOT report it on the public issue tracker. Instead, send it to us at contributors@vuestorefront.io. We will work with you to verify and fix it as soon as possible.
-(https://github.com/vuestorefront/vue-storefront/blob/master/README.md#documentation--table-of-contents))
+To help everyone with understanding the commit history of commits the following rules are enforced.
-## Acceptance Criteria
+To make your life easier our repository is commitizen-friendly and provides the npm run-script `commit`.
-Your pull request will be merged after meeting following criteria:
-- Everything from "Pull Request Checklist"
-- PR is proposed to appropriate branch
-- There are at least two approvals from core team members
+> Commit standards
+
+- [conventional-changelog](https://github.com/conventional-changelog)
+- husky commit message hook available
+- present tense
+- maximum of 100 characters
+- message format of `$type($scope): $message`
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 7a7f031b68..0000000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2017 Divante Ltd.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000000..2801ae1d5b
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Vue Storefront
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 08e1a8886b..a7cc33ad76 100644
--- a/README.md
+++ b/README.md
@@ -1,304 +1,72 @@
+![Vue Storefront](https://camo.githubusercontent.com/48c886ac0703e3a46bc0ec963e20f126337229fc/68747470733a2f2f643968687267346d6e767a6f772e636c6f756466726f6e742e6e65742f7777772e76756573746f726566726f6e742e696f2f32383062313964302d6c6f676f2d76735f3062793032633062793032633030303030302e6a7067)
+# Vue Storefront 2
-
-# Vue Storefront - Headless PWA for any eCommerce
+[![Coverage Status](https://coveralls.io/repos/github/vuestorefront/vue-storefront/badge.svg?branch=next) ](https://coveralls.io/github/vuestorefront/vue-storefront/?branch=next)
+[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
+[![Discord](https://img.shields.io/discord/770285988244750366?label=join%20discord&logo=Discord&logoColor=white)](https://discord.vuestorefront.io)
-
-![version](https://img.shields.io/badge/node-v10.x-blue.svg)
-
-
-![Branch Develop](https://img.shields.io/badge/community%20chat-slack-FF1493.svg)
+Vue Storefront is the most popular and most advanced Frontend Platform for eCommerce
+- [Documentation](https://docs.vuestorefront.io/v2/)
+- [Demo](https://demo-ct.vuestorefront.io)
+- [Installation](https://docs.vuestorefront.io/v2/general/installation.html)
-Vue Storefront is a standalone PWA storefront for your eCommerce, possible to connect with any eCommerce backends, for example:
-- Magento
-- Shopware
-- commercetools
-- About You Cloud
-- Pimcore/CoreShop
-- [BigCommerce](https://github.com/vuestorefront/bigcommerce2vuestorefront)
+![Screenshots](https://blog.vuestorefront.io/wp-content/uploads/2020/03/3-views-Vue-Storefront-.png)
-Vue Storefront is and always will be **open source** (MIT Licence). Anyone can use and support the project, we want it to be a tool for the improvement of the shopping experience.
-The project is in the **production ready** phase.
+# Supported platforms
-## Links
-
-- 📘 Documentation: [docs.vuestorefront.io](https://docs.vuestorefront.io)
-- 👥 Slack Community: [slack.vuestorefront.io](https://slack.vuestorefront.io/)
-- 🐦 Twitter: [@VueStorefront](https://twitter.com/VueStorefront)
-- 💬 Forum: [forum.vuestorefront.io](https://forum.vuestorefront.io/)
-- 🌟 [Live Projects List](https://www.vuestorefront.io/live-projects/?utm_source=github.com&utm_medium=referral&utm_campaign=readme)
-
-## How to start?
-
-Which Vue Storefront should I choose for my next project?
-
- - If you’re on **Magento 1 or Magento 2** choose Vue Storefront 1.x
- with vsf-capybara theme, [Install it using CLI](https://docs.vuestorefront.io/guide/cookbook/setup.html)
-
- - If you’re on **commercetools / About You Cloud** choose Vue Storefront Next clone it from [`next`](https://github.com/vuestorefront/vue-storefront/tree/next)
-
- - If you’re on **Shopware 6** go to [`shopware-pwa`](https://github.com/vuestorefront/shopware-pwa) sub-project and use the Shopware PWA powered by Vue Storefront
-
-Check our Rodmap -> link do [https://github.com/vuestorefront/vue-storefront#roadmap](https://github.com/vuestorefront/vue-storefront#roadmap)
-
-## About Vue Storefront Next
-
-We're developing a next version of Vue Storefront on the [`next` branch](https://github.com/vuestorefront/vue-storefront/tree/next).
-
-We're building the following integrations within Next architecture:
-
-- Shopware 6 (developer preview)
-- Commercetools (developer preview)
-- AboutYou Cloud
-- Shopify
-- Salesforce Commerce Cloud
-
-You can learn more about Vue Storefront Next from the README on the `next` branch and [this](https://www.youtube.com/watch?v=0e2wyhR0ZyQ&t=3s) video
-
-
-
-
-
-
If you want to learn more about Vue Storefront Next, contribute or build an integration reach to Filip Rakowski on our Slack
-
-
-
-
-## About Vue Storefront 1.x
-
-**Important note to developers:** From 1.0RC we started using [develop](https://github.com/vuestorefront/vue-storefront/tree/develop) branch for nightly builds (contains all new features) and [master](https://github.com/vuestorefront/vue-storefront/tree/master) branch for stable. Please make sure you're working on right branch. Please take a look at [Contributing guidelines](https://github.com/vuestorefront/vue-storefront/blob/master/CONTRIBUTING.md).
-
-
-
-
-
-
-
If you're new and need some guidance feel free to visit out forum or reach to Filip Jędrasik (@Fifciuu) from the core team on our Slack
-
-
-
-
-
-
-Want to invest some time in building the future of eCommerce? we are looking for agencies and developers willing to help us make VS even more awesome. Interested - contact `@Filip Rakowski` on slack
-
-**We are looking for Contributors and Designer willing to help us in the solution development.**
-
-**Read [contribution rules](https://github.com/vuestorefront/vue-storefront/blob/master/CONTRIBUTING.md) before making any pull request. Pull request that doesn't meet these requirements will not be merged**
-
-PS: Check [Storefront UI](https://github.com/vuestorefront/storefront-ui/) - our UI library for eCommerce.
-
-
-## See it in action
-
-
- Try out our open demo and if you like it first give us some star on Github ★ and then contact us on Slack or via contributors@vuestorefront.io.
This demo site is connected to Magento 2.2 with shopping carts and users synchronization so You can make an order (which unfortunately won't be shipped ;P).
If You like to see Magento 1 integration demo please do contact us.
-
- Try out our open demo and if you like it first give us some star on Github ★ and then contact us on Vue Storefront Official Slack or via contributors@vuestorefront.io.
This demo site is connected to Magento2.
-
-
-
-
-
-## Be up to date with the news
-
-We're trying to be very open regarding our development plans, news, roadmap and in general: sharing a lot. Please do bookmark our [Official blog](https://blog.vuestorefront.io/) to be always up to date!
-
-## Foundations | Vue Storefront 1.x
-
-[![See how it works!](https://blog.vuestorefront.io/wp-content/uploads/2020/03/Foundations-_-Vue-Storefront.png)](https://www.youtube.com/watch?v=o10oinxCYfY&list=PLIDwzUVxSXjN9pK1NzBTcirV3-K0OCay0)
-
-## How to install Vue Storefront on Windows?
-
-[![Demo and the architecture of Vue Storefront](https://blog.vuestorefront.io/wp-content/uploads/2020/03/How-to-install-Vue-Storefront-on-Windows_.png)](https://www.youtube.com/watch?v=zL_T3WzVLG0&list=PLIDwzUVxSXjN9pK1NzBTcirV3-K0OCay0&index=2)
-
-- [Read on how to integrate it with Magento2](https://docs.vuestorefront.io/guide/installation/magento.html#using-native-magento-2-module), [Read how to create Vue Storefront theme](https://docs.vuestorefront.io/guide/core-themes/themes.html),
-- [Read the interviews with authors of first production deployments](http://blog.vuestorefront.io/vsf-on-production-interview-with-gogetgold-com/)
-
-## Is it production ready?
-
-Yes! There are more than **140 implementations** happening right now and many live shops (check [awesome live projects on Vue Storefront](https://www.vuestorefront.io/live-projects/?utm_source=github.com&utm_medium=referral&utm_campaign=readme)).
-
-## Browser Compatibility
-
-* last 2 Chrome versions
-* last 2 Firefox versions
-* last 2 Edge versions
-* modern browsers
-
-For an up-to-date list of supported browsers please see "browserslist" in package.json
-
-## Join the community on Slack
-
-If you have any questions or ideas feel free to join our slack via invitation link: [https://slack.vuestorefront.io/](https://slack.vuestorefront.io/)
-
-## Roadmap
+- [Commercetools](https://github.com/vuestorefront/commercetools)
+- [Shopify](https://github.com/vuestorefront/shopify)
+- [Magento 2](https://github.com/vuestorefront/magento2) [Beta]
+- Spryker [Beta]
+- [Salesforce Commerce Cloud](https://github.com/vuestorefront/salesforce-commerce-cloud) [Beta]
-[Here](https://github.com/vuestorefront/vue-storefront/milestones) you can find the accepted roadmap for current milestone and what you can expect with next release.
-#### Roadmap planning
-[Here](https://github.com/vuestorefront/vue-storefront/projects/3) you can vote for feature requests and see which ones were accepted. The most upvoted ones will be added to the next milestones. You can also join the slack channel `#roadmap-planning` where we discuss the next milestones.
+[Learn more about available integrations](https://docs.vuestorefront.io/v2/integrations/)
-The process of adding new features to the roadmap looks like this:
-1. You create an issue and label it as `feature request`.
-2. One of VS Core team verifies the feature request and if the explanation is clear, it is added to the `Roadmap` project so it's visible in the board.
-3. Now people can vote for this feature to be added into next milestone with `thumb up` emoji.
-4. Feature requests with the biggest popularity will be added into next milestones.
-We are planning 1-2 milestones ahead. Our milestones are based on requirements from community, partners and production implementations.
-
-Please note that bugfixes are treated separately and in most cases added to the milestones immediately.
-
-
-
-[Check the feature list of 1.0](https://docs.vuestorefront.io/guide/basics/feature-list.html).
-
-If youd like to take part in roadmap planning feel free to join #roadmap-planning channel on our slack
-
-## Documentation + table of contents
-
-The documentation is always THE HARDEST PART of each open source project! But we're trying hard.
-
-**Please find out what we've already managed to prepare:** [available on Github Pages](https://docs.vuestorefront.io/). Please note that new docs are still Work In Progress and will be successfully updated. You can find them also under the `docs` folder.
-
-You can find some tutorials and explanations on our [YouTube channel](https://www.youtube.com/vuestorefront)
-
-### Installation
-
-- [Starter pack for install](https://docs.vuestorefront.io/guide/cookbook/setup.html)
-- [Installing on Linux/MacOS](https://docs.vuestorefront.io/guide/installation/linux-mac.html)
-- [Installing on Windows](https://docs.vuestorefront.io/guide/installation/windows.html)
-- [How to install and integrate with Magento2](https://docs.vuestorefront.io/guide/installation/magento.html)
-- [Production setup](https://docs.vuestorefront.io/guide/installation/production-setup.html)
-
-### Cookbooks
-
-- [Ch1. Data Imports](https://docs.vuestorefront.io/guide/cookbook/data-import.html)
-- [Ch2. Elasticsearch in the VSF context](https://docs.vuestorefront.io/guide/cookbook/elastic.html)
-- [Ch3. Starter pack for new comers (Install)](https://docs.vuestorefront.io/guide/cookbook/setup.html)
-- [Ch5. Building a Module from scratch](https://docs.vuestorefront.io/guide/cookbook/module.html)
-- [Ch6. Theming in depth](https://docs.vuestorefront.io/guide/cookbook/theme.html)
-- [Chef's secret note: Hardcore training for serious business](https://docs.vuestorefront.io/guide/cookbook/checklist.html)
-
-## Awesome projects on Vue Storefront
-
-Check [**Vue Storefront Live Projects**](https://www.vuestorefront.io/live-projects/?utm_source=github.com&utm_medium=referral&utm_campaign=readme)
-
-![Vue Storefront Live Projects](https://uploads-ssl.webflow.com/5e7cf661c23ac9df156d9c3d/5eff4e5149334a10bb672790_GitHub_Live%20Projects.png)
+## Links
+- 📘 Documentation: [docs.vuestorefront.io](https://docs.vuestorefront.io/v2/)
+- 👥 Discord Community: [discord.vuestorefront.io](https://discord.vuestorefront.io/)
+- 🐦 Twitter: [@VueStorefront](https://twitter.com/VueStorefront)
+- 💬 Forum: [forum.vuestorefront.io](https://forum.vuestorefront.io/)
+- 🌟 [Live Projects List](https://www.vuestorefront.io/live-projects/?utm_source=github.com&utm_medium=referral&utm_campaign=readme)
## The business challenges
-Vue Storefront was created to solve a set of key business challenges from the world of the shopping experience. Our goal for the application is to provide the solution with:
-
-- The ultrafast front-end for the store - with the PWA approach we can now render the catalog of products within milliseconds;
-- The endurance for traffic overloads on the store;
-- The off-line shopping capabilities;
-- The smooth shopping experience close to the user experience from the native mobile applications;
-- The all-in-one front-end for desktop and mobile screens with no necessity for maintaining 3 or more applications for different touchpoints (web browser, Android, iOS etc.).
-- Rapid development without architecture limitations.
-
-## The technology
+Vue Storefront solves a set of key business challenges from the world of the shopping experience. Our goal is to provide the solution with:
-Vue Storefront was built as an all-in-one front-end for eCommerce. For providing the best performance we decided to use Vue.js as a front-end library, Node.js + Express (and maybe GraphQL support) as a server-API, Elastic Search as a database of products and full PWA/off-line support.
-Here you can read more about the proof of concept for [Vue Storefront connected with Magento2](https://www.linkedin.com/pulse/magento2-nosql-database-pwa-support-piotr-karwatka).
+- ultrafast front-end for the store - with the PWA approach, we can now render the catalog of products within milliseconds;
+- endurance for traffic overloads on the store;
+- off-line shopping capabilities;
+- smooth shopping experience close to the user experience from the native mobile applications;
+- all-in-one front-end for desktop and mobile screens with no necessity for maintaining 3 or more applications for different touchpoints (web browser, Android, iOS, etc.).
+- rapid development without architecture limitations.
-Besides a big improvement for the shopping experience, we also want to create a great code base for every developer who needs to work on a front-end application for the eCommerce.
## The headless architecture
![Vue Storefront - Headless Architecture](https://uploads-ssl.webflow.com/5e7cf661c23ac9df156d9c3d/5eff4a2497a1546ca057dcca_github_headless_architecture.png)
-## Design
-
-Vue Storefront supports by default **two different themes:**
-1. **[Capybara Theme based on Storefront UI](https://github.com/vuestorefront/vsf-capybara)**
-
-
-
-
-2. **[Classic/Default ](https://github.com/vuestorefront/vsf-default)**
-
-The application is prepared to be fully customized in design through the theming system.
-With the current version we work on raw, basic template of typical eCommerce for a fashion industry. In the project we used [Material Icons](https://github.com/google/material-design-icons).
-
-
-
-Here you can read more about the process of [designing PWA for eCommerce](https://www.linkedin.com/pulse/designing-pwa-ecommerce-karl-bzik/).
-
-The design is available in open source in the Figma file format under the URL https://www.figma.com/file/VKyqbHFI55TKIKcQlFLiVpVF/Vue-Storefront-Open-Source.
-
-## Concerns when hosting
-When hosting NodeJS applications there are some differences compared to, for example, hosting PHP or Java applications.
-Server Side Rendering via NodeJS can have memory leaks because of suboptimal code. Although core code is optimized, project specific features or misaligned hosting configuration can introduce this. More on how to avoid these for VueJS can be ready in [this article](https://vuejs.org/v2/cookbook/avoiding-memory-leaks.html). We also recommend reading about [VueJS best practices](https://blog.usejournal.com/vue-js-best-practices-c5da8d7af48d).
-
- On the server we advice to run [PM2](http://pm2.keymetrics.io/) which offers features to keep your NodeJS application stable. When hosting on Kubernetes the checks and memory limits can be leveraged to kill unhealthy containers.
-More on hosting can be found in [the documentation](https://docs.vuestorefront.io/guide/installation/production-setup.html#production-setup-bare-vps).
-
-## Other platforms
-Vue Storefront is platform agnostic which means it can be connected to virtually any CMS. Please take a look at [Pimcore bridge](https://github.com/vuestorefront/coreshop-vsbridge) to give you an idea of how other platforms can be connected. Any support for integrating Prestashop, Shopify ... - much appreciated.
## Contributing
-If you like the idea behind Vue Storefront and want to become a contributor - do not hesitate and check our [list of the active issues](https://github.com/vuestorefront/vue-storefront/issues) or contact us directly via contributors@vuestorefront.io.
-
-If you have discovered a 🐜 or have a feature suggestion, feel free to create an issue on Github.
+If you like the ideas behind Vue Storefront and want to become a contributor - join our [Discord server](https://discord.vuestorefront.io), check the [list of the active issues](https://github.com/vuestorefront/vue-storefront/issues) or contact us directly via contributors@vuestorefront.io.
-## Workshops
+If you have discovered a 🐜 or have feature suggestion, feel free to create an issue on Github.
-If you like our project and would like to learn more on how to create Progressive Web Apps you can ask us for a dedicated workshop at your office! Conducted by Vue Storefront core contributors! All the profits are used for supporting Vue Storefront development. [Learn more]([https://divante.com/products/vue-storefront](https://divante.com/products/vue-storefront))
## Support us!
**Vue Storefront is and always will be Open Source, released under MIT Licence.**
-Most of the core team members, VS contributors and contributors in the ecosystem do this open source work in their free time. If you use Vue Storefront for a serious task, and you'd like us to invest more time on it, you can donate the project! You can support us in various ways:
+You can support us in various ways:
- **Contribute** - this is how the Core Team is supporting the project!
-- **Evangelize** - tweet about us, take some speaking slot at tech conference etc.
-- **Sponsor** - if you're doing serious business on VS maybe You would like to donate the project and put your logo in here?
-
-This is how we will use the donations:
-
-- Allow the core team to work on VS
-- Thank contributors if they invested a large amount of time in contributing
-- Support projects in the ecosystem that are of great value for users
-- Infrastructure cost
-- Fees for money handling
-
-**If you would like to support us please just let us know: contributors@vuestorefront.io**
+- **Evangelize** - tweet about us, take some speaking slot at a tech conference, etc.
## Partners
@@ -306,21 +74,7 @@ Vue Storefront is a Community effort brought to You by our great Core Team and s
[**See Vue Storefront partners directory**](https://www.vuestorefront.io/partner-agencies?utm_source=github.com&utm_medium=referral&utm_campaign=readme)
-![enter image description here](https://uploads-ssl.webflow.com/5e7cf661c23ac9df156d9c3d/5eff4e56262af66301c950e4_github_partner_agencies.png)
-
-
-Partners are encouraged to support the project in various ways - mostly by contributing the source code, marketing activities, evangelizing and of course - implementing the production projects. We do support our partners by dedicated contact channels, workshops and by sharing the leads from merchants interested in implementations.
-
-If you like to become our Partner just let us know via contributors@vuestorefront.io.
-
-## The screenshots
-
-
-
-
-
-## The license
Vue Storefront source code is completely free and released under the [MIT License](https://github.com/vuestorefront/vue-storefront/blob/master/LICENSE).
-[![analytics](http://www.google-analytics.com/collect?v=1&t=pageview&_s=1&dl=https%3A%2F%2Fgithub.com%2FDivanteLtd%2Fvue-storefront&_u=MAC~&cid=1757014354.1393964045&tid=UA-108235765-10)]()
\ No newline at end of file
+[![analytics](http://www.google-analytics.com/collect?v=1&t=pageview&_s=1&dl=https%3A%2F%2Fgithub.com%2FDivanteLtd%2Fvue-storefront&_u=MAC~&cid=1757014354.1393964045&tid=UA-108235765-10)]()
diff --git a/babel.config.js b/babel.config.js
deleted file mode 100644
index 5219ca3b33..0000000000
--- a/babel.config.js
+++ /dev/null
@@ -1,19 +0,0 @@
-module.exports = {
- presets: [
- [
- '@babel/preset-env',
- {
- 'modules': false,
- 'useBuiltIns': 'entry',
- 'corejs': 2
- }
- ]
- ],
- plugins: ['@babel/plugin-syntax-dynamic-import'],
- env: {
- test: {
- plugins: ['transform-es2015-modules-commonjs', 'babel-plugin-dynamic-import-node'],
- ignore: [/node_modules\/(?!lodash-es|@vue\/test-utils)/]
- }
- }
-}
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000000..850aad312a
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,24 @@
+comment: false
+
+coverage:
+ precision: 2
+ round: down
+ range: "70...100"
+
+ status:
+ patch: no
+ project:
+ default: no
+ commercetools-api-client:
+ flags: commercetools-api-client
+ target: 90%
+ commercetools-composables:
+ flags: commercetools-composables
+ target: 90%
+flags:
+ commercetools-api-client:
+ paths:
+ - packages/commercetools/api-client
+ commercetools-composables:
+ paths:
+ - packages/commercetools/composables
diff --git a/commitlint.config.js b/commitlint.config.js
new file mode 100644
index 0000000000..6fdb2aef92
--- /dev/null
+++ b/commitlint.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ extends: [
+ '@commitlint/config-conventional',
+ '@commitlint/config-lerna-scopes'
+ ]
+};
diff --git a/config/custom-environment-variables.json b/config/custom-environment-variables.json
deleted file mode 100644
index d4816ac526..0000000000
--- a/config/custom-environment-variables.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "server": {
- "host": "BIND_HOST",
- "port": "BIND_PORT"
- }
-}
diff --git a/config/default.json b/config/default.json
deleted file mode 100644
index 16199e4c71..0000000000
--- a/config/default.json
+++ /dev/null
@@ -1,906 +0,0 @@
-{
- "server": {
- "host": "localhost",
- "port": 3000,
- "protocol": "http",
- "api": "api",
- "devServiceWorker": false,
- "useHtmlMinifier": true,
- "htmlMinifierOptions": {
- "minifyJS": true,
- "minifyCSS": true
- },
- "useOutputCacheTagging": false,
- "useOutputCache": false,
- "outputCacheDefaultTtl": 86400,
- "availableCacheTags": [
- "attribute",
- "C",
- "category",
- "checkout",
- "compare",
- "error",
- "home",
- "my-account",
- "P",
- "page-not-found",
- "product",
- "taxrule"
- ],
- "invalidateCacheKey": "aeSu7aip",
- "invalidateCacheForwarding": false,
- "invalidateCacheForwardUrl": "http://localhost:8080/invalidate?key=aeSu7aip&tag=",
- "dynamicConfigReload": true,
- "dynamicConfigReloadWithEachRequest": false,
- "dynamicConfigContinueOnError": false,
- "dynamicConfigExclude": [
- "entities",
- "boost",
- "localForage",
- "query",
- "shipping",
- "ssr",
- "storeViews"
- ],
- "dynamicConfigInclude": [],
- "elasticCacheQuota": 4096,
- "ssrDisabledFor": {
- "extensions": [
- "css",
- "eot",
- "gif",
- "ico",
- "jpg",
- "jpeg",
- "js",
- "json",
- "png",
- "raw",
- "svg",
- "tiff",
- "tif",
- "ttf",
- "woff",
- "woff2"
- ]
- },
- "trace": {
- "enabled": false,
- "config": {}
- },
- "helmet": {
- "enabled": true
- }
- },
- "initialResources": [
- {
- "filters": ["vsf-newsletter-modal", "vsf-languages-modal", "vsf-layout-empty", "vsf-layout-minimal", "vsf-order-confirmation", "vsf-search-panel"],
- "type": "script",
- "onload": true,
- "rel": "prefetch"
- },
- {
- "filters": ["vsf-category", "vsf-home", "vsf-not-found", "vsf-error", "vsf-product", "vsf-cms", "vsf-checkout", "vsf-compare", "vsf-my-account", "vsf-static", "vsf-reset-password"],
- "type": "script",
- "onload": true,
- "rel": "prefetch"
- }
- ],
- "staticPages": {
- "updateOnRequest": true,
- "destPath": "static"
- },
- "seo": {
- "useUrlDispatcher": true,
- "disableUrlRoutesPersistentCache": true,
- "defaultTitle": "Vue Storefront"
- },
- "console": {
- "showErrorOnProduction": false,
- "verbosityLevel": "display-everything"
- },
- "redis": {
- "host": "localhost",
- "port": 6379,
- "db": 0
- },
- "graphql": {
- "host": "localhost",
- "port": 8080
- },
- "api": {
- "url": "http://localhost:8080",
- "saveBandwidthOverCache": true
- },
- "elasticsearch": {
- "httpAuth": "",
- "host": "/api/catalog",
- "index": "vue_storefront_catalog",
- "min_score": 0.02,
- "csrTimeout": 5000,
- "ssrTimeout": 1000,
- "queryMethod": "GET",
- "disablePersistentQueriesCache": true,
- "searchScoring": {
- "attributes": {
- "attribute_code": {
- "scoreValues": {
- "attribute_value": {
- "weight": 1
- }
- }
- }
- },
- "fuzziness": 2,
- "cutoff_frequency": 0.01,
- "max_expansions": 3,
- "minimum_should_match": "75%",
- "prefix_length": 2,
- "boost_mode": "multiply",
- "score_mode": "multiply",
- "max_boost": 100,
- "function_min_score": 1
- },
- "searchableAttributes": {
- "name": {
- "boost": 4
- },
- "sku": {
- "boost": 2
- },
- "category.name": {
- "boost": 1
- }
- }
- },
- "ssr": {
- "templates": {
- "default": "dist/index.html",
- "minimal": "dist/index.minimal.html",
- "basic": "dist/index.basic.html",
- "amp": "dist/index.amp.html"
- },
- "lazyHydrateFor": [
- "category-next.products",
- "homepage.new_collection"
- ],
- "executeMixedinAsyncData": true,
- "initialStateFilter": [
- "__DEMO_MODE__",
- "version",
- "storeView",
- "attribute.list_by_id"
- ],
- "useInitialStateFilter": true
- },
- "queues": {
- "maxNetworkTaskAttempts": 1,
- "maxCartBypassAttempts": 1
- },
- "defaultStoreCode": "",
- "storeViews": {
- "multistore": false,
- "commonCache": false,
- "mapStoreUrlsFor": [
- "de",
- "it"
- ],
- "de": {
- "storeCode": "de",
- "storeId": 3,
- "name": "German Store",
- "url": "/de",
- "appendStoreCode": true,
- "elasticsearch": {
- "host": "/api/catalog",
- "index": "vue_storefront_catalog_de"
- },
- "tax": {
- "sourcePriceIncludesTax": false,
- "defaultCountry": "DE",
- "defaultRegion": "",
- "calculateServerSide": true
- },
- "i18n": {
- "fullCountryName": "Germany",
- "fullLanguageName": "German",
- "defaultLanguage": "DE",
- "defaultCountry": "DE",
- "defaultLocale": "de-DE",
- "currencyCode": "EUR",
- "currencySign": "EUR",
- "dateFormat": "HH:mm D-M-YYYY"
- },
- "seo": {
- "defaultTitle": "Vue Storefront"
- }
- },
- "it": {
- "extend": "de",
- "storeCode": "it",
- "storeId": 4,
- "name": "Italian Store",
- "url": "/it",
- "appendStoreCode": true,
- "elasticsearch": {
- "host": "/api/catalog",
- "index": "vue_storefront_catalog_it"
- },
- "tax": {
- "defaultCountry": "IT"
- },
- "i18n": {
- "fullCountryName": "Italy",
- "fullLanguageName": "Italian",
- "defaultCountry": "IT",
- "defaultLanguage": "IT",
- "defaultLocale": "it-IT"
- },
- "seo": {
- "defaultTitle": "Vue Storefront"
- }
- }
- },
- "entities": {
- "optimize": true,
- "twoStageCaching": true,
- "optimizeShoppingCart": true,
- "optimizeShoppingCartOmitFields": [
- "category",
- "category_ids",
- "configurable_children",
- "configurable_options",
- "description",
- "media_gallery",
- "product_links",
- "stock"
- ],
- "category": {
- "includeFields": [
- "children_count",
- "id",
- "is_active",
- "level",
- "name",
- "parent_id",
- "path",
- "position",
- "product_count",
- "sku",
- "url_key",
- "url_path",
- "*.children_data.id",
- "*.id"
- ],
- "excludeFields": [
- "sgn"
- ],
- "filterFields": {},
- "breadcrumbFilterFields": {},
- "categoriesRootCategorylId": 2,
- "categoriesDynamicPrefetchLevel": 2,
- "categoriesDynamicPrefetch": true,
- "validSearchOptionsFromRouteParams": [
- "url-key",
- "slug",
- "id"
- ]
- },
- "attribute": {
- "includeFields": [
- "activity",
- "attribute_code",
- "attribute_id",
- "default_frontend_label",
- "default_value",
- "entity_type_id",
- "frontend_input",
- "frontend_label",
- "id",
- "is_user_defined",
- "is_visible_on_front",
- "is_visible",
- "is_comparable",
- "options",
- "tier_prices"
- ],
- "loadByAttributeMetadata": false
- },
- "productList": {
- "sort": "updated_at:desc",
- "includeFields": [
- "activity",
- "configurable_children.attributes",
- "configurable_children.id",
- "configurable_children.final_price",
- "configurable_children.color",
- "configurable_children.original_price",
- "configurable_children.original_price_incl_tax",
- "configurable_children.price",
- "configurable_children.price_incl_tax",
- "configurable_children.size",
- "configurable_children.sku",
- "configurable_children.special_price",
- "configurable_children.special_price_incl_tax",
- "configurable_children.tier_prices",
- "final_price",
- "id",
- "image",
- "name",
- "new",
- "original_price_incl_tax",
- "original_price",
- "price",
- "price_incl_tax",
- "product_links",
- "sale",
- "special_price",
- "special_to_date",
- "special_from_date",
- "special_price_incl_tax",
- "status",
- "tax_class_id",
- "tier_prices",
- "type_id",
- "url_path",
- "url_key",
- "*image",
- "*sku",
- "*small_image"
- ],
- "excludeFields": [
- "attribute_set_id",
- "configurable_options",
- "description",
- "sgn",
- "*.sgn",
- "msrp_display_actual_price_type",
- "*.msrp_display_actual_price_type",
- "required_options",
- "media_gallery",
- "stock.use_config_min_qty",
- "stock.use_config_notify_stock_qty",
- "stock.stock_id",
- "stock.use_config_backorders",
- "stock.use_config_enable_qty_inc",
- "stock.enable_qty_increments",
- "stock.use_config_manage_stock",
- "stock.use_config_min_sale_qty",
- "stock.notify_stock_qty",
- "stock.use_config_max_sale_qty",
- "stock.use_config_max_sale_qty",
- "stock.qty_increments",
- "stock.stock_status_changed_auto",
- "stock.show_default_notification_message",
- "stock.use_config_qty_increments",
- "stock.is_decimal_divided"
- ]
- },
- "productListWithChildren": {
- "includeFields": [
- "activity",
- "configurable_children.attributes",
- "configurable_children.image",
- "configurable_children.sku",
- "configurable_children.price",
- "configurable_children.special_price",
- "configurable_children.price_incl_tax",
- "configurable_children.special_price_incl_tax",
- "configurable_children.original_price",
- "configurable_children.original_price_incl_tax",
- "configurable_children.color",
- "configurable_children.size",
- "configurable_children.id",
- "configurable_children.tier_prices",
- "configurable_children.special_to_date",
- "configurable_children.special_from_date",
- "configurable_children.regular_price",
- "configurable_children.final_price",
- "final_price",
- "id",
- "image",
- "name",
- "new",
- "original_price",
- "original_price_incl_tax",
- "price",
- "price_incl_tax",
- "product_links",
- "sale",
- "sku",
- "special_price",
- "special_price_incl_tax",
- "special_from_date",
- "special_to_date",
- "status",
- "tax_class_id",
- "tier_prices",
- "type_id",
- "url_path",
- "url_key"
- ],
- "excludeFields": [
- "attribute_set_id",
- "description",
- "sgn",
- "*.sgn",
- "msrp_display_actual_price_type",
- "*.msrp_display_actual_price_type",
- "required_options",
- "media_gallery",
- "stock.use_config_min_qty",
- "stock.use_config_notify_stock_qty",
- "stock.stock_id",
- "stock.use_config_backorders",
- "stock.use_config_enable_qty_inc",
- "stock.enable_qty_increments",
- "stock.use_config_manage_stock",
- "stock.use_config_min_sale_qty",
- "stock.notify_stock_qty",
- "stock.use_config_max_sale_qty",
- "stock.use_config_max_sale_qty",
- "stock.qty_increments",
- "stock.stock_status_changed_auto",
- "stock.show_default_notification_message",
- "stock.use_config_qty_increments",
- "stock.is_decimal_divided"
- ]
- },
- "review": {
- "excludeFields": [
- "review_entity",
- "review_status"
- ]
- },
- "product": {
- "excludeFields": [
- "attribute_set_id",
- "created_at",
- "has_options",
- "msrp_display_actual_price_type",
- "*.msrp_display_actual_price_type",
- "options_container",
- "required_options",
- "small_image",
- "stock.enable_qty_increments",
- "stock.is_decimal_divided",
- "stock.manage_stock",
- "stock.notify_stock_qty",
- "stock.qty_increments",
- "stock.show_default_notification_message",
- "stock.stock_id",
- "stock.stock_status_changed_auto",
- "stock.use_config_qty_increments",
- "stock.use_config_min_qty",
- "stock.use_config_notify_stock_qty",
- "stock.use_config_backorders",
- "stock.use_config_enable_qty_inc",
- "stock.use_config_manage_stock",
- "stock.use_config_min_sale_qty",
- "stock.use_config_max_sale_qty",
- "sgn",
- "*.sgn",
- "updated_at"
- ],
- "includeFields": null,
- "useDynamicAttributeLoader": true,
- "standardSystemFields": [
- "category",
- "category_ids",
- "color_options",
- "configurable_children",
- "configurable_options",
- "custom_attributes",
- "custom_design_from",
- "description",
- "erin_recommends",
- "errors",
- "final_price",
- "final_price_incl_tax",
- "final_price_tax",
- "gift_message_available",
- "id",
- "image",
- "info",
- "is_configured",
- "links",
- "max_price",
- "max_regular_price",
- "media_gallery",
- "minimal_regular_price",
- "minimal_price",
- "name",
- "news_from_date",
- "original_price",
- "original_price_incl_tax",
- "options",
- "parentSku",
- "priceTax",
- "priceInclTax",
- "product_option",
- "price",
- "price_incl_tax",
- "price_tax",
- "qty",
- "regular_price",
- "size_options",
- "sku",
- "slug",
- "specialPriceInclTax",
- "specialPriceTax",
- "special_price_tax",
- "special_price_incl_tax",
- "special_from_date",
- "special_price",
- "status",
- "stock",
- "_score",
- "tax_class_id",
- "thumbnail",
- "tsk",
- "type_id",
- "url_key",
- "url_path",
- "visibility"
- ]
- }
- },
- "cart": {
- "thumbnails": {
- "width": 150,
- "height": 150
- },
- "serverMergeByDefault": true,
- "serverSyncCanRemoveLocalItems": false,
- "serverSyncCanModifyLocalItems": false,
- "synchronize": true,
- "synchronize_totals": true,
- "setCustomProductOptions": true,
- "setConfigurableProductOptions": true,
- "askBeforeRemoveProduct": true,
- "displayItemDiscounts": true,
- "productsAreReconfigurable": true,
- "minicartCountType": "quantities",
- "create_endpoint": "/api/cart/create?token={{token}}",
- "updateitem_endpoint": "/api/cart/update?token={{token}}&cartId={{cartId}}",
- "deleteitem_endpoint": "/api/cart/delete?token={{token}}&cartId={{cartId}}",
- "pull_endpoint": "/api/cart/pull?token={{token}}&cartId={{cartId}}",
- "totals_endpoint": "/api/cart/totals?token={{token}}&cartId={{cartId}}",
- "paymentmethods_endpoint": "/api/cart/payment-methods?token={{token}}&cartId={{cartId}}",
- "shippingmethods_endpoint": "/api/cart/shipping-methods?token={{token}}&cartId={{cartId}}",
- "shippinginfo_endpoint": "/api/cart/shipping-information?token={{token}}&cartId={{cartId}}",
- "collecttotals_endpoint": "/api/cart/collect-totals?token={{token}}&cartId={{cartId}}",
- "deletecoupon_endpoint": "/api/cart/delete-coupon?token={{token}}&cartId={{cartId}}",
- "applycoupon_endpoint": "/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}"
- },
- "attributes": {
- "disablePersistentAttributesCache": false
- },
- "products": {
- "fieldsToCompact": {
- "minimal_price": "mp",
- "has_options": "ho",
- "url_key": "u",
- "status": "s",
- "required_options": "ro",
- "name": "nm",
- "tax_class_id": "tci",
- "description": "desc",
- "minimal_regular_price": "mrp",
- "final_price": "fp",
- "price": "p",
- "special_price": "sp",
- "original_final_price": "ofp",
- "original_price": "op",
- "original_special_price": "osp",
- "final_price_incl_tax": "fpit",
- "original_price_incl_tax": "opit",
- "price_incl_tax": "pit",
- "special_price_incl_tax": "spit",
- "final_price_tax": "fpt",
- "price_tax": "pt",
- "special_price_tax": "spt",
- "original_price_tax": "opt",
- "image": "i",
- "small_image": "si",
- "thumbnail": "t"
- },
- "disablePersistentProductsCache": true,
- "useMagentoUrlKeys": true,
- "setFirstVarianAsDefaultInURL": false,
- "configurableChildrenStockPrefetchStatic": false,
- "configurableChildrenStockPrefetchDynamic": true,
- "configurableChildrenStockPrefetchStaticPrefetchCount": 8,
- "filterUnavailableVariants": false,
- "listOutOfStockProducts": true,
- "preventConfigurableChildrenDirectAccess": true,
- "alwaysSyncPlatformPricesOver": false,
- "alwaysSyncPricesClientSide": false,
- "clearPricesBeforePlatformSync": false,
- "waitForPlatformSync": false,
- "setupVariantByAttributeCode": true,
- "omitVariantFields": [
- "name",
- "visibility"
- ],
- "calculateBundlePriceByOptions": true,
- "endpoint": "/api/product",
- "defaultFilters": [
- "color",
- "erin_recommends",
- "price",
- "size"
- ],
- "systemFilterNames": [
- "sort"
- ],
- "maxFiltersQuerySize": 999,
- "routerFiltersSource": "query",
- "filterFieldMapping": {
- "category.name": "category.name.keyword"
- },
- "colorMappings": {
- "Melange graphite": "#eeeeee"
- },
- "defaultSortBy": {
- "attribute": "updated_at",
- "order": "desc"
- },
- "sortByAttributes": {
- "Latest": "updated_at:desc",
- "Price: Low to high": "final_price",
- "Price: High to low": "final_price:desc"
- },
- "gallery": {
- "mergeConfigurableChildren": true,
- "imageAttributes": [
- "image",
- "thumbnail",
- "small_image"
- ],
- "width": 600,
- "height": 744
- },
- "thumbnails": {
- "width": 310,
- "height": 300
- },
- "filterAggregationSize": {
- "default": 10,
- "size": 10,
- "color": 10
- },
- "priceFilterKey": "final_price",
- "priceFilters": {
- "ranges": [
- { "from": 0, "to": 50 },
- { "from": 50, "to": 100 },
- { "from": 100, "to": 150 },
- { "from": 150 }
- ]
- },
- "aggregate": {
- "maxPrice": false,
- "minPrice": false
- }
- },
- "orders": {
- "directBackendSync": true,
- "endpoint": "/api/order",
- "payment_methods_mapping": {
- },
- "offline_orders": {
- "automatic_transmission_enabled": false,
- "notification": {
- "enabled": true,
- "title": "Order waiting!",
- "message": "Click here to confirm the order that you made offline.",
- "icon": "/assets/logo.png"
- }
- }
- },
- "localForage": {
- "defaultDrivers": {
- "user": "LOCALSTORAGE",
- "cmspage": "LOCALSTORAGE",
- "cmsblock": "LOCALSTORAGE",
- "carts": "LOCALSTORAGE",
- "orders": "LOCALSTORAGE",
- "wishlist": "LOCALSTORAGE",
- "categories": "LOCALSTORAGE",
- "attributes": "LOCALSTORAGE",
- "elasticCache": "LOCALSTORAGE",
- "claims": "LOCALSTORAGE",
- "syncTasks": "LOCALSTORAGE",
- "ordersHistory": "LOCALSTORAGE",
- "checkout": "LOCALSTORAGE"
- },
- "preserveCollections": [
- "cart",
- "user"
- ]
- },
- "reviews": {
- "create_endpoint": "/api/review/create"
- },
- "users": {
- "autoRefreshTokens": true,
- "loginAfterCreatePassword": true,
- "endpoint": "/api/user",
- "history_endpoint": "/api/user/order-history?token={{token}}&pageSize={{pageSize}}¤tPage={{currentPage}}",
- "resetPassword_endpoint": "/api/user/reset-password",
- "createPassword_endpoint": "http://localhost:8080/api/user/create-password",
- "changePassword_endpoint": "/api/user/change-password?token={{token}}",
- "login_endpoint": "/api/user/login",
- "create_endpoint": "/api/user/create",
- "me_endpoint": "/api/user/me?token={{token}}",
- "refresh_endpoint": "/api/user/refresh",
- "allowModification": ["firstname", "lastname", "email", "addresses"],
- "tokenInHeader": false
- },
- "stock": {
- "synchronize": true,
- "allowOutOfStockInCart": true,
- "endpoint": "/api/stock"
- },
- "images": {
- "useExactUrlsNoProxy": false,
- "baseUrl": "https://demo.vuestorefront.io/img/",
- "useSpecificImagePaths": false,
- "paths": {
- "product": "/catalog/product"
- },
- "productPlaceholder": "/assets/placeholder.jpg"
- },
- "install": {
- "is_local_backend": true,
- "backend_dir": "../vue-storefront-api"
- },
- "demomode": false,
- "tax": {
- "defaultCountry": "US",
- "defaultRegion": "",
- "sourcePriceIncludesTax": false,
- "calculateServerSide": true,
- "userGroupId": null,
- "useOnlyDefaultUserGroupId": false,
- "deprecatedPriceFieldsSupport": true,
- "finalPriceIncludesTax": false
- },
- "shipping": {
- "methods": [
- {
- "method_title": "DPD Courier",
- "method_code": "flatrate",
- "carrier_code": "flatrate",
- "amount": 4,
- "price_incl_tax": 5,
- "default": true,
- "offline": true
- }
- ]
- },
- "syncTasks": {
- "disablePersistentTaskQueue": true
- },
- "i18n": {
- "defaultCountry": "US",
- "defaultLanguage": "EN",
- "availableLocale": [
- "en-US"
- ],
- "defaultLocale": "en-US",
- "currencyCode": "USD",
- "currencySign": "$",
- "currencyDecimal": "",
- "currencyGroup": "",
- "fractionDigits": 2,
- "priceFormat": "{sign}{amount}",
- "dateFormat": "HH:mm D/M/YYYY",
- "fullCountryName": "United States",
- "fullLanguageName": "English",
- "bundleAllStoreviewLanguages": false
- },
- "expireHeaders": {
- "default": "30d",
- "application/json": "24h",
- "image/png": "7d"
- },
- "newsletter": {
- "endpoint": "/api/ext/mailchimp-subscribe/subscribe"
- },
- "mailer": {
- "endpoint": {
- "send": "/api/ext/mail-service/send-email",
- "token": "/api/ext/mail-service/get-token"
- },
- "contactAddress": "contributors@vuestorefront.io",
- "sendConfirmation": true
- },
- "theme": "@vue-storefront/theme-default",
- "analytics": {
- "id": false
- },
- "googleTagManager": {
- "id": false,
- "debug": true,
- "product_attributes": [
- "name",
- "id",
- "sku",
- {
- "priceInclTax": "price"
- },
- {
- "qty": "quantity"
- }
- ]
- },
- "hotjar": {
- "id": false
- },
- "cms": {
- "endpoint": "/api/ext/cms-data/cms{{type}}/{{cmsId}}",
- "endpointIdentifier": "/api/ext/cms-data/cms{{type}}Identifier/{{cmsIdentifier}}/storeId/{{storeId}}"
- },
- "cms_block": {
- "max_count": 500
- },
- "cms_page": {
- "max_count": 500
- },
- "usePriceTiers": false,
- "useZeroPriceProduct": true,
- "query": {
- "inspirations": {
- "filter": [
- {
- "key": "category.name",
- "value": { "eq": "Performance Fabrics" }
- }
- ]
- },
- "newProducts": {
- "filter": [
- {
- "key": "new",
- "value": { "eq": 1 }
- }
- ]
- },
- "bestSellers": {
- "filter": [
- {
- "key": "category.name",
- "value": { "eq": "Tees" }
- }
- ]
- }
- },
- "urlModule": {
- "enableMapFallbackUrl": false,
- "endpoint": "/api/url",
- "map_endpoint": "/api/url/map"
- },
- "fastly": {
- "enabled":false
- },
- "nginx": {
- "enabled":false
- },
- "varnish": {
- "enabled":false
- },
- "purgeConfig": [
- "server.invalidateCacheKey",
- "server.invalidateCacheForwardUrl",
- "server.trace",
- "redis",
- "install",
- "expireHeaders",
- "fastly",
- "nginx",
- "varnish",
- "cloudflare"
- ]
-}
diff --git a/config/test.json b/config/test.json
deleted file mode 100644
index 9e26dfeeb6..0000000000
--- a/config/test.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
\ No newline at end of file
diff --git a/core/app.ts b/core/app.ts
deleted file mode 100755
index 72fc80ed66..0000000000
--- a/core/app.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-import { Store } from 'vuex'
-import RootState from '@vue-storefront/core/types/RootState'
-import Vue from 'vue'
-import { isServer } from '@vue-storefront/core/helpers'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import i18n from '@vue-storefront/i18n'
-import VueRouter from 'vue-router'
-import VueLazyload from 'vue-lazyload'
-import Vuelidate from 'vuelidate'
-import Meta from 'vue-meta'
-import { sync } from 'vuex-router-sync'
-import VueObserveVisibility from 'vue-observe-visibility'
-import { getApolloProvider } from './scripts/resolvers/resolveGraphQL'
-// TODO simplify by removing global mixins, plugins and filters - it can be done in normal 'vue' way
-import { registerTheme } from '@vue-storefront/core/lib/themes'
-import { themeEntry } from 'theme/index.js'
-import { registerModules } from '@vue-storefront/core/lib/module'
-import { prepareStoreView, currentStoreView } from '@vue-storefront/core/lib/multistore'
-import * as coreMixins from '@vue-storefront/core/mixins'
-import * as coreFilters from '@vue-storefront/core/filters'
-import * as corePlugins from '@vue-storefront/core/compatibility/plugins'
-import { once } from '@vue-storefront/core/helpers'
-import store from '@vue-storefront/core/store'
-import { enabledModules } from './modules-entry'
-import globalConfig from 'config'
-import { injectReferences } from '@vue-storefront/core/lib/modules'
-import { coreHooksExecutors } from '@vue-storefront/core/hooks'
-import { registerClientModules } from 'src/modules/client'
-import initialStateFactory from '@vue-storefront/core/helpers/initialStateFactory'
-import { createRouter, createRouterProxy } from '@vue-storefront/core/helpers/router'
-import { checkForIntlPolyfill } from '@vue-storefront/i18n/intl'
-
-const stateFactory = initialStateFactory(store.state)
-
-let router: VueRouter = null
-let routerProxy: VueRouter = null
-
-once('__VUE_EXTEND_RR__', () => {
- Vue.use(VueRouter)
-})
-
-const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vue, router: VueRouter, store: Store, initialState: RootState}> => {
- router = createRouter()
- routerProxy = createRouterProxy(router)
- // sync router with vuex 'router' store
- sync(store, routerProxy)
- // TODO: Don't mutate the state directly, use mutation instead
- store.state.version = process.env.APPVERSION
- store.state.config = config // @deprecated
- store.state.__DEMO_MODE__ = (config.demomode === true)
- if (ssrContext) {
- // @deprecated - we shouldn't share server context between requests
- Vue.prototype.$ssrRequestContext = {
- output: {
- cacheTags: ssrContext.output.cacheTags
- },
- userAgent: ssrContext.server.request.headers['user-agent']
- }
-
- Vue.prototype.$cacheTags = ssrContext.output.cacheTags
- }
- if (!store.state.config) store.state.config = globalConfig // @deprecated - we should avoid the `config`
- const storeView = await prepareStoreView(storeCode) // prepare the default storeView
- store.state.storeView = storeView
-
- // @deprecated from 2.0
- once('__VUE_EXTEND__', () => {
- Vue.use(Vuelidate)
- Vue.use(VueLazyload, { attempt: 2, preLoad: 1.5 })
- Vue.use(Meta, {
- ssrAppId: 1
- })
- Vue.use(VueObserveVisibility)
-
- Object.keys(corePlugins).forEach(key => {
- Vue.use(corePlugins[key])
- })
-
- Object.keys(coreMixins).forEach(key => {
- Vue.mixin(coreMixins[key])
- })
-
- Object.keys(coreFilters).forEach(key => {
- Vue.filter(key, coreFilters[key])
- })
- })
-
- let vueOptions = {
- router: routerProxy,
- store,
- i18n,
- render: h => h(themeEntry)
- }
-
- const apolloProvider = await getApolloProvider()
- if (apolloProvider) Object.assign(vueOptions, { provider: apolloProvider })
-
- const app = new Vue(vueOptions)
-
- const appContext = {
- isServer,
- ssrContext
- }
-
- injectReferences(app, store, routerProxy, globalConfig)
- registerClientModules()
- registerModules(enabledModules, appContext)
- registerTheme(globalConfig.theme, app, routerProxy, store, globalConfig, ssrContext)
-
- await checkForIntlPolyfill(storeView)
-
- coreHooksExecutors.afterAppInit()
- // @deprecated from 2.0
- EventBus.$emit('application-after-init', app)
-
- return { app, router: routerProxy, store, initialState: stateFactory.createInitialState(store.state) }
-}
-
-export { routerProxy as router, createApp, router as baseRouter }
diff --git a/core/build/dev-server.js b/core/build/dev-server.js
deleted file mode 100644
index b40d7554ff..0000000000
--- a/core/build/dev-server.js
+++ /dev/null
@@ -1,67 +0,0 @@
-const path = require('path')
-const webpack = require('webpack')
-const MFS = require('memory-fs')
-
-let baseClientConfig = require('./webpack.client.config').default
-let baseServerConfig = require('./webpack.server.config').default
-
-const themeRoot = require('./theme-path')
-const extendedConfig = require(path.join(themeRoot, '/webpack.config.js'))
-
-let clientConfig = extendedConfig(baseClientConfig, { isClient: true, isDev: true })
-let serverConfig = extendedConfig(baseServerConfig, { isClient: false, isDev: true })
-
-module.exports = function setupDevServer (app, cb) {
- let bundle
- let template
-
- // Modify client config to work with hot middleware
- clientConfig.entry.app = ['webpack-hot-middleware/client', ...clientConfig.entry.app]
- clientConfig.output.filename = '[name].js'
- clientConfig.plugins.push(
- new webpack.HotModuleReplacementPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- )
-
- // Dev middleware
- const clientCompiler = webpack(clientConfig)
- const devMiddleware = require('webpack-dev-middleware')(clientCompiler, {
- publicPath: clientConfig.output.publicPath,
- stats: {
- colors: true,
- chunks: false
- }
- })
- app.use(devMiddleware)
- clientCompiler.plugin('done', () => {
- const fs = devMiddleware.fileSystem
- const filePath = path.join(clientConfig.output.path, 'index.html')
- if (fs.existsSync(filePath)) {
- template = fs.readFileSync(filePath, 'utf-8')
- if (bundle) {
- cb(bundle, template)
- }
- }
- })
-
- // Hot middleware
- app.use(require('webpack-hot-middleware')(clientCompiler))
-
- // watch and update server renderer
- const serverCompiler = webpack(serverConfig)
- const mfs = new MFS()
- serverCompiler.outputFileSystem = mfs
- serverCompiler.watch({}, (err, stats) => {
- if (err) throw err
- stats = stats.toJson()
- stats.errors.forEach(err => console.error(err))
- stats.warnings.forEach(err => console.warn(err))
-
- // Read bundle generated by vue-ssr-webpack-plugin
- const bundlePath = path.join(serverConfig.output.path, 'vue-ssr-bundle.json')
- bundle = JSON.parse(mfs.readFileSync(bundlePath, 'utf-8'))
- if (template) {
- cb(bundle, template)
- }
- })
-}
diff --git a/core/build/module-build.config.js b/core/build/module-build.config.js
deleted file mode 100644
index 82dc4d6c48..0000000000
--- a/core/build/module-build.config.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Webpack config used to build VS modules
-module.exports = {
- mode: 'production',
- entry: './src/index.ts',
- output: {
- libraryTarget: 'umd',
- globalObject: 'typeof self !== \'undefined\' ? self : this'
- },
- resolve: {
- extensions: ['.ts', '.js', '.json']
- },
- module: {
- rules: [
- {
- test: /\.ts$/,
- use: ['ts-loader'],
- options: {
- transpileOnly: true
- },
- exclude: /node_modules/
- }
- ]
- },
- externals: ['@vue-storefront/core']
-}
diff --git a/core/build/purge-config/purgeConfig.ts b/core/build/purge-config/purgeConfig.ts
deleted file mode 100644
index afd4f4d9b5..0000000000
--- a/core/build/purge-config/purgeConfig.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import omit from 'lodash/omit';
-
-export default config => {
- const purgeConfig = (config.purgeConfig || []).slice();
-
- config = omit(config, purgeConfig);
- delete config['purgeConfig'];
-
- return config;
-}
diff --git a/core/build/purge-config/purgeConfigLoader.ts b/core/build/purge-config/purgeConfigLoader.ts
deleted file mode 100644
index 9615509060..0000000000
--- a/core/build/purge-config/purgeConfigLoader.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import purgeConfig from './purgeConfig';
-
-/**
- * clear config properties that shouldn't be visible on frontend
- */
-export default function loader (source) {
- let config = JSON.parse(source);
- config = purgeConfig(config);
-
- return JSON.stringify(config);
-}
diff --git a/core/build/theme-path.js b/core/build/theme-path.js
deleted file mode 100644
index 671fa7000f..0000000000
--- a/core/build/theme-path.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const path = require('path')
-const detectInstalled = require('detect-installed')
-const config = require('./config.json')
-const fs = require("fs")
-
-// TODO: Refactor and simplify themePath resoultion
-let themePath = ''
-let themeName = config.theme
-if (detectInstalled.sync(config.theme, { local: true })) {
- themePath = path.resolve(__dirname, '../../node_modules/' + themeName)
-}
-else {
- themeName = themeName.replace('@vue-storefront/theme-', '')
- themePath = path.resolve(__dirname, '../../src/themes/' + themeName)
- if(!fs.existsSync(themePath)) {
- console.error(`
- The theme you want to use does not exist.
- Please check theme installation: https://docs.vuestorefront.io/guide/installation/theme.html
- `)
- process.exit(1)
- }
-}
-
-module.exports = themePath
diff --git a/core/build/webpack.base.config.ts b/core/build/webpack.base.config.ts
deleted file mode 100644
index fabf6cdf48..0000000000
--- a/core/build/webpack.base.config.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-import { buildLocaleIgnorePattern } from './../i18n/helpers';
-import path from 'path';
-import fs from 'fs';
-import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';
-import VueLoaderPlugin from 'vue-loader/lib/plugin';
-import autoprefixer from 'autoprefixer';
-import HTMLPlugin from 'html-webpack-plugin';
-import webpack from 'webpack';
-import dayjs from 'dayjs';
-import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
-// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
-
-// eslint-disable-next-line import/first
-import themeRoot from './theme-path';
-
-const themesRoot = '../../src/themes'
-const themeResources = themeRoot + '/resource'
-const themeCSS = themeRoot + '/css'
-const themeApp = themeRoot + '/App.vue'
-const themedIndex = path.join(themeRoot, '/templates/index.template.html')
-const themedIndexMinimal = path.join(themeRoot, '/templates/index.minimal.template.html')
-const themedIndexBasic = path.join(themeRoot, '/templates/index.basic.template.html')
-const themedIndexAmp = path.join(themeRoot, '/templates/index.amp.template.html')
-
-const postcssConfig = {
- loader: 'postcss-loader',
- options: {
- ident: 'postcss',
- plugins: (loader) => [
- require('postcss-flexbugs-fixes'),
- require('autoprefixer')({
- flexbox: 'no-2009'
- })
- ]
- }
-};
-const isProd = process.env.NODE_ENV === 'production'
-// todo: usemultipage-webpack-plugin for multistore
-export default {
- plugins: [
- new webpack.ContextReplacementPlugin(/dayjs[/\\]locale$/, buildLocaleIgnorePattern()),
- new webpack.ProgressPlugin(),
- /* new BundleAnalyzerPlugin({
- generateStatsFile: true
- }), */
- new CaseSensitivePathsPlugin(),
- new VueLoaderPlugin(),
- // generate output HTML
- new HTMLPlugin({
- template: fs.existsSync(themedIndex) ? themedIndex : 'src/index.template.html',
- filename: 'index.html',
- chunksSortMode: 'none',
- inject: isProd === false // in dev mode we're not using clientManifest therefore renderScripts() is returning empty string and we need to inject scripts using HTMLPlugin
- }),
- new HTMLPlugin({
- template: fs.existsSync(themedIndexMinimal) ? themedIndexMinimal : 'src/index.minimal.template.html',
- filename: 'index.minimal.html',
- chunksSortMode: 'none',
- inject: isProd === false
- }),
- new HTMLPlugin({
- template: fs.existsSync(themedIndexBasic) ? themedIndexBasic : 'src/index.basic.template.html',
- filename: 'index.basic.html',
- chunksSortMode: 'none',
- inject: isProd === false
- }),
- new HTMLPlugin({
- template: fs.existsSync(themedIndexAmp) ? themedIndexAmp : 'src/index.amp.template.html',
- filename: 'index.amp.html',
- chunksSortMode: 'none',
- inject: isProd === false
- }),
- new webpack.DefinePlugin({
- 'process.env.__APPVERSION__': JSON.stringify(require('../../package.json').version),
- 'process.env.__BUILDTIME__': JSON.stringify(dayjs().format('YYYY-MM-DD HH:mm:ss'))
- }),
- new ForkTsCheckerWebpackPlugin({
- typescript: {
- extensions: {
- vue: true
- }
- }
- })
- ],
- devtool: 'source-map',
- entry: {
- app: ['@babel/polyfill', './core/client-entry.ts']
- },
- output: {
- path: path.resolve(__dirname, '../../dist'),
- publicPath: '/dist/',
- filename: '[name].[hash].js'
- },
- resolveLoader: {
- modules: [
- 'node_modules',
- path.resolve(__dirname, themesRoot)
- ]
- },
- resolve: {
- modules: [
- 'node_modules',
- path.resolve(__dirname, themesRoot)
- ],
- extensions: ['.js', '.vue', '.gql', '.graphqls', '.ts'],
- alias: {
- // Main aliases
- 'config': path.resolve(__dirname, './config.json'),
- 'src': path.resolve(__dirname, '../../src'),
-
- // Theme aliases
- 'theme': themeRoot,
- 'theme/app': themeApp,
- 'theme/css': themeCSS,
- 'theme/resource': themeResources,
-
- // Backward compatible
- '@vue-storefront/core/lib/store/multistore': path.resolve(__dirname, '../lib/multistore.ts'),
- 'src/modules/order-history/components/UserOrders': path.resolve(__dirname, '../../core/modules/order/components/UserOrdersHistory'),
- '@vue-storefront/core/modules/social-share/components/WebShare': path.resolve(__dirname, '../../src/themes/default/components/theme/WebShare.vue'),
- '@vue-storefront/core/helpers/initCacheStorage': path.resolve(__dirname, '../lib/storage-manager.ts')
- }
- },
- module: {
- rules: [
- {
- enforce: 'pre',
- test: /\.(js|vue,ts)$/,
- loader: 'eslint-loader',
- exclude: [/node_modules/, /test/]
- },
- {
- test: /\.vue$/,
- loader: 'vue-loader',
- options: {
- preserveWhitespace: false,
- postcss: [autoprefixer()]
- }
- },
- {
- test: /\.ts$/,
- loader: 'ts-loader',
- options: {
- appendTsSuffixTo: [/\.vue$/],
- transpileOnly: true
- },
- exclude: /node_modules/
- },
- {
- test: /\.js$/,
- loader: 'babel-loader',
- include: [
- path.resolve(__dirname, '../../node_modules/@vue-storefront'),
- path.resolve(__dirname, '../../src'),
- path.resolve(__dirname, '../../core')
- ]
- },
- {
- test: /\.(png|jpg|gif|svg)$/,
- loader: 'file-loader',
- options: {
- name: '[name].[ext]?[hash]'
- }
- },
- {
- test: /\.css$/,
- use: [
- 'vue-style-loader',
- 'css-loader',
- postcssConfig
- ]
- },
- {
- test: /\.scss$/,
- use: [
- 'vue-style-loader',
- 'css-loader',
- postcssConfig,
- 'sass-loader'
- ]
- },
- {
- test: /\.sass$/,
- use: [
- 'vue-style-loader',
- 'css-loader',
- postcssConfig,
- {
- loader: 'sass-loader',
- options: {
- indentedSyntax: true
- }
- }
- ]
- },
- {
- test: /\.(woff|woff2|eot|ttf)(\?.*$|$)/,
- loader: 'url-loader?importLoaders=1&limit=10000'
- },
- {
- test: /\.(graphqls|gql)$/,
- exclude: /node_modules/,
- loader: ['graphql-tag/loader']
- },
- {
- test: /core\/build\/config\.json$/,
- loader: path.resolve('core/build/purge-config/purgeConfigLoader.ts')
- }
- ]
- }
-}
diff --git a/core/build/webpack.client.config.ts b/core/build/webpack.client.config.ts
deleted file mode 100644
index 553d7d8ece..0000000000
--- a/core/build/webpack.client.config.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import webpack from 'webpack'
-import merge from 'webpack-merge'
-import base from './webpack.base.config'
-import VueSSRClientPlugin from 'vue-server-renderer/client-plugin'
-// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
-
-const config = merge(base, {
- optimization: {
- splitChunks: {
- cacheGroups: {
- commons: {
- // create 'vendor' group from initial packages from node_modules
- test: /node_modules/,
- name: 'vendor',
- chunks: 'initial',
- priority: 1
- }
- }
- },
- runtimeChunk: {
- name: 'manifest'
- }
- },
- mode: 'development',
- resolve: {
- alias: {
- 'create-api': './create-api-client.js'
- }
- },
- plugins: [
- // new BundleAnalyzerPlugin(),
- // strip dev-only code in Vue source
- new webpack.DefinePlugin({
- 'process.env.VUE_ENV': '"client"'
- }),
- new VueSSRClientPlugin()
- ]
-})
-
-export default config;
diff --git a/core/build/webpack.prod.client.config.ts b/core/build/webpack.prod.client.config.ts
deleted file mode 100644
index 426e14b57f..0000000000
--- a/core/build/webpack.prod.client.config.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import path from 'path';
-import merge from 'webpack-merge';
-import baseClientConfig from './webpack.client.config';
-const themeRoot = require('./theme-path');
-
-const extendedConfig = require(path.join(themeRoot, '/webpack.config.js'))
-
-const prodClientConfig = merge(baseClientConfig, {
- mode: 'production',
- devtool: 'nosources-source-map',
- plugins: [
- ]
-})
-
-module.exports = extendedConfig(prodClientConfig, {
- isClient: true,
- isDev: false
-})
diff --git a/core/build/webpack.prod.server.config.ts b/core/build/webpack.prod.server.config.ts
deleted file mode 100644
index 3c22944a12..0000000000
--- a/core/build/webpack.prod.server.config.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import path from 'path';
-
-import baseServerConfig from './webpack.server.config';
-
-import themeRoot from './theme-path';
-
-const extendedConfig = require(path.join(themeRoot, '/webpack.config.js'))
-
-export default extendedConfig(baseServerConfig, {
- mode: 'production',
- devtool: 'nosources-source-map',
- isClient: false,
- isDev: false
-})
diff --git a/core/build/webpack.prod.sw.config.ts b/core/build/webpack.prod.sw.config.ts
deleted file mode 100644
index 64f90aa020..0000000000
--- a/core/build/webpack.prod.sw.config.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-import webpack from 'webpack';
-import merge from 'webpack-merge';
-import base from './webpack.base.config';
-import SWPrecachePlugin from 'sw-precache-webpack-plugin';
-
-module.exports = merge(base, {
- mode: 'production',
- target: 'web',
- entry: ['@babel/polyfill', './core/service-worker/index.js'],
- output: {
- filename: 'core-service-worker.js'
- },
- plugins: [
- new webpack.DefinePlugin({
- 'process.env.VUE_ENV': '"client"'
- }),
- // auto generate service worker
- new SWPrecachePlugin({
- cacheId: 'vue-sfr',
- filename: 'service-worker.js',
- staticFileGlobsIgnorePatterns: [/\.map$/],
- staticFileGlobs: [
- 'dist/**.*.js',
- 'dist/**.*.json',
- 'dist/**.*.css',
- 'assets/**.*',
- 'assets/ig/**.*',
- 'index.html',
- '/'
- ],
- runtimeCaching: [
- {
- // eslint-disable-next-line no-useless-escape
- urlPattern: '^https://fonts\.googleapis\.com/', /** cache the html stub */
- handler: 'cacheFirst'
- },
- {
- // eslint-disable-next-line no-useless-escape
- urlPattern: '^https://fonts\.gstatic\.com/', /** cache the html stub */
- handler: 'cacheFirst'
- },
- {
- // eslint-disable-next-line no-useless-escape
- urlPattern: '^https://unpkg\.com/', /** cache the html stub */
- handler: 'cacheFirst'
- },
- {
- urlPattern: '/pwa.html', /** cache the html stub */
- handler: 'networkFirst'
- }, {
- urlPattern: '/', /** cache the html stub for homepage */
- handler: 'networkFirst'
- },
- {
- urlPattern: '/p/*', /** cache the html stub */
- handler: 'networkFirst'
- },
- {
- urlPattern: '/c/*', /** cache the html stub */
- handler: 'networkFirst'
- },
- {
- urlPattern: '/img/(.*)',
- handler: 'fastest'
- },
- {
- urlPattern: /(http[s]?:\/\/)?(\/)?([^\/\s]+\/)?(api\/catalog\/)(.*)/g, // eslint-disable-line no-useless-escape
- handler: 'networkFirst'
- },
- {
- urlPattern: '/api/*',
- handler: 'networkFirst'
- }, {
- urlPattern: '/assets/logo.svg',
- handler: 'networkFirst'
- }, {
- urlPattern: '/index.html',
- handler: 'networkFirst'
- }, {
- urlPattern: '/assets/*',
- handler: 'fastest'
- }, {
- urlPattern: '/assets/ig/(.*)',
- handler: 'fastest'
- }, {
- urlPattern: '/dist/(.*)',
- handler: 'fastest'
- }, {
- urlPattern: '/*/*', /** this is new product URL format */
- handler: 'networkFirst'
- },
- {
- urlPattern: '/*/*/*', /** this is new product URL format */
- handler: 'networkFirst'
- },
- {
- urlPattern: '/*', /** this is new category URL format */
- handler: 'networkFirst'
- }],
- 'importScripts': ['/dist/core-service-worker.js'] /* custom logic */
- })
- ]
-})
diff --git a/core/build/webpack.server.config.ts b/core/build/webpack.server.config.ts
deleted file mode 100644
index 729ff89a57..0000000000
--- a/core/build/webpack.server.config.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import webpack from 'webpack';
-import merge from 'webpack-merge';
-import base from './webpack.base.config';
-import VueSSRPlugin from 'vue-ssr-webpack-plugin';
-
-// when output cache is enabled generate cache version key
-import config from 'config'
-import fs from 'fs'
-import path from 'path'
-import uuid from 'uuid/v4'
-
-if (config.server.useOutputCache) {
- fs.writeFileSync(
- path.join(__dirname, 'cache-version.json'),
- JSON.stringify(uuid())
- )
-}
-
-export default merge(base, {
- mode: 'development',
- target: 'node',
- entry: ['@babel/polyfill', './core/server-entry.ts'],
- output: {
- filename: 'server-bundle.js',
- libraryTarget: 'commonjs2'
- },
- resolve: {
- alias: {
- 'create-api': './create-api-server.js'
- }
- },
- externals: Object.keys(require('../../package.json').dependencies),
- plugins: [
- new webpack.DefinePlugin({
- 'process.env.VUE_ENV': '"server"'
- }),
- new VueSSRPlugin()
- ]
-})
diff --git a/core/client-entry.ts b/core/client-entry.ts
deleted file mode 100755
index e197396125..0000000000
--- a/core/client-entry.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-import Vue from 'vue'
-import union from 'lodash-es/union'
-import { createApp } from '@vue-storefront/core/app'
-import rootStore from '@vue-storefront/core/store'
-import { registerSyncTaskProcessor } from '@vue-storefront/core/lib/sync/task'
-import i18n from '@vue-storefront/i18n'
-import omit from 'lodash-es/omit'
-import storeCodeFromRoute from '@vue-storefront/core/lib/storeCodeFromRoute'
-import { currentStoreView, localizedRoute } from '@vue-storefront/core/lib/multistore'
-import { onNetworkStatusChange } from '@vue-storefront/core/modules/offline-order/helpers/onNetworkStatusChange'
-import '@vue-storefront/core/service-worker/registration' // register the service worker
-import { AsyncDataLoader } from './lib/async-data-loader'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import globalConfig from 'config'
-import { coreHooksExecutors } from './hooks'
-import { RouterManager } from './lib/router-manager';
-declare var window: any
-
-const invokeClientEntry = async () => {
- const dynamicRuntimeConfig = window.__INITIAL_STATE__.config ? Object.assign(globalConfig, window.__INITIAL_STATE__.config) : globalConfig
- // Get storeCode from server (received either from cache header or env variable)
- let storeCode = window.__INITIAL_STATE__.storeView.storeCode
- const { app, router, store } = await createApp(null, dynamicRuntimeConfig, storeCode)
-
- if (window.__INITIAL_STATE__) {
- // skip fields that were set by createApp
- const initialState = coreHooksExecutors.beforeHydrated(
- omit(window.__INITIAL_STATE__, ['storeView', 'config', 'version', 'route'])
- )
- store.replaceState(Object.assign({}, store.state, initialState, { config: globalConfig }))
- }
-
- await store.dispatch('url/registerDynamicRoutes')
- RouterManager.flushRouteQueue()
-
- function _commonErrorHandler (err, reject) {
- if (err.message.indexOf('query returned empty result') > 0) {
- rootStore.dispatch('notification/spawnNotification', {
- type: 'error',
- message: i18n.t('The product, category or CMS page is not available in Offline mode. Redirecting to Home.'),
- action1: { label: i18n.t('OK') }
- })
- router.push(localizedRoute('/', currentStoreView().storeCode))
- } else {
- rootStore.dispatch('notification/spawnNotification', {
- type: 'error',
- message: i18n.t(err.message),
- action1: { label: i18n.t('OK') }
- })
- reject()
- }
- }
-
- function _ssrHydrateSubcomponents (components, next, to) {
- Promise.all(components.map(SubComponent => {
- if (SubComponent.asyncData) {
- return SubComponent.asyncData({
- store,
- route: to
- })
- } else {
- return Promise.resolve(null)
- }
- })).then(() => {
- AsyncDataLoader.flush({ store, route: to, context: null }).then(next).catch(err => {
- _commonErrorHandler(err, next)
- })
- }).catch(err => {
- _commonErrorHandler(err, next)
- })
- }
- router.onReady(async () => {
- // check if app can be mounted
- const canBeMounted = () => RouterManager.isRouteDispatched() && // route is dispatched
- !(router as any).history.pending && // there is no pending in router history
- !(app as any)._isMounted // it's not mounted before
-
- if (canBeMounted()) {
- app.$mount('#app')
- }
- router.beforeResolve((to, from, next) => {
- if (!from.name) {
- next()
- if (canBeMounted()) {
- app.$mount('#app')
- }
- return // do not resolve asyncData on server render - already been done
- }
- if (!Vue.prototype.$cacheTags) Vue.prototype.$cacheTags = new Set()
- const matched = router.getMatchedComponents(to)
- if (to) { // this is from url
- if (globalConfig.storeViews.multistore === true) {
- const currentRoute = Object.assign({}, to, { host: window.location.host })
- const storeCode = storeCodeFromRoute(currentRoute)
- const currentStore = currentStoreView()
- if (storeCode !== '' && storeCode !== null) {
- if (storeCode !== currentStore.storeCode) {
- (document as any).location = to.path // full reload
- }
- }
- }
- }
- if (!matched.length || !matched[0]) {
- return next()
- }
-
- store.dispatch('url/setCurrentRoute', { to, from })
-
- Promise.all(matched.map((c: any) => { // TODO: update me for mixins support
- const components = c.mixins && globalConfig.ssr.executeMixedinAsyncData ? Array.from(c.mixins) : []
- union(components, [c]).map(SubComponent => {
- if (SubComponent.preAsyncData) {
- SubComponent.preAsyncData({ store, route: to })
- }
- })
- if (c.asyncData) {
- c.asyncData({ store, route: to }).then(result => { // always execute the asyncData() from the top most component first
- Logger.debug('Top-most asyncData executed')()
- _ssrHydrateSubcomponents(components, next, to)
- }).catch(next)
- } else {
- _ssrHydrateSubcomponents(components, next, to)
- }
- }))
- })
- })
- registerSyncTaskProcessor()
- window.addEventListener('online', () => { onNetworkStatusChange(store) })
-}
-
-invokeClientEntry()
diff --git a/core/compatibility/README.md b/core/compatibility/README.md
deleted file mode 100644
index 11196bc1cf..0000000000
--- a/core/compatibility/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Outdated VS APIs that shouldn't be used in new projects. They are safe to use in current ones tho since we are providing backward support for them. Most of the components here was refactored and placed inside core modules.
\ No newline at end of file
diff --git a/core/compatibility/components/AddToCart.js b/core/compatibility/components/AddToCart.js
deleted file mode 100644
index be5981cf12..0000000000
--- a/core/compatibility/components/AddToCart.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { AddToCart } from '@vue-storefront/core/modules/cart/components/AddToCart.ts'
-
-export default {
- name: 'AddToCart',
- mixins: [ AddToCart ]
-}
diff --git a/core/compatibility/components/Breadcrumbs.js b/core/compatibility/components/Breadcrumbs.js
deleted file mode 100644
index b7f1c0b0c7..0000000000
--- a/core/compatibility/components/Breadcrumbs.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// breadcrumbs functionality will be rewritten, and this component is theme-specific
-export default {
- name: 'Breadcrumbs',
- props: {
- routes: {
- type: Array,
- required: true
- },
- activeRoute: {
- type: String,
- default: ''
- }
- }
-}
diff --git a/core/compatibility/components/GenericSelector.js b/core/compatibility/components/GenericSelector.js
deleted file mode 100644
index 880a39dc33..0000000000
--- a/core/compatibility/components/GenericSelector.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { ProductCustomOption } from '@vue-storefront/core/modules/catalog/components/ProductCustomOption'
-// renamed to ProductCustomOption and placed in catalog module
-export default {
- name: 'GenericSelector',
- mixins: [ProductCustomOption]
-}
diff --git a/core/compatibility/components/Notification.js b/core/compatibility/components/Notification.js
deleted file mode 100644
index ee260ca989..0000000000
--- a/core/compatibility/components/Notification.js
+++ /dev/null
@@ -1,40 +0,0 @@
-// deprecated moved to store
-export default {
- name: 'Notification',
- data () {
- return {
- notifications: []
- }
- },
- beforeMount () {
- this.$bus.$on('notification', this.onNotification)
- },
- beforeDestroy () {
- this.$bus.$off('notification', this.onNotification)
- },
- methods: {
- onNotification (data) {
- if (this.notifications.length > 0 && this.notifications[this.notifications.length - 1].message === data.message) {
- return
- }
- this.notifications.push(data)
-
- if (!data.hasNoTimeout) {
- setTimeout(() => {
- this.action('close', this.notifications.length - 1)
- }, data.timeToLive || 5000)
- }
- },
- action (action, id, notification) {
- this.$bus.$emit('notification-after-' + action, notification)
- switch (action) {
- case 'goToCheckout':
- this.$router.push(this.localizedRoute('/checkout'))
- this.notifications.splice(id, 1)
- break
- default:
- this.notifications.splice(id, 1)
- }
- }
- }
-}
diff --git a/core/compatibility/components/Overlay.js b/core/compatibility/components/Overlay.js
deleted file mode 100644
index 7822e68f12..0000000000
--- a/core/compatibility/components/Overlay.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// theme-specific component
-export default {
- name: 'Overlay',
- computed: {
- isVisible () {
- return this.$store.state.ui.overlay
- }
- },
- methods: {
- close () {
- this.$store.commit('ui/setOverlay', false)
- }
- }
-}
diff --git a/core/compatibility/components/PriceSelector.js b/core/compatibility/components/PriceSelector.js
deleted file mode 100644
index 93de829a8b..0000000000
--- a/core/compatibility/components/PriceSelector.js
+++ /dev/null
@@ -1,65 +0,0 @@
-// replaced with generic ProductCustomOption
-export default {
- name: 'PriceSelector',
- props: {
- content: {
- type: null,
- default: ''
- },
- id: {
- type: null,
- required: true
- },
- code: {
- type: null,
- required: true
- },
- from: {
- type: null,
- required: true
- },
- to: {
- type: null,
- required: true
- },
- context: {
- type: null,
- default: ''
- }
- },
- data () {
- return {
- active: false
- }
- },
- beforeMount () {
- this.$bus.$on('filter-reset', this.filterReset)
- this.$bus.$on('filter-changed-' + this.context, this.filterChanged)
- },
- beforeDestroy () {
- this.$bus.$off('filter-reset', this.filterReset)
- this.$bus.$off('filter-changed-' + this.context, this.filterChanged)
- },
- methods: {
- filterChanged (filterOption) {
- if (filterOption.attribute_code === this.code) {
- if (filterOption.id === this.id) {
- if (this.active) {
- this.active = false
- } else {
- this.active = true
- }
- } else {
- this.active = false
- }
- // filterOption.id === this.id ? this.active = true : this.active = false
- }
- },
- filterReset (filterOption) {
- this.active = false
- },
- switchFilter (id, from, to) {
- this.$bus.$emit('filter-changed-' + this.context, { attribute_code: this.code, id: id, from: from, to: to })
- }
- }
-}
diff --git a/core/compatibility/components/SortBy.js b/core/compatibility/components/SortBy.js
deleted file mode 100644
index db004c6050..0000000000
--- a/core/compatibility/components/SortBy.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { CategorySort } from '@vue-storefront/core/modules/catalog/components/CategorySort'
-import config from 'config'
-
-export default {
- name: 'SortBy',
- methods: {
- changeOrder () {
- // renamed to sort
- this.sort()
- }
- },
- computed: {
- sortByAttribute () {
- // renamed to sortingOptions
- return config.products.sortByAttributes
- }
- },
- mixins: [CategorySort]
-}
diff --git a/core/compatibility/components/ValidationError.js b/core/compatibility/components/ValidationError.js
deleted file mode 100644
index 2b2036d3a9..0000000000
--- a/core/compatibility/components/ValidationError.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// theme-specific component
-export default {
- name: 'ValidationError',
- props: {
- message: {
- type: String,
- default: ''
- }
- }
-}
diff --git a/core/compatibility/components/blocks/Auth/Login.js b/core/compatibility/components/blocks/Auth/Login.js
deleted file mode 100644
index bf1ebe4d0e..0000000000
--- a/core/compatibility/components/blocks/Auth/Login.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import { Login } from '@vue-storefront/core/modules/user/components/Login'
-export default {
- mixins: [Login]
-}
diff --git a/core/compatibility/components/blocks/Auth/Register.js b/core/compatibility/components/blocks/Auth/Register.js
deleted file mode 100644
index 52de38a824..0000000000
--- a/core/compatibility/components/blocks/Auth/Register.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import { Register } from '@vue-storefront/core/modules/user/components/Register'
-export default {
- mixins: [Register]
-}
diff --git a/core/compatibility/components/blocks/Category/Sidebar.js b/core/compatibility/components/blocks/Category/Sidebar.js
deleted file mode 100644
index c422975fa5..0000000000
--- a/core/compatibility/components/blocks/Category/Sidebar.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { buildFilterProductsQuery } from '@vue-storefront/core/helpers'
-import { mapGetters } from 'vuex'
-import pickBy from 'lodash-es/pickBy'
-
-export default {
- name: 'CategorySidebar',
- props: {
- filters: {
- type: Object,
- required: true
- }
- },
- computed: {
- ...mapGetters('category', ['getCurrentCategory', 'getActiveCategoryFilters', 'getCurrentCategoryProductQuery']),
- category () {
- return this.getCurrentCategory
- },
- activeFilters () {
- return this.getActiveCategoryFilters
- },
- availableFilters () {
- return pickBy(this.filters, (filter, filterType) => { return (filter.length && !this.$store.getters['category-next/getSystemFilterNames'].includes(filterType)) })
- },
- hasActiveFilters () {
- return Object.keys(this.activeFilters).length !== 0
- }
- },
- mounted () {
- this.resetAllFilters()
- },
- methods: {
- sortById (filters) {
- return [...filters].sort((a, b) => { return a.id - b.id })
- },
- resetAllFilters () {
- if (this.hasActiveFilters) {
- this.$bus.$emit('filter-reset')
- this.$store.dispatch('category/resetFilters')
- this.$store.dispatch('category/searchProductQuery', {})
- this.$store.dispatch('category/mergeSearchOptions', {
- searchProductQuery: buildFilterProductsQuery(this.category, this.activeFilters)
- })
- this.$store.dispatch('category/products', this.getCurrentCategoryProductQuery)
- }
- }
- }
-}
diff --git a/core/compatibility/components/blocks/Header/AccountIcon.js b/core/compatibility/components/blocks/Header/AccountIcon.js
deleted file mode 100644
index 8dae2e3c03..0000000000
--- a/core/compatibility/components/blocks/Header/AccountIcon.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { AccountButton } from '@vue-storefront/core/modules/user/components/AccountButton'
-
-export default {
- name: 'AccountIcon',
- data () {
- // theme-specific, deprecated
- return {
- navigation: []
- }
- },
- computed: {
- currentUser () {
- // renamed to 'user'
- return this.user
- }
- },
- mixins: [AccountButton]
-}
diff --git a/core/compatibility/components/blocks/Header/CompareIcon.js b/core/compatibility/components/blocks/Header/CompareIcon.js
deleted file mode 100644
index 5b12a1638c..0000000000
--- a/core/compatibility/components/blocks/Header/CompareIcon.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { CompareButton } from '@vue-storefront/core/modules/compare/components/CompareButton.ts'
-
-export default {
- name: 'CompareIcon',
- mixins: [CompareButton],
- computed: {
- isActive () {
- // Computed Property renamed to 'isEmpty'
- return !this.isEmpty
- }
- }
-}
diff --git a/core/compatibility/components/blocks/Header/HamburgerIcon.js b/core/compatibility/components/blocks/Header/HamburgerIcon.js
deleted file mode 100644
index f830f3a4f2..0000000000
--- a/core/compatibility/components/blocks/Header/HamburgerIcon.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { mapState } from 'vuex'
-
-// deprecated as theme specific
-export default {
- name: 'HamburgerIcon',
- computed: mapState({
- isOpen: state => state.ui.sidebar
- }),
- methods: {
- openSidebarMenu () {
- this.$store.commit('ui/setSidebar', !this.isOpen)
- }
- }
-}
diff --git a/core/compatibility/components/blocks/Header/MicrocartIcon.js b/core/compatibility/components/blocks/Header/MicrocartIcon.js
deleted file mode 100644
index 00ebeff97d..0000000000
--- a/core/compatibility/components/blocks/Header/MicrocartIcon.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { MicrocartButton } from '@vue-storefront/core/modules/cart/components/MicrocartButton.ts'
-
-export default {
- methods: {
- openMicrocart () {
- // Method renamed to 'toggleMicrocart' and is using cart store now
- this.$store.dispatch('ui/toggleMicrocart')
- }
- },
- computed: {
- totalQuantity () {
- // Data field renamed to 'quantity'
- return this.quantity
- }
- },
- mixins: [
- MicrocartButton
- ]
-}
diff --git a/core/compatibility/components/blocks/Header/ReturnIcon.js b/core/compatibility/components/blocks/Header/ReturnIcon.js
deleted file mode 100644
index 5d3956049d..0000000000
--- a/core/compatibility/components/blocks/Header/ReturnIcon.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// deprecated as theme-specific
-export default {
- name: 'ReturnIcon',
- props: {
- to: {
- type: String | Object,
- default: null
- }
- },
- methods: {
- goBack () {
- if (this.to) {
- this.$router.push(this.to)
- } else {
- this.$router.back()
- }
- }
- }
-}
diff --git a/core/compatibility/components/blocks/Header/SearchIcon.js b/core/compatibility/components/blocks/Header/SearchIcon.js
deleted file mode 100644
index c904d46c79..0000000000
--- a/core/compatibility/components/blocks/Header/SearchIcon.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { mapState } from 'vuex'
-
-export default {
- name: 'SearchIcon',
- computed: {
- ...mapState({
- isOpen: state => state.ui.searchpanel
- })
- },
- methods: {
- toggleSearchpanel () {
- this.$store.commit('ui/setSearchpanel', !this.isOpen)
- }
- }
-}
diff --git a/core/compatibility/components/blocks/Header/WishlistIcon.js b/core/compatibility/components/blocks/Header/WishlistIcon.js
deleted file mode 100644
index 8cc9d63afe..0000000000
--- a/core/compatibility/components/blocks/Header/WishlistIcon.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { WishlistButton } from '@vue-storefront/core/modules/wishlist/components/WishlistButton'
-export default {
- name: 'WishlistIcon',
- mixins: [ WishlistButton ],
- props: {
- product: {
- type: Object,
- required: false,
- default: () => { }
- }
- },
- computed: {
- // deprecated in this component
- isWishlistOpen () {
- return this.$store.state.ui.wishlist
- }
- },
- methods: {
- // deprecated
- closeWishlist () {
- this.$store.commit('ui/setWishlist', false)
- },
- // deprecated
- openWishlist () {
- this.$store.commit('ui/setWishlist', true)
- },
- // method renamed to toggleWishlist
- toggleWishlistPanel () {
- this.toggleWishlist()
- }
- }
-}
diff --git a/core/compatibility/components/blocks/Microcart/Microcart.js b/core/compatibility/components/blocks/Microcart/Microcart.js
deleted file mode 100644
index ac43fbd7a8..0000000000
--- a/core/compatibility/components/blocks/Microcart/Microcart.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Core dependecies
-import { Microcart } from '@vue-storefront/core/modules/cart/components/Microcart.ts'
-
-export default {
- methods: {
- closeMicrocart () {
- // Method renamed to 'toggleMicrocart'
- this.toggleMicrocart()
- }
- },
- computed: {
- isMicrocartOpen () {
- return this.$store.state.ui.microcart
- }
- },
- mixins: [
- Microcart
- ]
-}
diff --git a/core/compatibility/components/blocks/Microcart/Product.js b/core/compatibility/components/blocks/Microcart/Product.js
deleted file mode 100644
index 50326a8b53..0000000000
--- a/core/compatibility/components/blocks/Microcart/Product.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import { MicrocartProduct } from '@vue-storefront/core/modules/cart/components/Product.ts'
-import i18n from '@vue-storefront/i18n'
-import debounce from 'lodash-es/debounce'
-import config from 'config'
-
-export default {
- data () {
- // deprecated
- return {
- }
- },
- beforeMount () {
- // deprecated, will be moved to theme or removed in the near future #1742
- this.$bus.$on('cart-after-itemchanged', this.onProductChanged)
- this.$bus.$on('notification-after-itemremoved', this.onProductRemoved)
- this.updateQuantity = debounce(this.updateQuantity, 1000)
- },
- beforeDestroy () {
- // deprecated, will be moved to theme or removed in the near future #1742
- this.$bus.$off('cart-after-itemchanged', this.onProductChanged)
- this.$bus.$off('notification-after-itemremoved', this.onProductRemoved)
- this.updateQuantity.cancel()
- },
- methods: {
- removeItem () {
- if (config.cart.askBeforeRemoveProduct) {
- this.$store.dispatch('notification/spawnNotification', {
- type: 'warning',
- item: this.product,
- message: i18n.t('Are you sure you would like to remove this item from the shopping cart?'),
- action2: { label: i18n.t('OK'), action: this.removeFromCart },
- action1: { label: i18n.t('Cancel'), action: 'close' },
- hasNoTimeout: true
- })
- } else {
- this.removeFromCart()
- }
- },
- updateQuantity (newQuantity) {
- let quantity = parseInt(newQuantity)
- if (quantity < 1) quantity = 1
- MicrocartProduct.methods.updateQuantity.call(this, quantity)
- },
- onProductChanged (event) {
- // deprecated, will be moved to theme or removed in the near future #1742
- if (event.item.sku === this.product.sku) {
- this.$forceUpdate()
- }
- },
- onProductRemoved (event) {
- if (event.item.sku === this.product.sku) {
- this.removeFromCart(event.item)
- }
- }
- }
-}
diff --git a/core/compatibility/components/blocks/MyAccount/MyOrder.js b/core/compatibility/components/blocks/MyAccount/MyOrder.js
deleted file mode 100644
index b107d19ead..0000000000
--- a/core/compatibility/components/blocks/MyAccount/MyOrder.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { UserSingleOrder } from '@vue-storefront/core/modules/order/components/UserSingleOrder'
-
-// Component deprecated, now in Order module
-export default {
- name: 'MyOrder',
- mixins: [UserSingleOrder]
-}
diff --git a/core/compatibility/components/blocks/MyAccount/MyOrders.js b/core/compatibility/components/blocks/MyAccount/MyOrders.js
deleted file mode 100644
index e63625750c..0000000000
--- a/core/compatibility/components/blocks/MyAccount/MyOrders.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { UserOrders } from '@vue-storefront/core/modules/order/components/UserOrders'
-
-// component fully deprecated. Use user/components/Orders instead
-export default {
- name: 'MyOrders',
- mixins: [UserOrders]
-}
diff --git a/core/compatibility/components/blocks/MyAccount/MyProfile.js b/core/compatibility/components/blocks/MyAccount/MyProfile.js
deleted file mode 100644
index 89081c635d..0000000000
--- a/core/compatibility/components/blocks/MyAccount/MyProfile.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { UserAccount } from '@vue-storefront/core/modules/user/components/UserAccount'
-
-// Component deprecated, now in User module
-
-export default {
- name: 'MyProfile',
- mixins: [UserAccount]
-}
diff --git a/core/compatibility/components/blocks/MyAccount/MyShippingDetails.js b/core/compatibility/components/blocks/MyAccount/MyShippingDetails.js
deleted file mode 100644
index 006c946401..0000000000
--- a/core/compatibility/components/blocks/MyAccount/MyShippingDetails.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import { UserShippingDetails } from '@vue-storefront/core/modules/user/components/UserShippingDetails'
-export default {
- mixins: [UserShippingDetails]
-}
diff --git a/core/compatibility/components/blocks/SearchPanel/SearchPanel.js b/core/compatibility/components/blocks/SearchPanel/SearchPanel.js
deleted file mode 100644
index 48614f244c..0000000000
--- a/core/compatibility/components/blocks/SearchPanel/SearchPanel.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Search } from '@vue-storefront/core/modules/catalog/components/Search'
-
-// Moved to search module
-export default {
- mixins: [Search],
- computed: {
- showPanel () {
- return this.isOpen && this.componentLoaded
- }
- },
- mounted () {
- this.$nextTick(() => {
- this.componentLoaded = true
- })
- }
-}
diff --git a/core/compatibility/components/blocks/SidebarMenu/SidebarMenu.js b/core/compatibility/components/blocks/SidebarMenu/SidebarMenu.js
deleted file mode 100644
index a92416ec26..0000000000
--- a/core/compatibility/components/blocks/SidebarMenu/SidebarMenu.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { mapState, mapGetters } from 'vuex'
-import onEscapePress from '@vue-storefront/core/mixins/onEscapePress'
-import { CompareButton } from '@vue-storefront/core/modules/compare/components/CompareButton.ts'
-import config from 'config'
-
-// deprecated as theme-specific
-export default {
- name: 'SidebarMenu',
- mixins: [onEscapePress, CompareButton],
- computed: {
- ...mapGetters('category-next', ['getMenuCategories']),
- getCategories () {
- return this.getMenuCategories
- },
- categories () {
- return this.getCategories.filter((op) => {
- return op.level === (config.entities.category.categoriesDynamicPrefetchLevel >= 0 ? config.entities.category.categoriesDynamicPrefetchLevel : 2) // display only the root level (level =1 => Default Category), categoriesDynamicPrefetchLevel = 2 by default
- })
- },
- ...mapState({
- isOpen: state => state.ui.sidebar
- }),
- compareIsActive () {
- // Computed property renamed to 'isEmpty'
- return !this.isEmpty
- }
- },
- created () {
- },
- methods: {
- onEscapePress () {
- this.closeMenu()
- },
- closeMenu () {
- this.$store.commit('ui/setSidebar', false)
- this.$store.commit('ui/setMicrocart', false)
- }
- }
-}
diff --git a/core/compatibility/components/blocks/Wishlist/Product.js b/core/compatibility/components/blocks/Wishlist/Product.js
deleted file mode 100644
index de87541b62..0000000000
--- a/core/compatibility/components/blocks/Wishlist/Product.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { WishlistProduct } from '@vue-storefront/core/modules/wishlist/components/Product'
-export default {
- name: 'Product',
- methods: {
- // deprecated
- closeWishlist () {
- this.$store.commit('ui/setWishlist', false)
- }
- },
- mixins: [WishlistProduct]
-}
diff --git a/core/compatibility/components/blocks/Wishlist/Wishlist.js b/core/compatibility/components/blocks/Wishlist/Wishlist.js
deleted file mode 100644
index 97d9235b75..0000000000
--- a/core/compatibility/components/blocks/Wishlist/Wishlist.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import onEscapePress from '@vue-storefront/core/mixins/onEscapePress'
-import { Wishlist } from '@vue-storefront/core/modules/wishlist/components/Wishlist'
-export default {
- name: 'Wishlist',
- props: {
- // deprecated
- product: {
- type: Object,
- required: false,
- default: () => { }
- }
- },
- methods: {
- // theme-specific
- onEscapePress () {
- this.$store.dispatch('ui/closeWishlist')
- }
- },
- mixins: [ Wishlist, onEscapePress ]
-}
diff --git a/core/compatibility/plugins/config/index.js b/core/compatibility/plugins/config/index.js
deleted file mode 100644
index db7ff3eb99..0000000000
--- a/core/compatibility/plugins/config/index.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import config from 'config'
-
-// deprecated, use vuex store instead
-const ConfigPlugin = {
- install (Vue) {
- if (!Vue.prototype.$config) {
- Object.defineProperties(Vue.prototype, {
- $config: {
- get: function () {
- return config
- }
- }
- })
- }
- }
-}
-
-export { config as default, ConfigPlugin }
diff --git a/core/compatibility/plugins/event-bus/index.js b/core/compatibility/plugins/event-bus/index.js
deleted file mode 100644
index a81ebee444..0000000000
--- a/core/compatibility/plugins/event-bus/index.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import Vue from 'vue'
-// will be replaced with new mechanism with code-completion (via modules), don't use if you don't need to
-/**
- * Filter extension is for running async data filters as event handlers
- * Example:
- * let product = {}
- * EventBus.$filter('after-product-changed', (product) => {
- * return Promise ((resolve, reject) => {
- * product.sku = 'abc'
- * resolve (product)
- * })
- * })
- * EventBus.$filter('after-product-changed', (product) => {
- * return Promise ((resolve, reject) => {
- * product.name = 'ABC'
- * resolve (product)
- * })
- * })
- * EventBus.$emitFilter('after-product-changed', product).then((resultsFromEventHanlders) => {
- * // here you have data modified by extensions
- * // resultsFromEventHanlders = [ { sku: abc, name: 'ABC' }, { sku: abc, name: 'ABC' } ]
- * })
- */
-const filterExt = {
- $dataFilters: {
- value: [],
- writable: true
- }, // data filters to be registered by extension developers
- $filter: {
- get: function () {
- return (eventName, callback) => {
- if (!this.$dataFilters[eventName]) {
- this.$dataFilters[eventName] = []
- }
- this.$dataFilters[eventName].push(callback)
- }
- }
- },
- $emitFilter: {
- get: function () {
- return (eventName, ...args) => {
- if (args.length === 1) {
- args = args[0]
- }
- this.$emit(eventName, args)
- let promises = []
- if (this.$dataFilters[eventName]) {
- for (let cb of this.$dataFilters[eventName]) {
- promises.push(cb(args))
- }
- }
- return Promise.all(promises)
- }
- }
- }
-}
-const EventBus = new Vue()
-if (!EventBus.$dataFilters) {
- Object.defineProperties(EventBus, filterExt)
-}
-
-const EventBusPlugin = {
- install (Vue) {
- if (!Vue.prototype.$bus) { /** Vue.prototype.$bus is now @deprecated please do use `EventBus` instead */
- Object.defineProperties(Vue.prototype, {
- $bus: {
- get: function () {
- return EventBus
- }
- }
- })
- }
- }
-}
-export { EventBus as default, EventBusPlugin }
diff --git a/core/compatibility/plugins/index.js b/core/compatibility/plugins/index.js
deleted file mode 100644
index 42a61e6953..0000000000
--- a/core/compatibility/plugins/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { EventBusPlugin } from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { ConfigPlugin } from '@vue-storefront/core/compatibility/plugins/config'
-// used in core entrys and themes.js, deprecated bc of redundancy and for simplification of a project
-export {
- EventBusPlugin,
- ConfigPlugin
-}
diff --git a/core/data-resolver/CartService.ts b/core/data-resolver/CartService.ts
deleted file mode 100644
index 770d2a7295..0000000000
--- a/core/data-resolver/CartService.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-import { DataResolver } from './types/DataResolver'
-import Task from '@vue-storefront/core/lib/sync/types/Task'
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import { TaskQueue } from '@vue-storefront/core/lib/sync'
-import { processLocalizedURLAddress } from '@vue-storefront/core/helpers'
-import config from 'config';
-
-const setShippingInfo = async (addressInformation: any): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'shippinginfo_endpoint')),
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify({ addressInformation })
- },
- silent: true
- });
-
-const getTotals = async (): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'totals_endpoint')),
- payload: {
- method: 'GET',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- silent: true
- });
-
-const getCartToken = async (guestCart: boolean = false, forceClientState: boolean = false): Promise => {
- const url = processLocalizedURLAddress(guestCart
- ? getApiEndpointUrl(config.cart, 'create_endpoint').replace('{{token}}', '')
- : getApiEndpointUrl(config.cart, 'create_endpoint'))
-
- return TaskQueue.execute({
- url,
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- force_client_state: forceClientState,
- silent: true
- });
-}
-
-const updateItem = async (cartServerToken: string, cartItem: CartItem): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'updateitem_endpoint')),
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify({
- cartItem: {
- ...cartItem,
- quoteId: cartItem.quoteId || cartServerToken
- }
- })
- }
- });
-
-const deleteItem = async (cartServerToken: string, cartItem: CartItem): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'deleteitem_endpoint')),
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify({
- cartItem: {
- ...cartItem,
- quoteId: cartServerToken
- }
- })
- },
- silent: true
- });
-
-const getPaymentMethods = async (): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'paymentmethods_endpoint')),
- payload: {
- method: 'GET',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- silent: true
- });
-
-const getShippingMethods = async (address: any): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'shippingmethods_endpoint')),
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify({
- address
- })
- },
- silent: true
- });
-
-const getItems = async (): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'pull_endpoint')),
- payload: {
- method: 'GET',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- silent: true
- });
-
-const applyCoupon = async (couponCode: string): Promise => {
- const url = processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'applycoupon_endpoint').replace('{{coupon}}', couponCode))
-
- return TaskQueue.execute({
- url,
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- silent: false
- });
-}
-
-const removeCoupon = async (): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.cart, 'deletecoupon_endpoint')),
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- silent: false
- });
-
-export const CartService: DataResolver.CartService = {
- setShippingInfo,
- getTotals,
- getCartToken,
- updateItem,
- deleteItem,
- getPaymentMethods,
- getShippingMethods,
- getItems,
- applyCoupon,
- removeCoupon
-}
diff --git a/core/data-resolver/CategoryService.ts b/core/data-resolver/CategoryService.ts
deleted file mode 100644
index 1505f8eda0..0000000000
--- a/core/data-resolver/CategoryService.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { quickSearchByQuery } from '@vue-storefront/core/lib/search';
-import { SearchQuery } from 'storefront-query-builder'
-import config from 'config';
-import { DataResolver } from './types/DataResolver';
-import { Category } from 'core/modules/catalog-next/types/Category';
-
-const getCategories = async ({
- parentId = null,
- filters = {},
- level = null,
- onlyActive = true,
- onlyNotEmpty = false,
- size = 4000,
- start = 0,
- sort = 'position:asc',
- includeFields = config.entities.optimize ? config.entities.category.includeFields : null,
- excludeFields = config.entities.optimize ? config.entities.category.excludeFields : null
-}: DataResolver.CategorySearchOptions = {}): Promise => {
- let searchQuery = new SearchQuery()
- if (parentId) {
- searchQuery = searchQuery.applyFilter({ key: 'parent_id', value: { 'eq': parentId } })
- }
- if (level) {
- searchQuery = searchQuery.applyFilter({ key: 'level', value: { 'eq': level } })
- }
-
- for (var [key, value] of Object.entries(filters)) {
- if (value !== null) {
- if (Array.isArray(value)) {
- searchQuery = searchQuery.applyFilter({ key: key, value: { 'in': value } })
- } else if (typeof value === 'object') {
- searchQuery = searchQuery.applyFilter({ key: key, value: value })
- } else {
- searchQuery = searchQuery.applyFilter({ key: key, value: { 'eq': value } })
- }
- }
- }
-
- if (onlyActive === true) {
- searchQuery = searchQuery.applyFilter({ key: 'is_active', value: { 'eq': true } })
- }
-
- if (onlyNotEmpty === true) {
- searchQuery = searchQuery.applyFilter({ key: 'product_count', value: { 'gt': 0 } })
- }
- const response = await quickSearchByQuery({ entityType: 'category', query: searchQuery, sort: sort, size: size, start: start, includeFields: includeFields, excludeFields: excludeFields })
- return response.items as Category[]
-}
-
-export const CategoryService: DataResolver.CategoryService = {
- getCategories
-}
diff --git a/core/data-resolver/NewsletterService.ts b/core/data-resolver/NewsletterService.ts
deleted file mode 100644
index 7aaee8e32d..0000000000
--- a/core/data-resolver/NewsletterService.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import config from 'config';
-import { DataResolver } from './types/DataResolver';
-import { processURLAddress } from '@vue-storefront/core/helpers';
-import { TaskQueue } from '@vue-storefront/core/lib/sync'
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-
-const isSubscribed = (email: string): Promise =>
- TaskQueue.execute({
- url: processURLAddress(getApiEndpointUrl(config.newsletter, 'endpoint')) + '?email=' + encodeURIComponent(email),
- payload: {
- method: 'GET',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- silent: true
- }).then(({ result }) => result === 'subscribed')
-
-const subscribe = (email: string): Promise =>
- TaskQueue.execute({
- url: processURLAddress(getApiEndpointUrl(config.newsletter, 'endpoint')),
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify({ email })
- }
- }).then(({ code }) => code === 200)
-
-const unsubscribe = (email: string): Promise =>
- TaskQueue.execute({
- url: processURLAddress(getApiEndpointUrl(config.newsletter, 'endpoint')),
- payload: {
- method: 'DELETE',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify({ email })
- }
- }).then(({ code }) => code === 200)
-
-export const NewsletterService: DataResolver.NewsletterService = {
- isSubscribed,
- subscribe,
- unsubscribe
-}
diff --git a/core/data-resolver/OrderService.ts b/core/data-resolver/OrderService.ts
deleted file mode 100644
index 96054296ef..0000000000
--- a/core/data-resolver/OrderService.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import config from 'config';
-import { DataResolver } from './types/DataResolver';
-import { Order } from '@vue-storefront/core/modules/order/types/Order'
-import { TaskQueue } from '@vue-storefront/core/lib/sync'
-import Task from '@vue-storefront/core/lib/sync/types/Task'
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-
-const placeOrder = (order: Order): Promise =>
- TaskQueue.execute({ url: getApiEndpointUrl(config.orders, 'endpoint'), // sync the order
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify(order)
- }
- })
-
-export const OrderService: DataResolver.OrderService = {
- placeOrder
-}
diff --git a/core/data-resolver/ProductService.ts b/core/data-resolver/ProductService.ts
deleted file mode 100644
index 3dd1622d38..0000000000
--- a/core/data-resolver/ProductService.ts
+++ /dev/null
@@ -1,199 +0,0 @@
-import { getOptimizedFields } from '@vue-storefront/core/modules/catalog/helpers/search';
-import { canCache, storeProductToCache } from './../modules/catalog/helpers/search';
-import { doPlatformPricesSync } from '@vue-storefront/core/modules/catalog/helpers';
-import { isServer } from '@vue-storefront/core/helpers';
-import { quickSearchByQuery, isOnline } from '@vue-storefront/core/lib/search';
-import { SearchQuery } from 'storefront-query-builder'
-import config from 'config';
-import { DataResolver } from './types/DataResolver';
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-import { TaskQueue } from '@vue-storefront/core/lib/sync'
-import { entityKeyName } from '@vue-storefront/core/lib/store/entities'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import { Logger } from '@vue-storefront/core/lib/logger';
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-import { prepareProducts } from '@vue-storefront/core/modules/catalog/helpers/prepare';
-import { configureProducts } from '@vue-storefront/core/modules/catalog/helpers/configure';
-
-const getProducts = async ({
- query,
- start = 0,
- size = 50,
- sort = '',
- excludeFields = null,
- includeFields = null,
- configuration = null,
- options: {
- prefetchGroupProducts = !isServer,
- fallbackToDefaultWhenNoAvailable = true,
- setProductErrors = false,
- setConfigurableProductOptions = config.cart.setConfigurableProductOptions,
- filterUnavailableVariants = config.products.filterUnavailableVariants,
- assignProductConfiguration = false,
- separateSelectedVariant = false
- } = {}
-}: DataResolver.ProductSearchOptions): Promise => {
- const isCacheable = canCache({ includeFields, excludeFields })
- const { excluded, included } = getOptimizedFields({ excludeFields, includeFields })
- let {
- items: products = [],
- attributeMetadata = [],
- aggregations = [],
- total,
- perPage
- } = await quickSearchByQuery({
- query,
- start,
- size,
- entityType: 'product',
- sort,
- excludeFields: excluded,
- includeFields: included
- })
-
- products = prepareProducts(products)
-
- for (let product of products) { // we store each product separately in cache to have offline access to products/single method
- if (isCacheable) { // store cache only for full loads
- storeProductToCache(product, 'sku')
- }
- }
-
- const configuredProducts = await configureProducts({
- products,
- attributes_metadata: attributeMetadata,
- configuration,
- options: {
- prefetchGroupProducts,
- fallbackToDefaultWhenNoAvailable,
- setProductErrors,
- setConfigurableProductOptions,
- filterUnavailableVariants,
- assignProductConfiguration,
- separateSelectedVariant
- },
- excludeFields: excluded,
- includeFields: included
- })
-
- return {
- items: configuredProducts,
- perPage,
- start,
- total,
- aggregations,
- attributeMetadata
- }
-}
-
-const getProductRenderList = async ({
- skus,
- isUserGroupedTaxActive,
- userGroupId,
- token
-}): Promise => {
- const { i18n, storeId } = currentStoreView()
- let url = [
- `${getApiEndpointUrl(config.products, 'endpoint')}/render-list`,
- `?skus=${encodeURIComponent(skus.join(','))}`,
- `¤cyCode=${encodeURIComponent(i18n.currencyCode)}`,
- `&storeId=${encodeURIComponent(storeId)}`
- ].join('')
- if (isUserGroupedTaxActive) {
- url = `${url}&userGroupId=${userGroupId}`
- }
-
- if (token && !config.users.tokenInHeader) {
- url = `${url}&token=${token}`
- }
-
- try {
- const task = await TaskQueue.execute({ url, // sync the cart
- payload: {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- ...(token && config.users.tokenInHeader ? { authorization: `Bearer ${token}` } : {})
- },
- mode: 'cors'
- },
- callback_event: 'prices-after-sync'
- })
- return task.result as DataResolver.ProductsListResponse
- } catch (err) {
- console.error(err)
- return { items: [] }
- }
-}
-
-const getProduct = async (options: { [key: string]: string }, key: string): Promise => {
- let searchQuery = new SearchQuery()
- searchQuery = searchQuery.applyFilter({ key: key, value: { 'eq': options[key] } })
- const { items = [] } = await getProducts({
- query: searchQuery,
- size: 1,
- configuration: { sku: options.childSku },
- options: {
- prefetchGroupProducts: true,
- assignProductConfiguration: true
- }
- })
- return items[0] || null
-}
-
-const getProductFromCache = async (options: { [key: string]: string }, key: string): Promise => {
- try {
- const cacheKey = entityKeyName(key, options[key])
- const cache = StorageManager.get('elasticCache')
- const result = await cache.getItem(cacheKey)
- if (result !== null) {
- if (config.products.alwaysSyncPlatformPricesOver) {
- if (!config.products.waitForPlatformSync) {
- await doPlatformPricesSync([result])
- } else {
- doPlatformPricesSync([result])
- }
- }
- const { excluded, included } = getOptimizedFields({ excludeFields: null, includeFields: null })
- const [product] = await configureProducts({
- products: [result],
- attributes_metadata: [],
- configuration: { [key]: options.childSku || options.sku || options[key] },
- options: {
- prefetchGroupProducts: true,
- setConfigurableProductOptions: config.cart.setConfigurableProductOptions,
- filterUnavailableVariants: config.products.filterUnavailableVariants,
- assignProductConfiguration: true
- },
- excludeFields: excluded,
- includeFields: included
- })
- return product
- } else {
- return getProduct(options, key)
- }
- } catch (err) {
- // report errors
- if (err) {
- Logger.error(err, 'product')()
- }
- return getProduct(options, key)
- }
-}
-
-const getProductByKey = async ({ options, key, skipCache }: DataResolver.ProductByKeySearchOptions): Promise => {
- if (!isOnline()) {
- return getProductFromCache(options, key)
- }
- const result = skipCache
- ? await getProduct(options, key)
- : await getProductFromCache(options, key)
- return result
-}
-
-export const ProductService: DataResolver.ProductService = {
- getProducts,
- getProductRenderList,
- getProductByKey
-}
diff --git a/core/data-resolver/ReviewsService.ts b/core/data-resolver/ReviewsService.ts
deleted file mode 100644
index da3fa3e88e..0000000000
--- a/core/data-resolver/ReviewsService.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { DataResolver } from './types/DataResolver';
-import { TaskQueue } from '@vue-storefront/core/lib/sync'
-import { processLocalizedURLAddress } from '@vue-storefront/core/helpers'
-import config from 'config'
-import Review from 'core/modules/review/types/Review';
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-
-const createReview = (review: Review): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.reviews, 'create_endpoint')),
- payload: {
- method: 'POST',
- mode: 'cors',
- headers: {
- 'Accept': 'application/json, text/plain, */*',
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({ review })
- }
- }).then(({ code }) => code === 200)
-
-export const ReviewsService: DataResolver.ReviewsService = {
- createReview
-}
diff --git a/core/data-resolver/StockService.ts b/core/data-resolver/StockService.ts
deleted file mode 100644
index 7c89bc5961..0000000000
--- a/core/data-resolver/StockService.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import config from 'config';
-import { DataResolver } from './types/DataResolver';
-import { TaskQueue } from '@vue-storefront/core/lib/sync';
-import Task from '@vue-storefront/core/lib/sync/types/Task';
-import { processURLAddress } from '@vue-storefront/core/helpers';
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-
-const queueCheck = (sku: string, actionName: string): Promise =>
- TaskQueue.queue({
- url: processURLAddress(`${getApiEndpointUrl(config.stock, 'endpoint')}/check?sku=${encodeURIComponent(sku)}`),
- payload: {
- method: 'GET',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- is_result_cacheable: true,
- product_sku: sku,
- callback_event: `store:${actionName}`
- })
-
-const check = (sku: string): Promise =>
- TaskQueue.execute({
- url: processURLAddress(`${getApiEndpointUrl(config.stock, 'endpoint')}/check?sku=${encodeURIComponent(sku)}`),
- payload: {
- method: 'GET',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- is_result_cacheable: true,
- product_sku: sku
- })
-
-const list = (skuList: string[]): Promise =>
- TaskQueue.execute({
- url: processURLAddress(
- `${getApiEndpointUrl(config.stock, 'endpoint')}/list?skus=${encodeURIComponent(
- skuList.join(',')
- )}`
- ),
- payload: {
- method: 'GET',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors'
- },
- skus: skuList
- })
-
-export const StockService: DataResolver.StockService = {
- check,
- list,
- queueCheck
-}
diff --git a/core/data-resolver/UserService.ts b/core/data-resolver/UserService.ts
deleted file mode 100644
index 97ad0aa499..0000000000
--- a/core/data-resolver/UserService.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-import { DataResolver } from './types/DataResolver';
-import { UserProfile } from '@vue-storefront/core/modules/user/types/UserProfile'
-import { TaskQueue } from '@vue-storefront/core/lib/sync'
-import Task from '@vue-storefront/core/lib/sync/types/Task'
-import { processLocalizedURLAddress } from '@vue-storefront/core/helpers'
-import config from 'config'
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-
-const headers = {
- 'Accept': 'application/json, text/plain, */*',
- 'Content-Type': 'application/json'
-}
-
-const resetPassword = async (email: string): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.users, 'resetPassword_endpoint')),
- payload: {
- method: 'POST',
- mode: 'cors',
- headers,
- body: JSON.stringify({ email })
- }
- })
-
-const createPassword = async (email: string, newPassword: string, resetToken: string): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(config.users.createPassword_endpoint),
- payload: {
- method: 'POST',
- mode: 'cors',
- headers,
- body: JSON.stringify({ email, newPassword, resetToken })
- }
- })
-
-const login = async (username: string, password: string): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.users, 'login_endpoint')),
- payload: {
- method: 'POST',
- mode: 'cors',
- headers,
- body: JSON.stringify({ username, password })
- }
- })
-
-const register = async (customer: DataResolver.Customer, password: string): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.users, 'create_endpoint')),
- payload: {
- method: 'POST',
- headers,
- body: JSON.stringify({ customer, password })
- }
- })
-
-const updateProfile = async (userProfile: UserProfile, actionName: string): Promise =>
- TaskQueue.queue({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.users, 'me_endpoint')),
- payload: {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify(userProfile)
- },
- callback_event: `store:${actionName}`
- })
-
-const getProfile = async () =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.users, 'me_endpoint')),
- payload: {
- method: 'GET',
- mode: 'cors',
- headers
- }
- })
-
-const getOrdersHistory = async (pageSize = 20, currentPage = 1): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(
- getApiEndpointUrl(config.users, 'history_endpoint').replace('{{pageSize}}', pageSize + '').replace('{{currentPage}}', currentPage + '')
- ),
- payload: {
- method: 'GET',
- mode: 'cors',
- headers
- }
- })
-
-const changePassword = async (passwordData: DataResolver.PasswordData): Promise =>
- TaskQueue.execute({
- url: processLocalizedURLAddress(getApiEndpointUrl(config.users, 'changePassword_endpoint')),
- payload: {
- method: 'POST',
- mode: 'cors',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(passwordData)
- }
- })
-
-const refreshToken = async (refreshToken: string): Promise =>
- fetch(processLocalizedURLAddress(getApiEndpointUrl(config.users, 'refresh_endpoint')), {
- method: 'POST',
- mode: 'cors',
- headers,
- body: JSON.stringify({ refreshToken })
- }).then(resp => resp.json())
- .then(resp => resp.result)
-
-export const UserService: DataResolver.UserService = {
- resetPassword,
- createPassword,
- login,
- register,
- updateProfile,
- getProfile,
- getOrdersHistory,
- changePassword,
- refreshToken
-}
diff --git a/core/data-resolver/index.ts b/core/data-resolver/index.ts
deleted file mode 100644
index 35504d297e..0000000000
--- a/core/data-resolver/index.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { CategoryService } from './CategoryService'
-import { UserService } from './UserService'
-import { CartService } from './CartService'
-import { OrderService } from './OrderService'
-import { StockService } from './StockService'
-import { ReviewsService } from './ReviewsService'
-import { NewsletterService } from './NewsletterService'
-
-export {
- CategoryService,
- UserService,
- CartService,
- OrderService,
- StockService,
- ReviewsService,
- NewsletterService
-}
diff --git a/core/data-resolver/types/DataResolver.d.ts b/core/data-resolver/types/DataResolver.d.ts
deleted file mode 100644
index 88631409dc..0000000000
--- a/core/data-resolver/types/DataResolver.d.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-import { AttributesMetadata } from '@vue-storefront/core/modules/catalog/types/Attribute';
-import { Category } from '@vue-storefront/core/modules/catalog-next/types/Category';
-import { UserProfile } from '@vue-storefront/core/modules/user/types/UserProfile'
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import { Order } from '@vue-storefront/core/modules/order/types/Order'
-import Task from '@vue-storefront/core/lib/sync/types/Task'
-import Review from '@vue-storefront/core/modules/review/types/Review';
-import { SearchQuery } from 'storefront-query-builder';
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-declare namespace DataResolver {
-
- interface CategorySearchOptions {
- parentId?: number | string,
- filters?: { [key: string]: string[] | string },
- level?: number,
- onlyActive?: boolean,
- onlyNotEmpty?: boolean,
- size?: number,
- start?: number,
- sort?: string,
- includeFields?: string[],
- excludeFields?: string[],
- reloadAll?: boolean
- }
-
- interface ProductSearchOptions {
- query: SearchQuery,
- size?: number,
- start?: number,
- sort?: string,
- includeFields?: string[],
- excludeFields?: string[],
- configuration?: { [key: string]: string[] | string },
- options?: {
- prefetchGroupProducts?: boolean,
- fallbackToDefaultWhenNoAvailable?: boolean,
- setProductErrors?: boolean,
- setConfigurableProductOptions?: boolean,
- filterUnavailableVariants?: boolean,
- assignProductConfiguration?: boolean,
- separateSelectedVariant?: boolean
- }
- }
-
- interface ProductRenderListSearchOptions {
- skus: string[],
- isUserGroupedTaxActive?: boolean,
- userGroupId?: string,
- token?: string
- }
-
- interface ProductByKeySearchOptions {
- options: { [key: string]: string },
- key?: string,
- skipCache?: boolean
- }
-
- interface Customer {
- email: string,
- firstname: string,
- lastname: string,
- addresses: string
- }
-
- interface PasswordData {
- currentPassword: string,
- newPassword: string
- }
-
- interface ProductsListResponse {
- items: Product[],
- perPage?: number,
- start?: number,
- total?: number,
- aggregations?: any[],
- attributeMetadata?: AttributesMetadata[]
- }
-
- interface ProductService {
- getProducts: (searchRequest: ProductSearchOptions) => Promise,
- getProductRenderList: (searchRequest: ProductRenderListSearchOptions) => Promise,
- getProductByKey: (searchRequest: ProductByKeySearchOptions) => Promise
- }
-
- interface CategoryService {
- getCategories: (searchRequest?: CategorySearchOptions) => Promise
- }
-
- interface UserService {
- resetPassword: (email: string) => Promise,
- createPassword: (email: string, newPassword: string, resetToken: string) => Promise,
- login: (username: string, password: string) => Promise,
- register: (customer: Customer, pssword: string) => Promise,
- updateProfile: (userProfile: UserProfile, actionName: string) => Promise,
- getProfile: () => Promise,
- getOrdersHistory: (pageSize?: number, currentPage?: number) => Promise,
- changePassword: (passwordData: PasswordData) => Promise,
- refreshToken: (refreshToken: string) => Promise
- }
-
- interface CartService {
- setShippingInfo: (methodsData: any /*: ShippingMethodsData */) => Promise,
- getTotals: () => Promise,
- getCartToken: (guestCart: boolean, forceClientState: boolean) => Promise,
- updateItem: (cartServerToken: string, cartItem: CartItem) => Promise,
- deleteItem: (cartServerToken: string, cartItem: CartItem) => Promise,
- getPaymentMethods: () => Promise,
- getShippingMethods: (address: any /*: ShippingMethodsData */) => Promise,
- getItems: () => Promise,
- applyCoupon: (couponCode: string) => Promise,
- removeCoupon: () => Promise
- }
-
- interface OrderService {
- placeOrder: (order: Order) => Promise
- }
-
- interface StockService {
- check: (sku: string) => Promise,
- queueCheck: (sku: string, actionName: string) => Promise,
- list: (skuList: string[]) => Promise
- }
-
- interface ReviewsService {
- createReview: (review: Review) => Promise
- }
-
- interface NewsletterService {
- isSubscribed: (email: string) => Promise,
- subscribe: (email: string) => Promise,
- unsubscribe: (email: string) => Promise
- }
-}
diff --git a/core/filters/capitalize.js b/core/filters/capitalize.js
deleted file mode 100644
index 072a7ef840..0000000000
--- a/core/filters/capitalize.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Capitalize first letter of provided text
- * @param {String} text
- */
-export function capitalize (text) {
- if (!text) return ''
- text = text.toString()
- return text.charAt(0).toUpperCase() + text.slice(1)
-}
diff --git a/core/filters/date.js b/core/filters/date.js
deleted file mode 100644
index 1bcd01b9c2..0000000000
--- a/core/filters/date.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-import dayjs from 'dayjs'
-import dayjsLocalizedFormat from 'dayjs/plugin/localizedFormat'
-import { once } from '../helpers';
-
-once('__VUE_EXTEND_DAYJS_LOCALIZED_FORMAT__', () => {
- dayjs.extend(dayjsLocalizedFormat)
-})
-
-/**
- * Converts date to format provided as an argument or defined in config file (if argument not provided)
- * @param {String} date
- * @param {String} format
- */
-export function date (date, format, storeView) {
- const _storeView = storeView || currentStoreView()
- const displayFormat = format || _storeView.i18n.dateFormat
- let storeLocale = _storeView.i18n.defaultLocale.toLocaleLowerCase()
- const separatorIndex = storeLocale.indexOf('-')
- const languageCode = (separatorIndex > -1) ? storeLocale.substr(0, separatorIndex) : storeLocale
-
- const isStoreLocale = dayjs().locale(storeLocale).locale()
- const isLanguageLocale = dayjs().locale(languageCode).locale()
- const locale = isStoreLocale || isLanguageLocale
-
- if (locale) return dayjs(date).locale(languageCode).format(displayFormat)
- return dayjs(date).format(displayFormat)
-}
diff --git a/core/filters/html-decode.js b/core/filters/html-decode.js
deleted file mode 100644
index c40b677072..0000000000
--- a/core/filters/html-decode.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import decode from 'lean-he/decode'
-
-/**
- * Decodes any named and numerical character references in text
- * @param {String} value
- */
-export function htmlDecode (value) {
- return value ? decode(value) : ''
-}
diff --git a/core/filters/index.js b/core/filters/index.js
deleted file mode 100644
index f649e07fa5..0000000000
--- a/core/filters/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { price } from './price'
-import { htmlDecode } from './html-decode'
-import { date } from './date'
-import { capitalize } from './capitalize'
-import { formatProductMessages } from './product-messages'
-import { stripHTML } from './strip-html'
-
-export {
- price,
- htmlDecode,
- date,
- capitalize,
- formatProductMessages,
- stripHTML
-}
diff --git a/core/filters/price.js b/core/filters/price.js
deleted file mode 100644
index c7e5558bba..0000000000
--- a/core/filters/price.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-
-const applyCurrencySign = (formattedPrice, { currencySign, priceFormat }) => {
- return priceFormat.replace('{sign}', currencySign).replace('{amount}', formattedPrice)
-};
-
-const getLocaleSeparators = (defaultLocale) => {
- return {
- decimal: (0.01).toLocaleString(defaultLocale).replace(/[0-9]/g, ''),
- group: (1000).toLocaleString(defaultLocale).replace(/[0-9]/g, '')
- }
-};
-
-const replaceSeparators = (formattedPrice, currencySeparators, separators) => {
- if (currencySeparators.decimal) formattedPrice = formattedPrice.replace(separators.decimal, currencySeparators.decimal);
- if (currencySeparators.group) formattedPrice = formattedPrice.replace(separators.group, currencySeparators.group);
- return formattedPrice;
-};
-
-/**
- * Converts number to price string
- * @param {Number} value
- */
-export function price (value, storeView) {
- if (isNaN(value)) {
- return value
- }
- const _storeView = storeView || currentStoreView();
- if (!_storeView.i18n) {
- return Number(value).toFixed(2)
- }
-
- const { defaultLocale, currencySign, currencyDecimal, currencyGroup, fractionDigits, priceFormat } = _storeView.i18n;
-
- const options = { minimumFractionDigits: fractionDigits, maximumFractionDigits: fractionDigits };
-
- let localePrice = Math.abs(value).toLocaleString(defaultLocale, options);
-
- if (currencyDecimal !== '' || currencyGroup !== '') {
- localePrice = replaceSeparators(localePrice, { decimal: currencyDecimal, group: currencyGroup }, getLocaleSeparators(defaultLocale));
- }
-
- const valueWithSign = applyCurrencySign(localePrice, { currencySign, priceFormat });
-
- return value >= 0 ? valueWithSign : '-' + valueWithSign;
-}
diff --git a/core/filters/product-messages.ts b/core/filters/product-messages.ts
deleted file mode 100644
index 2442a66f4b..0000000000
--- a/core/filters/product-messages.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Format message string for product validation messages object
- */
-export function formatProductMessages (messages: Record): string {
- const msgs = []
- for (const infoKey in messages) {
- if (messages[infoKey]) {
- msgs.push(messages[infoKey])
- }
- }
- return msgs.join(', ')
-}
diff --git a/core/filters/strip-html.js b/core/filters/strip-html.js
deleted file mode 100644
index 2f6c5f6d29..0000000000
--- a/core/filters/strip-html.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Strip HTML tags
- * @param {String} html
- */
-export function stripHTML (html) {
- if (!html) return ''
- return html.replace(/<[^>]+>/g, '').trim()
-}
diff --git a/core/helpers/getApiEndpointUrl.ts b/core/helpers/getApiEndpointUrl.ts
deleted file mode 100644
index 86b5a4f0ca..0000000000
--- a/core/helpers/getApiEndpointUrl.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { isServer } from '@vue-storefront/core/helpers';
-
-// object - parent object in the config, e.g. config.cart
-// field - field inside the object, e.g. create_endpoint
-
-// returns - object.[field]_ssr if it exists and it is a server,
-// object.field otherwise
-
-export default (object: Record, field: string): string => {
- return isServer && object[`${field}_ssr`] ? object[`${field}_ssr`] : object[field]
-}
diff --git a/core/helpers/index.ts b/core/helpers/index.ts
deleted file mode 100644
index 7cd2e1eded..0000000000
--- a/core/helpers/index.ts
+++ /dev/null
@@ -1,358 +0,0 @@
-import { SearchQuery } from 'storefront-query-builder'
-import { remove as removeAccents } from 'remove-accents'
-import { formatCategoryLink } from '@vue-storefront/core/modules/url/helpers'
-import Vue from 'vue'
-import config from 'config'
-import { sha3_224 } from 'js-sha3'
-import store from '@vue-storefront/core/store'
-import { adjustMultistoreApiUrl } from '@vue-storefront/core/lib/multistore'
-import { coreHooksExecutors } from '@vue-storefront/core/hooks';
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-import omit from 'lodash-es/omit'
-
-export const processURLAddress = (url: string = '') => {
- if (url.startsWith('/')) return `${getApiEndpointUrl(config.api, 'url')}${url}`
- return url
-}
-
-export const processLocalizedURLAddress = (url: string = '') => {
- if (config.storeViews.multistore) {
- return processURLAddress(adjustMultistoreApiUrl(url))
- }
-
- return processURLAddress(url)
-}
-
-/**
- * Create slugify -> "create-slugify" permalink of text
- * @param {String} text
- */
-export function slugify (text) {
- // remove regional characters
- text = removeAccents(text)
-
- return text
- .toString()
- .toLowerCase()
- .replace(/\s+/g, '-') // Replace spaces with -
- .replace(/&/g, '-and-') // Replace & with 'and'
- .replace(/[^\w-]+/g, '') // Remove all non-word chars
- .replace(/--+/g, '-') // Replace multiple - with single -
-}
-
-/**
- * @param {string} relativeUrl
- * @param {number} width
- * @param {number} height
- * @param {string} pathType
- * @returns {string}
- */
-export function getThumbnailPath (relativeUrl: string, width: number = 0, height: number = 0, pathType: string = 'product'): string {
- if (config.images.useSpecificImagePaths) {
- const path = config.images.paths[pathType] !== undefined ? config.images.paths[pathType] : ''
- relativeUrl = path + relativeUrl
- }
-
- if (config.images.useExactUrlsNoProxy) {
- return coreHooksExecutors.afterProductThumbnailPathGenerate({ path: relativeUrl, sizeX: width, sizeY: height, pathType }).path // this is exact url mode
- } else {
- let resultUrl
- if (relativeUrl && (relativeUrl.indexOf('://') > 0 || relativeUrl.indexOf('?') > 0 || relativeUrl.indexOf('&') > 0)) relativeUrl = encodeURIComponent(relativeUrl)
- // proxyUrl is not a url base path but contains {{url}} parameters and so on to use the relativeUrl as a template value and then do the image proxy opertions
- let baseUrl = processURLAddress(config.images.proxyUrl ? config.images.proxyUrl : config.images.baseUrl)
- if (baseUrl.indexOf('{{') >= 0) {
- baseUrl = baseUrl.replace('{{url}}', relativeUrl)
- baseUrl = baseUrl.replace('{{width}}', width.toString())
- baseUrl = baseUrl.replace('{{height}}', height.toString())
- resultUrl = baseUrl
- } else {
- resultUrl = `${baseUrl}${width.toString()}/${height.toString()}/resize${relativeUrl}`
- }
- const path = relativeUrl && relativeUrl.indexOf('no_selection') < 0 ? resultUrl : config.images.productPlaceholder || ''
-
- return coreHooksExecutors.afterProductThumbnailPathGenerate({ path, sizeX: width, sizeY: height, pathType }).path
- }
-}
-
-/**
- * Re-format category path to be suitable for breadcrumb
- * @param {Array} categoryPath
- */
-export function formatBreadCrumbRoutes (categoryPath) {
- const breadCrumbRoutesArray = []
- for (let category of categoryPath) {
- breadCrumbRoutesArray.push({
- name: category.name,
- route_link: formatCategoryLink(category)
- })
- }
- return breadCrumbRoutesArray
-}
-
-/**
- * Return configurable product thumbnail depending on the configurable_children
- * @param {object} product
- * @param {bool} ignoreConfig
- */
-export function productThumbnailPath (product, ignoreConfig = false) {
- let thumbnail = product.image
- if ((!thumbnail && product.type_id && product.type_id === 'configurable') && product.hasOwnProperty('configurable_children') &&
- product.configurable_children.length && (ignoreConfig || !product.is_configured) &&
- ('image' in product.configurable_children[0])
- ) {
- thumbnail = product.configurable_children[0].image
- if (!thumbnail || thumbnail === 'no_selection') {
- const childWithImg = product.configurable_children.find(f => f.image && f.image !== 'no_selection')
- if (childWithImg) {
- thumbnail = childWithImg.image
- } else {
- thumbnail = product.image
- }
- }
- }
- return thumbnail
-}
-
-export function baseFilterProductsQuery (parentCategory, filters = []) { // TODO add aggregation of color_options and size_options fields
- let searchProductQuery = new SearchQuery()
- searchProductQuery = searchProductQuery
- .applyFilter({ key: 'visibility', value: { 'in': [2, 3, 4] } })
- .applyFilter({ key: 'status', value: { 'in': [0, 1] } }) /* 2 = disabled, 4 = out of stock */
-
- if (config.products.listOutOfStockProducts === false) {
- searchProductQuery = searchProductQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } })
- }
- // Add available catalog filters
- for (let attrToFilter of filters) {
- searchProductQuery = searchProductQuery.addAvailableFilter({ field: attrToFilter, scope: 'catalog' })
- }
-
- let childCats = [parentCategory.id]
- if (parentCategory.children_data) {
- let recurCatFinderBuilder = (category) => {
- if (!category) {
- return
- }
-
- if (!category.children_data) {
- return
- }
-
- for (let sc of category.children_data) {
- if (sc && sc.id) {
- childCats.push(sc.id)
- }
- recurCatFinderBuilder(sc)
- }
- }
- recurCatFinderBuilder(parentCategory)
- }
- searchProductQuery = searchProductQuery.applyFilter({ key: 'category_ids', value: { 'in': childCats } })
- return searchProductQuery
-}
-
-export function buildFilterProductsQuery (currentCategory, chosenFilters = {}, defaultFilters = null) {
- let filterQr = baseFilterProductsQuery(currentCategory, defaultFilters == null ? config.products.defaultFilters : defaultFilters)
-
- // add choosedn filters
- for (let code of Object.keys(chosenFilters)) {
- const filter = chosenFilters[code]
- const attributeCode = Array.isArray(filter) ? filter[0].attribute_code : filter.attribute_code
-
- if (Array.isArray(filter) && attributeCode !== 'price') {
- const values = filter.map(filter => filter.id)
- filterQr = filterQr.applyFilter({ key: attributeCode, value: { 'in': values }, scope: 'catalog' })
- } else if (attributeCode !== 'price') {
- filterQr = filterQr.applyFilter({ key: attributeCode, value: { 'eq': filter.id }, scope: 'catalog' })
- } else { // multi should be possible filter here?
- const rangeqr = {}
- const filterValues = Array.isArray(filter) ? filter : [filter]
- filterValues.forEach(singleFilter => {
- if (singleFilter.from) rangeqr['gte'] = singleFilter.from
- if (singleFilter.to) rangeqr['lte'] = singleFilter.to
- })
- filterQr = filterQr.applyFilter({ key: attributeCode, value: rangeqr, scope: 'catalog' })
- }
- }
-
- return filterQr
-}
-
-export function once (key, fn) {
- const { process = {} } = global
- const processKey = key + '__ONCE__'
- if (!process.hasOwnProperty(processKey)) {
- // Logger.debug(`Once ${key}`, 'helper')()
- process[processKey] = true
- fn()
- }
-}
-
-export const isServer: boolean = typeof window === 'undefined'
-
-// Online/Offline helper
-export const onlineHelper = Vue.observable({
- isOnline: isServer || navigator.onLine
-})
-
-export const routerHelper = Vue.observable({
- popStateDetected: false
-})
-
-!isServer && window.addEventListener('online', () => { onlineHelper.isOnline = true })
-!isServer && window.addEventListener('offline', () => { onlineHelper.isOnline = false })
-!isServer && window.addEventListener('popstate', () => { routerHelper.popStateDetected = true })
-if (!isServer && 'scrollRestoration' in history) {
- history.scrollRestoration = 'manual'
-}
-
-/*
- * serial executes Promises sequentially.
- * @param {funcs} An array of funcs that return promises.
- * @example
- * const urls = ['/url1', '/url2', '/url3']
- * serial(urls.map(url => () => $.ajax(url)))
- * .then(Logger.log.bind(Logger))()
- */
-export const serial = async promises => {
- const results = []
- for (const item of promises) {
- const result = await item;
- results.push(result)
- }
- return results
-}
-
-// helper to calculate the hash of the shopping cart
-export const calcItemsHmac = (items = [], token) => {
- return sha3_224(JSON.stringify({
- // we need to omit those properties because they are loaded async and added to product data
- // and they are not needed to compare products
- items: items.map(item => omit(item, ['stock', 'totals'])),
- token: token
- }))
-}
-
-export function extendStore (moduleName: string | string[], module: any) {
- const merge = function (object: any = {}, source: any) {
- for (let key in source) {
- if (Array.isArray(source[key])) {
- object[key] = merge([], source[key])
- } else if (source[key] === null && !object[key]) {
- object[key] = null
- } else if (typeof source[key] === 'object' && Object.keys(source[key]).length > 0) {
- object[key] = merge(object[key], source[key])
- } else if (typeof source[key] === 'object' && object === null) {
- object = {}
- object[key] = source[key]
- } else {
- object[key] = source[key]
- }
- }
- return object
- };
- moduleName = Array.isArray(moduleName) ? moduleName : [moduleName]
- const originalModule: any = moduleName.reduce(
- (state: any, moduleName: string) => state._children[moduleName],
- (store as any)._modules.root
- )
- const rawModule: any = merge({}, originalModule._rawModule)
- const extendedModule: any = merge(rawModule, module)
-
- store.unregisterModule(moduleName)
- store.registerModule(moduleName, extendedModule)
-}
-
-export function reviewJsonLd (reviews, { name, category, mpn, url_path, price, stock, is_in_stock, sku, image, description }, priceCurrency) {
- return reviews.map(({ title, detail, nickname, created_at }) => (
- {
- '@context': 'http://schema.org/',
- '@type': 'Review',
- reviewAspect: title,
- reviewBody: detail,
- datePublished: created_at,
- author: nickname,
- itemReviewed: {
- '@type': 'Product',
- name,
- sku,
- image,
- description,
- offers: {
- '@type': 'Offer',
- category: category
- ? category
- .map(({ name }) => name || null)
- .filter(name => name !== null)
- : null,
- mpn,
- url: url_path,
- priceCurrency,
- price,
- itemCondition: 'https://schema.org/NewCondition',
- availability: stock && is_in_stock ? 'InStock' : 'OutOfStock'
- }
- }
- }
- )
- )
-}
-
-function getMaterials (material, customAttributes) {
- const materialsArr = []
- if (customAttributes && customAttributes.length && customAttributes.length > 0 && material && material.length && material.length > 0) {
- const materialOptions = customAttributes.find(({ attribute_code }) => attribute_code === 'material').options
- if (Array.isArray(material)) {
- for (let key in materialOptions) {
- material.forEach(el => {
- if (String(el) === materialOptions[key].value) {
- materialsArr.push(materialOptions[key].label)
- }
- })
- }
- } else {
- for (let key in materialOptions) {
- if (material === materialOptions[key].value) {
- materialsArr.push(materialOptions[key].label)
- }
- }
- }
- }
- return materialsArr
-}
-
-export function productJsonLd ({ category, image, name, id, sku, mpn, description, price, url_path, stock, is_in_stock, material }, color, priceCurrency, customAttributes) {
- return {
- '@context': 'http://schema.org',
- '@type': 'Product',
- category: category
- ? category
- .map(({ name }) => name || null)
- .filter(name => name !== null)
- : null,
- color,
- description,
- image,
- itemCondition: 'http://schema.org/NewCondition',
- material: getMaterials(material, customAttributes),
- name,
- productID: id,
- sku,
- mpn,
- offers: {
- '@type': 'Offer',
- category: category
- ? category
- .map(({ name }) => name || null)
- .filter(name => name !== null)
- : null,
- mpn,
- url: url_path,
- priceCurrency,
- price,
- itemCondition: 'https://schema.org/NewCondition',
- availability: stock && is_in_stock ? 'InStock' : 'OutOfStock',
- sku
- }
- }
-}
diff --git a/core/helpers/initialStateFactory.ts b/core/helpers/initialStateFactory.ts
deleted file mode 100644
index b1e2884028..0000000000
--- a/core/helpers/initialStateFactory.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import cloneDeep from 'lodash-es/cloneDeep'
-import pick from 'lodash-es/pick'
-
-const initialStateFactory = (defaultState) => {
- // storing default values for the fields that will be set in createApp
- const defaultFields = pick(defaultState, ['version', 'config', '__DEMO_MODE__', 'storeView'])
-
- const createInitialState = (currentState) => ({
- ...cloneDeep(currentState),
- ...defaultFields,
- storeView: { storeCode: currentState.storeView.storeCode }
- })
-
- return { createInitialState }
-}
-
-export default initialStateFactory
diff --git a/core/helpers/internal.ts b/core/helpers/internal.ts
deleted file mode 100644
index 71eb8ab624..0000000000
--- a/core/helpers/internal.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { isServer } from '@vue-storefront/core/helpers'
-
-/**
- * ValidationError to be used with multiple validation errors return from Ajv or other validators
-*/
-export class HttpError {
- private message: string
- private code: string | number
- private name: string
-
- public constructor (message, code) {
- this.message = message
- this.code = code
- this.name = 'ValidationError'
- }
- public toString () {
- return 'HttpError' + this.code + ': ' + this.message
- }
-}
-
-/**
- * @param {string} level available options: 'no-console', 'only-errors', 'all'
- */
-export function takeOverConsole (level = 'no-console') {
- const console = !isServer ? window.console : global.console
- if (!console) return
-
- function intercept (method) {
- const original = console[method]
- console[method] = function () {
- let filterMethods = []
-
- if (level === 'no-console') {
- filterMethods = ['warn', 'debug', 'log', 'error']
- }
- if (level === 'only-errors') {
- filterMethods = ['warn', 'debug', 'log']
- }
-
- if (filterMethods.indexOf(method) >= 0) {
- return
- }
- // do sneaky stuff
- if (original.apply) {
- // Do this for normal browsers
- original.apply(console, arguments)
- } else {
- // Do this for IE
- const message = Array.prototype.slice.apply(arguments).join(' ')
- original(message)
- }
- }
- }
- const methods = ['log', 'warn', 'error', 'debug']
- for (let i = 0; i < methods.length; i++) {
- intercept(methods[i])
- }
-}
diff --git a/core/helpers/router.ts b/core/helpers/router.ts
deleted file mode 100644
index 331beb48cf..0000000000
--- a/core/helpers/router.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import rootStore from '@vue-storefront/core/store';
-import VueRouter, { RouteConfig } from 'vue-router'
-import { RouterManager } from '@vue-storefront/core/lib/router-manager'
-import { ErrorHandler, RawLocation, Route } from 'vue-router/types/router'
-import { once } from '@vue-storefront/core/helpers'
-
-once('__VUE_EXTEND_PUSH_RR__', () => {
- const originalPush = VueRouter.prototype.push
- VueRouter.prototype.push = function push (location: RawLocation, onComplete: Function = () => {}, onAbort?: ErrorHandler): Promise {
- if (onComplete || onAbort) return originalPush.call(this, location, onComplete, onAbort)
- return originalPush.call(this, location).catch(err => err)
- }
-})
-
-export const createRouter = (): VueRouter => {
- return new VueRouter({
- mode: 'history',
- base: __dirname,
- scrollBehavior: (to, from) => {
- if (to.hash) {
- return {
- selector: to.hash
- }
- }
- if (rootStore.getters['url/isBackRoute']) {
- const { scrollPosition = { x: 0, y: 0 } } = rootStore.getters['url/getCurrentRoute']
- return scrollPosition
- } else if (to.path !== from.path) { // do not change scroll position when navigating on the same page (ex. change filters)
- return { x: 0, y: 0 }
- }
- }
- })
-}
-
-export const createRouterProxy = (router: VueRouter): VueRouter => {
- const ProxyConstructor = Proxy || require('proxy-polyfill/src/proxy')
-
- return new ProxyConstructor(router, {
- get (target, propKey) {
- const origMethod = target[propKey]
-
- if (propKey === 'addRoutes') {
- return function (routes: RouteConfig[], ...args): void {
- return RouterManager.addRoutes(routes, ...args)
- }
- }
-
- return origMethod
- }
- })
-}
diff --git a/core/helpers/test/unit/getThumbnailPath.spec.ts b/core/helpers/test/unit/getThumbnailPath.spec.ts
deleted file mode 100644
index dc85506d96..0000000000
--- a/core/helpers/test/unit/getThumbnailPath.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { slugify } from '@vue-storefront/core/helpers'
-import config from 'config'
-
-jest.clearAllMocks()
-jest.mock('config', () => ({}))
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {}
-}))
-jest.mock('@vue-storefront/core/store', () => ({}))
-jest.mock('@vue-storefront/core/modules/url/helpers', () => ({}))
-jest.mock('@vue-storefront/core/lib/multistore', () => ({}))
-
-describe('slugify', () => {
- it('Check if all strings are replaced to the right chars and that text is lowercase in the return', () => {
- expect(slugify('testing')).toBe('testing')
- expect(slugify('testing--')).toBe('testing-')
- expect(slugify('TESTING--&')).toBe('testing-and-')
- expect(slugify('TESTING--& ')).toBe('testing-and-')
- expect(slugify('TES TING--& ')).toBe('tes-ting-and-')
- })
-
- it('Check that an error is thrown when the parameter is not an string', () => {
- expect(() => slugify(12)).toThrow('string.replace is not a function')
- })
-})
diff --git a/core/helpers/test/unit/processURLAddress.spec.ts b/core/helpers/test/unit/processURLAddress.spec.ts
deleted file mode 100644
index d44e041261..0000000000
--- a/core/helpers/test/unit/processURLAddress.spec.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { processURLAddress } from '@vue-storefront/core/helpers'
-import config from 'config'
-
-jest.clearAllMocks()
-jest.mock('config', () => ({}))
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {}
-}))
-jest.mock('@vue-storefront/core/store', () => ({}))
-jest.mock('@vue-storefront/core/modules/url/helpers', () => ({}))
-jest.mock('@vue-storefront/core/lib/multistore', () => ({}))
-
-describe('processURLAddress', () => {
- it('Check that the url that comes back has the right value', () => {
- config.api = {
- url: 'api'
- }
- expect(processURLAddress('/testing')).toBe('api/testing')
- expect(processURLAddress('testing')).toBe('testing')
- })
-})
diff --git a/core/helpers/test/unit/slugify.spec.ts b/core/helpers/test/unit/slugify.spec.ts
deleted file mode 100644
index b9bdb582f4..0000000000
--- a/core/helpers/test/unit/slugify.spec.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { getThumbnailPath } from '@vue-storefront/core/helpers'
-import config from 'config'
-
-jest.clearAllMocks()
-jest.mock('config', () => ({}))
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {}
-}))
-jest.mock('@vue-storefront/core/store', () => ({}))
-jest.mock('@vue-storefront/core/modules/url/helpers', () => ({}))
-jest.mock('@vue-storefront/core/lib/multistore', () => ({}))
-
-describe('getThumbnailPath', () => {
- it('Get right value when useExactUrlsNoProxy is set', () => {
- config.images = {
- useExactUrlsNoProxy: true
- }
- expect(getThumbnailPath('testing')).toBe('testing')
- })
-
- it('Get right value when productPlaceholder is set', () => {
- config.images = {
- productPlaceholder: 'productPlaceholder'
- }
- expect(getThumbnailPath('no_selection')).toBe('productPlaceholder')
- })
-
- it('Get right value when useSpecificImagePaths is set', () => {
- config.images = {
- useSpecificImagePaths: true,
- paths: {
- product: '/catalog/product',
- test: '/test'
- }
- }
- expect(getThumbnailPath('/prod', 10, 10, 'test')).toBe('10/10/resize/test/prod')
- expect(getThumbnailPath('/prod', 10, 10)).toBe('10/10/resize/catalog/product/prod')
- })
- it('Get right value when useSpecificImagePaths and baseUrl are set', () => {
- config.images = {
- useSpecificImagePaths: true,
- baseUrl: 'test/',
- paths: {
- product: '/catalog/product',
- test: '/test'
- }
- }
- expect(getThumbnailPath('/prod', 10, 10, 'test')).toBe('test/10/10/resize/test/prod')
- expect(getThumbnailPath('/prod', 10, 10)).toBe('test/10/10/resize/catalog/product/prod')
- })
-
- it('Get right value when baseUrl is set', () => {
- config.images = {
- baseUrl: 'test/'
- }
- expect(getThumbnailPath('/test')).toBe('test/0/0/resize/test')
- expect(getThumbnailPath('/test', 10, 20)).toBe('test/10/20/resize/test')
- expect(getThumbnailPath('/test', 30, 20)).toBe('test/30/20/resize/test')
- })
-})
diff --git a/core/helpers/validators/index.ts b/core/helpers/validators/index.ts
deleted file mode 100644
index 26c866282c..0000000000
--- a/core/helpers/validators/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-/** check if string contains some any unicode alphabet characters */
-export const unicodeAlpha = (value: string): boolean => /[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7C6\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB67\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC\u{10000}-\u{1000B}\u{1000D}-\u{10026}\u{10028}-\u{1003A}\u{1003C}\u{1003D}\u{1003F}-\u{1004D}\u{10050}-\u{1005D}\u{10080}-\u{100FA}\u{10280}-\u{1029C}\u{102A0}-\u{102D0}\u{10300}-\u{1031F}\u{1032D}-\u{10340}\u{10342}-\u{10349}\u{10350}-\u{10375}\u{10380}-\u{1039D}\u{103A0}-\u{103C3}\u{103C8}-\u{103CF}\u{10400}-\u{1049D}\u{104B0}-\u{104D3}\u{104D8}-\u{104FB}\u{10500}-\u{10527}\u{10530}-\u{10563}\u{10600}-\u{10736}\u{10740}-\u{10755}\u{10760}-\u{10767}\u{10800}-\u{10805}\u{10808}\u{1080A}-\u{10835}\u{10837}\u{10838}\u{1083C}\u{1083F}-\u{10855}\u{10860}-\u{10876}\u{10880}-\u{1089E}\u{108E0}-\u{108F2}\u{108F4}\u{108F5}\u{10900}-\u{10915}\u{10920}-\u{10939}\u{10980}-\u{109B7}\u{109BE}\u{109BF}\u{10A00}\u{10A10}-\u{10A13}\u{10A15}-\u{10A17}\u{10A19}-\u{10A35}\u{10A60}-\u{10A7C}\u{10A80}-\u{10A9C}\u{10AC0}-\u{10AC7}\u{10AC9}-\u{10AE4}\u{10B00}-\u{10B35}\u{10B40}-\u{10B55}\u{10B60}-\u{10B72}\u{10B80}-\u{10B91}\u{10C00}-\u{10C48}\u{10C80}-\u{10CB2}\u{10CC0}-\u{10CF2}\u{10D00}-\u{10D23}\u{10F00}-\u{10F1C}\u{10F27}\u{10F30}-\u{10F45}\u{10FE0}-\u{10FF6}\u{11003}-\u{11037}\u{11083}-\u{110AF}\u{110D0}-\u{110E8}\u{11103}-\u{11126}\u{11144}\u{11150}-\u{11172}\u{11176}\u{11183}-\u{111B2}\u{111C1}-\u{111C4}\u{111DA}\u{111DC}\u{11200}-\u{11211}\u{11213}-\u{1122B}\u{11280}-\u{11286}\u{11288}\u{1128A}-\u{1128D}\u{1128F}-\u{1129D}\u{1129F}-\u{112A8}\u{112B0}-\u{112DE}\u{11305}-\u{1130C}\u{1130F}\u{11310}\u{11313}-\u{11328}\u{1132A}-\u{11330}\u{11332}\u{11333}\u{11335}-\u{11339}\u{1133D}\u{11350}\u{1135D}-\u{11361}\u{11400}-\u{11434}\u{11447}-\u{1144A}\u{1145F}\u{11480}-\u{114AF}\u{114C4}\u{114C5}\u{114C7}\u{11580}-\u{115AE}\u{115D8}-\u{115DB}\u{11600}-\u{1162F}\u{11644}\u{11680}-\u{116AA}\u{116B8}\u{11700}-\u{1171A}\u{11800}-\u{1182B}\u{118A0}-\u{118DF}\u{118FF}\u{119A0}-\u{119A7}\u{119AA}-\u{119D0}\u{119E1}\u{119E3}\u{11A00}\u{11A0B}-\u{11A32}\u{11A3A}\u{11A50}\u{11A5C}-\u{11A89}\u{11A9D}\u{11AC0}-\u{11AF8}\u{11C00}-\u{11C08}\u{11C0A}-\u{11C2E}\u{11C40}\u{11C72}-\u{11C8F}\u{11D00}-\u{11D06}\u{11D08}\u{11D09}\u{11D0B}-\u{11D30}\u{11D46}\u{11D60}-\u{11D65}\u{11D67}\u{11D68}\u{11D6A}-\u{11D89}\u{11D98}\u{11EE0}-\u{11EF2}\u{12000}-\u{12399}\u{12480}-\u{12543}\u{13000}-\u{1342E}\u{14400}-\u{14646}\u{16800}-\u{16A38}\u{16A40}-\u{16A5E}\u{16AD0}-\u{16AED}\u{16B00}-\u{16B2F}\u{16B40}-\u{16B43}\u{16B63}-\u{16B77}\u{16B7D}-\u{16B8F}\u{16E40}-\u{16E7F}\u{16F00}-\u{16F4A}\u{16F50}\u{16F93}-\u{16F9F}\u{16FE0}\u{16FE1}\u{16FE3}\u{17000}-\u{187F7}\u{18800}-\u{18AF2}\u{1B000}-\u{1B11E}\u{1B150}-\u{1B152}\u{1B164}-\u{1B167}\u{1B170}-\u{1B2FB}\u{1BC00}-\u{1BC6A}\u{1BC70}-\u{1BC7C}\u{1BC80}-\u{1BC88}\u{1BC90}-\u{1BC99}\u{1D400}-\u{1D454}\u{1D456}-\u{1D49C}\u{1D49E}\u{1D49F}\u{1D4A2}\u{1D4A5}\u{1D4A6}\u{1D4A9}-\u{1D4AC}\u{1D4AE}-\u{1D4B9}\u{1D4BB}\u{1D4BD}-\u{1D4C3}\u{1D4C5}-\u{1D505}\u{1D507}-\u{1D50A}\u{1D50D}-\u{1D514}\u{1D516}-\u{1D51C}\u{1D51E}-\u{1D539}\u{1D53B}-\u{1D53E}\u{1D540}-\u{1D544}\u{1D546}\u{1D54A}-\u{1D550}\u{1D552}-\u{1D6A5}\u{1D6A8}-\u{1D6C0}\u{1D6C2}-\u{1D6DA}\u{1D6DC}-\u{1D6FA}\u{1D6FC}-\u{1D714}\u{1D716}-\u{1D734}\u{1D736}-\u{1D74E}\u{1D750}-\u{1D76E}\u{1D770}-\u{1D788}\u{1D78A}-\u{1D7A8}\u{1D7AA}-\u{1D7C2}\u{1D7C4}-\u{1D7CB}\u{1E100}-\u{1E12C}\u{1E137}-\u{1E13D}\u{1E14E}\u{1E2C0}-\u{1E2EB}\u{1E800}-\u{1E8C4}\u{1E900}-\u{1E943}\u{1E94B}\u{1EE00}-\u{1EE03}\u{1EE05}-\u{1EE1F}\u{1EE21}\u{1EE22}\u{1EE24}\u{1EE27}\u{1EE29}-\u{1EE32}\u{1EE34}-\u{1EE37}\u{1EE39}\u{1EE3B}\u{1EE42}\u{1EE47}\u{1EE49}\u{1EE4B}\u{1EE4D}-\u{1EE4F}\u{1EE51}\u{1EE52}\u{1EE54}\u{1EE57}\u{1EE59}\u{1EE5B}\u{1EE5D}\u{1EE5F}\u{1EE61}\u{1EE62}\u{1EE64}\u{1EE67}-\u{1EE6A}\u{1EE6C}-\u{1EE72}\u{1EE74}-\u{1EE77}\u{1EE79}-\u{1EE7C}\u{1EE7E}\u{1EE80}-\u{1EE89}\u{1EE8B}-\u{1EE9B}\u{1EEA1}-\u{1EEA3}\u{1EEA5}-\u{1EEA9}\u{1EEAB}-\u{1EEBB}\u{20000}-\u{2A6D6}\u{2A700}-\u{2B734}\u{2B740}-\u{2B81D}\u{2B820}-\u{2CEA1}\u{2CEB0}-\u{2EBE0}\u{2F800}-\u{2FA1D}]+/u.test(value)
-
-/** check if string contains some any unicode alphabet characters or digits */
-export const unicodeAlphaNum = (value: string): boolean => unicodeAlpha(value) || /[0-9]+/.test(value)
diff --git a/core/hooks.ts b/core/hooks.ts
deleted file mode 100644
index 8d4152b2bb..0000000000
--- a/core/hooks.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { createListenerHook, createMutatorHook } from '@vue-storefront/core/lib/hooks'
-
-const {
- hook: beforeStoreViewChangedHook,
- executor: beforeStoreViewChangedExecutor
-} = createMutatorHook()
-
-const {
- hook: afterStoreViewChangedHook,
- executor: afterStoreViewChangedExecutor
-} = createListenerHook()
-
-const {
- hook: afterAppInitHook,
- executor: afterAppInitExecutor
-} = createListenerHook()
-
-const {
- hook: beforeHydratedHook,
- executor: beforeHydratedExecutor
-} = createMutatorHook()
-
-const {
- hook: afterProductThumbnailPathGeneratedHook,
- executor: afterProductThumbnailPathGeneratedExecutor
-} = createMutatorHook<{ path: string, pathType: string, sizeX: number, sizeY: number }, { path: string }>()
-
-const {
- hook: beforeLogRenderedHook,
- executor: beforeLogRenderedExecutor
-} = createMutatorHook<{ type: string, message: any, tag: any, context: any, noDefaultOutput?: boolean }, { message: any, tag: any, context: any, noDefaultOutput?: boolean }>()
-
-/** Only for internal usage in core */
-const coreHooksExecutors = {
- afterAppInit: afterAppInitExecutor,
- beforeStoreViewChanged: beforeStoreViewChangedExecutor,
- afterStoreViewChanged: afterStoreViewChangedExecutor,
- beforeHydrated: beforeHydratedExecutor,
- afterProductThumbnailPathGenerate: afterProductThumbnailPathGeneratedExecutor,
- beforeLogRendered: beforeLogRenderedExecutor
-}
-
-const coreHooks = {
- /** Hook is fired right after whole application is initialized. Modules are registered and theme setted up */
- afterAppInit: afterAppInitHook,
- /** Hook is fired directly before changing current storeView (multistrore)
- * @param storeView Inside this function you have access to order object that you can access and modify. It should return order object.
- */
- beforeStoreViewChanged: beforeStoreViewChangedHook,
- /** Hook is fired right after storeView (multistore) is changed
- * @param storeView current storeView
- */
- afterStoreViewChanged: afterStoreViewChangedHook,
- beforeHydrated: beforeHydratedHook,
- afterProductThumbnailPathGenerate: afterProductThumbnailPathGeneratedHook,
- beforeLogRendered: beforeLogRenderedHook
-}
-
-export {
- coreHooks,
- coreHooksExecutors
-}
diff --git a/core/i18n/.gitignore b/core/i18n/.gitignore
deleted file mode 100644
index c61a80f825..0000000000
--- a/core/i18n/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-resource/i18n/*.json
\ No newline at end of file
diff --git a/core/i18n/helpers.ts b/core/i18n/helpers.ts
deleted file mode 100644
index f816174c5c..0000000000
--- a/core/i18n/helpers.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import config from 'config'
-
-export const currentBuildLocales = (): string[] => {
- const defaultLocale = config.i18n.defaultLocale || 'en-US'
- const multistoreLocales = config.storeViews.multistore
- ? Object.values(config.storeViews)
- .map((store: any) => store && typeof store === 'object' && store.i18n && store.i18n.defaultLocale)
- .filter(Boolean)
- : config.i18n.availableLocale
- const locales = multistoreLocales.includes(defaultLocale)
- ? multistoreLocales
- : [defaultLocale, ...multistoreLocales]
-
- return locales
-}
-
-export const transformToShortLocales = (locales: string[]): string[] => locales.map(locale => {
- const separatorIndex = locale.indexOf('-')
- const shortLocale = separatorIndex ? locale.substr(0, separatorIndex) : locale
-
- return shortLocale
-})
-
-export const buildLocaleIgnorePattern = (): RegExp => {
- const locales = transformToShortLocales(currentBuildLocales())
- const localesRegex = locales.map(locale => `${locale}$`).join('|')
-
- return new RegExp(localesRegex)
-}
diff --git a/core/i18n/index.ts b/core/i18n/index.ts
deleted file mode 100644
index c807b29e37..0000000000
--- a/core/i18n/index.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import Vue from 'vue'
-import VueI18n from 'vue-i18n'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { once } from '@vue-storefront/core/helpers'
-import config from 'config'
-
-once('__VUE_EXTEND_I18N__', () => {
- Vue.use(VueI18n)
-})
-
-const defaultLocale = config.i18n.defaultLocale || 'en-US'
-const loadedLanguages = [defaultLocale]
-const i18n = new VueI18n({
- locale: defaultLocale, // set locale
- fallbackLocale: defaultLocale,
- messages: config.i18n.bundleAllStoreviewLanguages ? require('./resource/i18n/multistoreLanguages.json') : {
- [defaultLocale]: require(`./resource/i18n/${defaultLocale}.json`)
- }
-})
-
-function setI18nLanguage (lang: string): string {
- i18n.locale = lang
- return lang
-}
-
-/**
- * Lazy load date locales file for current switched language.
- */
-const loadDateLocales = async (lang: string = 'en'): Promise => {
- let localeCode = lang.toLocaleLowerCase()
- try { // try to load full locale name
- await import(/* webpackChunkName: "dayjs-locales-[request]" */ `dayjs/locale/${localeCode}`)
- } catch (e) { // load simplified locale name, example: de-DE -> de
- const separatorIndex = localeCode.indexOf('-')
- if (separatorIndex) {
- localeCode = separatorIndex ? localeCode.substr(0, separatorIndex) : localeCode
- try {
- await import(/* webpackChunkName: "dayjs-locales-[request]" */ `dayjs/locale/${localeCode}`)
- } catch (err) {
- Logger.debug('Unable to load translation from dayjs')()
- }
- }
- }
-}
-
-export async function loadLanguageAsync (lang: string): Promise {
- await loadDateLocales(lang)
- if (!config.i18n.bundleAllStoreviewLanguages) {
- if (i18n.locale !== lang) {
- if (!loadedLanguages.includes(lang)) {
- try {
- const msgs = await import(/* webpackChunkName: "lang-[request]" */ `./resource/i18n/${lang}.json`)
- i18n.setLocaleMessage(lang, msgs.default)
- loadedLanguages.push(lang)
- return setI18nLanguage(lang)
- } catch (e) { // eslint-disable-line handle-callback-err
- Logger.debug('Unable to load translation')()
- return ''
- }
- }
- return setI18nLanguage(lang)
- }
- } else {
- loadedLanguages.push(lang)
- return setI18nLanguage(lang)
- }
- return lang
-}
-
-export default i18n
diff --git a/core/i18n/intl.ts b/core/i18n/intl.ts
deleted file mode 100644
index 05a548f95c..0000000000
--- a/core/i18n/intl.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import areIntlLocalesSupported from 'intl-locales-supported'
-
-export const importIntlPolyfill = async () => {
- const IntlPolyfill = await import('intl')
- global.Intl = IntlPolyfill.default
-}
-
-export const checkForIntlPolyfill = async (storeView) => {
- const globDTO = typeof window !== 'undefined' ? window : global
- if (!globDTO.hasOwnProperty('Intl') || !areIntlLocalesSupported(storeView.i18n.defaultLocale)) {
- await importIntlPolyfill()
- }
-}
diff --git a/core/i18n/package.json b/core/i18n/package.json
deleted file mode 100644
index 873aa226c4..0000000000
--- a/core/i18n/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "@vue-storefront/i18n",
- "version": "1.12.2",
- "description": "Vue Storefront i18n",
- "license": "MIT",
- "main": "index.ts",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "dependencies": {
- "vue-i18n": "^8.0.0"
- },
- "publishConfig": {
- "access": "public"
- }
-}
diff --git a/core/i18n/resource/countries.json b/core/i18n/resource/countries.json
deleted file mode 100644
index 66c08c9fc9..0000000000
--- a/core/i18n/resource/countries.json
+++ /dev/null
@@ -1,986 +0,0 @@
-[
- {
- "name": "Afghanistan",
- "code": "AF"
- },
- {
- "name": "Albania",
- "code": "AL"
- },
- {
- "name": "Algeria",
- "code": "DZ"
- },
- {
- "name": "American Samoa",
- "code": "AS"
- },
- {
- "name": "Andorra",
- "code": "AD"
- },
- {
- "name": "Angola",
- "code": "AO"
- },
- {
- "name": "Anguilla",
- "code": "AI"
- },
- {
- "name": "Antarctica",
- "code": "AQ"
- },
- {
- "name": "Antigua and Barbuda",
- "code": "AG"
- },
- {
- "name": "Argentina",
- "code": "AR"
- },
- {
- "name": "Armenia",
- "code": "AM"
- },
- {
- "name": "Aruba",
- "code": "AW"
- },
- {
- "name": "Australia",
- "code": "AU"
- },
- {
- "name": "Austria",
- "code": "AT"
- },
- {
- "name": "Azerbaijan",
- "code": "AZ"
- },
- {
- "name": "Bahamas",
- "code": "BS"
- },
- {
- "name": "Bahrain",
- "code": "BH"
- },
- {
- "name": "Bangladesh",
- "code": "BD"
- },
- {
- "name": "Barbados",
- "code": "BB"
- },
- {
- "name": "Belarus",
- "code": "BY"
- },
- {
- "name": "Belgium",
- "code": "BE"
- },
- {
- "name": "Belize",
- "code": "BZ"
- },
- {
- "name": "Benin",
- "code": "BJ"
- },
- {
- "name": "Bermuda",
- "code": "BM"
- },
- {
- "name": "Bhutan",
- "code": "BT"
- },
- {
- "name": "Bolivia",
- "code": "BO"
- },
- {
- "name": "Bosnia and Herzegovina",
- "code": "BA"
- },
- {
- "name": "Botswana",
- "code": "BW"
- },
- {
- "name": "Bouvet Island",
- "code": "BV"
- },
- {
- "name": "Brazil",
- "code": "BR"
- },
- {
- "name": "British Indian Ocean Territory",
- "code": "IO"
- },
- {
- "name": "British Virgin Islands",
- "code": "VG"
- },
- {
- "name": "Brunei",
- "code": "BN"
- },
- {
- "name": "Bulgaria",
- "code": "BG"
- },
- {
- "name": "Burkina Faso",
- "code": "BF"
- },
- {
- "name": "Burundi",
- "code": "BI"
- },
- {
- "name": "Cambodia",
- "code": "KH"
- },
- {
- "name": "Cameroon",
- "code": "CM"
- },
- {
- "name": "Canada",
- "code": "CA"
- },
- {
- "name": "Cape Verde",
- "code": "CV"
- },
- {
- "name": "Cayman Islands",
- "code": "KY"
- },
- {
- "name": "Central African Republic",
- "code": "CF"
- },
- {
- "name": "Chad",
- "code": "TD"
- },
- {
- "name": "Chile",
- "code": "CL"
- },
- {
- "name": "China",
- "code": "CN"
- },
- {
- "name": "Christmas Island",
- "code": "CX"
- },
- {
- "name": "Cocos [Keeling] Islands",
- "code": "CC"
- },
- {
- "name": "Colombia",
- "code": "CO"
- },
- {
- "name": "Comoros",
- "code": "KM"
- },
- {
- "name": "Congo",
- "code": "CG"
- },
- {
- "name": "Congo",
- "code": "CD"
- },
- {
- "name": "Cook Islands",
- "code": "CK"
- },
- {
- "name": "Costa Rica",
- "code": "CR"
- },
- {
- "name": "Croatia",
- "code": "HR"
- },
- {
- "name": "Cuba",
- "code": "CU"
- },
- {
- "name": "Cyprus",
- "code": "CY"
- },
- {
- "name": "Czech Republic",
- "code": "CZ"
- },
- {
- "name": "Côte d’Ivoire",
- "code": "CI"
- },
- {
- "name": "Denmark",
- "code": "DK"
- },
- {
- "name": "Djibouti",
- "code": "DJ"
- },
- {
- "name": "Dominica",
- "code": "DM"
- },
- {
- "name": "Dominican Republic",
- "code": "DO"
- },
- {
- "name": "Ecuador",
- "code": "EC"
- },
- {
- "name": "Egypt",
- "code": "EG"
- },
- {
- "name": "El Salvador",
- "code": "SV"
- },
- {
- "name": "Equatorial Guinea",
- "code": "GQ"
- },
- {
- "name": "Eritrea",
- "code": "ER"
- },
- {
- "name": "Estonia",
- "code": "EE"
- },
- {
- "name": "Ethiopia",
- "code": "ET"
- },
- {
- "name": "Falkland Islands",
- "code": "FK"
- },
- {
- "name": "Faroe Islands",
- "code": "FO"
- },
- {
- "name": "Fiji",
- "code": "FJ"
- },
- {
- "name": "Finland",
- "code": "FI"
- },
- {
- "name": "France",
- "code": "FR"
- },
- {
- "name": "French Guiana",
- "code": "GF"
- },
- {
- "name": "French Polynesia",
- "code": "PF"
- },
- {
- "name": "French Southern Territories",
- "code": "TF"
- },
- {
- "name": "Gabon",
- "code": "GA"
- },
- {
- "name": "Gambia",
- "code": "GM"
- },
- {
- "name": "Georgia",
- "code": "GE"
- },
- {
- "name": "Germany",
- "code": "DE"
- },
- {
- "name": "Ghana",
- "code": "GH"
- },
- {
- "name": "Gibraltar",
- "code": "GI"
- },
- {
- "name": "Greece",
- "code": "GR"
- },
- {
- "name": "Greenland",
- "code": "GL"
- },
- {
- "name": "Grenada",
- "code": "GD"
- },
- {
- "name": "Guadeloupe",
- "code": "GP"
- },
- {
- "name": "Guam",
- "code": "GU"
- },
- {
- "name": "Guatemala",
- "code": "GT"
- },
- {
- "name": "Guernsey",
- "code": "GG"
- },
- {
- "name": "Guinea",
- "code": "GN"
- },
- {
- "name": "Guinea",
- "code": "GW"
- },
- {
- "name": "Guyana",
- "code": "GY"
- },
- {
- "name": "Haiti",
- "code": "HT"
- },
- {
- "name": "Heard Island and McDonald Islands",
- "code": "HM"
- },
- {
- "name": "Honduras",
- "code": "HN"
- },
- {
- "name": "Hong Kong SAR China",
- "code": "HK"
- },
- {
- "name": "Hungary",
- "code": "HU"
- },
- {
- "name": "Iceland",
- "code": "IS"
- },
- {
- "name": "India",
- "code": "IN"
- },
- {
- "name": "Indonesia",
- "code": "ID"
- },
- {
- "name": "Iran",
- "code": "IR"
- },
- {
- "name": "Iraq",
- "code": "IQ"
- },
- {
- "name": "Ireland",
- "code": "IE"
- },
- {
- "name": "Isle of Man",
- "code": "IM"
- },
- {
- "name": "Israel",
- "code": "IL"
- },
- {
- "name": "Italy",
- "code": "IT"
- },
- {
- "name": "Jamaica",
- "code": "JM"
- },
- {
- "name": "Japan",
- "code": "JP"
- },
- {
- "name": "Jersey",
- "code": "JE"
- },
- {
- "name": "Jordan",
- "code": "JO"
- },
- {
- "name": "Kazakhstan",
- "code": "KZ"
- },
- {
- "name": "Kenya",
- "code": "KE"
- },
- {
- "name": "Kiribati",
- "code": "KI"
- },
- {
- "name": "Kuwait",
- "code": "KW"
- },
- {
- "name": "Kyrgyzstan",
- "code": "KG"
- },
- {
- "name": "Laos",
- "code": "LA"
- },
- {
- "name": "Latvia",
- "code": "LV"
- },
- {
- "name": "Lebanon",
- "code": "LB"
- },
- {
- "name": "Lesotho",
- "code": "LS"
- },
- {
- "name": "Liberia",
- "code": "LR"
- },
- {
- "name": "Libya",
- "code": "LY"
- },
- {
- "name": "Liechtenstein",
- "code": "LI"
- },
- {
- "name": "Lithuania",
- "code": "LT"
- },
- {
- "name": "Luxembourg",
- "code": "LU"
- },
- {
- "name": "Macau SAR China",
- "code": "MO"
- },
- {
- "name": "Macedonia",
- "code": "MK"
- },
- {
- "name": "Madagascar",
- "code": "MG"
- },
- {
- "name": "Malawi",
- "code": "MW"
- },
- {
- "name": "Malaysia",
- "code": "MY"
- },
- {
- "name": "Maldives",
- "code": "MV"
- },
- {
- "name": "Mali",
- "code": "ML"
- },
- {
- "name": "Malta",
- "code": "MT"
- },
- {
- "name": "Marshall Islands",
- "code": "MH"
- },
- {
- "name": "Martinique",
- "code": "MQ"
- },
- {
- "name": "Mauritania",
- "code": "MR"
- },
- {
- "name": "Mauritius",
- "code": "MU"
- },
- {
- "name": "Mayotte",
- "code": "YT"
- },
- {
- "name": "Mexico",
- "code": "MX"
- },
- {
- "name": "Micronesia",
- "code": "FM"
- },
- {
- "name": "Moldova",
- "code": "MD"
- },
- {
- "name": "Monaco",
- "code": "MC"
- },
- {
- "name": "Mongolia",
- "code": "MN"
- },
- {
- "name": "Montenegro",
- "code": "ME"
- },
- {
- "name": "Montserrat",
- "code": "MS"
- },
- {
- "name": "Morocco",
- "code": "MA"
- },
- {
- "name": "Mozambique",
- "code": "MZ"
- },
- {
- "name": "Myanmar [Burma]",
- "code": "MM"
- },
- {
- "name": "Namibia",
- "code": "NA"
- },
- {
- "name": "Nauru",
- "code": "NR"
- },
- {
- "name": "Nepal",
- "code": "NP"
- },
- {
- "name": "Netherlands",
- "code": "NL"
- },
- {
- "name": "Netherlands Antilles",
- "code": "AN"
- },
- {
- "name": "New Caledonia",
- "code": "NC"
- },
- {
- "name": "New Zealand",
- "code": "NZ"
- },
- {
- "name": "Nicaragua",
- "code": "NI"
- },
- {
- "name": "Niger",
- "code": "NE"
- },
- {
- "name": "Nigeria",
- "code": "NG"
- },
- {
- "name": "Niue",
- "code": "NU"
- },
- {
- "name": "Norfolk Island",
- "code": "NF"
- },
- {
- "name": "North Korea",
- "code": "KP"
- },
- {
- "name": "Northern Mariana Islands",
- "code": "MP"
- },
- {
- "name": "Norway",
- "code": "NO"
- },
- {
- "name": "Oman",
- "code": "OM"
- },
- {
- "name": "Pakistan",
- "code": "PK"
- },
- {
- "name": "Palau",
- "code": "PW"
- },
- {
- "name": "Palestinian Territories",
- "code": "PS"
- },
- {
- "name": "Panama",
- "code": "PA"
- },
- {
- "name": "Papua New Guinea",
- "code": "PG"
- },
- {
- "name": "Paraguay",
- "code": "PY"
- },
- {
- "name": "Peru",
- "code": "PE"
- },
- {
- "name": "Philippines",
- "code": "PH"
- },
- {
- "name": "Pitcairn Islands",
- "code": "PN"
- },
- {
- "name": "Poland",
- "code": "PL"
- },
- {
- "name": "Portugal",
- "code": "PT"
- },
- {
- "name": "Puerto Rico",
- "code": "PR"
- },
- {
- "name": "Qatar",
- "code": "QA"
- },
- {
- "name": "Romania",
- "code": "RO"
- },
- {
- "name": "Russia",
- "code": "RU"
- },
- {
- "name": "Rwanda",
- "code": "RW"
- },
- {
- "name": "Réunion",
- "code": "RE"
- },
- {
- "name": "Saint Barthélemy",
- "code": "BL"
- },
- {
- "name": "Saint Helena",
- "code": "SH"
- },
- {
- "name": "Saint Kitts and Nevis",
- "code": "KN"
- },
- {
- "name": "Saint Lucia",
- "code": "LC"
- },
- {
- "name": "Saint Martin",
- "code": "MF"
- },
- {
- "name": "Saint Pierre and Miquelon",
- "code": "PM"
- },
- {
- "name": "Saint Vincent and the Grenadines",
- "code": "VC"
- },
- {
- "name": "Samoa",
- "code": "WS"
- },
- {
- "name": "San Marino",
- "code": "SM"
- },
- {
- "name": "Saudi Arabia",
- "code": "SA"
- },
- {
- "name": "Senegal",
- "code": "SN"
- },
- {
- "name": "Serbia",
- "code": "RS"
- },
- {
- "name": "Seychelles",
- "code": "SC"
- },
- {
- "name": "Sierra Leone",
- "code": "SL"
- },
- {
- "name": "Singapore",
- "code": "SG"
- },
- {
- "name": "Slovakia",
- "code": "SK"
- },
- {
- "name": "Slovenia",
- "code": "SI"
- },
- {
- "name": "Solomon Islands",
- "code": "SB"
- },
- {
- "name": "Somalia",
- "code": "SO"
- },
- {
- "name": "South Africa",
- "code": "ZA"
- },
- {
- "name": "South Georgia and the South Sandwich Islands",
- "code": "GS"
- },
- {
- "name": "South Korea",
- "code": "KR"
- },
- {
- "name": "Spain",
- "code": "ES"
- },
- {
- "name": "Sri Lanka",
- "code": "LK"
- },
- {
- "name": "Sudan",
- "code": "SD"
- },
- {
- "name": "Suriname",
- "code": "SR"
- },
- {
- "name": "Svalbard and Jan Mayen",
- "code": "SJ"
- },
- {
- "name": "Swaziland",
- "code": "SZ"
- },
- {
- "name": "Sweden",
- "code": "SE"
- },
- {
- "name": "Switzerland",
- "code": "CH"
- },
- {
- "name": "Syria",
- "code": "SY"
- },
- {
- "name": "São Tomé and Príncipe",
- "code": "ST"
- },
- {
- "name": "Taiwan",
- "code": "TW"
- },
- {
- "name": "Tajikistan",
- "code": "TJ"
- },
- {
- "name": "Tanzania",
- "code": "TZ"
- },
- {
- "name": "Thailand",
- "code": "TH"
- },
- {
- "name": "Timor",
- "code": "TL"
- },
- {
- "name": "Togo",
- "code": "TG"
- },
- {
- "name": "Tokelau",
- "code": "TK"
- },
- {
- "name": "Tonga",
- "code": "TO"
- },
- {
- "name": "Trinidad and Tobago",
- "code": "TT"
- },
- {
- "name": "Tunisia",
- "code": "TN"
- },
- {
- "name": "Turkey",
- "code": "TR"
- },
- {
- "name": "Turkmenistan",
- "code": "TM"
- },
- {
- "name": "Turks and Caicos Islands",
- "code": "TC"
- },
- {
- "name": "Tuvalu",
- "code": "TV"
- },
- {
- "name": "U.S. Minor Outlying Islands",
- "code": "UM"
- },
- {
- "name": "U.S. Virgin Islands",
- "code": "VI"
- },
- {
- "name": "Uganda",
- "code": "UG"
- },
- {
- "name": "Ukraine",
- "code": "UA"
- },
- {
- "name": "United Arab Emirates",
- "code": "AE"
- },
- {
- "name": "United Kingdom",
- "code": "GB"
- },
- {
- "name": "United States",
- "code": "US"
- },
- {
- "name": "Uruguay",
- "code": "UY"
- },
- {
- "name": "Uzbekistan",
- "code": "UZ"
- },
- {
- "name": "Vanuatu",
- "code": "VU"
- },
- {
- "name": "Vatican City",
- "code": "VA"
- },
- {
- "name": "Venezuela",
- "code": "VE"
- },
- {
- "name": "Vietnam",
- "code": "VN"
- },
- {
- "name": "Wallis and Futuna",
- "code": "WF"
- },
- {
- "name": "Western Sahara",
- "code": "EH"
- },
- {
- "name": "Yemen",
- "code": "YE"
- },
- {
- "name": "Zambia",
- "code": "ZM"
- },
- {
- "name": "Zimbabwe",
- "code": "ZW"
- },
- {
- "name": "Åland Islands",
- "code": "AX"
- }
-]
diff --git a/core/i18n/resource/i18n/ar-SA.csv b/core/i18n/resource/i18n/ar-SA.csv
deleted file mode 100644
index 4213bb2038..0000000000
--- a/core/i18n/resource/i18n/ar-SA.csv
+++ /dev/null
@@ -1,77 +0,0 @@
- is out of the stock!,غير متوفر بالمخزون!
-"Product price is unknown, product cannot be added to the cart!",سعر المنتج غير معلوم، لايمكن إضافته للسلة.
-"Stock check in progress, please wait while available stock quantities are checked",جاري فحص المخزون، يرجى الانتظار حتى يتم التأكد من التوفر
-"The product, category or CMS page is not available in Offline mode. Redirecting to Home.",المنتج أو التصنيف أو الصفحة غير متوفرة بدون اتصال إنترنت. جاري التحويل للصفحة الرئيسية.
-"Unhandled error, wrong response format!","Unhandled error, wrong response format!"
-404 Page Not Found,404 الصفحة غير متوفرة
-Account data has successfully been updated,تم تحديث الحساب بنجاح
-Add review,أضف مراجعة
-Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled.,العنوان المسجل في إنهاء الطلب يحتوي معلومات غير صالحة. يرجى التأكد من تعبئة جميع الحقول المطلوبة أيضاً يمكنك التواص معنا عبر {email} للمساعدة. تم إلغاء الطلب.
-Allow notification about the order,السماح بتنبيهات الطلب
-Are you sure you would like to remove this item from the shopping cart?,هل أنت متأكد من إزالة هذا المنتج من سلة التسوق
-Checkout,إتمام الطلب
-Columns,أعمدة
-Compare Products,مقارنة المنتجات
-Compare products,مقارنة المنتجات
-Confirm your order,أكّد طلبك
-Error refreshing user token. User is not authorized to access the resource,خطأ في تحديث التشفير. المستخدم غير مصرح له بالدخول
-Error with response - bad content-type!,خطأ بالرد - محتوى غير صالح!
-Error: Error while adding products,خطأ: خطأ أثناء إضافة المنتجات
-Extension developers would like to thank you for placing an order!,Extension developers would like to thank you for placing an order!
-Field is required,حقل مطلوب
-Field is required.,حقل مطلوب.
-Grand total,المجموع النهائي
-Home Page,الصفحة الرئيسية
-In stock!,متوفر!
-Internal Application error while refreshing the tokens. Please clear the storage and refresh page.,Internal Application error while refreshing the tokens. Please clear the storage and refresh page.
-Internal validation error. Please check if all required fields are filled in. Please contact us on {email},خطأ تحقق داخلي. يرجى التأكد من تعبئة جميع الحقول المطلوبة. فضلاً تواصل معنا على {email}
-Must be greater than 0,يجب أن يكون أكثر من 0
-My Account,حسابي
-Newsletter preferences have successfully been updated,تم تحديث تفضيلات النشرة البريدية
-No available product variants,لا يوجد منتجات متوفرة
-No products synchronized for this category. Please come back while online!,.لا يوجد منتجات تمت مزامنتها لهذا التصنيف. يرجى العودة مرة أخرى إذا تم الاتصال بالإنترنت
-No such configuration for the product. Please do choose another combination of attributes.,لا يوجد خيارات منطبقة لهذا المنتج من فضلك قم بتعديل الخيارات.
-OK,موافق
-Out of stock!,غير متوفر!
-Out of the stock!,غير متوفر بالمخزون!
-Payment Information,معلومات الدفع
-Please configure product bundle options and fix the validation errors,يرجى تحديد الخيارات وإصلاح خطأ التحقق
-Please configure product custom options and fix the validation errors,من فضلك حدد خيارات المنتج لإصلاح خطأ التحقق
-Please confirm order you placed when you was offline,فضلاً أكد الطلب الذي أنشأته بدون اتصال إنترنت
-Please fix the validation errors,يرجى إصلاح خطأ التحقق
-Please select the field which You like to sort by,اختر حقل للترتيب به
-Please wait ...,انتظر من فضلك…
-Proceed to checkout,إتمام الطلب
-Processing order...,جاري معالجة الطلب…
-Product has been added to the cart!,تمت إضافة المنتج للسلة!
-Product quantity has been updated!,تم تحديث الكمية!
-Product {productName} has been added to the compare!,تمت إضافة المنتج {productName} إلى المقارنة!
-Product {productName} has been added to wishlist!,تمت إضافة المنتج {productName} إلى قائمة الأمنيات بنجاح!
-Product {productName} has been removed from compare!,تمت إزالة المنتج {productName} من المقارنة!
-Product {productName} has been removed from wishlit!,تمت إزالة المنتج {productName} من قائمة الأمنيات بنجاح!
-Quantity must be above 0,يجب أن تكون الكمية أكثر من 0
-Registering the account ...,جاري تسجيل الحساب
-Reset password feature does not work while offline!,لا يمكن إستعادة كلمة المرور بدون اتصال بالشبكة!
-Review,مراجعة
-Reviews,مراجعات
-Shopping cart is empty. Please add some products before entering Checkout,سلة التسوق فارغة. يرجى إضافة بعض المنتجات للانتقال إلى صفحة إتمام الطلب
-Some of the ordered products are not available!,بعض المنتجات المطلوبة غير متاحة
-Subtotal incl. tax,المجموع متضمن الضريبة
-Summary,ملخص
-The product is out of stock and cannot be added to the cart!,المنتج غير متوفر بالمخزون ولا يمكن إضافته للسلة
-The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.,الكمية غير مؤكدة (volatile). تمت إضافة المنتج للسلة للحجز المسبق.
-There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.,لا يوجد اتصال بالإنترنت. مازال بإمكانك إتمام الطلب. وسنقوم بإخطارك إذا كان أي من المنتجات المطلوبة غير متوفر، لايمكننا التحقق الآن.
-This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!,This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!
-Type what you are looking for...,اكتب ما تبحث عنه…
-Unexpected authorization error. Check your Network conection.,خطأ تحقق غير متوقع. تحقق من اتصالك بالشبكة.
-You are logged in!,تم تسجيل دخولك!
-You are to pay for this order upon delivery.,ستقوم بالدفع لهذا الطلب عند الاستلام.
-You need to be logged in to see this page,يجب تسجيل الدخول لعرض الصفحة
-You're logged out,تم تسجيل خروجك
-email,البريد الإلكتروني
-have as many,have as many
-login,تسجيل الدخول
-most you may purchase,most you may purchase
-not authorized,غير مصرح
-password,كلمة المرور
-to account,إلى الحساب
diff --git a/core/i18n/resource/i18n/cs-CZ.csv b/core/i18n/resource/i18n/cs-CZ.csv
deleted file mode 100644
index c567556e61..0000000000
--- a/core/i18n/resource/i18n/cs-CZ.csv
+++ /dev/null
@@ -1,72 +0,0 @@
-" is out of stock!"," není na skladě!"
-"404 Page Not Found","404 Stránka nenalezena"
-"Account data has successfully been updated","Údaje účtu byly úspěšně aktualizovány"
-"Add review","Přidat recenzi"
-"Adding a review ...","Adding a review ..."
-"Allow notification about the order","Povolit oznámení o objednávce"
-"Are you sure you would like to remove this item from the shopping cart?","Opravdu chcete tuto položku odebrat z nákupního košíku?"
-"Checkout","Koupit"
-"Compare Products","Porovnání produktů"
-"Compare products","Porovnejte produkty"
-"Confirm your order","Potvrďte svou objednávku"
-"Error refreshing user token. User is not authorized to access the resource","Chyba obnovení uživatelského kupónu. Uživatel nemá oprávnění k přístupu"
-"Error with response - bad content-type!","Chyba s odpovědí - špatný typ obsahu!"
-"Extension developers would like to thank you for placing an order!","Vývojáři rozšíření by rádi poděkovali za zadání vaší objednávky!"
-"Field is required","Pole je povinné"
-"Field is required.","Pole je povinné."
-"Grand total","Celkový součet"
-"Home Page","Domovská stránka"
-"In stock!","Skladem!"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Chyba interní aplikace při aktualizaci kupónů. Vymažte úložiště a stránku aktualizujte."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Interní chyba ověření. Zkontrolujte, zda jsou vyplněna všechna povinná pole. Kontaktujte nás prosím na {email}"
-"Must be greater than 0","Musí být větší než 0"
-"My Account","Můj účet"
-"Newsletter preferences have successfully been updated","Preference zasílání novinek byly úspěšně aktualizovány"
-"No available product variants","Žádné dostupné varianty produktu"
-"No products synchronized for this category. Please come back while online!","V této kategorii nemáte žádné synchronizované produkty. Zkuste prosím znovu až budete online!"
-"No such configuration for the product. Please do choose another combination of attributes.","Neexistuje žádná taková konfigurace pro daný výrobek. Vyberte prosím jinou kombinaci vlastností."
-"OK","OK"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","Vyprodáno!"
-"Out of the stock!","Není skladem!"
-"Payment Information","Informace o platbě"
-"Please configure product custom options and fix the validation errors","Přizpůsobte vlastní navolené možnosti produktu a opravte chyby ověření"
-"Please confirm order you placed when you was offline","Potvrďte objednávku, kterou jste zadali, když jste byli offline"
-"Please fix the validation errors","Opravte chyby ověření"
-"Please select the field which You like to sort by","Vyberte pole, dle kterého chcete seřadit"
-"Proceed to checkout","Přejděte k nákupu"
-"Product has been added to the cart!","Produkt byl přidán do košíku!"
-"Product price is unknown, product cannot be added to the cart!","Cena produktu není známa, produkt nelze přidat do košíku!"
-"Product quantity has been updated!","Množství produktu bylo aktualizováno!"
-"Product {productName} has been added to the compare!","Produkt {productName} byl přidán k porovnání!"
-"Product {productName} has been added to wishlist!","Produkt {productName} byl přidán do seznamu přání!"
-"Product {productName} has been removed from compare!","Produkt {productName} byl odstraněn z porovnávání!"
-"Product {productName} has been removed from wishlist!","Produkt {productName} byl odstraněn ze seznamu přání!"
-"Registering the account ...","Registrace účtu ..."
-"Reset password feature does not work while offline!","Funkce obnovení hesla nefunguje offline!"
-"Review","Recenze"
-"Reviews","Recenze"
-"Shopping cart is empty. Please add some products before entering Checkout","Nákupní košík je prázdný. Prosím přidejte nějaké produkty než přistoupíte k nákupu"
-"Some of the ordered products are not available!","Některé z objednaných produktů nejsou k dispozici!"
-"Stock check in progress, please wait while available stock quantities are checked","Kontrola skladových zásob probíhá, prosím, počkejte, až se zkontroluje množství dostupných zásob"
-"Subtotal incl. tax","Mezisoučet vč. daně"
-"Summary","Shrnutí",
-"The product is out of stock and cannot be added to the cart!","Produkt není na skladě a nelze ho přidat do košíku!"
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","Systém si není jistý množstvím zásob (volatilní). Produkt byl přidán do košíku pro předběžnou rezervaci."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Připojení k internetu není k dispozici. Stále si však můžete zboží objednat. Budeme vás informovat v případě, že některý z objednaných produktů není k dispozici, protože to v současnosti nelze zkontrolovat."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Tato funkce zatím nebyla zavedena! Prosíme, podívejte se na https://github.com/vuestorefront/vue-storefront/issues pro podrobný návod!"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","Zadejte, co hledáte..."
-"Unhandled error, wrong response format!","Neošetřená chyba, nesprávný formát odpovědi!"
-"You are logged in!","Jste přihlášeni!"
-"You are to pay for this order upon delivery.","Tuto objednávku platíte při doručení."
-"You need to be logged in to see this page","Pro zobrazení této stránky musíte být přihlášeni"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Jste odhlášeni"
-"email","email"
-"have as many","mít tolik"
-"login","přihlásit se"
-"most you may purchase","nejvíce co si můžete koupit"
-"not authorized","neautorizováno"
-"password","heslo"
-"to account","na účet"
diff --git a/core/i18n/resource/i18n/de-DE.csv b/core/i18n/resource/i18n/de-DE.csv
deleted file mode 100644
index cd9aaf751d..0000000000
--- a/core/i18n/resource/i18n/de-DE.csv
+++ /dev/null
@@ -1,78 +0,0 @@
-" is out of stock!"," ist nicht auf Lager!"
-"404 Page Not Found","404 Seite nicht gefunden"
-"Account data has successfully been updated","Kontodaten wurden erfolgreich aktualisiert"
-"Add review","Bewertung hinzufügen"
-"Adding a review ...","Adding a review ..."
-"Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled.","Die angegebene Adresse ist nicht gültig. Bitte überprüfen Sie, ob alle notwenigen Felder ausgefüllt sind und kontaktieren Sie uns per {email} um den Fehler für die Zukunft zu beheben. Ihre Bestellung wurde abgebrochen."
-"Allow notification about the order","Erlauben Sie Benachrichtigungen über die Bestellung"
-"Are you sure you would like to remove this item from the shopping cart?","Sind Sie sicher, dass Sie diesen Artikel aus Ihrem Warenkorb entfernen wollen?"
-"Checkout","Kasse"
-"Compare Products","Produkte vergleichen"
-"Compare products","Produkte vergleichen"
-"Confirm your order","Bestätigen Sie ihre Bestellung"
-"Error refreshing user token. User is not authorized to access the resource","Fehler bei der Erneuerung des Benutzer-Tokens. Der Benutzer ist nicht authorisiert auf die Resource zuzugreifen"
-"Error with response - bad content-type!","Fehler in der Antwort vom Server - Falscher Inhaltstyp!"
-"Error: Error while adding products","Error: Fehler beim hinzufügen der Produkte"
-"Extension developers would like to thank you for placing an order!","Extension-Entwickler würden sich bei Ihnen gerne dafür bedanken, dass Sie eine Bestellung getätigt haben!"
-"Field is required","Dies ist ein Pflichtfeld"
-"Field is required.","Dies ist ein Pflichtfeld."
-"Grand total","Gesamtsumme"
-"Home Page","Startseite"
-"In stock!","Auf Lager!"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Ein interner Anwendungsfehler ist, während der Erneuerung des Tokens, aufgetreten. Bitte leeren Sie den Speicher und laden Sie die Seite neu."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Interner Validierungsfehler. Bitte überprüfen Sie, ob alle erforderlichen Felder ausgefüllt sind. Bei Problemen kontaktieren Sie uns bitte über {email}"
-"Must be greater than 0","Muss größer als 0 sein"
-"My Account","Mein Konto"
-"Newsletter preferences have successfully been updated","Die Newsletter-Einstellungen wurden erfolgreich aktualisiert"
-"No available product variants","Keine Produkte verfügbar"
-"No products synchronized for this category. Please come back while online!","Es sind keine Produkte für diese Kategorie synchronisiert. Bitte versuchen Sie es erneut, wenn Sie online sind!"
-"No such configuration for the product. Please do choose another combination of attributes.","Diese Konfiguration ist für dieses Produkt nicht möglich. Bitte wählen Sie eine andere Kombination von Eigenschaften."
-"OK","OK"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","Nicht auf Lager!"
-"Out of the stock!","Nicht mehr auf Lager!"
-"Payment Information","Bezahlinformationen"
-"Please configure product bundle options and fix the validation errors","Bitte konfigurieren Sie die Produktbündel-Optionen und beheben Sie die Validierungsfehler"
-"Please configure product custom options and fix the validation errors","Bitte konfigurieren Sie die angepassten Produktoptionen und beheben Sie die Validierungsfehler"
-"Please confirm order you placed when you was offline","Bitte bestätigen Sie ihre Bestellung, welche Sie getätigt haben während Sie offline waren"
-"Please fix the validation errors","Bitte beheben Sie die Validierungsfehler"
-"Please select the field which You like to sort by","Bitte wählen Sie das Feld aus, nach dem Sie sortieren möchten"
-"Proceed to checkout","Weiter zur Kasse"
-"Processing order...","Bestellung wird verarbeitet..."
-"Product has been added to the cart!","Produkt wurde zum Warenkorb hinzugefügt!"
-"Product price is unknown, product cannot be added to the cart!","Der Produktpreis ist unbekannt, daher kann dieses Produkt nicht zum Warenkorb hinzugefügt werden!"
-"Product quantity has been updated!","Produktmenge wurde aktualisiert!"
-"Product {productName} has been added to the compare!","Das Produkt {productName} wurde zur Vergleichsliste hinzugefügt!"
-"Product {productName} has been added to wishlist!","Das Produkt {productName} wurde der Wunschliste hinzugefügt!"
-"Product {productName} has been removed from compare!","Das Produkt {productName} wurde von der Vergleichsliste entfernt!"
-"Product {productName} has been removed from wishlist!","Das Produkt {productName} wurde von der Wunschliste entfernt!"
-"Quantity must be above 0","Die Menge muss größer als 0 sein"
-"Registering the account ...","Registrieren des Kontos ..."
-"Reset password feature does not work while offline!","Die Funktion zum Zurücksetzen des Passworts funktioniert nicht im Offline-Modus!"
-"Review","Bewertung"
-"Reviews","Bewertungen"
-"Shopping cart is empty. Please add some products before entering Checkout","Ihr Warenkorb ist leer. Bitte fügen Sie mindestens ein Produkt hinzu bevor Sie zur Kasse gehen"
-"Some of the ordered products are not available!","Einige der bestellten Produkte sind nicht auf Lager!"
-"Stock check in progress, please wait while available stock quantities are checked","Bestandskontrolle läuft. Bitte warten Sie einen Moment bis die verfügbare Bestandsmenge geprüft worden ist"
-"Subtotal incl. tax","Zwischensumme inkl. MwSt."
-"Summary","Zusammenfassung"
-"The product is out of stock and cannot be added to the cart!","Das Produkt ist nicht auf Lager und kann daher nicht zum Warenkorb hinzugefügt werden!"
-"The product, category or CMS page is not available in Offline mode. Redirecting to Home.","Das Produkt, die Kategorie oder die CMS Seite ist nicht verfügbar im Offline-Modus. Weiterleitung zur Startseite."
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","Das System konnte den genauen Lagerbestand nicht ermitteln, da dieser sehr volatil ist. Das Produkt wurde zur Vorreservierung in den Warenkorb gelegt."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Es besteht aktuell keine Verbindung zum Internet. Sie können ihre Bestellung dennoch aufgeben. Falls eines der bestellten Produkte bei Wiederaufbau der Verbindung nicht mehr verfügbar sein sollte, werden wir Sie umgehend benachrichtigen."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Diese Funktion wurde noch nicht implementiert. Für weitere Details schauen Sie bitte auf https://github.com/vuestorefront/vue-storefront/issues unsere Roadmap an!"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","Geben Sie ein, wonach Sie suchen..."
-"Unhandled error, wrong response format!","Unbehandelter Fehler. Die Antwort vom Server ist falsch formatiert!"
-"You are logged in!","Du wurdest eingeloggt!"
-"You are to pay for this order upon delivery.","Sie müssen bei Lieferung bezahlen."
-"You need to be logged in to see this page","Sie müssen angemeldet sein, um diese Seite anzuzeigen"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Sie wurden ausgeloggt"
-"email","Email"
-"have as many","hat so viele"
-"login","Login"
-"most you may purchase"," maximum das Sie kaufen können"
-"not authorized","Nicht authorisiert"
-"password","Passwort"
-"to account","zum Account"
diff --git a/core/i18n/resource/i18n/en-US.csv b/core/i18n/resource/i18n/en-US.csv
deleted file mode 100644
index 382225aeae..0000000000
--- a/core/i18n/resource/i18n/en-US.csv
+++ /dev/null
@@ -1,90 +0,0 @@
-" is out of stock!"," is out of stock!"
-"404 Page Not Found","404 Page Not Found"
-"Account data has successfully been updated","Account data has successfully been updated"
-"Add review","Add review"
-"Adding a review ...","Adding a review ..."
-"Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled.","Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled."
-"Allow notification about the order","Allow notification about the order"
-"Are you sure you would like to remove this item from the shopping cart?","Are you sure you would like to remove this item from the shopping cart?"
-"Checkout","Checkout"
-"Columns","Columns"
-"Compare Products","Compare Products"
-"Compare products","Compare products"
-"Confirm your order","Confirm your order"
-"Error refreshing user token. User is not authorized to access the resource","Error refreshing user token. User is not authorized to access the resource"
-"Error with response - bad content-type!","Error with response - bad content-type!"
-"Error: Error while adding products","Error: Error while adding products"
-"Extension developers would like to thank you for placing an order!","Extension developers would like to thank you for placing an order!"
-"Field is required","Field is required"
-"Field is required.","Field is required."
-"Grand total","Grand total"
-"Home Page","Home Page"
-"In stock!","In stock!"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Internal Application error while refreshing the tokens. Please clear the storage and refresh page."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Internal validation error. Please check if all required fields are filled in. Please contact us on {email}"
-"Must be greater than 0","Must be greater than 0"
-"My Account","My Account"
-"Newsletter preferences have successfully been updated","Newsletter preferences have successfully been updated"
-"No available product variants","No available product variants"
-"No products synchronized for this category. Please come back while online!","No products synchronized for this category. Please come back while online!"
-"No such configuration for the product. Please do choose another combination of attributes.","No such configuration for the product. Please do choose another combination of attributes."
-"OK","OK"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Or if you will stay on ""Order confirmation"" page, the order will be placed automatically without confirmation, once the internet connection will be back.","Or if you will stay on ""Order confirmation"" page, the order will be placed automatically without confirmation, once the internet connection will be back."
-"Out of stock!","Out of stock!"
-"Out of the stock!","Out of the stock!"
-"Payment Information","Payment Information"
-"Please configure product bundle options and fix the validation errors","Please configure product bundle options and fix the validation errors"
-"Please configure product custom options and fix the validation errors","Please configure product custom options and fix the validation errors"
-"Please confirm order you placed when you was offline","Please confirm order you placed when you was offline"
-"Please fix the validation errors","Please fix the validation errors"
-"Please select the field which You like to sort by","Please select the field which You like to sort by"
-"Please wait ...","Please wait ..."
-"Proceed to checkout","Proceed to checkout"
-"Processing order...","Processing order..."
-"Product has been added to the cart!","Product has been added to the cart!"
-"Product price is unknown, product cannot be added to the cart!","Product price is unknown, product cannot be added to the cart!"
-"Product quantity has been updated!","Product quantity has been updated!"
-"Product {productName} has been added to the compare!","Product {productName} has been added to the compare!"
-"Product {productName} has been added to wishlist!","Product {productName} has been added to wishlist!"
-"Product {productName} has been removed from compare!","Product {productName} has been removed from compare!"
-"Product {productName} has been removed from wishlist!","Product {productName} has been removed from wishlist!"
-"Quantity available offline","Quantity (offline mode)"
-"Quantity available","Quantity ({qty} available)"
-"Quantity must be above 0","Quantity must be above 0"
-"Quantity must be below {quantity}","Quantity must be below {quantity}"
-"Quantity must be positive integer","Quantity must be positive integer"
-"Registering the account ...","Registering the account ..."
-"Reset password feature does not work while offline!","Reset password feature does not work while offline!"
-"Review","Review"
-"Reviews","Reviews"
-"Select 0","Select 0"
-"Select 1","Select 1"
-"Shopping cart is empty. Please add some products before entering Checkout","Shopping cart is empty. Please add some products before entering Checkout"
-"Some of the ordered products are not available!","Some of the ordered products are not available!"
-"Stock check in progress, please wait while available stock quantities are checked","Stock check in progress, please wait while available stock quantities are checked"
-"Subtotal incl. tax","Subtotal incl. tax"
-"Summary","Summary"
-"The product is out of stock and cannot be added to the cart!","The product is out of stock and cannot be added to the cart!"
-"The product, category or CMS page is not available in Offline mode. Redirecting to Home.","The product, category or CMS page is not available in Offline mode. Redirecting to Home."
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not avaiable because we cannot check it right now."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","Type what you are looking for..."
-"Unexpected authorization error. Check your Network conection.","Unexpected authorization error. Check your Network conection."
-"Unhandled error, wrong response format!","Unhandled error, wrong response format!"
-"Vue Storefront", "Vue Storefront"
-"You are going to pay for this order upon delivery.","You are going to pay for this order upon delivery."
-"You are logged in!","You are logged in!"
-"You are to pay for this order upon delivery.","You are to pay for this order upon delivery."
-"You need to be logged in to see this page","You need to be logged in to see this page"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","You're logged out"
-"email","email"
-"have as many","have as many"
-"login","login"
-"most you may purchase","most you may purchase"
-"not authorized","not authorized"
-"password","password"
-"to account","to account"
diff --git a/core/i18n/resource/i18n/es-ES.csv b/core/i18n/resource/i18n/es-ES.csv
deleted file mode 100644
index 0563763dc1..0000000000
--- a/core/i18n/resource/i18n/es-ES.csv
+++ /dev/null
@@ -1,44 +0,0 @@
-" is out of stock!"," está agotado!"
-"404 Page Not Found","404 Pagina no encontrada"
-"Account data has successfully been updated","Los datos de la cuenta se han actualizado con éxito"
-"Adding a review ...","Adding a review ..."
-"Are you sure you would like to remove this item from the shopping cart?","¿Está seguro de que desea eliminar este artículo de la cesta de la compra?"
-"Checkout","Pagar"
-"Compare Products","Comparar productos"
-"Error with response - bad content-type!","Error con la respuesta - ¡tipo de contenido incorrecto!"
-"Field is required","El campo es requerido"
-"Field is required.","El campo es requerido."
-"Grand total","Gran total"
-"Home Page","Página de inicio"
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Error de validación interna. Por favor, compruebe si se completan todos los campos obligatorios. Póngase en contacto con nosotros en {email}"
-"My Account","Mi Cuenta"
-"Newsletter preferences have successfully been updated","Las preferencias del boletín se han actualizado con éxito"
-"No products synchronized for this category. Please come back while online!","No hay productos sincronizados para esta categoría. Por favor regrese mientras esta en linea!"
-"No such configuration for the product. Please do choose another combination of attributes.","No hay tal configuración para el producto. Por favor, elija otra combinación de atributos."
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","¡Agotado!"
-"Please fix the validation errors","Corrija los errores de validación"
-"Product has been added to the cart!","¡El producto ha sido agregado al carrito!"
-"Product price is unknown, product cannot be added to the cart!","El precio del producto es desconocido, ¡el producto no se puede agregar al carrito!"
-"Product quantity has been updated!","¡La cantidad del producto ha sido actualizada!"
-"Product {productName} has been added to the compare!","¡El producto {productName} se ha agregado a la comparación!"
-"Product {productName} has been added to wishlist!","¡El producto {productName} ha sido agregado a la lista de deseos!"
-"Product {productName} has been removed from compare!","¡El producto {productName} ha sido eliminado de la comparación!"
-"Product {productName} has been removed from wishlist!","¡El producto {productName} ha sido eliminado de la lista de deseos!"
-"Registering the account ...","Registrando la cuenta ..."
-"Reset password feature does not work while offline!","¡La función Restablecer contraseña no funciona sin conexión!"
-"Shopping cart is empty. Please add some products before entering Checkout","El Carro de Compras está Vacío. Por favor agregue algunos productos antes de ingresar al Checkout"
-"Some of the ordered products are not available!","¡Algunos de los productos pedidos no están disponibles!"
-"Stock check in progress, please wait while available stock quantities are checked","Verificación de stock en curso, espere mientras se verifican las cantidades de stock disponibles"
-"Subtotal incl. tax","Subtotal incl. impuesto"
-"The product is out of stock and cannot be added to the cart!","¡El producto no está disponible y no se puede agregar al carrito!"
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","El sistema no está seguro acerca de la cantidad de stock (volátil). El producto ha sido agregado al carrito para pre-reserva."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not avaiable because we cannot check it right now.","No hay conexión a internet. Todavía puedes hacer tu pedido. Le notificaremos si alguno de los productos solicitados no están disponible porque no podemos verificarlo ahora mismo."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","¡Esta característica aún no está implementada! ¡Por favor, eche un vistazo a https://github.com/vuestorefront/vue-storefront/issues para nuestra Hoja de ruta!"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","Escribe lo que estás buscando..."
-"Unhandled error, wrong response format!","¡Error no controlado, formato de respuesta incorrecto!"
-"You are logged in!","¡Has iniciado sesión!"
-"You need to be logged in to see this page","Necesitas iniciar sesión para ver esta página"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Estás desconectado"
diff --git a/core/i18n/resource/i18n/et-EE.csv b/core/i18n/resource/i18n/et-EE.csv
deleted file mode 100644
index a8500b1552..0000000000
--- a/core/i18n/resource/i18n/et-EE.csv
+++ /dev/null
@@ -1,90 +0,0 @@
-" is out of stock!","ei ole laos!"
-"404 Page Not Found","404 Lehekülge ei leitud"
-"Account data has successfully been updated","Konto andmed uuendatud"
-"Add review","Lisa kommentaar"
-"Adding a review ...","Lisan kommentaari ..."
-"Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled.","Ostuvormistamisel sisestatud aadress sisaldab vigu! Palun kontrolli, et kõik kohustuslikud väljad oleksid täidetud või kirjuta meile {email}."
-"Allow notification about the order","Luba tellimusge seotud teadete edastamine"
-"Are you sure you would like to remove this item from the shopping cart?","Olete kindel, et soovite antud toote ostukorvist eemaldada?"
-"Compare Products","Võrdle tooteid"
-"Compare products","Võrdle tooteid"
-"Confirm your order","Kinnitage oma tellimus"
-"Error refreshing user token. User is not authorized to access the resource","Kasutaja tokeni uuendamisel esineb probleeme. Kasutajal puuduvad õigused antud lehele sisenemiseks"
-"Error with response - bad content-type!","Viga sisu laadimisel"
-"Error: Error while adding products","Viga toote lisamisel."
-"Extension developers would like to thank you for placing an order!","Mooduli loojad tänavad tellimuse tegemise eest!"
-"Field is required",Kohustuslik
-"Field is required.",Kohustuslik.
-"Grand total",Kokku
-"Home Page",Esileht
-"In stock!",Laos
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Tokeni värskendamisel esines viga. Palun tühjendage vahemälu ja uuendage lehekülge."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Viga! Palun kontrolli, et kõik kohustuslikud väljad oleksid täidetud või kirjuta meile {email}."
-"Must be greater than 0","Peab olema suurem, kui 0"
-"My Account","Minu konto"
-"Newsletter preferences have successfully been updated","Uudiskirjaga liitumine uuendatud"
-"No available product variants","Toote valikvariandid puuduvad"
-"No products synchronized for this category. Please come back while online!","Kategooria on tühi."
-"No such configuration for the product. Please do choose another combination of attributes.","Sellise kombinatsiooniga toodet ei saa tellida."
-"Only {maxQuantity} products of this type are available!","Ainult {maxQuantity} seda tüüpi toodet on saadaval!"
-"Or if you will stay on ""Order confirmation"" page, the order will be placed automatically without confirmation, once the internet connection will be back.","Või kui sa jäää ""Tellimuse kinnitus"" lehele, tellimus esitatakse internetiühenduse taastudes tellimus automaatselt."
-"Out of stock!","Laost otsas!"
-"Out of the stock!","Laost otsas"
-"Payment Information","Makse informatsioon"
-"Please configure product bundle options and fix the validation errors","Toode on valikutega. Palun valige sobivad valikud"
-"Please configure product custom options and fix the validation errors","Palun valige sobiv toode"
-"Please confirm order you placed when you was offline","Palun kinnitage oma tellimuse, mille ilma interneti ühenduseta varasemalt tegite"
-"Please fix the validation errors","Palun parandage valideerimise vead"
-"Please select the field which You like to sort by","Palun valige sorteerimise viis"
-"Please wait ...","Palun oota ..."
-"Proceed to checkout","Vormista ost"
-"Processing order...","Tellimuse loomine ..."
-"Product has been added to the cart!","Toode lisati ostukorvi."
-"Product price is unknown, product cannot be added to the cart!","Tootel puudub hind. Toodet ei saa ostukorvi lisada."
-"Product quantity has been updated!","Toote laoseis on uuendatud."
-"Product {productName} has been added to the compare!","{productName} lisati võrdlusesse."
-"Product {productName} has been added to wishlist!","{productName} Lisati soovikorvi."
-"Product {productName} has been removed from compare!","{productName} võrdlusest eemaldatud."
-"Product {productName} has been removed from wishlist!","{productName} on sooviloendist eemaldatud."
-"Quantity available offline","Kogus on saadaval internetiühenduseta"
-"Quantity available","Kogus on saadaval"
-"Quantity must be above 0","Laokogus peab olema suurem, kui 0"
-"Quantity must be below {quantity}","Laokogus peab olema alla {quantity}"
-"Quantity must be positive integer","Laokogus peab olema positiivne täisarv"
-"Registering the account ...","Konto loomine..."
-"Reset password feature does not work while offline!","Parooli ei saa kahjuks ilma interneti ühenduseta muuta."
-"Select 0","Vali 0"
-"Select 1","Vali 1"
-"Shopping cart is empty. Please add some products before entering Checkout","Otsukorv on tühi."
-"Some of the ordered products are not available!","Mõned tellitud tooted ei ole kahjuks enam saadaval."
-"Stock check in progress, please wait while available stock quantities are checked","Palun oota, kontrollime laoseise."
-"Subtotal incl. tax","Kokku (sisaldab käibemaksu)"
-"The product is out of stock and cannot be added to the cart!","Toode on kahjuks laost otsa saanud."
-"The product, category or CMS page is not available in Offline mode. Redirecting to Home.","Antud toode, kategooria või sisuleht ei ole kahjuks ilma internetiühenduseta saadaval. Suuname ümber esilehele."
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","Antud toodet ostetakse väga palju ja me ei ole laoseisu osas kindlad. Toode on ostukorvi lisatud ja Teie jaoks broneeritud."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Interneti ühendus puudub. Saad sellegi poolest tellimuse luua. Kontrollime interneti ühenduse taastudes tellitud toodete laoseisu üle. Anname märku, kui mõni tellitud toodetest vahepeal otsa on saanud. "
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Sellist funktsionaalsust ei ole veel lisatud. Saad meie arendusplaanidega tutvuda https://github.com/vuestorefront/vue-storefront/issues."
-"Type what you are looking for...","Otsi ..."
-"Unexpected authorization error. Check your Network conection.","Internetiühenduse viga. Palun kontrollige oma internetiühendust."
-"Unhandled error, wrong response format!","Vale päringu formaat"
-"Vue Storefront","Vue Storefront"
-"You are going to pay for this order upon delivery.","Maksmine toimub tellimuse kättesaamisel."
-"You are logged in!","Olete sisse logitud."
-"You are to pay for this order upon delivery.","Saate makse teostada tellimuse kätte saamisel."
-"You need to be logged in to see this page","Palun logige lehe nägemisesse sisse"
-"You submitted your review for moderation.","Tagasiside on edastatud üle vaatamiseks."
-"You're logged out","Olete välja logitud"
-"have as many","osta kuni"
-"most you may purchase","maksimum ostu kogus"
-"not authorized","Ligipääs puudub"
-"to account",kontole
-Checkout,Ostuvormistamine
-Columns,Tulbad
-OK,Ok
-Review,Kommentaar
-Reviews,Kommentaarid
-Summary,Kokkuvõte
-Thumbnail,Pisipilt
-email,E-post
-login,"logi sisse"
-password,Parool
diff --git a/core/i18n/resource/i18n/fi-FI.csv b/core/i18n/resource/i18n/fi-FI.csv
deleted file mode 100644
index ebc7bd3a22..0000000000
--- a/core/i18n/resource/i18n/fi-FI.csv
+++ /dev/null
@@ -1,90 +0,0 @@
-" is out of stock!"," on loppu varastosta"
-"404 Page Not Found","404 Sivua ei löydy"
-"Account data has successfully been updated","Tilin tiedot on päivitetty"
-"Add review","Lisää arvostelu"
-"Adding a review ...","Lisätään arvostelua…"
-"Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled.","Kassalla annettu osoite on virheellinen. Tarkista, että kaikki pakolliset kentät on täytetty. Tilauksesi on peruttu. Ongelman jatkuessa ota yhteyttä sähköpostilla osoitteeseen {email}."
-"Allow notification about the order","Salli ilmoitus tilauksesta"
-"Are you sure you would like to remove this item from the shopping cart?","Haluatko varmasti poistaa tuotteen ostoskorista?"
-"Compare Products","Vertaile tuotteita"
-"Compare products","Vertaile tuotteita"
-"Confirm your order","Vahvista tilaus"
-"Error refreshing user token. User is not authorized to access the resource","Käyttöoikeus puuttuu."
-"Error with response - bad content-type!","Virhe sivun latauksessa - väärä sisältötyyppi."
-"Error: Error while adding products","Virhe tuotteiden lisäyksessä."
-"Extension developers would like to thank you for placing an order!","Laajennuksen kehittäjät kiittävät tilauksesta!"
-"Field is required","Vaadittu tieto"
-"Field is required.","Vaadittu tieto"
-"Grand total",Yhteensä
-"Home Page",Etusivu
-"In stock!",Varastossa
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Virhe käyttöoikeuksien tarkistuksessa. Tyhjennä selaimen muisti ja lataa sivu uudelleen."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Tarkista, että kaikki pakolliset kentät on täytetty. Ongelman jatkuessa ota yhteyttä sähköpostilla osoitteeseen {email}."
-"Must be greater than 0","Oltava suurempi kuin 0"
-"My Account","Oma tili"
-"Newsletter preferences have successfully been updated","Uutiskirjeen asetukset on päivitetty"
-"No available product variants","Tuotevaihtoehtoja ei ole saatavilla."
-"No products synchronized for this category. Please come back while online!","Kategoriassa ei ole tuotteita. Yritä uudelleen, kun verkkoyhteys on palautunut."
-"No such configuration for the product. Please do choose another combination of attributes.","Valintaa vastaavaa tuotetta ei löydy."
-"Only {maxQuantity} products of this type are available!","Vain {maxQuantity} saatavilla"
-"Or if you will stay on ""Order confirmation"" page, the order will be placed automatically without confirmation, once the internet connection will be back.","Tai, jos pysyt tilausvahvistussivulla, tilaus tehdään automaattisesti ilman vahvistusta yhteyden palautuessa."
-"Out of stock!","Loppu varastosta"
-"Out of the stock!","Loppu varastosta"
-"Payment Information","Maksun tiedot"
-"Please configure product bundle options and fix the validation errors","Tee valinnat"
-"Please configure product custom options and fix the validation errors","Tee valinnat"
-"Please confirm order you placed when you was offline","Vahvista yhteydettömässä tilassa tekemäsi tilaus"
-"Please fix the validation errors","Korjaa virheelliset tiedot."
-"Please select the field which You like to sort by","Valitse tieto, jonka mukaan haluat järjestää"
-"Please wait ...","Odota hetki ..."
-"Proceed to checkout",Kassalle
-"Processing order...","Käsitellään tilausta..."
-"Product has been added to the cart!","Tuote on lisätty ostoskoriin."
-"Product price is unknown, product cannot be added to the cart!","Tuotteen hinta ei ole saatavilla ja sitä ei voida lisätä ostoskoriin."
-"Product quantity has been updated!","Tuotteen varastosaldo on päivitetty."
-"Product {productName} has been added to the compare!","{productName} on lisätty tuotevertailuun."
-"Product {productName} has been added to wishlist!","{productName} on lisätty toivelistaan."
-"Product {productName} has been removed from compare!","{productName} on poistettu tuotevertailusta."
-"Product {productName} has been removed from wishlist!","{productName} on poistettu toivelistasta"
-"Quantity available offline","Määrä saatavilla yhteydettömässä tilassa"
-"Quantity available","Määrä saatavilla"
-"Quantity must be above 0","Määrän pitää olla suurempi kuin 0"
-"Quantity must be below {quantity}","Määrän pitää olla alle {quantity}"
-"Quantity must be positive integer","Määrän pitää olla kokonaisluku"
-"Registering the account ...","Luodaan tiliä ..."
-"Reset password feature does not work while offline!","Salasanan uusiminen ei ole käytössä yhteydettömässä tilassa."
-"Select 0","Valitse 0"
-"Select 1","Valitse 1"
-"Shopping cart is empty. Please add some products before entering Checkout","Ostoskori on tyhjä. Lisää tuotteita ennen kuin siirryt kassalle."
-"Some of the ordered products are not available!","Jotkut tilatuista tuotteista eivät ole saatavilla."
-"Stock check in progress, please wait while available stock quantities are checked","Odota hetki, varastosaldoja tarkistetaan"
-"Subtotal incl. tax","Välisumma (sis. ALV)"
-"The product is out of stock and cannot be added to the cart!","Tuotetta ei ole varastossa."
-"The product, category or CMS page is not available in Offline mode. Redirecting to Home.","Sivu ei ole saatavilla yhteydettömässä tilassa. Ohjataan etusivulle."
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","Tuotteen saatavuus on epävarma. Tuote on lisätty ostoskoriin ennakkovarauksena."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Verkkoyhteys ei ole saatavilla. Voit silti tehdä tilauksen. Saat myöhemmin ilmoituksen, mikäli jokin tilaamistasi tuotteista ei ole saatavilla."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Tätä ominaisuutta ei ole vielä toteutettu. Järjestelmän kehityssuunnitelma löytyy osoitteesta https://github.com/vuestorefront/vue-storefront/issues."
-"Type what you are looking for...",Hae
-"Unexpected authorization error. Check your Network conection.","Odottamaton virhe oikeuksien tarkistamisessa. Tarkista verkkoyhteys."
-"Unhandled error, wrong response format!","Odottamaton virhe, väärä vastauksen formaatti."
-"Vue Storefront","Vue Storefront"
-"You are going to pay for this order upon delivery.","Maksat tilauksen toimituksen yhteydessä"
-"You are logged in!","Olet kirjautuneena."
-"You are to pay for this order upon delivery.","Maksu peritään toimituksen yhteydessä"
-"You need to be logged in to see this page","Kirjaudu sisään nähdäksesi tämän sivun."
-"You submitted your review for moderation.","Arvostelu on lähetetty tarkastettavaksi"
-"You're logged out","Et ole kirjautuneena"
-"have as many","määrä on"
-"most you may purchase",Maksimitilausmäärä
-"not authorized","ei sallittu"
-"to account",tilille
-Checkout,Kassa
-Columns,Sarakkeet
-OK,Ok
-Review,Arvostelu
-Reviews,Arvostelut
-Summary,Tiivistelmä
-Thumbnail,Pienoiskuva
-email,sähköposti
-login,"kirjaudu sisään"
-password,salasana
diff --git a/core/i18n/resource/i18n/fr-FR.csv b/core/i18n/resource/i18n/fr-FR.csv
deleted file mode 100644
index 6e3b1eb403..0000000000
--- a/core/i18n/resource/i18n/fr-FR.csv
+++ /dev/null
@@ -1,54 +0,0 @@
-" is out of stock!"," n'est pas en stock !"
-"404 Page Not Found","404 Page non trouvée"
-"Account data has successfully been updated","Votre compte a été mis à jour avec succès"
-"Adding a review ...","Adding a review ..."
-"Are you sure you would like to remove this item from the shopping cart?","Etes-vous sûr de vouloir supprimer cet objet de votre panier ?"
-"Checkout","Valider"
-"Compare Products","Comparer les produits"
-"Error refreshing user token. User is not authorized to access the resource","Une erreur est survenue. L'utilisateur n'est pas autorisé à accéder à cette ressource"
-"Error with response - bad content-type!","Erreur avec réponse - mauvais type de contenu !"
-"Field is required","Champ requis"
-"Field is required.","Champ requis."
-"Grand total","Total"
-"Home Page","Page d'accueil"
-"In stock!","En stock !"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Une erreur interne est survenue. Veuillez nettoyer le stockage du site et rafraîchir la page."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Erreur de validation interne Veuillez vérifier si tous les champs requis sont remplis. Veuillez nous contacter sur {email}"
-"Must be greater than 0","Doit être supérieur à 0"
-"My Account","Mon compte"
-"Newsletter preferences have successfully been updated","Les préférences de la newsletter ont été mises à jour avec succès"
-"No products synchronized for this category. Please come back while online!","Aucun produit synchronisé dans cette catégorie. Merci de passer en ligne !"
-"No such configuration for the product. Please do choose another combination of attributes.","Aucune configuration de ce type pour le produit. Veuillez choisir une autre combinaison d'attributs."
-"OK","OK"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","Rupture de stock !"
-"Out of the stock!","Épuisé !"
-"Please configure product custom options and fix the validation errors","Veuillez configurer les options du produit et corriger les erreurs de validation"
-"Please fix the validation errors","Veuillez corriger les erreurs de validation"
-"Proceed to checkout","Passer la commande"
-"Product has been added to the cart!","Le produit a été ajouté au panier !"
-"Product price is unknown, product cannot be added to the cart!","Le prix du produit est inconnu, le produit ne peut pas être ajouté au panier !"
-"Product quantity has been updated!","La quantité de produit a été mise à jour!"
-"Product {productName} has been added to the compare!","Le produit {productName} a été ajouté au comparateur !"
-"Product {productName} has been added to wishlist!","Le produit {productName} a été ajouté à la liste des souhaits !"
-"Product {productName} has been removed from compare!","Le produit {productName} a été supprimé du comparateur !"
-"Product {productName} has been removed from wishlist!","Le produit {productName} a été supprimé de la liste des souhaits !"
-"Registering the account ...","Enregistrement du compte..."
-"Reset password feature does not work while offline!","La fonction de réinitialisation du mot de passe ne fonctionne pas en mode hors ligne !"
-"Shopping cart is empty. Please add some products before entering Checkout","Le panier d'achat est vide. Veuillez ajouter des produits avant de passer à la caisse"
-"Some of the ordered products are not available!","Certains des produits commandés ne sont pas disponibles !"
-"Stock check in progress, please wait while available stock quantities are checked","Vérification du stock en cours, veuillez patienter pendant que les stocks disponibles sont vérifiés"
-"Subtotal incl. tax","Sous-total taxes incluses"
-"The product is out of stock and cannot be added to the cart!","Le produit est en rupture de stock et ne peut être ajouté au panier !"
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","Le système n'est pas sûr de la quantité de stock (volatile). Le produit a été ajouté au panier pour la pré-réservation."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Il n'y a pas de connexion Internet. Vous pouvez toujours passer votre commande. Nous vous informerons si l'un des produits commandés n'est pas disponible car nous ne pouvons pas le vérifier en mode hors ligne."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Cette fonctionnalité n'est pas encore implémentée! Veuillez vous rendre sur https://github.com/vuestorefront/vue-storefront/issues pour consulter notre Roadmap!"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","Saisissez votre recherche ..."
-"Unhandled error, wrong response format!","Erreur non prise en charge, format de réponse incorrect !"
-"View all","Voir tout"
-"You are logged in!","Vous êtes authentifié !"
-"You need to be logged in to see this page","Vous devez être connecté pour voir cette page"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Vous êtes déconnecté"
-"not authorized","pas autorisé"
diff --git a/core/i18n/resource/i18n/it-IT.csv b/core/i18n/resource/i18n/it-IT.csv
deleted file mode 100644
index 7876995403..0000000000
--- a/core/i18n/resource/i18n/it-IT.csv
+++ /dev/null
@@ -1,89 +0,0 @@
-" is out of stock!"," non è disponibile!"
-"404 Page Not Found","404 Pagina non trovata"
-"Account data has successfully been updated","Le tue informazioni sono state aggiornate con successo"
-"Add review","Aggiungi una recensione"
-"Adding a review ...","Adding a review ..."
-"Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled.","L'indirizzo fornito nel checkout contiene dati non validi. Per favore controlla di averi riempito tutti i campi obbligatori e contattaci all'indirizzo email {email} per risolvere questo problema in futuro. Il tuo ordine è stato cancellato."
-"Allow notification about the order","Consenti notifiche sull'ordine"
-"Are you sure you would like to remove this item from the shopping cart?","Sei sicuro di voler rimuovere questo articolo dal carrello?"
-"Checkout","Cassa"
-"Columns","Colonne"
-"Compare Products","Confronta prodotti"
-"Compare products","Confronta prodotti"
-"Confirm your order","Conferma il tuo ordine"
-"Error refreshing user token. User is not authorized to access the resource","Errore durante l'aggiornamento del token. L'utente non è autorizzato ad accedere alla risorsa"
-"Error with response - bad content-type!","Errore nella risposta - content-type non valido!"
-"Error: Error while adding products","Errore: c'è stato un errore durante l'aggiunta dei prodotti"
-"Extension developers would like to thank you for placing an order!","Gli sviluppatori dell'estensione vorrebbero ringraziarti per aver fatto un ordine!"
-"Field is required","Campo obbligatorio"
-"Field is required.","Campo obbligatorio"
-"Grand total","Totale"
-"Home Page","Home"
-"In stock!","Disponibile"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Errore interno dell'applicazione durante l'aggiornamento dei token. Per favore svuota lo storage e ricarica la pagina."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Errore di validazione interno. Se tutti i campi sono stati compilati contattare {email}"
-"Must be greater than 0","Deve essere maggiore di 0"
-"My Account","Il mio account"
-"Newsletter preferences have successfully been updated","Le tue preferenze sulla newsletter sono state aggiornate con successo"
-"No available product variants","Non ci sono varianti disponibili"
-"No products synchronized for this category. Please come back while online!","Nessun prodotto in questa categoria. Verifica la connessione di rete e riprova!"
-"No such configuration for the product. Please do choose another combination of attributes.","Configurazione del prodotto inesistente. Scegli un'altra combinazione di attributi"
-"OK","OK"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Or if you will stay on ""Order confirmation"" page, the order will be placed automatically without confirmation, once the internet connection will be back.","Oppure se rimarrai nella pagina di ""Conferma ordine"", l'ordine verrà automaticamente evaso senza conferma, una volta che la connessione sarà ripristinata."
-"Out of stock!","Non disponibile"
-"Out of the stock!","Non disponibile"
-"Payment Information","Informazioni di pagamento"
-"Please configure product bundle options and fix the validation errors","Per favore completa la configurazione del prodotto bundle e verifica la validazione dei dati"
-"Please configure product custom options and fix the validation errors","Per favore configura le opzioni personabilizzate del prodotto e verifica di aver compilato correttamente tutti i campi"
-"Please confirm order you placed when you was offline","Per favore conferma l'ordine che hai fatto quando eri offline"
-"Please fix the validation errors","Verifica di aver compilato correttamente tutti i campi"
-"Please select the field which You like to sort by","Scegli il campo con cui vuoi ordinare"
-"Please wait ...","Attendere..."
-"Proceed to checkout","Vai alla cassa"
-"Processing order...","Ordine in corso..."
-"Product has been added to the cart!","Il prodotto è stato aggiunto al carrello!"
-"Product price is unknown, product cannot be added to the cart!","Il prezzo di questo prodotto è sconosciuto, non è possibile aggiungerlo al carrello!"
-"Product quantity has been updated!","La quantità è stata aggiornata!"
-"Product {productName} has been added to the compare!","Il prodotto {productName} è stato aggiunto al comparatore!"
-"Product {productName} has been added to wishlist!","Il prodotto {productName} è stato aggiunto alla lista dei desideri!"
-"Product {productName} has been removed from compare!","Il prodotto {productName} è stato rimosso dal comparatore"
-"Product {productName} has been removed from wishlist!","Il prodotto {productName} è stato rimosso dalla lista dei desideri"
-"Quantity available","Quantità ({qty} disponibile)"
-"Quantity must be above 0","La quantità deve essere superiore a 0"
-"Quantity must be below {quantity}","La quantità deve essere inferiore a {quantity}"
-"Quantity must be positive integer","La quantità deve essere un numero positivo"
-"Registering the account ...","Creazione dell'account..."
-"Reset password feature does not work while offline!","Non puoi reimpostare la password quando non sei in linea!"
-"Review","Recensione"
-"Reviews","Recensioni"
-"Select 0","Select 0"
-"Select 1","Select 1"
-"Shopping cart is empty. Please add some products before entering Checkout","Il tuo carrello è vuoto. Aggiungi almeno un prodotto prima di procedere alla cassa"
-"Some of the ordered products are not available!","Alcuni dei prodotti ordinati non sono disponibili!"
-"Stock check in progress, please wait while available stock quantities are checked","Verifica disponibilità in corso, attendere la verifica della quantità dei prodotti"
-"Subtotal incl. tax","Subtotale tasse incluse"
-"Summary","Riassunto"
-"The product is out of stock and cannot be added to the cart!","Il prodotto non è più disponibile e non può essere aggiunto al carrello"
-"The product, category or CMS page is not available in Offline mode. Redirecting to Home.","The product, category or CMS page is not available in Offline mode. Redirecting to Home."
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","Il sistema non è sicuro della disponibilità del prodotto (volatile). Il prodotto è stato aggiunto al carrello per prenotazione"
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Non sei connesso ad internet ma puoi ugualmente procedere con l'ordine. Non è possibile verificare adesso la disponibilità dei prodotti, se qualcuno dei prodotti ordinati non sarà più disponibile te lo faremo sapere."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Questa funzionalità non è ancora stata implementata! Dai un'occhiata alla nostra roadmap qui https://github.com/vuestorefront/vue-storefront/issues!"
-"Thumbnail","Miniatura"
-"Type what you are looking for...","Cerca nel catalogo..."
-"Unexpected authorization error. Check your Network conection.","Errore di autorizzazione inaspettato. Verifica la tua connesione."
-"Unhandled error, wrong response format!","Errore inatteso, formato della risposta non valido!"
-"Vue Storefront", "Vue Storefront"
-"You are going to pay for this order upon delivery.","Pagherai questo ordine alla consegna."
-"You are logged in!","Accesso eseguito!"
-"You are to pay for this order upon delivery.","Pagherai questo ordine alla consegna."
-"You need to be logged in to see this page","Devi essere loggato per vedere questa pagina"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Ti sei disconnesso"
-"email","email"
-"have as many","have as many"
-"login","accedi"
-"most you may purchase","most you may purchase"
-"not authorized","non autorizzato"
-"password","password"
-"to account","al tuo account"
diff --git a/core/i18n/resource/i18n/ja-JP.csv b/core/i18n/resource/i18n/ja-JP.csv
deleted file mode 100644
index 122a317f8f..0000000000
--- a/core/i18n/resource/i18n/ja-JP.csv
+++ /dev/null
@@ -1,172 +0,0 @@
-" is out of stock!"," は在庫がありません!"
-"404 Page Not Found","404ページが見つかりません"
-"About us (Magento CMS)","弊社について(Magento CMS)"
-"Add a discount code","ディスカウントコードの追加"
-"Add discount code","ディスカウントコードの追加"
-"Add to cart","カートに追加"
-"Add to compare","比べるに追加"
-"Add to favorite","お気に入りに追加"
-"Adding a review ...","Adding a review ..."
-"Allow notification about the order","注文に関する通知を送る"
-"Are you sure you would like to remove this item from the shopping cart?","この商品をショッピングカートから削除してもいいですか?"
-"Author","作者"
-"Back to login","ログインに戻る"
-"Back","戻る"
-"Billing address","請求書先住所"
-"Change my password","パスワードを変更する"
-"Choose your country","国を選択"
-"City","市町村名"
-"Clear","クリア"
-"Cms Page Sync","CMSページと同期"
-"Compare Products","商品を比べる"
-"Compare products","商品を比べる"
-"Confirmation of receival","商品受け取りの確認"
-"Continue to payment","支払いへ進む"
-"Continue to shipping","買い物へ進む"
-"Copy address data from shipping","配送住所からコピー"
-"Create a new account","新しいアカウントの作成"
-"Current password *","現在のパスワード *"
-"Custom Cms Page","カスタムCMSページ"
-"Date and time","日時と時間"
-"Discount code","ディスカウントコード"
-"Discount","ディスカウント"
-"E-mail us at demo@vuestorefront.io with any questions, suggestions how we could improve products or shopping experience","質問や私達のサービスをさらに良くする改善提案のある方はdemo@vuestorefront.ioまでメールで連絡をお願いします。"
-"Edit newsletter preferences","ニュースレターの設定を編集"
-"Edit payment","支払いの編集"
-"Edit personal details","ユーザー情報の編集"
-"Edit shipping","配送先の編集"
-"Edit your profile","プロフィールの編集"
-"Edit your shipping details","配送情報の編集"
-"Edit","編集"
-"Email address *","メールアドレス *"
-"Enter your email to receive instructions on how to reset your password.","メールを読んでそこにあるパスワード再設定の指示に従ってください。"
-"Erin recommends","Erinのおすすめ"
-"Error while sending reset password e-mail","パスワード再設定のメールの送信でエラー"
-"Everything new","全ての新製品"
-"Filter","フィルター"
-"Filters","フィルター"
-"Forgot the password?","パスワードを忘れましたか?"
-"General agreement","一般的な合意"
-"Get inspired","インスピレーションをもらおう"
-"Give a feedback","フィードバックを送る"
-"Go review the order","注文のレビュー"
-"Go to checkout","支払いへ進む"
-"Grand total","総合計額"
-"House/Apartment number","部屋番号"
-"I accept ","以下に同意します "
-"I accept terms and conditions","以下の利用規約に同意します"
-"I agree to","以下に合意します"
-"I want to create an account","アカウント作成したい"
-"I want to generate an invoice for the company","この会社への請求書を作りたい"
-"I want to receive a newsletter, and agree to its terms","利用規約に合意してニュースレーターを受け取ります"
-"Internal Server Error 500","500サーバーエラー"
-"Load more","もっと見る"
-"Log in to your account","アカウントにログイン"
-"Log in","ログイン"
-"Magazine","マガジン"
-"New Luma Yoga Collection","新しいLumaのヨガコレクション"
-"New password *","新しいパスワード *"
-"Newsletter","ニュースレター"
-"No orders yet","まだ注文はありません"
-"No products yet","商品はありません"
-"No reviews have been posted yet. Please don\","まだレビューは投稿されていません。"
-"No such configuration for the product. Please do choose another combination of attributes.","この商品へのこの構成はありません。別の組み合わせを試してみてください。"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Open menu","メニューを開く"
-"Open microcart","マイクロカートを開く"
-"Open my account","アカウントを開く"
-"Open search panel","検索パネルを開く"
-"Open wishlist","欲しいものリストを開く"
-"Order ID","注文ID"
-"Order Summary","注文詳細"
-"Order informations","注文情報"
-"Out of stock!","在庫はありません!"
-"Password must have at least 8 letters.","パスワードは英数半角で8文字以上である必要があります。"
-"Payment","支払い"
-"Personal Details","ユーザーの詳細"
-"Place the order","注文する"
-"Please check if all data are correct","全てのデータが正しいかチェックしてください"
-"Please confirm order you placed when you was offline","オフライン中に注文した商品を確認してください"
-"Please select the field which You like to sort by","ソートしたい項目を選んでください"
-"Product quantity has been updated!","製品の数量が更新されました!"
-"Products","商品"
-"Purchase","購入"
-"Register an account","アカウントを登録"
-"Register","登録"
-"Remember me","ログインを覚える"
-"Remove from compare","比べるから外す"
-"Repeat new password *","新しいパスワード(もう一度) *"
-"Reset password feature does not work while offline!","オフラインの間ではパスワードの再設定はできません!"
-"Returns","返品"
-"Review order","注文のレビュー"
-"Review","レビュー"
-"Reviews","レビュー"
-"Safety","安全"
-"Sale","購入"
-"See details","詳細を見る"
-"See our bestsellers","ベストセラーを見る"
-"Select color ","色の選択 "
-"Ship to my default address","デフォルトの住所に配送する"
-"Shipping address","配送用住所"
-"Shopping cart is empty. Please add some products before entering Checkout","ショッピングカートが空です。支払いに進むには商品を追加してください。"
-"Shopping cart","ショッピングカート"
-"Shopping summary","お買い物詳細"
-"Show subcategories","サブカテゴリーを表示"
-"Sign up to our newsletter and receive a coupon for 10% off!","ニュースレターに登録をして、10%OFFクーポンを手に入れましょう!"
-"Similar products","似ている商品"
-"Some of the ordered products are not available!","注文された商品に在庫切れがあります!"
-"Sort By","ソート"
-"Status","ステータス"
-"Stock check in progress, please wait while available stock quantities are checked","在庫チェックをしています。もう少々おまちください。"
-"Street name","通りの名前"
-"Subscribe to the newsletter and receive a coupon for 10% off","ニュースレターに登録をして、10%OFFクーポンを手に入れましょう!"
-"Summary","詳細"
-"Tax ID *","税金ID *"
-"Tax ID must have at least 3 letters.","税金登録番号は3桁以上である必要があります。"
-"Tax identification number *","税金登録番号 *"
-"Tax identification number must have at least 3 letters.","税金登録番号は3桁以上である必要があります。"
-"Tax","税金"
-"The new account will be created with the purchase. You will receive details on e-mail.","この注文後新しいアカウントが作られます。メールで詳細が送られます。"
-"The product is out of stock and cannot be added to the cart!","この商品は在庫がなく、カートに追加することができません!"
-"The server order id has been set to ","サーバー注文IDが以下に設定されました "
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","現在インターネットへ接続されていません。注文をすることはできますが、在庫がない場合はインターネットに接続後お知らせを送ります。"
-"Thumbnail","Thumbnail"
-"To finish the order just come back to our store while online. Your order will be sent to the server as soon as you come back here while online and then confirmed regarding the stock quantities of selected items","注文を終了するにはオンラインになったて再度確認する必要があります。オンラインになったら注文がサーバーに送られて在庫チェックが行われます。"
-"Type your opinion","意見を入力"
-"Type","入力"
-"Update my preferences","設定を更新"
-"Update my profile","プロフィールを更新"
-"Update my shipping details","配送住所を更新"
-"Update","更新"
-"Use my billing data","請求データを使う"
-"Value","価格"
-"View all","全てを見る"
-"View order","注文を見る"
-"We found other products you might like","おすすめの商品がありました"
-"We use cookies to give you the best shopping experience.","ベストな買い物体験を提供する為にクッキーが使われています。"
-"We will send you details regarding the order","注文についての詳細を送ります"
-"We will send you the invoice to given e-mail address","頂いたメールアドレスに請求書を送ります"
-"Wishlist","お気に入りリスト"
-"You are offline","オフラインです"
-"You can also use","またこれらを使うことができます"
-"You can log to your account using e-mail and password defined earlier. On your account you can edit your profile data, check history of transactions, edit subscription to newsletter.","登録されたメールアドレスとパスワードを使ってログインできます。アカウント内ではプロフィールの編集注文の履歴の確認ニュースレターへの購読が行えます。"
-"You have been successfully subscribed to our newsletter!","ニュースレターへの購読が完了しました!"
-"You have no items to compare.","比べる商品がありません"
-"You have successfuly placed the order. You can check status of your order by using our delivery status feature. You will receive an order confirmation e-mail with details of your order and a link to track its progress.","注文が終わりました。注文の状態は注文ステータス機能から確認できます。注文の注文の状態を確認できるリンクの入った注文の詳細がメールで送られます。"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You will receive Push notification after coming back online. You can confirm the order by clicking on it","オンラインになるとプッシュ通知が送られ、そこから注文の確認ができます。"
-"Your Account","アカウント"
-"Your feedback is important for us. Let us know what we could improve.","あなたからのフィードバックは重要です。どこを改善できるか是非お伝えください。"
-"Your purchase","購入"
-"Your shopping cart is empty.","ショッピングカートは空です。"
-"Your wishlist is empty.","お気に入りリストは空です。"
-"Zip-code","郵便番号"
-"Zipcode","郵便番号"
-"a chat","チャット"
-"notification-progress-start","進捗お知らせ開始"
-"or write to us through","か私達に連絡してください"
-"or","か"
-"register an account","アカウントを登録"
-"return to log in","戻ってログイン"
-"search","検索"
-"to find product you were looking for.","探している商品を見つける。"
diff --git a/core/i18n/resource/i18n/nl-NL.csv b/core/i18n/resource/i18n/nl-NL.csv
deleted file mode 100644
index f0dcffca16..0000000000
--- a/core/i18n/resource/i18n/nl-NL.csv
+++ /dev/null
@@ -1,44 +0,0 @@
- is out of stock!, is niet op voorraad!
-"Adding a review ...","Review aan het aanmaken ..."
-"Are you sure you would like to remove this item from the shopping cart?","Weet u zeker dat u dit artikel uit uw winkelwagen wilt verwijderen?"
-"Only {maxQuantity} products of this type are available!","Er zijn {maxQuantity} producten van dit type op voorraad!"
-"Product price is unknown, product cannot be added to the cart!",Productprijs onbekend. Dit product kan niet worden toegevoegd aan de winkelwagen!
-"Product quantity has been updated!","Producthoeveelheid is aangepast!"
-"Shopping cart is empty. Please add some products before entering Checkout",Uw winkelwagen is leeg. Voeg producten toe voordat u gaat afrekenen
-"Stock check in progress, please wait while available stock quantities are checked","Voorraadcontrole bezig. Een moment geduld alstublieft, we checken op dit moment de voorraden"
-"Thumbnail","Thumbnail"
-"Unhandled error, wrong response format!","Unhandled error, wrong response format!"
-"You need to be logged in to see this page","U moet ingelogd zijn om deze pagina te bekijken"
-"You submitted your review for moderation.","You submitted your review for moderation."
-404 Page Not Found,404 Pagina niet gevonden
-Account data has successfully been updated,Account gegevens succesvol geüpdatet.
-Checkout,Afrekenen
-Compare Products,Producten vergelijken
-Error with response - bad content-type!,Error with response - bad content-type!
-Field is required,Veld is verplicht
-Field is required.,Velden zijn verplicht.
-Grand total,Eindtotaal
-Home Page,Homepage
-Internal validation error. Please check if all required fields are filled in. Please contact us on {email},Interne validatie fout. Check of alle verplichte velden ingevuld zijn. Neem contact met ons op via {email}.
-My Account,Mijn Account
-Newsletter preferences have successfully been updated,Uw nieuwsbrief voorkeur is gewijzigd.
-No products synchronized for this category. Please come back while online!,Er zijn geen producten gesynchroniseerd in deze categorie. Kom alstublieft terug terwijl u online bent.
-No such configuration for the product. Please do choose another combination of attributes.,De gekozen productconfiguratie bestaat niet. Kies een andere combinatie.
-Out of stock!,Niet op voorraad!
-Please fix the validation errors,Corrigeer de validatiefouten
-Product has been added to the cart!,Product is toegevoegd aan de winkelwagen!
-Product {productName} has been added to the compare!,Product {productName} is toegevoegd aan de vergelijking!
-Product {productName} has been added to wishlist!,Product {productName} is toegevoegd aan de verlanglijst!
-Product {productName} has been removed from compare!,Product {productName} is verwijderd van de vergelijking!
-Product {productName} has been removed from wishlist!,Product {productName} is verwijderd van de verlanglijst
-Registering the account ...,Account registreren ...
-Reset password feature does not work while offline!,De reset wachtwoordfunctie werkt niet terwijl u offline bent!
-Some of the ordered products are not available!,Niet alle bestelde producten zijn beschikbaar!
-Subtotal incl. tax,Subtotaal incl. BTW
-The product is out of stock and cannot be added to the cart!,Dit product is niet in voorraad en kan niet toegevoegd worden aan de winkelwagen!
-The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.,Het is niet duidelijk hoeveel producten er exact op voorraad zijn. Het product is toegevoegd aan de winkelwagen als reservering.
-There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.,"U heeft geen internetverbinding. U kunt nog steeds een bestelling plaatsen. We laten het weten als de door u bestelde producten niet op voorraad zijn, dit kunnen we momenteel niet controleren."
-This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!,"Helaas, deze feature is nog niet geimplementeerd. Kijk op https://github.com/vuestorefront/vue-storefront/issues om de roadmap te zien."
-Type what you are looking for...,Waar bent u naar op zoek?
-You are logged in!,U bent ingelogd!
-You're logged out,U bent uitgelogd
diff --git a/core/i18n/resource/i18n/pl-PL.csv b/core/i18n/resource/i18n/pl-PL.csv
deleted file mode 100644
index 35536855de..0000000000
--- a/core/i18n/resource/i18n/pl-PL.csv
+++ /dev/null
@@ -1,53 +0,0 @@
-" is out of stock!"," jest niedostępny!"
-"404 Page Not Found","404 Nie ma takiej strony"
-"Account data has successfully been updated","Twoje dane zostały zaktualizowane"
-"Adding a review ...","Adding a review ..."
-"Are you sure you would like to remove this item from the shopping cart?","Czy na pewno chcesz usunąć ten produkt z koszyka?"
-"Checkout","Płatność"
-"Compare Products","Porównaj produkty"
-"Error refreshing user token. User is not authorized to access the resource","Błąd odświeżania tokenu użytkownika. Użytkownik nie dostępu do zasobu"
-"Error with response - bad content-type!","Błąd odpowiedzi - bad content-type!"
-"Field is required","Pole jest wymagane"
-"Field is required.","Pole jest wymagane."
-"Grand total","Łączna suma"
-"Home Page","Strona główna"
-"In stock!","W magazynie!"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Błąd odświeżania tokenów. Proszę wyczyścić pamięć podręczną przeglądarki."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Błąd walidacji. Sprawdź czy wszystkie wymagane pola zostały wybrane. Proszę, skontaktuj się z nami na adres {email}"
-"Must be greater than 0","Musi być większa niż 0"
-"My Account","Moje konto"
-"Newsletter preferences have successfully been updated","Twoje ustawienia subskrypcji zostały zaktualizowane"
-"No products synchronized for this category. Please come back while online!","Brak produktów dla tej kategorii. Spróbuj ponownie po uzyskaniu dostępu do Internetu!"
-"No such configuration for the product. Please do choose another combination of attributes.","Wybrane opcje są niedostępne. Wybierz inne opcje."
-"OK","OK"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","Produkt niedostępny!"
-"Out of the stock!","Brak w magazynie!"
-"Please configure product custom options and fix the validation errors","Skonfiguruj opcje produktu i popraw będy walidacji"
-"Please fix the validation errors","Popraw błędy walidacji"
-"Proceed to checkout","Przejdź do kasy"
-"Product has been added to the cart!","Produkt został dodany do koszyka!"
-"Product price is unknown, product cannot be added to the cart!","Nie można dodać produktu do koszyka, nie można potwierdzić ceny produktu!"
-"Product quantity has been updated!","Ilość produktu została zaktualizowana!"
-"Product {productName} has been added to the compare!","Produkt {productName} został dodany do porównania!"
-"Product {productName} has been added to wishlist!","Produkt {productName} został dodany do listy życzeń!"
-"Product {productName} has been removed from compare!","Produkt {productName} został usunięty z porównania!"
-"Product {productName} has been removed from wishlist!","Produkt {productName} został usunięty z listy życzeń!"
-"Registering the account ...","Tworzenie konta ..."
-"Reset password feature does not work while offline!","Aby zresetowa hasło musisz posiadać połączenie z Internetem!"
-"Shopping cart is empty. Please add some products before entering Checkout","Koszyk jest pusty. Dodaj produkty."
-"Some of the ordered products are not available!","Niektóre z produktów są niedostępne!"
-"Stock check in progress, please wait while available stock quantities are checked","Trwa sprawdzanie dostępności produktów, proszę czekać"
-"Subtotal incl. tax","Kwota częściowa brutto"
-"The product is out of stock and cannot be added to the cart!","Produkt jest niedostępny!"
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Brak połączenia z Internetem. Możesz nadal złożyć zamówienie. Poinformujemy Cię jeśli któryś z produktów nie będzie dostępny."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Wybrana opcja jest niedostępna!"
-"Thumbnail","Miniaturka"
-"Type what you are looking for...","Znajdź..."
-"Unhandled error, wrong response format!","Nieobsługiwany błąd, nieprawidłowy format odpowiedzi!"
-"You are logged in!","Jesteś zalogowany!"
-"You need to be logged in to see this page","Musisz być zalogowany, aby zobaczyć tę stronę"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Jesteś wylogowany"
-"not authorized","nieautoryzowany"
diff --git a/core/i18n/resource/i18n/pt-BR.csv b/core/i18n/resource/i18n/pt-BR.csv
deleted file mode 100644
index 9f53b09c13..0000000000
--- a/core/i18n/resource/i18n/pt-BR.csv
+++ /dev/null
@@ -1,48 +0,0 @@
-" is out of stock!"," está sem estoque!"
-"404 Page Not Found","404 Página Não Encontrada"
-"Account data has successfully been updated","Dados da conta foram atualizados"
-"Adding a review ...","Adding a review ..."
-"Are you sure you would like to remove this item from the shopping cart?","Tem certeza de que deseja remover este item do carrinho de compras?"
-"Checkout","Finalizar Compra"
-"Compare Products","Comparar Produtos"
-"Error with response - bad content-type!","Erro na resposta do servidor - bad content-type!"
-"Field is required","Campo obrigatório"
-"Field is required.","Campo obrigatório."
-"Grand total","Total"
-"Home Page","Página Inicial"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Erro Interno da Aplicação ao atualizar os tokens. Por favor limpe o cache do seu navegador e atualize a página."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Erro interno de validação. Por favor verifique se todos os campos obrigatórios estão preenchidos. Por favor contate-nos em {email}"
-"My Account","Minha Conta"
-"Newsletter preferences have successfully been updated","Configurações de Newsletter foram atualizadas."
-"No products synchronized for this category. Please come back while online!","Nenhum produto sincronizado para essa categoria. Por favor volte quando estiver online!"
-"No such configuration for the product. Please do choose another combination of attributes.","Nenhuma configuração desse tipo disponível para o produto. Por favor selecione outra combinação de opções."
-"OK","OK"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","Sem estoque!"
-"Please fix the validation errors","Por favor corrija os erros de validação"
-"Proceed to checkout","Finalizar Compra"
-"Product has been added to the cart!","Produto foi adicionado ao carrinho!"
-"Product price is unknown, product cannot be added to the cart!","Preço do produto é desconhecido, produto não pode ser adicionado ao carrinho!"
-"Product quantity has been updated!","A quantidade do produto foi atualizada!"
-"Product {productName} has been added to the compare!","Produto {productName} foi adicionado para comparação!"
-"Product {productName} has been added to wishlist!","Produto {productName} foi adicionado à lista de desejos!"
-"Product {productName} has been removed from compare!","Produto {productName} foi removido da comparação!"
-"Product {productName} has been removed from wishlist!","Produto {productName} foi removido da lista de desejos!"
-"Registering the account ...","Salvando a conta ..."
-"Reset password feature does not work while offline!","Recuperação de Senha não funciona sem conexão de internet!"
-"Shopping cart is empty. Please add some products before entering Checkout","Carrinho está vazio. Por favor adicione produtos antes de Finalizar a Compra"
-"Some of the ordered products are not available!","Alguns dos produtos comprados não estão disponíveis!"
-"Stock check in progress, please wait while available stock quantities are checked","Estamos verificando o estoque, por favor aguarde até verificarmos a quantidade solicitada."
-"Subtotal incl. tax","Subtotal c/ imposto"
-"The product is out of stock and cannot be added to the cart!","Produto não possui estoque e não pode ser adicionado ao carrinho!"
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","O sistema não tem certeza sobre a quantidade em estoque (volátil). O produto foi adicionado ao carrinho em pré-reserva."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Sem conexão de Internet. Você ainda pode finalizar seu pedido. Assim que possível o notificaremos se os produtos solicitados não estiverem disponíveis."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Essa funcionalidade não foi implementada ainda! Por favor verifique nosso planejamento em https://github.com/vuestorefront/vue-storefront/issues"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","Digite o que você está buscando..."
-"Unhandled error, wrong response format!","Erro desconhecido, formato de retorno errado!"
-"You are logged in!","Você está conectado!"
-"You need to be logged in to see this page","Você precisa estar logado para ver esta página"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Você foi desconectado"
-"not authorized","não autorizado"
diff --git a/core/i18n/resource/i18n/pt-PT.csv b/core/i18n/resource/i18n/pt-PT.csv
deleted file mode 100644
index b9955e6ded..0000000000
--- a/core/i18n/resource/i18n/pt-PT.csv
+++ /dev/null
@@ -1,48 +0,0 @@
-" is out of stock!"," está em ruptura de stock!"
-"404 Page Not Found","404 Página Não Encontrada"
-"Account data has successfully been updated","Os dados da conta foram atualizados"
-"Adding a review ...","Adding a review ..."
-"Are you sure you would like to remove this item from the shopping cart?","Tem a certeza de que deseja remover este item do Cesto de Compras?"
-"Checkout","Finalizar Compra"
-"Compare Products","Comparar Produtos"
-"Error with response - bad content-type!","Erro na resposta do servidor - bad content-type!"
-"Field is required","Campo obrigatório"
-"Field is required.","Campo obrigatório."
-"Grand total","Total"
-"Home Page","Página Inicial"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","Erro Interno da Aplicação ao atualizar as tokens. Por favor limpe o cache do seu browser e recarregue a página."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on contributors@vuestorefront.io","Erro interno de validação. Por favor verifique se todos os campos obrigatórios estão preenchidos. Por favor contate-nos em contributors@vuestorefront.io"
-"My Account","A Minha Conta"
-"Newsletter preferences have successfully been updated","As suas preferências para a Newsletter foram atualizadas."
-"No products synchronized for this category. Please come back while online!","Nenhum produto sincronizado para esta categoria. Por favor volte qundo estiver online!"
-"No such configuration for the product. Please do choose another combination of attributes.","Esta configuração não é possível para este produto. Por favor selecione outra configuração de opções."
-"OK","OK"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","Ruptura de stock!"
-"Please fix the validation errors","Por favor corrija os erros de validação"
-"Proceed to checkout","Ir para Finalizar Compra"
-"Product has been added to the cart!","O produto foi adicionado ao Cesto de Compras!"
-"Product price is unknown, product cannot be added to the cart!","O preço do produto é desconhecido, o produto não pode ser adicionado ao Cesto de Compras!"
-"Product quantity has been updated!","A quantidade do produto foi atualizada!"
-"Product {productName} has been added to the compare!","Produto {productName} foi adicionado a Comparar Produtos!"
-"Product {productName} has been added to wishlist!","Produto {productName} foi adicionado à Lista de Desejos!"
-"Product {productName} has been removed from compare!","Produto {productName} foi removido de Comparar Produtos!"
-"Product {productName} has been removed from wishlist!","Produto {productName} foi removido da Lista de Desejos!"
-"Registering the account ...","A registar a conta ..."
-"Reset password feature does not work while offline!","A funcionalidade de Recuperação de Senha não funciona sem ligação à internet!"
-"Shopping cart is empty. Please add some products before entering Checkout","O Cesto de Compras está vazio. Por favor adicione alguns produtos antes de Finalizar Compra"
-"Some of the ordered products are not available!","Alguns dos produtos solicitados não estão disponíveis!"
-"Stock check in progress, please wait while available stock quantities are checked","Estamos a verificar o stock, por favor aguarde até que verifiquemos se a quantidade solicitada está disponível."
-"Subtotal incl. tax","Subtotal c/ imposto"
-"The product is out of stock and cannot be added to the cart!","O produto não se encontra em stock e não pode ser adicionado ao Cesto de Compras!"
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","O sistema não tem certeza sobre a quantidade em stock (volátil). O produto foi adicionado ao Cesto de Compras em pré-reserva."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Sem ligação à Internet. Mas pode finalizar o seu pedido. Assim que possível iremos notifica-lo caso algum dos produtos solicitados não estiverem disponíveis."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Esta funcionalidade ainda não foi implementada! Por favor consulte o nosso Rodmap em https://github.com/vuestorefront/vue-storefront/issues!"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","Escreva o que está procurando..."
-"Unhandled error, wrong response format!","Erro desconhecido, formato de resposta errado!"
-"You are logged in!","Você está com sessão inicializada!"
-"You need to be logged in to see this page","Precisa de iniciar sessão para ver esta página"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Você não está com sessão inicializada"
-"not authorized","não autorizado"
diff --git a/core/i18n/resource/i18n/ru-RU.csv b/core/i18n/resource/i18n/ru-RU.csv
deleted file mode 100644
index 9d9be6ccfa..0000000000
--- a/core/i18n/resource/i18n/ru-RU.csv
+++ /dev/null
@@ -1,44 +0,0 @@
-" is out of stock!"," нет в наличии!"
-"404 Page Not Found","404 Страница не найдена"
-"Account data has successfully been updated","Данные учетной записи успешно обновлены"
-"Adding a review ...","Adding a review ..."
-"Are you sure you would like to remove this item from the shopping cart?","Вы уверены, что хотите удалить этот товар из корзины?"
-"Checkout","Оформление заказа"
-"Compare Products","Сравнить товары"
-"Error with response - bad content-type!","Ошибка в ответе - плохой content-type!"
-"Field is required","Обязательное поле"
-"Field is required.","Обязательное поле."
-"Grand total","Общий итог"
-"Home Page","Главная страница"
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","Внутренняя валидационная ошибка. Пожалуйста проверьте заполненность всех обязательных полей. Пожалуйста свяжитесь с нами по {email}"
-"My Account","Личный кабинет"
-"Newsletter preferences have successfully been updated","Предпочтения по новостям успешно обновлены"
-"No products synchronized for this category. Please come back while online!","По данной категории товары не синхронизированы. Пожалуйста вернитесь когда будете онлайн!"
-"No such configuration for the product. Please do choose another combination of attributes.","У товара отсутствует данная конфигурация. Пожалуйста выберите другие значения атрибутов."
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","Нет в наличии!"
-"Please fix the validation errors","Пожалуйста исправьте валидационные ошибки"
-"Product has been added to the cart!","Товар добавлен в корзину!"
-"Product price is unknown, product cannot be added to the cart!","Цена товара неизвестна, товар нельзя добавить в корзину!"
-"Product quantity has been updated!","Количество товара обновлено!"
-"Product {productName} has been added to the compare!","Товар {productName} добавлен к странице сравнения!"
-"Product {productName} has been added to wishlist!","Товар {productName} добавлен к списку пожеланий!"
-"Product {productName} has been removed from compare!","Товар {productName} удален из страницы сравнения!"
-"Product {productName} has been removed from wishlist!","Товар {productName} удален из списка пожеланий!"
-"Registering the account ...","Создается учетная запись ..."
-"Reset password feature does not work while offline!","Возможность переустановки пароля не работает при отсутствующем соединении к интернету!"
-"Shopping cart is empty. Please add some products before entering Checkout","Корзина пустая. Пожалуйста добавьте товары перед оформлением заказа"
-"Some of the ordered products are not available!","Некоторые из заказанных товаров не доступны!"
-"Stock check in progress, please wait while available stock quantities are checked","Производится проверка товаров на наличие, пожалуйста дождитесь завершения процесса проверки доступного количества"
-"Subtotal incl. tax","Подитог вкл. налог"
-"The product is out of stock and cannot be added to the cart!","Товара нет в наличии и его нельзя добавить в корзину"
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","Система не может удостовериться в наличии необходимого количества (изменчиво). Товар добавлен в корзину для предварительного бронирования."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","Отсутствует соединение к интернету. Однако вы можете оформить заказ. Мы уведомим Вас об отсутствии какого-либо из заказанных товаров позднее, так как не можем проверить это в данный момент."
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","Данная возможность пока не реализована! Пожалуйста ознакомьтесь с нашей дорожной картой тут: https://github.com/vuestorefront/vue-storefront/issues"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","Введите то что Вы ищите..."
-"Unhandled error, wrong response format!","Необработанная ошибка, неверный формат ответа!"
-"You are logged in!","Вы авторизовались!"
-"You need to be logged in to see this page","Вы должны войти в систему, чтобы увидеть эту страницу"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","Вы вышли из учетной записи"
diff --git a/core/i18n/resource/i18n/zh-cn.csv b/core/i18n/resource/i18n/zh-cn.csv
deleted file mode 100644
index 69c51afb8a..0000000000
--- a/core/i18n/resource/i18n/zh-cn.csv
+++ /dev/null
@@ -1,73 +0,0 @@
-" is out of stock!"," 没有库存!"
-"404 Page Not Found","404 出错了,网页未找到。"
-"Account data has successfully been updated","帐户数据已更新成功"
-"Add review","添加评论"
-"Adding a review ...","Adding a review ..."
-"Allow notification about the order","允许订阅有关订单的通知"
-"Are you sure you would like to remove this item from the shopping cart?","您确定要从购物车中删除此商品吗?"
-"Checkout","注销"
-"Compare Products","商品比较"
-"Compare products","商品比较"
-"Confirm your order","确认订单"
-"Error refreshing user token. User is not authorized to access the resource","刷新用户令牌时出错。 用户无权访问该资源"
-"Error with response - bad content-type!","服务端响应错误 - 错误的 content-type!"
-"Extension developers would like to thank you for placing an order!","拓展开发市场人员感谢您下订单!"
-"Field is required","必填字段"
-"Grand total","合计"
-"Home Page","主页"
-"In stock!","库存充足!"
-"Internal Application error while refreshing the tokens. Please clear the storage and refresh page.","刷新令牌时出现内部应用程序错误。 请清除浏览器缓存,刷新页面重试."
-"Internal validation error. Please check if all required fields are filled in. Please contact us on {email}","内部验证错误。 请检查是否填写了所有必填字段。请通过 {email} 与我们联系"
-"Must be greater than 0","必须大于0"
-"My Account","我的账户"
-"Newsletter preferences have successfully been updated","时事通讯首选项已成功更新"
-"No available product variants","没有可用的产品"
-"No products synchronized for this category. Please come back while online!","没有为此类别的商品。 请等商品上线后再来看看!"
-"No such configuration for the product. Please do choose another combination of attributes.","没有这样的商品配置。 请选择其他属性组合."
-"OK","确定"
-"Only {maxQuantity} products of this type are available!","Only {maxQuantity} products of this type are available!"
-"Out of stock!","缺库存!"
-"Payment Information","付款信息"
-"Please configure product bundle options and fix the validation errors","请配置商品属性选项并修复验证错误"
-"Please configure product custom options and fix the validation errors","请配置产品自定义选项并修复验证错误"
-"Please confirm order you placed when you was offline","请确认您离线时的订单"
-"Please fix the validation errors","请修复验证错误"
-"Please select the field which You like to sort by","请选择您要排序的字段"
-"Proceed to checkout","去结算"
-"Processing order...","订单处理中..."
-"Product has been added to the cart!","已成功将商品加入购物车!"
-"Product price is unknown, product cannot be added to the cart!","商品价格未确定,无法添加到购物车!"
-"Product quantity has been updated!","產品數量已更新!"
-"Product {productName} has been added to the compare!","商品 {productName} 已经添加到比较列表中!"
-"Product {productName} has been added to wishlist!","商品 {productName} 已添加到心愿单!"
-"Product {productName} has been removed from compare!","商品 {productName} 已从比较列表中移除!"
-"Product {productName} has been removed from wishlist!","已从心愿单中移除了商品 {productName} !"
-"Registering the account ...","注册帐户 ..."
-"Reset password feature does not work while offline!","离线状态时,不能重置密码!"
-"Review","评论"
-"Reviews","评论列表"
-"Shopping cart is empty. Please add some products before entering Checkout","亲,购物车空空如也~, 快去选择一些你喜欢的商品吧."
-"Some of the ordered products are not available!","部分订购的商品不可用!"
-"Stock check in progress, please wait while available stock quantities are checked","正在确认库存数量,请稍候"
-"Subtotal incl. tax","含税小计"
-"Summary","摘要",
-"The product is out of stock and cannot be added to the cart!","该商品缺货,无法添加到购物车!"
-"The product, category or CMS page is not available in Offline mode. Redirecting to Home.","在离线模式下,商品,类别或CMS页面不可用。 请返回主页."
-"The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.","系统不确定库存量(不稳定)。 产品已添加到购物车中进行预订."
-"There is no Internet connection. You can still place your order. We will notify you if any of ordered products is not available because we cannot check it right now.","网络连接不上 我们现在无法确认库存。但是您仍然可以下订单, 如果订购的产品有问题,我们会通知您。"
-"This feature is not implemented yet! Please take a look at https://github.com/vuestorefront/vue-storefront/issues for our Roadmap!","此功能尚未实现! 请查看我们的开发路线图https://github.com/vuestorefront/vue-storefront/issues!"
-"Thumbnail","Thumbnail"
-"Type what you are looking for...","请输入你想要查找的关键词..."
-"Unhandled error, wrong response format!","未处理的错误,错误的响应格式!"
-"You are logged in!","您已成功登录!"
-"You are to pay for this order upon delivery.","您需要在收货时支付此订单."
-"You need to be logged in to see this page","您需要登录才能查看此页面"
-"You submitted your review for moderation.","You submitted your review for moderation."
-"You're logged out","您已注销"
-"email","电子邮箱"
-"have as many","有尽可能多的"
-"login","登录"
-"most you may purchase","你最多可以买"
-"not authorized","没有权限"
-"password","密码"
-"to account","我的账户"
diff --git a/core/i18n/resource/states.json b/core/i18n/resource/states.json
deleted file mode 100644
index 80c553adc3..0000000000
--- a/core/i18n/resource/states.json
+++ /dev/null
@@ -1 +0,0 @@
-{"US":[{"name":"Alabama","code":"AL"},{"name":"Alaska","code":"AK"},{"name":"American Samoa","code":"AS"},{"name":"Arizona","code":"AZ"},{"name":"Arkansas","code":"AR"},{"name":"California","code":"CA"},{"name":"Colorado","code":"CO"},{"name":"Connecticut","code":"CT"},{"name":"Delaware","code":"DE"},{"name":"District Of Columbia","code":"DC"},{"name":"Federated States Of Micronesia","code":"FM"},{"name":"Florida","code":"FL"},{"name":"Georgia","code":"GA"},{"name":"Guam","code":"GU"},{"name":"Hawaii","code":"HI"},{"name":"Idaho","code":"ID"},{"name":"Illinois","code":"IL"},{"name":"Indiana","code":"IN"},{"name":"Iowa","code":"IA"},{"name":"Kansas","code":"KS"},{"name":"Kentucky","code":"KY"},{"name":"Louisiana","code":"LA"},{"name":"Maine","code":"ME"},{"name":"Marshall Islands","code":"MH"},{"name":"Maryland","code":"MD"},{"name":"Massachusetts","code":"MA"},{"name":"Michigan","code":"MI"},{"name":"Minnesota","code":"MN"},{"name":"Mississippi","code":"MS"},{"name":"Missouri","code":"MO"},{"name":"Montana","code":"MT"},{"name":"Nebraska","code":"NE"},{"name":"Nevada","code":"NV"},{"name":"New Hampshire","code":"NH"},{"name":"New Jersey","code":"NJ"},{"name":"New Mexico","code":"NM"},{"name":"New York","code":"NY"},{"name":"North Carolina","code":"NC"},{"name":"North Dakota","code":"ND"},{"name":"Northern Mariana Islands","code":"MP"},{"name":"Ohio","code":"OH"},{"name":"Oklahoma","code":"OK"},{"name":"Oregon","code":"OR"},{"name":"Palau","code":"PW"},{"name":"Pennsylvania","code":"PA"},{"name":"Puerto Rico","code":"PR"},{"name":"Rhode Island","code":"RI"},{"name":"South Carolina","code":"SC"},{"name":"South Dakota","code":"SD"},{"name":"Tennessee","code":"TN"},{"name":"Texas","code":"TX"},{"name":"Utah","code":"UT"},{"name":"Vermont","code":"VT"},{"name":"Virgin Islands","code":"VI"},{"name":"Virginia","code":"VA"},{"name":"Washington","code":"WA"},{"name":"West Virginia","code":"WV"},{"name":"Wisconsin","code":"WI"},{"name":"Wyoming","code":"WY"}]}
\ No newline at end of file
diff --git a/core/i18n/scripts/translation.preprocessor.js b/core/i18n/scripts/translation.preprocessor.js
deleted file mode 100644
index 8c99aa60f3..0000000000
--- a/core/i18n/scripts/translation.preprocessor.js
+++ /dev/null
@@ -1,67 +0,0 @@
-const fs = require('fs')
-const path = require('path')
-const dsvFormat = require('d3-dsv').dsvFormat
-const dsv = dsvFormat(',')
-const { currentBuildLocales } = require('../helpers')
-
-/**
- * Converts an Array to an Object
- */
-function convertToObject (array) {
- const obj = []
- array.forEach((element, index, array) => {
- obj[element[0]] = element[1]
- })
- return obj
-}
-
-module.exports = function (csvDirectories, config = null) {
- const currentLocales = currentBuildLocales()
- const fallbackLocale = config.i18n.defaultLocale || 'en-US'
- let messages = {}
- let languages = []
-
- // get messages from CSV files
- csvDirectories.forEach(directory => {
- fs.readdirSync(directory).forEach(file => {
- const fullFileName = path.join(directory, file)
- const extName = path.extname(fullFileName)
- const baseName = path.posix.basename(file, extName)
-
- if (currentLocales.indexOf(baseName) !== -1) {
- if (extName === '.csv') {
- const fileContent = fs.readFileSync(fullFileName, 'utf8')
- if (languages.indexOf(baseName) === -1) {
- languages.push(baseName)
- }
- console.debug(`Processing translation file: ${fullFileName}`)
- messages[baseName] = Object.assign(messages[baseName] ? messages[baseName] : {}, convertToObject(dsv.parseRows(fileContent)))
- }
- }
- })
- })
-
- // create fallback
- console.debug(`Writing JSON file fallback: ${fallbackLocale}.json`)
- fs.writeFileSync(path.join(__dirname, '../resource/i18n', `${fallbackLocale}.json`), JSON.stringify(messages[fallbackLocale] || {}))
-
- // bundle all messages in one file
- if (config && config.i18n.bundleAllStoreviewLanguages) {
- const bundledLanguages = { [fallbackLocale]: messages[fallbackLocale] } // fallback locale
- bundledLanguages[config.i18n.defaultLocale] = messages[config.i18n.defaultLocale] // default locale
- currentLocales.forEach((locale) => {
- bundledLanguages[locale] = messages[locale]
- })
-
- console.debug(`Writing JSON file multistoreLanguages`)
- fs.writeFileSync(path.join(__dirname, '../resource/i18n', `multistoreLanguages.json`), JSON.stringify(bundledLanguages))
- } else {
- currentLocales.forEach((language) => {
- if (language === fallbackLocale) return // it's already loaded
- const filePath = path.join(__dirname, '../resource/i18n', `${language}.json`)
- console.debug(`Writing JSON file: ${language}.json`)
- fs.writeFileSync(filePath, JSON.stringify(messages[language]))
- })
- fs.writeFileSync(path.join(__dirname, '../resource/i18n', `multistoreLanguages.json`), JSON.stringify({})) // fix for webpack compilation error in case of `bundleAllStoreviewLanguages` = `false` (#3188)
- }
-}
diff --git a/core/lib/async-data-loader.ts b/core/lib/async-data-loader.ts
deleted file mode 100644
index 0fbfad7397..0000000000
--- a/core/lib/async-data-loader.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
-* @deprecated This module has been created before Vue.js v2.6.0. From 2.6.x on please do preferably use the `serverPrefetch` hook to sync SSR Vuex data. More info: https://ssr.vuejs.org/api/#serverprefetch
-* @description Please note: This module can be used not only for `asyncData` extensibility but also for simplyfying the data loaders in Vuex actions or other components - basicaly everywhere where we must `wait` for some async operations to complete.
-*/
-import { isServer } from '@vue-storefront/core/helpers'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-const DEFAULT_ACTION_CATEGORY = 'asyncData'
-// Data loader queues all the data fetching operations and runs them at once - to be usedf for example in the `asyncData()` functions
-export interface AsyncDataLoaderActionContext {
- category?: string,
- route: any,
- store: any,
- context: any
-}
-
-// Data loader queues all the data fetching operations and runs them at once - to be usedf for example in the `asyncData()` functions
-export interface AsyncDataLoaderAction {
- execute: any, // this function must return a Promise
- category?: string,
- name?: string,
- executedAt?: Date,
- scheduledAt?: Date
-}
-
-/** AsyncDataLoader helper for queueing the data fetching operations. The main purpose is to decentralize the `asyncData()` SSR method */
-export const AsyncDataLoader = {
-
- queue: new Array(),
-
- push: function (action: AsyncDataLoaderAction) {
- if (!action.category) action.category = DEFAULT_ACTION_CATEGORY
- action.scheduledAt = new Date()
- this.queue.push(action)
- },
- flush: function (actionContext: AsyncDataLoaderActionContext) {
- if (!actionContext.category) actionContext.category = DEFAULT_ACTION_CATEGORY
- const actionsToExecute = this.queue.filter(ac => (!ac.category || !actionContext.category) || (ac.category === actionContext.category && (!ac.executedAt))).map(ac => {
- ac.executedAt = new Date()
- return ac.execute(actionContext) // function must return Promise
- })
- if (actionsToExecute.length > 0) {
- Logger.info('Executing data loader actions(' + actionsToExecute.length + ')', 'dataloader')()
- }
- return Promise.all(actionsToExecute).then(results => {
- return results
- })
- }
-}
diff --git a/core/lib/hooks.ts b/core/lib/hooks.ts
deleted file mode 100644
index 9ac954cd42..0000000000
--- a/core/lib/hooks.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- Listener hook just fires functions passed to hook function when executor is invoked.
- e. g. We want to listen for onAppInit event in various places of the application.
- Functions passed to this hook will be invoked only when executor function is executed.
- Usually we want to use hook in app/modules and executor in core.
- @return hook: a hook function to use in modules
- @return executor: a function that will run all the collected hooks
- */
-function createListenerHook () {
- const functionsToRun: ((arg: T) => void)[] = []
-
- function hook (fn: (arg?: T) => void) {
- functionsToRun.push(fn)
- }
-
- function executor (args: T = null): void {
- functionsToRun.forEach(fn => fn(args))
- }
-
- return {
- hook,
- executor
- }
-}
-
-/**
- Mutators work like listeners except they can modify passed value in hooks.
- e.g we can apply the hook mutator to object order that is returned before placing order
- now you can access and modify this value from hook returned by this function
- @return hook: a hook function to use in modules
- @return executor: a function that will apply all hooks on a given value
- */
-function createMutatorHook () {
- const mutators: ((arg: T) => R)[] = []
-
- function hook (mutator: (arg: T) => R) {
- mutators.push(mutator)
- }
-
- function executor (rawOutput: T): T | R {
- if (mutators.length > 0) {
- let modifiedOutput: R = null
- mutators.forEach(fn => {
- modifiedOutput = fn(rawOutput)
- })
- return modifiedOutput
- } else {
- return rawOutput
- }
- }
-
- return {
- hook,
- executor
- }
-}
-
-export {
- createListenerHook,
- createMutatorHook
-}
-
-// TODO: Hooks for Client entry, replaceState (can be part of client entry), shopping cart loaded, user logged
diff --git a/core/lib/logger.ts b/core/lib/logger.ts
deleted file mode 100644
index 9c0e3e931c..0000000000
--- a/core/lib/logger.ts
+++ /dev/null
@@ -1,200 +0,0 @@
-import { isServer } from '@vue-storefront/core/helpers'
-import { coreHooksExecutors } from '@vue-storefront/core/hooks'
-import buildTimeConfig from 'config'
-const bgColorStyle = (color) => `color: white; background: ${color}; padding: 4px; font-weight: bold; font-size: 0.8em'`
-
-/** VS message logger. By default works only on dev mode */
-class Logger {
- /**
- * Logger verbosity level
- */
- public verbosityLevel: string;
-
- /**
- * Is production environment
- */
- public isProduction: boolean;
-
- /**
- * Force to show error on production
- */
- public showErrorOnProduction: boolean;
-
- /**
- * Logger constructor
- *
- * @param verbosityLevel
- * @param showErrorOnProduction
- */
- public constructor (verbosityLevel: string = 'display-everything', showErrorOnProduction: boolean = false) {
- this.verbosityLevel = verbosityLevel
- this.showErrorOnProduction = showErrorOnProduction
- this.isProduction = process.env.NODE_ENV === 'production'
- }
-
- /**
- * Convert message to string - as it may be object, array either primitive
- * @param payload
- */
- public convertToString (payload: any) {
- if (typeof payload === 'string' || typeof payload === 'boolean' || typeof payload === 'number') return payload
- if (payload && payload.message) return payload.message
- return JSON.stringify(payload)
- }
-
- /**
- * Check if method can print into console
- *
- * @param {string} method
- */
- public canPrint (method: string) {
- const allowedMethods = []
-
- if (this.verbosityLevel === 'display-everything' && this.isProduction === false) {
- allowedMethods.push(...['info', 'warn', 'error', 'debug'])
- } else if (this.verbosityLevel === 'only-errors' && (this.isProduction === false || this.showErrorOnProduction === true)) {
- allowedMethods.push('error')
- }
-
- return allowedMethods.indexOf(method) !== -1
- }
-
- /**
- * Inform about debug events happening in the app
- * Don't forget to invoke created function after passing arguments to keep context
- * `Logger.debug(...args)()`
- * @param message
- * @param tag short tag specifying area where message was spawned (eg. cart, sync, module)
- * @param context meaningful data related to this message
- */
- public debug (message: any, tag: string = null, context: any = null): () => void {
- if (!this.canPrint('debug')) {
- return () => {}
- }
-
- let noDefaultOutput
- ({ message, tag, context, noDefaultOutput } = coreHooksExecutors.beforeLogRendered({ type: 'debug', message, tag, context }))
- if (noDefaultOutput === true) {
- return () => {}
- }
-
- if (isServer) {
- return console.debug.bind(console, (tag ? `[${tag}] ` : '') + this.convertToString(message), context)
- }
-
- if (tag) {
- return console.debug.bind(window.console, '%cVSF%c %c' + tag + '%c ' + this.convertToString(message), bgColorStyle('grey'), 'color: inherit', bgColorStyle('gray'), 'font-weight: normal', context)
- } else {
- return console.debug.bind(window.console, '%cVSF%c ' + this.convertToString(message), bgColorStyle('grey'), 'font-weight: normal', context)
- }
- }
-
- /**
- * Inform about log events happening in the app
- * Don't forget to invoke created function after passing arguments to keep context
- * `Logger.log(...args)()`
- * @param message
- * @param tag short tag specifying area where message was spawned (eg. cart, sync, module)
- * @param context meaningful data related to this message
- */
- public log (message: any, tag: string = null, context: any = null): () => void {
- return this.info(message, tag, context)
- }
-
- /**
- * Inform about succesful events happening in the app
- * Don't forget to invoke created function after passing arguments to keep context
- * `Logger.info(...args)()`
- * @param message
- * @param tag short tag specifying area where message was spawned (eg. cart, sync, module)
- * @param context meaningful data related to this message
- */
- public info (message: any, tag: string = null, context: any = null): () => void {
- if (!this.canPrint('info')) {
- return () => {}
- }
-
- let noDefaultOutput
- ({ message, tag, context, noDefaultOutput } = coreHooksExecutors.beforeLogRendered({ type: 'info', message, tag, context }))
- if (noDefaultOutput === true) {
- return () => {}
- }
-
- if (isServer) {
- return console.log.bind(console, (tag ? `[${tag}] ` : '') + this.convertToString(message), context)
- }
-
- if (tag) {
- return console.log.bind(window.console, '%cVSF%c %c' + tag + '%c ' + this.convertToString(message), bgColorStyle('green'), 'color: inherit', bgColorStyle('gray'), 'font-weight: bold', context)
- } else {
- return console.log.bind(window.console, '%cVSF%c ' + this.convertToString(message), bgColorStyle('green'), 'font-weight: bold', context)
- }
- }
-
- /**
- * Inform about potential problems that may be a cause of app break
- * Don't forget to invoke created function after passing arguments to keep context
- * `Logger.warn(...args)()`
- * @param message
- * @param tag short tag specifying area where message was spawned (eg. cart, sync, module)
- * @param context meaningful data related to this message
- */
- public warn (message: any, tag: string = null, context: any = null): () => void {
- if (!this.canPrint('warn')) {
- return () => {}
- }
-
- let noDefaultOutput
- ({ message, tag, context, noDefaultOutput } = coreHooksExecutors.beforeLogRendered({ type: 'warn', message, tag, context }))
- if (noDefaultOutput === true) {
- return () => {}
- }
-
- if (isServer) {
- return console.warn.bind(console, (tag ? `[${tag}] ` : '') + this.convertToString(message), context)
- }
-
- if (tag) {
- return console.warn.bind(window.console, '%cVSF%c %c' + tag + '%c ' + this.convertToString(message), bgColorStyle('orange'), 'color: inherit', bgColorStyle('gray'), 'font-weight: bold', context)
- } else {
- return console.warn.bind(window.console, '%cVSF%c ' + this.convertToString(message), bgColorStyle('orange'), 'font-weight: bold', context)
- }
- }
-
- /**
- * Inform about errors that will break the app
- * Don't forget to invoke created function after passing arguments to keep context
- * `Logger.error(...args)()`
- * @param message
- * @param tag short tag specifying area where message was spawned (eg. cart, sync, module)
- * @param context meaningful data related to this message
- */
- public error (message: any, tag: string = null, context: any = null): () => void {
- let noDefaultOutput
- ({ message, tag, context, noDefaultOutput } = coreHooksExecutors.beforeLogRendered({ type: 'error', message, tag, context }))
- if (noDefaultOutput === true) {
- return () => {}
- }
-
- if (isServer) { // always show errors in SSR
- return console.error.bind(console, (tag ? `[${tag}] ` : '') + this.convertToString(message), context)
- }
-
- if (this.canPrint('error')) {
- if (tag) {
- return console.error.bind(window.console, '%cVSF%c %c' + tag + '%c ' + this.convertToString(message), bgColorStyle('red'), 'color: inherit', bgColorStyle('gray'), 'font-weight: bold', context)
- } else {
- return console.error.bind(window.console, '%cVSF%c ' + this.convertToString(message), bgColorStyle('red'), 'font-weight: bold', context)
- }
- }
-
- return () => {}
- }
-}
-
-const logger = new Logger(
- buildTimeConfig.console.verbosityLevel,
- buildTimeConfig.console.showErrorOnProduction
-)
-
-export { logger as Logger }
diff --git a/core/lib/module/helpers.ts b/core/lib/module/helpers.ts
deleted file mode 100644
index e25d7aeeb4..0000000000
--- a/core/lib/module/helpers.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { VueStorefrontModuleConfig } from './types'
-import { Module } from 'vuex'
-import merge from 'lodash-es/merge'
-import some from 'lodash-es/some'
-import find from 'lodash-es/find'
-
-function doesStoreAlreadyExists (key: string, registeredModules: VueStorefrontModuleConfig[]): boolean {
- registeredModules.forEach(m => {
- if (m.store) {
- if (m.store.modules.some(m => m.key === key)) return true
- }
- })
- return false
-}
-
-function mergeStores (
- originalStore: { modules?: { key: string, module: Module }[], plugin?: Function },
- extendedStore: { modules?: { key: string, module: Module }[], plugin?: Function }
-) {
- let mergedArray = []
- originalStore.modules.map(item => {
- mergedArray.push(merge(item, find(extendedStore.modules, { 'key': item.key })));
- })
- extendedStore.modules.map(extendedStoreItem => {
- if (some(originalStore.modules, null, { 'key': extendedStoreItem.key }) === false) {
- mergedArray.push(extendedStoreItem)
- }
- })
- return mergedArray
-}
-
-export {
- doesStoreAlreadyExists,
- mergeStores
-}
diff --git a/core/lib/module/index.ts b/core/lib/module/index.ts
deleted file mode 100644
index 9ae5951e68..0000000000
--- a/core/lib/module/index.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-// @deprecated from 2.0
-import { Module } from 'vuex'
-import { RouteConfig, NavigationGuard } from 'vue-router'
-import Vue from 'vue'
-import merge from 'lodash-es/merge'
-import rootStore from '@vue-storefront/core/store'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { setupMultistoreRoutes } from '../multistore'
-import { router } from '@vue-storefront/core/app'
-import { isServer } from '@vue-storefront/core/helpers'
-import { VSF, VueStorefrontModuleConfig } from './types'
-import { doesStoreAlreadyExists, mergeStores } from './helpers'
-import config from 'config'
-
-const moduleExtendings: VueStorefrontModuleConfig[] = []
-const registeredModules: VueStorefrontModuleConfig[] = []
-
-function registerModules (modules: VueStorefrontModule[], context): void {
- modules.forEach(m => m.register())
- Logger.info('VS Modules registration finished.', 'module', {
- succesfulyRegistered: registeredModules.length + ' / ' + modules.length,
- registrationOrder: registeredModules
- }
- )()
-}
-
-function extendModule (moduleConfig: VueStorefrontModuleConfig) {
- moduleExtendings.push(moduleConfig)
-}
-
-class VueStorefrontModule {
- private _isRegistered = false
- private _c: VueStorefrontModuleConfig
- public constructor (_c: VueStorefrontModuleConfig) {
- this._c = _c
- }
-
- private static _extendStore (storeInstance: any, modules: { key: string, module: Module }[], plugin: any): void {
- if (modules) modules.forEach(store => storeInstance.registerModule(store.key, store.module))
- if (plugin) storeInstance.subscribe(plugin)
- }
-
- private static _extendRouter (routerInstance, routes?: RouteConfig[], beforeEach?: NavigationGuard, afterEach?: NavigationGuard): void {
- if (routes) {
- setupMultistoreRoutes(config, routerInstance, routes)
- }
- if (beforeEach) routerInstance.beforeEach(beforeEach)
- if (afterEach) routerInstance.afterEach(afterEach)
- }
-
- private _extendModule (extendedConfig: VueStorefrontModuleConfig): void {
- const mergedStore = { modules: [], plugin: null }
- const key = this._c.key
- const originalStore = this._c.store
- const extendedStore = extendedConfig.store
- delete this._c.store
- delete extendedConfig.store
- this._c = merge(this._c, extendedConfig)
- mergedStore.modules = mergeStores(originalStore, extendedStore)
- mergedStore.plugin = extendedStore.plugin || originalStore.plugin || null
- this._c.store = mergedStore
- Logger.info('Module "' + key + '" has been succesfully extended.', 'module')()
- }
-
- public get config () {
- return this._c
- }
-
- /** Use only if you want to explicitly modify module config. Otherwise it's much easier to use `extendModule` */
- public set config (config) {
- this._c = config
- }
-
- public register (): VueStorefrontModuleConfig | void {
- if (!this._isRegistered) {
- Logger.warn('The module you are registering is using outdated API that will soon be depreciated. Please check https://docs.vuestorefront.io to learn more.', 'module', this._c.key)()
- let areStoresUnique = true
- const VSF: VSF = {
- Vue,
- config: config,
- store: rootStore,
- isServer
- }
-
- moduleExtendings.forEach(extending => {
- if (extending.key === this._c.key) this._extendModule(extending)
- })
-
- if (this._c.store) {
- this._c.store.modules.forEach(store => {
- if (doesStoreAlreadyExists(store.key, registeredModules)) {
- Logger.warn('Error during "' + this._c.key + '" module registration! Store with key "' + store.key + '" already exists!', 'module')()
- areStoresUnique = false
- }
- })
- }
-
- if (areStoresUnique) {
- if (this._c.beforeRegistration) {
- if (this._c.beforeRegistration.length === 1) {
- this._c.beforeRegistration(VSF)
- } else {
- Logger.warn('You are using outdated signature for beforeRegistration hook that soon will be deprecated and module will stop working properly. Please update to the new signature that can be found in our docs: https://docs.vuestorefront.io/guide/modules/introduction.html#beforeregistration', 'module', this._c.key)()
- this._c.beforeRegistration(Vue, config, rootStore, isServer)
- }
- }
- if (this._c.store) VueStorefrontModule._extendStore(rootStore, this._c.store.modules, this._c.store.plugin)
- if (this._c.router) VueStorefrontModule._extendRouter(router, this._c.router.routes, this._c.router.beforeEach, this._c.router.afterEach)
- registeredModules.push(this._c)
- this._isRegistered = true
- if (this._c.afterRegistration) {
- if (this._c.afterRegistration.length === 1) {
- this._c.afterRegistration(VSF)
- } else {
- Logger.warn('You are using outdated signature for afterRegistration hook that soon will be deprecated and module will stop working properly. Please update to the new signature that can be found in our docs: https://docs.vuestorefront.io/guide/modules/introduction.html#afterregistration', 'module', this._c.key)()
- this._c.afterRegistration(Vue, config, rootStore, isServer)
- }
- }
- return this._c
- }
- }
- }
-}
-
-function createModule (config: VueStorefrontModuleConfig): VueStorefrontModule {
- return new VueStorefrontModule(config)
-}
-
-export {
- VSF,
- VueStorefrontModuleConfig,
- extendModule,
- VueStorefrontModule,
- registerModules,
- createModule
-}
diff --git a/core/lib/module/types.ts b/core/lib/module/types.ts
deleted file mode 100644
index 085b12dc73..0000000000
--- a/core/lib/module/types.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Module, Store } from 'vuex'
-import { RouteConfig, NavigationGuard } from 'vue-router'
-import { VueConstructor } from 'vue'
-import RootState from '@vue-storefront/core/types/RootState'
-
-export interface VSF {
- Vue?: VueConstructor,
- config?: Record,
- store?: Store,
- isServer?: boolean
-}
-
-export interface VueStorefrontModuleConfig {
- key: string,
- store?: { modules?: { key: string, module: Module }[], plugin?: Function },
- router?: { routes?: RouteConfig[], beforeEach?: NavigationGuard, afterEach?: NavigationGuard },
- beforeRegistration?: (VSF: VSF | VueConstructor, config?: Record, store?: Store, isServer?: boolean) => void,
- afterRegistration?: (VSF: VSF | VueConstructor, config?: Record, store?: Store, isServer?: boolean) => void
-}
diff --git a/core/lib/modules.ts b/core/lib/modules.ts
deleted file mode 100644
index e5b5e8001a..0000000000
--- a/core/lib/modules.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Store } from 'vuex'
-import VueRouter from 'vue-router'
-import Vue from 'vue'
-import RootState from '@vue-storefront/core/types/RootState'
-
-export type StorefrontModule = (
- options: {
- app: Vue,
- store: Store,
- router: VueRouter,
- moduleConfig: any,
- appConfig: any
- }
-) => void
-
-let refs: any = {}
-let registeredModules: StorefrontModule[] = []
-
-function injectReferences (app: any, store: Store, router: VueRouter, config: any): void {
- refs.app = app
- refs.store = store
- refs.router = router
- refs.config = config
-}
-
-function registerModule (module: StorefrontModule, config?: any) {
- if (!registeredModules.includes(module)) {
- module({
- app: refs.app,
- store: refs.store,
- router: refs.router,
- appConfig: refs.config,
- moduleConfig: config
- })
- registeredModules.push(module)
- }
-}
-
-function isModuleRegistered (name: string): boolean {
- return registeredModules.some(m => m.name === name)
-}
-
-export { refs, injectReferences, registerModule, isModuleRegistered }
diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts
deleted file mode 100644
index aacca65c2b..0000000000
--- a/core/lib/multistore.ts
+++ /dev/null
@@ -1,239 +0,0 @@
-import rootStore from '../store'
-import { loadLanguageAsync } from '@vue-storefront/i18n'
-import { initializeSyncTaskStorage } from './sync/task'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import Vue from 'vue'
-import queryString from 'query-string'
-import merge from 'lodash-es/merge'
-import VueRouter, { RouteConfig, RawLocation } from 'vue-router'
-import config from 'config'
-import { coreHooksExecutors } from '@vue-storefront/core/hooks'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import { LocalizedRoute, StoreView } from './types'
-import storeCodeFromRoute from './storeCodeFromRoute'
-import cloneDeep from 'lodash-es/cloneDeep'
-import get from 'lodash-es/get'
-import { isServer } from '@vue-storefront/core/helpers'
-
-function getExtendedStoreviewConfig (storeView: StoreView): StoreView {
- if (storeView.extend) {
- const originalParent = storeView.extend
-
- if (!config.storeViews[originalParent]) {
- Logger.error(`Storeview "${storeView.extend}" doesn't exist!`)()
- } else {
- storeView = merge(
- {},
- getExtendedStoreviewConfig(config.storeViews[originalParent]),
- storeView
- )
- }
- }
-
- return storeView
-}
-
-/**
- * Returns base storeView object that can be created without storeCode
- */
-function buildBaseStoreView (): StoreView {
- return cloneDeep({
- tax: config.tax,
- i18n: config.i18n,
- elasticsearch: config.elasticsearch,
- storeCode: null,
- storeId: config.defaultStoreCode && config.defaultStoreCode !== '' ? config.storeViews[config.defaultStoreCode].storeId : 1,
- seo: config.seo
- })
-}
-
-export function currentStoreView (): StoreView {
- const serverStoreView = get(global, 'process.storeView', undefined)
- const clientStoreView = get(rootStore, 'state.storeView', undefined)
- return (isServer ? serverStoreView : clientStoreView) || buildBaseStoreView()
-}
-
-export async function prepareStoreView (storeCode: string): Promise {
- let storeView: StoreView = buildBaseStoreView() // current, default store
- if (config.storeViews.multistore === true) {
- storeView.storeCode = storeCode || config.defaultStoreCode || ''
- } else {
- storeView.storeCode = storeCode || ''
- }
-
- const storeViewHasChanged = !rootStore.state.storeView || rootStore.state.storeView.storeCode !== storeCode
-
- if (storeView.storeCode && config.storeViews.multistore === true && config.storeViews[storeView.storeCode]) {
- storeView = merge(storeView, getExtendedStoreviewConfig(config.storeViews[storeView.storeCode]))
- }
-
- if (rootStore.state.user) {
- rootStore.state.user.current_storecode = storeView.storeCode
- }
-
- if (storeViewHasChanged) {
- storeView = coreHooksExecutors.beforeStoreViewChanged(storeView)
- rootStore.state.storeView = storeView
-
- if (global && isServer) {
- (global.process as any).storeView = storeView
- }
-
- await loadLanguageAsync(storeView.i18n.defaultLocale)
- }
- if (storeViewHasChanged || StorageManager.currentStoreCode !== storeCode) {
- initializeSyncTaskStorage()
- StorageManager.currentStoreCode = storeView.storeCode
- }
-
- coreHooksExecutors.afterStoreViewChanged(storeView)
-
- return storeView
-}
-
-export function removeStoreCodeFromRoute (matchedRouteOrUrl: LocalizedRoute | string): LocalizedRoute | string {
- const storeCodeInRoute = storeCodeFromRoute(matchedRouteOrUrl)
- if (storeCodeInRoute !== '') {
- let urlPath = typeof matchedRouteOrUrl === 'object' ? matchedRouteOrUrl.path : matchedRouteOrUrl
- return urlPath.replace(storeCodeInRoute + '/', '')
- } else {
- return matchedRouteOrUrl
- }
-}
-
-function removeURLQueryParameter (url, parameter) {
- // prefer to use l.search if you have a location/link object
- var urlparts = url.split('?');
- if (urlparts.length >= 2) {
- var prefix = encodeURIComponent(parameter) + '=';
- var pars = urlparts[1].split(/[&;]/g);
-
- // reverse iteration as may be destructive
- for (var i = pars.length; i-- > 0;) {
- // idiom for string.startsWith
- if (pars[i].lastIndexOf(prefix, 0) !== -1) {
- pars.splice(i, 1);
- }
- }
-
- return urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');
- }
- return url;
-}
-
-export function adjustMultistoreApiUrl (url: string): string {
- const { storeCode } = currentStoreView()
- if (storeCode) {
- url = removeURLQueryParameter(url, 'storeCode')
- const urlSep = (url.indexOf('?') > 0) ? '&' : '?'
- url += `${urlSep}storeCode=${storeCode}`
- }
- return url
-}
-
-export function localizedDispatcherRoute (routeObj: LocalizedRoute | string, storeCode?: string): LocalizedRoute | string {
- const { storeCode: currentStoreCode, appendStoreCode } = currentStoreView()
- if (!storeCode || !config.storeViews[storeCode]) {
- storeCode = currentStoreCode
- }
- const appendStoreCodePrefix = storeCode && appendStoreCode
-
- if (typeof routeObj === 'string') {
- if (routeObj[0] !== '/') routeObj = `/${routeObj}`
- return appendStoreCodePrefix ? `/${storeCode}${routeObj}` : routeObj
- }
-
- if (routeObj) {
- if ((routeObj as LocalizedRoute).fullPath && !(routeObj as LocalizedRoute).path) { // support both path and fullPath
- routeObj['path'] = (routeObj as LocalizedRoute).fullPath
- }
-
- if (routeObj.path) { // case of using dispatcher
- const routeCodePrefix = appendStoreCodePrefix ? `/${storeCode}` : ''
- const qrStr = queryString.stringify(routeObj.params);
-
- const normalizedPath = routeObj.path[0] !== '/' ? `/${routeObj.path}` : routeObj.path
- return `${routeCodePrefix}${normalizedPath}${qrStr ? `?${qrStr}` : ''}`
- }
- }
-
- return routeObj
-}
-
-export function localizedDispatcherRouteName (routeName: string, storeCode: string, appendStoreCode: boolean = false): string {
- if (appendStoreCode) {
- return `${storeCode}-${routeName}`
- }
- return routeName
-}
-
-/**
- * Returns route path with proper language prefix
- * @param path - route path
- * @param storeCode - language prefix specified in global config
- */
-export function localizedRoutePath (path: string, storeCode: string): string {
- const _path = path.startsWith('/') ? path.slice(1) : path
-
- return `/${storeCode}/${_path}`
-}
-
-/**
- * Returns transformed route config with language
- * @param route - route config object
- * @param storeCode - language prefix specified in global config
- * @param isChildRoute - determines if route config is for child route
- */
-export function localizedRouteConfig (route: RouteConfig, storeCode: string, isChildRoute: boolean = false): RouteConfig {
- // note: we need shallow copy to prevent modifications in provided route object
- const _route = { ...route }
-
- if (_route.name && storeCode) {
- _route.name = `${storeCode}-${_route.name}`
- }
-
- if (_route.path && !isChildRoute) {
- _route.path = localizedRoutePath(_route.path, storeCode)
- }
-
- if (_route.children) {
- _route.children = _route.children.map(childRoute => localizedRouteConfig(childRoute, storeCode, true))
- }
-
- return _route
-}
-
-export function localizedRoute (routeObj: LocalizedRoute | string | RouteConfig | RawLocation, storeCode: string = null): any {
- if (!storeCode) {
- storeCode = currentStoreView().storeCode
- }
- if (!routeObj) {
- return routeObj
- }
-
- if ((typeof routeObj === 'object') && (routeObj as LocalizedRoute)) {
- if ((routeObj as LocalizedRoute).fullPath && !(routeObj as LocalizedRoute).path) { // support both path and fullPath
- routeObj['path'] = (routeObj as LocalizedRoute).fullPath
- }
- }
-
- if (storeCode && config.defaultStoreCode !== storeCode && config.storeViews[storeCode] && config.storeViews[storeCode].appendStoreCode) {
- if (typeof routeObj !== 'object') {
- return localizedRoutePath(routeObj, storeCode)
- }
- return localizedRouteConfig(routeObj as RouteConfig, storeCode)
- }
-
- return routeObj
-}
-
-export function setupMultistoreRoutes (config, router: VueRouter, routes: RouteConfig[], priority: number = 0): void {
- const allRoutes: RouteConfig[] = []
- const { storeCode, appendStoreCode } = currentStoreView()
- if (storeCode && appendStoreCode) {
- allRoutes.push(...routes.map(route => localizedRouteConfig(route, storeCode)))
- } else {
- allRoutes.push(...routes)
- }
- router.addRoutes(allRoutes, true, priority)
-}
diff --git a/core/lib/passive-listeners.js b/core/lib/passive-listeners.js
deleted file mode 100644
index 890eff2c31..0000000000
--- a/core/lib/passive-listeners.js
+++ /dev/null
@@ -1,59 +0,0 @@
-const eventListenerOptionsSupported = () => {
- let supported = false
-
- try {
- const opts = Object.defineProperty({}, 'passive', {
- get () {
- supported = true
- }
- })
-
- window.addEventListener('test', null, opts)
- window.removeEventListener('test', null, opts)
- } catch (e) {}
-
- return supported
-}
-
-const defaultOptions = {
- passive: true,
- capture: false
-}
-const supportedPassiveTypes = [
- 'scroll', 'wheel',
- 'touchstart', 'touchmove', 'touchenter', 'touchend', 'touchleave',
- 'mouseout', 'mouseleave', 'mouseup', 'mousedown', 'mousemove', 'mouseenter', 'mousewheel', 'mouseover'
-]
-const getDefaultPassiveOption = (passive, eventName) => {
- if (passive !== undefined) return passive
-
- return supportedPassiveTypes.indexOf(eventName) === -1 ? false : defaultOptions.passive
-}
-
-const getWritableOptions = (options) => {
- const passiveDescriptor = Object.getOwnPropertyDescriptor(options, 'passive')
-
- return passiveDescriptor && passiveDescriptor.writable !== true && passiveDescriptor.set === undefined ? Object.assign({}, options) : options
-}
-
-const overwriteAddEvent = (superMethod) => {
- EventTarget.prototype.addEventListener = function (type, listener, options) {
- const usesListenerOptions = typeof options === 'object' && options !== null
- const useCapture = usesListenerOptions ? options.capture : options
-
- options = usesListenerOptions ? getWritableOptions(options) : {}
- options.passive = getDefaultPassiveOption(options.passive, type)
- options.capture = useCapture === undefined ? defaultOptions.capture : useCapture
-
- superMethod.call(this, type, listener, options)
- }
-
- EventTarget.prototype.addEventListener._original = superMethod
-}
-
-const supportsPassive = eventListenerOptionsSupported()
-
-if (supportsPassive) {
- const addEvent = EventTarget.prototype.addEventListener
- overwriteAddEvent(addEvent)
-}
diff --git a/core/lib/router-manager.ts b/core/lib/router-manager.ts
deleted file mode 100644
index e20ad54c87..0000000000
--- a/core/lib/router-manager.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import { baseRouter } from '@vue-storefront/core/app'
-import { RouteConfig } from 'vue-router'
-
-const RouterManager = {
- _registeredRoutes: new Array(),
- _routeQueue: new Array(),
- _routeQueueFlushed: false,
- _routeLock: null,
- _routeDispatched: false,
- _callbacks: [],
- addRoutes: function (routes: RouteConfig[], useRouteQueue: boolean = false, priority: number = 0): void {
- if (useRouteQueue && !this._routeQueueFlushed) {
- this._routeQueue.push(...routes.map(route => { return { route: route, priority: priority } }))
- } else {
- const uniqueRoutes = routes.filter((route) => {
- return this._registeredRoutes.findIndex(registeredRoute => registeredRoute.route.name === route.name && registeredRoute.route.path === route.path) < 0
- })
- if (uniqueRoutes.length > 0) {
- this._registeredRoutes.push(...uniqueRoutes.map(route => { return { route: route, priority: priority } }))
- baseRouter.addRoutes(uniqueRoutes)
- }
- }
- },
- flushRouteQueue: function (): void {
- if (!this._routeQueueFlushed) {
- this.addRoutesByPriority(this._routeQueue)
- this._routeQueueFlushed = true
- this._routeQueue = []
- }
- },
- addRoutesByPriority: function (routesData) {
- const routesToAdd = []
- for (const routeData of routesData) {
- let exisitingIndex = routesToAdd.findIndex(r => r.route.name === routeData.route.name && r.route.path === routeData.route.path)
- if ((exisitingIndex >= 0) && (routesToAdd[exisitingIndex].priority < routeData.priority)) { // same priority doesn't override exisiting
- routesToAdd.splice(exisitingIndex, 1)
- exisitingIndex = -1
- }
- if (exisitingIndex < 0) {
- routesToAdd.push(routeData)
- }
- }
- this._registeredRoutes.push(...routesToAdd)
- baseRouter.addRoutes(routesToAdd.map(r => r.route))
- },
- isRouteAdded: function (addedRoutes: any[], route: RouteConfig) {
- return addedRoutes.findIndex((addedRoute) => addedRoute.route.name === route.name && addedRoute.route.path === route.path) >= 0
- },
- addDispatchCallback: function (callback: Function) {
- this._callbacks.push(callback)
- },
- findByName: function (name: string): RouteConfig {
- return this.findByProperty('name', name)
- },
- findByPath: function (path: string): RouteConfig {
- return this.findByProperty('path', path)
- },
- findByProperty: function (property: string, value: string): RouteConfig {
- const registeredRoute = this._registeredRoutes.find(r => r.route[property] === value)
- if (registeredRoute) return registeredRoute.route
- if (this._routeQueueFlushed) return null
- const queuedRoute = this._routeQueue.find(queueItem => queueItem.route[property] === value)
- return queuedRoute ? queuedRoute.route : null
- },
- lockRoute: function () {
- let resolver
- this._routeLock = {
- lockPromise: new Promise(resolve => { resolver = resolve }),
- resolver
- }
- },
- isRouteProcessing: function () {
- return !!this._routeLock
- },
- isRouteDispatched: function () {
- return !!this._routeDispatched
- },
- getRouteLockPromise: function () {
- if (this._routeLock) return this._routeLock.lockPromise
- return Promise.resolve()
- },
- unlockRoute: function () {
- if (this._routeLock) {
- this._routeLock.resolver()
- this._routeLock = null
- }
- this._routeDispatched = true
- this._callbacks.forEach(callback => {
- callback()
- });
- }
-}
-
-export { RouterManager }
diff --git a/core/lib/search.ts b/core/lib/search.ts
deleted file mode 100644
index 6dd5800762..0000000000
--- a/core/lib/search.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-import Vue from 'vue'
-
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-import { sha3_224 } from 'js-sha3'
-import rootStore from '@vue-storefront/core/store'
-import { getSearchAdapter } from './search/adapter/searchAdapterFactory'
-import { SearchRequest } from '@vue-storefront/core/types/search/SearchRequest'
-import { SearchResponse } from '@vue-storefront/core/types/search/SearchResponse'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import config from 'config'
-import { isServer } from '@vue-storefront/core/helpers'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-
-// TODO - use one from helpers instead
-export function isOnline (): boolean {
- if (typeof navigator !== 'undefined') {
- return navigator.onLine
- } else {
- return true // SSR
- }
-}
-
-/**
- * Search ElasticSearch catalog of products using simple text query
- * Use bodybuilder to build the query, aggregations etc: http://bodybuilder.js.org/
- * @param {Object} query is the object of searchQuery class
- * @param {Int} start start index
- * @param {Int} size page size
- * @return {Promise}
- */
-export const quickSearchByQuery = async ({ query = {}, start = 0, size = 50, entityType = 'product', sort = '', storeCode = null, excludeFields = null, includeFields = null } = {}): Promise => {
- const searchAdapter = await getSearchAdapter()
- if (size <= 0) size = 50
- if (start < 0) start = 0
-
- return new Promise(async (resolve, reject) => {
- const storeView = currentStoreView()
- const Request: SearchRequest = {
- store: storeCode || storeView.storeCode, // TODO: add grouped product and bundled product support
- type: entityType,
- searchQuery: query,
- groupToken: null,
- groupId: null,
- size: size,
- from: start,
- sort: sort
- }
-
- if (excludeFields) Request._sourceExclude = excludeFields
- if (includeFields) Request._sourceInclude = includeFields
-
- if (config.usePriceTiers && (entityType === 'product') && rootStore.state.user.groupId) {
- Request.groupId = rootStore.state.user.groupId
- }
-
- const cache = StorageManager.get('elasticCache') // switch to appcache?
- let servedFromCache = false
- const cacheKey = sha3_224(JSON.stringify(Request))
- const benchmarkTime = new Date()
-
- try {
- const res = await cache.getItem(cacheKey)
- if (res !== null) {
- res.cache = true
- res.noresults = false
- res.offline = !isOnline() // TODO: refactor it to checking ES heartbit
- Logger.debug('Result from cache for ' + cacheKey + ' (' + entityType + '), ms=' + (new Date().getTime() - benchmarkTime.getTime()))()
-
- servedFromCache = true
- resolve(res)
- return
- }
- } catch (err) {
- Logger.error('Cannot read cache for ' + cacheKey + ', ' + err)()
- }
-
- /* use only for cache */
- if (Request.groupId) {
- delete Request.groupId
- }
-
- if (rootStore.state.user.groupToken) {
- Request.groupToken = rootStore.state.user.groupToken
- }
-
- if (!searchAdapter.entities[Request.type]) {
- throw new Error('No entity type registered for ' + Request.type)
- }
-
- searchAdapter.search(Request).then((resp) => { // we're always trying to populate cache - when online
- const res = searchAdapter.entities[Request.type].resultProcessor(resp, start, size)
-
- if (res) { // otherwise it can be just a offline mode
- cache.setItem(cacheKey, res, null, config.elasticsearch.disablePersistentQueriesCache).catch((err) => { Logger.error('Cannot store cache for ' + cacheKey + ', ' + err)() })
- if (!servedFromCache) { // if navigator onLine == false means ES is unreachable and probably this will return false; sometimes returned false faster than indexedDb cache returns result ...
- Logger.debug('Result from ES for ' + cacheKey + ' (' + entityType + '), ms=' + (new Date().getTime() - benchmarkTime.getTime()))()
- res.cache = false
- res.noresults = false
- res.offline = false
- resolve(res)
- }
- }
- }).catch(err => {
- if (!servedFromCache) {
- if (!isServer) {
- Logger.debug('No results and offline ' + cacheKey + ' (' + entityType + '), ms=' + (new Date().getTime() - benchmarkTime.getTime()))()
- const res = {
- items: [],
- total: 0,
- start: 0,
- perPage: 0,
- aggregations: {},
- offline: true,
- cache: true,
- noresults: true,
- suggestions: {}
- }
- resolve(res)
- } else {
- Logger.error('Can not connect the vue-storefront-api / ElasticSearch instance!', 'search', err)()
- reject(err)
- }
- }
- reject(err)
- })
- })
-}
diff --git a/core/lib/search/adapter/SeachAdapterInterface.ts b/core/lib/search/adapter/SeachAdapterInterface.ts
deleted file mode 100644
index 8178f558b5..0000000000
--- a/core/lib/search/adapter/SeachAdapterInterface.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-interface SearchAdapterInterface {
- search(Request: any): void,
- registerEntityType(entityType: string, options: any): void
-}
diff --git a/core/lib/search/adapter/api-search-query/searchAdapter.ts b/core/lib/search/adapter/api-search-query/searchAdapter.ts
deleted file mode 100644
index 5357c2571d..0000000000
--- a/core/lib/search/adapter/api-search-query/searchAdapter.ts
+++ /dev/null
@@ -1,160 +0,0 @@
-import map from 'lodash-es/map'
-import fetch from 'isomorphic-fetch'
-import { slugify, processURLAddress } from '@vue-storefront/core/helpers'
-import queryString from 'query-string'
-import { currentStoreView, prepareStoreView } from '@vue-storefront/core/lib/multistore'
-import { SearchQuery } from 'storefront-query-builder'
-import HttpQuery from '@vue-storefront/core/types/search/HttpQuery'
-import { SearchResponse } from '@vue-storefront/core/types/search/SearchResponse'
-import config from 'config'
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-
-export class SearchAdapter {
- public entities: any
-
- public constructor () {
- this.entities = []
- this.initBaseTypes()
- }
-
- protected decompactItem (item, fieldsToCompact) {
- for (let key in fieldsToCompact) {
- const value = fieldsToCompact[key]
- if (typeof item[value] !== 'undefined') {
- item[key] = item[value]
- delete item[value]
- }
- }
- return item
- }
-
- public async search (Request) {
- const rawQueryObject = Request.searchQuery
- if (!this.entities[Request.type]) {
- throw new Error('No entity type registered for ' + Request.type)
- }
- if (!(Request.searchQuery instanceof SearchQuery)) {
- throw new Error('The only supported type of the "Request.searchQuery" is "SearchQuery"')
- }
- if (Request.hasOwnProperty('groupId') && Request.groupId !== null) {
- rawQueryObject['groupId'] = Request.groupId
- }
- if (Request.hasOwnProperty('groupToken') && Request.groupToken !== null) {
- rawQueryObject['groupToken'] = Request.groupToken
- }
- if (Request.sort) {
- const [ field, options ] = Request.sort.split(':')
- rawQueryObject.applySort({ field, options })
- delete Request.sort
- }
- const storeView = (Request.store === null) ? currentStoreView() : await prepareStoreView(Request.store)
- Request.index = storeView.elasticsearch.index
-
- let url = processURLAddress(getApiEndpointUrl(storeView.elasticsearch, 'host'))
-
- if (this.entities[Request.type].url) {
- url = getApiEndpointUrl(this.entities[Request.type], 'url')
- }
-
- const httpQuery: HttpQuery = {
- size: Request.size,
- from: Request.from,
- sort: Request.sort,
- request_format: 'search-query',
- response_format: 'compact'
- }
-
- if (Request._sourceExclude) {
- httpQuery._source_exclude = Request._sourceExclude.join(',')
- }
- if (Request._sourceInclude) {
- httpQuery._source_include = Request._sourceInclude.join(',')
- }
- if (Request.q) {
- httpQuery.q = Request.q
- }
-
- if (!Request.index || !Request.type) {
- throw new Error('Query.index and Query.type are required arguments for executing ElasticSearch query')
- }
- if (config.elasticsearch.queryMethod === 'GET') {
- httpQuery.request = JSON.stringify(rawQueryObject)
- }
- url = url + '/' + encodeURIComponent(Request.index) + '/' + encodeURIComponent(Request.type) + '/_search'
- url = url + '?' + queryString.stringify(httpQuery)
- return fetch(url, { method: config.elasticsearch.queryMethod,
- mode: 'cors',
- headers: {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- },
- body: config.elasticsearch.queryMethod === 'POST' ? JSON.stringify(rawQueryObject) : null
- })
- .then(resp => { return resp.json() })
- .catch(error => {
- throw new Error('FetchError in request to API: ' + error.toString())
- })
- }
-
- public handleResult (resp, type, start = 0, size = 50): SearchResponse {
- if (resp === null) {
- throw new Error('Invalid API result - null not exepcted')
- }
- if (resp.hasOwnProperty('hits')) {
- return {
- items: map(resp.hits, hit => {
- if (type === 'product') {
- hit = this.decompactItem(hit, config.products.fieldsToCompact)
- if (hit.configurable_children) {
- hit.configurable_children = hit.configurable_children.map(childItem => {
- return this.decompactItem(childItem, config.products.fieldsToCompact)
- })
- }
- }
- return Object.assign(hit, { slug: hit.slug ? hit.slug : ((hit.hasOwnProperty('url_key') && config.products.useMagentoUrlKeys) ? hit.url_key : (hit.hasOwnProperty('name') ? slugify(hit.name) + '-' + hit.id : '')) }) // TODO: assign slugs server side
- }), // TODO: add scoring information
- total: resp.total,
- start: start,
- perPage: size,
- aggregations: resp.aggregations,
- attributeMetadata: resp.attribute_metadata,
- suggestions: resp.suggest
- }
- } else {
- if (resp.error) {
- throw new Error(JSON.stringify(resp.error))
- } else {
- throw new Error('Unknown error with API catalog result in resultProcessor for entity type \'' + type + '\'')
- }
- }
- }
-
- public registerEntityType (entityType, { url = '', url_ssr = '', queryProcessor, resultProcessor }) {
- this.entities[entityType] = {
- queryProcessor: queryProcessor,
- resultProcessor: resultProcessor
- }
- if (url !== '') {
- this.entities[entityType]['url'] = url
- }
- if (url_ssr !== '') {
- this.entities[entityType]['url_ssr'] = url_ssr
- }
- return this
- }
-
- public initBaseTypes () {
- const baseTypes = ['product', 'attribute', 'category', 'taxrule', 'review', 'cms_page', 'cms_block', 'cms_hierarchy']
- baseTypes.forEach(type => {
- this.registerEntityType(type, {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, type, start, size)
- }
- })
- })
- }
-}
diff --git a/core/lib/search/adapter/api/searchAdapter.ts b/core/lib/search/adapter/api/searchAdapter.ts
deleted file mode 100644
index 48c29a7b3d..0000000000
--- a/core/lib/search/adapter/api/searchAdapter.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-import map from 'lodash-es/map'
-import { elasticsearch } from 'storefront-query-builder'
-import fetch from 'isomorphic-fetch'
-import { slugify, processURLAddress } from '@vue-storefront/core/helpers'
-import queryString from 'query-string'
-import { currentStoreView, prepareStoreView } from '@vue-storefront/core/lib/multistore'
-import { SearchQuery } from 'storefront-query-builder'
-import HttpQuery from '@vue-storefront/core/types/search/HttpQuery'
-import { SearchResponse } from '@vue-storefront/core/types/search/SearchResponse'
-import config from 'config'
-import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl';
-
-export class SearchAdapter {
- public entities: any
-
- public constructor () {
- this.entities = []
- this.initBaseTypes()
- }
-
- public async search (Request) {
- if (!this.entities[Request.type]) {
- throw new Error('No entity type registered for ' + Request.type)
- }
- let ElasticsearchQueryBody = {}
- if (Request.searchQuery instanceof SearchQuery) {
- const bodybuilder = await import(/* webpackChunkName: "bodybuilder" */ 'bodybuilder')
- ElasticsearchQueryBody = await elasticsearch.buildQueryBodyFromSearchQuery({ config, queryChain: bodybuilder.default(), searchQuery: Request.searchQuery })
- if (Request.searchQuery.getSearchText() !== '') {
- ElasticsearchQueryBody['min_score'] = config.elasticsearch.min_score
- }
- } else {
- // backward compatibility for old themes uses bodybuilder
- ElasticsearchQueryBody = Request.searchQuery
- }
- if (Request.hasOwnProperty('groupId') && Request.groupId !== null) {
- ElasticsearchQueryBody['groupId'] = Request.groupId
- }
- if (Request.hasOwnProperty('groupToken') && Request.groupToken !== null) {
- ElasticsearchQueryBody['groupToken'] = Request.groupToken
- }
-
- const storeView = (Request.store === null) ? currentStoreView() : await prepareStoreView(Request.store)
-
- Request.index = storeView.elasticsearch.index
-
- let url = processURLAddress(getApiEndpointUrl(storeView.elasticsearch, 'host'))
-
- if (this.entities[Request.type].url) {
- url = getApiEndpointUrl(this.entities[Request.type], 'url')
- }
-
- const httpQuery: HttpQuery = {
- size: Request.size,
- from: Request.from,
- sort: Request.sort
- }
-
- if (Request._sourceExclude) {
- httpQuery._source_exclude = Request._sourceExclude.join(',')
- }
- if (Request._sourceInclude) {
- httpQuery._source_include = Request._sourceInclude.join(',')
- }
- if (Request.q) {
- httpQuery.q = Request.q
- }
-
- if (!Request.index || !Request.type) {
- throw new Error('Query.index and Query.type are required arguments for executing ElasticSearch query')
- }
- if (config.elasticsearch.queryMethod === 'GET') {
- httpQuery.request = JSON.stringify(ElasticsearchQueryBody)
- }
- url = url + '/' + encodeURIComponent(Request.index) + '/' + encodeURIComponent(Request.type) + '/_search'
- url = url + '?' + queryString.stringify(httpQuery)
-
- return fetch(url, {
- method: config.elasticsearch.queryMethod,
- mode: 'cors',
- headers: {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- },
- body: config.elasticsearch.queryMethod === 'POST' ? JSON.stringify(ElasticsearchQueryBody) : null
- })
- .then(resp => { return resp.json() })
- .catch(error => {
- throw new Error('FetchError in request to ES: ' + error.toString())
- })
- }
-
- public handleResult (resp, type, start = 0, size = 50): SearchResponse {
- if (resp === null) {
- throw new Error('Invalid ES result - null not exepcted')
- }
- if (resp.hasOwnProperty('hits')) {
- return {
- items: map(resp.hits.hits, hit => {
- return Object.assign(hit._source, { _score: hit._score, slug: hit._source.slug ? hit._source.slug : ((hit._source.hasOwnProperty('url_key') && config.products.useMagentoUrlKeys) ? hit._source.url_key : (hit._source.hasOwnProperty('name') ? slugify(hit._source.name) + '-' + hit._source.id : '')) }) // TODO: assign slugs server side
- }), // TODO: add scoring information
- total: resp.hits.total,
- start: start,
- perPage: size,
- aggregations: resp.aggregations,
- attributeMetadata: resp.attribute_metadata,
- suggestions: resp.suggest
- }
- } else {
- const isErrorObject = (resp && resp.code) >= 400 ? resp : null
- if (resp.error || isErrorObject) {
- throw new Error(JSON.stringify(resp.error || resp))
- } else {
- throw new Error('Unknown error with elasticsearch result in resultProcessor for entity type \'' + type + '\'')
- }
- }
- }
-
- public registerEntityType (entityType, { url = '', url_ssr = '', queryProcessor, resultProcessor }) {
- this.entities[entityType] = {
- queryProcessor: queryProcessor,
- resultProcessor: resultProcessor
- }
- if (url !== '') {
- this.entities[entityType]['url'] = url
- }
- if (url_ssr !== '') {
- this.entities[entityType]['url_ssr'] = url_ssr
- }
- return this
- }
-
- public initBaseTypes () {
- this.registerEntityType('product', {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, 'product', start, size)
- }
- })
-
- this.registerEntityType('attribute', {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, 'attribute', start, size)
- }
- })
-
- this.registerEntityType('category', {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, 'category', start, size)
- }
- })
-
- this.registerEntityType('taxrule', {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, 'taxrule', start, size)
- }
- })
-
- this.registerEntityType('review', {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, 'review', start, size)
- }
- })
- this.registerEntityType('cms_page', {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, 'cms_page', start, size)
- }
- })
- this.registerEntityType('cms_block', {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, 'cms_block', start, size)
- }
- })
- this.registerEntityType('cms_hierarchy', {
- queryProcessor: (query) => {
- // function that can modify the query each time before it's being executed
- return query
- },
- resultProcessor: (resp, start, size) => {
- return this.handleResult(resp, 'cms_hierarchy', start, size)
- }
- })
- }
-}
diff --git a/core/lib/search/adapter/searchAdapterFactory.js b/core/lib/search/adapter/searchAdapterFactory.js
deleted file mode 100644
index 9895d2eb6f..0000000000
--- a/core/lib/search/adapter/searchAdapterFactory.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { server } from 'config'
-let instances = {}
-
-const isImplementingSearchAdapterInterface = (obj) => {
- return typeof obj.search === 'function' && typeof obj.registerEntityType === 'function'
-}
-
-export const getSearchAdapter = async (adapterName = server.api) => {
- let SearchAdapterModule
-
- try {
- SearchAdapterModule = await import(/* webpackChunkName: "vsf-search-adapter-[request]" */ `src/search/adapter/${adapterName}/searchAdapter`)
- } catch {}
-
- if (!SearchAdapterModule) {
- try {
- SearchAdapterModule = await import(/* webpackChunkName: "vsf-search-adapter-[request]" */ `./${adapterName}/searchAdapter`)
- } catch {}
- }
-
- if (!SearchAdapterModule) {
- throw new Error('Search adapter module was not found in `src/search/adapter` neither in the `core/lib/search/adapter` folders')
- }
-
- const SearchAdapter = SearchAdapterModule.SearchAdapter
-
- if (!SearchAdapter) {
- throw new Error('Search adapter class is not provided')
- }
-
- if (instances[adapterName]) {
- return instances[adapterName]
- }
-
- const searchAdapter = new SearchAdapter()
- if (!isImplementingSearchAdapterInterface(searchAdapter)) {
- throw new Error('Not valid search adapter class provided. Search Adapter must implements SearchAdapterInterfaces')
- }
- instances[adapterName] = searchAdapter;
- return instances[adapterName];
-}
-
-export default {
- getSearchAdapter
-}
diff --git a/core/lib/search/adapter/test/unit/searchAdapterFactory.spec.ts b/core/lib/search/adapter/test/unit/searchAdapterFactory.spec.ts
deleted file mode 100644
index 9ffbb54f5b..0000000000
--- a/core/lib/search/adapter/test/unit/searchAdapterFactory.spec.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import { getSearchAdapter } from '@vue-storefront/core/lib/search/adapter/searchAdapterFactory'
-
-jest.mock('config', () => {
- return { server: { api: 'api' } };
-});
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {})
- }
-}));
-
-const mockSearchAdapterModule = {
- SearchAdapter: jest.fn().mockImplementation(() => {
- return {
- search: (Request: any): void => {
- },
- registerEntityType: (entityType: string, options: any): void => {
- }
- }
- })
-};
-
-describe('Search adapter factory tests', () => {
- it('Search adapter constructor called always only once', async () => {
- jest.mock('../../api/searchAdapter', () => {
- return mockSearchAdapterModule;
- })
-
- const apiSearchAdapter1 = await getSearchAdapter()
- const apiSearchAdapter2 = await getSearchAdapter('api')
- expect(mockSearchAdapterModule.SearchAdapter).toHaveBeenCalledTimes(1)
- })
-
- it('Search adapter class is not provided', async () => {
- jest.mock(
- '../../virtual/searchAdapter',
- () => {
- return {};
- },
- { virtual: true }
- )
-
- await expect(getSearchAdapter('virtual')).rejects.toThrowError(new Error('Search adapter class is not provided'))
- })
-
- it('Search adapter class has invalid search method', async () => {
- jest.mock(
- '../../invalidSearchMethod/searchAdapter',
- () => {
- return {
- SearchAdapter: jest.fn().mockImplementation(() => {
- return {
- search: 1,
- registerEntityType: (entityType: string, options: any): void => {
- }
- }
- })
- }
- },
- { virtual: true }
- )
-
- await expect(getSearchAdapter('invalidSearchMethod'))
- .rejects.toThrowError(
- new Error('Not valid search adapter class provided. Search Adapter must implements SearchAdapterInterfaces')
- )
- })
-
- it('Search adapter class has invalid registerEntityTypeMethod method', async () => {
- jest.mock(
- '../../invalidRegisterEntityTypeMethod/searchAdapter',
- () => {
- return {
- SearchAdapter: jest.fn().mockImplementation(() => {
- return {
- search: (Request: any): void => {
- },
- registerEntityType: 1
- }
- })
- }
- },
- { virtual: true }
- )
-
- await expect(getSearchAdapter('invalidRegisterEntityTypeMethod'))
- .rejects.toThrowError(
- new Error('Not valid search adapter class provided. Search Adapter must implements SearchAdapterInterfaces')
- )
- })
-})
diff --git a/core/lib/storage-manager.ts b/core/lib/storage-manager.ts
deleted file mode 100644
index 23b2c1e635..0000000000
--- a/core/lib/storage-manager.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import { Logger } from '@vue-storefront/core/lib/logger'
-import * as localForage from 'localforage'
-import UniversalStorage from '@vue-storefront/core/lib/store/storage'
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-import config from 'config'
-
-function _prepareCacheStorage (key, localized = !config.storeViews.commonCache, storageQuota = 0) {
- const storeView = currentStoreView()
- const dbNamePrefix = storeView && storeView.storeCode ? storeView.storeCode + '-' : ''
- const cacheDriver = config.localForage && config.localForage.defaultDrivers[key]
- ? config.localForage.defaultDrivers[key]
- : 'LOCALSTORAGE'
-
- return new UniversalStorage(localForage.createInstance({
- name: localized ? `${dbNamePrefix}shop` : 'shop',
- storeName: key,
- driver: localForage[cacheDriver]
- }), true, storageQuota)
-}
-
-const StorageManager = {
- currentStoreCode: '',
- storageMap: {},
- /**
- * Register the cache storage index that can be later accessed and modified - this is required prior to accessing the collection
- * @param collectionName name of the cache collection to create
- * @param isLocalized if set to `false` data will be shared between storeViews (default `true`)
- * @param storageQuota max size of storage, 0 if unlimited (default `0`)
- */
- init: function (collectionName: string, isLocalized = !config.storeViews.commonCache, storageQuota = 0) {
- this.storageMap[collectionName] = _prepareCacheStorage(collectionName, isLocalized, storageQuota)
- return this.storageMap[collectionName]
- },
- /**
- * Override or register the cache storage - this is required prior to accessing the collection
- * @param collectionName { string} string name of the cache collection to register
- * @param item UniversalStorage driver
- */
- set: function (collectionName: string, collectionInstance: UniversalStorage): UniversalStorage {
- this.storageMap[collectionName] = collectionInstance
- return collectionInstance
- },
- /**
- * Check if the specified collection is already registered
- * @param collectionName string collection name to check
- */
- exists (collectionName): boolean {
- return !!this.storageMap[collectionName]
- },
- /**
- * Returns the UniversalStorage driver for specific key.
- * If it doesnt exist it creates it with defaults for `init`
- * @returns UniversalStorage
- */
- get: function (collectionName): UniversalStorage {
- if (!this.exists(collectionName)) {
- Logger.warn('Called cache collection ' + collectionName + ' does not exist. Initializing.', 'cache')
- return this.set(collectionName, initCacheStorage(collectionName, true)) // eslint-disable-line @typescript-eslint/no-use-before-define
- } else {
- return this.storageMap[collectionName]
- }
- },
- clear (): Promise {
- const promiseArray = Object.keys(this.storageMap).map((collectionName) => {
- return (config.localForage.preserveCollections || []).every(collectionToKeep => collectionName !== collectionToKeep) && this.storageMap[collectionName].clear().then(() => {
- Logger.warn(`storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`, `storeManager cleared: ${collectionName}`)()
- })
- })
- return Promise.all(promiseArray)
- }
-}
-
-/**
- * @deprecated to be removed in 2.0 in favor to `StorageManager`
- * */
-function initCacheStorage (key, localised = true, registerStorgeManager = true) {
- if (registerStorgeManager) {
- if (!StorageManager.exists(key)) {
- return StorageManager.set(key, _prepareCacheStorage(key, localised))
- } else {
- return StorageManager.get(key)
- }
- } else {
- return _prepareCacheStorage(key, localised)
- }
-}
-
-export { StorageManager, initCacheStorage }
diff --git a/core/lib/store/entities.ts b/core/lib/store/entities.ts
deleted file mode 100644
index 76c6ebc881..0000000000
--- a/core/lib/store/entities.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * @returns {string}
- */
-export function guid () {
- function s4 () {
- return Math.floor((1 + Math.random()) * 0x10000)
- .toString(16)
- .substring(1)
- }
- return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
- s4() + '-' + s4() + s4() + s4()
-}
-/**
- * Return unique entity.id
- * @param {Object} entity
- */
-export function uniqueEntityId (entity) {
- return new Date().getTime() + '-' + guid()
-}
-
-/**
- * Return unique entity key name for specified key value
- * @param {String} key
- * @param {String} value
- */
-export function entityKeyName (...values) {
- return values.join('$$')
-}
diff --git a/core/lib/store/filters.ts b/core/lib/store/filters.ts
deleted file mode 100644
index 886b52f52d..0000000000
--- a/core/lib/store/filters.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import decode from 'lean-he/decode'
-
-/**
- * Decodes any named and numerical character references in the text
- * @param {String} value
- */
-export function htmlDecode (value: any) {
- return value ? decode(value) : ''
-}
diff --git a/core/lib/store/storage.ts b/core/lib/store/storage.ts
deleted file mode 100644
index 792c5d7c6f..0000000000
--- a/core/lib/store/storage.ts
+++ /dev/null
@@ -1,376 +0,0 @@
-import * as localForage from 'localforage'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { isServer } from '@vue-storefront/core/helpers'
-import cloneDeep from 'lodash-es/cloneDeep'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-
-const CACHE_TIMEOUT = 800
-const CACHE_TIMEOUT_ITERATE = 2000
-const DISABLE_PERSISTANCE_AFTER = 1
-const DISABLE_PERSISTANCE_AFTER_SAVE = 30
-
-const _globalCache = {}
-
-function roughSizeOfObject (object) {
- const objectList = []
- const stack = [ object ]
- let bytes = 0
- while (stack.length) {
- const value = stack.pop()
- if (typeof value === 'boolean') {
- bytes += 4
- } else if (typeof value === 'string') {
- bytes += value.length * 2
- } else if (typeof value === 'number') {
- bytes += 8
- } else if (
- typeof value === 'object' &&
- objectList.indexOf(value) === -1
- ) {
- objectList.push(value)
- for (var i in value) {
- stack.push(value[ i ])
- }
- }
- }
- return bytes
-}
-
-interface CacheTimeouts {
- getItem: any,
- iterate: any,
- setItem: any,
- base: any
-}
-
-class LocalForageCacheDriver {
- private _collectionName: string;
- private _dbName: string;
- private _lastError: any;
- private _localCache: any;
- private _localForageCollection: any;
- private _persistenceErrorNotified: boolean;
- private _useLocalCacheByDefault: boolean;
- private cacheErrorsCount: any;
- private _storageQuota: number;
- private _cacheTimeouts: CacheTimeouts = {
- getItem: null,
- iterate: null,
- setItem: null,
- base: null
- }
-
- public constructor (collection, useLocalCacheByDefault = true, storageQuota = 0) {
- const collectionName = collection._config.storeName
- const dbName = collection._config.name
- this._storageQuota = storageQuota
-
- if (this._storageQuota && !isServer) {
- const storageQuota = this._storageQuota
- const iterateFnc = this.iterate.bind(this)
- const removeItemFnc = this.removeItem.bind(this)
- clearInterval(this._cacheTimeouts.base)
- this._cacheTimeouts.base = setInterval(() => {
- let storageSize = 0
- this.iterate((item, id, number) => {
- storageSize += roughSizeOfObject(item)
- }, (err, result) => { // eslint-disable-line handle-callback-err
- if ((storageSize / 1024) > storageQuota) {
- Logger.info('Clearing out the storage ', 'cache', { storageSizeKB: Math.round(storageSize / 1024), storageQuotaKB: storageQuota })()
- const howManyItemsToRemove = 100
- const keysPurged = []
- iterateFnc((item, id, number) => {
- if (number < howManyItemsToRemove) {
- removeItemFnc(id)
- keysPurged.push(id)
- }
- }, (err, result) => { // eslint-disable-line handle-callback-err
- Logger.info('Cache purged', 'cache', { keysPurged })()
- })
- } else {
- Logger.info('Storage size', 'cache', { storageSizeKB: Math.round(storageSize / 1024) })()
- }
- })
- }, 30000)
- }
- if (typeof this.cacheErrorsCount === 'undefined') {
- this.cacheErrorsCount = {}
- }
- if (typeof this.cacheErrorsCount[collectionName] === 'undefined') {
- this.cacheErrorsCount[collectionName] = 0
- }
- if (isServer) {
- this._localCache = {}
- } else {
- if (typeof _globalCache[dbName] === 'undefined') {
- _globalCache[dbName] = {}
- }
- if (typeof _globalCache[dbName][collectionName] === 'undefined') {
- _globalCache[dbName][collectionName] = {}
- }
- this._localCache = _globalCache[dbName][collectionName]
- }
- this._collectionName = collectionName
- this._dbName = dbName
- this._useLocalCacheByDefault = useLocalCacheByDefault
- this._localForageCollection = collection
- this._lastError = null
- this._persistenceErrorNotified = false
- }
-
- public getLastError () {
- return this._lastError
- }
-
- public getDbName () {
- return this._dbName
- }
-
- // Remove all keys from the datastore, effectively destroying all data in
- // the app's key/value store!
- public clear (callback?) {
- return this._localForageCollection.clear(callback)
- }
-
- // Increment the database version number and recreate the context
- public recreateDb () {
- if (this._localForageCollection._config) {
- const existingConfig = Object.assign({}, this._localForageCollection._config)
- if (existingConfig.storeName) {
- // localForage.dropInstance(existingConfig) // drop the store and create the new one
- const destVersionNumber = this._localForageCollection && this._localForageCollection._dbInfo ? this._localForageCollection._dbInfo.version + 1 : 0
- if (destVersionNumber > 0) {
- this._localForageCollection = localForage.createInstance({ ...existingConfig, version: destVersionNumber })
- } else {
- this._localForageCollection = localForage.createInstance(existingConfig)
- }
- Logger.log('DB recreated with', existingConfig, destVersionNumber)()
- }
- }
- }
-
- public getLocalCache (key) {
- return typeof this._localCache[key] !== 'undefined' ? cloneDeep(this._localCache[key]) : null
- }
-
- // Retrieve an item from the store. Unlike the original async_storage
- // library in Gaia, we don't modify return values at all. If a key's value
- // is `undefined`, we pass that value to the callback function.
- public getItem (key, callback?) {
- const isCallbackCallable = (typeof callback !== 'undefined' && callback)
- let isResolved = false
- if (this._useLocalCacheByDefault && this._localCache[key]) {
- // Logger.debug('Local cache fallback for GET', key)()
- return new Promise((resolve, reject) => {
- const value = this.getLocalCache(key)
- if (isCallbackCallable) callback(null, value)
- resolve(value)
- })
- }
-
- if (!isServer) {
- if (this.cacheErrorsCount[this._collectionName] >= DISABLE_PERSISTANCE_AFTER && this._useLocalCacheByDefault) {
- if (!this._persistenceErrorNotified) {
- Logger.error('Persistent cache disabled becasue of previous errors [get]', key)()
- this._persistenceErrorNotified = true
- }
- return new Promise((resolve, reject) => {
- if (isCallbackCallable) callback(null, null)
- resolve(null)
- })
- } else {
- const startTime = new Date().getTime()
- // Logger.debug('No local cache fallback for GET', key)()
- const promise = this._localForageCollection.ready().then(() => this._localForageCollection.getItem(key).then(result => {
- const endTime = new Date().getTime()
- const clonedResult = cloneDeep(result)
- if ((endTime - startTime) >= CACHE_TIMEOUT) {
- Logger.error('Cache promise resolved after [ms]' + key + (endTime - startTime))()
- }
- if (!this._localCache[key] && clonedResult) {
- this._localCache[key] = clonedResult // populate the local cache for the next call
- }
- if (!isResolved) {
- if (isCallbackCallable) {
- callback(null, clonedResult)
- }
- isResolved = true
- } else {
- Logger.debug('Skipping return value as it was previously resolved')()
- }
- return clonedResult
- }).catch(err => {
- this._lastError = err
- if (!isResolved) {
- const value = this.getLocalCache(key)
- if (isCallbackCallable) callback(null, value)
- }
- Logger.error(err)()
- isResolved = true
- }))
- clearTimeout(this._cacheTimeouts.getItem)
- this._cacheTimeouts.getItem = setTimeout(() => {
- if (!isResolved) { // this is cache time out check
- if (!this._persistenceErrorNotified) {
- Logger.error('Cache not responding for ' + key + '.', 'cache', { timeout: CACHE_TIMEOUT, errorsCount: this.cacheErrorsCount[this._collectionName] })()
- this._persistenceErrorNotified = true
- this.recreateDb()
- }
- this.cacheErrorsCount[this._collectionName] = this.cacheErrorsCount[this._collectionName] ? this.cacheErrorsCount[this._collectionName] + 1 : 1
- const value = this.getLocalCache(key)
- if (isCallbackCallable) callback(null, value)
- }
- }, CACHE_TIMEOUT)
- return promise
- }
- } else {
- return new Promise((resolve, reject) => {
- const value = this.getLocalCache(key)
- if (isCallbackCallable) callback(null, value)
- resolve(value)
- })
- }
- }
-
- // Iterate over all items in the store.
- public iterate (iterator, callback?) {
- const isIteratorCallable = (typeof iterator !== 'undefined' && iterator)
- const isCallbackCallable = (typeof callback !== 'undefined' && callback)
- let globalIterationNumber = 1
- if (this._useLocalCacheByDefault) {
- // Logger.debug('Local cache iteration')()
- for (const localKey in this._localCache) {
- if (isIteratorCallable) {
- iterator(this._localCache[localKey], localKey, globalIterationNumber)
- globalIterationNumber++
- }
- }
- }
- let isResolved = false
- const promise = this._localForageCollection.ready().then(() => this._localForageCollection.iterate((value, key, iterationNumber) => {
- isResolved = true
- if (isIteratorCallable) {
- if (this._useLocalCacheByDefault) {
- if (typeof this._localCache[key] === 'undefined') {
- iterator(value, key, globalIterationNumber)
- globalIterationNumber++
- } else {
- // Logger.debug('Skipping iteration key because local cache executed', key)()
- }
- } else {
- iterator(value, key, iterationNumber)
- }
- }
- }, (err, result) => {
- if (isCallbackCallable) callback(err, result)
- isResolved = true
- })).catch(err => {
- this._lastError = err
- Logger.error(err)()
- if (!isResolved) {
- isResolved = true
- if (isCallbackCallable) callback(err, null)
- }
- })
- clearTimeout(this._cacheTimeouts.iterate)
- this._cacheTimeouts.iterate = setTimeout(() => {
- if (!isResolved) { // this is cache time out check
- if (!this._persistenceErrorNotified) {
- Logger.error('Cache not responding. (iterate)', 'cache', { timeout: CACHE_TIMEOUT, errorsCount: this.cacheErrorsCount[this._collectionName] })()
- this._persistenceErrorNotified = true
- this.recreateDb()
- }
- this.cacheErrorsCount[this._collectionName] = this.cacheErrorsCount[this._collectionName] ? this.cacheErrorsCount[this._collectionName] + 1 : 1
- if (isCallbackCallable) callback(null, null)
- }
- }, CACHE_TIMEOUT_ITERATE)
- return promise
- }
-
- // Same as localStorage's key() method, except takes a callback.
- public key (n, callback?) {
- return this._localForageCollection.key(n, callback)
- }
-
- public keys (callback?) {
- return this._localForageCollection.keys(callback)
- }
-
- // Supply the number of keys in the datastore to the callback function.
- public length (callback?) {
- return this._localForageCollection.length(callback)
- }
-
- // Remove an item from the store, nice and simple.
- public removeItem (key, callback?) {
- if (typeof this._localCache[key] !== 'undefined') {
- delete this._localCache[key]
- }
- return this._localForageCollection.removeItem(key, callback)
- }
-
- // Set a key's value and run an optional callback once the value is set.
- // Unlike Gaia's implementation, the callback function is passed the value,
- // in case you want to operate on that value only after you're sure it
- // saved, or something like that.
- public setItem (key, value, callback?, memoryOnly = false) {
- const isCallbackCallable = (typeof callback !== 'undefined' && callback)
- const copiedValue = cloneDeep(value)
- this._localCache[key] = copiedValue
- if (memoryOnly) {
- return new Promise((resolve, reject) => {
- if (isCallbackCallable) callback(null, null)
- resolve(null)
- })
- }
- if (!isServer) {
- if (this.cacheErrorsCount[this._collectionName] >= DISABLE_PERSISTANCE_AFTER_SAVE && this._useLocalCacheByDefault) {
- if (!this._persistenceErrorNotified) {
- Logger.error('Persistent cache disabled becasue of previous errors [set]', key)()
- this._persistenceErrorNotified = true
- }
- return new Promise((resolve, reject) => {
- if (isCallbackCallable) callback(null, null)
- resolve(null)
- })
- } else {
- let isResolved = false
- const handleSetItem = () => this._localForageCollection.setItem(key, copiedValue)
- .then(result => {
- if (isCallbackCallable) {
- callback(null, result)
- }
- isResolved = true
- })
- .catch(async err => {
- if (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
- await StorageManager.clear()
- handleSetItem()
- }
- isResolved = true
- this._lastError = err
- throw err
- })
- const promise = this._localForageCollection.ready().then(handleSetItem)
- clearTimeout(this._cacheTimeouts.iterate)
- this._cacheTimeouts.setItem = setTimeout(() => {
- if (!isResolved) { // this is cache time out check
- if (!this._persistenceErrorNotified) {
- Logger.error('Cache not responding for ' + key + '.', 'cache', { timeout: CACHE_TIMEOUT, errorsCount: this.cacheErrorsCount[this._collectionName] })()
- this._persistenceErrorNotified = true
- this.recreateDb()
- }
- this.cacheErrorsCount[this._collectionName] = this.cacheErrorsCount[this._collectionName] ? this.cacheErrorsCount[this._collectionName] + 1 : 1
- if (isCallbackCallable) callback(null, null)
- }
- }, CACHE_TIMEOUT)
- return promise
- }
- } else {
- return new Promise((resolve, reject) => resolve())
- }
- }
-}
-
-// The actual localForage object that we expose as a module. It's extended by pulling in one of our other libraries.
-export default LocalForageCacheDriver
diff --git a/core/lib/storeCodeFromRoute.ts b/core/lib/storeCodeFromRoute.ts
deleted file mode 100644
index 57b9567141..0000000000
--- a/core/lib/storeCodeFromRoute.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { RawLocation } from 'vue-router'
-import config from 'config'
-import { LocalizedRoute } from './types'
-
-const getNormalizedPath = (matchedRouteOrUrl) => {
- const matchingPath = matchedRouteOrUrl && (matchedRouteOrUrl.path || matchedRouteOrUrl)
-
- return matchingPath && (matchingPath.length > 0 && matchingPath[0] !== '/') ? `/${matchingPath}` : matchingPath
-}
-
-const getUrl = (matchedRouteOrUrl) => {
- const normalizedPath = getNormalizedPath(matchedRouteOrUrl)
-
- if (matchedRouteOrUrl && typeof matchedRouteOrUrl === 'object') {
- if (matchedRouteOrUrl['host']) {
- return matchedRouteOrUrl['host'] + normalizedPath
- }
-
- return ''
- }
-
- return matchedRouteOrUrl
-}
-
-const isMatchingByPath = (matchedRouteOrUrl, store) => {
- const normalizedPath = getNormalizedPath(matchedRouteOrUrl)
- return normalizedPath.startsWith(`${store.url}/`) || normalizedPath === store.url
-}
-
-const isMatchingByDomainAndPath = (matchedRouteOrUrl, store) => {
- const url = getUrl(matchedRouteOrUrl)
- return url.startsWith(`${store.url}/`) || url === store.url
-}
-
-const storeCodeFromRoute = (matchedRouteOrUrl: LocalizedRoute | RawLocation | string): string => {
- if (!matchedRouteOrUrl) return ''
-
- for (let storeCode of config.storeViews.mapStoreUrlsFor) {
- const store = config.storeViews[storeCode]
-
- if (isMatchingByPath(matchedRouteOrUrl, store) || isMatchingByDomainAndPath(matchedRouteOrUrl, store)) {
- return storeCode
- }
- }
-
- return ''
-}
-
-export default storeCodeFromRoute
diff --git a/core/lib/sync/helpers/index.ts b/core/lib/sync/helpers/index.ts
deleted file mode 100644
index 76bac21d1e..0000000000
--- a/core/lib/sync/helpers/index.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-export const hasResponseError = (jsonResponse): boolean => {
- if (typeof jsonResponse.result === 'string') {
- return true
- }
-
- const hasMessage = jsonResponse.result.result || jsonResponse.result.message
-
- return Boolean(hasMessage) && jsonResponse.result.code !== 'ENOTFOUND'
-}
-
-export const getResponseMessage = (jsonResponse): string => {
- if (typeof jsonResponse.result === 'string') {
- return jsonResponse.result
- }
-
- if (typeof jsonResponse.result.result === 'string') {
- return jsonResponse.result.result
- }
-
- return jsonResponse.result.message
-}
diff --git a/core/lib/sync/index.ts b/core/lib/sync/index.ts
deleted file mode 100644
index 999d37b7af..0000000000
--- a/core/lib/sync/index.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-
-import Vue from 'vue'
-import rootStore from '@vue-storefront/core/store'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { execute as taskExecute, _prepareTask } from './task'
-import { isServer } from '@vue-storefront/core/helpers'
-import config from 'config'
-import Task from '@vue-storefront/core/lib/sync/types/Task'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-
-/** Syncs given task. If user is offline request will be sent to the server after restored connection */
-async function queue (task) {
- const tasksCollection = StorageManager.get('syncTasks')
- task = _prepareTask(task)
- Logger.info('Sync task queued ' + task.url, 'sync', { task })()
- return new Promise((resolve, reject) => {
- tasksCollection.setItem(task.task_id.toString(), task, (err, resp) => {
- if (err) Logger.error(err, 'sync')()
- EventBus.$emit('sync/PROCESS_QUEUE', { config: config }) // process checkout queue
- resolve(task)
- }, config.syncTasks.disablePersistentTaskQueue).catch((reason) => {
- Logger.error(reason, 'sync')() // it doesn't work on SSR
- reject(reason)
- })
- })
-}
-
-/** Runs given task. If user is offline request will fail */
-async function execute (task): Promise { // not offline task
- task = _prepareTask(task)
- return new Promise((resolve, reject) => {
- if (isServer) {
- taskExecute(task, null, null).then((result) => {
- resolve(result)
- }).catch(err => {
- reject(err)
- })
- } else {
- const currentUserToken = rootStore.getters['user/getUserToken']
- const currentCartToken = rootStore.getters['cart/getCartToken']
- taskExecute(task, currentUserToken, currentCartToken).then((result) => {
- resolve(result)
- }).catch(err => {
- reject(err)
- })
- }
- })
-}
-
-/** Clear sync tasks that were not transmitted yet */
-function clearNotTransmited () {
- const syncTaskCollection = StorageManager.get('syncTasks')
- syncTaskCollection.iterate((task, id, iterationNumber) => {
- if (!task.transmited) {
- syncTaskCollection.removeItem(id)
- }
- })
-}
-
-export const TaskQueue = {
- queue,
- execute,
- clearNotTransmited
-}
diff --git a/core/lib/sync/task.ts b/core/lib/sync/task.ts
deleted file mode 100644
index 30eba0353b..0000000000
--- a/core/lib/sync/task.ts
+++ /dev/null
@@ -1,243 +0,0 @@
-import i18n from '@vue-storefront/i18n'
-import isNaN from 'lodash-es/isNaN'
-import isUndefined from 'lodash-es/isUndefined'
-import fetch from 'isomorphic-fetch'
-import rootStore from '@vue-storefront/core/store'
-import { adjustMultistoreApiUrl, currentStoreView } from '@vue-storefront/core/lib/multistore'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import Task from '@vue-storefront/core/lib/sync/types/Task'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { TaskQueue } from '@vue-storefront/core/lib/sync'
-import * as entities from '@vue-storefront/core/lib/store/entities'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import { processURLAddress } from '@vue-storefront/core/helpers'
-import { serial } from '@vue-storefront/core/helpers'
-import config from 'config'
-import { onlineHelper } from '@vue-storefront/core/helpers'
-import { hasResponseError, getResponseMessage } from '@vue-storefront/core/lib/sync/helpers'
-import queryString from 'query-string'
-
-export function _prepareTask (task) {
- const taskId = entities.uniqueEntityId(task) // timestamp as a order id is not the best we can do but it's enough
- task.task_id = taskId.toString()
- task.transmited = false
- task.created_at = new Date()
- task.updated_at = new Date()
- return task
-}
-
-function _sleep (time) {
- return new Promise((resolve) => setTimeout(resolve, time))
-}
-
-function getUrl (task, currentToken, currentCartId) {
- let url = task.url
- .replace('{{token}}', (currentToken == null) ? '' : currentToken)
- .replace('{{cartId}}', (currentCartId == null) ? '' : currentCartId)
-
- url = processURLAddress(url); // use relative url paths
- if (config.storeViews.multistore) {
- url = adjustMultistoreApiUrl(url)
- }
-
- if (config.users.tokenInHeader) {
- const parsedUrl = queryString.parseUrl(url)
- delete parsedUrl['query']['token']
- url = queryString.stringifyUrl(parsedUrl)
- }
-
- return url
-}
-
-function getPayload (task, currentToken) {
- const payload = {
- ...task.payload,
- headers: {
- ...task.payload.headers,
- ...(config.users.tokenInHeader ? { authorization: `Bearer ${currentToken}` } : {})
- }
- }
- return payload
-}
-
-function _internalExecute (resolve, reject, task: Task, currentToken, currentCartId) {
- if (currentToken && rootStore.state.userTokenInvalidateLock > 0) { // invalidate lock set
- Logger.log('Waiting for rootStore.state.userTokenInvalidateLock to release for ' + task.url, 'sync')()
- _sleep(1000).then(() => {
- Logger.log('Another try for rootStore.state.userTokenInvalidateLock for ' + task.url, 'sync')()
- _internalExecute(resolve, reject, task, currentToken, currentCartId)
- })
- return // return but not resolve
- } else if (rootStore.state.userTokenInvalidateLock < 0) {
- Logger.error('Aborting the network task' + task.url + rootStore.state.userTokenInvalidateLock, 'sync')()
- resolve({ code: 401, result: i18n.t('Error refreshing user token. User is not authorized to access the resource') })()
- return
- } else {
- if (rootStore.state.userTokenInvalidated) {
- Logger.log('Using new user token' + rootStore.state.userTokenInvalidated, 'sync')()
- currentToken = rootStore.state.userTokenInvalidated
- }
- }
- const isCartIdRequired = task.url.includes('{{cartId}}') // this is bypass for #2592
- if (isCartIdRequired && !currentCartId) { // by some reason we does't have the cart id yet
- reject('Error executing sync task ' + task.url + ' the required cartId argument is null. Re-creating shopping cart synchro.')
- return
- }
- const url = getUrl(task, currentToken, currentCartId)
- const payload = getPayload(task, currentToken)
- let silentMode = false
- Logger.info('Executing sync task ' + url, 'sync', task)()
- return fetch(url, payload).then((response) => {
- const contentType = response.headers.get('content-type')
- if (contentType && contentType.includes('application/json')) {
- return response.json()
- } else {
- const msg = i18n.t('Error with response - bad content-type!')
- Logger.error(msg.toString(), 'sync')()
- reject(msg)
- }
- }).then((jsonResponse) => {
- if (jsonResponse) {
- const responseCode = parseInt(jsonResponse.code)
- if (responseCode !== 200) {
- if (responseCode === 401 /** unauthorized */ && currentToken) { // the token is no longer valid, try to invalidate it
- Logger.error('Invalid token - need to be revalidated' + currentToken + task.url + rootStore.state.userTokenInvalidateLock, 'sync')()
- silentMode = true
- if (config.users.autoRefreshTokens) {
- if (!rootStore.state.userTokenInvalidateLock) {
- rootStore.state.userTokenInvalidateLock++
- if (rootStore.state.userTokenInvalidateAttemptsCount >= config.queues.maxNetworkTaskAttempts) {
- Logger.error('Internal Application error while refreshing the tokens. Please clear the storage and refresh page.', 'sync')()
- rootStore.state.userTokenInvalidateLock = -1
- rootStore.dispatch('user/logout', { silent: true })
- TaskQueue.clearNotTransmited()
- EventBus.$emit('modal-show', 'modal-signup')
- rootStore.dispatch('notification/spawnNotification', {
- type: 'error',
- message: i18n.t('Internal Application error while refreshing the tokens. Please clear the storage and refresh page.'),
- action1: { label: i18n.t('OK') }
- })
- rootStore.state.userTokenInvalidateAttemptsCount = 0
- } else {
- Logger.info('Invalidation process in progress (autoRefreshTokens is set to true)' + rootStore.state.userTokenInvalidateAttemptsCount + rootStore.state.userTokenInvalidateLock, 'sync')()
- rootStore.state.userTokenInvalidateAttemptsCount++
- rootStore.dispatch('user/refresh').then((token) => {
- if (token) {
- rootStore.state.userTokenInvalidateLock = 0
- rootStore.state.userTokenInvalidated = token
- Logger.info('User token refreshed successfully' + token, 'sync')()
- } else {
- rootStore.state.userTokenInvalidateLock = -1
- rootStore.dispatch('user/logout', { silent: true })
- EventBus.$emit('modal-show', 'modal-signup')
- TaskQueue.clearNotTransmited()
- Logger.error('Error refreshing user token' + token, 'sync')()
- }
- }).catch((excp) => {
- rootStore.state.userTokenInvalidateLock = -1
- rootStore.dispatch('user/logout', { silent: true })
- EventBus.$emit('modal-show', 'modal-signup')
- TaskQueue.clearNotTransmited()
- Logger.error('Error refreshing user token' + excp, 'sync')()
- })
- }
- }
- if (rootStore.state.userTokenInvalidateAttemptsCount <= config.queues.maxNetworkTaskAttempts) _internalExecute(resolve, reject, task, currentToken, currentCartId) // retry
- } else {
- Logger.info('Invalidation process is disabled (autoRefreshTokens is set to false)', 'sync')()
- rootStore.dispatch('user/logout', { silent: true })
- EventBus.$emit('modal-show', 'modal-signup')
- }
- }
-
- if (!task.silent && jsonResponse.result && hasResponseError(jsonResponse) && !silentMode) {
- rootStore.dispatch('notification/spawnNotification', {
- type: 'error',
- message: i18n.t(getResponseMessage(jsonResponse)),
- action1: { label: i18n.t('OK') }
- })
- }
- }
-
- Logger.debug('Response for: ' + task.task_id + ' = ' + JSON.stringify(jsonResponse.result), 'sync')()
- task.transmited = true
- task.transmited_at = new Date()
- task.result = jsonResponse.result
- task.resultCode = jsonResponse.code
- task.code = jsonResponse.code // backward compatibility to fetch()
- task.acknowledged = false
- task.meta = jsonResponse.meta
-
- if (task.callback_event) {
- if (task.callback_event.startsWith('store:')) {
- rootStore.dispatch(task.callback_event.split(':')[1], task)
- } else {
- EventBus.$emit(task.callback_event, task)
- }
- }
- if (!rootStore.state.userTokenInvalidateLock) { // in case we're revalidaing the token - user must wait for it
- resolve(task)
- }
- } else {
- const msg = i18n.t('Unhandled error, wrong response format!')
- Logger.error(msg.toString(), 'sync')()
- reject(msg)
- }
- }).catch((err) => {
- Logger.error(err, 'sync')()
- reject(err)
- })
-}
-
-export function execute (task: Task, currentToken = null, currentCartId = null): Promise {
- const taskId = task.task_id
-
- return new Promise((resolve, reject) => {
- _internalExecute(resolve, reject, task, currentToken, currentCartId)
- })
-}
-
-export function initializeSyncTaskStorage () {
- const storeView = currentStoreView()
- const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : ''
-
- StorageManager.init('syncTasks')
-}
-
-export function registerSyncTaskProcessor () {
- const mutex = {}
- EventBus.$on('sync/PROCESS_QUEUE', async data => {
- if (onlineHelper.isOnline) {
- // event.data.config - configuration, endpoints etc
- const syncTaskCollection = StorageManager.get('syncTasks')
- const currentUserToken = rootStore.getters['user/getUserToken']
- const currentCartToken = rootStore.getters['cart/getCartToken']
-
- const fetchQueue = []
- Logger.debug('Current User token = ' + currentUserToken)()
- Logger.debug('Current Cart token = ' + currentCartToken)()
- syncTaskCollection.iterate((task, id) => {
- if (task && !task.transmited && !mutex[id]) { // not sent to the server yet
- mutex[id] = true // mark this task as being processed
- fetchQueue.push(execute(task, currentUserToken, currentCartToken).then(executedTask => {
- if (!executedTask.is_result_cacheable) {
- syncTaskCollection.removeItem(id) // remove successfully executed task from the queue
- } else {
- syncTaskCollection.setItem(id, executedTask) // update the 'transmitted' field
- }
- mutex[id] = false
- }).catch(err => {
- mutex[id] = false
- Logger.error(err)()
- }))
- }
- }, (err) => {
- if (err) Logger.error(err)()
- Logger.debug('Iteration has completed')()
- // execute them serially
- serial(fetchQueue)
- Logger.debug('Processing sync tasks queue has finished')()
- })
- }
- })
-}
diff --git a/core/lib/sync/types/Task.ts b/core/lib/sync/types/Task.ts
deleted file mode 100644
index 1f723160b3..0000000000
--- a/core/lib/sync/types/Task.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export default interface Task {
- acknowledged: boolean,
- callback_event: string,
- code: number,
- payload: any,
- result: any,
- resultCode: number,
- silent: boolean,
- task_id: number,
- transmited: boolean,
- transmited_at: Date,
- url: string,
- is_result_cacheable?: boolean,
- meta: any
-}
diff --git a/core/lib/test/unit/logger.spec.ts b/core/lib/test/unit/logger.spec.ts
deleted file mode 100644
index 6713f7a1ad..0000000000
--- a/core/lib/test/unit/logger.spec.ts
+++ /dev/null
@@ -1,403 +0,0 @@
-import * as coreHelper from '@vue-storefront/core/helpers'
-import config from 'config'
-
-jest.mock('config', () => ({}))
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return true
- }
-}))
-
-describe('Logger', () => {
- const isServerSpy = jest.spyOn((coreHelper as any).default, 'isServer', 'get')
- const consoleDebugSpy = jest.spyOn(console, 'debug')
- const consoleErrorSpy = jest.spyOn(console, 'error')
- const consoleInfoSpy = jest.spyOn(console, 'log')
- const consoleWarnSpy = jest.spyOn(console, 'warn')
- const env = process.env
-
- consoleDebugSpy.mockImplementation(() => {})
- consoleErrorSpy.mockImplementation(() => {})
- consoleInfoSpy.mockImplementation(() => {})
- consoleWarnSpy.mockImplementation(() => {})
-
- beforeEach(() => {
- jest.clearAllMocks()
- config.console = {
- verbosityLevel: 'display-everything',
- showErrorOnProduction: true
- }
- process.env = Object.assign({}, env)
- })
-
- it('can be initialized with default settings', () => {
- jest.isolateModules(() => {
- config.console = {}
-
- expect(require('../../logger').Logger).toBeTruthy()
- })
- })
-
- describe('convertToString', () => {
- it('serializes objects to string', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- expect(Logger.convertToString({ foo: 'bar' })).toBe('{"foo":"bar"}')
- })
- })
-
- it('extracts message from complex objects (i.e. error)', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- expect(Logger.convertToString({ message: 'foo' })).toBe('foo')
- })
- })
- it('returns primitive payloads unchanged', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- expect(Logger.convertToString('foo')).toBe('foo')
- expect(Logger.convertToString(true)).toBe(true)
- expect(Logger.convertToString(1337)).toBe(1337)
- })
- })
- })
-
- describe('canPrint', () => {
- it('allows all types of logs when verbosity is set to display-everything in dev mode', () => {
- expect.assertions(4)
-
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- for (let method of ['info', 'warn', 'error', 'debug']) {
- expect(Logger.canPrint(method)).toBeTruthy()
- }
- })
- })
-
- it('allows showing errors when verbosity is set to only-errors in dev mode', () => {
- jest.isolateModules(() => {
- config.console.verbosityLevel = 'only-errors'
-
- const Logger = require('../../logger').Logger
-
- expect(Logger.canPrint('error')).toBeTruthy()
-
- for (let method of ['info', 'warn', 'debug']) {
- expect(Logger.canPrint(method)).toBeFalsy()
- }
- })
- })
-
- it('allows showing errors when verbosity is set to only-errors in prod mode but showErrorOnProduction is set', () => {
- jest.isolateModules(() => {
- config.console.verbosityLevel = 'only-errors'
- process.env.NODE_ENV = 'production'
-
- const Logger = require('../../logger').Logger
-
- expect(Logger.canPrint('error')).toBeTruthy()
-
- for (let method of ['info', 'warn', 'debug']) {
- expect(Logger.canPrint(method)).toBeFalsy()
- }
- })
- })
-
- it('does not show any logs when verbosity is set to none', () => {
- jest.isolateModules(() => {
- config.console.verbosityLevel = 'none'
-
- const Logger = require('../../logger').Logger
-
- for (let method of ['info', 'warn', 'debug', 'error']) {
- expect(Logger.canPrint(method)).toBeFalsy()
- }
- })
- })
- })
-
- describe('debug', () => {
- it('doesn\'t display message if logger is configured not to log it', () => {
- jest.isolateModules(() => {
- config.console.verbosityLevel = 'none'
-
- const Logger = require('../../logger').Logger
-
- Logger.debug('test', null, null)()
- expect(consoleDebugSpy).not.toBeCalled()
- })
- })
-
- it('displays message without tag if none was given in SSR and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.debug('test')()
- expect(consoleDebugSpy).toBeCalledWith('test', null)
- })
- })
-
- it('displays message with tag if one was given in SSR and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.debug('test', 'tag')()
- expect(consoleDebugSpy).toBeCalledWith('[tag] test', null)
- })
- })
-
- it('displays message without tag given no tag and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.debug('test')()
- expect(consoleDebugSpy).toBeCalledWith(
- '%cVSF%c test',
- expect.anything(),
- expect.anything(),
- null
- )
- })
- })
-
- it('displays message with tag given a tag and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.debug('test', 'tag')()
- expect(consoleDebugSpy).toBeCalledWith(
- '%cVSF%c %ctag%c test',
- expect.anything(),
- expect.anything(),
- expect.anything(),
- expect.anything(),
- null
- )
- })
- })
- })
-
- describe('log', () => {
- it('works as an alias of info', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.log('test')()
- expect(consoleInfoSpy).toBeCalled()
- })
- })
-
- it('can be called with custom tag and context', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.log('test', 'tag', 'context')()
- expect(consoleInfoSpy).toBeCalledWith(
- '%cVSF%c %ctag%c test',
- expect.anything(),
- expect.anything(),
- expect.anything(),
- expect.anything(),
- 'context'
- )
- })
- })
- })
-
- describe('info', () => {
- it('doesn\'t display message if logger is configured not to log it', () => {
- jest.isolateModules(() => {
- config.console.verbosityLevel = 'none'
-
- const Logger = require('../../logger').Logger
-
- Logger.info('test', null, null)()
- expect(consoleInfoSpy).not.toBeCalled()
- })
- })
-
- it('displays message without tag if none was given in SSR and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.info('test')()
- expect(consoleInfoSpy).toBeCalledWith('test', null)
- })
- })
-
- it('displays message with tag if one was given in SSR and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.info('test', 'tag')()
- expect(consoleInfoSpy).toBeCalledWith('[tag] test', null)
- })
- })
-
- it('displays message without tag given no tag and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.info('test')()
- expect(consoleInfoSpy).toBeCalledWith(
- '%cVSF%c test',
- expect.anything(),
- expect.anything(),
- null
- )
- })
- })
-
- it('displays message with tag given a tag and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.info('test', 'tag')()
- expect(consoleInfoSpy).toBeCalledWith(
- '%cVSF%c %ctag%c test',
- expect.anything(),
- expect.anything(),
- expect.anything(),
- expect.anything(),
- null
- )
- })
- })
- })
-
- describe('warn', () => {
- it('doesn\'t display message if logger is configured not to log it', () => {
- jest.isolateModules(() => {
- config.console.verbosityLevel = 'none'
-
- const Logger = require('../../logger').Logger
-
- Logger.warn('test', null, null)()
- expect(consoleWarnSpy).not.toBeCalled()
- })
- })
-
- it('displays message without tag if none was given in SSR and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.warn('test')()
- expect(consoleWarnSpy).toBeCalledWith('test', null)
- })
- })
-
- it('displays message with tag if one was given in SSR and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.warn('test', 'tag')()
- expect(consoleWarnSpy).toBeCalledWith('[tag] test', null)
- })
- })
-
- it('displays message without tag given no tag and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.warn('test')()
- expect(consoleWarnSpy).toBeCalledWith(
- '%cVSF%c test',
- expect.anything(),
- expect.anything(),
- null
- )
- })
- })
-
- it('displays message with tag given a tag and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.warn('test', 'tag')()
- expect(consoleWarnSpy).toBeCalledWith(
- '%cVSF%c %ctag%c test',
- expect.anything(),
- expect.anything(),
- expect.anything(),
- expect.anything(),
- null
- )
- })
- })
- })
-
- describe('error', () => {
- it('always displays messages in SSR', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.error('test')()
- expect(consoleErrorSpy).toBeCalled()
- })
- })
-
- it('displays message with tag if one was given in SSR and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- const Logger = require('../../logger').Logger
-
- Logger.error('test', 'tag')()
- expect(consoleErrorSpy).toBeCalledWith('[tag] test', null)
- })
- })
-
- it('doesn\'t display message if logger is configured not to log it and not in SSR mode', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- config.console.verbosityLevel = 'none'
-
- const Logger = require('../../logger').Logger
-
- Logger.error('test', null, null)()
- expect(consoleErrorSpy).not.toBeCalled()
- })
- })
-
- it('displays message without tag given no tag and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.error('test')()
- expect(consoleErrorSpy).toBeCalledWith(
- '%cVSF%c test',
- expect.anything(),
- expect.anything(),
- null
- )
- })
- })
-
- it('displays message with tag given a tag and logger is configured to log everything', () => {
- jest.isolateModules(() => {
- isServerSpy.mockReturnValueOnce(false)
- const Logger = require('../../logger').Logger
-
- Logger.error('test', 'tag')()
- expect(consoleErrorSpy).toBeCalledWith(
- '%cVSF%c %ctag%c test',
- expect.anything(),
- expect.anything(),
- expect.anything(),
- expect.anything(),
- null
- )
- })
- })
- })
-})
diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts
deleted file mode 100644
index d2cf2b2f2b..0000000000
--- a/core/lib/test/unit/multistore.spec.ts
+++ /dev/null
@@ -1,737 +0,0 @@
-import storeCodeFromRoute from '@vue-storefront/core/lib/storeCodeFromRoute'
-import { LocalizedRoute } from '@vue-storefront/core/lib/types'
-import {
- prepareStoreView,
- adjustMultistoreApiUrl,
- localizedDispatcherRoute,
- setupMultistoreRoutes,
- localizedRoutePath,
- localizedRouteConfig
-} from '@vue-storefront/core/lib/multistore'
-import config from 'config'
-import rootStore from '@vue-storefront/core/store';
-import { router } from '@vue-storefront/core/app';
-import { RouteConfig } from 'vue-router'
-
-jest.mock('@vue-storefront/core/app', () => ({
- createApp: jest.fn(),
- router: {
- addRoutes: jest.fn()
- }
-}))
-jest.mock('../../../store', () => ({}))
-jest.mock('@vue-storefront/i18n', () => ({ loadLanguageAsync: jest.fn() }))
-jest.mock('../../sync/task', () => ({ initializeSyncTaskStorage: jest.fn() }))
-jest.mock('@vue-storefront/core/hooks', () => ({ coreHooksExecutors: {
- beforeStoreViewChanged: jest.fn(args => args),
- afterStoreViewChanged: jest.fn(args => args)
-} }))
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {}
-}))
-jest.mock('config', () => ({}))
-
-describe('Multistore', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- (rootStore as any).state = {};
- Object.keys(config).forEach((key) => { delete config[key]; });
- rootStore.state.storeView = {
- appendStoreCode: true
- }
- })
-
- describe('storeCodeFromRoute', () => {
- it('returns store code given url matching a storeview by path', () => {
- config.storeViews = {
- mapStoreUrlsFor: ['us'],
- us: {
- url: '/us'
- }
- };
-
- expect(storeCodeFromRoute('/us')).toBe('us')
- })
-
- it('returns store code given a route matching a storeview by path', () => {
- config.storeViews = {
- mapStoreUrlsFor: ['us'],
- us: {
- url: '/us'
- }
- };
-
- const route = { path: 'us' }
-
- expect(storeCodeFromRoute(route)).toBe('us')
- })
-
- it('returns store code given a url matching a storeview by url', () => {
- config.storeViews = {
- mapStoreUrlsFor: ['us', 'gb'],
- us: {
- url: '/us'
- },
- gb: {
- url: 'domain.co.uk'
- }
- };
-
- const route = 'domain.co.uk'
-
- expect(storeCodeFromRoute(route)).toBe('gb')
- })
-
- it('returns store code given a url matching a storeview by url with path', () => {
- config.storeViews = {
- mapStoreUrlsFor: ['us', 'gb'],
- us: {
- url: '/us'
- },
- gb: {
- url: 'domain.co.uk/gb'
- }
- };
-
- const route = 'domain.co.uk/gb/foo'
-
- expect(storeCodeFromRoute(route)).toBe('gb')
- })
-
- it('returns store code given a route matching a storeview by url with path', () => {
- config.storeViews = {
- mapStoreUrlsFor: ['us', 'gb'],
- us: {
- url: '/us'
- },
- gb: {
- url: 'domain.co.uk/gb'
- }
- };
-
- const route = {
- host: 'domain.co.uk',
- path: 'gb/foo'
- }
-
- expect(storeCodeFromRoute(route)).toBe('gb')
- })
-
- it('returns empty string if given a route which doesn\'t have url and is not matched by path', () => {
- config.storeViews = {
- mapStoreUrlsFor: ['us', 'gb'],
- us: {
- url: '/us'
- },
- gb: {
- url: 'domain.co.uk'
- }
- };
-
- const route = { path: 'gb' }
-
- expect(storeCodeFromRoute(route)).toBe('')
- })
-
- it('returns empty string if route was not matched to any store', () => {
- config.storeViews = {
- mapStoreUrlsFor: ['us'],
- us: {
- url: 'us.domain.tld'
- }
- };
-
- expect(storeCodeFromRoute('unknown-domain.tld')).toBe('')
- })
-
- it('returns empty string if route is not given', () => {
- expect(storeCodeFromRoute('')).toBe('')
- })
- })
-
- describe('prepareStoreView', () => {
- it('returns default storeView given no storecode', async () => {
- rootStore.state.storeView = {}
- rootStore.state.user = {}
-
- config.storeViews = {
- multistore: false
- }
-
- config.tax = {
- defaultCountry: 'US'
- }
-
- config.i18n = {
- defaultLocale: 'en-US',
- fullCountryName: 'United States',
- fullLanguageName: 'English'
- }
-
- config.elasticsearch = {
- index: 'vue_storefront_catalog'
- }
- config.defaultStoreCode = ''
-
- config.seo = {
- defaultTitle: 'Vue Storefront'
- }
-
- expect(await prepareStoreView(null)).toStrictEqual({
- tax: {
- defaultCountry: 'US'
- },
- i18n: {
- defaultLocale: 'en-US',
- fullCountryName: 'United States',
- fullLanguageName: 'English'
- },
- seo: {
- defaultTitle: 'Vue Storefront'
- },
- elasticsearch: {
- index: 'vue_storefront_catalog'
- },
- storeId: 1,
- storeCode: ''
- })
- })
-
- it('returns default storeView without setting defaultStoreCode when multistore mode is disabled', async () => {
- rootStore.state.storeView = {}
- rootStore.state.user = {}
-
- config.storeViews = {
- multistore: false,
- de: {
- storeId: 4
- }
- }
-
- config.tax = {
- defaultCountry: 'US'
- }
-
- config.i18n = {
- defaultLocale: 'en-US',
- fullCountryName: 'United States',
- fullLanguageName: 'English'
- }
-
- config.elasticsearch = {
- index: 'vue_storefront_catalog'
- }
- config.defaultStoreCode = 'de'
-
- config.seo = {
- defaultTitle: 'Vue Storefront'
- }
-
- expect(await prepareStoreView(null)).toStrictEqual({
- tax: {
- defaultCountry: 'US'
- },
- i18n: {
- defaultLocale: 'en-US',
- fullCountryName: 'United States',
- fullLanguageName: 'English'
- },
- seo: {
- defaultTitle: 'Vue Storefront'
- },
- elasticsearch: {
- index: 'vue_storefront_catalog'
- },
- storeId: 4,
- storeCode: ''
- })
- })
-
- it('returns default storeView with defaultStoreCode set when multistore mode is enabled', async () => {
- rootStore.state.storeView = {}
- rootStore.state.user = {}
-
- config.storeViews = {
- multistore: true,
- de: {
- storeId: 4
- }
- }
-
- config.tax = {
- defaultCountry: 'US'
- }
-
- config.i18n = {
- defaultLocale: 'en-US',
- fullCountryName: 'United States',
- fullLanguageName: 'English'
- }
-
- config.seo = {
- defaultTitle: 'Vue Storefront'
- }
-
- config.elasticsearch = {
- index: 'vue_storefront_catalog'
- }
- config.defaultStoreCode = 'de'
-
- expect(await prepareStoreView(null)).toStrictEqual({
- tax: {
- defaultCountry: 'US'
- },
- i18n: {
- defaultLocale: 'en-US',
- fullCountryName: 'United States',
- fullLanguageName: 'English'
- },
- seo: {
- defaultTitle: 'Vue Storefront'
- },
- elasticsearch: {
- index: 'vue_storefront_catalog'
- },
- storeId: 4,
- storeCode: 'de'
- })
- })
-
- it('returns storeView overwritting default store config values when multistore mode is enabled', async () => {
- rootStore.state.storeView = {}
- rootStore.state.user = {}
-
- config.storeViews = {
- multistore: true,
- de: {
- storeCode: 'de',
- storeId: 3,
- name: 'German Store',
- elasticsearch: {
- index: 'vue_storefront_catalog_de'
- },
- tax: {
- defaultCountry: 'DE'
- },
- i18n: {
- fullCountryName: 'Germany',
- fullLanguageName: 'German',
- defaultLocale: 'de-DE'
- },
- seo: {
- defaultTitle: 'Vue Storefront'
- }
- }
- }
-
- config.tax = {
- defaultCountry: 'US'
- }
-
- config.i18n = {
- defaultLocale: 'en-US',
- fullCountryName: 'United States',
- fullLanguageName: 'English'
- }
-
- config.seo = {
- defaultTitle: 'Vue Storefront'
- }
-
- config.elasticsearch = {
- index: 'vue_storefront_catalog'
- }
- config.defaultStoreCode = 'de'
-
- expect(await prepareStoreView(null)).toStrictEqual({
- tax: {
- defaultCountry: 'DE'
- },
- i18n: {
- fullCountryName: 'Germany',
- fullLanguageName: 'German',
- defaultLocale: 'de-DE'
- },
- seo: {
- defaultTitle: 'Vue Storefront'
- },
- elasticsearch: {
- index: 'vue_storefront_catalog_de'
- },
- storeId: 3,
- name: 'German Store',
- storeCode: 'de'
- })
- })
-
- it('returns storeView extending other storeView in multistore mode', async () => {
- rootStore.state.storeView = {}
- rootStore.state.user = {}
-
- config.storeViews = {
- multistore: true,
- de: {
- storeCode: 'de',
- storeId: 3,
- name: 'German Store',
- elasticsearch: {
- index: 'vue_storefront_catalog_de'
- },
- tax: {
- defaultCountry: 'DE'
- },
- i18n: {
- fullCountryName: 'Germany',
- fullLanguageName: 'German',
- defaultLocale: 'de-DE'
- },
- seo: {
- defaultTitle: 'Vue Storefront'
- }
- },
- it: {
- extend: 'de',
- storeCode: 'it',
- storeId: 4,
- name: 'Italian Store',
- elasticsearch: {
- index: 'vue_storefront_catalog_it'
- },
- tax: {
- defaultCountry: 'IT'
- },
- i18n: {
- fullCountryName: 'Italy',
- fullLanguageName: 'Italian',
- defaultLocale: 'it-IT'
- },
- seo: {
- defaultTitle: 'Vue Storefront'
- }
- }
- }
-
- config.tax = {
- defaultCountry: 'US'
- }
-
- config.i18n = {
- defaultLocale: 'en-US',
- fullCountryName: 'United States',
- fullLanguageName: 'English'
- }
-
- config.seo = {
- defaultTitle: 'Vue Storefront'
- }
-
- config.elasticsearch = {
- index: 'vue_storefront_catalog'
- }
- config.defaultStoreCode = 'it'
-
- expect(await prepareStoreView(null)).toStrictEqual({
- tax: {
- defaultCountry: 'IT'
- },
- i18n: {
- fullCountryName: 'Italy',
- fullLanguageName: 'Italian',
- defaultLocale: 'it-IT'
- },
- seo: {
- defaultTitle: 'Vue Storefront'
- },
- elasticsearch: {
- index: 'vue_storefront_catalog_it'
- },
- storeId: 4,
- extend: 'de',
- name: 'Italian Store',
- storeCode: 'it'
- })
- })
- })
-
- describe('adjustMultistoreApiUrl', () => {
- it('returns URL /test without storeCode as parameter', () => {
- rootStore.state.storeView = {
- storeCode: null
- }
-
- expect(adjustMultistoreApiUrl('/test')).toStrictEqual('/test')
- })
-
- it('returns URL /test with storeCode de as parameter', () => {
- rootStore.state.storeView = {
- storeCode: 'de'
- }
-
- expect(adjustMultistoreApiUrl('/test')).toStrictEqual('/test?storeCode=de')
- })
-
- it('returns URL /test?a=b with storeCode de as parameter and current parameters from the URL', () => {
- rootStore.state.storeView = {
- storeCode: 'de'
- }
-
- expect(adjustMultistoreApiUrl('/test?a=b')).toStrictEqual('/test?a=b&storeCode=de')
- })
-
- it('returns URL /test?a=b&storeCode=de with added storeCode at as parameter and removes previous storeCode parameter', () => {
- rootStore.state.storeView = {
- storeCode: 'at'
- }
-
- expect(adjustMultistoreApiUrl('/test?a=b&storeCode=de')).toStrictEqual('/test?a=b&storeCode=at')
- })
-
- it('returns URL /test?storeCode=de with changed storeCode at as parameter', () => {
- rootStore.state.storeView = {
- storeCode: 'at'
- }
-
- expect(adjustMultistoreApiUrl('/test?storeCode=de')).toStrictEqual('/test?storeCode=at')
- })
-
- it('returns URL /test?storeCode=de with changed storeCode at as parameter', () => {
- rootStore.state.storeView = {
- storeCode: 'at'
- }
-
- expect(adjustMultistoreApiUrl('/test?storeCode=de&storeCode=de')).toStrictEqual('/test?storeCode=at')
- })
- })
-
- describe('localizedDispatcherRoute', () => {
- it('URL /test stays the same', () => {
- config.storeViews = {}
-
- expect(localizedDispatcherRoute('/test', 'de')).toStrictEqual('/test')
- })
-
- it('URL /test starts with /de', () => {
- config.storeViews = {
- de: {
- appendStoreCode: true
- }
- }
-
- expect(localizedDispatcherRoute('/test', 'de')).toStrictEqual('/de/test')
- })
-
- it('URL /test?a=b&b=a stays the same', () => {
- config.storeViews = {}
-
- expect(localizedDispatcherRoute('/test?a=b&b=a', 'de')).toStrictEqual('/test?a=b&b=a')
- })
-
- it('URL /test?a=b&b=a starts with /de', () => {
- config.storeViews = {
- de: {
- appendStoreCode: true
- }
- }
-
- expect(localizedDispatcherRoute('/test?a=b&b=a', 'de')).toStrictEqual('/de/test?a=b&b=a')
- })
-
- it('URL with LocalizedRoute object with fullPath test gets prefixed with /de', () => {
- config.storeViews = {}
-
- const LocalizedRoute: LocalizedRoute = {
- fullPath: 'test'
- }
-
- expect(localizedDispatcherRoute(LocalizedRoute, 'de')).toStrictEqual('/test')
- })
-
- it('URL with LocalizedRoute object with fullPath and parameter test stays the same', () => {
- config.storeViews = {}
-
- const LocalizedRoute: LocalizedRoute = {
- fullPath: 'test',
- params: {
- a: 'b',
- b: 'a'
- }
- }
-
- expect(localizedDispatcherRoute(LocalizedRoute, 'de')).toStrictEqual('/test?a=b&b=a')
- })
-
- it('URL with LocalizedRoute object with fullPath test gets prefixed with /de', () => {
- config.storeViews = {
- de: {
- appendStoreCode: true
- }
- }
-
- const LocalizedRoute: LocalizedRoute = {
- fullPath: 'test'
- }
-
- expect(localizedDispatcherRoute(LocalizedRoute, 'de')).toStrictEqual('/de/test')
- })
-
- it('URL with LocalizedRoute object with fullPath test and params gets prefixed with /de', () => {
- config.storeViews = {
- de: {
- appendStoreCode: true
- }
- }
-
- const LocalizedRoute: LocalizedRoute = {
- fullPath: 'test',
- params: {
- a: 'b',
- b: 'a'
- }
- }
-
- expect(localizedDispatcherRoute(LocalizedRoute, 'de')).toStrictEqual('/de/test?a=b&b=a')
- })
- })
-
- describe('setupMultistoreRoutes', () => {
- it('Add new routes for each store in mapStoreUrlsFor', () => {
- config.storeViews = {
- 'de': {
- appendStoreCode: true
- },
- mapStoreUrlsFor: [
- 'de'
- ],
- multistore: true
- }
- config.seo = {
- useUrlDispatcher: true
- }
-
- const routeConfig: RouteConfig[] = [
- {
- path: 'test'
- },
- {
- path: 'test2'
- }
- ]
-
- setupMultistoreRoutes(config, router, routeConfig)
-
- expect(router.addRoutes).toBeCalledTimes(1)
- })
-
- it('Do nothing as mapStoreUrlsFor is empty', () => {
- config.storeViews = {
- 'de': {
- },
- mapStoreUrlsFor: []
- }
-
- const routeConfig: RouteConfig[] = [
- {
- path: 'test'
- },
- {
- path: 'test2'
- }
- ]
-
- setupMultistoreRoutes(config, router, routeConfig)
-
- expect(router.addRoutes).toBeCalledTimes(1)
- })
- })
-
- describe('localizedRoutePath', () => {
- it('add storeCode to route path with slash', () => {
- const storeCode = 'de'
- const path = '/test'
-
- expect(localizedRoutePath(path, storeCode)).toBe('/de/test')
- })
-
- it('add storeCode to route path without slash', () => {
- const storeCode = 'de'
- const path = 'test'
-
- expect(localizedRoutePath(path, storeCode)).toBe('/de/test')
- })
-
- it('add storeCode to route path with hash', () => {
- const storeCode = 'de'
- const path = '/test#test'
-
- expect(localizedRoutePath(path, storeCode)).toBe('/de/test#test')
- })
- })
-
- describe('localizedRouteConfig', () => {
- it('create new route object with storeCode', () => {
- const storeCode = 'de'
- const route = {
- path: '/test',
- name: 'test'
- }
- const expectedRoute = {
- path: '/de/test',
- name: 'de-test'
- }
-
- expect(localizedRouteConfig(route, storeCode)).toEqual(expectedRoute)
- })
-
- it('change only route name for child route', () => {
- const storeCode = 'de'
- const childRoute = {
- path: '/test2',
- name: 'test2'
- }
- const expectedRoute = {
- path: '/test2',
- name: 'de-test2'
- }
-
- expect(localizedRouteConfig(childRoute, storeCode, true)).toEqual(expectedRoute)
- })
-
- it('add localization for nested routes', () => {
- const storeCode = 'de'
- const route = {
- path: '/test',
- name: 'test',
- children: [
- {
- path: 'test2',
- name: 'test2',
- children: [
- {
- path: '/test3',
- name: 'test3'
- }
- ]
- }
- ]
- }
- const expectedRoute = {
- path: '/de/test',
- name: 'de-test',
- children: [
- {
- path: 'test2',
- name: 'de-test2',
- children: [
- {
- path: '/test3',
- name: 'de-test3'
- }
- ]
- }
- ]
- }
-
- expect(localizedRouteConfig(route, storeCode)).toEqual(expectedRoute)
- })
- })
-})
diff --git a/core/lib/themes.ts b/core/lib/themes.ts
deleted file mode 100644
index e33b119367..0000000000
--- a/core/lib/themes.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export function registerTheme (themeName, app, routes, store, config, ssrContext) {
- const themeEntryPoint = require('theme/index.js')
- if (themeEntryPoint != null && themeEntryPoint.initTheme) {
- themeEntryPoint.initTheme(app, routes, store, config, ssrContext) // register theme
- } else {
- throw new Error('Wrong theme name: ' + themeName)
- }
-}
diff --git a/core/lib/types.ts b/core/lib/types.ts
deleted file mode 100644
index 8a57fc78a8..0000000000
--- a/core/lib/types.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { PathToRegexpOptions } from 'vue-router/types/router';
-
-export interface LocalizedRoute {
- path?: string,
- name?: string,
- hash?: string,
- params?: { [key: string]: unknown },
- fullPath?: string,
- host?: string,
- pathToRegexpOptions?: PathToRegexpOptions
-}
-
-export interface StoreView {
- storeCode: string,
- extend?: string,
- disabled?: boolean,
- storeId: any,
- name?: string,
- url?: string,
- appendStoreCode?: boolean,
- elasticsearch: {
- host: string,
- index: string
- },
- tax: {
- sourcePriceIncludesTax?: boolean,
- finalPriceIncludesTax?: boolean,
- deprecatedPriceFieldsSupport?: boolean,
- defaultCountry: string,
- defaultRegion: null | string,
- calculateServerSide: boolean,
- userGroupId?: number,
- useOnlyDefaultUserGroupId: boolean
- },
- i18n: {
- fullCountryName: string,
- fullLanguageName: string,
- defaultLanguage: string,
- defaultCountry: string,
- defaultLocale: string,
- currencyCode: string,
- currencySign: string,
- currencyDecimal: string,
- currencyGroup: string,
- fractionDigits: number,
- priceFormat: string,
- dateFormat: string
- },
- seo: {
- defaultTitle: string
- }
-}
diff --git a/core/mixins/composite.js b/core/mixins/composite.js
deleted file mode 100644
index 79345e6ebe..0000000000
--- a/core/mixins/composite.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-// @deprecated from 2.0
-export default {
- beforeCreated () {
- const eventName = this.$options.name.toLowerCase() + '-before-created'
- Logger.debug(eventName, 'event')()
- EventBus.$emit(eventName, this)
- },
- created () {
- const eventName = this.$options.name.toLowerCase() + '-after-created'
- Logger.debug(eventName, 'event')()
- EventBus.$emit(eventName, this)
- },
- beforeMount () {
- const eventName = this.$options.name.toLowerCase() + '-before-mount'
- Logger.debug(eventName, 'event')()
- EventBus.$emit(eventName, this)
- },
- mounted () {
- const eventName = this.$options.name.toLowerCase() + '-after-mounted'
- Logger.debug(eventName, 'event')()
- EventBus.$emit(eventName, this)
- }
-
-}
diff --git a/core/mixins/index.js b/core/mixins/index.js
deleted file mode 100644
index 990684de30..0000000000
--- a/core/mixins/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { thumbnail } from './thumbnail.js'
-import { multistore } from './multistore.js'
-
-export {
- thumbnail,
- multistore
-}
diff --git a/core/mixins/multistore.js b/core/mixins/multistore.js
deleted file mode 100644
index 8964566055..0000000000
--- a/core/mixins/multistore.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { localizedRoute as localizedRouteHelper, localizedDispatcherRoute as localizedDispatcherRouteHelper, currentStoreView } from '@vue-storefront/core/lib/multistore'
-import { isServer } from '../helpers';
-
-export const multistore = {
- methods: {
- /**
- * Return localized route params
- * @param {String} relativeUrl
- * @param {Int} width
- * @param {Int} height
- */
- localizedRoute (routeObj) {
- const storeView = currentStoreView()
-
- return localizedRouteHelper(routeObj, storeView.storeCode)
- },
- /**
- * Return localized route params for URL Dispatcher
- * @param {String} relativeUrl
- * @param {Int} width
- * @param {Int} height
- */
- localizedDispatcherRoute (routeObj) {
- const storeView = currentStoreView()
-
- return localizedDispatcherRouteHelper(routeObj, storeView.storeCode)
- }
- }
-}
diff --git a/core/mixins/onBottomScroll.js b/core/mixins/onBottomScroll.js
deleted file mode 100644
index 5f8402791e..0000000000
--- a/core/mixins/onBottomScroll.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { isServer } from '@vue-storefront/core/helpers'
-
-const isBottomVisible = () => {
- if (isServer) {
- return false
- }
- const SAFETY_MARGIN = 20
- const scrollY = window.scrollY
- const visible = window.innerHeight
- const pageHeight = document.documentElement.scrollHeight
- const bottomOfPage = scrollY + SAFETY_MARGIN >= pageHeight - visible
-
- return bottomOfPage || pageHeight < visible
-}
-
-/**
- * By implementing this mixin add "onBottomScroll" method in component.
- * It will be invoked when view reach the bottom.
- */
-export default {
- mounted () {
- const scrollHandler = () => {
- if (isBottomVisible()) {
- this.onBottomScroll()
- }
- }
- document.addEventListener('scroll', scrollHandler)
- this.$once('hook:destroyed', () => {
- document.removeEventListener('scroll', scrollHandler)
- })
- }
-}
diff --git a/core/mixins/onEscapePress.js b/core/mixins/onEscapePress.js
deleted file mode 100644
index 0876333d89..0000000000
--- a/core/mixins/onEscapePress.js
+++ /dev/null
@@ -1,14 +0,0 @@
-export default {
- mounted () {
- const keydownHandler = (e) => {
- // for old browser support as a fallback
- if (e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) {
- this.onEscapePress()
- }
- }
- document.addEventListener('keydown', keydownHandler)
- this.$once('hook:destroyed', () => {
- document.removeEventListener('keydown', keydownHandler)
- })
- }
-}
diff --git a/core/mixins/thumbnail.js b/core/mixins/thumbnail.js
deleted file mode 100644
index 0ffff030fc..0000000000
--- a/core/mixins/thumbnail.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { getThumbnailPath } from '@vue-storefront/core/helpers'
-
-export const thumbnail = {
- methods: {
- /**
- * Return thumbnail URL for specific base url and path
- * @param {string} relativeUrl
- * @param {number} width
- * @param {number} height
- * @param {string} pathType
- * @returns {string}
- */
- getThumbnail: (relativeUrl, width, height, pathType) => getThumbnailPath(relativeUrl, width, height, pathType),
-
- /**
- * Return thumbnail URL for specific base url using media path
- * @param {string} relativeUrl
- * @param {number} width
- * @param {number} height
- * @returns {string}
- */
- getMediaThumbnail: (relativeUrl, width, height) => getThumbnailPath(relativeUrl, width, height, 'media')
- }
-}
diff --git a/core/modules-entry.ts b/core/modules-entry.ts
deleted file mode 100644
index fd8f38bf66..0000000000
--- a/core/modules-entry.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-
-import { VueStorefrontModule } from '@vue-storefront/core/lib/module'
-import { registerModules } from 'src/modules/client'
-
-// @deprecated from 2.0, use registerModule instead
-export const enabledModules: VueStorefrontModule[] = [
- ...registerModules
-]
diff --git a/core/modules/breadcrumbs/README.md b/core/modules/breadcrumbs/README.md
deleted file mode 100644
index fc428990f6..0000000000
--- a/core/modules/breadcrumbs/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-This module is not finished.
-
-So far it's save to use in:
-- Product page
\ No newline at end of file
diff --git a/core/modules/breadcrumbs/components/Breadcrumbs.ts b/core/modules/breadcrumbs/components/Breadcrumbs.ts
deleted file mode 100644
index b0c097acbf..0000000000
--- a/core/modules/breadcrumbs/components/Breadcrumbs.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { localizedRoute, currentStoreView } from '@vue-storefront/core/lib/multistore'
-import i18n from '@vue-storefront/i18n'
-import { mapGetters } from 'vuex'
-
-export const Breadcrumbs = {
- computed: {
- ...mapGetters({
- getBreadcrumbsRoutes: 'breadcrumbs/getBreadcrumbsRoutes',
- getBreadcrumbsCurrent: 'breadcrumbs/getBreadcrumbsCurrent'
- }),
- paths () {
- const routes = this.routes ? this.routes : this.getBreadcrumbsRoutes
-
- if (this.withHomepage) {
- return [
- { name: i18n.t('Homepage'), route_link: localizedRoute('/', currentStoreView().storeCode) },
- ...routes
- ]
- }
-
- return routes
- },
- current () {
- return this.activeRoute || this.getBreadcrumbsCurrent
- }
- },
- props: {
- routes: {
- type: Array,
- required: false,
- default: null
- },
- withHomepage: {
- type: Boolean,
- default: false
- },
- activeRoute: {
- type: String,
- default: ''
- }
- }
-}
diff --git a/core/modules/breadcrumbs/helpers/index.ts b/core/modules/breadcrumbs/helpers/index.ts
deleted file mode 100644
index 18f3e7d8b8..0000000000
--- a/core/modules/breadcrumbs/helpers/index.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { formatCategoryLink } from '@vue-storefront/core/modules/url/helpers'
-
-// Duplicate of breadCrumbRoutes, to repalce it soon.
-/** Parse category path for product/category */
-export function parseCategoryPath (categoryPath) {
- let routesArray = []
- for (let category of categoryPath) {
- if (category.url_path === undefined || category.url_path === null) continue;
- routesArray.push({
- name: category.name,
- route_link: formatCategoryLink(category)
- })
- }
-
- return routesArray
-}
diff --git a/core/modules/breadcrumbs/index.ts b/core/modules/breadcrumbs/index.ts
deleted file mode 100644
index fbf2320cb0..0000000000
--- a/core/modules/breadcrumbs/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { breadcrumbsStore } from './store'
-import { StorefrontModule } from '@vue-storefront/core/lib/modules'
-
-export const BreadcrumbsModule: StorefrontModule = function ({ store }) {
- store.registerModule('breadcrumbs', breadcrumbsStore)
-}
diff --git a/core/modules/breadcrumbs/store/index.ts b/core/modules/breadcrumbs/store/index.ts
deleted file mode 100644
index 02f195275d..0000000000
--- a/core/modules/breadcrumbs/store/index.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-
-export const breadcrumbsStore = {
- namespaced: true,
- state: {
- routes: [],
- current: null
- },
- mutations: {
- set (state, payload) {
- state.routes = payload.routes
- state.current = payload.current
- }
- },
- actions: {
- set ({ commit }, payload) {
- commit('set', payload)
- }
- },
- getters: {
- getBreadcrumbsRoutes: (state) => state.routes,
- getBreadcrumbsCurrent: (state) => state.current
- }
-}
diff --git a/core/modules/breadcrumbs/test/unit/parseCategoryPath.spec.ts b/core/modules/breadcrumbs/test/unit/parseCategoryPath.spec.ts
deleted file mode 100644
index 7e357c8e2c..0000000000
--- a/core/modules/breadcrumbs/test/unit/parseCategoryPath.spec.ts
+++ /dev/null
@@ -1,175 +0,0 @@
-import { parseCategoryPath } from '@vue-storefront/core/modules/breadcrumbs/helpers';
-import { Category } from '@vue-storefront/core/modules/catalog-next/types/Category';
-import { currentStoreView } from '@vue-storefront/core/lib/multistore';
-
-jest.mock('@vue-storefront/core/app', () => jest.fn());
-jest.mock('@vue-storefront/core/lib/router-manager', () => jest.fn());
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedDispatcherRoute: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/helpers', () => ({
- once: (str) => jest.fn()
-}))
-
-describe('parseCategoryPath method', () => {
- describe('on category page', () => {
- let categories: Category[];
-
- beforeEach(() => {
- jest.clearAllMocks();
- (currentStoreView as jest.Mock).mockImplementation(() => ({ storeCode: '' }));
- categories = [
- {
- path: '1/2',
- is_active: true,
- level: 1,
- product_count: 1181,
- children_count: '38',
- parent_id: 1,
- name: 'All',
- id: 2,
- url_key: 'all-2',
- children_data: [],
- url_path: 'all-2',
- slug: 'all-2'
- },
- { path: '1/2/20',
- is_active: true,
- level: 2,
- product_count: 0,
- children_count: '8',
- parent_id: 2,
- name: 'Women',
- id: 20,
- url_path: 'women/women-20',
- url_key: 'women-20',
- children_data: [],
- slug: 'women-20'
- },
- {
- path: '1/2/20/21',
- is_active: true,
- level: 3,
- product_count: 0,
- children_count: '4',
- parent_id: 20,
- name: 'Tops',
- id: 21,
- url_path: 'women/tops-women/tops-21',
- url_key: 'tops-21',
- children_data: [],
- slug: 'tops-21'
- }
- ];
- });
-
- it('should return formatted category path for breadcrumbs', () => {
- const result = parseCategoryPath(categories);
- const expected = [
- {
- name: 'All',
- route_link: '/all-2'
- },
- {
- name: 'Women',
- route_link: '/women/women-20'
- },
- {
- name: 'Tops',
- route_link: '/women/tops-women/tops-21'
- }
- ];
- expect(result).toEqual(expected);
- });
- });
-
- describe('on product page', () => {
- let categories;
-
- beforeEach(() => {
- jest.clearAllMocks();
- (currentStoreView as jest.Mock).mockImplementation(() => ({ storeCode: '' }));
- categories = [
- {
- path: '1/2',
- is_active: true,
- level: 1,
- product_count: 1181,
- children_count: '38',
- parent_id: 1,
- name: 'All',
- id: 2,
- url_key: 'all-2',
- children_data: [],
- url_path: 'all-2',
- slug: 'all-2'
- },
- { path: '1/2/20',
- is_active: true,
- level: 2,
- product_count: 0,
- children_count: '8',
- parent_id: 2,
- name: 'Women',
- id: 20,
- url_path: 'women/women-20',
- url_key: 'women-20',
- children_data: [],
- slug: 'women-20'
- },
- {
- path: '1/2/20/21',
- is_active: true,
- level: 3,
- product_count: 0,
- children_count: '4',
- parent_id: 20,
- name: 'Tops',
- id: 21,
- url_path: 'women/tops-women/tops-21',
- url_key: 'tops-21',
- children_data: [],
- slug: 'tops-21'
- },
- {
- path: '1/2/20/21/23',
- is_active: true,
- level: 4,
- product_count: 186,
- children_count: '0',
- parent_id: 21,
- name: 'Jackets',
- id: 23,
- url_key: 'jackets-23',
- url_path: 'women/tops-women/jackets-women/jackets-23',
- slug: 'jackets-23'
- }
- ];
- });
-
- it('should return formatted category path for breadcrumbs', () => {
- const result = parseCategoryPath(categories);
- const expected = [
- {
- name: 'All',
- route_link: '/all-2'
- },
- {
- name: 'Women',
- route_link: '/women/women-20'
- },
- {
- name: 'Tops',
- route_link: '/women/tops-women/tops-21'
- },
- {
- name: 'Jackets',
- route_link: '/women/tops-women/jackets-women/jackets-23'
- }
- ];
- expect(result).toEqual(expected);
- });
- });
-});
diff --git a/core/modules/cart/components/AddToCart.ts b/core/modules/cart/components/AddToCart.ts
deleted file mode 100644
index 73f447159b..0000000000
--- a/core/modules/cart/components/AddToCart.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product'
-import { Logger } from '@vue-storefront/core/lib/logger';
-
-// @deprecated moved to store
-export const AddToCart = {
- name: 'AddToCart',
- data () {
- return {
- isAddingToCart: false
- }
- },
- props: {
- product: {
- required: true,
- type: Object
- },
- disabled: {
- type: Boolean,
- default: false
- }
- },
- methods: {
- async addToCart (product: Product) {
- this.isAddingToCart = true
- try {
- const diffLog = await this.$store.dispatch('cart/addItem', { productToAdd: product })
-
- if (diffLog) {
- if (diffLog.clientNotifications && diffLog.clientNotifications.length > 0) {
- diffLog.clientNotifications.forEach(notificationData => {
- this.notifyUser(notificationData)
- })
- }
- } else {
- this.notifyUser({
- type: 'success',
- message: this.$t('Product has been added to the cart!'),
- action1: { label: this.$t('OK') },
- action2: null
- })
- }
- return diffLog
- } catch (err) {
- this.notifyUser({
- type: 'error',
- message: err,
- action1: { label: this.$t('OK') }
- })
- return null
- } finally {
- this.isAddingToCart = false
- }
- }
- }
-}
diff --git a/core/modules/cart/components/Microcart.ts b/core/modules/cart/components/Microcart.ts
deleted file mode 100644
index 667c2c1aae..0000000000
--- a/core/modules/cart/components/Microcart.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import AppliedCoupon from '../types/AppliedCoupon'
-import Product from '@vue-storefront/core/modules/catalog/types/Product'
-import CartTotalSegments from '../types/CartTotalSegments'
-
-// @deprecated moved to store
-export const Microcart = {
- name: 'Microcart',
- computed: {
- productsInCart (): Product[] {
- return this.$store.state.cart.cartItems
- },
- appliedCoupon (): AppliedCoupon | false {
- return this.$store.getters['cart/getCoupon']
- },
- totals (): CartTotalSegments {
- return this.$store.getters['cart/getTotals']
- },
- isOpen (): boolean {
- return this.$store.state.cart.isMicrocartOpen
- }
- },
- methods: {
- applyCoupon (code: string): Promise {
- return this.$store.dispatch('cart/applyCoupon', code)
- },
- removeCoupon (): Promise {
- return this.$store.dispatch('cart/removeCoupon')
- },
- toggleMicrocart (): void {
- this.$store.dispatch('ui/toggleMicrocart')
- }
- }
-}
diff --git a/core/modules/cart/components/MicrocartButton.ts b/core/modules/cart/components/MicrocartButton.ts
deleted file mode 100644
index 0a2b3e9cf6..0000000000
--- a/core/modules/cart/components/MicrocartButton.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-
-// @deprecated moved to theme
-export const MicrocartButton = {
- name: 'MicrocartButton',
- mounted () {
- document.addEventListener('visibilitychange', () => {
- if (!document.hidden) {
- this.$store.dispatch('cart/load')
- }
- })
- },
- methods: {
- toggleMicrocart () {
- this.$store.dispatch('cart/toggleMicrocart')
- }
- },
- computed: {
- quantity () {
- return this.$store.getters['cart/getItemsTotalQuantity']
- }
- }
-}
diff --git a/core/modules/cart/components/Product.ts b/core/modules/cart/components/Product.ts
deleted file mode 100644
index bd30e7617e..0000000000
--- a/core/modules/cart/components/Product.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { getThumbnailForProduct, getProductConfiguration } from '@vue-storefront/core/modules/cart/helpers'
-
-// @deprecated moved to theme
-export const MicrocartProduct = {
- name: 'MicrocartProduct',
- props: {
- product: {
- type: Object,
- required: true
- }
- },
- computed: {
- thumbnail () {
- return getThumbnailForProduct(this.product)
- },
- configuration () {
- return getProductConfiguration(this.product)
- }
- },
- methods: {
- removeFromCart () {
- this.$store.dispatch('cart/removeItem', { product: this.product })
- },
- updateQuantity (quantity) {
- this.$store.dispatch('cart/updateQuantity', { product: this.product, qty: quantity })
- }
- }
-}
diff --git a/core/modules/cart/helpers/calculateTotals.ts b/core/modules/cart/helpers/calculateTotals.ts
deleted file mode 100644
index b7c54b4749..0000000000
--- a/core/modules/cart/helpers/calculateTotals.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import i18n from '@vue-storefront/i18n'
-import sumBy from 'lodash-es/sumBy'
-import ShippingMethod from '@vue-storefront/core/modules/cart/types/ShippingMethod'
-import PaymentMethod from '@vue-storefront/core/modules/cart/types/PaymentMethod'
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-
-const calculateTotals = (shippingMethod: ShippingMethod, paymentMethod: PaymentMethod, cartItems: CartItem[]) => {
- const shippingTax = shippingMethod ? shippingMethod.price_incl_tax : 0
-
- const totalsArray = [
- {
- code: 'subtotal_incl_tax',
- title: i18n.t('Subtotal incl. tax'),
- value: sumBy(cartItems, (p) => p.qty * p.price_incl_tax)
- },
- {
- code: 'grand_total',
- title: i18n.t('Grand total'),
- value: sumBy(cartItems, (p) => p.qty * p.price_incl_tax + shippingTax)
- }
- ]
-
- if (paymentMethod) {
- totalsArray.push({
- code: 'payment',
- title: i18n.t(paymentMethod.title),
- value: paymentMethod.cost_incl_tax
- })
- }
- if (shippingMethod) {
- totalsArray.push({
- code: 'shipping',
- title: i18n.t(shippingMethod.method_title),
- value: shippingMethod.price_incl_tax
- })
- }
-
- return totalsArray
-}
-
-export default calculateTotals
diff --git a/core/modules/cart/helpers/cartCacheHandler.ts b/core/modules/cart/helpers/cartCacheHandler.ts
deleted file mode 100644
index a870d1e072..0000000000
--- a/core/modules/cart/helpers/cartCacheHandler.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as types from '../store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-
-export const cartCacheHandlerPlugin = (mutation, state) => {
- const type = mutation.type;
-
- if (
- type.endsWith(types.CART_LOAD_CART) ||
- type.endsWith(types.CART_ADD_ITEM) ||
- type.endsWith(types.CART_DEL_ITEM) ||
- type.endsWith(types.CART_UPD_ITEM) ||
- type.endsWith(types.CART_DEL_NON_CONFIRMED_ITEM) ||
- type.endsWith(types.CART_UPD_ITEM_PROPS)
- ) {
- return StorageManager.get('cart').setItem('current-cart', state.cart.cartItems).catch((reason) => {
- Logger.error(reason)() // it doesn't work on SSR
- }) // populate cache
- } else if (
- type.endsWith(types.CART_LOAD_CART_SERVER_TOKEN)
- ) {
- return StorageManager.get('cart').setItem('current-cart-token', state.cart.cartServerToken).catch((reason) => {
- Logger.error(reason)()
- })
- } else if (
- type.endsWith(types.CART_SET_ITEMS_HASH)
- ) {
- return StorageManager.get('cart').setItem('current-cart-hash', state.cart.cartItemsHash).catch((reason) => {
- Logger.error(reason)()
- })
- }
-}
diff --git a/core/modules/cart/helpers/createCartItemForUpdate.ts b/core/modules/cart/helpers/createCartItemForUpdate.ts
deleted file mode 100644
index 6b13be97ae..0000000000
--- a/core/modules/cart/helpers/createCartItemForUpdate.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import config from 'config'
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem';
-
-const createCartItemForUpdate = (clientItem: CartItem, serverItem: any, updateIds: boolean = false, mergeQty: boolean = false): CartItem => {
- const sku = clientItem.parentSku && config.cart.setConfigurableProductOptions ? clientItem.parentSku : clientItem.sku
- const cartItem = {
- sku,
- ...((serverItem && serverItem.item_id) ? { item_id: serverItem.item_id } : {}),
- qty: mergeQty ? (clientItem.qty + serverItem.qty) : clientItem.qty,
- product_option: clientItem.product_option
- } as any as CartItem
-
- if (updateIds && serverItem.quote_id && serverItem.item_id) {
- return {
- ...cartItem,
- quoteId: serverItem.quote_id,
- item_id: serverItem.item_id
- }
- }
-
- return cartItem
-}
-
-export default createCartItemForUpdate
diff --git a/core/modules/cart/helpers/createDiffLog.ts b/core/modules/cart/helpers/createDiffLog.ts
deleted file mode 100644
index 597aa159ea..0000000000
--- a/core/modules/cart/helpers/createDiffLog.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { Notification, ServerResponse, Party } from '@vue-storefront/core/modules/cart/types/DiffLog'
-
-class DiffLog {
- public items: Party[]
- public serverResponses: ServerResponse[]
- public clientNotifications: Notification[]
-
- public constructor () {
- this.items = []
- this.serverResponses = []
- this.clientNotifications = []
- }
-
- public pushParty (party: Party): DiffLog {
- this.items.push(party)
- return this
- }
-
- public pushClientParty (party: any): DiffLog {
- this.pushParty({ party: 'client', ...party })
- return this
- }
-
- public pushServerParty (party: any): DiffLog {
- this.pushParty({ party: 'server', ...party })
- return this
- }
-
- public pushServerResponse (response: ServerResponse): DiffLog {
- this.serverResponses.push(response)
- return this
- }
-
- public pushNotification (notification: Notification): DiffLog {
- this.clientNotifications.push(notification)
- return this
- }
-
- public pushNotifications (notifications: Notification[]): DiffLog {
- this.clientNotifications = this.clientNotifications.concat(notifications)
- return this
- }
-
- public merge (diffLog: DiffLog): DiffLog {
- this.items = this.items.concat(diffLog.items)
- this.serverResponses = this.serverResponses.concat(diffLog.serverResponses)
- this.clientNotifications = this.clientNotifications.concat(diffLog.clientNotifications)
- return this
- }
-
- public hasClientNotifications () {
- return this.clientNotifications.length > 0
- }
-
- public hasServerResponses () {
- return this.serverResponses.length > 0
- }
-
- public hasParties () {
- return this.items.length > 0
- }
-
- public isEmpty (): boolean {
- return !this.hasParties &&
- !this.hasClientNotifications() &&
- !this.hasServerResponses()
- }
-}
-
-const createDiffLog = (): DiffLog => new DiffLog()
-
-export default createDiffLog
diff --git a/core/modules/cart/helpers/createOrderData.ts b/core/modules/cart/helpers/createOrderData.ts
deleted file mode 100644
index 37c12e34ac..0000000000
--- a/core/modules/cart/helpers/createOrderData.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import OrderShippingDetails from '@vue-storefront/core/modules/cart/types/OrderShippingDetails'
-import PaymentMethod from '@vue-storefront/core/modules/cart/types/PaymentMethod'
-import ShippingMethod from '@vue-storefront/core/modules/cart/types/ShippingMethod'
-import CheckoutData from '@vue-storefront/core/modules/cart/types/CheckoutData'
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-
-const getDefaultShippingMethod = (shippingMethods: ShippingMethod[] = []): ShippingMethod => {
- const onlineShippingMethods = shippingMethods.filter(shippingMethod => !shippingMethod.offline)
- if (!onlineShippingMethods.length) return
-
- return onlineShippingMethods.find(shippingMethod => !!shippingMethod.default) || onlineShippingMethods[0]
-}
-
-const getDefaultPaymentMethod = (paymentMethods: PaymentMethod[] = []): PaymentMethod => {
- if (!paymentMethods || !paymentMethods.length) return
-
- return paymentMethods.find(item => item.default) || paymentMethods[0]
-}
-
-const createOrderData = ({
- shippingDetails,
- shippingMethods,
- paymentMethods,
- paymentDetails,
- taxCountry = currentStoreView().tax.defaultCountry
-}: CheckoutData): OrderShippingDetails => {
- const country = shippingDetails.country ? shippingDetails.country : taxCountry
- const shipping = getDefaultShippingMethod(shippingMethods)
- const payment = getDefaultPaymentMethod(paymentMethods)
-
- return {
- country,
- shippingAddress: {
- firstname: shippingDetails.firstName,
- lastname: shippingDetails.lastName,
- city: shippingDetails.city,
- postcode: shippingDetails.zipCode,
- street: [shippingDetails.streetAddress]
- },
- billingAddress: {
- firstname: paymentDetails.firstName,
- lastname: paymentDetails.lastName,
- city: paymentDetails.city,
- postcode: paymentDetails.zipCode,
- street: [paymentDetails.streetAddress],
- countryId: paymentDetails.country
- },
- method_code: shipping && shipping.method_code ? shipping.method_code : null,
- carrier_code: shipping && shipping.carrier_code ? shipping.carrier_code : null,
- payment_method: payment && payment.code ? payment.code : null
- }
-}
-
-export default createOrderData
diff --git a/core/modules/cart/helpers/createShippingInfoData.ts b/core/modules/cart/helpers/createShippingInfoData.ts
deleted file mode 100644
index 8395dcd816..0000000000
--- a/core/modules/cart/helpers/createShippingInfoData.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-const createShippingInfoData = (methodsData) => ({
- shippingAddress: {
- countryId: methodsData.country,
- ...(methodsData.shippingAddress ? methodsData.shippingAddress : {})
- },
- billingAddress: {
- ...(methodsData.billingAddress ? methodsData.billingAddress : {})
- },
- ...(methodsData.carrier_code ? { shippingCarrierCode: methodsData.carrier_code } : {}),
- ...(methodsData.method_code ? { shippingMethodCode: methodsData.method_code } : {})
-});
-
-export default createShippingInfoData
diff --git a/core/modules/cart/helpers/getProductConfiguration.ts b/core/modules/cart/helpers/getProductConfiguration.ts
deleted file mode 100644
index d45200279c..0000000000
--- a/core/modules/cart/helpers/getProductConfiguration.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import { ProductConfiguration } from '@vue-storefront/core/modules/catalog/types/ProductConfiguration'
-import getProductOptions from './getProductOptions'
-
-const ATTRIBUTES = ['color', 'size']
-
-const getProductConfiguration = (product: CartItem): ProductConfiguration => {
- const options = getProductOptions(product)
- const getAttributesFields = (attributeCode) =>
- (options[attributeCode] || []).find(c => String(c.id) === String(product[attributeCode]))
-
- if (!options) {
- return null
- }
-
- return ATTRIBUTES.reduce((prev, curr) => ({
- ...prev,
- [curr]: {
- attribute_code: curr,
- ...getAttributesFields(curr)
- }
- }), {}) as any as ProductConfiguration
-}
-
-export default getProductConfiguration
diff --git a/core/modules/cart/helpers/getProductOptions.ts b/core/modules/cart/helpers/getProductOptions.ts
deleted file mode 100644
index aa4a5ec36a..0000000000
--- a/core/modules/cart/helpers/getProductOptions.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import { ProductOption } from '@vue-storefront/core/modules/catalog/types/ProductConfiguration'
-
-const mapValues = (current) => (val) => ({
- id: val.value_index,
- label: val.label,
- attribute_code: current.attribute_code,
- type: current.attribute_code
-})
-
-const reduceOptions = (prev, curr) => ({
- ...prev,
- [curr.attribute_code]: curr.values.map(mapValues(curr))
-})
-
-const getProductOptions = (product: CartItem): ProductOption => {
- if (!product.configurable_options) {
- return null
- }
-
- return product.configurable_options
- .reduce(reduceOptions, {})
-}
-
-export default getProductOptions
diff --git a/core/modules/cart/helpers/getThumbnailForProduct.ts b/core/modules/cart/helpers/getThumbnailForProduct.ts
deleted file mode 100644
index aa5eafe06b..0000000000
--- a/core/modules/cart/helpers/getThumbnailForProduct.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import config from 'config'
-import { getThumbnailPath } from '@vue-storefront/core/helpers'
-import { productThumbnailPath } from '@vue-storefront/core/helpers'
-
-const getThumbnailForProduct = (product: CartItem): string => {
- const thumbnail = productThumbnailPath(product)
-
- if (typeof navigator !== 'undefined' && !navigator.onLine) {
- return getThumbnailPath(thumbnail, config.products.thumbnails.width, config.products.thumbnails.height)
- }
-
- return getThumbnailPath(thumbnail, config.cart.thumbnails.width, config.cart.thumbnails.height)
-}
-
-export default getThumbnailForProduct
diff --git a/core/modules/cart/helpers/index.ts b/core/modules/cart/helpers/index.ts
deleted file mode 100644
index e29ad43e58..0000000000
--- a/core/modules/cart/helpers/index.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { cartCacheHandlerPlugin } from './cartCacheHandler'
-import { totalsCacheHandlerPlugin } from './totalsCacheHandler'
-import optimizeProduct from './optimizeProduct'
-import prepareProductsToAdd from './prepareProductsToAdd'
-import productChecksum from './productChecksum'
-import productsEquals from './productsEquals'
-import calculateTotals from './calculateTotals'
-import preparePaymentMethodsToSync from './preparePaymentMethodsToSync'
-import validateProduct from './validateProduct'
-import createDiffLog from './createDiffLog'
-import * as notifications from './notifications'
-import createCartItemForUpdate from './createCartItemForUpdate'
-import prepareShippingInfoForUpdateTotals from './prepareShippingInfoForUpdateTotals'
-import getThumbnailForProduct from './getThumbnailForProduct'
-import getProductOptions from './getProductOptions'
-import getProductConfiguration from './getProductConfiguration'
-import createOrderData from './createOrderData'
-import createShippingInfoData from './createShippingInfoData'
-import * as syncCartWhenLocalStorageChange from './syncCartWhenLocalStorageChange'
-
-export {
- cartCacheHandlerPlugin,
- totalsCacheHandlerPlugin,
- optimizeProduct,
- prepareProductsToAdd,
- productChecksum,
- productsEquals,
- calculateTotals,
- preparePaymentMethodsToSync,
- validateProduct,
- notifications,
- createDiffLog,
- createCartItemForUpdate,
- prepareShippingInfoForUpdateTotals,
- getThumbnailForProduct,
- getProductOptions,
- getProductConfiguration,
- createOrderData,
- createShippingInfoData,
- syncCartWhenLocalStorageChange
-}
diff --git a/core/modules/cart/helpers/notifications.ts b/core/modules/cart/helpers/notifications.ts
deleted file mode 100644
index 06e5872d5d..0000000000
--- a/core/modules/cart/helpers/notifications.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { router } from '@vue-storefront/core/app';
-import { currentStoreView, localizedRoute } from '@vue-storefront/core/lib/multistore';
-import i18n from '@vue-storefront/i18n';
-import config from 'config';
-
-const proceedToCheckoutAction = () => ({
- label: i18n.t('Proceed to checkout'),
- action: () => router.push(localizedRoute('/checkout', currentStoreView().storeCode))
-});
-const checkoutAction = () => !config.externalCheckout ? proceedToCheckoutAction() : null;
-
-const productAddedToCart = () => ({
- type: 'success',
- message: i18n.t('Product has been added to the cart!'),
- action1: { label: i18n.t('OK') },
- action2: checkoutAction()
-})
-
-const productQuantityUpdated = () => ({
- type: 'success',
- message: i18n.t('Product quantity has been updated!'),
- action1: { label: i18n.t('OK') },
- action2: checkoutAction()
-})
-
-const unsafeQuantity = () => ({
- type: 'warning',
- message: i18n.t(
- 'The system is not sure about the stock quantity (volatile). Product has been added to the cart for pre-reservation.'
- ),
- action1: { label: i18n.t('OK') }
-})
-
-const outOfStock = () => ({
- type: 'error',
- message: i18n.t('The product is out of stock and cannot be added to the cart!'),
- action1: { label: i18n.t('OK') }
-})
-
-const createNotification = ({ type, message }) => ({ type, message, action1: { label: i18n.t('OK') } })
-const createNotifications = ({ type, messages }) =>
- messages.map(message => createNotification({ type, message }));
-
-export {
- createNotification,
- createNotifications,
- productAddedToCart,
- productQuantityUpdated,
- unsafeQuantity,
- outOfStock
-};
diff --git a/core/modules/cart/helpers/optimizeProduct.ts b/core/modules/cart/helpers/optimizeProduct.ts
deleted file mode 100644
index 16370a516d..0000000000
--- a/core/modules/cart/helpers/optimizeProduct.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import config from 'config'
-import omit from 'lodash-es/omit'
-import pullAll from 'lodash-es/pullAll'
-
-const optimizeProduct = (product: CartItem): CartItem => {
- if (!config.entities.optimizeShoppingCart) {
- return product
- }
-
- let fieldsToOmit = config.entities.optimizeShoppingCartOmitFields
-
- if (config.cart.productsAreReconfigurable) {
- fieldsToOmit = pullAll(fieldsToOmit, ['configurable_children', 'configurable_options'])
- }
-
- return omit(product, fieldsToOmit)
-}
-
-export default optimizeProduct
diff --git a/core/modules/cart/helpers/preparePaymentMethodsToSync.ts b/core/modules/cart/helpers/preparePaymentMethodsToSync.ts
deleted file mode 100644
index 0f4d1d0717..0000000000
--- a/core/modules/cart/helpers/preparePaymentMethodsToSync.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import PaymentMethod from '@vue-storefront/core/modules/cart/types/PaymentMethod'
-
-const isPaymentMethodNotExist = (backendPaymentMethod: PaymentMethod, paymentMethods: PaymentMethod[]) =>
- typeof backendPaymentMethod === 'object' && !paymentMethods.find(item => item.code === backendPaymentMethod.code)
-
-const preparePaymentMethodsToSync = (
- backendPaymentMethods: PaymentMethod[],
- currentPaymentMethods: PaymentMethod[]
-): { uniqueBackendMethods: PaymentMethod[], paymentMethods: PaymentMethod[] } => {
- const paymentMethods = [...currentPaymentMethods]
- const uniqueBackendMethods = []
-
- for (const backendPaymentMethod of backendPaymentMethods) {
- if (isPaymentMethodNotExist(backendPaymentMethod, currentPaymentMethods)) {
- const backendMethod = {
- ...backendPaymentMethod,
- is_server_method: true
- }
-
- paymentMethods.push(backendMethod)
- uniqueBackendMethods.push(backendMethod)
- }
- }
-
- return { uniqueBackendMethods, paymentMethods }
-}
-
-export default preparePaymentMethodsToSync
diff --git a/core/modules/cart/helpers/prepareProductsToAdd.ts b/core/modules/cart/helpers/prepareProductsToAdd.ts
deleted file mode 100644
index d464694f34..0000000000
--- a/core/modules/cart/helpers/prepareProductsToAdd.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import productChecksum from './productChecksum'
-import optimizeProduct from './optimizeProduct'
-
-const readAssociated = product =>
- product.product_links.filter(p => p.link_type === 'associated').map(p => p.product)
-
-const isDefined = product => typeof product !== 'undefined' || product !== null
-
-const applyQty = product => ({
- ...product,
- qty: product.qty && typeof product.qty !== 'number' ? parseInt(product.qty) : product.qty
-});
-
-const applyChecksum = product => ({ ...product, checksum: productChecksum(product) })
-
-const prepareProductsToAdd = (product: CartItem): CartItem[] => {
- const products = product.type_id === 'grouped' ? readAssociated(product) : [product]
-
- return products
- .filter(isDefined)
- .map(applyQty)
- .map(p => optimizeProduct(p))
- .map(applyChecksum);
-};
-
-export default prepareProductsToAdd;
diff --git a/core/modules/cart/helpers/prepareShippingInfoForUpdateTotals.ts b/core/modules/cart/helpers/prepareShippingInfoForUpdateTotals.ts
deleted file mode 100644
index 3004d40350..0000000000
--- a/core/modules/cart/helpers/prepareShippingInfoForUpdateTotals.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import isString from 'lodash-es/isString'
-import Totals from '@vue-storefront/core/modules/cart/types/Totals'
-
-const applyOptions = (item: Totals) => {
- if (item.options && isString(item.options)) {
- return { ...item, options: JSON.parse(item.options) }
- }
-
- return item
-}
-
-const reduceToObject = (previousValue: any, currentValue: Totals) => ({
- ...previousValue,
- [currentValue.item_id]: currentValue
-})
-
-const prepareShippingInfoForUpdateTotals = (totals: Totals[]) =>
- totals
- .map(applyOptions)
- .reduce(reduceToObject, {})
-
-export default prepareShippingInfoForUpdateTotals
diff --git a/core/modules/cart/helpers/productChecksum.ts b/core/modules/cart/helpers/productChecksum.ts
deleted file mode 100644
index 4798da845f..0000000000
--- a/core/modules/cart/helpers/productChecksum.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import { sha3_224 } from 'js-sha3'
-import get from 'lodash-es/get'
-import flow from 'lodash-es/flow'
-import cloneDeep from 'lodash-es/cloneDeep';
-
-const replaceNumberToString = obj => {
- Object.keys(obj).forEach(key => {
- if (obj[key] !== null && typeof obj[key] === 'object') {
- return replaceNumberToString(obj[key]);
- } else if (typeof obj[key] === 'number') {
- obj[key] = String(obj[key]);
- }
- });
- return obj;
-}
-
-const transformToArray = value => Array.isArray(value) ? value : Object.values(value)
-
-export const getProductOptions = (product, optionsName) => {
- return flow([
- get,
- cloneDeep,
- transformToArray,
- replaceNumberToString
- ])(product, `product_option.extension_attributes.${optionsName}`, [])
-}
-
-const getDataToHash = (product: CartItem): any => {
- if (!product.product_option) {
- return null
- }
-
- const supportedProductOptions = ['bundle_options', 'custom_options', 'configurable_item_options']
-
- // returns first options that has array with options
- for (let optionName of supportedProductOptions) {
- const options = getProductOptions(product, optionName)
- if (options.length) {
- return options
- }
- }
-
- // if there are options that are not supported then just return all options
- return product.product_option
-}
-
-const productChecksum = (product: CartItem): string => sha3_224(JSON.stringify(getDataToHash(product)))
-
-export default productChecksum
diff --git a/core/modules/cart/helpers/productsEquals.ts b/core/modules/cart/helpers/productsEquals.ts
deleted file mode 100644
index 7af6cb287c..0000000000
--- a/core/modules/cart/helpers/productsEquals.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import productChecksum, { getProductOptions } from './productChecksum';
-
-type ProductEqualCheckFn = (product1: CartItem, product2: CartItem) => boolean
-
-// 'id' check
-const getServerItemId = (product: CartItem): string | number =>
- product.server_item_id || product.item_id
-const isServerIdsEquals = (product1: CartItem, product2: CartItem): boolean => {
- const product1ItemId = getServerItemId(product1)
- const product2ItemId = getServerItemId(product2)
-
- const areItemIdsDefined = product1ItemId !== undefined && product2ItemId !== undefined
-
- return areItemIdsDefined && product1ItemId === product2ItemId
-}
-
-// 'checksum' check
-const getChecksum = (product: CartItem) => {
- if (product.checksum) {
- return product.checksum
- }
- return productChecksum(product)
-}
-const isChecksumEquals = (product1: CartItem, product2: CartItem): boolean =>
- getChecksum(product1) === getChecksum(product2)
-
-// 'sku' check
-const isSkuEqual = (product1: CartItem, product2: CartItem): boolean =>
- String(product1.sku) === String(product2.sku)
-
-/**
- * Returns product equality check function
- * @param checkName - determines what type of check we want to do
- */
-const getCheckFn = (checkName: string): ProductEqualCheckFn => {
- switch (checkName) {
- case 'id': {
- return isServerIdsEquals
- }
- case 'checksum': {
- return isChecksumEquals
- }
- case 'sku': {
- return isSkuEqual
- }
- default: {
- return isSkuEqual
- }
- }
-}
-
-/**
- * It passes all types of checks and returns the first passed. The order of checks matters!
- */
-const makeCheck = (product1: CartItem, product2: CartItem, checks: string[]): boolean => {
- for (let checkName of checks) {
- const fn = getCheckFn(checkName)
- if (fn(product1, product2)) {
- return true
- }
- }
- return false
-}
-
-const productsEquals = (product1: CartItem, product2: CartItem): boolean => {
- if (!product1 || !product2) {
- return false
- }
-
- const check = makeCheck.bind(null, product1, product2)
-
- if (getProductOptions(product1, 'bundle_options').length || getProductOptions(product2, 'bundle_options').length) {
- // bundle options skus are merged into one sku so we can't rely on 'sku'
- // by default we want to check server_item_id ('id'), we can also use 'checksum'
- return check(['id', 'checksum'])
- }
-
- if (getProductOptions(product1, 'custom_options').length || getProductOptions(product2, 'custom_options').length) {
- // in admin panel we can add different sku for specific custom option so we can't rely on 'sku'
- // by default we want to check server_item_id ('id'), we can also use 'checksum'
- return check(['id', 'checksum'])
- }
-
- if (getProductOptions(product1, 'configurable_item_options').length || getProductOptions(product2, 'configurable_item_options').length) {
- // 'sku' should be uniq for configurable products
- // we can't check 'id' because it is the same when user edit product in microcart, so it can give wrong result
- return check(['sku'])
- }
-
- // by default we want to check if server_item_id is equal and check sku as fallback
- // this is for 'simple' and 'group' products
- return check(['id', 'sku'])
-}
-
-export default productsEquals
diff --git a/core/modules/cart/helpers/syncCartWhenLocalStorageChange.ts b/core/modules/cart/helpers/syncCartWhenLocalStorageChange.ts
deleted file mode 100644
index e3ed0bcd7c..0000000000
--- a/core/modules/cart/helpers/syncCartWhenLocalStorageChange.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import rootStore from '@vue-storefront/core/store'
-import { storeViews } from 'config'
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-
-function checkMultistoreKey (key: string, path: string): boolean {
- const { multistore, commonCache } = storeViews
- if (!multistore || (multistore && commonCache)) return key === path
- return key === `${currentStoreView().storeCode}-${path}`
-}
-
-function getItemsFromStorage ({ key }) {
- if (checkMultistoreKey(key, 'shop/cart/current-cart')) {
- const value = JSON.parse(localStorage[key])
- rootStore.dispatch('cart/updateCart', { items: value })
- } else if (checkMultistoreKey(key, 'shop/cart/current-totals')) {
- const value = JSON.parse(localStorage[key])
- rootStore.dispatch('cart/updateTotals', value)
- }
-}
-
-function addEventListener () {
- window.addEventListener('storage', getItemsFromStorage)
-}
-
-function removeEventListener () {
- window.removeEventListener('storage', getItemsFromStorage)
-}
-
-export {
- addEventListener,
- removeEventListener
-}
diff --git a/core/modules/cart/helpers/totalsCacheHandler.ts b/core/modules/cart/helpers/totalsCacheHandler.ts
deleted file mode 100644
index 515a347f27..0000000000
--- a/core/modules/cart/helpers/totalsCacheHandler.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import * as types from '../store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-
-export const totalsCacheHandlerPlugin = ({ type }, state) => {
- if (
- type.endsWith(types.CART_UPD_TOTALS)
- ) {
- return StorageManager.get('cart').setItem('current-totals', {
- platformTotalSegments: state.cart.platformTotalSegments,
- platformTotals: state.cart.platformTotals
- }).catch((reason) => {
- Logger.error(reason)()
- })
- }
-}
diff --git a/core/modules/cart/helpers/validateProduct.ts b/core/modules/cart/helpers/validateProduct.ts
deleted file mode 100644
index c348d86b71..0000000000
--- a/core/modules/cart/helpers/validateProduct.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import config from 'config'
-import i18n from '@vue-storefront/i18n'
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem';
-
-const validateProduct = (product: CartItem): string[] => {
- const errors = []
-
- if (config.useZeroPriceProduct ? product.price_incl_tax < 0 : product.price_incl_tax <= 0) {
- errors.push(i18n.t('Product price is unknown, product cannot be added to the cart!'))
- }
-
- if (product.errors !== null && typeof product.errors !== 'undefined') {
- for (const errKey in product.errors) {
- if (product.errors[errKey]) {
- errors.push(product.errors[errKey])
- }
- }
- }
-
- return errors
-};
-
-export default validateProduct;
diff --git a/core/modules/cart/hooks/index.ts b/core/modules/cart/hooks/index.ts
deleted file mode 100644
index 6d08ad598f..0000000000
--- a/core/modules/cart/hooks/index.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import { createListenerHook, createMutatorHook } from '@vue-storefront/core/lib/hooks'
-import CartItem from '../types/CartItem';
-
-const {
- hook: beforeSyncHook,
- executor: beforeSyncExecutor
-} = createMutatorHook<{ clientItems: CartItem[], serverItems: CartItem[] }, any>()
-
-const {
- hook: afterSyncHook,
- executor: afterSyncExecutor
-} = createListenerHook()
-
-const {
- hook: beforeAddToCartHook,
- executor: beforeAddToCartExecutor
-} = createMutatorHook<{ cartItem: CartItem }, any>()
-
-const {
- hook: afterAddToCartHook,
- executor: afterAddToCartExecutor
-} = createListenerHook()
-
-const {
- hook: beforeRemoveFromCartHook,
- executor: beforeRemoveFromCartExecutor
-} = createMutatorHook<{ cartItem: CartItem }, any>()
-
-const {
- hook: afterRemoveFromCartHook,
- executor: afterRemoveFromCartExecutor
-} = createListenerHook()
-
-const {
- hook: beforeMergeHook,
- executor: beforeMergeExecutor
-} = createMutatorHook<{ clientItems: CartItem[], serverItems: CartItem[] }, any>()
-
-const {
- hook: afterLoadHook,
- executor: afterLoadExecutor
-} = createListenerHook()
-
-const cartHooksExecutors = {
- beforeSync: beforeSyncExecutor,
- afterSync: afterSyncExecutor,
- beforeAddToCart: beforeAddToCartExecutor,
- afterAddToCart: afterAddToCartExecutor,
- beforeRemoveFromCart: beforeRemoveFromCartExecutor,
- afterRemoveFromCart: afterRemoveFromCartExecutor,
- beforeMerge: beforeMergeExecutor,
- afterLoad: afterLoadExecutor
-}
-
-const cartHooks = {
- beforeSync: beforeSyncHook,
- afterSync: afterSyncHook,
- beforeAddToCart: beforeAddToCartHook,
- afterAddToCart: afterAddToCartHook,
- beforeRemoveFromCart: beforeRemoveFromCartHook,
- afterRemoveFromCart: afterRemoveFromCartHook,
- beforeMerge: beforeMergeHook,
- afterLoad: afterLoadHook
-}
-
-export {
- cartHooks,
- cartHooksExecutors
-}
diff --git a/core/modules/cart/index.ts b/core/modules/cart/index.ts
deleted file mode 100644
index 6e2126d41e..0000000000
--- a/core/modules/cart/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { StorefrontModule } from '@vue-storefront/core/lib/modules'
-import { cartStore } from './store'
-import { cartCacheHandlerPlugin, totalsCacheHandlerPlugin } from './helpers';
-import { isServer } from '@vue-storefront/core/helpers'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-
-export const CartModule: StorefrontModule = function ({ store }) {
- StorageManager.init('cart')
-
- store.registerModule('cart', cartStore)
-
- if (!isServer) store.dispatch('cart/load')
- store.subscribe(cartCacheHandlerPlugin);
- store.subscribe(totalsCacheHandlerPlugin);
-}
diff --git a/core/modules/cart/store/actions/connectActions.ts b/core/modules/cart/store/actions/connectActions.ts
deleted file mode 100644
index 9b0ce22df7..0000000000
--- a/core/modules/cart/store/actions/connectActions.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import config from 'config'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import { CartService } from '@vue-storefront/core/data-resolver'
-import { createDiffLog } from '@vue-storefront/core/modules/cart/helpers'
-
-const connectActions = {
- toggleMicrocart ({ commit }) {
- commit(types.CART_TOGGLE_MICROCART)
- },
- /**
- * It will always clear cart items on frontend.
- * Options:
- * sync - if you want to sync it with backend.
- * disconnect - if you want to clear cart token.
- */
- async clear ({ commit, dispatch }, { disconnect = true, sync = true } = {}) {
- await commit(types.CART_LOAD_CART, [])
- if (sync) {
- await dispatch('sync', { forceClientState: true, forceSync: true })
- }
- if (disconnect) {
- await commit(types.CART_SET_ITEMS_HASH, null)
- await dispatch('disconnect')
- }
- },
- async disconnect ({ commit }) {
- commit(types.CART_LOAD_CART_SERVER_TOKEN, null)
- },
- async authorize ({ dispatch, getters }) {
- const coupon = getters.getCoupon.code
- if (coupon) {
- await dispatch('removeCoupon', { sync: false })
- }
-
- await dispatch('connect', { guestCart: false, mergeQty: true })
-
- if (coupon) {
- await dispatch('applyCoupon', coupon)
- }
- },
- async connect ({ getters, dispatch, commit }, { guestCart = false, forceClientState = false, mergeQty = false }) {
- if (!getters.isCartSyncEnabled) return
- const { result, resultCode } = await CartService.getCartToken(guestCart, forceClientState)
-
- if (resultCode === 200) {
- Logger.info('Server cart token created.', 'cart', result)()
- commit(types.CART_LOAD_CART_SERVER_TOKEN, result)
-
- return dispatch('sync', { forceClientState, dryRun: !config.cart.serverMergeByDefault, mergeQty })
- }
-
- if (resultCode === 401 && getters.bypassCounter < config.queues.maxCartBypassAttempts) {
- Logger.log('Bypassing with guest cart' + getters.bypassCounter, 'cart')()
- commit(types.CART_UPDATE_BYPASS_COUNTER, { counter: 1 })
- Logger.error(result, 'cart')()
- return dispatch('connect', { guestCart: true })
- }
-
- Logger.warn('Cart sync is disabled by the config', 'cart')()
- return createDiffLog()
- },
- /**
- * Create cart token when there are products in cart and we don't have token already
- */
- async create ({ dispatch, getters }) {
- const storedItems = getters['getCartItems'] || []
- const cartToken = getters['getCartToken']
- if (storedItems.length && !cartToken) {
- Logger.info('Creating server cart token', 'cart')()
- return dispatch('connect', { guestCart: false })
- }
- }
-}
-
-export default connectActions
diff --git a/core/modules/cart/store/actions/couponActions.ts b/core/modules/cart/store/actions/couponActions.ts
deleted file mode 100644
index cdb7005f09..0000000000
--- a/core/modules/cart/store/actions/couponActions.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { CartService } from '@vue-storefront/core/data-resolver'
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-
-const couponActions = {
- async removeCoupon ({ getters, dispatch, commit }, { sync = true } = {}) {
- if (getters.canSyncTotals) {
- const { result } = await CartService.removeCoupon()
-
- if (result && sync) {
- await dispatch('syncTotals', { forceServerSync: true })
-
- // 'getCurrentCartHash' has been changed (it's based on cart items data)
- // so we need to update it in vuex and StorageManager
- commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash)
- return result
- }
- }
- },
- async applyCoupon ({ getters, dispatch, commit }, couponCode) {
- if (couponCode && getters.canSyncTotals) {
- const { result } = await CartService.applyCoupon(couponCode)
-
- if (result) {
- await dispatch('syncTotals', { forceServerSync: true })
-
- // 'getCurrentCartHash' has been changed (it's based on cart items data)
- // so we need to update it in vuex and StorageManager
- commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash)
- }
- return result
- }
- }
-}
-
-export default couponActions
diff --git a/core/modules/cart/store/actions/index.ts b/core/modules/cart/store/actions/index.ts
deleted file mode 100644
index 4f45902790..0000000000
--- a/core/modules/cart/store/actions/index.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-
-import { ActionTree } from 'vuex'
-import RootState from '@vue-storefront/core/types/RootState'
-import CartState from '@vue-storefront/core/modules/cart/types/CartState'
-import connectActions from './connectActions'
-import couponActions from './couponActions'
-import itemActions from './itemActions'
-import mergeActions from './mergeActions';
-import methodsActions from './methodsActions'
-import productActions from './productActions'
-import quantityActions from './quantityActions'
-import synchronizeActions from './synchronizeActions'
-import totalsActions from './totalsActions'
-
-const actions: ActionTree = {
- ...connectActions,
- ...itemActions,
- ...couponActions,
- ...mergeActions,
- ...methodsActions,
- ...productActions,
- ...quantityActions,
- ...synchronizeActions,
- ...totalsActions
-}
-
-export default actions
diff --git a/core/modules/cart/store/actions/itemActions.ts b/core/modules/cart/store/actions/itemActions.ts
deleted file mode 100644
index 02f0625fb3..0000000000
--- a/core/modules/cart/store/actions/itemActions.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import {
- prepareProductsToAdd,
- productsEquals,
- validateProduct,
- createDiffLog,
- notifications
-} from '@vue-storefront/core/modules/cart/helpers'
-import { cartHooksExecutors } from './../../hooks'
-import config from 'config'
-
-const itemActions = {
- async configureItem (context, { product, configuration }) {
- const { commit, dispatch, getters } = context
- const variant = await dispatch('product/getProductVariant', {
- product,
- configuration
- }, { root: true })
-
- const itemWithSameSku = getters.getCartItems.find(item => item.sku === variant.sku)
-
- if (itemWithSameSku && product.sku !== variant.sku) {
- Logger.debug('Item with the same sku detected', 'cart', { sku: itemWithSameSku.sku })()
- commit(types.CART_DEL_ITEM, { product: itemWithSameSku })
- product.qty = parseInt(product.qty) + parseInt(itemWithSameSku.qty)
- }
-
- commit(types.CART_UPD_ITEM_PROPS, { product: { ...product, ...variant } })
-
- if (getters.isCartSyncEnabled && product.server_item_id) {
- await dispatch('sync', { forceClientState: true })
- }
- },
- updateItem ({ commit }, { product }) {
- commit(types.CART_UPD_ITEM_PROPS, { product })
- },
- getItem ({ getters }, { product }) {
- return getters.getCartItems.find(p => productsEquals(p, product))
- },
- async addItem ({ dispatch, commit }, { productToAdd, forceServerSilence = false }) {
- const { cartItem } = cartHooksExecutors.beforeAddToCart({ cartItem: productToAdd })
- commit(types.CART_ADDING_ITEM, { isAdding: true })
- const result = await dispatch('addItems', { productsToAdd: prepareProductsToAdd(cartItem), forceServerSilence })
- commit(types.CART_ADDING_ITEM, { isAdding: false })
- cartHooksExecutors.afterAddToCart(result)
- return result
- },
- async checkProductStatus ({ dispatch, getters }, { product }) {
- const record = getters.getCartItems.find(p => productsEquals(p, product))
- const qty = record ? record.qty + 1 : (product.qty ? product.qty : 1)
-
- return dispatch('stock/queueCheck', { product, qty }, { root: true })
- },
- async addItems ({ commit, dispatch, getters }, { productsToAdd, forceServerSilence = false }) {
- let productIndex = 0
- const diffLog = createDiffLog()
- for (let product of productsToAdd) {
- const errors = validateProduct(product)
- diffLog.pushNotifications(notifications.createNotifications({ type: 'error', messages: errors }))
-
- if (errors.length === 0) {
- const { status, onlineCheckTaskId } = await dispatch('checkProductStatus', { product })
-
- if (status === 'volatile' && !config.stock.allowOutOfStockInCart) {
- diffLog.pushNotification(notifications.unsafeQuantity())
- }
- if (status === 'out_of_stock') {
- diffLog.pushNotification(notifications.outOfStock())
- }
-
- if (status === 'ok' || status === 'volatile') {
- commit(types.CART_ADD_ITEM, {
- product: { ...product, onlineStockCheckid: onlineCheckTaskId }
- })
- }
- if (productIndex === (productsToAdd.length - 1) && (!getters.isCartSyncEnabled || forceServerSilence)) {
- diffLog.pushNotification(notifications.productAddedToCart())
- }
- productIndex++
- }
- }
-
- let newDiffLog = await dispatch('create')
- if (newDiffLog !== undefined) {
- diffLog.merge(newDiffLog)
- }
-
- if (getters.isCartSyncEnabled && getters.isCartConnected && !forceServerSilence) {
- const syncDiffLog = await dispatch('sync', { forceClientState: true })
-
- if (!syncDiffLog.isEmpty()) {
- diffLog.merge(syncDiffLog)
- }
- }
-
- return diffLog
- },
- async removeItem ({ commit, dispatch, getters }, payload) {
- const removeByParentSku = payload.product ? !!payload.removeByParentSku && payload.product.type_id !== 'bundle' : true
- const product = payload.product || payload
- const { cartItem } = cartHooksExecutors.beforeRemoveFromCart({ cartItem: product })
-
- commit(types.CART_DEL_ITEM, { product: cartItem, removeByParentSku })
-
- if (getters.isCartSyncEnabled && cartItem.server_item_id) {
- const diffLog = await dispatch('sync', { forceClientState: true })
- cartHooksExecutors.afterRemoveFromCart(diffLog)
- return diffLog
- }
-
- const diffLog = createDiffLog()
- .pushClientParty({ status: 'no-item', sku: product.sku })
- cartHooksExecutors.afterRemoveFromCart(diffLog)
- return diffLog
- }
-}
-
-export default itemActions
diff --git a/core/modules/cart/store/actions/mergeActions.ts b/core/modules/cart/store/actions/mergeActions.ts
deleted file mode 100644
index b2fbf76ba0..0000000000
--- a/core/modules/cart/store/actions/mergeActions.ts
+++ /dev/null
@@ -1,217 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import config from 'config'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { CartService } from '@vue-storefront/core/data-resolver'
-import {
- productsEquals,
- createDiffLog,
- notifications,
- createCartItemForUpdate
-} from '@vue-storefront/core/modules/cart/helpers'
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem';
-import { cartHooksExecutors } from './../../hooks'
-
-const mergeActions = {
- async updateClientItem ({ dispatch }, { clientItem, serverItem }) {
- const cartItem = clientItem === null ? await dispatch('getItem', serverItem) : clientItem
-
- if (!cartItem || typeof serverItem.item_id === 'undefined') return
-
- const product = {
- server_item_id: serverItem.item_id,
- sku: cartItem.sku,
- server_cart_id: serverItem.quote_id,
- prev_qty: cartItem.qty,
- product_option: serverItem.product_option,
- type_id: serverItem.product_type
- }
-
- await dispatch('updateItem', { product })
- EventBus.$emit('cart-after-itemchanged', { item: cartItem })
- },
- async updateServerItem ({ getters, rootGetters, commit, dispatch }, { clientItem, serverItem, updateIds, mergeQty }) {
- const diffLog = createDiffLog()
- const cartItem = createCartItemForUpdate(clientItem, serverItem, updateIds, mergeQty)
- const event = await CartService.updateItem(getters.getCartToken, cartItem)
- const wasUpdatedSuccessfully = event.resultCode === 200
- Logger.debug('Cart item server sync' + event, 'cart')()
- diffLog.pushServerResponse({ status: event.resultCode, sku: clientItem.sku, result: event })
-
- if (!wasUpdatedSuccessfully && !serverItem) {
- commit(types.CART_DEL_ITEM, { product: clientItem, removeByParentSku: false })
- return diffLog
- }
-
- if (!wasUpdatedSuccessfully && (clientItem.server_item_id || clientItem.item_id)) {
- await dispatch('restoreQuantity', { product: clientItem })
- return diffLog
- }
-
- if (!wasUpdatedSuccessfully) {
- Logger.warn('Removing product from cart', 'cart', clientItem)()
- commit(types.CART_DEL_NON_CONFIRMED_ITEM, { product: clientItem })
- return diffLog
- }
-
- if (!rootGetters['checkout/isUserInCheckout']) {
- const isThisNewItemAddedToTheCart = (!clientItem || !clientItem.server_item_id)
- diffLog.pushNotification(
- isThisNewItemAddedToTheCart ? notifications.productAddedToCart() : notifications.productQuantityUpdated()
- )
- }
-
- await dispatch('updateClientItem', { clientItem, serverItem: event.result })
-
- return diffLog
- },
- async synchronizeServerItem ({ dispatch }, { serverItem, clientItem, forceClientState, dryRun, mergeQty }) {
- const diffLog = createDiffLog()
-
- if (!serverItem) {
- Logger.warn('No server item with sku ' + clientItem.sku + ' on stock.', 'cart')()
- diffLog.pushServerParty({ sku: clientItem.sku, status: 'no-item' })
-
- if (dryRun) return diffLog
- if (forceClientState || !config.cart.serverSyncCanRemoveLocalItems) {
- const updateServerItemDiffLog = await dispatch('updateServerItem', { clientItem, serverItem, updateIds: false })
- return diffLog.merge(updateServerItemDiffLog)
- }
-
- await dispatch('removeItem', { product: clientItem })
- return diffLog
- }
-
- if (serverItem.qty !== clientItem.qty || mergeQty) {
- Logger.log('Wrong qty for ' + clientItem.sku, clientItem.qty, serverItem.qty)()
- diffLog.pushServerParty({ sku: clientItem.sku, status: 'wrong-qty', 'client-qty': clientItem.qty, 'server-qty': serverItem.qty })
- if (dryRun) return diffLog
- if (forceClientState || !config.cart.serverSyncCanModifyLocalItems) {
- const updateServerItemDiffLog = await dispatch('updateServerItem', { clientItem, serverItem, updateIds: true, mergeQty })
-
- return diffLog.merge(updateServerItemDiffLog)
- }
-
- await dispatch('updateItem', { product: serverItem })
- }
-
- return diffLog
- },
- async mergeClientItem ({ dispatch }, { clientItem, serverItems, forceClientState, dryRun, mergeQty }) {
- const serverItem = serverItems.find(itm => productsEquals(itm, clientItem))
- const diffLog = await dispatch('synchronizeServerItem', { serverItem, clientItem, forceClientState, dryRun, mergeQty })
-
- if (!diffLog.isEmpty()) return diffLog
-
- Logger.info('Server and client item with SKU ' + clientItem.sku + ' synced. Updating cart.', 'cart', 'cart')()
- if (!dryRun) {
- const product = {
- sku: clientItem.sku,
- server_cart_id: serverItem.quote_id,
- server_item_id: serverItem.item_id,
- product_option: serverItem.product_option,
- type_id: serverItem.product_type
- }
-
- await dispatch('updateItem', { product })
- }
-
- return diffLog
- },
- async mergeClientItems ({ dispatch }, { clientItems, serverItems, forceClientState, dryRun, mergeQty }) {
- const diffLog = createDiffLog()
-
- for (const clientItem of clientItems) {
- try {
- const mergeClientItemDiffLog = await dispatch('mergeClientItem', { clientItem, serverItems, forceClientState, dryRun, mergeQty })
- diffLog.merge(mergeClientItemDiffLog)
- } catch (e) {
- Logger.debug('Problem syncing clientItem', 'cart', clientItem)()
- }
- }
-
- return diffLog
- },
- async mergeServerItem ({ dispatch, getters }, { clientItems, serverItem, forceClientState, dryRun }) {
- const diffLog = createDiffLog()
- const clientItem = clientItems.find(itm => productsEquals(itm, serverItem))
- if (clientItem) return diffLog
- Logger.info('No client item for' + serverItem.sku, 'cart')()
- diffLog.pushClientParty({ sku: serverItem.sku, status: 'no-item' })
- if (dryRun) return diffLog
-
- if (forceClientState) {
- Logger.info('Removing product from cart', 'cart', serverItem)()
- Logger.log('Removing item' + serverItem.sku + serverItem.item_id, 'cart')()
- const cartItem = {
- sku: serverItem.sku,
- item_id: serverItem.item_id,
- quoteId: serverItem.quote_id
- } as any as CartItem
-
- const resp = await CartService.deleteItem(getters.getCartToken, cartItem)
- return diffLog.pushServerResponse({ status: resp.resultCode, sku: serverItem.sku, result: resp })
- }
-
- const productToAdd = await dispatch('getProductVariant', { serverItem })
-
- if (productToAdd) {
- await dispatch('addItem', { productToAdd, forceServerSilence: true })
- Logger.debug('Product variant for given serverItem has not found', 'cart', serverItem)()
- }
-
- return diffLog
- },
- async mergeServerItems ({ dispatch }, { serverItems, clientItems, forceClientState, dryRun }) {
- const diffLog = createDiffLog()
- const definedServerItems = serverItems.filter(serverItem => serverItem)
-
- for (const serverItem of definedServerItems) {
- try {
- const mergeServerItemDiffLog = await dispatch('mergeServerItem', { clientItems, serverItem, forceClientState, dryRun })
- diffLog.merge(mergeServerItemDiffLog)
- } catch (e) {
- Logger.debug('Problem syncing serverItem', 'cart', serverItem)()
- }
- }
-
- return diffLog
- },
- async updateTotalsAfterMerge ({ dispatch, getters, commit }, { clientItems, dryRun }) {
- if (dryRun) return
-
- if (getters.isTotalsSyncRequired && clientItems.length > 0) {
- await dispatch('syncTotals')
- }
-
- commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash)
- },
- async merge ({ getters, dispatch }, { serverItems, clientItems, dryRun = false, forceClientState = false, mergeQty = false }) {
- const hookResult = cartHooksExecutors.beforeSync({ clientItems, serverItems })
-
- const diffLog = createDiffLog()
- const mergeParameters = {
- clientItems: hookResult.clientItems,
- serverItems: hookResult.serverItems,
- forceClientState,
- dryRun,
- mergeQty
- }
- const mergeClientItemsDiffLog = await dispatch('mergeClientItems', mergeParameters)
- const mergeServerItemsDiffLog = await dispatch('mergeServerItems', mergeParameters)
- await dispatch('updateTotalsAfterMerge', { clientItems, dryRun })
-
- diffLog
- .merge(mergeClientItemsDiffLog)
- .merge(mergeServerItemsDiffLog)
- .pushClientParty({ status: getters.isCartHashChanged ? 'update-required' : 'no-changes' })
- .pushServerParty({ status: getters.isTotalsSyncRequired ? 'update-required' : 'no-changes' })
-
- EventBus.$emit('servercart-after-diff', { diffLog: diffLog, serverItems: hookResult.serverItems, clientItems: hookResult.clientItems, dryRun: dryRun })
- Logger.info('Client/Server cart synchronised ', 'cart', diffLog)()
-
- return diffLog
- }
-}
-
-export default mergeActions
diff --git a/core/modules/cart/store/actions/methodsActions.ts b/core/modules/cart/store/actions/methodsActions.ts
deleted file mode 100644
index e839481dd3..0000000000
--- a/core/modules/cart/store/actions/methodsActions.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { CartService } from '@vue-storefront/core/data-resolver'
-import { preparePaymentMethodsToSync, createOrderData, createShippingInfoData } from '@vue-storefront/core/modules/cart/helpers'
-import PaymentMethod from '../../types/PaymentMethod'
-
-const methodsActions = {
- async pullMethods ({ getters, dispatch }, { forceServerSync }) {
- if (getters.isTotalsSyncRequired || forceServerSync) {
- await dispatch('syncShippingMethods', { forceServerSync })
- await dispatch('syncPaymentMethods', { forceServerSync })
- } else {
- Logger.debug('Skipping payment & shipping methods update as cart has not been changed', 'cart')()
- }
- },
- async setDefaultCheckoutMethods ({ getters, rootGetters, commit }) {
- if (!getters.getShippingMethodCode) {
- commit(types.CART_UPD_SHIPPING, rootGetters['checkout/getDefaultShippingMethod'])
- }
-
- if (!getters.getPaymentMethodCode) {
- commit(types.CART_UPD_PAYMENT, rootGetters['checkout/getDefaultPaymentMethod'])
- }
- },
- async syncPaymentMethods ({ getters, rootGetters, dispatch }, { forceServerSync = false }) {
- if (getters.canUpdateMethods && (getters.isTotalsSyncRequired || forceServerSync)) {
- Logger.debug('Refreshing payment methods', 'cart')()
- let backendPaymentMethods: PaymentMethod[]
-
- const paymentDetails = rootGetters['checkout/getPaymentDetails']
- if (paymentDetails.country) {
- // use shipping info endpoint to get payment methods using billing address
- const shippingMethodsData = createOrderData({
- shippingDetails: rootGetters['checkout/getShippingDetails'],
- shippingMethods: rootGetters['checkout/getShippingMethods'],
- paymentMethods: rootGetters['checkout/getPaymentMethods'],
- paymentDetails: paymentDetails
- })
-
- if (shippingMethodsData.country) {
- const { result } = await CartService.setShippingInfo(createShippingInfoData(shippingMethodsData))
- backendPaymentMethods = result.payment_methods || []
- }
- }
- if (!backendPaymentMethods || backendPaymentMethods.length === 0) {
- const { result } = await CartService.getPaymentMethods()
- backendPaymentMethods = result
- }
-
- const { uniqueBackendMethods, paymentMethods } = preparePaymentMethodsToSync(
- backendPaymentMethods,
- rootGetters['checkout/getNotServerPaymentMethods']
- )
- await dispatch('checkout/replacePaymentMethods', paymentMethods, { root: true })
- EventBus.$emit('set-unique-payment-methods', uniqueBackendMethods)
- } else {
- Logger.debug('Payment methods does not need to be updated', 'cart')()
- }
- },
- async updateShippingMethods ({ dispatch }, { shippingMethods }) {
- const newShippingMethods = shippingMethods
- .map(method => ({ ...method, is_server_method: true }))
- .filter(method => !method.hasOwnProperty('available') || method.available)
- await dispatch('checkout/replaceShippingMethods', newShippingMethods, { root: true })
- },
- async syncShippingMethods ({ getters, rootGetters, dispatch }, { forceServerSync = false }) {
- if (getters.canUpdateMethods && (getters.isTotalsSyncRequired || forceServerSync)) {
- const storeView = currentStoreView()
- Logger.debug('Refreshing shipping methods', 'cart')()
- const shippingDetails = rootGetters['checkout/getShippingDetails']
-
- // build address data with what we have
- const address = (shippingDetails) ? {
- region: shippingDetails.state,
- region_id: shippingDetails.region_id ? shippingDetails.region_id : 0,
- country_id: shippingDetails.country,
- street: [shippingDetails.streetAddress1, shippingDetails.streetAddress2],
- postcode: shippingDetails.zipCode,
- city: shippingDetails.city,
- region_code: shippingDetails.region_code ? shippingDetails.region_code : ''
- } : { country_id: storeView.tax.defaultCountry }
-
- const { result } = await CartService.getShippingMethods(address)
- await dispatch('updateShippingMethods', { shippingMethods: result })
- } else {
- Logger.debug('Shipping methods does not need to be updated', 'cart')()
- }
- }
-}
-
-export default methodsActions
diff --git a/core/modules/cart/store/actions/productActions.ts b/core/modules/cart/store/actions/productActions.ts
deleted file mode 100644
index 1c138835b3..0000000000
--- a/core/modules/cart/store/actions/productActions.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { SearchQuery } from 'storefront-query-builder'
-
-const productActions = {
- async findProductOption ({ dispatch }, { serverItem }) {
- if (serverItem.product_type === 'configurable') {
- let query = new SearchQuery()
- query = query.applyFilter({ key: 'configurable_children.sku', value: { 'eq': serverItem.sku } })
-
- const { items } = await dispatch('product/findProducts', {
- query,
- start: 0,
- size: 1,
- options: {
- populateRequestCacheTags: false,
- prefetchGroupProducts: false,
- separateSelectedVariant: true
- }
- }, { root: true })
-
- return items.length >= 1 ? { sku: items[0].sku, childSku: serverItem.sku } : null
- }
-
- return { sku: serverItem.sku }
- },
- async getProductVariant ({ dispatch }, { serverItem }) {
- try {
- const options = await dispatch('findProductOption', { serverItem })
- const singleProduct = await dispatch('product/single', { options }, { root: true })
-
- return {
- ...singleProduct,
- server_item_id: serverItem.item_id,
- qty: serverItem.qty,
- server_cart_id: serverItem.quote_id,
- product_option: serverItem.product_option || singleProduct.product_option
- }
- } catch (e) {
- return null
- }
- }
-}
-
-export default productActions
diff --git a/core/modules/cart/store/actions/quantityActions.ts b/core/modules/cart/store/actions/quantityActions.ts
deleted file mode 100644
index e217c48959..0000000000
--- a/core/modules/cart/store/actions/quantityActions.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { createDiffLog } from '@vue-storefront/core/modules/cart/helpers'
-
-const quantityActions = {
- async restoreQuantity ({ dispatch }, { product }) {
- const currentCartItem = await dispatch('getItem', { product })
- if (currentCartItem) {
- Logger.log('Restoring qty after error' + product.sku + currentCartItem.prev_qty, 'cart')()
- if (currentCartItem.prev_qty > 0) {
- await dispatch('updateItem', {
- product: {
- ...product,
- qty: currentCartItem.prev_qty
- }
- })
- EventBus.$emit('cart-after-itemchanged', { item: currentCartItem })
- } else {
- await dispatch('removeItem', { product: currentCartItem, removeByParentSku: false })
- }
- }
- },
- async updateQuantity ({ commit, dispatch, getters }, { product, qty, forceServerSilence = false }) {
- commit(types.CART_UPD_ITEM, { product, qty })
- if (getters.isCartSyncEnabled && product.server_item_id && !forceServerSilence) {
- return dispatch('sync', { forceClientState: true })
- }
-
- return createDiffLog()
- .pushClientParty({ status: 'wrong-qty', sku: product.sku, 'client-qty': qty })
- }
-}
-
-export default quantityActions
diff --git a/core/modules/cart/store/actions/synchronizeActions.ts b/core/modules/cart/store/actions/synchronizeActions.ts
deleted file mode 100644
index f332fabe2f..0000000000
--- a/core/modules/cart/store/actions/synchronizeActions.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { isServer } from '@vue-storefront/core/helpers'
-import config from 'config'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import { CartService } from '@vue-storefront/core/data-resolver'
-import { createDiffLog } from '@vue-storefront/core/modules/cart/helpers'
-import i18n from '@vue-storefront/i18n'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { cartHooksExecutors } from '../../hooks'
-
-const synchronizeActions = {
- async load ({ commit, dispatch }, { forceClientState = false }: {forceClientState?: boolean} = {}) {
- if (isServer) return
-
- dispatch('setDefaultCheckoutMethods')
- const storedItems = await StorageManager.get('cart').getItem('current-cart')
- commit(types.CART_LOAD_CART, storedItems)
- dispatch('synchronizeCart', { forceClientState })
-
- cartHooksExecutors.afterLoad(storedItems)
- },
- updateCart ({ commit }, { items }) {
- commit(types.CART_LOAD_CART, items)
- },
- async synchronizeCart ({ commit, dispatch }, { forceClientState }) {
- const { synchronize, serverMergeByDefault } = config.cart
- if (!synchronize) return
- const cartStorage = StorageManager.get('cart')
- const token = await cartStorage.getItem('current-cart-token')
- const hash = await cartStorage.getItem('current-cart-hash')
-
- if (hash) {
- commit(types.CART_SET_ITEMS_HASH, hash)
- Logger.info('Cart hash received from cache.', 'cache', hash)()
- }
- if (token) {
- commit(types.CART_LOAD_CART_SERVER_TOKEN, token)
- Logger.info('Cart token received from cache.', 'cache', token)()
- Logger.info('Syncing cart with the server.', 'cart')()
- dispatch('sync', { forceClientState, dryRun: !serverMergeByDefault })
- }
- await dispatch('create')
- },
- /** @deprecated backward compatibility only */
- async serverPull ({ dispatch }, { forceClientState = false, dryRun = false }) {
- Logger.warn('The "cart/serverPull" action is deprecated and will not be supported with the Vue Storefront 1.11', 'cart')()
- return dispatch('sync', { forceClientState, dryRun })
- },
- async sync ({ getters, rootGetters, commit, dispatch, state }, { forceClientState = false, dryRun = false, mergeQty = false, forceSync = false }) {
- const shouldUpdateClientState = rootGetters['checkout/isUserInCheckout'] || forceClientState
- const { getCartItems, canUpdateMethods, isSyncRequired, bypassCounter } = getters
- if ((!canUpdateMethods || !isSyncRequired) && !forceSync) return createDiffLog()
- commit(types.CART_SET_SYNC)
- const { result, resultCode } = await CartService.getItems()
- const { serverItems, clientItems } = cartHooksExecutors.beforeSync({ clientItems: getCartItems, serverItems: result })
-
- if (resultCode === 200) {
- const diffLog = await dispatch('merge', {
- dryRun,
- serverItems,
- clientItems,
- forceClientState: shouldUpdateClientState,
- mergeQty
- })
- cartHooksExecutors.afterSync(diffLog)
- return diffLog
- }
-
- if (bypassCounter < config.queues.maxCartBypassAttempts) {
- Logger.log('Bypassing with guest cart' + bypassCounter, 'cart')()
- commit(types.CART_UPDATE_BYPASS_COUNTER, { counter: 1 })
- await dispatch('connect', { guestCart: true })
- }
-
- Logger.error(result, 'cart')
- cartHooksExecutors.afterSync(result)
- commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash)
- return createDiffLog()
- },
- async stockSync ({ dispatch, commit, getters }, stockTask) {
- const product = { sku: stockTask.product_sku }
-
- const cartItem = await dispatch('getItem', { product })
-
- if (!cartItem || stockTask.result.code === 'ENOTFOUND') return
-
- if (!stockTask.result.is_in_stock) {
- if (!config.stock.allowOutOfStockInCart && !config.cart.synchronize) {
- Logger.log('Removing product from cart' + stockTask.product_sku, 'stock')()
- commit(types.CART_DEL_ITEM, { product: { sku: stockTask.product_sku } }, { root: true })
- return
- }
-
- dispatch('updateItem', {
- product: { errors: { stock: i18n.t('Out of the stock!') }, sku: stockTask.product_sku, is_in_stock: false }
- })
-
- return
- }
-
- dispatch('updateItem', {
- product: { info: { stock: i18n.t('In stock!') }, sku: stockTask.product_sku, is_in_stock: true }
- })
- EventBus.$emit('cart-after-itemchanged', { item: cartItem })
- commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash)
- }
-}
-
-export default synchronizeActions
diff --git a/core/modules/cart/store/actions/totalsActions.ts b/core/modules/cart/store/actions/totalsActions.ts
deleted file mode 100644
index cbaf541e34..0000000000
--- a/core/modules/cart/store/actions/totalsActions.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { CartService } from '@vue-storefront/core/data-resolver'
-import {
- preparePaymentMethodsToSync,
- prepareShippingInfoForUpdateTotals,
- createOrderData,
- createShippingInfoData
-} from '@vue-storefront/core/modules/cart/helpers'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-
-const totalsActions = {
- async updateTotals ({ commit }, payload) {
- commit(types.CART_UPD_TOTALS, payload)
- },
- async getTotals (context, { addressInformation, hasShippingInformation }) {
- if (hasShippingInformation) {
- return CartService.setShippingInfo(addressInformation)
- }
-
- return CartService.getTotals()
- },
- async overrideServerTotals ({ commit, getters, rootGetters, dispatch }, { addressInformation, hasShippingInformation }) {
- const { resultCode, result } = await dispatch('getTotals', { addressInformation, hasShippingInformation })
-
- if (resultCode === 200) {
- const totals = result.totals || result
- Logger.info('Overriding server totals. ', 'cart', totals)()
- const itemsAfterTotal = prepareShippingInfoForUpdateTotals(totals.items)
-
- for (let key of Object.keys(itemsAfterTotal)) {
- const item = itemsAfterTotal[key]
- const product = { server_item_id: item.item_id, totals: item, qty: item.qty }
- await dispatch('updateItem', { product })
- }
-
- commit(types.CART_UPD_TOTALS, { itemsAfterTotal, totals, platformTotalSegments: totals.total_segments })
- commit(types.CART_SET_TOTALS_SYNC)
-
- // we received payment methods as a result of this call, updating state
- if (result.payment_methods && getters.canUpdateMethods) {
- const { uniqueBackendMethods, paymentMethods } = preparePaymentMethodsToSync(
- result.payment_methods.map(method => ({ ...method, is_server_method: true })),
- rootGetters['checkout/getNotServerPaymentMethods']
- )
- dispatch('checkout/replacePaymentMethods', paymentMethods, { root: true })
- EventBus.$emit('set-unique-payment-methods', uniqueBackendMethods)
- }
-
- return
- }
-
- Logger.error(result, 'cart')()
- },
- async syncTotals ({ dispatch, getters, rootGetters }, payload: { forceServerSync: boolean, methodsData?: any } = { forceServerSync: false, methodsData: null }) {
- const methodsData = payload ? payload.methodsData : null
- await dispatch('pullMethods', { forceServerSync: payload.forceServerSync })
-
- if (getters.canSyncTotals && (getters.isTotalsSyncRequired || payload.forceServerSync)) {
- const shippingMethodsData = methodsData || createOrderData({
- shippingDetails: rootGetters['checkout/getShippingDetails'],
- shippingMethods: rootGetters['checkout/getShippingMethods'],
- paymentMethods: rootGetters['checkout/getPaymentMethods'],
- paymentDetails: rootGetters['checkout/getPaymentDetails']
- })
-
- if (shippingMethodsData.country) {
- await dispatch('overrideServerTotals', {
- hasShippingInformation: shippingMethodsData.method_code || shippingMethodsData.carrier_code,
- addressInformation: createShippingInfoData(shippingMethodsData)
- })
- return
- }
-
- Logger.error('Please do set the tax.defaultCountry in order to calculate totals', 'cart')()
- }
- },
- async refreshTotals ({ dispatch }, payload) {
- Logger.warn('The "cart/refreshTotals" action is deprecated and will not be supported with the Vue Storefront 1.11', 'cart')()
- await dispatch('syncTotals', payload)
- }
-}
-
-export default totalsActions
diff --git a/core/modules/cart/store/getters.ts b/core/modules/cart/store/getters.ts
deleted file mode 100644
index 523381646f..0000000000
--- a/core/modules/cart/store/getters.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { GetterTree } from 'vuex'
-import sumBy from 'lodash-es/sumBy'
-import CartState from '../types/CartState'
-import RootState from '@vue-storefront/core/types/RootState'
-import AppliedCoupon from '../types/AppliedCoupon'
-import { onlineHelper, isServer, calcItemsHmac } from '@vue-storefront/core/helpers'
-import { calculateTotals } from '@vue-storefront/core/modules/cart/helpers'
-import config from 'config'
-
-const getters: GetterTree = {
- getCartToken: state => state.cartServerToken,
- getLastSyncDate: state => state.cartServerLastSyncDate,
- getLastTotalsSyncDate: state => state.cartServerLastTotalsSyncDate,
- getShippingMethod: state => state.shipping,
- getPaymentMethod: state => state.payment,
- getLastCartHash: state => state.cartItemsHash,
- getCurrentCartHash: state => calcItemsHmac(state.cartItems, state.cartServerToken),
- isCartHashChanged: (state, getters) => getters.getCurrentCartHash !== state.cartItemsHash,
- isSyncRequired: (state, getters) => getters.isCartHashEmptyOrChanged || !state.cartServerLastSyncDate,
- isTotalsSyncRequired: (state, getters) => getters.isCartHashEmptyOrChanged || !state.cartServerLastTotalsSyncDate,
- isCartHashEmptyOrChanged: (state, getters) => !state.cartItemsHash || getters.isCartHashChanged,
- getCartItems: state => state.cartItems,
- isTotalsSyncEnabled: () => config.cart.synchronize_totals && onlineHelper.isOnline && !isServer,
- isCartConnected: state => !!state.cartServerToken,
- isCartSyncEnabled: () => config.cart.synchronize && onlineHelper.isOnline && !isServer,
- getFirstShippingMethod: state => state.shipping instanceof Array ? state.shipping[0] : state.shipping,
- getFirstPaymentMethod: state => state.payment instanceof Array ? state.payment[0] : state.payment,
- getTotals: ({ cartItems, platformTotalSegments }, getters) =>
- (platformTotalSegments && onlineHelper.isOnline) ? platformTotalSegments : calculateTotals(getters.getFirstShippingMethod, getters.getFirstPaymentMethod, cartItems),
- getItemsTotalQuantity: ({ cartItems }) => config.cart.minicartCountType === 'items' ? cartItems.length : sumBy(cartItems, p => p.qty),
- getCoupon: ({ platformTotals }): AppliedCoupon | false =>
- !(platformTotals && platformTotals.hasOwnProperty('coupon_code')) ? false : { code: platformTotals.coupon_code, discount: platformTotals.discount_amount },
- isVirtualCart: ({ cartItems }) => cartItems.length ? cartItems.every(itm => itm.type_id === 'downloadable' || itm.type_id === 'virtual') : false,
- canUpdateMethods: (state, getters) => getters.isCartSyncEnabled && getters.isCartConnected,
- canSyncTotals: (state, getters) => getters.isTotalsSyncEnabled && getters.isCartConnected,
- isCartEmpty: state => state.cartItems.length === 0,
- bypassCounter: state => state.connectBypassCount,
- getShippingMethodCode: state => state.shipping && state.shipping.method_code,
- getPaymentMethodCode: state => state.payment && state.payment.code,
- getIsAdding: state => state.isAddingToCart,
- getIsMicroCartOpen: state => state.isMicrocartOpen
-
-}
-
-export default getters
diff --git a/core/modules/cart/store/index.ts b/core/modules/cart/store/index.ts
deleted file mode 100644
index 34ea8c3374..0000000000
--- a/core/modules/cart/store/index.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { Module } from 'vuex'
-import actions from './actions'
-import getters from './getters'
-import mutations from './mutations'
-import CartState from '../types/CartState'
-
-export const cartStore: Module = {
- namespaced: true,
- state: {
- isMicrocartOpen: false,
- itemsAfterPlatformTotals: {},
- platformTotals: null,
- platformTotalSegments: null,
- cartIsLoaded: false,
- cartServerToken: '', // server side ID to synchronize with Backend (for example Magento)
- shipping: [],
- payment: [],
- cartItemsHash: '',
- cartServerLastSyncDate: 0,
- cartServerLastTotalsSyncDate: 0,
- cartItems: [], // TODO: check if it's properly namespaced
- connectBypassCount: 0,
- isAddingToCart: false
- },
- getters,
- actions,
- mutations
-}
diff --git a/core/modules/cart/store/mutation-types.ts b/core/modules/cart/store/mutation-types.ts
deleted file mode 100644
index 5831ea5bb7..0000000000
--- a/core/modules/cart/store/mutation-types.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-export const SN_CART = 'cart'
-export const CART_ADD_ITEM = SN_CART + '/ADD'
-export const CART_DEL_ITEM = SN_CART + '/DEL'
-export const CART_DEL_NON_CONFIRMED_ITEM = SN_CART + '/DEL_NONCONFIRMED'
-export const CART_UPD_ITEM = SN_CART + '/UPD'
-export const CART_LOAD_CART = SN_CART + '/LOAD'
-export const CART_UPD_SHIPPING = SN_CART + '/SHIPPING'
-export const CART_SAVE = SN_CART + '/SAVE'
-export const CART_SET_ITEMS_HASH = SN_CART + '/SAVE_HASH'
-export const CART_SET_SYNC = SN_CART + '/MARK_SYNC'
-export const CART_SET_TOTALS_SYNC = SN_CART + '/MARK_TOTALS_SYNC'
-export const CART_UPD_ITEM_PROPS = SN_CART + '/UPD_PROPS'
-export const CART_UPD_TOTALS = SN_CART + '/UPD_TOTALS'
-export const CART_LOAD_CART_SERVER_TOKEN = SN_CART + '/SRV_TOKEN'
-export const CART_UPD_PAYMENT = SN_CART + '/UPD_PAYMENT'
-export const CART_TOGGLE_MICROCART = SN_CART + '/TOGGLE_MICROCART'
-export const CART_UPDATE_BYPASS_COUNTER = SN_CART + '/UPD_BYPASS_COUNTER'
-export const CART_ADDING_ITEM = SN_CART + '/UPD_ADDING_ITEM'
diff --git a/core/modules/cart/store/mutations.ts b/core/modules/cart/store/mutations.ts
deleted file mode 100644
index a0bfce3a1b..0000000000
--- a/core/modules/cart/store/mutations.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import Vue from 'vue'
-import { MutationTree } from 'vuex'
-import * as types from './mutation-types'
-import CartState from '../types/CartState'
-import config from 'config'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import productsEquals from './../helpers/productsEquals'
-
-const mutations: MutationTree = {
- /**
- * Add product to cart
- * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md
- */
- [types.CART_ADD_ITEM] (state, { product }) {
- const record = state.cartItems.find(p => productsEquals(p, product))
- if (!record) {
- let item = {
- ...product,
- qty: parseInt(product.qty ? product.qty : 1)
- }
- EventBus.$emit('cart-before-add', { product: item })
- state.cartItems.push(item)
- } else {
- EventBus.$emit('cart-before-update', { product: record })
- record.qty += parseInt((product.qty ? product.qty : 1))
- }
- },
- [types.CART_SET_ITEMS_HASH] (state, hash = null) {
- state.cartItemsHash = hash
- },
- [types.CART_SET_SYNC] (state) {
- state.cartServerLastSyncDate = new Date().getTime()
- },
- [types.CART_SET_TOTALS_SYNC] (state) {
- state.cartServerLastTotalsSyncDate = new Date().getTime()
- },
- [types.CART_DEL_ITEM] (state, { product, removeByParentSku = true }) {
- EventBus.$emit('cart-before-delete', { items: state.cartItems })
- state.cartItems = state.cartItems.filter(p => !productsEquals(p, product) && (p.parentSku !== product.sku || removeByParentSku === false))
- EventBus.$emit('cart-after-delete', { items: state.cartItems })
- },
- [types.CART_DEL_NON_CONFIRMED_ITEM] (state, { product, removeByParentSku = true }) {
- EventBus.$emit('cart-before-delete', { items: state.cartItems })
- state.cartItems = state.cartItems.filter(p => (!productsEquals(p, product) && (p.parentSku !== product.sku || removeByParentSku === false)) || p.server_item_id/* it's confirmed if server_item_id is set */)
- EventBus.$emit('cart-after-delete', { items: state.cartItems })
- },
- [types.CART_UPD_ITEM] (state, { product, qty }) {
- const record = state.cartItems.find(p => productsEquals(p, product))
-
- if (record) {
- EventBus.$emit('cart-before-update', { product: record })
- record.qty = parseInt(qty)
- EventBus.$emit('cart-after-update', { product: record })
- }
- },
- [types.CART_UPD_ITEM_PROPS] (state, { product }) {
- let record = state.cartItems.find(p => (productsEquals(p, product) || (p.server_item_id && p.server_item_id === product.server_item_id)))
- if (record) {
- EventBus.$emit('cart-before-itemchanged', { item: record })
- Object.entries(product).forEach(([key, value]) => Vue.set(record, key, value))
- EventBus.$emit('cart-after-itemchanged', { item: record })
- }
- },
- [types.CART_UPD_SHIPPING] (state, shippingMethod) {
- state.shipping = shippingMethod
- },
- [types.CART_LOAD_CART] (state, storedItems) {
- state.cartItems = storedItems || []
- state.cartIsLoaded = true
-
- // EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue
- EventBus.$emit('sync/PROCESS_QUEUE', { config }) // process checkout queue
- EventBus.$emit('application-after-loaded')
- EventBus.$emit('cart-after-loaded')
- },
- [types.CART_LOAD_CART_SERVER_TOKEN] (state, token) {
- state.cartServerToken = token
- },
- [types.CART_UPD_TOTALS] (state, { itemsAfterTotals, totals, platformTotalSegments }) {
- state.itemsAfterPlatformTotals = itemsAfterTotals
- state.platformTotals = totals
- state.platformTotalSegments = platformTotalSegments
- EventBus.$emit('cart-after-updatetotals', { platformTotals: totals, platformTotalSegments: platformTotalSegments })
- },
- [types.CART_UPD_PAYMENT] (state, paymentMethod) {
- state.payment = paymentMethod
- },
- [types.CART_TOGGLE_MICROCART] (state) {
- state.isMicrocartOpen = !state.isMicrocartOpen
- },
- [types.CART_UPDATE_BYPASS_COUNTER] (state, { counter }) {
- state.connectBypassCount = state.connectBypassCount + counter
- },
- [types.CART_ADDING_ITEM] (state, { isAdding }) {
- state.isAddingToCart = isAdding
- }
-}
-
-export default mutations
diff --git a/core/modules/cart/test/unit/components/AddToCart.spec.ts b/core/modules/cart/test/unit/components/AddToCart.spec.ts
deleted file mode 100644
index a09a411320..0000000000
--- a/core/modules/cart/test/unit/components/AddToCart.spec.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { mountMixinWithStore } from '@vue-storefront/unit-tests/utils';
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-import { AddToCart } from '../../../components/AddToCart'
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() }))
-jest.mock('@vue-storefront/i18n', () => ({ loadLanguageAsync: jest.fn() }))
-jest.mock('@vue-storefront/core/helpers', () => ({
- once: jest.fn()
-}));
-
-describe('AddToCart', () => {
- it('addToCart dispatches addItem action', () => {
- const product = {} as any as Product;
-
- const storeMock = {
- modules: {
- cart: {
- actions: {
- addItem: jest.fn(() => [])
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(AddToCart, storeMock, { propsData: { product } });
-
- (wrapper.vm as any).addToCart(product);
-
- expect(storeMock.modules.cart.actions.addItem).toBeCalledWith(expect.anything(), { productToAdd: product });
- })
-});
diff --git a/core/modules/cart/test/unit/components/Microcart.spec.ts b/core/modules/cart/test/unit/components/Microcart.spec.ts
deleted file mode 100644
index 5c3c30ec86..0000000000
--- a/core/modules/cart/test/unit/components/Microcart.spec.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import { mountMixinWithStore } from '@vue-storefront/unit-tests/utils';
-
-import AppliedCoupon from '../../../types/AppliedCoupon'
-import CartTotalSegments from '../../../types/CartTotalSegments'
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-import { Microcart } from '../../../components/Microcart'
-
-describe('Microcart', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- it('productsInCart returns products in cart', () => {
- const storeMock = {
- modules: {
- cart: {
- state: {
- cartItems: [{} as any as Product]
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(Microcart, storeMock);
-
- expect((wrapper.vm as any).productsInCart).toBe(storeMock.modules.cart.state.cartItems);
- });
-
- it('appliedCoupon returns currently set coupon', () => {
- const storeMock = {
- modules: {
- cart: {
- getters: {
- getCoupon: () => ({} as any as AppliedCoupon)
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(Microcart, storeMock);
-
- expect((wrapper.vm as any).appliedCoupon).toEqual(storeMock.modules.cart.getters.getCoupon());
- });
-
- it('totals returns cart totals', () => {
- const storeMock = {
- modules: {
- cart: {
- getters: {
- getTotals: () => ({} as any as CartTotalSegments)
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(Microcart, storeMock);
-
- expect((wrapper.vm as any).totals).toEqual(storeMock.modules.cart.getters.getTotals());
- });
-
- it('isOpen returns cart state if it is open', () => {
- const storeMock = {
- modules: {
- cart: {
- state: {
- isMicrocartOpen: true
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(Microcart, storeMock);
-
- expect((wrapper.vm as any).isOpen).toBe(storeMock.modules.cart.state.isMicrocartOpen);
- });
-
- it('applyCoupon dispatches applyCupon action to save it', () => {
- const couponCode = 'foo';
- const storeMock = {
- modules: {
- cart: {
- actions: {
- applyCoupon: jest.fn()
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(Microcart, storeMock);
-
- (wrapper.vm as any).applyCoupon(couponCode);
-
- expect(storeMock.modules.cart.actions.applyCoupon).toBeCalledWith(expect.anything(), 'foo');
- });
-
- it('removeCoupon dispatches removeCoupon action to delete it', () => {
- const storeMock = {
- modules: {
- cart: {
- actions: {
- removeCoupon: jest.fn()
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(Microcart, storeMock);
-
- (wrapper.vm as any).removeCoupon();
-
- expect(storeMock.modules.cart.actions.removeCoupon).toBeCalled();
- });
-
- it('toggleMicrocart dispatches toggleMicrocart to change its state', () => {
- const storeMock = {
- modules: {
- ui: {
- actions: {
- toggleMicrocart: jest.fn()
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(Microcart, storeMock);
-
- (wrapper.vm as any).toggleMicrocart();
-
- expect(storeMock.modules.ui.actions.toggleMicrocart).toBeCalled();
- });
-});
diff --git a/core/modules/cart/test/unit/components/MicrocartButton.spec.ts b/core/modules/cart/test/unit/components/MicrocartButton.spec.ts
deleted file mode 100644
index 012b3737dd..0000000000
--- a/core/modules/cart/test/unit/components/MicrocartButton.spec.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { mountMixinWithStore } from '@vue-storefront/unit-tests/utils';
-
-import { MicrocartButton } from '../../../components/MicrocartButton'
-
-describe('MicrocartButton', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- it('quantity returns total quantity of products in cart', () => {
- const storeMock = {
- modules: {
- cart: {
- getters: {
- getItemsTotalQuantity: () => 123
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(MicrocartButton, storeMock);
-
- expect((wrapper.vm as any).quantity).toEqual(storeMock.modules.cart.getters.getItemsTotalQuantity());
- });
-
- it('toggleMicrocart dispatches toggleMicrocart to change its state', () => {
- const storeMock = {
- modules: {
- cart: {
- actions: {
- toggleMicrocart: jest.fn()
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(MicrocartButton, storeMock);
-
- (wrapper.vm as any).toggleMicrocart();
-
- expect(storeMock.modules.cart.actions.toggleMicrocart).toBeCalled();
- });
-});
diff --git a/core/modules/cart/test/unit/components/Product.spec.ts b/core/modules/cart/test/unit/components/Product.spec.ts
deleted file mode 100644
index 10dff6749d..0000000000
--- a/core/modules/cart/test/unit/components/Product.spec.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-import { mountMixin, mountMixinWithStore } from '@vue-storefront/unit-tests/utils';
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-import { productThumbnailPath, getThumbnailPath } from '@vue-storefront/core/helpers';
-import config from 'config'
-import { MicrocartProduct } from '../../../components/Product';
-import Mock = jest.Mock;
-
-jest.mock('@vue-storefront/core/helpers', () => ({
- productThumbnailPath: jest.fn(),
- getThumbnailPath: jest.fn()
-}));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('@vue-storefront/core/app', () => jest.fn())
-jest.mock('@vue-storefront/core/lib/multistore', () => jest.fn())
-jest.mock('@vue-storefront/core/lib/storage-manager', () => jest.fn())
-jest.mock('@vue-storefront/core/store', () => ({}))
-
-describe('MicrocartProduct', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- Object.keys(config).forEach((key) => { delete config[key]; });
- });
-
- it('thumbnail in online mode returns thumbnail in lower size', () => {
- config.products = {
- thumbnails: {
- width: 300,
- height: 300
- }
- };
- config.cart = {
- thumbnails: {
- width: 150,
- height: 150
- }
- };
-
- (productThumbnailPath as Mock).mockReturnValueOnce('thumbnail-path');
- (getThumbnailPath as Mock).mockReturnValueOnce('resized-thumbnail-path');
-
- Object.defineProperty(navigator, 'onLine', { value: true, configurable: true });
-
- const product = {} as any as Product;
- const wrapper = mountMixin(MicrocartProduct, { propsData: { product } });
-
- expect((wrapper.vm as any).thumbnail).toEqual('resized-thumbnail-path');
- expect(getThumbnailPath).toBeCalledWith('thumbnail-path', 150, 150);
- });
-
- it('thumbnail in offline mode returns thumbnail in greater size', () => {
- config.products = {
- thumbnails: {
- width: 300,
- height: 300
- }
- };
- config.cart = {
- thumbnails: {
- width: 150,
- height: 150
- }
- };
-
- (productThumbnailPath as Mock).mockReturnValueOnce('thumbnail-path');
- (getThumbnailPath as Mock).mockReturnValueOnce('resized-thumbnail-path');
-
- Object.defineProperty(navigator, 'onLine', { value: false, configurable: true });
-
- const product = {} as any as Product;
- const wrapper = mountMixin(MicrocartProduct, { propsData: { product } });
-
- expect((wrapper.vm as any).thumbnail).toEqual('resized-thumbnail-path');
- expect(getThumbnailPath).toBeCalledWith('thumbnail-path', 300, 300);
- });
-
- it('removeFromCart dispatches removeItem to remove product from cart', () => {
- const product = {} as any as Product;
- const storeMock = {
- modules: {
- cart: {
- actions: {
- removeItem: jest.fn()
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(MicrocartProduct, storeMock, { propsData: { product } });
-
- (wrapper.vm as any).removeFromCart();
-
- expect(storeMock.modules.cart.actions.removeItem).toBeCalledWith(expect.anything(), { product });
- });
-
- it('updateQuantity dispatches updateQuantity update product quantity in cart', () => {
- const product = {} as any as Product;
- const qty = 123;
- const storeMock = {
- modules: {
- cart: {
- actions: {
- updateQuantity: jest.fn()
- },
- namespaced: true
- }
- }
- };
-
- const wrapper = mountMixinWithStore(MicrocartProduct, storeMock, { propsData: { product } });
-
- (wrapper.vm as any).updateQuantity(qty);
-
- expect(storeMock.modules.cart.actions.updateQuantity).toBeCalledWith(
- expect.anything(),
- { product, qty }
- );
- });
-});
diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts
deleted file mode 100644
index 8f97923b46..0000000000
--- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-import Vue from 'vue'
-import Vuex from 'vuex'
-
-import * as types from '../../../store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-const StorageManager = {
- cart: {
- setItem: jest.fn()
- },
- get (key) {
- return this[key]
- },
- clear () {
- return new Promise((resolve, reject) => {
- resolve()
- })
- }
-};
-const cartCacheHandlerPlugin = require('../../../helpers/cartCacheHandler').cartCacheHandlerPlugin
-
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({ StorageManager }))
-jest.mock('@vue-storefront/core/helpers', () => ({
- isServer: () => false
-}));
-jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() }))
-jest.mock('@vue-storefront/i18n', () => ({ loadLanguageAsync: jest.fn() }))
-
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- error: () => () => {}
- }
-}))
-
-Vue.use(Vuex);
-
-describe('Cart afterRegistration', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- it.each([
- types.CART_LOAD_CART,
- types.CART_ADD_ITEM,
- types.CART_DEL_ITEM,
- types.CART_UPD_ITEM,
- types.CART_UPD_ITEM_PROPS
- ])('handler populates cart cache on mutation %s that modifies cart items', async (mutationType) => {
- const stateMock = {
- cart: {
- cartItems: [{}]
- }
- };
-
- StorageManager.get('cart').setItem.mockImplementationOnce(() => Promise.resolve('foo'));
-
- await cartCacheHandlerPlugin({ type: mutationType }, stateMock);
-
- expect(StorageManager.get('cart').setItem)
- .toBeCalledWith('current-cart', stateMock.cart.cartItems);
- });
-
- it('handler logs error when populating cart cache with items fails', async () => {
- const stateMock = {
- cart: {
- cartItems: [{}]
- }
- };
-
- const consoleErrorSpy = jest.spyOn(Logger, 'error');
-
- StorageManager.get('cart').setItem.mockImplementationOnce(() => Promise.reject('foo'));
-
- await cartCacheHandlerPlugin({ type: types.CART_LOAD_CART }, stateMock);
-
- expect(consoleErrorSpy).toBeCalled();
- });
-
- it('hook updates cart token in cache on mutation changing cart token', async () => {
- const stateMock = {
- cart: {
- cartServerToken: 'token'
- }
- };
-
- StorageManager.get('cart').setItem.mockImplementationOnce(() => Promise.resolve('foo'));
-
- await cartCacheHandlerPlugin({ type: types.CART_LOAD_CART_SERVER_TOKEN }, stateMock);
-
- expect(StorageManager.get('cart').setItem)
- .toBeCalledWith('current-cart-token', stateMock.cart.cartServerToken);
- });
-
- it('handler logs error when changing cached token fails', async () => {
- const stateMock = {
- cart: {
- cartServerToken: 'token'
- }
- };
-
- const consoleErrorSpy = jest.spyOn(Logger, 'error');
-
- StorageManager.get('cart').setItem.mockImplementationOnce(() => Promise.reject('foo'));
-
- await cartCacheHandlerPlugin({ type: types.CART_LOAD_CART_SERVER_TOKEN }, stateMock);
-
- expect(consoleErrorSpy).toBeCalled();
- });
-
- it('handler ignores mutation not related to cart cache', async () => {
- const stateMock = {
- cart: {
- cartServerToken: 'token'
- }
- };
-
- const consoleErrorSpy = jest.spyOn(Logger, 'error');
-
- StorageManager.get('cart').setItem.mockImplementationOnce(() => Promise.reject('foo'));
-
- await cartCacheHandlerPlugin({ type: 'bar' }, stateMock);
-
- expect(consoleErrorSpy).not.toBeCalled();
- });
-});
diff --git a/core/modules/cart/test/unit/helpers/createOrderData.spec.ts b/core/modules/cart/test/unit/helpers/createOrderData.spec.ts
deleted file mode 100644
index 411162be95..0000000000
--- a/core/modules/cart/test/unit/helpers/createOrderData.spec.ts
+++ /dev/null
@@ -1,171 +0,0 @@
-import createOrderData from '@vue-storefront/core/modules/cart/helpers/createOrderData';
-
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-
-const shippingDetails = {
- country: 'UK',
- firstName: 'John',
- lastName: 'Doe',
- city: 'London',
- zipCode: 'EC123',
- streetAddress: 'JohnDoe street',
- region_id: 1,
- apartmentNumber: '12',
- state: 'xxxx',
- phoneNumber: '123123123',
- shippingMethod: 'method'
-};
-
-const paymentDetails = {
- country: 'UK',
- firstName: 'John',
- lastName: 'Doe',
- city: 'London',
- zipCode: 'EC123',
- streetAddress: 'JohnDoe street',
- region_id: 1,
- apartmentNumber: '12',
- state: 'xxxx',
- phoneNumber: '123123123',
- company: '',
- taxId: '',
- paymentMethod: '',
- paymentMethodAdditional: []
-};
-
-describe('Cart createOrderData', () => {
- it('returns data with default shipping and default payment', async () => {
- const shippingMethods = [
- {
- default: false,
- offline: false,
- method_code: 'CODE1',
- carrier_code: 'CODE2'
- },
- {
- default: true,
- offline: false,
- method_code: 'CODE3',
- carrier_code: 'CODE4'
- }
- ];
-
- const paymentMethods = [
- {
- default: false,
- code: 'CODE3'
- },
- {
- default: true,
- code: 'CODE4'
- }
- ];
-
- const methodsData = createOrderData({ shippingDetails, shippingMethods, paymentMethods, paymentDetails, taxCountry: 'DE' })
-
- expect(methodsData).toEqual({
- carrier_code: 'CODE4',
- country: 'UK',
- method_code: 'CODE3',
- payment_method: 'CODE4',
- shippingAddress: {
- city: 'London',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- },
- billingAddress: {
- city: 'London',
- countryId: 'UK',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- }
- });
- });
-
- it('returns data with first online shipping and first payment', async () => {
- const shippingMethods = [
- {
- default: false,
- offline: false,
- method_code: 'CODE1-first',
- carrier_code: 'CODE2-first'
- },
- {
- default: false,
- offline: false,
- method_code: 'CODE3',
- carrier_code: 'CODE4'
- }
- ];
-
- const paymentMethods = [
- {
- default: false,
- code: 'CODE3'
- },
- {
- default: false,
- code: 'CODE4'
- }
- ];
-
- const methodsData = createOrderData({ shippingDetails, shippingMethods, paymentMethods, paymentDetails, taxCountry: 'DE' })
-
- expect(methodsData).toEqual({
- carrier_code: 'CODE2-first',
- country: 'UK',
- method_code: 'CODE1-first',
- payment_method: 'CODE3',
- shippingAddress: {
- city: 'London',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- },
- billingAddress: {
- city: 'London',
- countryId: 'UK',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- }
- });
- });
-
- it('returns data without payment, carrier and method', async () => {
- const shippingMethods = [];
- const paymentMethods = [];
- const methodsData = createOrderData({ shippingDetails, shippingMethods, paymentMethods, paymentDetails, taxCountry: 'DE' });
-
- expect(methodsData).toEqual({
- carrier_code: null,
- country: 'UK',
- method_code: null,
- payment_method: null,
- shippingAddress: {
- city: 'London',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- },
- billingAddress: {
- city: 'London',
- countryId: 'UK',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- }
- });
- });
-});
diff --git a/core/modules/cart/test/unit/helpers/createShippingInfoData.spec.ts b/core/modules/cart/test/unit/helpers/createShippingInfoData.spec.ts
deleted file mode 100644
index 3fbcf461f3..0000000000
--- a/core/modules/cart/test/unit/helpers/createShippingInfoData.spec.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import createShippingInfoData from './../../../helpers/createShippingInfoData';
-
-describe('Cart createShippingInfoData', () => {
- it('returns methods data', async () => {
- const methodsData = {
- country: 'UK',
- carrier_code: 'XX',
- method_code: 'YY'
- };
- const shippingInfoData = createShippingInfoData(methodsData);
- expect(shippingInfoData).toEqual({
- billingAddress: {},
- shippingAddress: {
- countryId: 'UK'
- },
- shippingCarrierCode: 'XX',
- shippingMethodCode: 'YY'
- });
- });
-
- it('returns methods data with shipping address', async () => {
- const methodsData = {
- country: 'UK',
- carrier_code: 'XX',
- method_code: 'YY',
- shippingAddress: {
- city: 'London',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- }
- };
- const shippingInfoData = createShippingInfoData(methodsData);
- expect(shippingInfoData).toEqual({
- billingAddress: {},
- shippingAddress: {
- city: 'London',
- countryId: 'UK',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- },
- shippingCarrierCode: 'XX',
- shippingMethodCode: 'YY'
- });
- });
-
- it('returns methods data with billing address', async () => {
- const methodsData = {
- country: 'UK',
- carrier_code: 'XX',
- method_code: 'YY',
- billingAddress: {
- city: 'London',
- countryId: 'UK',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- }
- };
- const shippingInfoData = createShippingInfoData(methodsData);
- expect(shippingInfoData).toEqual({
- shippingAddress: { countryId: 'UK' },
- billingAddress: {
- city: 'London',
- countryId: 'UK',
- firstname: 'John',
- lastname: 'Doe',
- postcode: 'EC123',
- street: ['JohnDoe street']
- },
- shippingCarrierCode: 'XX',
- shippingMethodCode: 'YY'
- });
- });
-
- it('doesn\t add shippingCarrierCode or shippingMethodCode if missing carrier_code or method_code', async () => {
- const methodsData = {
- country: 'UK'
- };
- const shippingInfoData = createShippingInfoData(methodsData);
- expect(shippingInfoData).toEqual({
- billingAddress: {},
- shippingAddress: {
- countryId: 'UK'
- }
- });
- });
-});
diff --git a/core/modules/cart/test/unit/helpers/prepareProductsToAdd.spec.ts b/core/modules/cart/test/unit/helpers/prepareProductsToAdd.spec.ts
deleted file mode 100644
index 4af8c9556b..0000000000
--- a/core/modules/cart/test/unit/helpers/prepareProductsToAdd.spec.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import prepareProductsToAdd from './../../../helpers/prepareProductsToAdd';
-
-jest.mock('@vue-storefront/core/modules/cart/helpers/productChecksum', () => () => 'some checksum')
-
-const createProduct = ({ type_id }): CartItem => ({
- type_id,
- qty: 1,
- product_links: [
- {
- link_type: 'associated',
- product: {
- sku: 'SK-001'
- }
- }
- ]
-} as any as CartItem)
-
-describe('Cart prepareProductsToAdd', () => {
- it('returns associated products', async () => {
- const product = createProduct({ type_id: 'grouped' })
- expect(prepareProductsToAdd(product)).toEqual([{ sku: 'SK-001', checksum: 'some checksum' }])
- });
-
- it('returns products with checksum applied', async () => {
- const product = createProduct({ type_id: 'bundle' })
- expect(prepareProductsToAdd(product)).toEqual([{ qty: 1, type_id: 'bundle', checksum: 'some checksum' }])
- });
-});
diff --git a/core/modules/cart/test/unit/helpers/prepareShippingInfoForUpdateTotals.spec.ts b/core/modules/cart/test/unit/helpers/prepareShippingInfoForUpdateTotals.spec.ts
deleted file mode 100644
index c1c9b50ccf..0000000000
--- a/core/modules/cart/test/unit/helpers/prepareShippingInfoForUpdateTotals.spec.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import prepareShippingInfoForUpdateTotals from '@vue-storefront/core/modules/cart/helpers/prepareShippingInfoForUpdateTotals'
-import Totals from '@vue-storefront/core/modules/cart/types/Totals'
-
-describe('Cart prepareShippingInfoForUpdateTotals', () => {
- it('returns shipping info', () => {
- const shippingInfoItems = [
- { item_id: 1, key1: 1, key2: 2 },
- { item_id: 2, key1: 3, key2: 4 },
- { item_id: 3, key1: 5, key2: 6 }
- ] as any as Totals[]
-
- expect(prepareShippingInfoForUpdateTotals(shippingInfoItems)).toEqual({
- 1: { item_id: 1, key1: 1, key2: 2 },
- 2: { item_id: 2, key1: 3, key2: 4 },
- 3: { item_id: 3, key1: 5, key2: 6 }
- })
- });
-
- it('returns shipping info with options', () => {
- const shippingInfoItems = [
- { item_id: 1, key1: 1, key2: 2, options: JSON.stringify({ opt1: 1, opt2: 2 }) },
- { item_id: 2, key1: 3, key2: 4, options: JSON.stringify({ opt1: 3, opt2: 4 }) },
- { item_id: 3, key1: 5, key2: 6, options: JSON.stringify({ opt1: 5, opt2: 6 }) }
- ] as any as Totals[]
-
- expect(prepareShippingInfoForUpdateTotals(shippingInfoItems)).toEqual({
- 1: { item_id: 1, key1: 1, key2: 2, options: { opt1: 1, opt2: 2 } },
- 2: { item_id: 2, key1: 3, key2: 4, options: { opt1: 3, opt2: 4 } },
- 3: { item_id: 3, key1: 5, key2: 6, options: { opt1: 5, opt2: 6 } }
- })
- });
-});
diff --git a/core/modules/cart/test/unit/helpers/productChecksum.spec.ts b/core/modules/cart/test/unit/helpers/productChecksum.spec.ts
deleted file mode 100644
index 3ed37bda09..0000000000
--- a/core/modules/cart/test/unit/helpers/productChecksum.spec.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import productChecksum from './../../../helpers/productChecksum';
-
-const configurableProduct: CartItem = {
- product_option: {
- extension_attributes: {
- configurable_item_options: [
- { option_id: '93', option_value: '53' },
- { option_id: '142', option_value: '169' }
- ]
- }
- }
-} as any as CartItem;
-
-const bundleProduct: CartItem = {
- product_option: {
- extension_attributes: {
- bundle_options: [
- { option_id: '1', option_qty: '1', option_selections: [ '2' ] },
- { option_id: '2', option_qty: '1', option_selections: [ '4' ] },
- { option_id: '3', option_qty: '1', option_selections: [ '5' ] },
- { option_id: '4', option_qty: '1', option_selections: [ '8' ] }
- ]
- }
- }
-} as any as CartItem;
-
-describe('Cart productChecksum', () => {
- it('returns checksum for bundle product', async () => {
- expect(productChecksum(bundleProduct)).toBe('3e183f026489207a9cd535d20f141e07ddfea729af58a9088b82612f');
- });
-
- it('returns checksum for configurable product', async () => {
- expect(productChecksum(configurableProduct)).toBe('357e8f9f8918873f12ed993c3073ddd3e8980c933034b5e2fdab10b6');
- });
-});
diff --git a/core/modules/cart/test/unit/helpers/productEquals.spec.ts b/core/modules/cart/test/unit/helpers/productEquals.spec.ts
deleted file mode 100644
index 9e8e40bd14..0000000000
--- a/core/modules/cart/test/unit/helpers/productEquals.spec.ts
+++ /dev/null
@@ -1,142 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import productsEquals from './../../../helpers/productsEquals';
-
-const createBundleOptions = (options) => {
- if (!options) {
- return []
- }
-
- return [
- {
- option_id: 1,
- option_qty: 1
- },
- {
- option_id: 2,
- option_qty: 1
- },
- {
- option_id: 3,
- option_qty: 1
- },
- {
- option_id: 4,
- option_qty: 1
- }
- ].map((o, index) => ({ ...o, option_selections: [options[index]] }))
-}
-
-const createBundleProduct = ({ id, sku, type_id, options }): CartItem => ({
- sku,
- type_id,
- server_item_id: id,
- product_option: {
- extension_attributes: {
- bundle_options: createBundleOptions(options)
- }
- }
-} as any as CartItem)
-
-const createCustomOptions = (options) => {
- if (!options) {
- return []
- }
-
- return options.map((option, index) => ({
- option_id: index + 1,
- option_value: option
- }))
-}
-
-const createCustomOptionsProduct = ({ id, sku, options }): CartItem => ({
- sku,
- server_item_id: id,
- product_option: {
- extension_attributes: {
- custom_options: createCustomOptions(options)
- }
- }
-} as any as CartItem)
-
-const createConfigurableProduct = ({ id, sku }): CartItem => ({
- sku,
- type_id: 'configurable',
- server_item_id: id,
- product_option: {
- extension_attributes: {
- configurable_item_options: [
- {
- option_id: '93',
- option_value: 53
- },
- {
- option_id: '142',
- option_value: 169
- }
- ]
- }
- }
-} as any as CartItem)
-
-describe('Cart productEquals', () => {
- describe('bundle product', () => {
- it('returns true because products have the same options selected', async () => {
- const product1 = createBundleProduct({ id: 1, sku: 'WG-001', type_id: 'bundle', options: [2, 4, 5, 8] })
- const product2 = createBundleProduct({ id: 2, sku: 'WG-001', type_id: 'bundle', options: [2, 4, 5, 8] })
-
- expect(productsEquals(product1, product2)).toBeTruthy()
- });
-
- it('returns true because products have the same server id', async () => {
- const product1 = createBundleProduct({ id: 1, sku: 'WG-001', type_id: 'bundle', options: null })
- const product2 = createBundleProduct({ id: 1, sku: 'WG-001', type_id: 'none', options: [2, 4, 5, 8] })
-
- expect(productsEquals(product1, product2)).toBeTruthy()
- });
-
- it('returns false because products have not the same options selected', async () => {
- const product1 = createBundleProduct({ id: 1, sku: 'WG-001', type_id: 'bundle', options: [2, 2, 5, 8] })
- const product2 = createBundleProduct({ id: 2, sku: 'WG-001', type_id: 'bundle', options: [2, 4, 5, 8] })
-
- expect(productsEquals(product1, product2)).toBeFalsy()
- });
- })
-
- describe('custom options product', () => {
- it('returns true because products have the same options selected', async () => {
- const product1 = createCustomOptionsProduct({ id: 1, sku: 'WG-001', options: [2, 4, 5, 8] })
- const product2 = createCustomOptionsProduct({ id: 2, sku: 'WG-001', options: [2, 4, 5, 8] })
-
- expect(productsEquals(product1, product2)).toBeTruthy()
- });
-
- it('returns false because bundle products have not the same options selected', async () => {
- const product1 = createBundleProduct({ id: 1, sku: 'WG-001', type_id: 'bundle', options: [2, 2, 5, 8] })
- const product2 = createBundleProduct({ id: 2, sku: 'WG-001', type_id: 'bundle', options: [2, 4, 5, 8] })
- expect(productsEquals(product1, product2)).toBeFalsy()
- });
-
- it('returns true because products have the same server id', async () => {
- const product1 = createCustomOptionsProduct({ id: 1, sku: 'WG-001', options: null })
- const product2 = createCustomOptionsProduct({ id: 1, sku: 'WG-001', options: [2, 4, 5, 8] })
-
- expect(productsEquals(product1, product2)).toBeTruthy()
- });
-
- it('returns false because products have not the same options selected', async () => {
- const product1 = createCustomOptionsProduct({ id: 1, sku: 'WG-001', options: [2, 2, 5, 8] })
- const product2 = createCustomOptionsProduct({ id: 2, sku: 'WG-001', options: [2, 4, 5, 8] })
-
- expect(productsEquals(product1, product2)).toBeFalsy()
- });
- })
-
- describe('configurable product', () => {
- it('returns true because products have the same sku', async () => {
- const product1 = createConfigurableProduct({ id: 1, sku: 'WG-001' })
- const product2 = createConfigurableProduct({ id: 2, sku: 'WG-001' })
-
- expect(productsEquals(product1, product2)).toBeTruthy()
- });
- })
-});
diff --git a/core/modules/cart/test/unit/helpers/totalsCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/totalsCacheHandler.spec.ts
deleted file mode 100644
index beb39fcae5..0000000000
--- a/core/modules/cart/test/unit/helpers/totalsCacheHandler.spec.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import Vue from 'vue'
-import Vuex from 'vuex'
-
-import * as types from '../../../store/mutation-types'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-const StorageManager = {
- cart: {
- setItem: jest.fn()
- },
- get (key) {
- return this[key]
- },
- clear () {
- return new Promise((resolve, reject) => {
- resolve()
- })
- }
-};
-const totalsCacheHandlerPlugin = require('../../../helpers/totalsCacheHandler').totalsCacheHandlerPlugin
-
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({ StorageManager }))
-jest.mock('@vue-storefront/core/helpers', () => ({
- isServer: () => false
-}));
-jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() }))
-jest.mock('@vue-storefront/i18n', () => ({ loadLanguageAsync: jest.fn() }))
-
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- error: () => () => {}
- }
-}))
-
-Vue.use(Vuex);
-
-describe('Cart afterRegistration', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- it('handler populates cart cache on mutation CART_UPD_TOTALS that modifies totals', async () => {
- const stateMock = {
- cart: {
- platformTotalSegments: 1,
- platformTotals: 2
- }
- };
-
- StorageManager.get('cart').setItem.mockImplementationOnce(() => Promise.resolve('foo'));
-
- await totalsCacheHandlerPlugin({ type: types.CART_UPD_TOTALS }, stateMock);
-
- expect(StorageManager.get('cart').setItem)
- .toBeCalledWith('current-totals', {
- platformTotalSegments: 1,
- platformTotals: 2
- });
- });
-
- it('handler logs error when populating cart cache with items fails', async () => {
- const stateMock = {
- cart: {
- cartItems: [{}]
- }
- };
-
- const consoleErrorSpy = jest.spyOn(Logger, 'error');
-
- StorageManager.get('cart').setItem.mockImplementationOnce(() => Promise.reject('foo'));
-
- await totalsCacheHandlerPlugin({ type: types.CART_UPD_TOTALS }, stateMock);
-
- expect(consoleErrorSpy).toBeCalled();
- });
-
- it('nothing happens for mutation different than CART_UPD_TOTALS', async () => {
- const stateMock = {
- cart: {
- cartItems: [{}]
- }
- };
-
- const consoleErrorSpy = jest.spyOn(Logger, 'error');
- const storageManagerSpy = jest.spyOn(StorageManager.get('cart'), 'setItem');
-
- await totalsCacheHandlerPlugin({ type: 'abc' }, stateMock);
-
- expect(consoleErrorSpy).not.toBeCalled();
- expect(storageManagerSpy).not.toBeCalled();
- });
-});
diff --git a/core/modules/cart/test/unit/helpers/validateProduct.spec.ts b/core/modules/cart/test/unit/helpers/validateProduct.spec.ts
deleted file mode 100644
index f9180c6798..0000000000
--- a/core/modules/cart/test/unit/helpers/validateProduct.spec.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import CartItem from '@vue-storefront/core/modules/cart/types/CartItem'
-import validateProduct from '@vue-storefront/core/modules/cart/helpers/validateProduct'
-
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('@vue-storefront/core/lib/multistore', () => jest.fn())
-
-describe('Cart validateProduct', () => {
- it('returns error about unknown price', () => {
- const product = {
- price_incl_tax: -1,
- errors: {}
- } as any as CartItem
-
- expect(validateProduct(product)).toEqual(['Product price is unknown, product cannot be added to the cart!'])
- });
-
- it('returns product errors', () => {
- const product = {
- price_incl_tax: 5,
- errors: {
- error1: 'error 1',
- error2: 'error 2'
- }
- } as any as CartItem
-
- expect(validateProduct(product)).toEqual(['error 1', 'error 2'])
- });
-});
diff --git a/core/modules/cart/test/unit/index.spec.ts b/core/modules/cart/test/unit/index.spec.ts
deleted file mode 100644
index 0e405fcc6e..0000000000
--- a/core/modules/cart/test/unit/index.spec.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CartModule } from '../../index'
-
-jest.mock('../../store', () => ({}));
-jest.mock('@vue-storefront/core/lib/modules', () => ({ createModule: jest.fn(() => ({ module: 'cart' })) }));
-jest.mock('../../helpers/cartCacheHandler', () => ({ cartCacheHandlerFactory: jest.fn() }))
-jest.mock('@vue-storefront/core/helpers', () => ({ isServer: false }))
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({ initCacheStorage: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('@vue-storefront/core/app', () => jest.fn())
-jest.mock('@vue-storefront/core/store', () => ({}))
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-
-describe('Cart Module', () => {
- it('can be initialized', () => {
- expect(CartModule).toBeTruthy()
- })
-});
diff --git a/core/modules/cart/test/unit/store/connectActions.spec.ts b/core/modules/cart/test/unit/store/connectActions.spec.ts
deleted file mode 100644
index 5c12c72559..0000000000
--- a/core/modules/cart/test/unit/store/connectActions.spec.ts
+++ /dev/null
@@ -1,205 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import config from 'config';
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import { CartService } from '@vue-storefront/core/data-resolver'
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({ CartService: {
- getCartToken: jest.fn()
-} }));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return true
- },
- onlineHelper: {
- get isOnline () {
- return true
- }
- },
- processLocalizedURLAddress: (url) => url
-}));
-
-describe('Cart connectActions', () => {
- it('clear deletes all cart products and token', async () => {
- const contextMock = {
- commit: jest.fn(),
- dispatch: jest.fn(),
- getters: { isCartSyncEnabled: false }
- };
- const wrapper = (actions: any) => actions.clear(contextMock);
- config.cart = { synchronize: false };
-
- await wrapper(cartActions);
-
- expect(contextMock.commit).toHaveBeenNthCalledWith(1, types.CART_LOAD_CART, []);
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'sync', { forceClientState: true, forceSync: true });
- expect(contextMock.commit).toHaveBeenNthCalledWith(2, types.CART_SET_ITEMS_HASH, null);
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'disconnect');
- });
-
- it('clear deletes all cart products but keep token', async () => {
- const contextMock = {
- commit: jest.fn(),
- dispatch: jest.fn(),
- getters: { isCartSyncEnabled: false }
- };
- const wrapper = (actions: any) => actions.clear(contextMock, { disconnect: false });
-
- config.cart = { synchronize: false };
-
- await wrapper(cartActions);
-
- expect(contextMock.commit).toHaveBeenNthCalledWith(1, types.CART_LOAD_CART, []);
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'sync', { forceClientState: true, forceSync: true });
- });
-
- it('clear deletes all cart products and token, but not sync with backend', async () => {
- const contextMock = {
- commit: jest.fn(),
- dispatch: jest.fn(),
- getters: { isCartSyncEnabled: false }
- };
- const wrapper = (actions: any) => actions.clear(contextMock, { sync: false });
-
- config.cart = { synchronize: false };
-
- await wrapper(cartActions);
-
- expect(contextMock.commit).toHaveBeenNthCalledWith(1, types.CART_LOAD_CART, []);
- expect(contextMock.commit).toHaveBeenNthCalledWith(2, types.CART_SET_ITEMS_HASH, null);
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'disconnect');
- });
-
- it('disconnects cart', async () => {
- const contextMock = createContextMock()
- await (cartActions as any).disconnect(contextMock)
- expect(contextMock.commit).toBeCalledWith(types.CART_LOAD_CART_SERVER_TOKEN, null);
- })
-
- it('authorizes server cart token', async () => {
- (StorageManager.get as jest.Mock).mockImplementation(() => ({
- getItem: async () => 1
- }));
-
- const contextMock = createContextMock({
- getters: {
- getCoupon: {
- code: null
- }
- }
- })
-
- await (cartActions as any).authorize(contextMock)
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'connect', { guestCart: false, mergeQty: true });
- })
-
- it('creates cart token', async () => {
- (CartService.getCartToken as jest.Mock).mockImplementation(async () =>
- ({ resultCode: 200, result: 'server-cart-token' })
- );
-
- const contextMock = createContextMock({
- getters: {
- isCartSyncEnabled: true
- }
- })
-
- config.cart = {
- serverMergeByDefault: false
- }
-
- await (cartActions as any).connect(contextMock, {})
- expect(contextMock.commit).toBeCalledWith(types.CART_LOAD_CART_SERVER_TOKEN, 'server-cart-token')
- expect(contextMock.dispatch).toBeCalledWith('sync', { forceClientState: false, dryRun: true, mergeQty: false })
- })
-
- it('attempts bypassing guest cart', async () => {
- (CartService.getCartToken as jest.Mock).mockImplementation(async () =>
- ({ resultCode: 401, result: null })
- );
-
- const contextMock = createContextMock({
- getters: {
- isCartSyncEnabled: true,
- bypassCounter: 0
- }
- })
-
- config.cart = {
- serverMergeByDefault: false
- }
- config.queues = {
- maxCartBypassAttempts: 4
- }
-
- await (cartActions as any).connect(contextMock, {})
- expect(contextMock.commit).toBeCalledWith(types.CART_UPDATE_BYPASS_COUNTER, { counter: 1 })
- expect(contextMock.dispatch).toBeCalledWith('connect', { guestCart: true })
- })
- it('Create cart token when there are products in cart and we don\'t have token already', async () => {
- const contextMock = {
- commit: jest.fn(),
- dispatch: jest.fn(),
- getters: { getCartItems: [{ id: 1 }], getCartToken: '' }
- };
-
- const wrapper = (actions: any) => actions.create(contextMock);
-
- await wrapper(cartActions);
-
- expect(contextMock.dispatch).toBeCalledWith('connect', { guestCart: false });
- })
- it('doesn\'t create cart token when there are NO products in cart', async () => {
- const contextMock = {
- commit: jest.fn(),
- dispatch: jest.fn(),
- getters: { getCartItems: [], getCartToken: '' }
- };
-
- const wrapper = (actions: any) => actions.create(contextMock);
-
- await wrapper(cartActions);
-
- expect(contextMock.dispatch).toHaveBeenCalledTimes(0);
- })
- it('doesn\'t create cart token when there are products in cart but we have token already', async () => {
- const contextMock = {
- commit: jest.fn(),
- dispatch: jest.fn(),
- getters: { getCartItems: [{ id: 1 }], getCartToken: 'xyz' }
- };
-
- const wrapper = (actions: any) => actions.create(contextMock);
-
- await wrapper(cartActions);
-
- expect(contextMock.dispatch).toHaveBeenCalledTimes(0);
- })
-})
diff --git a/core/modules/cart/test/unit/store/couponActions.spec.ts b/core/modules/cart/test/unit/store/couponActions.spec.ts
deleted file mode 100644
index eced8f89cc..0000000000
--- a/core/modules/cart/test/unit/store/couponActions.spec.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({ CartService: {
- applyCoupon: async () => ({ result: true }),
- removeCoupon: async () => ({ result: true })
-} }));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return true
- },
- onlineHelper: {
- get isOnline () {
- return true
- }
- },
- processLocalizedURLAddress: (url) => url
-}));
-
-describe('Cart couponActions', () => {
- it('applies coupon', async () => {
- const contextMock = createContextMock({
- getters: {
- canSyncTotals: true
- }
- })
- await (cartActions as any).applyCoupon(contextMock, 'coupon-code')
-
- expect(contextMock.dispatch).toBeCalledWith('syncTotals', { forceServerSync: true })
- })
-
- it('removes coupon', async () => {
- const contextMock = createContextMock({
- getters: {
- canSyncTotals: true
- }
- })
- await (cartActions as any).removeCoupon(contextMock)
-
- expect(contextMock.dispatch).toBeCalledWith('syncTotals', { forceServerSync: true })
- })
-})
diff --git a/core/modules/cart/test/unit/store/getters.spec.ts b/core/modules/cart/test/unit/store/getters.spec.ts
deleted file mode 100644
index 5da051496a..0000000000
--- a/core/modules/cart/test/unit/store/getters.spec.ts
+++ /dev/null
@@ -1,245 +0,0 @@
-import cartGetters from '../../../store/getters';
-import { onlineHelper } from '@vue-storefront/core/helpers'
-import config from 'config'
-
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => jest.fn())
-jest.mock('@vue-storefront/core/app', () => jest.fn())
-jest.mock('@vue-storefront/core/lib/multistore', () => jest.fn())
-jest.mock('@vue-storefront/core/store', () => ({}))
-jest.mock('@vue-storefront/core/helpers', () => ({
- onlineHelper: {
- get isOnline () {
- return true
- }
- }
-}));
-
-describe('Cart getters', () => {
- const isOnlineSpy = jest.spyOn(onlineHelper, 'isOnline', 'get');
-
- beforeEach(() => {
- jest.clearAllMocks();
- Object.keys(config).forEach((key) => { delete config[key]; });
- });
-
- it('totals returns platform total segments if they has been saved in store and client is online', () => {
- const stateMock = {
- platformTotalSegments: [
- { 'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36 },
- { 'code': 'shipping', 'title': 'Shipping & Handling (Flat Rate - Fixed)', 'value': 5 },
- { 'code': 'discount', 'title': 'Discount', 'value': -4.8 },
- { 'code': 'tax',
- 'title': 'Tax',
- 'value': 6.26,
- 'area': 'taxes',
- 'extension_attributes': {
- 'tax_grandtotal_details': [{
- 'amount': 6.26,
- 'rates': [{ 'percent': '23', 'title': 'VAT23-PL' }],
- 'group_id': 1
- }]
- } },
- { 'code': 'grand_total', 'title': 'Grand Total', 'value': 38.46, 'area': 'footer' }
- ]
- };
- const wrapper = (getters: any) => getters.getTotals(stateMock, getters);
-
- expect(wrapper(cartGetters)).toEqual(stateMock.platformTotalSegments);
- });
-
- it(`totals returns totals without shipping and payment prices having neither platformTotalSegments
- nor additional prices`, () => {
- const stateMock = {
- cartItems: [
- { qty: 1, price_incl_tax: 1 },
- { qty: 2, price_incl_tax: 2 }
- ]
- };
- const wrapper = (getters: any) => getters.getTotals(stateMock, {
- ...getters,
- getFirstShippingMethod: getters.getFirstShippingMethod(stateMock),
- getFirstPaymentMethod: getters.getFirstPaymentMethod(stateMock)
- });
-
- expect(wrapper(cartGetters)).toEqual([
- { 'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5 },
- { 'code': 'grand_total', 'title': 'Grand total', 'value': 5 }
- ]);
- });
-
- it(`totals returns totals even when there are platform total segments but client is offline`, () => {
- isOnlineSpy.mockReturnValueOnce(false);
- const stateMock = {
- platformTotalSegments: [
- { 'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36 },
- { 'code': 'shipping', 'title': 'Shipping & Handling (Flat Rate - Fixed)', 'value': 5 }
- ],
- cartItems: [
- { qty: 1, price_incl_tax: 1 },
- { qty: 2, price_incl_tax: 2 }
- ]
- };
- const wrapper = (getters: any) => getters.getTotals(stateMock, {
- ...getters,
- getFirstShippingMethod: getters.getFirstShippingMethod(stateMock),
- getFirstPaymentMethod: getters.getFirstPaymentMethod(stateMock)
- });
-
- expect(wrapper(cartGetters)).toEqual([
- { 'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5 },
- { 'code': 'grand_total', 'title': 'Grand total', 'value': 5 }
- ]);
- });
-
- it(`totals returns totals including shipping and payment prices having these prices in store
- but no platformTotalSegments`, () => {
- const stateMock = {
- cartItems: [
- { qty: 1, price_incl_tax: 1 },
- { qty: 2, price_incl_tax: 2 }
- ],
- payment: {
- title: 'payment',
- cost_incl_tax: 4
- },
- shipping: {
- method_title: 'shipping',
- price_incl_tax: 8
- }
- };
- const wrapper = (getters: any) => getters.getTotals(stateMock, {
- ...getters,
- getFirstShippingMethod: getters.getFirstShippingMethod(stateMock),
- getFirstPaymentMethod: getters.getFirstPaymentMethod(stateMock)
- });
-
- expect(wrapper(cartGetters)).toEqual([
- { 'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5 },
- { 'code': 'grand_total', 'title': 'Grand total', 'value': 21 },
- { 'code': 'payment', 'title': 'payment', 'value': 4 },
- { 'code': 'shipping', 'title': 'shipping', 'value': 8 }
- ]);
- });
-
- it(`totals returns totals including first shipping and first payment prices having multiple prices in store
- but no platformTotalSegments`, () => {
- const stateMock = {
- cartItems: [
- { qty: 1, price_incl_tax: 1 },
- { qty: 2, price_incl_tax: 2 }
- ],
- payment: [
- {
- title: 'payment',
- cost_incl_tax: 4
- },
- {
- title: 'another-payment',
- cost_incl_tax: 16
- }
- ],
- shipping: [
- {
- method_title: 'shipping',
- price_incl_tax: 8
- },
- {
- method_title: 'another-shipping',
- price_incl_tax: 32
- }
- ]
- };
- const wrapper = (getters: any) => getters.getTotals(stateMock, {
- ...getters,
- getFirstShippingMethod: getters.getFirstShippingMethod(stateMock),
- getFirstPaymentMethod: getters.getFirstPaymentMethod(stateMock)
- });
-
- expect(wrapper(cartGetters)).toEqual([
- { 'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5 },
- { 'code': 'grand_total', 'title': 'Grand total', 'value': 21 },
- { 'code': 'payment', 'title': 'payment', 'value': 4 },
- { 'code': 'shipping', 'title': 'shipping', 'value': 8 }
- ]);
- });
-
- it('totalQuantity returns total quantity of all products in cart if minicart configuration is set to quantities', () => {
- config.cart = {
- minicartCountType: 'quantities'
- }
- const stateMock = {
- cartItems: [
- { qty: 1 },
- { qty: 2 }
- ]
- };
-
- const wrapper = (getters: any) => getters.getItemsTotalQuantity(stateMock, {});
-
- expect(wrapper(cartGetters)).toBe(3);
- });
-
- it('totalQuantity returns number of different products instead of their sum if minicart configuration is set to items', () => {
- config.cart = {
- minicartCountType: 'items'
- }
-
- const stateMock = {
- cartItems: [
- { qty: 1 },
- { qty: 2 }
- ]
- };
-
- const wrapper = (getters: any) => getters.getItemsTotalQuantity(stateMock, {});
-
- expect(wrapper(cartGetters)).toBe(2);
- });
-
- it('coupon returns coupon information when coupon has been applied to the cart', () => {
- const stateMock = {
- platformTotals: {
- coupon_code: 'foo',
- discount_amount: 1.23
- }
- };
- const wrapper = (getters: any) => getters.getCoupon(stateMock);
-
- expect(wrapper(cartGetters)).toEqual({
- code: stateMock.platformTotals.coupon_code,
- discount: stateMock.platformTotals.discount_amount
- });
- });
-
- it('coupon returns false given no coupons applied to the cart', () => {
- const stateMock = {};
- const wrapper = (getters: any) => getters.getCoupon(stateMock);
-
- expect(wrapper(cartGetters)).toBe(false);
- });
-
- it('isVirtualCart returns true given only virtual items in cart', () => {
- const stateMock = {
- cartItems: [
- { type_id: 'virtual' },
- { type_id: 'downloadable' }
- ]
- };
- const wrapper = (getters: any) => getters.isVirtualCart(stateMock);
-
- expect(wrapper(cartGetters)).toBe(true);
- });
-
- it('isVirtualCart returns false given any non virtual items in cart', () => {
- const stateMock = {
- cartItems: [
- { type_id: 'virtual' },
- { type_id: 'definitely-not-virtual' }
- ]
- };
- const wrapper = (getters: any) => getters.isVirtualCart(stateMock);
-
- expect(wrapper(cartGetters)).toBe(false);
- });
-});
diff --git a/core/modules/cart/test/unit/store/index.spec.ts b/core/modules/cart/test/unit/store/index.spec.ts
deleted file mode 100644
index 4f56009798..0000000000
--- a/core/modules/cart/test/unit/store/index.spec.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('../../../store/actions', () => ({}));
-jest.mock('../../../store/getters', () => ({}));
-jest.mock('../../../store/mutations', () => ({}));
-
-describe('Cart Module', () => {
- it('can be loaded', () => {
- expect(module).toBeTruthy()
- })
-});
diff --git a/core/modules/cart/test/unit/store/itemActions.spec.ts b/core/modules/cart/test/unit/store/itemActions.spec.ts
deleted file mode 100644
index 89b1517b88..0000000000
--- a/core/modules/cart/test/unit/store/itemActions.spec.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'
-import { configureProductAsync } from '@vue-storefront/core/modules/catalog/helpers'
-import { prepareProductsToAdd, productsEquals, validateProduct } from '@vue-storefront/core/modules/cart/helpers'
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-import config from 'config';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({ CartService: {
- applyCoupon: async () => ({ result: true }),
- removeCoupon: async () => ({ result: true })
-} }));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }))
-jest.mock('@vue-storefront/core/modules/catalog/helpers', () => ({
- configureProductAsync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/modules/cart/helpers', () => ({
- prepareProductsToAdd: jest.fn(),
- productsEquals: jest.fn(),
- validateProduct: jest.fn(),
- notifications: {
- createNotifications: jest.fn()
- },
- createDiffLog: () => ({
- pushNotifications: jest.fn(),
- merge: jest.fn()
- })
-}));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return true
- },
- onlineHelper: {
- get isOnline () {
- return true
- }
- },
- processLocalizedURLAddress: (url) => url
-}));
-jest.mock('config', () => ({}));
-
-describe('Cart itemActions', () => {
- it('configures item and deletes when there is same sku', async () => {
- const product1 = { sku: 1, name: 'product1', server_item_id: 1 }
- const product2 = { sku: 2, name: 'product2', server_item_id: 2 }
-
- const contextMock = createContextMock({
- getters: {
- isCartSyncEnabled: true,
- getCartItems: [product2]
- },
- dispatch: jest.fn((actionName) => {
- switch (actionName) {
- case 'product/getProductVariant': {
- return product2
- }
- }
- })
- })
-
- await (cartActions as any).configureItem(contextMock, { product: product1, configuration: {} })
- expect(contextMock.commit).toHaveBeenNthCalledWith(1, types.CART_DEL_ITEM, { product: product2 })
- expect(contextMock.commit).toHaveBeenNthCalledWith(2, types.CART_UPD_ITEM_PROPS, { product: { ...product1, ...product2 } })
- expect(contextMock.dispatch).toBeCalledWith('sync', { forceClientState: true })
- })
-
- it('configures item', async () => {
- const product1 = { sku: 1, name: 'product1', server_item_id: 1 }
- const product2 = { sku: 2, name: 'product2', server_item_id: 2 }
-
- const contextMock = createContextMock({
- getters: {
- isCartSyncEnabled: true,
- getCartItems: [product1]
- },
- dispatch: jest.fn((actionName) => {
- switch (actionName) {
- case 'product/getProductVariant': {
- return product2
- }
- }
- })
- })
-
- await (cartActions as any).configureItem(contextMock, { product: product1, configuration: {} })
- expect(contextMock.commit).not.toHaveBeenNthCalledWith(1, types.CART_DEL_ITEM, { product: product2 })
- expect(contextMock.commit).toHaveBeenNthCalledWith(1, types.CART_UPD_ITEM_PROPS, { product: { ...product1, ...product2 } })
- expect(contextMock.dispatch).toBeCalledWith('sync', { forceClientState: true })
- })
-
- it('adds item to the cart', async () => {
- const product1 = { sku: 1, name: 'product1', server_item_id: 1 }
- const prepareProductsToAddMock = prepareProductsToAdd as jest.Mock
- prepareProductsToAddMock.mockImplementation(() => [product1])
- const contextMock = createContextMock()
-
- await (cartActions as any).addItem(contextMock, { productToAdd: product1 })
-
- expect(contextMock.commit).toHaveBeenNthCalledWith(1, types.CART_ADDING_ITEM, { isAdding: true })
- expect(contextMock.dispatch).toBeCalledWith('addItems', { productsToAdd: [product1], forceServerSilence: false })
- expect(contextMock.commit).toHaveBeenNthCalledWith(2, types.CART_ADDING_ITEM, { isAdding: false })
- })
-
- it('checks product status', async () => {
- (productsEquals as jest.Mock).mockImplementation(() => true)
-
- const product1 = { sku: 1, name: 'product1', server_item_id: 1, qty: 1 }
- const contextMock = createContextMock({
- getters: {
- getCartItems: [product1]
- }
- })
-
- await (cartActions as any).checkProductStatus(contextMock, { product: product1 })
- expect(contextMock.dispatch).toBeCalledWith('stock/queueCheck', { product: product1, qty: 2 }, { root: true })
- })
-
- it('adds items to the cart', async () => {
- (validateProduct as jest.Mock).mockImplementation(() => [])
- const product = { sku: 1, name: 'product1', server_item_id: 1, qty: 1 }
-
- const contextMock = createContextMock({
- getters: {
- isCartSyncEnabled: true,
- isCartConnected: true
- }
- })
-
- // The third 'dispatch' call gets an instance of DiffLog class, which has the isEmpty() method.
- // The return value of the second 'dispatch' call is not used at all, so it can be left empty.
- contextMock.dispatch
- .mockImplementationOnce(() => Promise.resolve({ status: 'ok', onlineCheckTaskId: 1 }))
- .mockImplementationOnce(() => Promise.resolve({}))
- .mockImplementationOnce(() => Promise.resolve({ isEmpty: () => { return true } }))
-
- await (cartActions as any).addItems(contextMock, { productsToAdd: [product] })
- expect(contextMock.commit).toBeCalledWith(types.CART_ADD_ITEM, { product: { ...product, onlineStockCheckid: 1 } })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'checkProductStatus', { product })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'create')
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(3, 'sync', { forceClientState: true })
- })
-
- it('removes item from the cart', async () => {
- const product = { sku: 1, name: 'product1', server_item_id: 1, qty: 1 }
-
- const contextMock = createContextMock({
- getters: {
- isCartSyncEnabled: true
- }
- })
-
- await (cartActions as any).removeItem(contextMock, { product })
- expect(contextMock.commit).toBeCalledWith(types.CART_DEL_ITEM, { product, removeByParentSku: false })
- expect(contextMock.dispatch).toBeCalledWith('sync', { forceClientState: true })
- })
-})
diff --git a/core/modules/cart/test/unit/store/mergeActions.spec.ts b/core/modules/cart/test/unit/store/mergeActions.spec.ts
deleted file mode 100644
index fed23f94e4..0000000000
--- a/core/modules/cart/test/unit/store/mergeActions.spec.ts
+++ /dev/null
@@ -1,357 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types';
-import config from 'config';
-import { CartService } from '@vue-storefront/core/data-resolver';
-import {
- productsEquals,
- createCartItemForUpdate,
- createDiffLog
-} from '@vue-storefront/core/modules/cart/helpers';
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({
- CartService: {
- applyCoupon: async () => ({ result: true }),
- removeCoupon: async () => ({ result: true }),
- updateItem: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }));
-jest.mock('@vue-storefront/core/modules/catalog/helpers', () => ({
- configureProductAsync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/modules/cart/helpers', () => ({
- prepareProductsToAdd: jest.fn(),
- productsEquals: jest.fn(),
- validateProduct: jest.fn(),
- notifications: {
- createNotifications: jest.fn()
- },
- createCartItemForUpdate: jest.fn(),
- createDiffLog: jest.fn(() => ({
- pushNotifications: jest.fn(),
- pushServerResponse: jest.fn(),
- pushServerParty: jest.fn(),
- pushClientParty: jest.fn(),
- merge: jest.fn(),
- isEmpty: jest.fn()
- }))
-}));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return true;
- },
- onlineHelper: {
- get isOnline () {
- return true;
- }
- },
- processLocalizedURLAddress: url => url
-}));
-
-describe('Cart mergeActions', () => {
- it('updates client item', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 2,
- item_id: 1
- };
-
- const contextMock = createContextMock();
-
- await (cartActions as any).updateClientItem(contextMock, { clientItem, serverItem });
-
- expect(contextMock.dispatch).toBeCalledWith('updateItem', {
- product: {
- prev_qty: 2,
- product_option: 'a',
- server_cart_id: undefined,
- server_item_id: 1,
- sku: '1',
- type_id: 'b'
- }
- });
- });
-
- it('updates server item - removes when updating was not successful', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1, item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 2,
- item_id: 1
- };
-
- (createCartItemForUpdate as jest.Mock).mockImplementation(() => clientItem);
- (CartService.updateItem as jest.Mock).mockImplementation(() => Promise.resolve({ resultCode: 500 }));
-
- const contextMock = createContextMock({
- getters: {
- getCartToken: 'cart-token'
- }
- });
-
- await (cartActions as any).updateServerItem(contextMock, { clientItem, serverItem: null });
- expect(contextMock.commit).toBeCalledWith(types.CART_DEL_ITEM, { product: clientItem, removeByParentSku: false })
- })
-
- it('updates server item - restoring quantity', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1, item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 2,
- item_id: 1
- };
-
- (createCartItemForUpdate as jest.Mock).mockImplementation(() => clientItem);
- (CartService.updateItem as jest.Mock).mockImplementation(() => Promise.resolve({ resultCode: 500 }));
-
- const contextMock = createContextMock({
- getters: {
- getCartToken: 'cart-token'
- }
- });
-
- await (cartActions as any).updateServerItem(contextMock, { clientItem, serverItem });
- expect(contextMock.commit).not.toBeCalledWith(types.CART_DEL_ITEM, { product: clientItem, removeByParentSku: false })
- expect(contextMock.dispatch).toBeCalledWith('restoreQuantity', { product: clientItem })
- })
-
- it('updates server item - deletes non confirmed item', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 2,
- item_id: 1
- };
-
- (createCartItemForUpdate as jest.Mock).mockImplementation(() => clientItem);
- (CartService.updateItem as jest.Mock).mockImplementation(() => Promise.resolve({ resultCode: 500 }));
-
- const contextMock = createContextMock({
- getters: {
- getCartToken: 'cart-token'
- }
- });
-
- await (cartActions as any).updateServerItem(contextMock, { clientItem, serverItem });
- expect(contextMock.commit).not.toBeCalledWith(types.CART_DEL_ITEM, { product: clientItem, removeByParentSku: false })
- expect(contextMock.dispatch).not.toBeCalledWith('restoreQuantity', { product: clientItem })
- expect(contextMock.commit).toBeCalledWith(types.CART_DEL_NON_CONFIRMED_ITEM, { product: clientItem })
- })
-
- it('updates server item - apply changes for client item', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 2,
- item_id: 1
- };
-
- (createCartItemForUpdate as jest.Mock).mockImplementation(() => clientItem);
- (CartService.updateItem as jest.Mock).mockImplementation(() => Promise.resolve({ resultCode: 200, result: serverItem }));
-
- const contextMock = createContextMock({
- getters: {
- getCartToken: 'cart-token'
- },
- rootGetters: {
- 'checkout/isUserInCheckout': true
- }
- });
-
- await (cartActions as any).updateServerItem(contextMock, { clientItem, serverItem });
- expect(contextMock.commit).not.toBeCalledWith(types.CART_DEL_ITEM, { product: clientItem, removeByParentSku: false })
- expect(contextMock.dispatch).not.toBeCalledWith('restoreQuantity', { product: clientItem })
- expect(contextMock.commit).not.toBeCalledWith(types.CART_DEL_NON_CONFIRMED_ITEM, { product: clientItem })
- expect(contextMock.dispatch).toBeCalledWith('updateClientItem', { clientItem, serverItem: serverItem })
- })
-
- it('synchronizes item with server when there is no given server item', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 2,
- item_id: 1
- };
-
- config.cart = {
- serverSyncCanRemoveLocalItems: false
- }
-
- const contextMock = createContextMock()
-
- await (cartActions as any).synchronizeServerItem(contextMock, { clientItem, serverItem: null });
- expect(contextMock.dispatch).toBeCalledWith('updateServerItem', { clientItem, serverItem: null, updateIds: false })
- })
-
- it('synchronizes item with server when there quantities are different', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 1,
- item_id: 1
- };
-
- config.cart = {
- serverSyncCanRemoveLocalItems: false
- }
-
- const contextMock = createContextMock()
-
- await (cartActions as any).synchronizeServerItem(contextMock, { clientItem, serverItem });
- expect(contextMock.dispatch).not.toBeCalledWith('updateServerItem', { clientItem, serverItem: null, updateIds: false })
- expect(contextMock.dispatch).toBeCalledWith('updateServerItem', { clientItem, serverItem, updateIds: true })
- })
-
- it('merges client item', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 1,
- item_id: 1
- };
-
- const contextMock = createContextMock();
- (productsEquals as jest.Mock).mockImplementation(() => true);
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => Promise.resolve({ isEmpty: () => true }));
-
- await (cartActions as any).mergeClientItem(contextMock, { clientItem, serverItems: [serverItem], forceClientState: false, dryRun: false });
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'synchronizeServerItem', { serverItem, clientItem, forceClientState: false, dryRun: false })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'updateItem', { product: { product_option: 'a', server_cart_id: undefined, server_item_id: 1, sku: '1', type_id: 'b' } })
- })
-
- it('merges server item', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 1,
- item_id: 1
- };
-
- const contextMock = createContextMock();
-
- (productsEquals as jest.Mock).mockImplementation(() => false);
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => Promise.resolve(serverItem));
-
- await (cartActions as any).mergeServerItem(contextMock, { clientItems: [clientItem], serverItem, forceClientState: false, dryRun: false });
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'getProductVariant', { serverItem })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'addItem', { productToAdd: serverItem, forceServerSilence: true })
- })
-
- it('updates totals after merge', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1 };
-
- const contextMock = createContextMock({
- getters: {
- isTotalsSyncRequired: true,
- getCurrentCartHash: 'cart-hash'
- }
- });
- await (cartActions as any).updateTotalsAfterMerge(contextMock, { clientItems: [clientItem], dryRun: false });
- expect(contextMock.dispatch).toBeCalledWith('syncTotals')
- expect(contextMock.commit).toBeCalledWith(types.CART_SET_ITEMS_HASH, 'cart-hash')
- })
-
- it('merges client and server cart', async () => {
- const clientItem = { sku: '1', name: 'product1', qty: 2, server_item_id: 1 };
- const serverItem = {
- sku: '1',
- name: 'product1',
- server_item_id: 1,
- server_cart_id: 12,
- product_option: 'a',
- product_type: 'b',
- qty: 1,
- item_id: 1
- };
- const contextMock = createContextMock({
- getters: {
- isCartHashChanged: false
- }
- });
-
- const diffLog = {
- pushServerParty: () => diffLog,
- pushClientParty: () => diffLog,
- merge: () => diffLog
- };
-
- (createDiffLog as jest.Mock).mockImplementation(() => diffLog)
-
- await (cartActions as any).merge(contextMock, { clientItems: [clientItem], serverItems: [serverItem] });
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'mergeClientItems', { clientItems: [clientItem], serverItems: [serverItem], dryRun: false, forceClientState: false, mergeQty: false })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'mergeServerItems', { clientItems: [clientItem], serverItems: [serverItem], dryRun: false, forceClientState: false, mergeQty: false })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(3, 'updateTotalsAfterMerge', { clientItems: [clientItem], dryRun: false })
- })
-});
diff --git a/core/modules/cart/test/unit/store/methodsActions.spec.ts b/core/modules/cart/test/unit/store/methodsActions.spec.ts
deleted file mode 100644
index 8fe7dc93ad..0000000000
--- a/core/modules/cart/test/unit/store/methodsActions.spec.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types';
-import { CartService } from '@vue-storefront/core/data-resolver';
-import { preparePaymentMethodsToSync, createOrderData } from '@vue-storefront/core/modules/cart/helpers';
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({
- CartService: {
- applyCoupon: async () => ({ result: true }),
- removeCoupon: async () => ({ result: true }),
- getPaymentMethods: jest.fn(),
- updateItem: jest.fn(),
- getShippingMethods: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }));
-jest.mock('storefront-query-builder', () => jest.fn());
-jest.mock('@vue-storefront/core/modules/catalog/helpers', () => ({
- configureProductAsync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/modules/cart/helpers', () => ({
- prepareProductsToAdd: jest.fn(),
- productsEquals: jest.fn(),
- validateProduct: jest.fn(),
- notifications: {
- createNotifications: jest.fn()
- },
- createCartItemForUpdate: jest.fn(),
- createDiffLog: jest.fn(() => ({
- pushNotifications: jest.fn(),
- pushServerResponse: jest.fn(),
- pushServerParty: jest.fn(),
- pushClientParty: jest.fn(),
- merge: jest.fn(),
- isEmpty: jest.fn()
- })),
- preparePaymentMethodsToSync: jest.fn(),
- createOrderData: jest.fn()
-}));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return true;
- },
- onlineHelper: {
- get isOnline () {
- return true;
- }
- },
- processLocalizedURLAddress: url => url
-}));
-
-describe('Cart methodsActions', () => {
- it('fetches payment and shipping methods', async () => {
- const contextMock = createContextMock({
- getters: {
- isTotalsSyncRequired: true
- }
- })
-
- await (cartActions as any).pullMethods(contextMock, { forceServerSync: false });
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'syncShippingMethods', { forceServerSync: false })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'syncPaymentMethods', { forceServerSync: false })
- });
-
- it('sets default shipping methods', async () => {
- const contextMock = createContextMock({
- rootGetters: {
- 'checkout/getDefaultShippingMethod': { shipping: 1 }
- },
- getters: {
- getShippingMethodCode: false,
- getPaymentMethodCode: true
- }
- })
-
- await (cartActions as any).setDefaultCheckoutMethods(contextMock);
- expect(contextMock.commit).toBeCalledWith(types.CART_UPD_SHIPPING, { shipping: 1 })
- })
-
- it('sets default payment methods', async () => {
- const contextMock = createContextMock({
- rootGetters: {
- 'checkout/getDefaultPaymentMethod': { payment: 1 }
- },
- getters: {
- getShippingMethodCode: true,
- getPaymentMethodCode: false
- }
- })
-
- await (cartActions as any).setDefaultCheckoutMethods(contextMock);
- expect(contextMock.commit).toBeCalledWith(types.CART_UPD_PAYMENT, { payment: 1 })
- })
-
- it('synchronizes payment methods', async () => {
- const contextMock = createContextMock({
- rootGetters: {
- 'checkout/getNotServerPaymentMethods': [],
- 'checkout/getPaymentDetails': { country: 'US' }
- },
- getters: {
- canUpdateMethods: true,
- isTotalsSyncRequired: true
- }
- });
-
- (CartService.getPaymentMethods as jest.Mock).mockImplementation(() => Promise.resolve({ result: {} }));
- (createOrderData as jest.Mock).mockImplementation(() => ({ shippingMethodsData: {} }));
- (preparePaymentMethodsToSync as jest.Mock).mockImplementation(() => ({ uniqueBackendMethods: [], paymentMethods: [] }));
-
- await (cartActions as any).syncPaymentMethods(contextMock, {});
- expect(contextMock.dispatch).toBeCalledWith('checkout/replacePaymentMethods', [], { root: true })
- })
-
- it('synchronizes shipping methods', async () => {
- const contextMock = createContextMock({
- rootGetters: {
- 'checkout/getShippingDetails': { country: 'US' }
- },
- getters: {
- canUpdateMethods: true,
- isTotalsSyncRequired: true
- }
- });
-
- (CartService.getShippingMethods as jest.Mock).mockImplementation(() => Promise.resolve({ result: [] }));
-
- await (cartActions as any).syncShippingMethods(contextMock, {});
- expect(contextMock.dispatch).toBeCalledWith('updateShippingMethods', { shippingMethods: [] })
- })
-
- it('updates shipping methods', async () => {
- const contextMock = createContextMock()
- await (cartActions as any).updateShippingMethods(contextMock, { shippingMethods: [{ method: 1 }] });
- expect(contextMock.dispatch).toBeCalledWith('checkout/replaceShippingMethods', [{ is_server_method: true, method: 1 }], { root: true })
- })
-
- it('doesn\'t add not available method', async () => {
- const contextMock = createContextMock()
- await (cartActions as any).updateShippingMethods(contextMock, { shippingMethods: [{ method: 1, available: false }] });
- expect(contextMock.dispatch).toBeCalledWith('checkout/replaceShippingMethods', [], { root: true })
- })
-});
diff --git a/core/modules/cart/test/unit/store/mutations.spec.ts b/core/modules/cart/test/unit/store/mutations.spec.ts
deleted file mode 100644
index fa21430147..0000000000
--- a/core/modules/cart/test/unit/store/mutations.spec.ts
+++ /dev/null
@@ -1,585 +0,0 @@
-import * as types from '../../../store/mutation-types'
-import cartMutations from '../../../store/mutations'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-jest.mock('@vue-storefront/core/helpers', () => ({
- once: (str) => jest.fn()
-}))
-
-EventBus.$emit = jest.fn()
-
-jest.mock('@vue-storefront/core/store', () => ({
- state: {
- config: {}
- }
-}))
-
-describe('Cart mutations', () => {
- beforeEach(() => {
- jest.clearAllMocks()
- })
-
- describe('CART_ADD_ITEM', () => {
- it('adds a product to cart if none of its sku is there yet', () => {
- const stateMock = {
- cartItems: []
- }
- const product = {
- qty: 123,
- sku: 'foo'
- }
- const expectedState = {
- cartItems: [
- {
- qty: 123,
- sku: 'foo'
- }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_ADD_ITEM](stateMock, { product })
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('cart-before-add', { product })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('adds a product to cart with quantity of 1 if none of its sku is there yet and product qty is not provided', () => {
- const stateMock = {
- cartItems: []
- }
- const product = {
- sku: 'foo'
- }
- const expectedState = {
- cartItems: [
- {
- qty: 1,
- sku: 'foo'
- }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_ADD_ITEM](stateMock, { product })
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('cart-before-add', { product: { ...product, qty: 1 } })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('increases quantity of a a product in cart if one of its sku is already there', () => {
- const stateMock = {
- cartItems: [
- {
- qty: 10,
- sku: 'foo'
- }
- ]
- }
- const product = {
- qty: 10,
- sku: 'foo'
- }
- const expectedState = {
- cartItems: [
- {
- qty: 20,
- sku: 'foo'
- }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_ADD_ITEM](stateMock, { product })
-
- wrapper(cartMutations)
-
- expect(stateMock).toEqual(expectedState)
- })
-
- it('increases quantity of a a product in cart by 1 if quantity was not provided', () => {
- const stateMock = {
- cartItems: [
- {
- qty: 10,
- sku: 'foo'
- }
- ]
- }
- const product = {
- sku: 'foo'
- }
- const expectedState = {
- cartItems: [
- {
- qty: 11,
- sku: 'foo'
- }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_ADD_ITEM](stateMock, { product })
-
- wrapper(cartMutations)
-
- expect(stateMock).toEqual(expectedState)
- })
- })
-
- describe('CART_DEL_ITEM', () => {
- it('removes product from cart by sku', () => {
- const stateMock = {
- cartItems: [
- {
- qty: 10,
- sku: 'foo'
- }
- ]
- }
- const expectedState = {
- cartItems: []
- }
- const wrapper = (mutations: any) => mutations[types.CART_DEL_ITEM](
- stateMock,
- {
- product: { sku: 'foo' },
- removeByParentSku: false
- }
- )
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('cart-before-delete', {
- items: [{
- qty: 10,
- sku: 'foo'
- }]
- })
- expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('removes product from cart by parent sku', () => {
- const stateMock = {
- cartItems: [
- {
- qty: 10,
- sku: 'foo'
- }
- ]
- }
- const expectedState = {
- cartItems: []
- }
- const wrapper = (mutations: any) => mutations[types.CART_DEL_ITEM](
- stateMock,
- {
- product: { parentSku: 'foo' }
- }
- )
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('cart-before-delete', {
- items: [{
- qty: 10,
- sku: 'foo'
- }]
- })
- expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems })
- expect(stateMock).toEqual(expectedState)
- })
- })
-
- describe('CART_DEL_NON_CONFIRMED_ITEM', () => {
- it('removes product from cart by sku', () => {
- const stateMock = {
- cartItems: [
- {
- qty: 10,
- sku: 'foo'
- }
- ]
- }
- const expectedState = {
- cartItems: [] }
- const wrapper = (mutations: any) => mutations[types.CART_DEL_NON_CONFIRMED_ITEM](
- stateMock,
- {
- product: { sku: 'foo' },
- removeByParentSku: false
- }
- )
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('cart-before-delete', {
- items: [{
- qty: 10,
- sku: 'foo'
- }]
- })
- expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('removes product from cart by parent sku', () => {
- const stateMock = {
- cartItems: [
- {
- qty: 10,
- sku: 'foo'
- }
- ]
- }
- const expectedState = {
- cartItems: []
- }
- const wrapper = (mutations: any) => mutations[types.CART_DEL_NON_CONFIRMED_ITEM](
- stateMock,
- {
- product: { parentSku: 'foo' }
- }
- )
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('cart-before-delete', {
- items: [{
- qty: 10,
- sku: 'foo'
- }]
- })
- expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('does not remove a product that has server_item_id set, so it surely exists in the backend', () => {
- const stateMock = {
- cartItems: [
- {
- qty: 10,
- sku: 'foo',
- server_item_id: 123
- }
- ]
- }
- const expectedState = {
- cartItems: [
- {
- qty: 10,
- sku: 'foo',
- server_item_id: 123
- }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_DEL_NON_CONFIRMED_ITEM](
- stateMock,
- {
- product: { sku: 'foo' },
- removeByParentSku: false
- }
- )
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('cart-before-delete', { items: stateMock.cartItems })
- expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems })
- expect(stateMock).toEqual(expectedState)
- })
- })
-
- describe('CART_UPD_ITEM', () => {
- it('updates product quantity by sku', () => {
- const stateMock = {
- cartItems: [
- {
- sku: 'foo',
- qty: 10
- }
- ]
- }
- const expectedState = {
- cartItems: [
- {
- qty: 20,
- sku: 'foo'
- }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM](
- stateMock,
- {
- product: { sku: 'foo' },
- qty: 20
- }
- )
- wrapper(cartMutations)
-
- // unfortunately before and after events return a reference to the same object, therefore
- // after performing this mutation after event return same object with same, updated value as before event
- expect(EventBus.$emit).toBeCalledWith('cart-before-update', { product: expectedState.cartItems[0] })
- expect(EventBus.$emit).toBeCalledWith('cart-after-update', { product: expectedState.cartItems[0] })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('doesn\'t update anything if product is not found in cart', () => {
- const stateMock = {
- cartItems: [
- {
- sku: 'foo',
- qty: 10
- }
- ]
- }
- const expectedState = { ...stateMock }
- const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM](
- stateMock,
- {
- product: { sku: 'qux' },
- qty: 20
- }
- )
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).not.toBeCalled()
- expect(stateMock).toEqual(expectedState)
- })
- })
-
- describe('CART_UPD_ITEM_PROPS', () => {
- it('updates product properties by sku', () => {
- const stateMock = {
- cartItems: [
- {
- sku: 'foo',
- someProp: 'bar',
- qty: 10
- }
- ]
- }
- const expectedState = {
- cartItems: [
- {
- qty: 20,
- sku: 'foo',
- someProp: 'baz'
- }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM_PROPS](
- stateMock,
- {
- product: { sku: 'foo', someProp: 'baz', qty: 20 }
- }
- )
- let firstEmitCall = []
-
- EventBus.$emit.mockImplementationOnce((eventName, args) => {
- firstEmitCall.push(eventName)
- firstEmitCall.push(args)
- })
- wrapper(cartMutations)
-
- expect(firstEmitCall).toEqual(['cart-before-itemchanged', { item: expectedState.cartItems[0] }])
- expect(EventBus.$emit).toBeCalledWith('cart-after-itemchanged', { item: expectedState.cartItems[0] })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('updates product properties by server_item_id', () => {
- const stateMock = {
- cartItems: [
- {
- sku: 'foo',
- server_item_id: 123,
- someProp: 'bar',
- qty: 10
- }
- ]
- }
- const expectedState = {
- cartItems: [
- {
- server_item_id: 123,
- qty: 20,
- sku: 'bar',
- someProp: 'baz'
- }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM_PROPS](
- stateMock,
- {
- product: { server_item_id: 123, sku: 'bar', someProp: 'baz', qty: 20 }
- }
- )
- let firstEmitCall = []
-
- EventBus.$emit.mockImplementationOnce((eventName, args) => {
- firstEmitCall.push(eventName)
- firstEmitCall.push(args)
- })
- wrapper(cartMutations)
-
- expect(firstEmitCall).toEqual(['cart-before-itemchanged', { item: expectedState.cartItems[0] }])
- expect(EventBus.$emit).toBeCalledWith('cart-after-itemchanged', { item: expectedState.cartItems[0] })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('doesn\'t update anything if product is not found in cart', () => {
- const stateMock = {
- cartItems: [
- {
- sku: 'foo',
- someProp: 'bar',
- qty: 10
- }
- ]
- }
- const expectedState = { ...stateMock }
- const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM_PROPS](
- stateMock,
- {
- product: { sku: 'qux', someProp: 'baz', qty: 20 }
- }
- )
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).not.toBeCalled()
- expect(stateMock).toEqual(expectedState)
- })
- })
-
- it('CART_UPD_SHIPPING sets given shipping method', () => {
- const stateMock = {
- shipping: 'foo'
- }
- const expectedState = {
- shipping: 'bar'
- }
- const wrapper = (mutations: any) => mutations[types.CART_UPD_SHIPPING](
- stateMock,
- expectedState.shipping
- )
-
- wrapper(cartMutations)
-
- expect(stateMock).toEqual(expectedState)
- })
-
- it('CART_LOAD_CART initializes cart with given products', () => {
- const stateMock = {}
- const expectedState = {
- cartItems: [
- {
- sku: 'foo',
- qty: 10
- }
- ],
- cartIsLoaded: true
- }
- const wrapper = (mutations: any) => mutations[types.CART_LOAD_CART](
- stateMock,
- expectedState.cartItems
- )
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('sync/PROCESS_QUEUE', expect.anything())
- expect(EventBus.$emit).toBeCalledWith('application-after-loaded')
- expect(EventBus.$emit).toBeCalledWith('cart-after-loaded')
- expect(stateMock).toEqual(expectedState)
- })
-
- it('CART_LOAD_CART initializes an empty cart when no products are given', () => {
- const stateMock = {}
- const expectedState = {
- cartItems: [],
- cartIsLoaded: true
- }
- const wrapper = (mutations: any) => mutations[types.CART_LOAD_CART](
- stateMock
- )
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('sync/PROCESS_QUEUE', expect.anything())
- expect(EventBus.$emit).toBeCalledWith('application-after-loaded')
- expect(EventBus.$emit).toBeCalledWith('cart-after-loaded')
- expect(stateMock).toEqual(expectedState)
- })
-
- it('CART_LOAD_CART_SERVER_TOKEN saves given cart token in cart data', () => {
- const stateMock = {}
- const expectedState = {
- cartServerToken: 'foo'
- }
- const wrapper = (mutations: any) => mutations[types.CART_LOAD_CART_SERVER_TOKEN](
- stateMock,
- expectedState.cartServerToken
- )
-
- wrapper(cartMutations)
-
- expect(stateMock).toEqual(expectedState)
- })
-
- it('CART_UPD_TOTALS updates totals related data', () => {
- const stateMock = {}
- const expectedState = {
- itemsAfterPlatformTotals: ['foo'],
- platformTotals: {
- bar: 1 /** @todo replace with real alike data to show what it can be filled with */
- },
- platformTotalSegments: [
- { 'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36 },
- { 'code': 'grand_total', 'title': 'Grand Total', 'value': 39.36, 'area': 'footer' }
- ]
- }
- const wrapper = (mutations: any) => mutations[types.CART_UPD_TOTALS](
- stateMock,
- {
- itemsAfterTotals: expectedState.itemsAfterPlatformTotals,
- totals: expectedState.platformTotals,
- platformTotalSegments: expectedState.platformTotalSegments
- }
- )
-
- wrapper(cartMutations)
-
- expect(EventBus.$emit).toBeCalledWith('cart-after-updatetotals', {
- platformTotals: expectedState.platformTotals,
- platformTotalSegments: expectedState.platformTotalSegments
- })
- expect(stateMock).toEqual(expectedState)
- })
-
- it('CART_UPD_PAYMENT sets given payment method', () => {
- const stateMock = {
- payment: 'foo'
- }
- const expectedState = {
- payment: 'bar'
- }
- const wrapper = (mutations: any) => mutations[types.CART_UPD_PAYMENT](
- stateMock,
- expectedState.payment
- )
-
- wrapper(cartMutations)
-
- expect(stateMock).toEqual(expectedState)
- })
-
- it('CART_TOGGLE_MICROCART changes microcart open status to the opposite one', () => {
- const stateMock = {
- isMicrocartOpen: true
- }
- const expectedState = {
- isMicrocartOpen: false
- }
- const wrapper = (mutations: any) => mutations[types.CART_TOGGLE_MICROCART](
- stateMock
- )
-
- wrapper(cartMutations)
-
- expect(stateMock).toEqual(expectedState)
- })
-})
diff --git a/core/modules/cart/test/unit/store/productActions.spec.ts b/core/modules/cart/test/unit/store/productActions.spec.ts
deleted file mode 100644
index 753b502d33..0000000000
--- a/core/modules/cart/test/unit/store/productActions.spec.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({
- CartService: {
- applyCoupon: async () => ({ result: true }),
- removeCoupon: async () => ({ result: true }),
- getPaymentMethods: jest.fn(),
- updateItem: jest.fn(),
- getShippingMethods: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }));
-jest.mock('@vue-storefront/core/modules/catalog/helpers', () => ({
- configureProductAsync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/modules/cart/helpers', () => ({
- prepareProductsToAdd: jest.fn(),
- productsEquals: jest.fn(),
- validateProduct: jest.fn(),
- notifications: {
- createNotifications: jest.fn()
- },
- createCartItemForUpdate: jest.fn(),
- createDiffLog: jest.fn(() => ({
- pushNotifications: jest.fn(),
- pushServerResponse: jest.fn(),
- pushServerParty: jest.fn(),
- pushClientParty: jest.fn(),
- merge: jest.fn(),
- isEmpty: jest.fn()
- })),
- preparePaymentMethodsToSync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return true;
- },
- onlineHelper: {
- get isOnline () {
- return true;
- }
- },
- processLocalizedURLAddress: url => url
-}));
-
-describe('Cart productActions', () => {
- it('finds configurable children', async () => {
- const serverItem = { sku: 1, name: 'product1', product_type: 'configurable' }
- const contextMock = createContextMock();
-
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => ({ items: [serverItem] }));
- const result = await (cartActions as any).findProductOption(contextMock, { serverItem });
- expect(contextMock.dispatch).toBeCalledWith('product/findProducts', { query: { _appliedFilters: [{ attribute: 'configurable_children.sku', options: Object, scope: 'default', value: { eq: 1 } }], _availableFilters: [], _appliedSort: [], _searchText: '' }, size: 1, start: 0, options: { populateRequestCacheTags: false, prefetchGroupProducts: false, separateSelectedVariant: true } }, { root: true })
- expect(result).toEqual({ childSku: 1, sku: 1 })
- });
-
- it('finds product variant', async () => {
- const serverItem = { sku: 1, name: 'product1', product_type: 'configurable', qty: 1, quote_id: 1, item_id: 1, product_option: 'opt1' }
- const contextMock = createContextMock();
-
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => ({}));
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => ({ sku: 1, name: 'product1', product_type: 'configurable', opt1: 1 }));
-
- const result = await (cartActions as any).getProductVariant(contextMock, { serverItem });
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'findProductOption', { serverItem })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'product/single', { options: {} }, { root: true })
- expect(result).toEqual({
- name: 'product1',
- opt1: 1,
- product_option: 'opt1',
- product_type: 'configurable',
- qty: 1,
- server_cart_id: 1,
- server_item_id: 1,
- sku: 1
- })
- });
-});
diff --git a/core/modules/cart/test/unit/store/quantityActions.spec.ts b/core/modules/cart/test/unit/store/quantityActions.spec.ts
deleted file mode 100644
index 15f3bba5d8..0000000000
--- a/core/modules/cart/test/unit/store/quantityActions.spec.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types';
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({
- CartService: {
- applyCoupon: async () => ({ result: true }),
- removeCoupon: async () => ({ result: true }),
- getPaymentMethods: jest.fn(),
- updateItem: jest.fn(),
- getShippingMethods: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }));
-jest.mock('@vue-storefront/core/modules/catalog/helpers', () => ({
- configureProductAsync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/modules/cart/helpers', () => ({
- prepareProductsToAdd: jest.fn(),
- productsEquals: jest.fn(),
- validateProduct: jest.fn(),
- notifications: {
- createNotifications: jest.fn()
- },
- createCartItemForUpdate: jest.fn(),
- createDiffLog: jest.fn(() => ({
- pushNotifications: jest.fn(),
- pushServerResponse: jest.fn(),
- pushServerParty: jest.fn(),
- pushClientParty: jest.fn(),
- merge: jest.fn(),
- isEmpty: jest.fn()
- })),
- preparePaymentMethodsToSync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return true;
- },
- onlineHelper: {
- get isOnline () {
- return true;
- }
- },
- processLocalizedURLAddress: url => url
-}));
-
-describe('Cart quantityActions', () => {
- it('restores original quantity', async () => {
- const cartItem = { sku: 1, name: 'product1', prev_qty: 2 }
- const clientItem = { sku: 1, name: 'product1' }
-
- const contextMock = createContextMock();
-
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => cartItem);
- await (cartActions as any).restoreQuantity(contextMock, { product: clientItem })
- expect(contextMock.dispatch).toBeCalledWith('getItem', { product: clientItem })
- expect(contextMock.dispatch).toBeCalledWith('updateItem', { product: { ...clientItem, qty: 2 } })
- });
-
- it('removes item that has not quantity', async () => {
- const cartItem = { sku: 1, name: 'product1' }
- const clientItem = { sku: 1, name: 'product1' }
-
- const contextMock = createContextMock();
-
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => cartItem);
- await (cartActions as any).restoreQuantity(contextMock, { product: clientItem });
- expect(contextMock.dispatch).toBeCalledWith('getItem', { product: clientItem })
- expect(contextMock.dispatch).toBeCalledWith('removeItem', { product: cartItem, removeByParentSku: false })
- });
-
- it('updates quantity', async () => {
- const product = { sku: 1, name: 'product1', qty: 2, server_item_id: 1 }
-
- const contextMock = createContextMock({
- getters: {
- isCartSyncEnabled: true
- }
- });
-
- await (cartActions as any).updateQuantity(contextMock, { product, qty: 3 });
- expect(contextMock.commit).toBeCalledWith(types.CART_UPD_ITEM, { product, qty: 3 })
- expect(contextMock.dispatch).toBeCalledWith('sync', { forceClientState: true })
- })
-});
diff --git a/core/modules/cart/test/unit/store/synchronizeActions.spec.ts b/core/modules/cart/test/unit/store/synchronizeActions.spec.ts
deleted file mode 100644
index 27c1840794..0000000000
--- a/core/modules/cart/test/unit/store/synchronizeActions.spec.ts
+++ /dev/null
@@ -1,244 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types';
-import config from 'config';
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager';
-import { CartService } from '@vue-storefront/core/data-resolver';
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({
- CartService: {
- applyCoupon: async () => ({ result: true }),
- removeCoupon: async () => ({ result: true }),
- getPaymentMethods: jest.fn(),
- updateItem: jest.fn(),
- getShippingMethods: jest.fn(),
- getItems: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }));
-jest.mock('@vue-storefront/core/modules/catalog/helpers', () => ({
- configureProductAsync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/modules/cart/helpers', () => ({
- prepareProductsToAdd: jest.fn(),
- productsEquals: jest.fn(),
- validateProduct: jest.fn(),
- notifications: {
- createNotifications: jest.fn()
- },
- createCartItemForUpdate: jest.fn(),
- createDiffLog: jest.fn(() => ({
- pushNotifications: jest.fn(),
- pushServerResponse: jest.fn(),
- pushServerParty: jest.fn(),
- pushClientParty: jest.fn(),
- merge: jest.fn(),
- isEmpty: jest.fn()
- })),
- preparePaymentMethodsToSync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return false;
- },
- onlineHelper: {
- get isOnline () {
- return true;
- }
- },
- processLocalizedURLAddress: url => url
-}));
-
-describe('Cart synchronizeActions', () => {
- it('loads current cart', async () => {
- const contextMock = createContextMock();
-
- (StorageManager.get as jest.Mock).mockImplementation(() => ({
- getItem: async () => ({})
- }))
- await (cartActions as any).load(contextMock, {});
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'setDefaultCheckoutMethods')
- expect(contextMock.commit).toBeCalledWith(types.CART_LOAD_CART, {})
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'synchronizeCart', { forceClientState: false })
- });
-
- it('synchronizes cart', async () => {
- (StorageManager.get as jest.Mock).mockImplementation(() => ({
- getItem: async () => 'hash-token'
- }))
-
- config.cart = {
- synchronize: true,
- serverMergeByDefault: false
- }
- const contextMock = createContextMock();
-
- await (cartActions as any).synchronizeCart(contextMock, { forceClientState: false });
- expect(contextMock.commit).toHaveBeenNthCalledWith(1, types.CART_SET_ITEMS_HASH, 'hash-token')
- expect(contextMock.commit).toHaveBeenNthCalledWith(2, types.CART_LOAD_CART_SERVER_TOKEN, 'hash-token')
- expect(contextMock.dispatch).toBeCalledWith('sync', { forceClientState: false, dryRun: true })
- })
-
- it('creates a new cart token', async () => {
- (StorageManager.get as jest.Mock).mockImplementation(() => ({
- getItem: async () => null
- }))
-
- config.cart = {
- synchronize: true,
- serverMergeByDefault: false
- }
- const contextMock = createContextMock();
-
- await (cartActions as any).synchronizeCart(contextMock, { forceClientState: false });
- expect(contextMock.commit).not.toHaveBeenNthCalledWith(1, types.CART_SET_ITEMS_HASH, 'hash-token')
- expect(contextMock.commit).not.toHaveBeenNthCalledWith(2, types.CART_LOAD_CART_SERVER_TOKEN, 'hash-token')
- expect(contextMock.dispatch).toBeCalledWith('create')
- })
-
- it('merges current cart', async () => {
- (CartService.getItems as jest.Mock).mockImplementation(async () => ({
- resultCode: 200,
- result: []
- }))
-
- const contextMock = createContextMock({
- rootGetters: {
- 'checkout/isUserInCheckout': true
- },
- getters: {
- getCartItems: [],
- canUpdateMethods: true,
- isSyncRequired: true,
- bypassCounter: 0
- }
- });
- await (cartActions as any).sync(contextMock, {});
- expect(contextMock.dispatch).toBeCalledWith('merge', {
- clientItems: [],
- dryRun: false,
- forceClientState: true,
- serverItems: [],
- mergeQty: false
- })
- })
-
- it('attempts to bypass guest cart', async () => {
- (CartService.getItems as jest.Mock).mockImplementation(async () => ({
- resultCode: 500,
- result: null
- }))
-
- config.queues = {
- maxCartBypassAttempts: 4
- }
-
- const contextMock = createContextMock({
- rootGetters: {
- 'checkout/isUserInCheckout': true
- },
- getters: {
- getCartItems: [],
- canUpdateMethods: true,
- isSyncRequired: true,
- bypassCounter: 0
- }
- });
-
- await (cartActions as any).sync(contextMock, {});
- expect(contextMock.dispatch).toBeCalledWith('connect', { guestCart: true })
- })
-
- it('removes product when there is out of stock', async () => {
- const product = { sku: 1, name: 'product1' }
- const stockTask = { sku: 1, product_sku: 1, result: { is_in_stock: false, code: 'ok' } }
- config.stock = {
- allowOutOfStockInCart: false
- }
- config.cart = {
- synchronize: false
- }
- const contextMock = createContextMock();
-
- (contextMock.dispatch as jest.Mock).mockImplementation(() => product)
-
- await (cartActions as any).stockSync(contextMock, stockTask);
- expect(contextMock.dispatch).toBeCalledWith('getItem', { product: { sku: 1 } })
- expect(contextMock.commit).toBeCalledWith(types.CART_DEL_ITEM, { product: { sku: 1 } }, { root: true })
- })
- it('triggers an error when there is out of stock', async () => {
- const product = { sku: 1, name: 'product1' }
- const stockTask = { sku: 1, product_sku: 1, result: { is_in_stock: false, code: 'ok' } }
- config.stock = {
- allowOutOfStockInCart: true
- }
- config.cart = {
- synchronize: false
- }
- const contextMock = createContextMock();
-
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => product)
-
- await (cartActions as any).stockSync(contextMock, stockTask);
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'getItem', { product: { sku: 1 } })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'updateItem', {
- product: {
- errors: { stock: 'Out of the stock!' },
- is_in_stock: false,
- sku: 1
- }
- })
- })
- it('shows that product is in stock', async () => {
- const product = { sku: 1, name: 'product1' }
- const stockTask = { sku: 1, product_sku: 1, result: { is_in_stock: true, code: 'ok' } }
- config.stock = {
- allowOutOfStockInCart: true
- }
- config.cart = {
- synchronize: false
- }
- const contextMock = createContextMock({
- getters: {
- getCurrentCartHash: 'zyx'
- }
- });
-
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => product)
-
- await (cartActions as any).stockSync(contextMock, stockTask);
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'getItem', { product: { sku: 1 } })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'updateItem', {
- product: {
- info: { stock: 'In stock!' },
- is_in_stock: true,
- sku: 1
- }
- })
- })
-});
diff --git a/core/modules/cart/test/unit/store/totalsActions.spec.ts b/core/modules/cart/test/unit/store/totalsActions.spec.ts
deleted file mode 100644
index 3319703948..0000000000
--- a/core/modules/cart/test/unit/store/totalsActions.spec.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import * as types from '@vue-storefront/core/modules/cart/store/mutation-types';
-import {
- prepareShippingInfoForUpdateTotals,
- createOrderData,
- createShippingInfoData
-} from '@vue-storefront/core/modules/cart/helpers';
-import cartActions from '@vue-storefront/core/modules/cart/store/actions';
-import { createContextMock } from '@vue-storefront/unit-tests/utils';
-
-jest.mock('@vue-storefront/core/store', () => ({
- dispatch: jest.fn(),
- state: {}
-}));
-jest.mock('js-sha3', () => ({ sha3_224: jest.fn() }));
-jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) }));
-jest.mock('config', () => ({}));
-jest.mock('@vue-storefront/core/lib/multistore', () => ({
- currentStoreView: jest.fn(),
- localizedRoute: jest.fn()
-}));
-jest.mock('@vue-storefront/core/lib/logger', () => ({
- Logger: {
- log: jest.fn(() => () => {}),
- debug: jest.fn(() => () => {}),
- warn: jest.fn(() => () => {}),
- error: jest.fn(() => () => {}),
- info: jest.fn(() => () => {})
- }
-}));
-jest.mock('@vue-storefront/core/data-resolver', () => ({
- CartService: {
- applyCoupon: async () => ({ result: true }),
- removeCoupon: async () => ({ result: true }),
- getPaymentMethods: jest.fn(),
- updateItem: jest.fn(),
- getShippingMethods: jest.fn(),
- getItems: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/lib/storage-manager', () => ({
- StorageManager: {
- get: jest.fn()
- }
-}));
-jest.mock('@vue-storefront/core/app', () => ({ router: jest.fn() }));
-jest.mock('@vue-storefront/core/modules/catalog/helpers', () => ({
- configureProductAsync: jest.fn()
-}));
-jest.mock('@vue-storefront/core/modules/cart/helpers', () => ({
- prepareProductsToAdd: jest.fn(),
- productsEquals: jest.fn(),
- validateProduct: jest.fn(),
- notifications: {
- createNotifications: jest.fn()
- },
- createCartItemForUpdate: jest.fn(),
- createDiffLog: jest.fn(() => ({
- pushNotifications: jest.fn(),
- pushServerResponse: jest.fn(),
- pushServerParty: jest.fn(),
- pushClientParty: jest.fn(),
- merge: jest.fn(),
- isEmpty: jest.fn()
- })),
- preparePaymentMethodsToSync: jest.fn(),
- prepareShippingInfoForUpdateTotals: jest.fn(),
- createOrderData: jest.fn(),
- createShippingInfoData: jest.fn()
-}));
-jest.mock('@vue-storefront/core/helpers', () => ({
- get isServer () {
- return false;
- },
- onlineHelper: {
- get isOnline () {
- return true;
- }
- },
- processLocalizedURLAddress: url => url
-}));
-
-describe('Cart totalsActions', () => {
- it('replaces server totals', async () => {
- const itemsAfterTotal = {
- key1: { qty: 1, param1: 1, param2: 2, item_id: 1 },
- key2: { qty: 3, param1: 3, param2: 5, item_id: 2 },
- key3: { qty: 5, param1: 1, param2: 6, item_id: 3 }
- }
- const totals = { total_segments: {} }
- const contextMock = createContextMock();
-
- (contextMock.dispatch as jest.Mock).mockImplementationOnce(async () => ({
- resultCode: 200,
- result: { totals }
- }));
- (prepareShippingInfoForUpdateTotals as jest.Mock).mockImplementation(() => itemsAfterTotal);
-
- await (cartActions as any).overrideServerTotals(contextMock, { addressInformation: {}, hasShippingInformation: true });
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'updateItem', {
- product: { qty: 1, server_item_id: 1, totals: { item_id: 1, param1: 1, param2: 2, qty: 1 } }
- })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(3, 'updateItem', {
- product: { qty: 3, server_item_id: 2, totals: { item_id: 2, param1: 3, param2: 5, qty: 3 } }
- })
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(4, 'updateItem', {
- product: { qty: 5, server_item_id: 3, totals: { item_id: 3, param1: 1, param2: 6, qty: 5 } }
- })
- expect(contextMock.commit).toHaveBeenNthCalledWith(1, types.CART_UPD_TOTALS, { itemsAfterTotal, totals, platformTotalSegments: totals.total_segments })
- });
-
- it('synchronizes totals', async () => {
- (createOrderData as jest.Mock).mockImplementation(() => ({ country: 'US', method_code: 'XXX' }));
- (createShippingInfoData as jest.Mock).mockImplementation(() => 'address information');
- const contextMock = createContextMock({
- rootGetters: {
- 'checkout/getShippingDetails': {},
- 'checkout/getShippingMethods': {},
- 'checkout/getPaymentMethods': {}
- },
- getters: {
- canSyncTotals: true,
- isTotalsSyncRequired: true
- }
- });
- await (cartActions as any).syncTotals(contextMock, {});
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'pullMethods', {})
- expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'overrideServerTotals', { hasShippingInformation: 'XXX', addressInformation: 'address information' })
- })
-});
diff --git a/core/modules/cart/types/AppliedCoupon.ts b/core/modules/cart/types/AppliedCoupon.ts
deleted file mode 100644
index 7fdd6811e4..0000000000
--- a/core/modules/cart/types/AppliedCoupon.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default interface AppliedCoupon {
- code: string,
- discount: number
-}
diff --git a/core/modules/cart/types/BillingAddress.ts b/core/modules/cart/types/BillingAddress.ts
deleted file mode 100644
index be0bae3f4b..0000000000
--- a/core/modules/cart/types/BillingAddress.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export default interface BillingAddress {
- firstname: string,
- lastname: string,
- city: string,
- postcode: string,
- street: string[],
- countryId: string
-}
diff --git a/core/modules/cart/types/CartItem.ts b/core/modules/cart/types/CartItem.ts
deleted file mode 100644
index 395cf363dd..0000000000
--- a/core/modules/cart/types/CartItem.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product'
-
-import CartItemOption from './CartItemOption'
-import CartItemTotals from './CartItemTotals'
-
-export default interface CartItem extends Product {
- qty: number,
- options: CartItemOption[],
- totals: CartItemTotals,
- server_item_id: number | string,
- server_cart_id: any,
- product_type?: string,
- item_id?: number | string,
- checksum?: string,
- quoteId?: string
-}
diff --git a/core/modules/cart/types/CartItemOption.ts b/core/modules/cart/types/CartItemOption.ts
deleted file mode 100644
index 3a40d3f48d..0000000000
--- a/core/modules/cart/types/CartItemOption.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default interface CartItemOption {
- label: string,
- value: string
-}
diff --git a/core/modules/cart/types/CartItemTotals.ts b/core/modules/cart/types/CartItemTotals.ts
deleted file mode 100644
index cec1756d35..0000000000
--- a/core/modules/cart/types/CartItemTotals.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-
-import CartItemOption from './CartItemOption'
-
-export default interface CartItemTotals {
- base_discount_amount: number,
- base_price: number,
- base_price_incl_tax: number,
- base_row_total: number,
- base_row_total_incl_tax: number,
- base_tax_amount: number,
- discount_amount: number,
- discount_percent: number,
- item_id: number | string,
- name: string,
- options: CartItemOption[],
- price: number,
- price_incl_tax: number,
- qty: number,
- row_total: number,
- row_total_incl_tax: number,
- row_total_with_discount: number,
- tax_amount: number,
- tax_percent: number
-}
diff --git a/core/modules/cart/types/CartState.ts b/core/modules/cart/types/CartState.ts
deleted file mode 100644
index 5db0c3435b..0000000000
--- a/core/modules/cart/types/CartState.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-export default interface CartState {
- isMicrocartOpen: boolean,
- itemsAfterPlatformTotals: any,
- platformTotals: any,
- platformTotalSegments: any,
- cartIsLoaded: boolean,
- cartServerToken: string,
- shipping: any,
- payment: any,
- cartItemsHash: string,
- cartServerLastSyncDate: number,
- cartServerLastTotalsSyncDate: number,
- cartItems: any[],
- connectBypassCount: number,
- isAddingToCart: boolean
-}
diff --git a/core/modules/cart/types/CartTotalSegments.ts b/core/modules/cart/types/CartTotalSegments.ts
deleted file mode 100644
index 6ed65a223b..0000000000
--- a/core/modules/cart/types/CartTotalSegments.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import CartTotalSegmentsItem from './CartTotalSegmentsItem'
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-export default interface CartTotalSegments extends Array{}
diff --git a/core/modules/cart/types/CartTotalSegmentsItem.ts b/core/modules/cart/types/CartTotalSegmentsItem.ts
deleted file mode 100644
index cb818b885a..0000000000
--- a/core/modules/cart/types/CartTotalSegmentsItem.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export default interface CartTotalSegmentsItem {
- code: string,
- title: string,
- value: number,
- area?: string,
- extension_attributes?: object
-}
diff --git a/core/modules/cart/types/CheckoutData.ts b/core/modules/cart/types/CheckoutData.ts
deleted file mode 100644
index 4e2c5c676e..0000000000
--- a/core/modules/cart/types/CheckoutData.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import ShippingDetails from '@vue-storefront/core/modules/checkout/types/ShippingDetails'
-import ShippingMethod from './ShippingMethod'
-import PaymentMethod from './PaymentMethod'
-import PaymentDetails from '@vue-storefront/core/modules/checkout/types/PaymentDetails'
-
-export default interface CheckoutData {
- shippingDetails: ShippingDetails,
- shippingMethods: ShippingMethod[],
- paymentMethods: PaymentMethod[],
- paymentDetails: PaymentDetails,
- taxCountry?: string
-}
diff --git a/core/modules/cart/types/DiffLog.ts b/core/modules/cart/types/DiffLog.ts
deleted file mode 100644
index 0e29914953..0000000000
--- a/core/modules/cart/types/DiffLog.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-export interface Notification {
- type: string,
- message: any,
- action1: any,
- action2?: any
-}
-
-export interface ServerResponse {
- status: string | number,
- sku: string,
- result: any
-}
-
-export interface Party {
- party: string,
- status: string,
- sku: string
-}
diff --git a/core/modules/cart/types/OrderShippingDetails.ts b/core/modules/cart/types/OrderShippingDetails.ts
deleted file mode 100644
index ebfc2005c5..0000000000
--- a/core/modules/cart/types/OrderShippingDetails.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import ShippingAddress from './ShippingAddress'
-import BillingAddress from './BillingAddress'
-
-export default interface OrderShippingDetails {
- country?: string,
- method_code?: string,
- carrier_code?: string,
- payment_method?: string,
- shippingAddress?: ShippingAddress,
- billingAddress?: BillingAddress
-}
diff --git a/core/modules/cart/types/PaymentMethod.ts b/core/modules/cart/types/PaymentMethod.ts
deleted file mode 100644
index cb86869fe7..0000000000
--- a/core/modules/cart/types/PaymentMethod.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export default interface PaymentMethod {
- default: boolean,
- code?: string,
- cost_incl_tax?: number,
- title?: string
-}
diff --git a/core/modules/cart/types/ShippingAddress.ts b/core/modules/cart/types/ShippingAddress.ts
deleted file mode 100644
index a0e200c0f4..0000000000
--- a/core/modules/cart/types/ShippingAddress.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export default interface ShippingAddress {
- firstname: string,
- lastname: string,
- city: string,
- postcode: string,
- street: string[]
-}
diff --git a/core/modules/cart/types/ShippingMethod.ts b/core/modules/cart/types/ShippingMethod.ts
deleted file mode 100644
index 1620052bbd..0000000000
--- a/core/modules/cart/types/ShippingMethod.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export default interface ShippingMethod {
- method_code?: string,
- carrier_code?: string,
- offline: boolean,
- default: boolean,
- price_incl_tax?: number,
- method_title?: string
-}
diff --git a/core/modules/cart/types/Totals.ts b/core/modules/cart/types/Totals.ts
deleted file mode 100644
index 68c99e731f..0000000000
--- a/core/modules/cart/types/Totals.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export default interface Totals {
- item_id?: number | string,
- options?: string,
- name: string,
- qty: number,
- row_total: number,
- row_total_incl_tax: number,
- tax_amount: number,
- tax_percent: number
-}
diff --git a/core/modules/catalog-next/helpers/cacheProductsHelper.ts b/core/modules/catalog-next/helpers/cacheProductsHelper.ts
deleted file mode 100644
index d5fe9a83d8..0000000000
--- a/core/modules/catalog-next/helpers/cacheProductsHelper.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { products } from 'config'
-
-export const prefetchStockItems = (cachedProductsResponse, cache = {}) => {
- const skus = []
- let prefetchIndex = 0
- cachedProductsResponse.items.map(i => {
- if (products.configurableChildrenStockPrefetchStatic &&
- products.configurableChildrenStockPrefetchStaticPrefetchCount > 0) {
- if (prefetchIndex > products.configurableChildrenStockPrefetchStaticPrefetchCount) return
- }
- skus.push(i.sku) // main product sku to be checked anyway
- if (i.type_id === 'configurable' && i.configurable_children && i.configurable_children.length > 0) {
- for (const confChild of i.configurable_children) {
- const cachedItem = cache[confChild.id]
- if (typeof cachedItem === 'undefined' || cachedItem === null) {
- skus.push(confChild.sku)
- }
- }
- prefetchIndex++
- }
- })
-
- return skus
-}
diff --git a/core/modules/catalog-next/helpers/categoryHelpers.ts b/core/modules/catalog-next/helpers/categoryHelpers.ts
deleted file mode 100644
index 98a3b72521..0000000000
--- a/core/modules/catalog-next/helpers/categoryHelpers.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { entities } from 'config'
-import { Category, ChildrenData } from '../types/Category'
-
-export const compareByLabel = (a, b) => {
- if (a.label < b.label) {
- return -1
- }
- if (a.label > b.label) {
- return 1
- }
- return 0
-}
-
-export const _prepareCategoryPathIds = (category: Category): string[] => {
- if (!category || !category.path) return []
- return category.path.split('/')
-}
-
-export const getSearchOptionsFromRouteParams = (params: { [key: string]: string } = {}): Record => {
- const filterableKeys = entities.category.validSearchOptionsFromRouteParams
- let filters: { [key: string]: string } = {}
-
- Object.keys(params)
- .filter(key => filterableKeys.includes(key))
- .forEach(key => { filters[key] = params[key] })
-
- return filters
-}
diff --git a/core/modules/catalog-next/helpers/filterHelpers.ts b/core/modules/catalog-next/helpers/filterHelpers.ts
deleted file mode 100644
index 5b29e3dd4d..0000000000
--- a/core/modules/catalog-next/helpers/filterHelpers.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import config from 'config'
-import FilterVariant from 'core/modules/catalog-next/types/FilterVariant'
-import { Filters } from '../types/Category'
-
-export const getSystemFilterNames: string[] = config.products.systemFilterNames
-
-/**
- * Creates new filtersQuery (based on currentQuery) by modifying specific filter variant.
- */
-export const changeFilterQuery = ({ currentQuery = {}, filterVariant }: {currentQuery?: any, filterVariant?: FilterVariant} = {}) => {
- const newQuery = JSON.parse(JSON.stringify(currentQuery))
- if (!filterVariant) return newQuery
- if (getSystemFilterNames.includes(filterVariant.type)) {
- if (newQuery[filterVariant.type] && newQuery[filterVariant.type] === filterVariant.id) {
- delete newQuery[filterVariant.type]
- } else {
- newQuery[filterVariant.type] = filterVariant.id
- }
- } else {
- let queryFilter = newQuery[filterVariant.type] || []
- if (!Array.isArray(queryFilter)) queryFilter = [queryFilter]
- if (queryFilter.includes(filterVariant.id)) {
- queryFilter = queryFilter.filter(value => value !== filterVariant.id)
- } else if (filterVariant.single) {
- queryFilter = [filterVariant.id]
- } else {
- queryFilter.push(filterVariant.id)
- }
- // delete or add filter variant to query
- if (!queryFilter.length) delete newQuery[filterVariant.type]
- else newQuery[filterVariant.type] = queryFilter
- }
- return newQuery
-}
-
-export const getFiltersFromQuery = ({ filtersQuery = {}, availableFilters = {} } = {}): { filters: Filters } => {
- const searchQuery = {
- filters: {}
- }
- Object.keys(filtersQuery).forEach(filterKey => {
- const filter = availableFilters[filterKey]
- let queryValue = filtersQuery[filterKey]
- if (!filter) return
- // keep original value for system filters - for example sort
- if (getSystemFilterNames.includes(filterKey)) {
- searchQuery[filterKey] = queryValue
- } else {
- queryValue = [].concat(filtersQuery[filterKey])
- queryValue.map(singleValue => {
- const variant = filter.find(filterVariant => filterVariant.id === singleValue)
- if (!variant) return
- if (!Array.isArray(searchQuery.filters[filterKey])) searchQuery.filters[filterKey] = []
- searchQuery.filters[filterKey].push({ ...variant, attribute_code: filterKey })
- })
- }
- })
- return searchQuery
-}
diff --git a/core/modules/catalog-next/helpers/optionLabel.ts b/core/modules/catalog-next/helpers/optionLabel.ts
deleted file mode 100644
index 49d3ed76fc..0000000000
--- a/core/modules/catalog-next/helpers/optionLabel.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { optionLabel } from '@vue-storefront/core/modules/catalog/helpers/optionLabel'
-
-// TODO in future move old helper here, add tests and refactor
-export { optionLabel }
diff --git a/core/modules/catalog-next/hooks.ts b/core/modules/catalog-next/hooks.ts
deleted file mode 100644
index 87f6f71d37..0000000000
--- a/core/modules/catalog-next/hooks.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { createListenerHook } from '@vue-storefront/core/lib/hooks'
-import { Category } from './types/Category';
-import Product from 'core/modules/catalog/types/Product';
-
-const {
- hook: categoryPageVisitedHook,
- executor: categoryPageVisitedExecutor
-} = createListenerHook()
-
-const {
- hook: productPageVisitedHook,
- executor: productPageVisitedExecutor
-} = createListenerHook()
-
-/** Only for internal usage */
-const catalogHooksExecutors = {
- categoryPageVisited: categoryPageVisitedExecutor,
- productPageVisited: productPageVisitedExecutor
-}
-
-const catalogHooks = {
- /**
- * Hook is fired right after category page is visited.
- * @param category visited category
- */
- categoryPageVisited: categoryPageVisitedHook,
- /**
- * Hook is fired right after product page is visited.
- * @param product visited product
- */
- productPageVisited: productPageVisitedHook
-}
-
-export {
- catalogHooks,
- catalogHooksExecutors
-}
diff --git a/core/modules/catalog-next/index.ts b/core/modules/catalog-next/index.ts
deleted file mode 100644
index 5ea5cd1222..0000000000
--- a/core/modules/catalog-next/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { categoryModule } from './store/category'
-import { StorefrontModule } from '@vue-storefront/core/lib/modules';
-
-export const CatalogNextModule: StorefrontModule = function ({ store }) {
- store.registerModule('category-next', categoryModule)
-}
diff --git a/core/modules/catalog-next/store/category/CategoryState.ts b/core/modules/catalog-next/store/category/CategoryState.ts
deleted file mode 100644
index d3af9e7a3b..0000000000
--- a/core/modules/catalog-next/store/category/CategoryState.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Category } from '../../types/Category';
-import Product from 'core/modules/catalog/types/Product';
-
-export default interface CategoryState {
- categoriesMap: { [id: string]: Category },
- notFoundCategoryIds: string[],
- filtersMap: { [id: string]: any },
- products: Product[],
- searchProductsStats: any,
- menuCategories: Category[]
-}
diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts
deleted file mode 100644
index 8b8a06bde3..0000000000
--- a/core/modules/catalog-next/store/category/actions.ts
+++ /dev/null
@@ -1,269 +0,0 @@
-import Vue from 'vue'
-import { ActionTree } from 'vuex'
-import * as types from './mutation-types'
-import RootState from '@vue-storefront/core/types/RootState'
-import CategoryState from './CategoryState'
-import { quickSearchByQuery } from '@vue-storefront/core/lib/search'
-import { buildFilterProductsQuery } from '@vue-storefront/core/helpers'
-import { router } from '@vue-storefront/core/app'
-import { localizedDispatcherRoute } from '@vue-storefront/core/lib/multistore'
-import FilterVariant from '../../types/FilterVariant'
-import { CategoryService } from '@vue-storefront/core/data-resolver'
-import { changeFilterQuery } from '../../helpers/filterHelpers'
-import { products, entities } from 'config'
-import { DataResolver } from 'core/data-resolver/types/DataResolver';
-import { Category } from '../../types/Category';
-import { _prepareCategoryPathIds } from '../../helpers/categoryHelpers';
-import { prefetchStockItems } from '../../helpers/cacheProductsHelper';
-import chunk from 'lodash-es/chunk'
-import omit from 'lodash-es/omit'
-import cloneDeep from 'lodash-es/cloneDeep'
-import config from 'config'
-import { parseCategoryPath } from '@vue-storefront/core/modules/breadcrumbs/helpers'
-import createCategoryListQuery from '@vue-storefront/core/modules/catalog/helpers/createCategoryListQuery'
-import { transformCategoryUrl } from '@vue-storefront/core/modules/url/helpers/transformUrl';
-
-const actions: ActionTree = {
- async loadCategoryProducts ({ commit, getters, dispatch, rootState }, { route, category, pageSize = 50 } = {}) {
- const searchCategory = category || getters.getCategoryFrom(route.path) || {}
- const areFiltersInQuery = !!Object.keys(route[products.routerFiltersSource]).length
- let categoryMappedFilters = getters.getFiltersMap[searchCategory.id]
- if (!categoryMappedFilters && areFiltersInQuery) { // loading all filters only when some filters are currently chosen and category has no available filters yet
- await dispatch('loadCategoryFilters', searchCategory)
- categoryMappedFilters = getters.getFiltersMap[searchCategory.id]
- }
- const searchQuery = getters.getCurrentFiltersFrom(route[products.routerFiltersSource], categoryMappedFilters)
- let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters)
- const { items, perPage, start, total, aggregations, attributeMetadata } = await dispatch('product/findProducts', {
- query: filterQr,
- sort: searchQuery.sort || `${products.defaultSortBy.attribute}:${products.defaultSortBy.order}`,
- includeFields: entities.productList.includeFields,
- excludeFields: entities.productList.excludeFields,
- size: pageSize,
- configuration: searchQuery.filters,
- options: {
- populateRequestCacheTags: true,
- prefetchGroupProducts: false,
- setProductErrors: false,
- fallbackToDefaultWhenNoAvailable: true,
- assignProductConfiguration: false,
- separateSelectedVariant: false
- }
- }, { root: true })
- await dispatch('loadAvailableFiltersFrom', {
- aggregations,
- attributeMetadata,
- category: searchCategory,
- filters: searchQuery.filters
- })
- commit(types.CATEGORY_SET_SEARCH_PRODUCTS_STATS, { perPage, start, total })
- commit(types.CATEGORY_SET_PRODUCTS, items)
-
- return items
- },
- async loadMoreCategoryProducts ({ commit, getters, rootState, dispatch }) {
- const { perPage, start, total } = getters.getCategorySearchProductsStats
- const totalValue = typeof total === 'object' ? total.value : total
- if (start >= totalValue || totalValue < perPage) return
-
- const searchQuery = getters.getCurrentSearchQuery
- let filterQr = buildFilterProductsQuery(getters.getCurrentCategory, searchQuery.filters)
- const searchResult = await dispatch('product/findProducts', {
- query: filterQr,
- sort: searchQuery.sort || `${products.defaultSortBy.attribute}:${products.defaultSortBy.order}`,
- start: start + perPage,
- size: perPage,
- includeFields: entities.productList.includeFields,
- excludeFields: entities.productList.excludeFields,
- configuration: searchQuery.filters,
- options: {
- populateRequestCacheTags: true,
- prefetchGroupProducts: false,
- setProductErrors: false,
- fallbackToDefaultWhenNoAvailable: true,
- assignProductConfiguration: false,
- separateSelectedVariant: false
- }
- }, { root: true })
- commit(types.CATEGORY_SET_SEARCH_PRODUCTS_STATS, {
- perPage: searchResult.perPage,
- start: searchResult.start,
- total: searchResult.total
- })
-
- commit(types.CATEGORY_ADD_PRODUCTS, searchResult.items)
-
- return searchResult.items
- },
- async cacheProducts ({ commit, getters, dispatch, rootState }, { route } = {}) {
- if (config.api.saveBandwidthOverCache) {
- return
- }
-
- const searchCategory = getters.getCategoryFrom(route.path) || {}
- const searchQuery = getters.getCurrentFiltersFrom(route[products.routerFiltersSource])
- let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters)
-
- const cachedProductsResponse = await dispatch('product/findProducts', {
- query: filterQr,
- sort: searchQuery.sort,
- options: {
- populateRequestCacheTags: false,
- prefetchGroupProducts: false
- }
- }, { root: true })
- if (products.filterUnavailableVariants) { // prefetch the stock items
- const skus = prefetchStockItems(cachedProductsResponse, rootState.stock.cache)
-
- for (const chunkItem of chunk(skus, 15)) {
- dispatch('stock/list', { skus: chunkItem }, { root: true }) // store it in the cache
- }
- }
- },
- async findCategories (context, categorySearchOptions: DataResolver.CategorySearchOptions): Promise {
- return CategoryService.getCategories(categorySearchOptions)
- },
- async loadCategories ({ commit, getters }, categorySearchOptions: DataResolver.CategorySearchOptions): Promise {
- const searchingByIds = !(!categorySearchOptions || !categorySearchOptions.filters || !categorySearchOptions.filters.id)
- const searchedIds: string[] = searchingByIds ? [...categorySearchOptions.filters.id].map(String) : []
- const loadedCategories: Category[] = []
- if (searchingByIds && !categorySearchOptions.reloadAll) { // removing from search query already loaded categories, they are added to returned results
- for (const [categoryId, category] of Object.entries(getters.getCategoriesMap)) {
- if (searchedIds.includes(categoryId)) {
- loadedCategories.push(category as Category)
- }
- }
- categorySearchOptions.filters.id = searchedIds.filter(categoryId => !getters.getCategoriesMap[categoryId] && !getters.getNotFoundCategoryIds.includes(categoryId))
- }
- if (!searchingByIds || categorySearchOptions.filters.id.length) {
- categorySearchOptions.filters = Object.assign(cloneDeep(config.entities.category.filterFields), categorySearchOptions.filters ? cloneDeep(categorySearchOptions.filters) : {})
- const categories = await CategoryService.getCategories(categorySearchOptions)
- if (Vue.prototype.$cacheTags) {
- categories.forEach(category => {
- Vue.prototype.$cacheTags.add(`C${category.id}`)
- })
- }
- const notFoundCategories = searchedIds.filter(categoryId => !categories.some(cat => cat.id === parseInt(categoryId) || cat.id === categoryId))
-
- commit(types.CATEGORY_ADD_CATEGORIES, categories)
- commit(types.CATEGORY_ADD_NOT_FOUND_CATEGORY_IDS, notFoundCategories)
- return [...loadedCategories, ...categories]
- }
- return loadedCategories
- },
- async loadCategory ({ commit }, categorySearchOptions: DataResolver.CategorySearchOptions): Promise {
- const categories: Category[] = await CategoryService.getCategories(categorySearchOptions)
- const category: Category = categories && categories.length ? categories[0] : null
- if (Vue.prototype.$cacheTags) {
- Vue.prototype.$cacheTags.add(`C${category.id}`)
- }
- commit(types.CATEGORY_ADD_CATEGORY, category)
- return category
- },
- /**
- * Fetch and process filters from current category and sets them in available filters.
- */
- async loadCategoryFilters ({ dispatch, getters }, category) {
- const searchCategory = category || getters.getCurrentCategory
- let filterQr = buildFilterProductsQuery(searchCategory)
- const { aggregations, attributeMetadata } = await quickSearchByQuery({
- query: filterQr,
- size: config.products.maxFiltersQuerySize,
- excludeFields: ['*']
- })
- await dispatch('loadAvailableFiltersFrom', { aggregations, attributeMetadata: attributeMetadata, category })
- },
- async loadAvailableFiltersFrom ({ commit, getters, dispatch }, { aggregations, attributeMetadata, category, filters = {} }) {
- if (config.entities.attribute.loadByAttributeMetadata) {
- await dispatch('attribute/loadCategoryAttributes', { attributeMetadata }, { root: true })
- }
- const aggregationFilters = getters.getAvailableFiltersFrom(aggregations)
- const currentCategory = category || getters.getCurrentCategory
- const categoryMappedFilters = getters.getFiltersMap[currentCategory.id]
- let resultFilters = aggregationFilters
- const filtersKeys = Object.keys(filters)
- if (categoryMappedFilters && filtersKeys.length) {
- resultFilters = Object.assign(cloneDeep(categoryMappedFilters), cloneDeep(omit(aggregationFilters, filtersKeys)))
- }
- commit(types.CATEGORY_SET_CATEGORY_FILTERS, { category, filters: resultFilters })
- },
-
- async switchSearchFilters ({ dispatch }, filterVariants: FilterVariant[] = []) {
- let currentQuery = router.currentRoute[products.routerFiltersSource]
- filterVariants.forEach(filterVariant => {
- currentQuery = changeFilterQuery({ currentQuery, filterVariant })
- })
- await dispatch('changeRouterFilterParameters', currentQuery)
- },
- async resetSearchFilters ({ dispatch }) {
- await dispatch('changeRouterFilterParameters', {})
- },
- async changeRouterFilterParameters (context, query) {
- router.push({ [products.routerFiltersSource]: query })
- },
- async loadCategoryBreadcrumbs ({ dispatch, getters }, { category, currentRouteName, omitCurrent = false }) {
- if (!category) return
- const categoryHierarchyIds = category.parent_ids ? [...category.parent_ids, category.id] : _prepareCategoryPathIds(category) // getters.getCategoriesHierarchyMap.find(categoryMapping => categoryMapping.includes(category.id))
- const categoryFilters = Object.assign({ 'id': categoryHierarchyIds }, cloneDeep(config.entities.category.breadcrumbFilterFields))
- const categories = await dispatch('loadCategories', { filters: categoryFilters, reloadAll: Object.keys(config.entities.category.breadcrumbFilterFields).length > 0 })
- const sorted = []
- for (const id of categoryHierarchyIds) {
- const index = categories.findIndex(cat => cat.id.toString() === id)
- if (index >= 0 && (!omitCurrent || categories[index].id !== category.id)) {
- sorted.push(categories[index])
- }
- }
- await dispatch('breadcrumbs/set', { current: currentRouteName, routes: parseCategoryPath(sorted) }, { root: true })
- return sorted
- },
- /**
- * Load categories within specified parent
- * @param {Object} commit promise
- * @param {Object} parent parent category
- */
- async fetchMenuCategories ({ commit, getters, dispatch }, {
- parent = null,
- key = null,
- value = null,
- level = null,
- onlyActive = true,
- onlyNotEmpty = false,
- size = 4000,
- start = 0,
- sort = 'position:asc',
- includeFields = (config.entities.optimize ? config.entities.category.includeFields : null),
- excludeFields = (config.entities.optimize ? config.entities.category.excludeFields : null),
- skipCache = false
- }) {
- const { searchQuery, isCustomizedQuery } = createCategoryListQuery({ parent, level, key, value, onlyActive, onlyNotEmpty })
- const shouldLoadCategories = skipCache || isCustomizedQuery
-
- if (shouldLoadCategories) {
- const resp = await quickSearchByQuery({ entityType: 'category', query: searchQuery, sort, size, start, includeFields, excludeFields })
-
- await dispatch('registerCategoryMapping', { categories: resp.items })
-
- commit(types.CATEGORY_UPD_MENU_CATEGORIES, { items: resp.items })
-
- return resp
- }
-
- const list = { items: getters.getMenuCategories, total: getters.getMenuCategories.length }
-
- return list
- },
- async registerCategoryMapping ({ dispatch }, { categories }) {
- for (let category of categories) {
- if (category.url_path) {
- await dispatch('url/registerMapping', {
- url: localizedDispatcherRoute(category.url_path),
- routeData: transformCategoryUrl(category)
- }, { root: true })
- }
- }
- },
- /** Below actions are not used from 1.12 and can be removed to reduce bundle */
- ...require('./deprecatedActions').default
-}
-
-export default actions
diff --git a/core/modules/catalog-next/store/category/deprecatedActions.ts b/core/modules/catalog-next/store/category/deprecatedActions.ts
deleted file mode 100644
index f6701570ed..0000000000
--- a/core/modules/catalog-next/store/category/deprecatedActions.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { currentStoreView, localizedDispatcherRoute, localizedDispatcherRouteName } from '@vue-storefront/core/lib/multistore'
-import { preConfigureProduct } from '@vue-storefront/core/modules/catalog/helpers/search'
-import omit from 'lodash-es/omit'
-import config from 'config'
-const { configureProductAsync } = require('@vue-storefront/core/modules/catalog/helpers')
-
-const actions = {
- /**
- * Calculates products taxes
- * Registers URLs
- * Configures products
- */
- async processCategoryProducts ({ dispatch, rootState }, { products = [], filters = {} } = {}) {
- dispatch('registerCategoryProductsMapping', products) // we don't need to wait for this
- const configuredProducts = await dispatch('configureProducts', { products, filters })
- return dispatch('tax/calculateTaxes', { products: configuredProducts }, { root: true })
- },
- /**
- * Configure configurable products to have first available options selected
- * so they can be added to cart/wishlist/compare without manual configuring
- */
- async configureProducts ({ rootState }, { products = [], filters = {}, populateRequestCacheTags = config.server.useOutputCacheTagging } = {}) {
- return products.map(product => {
- product = Object.assign({}, preConfigureProduct({ product, populateRequestCacheTags }))
- const configuredProductVariant = configureProductAsync({ rootState, state: { current_configuration: {} } }, { product, configuration: filters, selectDefaultVariant: false, fallbackToDefaultWhenNoAvailable: true, setProductErorrs: false })
- return Object.assign(product, omit(configuredProductVariant, ['visibility']))
- })
- },
- async registerCategoryProductsMapping ({ dispatch }, products = []) {
- const { storeCode, appendStoreCode } = currentStoreView()
- await Promise.all(products.map(product => {
- const { url_path, sku, slug, type_id } = product
- return dispatch('url/registerMapping', {
- url: localizedDispatcherRoute(url_path, storeCode),
- routeData: {
- params: {
- parentSku: product.parentSku || product.sku,
- slug
- },
- 'name': localizedDispatcherRouteName(type_id + '-product', storeCode, appendStoreCode)
- }
- }, { root: true })
- }))
- }
-}
-
-export default actions
diff --git a/core/modules/catalog-next/store/category/getters.ts b/core/modules/catalog-next/store/category/getters.ts
deleted file mode 100644
index 70a5e89531..0000000000
--- a/core/modules/catalog-next/store/category/getters.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-import { nonReactiveState } from './index';
-import { GetterTree } from 'vuex'
-import RootState from '@vue-storefront/core/types/RootState'
-import CategoryState from './CategoryState'
-import { compareByLabel } from '../../helpers/categoryHelpers'
-import { products } from 'config'
-import FilterVariant from '../../types/FilterVariant'
-import { optionLabel } from '@vue-storefront/core/modules/catalog/helpers'
-import trim from 'lodash-es/trim'
-import toString from 'lodash-es/toString'
-import forEach from 'lodash-es/forEach'
-import get from 'lodash-es/get'
-import { getFiltersFromQuery } from '../../helpers/filterHelpers'
-import { Category } from '../../types/Category'
-import { parseCategoryPath } from '@vue-storefront/core/modules/breadcrumbs/helpers'
-import { _prepareCategoryPathIds, getSearchOptionsFromRouteParams } from '../../helpers/categoryHelpers';
-import { currentStoreView, removeStoreCodeFromRoute } from '@vue-storefront/core/lib/multistore'
-import cloneDeep from 'lodash-es/cloneDeep'
-import config from 'config';
-
-function mapCategoryProducts (productsFromState, productsData) {
- return productsFromState.map(prodState => {
- if (typeof prodState === 'string') {
- const product = productsData.find(prodData => prodData.sku === prodState)
- return cloneDeep(product)
- }
- return prodState
- })
-}
-
-const getters: GetterTree = {
- getCategories: (state): Category[] => Object.values(state.categoriesMap),
- getCategoriesMap: (state): { [id: string]: Category} => state.categoriesMap,
- getNotFoundCategoryIds: (state): string[] => state.notFoundCategoryIds,
- getCategoryProducts: (state) => mapCategoryProducts(state.products, nonReactiveState.products),
- getCategoryFrom: (state, getters) => (path: string = '') => {
- return getters.getCategories.find(category => (removeStoreCodeFromRoute(path) as string).replace(/^(\/)/gm, '') === category.url_path)
- },
- getCategoryByParams: (state, getters, rootState) => (params: { [key: string]: string } = {}) => {
- return getters.getCategories.find(category => {
- let valueCheck = []
- const searchOptions = getSearchOptionsFromRouteParams(params)
- forEach(searchOptions, (value, key) => valueCheck.push(category[key] && category[key] === (category[key].constructor)(value)))
- return valueCheck.filter(check => check === true).length === Object.keys(searchOptions).length
- }) || {}
- },
- getCurrentCategory: (state, getters, rootState, rootGetters) => {
- return getters.getCategoryByParams(rootState.route.params)
- },
- getAvailableFiltersFrom: (state, getters, rootState) => (aggregations) => {
- const filters = {}
- if (aggregations) { // populate filter aggregates
- for (let attrToFilter of products.defaultFilters) { // fill out the filter options
- let filterOptions: FilterVariant[] = []
-
- let uniqueFilterValues = new Set()
- if (attrToFilter !== 'price') {
- if (aggregations['agg_terms_' + attrToFilter]) {
- let buckets = aggregations['agg_terms_' + attrToFilter].buckets
- if (aggregations['agg_terms_' + attrToFilter + '_options']) {
- buckets = buckets.concat(aggregations['agg_terms_' + attrToFilter + '_options'].buckets)
- }
-
- for (let option of buckets) {
- uniqueFilterValues.add(toString(option.key))
- }
- }
-
- uniqueFilterValues.forEach(key => {
- const label = optionLabel(rootState.attribute, { attributeKey: attrToFilter, optionId: key })
- if (trim(label) !== '') { // is there any situation when label could be empty and we should still support it?
- filterOptions.push({
- id: key,
- label: label,
- type: attrToFilter
- })
- }
- });
- filters[attrToFilter] = filterOptions.sort(compareByLabel)
- } else { // special case is range filter for prices
- const currencySign = currentStoreView().i18n.currencySign
-
- if (aggregations['agg_range_' + attrToFilter]) {
- let index = 0
- let count = aggregations['agg_range_' + attrToFilter].buckets.length
- for (let option of aggregations['agg_range_' + attrToFilter].buckets) {
- filterOptions.push({
- id: option.key,
- type: attrToFilter,
- from: option.from,
- to: option.to,
- label: (index === 0 || (index === count - 1)) ? (option.to ? '< ' + currencySign + option.to : '> ' + currencySign + option.from) : currencySign + option.from + (option.to ? ' - ' + option.to : ''), // TODO: add better way for formatting, extract currency sign
- single: true
- })
- index++
- }
- filters[attrToFilter] = filterOptions
- }
- }
- }
- // Add sort to available filters
- let variants = []
- Object.keys(products.sortByAttributes).map(label => {
- variants.push({
- label: label,
- id: products.sortByAttributes[label],
- type: 'sort'
- })
- })
- filters['sort'] = variants
- }
- return filters
- },
- getFiltersMap: state => state.filtersMap,
- getAvailableFilters: (state, getters) => {
- const categoryId = get(getters.getCurrentCategory, 'id', null)
- return state.filtersMap[categoryId] || {}
- },
- getCurrentFiltersFrom: (state, getters, rootState) => (filters, categoryFilters) => {
- const currentQuery = filters || rootState.route[products.routerFiltersSource]
- const availableFilters = categoryFilters || getters.getAvailableFilters
- return getFiltersFromQuery({ availableFilters, filtersQuery: currentQuery })
- },
- getCurrentSearchQuery: (state, getters, rootState) => getters.getCurrentFiltersFrom(rootState.route[products.routerFiltersSource]),
- getCurrentFilters: (state, getters) => getters.getCurrentSearchQuery.filters,
- hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length,
- getSystemFilterNames: () => products.systemFilterNames,
- getBreadcrumbs: (state, getters) => getters.getBreadcrumbsFor(getters.getCurrentCategory),
- getBreadcrumbsFor: (state, getters) => category => {
- if (!category) return []
- const categoryHierarchyIds = _prepareCategoryPathIds(category)
- let resultCategoryList = categoryHierarchyIds.map(categoryId => {
- return getters.getCategoriesMap[categoryId]
- }).filter(c => !!c)
- return parseCategoryPath(resultCategoryList)
- },
- getCategorySearchProductsStats: state => state.searchProductsStats || {},
- getCategoryProductsTotal: (state, getters) => {
- const { total } = getters.getCategorySearchProductsStats
- const totalValue = typeof total === 'object' ? total.value : total
-
- return totalValue || 0
- },
- getMenuCategories (state, getters, rootState, rootGetters) {
- return state.menuCategories || rootGetters['category/getCategories']
- }
-}
-
-export default getters
diff --git a/core/modules/catalog-next/store/category/index.ts b/core/modules/catalog-next/store/category/index.ts
deleted file mode 100644
index 6d2f9f7eaa..0000000000
--- a/core/modules/catalog-next/store/category/index.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Module } from 'vuex'
-import actions from './actions'
-import getters from './getters'
-import mutations from './mutations'
-import RootState from '@vue-storefront/core/types/RootState'
-import CategoryState from './CategoryState'
-
-export const categoryModule: Module = {
- namespaced: true,
- state: {
- categoriesMap: {},
- notFoundCategoryIds: [],
- filtersMap: {},
- products: [],
- searchProductsStats: {},
- menuCategories: []
- },
- getters,
- actions,
- mutations
-}
-
-export const nonReactiveState = {
- products: []
-}
diff --git a/core/modules/catalog-next/store/category/mutation-types.ts b/core/modules/catalog-next/store/category/mutation-types.ts
deleted file mode 100644
index 3234f97a9b..0000000000
--- a/core/modules/catalog-next/store/category/mutation-types.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export const SN_CATEGORY = 'category'
-export const CATEGORY_SET_PRODUCTS = `${SN_CATEGORY}/SET_PRODUCTS`
-export const CATEGORY_ADD_PRODUCTS = `${SN_CATEGORY}/ADD_PRODUCTS`
-export const CATEGORY_SET_SEARCH_PRODUCTS_STATS = `${SN_CATEGORY}/SET_SEARCH_PRODUCTS_STATS`
-export const CATEGORY_ADD_CATEGORIES = `${SN_CATEGORY}/ADD_CATEGORIES`
-export const CATEGORY_ADD_CATEGORY = `${SN_CATEGORY}/ADD_CATEGORY`
-export const CATEGORY_SET_CATEGORY_FILTERS = `${SN_CATEGORY}/SET_CATEGORY_FILTERS`
-export const CATEGORY_ADD_NOT_FOUND_CATEGORY_IDS = `${SN_CATEGORY}/ADD_NOT_FOUND_CATEGORY_IDS`
-export const CATEGORY_UPD_MENU_CATEGORIES = `${SN_CATEGORY}/UPD_MENU_CATEGORIES`
diff --git a/core/modules/catalog-next/store/category/mutations.ts b/core/modules/catalog-next/store/category/mutations.ts
deleted file mode 100644
index fcee774545..0000000000
--- a/core/modules/catalog-next/store/category/mutations.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { isServer } from '@vue-storefront/core/helpers';
-import { nonReactiveState } from './index';
-import Vue from 'vue'
-import { MutationTree } from 'vuex'
-import * as types from './mutation-types'
-import CategoryState from './CategoryState'
-import { Category } from '../../types/Category'
-import cloneDeep from 'lodash-es/cloneDeep'
-import slugifyCategories from '@vue-storefront/core/modules/catalog/helpers/slugifyCategories'
-
-const mutations: MutationTree = {
- [types.CATEGORY_SET_PRODUCTS] (state, products = []) {
- nonReactiveState.products = cloneDeep(products)
- state.products = isServer ? products : products.map(prod => prod.sku)
- },
- [types.CATEGORY_ADD_PRODUCTS] (state, products = []) {
- nonReactiveState.products.push(...cloneDeep(products))
- state.products.push(...(isServer ? products : products.map(prod => prod.sku)))
- },
- [types.CATEGORY_ADD_CATEGORY] (state, category: Category) {
- if (category) {
- Vue.set(state.categoriesMap, category.id, category)
- }
- },
- [types.CATEGORY_ADD_CATEGORIES] (state, categories: Category[] = []) {
- if (categories.length) {
- let newCategoriesEntry = {}
- categories.forEach(category => {
- newCategoriesEntry[category.id] = category
- })
- state.categoriesMap = Object.assign({}, state.categoriesMap, newCategoriesEntry)
- }
- },
- [types.CATEGORY_ADD_NOT_FOUND_CATEGORY_IDS] (state, categoryIds: string[] = []) {
- state.notFoundCategoryIds = [...state.notFoundCategoryIds, ...categoryIds]
- },
- [types.CATEGORY_SET_CATEGORY_FILTERS] (state, { category, filters }) {
- Vue.set(state.filtersMap, category.id, filters)
- },
- [types.CATEGORY_SET_SEARCH_PRODUCTS_STATS] (state, stats = {}) {
- state.searchProductsStats = stats
- },
- [types.CATEGORY_UPD_MENU_CATEGORIES] (state, categories) {
- for (let category of categories.items) {
- category = slugifyCategories(category)
- const catExist = state.menuCategories.find(existingCat => existingCat.id === category.id)
-
- if (!catExist) {
- state.menuCategories.push(category)
- }
- }
-
- state.menuCategories.sort((catA, catB) => {
- if (catA.position && catB.position) {
- if (catA.position < catB.position) return -1
- if (catA.position > catB.position) return 1
- }
- return 0
- })
- }
-}
-
-export default mutations
diff --git a/core/modules/catalog-next/test/unit/_prepareCategoryPathIds.spec.ts b/core/modules/catalog-next/test/unit/_prepareCategoryPathIds.spec.ts
deleted file mode 100644
index 00fac236a8..0000000000
--- a/core/modules/catalog-next/test/unit/_prepareCategoryPathIds.spec.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { _prepareCategoryPathIds } from '@vue-storefront/core/modules/catalog-next/helpers/categoryHelpers';
-import { Category } from '../../types/Category';
-
-jest.mock('@vue-storefront/core/modules/breadcrumbs/helpers', () => jest.fn());
-
-describe('_prepareCategoryPathIds method', () => {
- let parentCategory: Category
-
- beforeEach(() => {
- parentCategory = {
- 'path': '1/2',
- 'is_active': true,
- 'level': 1,
- 'product_count': 1181,
- 'children_count': '38',
- 'parent_id': 1,
- 'name': 'All',
- 'id': 2,
- 'url_key': 'all-2',
- 'children_data': [],
- 'url_path': 'all-2',
- 'slug': 'all-2'
- }
- })
-
- it('should return empty array when no category provided', () => {
- const result = _prepareCategoryPathIds(null)
- expect(result).toBeDefined()
- expect(result.length).toEqual(0)
- });
-
- it('should return an array from category path', () => {
- const result = _prepareCategoryPathIds(parentCategory)
- expect(result).toBeDefined()
- expect(result).toEqual(['1', '2'])
- });
-
- it('should return array with single value', () => {
- parentCategory.path = '2'
- const result = _prepareCategoryPathIds(parentCategory)
- expect(result).toBeDefined()
- expect(result).toEqual(['2'])
- })
-
- it('should return array deep connection', () => {
- parentCategory.path = '1/2/20/21/252'
- const result = _prepareCategoryPathIds(parentCategory)
- expect(result).toBeDefined()
- expect(result).toEqual(['1', '2', '20', '21', '252'])
- })
-})
diff --git a/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts b/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts
deleted file mode 100644
index d0145e9329..0000000000
--- a/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { changeFilterQuery } from '@vue-storefront/core/modules/catalog-next/helpers/filterHelpers';
-import FilterVariant from '@vue-storefront/core/modules/catalog-next/types/FilterVariant';
-
-describe('changeFilterQuery method', () => {
- it('should not change query when no filter variant provided', () => {
- const currentQuery = {
- color: 1
- };
- const result = changeFilterQuery({ currentQuery });
- expect(result).toEqual(currentQuery);
- });
-
- it('should not return same query object instance', () => {
- const currentQuery = {
- color: 1
- };
- const result = changeFilterQuery({ currentQuery });
- expect(result).not.toBe(currentQuery);
- });
-
- it('should add filter to array', () => {
- const currentQuery = {};
- const filterVariant: FilterVariant = {
- id: '33',
- label: 'Red',
- type: 'color'
- };
- const result = changeFilterQuery({ currentQuery, filterVariant });
- expect(result).toEqual({ color: ['33'] });
- });
-
- it('should remove filter if exist in query', () => {
- const currentQuery = {
- color: ['23', '33']
- };
- const filterVariant: FilterVariant = {
- id: '33',
- label: 'Red',
- type: 'color'
- };
- const result = changeFilterQuery({ currentQuery, filterVariant });
- expect(result).toEqual({ color: ['23'] });
- });
-
- it('should add sort filter', () => {
- const currentQuery = {};
- const filterVariant: FilterVariant = {
- id: 'final_price',
- label: 'Price: Low to high',
- type: 'sort'
- };
- const result = changeFilterQuery({ currentQuery, filterVariant });
- expect(result).toEqual({ sort: 'final_price' });
- });
-
- it('should remove sort filter', () => {
- const currentQuery = { sort: 'final_price' };
- const filterVariant: FilterVariant = {
- id: 'final_price',
- label: 'Price: Low to high',
- type: 'sort'
- };
- const result = changeFilterQuery({ currentQuery, filterVariant });
- expect(result).toEqual({});
- });
-
- it('should change sort filter', () => {
- const currentQuery = { sort: 'final_price' };
- const filterVariant: FilterVariant = {
- id: 'updated_at',
- label: 'Latest',
- type: 'sort'
- };
- const result = changeFilterQuery({ currentQuery, filterVariant });
- expect(result).toEqual({ sort: 'updated_at' });
- });
-
- it('should add single filter when there is none', () => {
- const currentQuery = {
- };
- const filterVariant: FilterVariant = {
- id: '50.0-100.0',
- type: 'price',
- from: '50',
- to: '100',
- label: '$50 - 100',
- single: true
- };
- const result = changeFilterQuery({ currentQuery, filterVariant });
- expect(result).toEqual({ price: ['50.0-100.0'] });
- });
-
- it('should remove single filter when adding is the same', () => {
- const currentQuery = {
- price: ['50.0-100.0']
- };
- const filterVariant: FilterVariant = {
- id: '50.0-100.0',
- type: 'price',
- from: '50',
- to: '100',
- label: '$50 - 100',
- single: true
- };
- const result = changeFilterQuery({ currentQuery, filterVariant });
- expect(result).toEqual({});
- });
-
- it('should change single filter when adding another single', () => {
- const currentQuery = {
- price: ['100.0-150.0']
- };
- const filterVariant: FilterVariant = {
- id: '50.0-100.0',
- type: 'price',
- from: '50',
- to: '100',
- label: '$50 - 100',
- single: true
- };
- const result = changeFilterQuery({ currentQuery, filterVariant });
- expect(result).toEqual({ price: ['50.0-100.0'] });
- });
-});
diff --git a/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts b/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts
deleted file mode 100644
index 6f0b607a9c..0000000000
--- a/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import { getFiltersFromQuery } from '../../helpers/filterHelpers';
-
-describe('getFiltersFromQuery method', () => {
- let availableFilters
- beforeEach(() => {
- availableFilters = {
- 'color': [
- {
- 'id': '49',
- 'label': 'Black',
- 'type': 'color'
- },
- {
- 'id': '50',
- 'label': 'Blue',
- 'type': 'color'
- }
- ],
- 'size': [
- {
- 'id': '172',
- 'label': '28',
- 'type': 'size'
- },
- {
- 'id': '170',
- 'label': 'L',
- 'type': 'size'
- },
- {
- 'id': '169',
- 'label': 'M',
- 'type': 'size'
- }
- ],
- 'price': [
- {
- 'id': '0.0-50.0',
- 'type': 'price',
- 'from': 0,
- 'to': 50,
- 'label': '< $50'
- },
- {
- 'id': '50.0-100.0',
- 'type': 'price',
- 'from': 50,
- 'to': 100,
- 'label': '$50 - 100'
- },
- {
- 'id': '150.0-*',
- 'type': 'price',
- 'from': 150,
- 'label': '> $150'
- }
- ],
- 'erin_recommends': [
- {
- 'id': '0',
- 'label': 'No',
- 'type': 'erin_recommends'
- },
- {
- 'id': '1',
- 'label': 'Yes',
- 'type': 'erin_recommends'
- }
- ],
- 'sort': [
- {
- 'label': 'Latest',
- 'id': 'updated_at',
- 'type': 'sort'
- },
- {
- 'label': 'Price: Low to high',
- 'id': 'final_price',
- 'type': 'sort'
- },
- {
- 'label': 'Price: High to low',
- 'id': 'final_price:desc',
- 'type': 'sort'
- }
- ]
- }
- });
-
- it('should return color filter', () => {
- const filtersQuery = {
- color: '49'
- }
- const result = getFiltersFromQuery({ availableFilters, filtersQuery })
- expect(result).toEqual({
- filters: {
- color: [
- {
- 'id': '49',
- 'label': 'Black',
- 'type': 'color',
- 'attribute_code': 'color'
- }
- ]
- }
- })
- });
-
- it('should return color filters', () => {
- const filtersQuery = {
- color: ['49', '50']
- }
- const result = getFiltersFromQuery({ availableFilters, filtersQuery })
- expect(result).toEqual({
- filters: {
- color: [
- {
- 'id': '49',
- 'label': 'Black',
- 'type': 'color',
- 'attribute_code': 'color'
- },
- {
- 'id': '50',
- 'label': 'Blue',
- 'type': 'color',
- 'attribute_code': 'color'
- }
- ]
- }
- })
- });
-
- it('should not return not existing filter', () => {
- const filtersQuery = {
- color: '111'
- }
- const result = getFiltersFromQuery({ availableFilters, filtersQuery })
- expect(result).toEqual({
- filters: {}
- })
- });
-
- it('should return size filter', () => {
- const filtersQuery = {
- sort: 'updated_at'
- }
- const result = getFiltersFromQuery({ availableFilters, filtersQuery })
- expect(result).toEqual({
- filters: {},
- sort: 'updated_at'
- })
- });
-});
diff --git a/core/modules/catalog-next/test/unit/prefetchStockItems.spec.ts b/core/modules/catalog-next/test/unit/prefetchStockItems.spec.ts
deleted file mode 100644
index 12b2ed2b66..0000000000
--- a/core/modules/catalog-next/test/unit/prefetchStockItems.spec.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { prefetchStockItems } from '../../helpers/cacheProductsHelper';
-import config from 'config';
-
-describe('prefetchStockItems method', () => {
- describe('default configurableChildrenStockPrefetchStaticPrefetchCount', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- jest.mock('config', () => ({}));
- })
-
- it('returns an empty array when no items are provided', () => {
- const cachedProductsResponse = {
- items: []
- }
- const result = prefetchStockItems(cachedProductsResponse)
- expect(result).toEqual([]);
- })
-
- it('returns the skus of the children of a configurable', () => {
- const cachedProductsResponse = {
- items: [
- { sku: 'foo' },
- {
- sku: 'bar',
- type_id: 'configurable',
- configurable_children: [
- { sku: 'bar.foo' },
- { sku: 'bar.bar' },
- { sku: 'bar.baz' }
- ]
- },
- { sku: 'baz' }
- ]
- }
- const result = prefetchStockItems(cachedProductsResponse)
- expect(result).toEqual(['foo', 'bar', 'bar.foo', 'bar.bar', 'bar.baz', 'baz']);
- })
-
- it('returns the same skus of the provided simple products', () => {
- const cachedProductsResponse = {
- items: [
- { sku: 'foo' },
- { sku: 'bar' },
- { sku: 'baz' }
- ]
- }
- const result = prefetchStockItems(cachedProductsResponse)
- expect(result).toEqual(['foo', 'bar', 'baz']);
- })
-
- it('ignores the pre-cached skus of children of a configurable', () => {
- const cachedProductsResponse = {
- items: [
- { sku: 'foo' },
- {
- sku: 'bar',
- type_id: 'configurable',
- configurable_children: [
- { sku: 'bar.foo', id: 1337 },
- { sku: 'bar.bar' },
- { sku: 'bar.baz', id: 4711 }
- ]
- },
- { sku: 'baz' }
- ]
- }
- const result = prefetchStockItems(cachedProductsResponse, { 1337: {}, 4711: {} })
- expect(result).toEqual(['foo', 'bar', 'bar.bar', 'baz']);
- })
- })
-})
diff --git a/core/modules/catalog-next/types/Category.d.ts b/core/modules/catalog-next/types/Category.d.ts
deleted file mode 100644
index a5bc993eb7..0000000000
--- a/core/modules/catalog-next/types/Category.d.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import FilterVariant from './FilterVariant'
-
-export interface ChildrenData {
- id: number | string,
- children_data?: ChildrenData[],
- name?: string,
- slug?: string,
- url_key?: string
-}
-
-export interface Category {
- path: string,
- is_active: boolean,
- level: number,
- product_count: number,
- children_count: string,
- parent_id: number | string,
- name: string,
- id: number | string,
- url_path: string,
- url_key: string,
- children_data: ChildrenData[],
- slug: string,
- position?: number
-}
-
-export interface Filters {
- [key: string]: FilterVariant[]
-}
diff --git a/core/modules/catalog-next/types/FilterVariant.ts b/core/modules/catalog-next/types/FilterVariant.ts
deleted file mode 100644
index 8f8f2d8d75..0000000000
--- a/core/modules/catalog-next/types/FilterVariant.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export default interface FilterVariant {
- id: string,
- label: string,
- type: string,
- from?: string,
- to?: string,
- single?: boolean
-}
diff --git a/core/modules/catalog/components/CategoryFilters.ts b/core/modules/catalog/components/CategoryFilters.ts
deleted file mode 100644
index 75b9baf952..0000000000
--- a/core/modules/catalog/components/CategoryFilters.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { buildFilterProductsQuery } from '@vue-storefront/core/helpers'
-import { mapGetters } from 'vuex';
-
-export default {
- name: 'CategoryFilters',
- computed: {
- ...mapGetters('category', ['getActiveCategoryFilters', 'getCurrentCategoryProductQuery', 'getAllCategoryFilters']),
- filters () {
- return this.getAllCategoryFilters
- },
- activeFilters () {
- return this.getActiveCategoryFilters
- }
- },
- methods: {
- /** used to sort filters descending by id */
- sortById (filters) {
- return [...filters].sort((a, b) => { return a.id - b.id })
- },
- resetAllFilters () {
- // todo: get rid of this one
- this.$bus.$emit('filter-reset')
- this.$store.dispatch('category/resetFilters')
- this.$store.dispatch('category/searchProductQuery', {})
- this.$store.dispatch('category/mergeSearchOptions', {
- searchProductQuery: buildFilterProductsQuery(this.category, this.activeFilters)
- })
- this.$store.dispatch('category/products', this.getCurrentCategoryProductQuery)
- }
- }
-}
diff --git a/core/modules/catalog/components/CategorySort.ts b/core/modules/catalog/components/CategorySort.ts
deleted file mode 100644
index 10214890ef..0000000000
--- a/core/modules/catalog/components/CategorySort.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import config from 'config'
-import { mapGetters } from 'vuex'
-export const CategorySort = {
- name: 'SortBy',
- data () {
- return {
- sortby: ''
- }
- },
- mounted () {
- const sort = this.getCurrentCategoryProductQuery && this.getCurrentCategoryProductQuery.sort ? this.getCurrentCategoryProductQuery.sort : null
- if (sort) {
- const sortingOptionValues = Object.values(this.sortingOptions)
- const sortOptionExist = sortingOptionValues.includes(sort)
- if (sortOptionExist) {
- this.sortby = sort
- }
- }
- },
- methods: {
- // emit to category, todo: move all logic inside
- sort () {
- this.$emit('change', this.sortby)
- // this.$bus.$emit('list-change-sort', { attribute: this.sortby })
- }
- },
- computed: {
- ...mapGetters('category', ['getCurrentCategoryProductQuery']),
- sortingOptions () {
- return config.products.sortByAttributes
- },
- sortingVariants () {
- let variants = []
- Object.keys(this.sortingOptions).map(label => {
- variants.push({
- label: label,
- id: this.sortingOptions[label],
- type: 'sort'
- })
- })
- return variants
- }
- }
-}
diff --git a/core/modules/catalog/components/ProductAttribute.ts b/core/modules/catalog/components/ProductAttribute.ts
deleted file mode 100644
index c0a855ecdd..0000000000
--- a/core/modules/catalog/components/ProductAttribute.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-export const ProductAttribute = {
- name: 'ProductAttribute',
- props: {
- product: {
- type: Object,
- required: true
- },
- attribute: {
- type: null,
- required: true
- },
- emptyPlaceholder: {
- type: String,
- default: ''
- }
- },
- computed: {
- label () {
- return (this.attribute && this.attribute.frontend_label) ? this.attribute.frontend_label : ((this.attribute && this.attribute.default_frontend_label) ? this.attribute.default_frontend_label : '')
- },
- value () {
- let parsedValues = this.product[this.attribute.attribute_code]
-
- if (!parsedValues) {
- return this.emptyPlaceholder
- } else if (this.attribute.frontend_input !== 'multiselect' && this.attribute.frontend_input !== 'select') {
- return parsedValues.toString()
- } else {
- parsedValues = typeof parsedValues === 'string' ? parsedValues.split(',') : parsedValues
-
- if (!Array.isArray(parsedValues)) {
- parsedValues = [parsedValues]
- }
-
- let results = []
- for (let parsedVal of parsedValues) {
- if (this.attribute.options) {
- let option = this.attribute.options.find(av => {
- /* eslint eqeqeq: "off" */
- return av.value == parsedVal
- })
- if (option) {
- results.push(option.label)
- } else {
- results.push(parsedVal)
- }
- } else {
- results.push(parsedVal)
- }
- }
- return results.join(', ')
- }
- }
- }
-}
diff --git a/core/modules/catalog/components/ProductBundleOption.ts b/core/modules/catalog/components/ProductBundleOption.ts
deleted file mode 100644
index d902cbead3..0000000000
--- a/core/modules/catalog/components/ProductBundleOption.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import config from 'config'
-
-export const ProductBundleOption = {
- name: 'ProductBundleOption',
- props: {
- option: {
- type: Object,
- required: true
- },
- errorMessages: {
- type: Object,
- default: null
- }
- },
- data () {
- return {
- productOptionId: null,
- quantity: 1
- }
- },
- computed: {
- productBundleOption () {
- return `bundleOption_${this.option.option_id}`
- },
- bundleOptionName () {
- return `bundleOption_${this._uid}_${this.option.option_id}_`
- },
- quantityName () {
- return `bundleOptionQty_${this.option.option_id}`
- },
- value () {
- const { product_links } = this.option
- if (Array.isArray(product_links)) {
- return product_links.find(product => product.id === this.productOptionId)
- }
- return product_links
- },
- errorMessage () {
- return this.errorMessages ? this.errorMessages[this.quantityName] : ''
- }
- },
- mounted () {
- this.setDefaultValues()
- if (config.usePriceTiers) {
- this.$bus.$on('product-after-setup-associated', this.setDefaultValues)
- }
- },
- beforeDestroy () {
- if (config.usePriceTiers) {
- this.$bus.$off('product-after-setup-associated', this.setDefaultValues)
- }
- },
- watch: {
- productOptionId (value) {
- this.bundleOptionChanged()
- },
- quantity (value) {
- this.bundleOptionChanged()
- }
- },
- methods: {
- setDefaultValues () {
- const { product_links } = this.option
-
- if (product_links) {
- const defaultOption = Array.isArray(product_links)
- ? product_links.find(pl => pl.is_default)
- : product_links
-
- this.productOptionId = defaultOption ? defaultOption.id : product_links[0].id
- this.quantity = defaultOption ? defaultOption.qty : 1
- }
- },
- bundleOptionChanged () {
- this.$emit('option-changed', {
- option: this.option,
- fieldName: this.productBundleOption,
- qty: this.quantity,
- value: this.value
- })
- }
- }
-}
diff --git a/core/modules/catalog/components/ProductBundleOptions.ts b/core/modules/catalog/components/ProductBundleOptions.ts
deleted file mode 100644
index 240a3a1ecb..0000000000
--- a/core/modules/catalog/components/ProductBundleOptions.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import { mapMutations } from 'vuex'
-import * as types from '../store/product/mutation-types'
-import rootStore from '@vue-storefront/core/store'
-import i18n from '@vue-storefront/i18n'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-function _fieldName (co) {
- return ['bundleOption_' + co.option_id, 'bundleOptionQty_' + co.option_id]
-}
-
-export const ProductBundleOptions = {
- name: 'ProductBundleOptions',
- props: {
- product: {
- type: Object,
- required: true
- }
- },
- data () {
- return {
- selectedOptions: {},
- validationRules: {},
- validationResults: {}
- }
- },
- computed: {
- /**
- * Error messages map for validation options
- */
- errorMessages () {
- let messages = {}
- Object.keys(this.validationResults).map(optionKey => {
- const validationResult = this.validationResults[optionKey]
- if (validationResult.error) {
- messages[optionKey] = validationResult.message
- }
- })
- return messages
- }
- },
- beforeMount () {
- this.setupValidationRules()
- },
- methods: {
- ...mapMutations('product', {
- setBundleOptionValue: types.PRODUCT_SET_BUNDLE_OPTION // map `this.add()` to `this.$store.commit('increment')`
- }),
- setupValidationRules () {
- rootStore.dispatch('product/addCustomOptionValidator', {
- validationRule: 'gtzero', // You may add your own custom fields validators elsewhere in the theme
- validatorFunction: (value) => {
- return { error: (value === null || value === '') || (value === false) || (value <= 0), message: i18n.t('Must be greater than 0') }
- }
- })
-
- for (let co of this.product.bundle_options) {
- for (let fieldName of _fieldName(co)) {
- if (co.required) { // validation rules are very basic
- this.validationRules[fieldName] = 'gtzero' // TODO: add custom validators for the custom options
- }
- }
- }
- },
- optionChanged ({ fieldName, option, qty, value }) {
- if (!fieldName) return
- this.setBundleOptionValue({ optionId: option.option_id, optionQty: parseInt(qty), optionSelections: [parseInt(value.id)] })
- this.$store.dispatch('product/setBundleOptions', { product: this.product, bundleOptions: this.$store.state.product.current_bundle_options }) // TODO: move it to "AddToCart"
- this.selectedOptions[fieldName] = { qty, value }
- const valueId = value ? value.id : null
- if (this.validateField(option, qty, valueId)) {
- this.$bus.$emit('product-after-bundleoptions', { product: this.product, option: option, optionValues: this.selectedOptions })
- }
- },
- isValid () {
- let isValid = true
- this.validationResults.map((res) => { if (res.error) isValid = false })
- return isValid
- },
- validateField (option, qty, optionId) {
- let result = true
- let validationResult = { error: false, message: '' }
- for (let fieldName of _fieldName(option)) {
- const validationRule = this.validationRules[fieldName]
- this.product.errors.custom_options = null
- if (validationRule) {
- const validator = this.$store.state.product.custom_options_validators[validationRule]
- if (typeof validator === 'function') {
- const quantityValidationResult = validator(qty)
- if (quantityValidationResult.error) validationResult = quantityValidationResult
- const optionValidationResult = validator(optionId)
- if (optionValidationResult.error) validationResult = optionValidationResult
- this.$set(this.validationResults, fieldName, validationResult)
- if (validationResult.error) {
- this.product.errors['bundle_options_' + fieldName] = i18n.t('Please configure product bundle options and fix the validation errors')
- result = false
- } else {
- this.product.errors['bundle_options_' + fieldName] = null
- }
- } else {
- Logger.error('No validation rule found for ' + validationRule, 'components-product-bundle-options')()
- this.$set(this.validationResults, fieldName, validationResult)
- }
- } else {
- this.$set(this.validationResults, fieldName, validationResult)
- }
- }
- return result
- }
- }
-}
diff --git a/core/modules/catalog/components/ProductCustomOption.ts b/core/modules/catalog/components/ProductCustomOption.ts
deleted file mode 100644
index e3752ecb13..0000000000
--- a/core/modules/catalog/components/ProductCustomOption.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-export const ProductCustomOption = {
- name: 'ProductCustomOption',
- props: {
- label: {
- type: String,
- required: false,
- default: ''
- },
- id: {
- type: null,
- required: false,
- default: () => false
- },
- code: {
- type: null,
- required: false,
- default: () => false
- },
- context: {
- type: null,
- required: false,
- default: () => false
- }
- },
- data () {
- return {
- active: false
- }
- },
- beforeMount () {
- this.$bus.$on('filter-reset', this.filterReset)
- this.$bus.$on('filter-changed-' + this.context, this.filterChanged)
- },
- beforeDestroy () {
- this.$bus.$off('filter-reset', this.filterReset)
- this.$bus.$off('filter-changed-' + this.context, this.filterChanged)
- },
- methods: {
- filterChanged (filterOption) {
- if (filterOption.attribute_code === this.code) {
- this.active = filterOption.id === this.id ? !this.active : false
- }
- },
- filterReset (filterOption) {
- this.active = false
- },
- switchFilter (id, label) {
- this.$bus.$emit('filter-changed-' + this.context, { attribute_code: this.code, id: id, label: label })
- }
- }
-}
diff --git a/core/modules/catalog/components/ProductCustomOptions.ts b/core/modules/catalog/components/ProductCustomOptions.ts
deleted file mode 100644
index 412e06fcb2..0000000000
--- a/core/modules/catalog/components/ProductCustomOptions.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import { customOptionFieldName, selectedCustomOptionValue, defaultCustomOptionValue } from '@vue-storefront/core/modules/catalog/helpers/customOption';
-import { mapMutations } from 'vuex'
-import * as types from '../store/product/mutation-types'
-import rootStore from '@vue-storefront/core/store'
-import i18n from '@vue-storefront/i18n'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-export const ProductCustomOptions = {
- name: 'ProductCustomOptions',
- props: {
- product: {
- type: Object,
- required: true
- }
- },
- data () {
- return {
- inputValues: {},
- validation: {
- rules: {},
- results: {}
- }
- }
- },
- computed: {
- selectedOptions () {
- const customOptions = this.product.custom_options
- if (!customOptions) {
- return {}
- }
-
- return customOptions.reduce((selectedOptions, option) => {
- const fieldName = customOptionFieldName(option)
- selectedOptions[fieldName] = selectedCustomOptionValue(option.type, option.values, this.inputValues[fieldName])
- return selectedOptions
- }, {})
- }
- },
- created () {
- rootStore.dispatch('product/addCustomOptionValidator', {
- validationRule: 'required', // You may add your own custom fields validators elsewhere in the theme
- validatorFunction: (value) => {
- const error = Array.isArray(value) ? !value.length : !value
- const message = i18n.t('Field is required.')
- return { error, message }
- }
- })
- this.setupInputFields()
- },
- methods: {
- ...mapMutations('product', {
- setCustomOptionValue: types.PRODUCT_SET_CUSTOM_OPTION // map `this.add()` to `this.$store.commit('increment')`
- }),
- setupInputFields () {
- for (const customOption of this.product.custom_options) {
- const fieldName = customOptionFieldName(customOption)
- this.$set(this.inputValues, fieldName, defaultCustomOptionValue(customOption))
- if (customOption.is_require) { // validation rules are very basic
- this.$set(this.validation.rules, fieldName, 'required') // TODO: add custom validators for the custom options
- }
- this.optionChanged(customOption)
- }
- },
- optionChanged (option) {
- const fieldName = customOptionFieldName(option)
- this.validateField(option)
- this.setCustomOptionValue({ optionId: option.option_id, optionValue: this.selectedOptions[fieldName] })
- this.$store.dispatch('product/setCustomOptions', { product: this.product, customOptions: this.$store.state.product.current_custom_options }) // TODO: move it to "AddToCart"
- this.$bus.$emit('product-after-customoptions', { product: this.product, option: option, optionValues: this.selectedOptions })
- },
- validateField (option) {
- const fieldName = customOptionFieldName(option)
- const validationRule = this.validation.rules[fieldName]
- this.product.errors.custom_options = null
- if (validationRule) {
- const validator = this.$store.state.product.custom_options_validators[validationRule]
- if (typeof validator === 'function') {
- const validationResult = validator(this['inputValues'][fieldName])
- this.validation.results[fieldName] = validationResult
- if (validationResult.error) {
- this.product.errors['custom_options_' + fieldName] = i18n.t('Please configure product custom options and fix the validation errors')
- } else {
- this.product.errors['custom_options_' + fieldName] = null
- }
- } else {
- Logger.error('No validation rule found for ' + validationRule, 'components-product-custom-options')()
- this.validation.results[fieldName] = { error: false, message: '' }
- }
- } else {
- this.validation.results[fieldName] = { error: false, message: '' }
- }
- },
- isValid () {
- let isValid = true
- this.validation.results.map((res) => { if (res.error) isValid = false })
- return isValid
- }
- }
-}
diff --git a/core/modules/catalog/components/ProductGallery.ts b/core/modules/catalog/components/ProductGallery.ts
deleted file mode 100644
index dc85cfcb6e..0000000000
--- a/core/modules/catalog/components/ProductGallery.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import VueOffline from 'vue-offline'
-
-export const ProductGallery = {
- name: 'ProductGallery',
- components: {
- VueOffline
- },
- props: {
- gallery: {
- type: Array,
- required: true
- },
- configuration: {
- type: Object,
- required: true
- },
- offline: {
- type: Object,
- required: false
- },
- product: {
- type: Object,
- required: true
- }
- },
- computed: {
- }
-}
diff --git a/core/modules/catalog/components/ProductOption.ts b/core/modules/catalog/components/ProductOption.ts
deleted file mode 100644
index 4aa4c44523..0000000000
--- a/core/modules/catalog/components/ProductOption.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { isOptionAvailableAsync } from '@vue-storefront/core/modules/catalog/helpers/index'
-import { getAvailableFiltersByProduct, getSelectedFiltersByProduct } from '@vue-storefront/core/modules/catalog/helpers/filters'
-
-export const ProductOption = {
- computed: {
- getAvailableFilters () {
- return getAvailableFiltersByProduct(this.product)
- },
- getSelectedFilters () {
- return getSelectedFiltersByProduct(this.product, this.configuration)
- }
- },
- methods: {
- isOptionAvailable (option) { // check if the option is available
- let currentConfig = Object.assign({}, this.configuration)
- currentConfig[option.type] = option
- return isOptionAvailableAsync(this.$store, { product: this.product, configuration: currentConfig })
- }
- }
-}
diff --git a/core/modules/catalog/components/ProductTile.ts b/core/modules/catalog/components/ProductTile.ts
deleted file mode 100644
index 8dcdad0356..0000000000
--- a/core/modules/catalog/components/ProductTile.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { productThumbnailPath } from '@vue-storefront/core/helpers'
-import { currentStoreView } from '@vue-storefront/core/lib/multistore'
-import { formatProductLink } from '@vue-storefront/core/modules/url/helpers'
-import config from 'config'
-
-export const ProductTile = {
- name: 'ProductTile',
- props: {
- product: {
- type: Object,
- required: true
- }
- },
- data () {
- return {
- clicks: 0,
- placeholder: '/assets/placeholder.jpg'
- }
- },
- computed: {
- productLink () {
- return formatProductLink(this.product, currentStoreView().storeCode)
- },
- thumbnail () {
- // todo: play with the image based on category page filters - eg. when 'red' color is chosen, the image is going to be 'red'
- let thumbnail = productThumbnailPath(this.product)
- return this.getThumbnail(thumbnail, config.products.thumbnails.width, config.products.thumbnails.height)
- },
- thumbnailObj () {
- return {
- src: this.thumbnail,
- loading: this.placeholder,
- error: this.placeholder
- }
- },
- isOnSale () {
- return [true, '1'].includes(this.product.sale) ? 'sale' : ''
- },
- isNew () {
- return [true, '1'].includes(this.product.new) ? 'new' : ''
- }
- }
-}
diff --git a/core/modules/catalog/components/ProductVideo.ts b/core/modules/catalog/components/ProductVideo.ts
deleted file mode 100644
index 9c66809bfb..0000000000
--- a/core/modules/catalog/components/ProductVideo.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-export const ProductVideo = {
- name: 'ProductVideo',
- props: {
- url: {
- type: String,
- required: true
- },
- id: {
- type: String,
- required: true
- },
- type: {
- type: String,
- required: true
- },
- index: {
- type: Number,
- required: false,
- default: 0
- }
- },
- data () {
- return {
- videoStarted: false,
- iframeLoaded: false
- }
- },
- methods: {
- initVideo () {
- this.videoStarted = true
- this.$emit('video-started', this.index)
- },
- iframeIsLoaded () {
- this.iframeLoaded = true
- }
- },
- computed: {
- embedUrl () {
- switch (this.type) {
- case 'youtube':
- return `https://www.youtube.com/embed/${this.id}?autoplay=1`
- case 'vimeo':
- return `https://player.vimeo.com/video/${this.id}?autoplay=1`
- default:
- }
- }
- }
-}
diff --git a/core/modules/catalog/components/Search.ts b/core/modules/catalog/components/Search.ts
deleted file mode 100644
index f22343331a..0000000000
--- a/core/modules/catalog/components/Search.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-import { mapState } from 'vuex'
-import i18n from '@vue-storefront/i18n'
-import onEscapePress from '@vue-storefront/core/mixins/onEscapePress'
-import { prepareQuickSearchQuery } from '@vue-storefront/core/modules/catalog/queries/searchPanel'
-import RootState from '@vue-storefront/core/types/RootState'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-export const Search = {
- name: 'SearchPanel',
- data () {
- return {
- products: [],
- search: '',
- size: 18,
- start: 0,
- placeholder: i18n.t('Type what you are looking for...'),
- emptyResults: false,
- readMore: true,
- componentLoaded: false
- }
- },
- mounted () {
- this.search = localStorage.getItem(`shop/user/searchQuery`) || ''
-
- if (this.search) {
- this.makeSearch();
- }
- },
- beforeDestroy () {
- localStorage.setItem(`shop/user/searchQuery`, this.search ? this.search : '');
- },
- methods: {
- onEscapePress () {
- this.closeSearchpanel()
- },
- closeSearchpanel () {
- this.$store.commit('ui/setSidebar', false)
- this.$store.commit('ui/setMicrocart', false)
- this.$store.commit('ui/setSearchpanel', false)
- },
- buildSearchQuery (queryText) {
- let searchQuery = prepareQuickSearchQuery(queryText)
- return searchQuery
- },
- async makeSearch () {
- if (this.search !== '' && this.search !== undefined) {
- let query = this.buildSearchQuery(this.search)
- let startValue = 0;
- this.start = startValue
- this.readMore = true
- try {
- const { items } = await this.$store.dispatch('product/findProducts', {
- query,
- start: this.start,
- size: this.size,
- options: {
- populateRequestCacheTags: false,
- prefetchGroupProducts: false
- }
- })
- this.products = items
- this.start = startValue + this.size
- this.emptyResults = items.length < 1
- } catch (err) {
- Logger.error(err, 'components-search')()
- }
- } else {
- this.products = []
- this.emptyResults = 0
- }
- },
- async seeMore () {
- if (this.search !== '' && this.search !== undefined) {
- let query = this.buildSearchQuery(this.search)
- let startValue = this.start;
- try {
- const { items, total, start } = await this.$store.dispatch('product/findProducts', {
- query,
- start: startValue,
- size: this.size,
- options: {
- populateRequestCacheTags: false,
- prefetchGroupProducts: false
- }
- })
- let page = Math.floor(total / this.size)
- let exceeed = total - this.size * page
- if (start === total - exceeed) {
- this.readMore = false
- }
- this.products = this.products.concat(items)
- this.start = startValue + this.size
- this.emptyResults = this.products.length < 1
- } catch (err) {
- Logger.error(err, 'components-search')()
- }
- } else {
- this.products = []
- this.emptyResults = 0
- }
- }
- },
- computed: {
- items () {
- return this.$store.state.search
- },
- ...mapState({
- isOpen: (state: RootState) => state.ui.searchpanel
- })
- },
- mixins: [onEscapePress]
-}
diff --git a/core/modules/catalog/events.ts b/core/modules/catalog/events.ts
deleted file mode 100644
index 8c63658bf6..0000000000
--- a/core/modules/catalog/events.ts
+++ /dev/null
@@ -1,160 +0,0 @@
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { PRODUCT_SET_CURRENT } from './store/product/mutation-types'
-import omit from 'lodash-es/omit'
-import config from 'config'
-import i18n from '@vue-storefront/core/i18n';
-import { SearchQuery } from 'storefront-query-builder'
-import { AsyncDataLoader } from '@vue-storefront/core/lib/async-data-loader';
-import { currentStoreView } from '@vue-storefront/core/lib/multistore';
-import { formatProductLink } from '@vue-storefront/core/modules/url/helpers';
-import { Logger } from '@vue-storefront/core/lib/logger';
-import { isServer } from '@vue-storefront/core/helpers';
-import { router } from '@vue-storefront/core/app'
-
-// Listeners moved from Product.js
-
-const prefixMutation = (mutationKey) => `product/${mutationKey}`
-
-export const productAfterPriceupdate = async (product, store) => {
- if (store.getters['product/getCurrentProduct'] && product.sku === store.getters['product/getCurrentProduct'].sku) {
- // join selected variant object to the store
- await store.dispatch('product/setCurrent', omit(product, ['name']))
- }
-}
-
-export const filterChangedProduct = async (filterOption, store, router) => {
- EventBus.$emit('product-before-configure', { filterOption: filterOption, configuration: store.getters['product/getCurrentProductConfiguration'] })
- const currentProductConfiguration = store.getters['product/getCurrentProductConfiguration']
- const changedConfig = Object.assign({}, currentProductConfiguration, { [filterOption.attribute_code]: filterOption })
- let searchQuery = new SearchQuery()
- searchQuery = searchQuery.applyFilter({ key: 'sku', value: { 'eq': store.getters['product/getCurrentProduct'].parentSku } })
- const { items: [newProductVariant] } = await store.dispatch('product/findProducts', {
- query: searchQuery,
- size: 1,
- configuration: changedConfig,
- options: {
- fallbackToDefaultWhenNoAvailable: false,
- setProductErrors: true,
- assignProductConfiguration: true,
- separateSelectedVariant: true
- }
- }, { root: true })
- const { configuration, selectedVariant, options, product_option } = newProductVariant
- const routeProp = config.seo.useUrlDispatcher ? 'query' : 'params';
-
- if (config.products.setFirstVarianAsDefaultInURL && selectedVariant) {
- router.push({ [routeProp]: { childSku: selectedVariant.sku } })
- }
- if (selectedVariant) {
- const newProductConfiguration = Object.assign(
- {},
- store.getters['product/getCurrentProduct'],
- selectedVariant,
- { configuration, options, product_option }
- )
- await store.dispatch('product/setCurrent', newProductConfiguration)
- EventBus.$emit('product-after-configure', { product: newProductConfiguration, configuration: configuration, selectedVariant: selectedVariant })
-
- if (router?.currentRoute?.[routeProp]?.childSku) {
- router.push(
- {
- [routeProp]: {
- ...router.currentRoute[routeProp],
- childSku: selectedVariant.sku
- }
- }
- )
- }
- return selectedVariant
- } else {
- store.dispatch('notification/spawnNotification', {
- type: 'warning',
- message: i18n.t(
- 'No such configuration for the product. Please do choose another combination of attributes.'
- ),
- action1: { label: i18n.t('OK') }
- })
- }
-}
-
-export const productAfterCustomoptions = async (payload, store) => {
- let priceDelta = 0
- let priceDeltaInclTax = 0
- const optionValues: any[] = Object.values(payload.optionValues)
- optionValues.forEach(optionValue => {
- if (optionValue && parseInt(optionValue.option_type_id) > 0) {
- if (optionValue.price_type === 'fixed' && optionValue.price !== 0) {
- priceDelta += optionValue.price
- priceDeltaInclTax += optionValue.price
- }
- if (optionValue.price_type === 'percent' && optionValue.price !== 0) {
- priceDelta += ((optionValue.price / 100) * store.getters['product/getCurrentProduct'].price)
- priceDeltaInclTax += ((optionValue.price / 100) * store.getters['product/getCurrentProduct'].price_incl_tax)
- }
- }
- })
-
- store.commit(prefixMutation(PRODUCT_SET_CURRENT), Object.assign(
- {},
- store.getters['product/getCurrentProduct'],
- {
- price: store.getters['product/getCurrentProduct'].price + priceDelta,
- price_incl_tax: store.getters['product/getCurrentProduct'].price_incl_tax + priceDeltaInclTax
- }
- ), { root: true })
-}
-
-export const productAfterBundleoptions = async (payload, store) => {
- let priceDelta = 0
- let priceDeltaInclTax = 0
- const optionValues: any[] = Object.values(payload.optionValues)
- optionValues.forEach(optionValue => {
- if (optionValue && optionValue.value && optionValue.product && parseInt(optionValue.qty) >= 0) {
- priceDelta += optionValue.value.product.price * parseInt(optionValue.qty)
- priceDeltaInclTax += optionValue.value.product.price_incl_tax * parseInt(optionValue.qty)
- }
- })
- if (priceDelta > 0) {
- store.commit(prefixMutation(PRODUCT_SET_CURRENT), Object.assign(
- {},
- store.getters['product/getCurrentProduct'],
- {
- price: priceDelta,
- price_incl_tax: priceDeltaInclTax
- }
- ), { root: true })
- }
-}
-
-export const onUserPricesRefreshed = async (store, router) => {
- if (router.currentRoute.params.parentSku) {
- await store.dispatch('product/reset', {}, { root: true })
- await store.dispatch('product/single', {
- options: {
- sku: router.currentRoute.params.parentSku,
- childSku: router && router.currentRoute.params && router.currentRoute.params.childSku ? router.currentRoute.params.childSku : null
- },
- skipCache: true
- }, { root: true })
- }
-}
-
-export const checkParentRedirection = (currentProduct, parentProduct) => {
- if (parentProduct && parentProduct.id !== currentProduct.id && config.products.preventConfigurableChildrenDirectAccess) {
- Logger.log('Redirecting to parent, configurable product', parentProduct.sku)()
- parentProduct.parentSku = parentProduct.sku
- parentProduct.sku = currentProduct.sku
- const parentUrl = formatProductLink(parentProduct, currentStoreView().storeCode)
- if (isServer) {
- AsyncDataLoader.push({
- execute: async ({ context }) => {
- if (context && !context.url.includes(parentUrl)) {
- context.server.response.redirect(301, parentUrl)
- }
- }
- })
- } else {
- router.replace(parentUrl as string)
- }
- }
-}
diff --git a/core/modules/catalog/helpers/associatedProducts/buildQuery.ts b/core/modules/catalog/helpers/associatedProducts/buildQuery.ts
deleted file mode 100644
index 5a409f6553..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/buildQuery.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import config from 'config'
-import { SearchQuery } from 'storefront-query-builder'
-
-/**
- * Creates simple query that will search product by skus list
- */
-export default function buildQuery (skus: string[]): SearchQuery {
- let productsQuery = new SearchQuery()
- productsQuery = productsQuery
- .applyFilter({ key: 'sku', value: { 'in': skus } })
- .applyFilter({ key: 'status', value: { 'in': [1] } })
- if (config.products.listOutOfStockProducts === false) {
- productsQuery = productsQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } })
- }
- return productsQuery
-}
diff --git a/core/modules/catalog/helpers/associatedProducts/getAttributesFromMetadata.ts b/core/modules/catalog/helpers/associatedProducts/getAttributesFromMetadata.ts
deleted file mode 100644
index e44a424e12..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/getAttributesFromMetadata.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import config from 'config'
-import Product from '@vue-storefront/core/modules/catalog/types/Product'
-
-/**
- * Set associated attributes by meta data of product links
- */
-export default async function getAttributesFromMetadata (context: any, products: Product[]) {
- if (config.entities.attribute.loadByAttributeMetadata) {
- context.dispatch('attribute/loadProductAttributes', { products, merge: true }, { root: true })
- }
-}
diff --git a/core/modules/catalog/helpers/associatedProducts/getBundleProductPrice.ts b/core/modules/catalog/helpers/associatedProducts/getBundleProductPrice.ts
deleted file mode 100644
index 5ceb6b7386..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/getBundleProductPrice.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import {
- getBundleOptionsValues,
- getBundleOptionPrice,
- getSelectedBundleOptions
-} from '@vue-storefront/core/modules/catalog/helpers/bundleOptions'
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-export default function getBundleProductPrice (product: Product) {
- const selectedBundleOptions = getSelectedBundleOptions(product)
- const { price, priceInclTax } = getBundleOptionPrice(
- getBundleOptionsValues(selectedBundleOptions, product.bundle_options)
- )
-
- return { price, priceInclTax }
-}
diff --git a/core/modules/catalog/helpers/associatedProducts/getGroupedProductPrice.ts b/core/modules/catalog/helpers/associatedProducts/getGroupedProductPrice.ts
deleted file mode 100644
index ac50a373f3..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/getGroupedProductPrice.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import Product, { ProductLink } from '@vue-storefront/core/modules/catalog/types/Product';
-import { getProductLinkPrice } from './getProductLinkPrice';
-
-export default function getGroupedProductPrice (product: Product) {
- const productLinks: ProductLink[] = (product.product_links || [])
-
- return getProductLinkPrice(productLinks)
-}
diff --git a/core/modules/catalog/helpers/associatedProducts/getProductLinkPrice.ts b/core/modules/catalog/helpers/associatedProducts/getProductLinkPrice.ts
deleted file mode 100644
index 34339f6908..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/getProductLinkPrice.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-interface BaseProductLink {
- product?: Product,
- qty?: number
-}
-
-export const calculateProductLinkPrice = ({ price = 1, priceInclTax = 1, qty = 1 }) => {
- const product = {
- price: 0,
- priceInclTax: 0
- }
- const qtyNum = typeof qty === 'string' ? parseInt(qty) : qty
- if (qtyNum >= 0) {
- product.price += price * qtyNum
- product.priceInclTax += priceInclTax * qtyNum
- }
- return product
-}
-
-export const getProductLinkPrice = (productLinks: BaseProductLink[]) => productLinks
- .map((productLink) => {
- const product = productLink.product || { price: 1, price_incl_tax: 1, priceInclTax: 1 }
- return calculateProductLinkPrice({
- price: product.price,
- priceInclTax: product.price_incl_tax || product.priceInclTax,
- qty: productLink.qty
- })
- })
- .reduce(
- (priceDelta, currentPriceDelta) => ({
- price: currentPriceDelta.price + priceDelta.price,
- priceInclTax: currentPriceDelta.priceInclTax + priceDelta.priceInclTax
- }),
- { price: 0, priceInclTax: 0 }
- )
diff --git a/core/modules/catalog/helpers/associatedProducts/index.ts b/core/modules/catalog/helpers/associatedProducts/index.ts
deleted file mode 100644
index 5918ed1dfa..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import setGroupedProduct from './setGroupedProduct'
-import setBundleProducts from './setBundleProducts'
-import getAttributesFromMetadata from './getAttributesFromMetadata'
-
-export {
- setGroupedProduct,
- setBundleProducts,
- getAttributesFromMetadata
-}
diff --git a/core/modules/catalog/helpers/associatedProducts/setBundleProducts.ts b/core/modules/catalog/helpers/associatedProducts/setBundleProducts.ts
deleted file mode 100644
index aa836cf228..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/setBundleProducts.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import config from 'config'
-import Product from '@vue-storefront/core/modules/catalog/types/Product'
-import buildQuery from './buildQuery'
-import setProductLink from './setProductLink'
-import getBundleProductPrice from './getBundleProductPrice'
-import { isBundleProduct } from './..'
-import { ProductService } from '@vue-storefront/core/data-resolver/ProductService'
-import { catalogHooksExecutors } from './../../hooks'
-
-/**
- * This function prepare all product_links for bundle products.
- * It fetches products by sku.
- */
-export default async function setBundleProducts (product: Product, { includeFields = null, excludeFields = null } = {}) {
- if (isBundleProduct(product) && product.bundle_options) {
- const skus = product.bundle_options
- .map((bundleOption) => bundleOption.product_links.map((productLink) => productLink.sku))
- .reduce((acc, next) => acc.concat(next), [])
-
- const query = buildQuery(skus)
- const { items } = await ProductService.getProducts({
- query,
- excludeFields,
- includeFields,
- options: {
- prefetchGroupProducts: false,
- fallbackToDefaultWhenNoAvailable: false,
- setProductErrors: false,
- setConfigurableProductOptions: false,
- assignProductConfiguration: false,
- separateSelectedVariant: false
- }
- })
-
- catalogHooksExecutors.afterSetBundleProducts(items)
-
- for (const bundleOption of product.bundle_options) {
- for (const productLink of bundleOption.product_links) {
- const associatedProduct = items.find((associatedProduct) => associatedProduct.sku === productLink.sku)
- setProductLink(productLink, associatedProduct)
- }
- }
-
- if (config.products.calculateBundlePriceByOptions) {
- const { price, priceInclTax } = getBundleProductPrice(product)
- product.price = price
- product.priceInclTax = priceInclTax
- product.price_incl_tax = priceInclTax
- }
- }
-}
diff --git a/core/modules/catalog/helpers/associatedProducts/setGroupedProduct.ts b/core/modules/catalog/helpers/associatedProducts/setGroupedProduct.ts
deleted file mode 100644
index c27e04edcd..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/setGroupedProduct.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product'
-import buildQuery from './buildQuery'
-import setProductLink from './setProductLink'
-import getGroupedProductPrice from './getGroupedProductPrice'
-import { isGroupedProduct } from './..'
-import { ProductService } from '@vue-storefront/core/data-resolver/ProductService'
-import { catalogHooksExecutors } from './../../hooks'
-
-/**
- * This function prepare all product_links for grouped products.
- * It fetches products by sku.
- */
-export default async function setGroupedProduct (product: Product, { includeFields = null, excludeFields = null } = {}) {
- if (isGroupedProduct(product) && product.product_links) {
- const productLinks = product.product_links.filter((productLink) => productLink.link_type === 'associated' && productLink.linked_product_type === 'simple')
- const skus = productLinks.map((productLink) => productLink.linked_product_sku)
-
- const query = buildQuery(skus)
- const { items } = await ProductService.getProducts({
- query,
- excludeFields,
- includeFields,
- options: {
- prefetchGroupProducts: false,
- fallbackToDefaultWhenNoAvailable: false,
- setProductErrors: false,
- setConfigurableProductOptions: false,
- assignProductConfiguration: false,
- separateSelectedVariant: false
- }
- })
-
- catalogHooksExecutors.afterSetGroupedProduct(items)
-
- for (const productLink of productLinks) {
- const associatedProduct = items.find((associatedProduct) => associatedProduct.sku === productLink.linked_product_sku)
- setProductLink(productLink, associatedProduct)
- }
-
- const { price, priceInclTax } = getGroupedProductPrice(product)
- product.price = price
- product.priceInclTax = priceInclTax
- product.price_incl_tax = priceInclTax
- }
-}
diff --git a/core/modules/catalog/helpers/associatedProducts/setProductLink.ts b/core/modules/catalog/helpers/associatedProducts/setProductLink.ts
deleted file mode 100644
index bb9b0da7f5..0000000000
--- a/core/modules/catalog/helpers/associatedProducts/setProductLink.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import Product, { ProductLink } from '@vue-storefront/core/modules/catalog/types/Product';
-import { preConfigureProduct } from '../prepare';
-import { Logger } from '@vue-storefront/core/lib/logger';
-import { BundleOptionsProductLink } from '@vue-storefront/core/modules/catalog/types/BundleOption';
-
-/**
- * Set associated product to product link object
- */
-
-export default async function setProductLink (productLink: BundleOptionsProductLink | ProductLink, associatedProduct: Product) {
- if (associatedProduct) {
- productLink.product = preConfigureProduct(associatedProduct)
- productLink.product.qty = Number((productLink as BundleOptionsProductLink).qty || '1')
- } else {
- Logger.error('Product not found', (productLink as ProductLink).linked_product_sku || productLink.sku)()
- }
-}
diff --git a/core/modules/catalog/helpers/bundleOptions.ts b/core/modules/catalog/helpers/bundleOptions.ts
deleted file mode 100644
index b54561390a..0000000000
--- a/core/modules/catalog/helpers/bundleOptions.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { getProductLinkPrice } from './associatedProducts/getProductLinkPrice';
-import get from 'lodash-es/get'
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-import { BundleOption, BundleOptionsProductLink, SelectedBundleOption } from '@vue-storefront/core/modules/catalog/types/BundleOption';
-
-export const getBundleOptionPrice = (bundleOptionValues: BundleOptionsProductLink[]) => getProductLinkPrice(bundleOptionValues)
-
-export const getBundleOptionsValues = (selectedBundleOptions: SelectedBundleOption[], allBundeOptions: BundleOption[]): BundleOptionsProductLink[] => selectedBundleOptions
- .map(selectedBundleOption => {
- const {
- product_links: productLinks = []
- } = allBundeOptions.find(bundleOption => bundleOption.option_id === selectedBundleOption.option_id) || {}
- const value = productLinks.find(productLink => String(productLink.id) === String(selectedBundleOption.option_selections[0]))
- return { ...value, qty: selectedBundleOption.option_qty }
- })
-
-export const getSelectedBundleOptions = (product: Product): SelectedBundleOption[] => {
- const selectedBundleOptions = Object.values(get(product, 'product_option.extension_attributes.bundle_options', {}))
- if (selectedBundleOptions.length) {
- return selectedBundleOptions as any as SelectedBundleOption[]
- }
-
- // get default options
- const allBundeOptions = product.bundle_options || []
- return allBundeOptions.map((bundleOption) => {
- const productLinks = bundleOption.product_links || []
- const defaultLink = productLinks.find((productLink) => productLink.is_default) || productLinks[0]
- const qty = (typeof defaultLink.qty === 'string' ? parseInt(defaultLink.qty) : defaultLink.qty) || 1
- return {
- option_id: bundleOption.option_id,
- option_qty: qty,
- option_selections: [Number(defaultLink.id)]
- }
- })
-}
diff --git a/core/modules/catalog/helpers/configure/configureProductAsync.ts b/core/modules/catalog/helpers/configure/configureProductAsync.ts
deleted file mode 100644
index a1417bd204..0000000000
--- a/core/modules/catalog/helpers/configure/configureProductAsync.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-import cloneDeep from 'lodash-es/cloneDeep'
-import { getSelectedVariant, omitSelectedVariantFields } from '../variant';
-import { getProductConfiguration, setProductConfigurableOptions } from '../productOptions';
-import { filterOutUnavailableVariants } from '../stock';
-import { setGroupedProduct, setBundleProducts } from '../associatedProducts';
-import { hasConfigurableChildren } from './..'
-
-interface ConfigureProductAsyncParams {
- product: Product,
- configuration: any,
- attribute: any,
- options?: {
- fallbackToDefaultWhenNoAvailable?: boolean,
- setProductErrors?: boolean,
- setConfigurableProductOptions?: boolean,
- filterUnavailableVariants?: boolean,
- assignProductConfiguration?: boolean,
- separateSelectedVariant?: boolean,
- prefetchGroupProducts?: boolean
- },
- stockItems: any[],
- excludeFields?: string[],
- includeFields?: string[]
-}
-
-/**
- * This function configure product for 'configurable', 'bundle' or 'group' product.
- */
-export default async function configureProductAsync ({
- product,
- configuration,
- attribute,
- options: {
- fallbackToDefaultWhenNoAvailable = true,
- setProductErrors = true,
- setConfigurableProductOptions = true,
- filterUnavailableVariants = false,
- assignProductConfiguration = false,
- separateSelectedVariant = false,
- prefetchGroupProducts = false
- } = {},
- stockItems = [],
- excludeFields,
- includeFields
-}: ConfigureProductAsyncParams) {
- // it not only filter variants but also it apply stock object
- if (filterUnavailableVariants) {
- filterOutUnavailableVariants(product, stockItems)
- }
-
- // setup bundle or group product. Product is filled with productLinks
- if (prefetchGroupProducts) {
- await setGroupedProduct(product, { includeFields, excludeFields })
- await setBundleProducts(product, { includeFields, excludeFields })
- }
-
- // setup configurable product
- if (hasConfigurableChildren(product)) {
- // we don't want to modify configuration object
- let _configuration = cloneDeep(configuration)
-
- // find selected variant by configuration
- let selectedVariant = getSelectedVariant(product, _configuration, { fallbackToDefaultWhenNoAvailable })
-
- if (selectedVariant) {
- // if there is selectedVariant we want to get configuration based on that variant
- _configuration = getProductConfiguration({ product, selectedVariant, attribute })
-
- // here we add product_options with selected configuration. It only applies to configurable product
- setProductConfigurableOptions({ product, configuration: _configuration, setConfigurableProductOptions }) // set the custom options
-
- product.is_configured = true
-
- // remove props from variant that we don't want need to override in base product
- selectedVariant = omitSelectedVariantFields(selectedVariant)
- }
- if (!selectedVariant && setProductErrors) { // can not find variant anyway, even the default one
- product.errors.variants = 'No available product variants'
- }
-
- const configuredProduct = {
- ...product,
- ...(assignProductConfiguration ? { configuration: _configuration } : {}) // we can need configuration as separate object
- }
- return {
- ...configuredProduct,
- ...(separateSelectedVariant ? { selectedVariant } : selectedVariant) // we can need selected variant as separate object
- }
- }
-
- return product
-}
diff --git a/core/modules/catalog/helpers/configure/configureProducts.ts b/core/modules/catalog/helpers/configure/configureProducts.ts
deleted file mode 100644
index f8d0589a4a..0000000000
--- a/core/modules/catalog/helpers/configure/configureProducts.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { AttributesMetadata } from './../../types/Attribute';
-import { getStockItems } from '../stock';
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-import transformMetadataToAttributes from '../transformMetadataToAttributes';
-import configureProductAsync from './configureProductAsync';
-
-interface ConfigureProductsParams {
- products: Product[],
- attributes_metadata: AttributesMetadata[],
- configuration: any,
- options?: {
- fallbackToDefaultWhenNoAvailable?: boolean,
- setProductErrors?: boolean,
- setConfigurableProductOptions?: boolean,
- filterUnavailableVariants?: boolean,
- assignProductConfiguration?: boolean,
- separateSelectedVariant?: boolean,
- prefetchGroupProducts?: boolean
- },
- excludeFields?: string[],
- includeFields?: string[]
-}
-
-/**
- * Prepare all data needed to make product configuration.
- * After common data is setup this function map through every product and configure it based on 'configuration' object
- */
-export default async function configureProducts ({
- products,
- attributes_metadata = [],
- configuration = {},
- options = {},
- excludeFields = null,
- includeFields = null
-}: ConfigureProductsParams) {
- const productAttributesMetadata = products.map((product) => product.attributes_metadata || [])
- const attribute = transformMetadataToAttributes([attributes_metadata, ...productAttributesMetadata])
- const attributeStateFormat = { list_by_code: attribute.attrHashByCode, list_by_id: attribute.attrHashById }
-
- let stockItems = []
- if (options.filterUnavailableVariants) {
- stockItems = await getStockItems(products)
- }
-
- const configuredProducts = await Promise.all((products as Product[]).map(async (product) => {
- const configuredProduct = await configureProductAsync({
- product,
- configuration,
- attribute: attributeStateFormat,
- options: options,
- stockItems,
- excludeFields,
- includeFields
- })
- return configuredProduct as Product
- }))
-
- return configuredProducts
-}
diff --git a/core/modules/catalog/helpers/configure/index.ts b/core/modules/catalog/helpers/configure/index.ts
deleted file mode 100644
index 258ce96379..0000000000
--- a/core/modules/catalog/helpers/configure/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import configureProducts from './configureProducts'
-
-export {
- configureProducts
-}
diff --git a/core/modules/catalog/helpers/createAttributesListQuery.ts b/core/modules/catalog/helpers/createAttributesListQuery.ts
deleted file mode 100644
index e5fa9de967..0000000000
--- a/core/modules/catalog/helpers/createAttributesListQuery.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { SearchQuery } from 'storefront-query-builder'
-
-const createAttributesListQuery = ({
- filterValues,
- filterField,
- onlyDefinedByUser,
- onlyVisible
-}: {
- filterValues: string[],
- filterField: string,
- onlyDefinedByUser: boolean,
- onlyVisible: boolean
-}): SearchQuery => {
- let searchQuery = new SearchQuery()
-
- if (filterValues) {
- searchQuery = searchQuery.applyFilter({ key: filterField, value: { 'in': filterValues } })
- }
- if (onlyDefinedByUser) {
- searchQuery = searchQuery.applyFilter({ key: 'is_user_defined', value: { 'in': [true] } })
- }
- if (onlyVisible) {
- searchQuery = searchQuery.applyFilter({ key: 'is_visible', value: { 'in': [true] } })
- }
-
- return searchQuery
-}
-
-export default createAttributesListQuery
diff --git a/core/modules/catalog/helpers/createCategoryListQuery.ts b/core/modules/catalog/helpers/createCategoryListQuery.ts
deleted file mode 100644
index 5e6db47db2..0000000000
--- a/core/modules/catalog/helpers/createCategoryListQuery.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { SearchQuery } from 'storefront-query-builder'
-import { isServer } from '@vue-storefront/core/helpers'
-import config from 'config'
-
-const createCategoryListQuery = ({ parent, level, key, value, onlyActive, onlyNotEmpty }) => {
- let isCustomizedQuery = false
- let searchQuery = new SearchQuery()
-
- if (parent) {
- searchQuery = searchQuery.applyFilter({ key: 'parent_id', value: { 'eq': typeof parent === 'object' ? parent.id : parent } })
- isCustomizedQuery = true
- }
-
- if (level !== null) {
- searchQuery = searchQuery.applyFilter({ key: 'level', value: { 'eq': level } })
- if (level !== config.entities.category.categoriesDynamicPrefetchLevel && !isServer) {
- isCustomizedQuery = true
- }
- }
-
- if (key !== null) {
- if (Array.isArray(value)) {
- searchQuery = searchQuery.applyFilter({ key: key, value: { 'in': value } })
- } else {
- searchQuery = searchQuery.applyFilter({ key: key, value: { 'eq': value } })
- }
- isCustomizedQuery = true
- }
-
- if (onlyActive === true) {
- searchQuery = searchQuery.applyFilter({ key: 'is_active', value: { 'eq': true } })
- }
-
- if (onlyNotEmpty === true) {
- searchQuery = searchQuery.applyFilter({ key: 'product_count', value: { 'gt': 0 } })
- isCustomizedQuery = true
- }
-
- return { searchQuery, isCustomizedQuery }
-}
-
-export default createCategoryListQuery
diff --git a/core/modules/catalog/helpers/customOption.ts b/core/modules/catalog/helpers/customOption.ts
deleted file mode 100644
index 2ff7a837bb..0000000000
--- a/core/modules/catalog/helpers/customOption.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-import { CustomOption, OptionValue, InputValue, SelectedCustomOption } from '@vue-storefront/core/modules/catalog/types/CustomOption';
-
-export const defaultCustomOptionValue = (customOption: CustomOption): InputValue => {
- switch (customOption.type) {
- case 'radio': {
- return customOption.values && customOption.values.length ? customOption.values[0].option_type_id : 0
- }
- case 'checkbox': {
- return []
- }
- default: {
- return ''
- }
- }
-}
-
-export const customOptionFieldName = (customOption: CustomOption): string => {
- return 'customOption_' + customOption.option_id
-}
-
-export const selectedCustomOptionValue = (optionType: string, optionValues: OptionValue[] = [], inputValue: InputValue): string => {
- switch (optionType) {
- case 'field': {
- return inputValue as string
- }
- case 'radio':
- case 'select':
- case 'drop_down': {
- const selectedValue = optionValues.find((value) => value.option_type_id === inputValue as number)
- const optionTypeId = selectedValue && selectedValue.option_type_id
-
- return optionTypeId ? String(optionTypeId) : null
- }
- case 'checkbox': {
- const checkboxOptionValues = inputValue as number[] || []
-
- return optionValues.filter((value) => checkboxOptionValues.includes(value.option_type_id))
- .map((value) => value.option_type_id)
- .join(',') || null
- }
- default: {
- return null
- }
- }
-}
-
-export const getCustomOptionValues = (selectedCustomOptions: SelectedCustomOption[], allCustomOptions: CustomOption[]): OptionValue[] => selectedCustomOptions
- .filter(customOptionIds => customOptionIds.option_value) // remove null | undefined values
- .map(customOptionIds => {
- const { values = [] } = allCustomOptions.find(
- customOption => String(customOption.option_id) === String(customOptionIds.option_id) // get all custom option values based on 'option_id'
- )
- const customOptionValues = customOptionIds.option_value
- .split(',') // split ids, because there can be '1,2' for checkbox
- .map(optionValueId => values.find(value => String(value.option_type_id) === optionValueId)) // get custom option value based on selected option value id
- .filter(Boolean) // remove falsy results
-
- return customOptionValues
- })
- .reduce((allCustomOptionValues, customOptionValue) => allCustomOptionValues.concat(customOptionValue), []) // merge all values in one array
-
-export const getCustomOptionPriceDelta = (customOptionValues: OptionValue[], { price, priceInclTax, price_incl_tax }: Pick) => customOptionValues
- .reduce((delta, customOptionValue) => {
- if (customOptionValue.price_type === 'fixed' && customOptionValue.price !== 0) {
- delta.price += customOptionValue.price
- delta.priceInclTax += customOptionValue.price
- }
- if (customOptionValue.price_type === 'percent' && customOptionValue.price !== 0) {
- delta.price += ((customOptionValue.price / 100) * price)
- delta.priceInclTax += ((customOptionValue.price / 100) * (priceInclTax || price_incl_tax))
- }
- return delta
- }, {
- price: 0,
- priceInclTax: 0
- })
diff --git a/core/modules/catalog/helpers/deprecatedHelpers.ts b/core/modules/catalog/helpers/deprecatedHelpers.ts
deleted file mode 100644
index 2917769e9e..0000000000
--- a/core/modules/catalog/helpers/deprecatedHelpers.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import Vue from 'vue'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import omit from 'lodash-es/omit'
-import i18n from '@vue-storefront/i18n'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { optionLabel } from './optionLabel'
-import { setProductConfigurableOptions } from './productOptions'
-import config from 'config'
-import { findConfigurableVariant } from './variant'
-import { hasImage } from './'
-
-export function populateProductConfigurationAsync (context, { product, selectedVariant }) {
- Logger.warn('deprecated, will be not used from 1.12')()
- if (product.configurable_options) {
- for (let option of product.configurable_options) {
- let attribute_code
- let attribute_label
- if (option.attribute_code) {
- attribute_code = option.attribute_code
- attribute_label = option.label ? option.label : (option.frontend_label ? option.frontend_label : option.default_frontend_label)
- } else {
- if (option.attribute_id) {
- let attr = context.rootState.attribute.list_by_id[option.attribute_id]
- if (!attr) {
- Logger.error('Wrong attribute given in configurable_options - can not find by attribute_id', option)()
- continue
- } else {
- attribute_code = attr.attribute_code
- attribute_label = attr.frontend_label ? attr.frontend_label : attr.default_frontend_label
- }
- } else {
- Logger.error('Wrong attribute given in configurable_options - no attribute_code / attribute_id', option)()
- }
- }
- let selectedOption = null
- if (selectedVariant.custom_attributes) {
- selectedOption = selectedVariant.custom_attributes.find((a) => { // this is without the "label"
- return (a.attribute_code === attribute_code)
- })
- } else {
- selectedOption = {
- attribute_code: attribute_code,
- value: selectedVariant[attribute_code]
- }
- }
- if (option.values && option.values.length) {
- const selectedOptionMeta = option.values.find(ov => { return ov.value_index === selectedOption.value })
- if (selectedOptionMeta) {
- selectedOption.label = selectedOptionMeta.label ? selectedOptionMeta.label : selectedOptionMeta.default_label
- selectedOption.value_data = selectedOptionMeta.value_data
- }
- }
-
- const confVal = {
- attribute_code: attribute_code,
- id: selectedOption.value,
- label: selectedOption.label ? selectedOption.label : /* if not set - find by attribute */optionLabel(context.rootState.attribute, { attributeKey: selectedOption.attribute_code, searchBy: 'code', optionId: selectedOption.value })
- }
- Vue.set(context.state.current_configuration, attribute_code, confVal)
- }
- setProductConfigurableOptions({
- product,
- configuration: context.state.current_configuration,
- setConfigurableProductOptions: config.cart.setConfigurableProductOptions
- }) // set the custom options
- }
- return selectedVariant
-}
-
-export function configureProductAsync (context, { product, configuration, selectDefaultVariant = true, fallbackToDefaultWhenNoAvailable = true, setProductErorrs = false }) {
- Logger.warn('deprecated, will be not used from 1.12')()
- // use current product if product wasn't passed
- if (product === null) product = context.getters.getCurrentProduct
- const hasConfigurableChildren = (product.configurable_children && product.configurable_children.length > 0)
-
- if (hasConfigurableChildren) {
- // handle custom_attributes for easier comparing in the future
- product.configurable_children.forEach((child) => {
- let customAttributesAsObject = {}
- if (child.custom_attributes) {
- child.custom_attributes.forEach((attr) => {
- customAttributesAsObject[attr.attribute_code] = attr.value
- })
- // add values from custom_attributes in a different form
- Object.assign(child, customAttributesAsObject)
- }
- })
- // find selected variant
- let desiredProductFound = false
- let selectedVariant = findConfigurableVariant({ product, configuration, availabilityCheck: true })
- if (!selectedVariant) {
- if (fallbackToDefaultWhenNoAvailable) {
- selectedVariant = findConfigurableVariant({ product, selectDefaultChildren: true, availabilityCheck: true }) // return first available child
- desiredProductFound = false
- } else {
- desiredProductFound = false
- }
- } else {
- desiredProductFound = true
- }
-
- if (selectedVariant) {
- if (!desiredProductFound && selectDefaultVariant /** don't change the state when no selectDefaultVariant is set */) { // update the configuration
- populateProductConfigurationAsync(context, { product: product, selectedVariant: selectedVariant })
- configuration = context.state.current_configuration
- }
- if (setProductErorrs) {
- product.errors = {} // clear the product errors
- }
- product.is_configured = true
-
- if (config.cart.setConfigurableProductOptions && !selectDefaultVariant && !(Object.keys(configuration).length === 1 && configuration.sku)) {
- // the condition above: if selectDefaultVariant - then "setCurrent" is seeting the configurable options; if configuration = { sku: '' } -> this is a special case when not configuring the product but just searching by sku
- setProductConfigurableOptions({
- product,
- configuration,
- setConfigurableProductOptions: config.cart.setConfigurableProductOptions
- }) // set the custom options
- }/* else {
- Logger.debug('Skipping configurable options setup', configuration)()
- } */
- const fieldsToOmit = ['name']
- if (!hasImage(selectedVariant)) fieldsToOmit.push('image')
- selectedVariant = omit(selectedVariant, fieldsToOmit) // We need to send the parent SKU to the Magento cart sync but use the child SKU internally in this case
- // use chosen variant for the current product
- if (selectDefaultVariant) {
- context.dispatch('setCurrent', selectedVariant)
- }
- EventBus.$emit('product-after-configure', { product: product, configuration: configuration, selectedVariant: selectedVariant })
- }
- if (!selectedVariant && setProductErorrs) { // can not find variant anyway, even the default one
- product.errors.variants = i18n.t('No available product variants')
- if (selectDefaultVariant) {
- context.dispatch('setCurrent', product) // without the configuration
- }
- }
- return selectedVariant
- } else {
- if (fallbackToDefaultWhenNoAvailable) {
- return product
- } else {
- return null
- }
- }
-}
diff --git a/core/modules/catalog/helpers/filterAttributes.ts b/core/modules/catalog/helpers/filterAttributes.ts
deleted file mode 100644
index ff3b26013b..0000000000
--- a/core/modules/catalog/helpers/filterAttributes.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import config from 'config'
-
-export default function filterAttributes ({
- filterValues,
- filterField,
- blacklist,
- idsList,
- codesList
-}: {
- filterValues: string[],
- filterField: string,
- blacklist: string[],
- idsList: any,
- codesList: any
-}) {
- return filterValues.filter(fv => {
- if (fv.indexOf('.') >= 0) {
- return false
- }
- if (blacklist !== null && blacklist.includes(fv)) {
- return false
- }
- if (filterField === 'attribute_id') {
- return (typeof idsList[fv] === 'undefined' || idsList[fv] === null)
- }
- if (filterField === 'attribute_code') {
- return (typeof codesList[fv] === 'undefined' || codesList[fv] === null)
- }
- })
-}
diff --git a/core/modules/catalog/helpers/filters.ts b/core/modules/catalog/helpers/filters.ts
deleted file mode 100644
index 000157ec72..0000000000
--- a/core/modules/catalog/helpers/filters.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product'
-import { ProductConfiguration } from '@vue-storefront/core/modules/catalog/types/ProductConfiguration'
-
-const getAvailableFiltersByProduct = (product: Product) => {
- let filtersMap = {}
- if (product && product.configurable_options) {
- product.configurable_options.forEach(configurableOption => {
- const type = configurableOption.attribute_code
- const filterVariants = configurableOption.values.map(({ value_index, label }) => {
- return { id: value_index, label, type }
- })
- filtersMap[type] = filterVariants
- })
- }
- return filtersMap
-}
-
-const getSelectedFiltersByProduct = (product: Product, configuration: ProductConfiguration) => {
- if (!configuration) {
- return null
- }
-
- let selectedFilters = {}
- if (configuration && product) {
- Object.keys(configuration).map(filterType => {
- const filter = configuration[filterType]
- selectedFilters[filterType] = {
- id: filter.id,
- label: filter.label,
- type: filterType
- }
- })
- }
- return selectedFilters
-}
-
-export { getAvailableFiltersByProduct, getSelectedFiltersByProduct }
diff --git a/core/modules/catalog/helpers/getProductGallery.ts b/core/modules/catalog/helpers/getProductGallery.ts
deleted file mode 100644
index 87709f7f23..0000000000
--- a/core/modules/catalog/helpers/getProductGallery.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import config from 'config'
-import {
- getMediaGallery,
- configurableChildrenImages,
- attributeImages
-} from './'
-import uniqBy from 'lodash-es/uniqBy'
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-export default function getProductGallery (product: Product) {
- if (product.type_id === 'configurable' && product.hasOwnProperty('configurable_children')) {
- if (!config.products.gallery.mergeConfigurableChildren && product.is_configured) {
- return attributeImages(product)
- }
- }
-
- const productGallery = uniqBy(configurableChildrenImages(product).concat(getMediaGallery(product)), 'src')
- .filter(f => f.src && f.src !== config.images.productPlaceholder)
-
- return productGallery
-}
diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts
deleted file mode 100644
index 5eeedb7c20..0000000000
--- a/core/modules/catalog/helpers/index.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-import Vue from 'vue'
-// TODO: Remove this dependency
-import { optionLabel } from './optionLabel'
-import { getThumbnailPath } from '@vue-storefront/core/helpers'
-import config from 'config'
-import registerProductsMapping from './registerProductsMapping'
-import getProductGallery from './getProductGallery'
-import { findConfigurableVariant, isOptionAvailable } from './variant'
-import { filterOutUnavailableVariants } from './stock'
-import { doPlatformPricesSync } from './price'
-import { setProductConfigurableOptions } from './productOptions'
-
-/** Below helpers are not used from 1.12 and can be removed to reduce bundle */
-import { populateProductConfigurationAsync, configureProductAsync } from './deprecatedHelpers'
-export {
- populateProductConfigurationAsync,
- configureProductAsync
-}
-/***/
-
-export {
- registerProductsMapping,
- getProductGallery,
- optionLabel,
- findConfigurableVariant as findConfigurableChildAsync,
- isOptionAvailable as isOptionAvailableAsync,
- filterOutUnavailableVariants,
- doPlatformPricesSync,
- setProductConfigurableOptions as setConfigurableProductOptionsAsync
-}
-
-export const hasConfigurableChildren = (product) => product && product.configurable_children && product.configurable_children.length
-export const isGroupedProduct = (product) => product.type_id === 'grouped'
-export const isBundleProduct = (product) => product.type_id === 'bundle'
-
-/**
- * check if object have an image
- */
-export const hasImage = (product) => product && product.image && product.image !== 'no_selection'
-/**
- * check if one of the configuableChildren has an image
- */
-export const childHasImage = (children = []) => children.some(hasImage)
-
-function _prepareProductOption (product) {
- let product_option = {
- extension_attributes: {
- custom_options: [],
- configurable_item_options: [],
- bundle_options: []
- }
- }
- /* if (product.product_option) {
- product_option = product.product_option
- } */
- return product_option
-}
-
-export function setCustomProductOptionsAsync (context, { product, customOptions }) {
- const productOption = _prepareProductOption(product)
- productOption.extension_attributes.custom_options = customOptions
- return productOption
-}
-
-export function setBundleProductOptionsAsync (context, { product, bundleOptions }) {
- const productOption = _prepareProductOption(product)
- productOption.extension_attributes.bundle_options = bundleOptions
- return productOption
-}
-
-/**
- * Get media Gallery images from product
- */
-
-export function getMediaGallery (product) {
- let mediaGallery = []
- if (product.media_gallery) {
- for (let mediaItem of product.media_gallery) {
- if (mediaItem.image) {
- let video = mediaItem.vid
-
- if (video && video.video_id) {
- video.id = video.video_id
- delete video.video_id
- }
-
- mediaGallery.push({
- 'src': getThumbnailPath(mediaItem.image, config.products.gallery.width, config.products.gallery.height),
- 'loading': getThumbnailPath(mediaItem.image, config.products.thumbnails.width, config.products.thumbnails.height),
- 'error': getThumbnailPath(mediaItem.image, config.products.thumbnails.width, config.products.thumbnails.height),
- 'video': video
- })
- }
- }
- }
- return mediaGallery
-}
-
-/**
- * Get images from configured attribute images
- */
-export function attributeImages (product) {
- let attributeImages = []
- if (config.products.gallery.imageAttributes) {
- for (let attribute of config.products.gallery.imageAttributes) {
- if (product[attribute] && product[attribute] !== 'no_selection') {
- attributeImages.push({
- 'src': getThumbnailPath(product[attribute], config.products.gallery.width, config.products.gallery.height),
- 'loading': getThumbnailPath(product[attribute], 310, 300),
- 'error': getThumbnailPath(product[attribute], 310, 300)
- })
- }
- }
- }
- return attributeImages
-}
-/**
- * Get configurable_children images from product if any
- * otherwise get attribute images
- */
-
-export function configurableChildrenImages (product) {
- let configurableChildrenImages = []
- if (childHasImage(product.configurable_children)) {
- let configurableAttributes = product.configurable_options.map(option => option.attribute_code)
- configurableChildrenImages = product.configurable_children.map(child =>
- ({
- 'src': getThumbnailPath((!hasImage(child) ? product.image : child.image), config.products.gallery.width, config.products.gallery.height),
- 'loading': getThumbnailPath((!hasImage(child) ? product.image : child.image), config.products.thumbnails.width, config.products.thumbnails.height),
- 'id': configurableAttributes.reduce((result, attribute) => {
- result[attribute] = child[attribute]
- return result
- }, {})
- })
- )
- } else {
- configurableChildrenImages = attributeImages(product)
- }
- return configurableChildrenImages
-}
-
-export const setRequestCacheTags = ({ products = [] }) => {
- if (Vue.prototype.$cacheTags) {
- products.forEach((product) => {
- Vue.prototype.$cacheTags.add(`P${product.id}`);
- })
- }
-}
diff --git a/core/modules/catalog/helpers/optionLabel.ts b/core/modules/catalog/helpers/optionLabel.ts
deleted file mode 100644
index d169855152..0000000000
--- a/core/modules/catalog/helpers/optionLabel.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Helper method for getting attribute name - TODO: to be moved to external/shared helper
- *
- * @param {String} attributeCode
- * @param {String} optionId - value to get label for
- */
-import toString from 'lodash-es/toString'
-import get from 'lodash-es/get'
-
-export function optionLabel (state, { attributeKey, searchBy = 'code', optionId }) {
- if (!state.labels) {
- state.labels = {}
- }
-
- // check cached attribute
- const attrCache = get(state, `labels.${attributeKey}.${optionId}`, null)
- if (attrCache) {
- return attrCache
- }
-
- let attr = state['list_by_' + searchBy][attributeKey]
- if (attr) {
- let opt = attr.options.find((op) => toString(op.value) === toString(optionId))
-
- if (opt) {
- if (!state.labels[attributeKey]) {
- state.labels[attributeKey] = {}
- }
- state.labels[attributeKey][optionId] = opt.label
- return opt ? opt.label : optionId
- } else {
- return optionId
- }
- } else {
- return optionId
- }
-}
diff --git a/core/modules/catalog/helpers/prefetchCachedAttributes.ts b/core/modules/catalog/helpers/prefetchCachedAttributes.ts
deleted file mode 100644
index 6a40b10cf7..0000000000
--- a/core/modules/catalog/helpers/prefetchCachedAttributes.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import { entityKeyName } from '@vue-storefront/core/lib/store/entities'
-import config from 'config'
-
-async function prefetchCachedAttributes (filterField, filterValues) {
- if (!config.attributes || !config.attributes.disablePersistentAttributesCache) {
- const attrCollection = StorageManager.get('attributes')
- const cachedAttributes = filterValues.map(
- async filterValue => attrCollection.getItem(entityKeyName(filterField, String(filterValue).toLowerCase()))
- )
- return Promise.all(cachedAttributes)
- }
-}
-
-export { prefetchCachedAttributes }
diff --git a/core/modules/catalog/helpers/prepare/index.ts b/core/modules/catalog/helpers/prepare/index.ts
deleted file mode 100644
index 62417fd11e..0000000000
--- a/core/modules/catalog/helpers/prepare/index.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import setDefaultQty from './setDefaultQty';
-import setDefaultObjects from './setDefaultObjects';
-import setParentSku from './setParentSku';
-import setParentId from './setParentId';
-import setCustomAttributesForChild from './setCustomAttributesForChild';
-import setDefaultProductOptions from './setDefaultProductOptions';
-
-/**
- * Apply base modification to product, after those modification we can store product in cache.
- */
-function preConfigureProduct (product) {
- // base product modifications
- setDefaultQty(product)
- setDefaultObjects(product)
- setParentSku(product)
- setParentId(product)
- setCustomAttributesForChild(product)
- setDefaultProductOptions(product)
-
- return product;
-}
-
-/**
- * Apply base modification to product list, after those modification we can store product in cache.
- */
-function prepareProducts (products) {
- const preparedProducts = products.map(preConfigureProduct)
-
- return preparedProducts
-}
-
-export {
- prepareProducts,
- preConfigureProduct
-}
diff --git a/core/modules/catalog/helpers/prepare/setCustomAttributesForChild.ts b/core/modules/catalog/helpers/prepare/setCustomAttributesForChild.ts
deleted file mode 100644
index 73ba3a7be6..0000000000
--- a/core/modules/catalog/helpers/prepare/setCustomAttributesForChild.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-import { hasConfigurableChildren } from '../';
-/**
- * Fill custom attributes for every configurable child
- */
-export default function setCustomAttributesForChild (product: Product) {
- if (!hasConfigurableChildren(product)) return
- // handle custom_attributes for easier comparing in the future
- product.configurable_children.forEach((child) => {
- let customAttributesAsObject = {}
- if (child.custom_attributes) {
- child.custom_attributes.forEach((attr) => {
- customAttributesAsObject[attr.attribute_code] = attr.value
- })
- // add values from custom_attributes in a different form
- Object.assign(child, customAttributesAsObject)
- }
- })
-}
diff --git a/core/modules/catalog/helpers/prepare/setDefaultObjects.ts b/core/modules/catalog/helpers/prepare/setDefaultObjects.ts
deleted file mode 100644
index 00fc289ca1..0000000000
--- a/core/modules/catalog/helpers/prepare/setDefaultObjects.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-/**
- * Default object that are used in vsf
- */
-export default function setDefaultObjects (product: Product) {
- product.errors = {}; // this is an object to store validation result for custom options and others
- product.info = {};
-}
diff --git a/core/modules/catalog/helpers/prepare/setDefaultProductOptions.ts b/core/modules/catalog/helpers/prepare/setDefaultProductOptions.ts
deleted file mode 100644
index 22ef357177..0000000000
--- a/core/modules/catalog/helpers/prepare/setDefaultProductOptions.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-/**
- * Init product_option, needed to next configuration step
- */
-export default function setDefaultProductOptions (product: Product) {
- if (product.product_option) return
- product.product_option = {
- extension_attributes: {
- custom_options: [],
- configurable_item_options: [],
- bundle_options: []
- }
- }
-}
diff --git a/core/modules/catalog/helpers/prepare/setDefaultQty.ts b/core/modules/catalog/helpers/prepare/setDefaultQty.ts
deleted file mode 100644
index bd3d27321e..0000000000
--- a/core/modules/catalog/helpers/prepare/setDefaultQty.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-/**
- * set product quantity to 1
- */
-export default function setDefaultQty (product: Product) {
- if (!product.qty) {
- product.qty = 1
- }
-}
diff --git a/core/modules/catalog/helpers/prepare/setParentId.ts b/core/modules/catalog/helpers/prepare/setParentId.ts
deleted file mode 100644
index 169fea5844..0000000000
--- a/core/modules/catalog/helpers/prepare/setParentId.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-/**
- * set parent id, this is needed, because in configuration process we will override id by configurable_children.id
- */
-export default function setParentId (product: Product) {
- if (!product.parentId) {
- product.parentId = product.id
- }
-}
diff --git a/core/modules/catalog/helpers/prepare/setParentSku.ts b/core/modules/catalog/helpers/prepare/setParentSku.ts
deleted file mode 100644
index d0c0038c0f..0000000000
--- a/core/modules/catalog/helpers/prepare/setParentSku.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-/**
- * set parent sku, this is needed, because in configuration process we will override sku by configurable_children.sku
- */
-export default function setParentSku (product: Product) {
- if (!product.parentSku) {
- product.parentSku = product.sku
- }
-}
diff --git a/core/modules/catalog/helpers/price/doPlatformPricesSync.ts b/core/modules/catalog/helpers/price/doPlatformPricesSync.ts
deleted file mode 100644
index 2c9556ad45..0000000000
--- a/core/modules/catalog/helpers/price/doPlatformPricesSync.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-import { isServer } from '@vue-storefront/core/helpers'
-import config from 'config'
-import flattenDeep from 'lodash-es/flattenDeep'
-import union from 'lodash-es/union'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import rootStore from '@vue-storefront/core/store'
-import { ProductService } from '@vue-storefront/core/data-resolver/ProductService'
-import syncProductPrice from './syncProductPrice'
-
-/**
- * Synchronize / override prices got from ElasticSearch with current one's from Magento2 or other platform backend
- * @param {Array} products
- */
-export default function doPlatformPricesSync (products) {
- return new Promise(async (resolve, reject) => {
- if (config.products.alwaysSyncPlatformPricesOver) {
- if (config.products.clearPricesBeforePlatformSync) {
- for (let product of products) { // clear out the prices as we need to sync them with Magento
- product.price_incl_tax = null
- product.original_price_incl_tax = null
- product.special_price_incl_tax = null
-
- product.special_price = null
- product.price = null
- product.original_price = null
-
- product.price_tax = null
- product.special_price_tax = null
- product.original_price_tax = null
-
- /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */
- product.priceInclTax = product.price_incl_tax
- product.priceTax = product.price_tax
- product.originalPrice = product.original_price
- product.originalPriceInclTax = product.original_price_incl_tax
- product.originalPriceTax = product.original_price_tax
- product.specialPriceInclTax = product.special_price_incl_tax
- product.specialPriceTax = product.special_price_tax
- /** END */
-
- if (product.configurable_children) {
- for (let sc of product.configurable_children) {
- sc.price_incl_tax = null
- sc.original_price_incl_tax = null
- sc.special_price_incl_tax = null
-
- sc.special_price = null
- sc.price = null
- sc.original_price = null
-
- sc.price_tax = null
- sc.special_price_tax = null
- sc.original_price_tax = null
-
- /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */
- sc.priceInclTax = sc.price_incl_tax
- sc.priceTax = sc.price_tax
- sc.originalPrice = sc.original_price
- sc.originalPriceInclTax = sc.original_price_incl_tax
- sc.originalPriceTax = sc.original_price_tax
- sc.specialPriceInclTax = sc.special_price_incl_tax
- sc.specialPriceTax = sc.special_price_tax
- /** END */
- }
- }
- }
- }
-
- let skus = products.map((p) => { return p.sku })
-
- if (products.length === 1) { // single product - download child data
- const childSkus = flattenDeep(products.map((p) => { return (p.configurable_children) ? p.configurable_children.map((cc) => { return cc.sku }) : null }))
- skus = union(skus, childSkus)
- }
- if (skus && skus.length > 0) {
- Logger.log('Starting platform prices sync for', skus) // TODO: add option for syncro and non syncro return()
- const { items } = await ProductService.getProductRenderList({
- skus,
- isUserGroupedTaxActive: rootStore.getters['tax/getIsUserGroupedTaxActive'],
- userGroupId: rootStore.getters['tax/getUserTaxGroupId'],
- token: rootStore.getters['user/getToken']
- })
- if (items) {
- for (let product of products) {
- const backProduct = items.find((itm) => itm.id === product.id)
- if (backProduct) {
- product.price_is_current = true // in case we're syncing up the prices we should mark if we do have current or not
- product.price_refreshed_at = new Date()
- product = syncProductPrice(product, backProduct)
-
- if (product.configurable_children) {
- for (let configurableChild of product.configurable_children) {
- const backProductChild = items.find((itm) => itm.id === configurableChild.id)
- if (backProductChild) {
- configurableChild = syncProductPrice(configurableChild, backProductChild)
- }
- }
- }
- // TODO: shall we update local storage here for the main product?
- }
- }
- }
- resolve(products)
- } else { // empty list of products
- resolve(products)
- }
- if (!config.products.waitForPlatformSync && !isServer) {
- Logger.log('Returning products, the prices yet to come from backend!')()
- for (let product of products) {
- product.price_is_current = false // in case we're syncing up the prices we should mark if we do have current or not
- product.price_refreshed_at = null
- }
- resolve(products)
- }
- } else {
- resolve(products)
- }
- })
-}
diff --git a/core/modules/catalog/helpers/price/index.ts b/core/modules/catalog/helpers/price/index.ts
deleted file mode 100644
index 93dc819cc5..0000000000
--- a/core/modules/catalog/helpers/price/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import doPlatformPricesSync from './doPlatformPricesSync'
-
-export {
- doPlatformPricesSync
-}
diff --git a/core/modules/catalog/helpers/price/syncProductPrice.ts b/core/modules/catalog/helpers/price/syncProductPrice.ts
deleted file mode 100644
index c36d516311..0000000000
--- a/core/modules/catalog/helpers/price/syncProductPrice.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-
-export default function syncProductPrice (product, backProduct) { // TODO: we probably need to update the Net prices here as well
- product.sgn = backProduct.sgn // copy the signature for the modified price
- product.price_incl_tax = backProduct.price_info.final_price
- product.original_price_incl_tax = backProduct.price_info.regular_price
- product.special_price_incl_tax = backProduct.price_info.special_price
-
- product.special_price = backProduct.price_info.extension_attributes.tax_adjustments.special_price
- product.price = backProduct.price_info.extension_attributes.tax_adjustments.final_price
- product.original_price = backProduct.price_info.extension_attributes.tax_adjustments.regular_price
-
- product.price_tax = product.price_incl_tax - product.price
- product.special_price_tax = product.special_price_incl_tax - product.special_price
- product.original_price_tax = product.original_price_incl_tax - product.original_price
-
- if (product.price_incl_tax >= product.original_price_incl_tax) {
- product.special_price_incl_tax = 0
- product.special_price = 0
- }
-
- /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */
- product.priceInclTax = product.price_incl_tax
- product.priceTax = product.price_tax
- product.originalPrice = product.original_price
- product.originalPriceInclTax = product.original_price_incl_tax
- product.originalPriceTax = product.original_price_tax
- product.specialPriceInclTax = product.special_price_incl_tax
- product.specialPriceTax = product.special_price_tax
- /** END */
- EventBus.$emit('product-after-priceupdate', product)
- // Logger.log(product.sku, product, backProduct)()
- return product
-}
diff --git a/core/modules/catalog/helpers/productOptions/getAllProductConfigurations.ts b/core/modules/catalog/helpers/productOptions/getAllProductConfigurations.ts
deleted file mode 100644
index 2f50e8e7ff..0000000000
--- a/core/modules/catalog/helpers/productOptions/getAllProductConfigurations.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { ProductOptions } from '@vue-storefront/core/modules/catalog/types/Product';
-
-/**
- * It returns all available options for configurable product
- */
-export default function getAllProductConfigurations ({ configurableOptions, configuration }): ProductOptions {
- const product_option: ProductOptions = {
- extension_attributes: {
- custom_options: [],
- configurable_item_options: [],
- bundle_options: []
- }
- }
- /* eslint camelcase: "off" */
- product_option.extension_attributes.configurable_item_options = Object.keys(configuration)
- .map((key) => configuration[key])
- .filter((configOption) =>
- configOption &&
- configOption.attribute_code &&
- configOption.attribute_code !== 'price'
- )
- .map((configOption) => ({
- configOption,
- productOption: configurableOptions.find((productConfigOption) => productConfigOption.attribute_code === configOption.attribute_code)
- }))
- .filter(({ productOption }) => productOption)
- .map(({ configOption, productOption }) => ({
- option_id: String(productOption.attribute_id),
- option_value: String(configOption.id),
- label: productOption.label || configOption.attribute_code,
- value: configOption.label
- }))
-
- return product_option
-}
diff --git a/core/modules/catalog/helpers/productOptions/getAttributeCode.ts b/core/modules/catalog/helpers/productOptions/getAttributeCode.ts
deleted file mode 100644
index 1362630954..0000000000
--- a/core/modules/catalog/helpers/productOptions/getAttributeCode.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Returns attribute_code for product option
- */
-export default function getAttributeCode (option, attribute): string {
- const attribute_code = option.attribute_code
- ? option.attribute_code
- : option.attribute_id && (attribute.list_by_id[option.attribute_id] || {}).attribute_code
- return attribute_code || option.label.toLowerCase()
-}
diff --git a/core/modules/catalog/helpers/productOptions/getInternalOptionsFormat.ts b/core/modules/catalog/helpers/productOptions/getInternalOptionsFormat.ts
deleted file mode 100644
index 407e0d0a50..0000000000
--- a/core/modules/catalog/helpers/productOptions/getInternalOptionsFormat.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * Returns internal format for product options
- */
-export default function getInternalOptionsFormat (productOption) {
- return productOption.extension_attributes.configurable_item_options
- .map(({ label, value }) => ({ label, value }))
-}
diff --git a/core/modules/catalog/helpers/productOptions/getProductConfiguration.ts b/core/modules/catalog/helpers/productOptions/getProductConfiguration.ts
deleted file mode 100644
index 55c8e6ea91..0000000000
--- a/core/modules/catalog/helpers/productOptions/getProductConfiguration.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { optionLabel } from '@vue-storefront/core/modules/catalog/helpers';
-import getAttributeCode from './getAttributeCode'
-import getSelectedOption from './getSelectedOption'
-
-/**
- * Returns configuration based on selected variant. Only applies to configurable product
- */
-export default function getProductConfiguration ({ product, selectedVariant, attribute }) {
- const currentProductOption = {}
- const configurableOptions = product.configurable_options || []
- for (const option of configurableOptions) {
- const attributeCode = getAttributeCode(option, attribute)
- const selectedOption = getSelectedOption(selectedVariant, attributeCode, option)
- const label = selectedOption.label
- ? selectedOption.label
- : optionLabel(attribute, {
- attributeKey: selectedOption.attribute_code,
- searchBy: 'code',
- optionId: selectedOption.value
- })
- currentProductOption[attributeCode] = {
- attribute_code: attributeCode,
- id: String(selectedOption.value),
- label: label
- }
- }
- return currentProductOption
-}
diff --git a/core/modules/catalog/helpers/productOptions/getProductConfigurationOptions.ts b/core/modules/catalog/helpers/productOptions/getProductConfigurationOptions.ts
deleted file mode 100644
index 93a0adf456..0000000000
--- a/core/modules/catalog/helpers/productOptions/getProductConfigurationOptions.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import getAttributeCode from './getAttributeCode'
-import trim from 'lodash-es/trim'
-import { optionLabel } from '@vue-storefront/core/modules/catalog/helpers';
-
-export default function getProductConfigurationOptions ({ product, attribute }) {
- const productOptions = {}
- const configurableOptions = product.configurable_options || []
- for (let option of configurableOptions) {
- const attributeCode = getAttributeCode(option, attribute)
- const productOptionValues = option.values
- .map((optionValue) => ({
- label: optionValue.label
- ? optionValue.label
- : optionLabel(attribute, {
- attributeKey: option.attribute_id,
- searchBy: 'id',
- optionId: optionValue.value_index
- }),
- id: String(optionValue.value_index),
- attribute_code: option.attribute_code
- }))
- .filter((optionValue) => trim(optionValue.label) !== '')
-
- productOptions[attributeCode] = productOptionValues
- }
- return productOptions
-}
diff --git a/core/modules/catalog/helpers/productOptions/getSelectedOption.ts b/core/modules/catalog/helpers/productOptions/getSelectedOption.ts
deleted file mode 100644
index 8bf5bd12f2..0000000000
--- a/core/modules/catalog/helpers/productOptions/getSelectedOption.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Returns single option for configurable product based on attribute code
- */
-export default function getSelectedOption (selectedVariant, attributeCode, option) {
- let selectedOption = (selectedVariant.custom_attributes || []).find((a) => a.attribute_code === attributeCode)
- selectedOption = selectedOption || {
- attribute_code: attributeCode,
- value: selectedVariant[attributeCode]
- }
- if (option.values && option.values.length) {
- const selectedOptionMeta = option.values.find(ov => String(ov.value_index) === String(selectedOption.value))
- if (selectedOptionMeta) {
- selectedOption.label = selectedOptionMeta.label
- ? selectedOptionMeta.label
- : selectedOptionMeta.default_label
- }
- }
- return selectedOption
-}
diff --git a/core/modules/catalog/helpers/productOptions/index.ts b/core/modules/catalog/helpers/productOptions/index.ts
deleted file mode 100644
index 6370d77c60..0000000000
--- a/core/modules/catalog/helpers/productOptions/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import setProductConfigurableOptions from './setProductConfigurableOptions'
-import getProductConfiguration from './getProductConfiguration'
-import getProductConfigurationOptions from './getProductConfigurationOptions'
-
-export {
- setProductConfigurableOptions,
- getProductConfiguration,
- getProductConfigurationOptions
-}
diff --git a/core/modules/catalog/helpers/productOptions/omitInternalOptionsFormat.ts b/core/modules/catalog/helpers/productOptions/omitInternalOptionsFormat.ts
deleted file mode 100644
index b2098e3b9c..0000000000
--- a/core/modules/catalog/helpers/productOptions/omitInternalOptionsFormat.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import omit from 'lodash-es/omit'
-
-/**
- * Omit props that is not needed for product_option
- */
-export default function omitInternalOptionsFormat (productOption) {
- productOption.extension_attributes.configurable_item_options = productOption.extension_attributes.configurable_item_options
- .map((option) => omit(option, ['label', 'value']))
-}
diff --git a/core/modules/catalog/helpers/productOptions/setProductConfigurableOptions.ts b/core/modules/catalog/helpers/productOptions/setProductConfigurableOptions.ts
deleted file mode 100644
index b71c226aba..0000000000
--- a/core/modules/catalog/helpers/productOptions/setProductConfigurableOptions.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import getAllProductConfigurations from './getAllProductConfigurations'
-import getInternalOptionsFormat from './getInternalOptionsFormat'
-import omitInternalOptionsFormat from './omitInternalOptionsFormat'
-
-/**
- * set 'product_option' and 'options' based on selected configuration
- */
-export default function setProductConfigurableOptions ({ product, configuration, setConfigurableProductOptions }) {
- // return if there is no 'setConfigurableProductOptions' option
- if (!setConfigurableProductOptions) return
-
- const configurableOptions = product.configurable_options
-
- if (!configurableOptions) return
-
- const productOptions = getAllProductConfigurations({ configurableOptions, configuration })
-
- product.options = getInternalOptionsFormat(productOptions)
-
- omitInternalOptionsFormat(productOptions)
-
- product.product_option = productOptions
-}
diff --git a/core/modules/catalog/helpers/reduceAttributesLists.ts b/core/modules/catalog/helpers/reduceAttributesLists.ts
deleted file mode 100644
index 3662224e62..0000000000
--- a/core/modules/catalog/helpers/reduceAttributesLists.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import Attribute from '@vue-storefront/core/modules/catalog/types/Attribute'
-
-const reduceAttributes = (prev, curr) => {
- if (curr) {
- prev.attrHashByCode[curr.attribute_code] = curr
- prev.attrHashById[curr.attribute_id] = curr
- }
-
- return prev
-}
-
-const reduceAttributesLists = ({
- codesList,
- idsList,
- attributes
-}: {
- codesList: any,
- idsList: any,
- attributes: Attribute[]
-}) => {
- return attributes.reduce(
- reduceAttributes, { attrHashByCode: codesList, attrHashById: idsList }
- )
-}
-
-export default reduceAttributesLists
diff --git a/core/modules/catalog/helpers/registerProductsMapping.ts b/core/modules/catalog/helpers/registerProductsMapping.ts
deleted file mode 100644
index 13ebf84d25..0000000000
--- a/core/modules/catalog/helpers/registerProductsMapping.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { transformProductUrl } from '@vue-storefront/core/modules/url/helpers/transformUrl';
-import { localizedDispatcherRoute } from '@vue-storefront/core/lib/multistore';
-import { ActionContext } from 'vuex'
-import RootState from '@vue-storefront/core/types/RootState'
-
-export default async function registerProductsMapping ({ dispatch }: ActionContext, products = []): Promise {
- await Promise.all(products.map(product => {
- if (product.url_path) {
- const { url_path, sku, slug, type_id, parentSku } = product
- return dispatch('url/registerMapping', {
- url: localizedDispatcherRoute(url_path),
- routeData: transformProductUrl({ sku, parentSku, slug, type_id })
- }, { root: true })
- }
- }))
-}
diff --git a/core/modules/catalog/helpers/search.ts b/core/modules/catalog/helpers/search.ts
deleted file mode 100644
index 2be2cf5aac..0000000000
--- a/core/modules/catalog/helpers/search.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import Vue from 'vue';
-import { Logger } from '@vue-storefront/core/lib/logger';
-import config from 'config';
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager';
-import { entityKeyName } from '@vue-storefront/core/lib/store/entities';
-
-export const canCache = ({ includeFields, excludeFields }) => {
- const isCacheable = includeFields === null && excludeFields === null;
-
- if (isCacheable) {
- Logger.debug('Entity cache is enabled for productList')();
- } else {
- Logger.debug('Entity cache is disabled for productList')();
- }
-
- return isCacheable;
-};
-
-const getCacheKey = (product, cacheByKey) => {
- if (!product[cacheByKey]) {
- cacheByKey = 'id';
- }
-
- return entityKeyName(
- cacheByKey,
- product[cacheByKey === 'sku' && product['parentSku'] ? 'parentSku' : cacheByKey]
- ); // to avoid caching products by configurable_children.sku
-};
-
-export const configureChildren = product => {
- if (product.configurable_children) {
- for (let configurableChild of product.configurable_children) {
- if (configurableChild.custom_attributes) {
- for (let opt of configurableChild.custom_attributes) {
- configurableChild[opt.attribute_code] = opt.value;
- }
- }
- }
- }
-
- return product;
-};
-
-export const storeProductToCache = (product, cacheByKey) => {
- const cacheKey = getCacheKey(product, cacheByKey);
- const cache = StorageManager.get('elasticCache');
-
- cache.setItem(cacheKey, product, null, config.products.disablePersistentProductsCache)
-};
-
-export const preConfigureProduct = ({ product, populateRequestCacheTags }) => {
- const shouldPopulateCacheTags = populateRequestCacheTags && Vue.prototype.$cacheTags;
- const isFirstVariantAsDefaultInURL =
- config.products.setFirstVarianAsDefaultInURL &&
- product.hasOwnProperty('configurable_children') &&
- product.configurable_children.length > 0;
- product.errors = {}; // this is an object to store validation result for custom options and others
- product.info = {};
-
- if (shouldPopulateCacheTags) {
- Vue.prototype.$cacheTags.add(`P${product.id}`);
- }
-
- if (!product.parentSku) {
- product.parentSku = product.sku;
- }
-
- if (isFirstVariantAsDefaultInURL) {
- product.sku = product.configurable_children[0].sku;
- }
-
- return product;
-};
-
-export const getOptimizedFields = ({ excludeFields, includeFields }) => {
- if (config.entities.optimize) {
- return {
- excluded: excludeFields || config.entities.product.excludeFields,
- included: includeFields || config.entities.product.includeFields
- };
- }
-
- return { excluded: excludeFields, included: includeFields };
-};
-
-export const isGroupedOrBundle = product =>
- product.type_id === 'grouped' || product.type_id === 'bundle';
diff --git a/core/modules/catalog/helpers/slugifyCategories.ts b/core/modules/catalog/helpers/slugifyCategories.ts
deleted file mode 100644
index 930cf18749..0000000000
--- a/core/modules/catalog/helpers/slugifyCategories.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import config from 'config'
-import { slugify } from '@vue-storefront/core/helpers'
-import { Category, ChildrenData } from '@vue-storefront/core/modules/catalog-next/types/Category'
-
-const createSlug = (category: ChildrenData): string => {
- if (category.url_key && config.products.useMagentoUrlKeys) {
- return category.url_key
- }
-
- return `${slugify(category.name)}-${category.id}`
-}
-
-const slugifyCategories = (category: Category | ChildrenData): Category | ChildrenData => {
- if (category.children_data) {
- category.children_data.forEach((subCat: ChildrenData): void => {
- if (subCat.name && !subCat.slug) {
- slugifyCategories({ ...subCat, slug: createSlug(subCat) } as any as ChildrenData)
- }
- })
- }
- return category
-}
-
-export default slugifyCategories
diff --git a/core/modules/catalog/helpers/stock/filterChildrenByStockitem.ts b/core/modules/catalog/helpers/stock/filterChildrenByStockitem.ts
deleted file mode 100644
index c41fca73a0..0000000000
--- a/core/modules/catalog/helpers/stock/filterChildrenByStockitem.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Add 'stock' object to 'configurable_children' and filter configurable child that is not available
- */
-export default function filterChildrenByStockitem (product, stockItems = []) {
- for (const stockItem of stockItems) {
- const confChild = product.configurable_children.find((child) => child.id === stockItem.product_id)
- if (!stockItem.is_in_stock || (confChild && confChild.status >= 2/* conf child is disabled */)) {
- product.configurable_children = product.configurable_children.filter((child) => child.id !== stockItem.product_id)
- } else {
- if (confChild) {
- confChild.stock = stockItem
- }
- }
- }
-}
diff --git a/core/modules/catalog/helpers/stock/filterOutUnavailableVariants.ts b/core/modules/catalog/helpers/stock/filterOutUnavailableVariants.ts
deleted file mode 100644
index cdb0778632..0000000000
--- a/core/modules/catalog/helpers/stock/filterOutUnavailableVariants.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import filterChildrenByStockitem from './filterChildrenByStockitem'
-import { hasConfigurableChildren } from './..';
-
-/**
- * Add 'stock' object to product. If product is out of stock then add error to product.
- * Also check all children for configurable products and remove if any children is out of stock.
- */
-export default function filterOutUnavailableVariants (product, stockItems = []) {
- const productStockItem = stockItems.find(p => p.product_id === product.id)
- product.stock = productStockItem
- if (productStockItem && !productStockItem.is_in_stock) {
- product.errors.variants = 'No available product variants'
- }
-
- if (product.type_id === 'configurable' && hasConfigurableChildren(product)) {
- filterChildrenByStockitem(product, stockItems)
- }
-}
diff --git a/core/modules/catalog/helpers/stock/getProductInfos.ts b/core/modules/catalog/helpers/stock/getProductInfos.ts
deleted file mode 100644
index 66f646e908..0000000000
--- a/core/modules/catalog/helpers/stock/getProductInfos.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-const getProductInfos = (products) => products.map(product => ({
- is_in_stock: product.is_in_stock,
- qty: product.qty,
- product_id: product.product_id
-}))
-
-export default getProductInfos
diff --git a/core/modules/catalog/helpers/stock/getStatus.ts b/core/modules/catalog/helpers/stock/getStatus.ts
deleted file mode 100644
index 552ffddf4e..0000000000
--- a/core/modules/catalog/helpers/stock/getStatus.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-const getStatus = (product, defaultStatus) => {
- if (product.stock) {
- return product.stock.is_in_stock ? 'ok' : 'out_of_stock'
- }
-
- return defaultStatus
-}
-
-export default getStatus
diff --git a/core/modules/catalog/helpers/stock/getStockItems.ts b/core/modules/catalog/helpers/stock/getStockItems.ts
deleted file mode 100644
index 76e5b98b95..0000000000
--- a/core/modules/catalog/helpers/stock/getStockItems.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { StockService } from '@vue-storefront/core/data-resolver';
-import config from 'config'
-
-/**
- * Get products skus and products children skus. Based on that search for stock objects and return them.
- */
-export default async function getStockItems (products) {
- const skuArray = products.map(({ sku, configurable_children = [] }) => {
- const childSkus = configurable_children.map((c) => c.sku)
- return [sku, ...childSkus]
- }).reduce((acc, curr) => acc.concat(curr), [])
- if (!config.stock.synchronize) return
- try {
- const task = await StockService.list(skuArray)
-
- if (task.resultCode === 200) {
- return task.result
- }
- return []
- } catch (err) {
- console.error(err)
- return []
- }
-}
diff --git a/core/modules/catalog/helpers/stock/index.ts b/core/modules/catalog/helpers/stock/index.ts
deleted file mode 100644
index fa4c682999..0000000000
--- a/core/modules/catalog/helpers/stock/index.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import getStatus from './getStatus'
-import getProductInfos from './getProductInfos'
-import getStockItems from './getStockItems'
-import filterOutUnavailableVariants from './filterOutUnavailableVariants'
-
-export {
- getStatus,
- getProductInfos,
- getStockItems,
- filterOutUnavailableVariants
-}
diff --git a/core/modules/catalog/helpers/taxCalc.ts b/core/modules/catalog/helpers/taxCalc.ts
deleted file mode 100644
index 46bdd61c02..0000000000
--- a/core/modules/catalog/helpers/taxCalc.ts
+++ /dev/null
@@ -1,230 +0,0 @@
-import camelCase from 'lodash-es/camelCase'
-import dayjs from 'dayjs'
-
-// this is the mirror copy of taxcalc.js from VSF API
-
-function isSpecialPriceActive (fromDate, toDate) {
- if (!fromDate && !toDate) {
- return true
- }
-
- const now = dayjs()
- fromDate = fromDate ? dayjs(fromDate) : false
- toDate = toDate ? dayjs(toDate) : false
-
- if (fromDate && toDate) {
- return fromDate.isBefore(now) && now.isBefore(toDate)
- }
-
- if (fromDate && !toDate) {
- return fromDate.isBefore(now)
- }
-
- if (!fromDate && toDate) {
- return now.isBefore(toDate)
- }
-}
-
-/**
- * change object keys to camelCase
- */
-function toCamelCase (obj: Record = {}): Record {
- return Object.keys(obj).reduce((accObj, currKey) => {
- accObj[camelCase(currKey)] = obj[currKey]
- return accObj
- }, {})
-}
-
-/**
- * Create price object with base price and tax
- * @param price - product price which is used to extract tax value
- * @param rateFactor - tax % in decimal
- * @param isPriceInclTax - determines if price already include tax
- */
-function createSinglePrice (price: number, rateFactor: number, isPriceInclTax: boolean) {
- const _price = isPriceInclTax ? price / (1 + rateFactor) : price
- const tax = _price * rateFactor
-
- return { price: _price, tax }
-}
-
-interface AssignPriceParams {
- product: any,
- target: string,
- price: number,
- tax?: number,
- deprecatedPriceFieldsSupport?: boolean
-}
-/**
- * assign price and tax to product with proper keys
- * @param AssignPriceParams
- */
-function assignPrice ({ product, target, price, tax = 0, deprecatedPriceFieldsSupport = true }: AssignPriceParams): void {
- let priceUpdate = {
- [target]: price,
- [`${target}_tax`]: tax,
- [`${target}_incl_tax`]: price + tax
- }
-
- if (deprecatedPriceFieldsSupport) {
- /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */
- priceUpdate = Object.assign(priceUpdate, toCamelCase(priceUpdate))
- /** END */
- }
-
- Object.assign(product, priceUpdate)
-}
-
-export function updateProductPrices ({ product, rate, sourcePriceInclTax = false, deprecatedPriceFieldsSupport = false, finalPriceInclTax = true }) {
- const rate_factor = parseFloat(rate.rate) / 100
- const hasOriginalPrices = (
- product.hasOwnProperty('original_price') &&
- product.hasOwnProperty('original_final_price') &&
- product.hasOwnProperty('original_special_price')
- )
-
- // build objects with original price and tax
- // for first calculation use `price`, for next one use `original_price`
- const priceWithTax = createSinglePrice(parseFloat(product.original_price || product.price), rate_factor, sourcePriceInclTax && !hasOriginalPrices)
- const finalPriceWithTax = createSinglePrice(parseFloat(product.original_final_price || product.final_price), rate_factor, finalPriceInclTax && !hasOriginalPrices)
- const specialPriceWithTax = createSinglePrice(parseFloat(product.original_special_price || product.special_price), rate_factor, sourcePriceInclTax && !hasOriginalPrices)
-
- // save original prices
- if (!hasOriginalPrices) {
- assignPrice({ product, target: 'original_price', ...priceWithTax, deprecatedPriceFieldsSupport })
-
- if (specialPriceWithTax.price) {
- product.original_special_price = specialPriceWithTax.price
- }
-
- if (finalPriceWithTax.price) {
- product.original_final_price = finalPriceWithTax.price
- }
- }
-
- // reset previous calculation
- assignPrice({ product, target: 'price', ...priceWithTax, deprecatedPriceFieldsSupport })
-
- if (specialPriceWithTax.price) {
- assignPrice({ product, target: 'special_price', ...specialPriceWithTax, deprecatedPriceFieldsSupport })
- }
- if (finalPriceWithTax.price) {
- assignPrice({ product, target: 'final_price', ...finalPriceWithTax, deprecatedPriceFieldsSupport })
- }
-
- if (product.final_price) {
- if (product.final_price < product.price) { // compare the prices with the product final price if provided; final prices is used in case of active catalog promo rules for example
- assignPrice({ product, target: 'price', ...finalPriceWithTax, deprecatedPriceFieldsSupport })
- if (product.special_price && product.final_price < product.special_price) { // for VS - special_price is any price lowered than regular price (`price`); in Magento there is a separate mechanism for setting the `special_prices`
- assignPrice({ product, target: 'price', ...specialPriceWithTax, deprecatedPriceFieldsSupport }) // if the `final_price` is lower than the original `special_price` - it means some catalog rules were applied over it
- assignPrice({ product, target: 'special_price', ...finalPriceWithTax, deprecatedPriceFieldsSupport })
- } else {
- assignPrice({ product, target: 'price', ...finalPriceWithTax, deprecatedPriceFieldsSupport })
- }
- }
- }
-
- if (product.special_price && (product.special_price < product.original_price)) {
- if (!isSpecialPriceActive(product.special_from_date, product.special_to_date)) {
- // out of the dates period
- assignPrice({ product, target: 'special_price', price: 0, tax: 0, deprecatedPriceFieldsSupport })
- } else {
- assignPrice({ product, target: 'price', ...specialPriceWithTax, deprecatedPriceFieldsSupport })
- }
- } else {
- // the same price as original; it's not a promotion
- assignPrice({ product, target: 'special_price', price: 0, tax: 0, deprecatedPriceFieldsSupport })
- }
-
- if (product.configurable_children) {
- for (let configurableChild of product.configurable_children) {
- if (configurableChild.custom_attributes) {
- for (let opt of configurableChild.custom_attributes) {
- configurableChild[opt.attribute_code] = opt.value
- }
- }
-
- // update children prices
- updateProductPrices({ product: configurableChild, rate, sourcePriceInclTax, deprecatedPriceFieldsSupport, finalPriceInclTax })
-
- if ((configurableChild.price_incl_tax <= product.price_incl_tax) || product.price === 0) { // always show the lowest price
- assignPrice({
- product,
- target: 'price',
- price: configurableChild.price,
- tax: configurableChild.price_tax,
- deprecatedPriceFieldsSupport
- })
- assignPrice({
- product,
- target: 'special_price',
- price: configurableChild.special_price,
- tax: configurableChild.special_price_tax,
- deprecatedPriceFieldsSupport
- })
- }
- }
- }
-}
-
-export function calculateProductTax ({ product, taxClasses, taxCountry = 'PL', taxRegion = '', sourcePriceInclTax = false, deprecatedPriceFieldsSupport = false, finalPriceInclTax = true, userGroupId = null, isTaxWithUserGroupIsActive }) {
- let rateFound = false
- let product_tax_class_id = parseInt(product.tax_class_id)
- if (product_tax_class_id > 0) {
- let taxClass
- if (isTaxWithUserGroupIsActive) {
- taxClass = taxClasses.find((el) =>
- el.product_tax_class_ids.indexOf(product_tax_class_id) >= 0 &&
- el.customer_tax_class_ids.indexOf(userGroupId) >= 0
- )
- } else {
- taxClass = taxClasses.find((el) => el.product_tax_class_ids.indexOf(product_tax_class_id) >= 0)
- }
-
- if (taxClass) {
- for (let rate of taxClass.rates) { // TODO: add check for zip code ranges (!)
- if (rate.tax_country_id === taxCountry && (rate.region_name === taxRegion || rate.tax_region_id === 0 || !rate.region_name)) {
- updateProductPrices({ product, rate, sourcePriceInclTax, deprecatedPriceFieldsSupport, finalPriceInclTax })
- rateFound = true
- break
- }
- }
- }
- }
- if (!rateFound) {
- updateProductPrices({ product, rate: { rate: 0 }, sourcePriceInclTax, deprecatedPriceFieldsSupport, finalPriceInclTax })
-
- product.price_incl_tax = product.price
- product.price_tax = 0
- product.special_price_incl_tax = 0
- product.special_price_tax = 0
-
- if (deprecatedPriceFieldsSupport) {
- /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */
- product.priceInclTax = product.price
- product.priceTax = 0
- product.specialPriceInclTax = 0
- product.specialPriceTax = 0
- /** END */
- }
-
- if (product.configurable_children) {
- for (let configurableChildren of product.configurable_children) {
- configurableChildren.price_incl_tax = configurableChildren.price
- configurableChildren.price_tax = 0
- configurableChildren.special_price_incl_tax = 0
- configurableChildren.special_price_tax = 0
-
- if (deprecatedPriceFieldsSupport) {
- /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */
- configurableChildren.priceInclTax = configurableChildren.price
- configurableChildren.priceTax = 0
- configurableChildren.specialPriceInclTax = 0
- configurableChildren.specialPriceTax = 0
- /** END */
- }
- }
- }
- }
- return product
-}
diff --git a/core/modules/catalog/helpers/transformMetadataToAttributes.ts b/core/modules/catalog/helpers/transformMetadataToAttributes.ts
deleted file mode 100644
index e857f10087..0000000000
--- a/core/modules/catalog/helpers/transformMetadataToAttributes.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import uniqBy from 'lodash-es/uniqBy'
-
-const transformMetadataToAttributes = (attributeMetadata) => attributeMetadata
- .reduce((prev, curr) => ([ ...prev, ...curr ]), [])
- .reduce((prev, curr) => {
- const attribute = prev.find(a => a.attribute_id === curr.attribute_id && a.options)
-
- if (attribute) {
- return prev.map(attr => {
- if (attr.attribute_id === curr.attribute_id) {
- return {
- ...attr,
- options: uniqBy([...(attr.options || []), ...(curr.options || [])], (obj) => `${obj.label}_${obj.value}`)
- }
- }
-
- return attr
- })
- }
-
- return [...prev, curr]
- }, [])
- .reduce((prev, curr) => ({
- attrHashByCode: {
- ...(prev.attrHashByCode || {}),
- [curr.attribute_code]: curr
- },
- attrHashById: {
- ...(prev.attrHashById || {}),
- [curr.attribute_id]: curr
- }
- }), { attrHashByCode: {}, attrHashById: {} })
-
-export default transformMetadataToAttributes
diff --git a/core/modules/catalog/helpers/variant/findConfigurableVariant.ts b/core/modules/catalog/helpers/variant/findConfigurableVariant.ts
deleted file mode 100644
index 3587d57f54..0000000000
--- a/core/modules/catalog/helpers/variant/findConfigurableVariant.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import getConfigurationMatchLevel from './getConfigurationMatchLevel'
-import getVariantWithLowestPrice from './getVariantWithLowestPrice'
-import config from 'config'
-
-/**
- * This function responsiblity is to find best matching variant for configurable product based on configuration object or stock availability.
- */
-export default function findConfigurableVariant ({ product, configuration = null, selectDefaultChildren = false, availabilityCheck = true }) {
- const selectedVariant = product.configurable_children.reduce((prevVariant, nextVariant) => {
- if (availabilityCheck) {
- if (nextVariant.stock && !config.products.listOutOfStockProducts) {
- if (!nextVariant.stock.is_in_stock) {
- return prevVariant
- }
- }
- }
- if (nextVariant.status >= 2/** disabled product */) {
- return prevVariant
- }
- if (selectDefaultChildren) {
- return prevVariant || nextVariant // return first
- }
- if (
- (configuration && configuration.sku) &&
- (nextVariant.sku === configuration.sku)
- ) { // by sku or first one
- return nextVariant
- } else {
- // get match level for each variant
- const prevVariantMatch = getConfigurationMatchLevel(configuration, prevVariant)
- const nextVariantMatch = getConfigurationMatchLevel(configuration, nextVariant)
-
- // if we have draw between prev variant and current variant then return one that has lowest price
- if (prevVariantMatch === nextVariantMatch) {
- return getVariantWithLowestPrice(prevVariant, nextVariant)
- }
-
- // return variant with best matching level
- return nextVariantMatch > prevVariantMatch ? nextVariant : prevVariant
- }
- }, undefined)
- return selectedVariant
-}
diff --git a/core/modules/catalog/helpers/variant/getConfigurationMatchLevel.ts b/core/modules/catalog/helpers/variant/getConfigurationMatchLevel.ts
deleted file mode 100644
index c49a71624b..0000000000
--- a/core/modules/catalog/helpers/variant/getConfigurationMatchLevel.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import toString from 'lodash-es/toString'
-import omit from 'lodash-es/omit'
-
-/**
- * Counts how much coniguration match for specific variant
- */
-export default function getConfigurationMatchLevel (configuration, variant): number {
- if (!variant || !configuration) return 0
- const configProperties = Object.keys(omit(configuration, ['price']))
- return configProperties
- .map(configProperty => {
- const variantPropertyId = variant[configProperty]
- if (configuration[configProperty] === null) {
- return false
- }
-
- return [].concat(configuration[configProperty])
- .map(f => typeof f === 'object' ? toString(f.id) : f)
- .includes(toString(variantPropertyId))
- })
- .filter(Boolean)
- .length
-}
diff --git a/core/modules/catalog/helpers/variant/getSelectedVariant.ts b/core/modules/catalog/helpers/variant/getSelectedVariant.ts
deleted file mode 100644
index 359705bfa4..0000000000
--- a/core/modules/catalog/helpers/variant/getSelectedVariant.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import findConfigurableVariant from './findConfigurableVariant'
-
-/**
- * Returns product based on configuration or if there is no match then return first variant as default.
- */
-export default function getSelectedVariant (product, configuration, { fallbackToDefaultWhenNoAvailable }) {
- let selectedVariant = findConfigurableVariant({ product, configuration, availabilityCheck: true })
- if (!selectedVariant) {
- if (fallbackToDefaultWhenNoAvailable) {
- selectedVariant = findConfigurableVariant({ product, selectDefaultChildren: true, availabilityCheck: true }) // return first available child
- }
- }
-
- return selectedVariant
-}
diff --git a/core/modules/catalog/helpers/variant/getVariantWithLowestPrice.ts b/core/modules/catalog/helpers/variant/getVariantWithLowestPrice.ts
deleted file mode 100644
index 1dbfa6879b..0000000000
--- a/core/modules/catalog/helpers/variant/getVariantWithLowestPrice.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Makes product variants comparission and returns variant with lowest price
- */
-export default function getVariantWithLowestPrice (prevVariant, nextVariant) {
- if (!prevVariant || !prevVariant.original_price_incl_tax) {
- return nextVariant
- }
-
- const prevPrice = prevVariant.price_incl_tax || prevVariant.original_price_incl_tax
- const nextPrice = nextVariant.price_incl_tax || nextVariant.original_price_incl_tax
- return nextPrice < prevPrice ? nextVariant : prevVariant
-}
diff --git a/core/modules/catalog/helpers/variant/index.ts b/core/modules/catalog/helpers/variant/index.ts
deleted file mode 100644
index 6a9bdc17a1..0000000000
--- a/core/modules/catalog/helpers/variant/index.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import omitSelectedVariantFields from './omitSelectedVariantFields'
-import getSelectedVariant from './getSelectedVariant'
-import isOptionAvailable from './isOptionAvailable'
-import findConfigurableVariant from './findConfigurableVariant'
-
-export {
- omitSelectedVariantFields,
- getSelectedVariant,
- isOptionAvailable,
- findConfigurableVariant
-}
diff --git a/core/modules/catalog/helpers/variant/isOptionAvailable.ts b/core/modules/catalog/helpers/variant/isOptionAvailable.ts
deleted file mode 100644
index 1c5ee5542d..0000000000
--- a/core/modules/catalog/helpers/variant/isOptionAvailable.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import findConfigurableVariant from './findConfigurableVariant'
-
-/**
- * Checks if variant with specific configuration exist
- */
-export default function isOptionAvailable (context, { product, configuration }): boolean {
- const variant = findConfigurableVariant({ product: product, configuration: configuration, availabilityCheck: true })
- return typeof variant !== 'undefined' && variant !== null
-}
diff --git a/core/modules/catalog/helpers/variant/omitSelectedVariantFields.ts b/core/modules/catalog/helpers/variant/omitSelectedVariantFields.ts
deleted file mode 100644
index f59acc883c..0000000000
--- a/core/modules/catalog/helpers/variant/omitSelectedVariantFields.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import omit from 'lodash-es/omit'
-import config from 'config'
-
-/**
- * Omit some variant fields to prevent overriding same base product fields
- */
-export default function omitSelectedVariantFields (selectedVariant): void {
- const hasImage = selectedVariant && selectedVariant.image && selectedVariant.image !== 'no_selection'
- const fieldsToOmit = config.products.omitVariantFields
- if (!hasImage) fieldsToOmit.push('image')
- return omit(selectedVariant, fieldsToOmit)
-}
diff --git a/core/modules/catalog/hooks/index.ts b/core/modules/catalog/hooks/index.ts
deleted file mode 100644
index c6b04decb3..0000000000
--- a/core/modules/catalog/hooks/index.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { createMutatorHook, createListenerHook } from '@vue-storefront/core/lib/hooks'
-import Product from '../types/Product';
-
-const {
- hook: beforeTaxesCalculatedHook,
- executor: beforeTaxesCalculatedExecutor
-} = createMutatorHook()
-
-const {
- hook: afterSetBundleProductsHook,
- executor: afterSetBundleProductsExecutor
-} = createListenerHook()
-
-const {
- hook: afterSetGroupedProductHook,
- executor: afterSetGroupedProductExecutor
-} = createListenerHook()
-
-const catalogHooksExecutors = {
- beforeTaxesCalculated: beforeTaxesCalculatedExecutor,
- afterSetBundleProducts: afterSetBundleProductsExecutor,
- afterSetGroupedProduct: afterSetGroupedProductExecutor
-}
-
-const catalogHooks = {
- beforeTaxesCalculated: beforeTaxesCalculatedHook,
- afterSetBundleProducts: afterSetBundleProductsHook,
- afterSetGroupedProduct: afterSetGroupedProductHook
-}
-
-export {
- catalogHooks,
- catalogHooksExecutors
-}
diff --git a/core/modules/catalog/index.ts b/core/modules/catalog/index.ts
deleted file mode 100644
index ce3cc6dd7a..0000000000
--- a/core/modules/catalog/index.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { StorefrontModule } from '@vue-storefront/core/lib/modules'
-import { productModule } from './store/product'
-import { attributeModule } from './store/attribute'
-import { stockModule } from './store/stock'
-import { taxModule } from './store/tax'
-import { categoryModule } from './store/category'
-import { catalogHooks } from './hooks'
-import { getAttributesFromMetadata } from './helpers/associatedProducts'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import config from 'config'
-import { filterChangedProduct, productAfterCustomoptions, productAfterBundleoptions, productAfterPriceupdate, onUserPricesRefreshed } from './events'
-import { isServer } from '@vue-storefront/core/helpers'
-import uniq from 'lodash-es/uniq'
-
-export const CatalogModule: StorefrontModule = async function ({ store, router, appConfig }) {
- StorageManager.init('categories')
- StorageManager.init('attributes')
- StorageManager.init('products')
- StorageManager.init('elasticCache', true, appConfig.server.elasticCacheQuota)
-
- store.registerModule('product', productModule)
- store.registerModule('attribute', attributeModule)
- store.registerModule('stock', stockModule)
- store.registerModule('tax', taxModule)
- store.registerModule('category', categoryModule)
-
- catalogHooks.afterSetBundleProducts(products => getAttributesFromMetadata(store, products))
- catalogHooks.afterSetGroupedProduct(products => getAttributesFromMetadata(store, products))
-
- if (!config.entities.attribute.loadByAttributeMetadata) {
- await store.dispatch('attribute/list', { // loading attributes for application use
- filterValues: uniq([...config.products.defaultFilters, ...config.entities.productListWithChildren.includeFields])
- })
- }
-
- if (!isServer) {
- // Things moved from Product.js
- EventBus.$on('product-after-priceupdate', product => productAfterPriceupdate(product, store))
- EventBus.$on('filter-changed-product', filterOptions => filterChangedProduct(filterOptions, store, router))
- EventBus.$on('product-after-customoptions', payload => productAfterCustomoptions(payload, store))
- EventBus.$on('product-after-bundleoptions', payload => productAfterBundleoptions(payload, store))
-
- if (config.usePriceTiers || store.getters['tax/getIsUserGroupedTaxActive']) {
- EventBus.$on('user-after-loggedin', onUserPricesRefreshed.bind(null, store, router))
- EventBus.$on('user-after-logout', onUserPricesRefreshed.bind(null, store, router))
- }
- }
-}
diff --git a/core/modules/catalog/queries/common.js b/core/modules/catalog/queries/common.js
deleted file mode 100644
index adcc18346d..0000000000
--- a/core/modules/catalog/queries/common.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { SearchQuery } from 'storefront-query-builder'
-import config from 'config'
-
-export function prepareQuery ({ queryText = '', filters = [], queryConfig = '' }) {
- let query = new SearchQuery()
- // prepare filters and searchText
- if (filters.length === 0 && queryConfig !== '') {
- // try get filters from config
- if (config.hasOwnProperty('query') && config.query.hasOwnProperty(queryConfig) && config.query[queryConfig].hasOwnProperty('filter')) {
- filters = config.query[queryConfig].filter
- }
- }
-
- if (queryText === '') {
- // try to get searchText from config
- if (config.hasOwnProperty('query') && config.query.hasOwnProperty(queryConfig) && config.query[queryConfig].hasOwnProperty('searchText')) {
- queryText = config.query[queryConfig].searchText
- }
- }
-
- // Process filters and searchText if exists
- if (filters.length > 0) {
- filters.forEach(filter => {
- query = query.applyFilter({ key: filter.key, value: filter.value }) // Tees category
- })
- }
-
- if (queryText !== '') {
- query = query.setSearchText(queryText)
- }
-
- // Add basic filters
- query = query
- .applyFilter({ key: 'visibility', value: { 'in': [2, 3, 4] } })
- .applyFilter({ key: 'status', value: { 'in': [0, 1] } })
-
- return query
-}
diff --git a/core/modules/catalog/queries/related.js b/core/modules/catalog/queries/related.js
deleted file mode 100644
index 12a0d46da4..0000000000
--- a/core/modules/catalog/queries/related.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { SearchQuery } from 'storefront-query-builder'
-import config from 'config'
-
-export function prepareRelatedQuery (key, sku) {
- let relatedProductsQuery = new SearchQuery()
-
- relatedProductsQuery = relatedProductsQuery.applyFilter({ key: key, value: { 'in': sku } })
-
- relatedProductsQuery = relatedProductsQuery
- .applyFilter({ key: 'visibility', value: { 'in': [2, 3, 4] } })
- .applyFilter({ key: 'status', value: { 'in': [1] } })
-
- if (config.products.listOutOfStockProducts === false) {
- relatedProductsQuery = relatedProductsQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } })
- }
-
- return relatedProductsQuery
-}
diff --git a/core/modules/catalog/queries/searchPanel.js b/core/modules/catalog/queries/searchPanel.js
deleted file mode 100644
index 3543093f0b..0000000000
--- a/core/modules/catalog/queries/searchPanel.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { SearchQuery } from 'storefront-query-builder'
-import config from 'config'
-
-export function prepareQuickSearchQuery (queryText) {
- let searchQuery = new SearchQuery()
-
- searchQuery = searchQuery
- .setSearchText(queryText)
- .applyFilter({ key: 'visibility', value: { 'in': [3, 4] } })
- .applyFilter({ key: 'status', value: { 'in': [0, 1] } })/* 2 = disabled, 3 = out of stock */
-
- if (config.products.listOutOfStockProducts === false) {
- searchQuery = searchQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } })
- }
-
- return searchQuery
-}
diff --git a/core/modules/catalog/store/attribute/actions.ts b/core/modules/catalog/store/attribute/actions.ts
deleted file mode 100644
index d89fa32463..0000000000
--- a/core/modules/catalog/store/attribute/actions.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import * as types from './mutation-types'
-import { quickSearchByQuery } from '@vue-storefront/core/lib/search'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import AttributeState from '@vue-storefront/core/modules/catalog/types/AttributeState'
-import RootState from '@vue-storefront/core/types/RootState'
-import { ActionTree } from 'vuex'
-import config from 'config'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { entityKeyName } from '@vue-storefront/core/lib/store/entities'
-import { prefetchCachedAttributes } from '@vue-storefront/core/modules/catalog/helpers/prefetchCachedAttributes'
-import createAttributesListQuery from '@vue-storefront/core/modules/catalog/helpers/createAttributesListQuery'
-import reduceAttributesLists from '@vue-storefront/core/modules/catalog/helpers/reduceAttributesLists'
-import transformMetadataToAttributes from '@vue-storefront/core/modules/catalog/helpers/transformMetadataToAttributes'
-import filterAttributes from '@vue-storefront/core/modules/catalog/helpers/filterAttributes'
-
-const actions: ActionTree = {
- async updateAttributes ({ commit, getters }, { attributes }) {
- const idsList = getters.getAttributeListById
- const codesList = getters.getAttributeListByCode
-
- for (let attr of attributes) {
- if (attr && !config.attributes.disablePersistentAttributesCache) {
- const attrCollection = StorageManager.get('attributes')
-
- try {
- await attrCollection.setItem(entityKeyName('attribute_code', attr.attribute_code.toLowerCase()), attr)
- await attrCollection.setItem(entityKeyName('attribute_id', attr.attribute_id.toString()), attr)
- } catch (e) {
- Logger.error(e, 'mutations')()
- }
- }
- }
-
- commit(types.ATTRIBUTE_UPD_ATTRIBUTES, reduceAttributesLists({ codesList, idsList, attributes }))
- },
- async loadCachedAttributes ({ dispatch }, { filterField, filterValues }) {
- if (!filterValues) {
- return
- }
-
- const attributes = await prefetchCachedAttributes(filterField, filterValues)
-
- if (attributes) {
- await dispatch('updateAttributes', { attributes })
- }
- },
- updateBlacklist ({ commit, getters }, { filterValues, filterField, attributes }) {
- if (attributes && filterValues.length > 0) {
- const foundValues = attributes.map(attr => attr[filterField])
- const toBlackList = filterValues.filter(ofv => !foundValues.includes(ofv) && !getters.getBlacklist.includes(ofv))
- commit(types.ATTRIBUTE_UPD_BLACKLIST, toBlackList)
- }
- },
- /**
- * Load attributes with specific codes
- * @param {Object} context
- * @param {Array} attrCodes attribute codes to load
- */
- async list ({ getters, dispatch }, { filterValues = null, filterField = 'attribute_code', only_user_defined = false, only_visible = false, size = 150, start = 0, includeFields = config.entities.optimize ? config.entities.attribute.includeFields : null }) {
- const blacklist = getters.getBlacklist
- const idsList = getters.getAttributeListById
- const codesList = getters.getAttributeListByCode
- const orgFilterValues = filterValues || []
-
- await dispatch('loadCachedAttributes', { filterField, filterValues })
-
- filterValues = filterAttributes({ filterValues, filterField, blacklist, idsList, codesList })
- if (filterValues.length === 0) {
- Logger.info('Skipping attribute load - attributes already loaded', 'attr', { orgFilterValues, filterField })()
- return { items: Object.values(codesList) }
- }
-
- const query = createAttributesListQuery({
- filterValues,
- filterField,
- onlyDefinedByUser: only_user_defined,
- onlyVisible: only_visible
- })
- const resp = await quickSearchByQuery({ entityType: 'attribute', query, includeFields, start, size })
- const attributes = resp && orgFilterValues.length > 0 ? resp.items : null
-
- dispatch('updateBlacklist', { filterValues, filterField, attributes })
- await dispatch('updateAttributes', { attributes })
-
- return resp
- },
- async loadProductAttributes (context, { products, merge = false }) {
- const attributeMetadata = products
- .filter(product => product.attributes_metadata)
- .map(product => product.attributes_metadata)
-
- const attributes = transformMetadataToAttributes(attributeMetadata)
-
- if (merge) {
- attributes.attrHashByCode = { ...attributes.attrHashByCode, ...context.state.list_by_code }
- attributes.attrHashById = { ...attributes.attrHashById, ...context.state.list_by_id }
- }
-
- context.commit(types.ATTRIBUTE_UPD_ATTRIBUTES, attributes)
- },
- async loadCategoryAttributes (context, { attributeMetadata }) {
- if (!attributeMetadata) return
- const attributes = transformMetadataToAttributes([attributeMetadata])
-
- context.commit(types.ATTRIBUTE_UPD_ATTRIBUTES, attributes)
- }
-}
-
-export default actions
diff --git a/core/modules/catalog/store/attribute/getters.ts b/core/modules/catalog/store/attribute/getters.ts
deleted file mode 100644
index 13a87bce0d..0000000000
--- a/core/modules/catalog/store/attribute/getters.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { GetterTree } from 'vuex'
-import AttributeState from '../../types/AttributeState'
-import RootState from '@vue-storefront/core/types/RootState'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-const getters: GetterTree = {
- getAttributeListByCode: (state) => state.list_by_code,
- getAttributeListById: (state) => state.list_by_id,
- // @deprecated
- attributeListByCode: (state, getters) => getters.getAttributeListByCode,
- // @deprecated
- attributeListById: (state, getters) => getters.getAttributeListById,
- getBlacklist: (state) => state.blacklist,
- getAllComparableAttributes: (state, getters) => {
- const attributesByCode = getters.getAttributeListByCode
- return Object.values(attributesByCode).filter((a: any) => ['1', true].includes(a.is_comparable)) // In some cases we get boolean instead of "0"/"1" that why we support both options
- }
-}
-
-export default getters
diff --git a/core/modules/catalog/store/attribute/index.ts b/core/modules/catalog/store/attribute/index.ts
deleted file mode 100644
index 9a747e3aba..0000000000
--- a/core/modules/catalog/store/attribute/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Module } from 'vuex'
-import actions from './actions'
-import getters from './getters'
-import mutations from './mutations'
-import RootState from '@vue-storefront/core/types/RootState'
-import AttributeState from '../../types/AttributeState'
-
-export const attributeModule: Module = {
- namespaced: true,
- state: {
- list_by_code: {},
- list_by_id: {},
- blacklist: [],
- labels: {}
- },
- getters,
- actions,
- mutations
-}
diff --git a/core/modules/catalog/store/attribute/mutation-types.ts b/core/modules/catalog/store/attribute/mutation-types.ts
deleted file mode 100644
index 67254b063a..0000000000
--- a/core/modules/catalog/store/attribute/mutation-types.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const SN_ATTRIBUTE = 'attribute'
-export const ATTRIBUTE_UPD_ATTRIBUTES = SN_ATTRIBUTE + '/UPD_ATTRIBUTES'
-export const ATTRIBUTE_UPD_BLACKLIST = SN_ATTRIBUTE + '/UPD_BLACKLIST_ATTRIBUTES'
diff --git a/core/modules/catalog/store/attribute/mutations.ts b/core/modules/catalog/store/attribute/mutations.ts
deleted file mode 100644
index 1a7f23a998..0000000000
--- a/core/modules/catalog/store/attribute/mutations.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import Vue from 'vue'
-import { MutationTree } from 'vuex'
-import * as types from './mutation-types'
-import AttributeState from '../../types/AttributeState'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-
-const mutations: MutationTree = {
- /**
- * Store attributes by code in state and localForage
- * @param {} state
- * @param {Array} attributes
- */
- async [types.ATTRIBUTE_UPD_ATTRIBUTES] (state, { attrHashByCode, attrHashById }) {
- Vue.set(state, 'list_by_code', attrHashByCode)
- Vue.set(state, 'list_by_id', attrHashById)
- EventBus.$emit('product-after-attributes-loaded')
- },
- [types.ATTRIBUTE_UPD_BLACKLIST] (state, blacklist) {
- state.blacklist = state.blacklist.concat(blacklist)
- }
-}
-
-export default mutations
diff --git a/core/modules/catalog/store/category/actions.ts b/core/modules/catalog/store/category/actions.ts
deleted file mode 100644
index e309307a46..0000000000
--- a/core/modules/catalog/store/category/actions.ts
+++ /dev/null
@@ -1,368 +0,0 @@
-import Vue from 'vue'
-import { ActionTree } from 'vuex'
-import * as types from './mutation-types'
-import { quickSearchByQuery } from '@vue-storefront/core/lib/search'
-import { entityKeyName } from '@vue-storefront/core/lib/store/entities'
-import rootStore from '@vue-storefront/core/store'
-import i18n from '@vue-storefront/i18n'
-import chunk from 'lodash-es/chunk'
-import trim from 'lodash-es/trim'
-import toString from 'lodash-es/toString'
-import { optionLabel } from '../../helpers/optionLabel'
-import RootState from '@vue-storefront/core/types/RootState'
-import CategoryState from '../../types/CategoryState'
-import { currentStoreView, localizedDispatcherRoute, localizedDispatcherRouteName } from '@vue-storefront/core/lib/multistore'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { isServer } from '@vue-storefront/core/helpers'
-import config from 'config'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import createCategoryListQuery from '@vue-storefront/core/modules/catalog/helpers/createCategoryListQuery'
-import { formatCategoryLink } from 'core/modules/url/helpers'
-import { transformCategoryUrl } from '@vue-storefront/core/modules/url/helpers/transformUrl';
-
-const actions: ActionTree = {
- /**
- * Reset current category and path
- * @param {Object} context
- */
- reset (context) {
- context.commit(types.CATEGORY_UPD_CURRENT_CATEGORY_PATH, [])
- context.commit(types.CATEGORY_UPD_CURRENT_CATEGORY, {})
- rootStore.dispatch('stock/clearCache')
- EventBus.$emit('category-after-reset', { })
- },
- /**
- * Load categories within specified parent
- * @param {Object} commit promise
- * @param {Object} parent parent category
- */
- async list ({ commit, state, dispatch }, { parent = null, key = null, value = null, level = null, onlyActive = true, onlyNotEmpty = false, size = 4000, start = 0, sort = 'position:asc', includeFields = config.entities.optimize ? config.entities.category.includeFields : null, excludeFields = config.entities.optimize ? config.entities.category.excludeFields : null, skipCache = false, updateState = true }) {
- const { searchQuery, isCustomizedQuery } = createCategoryListQuery({ parent, level, key, value, onlyActive, onlyNotEmpty })
- const shouldLoadCategories = skipCache || ((!state.list || state.list.length === 0) || isCustomizedQuery)
-
- if (shouldLoadCategories) {
- const resp = await quickSearchByQuery({ entityType: 'category', query: searchQuery, sort, size, start, includeFields, excludeFields })
-
- if (updateState) {
- await dispatch('registerCategoryMapping', { categories: resp.items })
-
- commit(types.CATEGORY_UPD_CATEGORIES, { ...resp, includeFields, excludeFields })
- EventBus.$emit('category-after-list', { query: searchQuery, sort, size, start, list: resp })
- }
-
- return resp
- }
-
- const list = { items: state.list, total: state.list.length }
-
- if (updateState) {
- EventBus.$emit('category-after-list', { query: searchQuery, sort, size, start, list })
- }
-
- return list
- },
- async registerCategoryMapping ({ dispatch }, { categories }) {
- const { storeCode, appendStoreCode } = currentStoreView()
- for (let category of categories) {
- if (category.url_path) {
- await dispatch('url/registerMapping', {
- url: localizedDispatcherRoute(category.url_path, storeCode),
- routeData: transformCategoryUrl(category)
- }, { root: true })
- }
- }
- },
-
- /**
- * Load category object by specific field - using local storage/indexed Db
- * loadCategories() should be called at first!
- * @param {Object} commit
- * @param {String} key
- * @param {String} value
- * @param {Bool} setCurrentCategory default=true and means that state.current_category is set to the one loaded
- */
- single (context, { key, value, setCurrentCategory = true, setCurrentCategoryPath = true, populateRequestCacheTags = true, skipCache = false }) {
- const state = context.state
- const commit = context.commit
- const dispatch = context.dispatch
-
- return new Promise((resolve, reject) => {
- const fetchCat = ({ key, value }) => {
- if (key !== 'id' || value >= config.entities.category.categoriesRootCategorylId/* root category */) {
- context.dispatch('list', { key: key, value: value }).then(res => {
- if (res && res.items && res.items.length) {
- setcat(null, res.items[0]) // eslint-disable-line @typescript-eslint/no-use-before-define
- } else {
- reject(new Error('Category query returned empty result ' + key + ' = ' + value))
- }
- }).catch(reject)
- } else {
- reject(new Error('Category query returned empty result ' + key + ' = ' + value))
- }
- }
- let setcat = (error, mainCategory) => {
- if (!mainCategory) {
- fetchCat({ key, value })
- return
- }
- if (error) {
- Logger.error(error)()
- reject(error)
- }
-
- if (setCurrentCategory) {
- commit(types.CATEGORY_UPD_CURRENT_CATEGORY, mainCategory)
- }
- if (populateRequestCacheTags && mainCategory && Vue.prototype.$cacheTags) {
- Vue.prototype.$cacheTags.add(`C${mainCategory.id}`)
- }
- if (setCurrentCategoryPath) {
- let currentPath = []
- let recurCatFinder = (category) => {
- if (!category) {
- return
- }
- if (category.parent_id >= config.entities.category.categoriesRootCategorylId) {
- dispatch('single', { key: 'id', value: category.parent_id, setCurrentCategory: false, setCurrentCategoryPath: false }).then((sc) => { // TODO: move it to the server side for one requests OR cache in indexedDb
- if (!sc || sc.parent_id === sc.id) {
- commit(types.CATEGORY_UPD_CURRENT_CATEGORY_PATH, currentPath)
- EventBus.$emit('category-after-single', { category: mainCategory })
- return resolve(mainCategory)
- }
- currentPath.unshift(sc)
- recurCatFinder(sc)
- }).catch(err => {
- Logger.error(err)()
- commit(types.CATEGORY_UPD_CURRENT_CATEGORY_PATH, currentPath) // this is the case when category is not binded to the root tree - for example 'Erin Recommends'
- resolve(mainCategory)
- })
- } else {
- commit(types.CATEGORY_UPD_CURRENT_CATEGORY_PATH, currentPath)
- EventBus.$emit('category-after-single', { category: mainCategory })
- resolve(mainCategory)
- }
- }
- if (typeof mainCategory !== 'undefined') {
- recurCatFinder(mainCategory) // TODO: Store breadcrumbs in IndexedDb for further usage to optimize speed?
- } else {
- reject(new Error('Category query returned empty result ' + key + ' = ' + value))
- }
- } else {
- EventBus.$emit('category-after-single', { category: mainCategory })
- resolve(mainCategory)
- }
- }
-
- let foundInLocalCache = false
- if (state.list.length > 0 && !skipCache) { // SSR - there were some issues with using localForage, so it's the reason to use local state instead, when possible
- let category = state.list.find((itm) => { return itm[key] === value })
- // Check if category exists in the store OR we have recursively reached Default category (id=1)
- if (category && value >= config.entities.category.categoriesRootCategorylId/** root category parent */) {
- foundInLocalCache = true
- setcat(null, category)
- }
- }
- if (!foundInLocalCache) {
- if (skipCache || isServer) {
- fetchCat({ key, value })
- } else {
- const catCollection = StorageManager.get('categories')
- // Check if category does not exist in the store AND we haven't recursively reached Default category (id=1)
- catCollection.getItem(entityKeyName(key, value), setcat)
- }
- }
- })
- },
- /**
- * Filter category products
- */
- products (context, { populateAggregations = false, filters = [], searchProductQuery, current = 0, perPage = 50, sort = '', includeFields = null, excludeFields = null, configuration = null, append = false, skipCache = false, cacheOnly = false }) {
- context.dispatch('setSearchOptions', {
- populateAggregations,
- filters,
- current,
- perPage,
- includeFields,
- excludeFields,
- configuration,
- append,
- sort
- })
-
- let prefetchGroupProducts = true
- if (config.entities.twoStageCaching && config.entities.optimize && !isServer && !rootStore.state.twoStageCachingDisabled) { // only client side, only when two stage caching enabled
- includeFields = config.entities.productListWithChildren.includeFields // we need configurable_children for filters to work
- excludeFields = config.entities.productListWithChildren.excludeFields
- prefetchGroupProducts = false
- Logger.log('Using two stage caching for performance optimization - executing first stage product pre-fetching')()
- } else {
- prefetchGroupProducts = true
- if (rootStore.state.twoStageCachingDisabled) {
- Logger.log('Two stage caching is disabled runtime because of no performance gain')()
- } else {
- Logger.log('Two stage caching is disabled by the config')()
- }
- }
- if (cacheOnly) {
- excludeFields = null
- includeFields = null
- Logger.log('Caching request only, no state update')()
- }
- let t0 = new Date().getTime()
-
- const precachedQuery = searchProductQuery
- let productPromise = rootStore.dispatch('product/list', {
- query: precachedQuery,
- start: current,
- size: perPage,
- excludeFields: excludeFields,
- includeFields: includeFields,
- configuration: configuration,
- append: append,
- sort: sort,
- updateState: !cacheOnly,
- prefetchGroupProducts: prefetchGroupProducts
- }).then((res) => {
- let t1 = new Date().getTime()
- rootStore.state.twoStageCachingDelta1 = t1 - t0
-
- let subloaders = []
- if (!res || (res.noresults)) {
- rootStore.dispatch('notification/spawnNotification', {
- type: 'warning',
- message: i18n.t('No products synchronized for this category. Please come back while online!'),
- action1: { label: i18n.t('OK') }
- })
- if (!append) rootStore.dispatch('product/reset')
- rootStore.state.product.list = { items: [] } // no products to show TODO: refactor to rootStore.state.category.reset() and rootStore.state.product.reset()
- // rootStore.state.category.filters = { color: [], size: [], price: [] }
- return []
- } else {
- if (config.products.filterUnavailableVariants && config.products.configurableChildrenStockPrefetchStatic) { // prefetch the stock items
- const skus = []
- let prefetchIndex = 0
- res.items.map(i => {
- if (config.products.configurableChildrenStockPrefetchStaticPrefetchCount > 0) {
- if (prefetchIndex > config.products.configurableChildrenStockPrefetchStaticPrefetchCount) return
- }
- skus.push(i.sku) // main product sku to be checked anyway
- if (i.type_id === 'configurable' && i.configurable_children && i.configurable_children.length > 0) {
- for (const confChild of i.configurable_children) {
- const cachedItem = context.rootState.stock.cache[confChild.id]
- if (typeof cachedItem === 'undefined' || cachedItem === null) {
- skus.push(confChild.sku)
- }
- }
- prefetchIndex++
- }
- })
- for (const chunkItem of chunk(skus, 15)) {
- rootStore.dispatch('stock/list', { skus: chunkItem, skipCache }) // store it in the cache
- }
- }
- if (populateAggregations === true && res.aggregations) { // populate filter aggregates
- for (let attrToFilter of filters) { // fill out the filter options
- let filterOptions = []
-
- let uniqueFilterValues = new Set()
- if (attrToFilter !== 'price') {
- if (res.aggregations['agg_terms_' + attrToFilter]) {
- let buckets = res.aggregations['agg_terms_' + attrToFilter].buckets
- if (res.aggregations['agg_terms_' + attrToFilter + '_options']) {
- buckets = buckets.concat(res.aggregations['agg_terms_' + attrToFilter + '_options'].buckets)
- }
-
- for (let option of buckets) {
- uniqueFilterValues.add(toString(option.key))
- }
- }
-
- uniqueFilterValues.forEach(key => {
- const label = optionLabel(rootStore.state.attribute, { attributeKey: attrToFilter, optionId: key })
- if (trim(label) !== '') { // is there any situation when label could be empty and we should still support it?
- filterOptions.push({
- id: key,
- label: label
- })
- }
- });
- } else { // special case is range filter for prices
- const storeView = currentStoreView()
- const currencySign = storeView.i18n.currencySign
- if (res.aggregations['agg_range_' + attrToFilter]) {
- let index = 0
- let count = res.aggregations['agg_range_' + attrToFilter].buckets.length
- for (let option of res.aggregations['agg_range_' + attrToFilter].buckets) {
- filterOptions.push({
- id: option.key,
- from: option.from,
- to: option.to,
- label: (index === 0 || (index === count - 1)) ? (option.to ? '< ' + currencySign + option.to : '> ' + currencySign + option.from) : currencySign + option.from + (option.to ? ' - ' + option.to : '')// TODO: add better way for formatting, extract currency sign
- })
- index++
- }
- }
- }
- context.dispatch('addAvailableFilter', {
- key: attrToFilter,
- options: filterOptions
- })
- }
- }
- }
- return subloaders
- }).catch((err) => {
- Logger.error(err)()
- rootStore.dispatch('notification/spawnNotification', {
- type: 'warning',
- message: i18n.t('No products synchronized for this category. Please come back while online!'),
- action1: { label: i18n.t('OK') }
- })
- })
-
- if (config.entities.twoStageCaching && config.entities.optimize && !isServer && !rootStore.state.twoStageCachingDisabled && !cacheOnly) { // second stage - request for caching entities; if cacheOnly set - the caching took place with the stage1 request!
- Logger.log('Using two stage caching for performance optimization - executing second stage product caching', 'category') // TODO: in this case we can pre-fetch products in advance getting more products than set by pageSize()
- rootStore.dispatch('product/list', {
- query: precachedQuery,
- start: current,
- size: perPage,
- excludeFields: null,
- includeFields: null,
- configuration: configuration,
- sort: sort,
- updateState: false, // not update the product listing - this request is only for caching
- prefetchGroupProducts: prefetchGroupProducts
- }).catch((err) => {
- Logger.info("Problem with second stage caching - couldn't store the data", 'category')()
- Logger.info(err, 'category')()
- }).then((res) => {
- let t2 = new Date().getTime()
- rootStore.state.twoStageCachingDelta2 = t2 - t0
- Logger.log('Using two stage caching for performance optimization - Time comparison stage1 vs stage2' + rootStore.state.twoStageCachingDelta1 + rootStore.state.twoStageCachingDelta2, 'category')()
- if (rootStore.state.twoStageCachingDelta1 > rootStore.state.twoStageCachingDelta2) { // two stage caching is not making any good
- rootStore.state.twoStageCachingDisabled = true
- Logger.log('Disabling two stage caching', 'category')()
- }
- })
- }
- return productPromise
- },
- addAvailableFilter ({ commit }, { key, options } = {}) {
- if (key) commit(types.CATEGORY_ADD_AVAILABLE_FILTER, { key, options })
- },
- resetFilters (context) {
- context.commit(types.CATEGORY_REMOVE_FILTERS)
- },
- searchProductQuery (context, productQuery) {
- context.commit(types.CATEGORY_UPD_SEARCH_PRODUCT_QUERY, productQuery)
- },
- setSearchOptions ({ commit }, searchOptions) {
- commit(types.CATEGORY_SET_SEARCH_OPTIONS, searchOptions)
- },
- mergeSearchOptions ({ commit }, searchOptions) {
- commit(types.CATEGORY_MERGE_SEARCH_OPTIONS, searchOptions)
- }
-}
-
-export default actions
diff --git a/core/modules/catalog/store/category/getters.ts b/core/modules/catalog/store/category/getters.ts
deleted file mode 100644
index df3c5e2929..0000000000
--- a/core/modules/catalog/store/category/getters.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { GetterTree } from 'vuex'
-import RootState from '@vue-storefront/core/types/RootState'
-import CategoryState from '../../types/CategoryState'
-
-const getters: GetterTree = {
- getCurrentCategory: state => state.current,
- getCurrentCategoryPath: state => state.current_path,
- getAllCategoryFilters: state => state.filters,
- getActiveCategoryFilters: state => state.filters.chosen,
- getAvailableCategoryFilters: state => state.filters.available,
- getCurrentCategoryProductQuery: state => state.current_product_query,
- getCategories: state => state.list,
- getCategoryBreadcrumbs: state => state.breadcrumbs,
- /**
- * @deprecated use getCurrentCategory instead
- */
- current: (state, getters) => getters.getCurrentCategory,
- /**
- * @deprecated use getCategories instead
- */
- list: (state, getters) => getters.getCategories
-}
-
-export default getters
diff --git a/core/modules/catalog/store/category/index.ts b/core/modules/catalog/store/category/index.ts
deleted file mode 100644
index 5030f514cd..0000000000
--- a/core/modules/catalog/store/category/index.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Module } from 'vuex'
-import actions from './actions'
-import getters from './getters'
-import mutations from './mutations'
-import RootState from '@vue-storefront/core/types/RootState'
-import CategoryState from '../../types/CategoryState'
-
-export const categoryModule: Module = {
- namespaced: true,
- state: {
- list: [],
- current: {},
- filters: {
- available: {},
- chosen: {}
- },
- breadcrumbs: {
- routes: []
- },
- current_product_query: null,
- current_path: [] // list of categories from root to current
- },
- getters,
- actions,
- mutations
-}
diff --git a/core/modules/catalog/store/category/mutation-types.ts b/core/modules/catalog/store/category/mutation-types.ts
deleted file mode 100644
index ed0852a01f..0000000000
--- a/core/modules/catalog/store/category/mutation-types.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export const SN_CATEGORY = 'category'
-export const CATEGORY_UPD_CATEGORIES = SN_CATEGORY + '/UPD_CATEGORIES'
-export const CATEGORY_UPD_CURRENT_CATEGORY = SN_CATEGORY + '/UPD_CURRENT_CATEGORY'
-export const CATEGORY_UPD_CURRENT_CATEGORY_PATH = SN_CATEGORY + '/UPD_CURRENT_CATEGORY_PATH'
-export const CATEGORY_UPD_SEARCH_PRODUCT_QUERY = SN_CATEGORY + '/UPD_SEARCH_PRODUCT_QUERY'
-export const CATEGORY_ADD_AVAILABLE_FILTER = `${SN_CATEGORY}/ADD_AVAILABLE_FILTER`
-export const CATEGORY_REMOVE_FILTERS = SN_CATEGORY + '/REMOVE_FILTERS'
-export const CATEGORY_SET_SEARCH_OPTIONS = `${SN_CATEGORY}/SET_SEARCH_OPTIONS`
-export const CATEGORY_MERGE_SEARCH_OPTIONS = `${SN_CATEGORY}/MERGE_SEARCH_OPTIONS`
diff --git a/core/modules/catalog/store/category/mutations.ts b/core/modules/catalog/store/category/mutations.ts
deleted file mode 100644
index d749ae0cce..0000000000
--- a/core/modules/catalog/store/category/mutations.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import Vue from 'vue'
-import { MutationTree } from 'vuex'
-import * as types from './mutation-types'
-import { formatBreadCrumbRoutes } from '@vue-storefront/core/helpers'
-import { entityKeyName } from '@vue-storefront/core/lib/store/entities'
-import CategoryState from '../../types/CategoryState'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import slugifyCategories from '@vue-storefront/core/modules/catalog/helpers/slugifyCategories'
-
-const mutations: MutationTree = {
- [types.CATEGORY_UPD_CURRENT_CATEGORY] (state, category) {
- state.current = category
- EventBus.$emit('category-after-current', { category: category })
- },
- [types.CATEGORY_UPD_CURRENT_CATEGORY_PATH] (state, path) {
- state.current_path = path // TODO: store to cache
- state.breadcrumbs.routes = formatBreadCrumbRoutes(state.current_path)
- },
- [types.CATEGORY_UPD_CATEGORIES] (state, categories) {
- const catCollection = StorageManager.get('categories')
-
- for (let category of categories.items) {
- category = slugifyCategories(category)
- const catExist = state.list.find(existingCat => existingCat.id === category.id)
-
- if (!catExist) {
- state.list.push(category)
- }
-
- if (!categories.includeFields) {
- try {
- catCollection
- .setItem(entityKeyName('slug', category.slug.toLowerCase()), category)
- .catch(reason => Logger.error(reason, 'category'))
-
- catCollection
- .setItem(entityKeyName('id', category.id), category)
- .catch(reason => Logger.error(reason, 'category'))
- } catch (e) {
- Logger.error(e, 'category')()
- }
- }
- }
-
- state.list.sort((catA, catB) => {
- if (catA.position && catB.position) {
- if (catA.position < catB.position) return -1
- if (catA.position > catB.position) return 1
- }
- return 0
- })
- },
- [types.CATEGORY_ADD_AVAILABLE_FILTER] (state, { key, options = [] }) {
- Vue.set(state.filters.available, key, options)
- },
- [types.CATEGORY_REMOVE_FILTERS] (state) {
- state.filters.chosen = {}
- state.current_product_query.configuration = {}
- },
- [types.CATEGORY_UPD_SEARCH_PRODUCT_QUERY] (state, newQuery) {
- state.current_product_query = newQuery
- },
- [types.CATEGORY_SET_SEARCH_OPTIONS] (state, searchOptions) {
- state.current_product_query = searchOptions || null
- },
- [types.CATEGORY_MERGE_SEARCH_OPTIONS] (state, searchOptions = {}) {
- let currentOptions = state.current_product_query || {}
- state.current_product_query = Object.assign(currentOptions, searchOptions)
- }
-}
-
-export default mutations
diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts
deleted file mode 100644
index af1d1583af..0000000000
--- a/core/modules/catalog/store/product/actions.ts
+++ /dev/null
@@ -1,321 +0,0 @@
-import { ActionTree } from 'vuex'
-import * as types from './mutation-types'
-import { isServer } from '@vue-storefront/core/helpers'
-import { SearchQuery } from 'storefront-query-builder'
-import cloneDeep from 'lodash-es/cloneDeep'
-import rootStore from '@vue-storefront/core/store'
-import RootState from '@vue-storefront/core/types/RootState'
-import ProductState from '../../types/ProductState'
-import { Logger } from '@vue-storefront/core/lib/logger';
-import config from 'config'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-import { ProductService } from '@vue-storefront/core/data-resolver/ProductService'
-import {
- registerProductsMapping,
- doPlatformPricesSync,
- setCustomProductOptionsAsync,
- setBundleProductOptionsAsync,
- getProductGallery,
- setRequestCacheTags
-} from '@vue-storefront/core/modules/catalog/helpers'
-import { getProductConfigurationOptions } from '@vue-storefront/core/modules/catalog/helpers/productOptions'
-import { checkParentRedirection } from '@vue-storefront/core/modules/catalog/events'
-
-const actions: ActionTree = {
- doPlatformPricesSync (context, { products }) {
- return doPlatformPricesSync(products)
- },
- /**
- * This is fix for https://github.com/vuestorefront/vue-storefront/issues/508
- * TODO: probably it would be better to have "parent_id" for simple products or to just ensure configurable variants are not visible in categories/search
- */
- checkConfigurableParent ({ commit, dispatch, getters }, { product }) {
- if (product.type_id === 'simple') {
- Logger.log('Checking configurable parent')()
- const parent = dispatch('findConfigurableParent', { product: { sku: getters.getCurrentProduct.sku } })
- if (parent) {
- commit(types.PRODUCT_SET_PARENT, parent)
- }
- return parent
- }
- },
- /**
- * Search ElasticSearch catalog of products using simple text query
- * Use bodybuilder to build the query, aggregations etc: http://bodybuilder.js.org/
- * @param {Object} query is the object of searchQuery class
- * @param {Int} start start index
- * @param {Int} size page size
- * @return {Promise}
- */
- async list (context, {
- query,
- start = 0,
- size = 50,
- sort = '',
- prefetchGroupProducts = !isServer,
- excludeFields = null,
- includeFields = null,
- configuration = null,
- populateRequestCacheTags = true,
- updateState = false,
- append = false
- } = {}) {
- Logger.warn('`product/list` deprecated, will be not used from 1.12, use "findProducts" instead')()
- const { items } = await context.dispatch('findProducts', {
- query,
- start,
- size,
- sort,
- excludeFields,
- includeFields,
- configuration,
- options: {
- populateRequestCacheTags,
- prefetchGroupProducts
- }
- })
-
- if (updateState) {
- Logger.warn('updateState and append are deprecated, will be not used from 1.12')()
- if (append) context.commit(types.PRODUCT_ADD_PAGED_PRODUCTS, { items })
- else context.commit(types.PRODUCT_SET_PAGED_PRODUCTS, { items })
- }
-
- EventBus.$emit('product-after-list', { query, start, size, sort, entityType: 'product', result: { items } })
-
- return { items }
- },
- async findProducts (context, {
- query,
- start = 0,
- size = 50,
- sort = '',
- excludeFields = null,
- includeFields = null,
- configuration = null,
- populateRequestCacheTags = false,
- options: {
- populateRequestCacheTags: populateRequestCacheTagsNew = false,
- prefetchGroupProducts = !isServer,
- setProductErrors = false,
- fallbackToDefaultWhenNoAvailable = true,
- assignProductConfiguration = false,
- separateSelectedVariant = false,
- setConfigurableProductOptions = config.cart.setConfigurableProductOptions,
- filterUnavailableVariants = config.products.filterUnavailableVariants
- } = {}
- } = {}) {
- const { items, ...restResponseData } = await ProductService.getProducts({
- query,
- start,
- size,
- sort,
- excludeFields,
- includeFields,
- configuration,
- options: {
- prefetchGroupProducts,
- fallbackToDefaultWhenNoAvailable,
- setProductErrors,
- setConfigurableProductOptions,
- filterUnavailableVariants,
- assignProductConfiguration,
- separateSelectedVariant
- }
- })
-
- registerProductsMapping(context, items)
-
- if (populateRequestCacheTags) {
- Logger.warn('deprecated from 1.13, use "options.populateRequestCacheTags" instead')()
- }
-
- if (populateRequestCacheTags || populateRequestCacheTagsNew) {
- setRequestCacheTags({ products: items })
- }
-
- await context.dispatch('tax/calculateTaxes', { products: items }, { root: true })
-
- return { ...restResponseData, items }
- },
- async findConfigurableParent (context, { product, configuration }) {
- const searchQuery = new SearchQuery()
- const query = searchQuery.applyFilter({ key: 'configurable_children.sku', value: { 'eq': product.sku } })
- const products = await context.dispatch('findProducts', { query, configuration })
- return products.items && products.items.length > 0 ? products.items[0] : null
- },
- /**
- * Search products by specific field
- * @param {Object} options
- */
- async single (context, {
- options = {},
- setCurrentProduct = false,
- key = 'sku',
- skipCache = false
- } = {}) {
- if (setCurrentProduct) {
- Logger.warn('option `setCurrentProduct` is deprecated, will be not used from 1.13')()
- }
- if (!options[key]) {
- throw new Error('Please provide the search key ' + key + ' for product/single action!')
- }
- const product = await ProductService.getProductByKey({
- options,
- key,
- skipCache
- })
-
- await context.dispatch('tax/calculateTaxes', { products: [product] }, { root: true })
-
- if (setCurrentProduct) await context.dispatch('setCurrent', product)
- EventBus.$emitFilter('product-after-single', { key, options, product })
-
- return product
- },
- /**
- * Assign the custom options object to the currentl product
- */
- setCustomOptions (context, { customOptions, product }) {
- if (customOptions) { // TODO: this causes some kind of recurrency error
- context.commit(types.PRODUCT_SET_CURRENT, Object.assign({}, product, { product_option: setCustomProductOptionsAsync(context, { product: context.getters.getCurrentProduct, customOptions: customOptions }) }))
- }
- },
- /**
- * Assign the bundle options object to the vurrent product
- */
- setBundleOptions (context, { bundleOptions, product }) {
- if (bundleOptions) { // TODO: this causes some kind of recurrency error
- context.commit(types.PRODUCT_SET_CURRENT, Object.assign({}, product, { product_option: setBundleProductOptionsAsync(context, { product: context.getters.getCurrentProduct, bundleOptions: bundleOptions }) }))
- }
- },
- /**
- * Set current product with given variant's properties
- * @param {Object} context
- * @param {Object} productVariant
- */
- setCurrent (context, product) {
- if (product && typeof product === 'object') {
- const { configuration, ...restProduct } = product
- const productUpdated = Object.assign({}, restProduct)
- if (!config.products.gallery.mergeConfigurableChildren) {
- context.dispatch('setProductGallery', { product: productUpdated })
- }
- const productOptions = getProductConfigurationOptions({ product, attribute: context.rootState.attribute })
- context.commit(types.PRODUCT_SET_CURRENT_OPTIONS, productOptions)
- context.commit(types.PRODUCT_SET_CURRENT_CONFIGURATION, configuration || {})
- context.commit(types.PRODUCT_SET_CURRENT, productUpdated)
- return productUpdated
- } else Logger.debug('Unable to update current product.', 'product')()
- },
- /**
- * Set related products
- */
- related (context, { key = 'related-products', items }) {
- context.commit(types.PRODUCT_SET_RELATED, { key, items })
- },
- /**
- * Load the product data and sets current product
- */
- async loadProduct ({ dispatch, state }, { parentSku, childSku = null, route = null, skipCache = false }) {
- Logger.info('Fetching product data asynchronously', 'product', { parentSku, childSku })()
- EventBus.$emit('product-before-load', { store: rootStore, route: route })
-
- const product = await dispatch('single', {
- options: {
- sku: parentSku,
- childSku: childSku
- },
- key: 'sku',
- skipCache
- })
-
- setRequestCacheTags({ products: [product] })
-
- await dispatch('setCurrent', product)
-
- if (product.status >= 2) {
- throw new Error(`Product query returned empty result product status = ${product.status}`)
- }
- if (product.visibility === 1) { // not visible individually (https://magento.stackexchange.com/questions/171584/magento-2-table-name-for-product-visibility)
- if (config.products.preventConfigurableChildrenDirectAccess) {
- const parentProduct = await dispatch('findConfigurableParent', { product })
- checkParentRedirection(product, parentProduct)
- } else {
- throw new Error(`Product query returned empty result product visibility = ${product.visibility}`)
- }
- }
-
- if (config.entities.attribute.loadByAttributeMetadata) {
- await dispatch('attribute/loadProductAttributes', { products: [product] }, { root: true })
- } else {
- await dispatch('loadProductAttributes', { product })
- }
-
- const syncPromises = []
- const gallerySetup = dispatch('setProductGallery', { product })
- if (isServer) {
- syncPromises.push(gallerySetup)
- }
- await Promise.all(syncPromises)
- await EventBus.$emitFilter('product-after-load', { store: rootStore, route: route })
- return product
- },
- /**
- * Add custom option validator for product custom options
- */
- addCustomOptionValidator (context, { validationRule, validatorFunction }) {
- context.commit(types.PRODUCT_SET_CUSTOM_OPTION_VALIDATOR, { validationRule, validatorFunction })
- },
-
- /**
- * Set product gallery depending on product type
- */
-
- setProductGallery (context, { product }) {
- const productGallery = getProductGallery(product)
- context.commit(types.PRODUCT_SET_GALLERY, productGallery)
- },
- async loadProductBreadcrumbs ({ dispatch, rootGetters }, { product } = {}) {
- if (product && product.category_ids) {
- const currentCategory = rootGetters['category-next/getCurrentCategory']
- let breadcrumbCategory
- const categoryFilters = Object.assign({ 'id': [...product.category_ids] }, cloneDeep(config.entities.category.breadcrumbFilterFields))
- const categories = await dispatch('category-next/loadCategories', { filters: categoryFilters, reloadAll: Object.keys(config.entities.category.breadcrumbFilterFields).length > 0 }, { root: true })
- if (
- (currentCategory && currentCategory.id) && // current category exist
- (config.entities.category.categoriesRootCategorylId !== currentCategory.id) && // is not highest category (All) - if we open product from different page then category page
- (categories.findIndex(category => category.id === currentCategory.id) >= 0) // can be found in fetched categories
- ) {
- breadcrumbCategory = currentCategory // use current category if set and included in the filtered list
- } else {
- breadcrumbCategory = categories.sort((a, b) => (a.level > b.level) ? -1 : 1)[0] // sort starting by deepest level
- }
- await dispatch('category-next/loadCategoryBreadcrumbs', { category: breadcrumbCategory, currentRouteName: product.name }, { root: true })
- }
- },
- async getProductVariant (context, { product, configuration } = {}) {
- let searchQuery = new SearchQuery()
- searchQuery = searchQuery.applyFilter({ key: 'sku', value: { 'eq': product.parentSku } })
- if (!product.parentSku) {
- throw new Error('Product doesn\'t have parentSku, please check if this is configurable product')
- }
- const { items: [newProductVariant] } = await context.dispatch('findProducts', {
- query: searchQuery,
- size: 1,
- configuration,
- options: {
- fallbackToDefaultWhenNoAvailable: false,
- setProductErrors: true,
- separateSelectedVariant: true
- }
- })
- const { selectedVariant = {}, options, product_option } = newProductVariant
-
- return { ...selectedVariant, options, product_option }
- },
- /** Below actions are not used from 1.12 and can be removed to reduce bundle */
- ...require('./deprecatedActions').default
-}
-
-export default actions
diff --git a/core/modules/catalog/store/product/deprecatedActions.ts b/core/modules/catalog/store/product/deprecatedActions.ts
deleted file mode 100644
index ef89406088..0000000000
--- a/core/modules/catalog/store/product/deprecatedActions.ts
+++ /dev/null
@@ -1,355 +0,0 @@
-import { optionLabel } from '../../helpers/optionLabel'
-import trim from 'lodash-es/trim'
-import { formatBreadCrumbRoutes, isServer } from '@vue-storefront/core/helpers'
-import { preConfigureProduct, storeProductToCache, isGroupedOrBundle } from '@vue-storefront/core/modules/catalog/helpers/search'
-import toString from 'lodash-es/toString'
-import {
- registerProductsMapping,
- filterOutUnavailableVariants
-} from '@vue-storefront/core/modules/catalog/helpers'
-import { Logger } from '@vue-storefront/core/lib/logger';
-import * as types from './mutation-types'
-import { ProductService } from '@vue-storefront/core/data-resolver/ProductService'
-import config from 'config'
-import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'
-const { populateProductConfigurationAsync } = require('@vue-storefront/core/modules/catalog/helpers')
-
-const actions = {
- /**
- * Reset current configuration and selected variatnts
- */
- reset (context) {
- Logger.warn('`product/reset` deprecated, will be not used from 1.12')()
- const originalProduct = Object.assign({}, context.getters.getOriginalProduct)
- context.commit(types.PRODUCT_RESET_CURRENT, originalProduct)
- },
- /**
- * Setup product breadcrumbs path
- */
- async setupBreadcrumbs (context, { product }) {
- Logger.warn('`product/setupBreadcrumbs` deprecated, will be not used from 1.12')()
- let breadcrumbsName = null
- let setBreadcrumbRoutesFromPath = (path) => {
- if (path.findIndex(itm => {
- return itm.slug === context.rootGetters['category/getCurrentCategory'].slug
- }) < 0) {
- path.push({
- url_path: context.rootGetters['category/getCurrentCategory'].url_path,
- slug: context.rootGetters['category/getCurrentCategory'].slug,
- name: context.rootGetters['category/getCurrentCategory'].name
- }) // current category at the end
- }
- // deprecated, TODO: base on breadcrumbs module
- breadcrumbsName = product.name
- const breadcrumbs = {
- routes: formatBreadCrumbRoutes(path),
- current: breadcrumbsName,
- name: breadcrumbsName
- }
- context.commit(types.CATALOG_SET_BREADCRUMBS, breadcrumbs)
- }
-
- if (product.category && product.category.length > 0) {
- const categoryIds = product.category.reverse().map(cat => cat.category_id)
- await context.dispatch('category/list', { key: 'id', value: categoryIds }, { root: true }).then(async (categories) => {
- const catList = []
-
- for (let catId of categoryIds) {
- let category = categories.items.find((itm) => { return toString(itm['id']) === toString(catId) })
- if (category) {
- catList.push(category)
- }
- }
-
- const rootCat = catList.shift()
- let catForBreadcrumbs = rootCat
-
- for (let cat of catList) {
- const catPath = cat.path
- if (catPath && catPath.includes(rootCat.path) && (catPath.split('/').length > catForBreadcrumbs.path.split('/').length)) {
- catForBreadcrumbs = cat
- }
- }
- if (typeof catForBreadcrumbs !== 'undefined') {
- await context.dispatch('category/single', { key: 'id', value: catForBreadcrumbs.id }, { root: true }).then(() => { // this sets up category path and current category
- setBreadcrumbRoutesFromPath(context.rootGetters['category/getCurrentCategoryPath'])
- }).catch(err => {
- setBreadcrumbRoutesFromPath(context.rootGetters['category/getCurrentCategoryPath'])
- Logger.error(err)()
- })
- } else {
- setBreadcrumbRoutesFromPath(context.rootGetters['category/getCurrentCategoryPath'])
- }
- })
- }
- },
- /**
- * Download Magento2 / other platform prices to put them over ElasticSearch prices
- */
- async syncPlatformPricesOver ({ rootGetters }, { skus }) {
- Logger.warn('`product/syncPlatformPricesOver`deprecated, will be not used from 1.12')()
- const result = await ProductService.getProductRenderList({
- skus,
- isUserGroupedTaxActive: rootGetters['tax/getIsUserGroupedTaxActive'],
- userGroupId: rootGetters['tax/getUserTaxGroupId'],
- token: rootGetters['user/getToken']
- })
- return result
- },
- /**
- * Setup associated products
- */
- setupAssociated (context, { product, skipCache = true }) {
- Logger.warn('`product/setupAssociated` deprecated, will be not used from 1.12')()
- let subloaders = []
- if (product.type_id === 'grouped') {
- product.price = 0
- product.price_incl_tax = 0
- Logger.debug(product.name + ' SETUP ASSOCIATED', product.type_id)()
- if (product.product_links && product.product_links.length > 0) {
- for (let pl of product.product_links) {
- if (pl.link_type === 'associated' && pl.linked_product_type === 'simple') { // prefetch links
- Logger.debug('Prefetching grouped product link for ' + pl.sku + ' = ' + pl.linked_product_sku)()
- subloaders.push(context.dispatch('single', {
- options: { sku: pl.linked_product_sku },
- setCurrentProduct: false,
- selectDefaultVariant: false,
- skipCache: skipCache
- }).catch(err => { Logger.error(err) }).then((asocProd) => {
- if (asocProd) {
- pl.product = asocProd
- pl.product.qty = 1
- product.price += pl.product.price
- product.price_incl_tax += pl.product.price_incl_tax
- product.tax += pl.product.tax
- } else {
- Logger.error('Product link not found', pl.linked_product_sku)()
- }
- }))
- }
- }
- } else {
- Logger.error('Product with type grouped has no product_links set!', product)()
- }
- }
- if (product.type_id === 'bundle') {
- product.price = 0
- product.price_incl_tax = 0
- Logger.debug(product.name + ' SETUP ASSOCIATED', product.type_id)()
- if (product.bundle_options && product.bundle_options.length > 0) {
- for (let bo of product.bundle_options) {
- let defaultOption = bo.product_links.find((p) => { return p.is_default })
- if (!defaultOption) defaultOption = bo.product_links[0]
- for (let pl of bo.product_links) {
- Logger.debug('Prefetching bundle product link for ' + bo.sku + ' = ' + pl.sku)()
- subloaders.push(context.dispatch('single', {
- options: { sku: pl.sku },
- setCurrentProduct: false,
- selectDefaultVariant: false,
- skipCache: skipCache
- }).catch(err => { Logger.error(err) }).then((asocProd) => {
- if (asocProd) {
- pl.product = asocProd
- pl.product.qty = pl.qty
-
- if (pl.id === defaultOption.id) {
- product.price += pl.product.price * pl.product.qty
- product.price_incl_tax += pl.product.price_incl_tax * pl.product.qty
- product.tax += pl.product.tax * pl.product.qty
- }
- } else {
- Logger.error('Product link not found', pl.sku)()
- }
- }))
- }
- }
- }
- }
- return Promise.all(subloaders)
- },
- /**
- * Load required configurable attributes
- * @param context
- * @param product
- */
- loadConfigurableAttributes (context, { product }) {
- Logger.warn('`product/loadConfigurableAttributes` deprecated, will be not used from 1.12')()
- let attributeKey = 'attribute_id'
- const configurableAttrKeys = product.configurable_options.map(opt => {
- if (opt.attribute_id) {
- attributeKey = 'attribute_id'
- return opt.attribute_id
- } else {
- attributeKey = 'attribute_code'
- return opt.attribute_code
- }
- })
- return context.dispatch('attribute/list', {
- filterValues: configurableAttrKeys,
- filterField: attributeKey
- }, { root: true })
- },
- /**
- * Setup product current variants
- */
- async setupVariants (context, { product }) {
- Logger.warn('`product/setupVariants` deprecated, will be not used from 1.12')()
- if (product.type_id !== 'configurable' || !product.hasOwnProperty('configurable_options')) {
- return
- }
- if (config.entities.attribute.loadByAttributeMetadata) {
- await context.dispatch('attribute/loadProductAttributes', { products: [product] }, { root: true })
- }
- let productOptions = {}
- for (let option of product.configurable_options) {
- for (let ov of option.values) {
- let lb = ov.label ? ov.label : optionLabel(context.rootState.attribute, { attributeKey: option.attribute_id, searchBy: 'id', optionId: ov.value_index })
- if (trim(lb) !== '') {
- let optionKey = option.attribute_code ? option.attribute_code : option.label.toLowerCase()
- if (!productOptions[optionKey]) {
- productOptions[optionKey] = []
- }
-
- productOptions[optionKey].push({
- label: lb,
- id: ov.value_index,
- attribute_code: option.attribute_code
- })
- }
- }
- }
- context.commit(types.PRODUCT_SET_CURRENT_OPTIONS, productOptions)
- let selectedVariant = context.getters.getCurrentProduct
- populateProductConfigurationAsync(context, { selectedVariant: selectedVariant, product: product })
- },
- filterUnavailableVariants (context, { product }) {
- Logger.warn('`product/filterUnavailableVariants` deprecated, will be not used from 1.12')()
- return filterOutUnavailableVariants(context, product)
- },
- preConfigureAssociated (context, { searchResult, prefetchGroupProducts }) {
- Logger.warn('`product/preConfigureAssociated` deprecated, will be not used from 1.12')()
- registerProductsMapping(context, searchResult.items)
- for (let product of searchResult.items) {
- if (isGroupedOrBundle(product) && prefetchGroupProducts && !isServer) {
- context.dispatch('setupAssociated', { product })
- }
- }
- },
- async preConfigureProduct (context, { product, populateRequestCacheTags, configuration }) {
- Logger.warn('`product/preConfigureProduct` deprecated, will be not used from 1.12')()
- let _product = preConfigureProduct({ product, populateRequestCacheTags })
-
- if (configuration) {
- const selectedVariant = await context.dispatch('getProductVariant', { product: _product, configuration })
- _product = Object.assign({}, _product, selectedVariant)
- }
-
- return _product
- },
- async configureLoadedProducts (context, { products, isCacheable, cacheByKey, populateRequestCacheTags, configuration }) {
- Logger.warn('`product/configureLoadedProducts` deprecated, will be not used from 1.12')()
- const configuredProducts = await context.dispatch(
- 'category-next/configureProducts',
- {
- products: products.items,
- filters: configuration || {},
- populateRequestCacheTags
- },
- { root: true }
- )
-
- await context.dispatch('tax/calculateTaxes', { products: configuredProducts }, { root: true })
-
- for (let product of configuredProducts) { // we store each product separately in cache to have offline access to products/single method
- if (isCacheable) { // store cache only for full loads
- storeProductToCache(product, cacheByKey)
- }
- }
-
- return products
- },
- /**
- * Update associated products for bundle product
- * @param context
- * @param product
- */
- configureBundleAsync (context, product) {
- Logger.warn('`product/configureBundleAsync` deprecated, will be not used from 1.12')()
- return context.dispatch(
- 'setupAssociated', {
- product: product,
- skipCache: true
- })
- .then(() => { context.dispatch('setCurrent', product) })
- .then(() => { EventBus.$emit('product-after-setup-associated') })
- },
-
- /**
- * Update associated products for group product
- * @param context
- * @param product
- */
- configureGroupedAsync (context, product) {
- Logger.warn('`product/configureGroupedAsync` deprecated, will be not used from 1.12')()
- return context.dispatch(
- 'setupAssociated', {
- product: product,
- skipCache: true
- })
- .then(() => { context.dispatch('setCurrent', product) })
- },
- /**
- * Configure product with given configuration and set it as current
- * @param {Object} context
- * @param {Object} product
- * @param {Array} configuration
- */
- async configure (context, { product = null, configuration, selectDefaultVariant = true, fallbackToDefaultWhenNoAvailable = false }) {
- Logger.warn('`product/configure` deprecated, will be not used from 1.12, use "product/getProductVariant"')()
- const result = await context.dispatch('getProductVariant', { product, configuration })
- return result
- },
-
- setCurrentOption (context, productOption) {
- Logger.warn('`product/setCurrentOption` deprecated, will be not used from 1.12')()
- if (productOption && typeof productOption === 'object') { // TODO: this causes some kind of recurrency error
- context.commit(types.PRODUCT_SET_CURRENT, Object.assign({}, context.getters.getCurrentProduct, { product_option: productOption }))
- }
- },
-
- setCurrentErrors (context, errors) {
- Logger.warn('`product/setCurrentErrors` deprecated, will be not used from 1.12')()
- if (errors && typeof errors === 'object') {
- context.commit(types.PRODUCT_SET_CURRENT, Object.assign({}, context.getters.getCurrentProduct, { errors: errors }))
- }
- },
- /**
- * Set given product as original
- * @param {Object} context
- * @param {Object} originalProduct
- */
- setOriginal (context, originalProduct) {
- Logger.warn('`product/setOriginal` deprecated, will be not used from 1.12')()
- if (originalProduct && typeof originalProduct === 'object') context.commit(types.PRODUCT_SET_ORIGINAL, Object.assign({}, originalProduct))
- else Logger.debug('Unable to setup original product.', 'product')()
- },
-
- /**
- * Load product attributes
- */
- async loadProductAttributes ({ dispatch }, { product }) {
- Logger.warn('`product/loadProductAttributes` deprecated, will be not used from 1.12')()
- const productFields = Object.keys(product).filter(fieldName => {
- return !config.entities.product.standardSystemFields.includes(fieldName) // don't load metadata info for standard fields
- })
- const { product: { useDynamicAttributeLoader }, optimize, attribute } = config.entities
- return dispatch('attribute/list', { // load attributes to be shown on the product details - the request is now async
- filterValues: useDynamicAttributeLoader ? productFields : null,
- only_visible: !!useDynamicAttributeLoader,
- only_user_defined: true,
- includeFields: optimize ? attribute.includeFields : null
- }, { root: true })
- }
-}
-
-export default actions
diff --git a/core/modules/catalog/store/product/getters.ts b/core/modules/catalog/store/product/getters.ts
deleted file mode 100644
index 700c69420e..0000000000
--- a/core/modules/catalog/store/product/getters.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { GetterTree } from 'vuex'
-import RootState from '@vue-storefront/core/types/RootState'
-import ProductState from '../../types/ProductState'
-import { Logger } from '@vue-storefront/core/lib/logger';
-
-const getters: GetterTree = {
- getCurrentProduct: state => state.current,
- getCurrentProductConfiguration: state => state.current_configuration,
- getCurrentProductOptions: state => state.current_options,
- getOriginalProduct: (state, getters) => {
- if (!getters.getCurrentProduct) return null
- return state.original || {
- ...getters.getCurrentProduct,
- id: getters.getCurrentProduct.parentId || getters.getCurrentProduct.id
- }
- },
- getParentProduct: state => state.parent,
- getProductsSearchResult: state => state.list,
- getProducts: (state, getters) => getters.getProductsSearchResult.items,
- getProductGallery: state => state.productGallery,
- getProductRelated: state => state.related,
- getCurrentCustomOptions: state => state.current_custom_options
-}
-
-export default getters
diff --git a/core/modules/catalog/store/product/index.ts b/core/modules/catalog/store/product/index.ts
deleted file mode 100644
index 4928c277fb..0000000000
--- a/core/modules/catalog/store/product/index.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { Module } from 'vuex'
-import actions from './actions'
-import getters from './getters'
-import mutations from './mutations'
-import RootState from '@vue-storefront/core/types/RootState'
-import ProductState from '../../types/ProductState'
-
-export const productModule: Module = {
- namespaced: true,
- state: {
- // TODO use breadcrumbs from category-next, leave here for backward compatibility
- breadcrumbs: {
- routes: [],
- name: ''
- },
- current: null, // shown product
- current_options: {
- color: [],
- size: []
- },
- current_configuration: {},
- parent: null,
- list: {
- start: 0,
- perPage: 50,
- total: 0,
- items: []
- },
- original: null, // default, not configured product
- related: {},
- offlineImage: null,
- current_custom_options: {},
- current_bundle_options: {},
- custom_options_validators: {},
- productLoadStart: 0,
- productLoadPromise: null,
- productGallery: []
- },
- getters,
- actions,
- mutations
-}
-
-export const nonReactiveState = {
- list: []
-}
diff --git a/core/modules/catalog/store/product/mutation-types.ts b/core/modules/catalog/store/product/mutation-types.ts
deleted file mode 100644
index 8b868541fe..0000000000
--- a/core/modules/catalog/store/product/mutation-types.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-export const SN_PRODUCT = 'product'
-export const PRODUCT_SET_PAGED_PRODUCTS = SN_PRODUCT + '/SET_PRODUCTS'
-export const PRODUCT_ADD_PAGED_PRODUCTS = SN_PRODUCT + '/ADD_PRODUCTS'
-export const PRODUCT_SET_RELATED = SN_PRODUCT + '/SET_RELATED'
-export const PRODUCT_SET_CURRENT = SN_PRODUCT + '/SET_CURRENT'
-export const PRODUCT_SET_CURRENT_OPTIONS = SN_PRODUCT + '/SET_CURRENT_OPTIONS'
-export const PRODUCT_RESET_CURRENT = SN_PRODUCT + '/RESET_CURRENT'
-export const PRODUCT_SET_ORIGINAL = SN_PRODUCT + '/SET_ORIGINAL'
-export const PRODUCT_SET_CURRENT_CONFIGURATION = SN_PRODUCT + '/SET_CURRENT_CONFIGURATION'
-export const PRODUCT_SET_PARENT = SN_PRODUCT + '/SET_PARENT'
-export const PRODUCT_SET_CUSTOM_OPTION = SN_PRODUCT + '/SET_CUSTOM_OPTION'
-export const PRODUCT_SET_CUSTOM_OPTION_VALIDATOR = SN_PRODUCT + '/SET_CUSTOM_OPTION_VALIDATOR'
-export const PRODUCT_SET_BUNDLE_OPTION = SN_PRODUCT + '/SET_BUNDLE_OPTION'
-export const PRODUCT_SET_GALLERY = SN_PRODUCT + '/SET_PRODUCT_GALLERY'
-// remove later
-export const CATALOG_UPD_PRODUCTS = SN_PRODUCT + '/UPD_PRODUCTS'
-export const CATALOG_UPD_RELATED = SN_PRODUCT + '/UPD_RELATED'
-export const CATALOG_SET_PRODUCT_CURRENT = SN_PRODUCT + '/SET_PRODUCT_CURRENT'
-export const CATALOG_SET_PRODUCT_ORIGINAL = SN_PRODUCT + '/SET_PRODUCT_ORIGINAL'
-export const CATALOG_RESET_PRODUCT = SN_PRODUCT + '/RESET_PRODUCT_ORIGINAL'
-export const CATALOG_SET_PRODUCT_PARENT = SN_PRODUCT + '/SET_PARENT'
-export const CATALOG_UPD_CUSTOM_OPTION = SN_PRODUCT + '/SET_CUSTOM_OPTION'
-export const CATALOG_UPD_BUNDLE_OPTION = SN_PRODUCT + '/UPD_BUNDLE_OPTION'
-export const CATALOG_ADD_CUSTOM_OPTION_VALIDATOR = SN_PRODUCT + '/ADD_CUSTOM_OPTION_VALIDATOR'
-export const CATALOG_UPD_GALLERY = SN_PRODUCT + '/SET_GALLERY'
-export const CATALOG_SET_BREADCRUMBS = SN_PRODUCT + '/SET_BREADCRUMBS'
diff --git a/core/modules/catalog/store/product/mutations.ts b/core/modules/catalog/store/product/mutations.ts
deleted file mode 100644
index bd415ba0d1..0000000000
--- a/core/modules/catalog/store/product/mutations.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-import { MutationTree } from 'vuex'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import * as types from './mutation-types'
-import ProductState, { PagedProductList } from '../../types/ProductState'
-import Vue from 'vue'
-
-const mutations: MutationTree = {
- [types.PRODUCT_SET_PAGED_PRODUCTS] (state, searchResult) {
- const { start, perPage, total, items } = searchResult
- state.list = {
- start,
- perPage,
- total,
- items
- }
- },
- [types.PRODUCT_ADD_PAGED_PRODUCTS] (state, searchResult) {
- const { start, perPage, items } = searchResult
- state.list = Object.assign(
- {},
- state.list,
- {
- start,
- perPage,
- items: [...(state.list as PagedProductList).items, ...items]
- }
- )
- },
- [types.PRODUCT_SET_RELATED] (state, { key, items }) {
- state.related = Object.assign(
- {},
- state.related,
- { [key]: items }
- )
- },
- [types.PRODUCT_SET_CURRENT] (state, product) {
- state.current = product
- },
- [types.PRODUCT_RESET_CURRENT] (state, originalProduct) {
- state.current = Object.assign({}, originalProduct)
- state.current_configuration = {}
- state.offlineImage = null
- state.parent = null
- state.current_options = { color: [], size: [] }
- state.current_bundle_options = {}
- state.current_custom_options = {}
- },
- [types.PRODUCT_SET_CURRENT_OPTIONS] (state, configuration = {}) {
- state.current_options = configuration
- },
- [types.PRODUCT_SET_CURRENT_CONFIGURATION] (state, configuration = {}) {
- Vue.set(state, 'current_configuration', configuration || {})
- },
- [types.PRODUCT_SET_ORIGINAL] (state, product) {
- state.original = product
- },
- [types.PRODUCT_SET_PARENT] (state, product) {
- state.parent = product
- },
- [types.PRODUCT_SET_CUSTOM_OPTION] (state, { optionId, optionValue }) {
- state.current_custom_options = Object.assign(
- {},
- state.current_custom_options,
- { [optionId]: {
- option_id: optionId,
- option_value: optionValue
- } }
- )
- },
- [types.PRODUCT_SET_BUNDLE_OPTION] (state, { optionId, optionQty, optionSelections }) {
- const option = {
- option_id: optionId,
- option_qty: optionQty,
- option_selections: optionSelections
- }
- state.current_bundle_options = Object.assign(
- {},
- state.current_bundle_options,
- { [optionId]: option }
- )
- },
- [types.PRODUCT_SET_CUSTOM_OPTION_VALIDATOR] (state, { validationRule, validatorFunction }) {
- state.custom_options_validators = Object.assign(
- {},
- state.custom_options_validators,
- { [validationRule]: validatorFunction }
- )
- },
- [types.PRODUCT_SET_GALLERY] (state, productGallery) {
- state.productGallery = productGallery
- },
- [types.CATALOG_SET_BREADCRUMBS] (state, payload) {
- state.breadcrumbs = payload
- },
- [types.CATALOG_ADD_CUSTOM_OPTION_VALIDATOR] (state, { validationRule, validatorFunction }) {
- Logger.error('Deprecated mutation CATALOG_ADD_CUSTOM_OPTION_VALIDATOR - use PRODUCT_SET_CUSTOM_OPTION_VALIDATOR instead')()
- },
- [types.CATALOG_UPD_RELATED] (state, { key, items }) {
- Logger.error('Deprecated mutation CATALOG_UPD_RELATED - use PRODUCT_SET_RELATED instead')()
- },
- [types.CATALOG_UPD_BUNDLE_OPTION] (state, { optionId, optionQty, optionSelections }) {
- Logger.error('Deprecated mutation CATALOG_UPD_BUNDLE_OPTION - use PRODUCT_SET_BUNDLE_OPTION instead')()
- },
- [types.CATALOG_UPD_PRODUCTS] (state, { products, append }) {
- Logger.error('Deprecated mutation CATALOG_UPD_PRODUCTS - use PRODUCT_SET_PAGED_PRODUCTS or PRODUCT_ADD_PAGED_PRODUCTS instead')()
- },
- [types.CATALOG_SET_PRODUCT_CURRENT] (state, product) {
- Logger.error('Deprecated mutation CATALOG_SET_PRODUCT_CURRENT - use PRODUCT_SET_CURRENT instead')()
- },
- [types.CATALOG_SET_PRODUCT_ORIGINAL] (state, product) {
- Logger.error('Deprecated mutation CATALOG_SET_PRODUCT_ORIGINAL - use PRODUCT_SET_ORIGINAL instead')()
- },
- [types.CATALOG_RESET_PRODUCT] (state, productOriginal) {
- Logger.error('Deprecated mutation CATALOG_RESET_PRODUCT - use PRODUCT_RESET_CURRENT instead')()
- },
- [types.CATALOG_UPD_GALLERY] (state, productGallery) {
- Logger.error('Deprecated mutation CATALOG_UPD_GALLERY - use PRODUCT_SET_GALLERY instead')()
- }
-}
-
-export default mutations
diff --git a/core/modules/catalog/store/stock/actions.ts b/core/modules/catalog/store/stock/actions.ts
deleted file mode 100644
index 5989318f19..0000000000
--- a/core/modules/catalog/store/stock/actions.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { ActionTree } from 'vuex'
-import * as stockMutationTypes from '@vue-storefront/core/modules/catalog/store/stock/mutation-types'
-import RootState from '@vue-storefront/core/types/RootState'
-import StockState from '../../types/StockState'
-import config from 'config'
-import { StockService } from '@vue-storefront/core/data-resolver'
-import { getStatus, getProductInfos } from '@vue-storefront/core/modules/catalog/helpers/stock'
-import { Logger } from '@vue-storefront/core/lib/logger'
-
-const actions: ActionTree = {
- async queueCheck ({ dispatch }, { product }) {
- const checkStatus = {
- qty: product.stock ? product.stock.qty : 0,
- status: getStatus(product, 'ok')
- }
-
- if (config.stock.synchronize) {
- const task = await StockService.queueCheck(product.sku, 'cart/stockSync')
-
- // @ts-ignore
- Logger.debug(`Stock quantity checked for ${task.product_sku}, response time: ${task.transmited_at - task.created_at} ms`, 'stock')()
-
- return {
- ...checkStatus,
- onlineCheckTaskId: task.task_id
- }
- }
-
- return {
- ...checkStatus,
- status: getStatus(product, 'volatile')
- }
- },
- async check (context, { product }) {
- if (config.stock.synchronize) {
- const { result, task_id } = await StockService.check(product.sku)
-
- return {
- qty: result ? result.qty : 0,
- status: getStatus(result, 'ok'),
- isManageStock: result.manage_stock,
- onlineCheckTaskId: task_id
- }
- }
-
- return {
- qty: product.stock ? product.stock.qty : 0,
- status: getStatus(product, 'volatile')
- }
- },
- async list ({ commit }, { skus }) {
- if (!config.stock.synchronize) return
-
- const task = await StockService.list(skus)
-
- if (task.resultCode === 200) {
- const productInfos = getProductInfos(task.result)
-
- for (const productInfo of productInfos) {
- commit(stockMutationTypes.SET_STOCK_CACHE_PRODUCT, {
- productId: productInfo.product_id,
- productInfo
- })
- }
- }
-
- return task
- },
- clearCache ({ commit }) {
- commit(stockMutationTypes.SET_STOCK_CACHE, {})
- }
-}
-
-export default actions
diff --git a/core/modules/catalog/store/stock/index.ts b/core/modules/catalog/store/stock/index.ts
deleted file mode 100644
index 264dd31fc2..0000000000
--- a/core/modules/catalog/store/stock/index.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Module } from 'vuex'
-import actions from './actions'
-import mutations from './mutations'
-import RootState from '@vue-storefront/core/types/RootState'
-import StockState from '../../types/StockState'
-
-export const stockModule: Module = {
- namespaced: true,
- actions,
- mutations,
- state: {
- cache: {}
- }
-}
diff --git a/core/modules/catalog/store/stock/mutation-types.ts b/core/modules/catalog/store/stock/mutation-types.ts
deleted file mode 100644
index 688b201064..0000000000
--- a/core/modules/catalog/store/stock/mutation-types.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const SN_CATALOG = 'catalog'
-export const SET_STOCK_CACHE = `${SN_CATALOG}/SET_STOCK_CACHE`
-export const SET_STOCK_CACHE_PRODUCT = `${SN_CATALOG}/SET_STOCK_CACHE_PRODUCT`
diff --git a/core/modules/catalog/store/stock/mutations.ts b/core/modules/catalog/store/stock/mutations.ts
deleted file mode 100644
index b684e25992..0000000000
--- a/core/modules/catalog/store/stock/mutations.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { MutationTree } from 'vuex'
-import StockState from '../../types/StockState'
-import * as types from './mutation-types'
-
-const mutations: MutationTree = {
- [types.SET_STOCK_CACHE] (state, cache) {
- state.cache = cache
- },
- [types.SET_STOCK_CACHE_PRODUCT] (state, { productId, productInfo }) {
- state.cache = Object.assign({}, state.cache, {
- [productId]: productInfo
- })
- }
-}
-
-export default mutations
diff --git a/core/modules/catalog/store/tax/actions.ts b/core/modules/catalog/store/tax/actions.ts
deleted file mode 100644
index 420c37613d..0000000000
--- a/core/modules/catalog/store/tax/actions.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { ActionTree } from 'vuex'
-import * as types from './mutation-types'
-import { quickSearchByQuery } from '@vue-storefront/core/lib/search'
-import { SearchQuery } from 'storefront-query-builder'
-import RootState from '@vue-storefront/core/types/RootState'
-import TaxState from '../../types/TaxState'
-import { Logger } from '@vue-storefront/core/lib/logger'
-import { StorageManager } from '@vue-storefront/core/lib/storage-manager'
-import { entityKeyName } from '@vue-storefront/core/lib/store/entities'
-import config from 'config'
-import { calculateProductTax } from '@vue-storefront/core/modules/catalog/helpers/taxCalc'
-import { doPlatformPricesSync } from '@vue-storefront/core/modules/catalog/helpers'
-import { catalogHooksExecutors } from './../../hooks'
-import { currentStoreView } from '@vue-storefront/core/lib/multistore';
-
-const actions: ActionTree = {
- async list ({ state, commit, dispatch }, { entityType = 'taxrule' }) {
- if (state.rules.length > 0) {
- Logger.info('Tax rules served from local memory', 'tax')()
- return { items: state.rules }
- }
-
- const resp = await quickSearchByQuery({ query: new SearchQuery(), entityType })
- dispatch('storeToRulesCache', { items: resp.items })
- commit(types.TAX_UPDATE_RULES, resp)
-
- return resp
- },
- storeToRulesCache (context, { items }) {
- const cache = StorageManager.get('elasticCache')
-
- for (let tc of items) {
- const cacheKey = entityKeyName('tc', tc.id)
- cache.setItem(cacheKey, tc).catch((err) => {
- Logger.error('Cannot store cache for ' + cacheKey + ', ' + err)()
- })
- }
- },
- single ({ getters }, { productTaxClassId }) {
- return getters.getRules.find((e) =>
- e.product_tax_class_ids.indexOf(parseInt(productTaxClassId)) >= 0
- )
- },
- async calculateTaxes ({ dispatch, getters, rootState }, { products }) {
- const mutatedProducts = catalogHooksExecutors.beforeTaxesCalculated(products)
-
- if (config.tax.calculateServerSide) {
- Logger.debug('Taxes calculated server side, skipping')()
- return doPlatformPricesSync(mutatedProducts)
- }
-
- let storeView = currentStoreView()
-
- const tcs = await dispatch('list', {})
- const {
- defaultCountry,
- defaultRegion,
- sourcePriceIncludesTax,
- finalPriceIncludesTax,
- deprecatedPriceFieldsSupport
- } = storeView.tax
-
- const recalculatedProducts = mutatedProducts.map(product =>
- calculateProductTax({
- product,
- taxClasses: tcs.items,
- taxCountry: defaultCountry,
- taxRegion: defaultRegion,
- finalPriceInclTax: finalPriceIncludesTax,
- sourcePriceInclTax: sourcePriceIncludesTax,
- userGroupId: getters.getUserTaxGroupId,
- deprecatedPriceFieldsSupport: deprecatedPriceFieldsSupport,
- isTaxWithUserGroupIsActive: getters.getIsUserGroupedTaxActive
- })
- )
-
- return doPlatformPricesSync(recalculatedProducts)
- }
-}
-
-export default actions
diff --git a/core/modules/catalog/store/tax/getters.ts b/core/modules/catalog/store/tax/getters.ts
deleted file mode 100644
index aa65d66f74..0000000000
--- a/core/modules/catalog/store/tax/getters.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { GetterTree } from 'vuex'
-import RootState from '@vue-storefront/core/types/RootState'
-import TaxState from '../../types/TaxState'
-import { currentStoreView } from '@vue-storefront/core/lib/multistore';
-
-const getters: GetterTree = {
- getRules: (state) => state.rules,
- getUserTaxGroupId: (state, getters, rootState) => {
- if (!getters.getIsUserGroupedTaxActive) return
-
- const storeViewTax = rootState.storeView.tax
- const currentUser = rootState.user.current
-
- if (storeViewTax.useOnlyDefaultUserGroupId || !currentUser) {
- return storeViewTax.userGroupId
- }
-
- return currentUser.group_id
- },
- getIsUserGroupedTaxActive: (state, getters, rootState) => {
- return typeof currentStoreView().tax.userGroupId === 'number'
- }
-}
-
-export default getters
diff --git a/core/modules/catalog/store/tax/index.ts b/core/modules/catalog/store/tax/index.ts
deleted file mode 100644
index c57a55eba9..0000000000
--- a/core/modules/catalog/store/tax/index.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Module } from 'vuex'
-import actions from './actions'
-import mutations from './mutations'
-import getters from './getters'
-import RootState from '@vue-storefront/core/types/RootState'
-import TaxState from '../../types/TaxState'
-
-export const taxModule: Module = {
- namespaced: true,
- state: {
- rules: []
- },
- actions,
- mutations,
- getters
-}
diff --git a/core/modules/catalog/store/tax/mutation-types.ts b/core/modules/catalog/store/tax/mutation-types.ts
deleted file mode 100644
index b970dc05c5..0000000000
--- a/core/modules/catalog/store/tax/mutation-types.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export const SN_TAX = 'tax'
-export const TAX_UPDATE_RULES = SN_TAX + '/UPDATE_RULES'
diff --git a/core/modules/catalog/store/tax/mutations.ts b/core/modules/catalog/store/tax/mutations.ts
deleted file mode 100644
index e731d955ac..0000000000
--- a/core/modules/catalog/store/tax/mutations.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { MutationTree } from 'vuex'
-import * as types from './mutation-types'
-import TaxState from '../../types/TaxState'
-
-const mutations: MutationTree = {
- [types.TAX_UPDATE_RULES] (state, taxClasses) {
- state.rules = taxClasses.items
- }
-}
-
-export default mutations
diff --git a/core/modules/catalog/test/helpers/createProduct.ts b/core/modules/catalog/test/helpers/createProduct.ts
deleted file mode 100644
index 2e3c689187..0000000000
--- a/core/modules/catalog/test/helpers/createProduct.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import Product from '@vue-storefront/core/modules/catalog/types/Product';
-
-export const createSimpleProduct = (): Product => ({
- 'id': 21,
- 'sku': '24-WG084',
- 'name': 'Sprite Foam Yoga Brick',
- 'price': 5,
- 'status': 1,
- 'visibility': 4,
- 'type_id': 'simple',
- 'product_links': [],
- 'custom_attributes': null,
- 'final_price': 5,
- 'max_price': 5,
- 'max_regular_price': 5,
- 'minimal_regular_price': 5,
- 'special_price': null,
- 'minimal_price': 5,
- 'regular_price': 5,
- 'description': '
Our top-selling yoga prop, the 4-inch, high-quality Sprite Foam Yoga Brick is popular among yoga novices and studio professionals alike. An essential yoga accessory, the yoga brick is a critical tool for finding balance and alignment in many common yoga poses. Choose from 5 color options.
A well-rounded yoga workout takes more than a mat. The Sprite Yoga Companion Kit helps stock your studio with the basics you need for a full-range workout. The kit is composed of four best-selling Luma Sprite accessories in one easy bundle: statis ball, foam block, yoga strap, and foam roller. Choose sizes and colors and leave the rest to us. The kit includes:
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/deploy.sh b/docs/deploy.sh
deleted file mode 100644
index 97a0fbb4fa..0000000000
--- a/docs/deploy.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env sh
-
-# abort on errors
-set -e
-
-# build
-npm run docs:build
-
-# navigate into the build output directory
-cd .vuepress/dist
-
-# if you are deploying to a custom domain
-# echo 'www.example.com' > CNAME
-
-git init
-git add -A
-git commit -m 'deploy'
-
-# if you are deploying to https://.github.io
-git push -f git@github.com:/.github.io.git master
-
-# if you are deploying to https://.github.io/
-git push -f git@github.com:DivanteLtd/vue-storefront.git master:gh-pages
-
-cd -
diff --git a/docs/guide/README.md b/docs/guide/README.md
deleted file mode 100644
index c0fa8c842b..0000000000
--- a/docs/guide/README.md
+++ /dev/null
@@ -1,125 +0,0 @@
-
-# Introduction to Vue Storefront
-
-Vue Storefront is a rather complex solution with a lot of possibilities. Learning all of them can take some time. In this introduction, we will learn all of its crucial concepts in a few minutes, which is enough to start playing with [Vue Storefront](https://www.vuestorefront.io/).
-
-
-## What is Vue Storefront
-![Vue Storefront](https://cdn-images-1.medium.com/max/1600/0*X7cXhVkWidbWFrbM)
-
-Vue Storefront is a headless and backend-agnostic eCommerce [Progressive Web App (PWA)](https://developers.google.com/web/progressive-web-apps/) written in Vue.js. The fact that it's using headless architecture allows Vue Storefront to connect with any eCommerce platform so it can be a frontend PWA for Magento, Shopify, BigCommerce, WooCommerce and etc.
-
- It's a very popular [Open Source project](https://github.com/vuestorefront/vue-storefront) with a strong and growing community.
-
-**Key features of Vue Storefront:**
-- Platform-agnostic
-- Focus on performance
-- Mobile-first approach
-- Cutting-edge tech
-- No limitations in theming and customization
-- Open Source with MIT license
-- Exciting developer experience
-- Out-of-the-box Server Side Rendering (for SEO)
-- Offline mode
-
-
-## How does it connect with backend platforms?
-Vue Storefront manages to be platform-agnostic thanks to the [vue-storefront-api](https://github.com/vuestorefront/vue-storefront-api) and [dedicated API connectors](https://github.com/vuestorefront/vue-storefront#integrations) for eCommerce backend platforms. The data format in vue-storefront-api is always the same for any platform, which means no matter what eCommerce backend you use, your frontend remains the same without any change.
-
-It's a great strategy for migrations since you can easily migrate from one platform to another (or one version to another, e.g. Magento 1 to 2) without touching your frontend.
-
-
-![Architecture diagram](https://raw.githubusercontent.com/DivanteLtd/vue-storefront/master/docs/.vuepress/public/GitHub-Architecture-VS.png)
-
-The API connector works in two phases:
-- **data pump** ([mage2nosql](https://github.com/vuestorefront/mage2vuestorefront) in the image) is pulling static data (catalog, orders, etc.) from your eCommerce platform to Vue Storefront Elasticsearch and changes its format to the one consumed by vue-storefront-api. Once finished pulling the data, you can display the product catalog in Vue Storefront. After pumping the data into Elasticsearch is done, it will stay in sync with changes made on the backend platform and update its content accordingly.
-
-- **worker pool** is a synchronization process of so-called dynamic calls (user sessions, cart rules, etc.) that couldn't be stored in the database and need to be called by vue-storefront-api directly from the backend platform.
-
-VueStorefront works seamlessly with your backend platform while two integration phases are managed as above.
-
-Some of the most popular backend platforms already have their integrations ([Magento 2](https://github.com/vuestorefront/magento2-vsbridge-indexer), [Magento 1](https://github.com/divanteLtd/magento1-vsbridge-indexer), [CoreShop](https://github.com/divanteLtd/coreshop-vsbridge), [BigCommerce](https://github.com/divanteLtd/bigcommerce2vuestorefront), [WooCommerce](https://github.com/divanteLtd/woocommerce2vuestorefront)), but you can easily make your own with the [integration boilerplate](https://github.com/divanteLtd/vue-storefront-integration-boilerplate).
-
-The blue parts on the diagram are responsible for offline cache and will be explained later in the article.
-
-## How does it work?
-
-There are 3 concepts you need to be familiar with while working with Vue Storefront.
-
-- **Vue Storefront Core** ( `core` folder) is the glue for all the features that allow Vue Storefront to work. It contains all the entry points, SSR behavior, build process, in-app libs and helpers. You shouldn't touch this folder directly when building your own implementations in order to stay up-to-date with its features and security.
-
-- **Vue Storefront Modules** ( `core/modules` and `src/modules` ) are the eCommerce features. Each module is one encapsulated feature (like cart, wishlist, catalog, and some third-party integrations). You can add/remove/edit these modules as you wish and compose your Vue Storefront shop with only the features that you need. They are also used for 3rd-party extensions.
-
-- **Vue Storefront Themes** ( `src/themes` ) are the actual shop implementation. In themes, you can use and extend all the logic from registered modules / core and add your HTML markup and styles. Vue Storefront provides a fully customizable default theme.
-
-To summarize: Your shop is basically a Vue Storefront theme that uses features provided by modules. Vue Storefront Core glues it all together.
-
-Knowing these 3 concepts allows you to confidently work with Vue Storefront and make your own shops.
-
-Useful materials: [Vue Storefront project structure](/guide/basics/project-structure.html)
-
-## Installing Vue Storefront
-When you want to play with Vue Storefront, there are three options:
-
-![install](https://cdn-images-1.medium.com/max/1200/0*dz-mwiEQ_Qkzpd5H)
-*This is everything you need to have VS working with our demo backend.*
-
-- You can set up the frontend connected to our demo backend platform (best for trying out Vue Storefront).
-- You can set up frontend with your own `vue-storefront-api` and database dumped from the demo.
-- You can set up frontend with `vue-storefront-api` connected to your eCommerce backend.
-
-To do any of this, simply type `yarn installer` in the root of the project and answer the questions in the console. Once the installation is done, type `yarn dev` to run your project (by default, on port `3000`). No matter what option you choose, you can change the settings in the config file later.
-
-## Vue Storefront config file
-
-Most of the Vue Storefront configuration (like the active theme, backend API addresses, multistore setup, etc.) is done through its [config](/guide/basics/configuration.html) file that can be found under the `config` folder. The `default.json` file contains all the default setup.
-
-For your own implementation you should create a `local.json` file in the same directory and include fields from `default.json` that you want to override. These two files will be merged in favor of `local.json` during the build process. If you use the installer to set up your Vue Storefront instance, it'll generate proper config files.
-
-## Building themes in Vue Storefront
-![themes structure](https://cdn-images-1.medium.com/max/1200/1*jMel95nhs5UTIi2DQdeq4Q.png)
-
-While making themes in Vue Storefront, in most cases, all you need to do is create your own HTML and CSS markup. All the required business logic is exposed by the core with its core modules and can be easily injected into any of the theme components.
-![biz-logic](https://cdn-images-1.medium.com/max/1200/1*tMwC0smduKIwKh82jTiJmw.png)
-*The business logic from the core component can be easily injected into any theme component as a Vue.js mixin.*
-
-The mechanism of injecting core business logic into themes is ridiculously simple. We are using [Vue.js mixins](https://vuejs.org/v2/guide/mixins.html) to maintain business logic upgradable in the core.
-
-So assume we have a core Microcart component with business logic as above (left side), we can easily inject it into any of our theme components (right side) just by importing it and adding as a mixin `mixins: [Microcart]`. This is all you need to make use of core business logic inside your theme. With this approach, we can easily ship updates to all core components without breaking your shop.
-
-[Check how to create theme based on our official themes](/guide/installation/theme.html).
-
-## Offline mode and cache
-Vue Storefront still works even while the user is offline.
-
-We managed to do this by making extensive use of the browser cache.
-- **For the static assets** (only prod) we use the [sw-precache](https://github.com/GoogleChromeLabs/sw-precache) plugin (config can be found in `core/build/webpack.prod.sw.config.js` ). They are cached in Service Worker and can be inspected under the `Application/Cache Storage` tab of your Developer Tools.
-
-![cache](https://cdn-images-1.medium.com/max/1200/1*BHVzt7oCIxcM3bNPZriKmw.png)
-*Here you can find cached static assets. Please notice that Service Worker works only in production mode.*
-
-:::warning
-Please note that Service Worker works only in production mode.
-:::
-
-- **For the catalog and store-data cache** we use IndexedDB and Local Storage. We also prefetch products from visited categories so once you enter one, all of its products are available offline. The mechanism of offline storage is located under `core/lin./storage`.
-
-We use some of the cached data even while the user is online to display the content instantly. This explains why Vue Storefront is lightning fast.
-
-
-## What else
-You may not believe me but this is all you need to know to start working with Vue Storefront! Once you are done wrapping your head around the basics, just look around docs and visit community [slack](https://vuestorefront.slack.com) to dig deeper into the project.
-
-## Useful Links
-
-- [Documentation](https://docs.vuestorefront.io/)
-- [Community slack invitation link](https://join.slack.com/t/vuestorefront/shared_invite/enQtOTUwNjQyNjY5MDI0LWFmYzE4NTYxNDBhZDRlMjM5MDUzY2RiMjU0YTRjYWQ3YzdkY2YzZjZhZDZmMDUwMWQyOWRmZjQ3NDgwZGQ3NTk)
-- [Project structure explained](https://docs.vuestorefront.io/guide/basics/project-structure.html)
-- [Configuration file explained](https://docs.vuestorefront.io/guide/basics/configuration.html)
-- [Extending Vue Storefront](https://docs.vuestorefront.io/guide/extensions/introduction.html)
-- [How to contribute](https://docs.vuestorefront.io/guide/basics/contributing.html#branches)
-
-## Video with training
-You can also watch a video recording from 4th Vue Storefront hackathon with free introduction training
-
-[![0.jpg](http://img.youtube.com/vi/IL2HMtvf_hw/0.jpg)](https://youtu.be/IL2HMtvf_hw)
diff --git a/docs/guide/archives/amp.md b/docs/guide/archives/amp.md
deleted file mode 100644
index fcd7008dfd..0000000000
--- a/docs/guide/archives/amp.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# Google Accelerated Mobile Pages
-
-:::danger REMINDER
-This document is _archived_ and _NOT_ relevant with the latest version which is `1.12` at the time of writing. Please keep in mind this document is supposed to help you maintain legacy product, not the fresh installation.
-:::
-
-
-Google Accelerated Mobile pages are available with Vue Storefront 1.6. By default, the Product and Category pages do support AMP. To get the AMP page, you should use the following URL:
-`http://localhost:3000/c/hoodies-and-sweatshirts-24` -> `http://localhost:3000/amp/c/hoodies-and-sweatshirts-24`.
-The discovery links are added as `
-
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
-
-```
-
-#### Available events:
-
-```html
-
-
-
-```
-
-#### Available props
-
-| Prop | Type | Required | Default | Description |
-| ----- | ------ | -------- | ------- | --------------------- |
-| name | String | true | | Unique name of modal |
-| delay | Number | false | 300 | Timeout to show modal |
-
-#### Available Methods
-
-| Method | Argument | Description |
-| ------ | -------------- | ---------------------------------------------------------- |
-| toggle | state: Boolean | Manually toggles a modal |
-| close | | Alias for manually hides a modal. Helpful for Close button |
-
-#### Styles
-
-Core component doesn't have CSS styles. If you want to see an example of our implementation please look [here](https://github.com/vuestorefront/vue-storefront/blob/master/src/themes/default/components/core/Modal.vue)
-
-
-
-## Events List
-
-To keep track and make debugging of `$bus.$emit` events across components easier, here is a list of such events that are triggered by components of the default theme.
-
-### ForgotPass
-
-On component close:
-- [`modal-hide`, `modal-signup`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Auth/ForgotPass.vue#L80)
-
-On send email action:
-- [`notification-progress-start`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Auth/ForgotPass.vue#L95)
-- [`notification-progress-stop`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Auth/ForgotPass.vue#L97)
-
-On error handler of email send action:
-- [`notification-progress-stop`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Auth/ForgotPass.vue#L109)
-
-### OrderConfirmation
-
-On mounted lifecycle hook:
-- [`modal-show`, `modal-order-confirmation`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Checkout/OrderConfirmation.vue#L65)
-
-On order confirmation:
-- [`modal-hide`, `modal-order-confirmation`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Checkout/OrderConfirmation.vue#L71)
-
-On order cancelling:
-- [`modal-show`, `modal-order-confirmation`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Checkout/OrderConfirmation.vue#L75)
-
-### OrderReview
-
-On 'Term and conditions' link click:
-- [`modal-toggle`, `modal-terms`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Checkout/OrderReview.vue#L51)
-
-### PersonalDetails
-
-On 'Term and conditions' link click:
-- [`modal-toggle`, `modal-terms`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Checkout/PersonalDetails.vue#L151)
-
-### Newsletter
-
-On newsletter popup show:
-- [`modal-show`, `modal-newsletter`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Footer/Newsletter.vue#L49)
-
-### Header
-
-On 'Login to your account' link click:
-- [`modal-toggle`, `modal-signup`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Header/Header.vue#L122)
-
-### Reviews
-
-On 'Login to your account' link click:
-- [`modal-show`, `modal-signup`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Reviews/Reviews.vue#L155)
-
-### SidebarMenu
-
-On 'Login to your account' link click:
-- [`modal-show`, `modal-signup`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue#L201)
-
-### SubCategory
-
-On user logout:
-- [`user-before-logout`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/SidebarMenu/SubCategory.vue#L131)
-
-### Language
-
-On mounted lifecycle hook:
-- [`modal-show`, `modal-switcher`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Switcher/Language.vue#L55)
-
-On component close:
-- [`modal-hide`, `modal-switcher`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/blocks/Switcher/Language.vue#L60)
-
-### LanguageSwitcher
-
-On showing language popup:
-- [`modal-show`, `modal-switcher`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/LanguageSwitcher.vue#L30)
-
-### NewsletterPopup
-
-On showing newsletter popup:
-- [`modal-show`, `modal-newsletter`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/NewsletterPopup.vue#L54)
-
-On hiding newsletter popup:
-- [`modal-hide`, `modal-newsletter`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/core/NewsletterPopup.vue#L67)
-
-### Onboard
-
-On component close:
-- [`modal-hide`, `modal-onboard`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/components/theme/blocks/Home/Onboard.vue#L45)
-
-### Home
-
-On beforeMount lifecycle hook:
-- [`modal-toggle`, `modal-onboard`](https://github.com/vuestorefront/vue-storefront/blob/6c100f978aa79975e4db22be3cefa7f8d38b4c97/src/themes/default/pages/Home.vue#L74)
diff --git a/docs/guide/archives/cookbook.md b/docs/guide/archives/cookbook.md
deleted file mode 100644
index 11a527acfe..0000000000
--- a/docs/guide/archives/cookbook.md
+++ /dev/null
@@ -1,1331 +0,0 @@
-# Cookbook
-
-:::danger REMINDER
-This document is _archived_ and _NOT_ relevant with the latest version which is `1.12` at the time of writing. Please keep in mind this document is supposed to help you maintain legacy product, not the fresh installation.
-:::
-
-## Install
-
-In this chapter, we will cover :
-
-[[toc]]
-
-
-### 0. Introduction
-Now you are definitely interested in **Vue Storefront**. That's why you are here. You've come across the line. You made a choice. You will have something in return, which is great. Be it developers, entrepreneurs or even marketing managers that they may want to try something new for better products in hopes of enhancing their clients or customers' experience. You chose the right path. We will explore anything you need to get you started at all with [**Vue Storefront** infrastructure](https://github.com/vuestorefront).
-
-
-### 1. Install with Docker
-Docker has been arguably the most sought-after, brought to the market which took the community by storm ever since its introduction. Although it's yet controversial whether it's the best choice among its peers, I have never seen such an unanimous enthusiasm over one tech product throughout the whole developers community.
-
-Then, why so? In modern computer engineering, products are so complex with an endless list of dependencies intertwined with each other. Building such dependencies in place for every occasion where it's required is one hell of a job, not to mention glitches from all the version variation. That's where Docker steps in to make you achieve **infrastructure automation**. This concept was conceived to help you focus on your business logic rather than having you stuck with hassles of lower level tinkering.
-
-Luckily, we already have been through all this for you, got our hands dirty. All you need is run a set of docker commands to get you up and running from scratch. Without further ado, let's get started!
-
-
-#### 1. Preparation
-- You need [`docker`](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04) and [`docker-compose`](https://www.digitalocean.com/community/tutorials/how-to-install-docker-compose-on-ubuntu-18-04) installed.
-
-- You need [`git`](https://www.digitalocean.com/community/tutorials/how-to-install-git-on-ubuntu-18-04) installed.
-
-:::tip NOTE
-We will walk you with docker on *Linux*. (Specifically *Ubuntu 18.04* if needed)
-
-There is only one bias for Docker before using it; *Run it on Linux*. Docker is native Linux, was created using a Linux technology; LXC (linux container) in the first place. Even though there were many attempts made to make it available to other platforms as it does on Linux, and it has definitely been on a progress, however, using Docker on Linux is the solidest way to deal with the technology.
-
-That being sad, there are tips for using other platforms for docker at [Chef's Secrets](#_4-chef-s-secret-protip) as well.
-:::
-
-#### 2. Recipe
-1. First, start with backend, download [**Vue Storefront API**](https://github.com/vuestorefront/vue-storefront-api) from github.
-```bash
-git clone https://github.com/vuestorefront/vue-storefront-api.git vue-storefront-api
-cd vue-storefront-api
-```
-
-2. Copy `./config/default.json` to `./config/local.json`
-```bash
-cp config/default.json config/local.json
-```
-Then edit `local.json` to your need.
-We will look into this in greater detail at [Chef's secret](#_4-chef-s-secret-protip)
-:::tip TIP
-This step can be skipped if you are OK with values of `default.json` since it follows the [files load order](https://github.com/lorenwest/node-config/wiki/Configuration-Files#file-load-order) of [node-config](https://github.com/lorenwest/node-config)
-
-:::
-
-3. Run the following Docker command :
-```bash
-docker-compose -f docker-compose.yml -f docker-compose.nodejs.yml up -d
-```
-
-Then the result would look something like this :
-```bash
-Building app
-Step 1/8 : FROM node:10-alpine
- ---> 9dfa73010b19
-Step 2/8 : ENV VS_ENV prod
- ---> Using cache
- ---> 4d0a83421665
-Step 3/8 : WORKDIR /var/www
- ---> Using cache
- ---> e3871c8db7f3
-Step 4/8 : RUN apk add --no-cache curl git
- ---> Using cache
- ---> 49e996f0f6cb
-Step 5/8 : COPY package.json ./
- ---> 14ed18d76efc
-Step 6/8 : RUN apk add --no-cache --virtual .build-deps ca-certificates wget && yarn install --no-cache && apk del .build-deps
- ---> Running in 3d6f91acc2fe
-fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gz
-fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/community/x86_64/APKINDEX.tar.gz
-(1/2) Installing wget (1.20.3-r0)
-(2/2) Installing .build-deps (0)
-Executing busybox-1.29.3-r10.trigger
-OK: 22 MiB in 26 packages
-yarn install v1.16.0
-info No lockfile found.
-[1/4] Resolving packages...
-warning @babel/node > @babel/polyfill@7.4.4: 🚨 As of Babel 7.4.0, this
-package has been deprecated in favor of directly
-including core-js/stable (to polyfill ECMAScript
-features) and regenerator-runtime/runtime
-(needed to use transpiled generator functions):
-
- > import "core-js/stable";
- > import "regenerator-runtime/runtime";
-warning eslint > file-entry-cache > flat-cache > circular-json@0.3.3: CircularJSON is in maintenance only, flatted is its successor.
-[2/4] Fetching packages...
-
-# ... abridged
-
-
-```
-:vhs: You may also watch it in [bash playback :movie_camera:](https://asciinema.org/a/7XT5CWP4ynrPItattiP3on6wS)
-
-:::tip TIP
-`-f` flag allows you to use the following docker-compose file. Without this flag, it will use the default file that is `docker-compose.yml`
-
-`-d` flag allows you to run the command in `detach mode` which means *running background*.
-:::
-3. In order to verify, run `docker ps` to show which containers are up
-```bash
-docker ps
-```
-
-Then,
-```bash
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-53a47d5a6440 vuestorefrontapi_kibana "/bin/bash /usr/loca…" 31 seconds ago Up 29 seconds 0.0.0.0:5601->5601/tcp vuestorefrontapi_kibana_1
-7d8f6328601b vuestorefrontapi_app "docker-entrypoint.s…" 31 seconds ago Up 27 seconds 0.0.0.0:8080->8080/tcp vuestorefrontapi_app_1
-165ae945dbe5 vuestorefrontapi_es1 "/bin/bash bin/es-do…" 8 days ago Up 30 seconds 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
-8dd144746cef redis:4-alpine "docker-entrypoint.s…" 11 days ago Up 31 seconds 0.0.0.0:6379->6379/tcp vuestorefrontapi_redis_1
-```
-The ports number will be used later in the frontend configuration. In fact, they are already set in as default values.
-
-You will see 4 containers are running, which is :
-| Container | Port |
-|------------------------|---------------------|
-| Vue Storefront API app | :8080 |
-| Elasticsearch | :9200 |
-| Kibana | :5601 |
-| Redis | :6379 |
-
-
-4. Now that backend part is done, let's work on frontend part, that is download [**Vue Storefront**](https://github.com/vuestorefront/vue-storefront)
-
-```bash
-git clone --single-branch --branch master https://github.com/vuestorefront/vue-storefront.git vue-storefront
-cd vue-storefront
-```
-
-5. Prepare the config file at `./config/local.json`. There is `default.json` file in the same folder which is a default set of configuration. Copy it as follows :
-```bash
-cp config/default.json config/local.json
-```
-Then fix the value as you need it in the `local.json` file.
-In `local.json`, you may change values for information of backend family. But if you followed this recipe verbatim, you don't have to, because it's already there with the default value. Should you study the contents, please see to [Chef's secret](#secret-1-study-in-local-json)
-
-6. Finally run the following Docker command :
-```bash
-docker-compose up -d
-```
-The result should be something like this :
-```bash
-Building app
-Step 1/8 : FROM node:10-alpine
- ---> 9dfa73010b19
-Step 2/8 : ENV VS_ENV prod
- ---> Using cache
- ---> 4d0a83421665
-Step 3/8 : WORKDIR /var/www
- ---> Using cache
- ---> e3871c8db7f3
-Step 4/8 : COPY package.json ./
- ---> 0eab68a8f13a
-Step 5/8 : COPY yarn.lock ./
- ---> ac1f5e4a1831
-Step 6/8 : RUN apk add --no-cache --virtual .build-deps ca-certificates wget git && yarn install --no-cache && apk del .build-deps
- ---> Running in 1ca7bc7782e3
-fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gz
-fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/community/x86_64/APKINDEX.tar.gz
-(1/9) Installing ca-certificates (20190108-r0)
-(2/9) Installing wget (1.20.3-r0)
-(3/9) Installing nghttp2-libs (1.35.1-r0)
-(4/9) Installing libssh2 (1.8.2-r0)
-(5/9) Installing libcurl (7.64.0-r2)
-(6/9) Installing expat (2.2.6-r0)
-(7/9) Installing pcre2 (10.32-r1)
-(8/9) Installing git (2.20.1-r0)
-(9/9) Installing .build-deps (0)
-Executing busybox-1.29.3-r10.trigger
-Executing ca-certificates-20190108-r0.trigger
-OK: 22 MiB in 25 packages
-yarn install v1.16.0
-[1/5] Validating package.json...
-[2/5] Resolving packages...
-[3/5] Fetching packages...
-info fsevents@1.2.4: The platform "linux" is incompatible with this module.
-
-# ... abridged
-
-```
-
-:vhs: You may also watch it in [bash playback :movie_camera:](https://asciinema.org/a/JZYI9ZE6DHeC7N2keBNoFUWjQ)
-
-7. In order to verify, run `docker ps`, there should be another container added to the list.
-```bash
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-88d758bc24d0 vuestorefront_app "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:3000->3000/tcp vuestorefront_app_1
-de560221fdaf vuestorefrontapi_kibana "/bin/bash /usr/loca…" 8 hours ago Up 23 minutes 0.0.0.0:5601->5601/tcp vuestorefrontapi_kibana_1
-5576cd9963a1 vuestorefrontapi_app "docker-entrypoint.s…" 8 hours ago Up 23 minutes 0.0.0.0:8080->8080/tcp vuestorefrontapi_app_1
-88f5db9486da vuestorefrontapi_es1 "/bin/bash bin/es-do…" 8 hours ago Up 24 minutes 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
-d46c1e0a22af redis:4-alpine "docker-entrypoint.s…" 8 hours ago Up 24 minutes 0.0.0.0:6379->6379/tcp vuestorefrontapi_redis_1
-
-```
-8. Open your browser and visit [http://localhost:3000/](http://localhost:3000/)
-
-After compiling, *Voila!*
-
-![vs_home_intro_borderline](../images/home-vuestorefront.png)
-
-#### 3. Peep into the kitchen (what happens internally)
-We used `docker-compose` for setting up the entire environment of Vue Storefront. It was more than enough to launch the machines behind for running the shop.
-
-It was possible because `docker` encapsulated the whole bunch of infrastructure into a linear set of declarative definition for the desired state.
-
-We had 2 steps of `docker-compose` one of which is for backend **Vue Storefront API**, the other for frontend **Vue Storefront**.
-
-The first `docker-compose` had two `yml` files for input. The first input file `docker-compose.yml` describe its base requirement all but **Vue Storefront API** itself; that is, **Elasticsearch** as data store, **Redis** for cache and **Kibana** for helping you grab your data visually (a pair of Elasticsearch).
-```yaml
-# docker-compose.yml
-version: '3.0'
-services:
- es1:
- container_name: elasticsearch
- build: docker/elasticsearch/
- volumes:
- - ./docker/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
- - ./docker/elasticsearch/data:/usr/share/elasticsearch/data
- ports:
- - '9200:9200'
- - '9300:9300'
- environment:
- ES_JAVA_OPTS: "-Xmx512m -Xms512m"
-
- kibana:
- build: docker/kibana/
- volumes:
- - ./docker/kibana/config/:/usr/share/kibana/config:ro
- ports:
- - '5601:5601'
- depends_on:
- - es1
-
- redis:
- image: 'redis:4-alpine'
- ports:
- - '6379:6379'
-
-volumes:
- esdat1:
-```
-:::tip NOTE
-Once a term explained, it will be ignored thereafter for consecutive occurrence.
-:::
-`version` denotes which version of `docker-compose` this file uses.
-
-`services` describe containers. It codifies how they should run. In other words, it codifies option flags used with `docker run ...`
-
-`es1` contains information of data store *Elasticsearch* container.
-- `build` denotes build path of container.
-- `volumes` contains the mount path of volumes shared between host and container as *host:container*
-- `ports` connect ports between host and container as in *host:container*
-- `environment` allows you to add environment variables. `Xmx512m` means JVM will take up to maximum 512MB memory. `Xms512m` means minimum memory. Combining them, there will be no memory resize, it will just stick to 512MB from start to end throughout its life cycle.
-
-`kibana` contains information of *Kibana* application container.
-- `depends_on` creates dependency for a container of other containers. So, this container is dependent on `es1` that's just described above.
-- `volumes` mean volumes shared, `:ro` creates the volume in `read-only` mode for the container.
-
-`redis` contains information of *Redis* cache application container.
-
-- `image` node contains the name of image this container is based on.
-
-`volumes` in top level can be used as a reference to be used across multiple services(containers).
-
-
-
-The second input file `docker-compose.nodejs.yml` deals with **Vue Storefront API** node application.
-```yaml
-version: '3.0'
-services:
- app:
- # image: divante/vue-storefront-api:latest
- build:
- context: .
- dockerfile: docker/vue-storefront-api/Dockerfile
- depends_on:
- - es1
- - redis
- env_file: docker/vue-storefront-api/default.env
- environment:
- VS_ENV: dev
- volumes:
- - './config:/var/www/config'
- - './ecosystem.json:/var/www/ecosystem.json'
- - './migrations:/var/www/migrations'
- - './package.json:/var/www/package.json'
- - './babel.config.js:/var/www/babel.config.js'
- - './scripts:/var/www/scripts'
- - './src:/var/www/src'
- - './var:/var/www/var'
- tmpfs:
- - /var/www/dist
- ports:
- - '8080:8080'
-```
-`app` contains information of *Vue Storefront API* application.
-- `build` is path for build information. If the value is string, it's a plain path. When it's object, you may have a few options to add. `context` is relative path or git repo url where `Dockerfile` is located. `dockerfile` node may change the path/name of `Dockerfile`. [more info](https://docs.docker.com/compose/compose-file/#build)
-- `depends_on` tells us this container is based on `es1` and `redis` containers we created above.
-- `env_file` helps you add environment values from files. It's relative path from the `docker-compose` file that is in the process, in this case, it's `docker-compose.nodejs.yml`
-- `environment` is to set `VS_ENV` as `dev` so that environment will be setup for developer mode.
-- `tmpfs` denotes temporary volumes that are only available to host memory. Unlike `volumes`, this `tmpfs` will be gone once the container stops. This option is only available to *Linux*.
-
-
-
-
-The second `docker-compose` step handles **Vue Storefront** frontend.
-``` yaml
-version: '2.0'
-services:
- app:
- # image: divante/vue-storefront:latest
- build:
- context: .
- dockerfile: docker/vue-storefront/Dockerfile
- env_file: docker/vue-storefront/default.env
- environment:
- VS_ENV: dev
- network_mode: host
- volumes:
- - './babel.config.js:/var/www/babel.config.js'
- - './config:/var/www/config'
- - './core:/var/www/core'
- - './ecosystem.json:/var/www/ecosystem.json'
- - './.eslintignore:/var/www/.eslintignore'
- - './.eslintrc.js:/var/www/.eslintrc.js'
- - './lerna.json:/var/www/lerna.json'
- - './tsconfig.json:/var/www/tsconfig.json'
- - './tsconfig-build.json:/var/www/tsconfig-build.json'
- - './shims.d.ts:/var/www/shims.d.ts'
- - './package.json:/var/www/package.json'
- - './src:/var/www/src'
- - './var:/var/www/var'
- tmpfs:
- - /var/www/dist
- ports:
- - '3000:3000'
-```
-This looks like by and large the same with *Vue Storefront API* with a few changes.
-
-`app` service describes options for *Vue Storefront* frontend application.
-- `network_mode` allows you to modify values for `--network` option of docker client. `host` option allows your designated container to open to host network. For example, if you bind your container in host's `80` port, then the container will be accessible at host's `:80` from the internet. In other words, the container is not isolated. [more info](https://docs.docker.com/network/host/)
-
-If you take a closer look inside `Dockerfile`s, you will notice they install all the dependencies of the project from `package.json` not to mention required OS features including `git`, `wget` and certificates. You don't have to worry what to do because we made it do for you.
-
-Next, you might want to import your goods data. Please jump to [Data imports](./data-import.md) if you don't want to stop.
-
-#### 4. Chef's secret (protip)
-##### Secret 1. Study in `local.json` for *Vue Storefront API*
-Starting point of customization is `default.json` or its copy `local.json` where the platform seeks configuration values.
-:::tip NOTE
-If you want to modify `default.json`, don't edit it directly but copy the whole file into `local.json` and start editing it in that file. Why it should be done that way is explained later at [Secret 3. Why use node-config?](#secret-3-why-use-node-config)
-:::
-We have 2 `local.json` files, one of which is for backend here, and we will look at [Secret 2](#secret-2-study-in-local-json-for-vue-storefront), the other for frontend .
-
-At [`vue-storefront-api/config/default.json`](https://github.com/vuestorefront/vue-storefront-api/blob/master/config/default.json) for **backend** :
-```json
- "server": {
- "host": "localhost",
- "port": 8080,
- "searchEngine": "elasticsearch"
- },
-```
-- This is where your API backend is defined. The server will listen `server.host`:`server.port` unless it's defined otherwise in environment variables.
-
-- `server.searchEngine` is used in the integration with `graphql` so please don't change it. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/graphql/resolvers.js#L6)
-```json
- "orders": {
- "useServerQueue": false
- },
- "catalog": {
- "excludeDisabledProducts": false
- },
-```
-- `orders.useServerQueue` allows you to use queue process when `order` API is used to create an order. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/order.js#L65)
-
-- `catalog.excludeDisabledProducts` allows you to skip disabled products when importing products using `mage2vs`.
-[jump to code](https://github.com/vuestorefront/mage2vuestorefront/blob/master/src/adapters/magento/product.js#L166)
-
-```json
- "elasticsearch": {
- "host": "localhost",
- "port": 9200,
- "protocol": "http",
- "user": "elastic",
- "password": "changeme",
- "min_score": 0.01,
- "indices": [
- "vue_storefront_catalog",
- "vue_storefront_catalog_de",
- "vue_storefront_catalog_it"
- ],
- "indexTypes": [
- "product",
- "category",
- "cms",
- "attribute",
- "taxrule",
- "review"
- ],
- "apiVersion": "5.6"
- },
-```
-- `elasticsearch` element is used widely across the whole platform. Considering `elasticsearch` works as a data store (database), it's natural.
-
- - `host`, `port`, `protocol` defines `elasticsearch` connect information.
-- `user`, `password` is default credentials of `elasticsearch`. If you changed the credentials of `elasticsearch`, please change this accordingly. [more info](https://www.elastic.co/guide/en/x-pack/current/security-getting-started.html)
- - `min_score` sets a `min_score` when building a query for `elasticsearch`. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/graphql/elasticsearch/queryBuilder.js#L172)
- :::tip TIP
- `min_score` helps you exclude documents with `_score` less than `min_score` value.
- :::
- - `indices` may contain one or multiple indexes. Each index acts as a data store for a storefront. You may add entries to the array with arbitrary names or remove entries from it.
- :::warning CAUTION !
- However, the index name should match the one you will use for [data pump](data-import.md#_2-2-recipe-b-using-on-premise).
- :::
- The default values for `indices` assume you have 2 additional stores(`de`, `it`) plus the default store.
- - `indexTypes` contains values for mapping. You can consider it as `table` if you take `indices` as database.
- - `apiVersion` defines the `elasticsearch` version it uses.
-
-```json
- "redis": {
- "host": "localhost",
- "port": 6379,
- "db": 0
- },
- "kue": {},
-```
-- `redis` contains `redis` server connect information.
-- `kue` contains `kue` application options. [jump to code for options](https://github.com/Automattic/kue/blob/master/lib/kue.js#L88)
-
-```json
- "availableStores": [
- "de",
- "it"
- ],
-```
-- `availableStores` contains additional stores code name. If this value is an empty array, it means you only have one default store.
-
-```json
-"storeViews": {
- "multistore": true,
- "mapStoreUrlsFor": [
- "de",
- "it"
- ],
- "de": {
- "storeCode": "de",
- "storeId": 3,
- "name": "German Store",
- "url": "/de",
- "elasticsearch": {
- "host": "localhost:8080/api/catalog",
- "index": "vue_storefront_catalog_de"
- },
- "tax": {
- "defaultCountry": "DE",
- "defaultRegion": "",
- "calculateServerSide": true,
- "sourcePriceIncludesTax": false
- },
- "i18n": {
- "fullCountryName": "Germany",
- "fullLanguageName": "German",
- "defaultLanguage": "DE",
- "defaultCountry": "DE",
- "defaultLocale": "de-DE",
- "currencyCode": "EUR",
- "currencySign": "EUR",
- "dateFormat": "HH:mm D-M-YYYY"
- }
- },
- "it": {
- "storeCode": "it",
- "storeId": 4,
- "name": "Italian Store",
- "url": "/it",
- "elasticsearch": {
- "host": "localhost:8080/api/catalog",
- "index": "vue_storefront_catalog_it"
- },
- "tax": {
- "defaultCountry": "IT",
- "defaultRegion": "",
- "calculateServerSide": true,
- "sourcePriceIncludesTax": false
- },
- "i18n": {
- "fullCountryName": "Italy",
- "fullLanguageName": "Italian",
- "defaultCountry": "IT",
- "defaultLanguage": "IT",
- "defaultLocale": "it-IT",
- "currencyCode": "EUR",
- "currencySign": "EUR",
- "dateFormat": "HH:mm D-M-YYYY"
- }
- }
- },
-
-```
-- `storeViews` element contains the whole information of ***additional*** stores. The default store information doesn't exist here, it exists on top level.
-- `multistore` is supposed to tell the platform if it has multiple stores to consider. For example, it is used to configure `tax` values of additional store. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/platform/magento2/tax.js#L14)
-- `mapStoreUrlsFor` is used for building url routes in frontend. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/lib/multistore.ts#L85)
-- `de` element contains detailed information of `de` store. You need to have this kind of element for all the additional stores you added to `availableStores` with `storeCode` as the key. `de` and `it` in the `default.json` exhibits an example you can copy & paste for other stores you need to add.
- - `storeCode` denotes store code for the store.
- - `storeId` denotes store ID of the store.
- - `name` denotes the store name.
- - `url` denotes URL for the store.
- - `elasticsearch` contains information for the store. This information may override the default one defined above.
- - `host` is where your *Elasticsearch* listens on.
- - `index` is the name of the index for the store.
- - `tax` contains tax information of the store.
- - `defaultCountry` is the code name of the country on which tax is calculated for the store.
- - `defaultRegion` is default region.
- - `calculateServerSide` determines if price is fetched with(`true`)/without(`false`) tax calculated. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/product.js#L48)
- - `sourcePriceIncludesTax` determines whether price is stored with tax applied (`true`) or tax calculated on runtime (`false`). [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/platform/magento2/tax.js#L12)
- - `i18n` connotes *internationalization*. [more info](https://en.wikipedia.org/wiki/Internationalization_and_localization)
- - `fullCountryName` is the full name of the country this `i18n` is applied to.
- - `fullLanguageName` is the full name of the language this `i18n` is applied to.
- - `defaultCountry` is the abbreviated name of the country this `i18n` is applied to by default.
- - `defaultLanguage` is the abbreviated name of the language this `i18n` is applied to by default.
- - `defaultLocale` is the default locale this `i18n` uses.
- - `currencyCode` is the currency code this store uses.
- - `currencySign` is the currency sign this store uses.
- - `dateFormat` is the date format this store uses.
-
-
- ```json
- "authHashSecret": "__SECRET_CHANGE_ME__",
- "objHashSecret": "__SECRET_CHANGE_ME__",
- ```
-- `authHashSecret` is used to encode & decode JWT for API use.
-- `objHashSecret` is 1) fallback secret hash for `authHashSecret`, 2) used for hashing in tax calculation.
-
-```json
- "cart": {
- "setConfigurableProductOptions": false
- },
- "tax": {
- "defaultCountry": "PL",
- "defaultRegion": "",
- "calculateServerSide": true,
- "alwaysSyncPlatformPricesOver": false,
- "usePlatformTotals": true,
- "setConfigurableProductOptions": true,
- "sourcePriceIncludesTax": false
- },
-```
-- `cart`
- - `setConfigurableProductOptions` flag determines to show either the parent item or the child item (aka selected option item) in the cart context. `true` shows parent item instead of the option item selected. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/platform/magento2/o2m.js#L94)
-- `tax`
- - `alwaysSyncPlatformPricesOver` [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/order.js#L49)
- - `usePlatformTotals`
- These two options are used to determine whether to fetch prices from data source on the fly or not. If you set `alwaysSyncPlatformPricesOver` true, then it skips checking the checksum for cart items based on price.
-
-```json
- "bodyLimit": "100kb",
- "corsHeaders": [
- "Link"
- ],
-```
-- `bodyLimit` limits how big a request can be for your application.
-- `corsHeaders` allows you to add entries to `Access-Control-Expose-Headers`
-
-```json
- "platform": "magento2",
-```
-- `platform` defines which e-commerce platform is used as a source. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/order.js#L13)
-
-```json
- "registeredExtensions": [
- "mailchimp-subscribe",
- "example-magento-api",
- "cms-data",
- "mail-service"
- ],
- "extensions": {
- "mailchimp": {
- "listId": "e06875a7e1",
- "apiKey": "a9a3318ea7d30f5c5596bd4a78ae0985-us3",
- "apiUrl": "https://us3.api.mailchimp.com/3.0"
- },
- "mailService": {
- "transport": {
- "host": "smtp.gmail.com",
- "port": 465,
- "secure": true,
- "user": "vuestorefront",
- "pass": "vuestorefront.io"
- },
- "targetAddressWhitelist": ["contributors@vuestorefront.io"],
- "secretString": "__THIS_IS_SO_SECRET__"
- }
- },
-```
-- `registeredExtensions` element contains the list of supported extensions, it bootstraps entry points for those extensions [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/index.js#L45)
-
-- `extensions` contains additional configuration for extensions. [jump to code](https://github.com/vuestorefront/vue-storefront-api/tree/master/src/api/extensions)
- - `mailchimp` provides `POST`, `DELETE` APIs for *Mailchimp* `subscribe` method.
- - `listId` is the ID of list you are publishing.
- - `apiKey` is API key you are assigned.
- - `apiUrl` is API base url for *Mailchimp* service.
- - `mailService` is used to send emails from Vue Storefront via *Gmail*.
- - `transport` contains basic information for *Gmail* service.
- - `host` is where your mail is sent en route.
- - `port` is the port number used for the service.
- - `secure` determines to use SSL connection.
- - `user` is `username` for the service.
- - `pass` is `password` for the service.
- - `targetAddressWhitelist` checks if an user confirmed his/her email address *and* source email is white-listed.
- - `secretString` is used for hashing.
-
-```json
- "magento2": {
- "url": "http://demo-magento2.vuestorefront.io/",
- "imgUrl": "http://demo-magento2.vuestorefront.io/media/catalog/product",
- "assetPath": "/../var/magento2-sample-data/pub/media",
- "magentoUserName": "",
- "magentoUserPassword": "",
- "httpUserName": "",
- "httpUserPassword": "",
- "api": {
- "url": "http://demo-magento2.vuestorefront.io/rest",
- "consumerKey": "byv3730rhoulpopcq64don8ukb8lf2gq",
- "consumerSecret": "u9q4fcobv7vfx9td80oupa6uhexc27rb",
- "accessToken": "040xx3qy7s0j28o3q0exrfop579cy20m",
- "accessTokenSecret": "7qunl3p505rubmr7u1ijt7odyialnih9"
- }
- },
- "magento1": {
- "url": "http://magento-demo.local",
- "imgUrl": "http://magento-demo.local/media/catalog/product",
- "magentoUserName": "",
- "magentoUserPassword": "",
- "httpUserName": "",
- "httpUserPassword": "",
- "api": {
- "url": "http://magento-demo.local/vsbridge",
- "consumerKey": "",
- "consumerSecret": "",
- "accessToken": "",
- "accessTokenSecret": ""
- }
- },
-```
-- `magento2` is used to integrate with Magento 2 as a data source.
-
- - `imgUrl` is base image url. [jump to code](https://github.com/kkdg/vue-storefront-api/blob/master/src/api/img.js#L38)
-
- - `assetPath` is used for the `media` path. [jump to code](https://github.com/kkdg/vue-storefront-api/blob/master/src/index.js#L22)
-
- - `api` contains API credentials for integration.
-
- - `url` is base url for Magento 2 instance.
- - `consumerKey` See **TIP**
- - `consumerSecret`
- - `accessToken`
- - `accessTokenSecret`
-
-
-
- :::tip TIP
-
- These 4 nodes above is the required credentials for integration with Magento 2. [how to get them](data-import.html#_2-2-recipe-b-using-on-premise)
-
- :::
-
-`magento1` has just the same structure with `magento2`.
-
-
-
-```json
- "imageable": {
- "namespace": "",
- "maxListeners": 512,
- "imageSizeLimit": 1024,
- "whitelist": {
- "allowedHosts": [
- ".*divante.pl",
- ".*vuestorefront.io"
- ]
- },
- "cache": {
- "memory": 50,
- "files": 20,
- "items": 100
- },
- "concurrency": 0,
- "counters": {
- "queue": 2,
- "process": 4
- },
- "simd": true,
- "keepDownloads": true
- },
-```
-- `imageable` deals with everything you need to configure when it comes to your storefront images, especially product images.
-
- - `maxListeners` limits maximum listeners to request's socket. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/img.js#L21)
- - `imageSizeLimit` limits maximum image size. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/img.js#L56)
- - `whitelist` contains a white-list of image source domains
-
- - `allowedHosts` contains the array of white-list
-
- :::warning DON'T FORGET
-
- You should include your source domain in `allowedHosts` or your request for product images will fail. [more info](data-import.html#secret-1-product-image-is-not-synced)
-
- :::
-
- :::tip NOTE
-
- From `cache` to `simd` they are used to configure [Sharp](https://github.com/lovell/sharp) library. *Sharp* is a popular library for image processing in *Node.js*. [jump to option docs](https://sharp.dimens.io/en/stable/api-utility/#cache)
-
- :::
-
- - `cache` limits `libvips` operation cache from *Sharp*. Values hereunder are default values. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/lib/image.js#L5)
-
- - `memory` is the maximum memory in MB to use for the cache.
- - `files` is the maximum number of files to hold open.
- - `items` is the maximum number of operations to cache.
-
- - `concurrency` is the number of threads for processing each image.
-
- - `counters` provides access to internal task counters.
-
- - `queue` is the number of tasks in queue for *libuv* to provide a worker thread.
- - `process` limits the number of resize tasks concurrently processed.
-
- - `simd` to use SIMD vector unit of the CPU in order to enhance the performance.
-
-
-
-```json
- "entities": {
- "category": {
- "includeFields": [ "children_data", "id", "children_count", "sku", "name", "is_active", "parent_id", "level", "url_key" ]
- },
- "attribute": {
- "includeFields": [ "attribute_code", "id", "entity_type_id", "options", "default_value", "is_user_defined", "frontend_label", "attribute_id", "default_frontend_label", "is_visible_on_front", "is_visible", "is_comparable" ]
- },
- "productList": {
- "sort": "",
- "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "url_key" ],
- "excludeFields": [ "configurable_children", "description", "configurable_options", "sgn" ]
- },
- "productListWithChildren": {
- "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.priceInclTax", "configurable_children.specialPriceInclTax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax", "configurable_children.color", "configurable_children.size", "product_links", "url_key"],
- "excludeFields": [ "description", "sgn"]
- },
- "product": {
- "excludeFields": [ "updated_at", "created_at", "attribute_set_id", "status", "visibility", "tier_prices", "options_container", "msrp_display_actual_price_type", "has_options", "stock.manage_stock", "stock.use_config_min_qty", "stock.use_config_notify_stock_qty", "stock.stock_id", "stock.use_config_backorders", "stock.use_config_enable_qty_inc", "stock.enable_qty_increments", "stock.use_config_manage_stock", "stock.use_config_min_sale_qty", "stock.notify_stock_qty", "stock.use_config_max_sale_qty", "stock.use_config_max_sale_qty", "stock.qty_increments", "small_image"],
- "includeFields": null,
- "filterFieldMapping": {
- "category.name": "category.name.keyword"
- }
- }
- },
-```
-- `entities` is used to integrate with *GraphQL* in **Vue Storefront API**.
- - `category`
- - `includeFields` contains an array of fields to be added as `sourceInclude` [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/graphql/elasticsearch/category/resolver.js#L10)
- - `product`
- - `filterFieldMapping` adds a field mapping to apply a filter in a query [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/graphql/elasticsearch/mapping.js#L19)
- - `category.name`
-
-```json
- "usePriceTiers": false,
- "boost": {
- "name": 3,
- "category.name": 1,
- "short_description": 1,
- "description": 1,
- "sku": 1,
- "configurable_children.sku": 1
- }
-```
-- `usePriceTiers` determines whether to use price tiers for customers in groups
-- `boost` is used to give weighted values to fields for a query to *Elasticsearch*, the bigger, the heavier.
- - `name` field has the value *3* so that matching query with the `name` has the highest priority.
- - `category.name` ,`short_description`, `description`, `sku`, `configurable_children.sku ` the rest of fields have the default value; 1.
-
-
-
-
-
-#### Secret 2. Study in `local.json` for *Vue Storefront*
-
-At [`vue-storefront/config/default.json`](https://github.com/vuestorefront/vue-storefront/blob/master/config/default.json) for **frontend** :
-
-```json
-"server": {
- "host": "localhost",
- "port": 3000,
- "protocol": "http",
- "api": "api",
- "devServiceWorker": false,
- "useOutputCacheTagging": false,
- "useOutputCache": false,
- "outputCacheDefaultTtl": 86400,
- "availableCacheTags": ["product", "category", "home", "checkout", "page-not-found", "compare", "my-account", "P", "C", "error"],
- "invalidateCacheKey": "aeSu7aip",
- "dynamicConfigReload": false,
- "dynamicConfigContinueOnError": false,
- "dynamicConfigExclude": ["ssr", "storeViews", "entities", "localForage", "shipping", "boost", "query"],
- "dynamicConfigInclude": [],
- "elasticCacheQuota": 4096
-},
-```
-
-- `server` contains information of various features related to *frontend* server.
-
- - `host` is the host address in which your *Vue Storefront* instance starts at.
-
- - `port` is the port number in which your *Vue Storefront* instance listens to.
-
- - `protocol` is used for *GraphQL* integration. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/lib/search/adapter/graphql/searchAdapter.ts#L48)
-
- - `api` determines API mode between `api` and `graphql`. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/resolvers/resolveGraphQL.js#L7)
-
- :::tip TIP
-
- You may take a look at [*GraphQL Action Plan*](/guide/basics/graphql.html) guide to help yourself make a decision which mode you should take.
- :::
-
- - `devServiceWorker` enables *service worker* in `develop` mode. The *service worker* is normally enabled by default for `production` mode, but not for `develop` mode. Setting this flag *true* forces to use *service worker* in `develop` mode too. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/service-worker/registration.js#L5)
- :::tip TIP
-
- You may take a look at [Working with Service Workers](/guide/core-themes/service-workers.html) for better understanding.
- :::
-
- - `useOutputCacheTagging` determines to allow *Output Cache Tags*. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/server.js#L168)
-
- - `useOutputCache` determines to allow *Output Cache*. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/server.js#L64)
-
- - `outputCacheDefaultTtl` defines the default timeout for *Redis Tag Cache*. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/utils/cache-instance.js#L16)
-
- - `availableCacheTags` contains a list of available cache tags. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/cache.js#L7)
-
- - `invalidateCacheKey` is the key used for checking validity of invalidation. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/server.js#L66)
- :::tip TIP
-
- You may take a look at [SSR Cache](/guide/basics/ssr-cache.html) in order to grab the idea of *Output Cache* in *Vue Storefront*
- :::
-
- - `dynamicConfigReload` enables to reload `config.json` on the fly with each server request. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/server.js#L232)
- - `dynamicConfigReloadWithEachRequest` enables to reload `config.json` on the fly with each server request. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/server.js#L313)
- - `dynamicConfigContinueOnError` allows to skip errors during configuration merge on the fly. [jump to code](https://github.com/vuestorefront/vue-storefront/blob/master/core/scripts/server.js#L240)
- - `dynamicConfigExclude`
- - `dynamicConfigInclude`
- - `elasticCacheQuota`
-
-
-```json
-"seo": {
- "useUrlDispatcher": true
-},
-"console": {
- "showErrorOnProduction" : true,
- "verbosityLevel": "display-everything"
-},
-"redis": {
- "host": "localhost",
- "port": 6379,
- "db": 0
-},
-"graphql":{
- "host": "localhost",
- "port": 8080
-},
-"api": {
- "url": "http://localhost:8080"
-},
-```
-
-- `seo`
-- `console`
-- `redis`
-- `graphql`
-- `api`
-
-```json
-"elasticsearch": {
- "httpAuth": "",
- "host": "/api/catalog",
- "index": "vue_storefront_catalog",
- "min_score": 0.02,
- "csrTimeout": 5000,
- "ssrTimeout": 1000,
- "queryMethod": "GET",
- "disableLocalStorageQueriesCache": true,
- "searchScoring": {
- "attributes": {
- "attribute_code": {
- "scoreValues": { "attribute_value": { "weight": 1 } }
- }
- },
- "fuzziness": 2,
- "cutoff_frequency": 0.01,
- "max_expansions": 3,
- "minimum_should_match": "75%",
- "prefix_length": 2,
- "boost_mode": "multiply",
- "score_mode": "multiply",
- "max_boost": 100,
- "function_min_score": 1
- },
- "searchableAttributes": {
- "name": {
- "boost": 4
- },
- "sku": {
- "boost": 2
- },
- "category.name": {
- "boost": 1
- }
- }
-},
-```
-`elasticsearch` ...
-
-```json
-"ssr": {
- "templates": {
- "default": "dist/index.html",
- "minimal": "dist/index.minimal.html",
- "basic": "dist/index.basic.html",
- "amp": "dist/index.amp.html"
- },
- "executeMixedinAsyncData": true,
- "initialStateFilter": ["__DEMO_MODE__", "version", "storeView"],
- "useInitialStateFilter": true
-},
-```
-- `ssr`
- - `templates`
- - `default`
-
-```json
-"defaultStoreCode": "",
-"storeViews": {
- "multistore": false,
- "commonCache": false,
- "mapStoreUrlsFor": ["de", "it"],
- "de": {
- "storeCode": "de",
- "storeId": 3,
- "name": "German Store",
- "url": "/de",
- "elasticsearch": {
- "host": "/api/catalog",
- "index": "vue_storefront_catalog_de"
- },
- "tax": {
- "sourcePriceIncludesTax": false,
- "defaultCountry": "DE",
- "defaultRegion": "",
- "calculateServerSide": true
- },
- "i18n": {
- "fullCountryName": "Germany",
- "fullLanguageName": "German",
- "defaultLanguage": "DE",
- "defaultCountry": "DE",
- "defaultLocale": "de-DE",
- "currencyCode": "EUR",
- "currencySign": "EUR",
- "dateFormat": "HH:mm D-M-YYYY"
- }
- },
- "it": {
- "storeCode": "it",
- "storeId": 4,
- "name": "Italian Store",
- "url": "/it",
- "elasticsearch": {
- "host": "/api/catalog",
- "index": "vue_storefront_catalog_it"
- },
- "tax": {
- "sourcePriceIncludesTax": false,
- "defaultCountry": "IT",
- "defaultRegion": "",
- "calculateServerSide": true
- },
- "i18n": {
- "fullCountryName": "Italy",
- "fullLanguageName": "Italian",
- "defaultCountry": "IT",
- "defaultLanguage": "IT",
- "defaultLocale": "it-IT",
- "currencyCode": "EUR",
- "currencySign": "EUR",
- "dateFormat": "HH:mm D-M-YYYY"
- }
- }
-},
-```
-- `defaultStoreCode`
-
-```json
-"entities": {
- "optimize": true,
- "twoStageCaching": true,
- "optimizeShoppingCart": true,
- "category": {
- "includeFields": [ "id", "*.children_data.id", "*.id", "children_count", "sku", "name", "is_active", "parent_id", "level", "url_key", "url_path", "product_count", "path"],
- "excludeFields": [ "sgn" ],
- "categoriesRootCategorylId": 2,
- "categoriesDynamicPrefetchLevel": 2,
- "categoriesDynamicPrefetch": true
- },
- "attribute": {
- "includeFields": [ "attribute_code", "id", "entity_type_id", "options", "default_value", "is_user_defined", "frontend_label", "attribute_id", "default_frontend_label", "is_visible_on_front", "is_visible", "is_comparable", "tier_prices", "frontend_input" ]
- },
- "productList": {
- "sort": "",
- "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "url_path", "url_key", "status", "tier_prices", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.priceInclTax", "configurable_children.specialPriceInclTax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax" ],
- "excludeFields": [ "description", "configurable_options", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options" ]
- },
- "productListWithChildren": {
- "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.priceInclTax", "configurable_children.specialPriceInclTax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "configurable_children.tier_prices", "product_links", "url_path", "url_key", "status", "tier_prices"],
- "excludeFields": [ "description", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options"]
- },
- "review": {
- "excludeFields": ["review_entity", "review_status"]
- },
- "product": {
- "excludeFields": [ "*.msrp_display_actual_price_type", "required_options", "updated_at", "created_at", "attribute_set_id", "options_container", "msrp_display_actual_price_type", "has_options", "stock.manage_stock", "stock.use_config_min_qty", "stock.use_config_notify_stock_qty", "stock.stock_id", "stock.use_config_backorders", "stock.use_config_enable_qty_inc", "stock.enable_qty_increments", "stock.use_config_manage_stock", "stock.use_config_min_sale_qty", "stock.notify_stock_qty", "stock.use_config_max_sale_qty", "stock.use_config_max_sale_qty", "stock.qty_increments", "small_image", "sgn", "*.sgn"],
- "includeFields": null,
- "useDynamicAttributeLoader": true,
- "standardSystemFields": [
- "description",
- "configurable_options",
- "tsk",
- "custom_attributes",
- "size_options",
- "regular_price",
- "final_price",
- "price",
- "color_options",
- "id",
- "links",
- "gift_message_available",
- "category_ids",
- "sku",
- "stock",
- "image",
- "thumbnail",
- "visibility",
- "type_id",
- "tax_class_id",
- "media_gallery",
- "url_key",
- "url_path",
- "max_price",
- "minimal_regular_price",
- "special_price",
- "minimal_price",
- "name",
- "configurable_children",
- "max_regular_price",
- "category",
- "status",
- "priceTax",
- "priceInclTax",
- "specialPriceTax",
- "specialPriceInclTax",
- "_score",
- "slug",
- "errors",
- "info",
- "erin_recommends",
- "special_from_date",
- "news_from_date",
- "custom_design_from",
- "originalPrice",
- "originalPriceInclTax",
- "parentSku",
- "options",
- "product_option",
- "qty",
- "is_configured"
- ]
- }
-},
-"cart": {
- "serverMergeByDefault": true,
- "serverSyncCanRemoveLocalItems": false,
- "serverSyncCanModifyLocalItems": false,
- "synchronize": true,
- "synchronize_totals": true,
- "setCustomProductOptions": true,
- "setConfigurableProductOptions": true,
- "askBeforeRemoveProduct": true,
- "displayItemDiscounts": true,
- "minicartCountType": "quantities",
- "create_endpoint": "http://localhost:8080/api/cart/create?token={{token}}",
- "updateitem_endpoint": "http://localhost:8080/api/cart/update?token={{token}}&cartId={{cartId}}",
- "deleteitem_endpoint": "http://localhost:8080/api/cart/delete?token={{token}}&cartId={{cartId}}",
- "pull_endpoint": "http://localhost:8080/api/cart/pull?token={{token}}&cartId={{cartId}}",
- "totals_endpoint": "http://localhost:8080/api/cart/totals?token={{token}}&cartId={{cartId}}",
- "paymentmethods_endpoint": "http://localhost:8080/api/cart/payment-methods?token={{token}}&cartId={{cartId}}",
- "shippingmethods_endpoint": "http://localhost:8080/api/cart/shipping-methods?token={{token}}&cartId={{cartId}}",
- "shippinginfo_endpoint": "http://localhost:8080/api/cart/shipping-information?token={{token}}&cartId={{cartId}}",
- "collecttotals_endpoint": "http://localhost:8080/api/cart/collect-totals?token={{token}}&cartId={{cartId}}",
- "deletecoupon_endpoint": "http://localhost:8080/api/cart/delete-coupon?token={{token}}&cartId={{cartId}}",
- "applycoupon_endpoint": "http://localhost:8080/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}"
-},
-"products": {
- "useShortCatalogUrls": false,
- "useMagentoUrlKeys": true,
- "setFirstVarianAsDefaultInURL": false,
- "configurableChildrenStockPrefetchStatic": false,
- "configurableChildrenStockPrefetchDynamic": false,
- "configurableChildrenStockPrefetchStaticPrefetchCount": 8,
- "filterUnavailableVariants": false,
- "listOutOfStockProducts": true,
- "preventConfigurableChildrenDirectAccess": true,
- "alwaysSyncPlatformPricesOver": false,
- "clearPricesBeforePlatformSync": false,
- "waitForPlatformSync": false,
- "setupVariantByAttributeCode": true,
- "endpoint": "http://localhost:8080/api/product",
- "defaultFilters": ["color", "size", "price", "erin_recommends"],
- "systemFilterNames": ["sort"],
- "filterFieldMapping": {
- "category.name": "category.name.keyword"
- },
- "colorMappings": {
- "Melange graphite": "#eeeeee"
- },
- "sortByAttributes": {
- "Latest": "updated_at",
- "Price: Low to high":"final_price",
- "Price: High to low":"final_price:desc"
- },
- "gallery": {
- "variantsGroupAttribute": "color",
- "mergeConfigurableChildren": true,
- "imageAttributes": ["image","thumbnail","small_image"],
- "width": 600,
- "height": 744
- },
- "filterAggregationSize": {
- "default": 10,
- "size": 10,
- "color": 10
- }
-},
-"orders": {
- "directBackendSync": true,
- "endpoint": "http://localhost:8080/api/order",
- "payment_methods_mapping": {
- },
- "offline_orders": {
- "automatic_transmission_enabled": false,
- "notification" : {
- "enabled": true,
- "title" : "Order waiting!",
- "message": "Click here to confirm the order that you made offline.",
- "icon": "/assets/logo.png"
- }
- }
-},
-"localForage": {
- "defaultDrivers": {
- "user": "LOCALSTORAGE",
- "cmspage": "LOCALSTORAGE",
- "cmsblock": "LOCALSTORAGE",
- "carts": "LOCALSTORAGE",
- "orders": "LOCALSTORAGE",
- "wishlist": "LOCALSTORAGE",
- "categories": "LOCALSTORAGE",
- "attributes": "LOCALSTORAGE",
- "products": "INDEXEDDB",
- "elasticCache": "LOCALSTORAGE",
- "claims": "LOCALSTORAGE",
- "syncTasks": "LOCALSTORAGE",
- "ordersHistory": "LOCALSTORAGE",
- "checkoutFieldValues": "LOCALSTORAGE"
- }
-},
-"reviews": {
- "create_endpoint": "http://localhost:8080/api/review/create"
-},
-"users": {
- "autoRefreshTokens": true,
- "endpoint": "http://localhost:8080/api/user",
- "history_endpoint": "http://localhost:8080/api/user/order-history?token={{token}}",
- "resetPassword_endpoint": "http://localhost:8080/api/user/reset-password",
- "changePassword_endpoint": "http://localhost:8080/api/user/change-password?token={{token}}",
- "login_endpoint": "http://localhost:8080/api/user/login",
- "create_endpoint": "http://localhost:8080/api/user/create",
- "me_endpoint": "http://localhost:8080/api/user/me?token={{token}}",
- "refresh_endpoint": "http://localhost:8080/api/user/refresh"
-},
-"stock": {
- "synchronize": true,
- "allowOutOfStockInCart": true,
- "endpoint": "http://localhost:8080/api/stock"
-},
-"images": {
- "useExactUrlsNoProxy": false,
- "baseUrl": "https://demo.vuestorefront.io/img/",
- "productPlaceholder": "/assets/placeholder.jpg"
-},
-"install": {
- "is_local_backend": true,
- "backend_dir": "../vue-storefront-api"
-},
-"demomode": false,
-"tax": {
- "defaultCountry": "US",
- "defaultRegion": "",
- "sourcePriceIncludesTax": false,
- "calculateServerSide": true,
- "userGroupId": null,
- "useOnlyDefaultUserGroupId": false,
- "deprecatedPriceFieldsSupport": true,
- "finalPriceIncludesTax": false
-},
-```
- - `tax`: ...
- - `defaultCountry` is the code name of the country on which tax is calculated for the store.
- - `defaultRegion` is default region.
- - `sourcePriceIncludesTax` determines whether price is stored with tax applied (`true`) or tax calculated on runtime (`false`). [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/platform/magento2/tax.js#L12)
- - `calculateServerSide` determines if price is fetched with(`true`)/without(`false`) tax calculated. [jump to code](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/product.js#L48)
- - `userGroupId`: null,
- - `useOnlyDefaultUserGroupId`: false,
- - `deprecatedPriceFieldsSupport`: true,
- - `finalPriceIncludesTax`: false
-```json
-"shipping": {
- "methods": [
- {
- "method_title": "DPD Courier",
- "method_code": "flatrate",
- "carrier_code": "flatrate",
- "amount": 4,
- "price_incl_tax": 5,
- "default": true,
- "offline": true
- }
- ]
-},
-"i18n": {
- "defaultCountry": "US",
- "defaultLanguage": "EN",
- "availableLocale": ["en-US","de-DE","fr-FR","es-ES","nl-NL", "ja-JP", "ru-RU", "it-IT", "pt-BR", "pl-PL", "cs-CZ"],
- "defaultLocale": "en-US",
- "currencyCode": "USD",
- "currencySign": "$",
- "currencyDecimal": null,
- "currencyGroup": null,
- "fractionDigits": 2,
- "priceFormat": "{sign}{amount}",
- "dateFormat": "HH:mm D/M/YYYY",
- "fullCountryName": "United States",
- "fullLanguageName": "English",
- "bundleAllStoreviewLanguages": true
-},
-"mailchimp": {
- "endpoint": "http://localhost:8080/api/ext/mailchimp-subscribe/subscribe"
-},
-"mailer": {
- "endpoint": {
- "send": "http://localhost:8080/api/ext/mail-service/send-email",
- "token": "http://localhost:8080/api/ext/mail-service/get-token"
- },
- "contactAddress": "contributors@vuestorefront.io",
- "sendConfirmation": true
-},
-"theme": "@vue-storefront/theme-default",
-"analytics": {
- "id": false
-},
-"hotjar": {
- "id": false
-},
-"cms": {
- "endpoint": "http://localhost:8080/api/ext/cms-data/cms{{type}}/{{cmsId}}",
- "endpointIdentifier": "http://localhost:8080/api/ext/cms-data/cms{{type}}Identifier/{{cmsIdentifier}}/storeId/{{storeId}}"
-},
-"cms_block": {
- "max_count": 500
-},
-"cms_page": {
- "max_count": 500
-},
-"usePriceTiers": false,
-"useZeroPriceProduct": true,
-"query": {
- "inspirations": {
- "filter": [
- {
- "key": "category.name",
- "value" : { "eq": "Performance Fabrics" }
- }
- ]
- },
- "newProducts": {
- "filter": [
- {
- "key": "category.name",
- "value" : { "eq": "Tees" }
- }
- ]
- },
- "bestSellers": {
- "filter": [
- {
- "key": "category.name",
- "value" : { "eq": "Tees" }
- }
- ]
- }
-}
-
-```
diff --git a/docs/guide/archives/entity_type.md b/docs/guide/archives/entity_type.md
deleted file mode 100644
index 4818721cec..0000000000
--- a/docs/guide/archives/entity_type.md
+++ /dev/null
@@ -1,113 +0,0 @@
-# Data Entity Types
-
-:::danger REMINDER
-This document is _archived_ and _NOT_ relevant with the latest version which is `1.12` at the time of writing. Please keep in mind this document is supposed to help you maintain legacy product, not the fresh installation.
-:::
-
-Vue Storefront uses multiple data-entity types to cover the whole scope of the storefront. Default entity types are:
-
-- Product
-- Category
-- Attribute
-- Taxrule
-
-These entity types were hardcoded and there was no ability to easily use another custom entity type required for customization.
-
-Now, Vue Storefront has a new logic to work with entities in the data-fetching perspective: Entity Types.
-
-Each search adapter should register an entity type to cover a search feature. Default API and new GraphQL search adapters are updated to register all required existing entity types, but developers can also inject custom entity types to work with some other custom entity type data (for example, to get a list of offline stores or something else).
-
-To use it, an internal GraphQL server should be updated with adding a corresponding resolver for the new entity type. Also, you can use some other external GraphQL server that already has implemented a resolver for this entity type.
-
-To register such an entity type, you should use the `searchAdapter.registerEntityTypeByQuery` method like shown in the example below:
-
-```js
-const factory = new SearchAdapterFactory();
-let searchAdapter = factory.getSearchAdapter('graphql');
-searchAdapter.registerEntityTypeByQuery('testentity', {
- url: 'http://localhost:8080/graphql/',
- query: require('./queries/testentity.gql'),
- queryProcessor: query => {
- // function that can modify the query each time before it's being executed
- return query;
- },
- resultProcessor: (resp, start, size) => {
- if (resp === null) {
- throw new Error('Invalid graphQl result - null not exepcted');
- }
- if (resp.hasOwnProperty('data')) {
- return processESResponseType(resp.data.testentity, start, size);
- } else {
- if (resp.error) {
- throw new Error(JSON.stringify(resp.error));
- } else {
- throw new Error(
- "Unknown error with graphQl result in resultProcessor for entity type 'category'",
- );
- }
- }
- },
-});
-```
-
-The sample extension `sample-custom-entity-graphql` was added to illustrate how it can be used. It injects a custom entity type `testentity` and sets a custom GraphQL server URL (it is the same as a default API host in the example, because a resolver for this `testentity` was added there for testing. But please notice it was removed there).
-
-To test a sample extension with resolver, you can add a GraphQL schema file and resolver file in the separate `src/graphql/elastcisearch/testentity` folder in the Vue Storefront API.
-
-`schema.graphqls` file:
-
-```graphql
-type Query {
- testentity(filter: TestInput): ESResponse
-}
-input TestInput
- @doc(
- description: "TaxRuleInput specifies the tax rules information to search"
- ) {
- id: FilterTypeInput
- @doc(description: "An ID that uniquely identifies the tax rule")
- code: FilterTypeInput
- @doc(
- description: "The unique identifier for an tax rule. This value should be in lowercase letters without spaces."
- )
- priority: FilterTypeInput @doc(description: "Priority of the tax rule")
- position: FilterTypeInput @doc(description: "Position of the tax rule")
- customer_tax_class_ids: FilterTypeInput
- @doc(description: "Cunstomer tax class ids of the tax rule")
- product_tax_class_ids: FilterTypeInput
- @doc(description: "Products tax class ids of the tax rule")
- tax_rate_ids: FilterTypeInput
- @doc(description: "Tax rates ids of the tax rule")
- calculate_subtotal: FilterTypeInput
- @doc(description: "Calculating subtotals of the tax rule")
- rates: FilterTypeInput @doc(description: "Rates of the tax rule")
-}
-```
-
-Resolver file `resolver.js`:
-
-```js
-import config from 'config';
-import client from '../client';
-import { buildQuery } from '../queryBuilder';
-
-async function testentity(filter) {
- let query = buildQuery({ filter, pageSize: 150, type: 'taxrule' });
-
- const response = await client.search({
- index: config.elasticsearch.indices[0],
- type: config.elasticsearch.indexTypes[4],
- body: query,
- });
-
- return response;
-}
-
-const resolver = {
- Query: {
- testentity: (_, { filter }) => testentity(filter),
- },
-};
-
-export default resolver;
-```
diff --git a/docs/guide/archives/extensions.md b/docs/guide/archives/extensions.md
deleted file mode 100644
index e193b3f2cb..0000000000
--- a/docs/guide/archives/extensions.md
+++ /dev/null
@@ -1,241 +0,0 @@
-# Extensions
-
-:::danger REMINDER
-This document is _archived_ and _NOT_ relevant with the latest version which is `1.11` at the time of writing. Please keep in mind this document is supposed to help you maintain legacy product, not the fresh installation.
-:::
-
-
-## Introduction
-
-### What do Vue Storefront extensions look like?
-
-Depending on your needs, Vue Storefront extensions can have two parts:
-- **Client-side part,** which is just a [Vue Storefront module](https://github.com/vuestorefront/vue-storefront/blob/master/docs/guide/modules/introduction.md). It covers most of the use cases.
-
-- **Server-side part** which is a [Vue Storefront API extension](https://github.com/vuestorefront/vue-storefront/blob/master/docs/guide/extensions/extending-api.md) and should be used if you want to add some endpoints to `vue-storefront-api` or interact with Elasticsearch.
-
-### Where extensions are located
-- On the client side, extension modules should be placed in `src/modules` folder of `vue-storefront` or installed via NPM cli and registered in `src/modules/index.ts`
-- On the server side, extensions should be placed in `src/api/extensions` folder of `vue-storefront-api` and registered in config file
-
-### Writing extensions
-If you are writing a VS extension as an NPM module, start the package name with a `vsf-` prefix so it can be transpiled with other VS code and ship it as a raw es6/typescript module. If you don't use the prefix, you need to handle transpilation by yourself. We are currently building an extension boilerplate to make it easier to develop one.
-
-Here, you can find two articles explaining how to create custom Vue Storefront extensions:
-- [How to create an Instagram Feed module for Vue Storefront](https://itnext.io/how-to-create-an-instagram-feed-module-for-vue-storefront-eaa03019b288) by Javier Villanueva
-- [Developing a Vue Storefront payment module](https://www.develodesign.co.uk/news/development-of-the-paypal-module-for-vue-storefront/#.XCoa2h2Mmmo.twitter) by Dmitry Schegolikhin from [Develo Design](https://www.develodesign.co.uk/)
-
-**IMPORTANT** If you are an extension developer, please join `#extension-dev` channel on our Slack to receive information about important API updates and new features.
-
-### Extensions list
-You can find a curated list of VS extensions in [Awesome Vue Storefront](https://github.com/frqnck/awesome-vue-storefront) list.
-
-
-## Extending the API
-
-Some extensions need to have additional API methods to get some data directly from Magento/other CMS or just from custom Elasticsearch data collections.
-
-You may add new ES collections [using the Migration mechanism](../data/data-migrations.md)
-
-Then you may extend the [`vue-storefront-api`](https://github.com/vuestorefront/vue-storefront-api) to add your custom API methods. Please take a look at: [mailchimp-subscribe](https://github.com/vuestorefront/vue-storefront-api/blob/master/src/api/extensions/mailchimp-subscribe/index.js) for reference.
-
-To add the API extension to `vue-storefront-api`:
-
-1. Create the folder within `src/api/extensions` for example 'custom_extension`.
-2. Then add the `index.js` file and put the API methods code inside. We're using Express.js. Here is a boilerplate/example for the extension code:
-
-```js
-import { apiStatus } from '../../../lib/util';
-import { Router } from 'express';
-
-module.exports = ({ config, db }) => {
- let mcApi = Router();
-
- /**
- * POST create an user
- */
- mcApi.post('/subscribe', (req, res) => {
- let userData = req.body;
- if (!userData.email) {
- apiStatus(res, 'Invalid e-mail provided!', 500);
- return;
- }
-
- let request = require('request');
- request(
- {
- url:
- config.extensions.mailchimp.apiUrl +
- '/lists/' +
- encodeURIComponent(config.extensions.mailchimp.listId) +
- '/members',
- method: 'POST',
- headers: {
- Authorization: 'apikey ' + config.extensions.mailchimp.apiKey,
- },
- json: true,
- body: { email_address: userData.email, status: 'subscribed' },
- },
- function(error, response, body) {
- if (error) {
- apiStatus(res, error, 500);
- } else {
- apiStatus(res, body, 200);
- }
- },
- );
- });
-
- /**
- * DELETE delete an user
- */
- mcApi.delete('/subscribe', (req, res) => {
- let userData = req.body;
- if (!userData.email) {
- apiStatus(res, 'Invalid e-mail provided!', 500);
- return;
- }
-
- let request = require('request');
- request(
- {
- url:
- config.extensions.mailchimp.apiUrl +
- '/lists/' +
- encodeURIComponent(config.extensions.mailchimp.listId),
- method: 'POST',
- headers: {
- Authorization: 'apikey ' + config.extensions.mailchimp.apiKey,
- },
- json: true,
- body: {
- members: [{ email_address: userData.email, status: 'unsubscribed' }],
- update_existing: true,
- },
- },
- function(error, response, body) {
- if (error) {
- apiStatus(res, error, 500);
- } else {
- apiStatus(res, body, 200);
- }
- },
- );
- });
- return mcApi;
-};
-```
-
-3. Add the extension to `config/local.json`:
-
-```json
- "registeredExtensions": ["mailchimp-subscribe"],
-```
-
-4. Restart the `vue-storefront-api`
-5. Your new API method is available on `localhost:8080/api/ext//` for example: `localhost:8080/api/ext/mailchimp-subscribe/subscribe`
-
-
-## Extending Express.js server-side routes
-
-From Vue Storefront 1.4.0, you can add your own custom server-side routes without Vue.js SSR context. These routes may be used, for example, for generating large, unbuffered files like XML maps, binary files, etc.
-
-You can add numerous, custom Express js middlewares and routes by simply modifying the `src/server/index.js`:
-
-```js
-// You can extend Vue Storefront server routes by binding to the Express.js (expressApp) in here
-module.exports.registerUserServerRoutes = expressApp => {
- require('./example/generator')(expressApp);
-};
-```
-
-The example route handler looks like this:
-
-```js
-module.exports = expressApp => {
- /**
- * This is an example on how You can bind Your own Express.js server routes to SSR server running Vue Storefront.
- * It may be usefull to avoid all the Vue.js processing and context - and useful for example for large XML/binary file generation
- */
- expressApp.get('/vue-storefront.xml', (req, res) => {
- res.end('Vue Storefront custom XML generator example');
- });
-};
-```
-
-### Data operations inside Express routes
-
-Unfortunately, as you may have seen above in the `core/scripts/server.js`, all modules used by the script (including the dynamic routes) can not use ES modules (`import ... from ...` type of statements). By this limitation, you can't currently use `@vue-storefront`modules inside the custom Express.js routes as they're not compiled to the CommonJS. This is likely to be fixed. To get the data, you may execute `fetch()` requests to the `vue-storefront-api` endpoints. You can still use `const config = require('config')` to read the endpoints, URLs, etc.
-
-
-## Using extensions to Modify Elasticsearch results
-
-Vue Storefront API has a built-in processor for calculating taxes and adding that data to product search results. API extensions can also add their own processors for modifying Elasticsearch results.
-
-Some possible use cases for this could be:
-- Replacing Magento product descriptions with data from a CMS.
-- Cleaning Magento "WYSIWYG" data.
-- Adding product ratings or other data from third-party systems.
-
-Here is an example of creating a custom result processor to replace Product descriptions with Prismic CMS data:
-
-1. Create the extension folder in `src/api/extensions`.
-2. The extension folder must contain another folder called `processors`.
-3. Add the processor file, for example `src/api/extensions/example-extension/processors/prismic-product.js`.
-```js
-import Prismic from 'prismic-javascript'
-import PrismicDOM from 'prismic-dom'
-
-class ProductPrismic {
- constructor (config, request) {
- this._request = request
- this._config = config
- }
-
- process (productList) {
- const skus = productList.map( prod => {
- return prod._source.sku.toLowerCase()
- })
- return Prismic.getApi(this._config.extensions['example-extension'].baseUrl).then((api) => {
- return api.query(Prismic.Predicates.in('my.product.uid', skus))
- }).then((result) => {
- for (const item of result.results) {
- const product = productList.find( prod => {
- return prod._source.sku.toLowerCase() === item.uid
- })
- if (product) {
- try {
- product._source.description = PrismicDOM.RichText.asHtml(item.data.description)
- }
- catch(error) {
- console.log(error)
- }
- }
- }
- return productList
- }).catch(err => {
- console.log(err)
- })
- }
-}
-
-module.exports = ProductPrismic
-```
-4. Add the extension to `config/local.json` and declare the custom processor in the extension settings. It needs to be in this structure:
-```json
- "registeredExtensions": ["example-extension"],
- "extensions": {
- "example-extension": {
- "baseUrl": "https://my_account.cdn.prismic.io/api/v2",
- "resultProcessors": {
- "product": "prismic-product"
- }
- }
- }
-```
-
-That's it. In Prismic, create documents with a uid matching each product SKU, and a description field. Those description will then appear in Vue Storefront product listings. The data update instantly, whenever a document is published in Prismic.
-
-Note: This example uses Prismic and PrismicDOM, so they'll need to be added to your dependencies in package.json
-
-Note 2: See `src/platform/magento2/tax.js` for another example of a results processor.
diff --git a/docs/guide/archives/graphql.md b/docs/guide/archives/graphql.md
deleted file mode 100644
index 73c942f582..0000000000
--- a/docs/guide/archives/graphql.md
+++ /dev/null
@@ -1,71 +0,0 @@
-# GraphQL
-
-:::danger REMINDER
-This document is _archived_ and _NOT_ relevant with the latest version which is `1.12` at the time of writing. Please keep in mind this document is supposed to help you maintain legacy product, not the fresh installation.
-:::
-
-## GraphQL Action Plan (Deprecated)
-
-Starting with Vue Storefront 1.4.0, we're supporting two ways of getting data from the backend:
-
-- existing `api` mode, which is using ElasticSearch DSL as a query language
-- new `graphql` mode, which is using GraphQL queries.
-
-You can set the desired API format in the `config/local.json` and `vue-storefront-api` is supporting both of them, however [the default is still set to `api`](https://github.com/vuestorefront/vue-storefront/blob/4cbf866ca93f917b04461d3ae139a2d26ddf552a/config/default.json#L6).
-
-We've introduced an abstract [`SearchQuery`](https://github.com/vuestorefront/vue-storefront/tree/develop/core/store/lib/search) interface with switchable Query Adapters to provide the abstraction layer. This is an ultra-cool feature, especially when you're integrating Vue Storefront with a custom backend application—you're able [to create your own adapter](https://github.com/vuestorefront/vue-storefront/tree/develop/core/lib/search/adapter) to customize the way data is gathered from the backend.
-
-From now on the **bodybuilder** package is **deprecated** and you should start using the `SearchQuery` interface to build the search queries that will be translated to GraphQL / API queries.
-
-Here is an example of how to build the Query:
-
-```js
-export function prepareRelatedQuery(key, sku) {
- let relatedProductsQuery = new SearchQuery();
-
- relatedProductsQuery = relatedProductsQuery.applyFilter({
- key: key,
- value: { in: sku },
- });
-
- relatedProductsQuery = relatedProductsQuery
- .applyFilter({ key: 'visibility', value: { in: [2, 3, 4] } })
- .applyFilter({ key: 'status', value: { in: [0, 1, 2] } }); // @TODO Check if status 2 (disabled) was set not by occasion here
-
- if (config.products.listOutOfStockProducts === false) {
- relatedProductsQuery = relatedProductsQuery.applyFilter({
- key: 'stock.is_in_stock',
- value: { eq: true },
- });
- }
-
- return relatedProductsQuery;
-}
-
-let relatedProductsQuery = prepareRelatedQuery(key, sku);
-
-this.$store
- .dispatch('product/list', {
- query: relatedProductsQuery,
- size: 8,
- prefetchGroupProducts: false,
- updateState: false,
- })
- .then(response => {
- if (response) {
- this.$store.dispatch('product/related', {
- key: this.type,
- items: response.items,
- });
- this.$forceUpdate();
- }
- });
-```
-
-[More information on how to query the data](https://github.com/vuestorefront/vue-storefront/blob/develop/docs/guide/data/elastic-queries.md).
-
-**Bodybuilder** queries are still supported by our backward-compatibility mode, so if you've used bodybuilder in your theme, it's fine as long as you're using the `api` mode for the backend queries.
-
-The **legacy queries** using bodybuilder will still work - and [here is an example](https://github.com/pkarw/vue-storefront/blob/28feb8e5dc30ec216353ef87a859212379901c57/src/extensions/template/index.js#L36).
-
-You can also use direct **ApolloQuery** GraphQL queries thanks to `vue-apollo` support. Please find the example [in here](https://github.com/vuestorefront/vue-storefront/blob/4cbf866ca93f917b04461d3ae139a2d26ddf552a/src/themes/default/components/core/blocks/SearchPanel/SearchPanel.gql.vue#L21).
diff --git a/docs/guide/archives/migration.md b/docs/guide/archives/migration.md
deleted file mode 100644
index 39b6fddf0d..0000000000
--- a/docs/guide/archives/migration.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Data Migrations for Elacticsearch
-
-:::danger REMINDER
-This document is _archived_ and _NOT_ relevant with the latest version which is `1.12` at the time of writing. Please keep in mind this document is supposed to help you maintain legacy product, not the fresh installation.
-:::
-
-Vue Storefront uses Elasticsearch as a primary data store. We're using Redis as a cache layer and Kue for queue processing.
-
-Although all of these data stores are basically schema-free, some mappings and meta data should be used for setting ES indices and so forth.
-
-Vue Storefront uses a data-migration mechanism based on [node-migrate](https://github.com/tj/node-migrate).
-
-## Migration tool
-
-We use node-migrate, which is pre-configured with npm, so we're using the following alias:
-
-```bash
-yarn migrate
-```
-
-which runs the migrations against `migrations` folder.
-
-## How to add new migration?
-
-You can add a new migration by simply adding a file to the `migrations` directory (not recommended) or using the command line tool:
-
-```bash
-yarn migrate create name-of-my-migration
-```
-
-The tool automatically generates the file under the `migrations` folder.
-
-## Examples
-
-The example migrations show how to manipulate products and mappings. Let's take a look at the mapping modification:
-
-```js
-// Migration scripts use: https://github.com/tj/node-migrate
-'use strict';
-
-let config = require('config');
-let common = require('./.common');
-
-module.exports.up = function(next) {
- // example of adding a field to the schema
- // other examples: https://stackoverflow.com/questions/22325708/elasticsearch-create-index-with-mappings-using-javascript,
- common.db.indices
- .putMapping({
- index: config.elasticsearch.indices[0],
- type: 'product',
- body: {
- properties: {
- slug: { type: 'string' }, // add slug field
- suggest: {
- type: 'completion',
- analyzer: 'simple',
- search_analyzer: 'simple',
- },
- },
- },
- })
- .then(res => {
- console.dir(res, { depth: null, colors: true });
- next();
- });
-};
-
-module.exports.down = function(next) {
- next();
-};
-```
-
-... and that's it :)
diff --git a/docs/guide/archives/modules.md b/docs/guide/archives/modules.md
deleted file mode 100644
index 0114207755..0000000000
--- a/docs/guide/archives/modules.md
+++ /dev/null
@@ -1,1342 +0,0 @@
-# Modules
-
-:::danger REMINDER
-This document is _archived_ and _NOT_ relevant with the latest version which is `1.11` at the time of writing. Please keep in mind this document is supposed to help you maintain legacy product, not the fresh installation.
-:::
-
-## Introduction
-### Table of contents
-
-**Introduction and motivation**
-- [What are VS Modules](#what-are-vs-modules)
-- [Motivation](#motivation)
-- [What is the purpose of VS modules?](#what-is-the-purpose-of-vs-modules)
-
-**Technical part**
-- [Module config and its capabilities](#module-config-and-capabilities)
-- [Module file structure](#module-file-structure)
-- [Module registration](#module-registration)
-
-**Patterns and good practices for common use cases**
-- [General rules and good practices](#general-rules-and-good-practices)
-- [Adding new features as VS modules](#adding-new-features-as-vs-modules)
-- [Extending and overriding Vue Storefront modules](#extending-and-overriding-vue-storefront-modules)
-- [Creating third party modules](#Creating-3rd-party-modules)
-
-
-### What are VS modules?
-
-You can think about each module as a one, independent feature available in Vue Storefront with all its logic and dependencies inside. This *one feature* however is a common denominator that links all the features inside. For example, the common denominator for adding a product to the cart, receiving a list of items that is in the cart or applying a cart coupon is obviously a `cart` and `cart` is not a feature of anything bigger than itself (its common denominator is the shop) so it should be a module. Wishlist, Reviews or Newsletter are also good examples of the module as we intuitively think about them as standalone features.
-
-#### Motivation
-
-I believe that an obvious metaphor can clearly describe the problem, at the same time, the solution.
-
-To better illustrate the whole concept I'll try to explain it with lego bricks.
-
-Let's say we have a box with 90 lego bricks that we can use to build some fancy things like Towers, Castles, or Helicopters. Unfortunately due to some stupid EU regulations we can only have 3 different colors of bricks in our box. As we all know, not every color is accurate for every structure that can be built so we need to swap one color with another in a shop from time to time in order to have bricks in colors that are best-suited for our next lego project.
-
-Cool, but there is one problem - since we have all our bricks in one box they look more or less as follows :
-
-![lego](../images/pile_of_legos.png)
-
-When we want to replace the green bricks with, let's say, the black ones we need to look for each green brick separately among all the others which can take a lot of time... and there is still a chance that we will miss some of them! Not to mention that finding the particular green brick that we need to finish the palm tree we are building () will require looking for it among all the other bricks which can make this task extremely difficult and time-consuming.
-
-This is obviously not a situation that we want to end up in with our small lego empire. Neither do we want it with Vue Storefront since it's meant to be easily extendable so you can replace your green bricks (or current user cart feature/cms provider/cms content provider) with the black ones (different cart feature with multiple carts, WordPress instead of Prismic for content etc) without hustles and bustles looking for each of them among all the bricks and without worries that you will miss some of them or EU will confiscate all the bricks that you have! We also want to make it easier to find the correct brick that we want right now to finish this damn palm tree!
-
-So how do we make this horrible situation better?
-
-Introducing... (drums build up in the background) **_bricks grouped by colors_**! (wows in the background)
-
-![lego2](../images/organized_lego_bricks.jpeg)
-
-When we have our bricks grouped by their colors (and in separate boxes - modules) it's much easier to find this green brick that we needed for a palm tree since we only need to search in a small subset of all bricks. Moreover when we want to replace green bricks with the black ones, then instead of looking for all the green representatives one by one we are just replacing their box with the one containing black bricks. We also don't need to worry if something was left behind since we know that all the green bricks were in the box.
-
-This is the modularity and extendability we are looking for in Vue Storefront and the architecture we are currently rewriting it into.
-
-### What is the purpose of VS modules?
-
-The purpose is well described in [this discussion](https://github.com/vuestorefront/vue-storefront/issues/1213). It can be summarized to:
-
-- **Better extendability**: We can extend each module or replace it completely with the new one. For example, we may want to replace our Cart module with the one that allows to have multiple carts. With module approach, we can just detach the current Cart module and replace it with the new one. Another example can be using different modules for different content CMSes integration etc.
-- **Better developer experience**: Along with the modules we are introducing many features focused on delivering better and easier experience for developers to hop on in a more predictable way. We changed the way you can compose components with features, added unit tests, TypeScript interfaces etc.
-- **Better upgradability**: Each module is a separate NPM package therefore can be upgraded independently and since it has all the logic encapsulated, it shouldn't break any other part of the application when detached, modified or replaced.
-
-### Module config and capabilities
-
-Module config is the object that is required to instantiate VS module. The config object you provide is later used to extend and hook into different parts of the application (e.g. router, Vuex etc).
-Please use this object as the only part that is responsible for extending Vue Storefront. Otherwise it may stop working after some breaking core updates.
-
-Vue Storefront module object with provided config should be exported to `index.ts` entry point. Ideally it should be an *export* named the same as modules key.
-
-This is how the signature of Vue Storefront Module looks like:
-
-```js
-interface VueStorefrontModuleConfig {
- key: string;
- store?: {
- modules?: { key: string, module: Module }[],
- plugin?: Function,
- };
- router?: {
- routes?: RouteConfig[],
- beforeEach?: NavigationGuard,
- afterEach?: NavigationGuard,
- };
- beforeRegistration?: (VSF) => void;
- afterRegistration?: (VSF) => void;
-}
-```
-
-See code [here](https://github.com/vuestorefront/vue-storefront/blob/develop/core/modules/index.ts)
-
-#### `key` (required)
-
-A key is an ID of your module. It's used to identify your module and to set keys in all key-based extensions that module is associated (e.g. creating namespaced store). This key should be unique.
-
-#### `store`
-
-The entry point for Vuex.
-
-- `modules` - array of Vuex modules to register under given keys
-- `plugin` - you can provide your own Vuex plugin here
-
-#### `router`
-
-The entry point for vue-router. You can provide additional routes and [navigation guards](https://router.vuejs.org/guide/advanced/navigation-guards.html) here.
-
-#### `beforeRegistration`
-
-A function that'll be called before registering the module both on server and client side. You have access to VSF object here.
-
-The `VSF` object is an instance of your Vue Storefront shop. It contains following properties
-````js
- Vue?: VueConstructor,
- config?: Object,
- store?: Store,
- isServer?: boolean
-````
-#### `afterRegistration`
-
-A function that'll be called after registering the module both on server and client side. You have access to VSF object here.
-
-The `VSF` object is an instance of your Vue Storefront shop. It contains following properties
-````js
- Vue?: VueConstructor,
- config?: Object,
- store?: Store,
- isServer?: boolean
-````
-### Module file structure
-
-Below you can see recommended file structure for VS module. All of the core ones are organised in this way.
-Try to have a similar file structure inside the ones that you create. If all the modules are implemented with a similar architecture, it'll be much easier to maintain and understand them. Please avoid unnecessary changes in design unless otherwise required so.
-
-Not all of this folders and files should exist in every module. The only mandatory file is `index.ts` which is the entry point. The rest depends on your needs and module functionality.
-
-You can take a look at [module template](https://github.com/vuestorefront/vue-storefront/tree/master/core/modules/module-template) with an example implementation of all features listed in config.
-
-- `components` - Components logic related to this module (eg. Microcart for Cart module). Normally it contains `.ts` files but you can also create `.vue` files and provide some baseline markup if it is required for the component to work out of the box.
-- `pages` - If you want to provide full pages with your module, place them here. It's also a good practice to extend router configuration for these pages
-- `store` - Vuex Module associated to this module. You can also place Vuex modules extensions in here
- - `index.ts` - Entry point and main export of your Vuex Module. Actions/getters/mutations can be split into different files if the logic is too complex to keep it in one file. Should be used in `store` config property.
- - `mutation-types.ts` - Mutation strings represented by variables to use instead of plain strings
- - `plugins.ts` - Good place to put vuex plugin. Should be used in `store.plugins` config object
-- `types` - TypeScript types associated with the module
-- `test` - Folder with unit tests which is _required_ for every new or rewritten module.
-- `hooks` - before/after hooks that are called before and after registration of the module.
- - `beforeRegistration.ts` - Should be used in `beforeRegistration` config property.
- - `afterRegistration.ts` - Should be used in `afterRegistration` config property.
-- `router` - routes and navigation guards associated to this module
- - `routes.ts`- array of route objects that will be added to the current router configuration. Should be used in `router.routes` config property.
- - `beforeEach.ts` - beforeEach navigation guard. Should be used in `router.beforeEach` config property.
- - `afterEach.ts`- afterEach navigation guard. Should be used in `router.afterEach` config property.
-- `queries` - GraphQL queries
-- `helpers` - everything else that is meant to support modules behavior
-- `index.js` - entry point for the module. Should export VueStorefrontModule. It's also a good place to instantiate cache storage.
-
-### Module registration
-
-All modules including the core ones are registered in `src/modules/index.ts` file. Thanks to this approach you can easily modify any of core modules object before registration (read more [here](#extending-and-overriding-vue-storefront-modules)).
-
-All VS modules from `registerModules` will be registered during the shop initialisation.
-
----
-
-### General rules and good practices
-
-First off, take a look at module template. It contains great examples, good practices and explanations for everything that can be put in a module.
-
-0. **THE MOST IMPORTANT RULE** Try to isolate all the logic required for a module to work properly and put them inside the module. You can import it from other parts of the app but the logic itself should exist in the module
-1. **Try not to rely on any other module. Keep everything encapsulated and only rely on core helpers and libs**. Use other stores only if it's the only way to achieve the functionality and import `rootStore` for this purpose. Modules should work standalone and rely only on themselves. Try to think about each module as a standalone npm package.
-1. Place all reusable features as Vuex actions (e.g. `addToCart(product)`, `subscribeNewsletter()` etc) instead of placing them in components. try to use getters for modified or filtered values from state. We are trying to place most of the logic in Vuex stores to allow easier core updates. Here is a good example of such externalisation.
-
-```js
-export const Microcart = {
- name: 'Microcart',
- computed: {
- productsInCart(): Product[] {
- return this.$store.state.cart.cartItems;
- },
- appliedCoupon(): AppliedCoupon | false {
- return this.$store.getters['cart/coupon'];
- },
- totals(): CartTotalSegments {
- return this.$store.getters['cart/totals'];
- },
- isMicrocartOpen(): boolean {
- return this.$store.state.ui.microcart;
- },
- },
- methods: {
- applyCoupon(code: String): Promise {
- return this.$store.dispatch('cart/applyCoupon', code);
- },
- removeCoupon(): Promise