From 5c0774a0b7be245a6811274fb4eec94411f6bcea Mon Sep 17 00:00:00 2001 From: Heitor Ramon Ribeiro Date: Fri, 7 May 2021 01:13:19 -0300 Subject: [PATCH 1/3] feat: product search and dynamic header menu (#39) * chore(api-client): added README.md * chore(composeables): added README.md * feat(theme): created getInstance hook helper * feat(theme): created useVueRouter.ts hook helper * refactor(theme): applied getInstance hook helper function * refactor(theme): added loading and cache id to Product.vue * refactor(theme): added redirect to product when addToCart is for ConfigurableProduct * chore(theme): fixed user fixtures * chore(theme): fixed middle version imports * refactor(api-client): improved categoryList cache * feat(api-client): added categorySearch API endpoint * refactor(composeables): improved useFacet for a search without categoryId * refactor(composeables): improved useProduct initial API calls with Promise.all * feat(composeables): added categorySearch and useCategorySearch to composeables * refactor(composeables): fixed some keys on useRouterFactory.ts * refactor(theme): added loading for category sidebar * refactor(api-client): improved graphql cache by removing useless fragmentType * refactor(api-client): removed category children from categorySearch query * refactor(composeables): fixed useCategorySearch composeables * feat(theme): added SearchResults.vue component * feat(theme): added search and dynamic menu on AppHeader.vue --- packages/api-client/README.md | 58 +++ packages/api-client/package.json | 2 - packages/api-client/partial-types.js | 39 -- packages/api-client/rollup.config.js | 2 - .../api-client/src/api/categoryList/index.ts | 1 + .../src/api/categorySearch/index.ts | 14 + .../src/api/categorySearch/query.graphql | 9 + packages/api-client/src/api/index.ts | 1 + packages/api-client/src/index.ts | 2 + packages/api-client/src/link.ts | 9 +- packages/api-client/src/types/API.ts | 4 +- packages/api-client/src/types/GraphQL.ts | 10 + .../api-client/src/types/fragmentTypes.json | 1 - packages/composables/README.md | 53 +++ packages/composables/package.json | 2 +- .../composables/useCategorySearch/index.ts | 16 + .../src/composables/useFacet/index.ts | 6 +- .../src/composables/useProduct/index.ts | 12 +- .../src/factories/useCategorySearchFactory.ts | 58 +++ .../src/factories/useRouterFactory.ts | 8 +- packages/composables/src/index.ts | 1 + packages/composables/src/types/index.ts | 11 + packages/theme/components/AppHeader.vue | 339 ++++++++++++++++++ packages/theme/components/SearchResults.vue | 306 ++++++++++++++++ .../theme/composables/useUiHelpers/index.ts | 6 +- packages/theme/helpers/hooks/getInstance.ts | 6 + packages/theme/helpers/hooks/useVueRouter.ts | 18 + packages/theme/package.json | 2 +- packages/theme/pages/Category.vue | 48 ++- packages/theme/pages/Product.vue | 56 ++- .../test-data/e2e-user-registration.json | 8 +- 31 files changed, 1003 insertions(+), 105 deletions(-) create mode 100644 packages/api-client/README.md delete mode 100644 packages/api-client/partial-types.js create mode 100644 packages/api-client/src/api/categorySearch/index.ts create mode 100644 packages/api-client/src/api/categorySearch/query.graphql delete mode 100644 packages/api-client/src/types/fragmentTypes.json create mode 100644 packages/composables/README.md create mode 100644 packages/composables/src/composables/useCategorySearch/index.ts create mode 100644 packages/composables/src/factories/useCategorySearchFactory.ts create mode 100644 packages/theme/components/AppHeader.vue create mode 100644 packages/theme/components/SearchResults.vue create mode 100644 packages/theme/helpers/hooks/getInstance.ts create mode 100644 packages/theme/helpers/hooks/useVueRouter.ts diff --git a/packages/api-client/README.md b/packages/api-client/README.md new file mode 100644 index 000000000..d9c317209 --- /dev/null +++ b/packages/api-client/README.md @@ -0,0 +1,58 @@ + + +## Vue Storefront 2 integration with Magento (WIP) + +### @vue-storefront/magento-api + +This is only the **api-client** package, you need to install the other dependencies also. + +------ +This project is a Magento 2 integration for Vue Storefront 2. +This integration is being developed by superheroes from [Cyberfuze](https://cyberfuze.com/), [Ecritel](https://www.ecritel.com/) and [Leonex](https://www.leonex.de/) ❤️ + +## How to start if you want to try out the integration + +``` +yarn global add @vue-storefront/cli +``` +``` +vsf init && cd && yarn && yarn dev +``` + +## How to start if you want to contribute? + +Want to contribute? Ping us on `magento2-vsf2` channel on [our Discord](https://discord.vuestorefront.io)! +### Requirements: + - NodeJS v12 or later + - Magento v2.4 instance for GraphQL endpoint +### Steps +1. Fork the repo +2. Clone your fork of the repo + ``` + example: + git clone https://github.com/vuestorefront/magento2.git + cd magento2 + ``` +3. Checkout develop branch `git checkout develop` +4. Run `yarn` to install dependencies +5. Copy .env.example and update GraphQL Endpoint + ``` + cp packages/theme/.env.example .env + ``` +6. Update `MAGENTO_GRAPHQL=` with url to Magento 2.4 GrapgQL endpoint + ``` + MAGENTO_GRAPHQL=https://{YOUR_SITE_FRONT_URL}/graphql + ``` +7. Build dependencies `yarn build:api-client && yarn build:composables` +8. Run `yarn dev:theme` to run theme. You can find other commands in `package.json` +- If you need HMR on Api Client/Composables run `yarn dev:api-client` or `yarn dev:composables` on a separate terminal window. + +## Resources + +- [Vue Storefront Documentation](https://docs.vuestorefront.io/v2/) +- [Magento 2 integration Documentation (WIP)](https://docs.vuestorefront.io/magento) +- [Community Chat](https://discord.vuestorefront.io) + +## Support + +If you have any questions about this integration we will be happy to answer them on `magento2-vsf2` channel on [our Discord](discord.vuestorefront.io). diff --git a/packages/api-client/package.json b/packages/api-client/package.json index d57dccb4d..f04a836a2 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -12,7 +12,6 @@ "dev": "rimraf lib server && rollup -c -w", "lint": "eslint ./src --ext .ts,.vue", "lint:fix": "eslint ./src --ext .ts --fix", - "partial:types": "node ./partial-types.js", "precommit": "lint-staged", "prepublish": "yarn build", "test": "jest", @@ -37,7 +36,6 @@ "@rollup/plugin-graphql": "^1.0.0", "rollup-plugin-typescript2": "^0.30.0", "@rollup/plugin-node-resolve": "^13.0.0", - "@rollup/plugin-json": "^4.1.0", "@types/isomorphic-fetch": "^0.0.35", "apollo-link-schema": "^1.2.5", "dotenv": "^9.0.0", diff --git a/packages/api-client/partial-types.js b/packages/api-client/partial-types.js deleted file mode 100644 index f70c70223..000000000 --- a/packages/api-client/partial-types.js +++ /dev/null @@ -1,39 +0,0 @@ -require('dotenv').config(); -const fetch = require('node-fetch'); -const fs = require('fs'); - -fetch(process.env.MAGENTO_GRAPHQL, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - variables: {}, - query: ` - { - __schema { - types { - kind - name - possibleTypes { - name - } - } - } - } - `, - }), -}) - .then((result) => result.json()) - .then((result) => { - // here we're filtering out any type information unrelated to unions or interfaces - const filteredData = result.data.__schema.types.filter( - (type) => type.possibleTypes !== null, - ); - result.data.__schema.types = filteredData; - fs.writeFile('./src/types/fragmentTypes.json', JSON.stringify(result.data), (err) => { - if (err) { - console.error('Error writing fragmentTypes file', err); - } else { - console.log('Fragment types successfully extracted!'); - } - }); - }); diff --git a/packages/api-client/rollup.config.js b/packages/api-client/rollup.config.js index a88dd0416..faea3906e 100644 --- a/packages/api-client/rollup.config.js +++ b/packages/api-client/rollup.config.js @@ -1,7 +1,6 @@ import nodeResolve from '@rollup/plugin-node-resolve'; import typescript from 'rollup-plugin-typescript2'; import graphql from '@rollup/plugin-graphql'; -import json from '@rollup/plugin-json'; import pkg from './package.json'; import { generateBaseConfig } from '../../rollup.base.config'; @@ -27,7 +26,6 @@ const server = { }), typescript({ useTsconfigDeclarationDir: true }), graphql(), - json(), ], }; diff --git a/packages/api-client/src/api/categoryList/index.ts b/packages/api-client/src/api/categoryList/index.ts index 9d3853b63..e3b97af5e 100644 --- a/packages/api-client/src/api/categoryList/index.ts +++ b/packages/api-client/src/api/categoryList/index.ts @@ -10,4 +10,5 @@ export default async ( .query({ query, variables: { ...params }, + fetchPolicy: 'cache-first', }); diff --git a/packages/api-client/src/api/categorySearch/index.ts b/packages/api-client/src/api/categorySearch/index.ts new file mode 100644 index 000000000..b145234c4 --- /dev/null +++ b/packages/api-client/src/api/categorySearch/index.ts @@ -0,0 +1,14 @@ +import { ApolloQueryResult } from 'apollo-client'; +import { CategorySearchQuery, CategorySearchQueryVariables } from '../../types/GraphQL'; +import query from './query.graphql'; +import { Context } from '../../types/context'; + +export default async ( + { client }: Context, + params: CategorySearchQueryVariables, +): Promise> => client + .query({ + query, + variables: { ...params }, + fetchPolicy: 'cache-first', +}); diff --git a/packages/api-client/src/api/categorySearch/query.graphql b/packages/api-client/src/api/categorySearch/query.graphql new file mode 100644 index 000000000..079495329 --- /dev/null +++ b/packages/api-client/src/api/categorySearch/query.graphql @@ -0,0 +1,9 @@ +#import "../../fragments/categoryDataFragment.graphql" +#import "../../fragments/categoryUrlData.graphql" + +query categorySearch($filters: CategoryFilterInput) { + categoryList(filters: $filters) { + ...CategoryData + ...CategoryUrlData + } +} diff --git a/packages/api-client/src/api/index.ts b/packages/api-client/src/api/index.ts index da021f671..b6ca2fde6 100644 --- a/packages/api-client/src/api/index.ts +++ b/packages/api-client/src/api/index.ts @@ -3,6 +3,7 @@ export { default as addSimpleProductsToCart } from './addSimpleProductsToCart'; export { default as applyCouponToCart } from './applyCouponToCart'; export { default as cart } from './cart'; export { default as categoryList } from './categoryList'; +export { default as categorySearch } from './categorySearch'; export { default as changeCustomerPassword } from './changeCustomerPassword'; export { default as cmsPage } from './cmsPage'; export { default as configurableProductDetail } from './configurableProductDetail'; diff --git a/packages/api-client/src/index.ts b/packages/api-client/src/index.ts index 31e9fcd77..c18639a67 100644 --- a/packages/api-client/src/index.ts +++ b/packages/api-client/src/index.ts @@ -517,4 +517,6 @@ export { RelatedProductQueryVariables, UpsellProductsQuery, UpsellProductsQueryVariables, + CategorySearchQuery, + CategorySearchQueryVariables, } from './types/GraphQL'; diff --git a/packages/api-client/src/link.ts b/packages/api-client/src/link.ts index ee891237e..8ab07c1c4 100644 --- a/packages/api-client/src/link.ts +++ b/packages/api-client/src/link.ts @@ -2,12 +2,11 @@ import { createHttpLink } from 'apollo-link-http'; import fetch from 'isomorphic-fetch'; import ApolloClient from 'apollo-client'; import { ApolloLink } from 'apollo-link'; -import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; +import { InMemoryCache } from 'apollo-cache-inmemory'; import { setContext } from 'apollo-link-context'; import { onError } from 'apollo-link-error'; import { Logger } from '@vue-storefront/core'; import { Config } from './types/setup'; -import introspectionQueryResultData from './types/fragmentTypes.json'; const createErrorHandler = () => onError(({ graphQLErrors, @@ -69,11 +68,7 @@ const createMagentoConnection = (settings: Config): ApolloClient => { const link: ApolloLink = ApolloLink.from([authLink, onErrorLink, httpLink]); - const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, - }); - - const cache = new InMemoryCache({ fragmentMatcher }); + const cache = new InMemoryCache(); return new ApolloClient({ cache, diff --git a/packages/api-client/src/types/API.ts b/packages/api-client/src/types/API.ts index da60dd9ac..c3597a18c 100644 --- a/packages/api-client/src/types/API.ts +++ b/packages/api-client/src/types/API.ts @@ -16,7 +16,7 @@ import { CartItemInterface, CartQuery, CategoryFilterInput, - CategoryListQuery, CategoryListQueryVariables, + CategoryListQuery, CategoryListQueryVariables, CategorySearchQuery, CategorySearchQueryVariables, CategoryTree, CmsPage, CmsPageQuery, @@ -121,6 +121,8 @@ export interface MagentoApiMethods { categoryList(categoryFilter?: CategoryListQueryVariables): Promise>; + categorySearch(categoryFilter?: CategorySearchQueryVariables): Promise>; + changeCustomerPassword(currentPassword: string, newPassword: string): Promise; cmsPage(indentifier: string): Promise>; diff --git a/packages/api-client/src/types/GraphQL.ts b/packages/api-client/src/types/GraphQL.ts index 06883ec30..9fc65882c 100644 --- a/packages/api-client/src/types/GraphQL.ts +++ b/packages/api-client/src/types/GraphQL.ts @@ -6828,6 +6828,16 @@ export type CategoryListQuery = { categories?: Maybe<{ items?: Maybe>> } )>>> }> }; +export type CategorySearchQueryVariables = Exact<{ + filters?: Maybe; +}>; + + +export type CategorySearchQuery = { categoryList?: Maybe>> }; + export type ChangeCustomerPasswordMutationVariables = Exact<{ currentPassword: Scalars['String']; newPassword: Scalars['String']; diff --git a/packages/api-client/src/types/fragmentTypes.json b/packages/api-client/src/types/fragmentTypes.json deleted file mode 100644 index 59f1713cd..000000000 --- a/packages/api-client/src/types/fragmentTypes.json +++ /dev/null @@ -1 +0,0 @@ -{"__schema":{"types":[{"kind":"INTERFACE","name":"CartAddressInterface","possibleTypes":[{"name":"BillingCartAddress"},{"name":"ShippingCartAddress"}]},{"kind":"INTERFACE","name":"CartItemInterface","possibleTypes":[{"name":"SimpleCartItem"},{"name":"VirtualCartItem"},{"name":"DownloadableCartItem"},{"name":"BundleCartItem"},{"name":"ConfigurableCartItem"}]},{"kind":"INTERFACE","name":"ProductInterface","possibleTypes":[{"name":"VirtualProduct"},{"name":"SimpleProduct"},{"name":"DownloadableProduct"},{"name":"BundleProduct"},{"name":"GroupedProduct"},{"name":"ConfigurableProduct"}]},{"kind":"INTERFACE","name":"CategoryInterface","possibleTypes":[{"name":"CategoryTree"}]},{"kind":"INTERFACE","name":"MediaGalleryInterface","possibleTypes":[{"name":"ProductImage"},{"name":"ProductVideo"}]},{"kind":"INTERFACE","name":"ProductLinksInterface","possibleTypes":[{"name":"ProductLinks"}]},{"kind":"INTERFACE","name":"CreditMemoItemInterface","possibleTypes":[{"name":"DownloadableCreditMemoItem"},{"name":"BundleCreditMemoItem"},{"name":"CreditMemoItem"}]},{"kind":"INTERFACE","name":"OrderItemInterface","possibleTypes":[{"name":"DownloadableOrderItem"},{"name":"BundleOrderItem"},{"name":"OrderItem"}]},{"kind":"INTERFACE","name":"InvoiceItemInterface","possibleTypes":[{"name":"DownloadableInvoiceItem"},{"name":"BundleInvoiceItem"},{"name":"InvoiceItem"}]},{"kind":"INTERFACE","name":"ShipmentItemInterface","possibleTypes":[{"name":"BundleShipmentItem"},{"name":"ShipmentItem"}]},{"kind":"INTERFACE","name":"WishlistItemInterface","possibleTypes":[{"name":"SimpleWishlistItem"},{"name":"VirtualWishlistItem"},{"name":"DownloadableWishlistItem"},{"name":"BundleWishlistItem"},{"name":"GroupedProductWishlistItem"},{"name":"ConfigurableWishlistItem"}]},{"kind":"INTERFACE","name":"AggregationOptionInterface","possibleTypes":[{"name":"AggregationOption"}]},{"kind":"INTERFACE","name":"LayerFilterItemInterface","possibleTypes":[{"name":"LayerFilterItem"},{"name":"SwatchLayerFilterItem"}]},{"kind":"INTERFACE","name":"PhysicalProductInterface","possibleTypes":[{"name":"SimpleProduct"},{"name":"BundleProduct"},{"name":"GroupedProduct"},{"name":"ConfigurableProduct"}]},{"kind":"INTERFACE","name":"CustomizableOptionInterface","possibleTypes":[{"name":"CustomizableAreaOption"},{"name":"CustomizableDateOption"},{"name":"CustomizableDropDownOption"},{"name":"CustomizableMultipleOption"},{"name":"CustomizableFieldOption"},{"name":"CustomizableFileOption"},{"name":"CustomizableRadioOption"},{"name":"CustomizableCheckboxOption"}]},{"kind":"INTERFACE","name":"CustomizableProductInterface","possibleTypes":[{"name":"VirtualProduct"},{"name":"SimpleProduct"},{"name":"DownloadableProduct"},{"name":"BundleProduct"},{"name":"ConfigurableProduct"}]},{"kind":"INTERFACE","name":"SwatchDataInterface","possibleTypes":[{"name":"ImageSwatchData"},{"name":"TextSwatchData"},{"name":"ColorSwatchData"}]},{"kind":"INTERFACE","name":"SwatchLayerFilterItemInterface","possibleTypes":[{"name":"SwatchLayerFilterItem"}]}]}} \ No newline at end of file diff --git a/packages/composables/README.md b/packages/composables/README.md new file mode 100644 index 000000000..931b82231 --- /dev/null +++ b/packages/composables/README.md @@ -0,0 +1,53 @@ + + +## Vue Storefront 2 integration with Magento (WIP) + +This project is a Magento 2 integration for Vue Storefront 2. +This integration is being developed by superheroes from [Cyberfuze](https://cyberfuze.com/), [Ecritel](https://www.ecritel.com/) and [Leonex](https://www.leonex.de/) ❤️ + +## How to start if you want to try out the integration + +``` +yarn global add @vue-storefront/cli +``` +``` +vsf init && cd && yarn && yarn dev +``` + +## How to start if you want to contribute? + +Want to contribute? Ping us on `magento2-vsf2` channel on [our Discord](https://discord.vuestorefront.io)! +### Requirements: + - NodeJS v12 or later + - Magento v2.4 instance for GraphQL endpoint +### Steps +1. Fork the repo +2. Clone your fork of the repo + ``` + example: + git clone https://github.com/vuestorefront/magento2.git + cd magento2 + ``` +3. Checkout develop branch `git checkout develop` +4. Run `yarn` to install dependencies +5. Copy .env.example and update GraphQL Endpoint + ``` + cp packages/theme/.env.example .env + ``` +6. Update `MAGENTO_GRAPHQL=` with url to Magento 2.4 GrapgQL endpoint + ``` + MAGENTO_GRAPHQL=https://{YOUR_SITE_FRONT_URL}/graphql + ``` +7. Build dependencies `yarn build:api-client && yarn build:composables` +8. Run `yarn dev:theme` to run theme. You can find other commands in `package.json` +- If you need HMR on Api Client/Composables run `yarn dev:api-client` or `yarn dev:composables` on a separate terminal window. + +## Resources + +- [Vue Storefront Documentation](https://docs.vuestorefront.io/v2/) +- [Magento 2 integration Documentation (WIP)](https://docs.vuestorefront.io/magento) +- [Community Chat](https://discord.vuestorefront.io) + +## Support + +If you have any questions about this integration we will be happy to answer them on `magento2-vsf2` channel on [our Discord](discord.vuestorefront.io). diff --git a/packages/composables/package.json b/packages/composables/package.json index 04a12f101..b702ae39c 100644 --- a/packages/composables/package.json +++ b/packages/composables/package.json @@ -24,7 +24,7 @@ "access": "public" }, "dependencies": { - "@vue-storefront/magento-api": "^1.0.0-beta.2", + "@vue-storefront/magento-api": "^1.0.0-beta.3", "@vue-storefront/core": "^2.3.1", "vue": "^2.6.x" }, diff --git a/packages/composables/src/composables/useCategorySearch/index.ts b/packages/composables/src/composables/useCategorySearch/index.ts new file mode 100644 index 000000000..35d6e2490 --- /dev/null +++ b/packages/composables/src/composables/useCategorySearch/index.ts @@ -0,0 +1,16 @@ +import { + Context, +} from '@vue-storefront/core'; +import { Category } from '@vue-storefront/magento-api'; +import { UseCategorySearchFactory, useCategorySearchFactory } from '../../factories/useCategorySearchFactory'; + +const factoryParams: UseCategorySearchFactory = { + search: async (context: Context, params): Promise => { + // @ts-ignore + const { data } = await context.$magento.api.categorySearch({ filters: { name: { match: `${params.term}` } } }); + + return data.categoryList; + }, +}; + +export default useCategorySearchFactory(factoryParams); diff --git a/packages/composables/src/composables/useFacet/index.ts b/packages/composables/src/composables/useFacet/index.ts index 7ec8ed042..fe8d393b1 100644 --- a/packages/composables/src/composables/useFacet/index.ts +++ b/packages/composables/src/composables/useFacet/index.ts @@ -64,12 +64,10 @@ const factoryParams = { search: async (context: Context, params: FacetSearchResult) => { const itemsPerPage = (params.input.itemsPerPage) ? params.input.itemsPerPage : 20; const inputFilters = (params.input.filters) ? params.input.filters : {}; - + const categoryId = (params.input.categoryId) ? { category_uid: { eq: params.input.categoryId } } : {}; const productParams: ProductsSearchParams = { filter: { - category_uid: { - eq: params.input.categoryId, - }, + ...categoryId, ...constructFilterObject({ ...inputFilters, }), diff --git a/packages/composables/src/composables/useProduct/index.ts b/packages/composables/src/composables/useProduct/index.ts index 68d3a16bd..f82d7cb24 100644 --- a/packages/composables/src/composables/useProduct/index.ts +++ b/packages/composables/src/composables/useProduct/index.ts @@ -18,9 +18,15 @@ const factoryParams: UseProductFactoryParams extends FactoryParams { + search: (context: Context, params: { term: string }) => Promise; +} + +export function useCategorySearchFactory( + factoryParams: UseCategorySearchFactory, +) { + return function useCategorySearch(id: string): UseCategorySearch { + const ssrKey = id || 'useCategorySearch'; + // @ts-ignore + const result = sharedRef([], `${ssrKey}-result`); + const loading = sharedRef(false, `${ssrKey}-loading`); + const error = sharedRef({ + search: null, + }, `${ssrKey}-error`); + // eslint-disable-next-line @typescript-eslint/naming-convention,no-underscore-dangle + const _factoryParams = configureFactoryParams(factoryParams); + + const search = async (params: { term: string }): Promise => { + Logger.debug(`useCategorySearch/${ssrKey}/search`); + + try { + loading.value = true; + + const data = await _factoryParams.search(params); + + result.value = data; + + error.value.search = null; + + return data; + } catch (err) { + error.value.search = err; + Logger.error(`useCategorySearch/${ssrKey}/search`, err); + } finally { + loading.value = false; + } + }; + + return { + search, + // @ts-ignore + result, + loading, + // @ts-ignore + error, + }; + }; +} diff --git a/packages/composables/src/factories/useRouterFactory.ts b/packages/composables/src/factories/useRouterFactory.ts index d54ca872a..2f8aa76ed 100644 --- a/packages/composables/src/factories/useRouterFactory.ts +++ b/packages/composables/src/factories/useRouterFactory.ts @@ -1,4 +1,4 @@ -import { computed } from '@vue/composition-api'; +// import { computed } from '@vue/composition-api'; import { configureFactoryParams, Context, @@ -15,13 +15,13 @@ export interface UseRouterFactoryParams extends FactoryParams { export const useRouterFactory = ( factoryParams: UseRouterFactoryParams, ) => function useRouter(id?: string): UseRouter { - const ssrKey = id || 'useFacet'; + const ssrKey = id || 'useRouter'; // @ts-ignore - const result = sharedRef({}, `useRouter-routers-${ssrKey}`); + const result = sharedRef({}, `${ssrKey}-result`); const loading = sharedRef(false, `${ssrKey}-loading`); const error = sharedRef({ search: null, - }, `useRouter-error-${id}`); + }, `${ssrKey}-error`); // eslint-disable-next-line @typescript-eslint/naming-convention,no-underscore-dangle const _factoryParams = configureFactoryParams(factoryParams); diff --git a/packages/composables/src/index.ts b/packages/composables/src/index.ts index b685b1788..01ccf71ed 100644 --- a/packages/composables/src/index.ts +++ b/packages/composables/src/index.ts @@ -6,6 +6,7 @@ track('VSFMagento'); export { default as useBilling } from './composables/useBilling'; export { default as useCart } from './composables/useCart'; export { default as useCategory } from './composables/useCategory'; +export { default as useCategorySearch } from './composables/useCategorySearch'; export { default as useCheckout } from './composables/useCheckout'; export { default as useConfig } from './composables/useConfig'; export { default as useFacet } from './composables/useFacet'; diff --git a/packages/composables/src/types/index.ts b/packages/composables/src/types/index.ts index 13dec4d33..12d4ce504 100644 --- a/packages/composables/src/types/index.ts +++ b/packages/composables/src/types/index.ts @@ -46,6 +46,17 @@ export interface UseRouterErrors { search: Error; } +export interface UseCategorySearch { + search: (params: { term: string }) => Promise; + result: ComputedProperty; + error: ComputedProperty; + loading: ComputedProperty; +} + +export interface UseCategorySearchErrors { + search: Error; +} + export interface UseConfig { config: ComputedRef; loadConfig: () => Promise; diff --git a/packages/theme/components/AppHeader.vue b/packages/theme/components/AppHeader.vue new file mode 100644 index 000000000..14abd7b5d --- /dev/null +++ b/packages/theme/components/AppHeader.vue @@ -0,0 +1,339 @@ + + + + + diff --git a/packages/theme/components/SearchResults.vue b/packages/theme/components/SearchResults.vue new file mode 100644 index 000000000..b606ab703 --- /dev/null +++ b/packages/theme/components/SearchResults.vue @@ -0,0 +1,306 @@ + + + diff --git a/packages/theme/composables/useUiHelpers/index.ts b/packages/theme/composables/useUiHelpers/index.ts index 632e45e72..e7071dc54 100644 --- a/packages/theme/composables/useUiHelpers/index.ts +++ b/packages/theme/composables/useUiHelpers/index.ts @@ -2,14 +2,10 @@ import { getCurrentInstance } from '@vue/composition-api'; // eslint-disable-next-line import/no-extraneous-dependencies import { Category } from '@vue-storefront/magento-api'; import { AgnosticCategoryTree, AgnosticFacet } from '@vue-storefront/core'; +import { getInstance } from '~/helpers/hooks/getInstance'; const nonFilters = ['page', 'sort', 'term', 'itemsPerPage']; -const getInstance = () => { - const vm = getCurrentInstance(); - return vm.$root as any; -}; - const reduceFilters = (query) => (prev, curr) => { const makeArray = Array.isArray(query[curr]) || nonFilters.includes(curr); diff --git a/packages/theme/helpers/hooks/getInstance.ts b/packages/theme/helpers/hooks/getInstance.ts new file mode 100644 index 000000000..708bcf473 --- /dev/null +++ b/packages/theme/helpers/hooks/getInstance.ts @@ -0,0 +1,6 @@ +import { getCurrentInstance } from '@vue/composition-api'; + +export const getInstance = () => { + const vm = getCurrentInstance(); + return vm.$root as any; +}; diff --git a/packages/theme/helpers/hooks/useVueRouter.ts b/packages/theme/helpers/hooks/useVueRouter.ts new file mode 100644 index 000000000..fdd0966cf --- /dev/null +++ b/packages/theme/helpers/hooks/useVueRouter.ts @@ -0,0 +1,18 @@ +/* istanbul ignore file */ +import { Route } from 'vue-router'; +import { reactive, watch } from '@vue/composition-api'; +import { getInstance } from '~/helpers/hooks/getInstance'; + +export const useVueRouter = () => { + const vm = getInstance(); + const state = reactive<{ route: Route }>({ route: vm.$route }); + + const defineRoute = (r: Route) => { state.route = r; }; + + watch(() => vm.$route, defineRoute); + + return { + ...state, + router: vm.$router, + }; +}; diff --git a/packages/theme/package.json b/packages/theme/package.json index 113458f03..d8ba78347 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -24,7 +24,7 @@ "@nuxtjs/style-resources": "^1.0.0", "@storefront-ui/vue": "^0.10.5", "@vue-storefront/core": "^2.3.1", - "@vue-storefront/magento": "^1.0.0-beta.2", + "@vue-storefront/magento": "^1.0.0-beta.3", "@vue-storefront/middleware": "^2.3.1", "@vue-storefront/nuxt": "^2.3.1", "@vue-storefront/nuxt-theme": "^2.3.1", diff --git a/packages/theme/pages/Category.vue b/packages/theme/pages/Category.vue index b69e0b130..db1af297d 100644 --- a/packages/theme/pages/Category.vue +++ b/packages/theme/pages/Category.vue @@ -91,8 +91,8 @@