From 7e27efd5e954a1ddeac053d92e1e748e36443971 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Tue, 13 Apr 2021 16:53:04 +0200 Subject: [PATCH 01/35] Feat: Add shallow export button to products --- .../ProductTranslation/ProductTranslation.tsx | 114 +++++++++++++----- 1 file changed, 81 insertions(+), 33 deletions(-) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index 6e946ac..fec7531 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -1,5 +1,12 @@ -import React, { FC, SyntheticEvent } from 'react' -import { InputSearch, PageBlock, Spinner } from 'vtex.styleguide' +import React, { FC, SyntheticEvent, useState } from 'react' +import { + InputSearch, + PageBlock, + Spinner, + ButtonWithIcon, + IconDownload, + ModalDialog, +} from 'vtex.styleguide' import { useLocaleSelector } from '../LocaleSelector' import getProductQuery from '../../graphql/getProduct.gql' @@ -8,6 +15,8 @@ import ErrorHandler from '../ErrorHandler' import useCatalogQuery from '../../hooks/useCatalogQuery' const ProductTranslation: FC = () => { + const [isExportOpen, setIsExportOpen] = useState(false) + const { entryInfo, isLoadingOrRefetching, @@ -22,7 +31,7 @@ const ProductTranslation: FC = () => { { identifier: { value: string; field: 'id' } } >(getProductQuery) - const { selectedLocale } = useLocaleSelector() + const { selectedLocale, isXVtexTenant } = useLocaleSelector() const handleSubmitProductId = (e: SyntheticEvent) => { e.preventDefault() @@ -37,38 +46,77 @@ const ProductTranslation: FC = () => { const { id, ...productInfo } = entryInfo?.product || ({} as Product) return ( -
-
- -
- {id || isLoadingOrRefetching || errorMessage ? ( - - {errorMessage ? ( - - ) : isLoadingOrRefetching ? ( - - ) : ( - +
+
+
+ +
+ {isXVtexTenant ? null : ( +
+ } + variation="primary" + onClick={() => setIsExportOpen(true)} + > + Export + +
)} - - ) : null} -
+ + {id || isLoadingOrRefetching || errorMessage ? ( + + {errorMessage ? ( + + ) : isLoadingOrRefetching ? ( + + ) : ( + + )} + + ) : null} +
+ { + setIsExportOpen(false) + }, + }} + confirmation={{ + label: 'Export Products', + // eslint-disable-next-line no-console + onClick: () => console.log('export'), + }} + onClose={() => { + setIsExportOpen(false) + }} + > +

Export product

+
+ ) } From b6f0408e0259a9402dcf311496badcc4fa21da43 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Tue, 13 Apr 2021 17:13:32 +0200 Subject: [PATCH 02/35] Feat: Add resolver and graphql query to get categories name --- graphql/schema.graphql | 1 + graphql/types/Category.graphql | 5 +++++ node/resolvers/category.ts | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/graphql/schema.graphql b/graphql/schema.graphql index 778263b..fefd62c 100644 --- a/graphql/schema.graphql +++ b/graphql/schema.graphql @@ -1,3 +1,4 @@ type Query { categoryTranslations(locale: String!, active: Boolean): [Category] + getCategoriesName: [CategoryName] } diff --git a/graphql/types/Category.graphql b/graphql/types/Category.graphql index d314a11..6b9cd85 100644 --- a/graphql/types/Category.graphql +++ b/graphql/types/Category.graphql @@ -5,3 +5,8 @@ type Category { description: String locale: String } + +type CategoryName { + id: String + name: String +} diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index 9616556..539f5d3 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -43,6 +43,29 @@ const categoryTranslations = async ( } } +const getCategoriesName = async ( + _root: unknown, + _args: unknown, + _ctx: Context +) => { + // const { + // // @ts- + // clients: { catalog }, + // } = ctx + + return [ + { + id: 1, + name: 'nameOne', + }, + { + id: 2, + name: 'nameTwo', + }, + ] +} + export const queries = { categoryTranslations, + getCategoriesName, } From 22c23af7932f376afb1ae61218659343cb52fb1a Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 14 Apr 2021 10:31:50 +0200 Subject: [PATCH 03/35] Fix: Make flag active effective on categoryTranslations query --- node/resolvers/category.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index 539f5d3..da1bb8f 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -25,10 +25,12 @@ const categoryTranslations = async ( clients: { catalog }, } = ctx + const { active } = args + ctx.state.locale = args.locale try { - const ids = await catalog.getCategoriesId() + const ids = await catalog.getCategoriesId(active) const translationsP = [] From 4d5246a7d0d207982b78ac9f38b1ad203ee912a5 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 14 Apr 2021 10:44:44 +0200 Subject: [PATCH 04/35] Refactor: Refactor category query to include category name --- node/clients/catalog.ts | 17 +++++++++-------- node/resolvers/category.ts | 2 +- node/typings/category.d.ts | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/node/clients/catalog.ts b/node/clients/catalog.ts index 071a705..01b3f94 100644 --- a/node/clients/catalog.ts +++ b/node/clients/catalog.ts @@ -5,10 +5,11 @@ import { statusToError } from '../utils' const CATALOG_GRAPHQL_APP = 'vtex.catalog-graphql@1.x' const CATEGORIES_QUERY = ` - query GetCategoriesId ($active: Boolean, $page: Int!) { + query GetCategories ($active: Boolean, $page: Int!) { categories(term:"*", page: $page, pageSize: 50, active: $active) { items { id + name } paging { pages @@ -33,25 +34,25 @@ export class Catalog extends AppGraphQLClient { super(CATALOG_GRAPHQL_APP, ctx, opts) } - public getCategoriesId = async (active = true) => { + public getCategories = async (active = true) => { try { - const response = await this.getCategoriesIdPerPage({ active, page: 1 }) + const response = await this.getCategoriesPerPage({ active, page: 1 }) const { items, paging: { pages }, - } = (response.data as CategoryIdsResponse).categories + } = (response.data as CategoryResponse).categories const collectItems = items const responsePromises = [] for (let i = 2; i <= pages; i++) { - const promise = this.getCategoriesIdPerPage({ active, page: i }) + const promise = this.getCategoriesPerPage({ active, page: i }) responsePromises.push(promise) } const resolvedPromises = await Promise.all(responsePromises) const flattenResponse = resolvedPromises.reduce((acc, curr) => { - return [...acc, ...(curr.data as CategoryIdsResponse).categories.items] + return [...acc, ...(curr.data as CategoryResponse).categories.items] }, collectItems) return flattenResponse @@ -60,14 +61,14 @@ export class Catalog extends AppGraphQLClient { } } - private getCategoriesIdPerPage = ({ + private getCategoriesPerPage = ({ active = true, page, }: { active: boolean page: number }) => - this.graphql.query({ + this.graphql.query({ query: CATEGORIES_QUERY, variables: { active, diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index da1bb8f..621b035 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -30,7 +30,7 @@ const categoryTranslations = async ( ctx.state.locale = args.locale try { - const ids = await catalog.getCategoriesId(active) + const ids = await catalog.getCategories(active) const translationsP = [] diff --git a/node/typings/category.d.ts b/node/typings/category.d.ts index 53094c2..e699922 100644 --- a/node/typings/category.d.ts +++ b/node/typings/category.d.ts @@ -1,6 +1,6 @@ -interface CategoryIdsResponse { +interface CategoryResponse { categories: { - items: Array<{ id: string }> + items: Array<{ id: string; name: string }> paging: { pages: number } From c4d829169461ab0093e89b8097547c348ae09205 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 14 Apr 2021 10:50:00 +0200 Subject: [PATCH 05/35] Feat: Done query to get categories name --- node/resolvers/category.ts | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index 621b035..742ae13 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -48,23 +48,14 @@ const categoryTranslations = async ( const getCategoriesName = async ( _root: unknown, _args: unknown, - _ctx: Context + ctx: Context ) => { - // const { - // // @ts- - // clients: { catalog }, - // } = ctx + const { + // @ts- + clients: { catalog }, + } = ctx - return [ - { - id: 1, - name: 'nameOne', - }, - { - id: 2, - name: 'nameTwo', - }, - ] + return catalog.getCategories(false) } export const queries = { From bfbfb0195ebd6c675ad19c06c335caaba7ca82ec Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 14 Apr 2021 12:01:54 +0200 Subject: [PATCH 06/35] Chore: Update vtex types --- node/package.json | 5 ++++- node/yarn.lock | 12 ++++++++++++ react/package.json | 6 +++++- react/yarn.lock | 16 ++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/node/package.json b/node/package.json index b4b0cc7..9337241 100644 --- a/node/package.json +++ b/node/package.json @@ -8,6 +8,9 @@ }, "devDependencies": { "@vtex/tsconfig": "^0.5.6", - "typescript": "3.9.7" + "typescript": "3.9.7", + "vtex.catalog-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.catalog-graphql@1.96.0/public/@types/vtex.catalog-graphql", + "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.138.0/public/@types/vtex.styleguide", + "vtex.tenant-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.tenant-graphql@0.1.2/public/@types/vtex.tenant-graphql" } } diff --git a/node/yarn.lock b/node/yarn.lock index 2a8e9bd..11c9a0b 100644 --- a/node/yarn.lock +++ b/node/yarn.lock @@ -1334,6 +1334,18 @@ vary@^1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +"vtex.catalog-graphql@http://vtex.vtexassets.com/_v/public/typings/v1/vtex.catalog-graphql@1.96.0/public/@types/vtex.catalog-graphql": + version "1.96.0" + resolved "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.catalog-graphql@1.96.0/public/@types/vtex.catalog-graphql#20fd7dc4f24848cb3e227a3ae369fcfb71861008" + +"vtex.styleguide@http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.138.0/public/@types/vtex.styleguide": + version "9.138.0" + resolved "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.138.0/public/@types/vtex.styleguide#ce25c45f1827df0a0f5024a40c9a93875f29e15c" + +"vtex.tenant-graphql@http://vtex.vtexassets.com/_v/public/typings/v1/vtex.tenant-graphql@0.1.2/public/@types/vtex.tenant-graphql": + version "0.1.2" + resolved "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.tenant-graphql@0.1.2/public/@types/vtex.tenant-graphql#74673fe86baefe74f21a6d2615993ea0ccb5e79e" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" diff --git a/react/package.json b/react/package.json index 7aa7c49..275d082 100644 --- a/react/package.json +++ b/react/package.json @@ -15,7 +15,11 @@ "react": "^16.8.6", "react-dom": "^16.8.6", "react-intl": "^2.7.2", - "typescript": "3.9.7" + "typescript": "3.9.7", + "vtex.catalog-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.catalog-graphql@1.96.0/public/@types/vtex.catalog-graphql", + "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.128.2/public/@types/vtex.render-runtime", + "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.138.0/public/@types/vtex.styleguide", + "vtex.tenant-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.tenant-graphql@0.1.2/public/@types/vtex.tenant-graphql" }, "dependencies": { "@types/faker": "^4.1.5", diff --git a/react/yarn.lock b/react/yarn.lock index 079bff6..bdc73bc 100644 --- a/react/yarn.lock +++ b/react/yarn.lock @@ -420,6 +420,22 @@ typescript@3.9.7: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +"vtex.catalog-graphql@http://vtex.vtexassets.com/_v/public/typings/v1/vtex.catalog-graphql@1.96.0/public/@types/vtex.catalog-graphql": + version "1.96.0" + resolved "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.catalog-graphql@1.96.0/public/@types/vtex.catalog-graphql#20fd7dc4f24848cb3e227a3ae369fcfb71861008" + +"vtex.render-runtime@http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.128.2/public/@types/vtex.render-runtime": + version "8.128.2" + resolved "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.128.2/public/@types/vtex.render-runtime#67f5975f7edd73c9afa7bee57734540c0ead5428" + +"vtex.styleguide@http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.138.0/public/@types/vtex.styleguide": + version "9.138.0" + resolved "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.138.0/public/@types/vtex.styleguide#ce25c45f1827df0a0f5024a40c9a93875f29e15c" + +"vtex.tenant-graphql@http://vtex.vtexassets.com/_v/public/typings/v1/vtex.tenant-graphql@0.1.2/public/@types/vtex.tenant-graphql": + version "0.1.2" + resolved "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.tenant-graphql@0.1.2/public/@types/vtex.tenant-graphql#74673fe86baefe74f21a6d2615993ea0ccb5e79e" + wmf@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da" From 71796d811b8371741be5d3e5884f1edbd14a0043 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 14 Apr 2021 16:59:00 +0200 Subject: [PATCH 07/35] Feat: Add Export product modal with autocomplete search --- node/resolvers/category.ts | 1 - .../ProductTranslation/ProductTranslation.tsx | 69 ++++++++++++++++++- react/graphql/getCategoriesName.gql | 6 ++ react/typings/catalog.d.ts | 4 ++ react/utils/index.ts | 18 +++++ 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 react/graphql/getCategoriesName.gql diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index 742ae13..29dfc00 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -51,7 +51,6 @@ const getCategoriesName = async ( ctx: Context ) => { const { - // @ts- clients: { catalog }, } = ctx diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index fec7531..336b317 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -6,16 +6,31 @@ import { ButtonWithIcon, IconDownload, ModalDialog, + AutocompleteInput, } from 'vtex.styleguide' +import { useQuery } from 'react-apollo' import { useLocaleSelector } from '../LocaleSelector' import getProductQuery from '../../graphql/getProduct.gql' import ProductForm from './ProductForm' import ErrorHandler from '../ErrorHandler' import useCatalogQuery from '../../hooks/useCatalogQuery' +import GET_CATEGORIES_NAME from '../../graphql/getCategoriesName.gql' +import { filterSearchCategories } from '../../utils' + +const AUTOCOMPLETE_LIST_SIZE = 6 + +interface AutocompleteValue { + label: string + value: string +} const ProductTranslation: FC = () => { const [isExportOpen, setIsExportOpen] = useState(false) + const [searchTerm, setSearchTerm] = useState('') + const [selectedCategory, setSelectedCategory] = useState( + {} as AutocompleteValue + ) const { entryInfo, @@ -33,6 +48,18 @@ const ProductTranslation: FC = () => { const { selectedLocale, isXVtexTenant } = useLocaleSelector() + const { data: categoryInfo, loading: loadingCategoryInfo, error } = useQuery< + CategoriesNameAndId + >(GET_CATEGORIES_NAME) + + // eslint-disable-next-line no-console + console.log({ error }) + + const listOfOptions = filterSearchCategories({ + categoryList: categoryInfo?.getCategoriesName ?? [], + term: searchTerm, + }) + const handleSubmitProductId = (e: SyntheticEvent) => { e.preventDefault() if (!entryId) { @@ -45,6 +72,8 @@ const ProductTranslation: FC = () => { } const { id, ...productInfo } = entryInfo?.product || ({} as Product) + const hasCategorySelected = !!selectedCategory.label + return ( <>
@@ -103,18 +132,56 @@ const ProductTranslation: FC = () => { label: 'Cancel', onClick: () => { setIsExportOpen(false) + setSearchTerm('') }, }} confirmation={{ label: 'Export Products', // eslint-disable-next-line no-console onClick: () => console.log('export'), + disabled: true, }} onClose={() => { setIsExportOpen(false) + setSearchTerm('') }} > -

Export product

+
+

Export Product Data for {selectedLocale}

+ {loadingCategoryInfo ? ( + + ) : ( +
+

Select category

+ setSearchTerm(term), + onClear: () => { + setSearchTerm('') + setSelectedCategory({} as AutocompleteValue) + }, + value: searchTerm, + }} + options={{ + onSelect: (selectedItem: AutocompleteValue) => + setSelectedCategory(selectedItem), + value: !searchTerm.length + ? [] + : listOfOptions.slice(0, AUTOCOMPLETE_LIST_SIZE), + loading: listOfOptions.length > AUTOCOMPLETE_LIST_SIZE, + }} + /> + {hasCategorySelected ? ( +
+

+ {`Download product information from category ${selectedCategory.label}`} +

+
+ ) : null} +
+ )} +
) diff --git a/react/graphql/getCategoriesName.gql b/react/graphql/getCategoriesName.gql new file mode 100644 index 0000000..fbe8c39 --- /dev/null +++ b/react/graphql/getCategoriesName.gql @@ -0,0 +1,6 @@ +query getCategoriesName { + getCategoriesName @context(provider: "vtex.admin-catalog-translation") { + id + name + } +} diff --git a/react/typings/catalog.d.ts b/react/typings/catalog.d.ts index a6c700c..069e103 100644 --- a/react/typings/catalog.d.ts +++ b/react/typings/catalog.d.ts @@ -49,3 +49,7 @@ interface ProductInputTranslation { title: string linkId: string } + +interface CategoriesNameAndId { + getCategoriesName: Array<{ id: string; name: string }> +} diff --git a/react/utils/index.ts b/react/utils/index.ts index aa064a5..9bc87c8 100644 --- a/react/utils/index.ts +++ b/react/utils/index.ts @@ -60,3 +60,21 @@ export function parseJSONToXLS( const exportFileName = `${fileName}.xls` XLSX.writeFile(workBook, exportFileName) } + +interface FilterSearchCategoriesArgs { + categoryList: Array<{ id: string; name: string }> + term: string +} + +export const filterSearchCategories = ({ + categoryList, + term, +}: FilterSearchCategoriesArgs): Array<{ label: string; value: string }> => { + return ( + categoryList + .map(({ id, name }) => ({ label: `${id} - ${name}`, value: id })) + .filter(({ label }) => + label.toLowerCase().includes(term.toLowerCase()) + ) ?? [] + ) +} From 6365a8bc5a6b1f028eeb93bf2223d017a300eadb Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 15 Apr 2021 12:17:08 +0200 Subject: [PATCH 08/35] Refactor: Change Client name to make room for a Catalog client --- node/clients/{catalog.ts => catalogGQL.ts} | 2 +- node/clients/index.ts | 6 +++--- node/resolvers/category.ts | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) rename node/clients/{catalog.ts => catalogGQL.ts} (97%) diff --git a/node/clients/catalog.ts b/node/clients/catalogGQL.ts similarity index 97% rename from node/clients/catalog.ts rename to node/clients/catalogGQL.ts index 01b3f94..4470755 100644 --- a/node/clients/catalog.ts +++ b/node/clients/catalogGQL.ts @@ -29,7 +29,7 @@ const GET_TRANSLATION_QUERY = ` } ` -export class Catalog extends AppGraphQLClient { +export class CatalogGQL extends AppGraphQLClient { constructor(ctx: IOContext, opts?: InstanceOptions) { super(CATALOG_GRAPHQL_APP, ctx, opts) } diff --git a/node/clients/index.ts b/node/clients/index.ts index c769ac8..8ba1179 100644 --- a/node/clients/index.ts +++ b/node/clients/index.ts @@ -1,9 +1,9 @@ import { IOClients } from '@vtex/api' -import { Catalog } from './catalog' +import { CatalogGQL } from './catalogGQL' export class Clients extends IOClients { - public get catalog() { - return this.getOrSet('catalog', Catalog) + public get catalogGQL() { + return this.getOrSet('catalogGQL', CatalogGQL) } } diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index 29dfc00..8e4af01 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -22,7 +22,7 @@ const categoryTranslations = async ( ctx: Context ) => { const { - clients: { catalog }, + clients: { catalogGQL }, } = ctx const { active } = args @@ -30,12 +30,12 @@ const categoryTranslations = async ( ctx.state.locale = args.locale try { - const ids = await catalog.getCategories(active) + const ids = await catalogGQL.getCategories(active) const translationsP = [] for (const { id } of ids) { - const promise = catalog.getTranslation(id) + const promise = catalogGQL.getTranslation(id) translationsP.push(promise) } @@ -51,10 +51,10 @@ const getCategoriesName = async ( ctx: Context ) => { const { - clients: { catalog }, + clients: { catalogGQL }, } = ctx - return catalog.getCategories(false) + return catalogGQL.getCategories(false) } export const queries = { From 9d8b95c4d83bcf2477c3a016187abd9692c4249e Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 16 Apr 2021 10:47:22 +0200 Subject: [PATCH 09/35] Feat: Add client to get all products ids from category id --- manifest.json | 7 +++ node/clients/catalog.ts | 89 +++++++++++++++++++++++++++++++++++++++ node/clients/index.ts | 5 +++ node/resolvers/product.ts | 17 ++++++++ node/typings/product.d.ts | 10 +++++ node/utils.ts | 18 ++++++++ 6 files changed, 146 insertions(+) create mode 100644 node/clients/catalog.ts create mode 100644 node/resolvers/product.ts create mode 100644 node/typings/product.d.ts diff --git a/manifest.json b/manifest.json index b727d7c..e82eefe 100644 --- a/manifest.json +++ b/manifest.json @@ -24,6 +24,13 @@ "policies": [ { "name": "vtex.catalog-graphql:resolve-graphql" + }, + { + "name": "outbound-access", + "attrs": { + "host": "portal.vtexcommercestable.com.br", + "path": "/api/catalog_system/*" + } } ], "$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema" diff --git a/node/clients/catalog.ts b/node/clients/catalog.ts new file mode 100644 index 0000000..db33049 --- /dev/null +++ b/node/clients/catalog.ts @@ -0,0 +1,89 @@ +import { + InstanceOptions, + IOContext, + JanusClient, + RequestConfig, +} from '@vtex/api' + +import { + statusToError, + interations, + getInterationPairs, + extractProductId, + MAX_PRODUCTS_PER_CATEGORY, +} from '../utils' + +export class Catalog extends JanusClient { + constructor(ctx: IOContext, opts?: InstanceOptions) { + super(ctx, { + ...opts, + headers: { + ...opts?.headers, + ...(ctx.adminUserAuthToken + ? { VtexIdclientAutCookie: ctx.adminUserAuthToken } + : null), + }, + }) + } + + public getAllProducts = async (categoryId: string) => { + const { range, ...products } = await this.getProductIdsByCategory( + categoryId, + 1, + MAX_PRODUCTS_PER_CATEGORY + ) + const { total } = range + const remainingInterations = interations(total) + const productPerCategorypromises = [] + + // /GetProductAndSkuIds returns max 50 responses. We loop over the remaining interations to get all products + for (let i = 1; i <= remainingInterations; i++) { + const [from, to] = getInterationPairs(i) + const productPerIdPromise = this.getProductIdsByCategory( + categoryId, + from, + to + ) + productPerCategorypromises.push(productPerIdPromise) + } + + const productPerCategoryCollection = await Promise.all( + productPerCategorypromises + ) + + const finalProducts = [] + + // we plug together the first response and all the others. Then we extract only the product ids from responses + for (const product of [products, ...productPerCategoryCollection]) { + const productIds = extractProductId(product.data) + finalProducts.push(...productIds) + } + return finalProducts + } + + private getProductIdsByCategory = ( + categoryId: string, + _from: number, + _to: number + ) => { + return this.get(this.routes.getProductAndSkuIds(), { + params: { categoryId, _from, _to }, + }) + } + + protected get = (url: string, config: RequestConfig = {}) => { + try { + return this.http.get(url, config) + } catch (e) { + return statusToError(e) + } + } + + private get routes() { + const basePath = '/api/catalog_system' + + return { + getProductAndSkuIds: () => `${basePath}/pvt/products/GetProductAndSkuIds`, + } + } +} diff --git a/node/clients/index.ts b/node/clients/index.ts index 8ba1179..02d7601 100644 --- a/node/clients/index.ts +++ b/node/clients/index.ts @@ -1,9 +1,14 @@ import { IOClients } from '@vtex/api' import { CatalogGQL } from './catalogGQL' +import { Catalog } from './catalog' export class Clients extends IOClients { public get catalogGQL() { return this.getOrSet('catalogGQL', CatalogGQL) } + + public get catalog() { + return this.getOrSet('catalog', Catalog) + } } diff --git a/node/resolvers/product.ts b/node/resolvers/product.ts new file mode 100644 index 0000000..fe44303 --- /dev/null +++ b/node/resolvers/product.ts @@ -0,0 +1,17 @@ +export const productTranslations = async ( + _root: unknown, + args: { locale: string; categoryId: string }, + ctx: Context +) => { + const { + clients: { catalog }, + } = ctx + + const { locale, categoryId } = args + + ctx.state.locale = locale + + const productIdCollection = catalog.getAllProducts(categoryId) + + return productIdCollection +} diff --git a/node/typings/product.d.ts b/node/typings/product.d.ts new file mode 100644 index 0000000..125140e --- /dev/null +++ b/node/typings/product.d.ts @@ -0,0 +1,10 @@ +interface GetProductAndSkuIds { + data: { + [productId: string]: number[] + } + range: { + total: number + from: number + to: number + } +} diff --git a/node/utils.ts b/node/utils.ts index cf6bb73..4915a19 100644 --- a/node/utils.ts +++ b/node/utils.ts @@ -27,3 +27,21 @@ export const statusToError = (e: AxiosError) => { throw new TypeError(e.message) } } + +export const MAX_PRODUCTS_PER_CATEGORY = 50 + +export const interations = (total: number) => { + return ( + Math.floor(total / MAX_PRODUCTS_PER_CATEGORY) - + (total % MAX_PRODUCTS_PER_CATEGORY ? 0 : 1) + ) +} + +export const getInterationPairs = (currentStep: number): number[] => [ + MAX_PRODUCTS_PER_CATEGORY * currentStep + 1, + MAX_PRODUCTS_PER_CATEGORY * currentStep + 50, +] + +export const extractProductId = (productResponse: Record) => { + return Object.keys(productResponse) +} From d5cefd5cd0307c75058bd79a390c4283bee4695e Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 16 Apr 2021 12:22:12 +0200 Subject: [PATCH 10/35] Feat: Add Graphql query returning all products id to a category --- graphql/schema.graphql | 1 + graphql/types/Product.graphql | 3 +++ node/resolvers/index.ts | 2 ++ node/resolvers/product.ts | 6 +++++- 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 graphql/types/Product.graphql diff --git a/graphql/schema.graphql b/graphql/schema.graphql index fefd62c..4f63f94 100644 --- a/graphql/schema.graphql +++ b/graphql/schema.graphql @@ -1,4 +1,5 @@ type Query { categoryTranslations(locale: String!, active: Boolean): [Category] getCategoriesName: [CategoryName] + productTranslations(locale: String!, categoryId: String!): [String] } diff --git a/graphql/types/Product.graphql b/graphql/types/Product.graphql new file mode 100644 index 0000000..4f5a776 --- /dev/null +++ b/graphql/types/Product.graphql @@ -0,0 +1,3 @@ +type Product { + id: String! +} diff --git a/node/resolvers/index.ts b/node/resolvers/index.ts index 11f38f1..b7c0aeb 100644 --- a/node/resolvers/index.ts +++ b/node/resolvers/index.ts @@ -1,7 +1,9 @@ import { Category, queries as categoryQueries } from './category' +import { queries as productQueries } from './product' export const queries = { ...categoryQueries, + ...productQueries, } export const resolvers = { diff --git a/node/resolvers/product.ts b/node/resolvers/product.ts index fe44303..66af720 100644 --- a/node/resolvers/product.ts +++ b/node/resolvers/product.ts @@ -1,4 +1,4 @@ -export const productTranslations = async ( +const productTranslations = async ( _root: unknown, args: { locale: string; categoryId: string }, ctx: Context @@ -15,3 +15,7 @@ export const productTranslations = async ( return productIdCollection } + +export const queries = { + productTranslations, +} From 209d8475f8cd4153742d170889a34b9d386ca588 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 16 Apr 2021 13:47:40 +0200 Subject: [PATCH 11/35] Refactor: Change method name getTranslation to getCaterogyTranslation --- node/clients/catalogGQL.ts | 2 +- node/resolvers/category.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node/clients/catalogGQL.ts b/node/clients/catalogGQL.ts index 4470755..357dc09 100644 --- a/node/clients/catalogGQL.ts +++ b/node/clients/catalogGQL.ts @@ -76,7 +76,7 @@ export class CatalogGQL extends AppGraphQLClient { }, }) - public getTranslation = (id: string) => + public getCategoryTranslation = (id: string) => this.graphql.query({ query: GET_TRANSLATION_QUERY, variables: { diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index 8e4af01..fb9ad05 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -35,7 +35,7 @@ const categoryTranslations = async ( const translationsP = [] for (const { id } of ids) { - const promise = catalogGQL.getTranslation(id) + const promise = catalogGQL.getCategoryTranslation(id) translationsP.push(promise) } From b15706d06ab8984485a13ce45e4a790c2546dd26 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 16 Apr 2021 14:28:46 +0200 Subject: [PATCH 12/35] Feat: Add logic to get translations for all products and serve them in a graphql query --- graphql/schema.graphql | 2 +- graphql/types/Product.graphql | 5 +++++ node/clients/catalogGQL.ts | 32 +++++++++++++++++++++++++++++--- node/resolvers/category.ts | 12 +++++++----- node/resolvers/index.ts | 3 ++- node/resolvers/product.ts | 33 ++++++++++++++++++++++++++++++--- node/typings/category.d.ts | 2 +- node/typings/product.d.ts | 10 ++++++++++ 8 files changed, 85 insertions(+), 14 deletions(-) diff --git a/graphql/schema.graphql b/graphql/schema.graphql index 4f63f94..74053a9 100644 --- a/graphql/schema.graphql +++ b/graphql/schema.graphql @@ -1,5 +1,5 @@ type Query { categoryTranslations(locale: String!, active: Boolean): [Category] getCategoriesName: [CategoryName] - productTranslations(locale: String!, categoryId: String!): [String] + productTranslations(locale: String!, categoryId: String!): [Product] } diff --git a/graphql/types/Product.graphql b/graphql/types/Product.graphql index 4f5a776..61c7f79 100644 --- a/graphql/types/Product.graphql +++ b/graphql/types/Product.graphql @@ -1,3 +1,8 @@ type Product { id: String! + name: String + description: String + shortDescription: String + title: String + locale: String } diff --git a/node/clients/catalogGQL.ts b/node/clients/catalogGQL.ts index 357dc09..36dc26a 100644 --- a/node/clients/catalogGQL.ts +++ b/node/clients/catalogGQL.ts @@ -18,7 +18,7 @@ const CATEGORIES_QUERY = ` } ` -const GET_TRANSLATION_QUERY = ` +const GET_CATEGORY_TRANSLATION_QUERY = ` query getTranslation($id:ID!) { category(id: $id) { id @@ -29,6 +29,18 @@ const GET_TRANSLATION_QUERY = ` } ` +const GET_PRODUCT_TRANSLATION_QUERY = ` + query getProductTranslation($identifier: ProductUniqueIdentifier) { + product(identifier: $identifier) { + id + name + description + shortDescription + title + } + } +` + export class CatalogGQL extends AppGraphQLClient { constructor(ctx: IOContext, opts?: InstanceOptions) { super(CATALOG_GRAPHQL_APP, ctx, opts) @@ -77,10 +89,24 @@ export class CatalogGQL extends AppGraphQLClient { }) public getCategoryTranslation = (id: string) => - this.graphql.query({ - query: GET_TRANSLATION_QUERY, + this.graphql.query({ + query: GET_CATEGORY_TRANSLATION_QUERY, variables: { id, }, }) + + public getProductTranslation = (id: string) => + this.graphql.query< + ProductTranslationResponse, + { identifier: { value: string; field: 'id' } } + >({ + query: GET_PRODUCT_TRANSLATION_QUERY, + variables: { + identifier: { + field: 'id', + value: id, + }, + }, + }) } diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index fb9ad05..e5f6822 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -2,18 +2,20 @@ import { statusToError } from '../utils' export const Category = { locale: ( - _root: ResolvedPromise, + _root: ResolvedPromise, _args: unknown, ctx: Context ) => { return ctx.state.locale }, - name: (root: ResolvedPromise) => root.data.category.name, - title: (root: ResolvedPromise) => + name: (root: ResolvedPromise) => + root.data.category.name, + title: (root: ResolvedPromise) => root.data.category.title, - description: (root: ResolvedPromise) => + description: (root: ResolvedPromise) => root.data.category.description, - id: (root: ResolvedPromise) => root.data.category.id, + id: (root: ResolvedPromise) => + root.data.category.id, } const categoryTranslations = async ( diff --git a/node/resolvers/index.ts b/node/resolvers/index.ts index b7c0aeb..87f1fc5 100644 --- a/node/resolvers/index.ts +++ b/node/resolvers/index.ts @@ -1,5 +1,5 @@ import { Category, queries as categoryQueries } from './category' -import { queries as productQueries } from './product' +import { Product, queries as productQueries } from './product' export const queries = { ...categoryQueries, @@ -8,4 +8,5 @@ export const queries = { export const resolvers = { Category, + Product, } diff --git a/node/resolvers/product.ts b/node/resolvers/product.ts index 66af720..6c0973f 100644 --- a/node/resolvers/product.ts +++ b/node/resolvers/product.ts @@ -1,19 +1,46 @@ +export const Product = { + locale: ( + _root: ResolvedPromise, + _args: unknown, + ctx: Context + ) => { + return ctx.state.locale + }, + id: (root: ResolvedPromise) => + root.data.product.id, + name: (root: ResolvedPromise) => + root.data.product.name, + description: (root: ResolvedPromise) => + root.data.product.description, + shortDescription: (root: ResolvedPromise) => + root.data.product.shortDescription, + title: (root: ResolvedPromise) => + root.data.product.title, +} + const productTranslations = async ( _root: unknown, args: { locale: string; categoryId: string }, ctx: Context ) => { const { - clients: { catalog }, + clients: { catalog, catalogGQL }, } = ctx const { locale, categoryId } = args ctx.state.locale = locale - const productIdCollection = catalog.getAllProducts(categoryId) + const productIdCollection = await catalog.getAllProducts(categoryId) + + const productTranslationPromises = [] + + for (const productId of productIdCollection) { + const translationPromise = catalogGQL.getProductTranslation(productId) + productTranslationPromises.push(translationPromise) + } - return productIdCollection + return productTranslationPromises } export const queries = { diff --git a/node/typings/category.d.ts b/node/typings/category.d.ts index e699922..a3f9091 100644 --- a/node/typings/category.d.ts +++ b/node/typings/category.d.ts @@ -7,7 +7,7 @@ interface CategoryResponse { } } -interface TranslationResponse { +interface CategoryTranslationResponse { category: { id: string name: string diff --git a/node/typings/product.d.ts b/node/typings/product.d.ts index 125140e..9073922 100644 --- a/node/typings/product.d.ts +++ b/node/typings/product.d.ts @@ -8,3 +8,13 @@ interface GetProductAndSkuIds { to: number } } + +interface ProductTranslationResponse { + product: { + id: string + name: string + description: string + shortDescription: string + title: string + } +} From 5aae040b411ec416ab97d78d9c4939ec3e6561b3 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 16 Apr 2021 14:31:23 +0200 Subject: [PATCH 13/35] Chore: Increase app memory --- node/service.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/node/service.json b/node/service.json index 21b58b2..8a24fa5 100644 --- a/node/service.json +++ b/node/service.json @@ -1,8 +1,8 @@ { - "memory": 256, + "memory": 1024, "ttl": 10, - "timeout": 5, + "timeout": 10, "minReplicas": 2, - "maxReplicas": 4, + "maxReplicas": 10, "workers": 2 } From 903c8e9ef99271c1d6d5b8bddda2cf27f97fcd4d Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Mon, 19 Apr 2021 12:54:32 +0200 Subject: [PATCH 14/35] Feat: Fetch product translation in the front end based on a category id --- .../ProductTranslation/ProductTranslation.tsx | 41 ++++++++++++++++--- react/graphql/getProductTranslations.gql | 11 +++++ react/typings/catalog.d.ts | 11 +++++ 3 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 react/graphql/getProductTranslations.gql diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index 336b317..0b62976 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -8,7 +8,7 @@ import { ModalDialog, AutocompleteInput, } from 'vtex.styleguide' -import { useQuery } from 'react-apollo' +import { useLazyQuery, useQuery } from 'react-apollo' import { useLocaleSelector } from '../LocaleSelector' import getProductQuery from '../../graphql/getProduct.gql' @@ -17,6 +17,7 @@ import ErrorHandler from '../ErrorHandler' import useCatalogQuery from '../../hooks/useCatalogQuery' import GET_CATEGORIES_NAME from '../../graphql/getCategoriesName.gql' import { filterSearchCategories } from '../../utils' +import GET_PRODUCT_TRANSLATION from '../../graphql/getProductTranslations.gql' const AUTOCOMPLETE_LIST_SIZE = 6 @@ -48,12 +49,28 @@ const ProductTranslation: FC = () => { const { selectedLocale, isXVtexTenant } = useLocaleSelector() - const { data: categoryInfo, loading: loadingCategoryInfo, error } = useQuery< - CategoriesNameAndId - >(GET_CATEGORIES_NAME) + const [fetchProductTranslations, { data, error }] = useLazyQuery< + ProductTranslations, + { locale: string; categoryId: string } + >(GET_PRODUCT_TRANSLATION, { + context: { + headers: { + 'x-vtex-locale': `${selectedLocale}`, + }, + }, + }) + + // eslint-disable-next-line no-console + console.log({ data, error }) + + const { + data: categoryInfo, + loading: loadingCategoryInfo, + error: categoryError, + } = useQuery(GET_CATEGORIES_NAME) // eslint-disable-next-line no-console - console.log({ error }) + console.log({ categoryError }) const listOfOptions = filterSearchCategories({ categoryList: categoryInfo?.getCategoriesName ?? [], @@ -70,6 +87,18 @@ const ProductTranslation: FC = () => { variables: { identifier: { field: 'id', value: entryId } }, }) } + + const downloadProducts = () => { + if (!selectedCategory.value) { + // eslint-disable-next-line no-console + console.log('Select category') + return + } + fetchProductTranslations({ + variables: { locale: selectedLocale, categoryId: selectedCategory.value }, + }) + } + const { id, ...productInfo } = entryInfo?.product || ({} as Product) const hasCategorySelected = !!selectedCategory.label @@ -138,7 +167,7 @@ const ProductTranslation: FC = () => { confirmation={{ label: 'Export Products', // eslint-disable-next-line no-console - onClick: () => console.log('export'), + onClick: downloadProducts, disabled: true, }} onClose={() => { diff --git a/react/graphql/getProductTranslations.gql b/react/graphql/getProductTranslations.gql new file mode 100644 index 0000000..c06deab --- /dev/null +++ b/react/graphql/getProductTranslations.gql @@ -0,0 +1,11 @@ +query getProductTranslations($locale: String!, $categoryId: String!) { + productTranslations(locale: $locale, categoryId: $categoryId) + @context(provider: "vtex.admin-catalog-translation") { + id + name + description + shortDescription + title + locale + } +} diff --git a/react/typings/catalog.d.ts b/react/typings/catalog.d.ts index 069e103..535896c 100644 --- a/react/typings/catalog.d.ts +++ b/react/typings/catalog.d.ts @@ -53,3 +53,14 @@ interface ProductInputTranslation { interface CategoriesNameAndId { getCategoriesName: Array<{ id: string; name: string }> } + +interface ProductTranslations { + productTranslations: { + id: string + name: string + description: string + shortDescription: string + title: string + locale: string + } +} From fb55c86e97e06aab795449133deffc3d0ef3b1ec Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Mon, 19 Apr 2021 13:20:06 +0200 Subject: [PATCH 15/35] WIP: Attempt to slow down the calls and stress the limit without getting 429 Limit: 2k products --- node/index.ts | 1 + node/resolvers/product.ts | 16 +++++++++++++++- node/service.json | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/node/index.ts b/node/index.ts index 16b8b87..40eca34 100644 --- a/node/index.ts +++ b/node/index.ts @@ -22,6 +22,7 @@ export default new Service({ options: { default: { retries: 2, + timeout: 2 * 60000, }, }, }, diff --git a/node/resolvers/product.ts b/node/resolvers/product.ts index 6c0973f..27bc9cd 100644 --- a/node/resolvers/product.ts +++ b/node/resolvers/product.ts @@ -18,6 +18,13 @@ export const Product = { root.data.product.title, } +// const sleep = () => +// new Promise((resolve) => { +// setTimeout(() => { +// resolve('done') +// }, 40) +// }) + const productTranslations = async ( _root: unknown, args: { locale: string; categoryId: string }, @@ -35,11 +42,18 @@ const productTranslations = async ( const productTranslationPromises = [] + let counter = 0 + for (const productId of productIdCollection) { + if (counter === 2000) { + break + } const translationPromise = catalogGQL.getProductTranslation(productId) productTranslationPromises.push(translationPromise) + counter++ + // eslint-disable-next-line no-await-in-loop + // await sleep() } - return productTranslationPromises } diff --git a/node/service.json b/node/service.json index 8a24fa5..9254e2c 100644 --- a/node/service.json +++ b/node/service.json @@ -1,7 +1,7 @@ { "memory": 1024, "ttl": 10, - "timeout": 10, + "timeout": 60, "minReplicas": 2, "maxReplicas": 10, "workers": 2 From f81222cc89d2ca6d5dfa4408d52d72abae4dddb0 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 21 Apr 2021 12:05:44 +0200 Subject: [PATCH 16/35] Feat: Add limite for product size return --- node/resolvers/product.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/node/resolvers/product.ts b/node/resolvers/product.ts index 27bc9cd..ba972b9 100644 --- a/node/resolvers/product.ts +++ b/node/resolvers/product.ts @@ -18,12 +18,7 @@ export const Product = { root.data.product.title, } -// const sleep = () => -// new Promise((resolve) => { -// setTimeout(() => { -// resolve('done') -// }, 40) -// }) +const PRODUCT_LIMIT = 1600 const productTranslations = async ( _root: unknown, @@ -45,14 +40,13 @@ const productTranslations = async ( let counter = 0 for (const productId of productIdCollection) { - if (counter === 2000) { + // Getting a 429 when products list > 2k. Setting threshold a little below it to ensure it works + if (counter === PRODUCT_LIMIT) { break } const translationPromise = catalogGQL.getProductTranslation(productId) productTranslationPromises.push(translationPromise) counter++ - // eslint-disable-next-line no-await-in-loop - // await sleep() } return productTranslationPromises } From 556f24806b3e805646edb74c1f3c52c170410306 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 21 Apr 2021 12:44:19 +0200 Subject: [PATCH 17/35] Feat: Add parse and download process for product info --- .../ProductTranslation/ProductTranslation.tsx | 59 ++++++++++++------- react/typings/catalog.d.ts | 4 +- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index 0b62976..a436433 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -1,4 +1,4 @@ -import React, { FC, SyntheticEvent, useState } from 'react' +import React, { FC, SyntheticEvent, useEffect, useState } from 'react' import { InputSearch, PageBlock, @@ -16,7 +16,7 @@ import ProductForm from './ProductForm' import ErrorHandler from '../ErrorHandler' import useCatalogQuery from '../../hooks/useCatalogQuery' import GET_CATEGORIES_NAME from '../../graphql/getCategoriesName.gql' -import { filterSearchCategories } from '../../utils' +import { filterSearchCategories, parseJSONToXLS } from '../../utils' import GET_PRODUCT_TRANSLATION from '../../graphql/getProductTranslations.gql' const AUTOCOMPLETE_LIST_SIZE = 6 @@ -32,6 +32,7 @@ const ProductTranslation: FC = () => { const [selectedCategory, setSelectedCategory] = useState( {} as AutocompleteValue ) + const [downloading, setDownloading] = useState(false) const { entryInfo, @@ -49,19 +50,22 @@ const ProductTranslation: FC = () => { const { selectedLocale, isXVtexTenant } = useLocaleSelector() - const [fetchProductTranslations, { data, error }] = useLazyQuery< - ProductTranslations, - { locale: string; categoryId: string } - >(GET_PRODUCT_TRANSLATION, { - context: { - headers: { - 'x-vtex-locale': `${selectedLocale}`, + const [ + fetchProductTranslations, + { data: productTranslations, error }, + ] = useLazyQuery( + GET_PRODUCT_TRANSLATION, + { + context: { + headers: { + 'x-vtex-locale': `${selectedLocale}`, + }, }, - }, - }) + } + ) // eslint-disable-next-line no-console - console.log({ data, error }) + console.log({ error }) const { data: categoryInfo, @@ -94,11 +98,31 @@ const ProductTranslation: FC = () => { console.log('Select category') return } + setDownloading(true) fetchProductTranslations({ variables: { locale: selectedLocale, categoryId: selectedCategory.value }, }) } + const handleClose = () => { + setSelectedCategory({} as AutocompleteValue) + setIsExportOpen(false) + setSearchTerm('') + } + + useEffect(() => { + // eslint-disable-next-line vtex/prefer-early-return + if (productTranslations) { + parseJSONToXLS(productTranslations.productTranslations, { + fileName: 'product-data', + sheetName: 'product_data', + }) + + setDownloading(false) + handleClose() + } + }, [productTranslations]) + const { id, ...productInfo } = entryInfo?.product || ({} as Product) const hasCategorySelected = !!selectedCategory.label @@ -157,12 +181,10 @@ const ProductTranslation: FC = () => {
{ - setIsExportOpen(false) - setSearchTerm('') - }, + onClick: handleClose, }} confirmation={{ label: 'Export Products', @@ -170,10 +192,7 @@ const ProductTranslation: FC = () => { onClick: downloadProducts, disabled: true, }} - onClose={() => { - setIsExportOpen(false) - setSearchTerm('') - }} + onClose={handleClose} >

Export Product Data for {selectedLocale}

diff --git a/react/typings/catalog.d.ts b/react/typings/catalog.d.ts index 535896c..3affa54 100644 --- a/react/typings/catalog.d.ts +++ b/react/typings/catalog.d.ts @@ -55,12 +55,12 @@ interface CategoriesNameAndId { } interface ProductTranslations { - productTranslations: { + productTranslations: Array<{ id: string name: string description: string shortDescription: string title: string locale: string - } + }> } From 47443c1ed0daadc00a4a1718361346c4e8e95f98 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 21 Apr 2021 13:26:55 +0200 Subject: [PATCH 18/35] Feat: Add handler to empty category input for product export --- .../ProductTranslation/ProductTranslation.tsx | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index a436433..7b1d035 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -1,4 +1,4 @@ -import React, { FC, SyntheticEvent, useEffect, useState } from 'react' +import React, { FC, SyntheticEvent, useEffect, useState, useRef } from 'react' import { InputSearch, PageBlock, @@ -7,6 +7,7 @@ import { IconDownload, ModalDialog, AutocompleteInput, + Alert, } from 'vtex.styleguide' import { useLazyQuery, useQuery } from 'react-apollo' @@ -33,6 +34,7 @@ const ProductTranslation: FC = () => { {} as AutocompleteValue ) const [downloading, setDownloading] = useState(false) + const [showMissingCatId, setShowMissingCatId] = useState(false) const { entryInfo, @@ -94,8 +96,7 @@ const ProductTranslation: FC = () => { const downloadProducts = () => { if (!selectedCategory.value) { - // eslint-disable-next-line no-console - console.log('Select category') + setShowMissingCatId(true) return } setDownloading(true) @@ -123,6 +124,17 @@ const ProductTranslation: FC = () => { } }, [productTranslations]) + const alertRef = useRef() + + useEffect(() => { + clearTimeout(alertRef.current) + if (showMissingCatId) { + alertRef.current = setTimeout(() => { + setShowMissingCatId(false) + }, 5000) + } + }, [showMissingCatId]) + const { id, ...productInfo } = entryInfo?.product || ({} as Product) const hasCategorySelected = !!selectedCategory.label @@ -188,12 +200,20 @@ const ProductTranslation: FC = () => { }} confirmation={{ label: 'Export Products', - // eslint-disable-next-line no-console onClick: downloadProducts, disabled: true, }} onClose={handleClose} > + {showMissingCatId ? ( +
+
+ setShowMissingCatId(false)}> + Please select a Category Id + +
+
+ ) : null}

Export Product Data for {selectedLocale}

{loadingCategoryInfo ? ( From 2966d7f214c2548d744fec888067a6b4d76a284e Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 21 Apr 2021 17:12:28 +0200 Subject: [PATCH 19/35] Feat: Add error handler to product export --- .../ProductTranslation/ProductTranslation.tsx | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index 7b1d035..641162d 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -35,6 +35,7 @@ const ProductTranslation: FC = () => { ) const [downloading, setDownloading] = useState(false) const [showMissingCatId, setShowMissingCatId] = useState(false) + const [hasError, setHasError] = useState(false) const { entryInfo, @@ -54,7 +55,7 @@ const ProductTranslation: FC = () => { const [ fetchProductTranslations, - { data: productTranslations, error }, + { data: productTranslations, error: prodTranslationError }, ] = useLazyQuery( GET_PRODUCT_TRANSLATION, { @@ -66,18 +67,12 @@ const ProductTranslation: FC = () => { } ) - // eslint-disable-next-line no-console - console.log({ error }) - const { data: categoryInfo, loading: loadingCategoryInfo, error: categoryError, } = useQuery(GET_CATEGORIES_NAME) - // eslint-disable-next-line no-console - console.log({ categoryError }) - const listOfOptions = filterSearchCategories({ categoryList: categoryInfo?.getCategoriesName ?? [], term: searchTerm, @@ -109,6 +104,7 @@ const ProductTranslation: FC = () => { setSelectedCategory({} as AutocompleteValue) setIsExportOpen(false) setSearchTerm('') + setHasError(false) } useEffect(() => { @@ -135,9 +131,15 @@ const ProductTranslation: FC = () => { } }, [showMissingCatId]) - const { id, ...productInfo } = entryInfo?.product || ({} as Product) + useEffect(() => { + // eslint-disable-next-line vtex/prefer-early-return + if (prodTranslationError || categoryError) { + setDownloading(false) + setHasError(true) + } + }, [prodTranslationError, categoryError]) - const hasCategorySelected = !!selectedCategory.label + const { id, ...productInfo } = entryInfo?.product || ({} as Product) return ( <> @@ -240,12 +242,11 @@ const ProductTranslation: FC = () => { loading: listOfOptions.length > AUTOCOMPLETE_LIST_SIZE, }} /> - {hasCategorySelected ? ( -
-

- {`Download product information from category ${selectedCategory.label}`} -

-
+ {hasError ? ( +

+ There was an error exporting products. Please try again in a + few minutes. +

) : null}
)} From 4f9783f1c8708746b4b393cb95b5535d528d5919 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Wed, 21 Apr 2021 17:28:49 +0200 Subject: [PATCH 20/35] Feat: Add disclaimer about product limit per download --- react/components/ProductTranslation/ProductTranslation.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index 641162d..55772bf 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -242,6 +242,9 @@ const ProductTranslation: FC = () => { loading: listOfOptions.length > AUTOCOMPLETE_LIST_SIZE, }} /> +

+ Currently, the app allows to export only 1.600 products +

{hasError ? (

There was an error exporting products. Please try again in a From 5713d60c2a5a85bbefaeec21b0e3c2d3c0ebbf17 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 14:43:24 +0200 Subject: [PATCH 21/35] Feat: Add linkId to category export resolver --- node/clients/catalogGQL.ts | 1 + node/resolvers/category.ts | 2 ++ node/typings/category.d.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/node/clients/catalogGQL.ts b/node/clients/catalogGQL.ts index 36dc26a..f2b47a5 100644 --- a/node/clients/catalogGQL.ts +++ b/node/clients/catalogGQL.ts @@ -25,6 +25,7 @@ const GET_CATEGORY_TRANSLATION_QUERY = ` name title description + linkId } } ` diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index e5f6822..c0a0435 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -16,6 +16,8 @@ export const Category = { root.data.category.description, id: (root: ResolvedPromise) => root.data.category.id, + linkId: (root: ResolvedPromise) => + root.data.category.linkId, } const categoryTranslations = async ( diff --git a/node/typings/category.d.ts b/node/typings/category.d.ts index a3f9091..5d094a8 100644 --- a/node/typings/category.d.ts +++ b/node/typings/category.d.ts @@ -13,6 +13,7 @@ interface CategoryTranslationResponse { name: string title: string description: string + linkId: string } } From 1a150a370734c18897b159a0aaf6699501ab90c7 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 14:48:55 +0200 Subject: [PATCH 22/35] Feat: Add linkId to category translation export --- graphql/types/Category.graphql | 1 + 1 file changed, 1 insertion(+) diff --git a/graphql/types/Category.graphql b/graphql/types/Category.graphql index 6b9cd85..b5fa8f3 100644 --- a/graphql/types/Category.graphql +++ b/graphql/types/Category.graphql @@ -3,6 +3,7 @@ type Category { name: String title: String description: String + linkId: String locale: String } From 1f68394ef5a26f41567271ab2319b22e2263ce1d Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:11:20 +0200 Subject: [PATCH 23/35] Feat: Allow to use category translation in the graphqlIDE --- node/clients/catalogGQL.ts | 20 ++++++++++++++------ node/resolvers/category.ts | 26 +++++++++++--------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/node/clients/catalogGQL.ts b/node/clients/catalogGQL.ts index f2b47a5..a7daf52 100644 --- a/node/clients/catalogGQL.ts +++ b/node/clients/catalogGQL.ts @@ -89,13 +89,21 @@ export class CatalogGQL extends AppGraphQLClient { }, }) - public getCategoryTranslation = (id: string) => - this.graphql.query({ - query: GET_CATEGORY_TRANSLATION_QUERY, - variables: { - id, + public getCategoryTranslation = (id: string, locale: string) => { + return this.graphql.query( + { + query: GET_CATEGORY_TRANSLATION_QUERY, + variables: { + id, + }, }, - }) + { + headers: { + 'x-vtex-locale': `${locale}`, + }, + } + ) + } public getProductTranslation = (id: string) => this.graphql.query< diff --git a/node/resolvers/category.ts b/node/resolvers/category.ts index c0a0435..46a565d 100644 --- a/node/resolvers/category.ts +++ b/node/resolvers/category.ts @@ -1,5 +1,3 @@ -import { statusToError } from '../utils' - export const Category = { locale: ( _root: ResolvedPromise, @@ -29,24 +27,22 @@ const categoryTranslations = async ( clients: { catalogGQL }, } = ctx - const { active } = args - - ctx.state.locale = args.locale + const { active, locale } = args - try { - const ids = await catalogGQL.getCategories(active) + ctx.state.locale = locale - const translationsP = [] + const ids = await catalogGQL.getCategories(active) - for (const { id } of ids) { - const promise = catalogGQL.getCategoryTranslation(id) - translationsP.push(promise) - } + const translationsP = [] - return translationsP - } catch (error) { - return statusToError(error) + for (const { id } of ids) { + const promise = catalogGQL.getCategoryTranslation(id, locale) + translationsP.push(promise) } + + const translations = await Promise.all(translationsP) + + return translations } const getCategoriesName = async ( From e9f8c8bcc24abcba95b0003dbec22ded6a11027e Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:15:54 +0200 Subject: [PATCH 24/35] Feat: Add link Id to the export category file --- react/graphql/getAllCategories.gql | 1 + 1 file changed, 1 insertion(+) diff --git a/react/graphql/getAllCategories.gql b/react/graphql/getAllCategories.gql index 4e95008..e37e51c 100644 --- a/react/graphql/getAllCategories.gql +++ b/react/graphql/getAllCategories.gql @@ -6,5 +6,6 @@ query getAllCategories($locale: String!, $active: Boolean) { title description locale + linkId } } From 1afdd01507d29ec7a07b1f36ef180698b9e41797 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:18:34 +0200 Subject: [PATCH 25/35] Feat: Add locale to product translation file name --- react/components/ProductTranslation/ProductTranslation.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index 55772bf..afc8a74 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -111,14 +111,14 @@ const ProductTranslation: FC = () => { // eslint-disable-next-line vtex/prefer-early-return if (productTranslations) { parseJSONToXLS(productTranslations.productTranslations, { - fileName: 'product-data', + fileName: `product-data-${selectedLocale}`, sheetName: 'product_data', }) setDownloading(false) handleClose() } - }, [productTranslations]) + }, [productTranslations, selectedLocale]) const alertRef = useRef() From 488ad50dbeeea84b2aef51a77c6ef1f75a8efa06 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:22:20 +0200 Subject: [PATCH 26/35] Fix: Allow user to download the same product file in a sequence --- react/components/ProductTranslation/ProductTranslation.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index afc8a74..45801df 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -109,7 +109,7 @@ const ProductTranslation: FC = () => { useEffect(() => { // eslint-disable-next-line vtex/prefer-early-return - if (productTranslations) { + if (productTranslations && downloading) { parseJSONToXLS(productTranslations.productTranslations, { fileName: `product-data-${selectedLocale}`, sheetName: 'product_data', @@ -118,7 +118,7 @@ const ProductTranslation: FC = () => { setDownloading(false) handleClose() } - }, [productTranslations, selectedLocale]) + }, [productTranslations, selectedLocale, downloading]) const alertRef = useRef() From 4b42bfb74219c86807b54e62feae0bf706600321 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:33:56 +0200 Subject: [PATCH 27/35] Feat: Use locale from args to allow graphql ide to return the right values for product translations --- node/clients/catalogGQL.ts | 23 +++++++++++++++-------- node/resolvers/product.ts | 5 ++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/node/clients/catalogGQL.ts b/node/clients/catalogGQL.ts index a7daf52..a9509de 100644 --- a/node/clients/catalogGQL.ts +++ b/node/clients/catalogGQL.ts @@ -105,17 +105,24 @@ export class CatalogGQL extends AppGraphQLClient { ) } - public getProductTranslation = (id: string) => + public getProductTranslation = (id: string, locale: string) => this.graphql.query< ProductTranslationResponse, { identifier: { value: string; field: 'id' } } - >({ - query: GET_PRODUCT_TRANSLATION_QUERY, - variables: { - identifier: { - field: 'id', - value: id, + >( + { + query: GET_PRODUCT_TRANSLATION_QUERY, + variables: { + identifier: { + field: 'id', + value: id, + }, }, }, - }) + { + headers: { + 'x-vtex-locale': `${locale}`, + }, + } + ) } diff --git a/node/resolvers/product.ts b/node/resolvers/product.ts index ba972b9..144460f 100644 --- a/node/resolvers/product.ts +++ b/node/resolvers/product.ts @@ -44,7 +44,10 @@ const productTranslations = async ( if (counter === PRODUCT_LIMIT) { break } - const translationPromise = catalogGQL.getProductTranslation(productId) + const translationPromise = catalogGQL.getProductTranslation( + productId, + locale + ) productTranslationPromises.push(translationPromise) counter++ } From 63e6de6343a222bc63c2645b7150010a25b7d235 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:35:55 +0200 Subject: [PATCH 28/35] Feat: Add link add to product translation resolver --- node/clients/catalogGQL.ts | 1 + node/resolvers/product.ts | 2 ++ node/typings/product.d.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/node/clients/catalogGQL.ts b/node/clients/catalogGQL.ts index a9509de..9232143 100644 --- a/node/clients/catalogGQL.ts +++ b/node/clients/catalogGQL.ts @@ -38,6 +38,7 @@ const GET_PRODUCT_TRANSLATION_QUERY = ` description shortDescription title + linkId } } ` diff --git a/node/resolvers/product.ts b/node/resolvers/product.ts index 144460f..2d2ee75 100644 --- a/node/resolvers/product.ts +++ b/node/resolvers/product.ts @@ -16,6 +16,8 @@ export const Product = { root.data.product.shortDescription, title: (root: ResolvedPromise) => root.data.product.title, + linkId: (root: ResolvedPromise) => + root.data.product.linkId, } const PRODUCT_LIMIT = 1600 diff --git a/node/typings/product.d.ts b/node/typings/product.d.ts index 9073922..e6aeb53 100644 --- a/node/typings/product.d.ts +++ b/node/typings/product.d.ts @@ -16,5 +16,6 @@ interface ProductTranslationResponse { description: string shortDescription: string title: string + linkId: string } } From 83c77f09ee58b9b292242e8e12ebfdda4df412ac Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:39:29 +0200 Subject: [PATCH 29/35] Feat: Add linkId to Product transltion schema --- graphql/types/Product.graphql | 1 + 1 file changed, 1 insertion(+) diff --git a/graphql/types/Product.graphql b/graphql/types/Product.graphql index 61c7f79..a13c8fd 100644 --- a/graphql/types/Product.graphql +++ b/graphql/types/Product.graphql @@ -5,4 +5,5 @@ type Product { shortDescription: String title: String locale: String + linkId: String } From 6b496187ce8d9400bfd589351f562bf0279da238 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:43:08 +0200 Subject: [PATCH 30/35] Fix: Resolve promise inside resolver to allow graphql response with proper errors --- node/resolvers/product.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/node/resolvers/product.ts b/node/resolvers/product.ts index 2d2ee75..74c70b2 100644 --- a/node/resolvers/product.ts +++ b/node/resolvers/product.ts @@ -53,7 +53,10 @@ const productTranslations = async ( productTranslationPromises.push(translationPromise) counter++ } - return productTranslationPromises + + const translations = await Promise.all(productTranslationPromises) + + return translations } export const queries = { From 099a9e52e51e7a06f23149aa3e8533526658d87c Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Thu, 22 Apr 2021 16:48:53 +0200 Subject: [PATCH 31/35] Feat: Add linkId to product etranslation export file --- react/graphql/getProductTranslations.gql | 1 + 1 file changed, 1 insertion(+) diff --git a/react/graphql/getProductTranslations.gql b/react/graphql/getProductTranslations.gql index c06deab..7306a79 100644 --- a/react/graphql/getProductTranslations.gql +++ b/react/graphql/getProductTranslations.gql @@ -6,6 +6,7 @@ query getProductTranslations($locale: String!, $categoryId: String!) { description shortDescription title + linkId locale } } From e8fc527387fe14703461e55532dc3e7b5876343f Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 23 Apr 2021 12:13:06 +0200 Subject: [PATCH 32/35] Refactor: Change limit message for product export --- react/components/ProductTranslation/ProductTranslation.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index 45801df..ecaac40 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -243,7 +243,8 @@ const ProductTranslation: FC = () => { }} />

- Currently, the app allows to export only 1.600 products + Currently, the app allows to export 1.600 products every 3 + minutes

{hasError ? (

From 9cc8ae59f6c26d87009d8be70a1c1112a86f488e Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 23 Apr 2021 12:35:09 +0200 Subject: [PATCH 33/35] Feat: Add category id to product export file --- react/components/ProductTranslation/ProductTranslation.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/react/components/ProductTranslation/ProductTranslation.tsx b/react/components/ProductTranslation/ProductTranslation.tsx index ecaac40..3163a58 100644 --- a/react/components/ProductTranslation/ProductTranslation.tsx +++ b/react/components/ProductTranslation/ProductTranslation.tsx @@ -111,14 +111,14 @@ const ProductTranslation: FC = () => { // eslint-disable-next-line vtex/prefer-early-return if (productTranslations && downloading) { parseJSONToXLS(productTranslations.productTranslations, { - fileName: `product-data-${selectedLocale}`, + fileName: `category-${selectedCategory.value}-product-data-${selectedLocale}`, sheetName: 'product_data', }) setDownloading(false) handleClose() } - }, [productTranslations, selectedLocale, downloading]) + }, [productTranslations, selectedLocale, downloading, selectedCategory]) const alertRef = useRef() From 6933d2d1072e513305dbcde5331ba8d5c1030556 Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 23 Apr 2021 15:27:57 +0200 Subject: [PATCH 34/35] Docs: Update README with Export Category --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 5d91411..9691374 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,7 +16,7 @@ There are two different pages for `Category` and `Product` translations. Both au From this binding list, the first one is always the `X-Vtex-Tenant` or the default language, for this option the details cannot be translated, to modify these values, the changes should be made inside your store's catalog. For all the others, it's possible to edit the content by category and by product. -It's also possible to export all current translations for `Categories`. Inside a binding different than the `X-Vtex-Tenant`, a button called `export` allows user to download the translations for that binding. +It's also possible to export all current translations for `Categories` and `Products`. Inside a binding different than the `X-Vtex-Tenant`, a button called `export` allows user to download the translations for that binding. Curently, it's only possible to export 1.600 products for a given category every 3 minutes. --- ## Usage From a94c9567cd88cd78c30d89dcc518ef04e72b1c3b Mon Sep 17 00:00:00 2001 From: Filadelfo Date: Fri, 23 Apr 2021 15:32:33 +0200 Subject: [PATCH 35/35] Docs: Add and update Changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dc7d0cc --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added +- Export all `Categories` translations in batch +- Export `Products` for a given category in batch - Limit of 1.600 products