From 673a3e7fe100ded6af53379717738d8ae95ac280 Mon Sep 17 00:00:00 2001 From: Emanuel Ramos <78380713+Emanuel-Ramos@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:00:11 -0300 Subject: [PATCH 1/4] feat: adding checkout url with app admin settings --- .vscode/settings.json | 2 +- docs/README.md | 6 +----- manifest.json | 18 +++++++++++++++--- node/package.json | 2 +- node/yarn.lock | 10 +++++----- react/AutocompleteBlock.tsx | 8 ++++++-- react/CategoryBlock.tsx | 7 +++++-- react/TextAreaBlock.tsx | 7 ++++--- react/UploadBlock.tsx | 8 ++++++-- react/queries/getSettings.gql | 6 ++++++ react/utils/getAppSettings.ts | 32 ++++++++++++++++++++++++++++++++ 11 files changed, 82 insertions(+), 24 deletions(-) create mode 100644 react/queries/getSettings.gql create mode 100644 react/utils/getAppSettings.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 5767b748..51db7632 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "eslint.validate": [ "javascript", diff --git a/docs/README.md b/docs/README.md index 5bce353c..47bce878 100644 --- a/docs/README.md +++ b/docs/README.md @@ -101,7 +101,6 @@ To use these blocks, follow the instructions below. "componentOnly": false, "text": "Copy/Paste Skus", "description": "[SKU Reference ID],[Quantity]", - "checkoutUrl:": "/checkout#/cart" } }, @@ -118,7 +117,6 @@ To use these blocks, follow the instructions below. "description": "Upload a Spreadsheet with two columns (SKU, Quantity) to bulk order", "downloadText": "Click here to download a spreadsheet model", "alwaysShowAddToCart:": true, - "checkoutUrl:": "/checkout#/cart" } }, @@ -133,7 +131,6 @@ To use these blocks, follow the instructions below. "componentOnly": false, "text": "One by One", "description": "Type the product name, select, enter quantity, add to the cart", - "checkoutUrl:": "/checkout#/cart" } }, @@ -148,7 +145,6 @@ To use these blocks, follow the instructions below. "componentOnly": false, "text": "Categories", "description": "Add products directly from their categories", - "checkoutUrl:": "/checkout#/cart" } } } @@ -163,7 +159,7 @@ All blocks exported by the `quickorder` app share the same props: | `text` | `string` | Component title. | `undefined` | | `description` | `string` | Component description. It should be used to explain users how to properly bulk order using the given component. | `undefined` | | `componentOnly` | `boolean` | If `true`, only the component will be loaded, removing the `text` and `description` column. | `false` | -| `checkoutUrl` | `string` | Checkout cart URL for redirect | `/checkout#/cart` | + Especially, the `quickorder-upload` block also can use the following prop: diff --git a/manifest.json b/manifest.json index 79d42737..4becf86b 100644 --- a/manifest.json +++ b/manifest.json @@ -22,7 +22,6 @@ "vtex.flex-layout": "0.x", "vtex.rich-text": "0.x", "vtex.checkout": "0.x", - "vtex.render-runtime": "7.x", "vtex.store": "2.x", "vtex.styleguide": "9.x", "vtex.store-graphql": "2.x", @@ -35,7 +34,8 @@ "vtex.pixel-manager": "1.x", "vtex.store-resources": "0.x", "vtex.css-handles": "0.x", - "vtex.store-icons": "0.x" + "vtex.store-icons": "0.x", + "vtex.render-runtime": "8.x" }, "policies": [ { @@ -82,7 +82,19 @@ } } ], - "settingsSchema": {}, + "settingsSchema": { + "title": "Quickorder settings", + "type": "object", + "access": "public", + "properties": { + "checkoutUrl": { + "title": "URL", + "type": "string", + "description": "Checkout redirect href", + "default": "/checkout#/cart" + } + } + }, "billingOptions": { "termsURL": "https://compliance.vtex.com/gdpr/policies/vtex-privacy-policy", "support": { diff --git a/node/package.json b/node/package.json index 5a1fc760..17390f90 100644 --- a/node/package.json +++ b/node/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@gocommerce/utils": "^0.7.3", - "@vtex/api": "6.46.1", + "@vtex/api": "6.48.0", "atob": "^2.1.2", "axios": "^0.19.0", "camelcase": "^5.0.0", diff --git a/node/yarn.lock b/node/yarn.lock index 1ad2e985..adcd5a7c 100644 --- a/node/yarn.lock +++ b/node/yarn.lock @@ -1863,10 +1863,10 @@ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d" integrity sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg== -"@vtex/api@6.46.1": - version "6.46.1" - resolved "https://registry.yarnpkg.com/@vtex/api/-/api-6.46.1.tgz#55a8755ae48f5400e7f1ed1921cd547950bb7a2a" - integrity sha512-geoxVvyWoQpOQ70Zmx3M8SBkRoGOS/bp9Gy26M+iCue63jofVSwmFz1zf66EaHA1PKOJNRgQPFwY+oeDE1U2lQ== +"@vtex/api@6.48.0": + version "6.48.0" + resolved "https://registry.yarnpkg.com/@vtex/api/-/api-6.48.0.tgz#67f9f11d197d543d4f854b057d31a8d6999241e9" + integrity sha512-mAdT7gbV0/BwiuqUkNH1E7KZqTUczT5NbBBZcPJq5kmTr73PUjbR9wh//70ryJo2EAdHlqIgqgwsCVpozenlhg== dependencies: "@types/koa" "^2.11.0" "@types/koa-compose" "^3.2.3" @@ -6071,7 +6071,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -stats-lite@vtex/node-stats-lite#dist: +"stats-lite@github:vtex/node-stats-lite#dist": version "2.2.0" resolved "https://codeload.github.com/vtex/node-stats-lite/tar.gz/1b0d39cc41ef7aaecfd541191f877887a2044797" dependencies: diff --git a/react/AutocompleteBlock.tsx b/react/AutocompleteBlock.tsx index 6945f44a..221d29b4 100644 --- a/react/AutocompleteBlock.tsx +++ b/react/AutocompleteBlock.tsx @@ -17,14 +17,15 @@ import { useApolloClient, useMutation } from 'react-apollo' import { autocompleteMessages as messages } from './utils/messages' import QuickOrderAutocomplete from './components/QuickOrderAutocomplete' import productQuery from './queries/product.gql' +import getAppSettings from './utils/getAppSettings' + import './global.css' const AutocompleteBlock: FunctionComponent = ({ text, description, componentOnly, - intl, - checkoutUrl + intl }) => { const client = useApolloClient() const { showToast } = useContext(ToastContext) @@ -34,6 +35,9 @@ const AutocompleteBlock: FunctionComponent = ({ unitMultiplier: 1, }) + const appSettings = getAppSettings() + const checkoutUrl = appSettings?.checkoutUrl ?? "/checkout#/cart" + const [addToCart, { error, loading }] = useMutation< { addToCart: OrderFormType }, { items: [] } diff --git a/react/CategoryBlock.tsx b/react/CategoryBlock.tsx index 68e345a5..059a78c3 100644 --- a/react/CategoryBlock.tsx +++ b/react/CategoryBlock.tsx @@ -24,14 +24,14 @@ import { graphql, useApolloClient, useMutation } from 'react-apollo' import { categoryMessages as messages } from './utils/messages' import getCategories from './queries/categoriesQuery.gql' import SearchByCategory from './queries/productsByCategory.gql' - +import getAppSettings from './utils/getAppSettings' const CategoryBlock: FunctionComponent = ({ text, description, componentOnly, intl, data: { categories }, - checkoutUrl + }) => { const [state, setState] = useState({ categoryItems: {}, @@ -40,6 +40,9 @@ const CategoryBlock: FunctionComponent = ({ // All the items with their respective units unitMultiplierList: {}, }) + + const appSettings = getAppSettings() + const checkoutUrl = appSettings?.checkoutUrl ?? "/checkout#/cart" const { showToast } = useContext(ToastContext) diff --git a/react/TextAreaBlock.tsx b/react/TextAreaBlock.tsx index cee37bf6..e462d69e 100644 --- a/react/TextAreaBlock.tsx +++ b/react/TextAreaBlock.tsx @@ -16,7 +16,7 @@ import { usePixel } from 'vtex.pixel-manager/PixelContext' import { categoryMessages as messages } from './utils/messages' import ReviewBlock from './components/ReviewBlock' import { ParseText, GetText } from './utils' - +import getAppSettings from './utils/getAppSettings' interface ItemType { id: string quantity: number @@ -24,14 +24,15 @@ interface ItemType { const TextAreaBlock: FunctionComponent< TextAreaBlockInterface & WrappedComponentProps -> = ({ intl, value, text, hiddenColumns, description, componentOnly, checkoutUrl }: any) => { +> = ({ intl, value, text, hiddenColumns, description, componentOnly }: any) => { const [state, setState] = useState({ reviewState: false, showAddToCart: null, textAreaValue: value || '', reviewItems: [], }) - + const appSettings = getAppSettings() + const checkoutUrl = appSettings?.checkoutUrl ?? "/checkout#/cart" const [refidLoading, setRefIdLoading] = useState() const { textAreaValue, reviewItems, reviewState, showAddToCart } = state diff --git a/react/UploadBlock.tsx b/react/UploadBlock.tsx index 0ac88907..28864dd5 100644 --- a/react/UploadBlock.tsx +++ b/react/UploadBlock.tsx @@ -18,7 +18,8 @@ import { categoryMessages as messages } from './utils/messages' import { ParseText, GetText } from './utils' import ReviewBlock from './components/ReviewBlock' import { DropzoneIcon } from './assets/DropZoneIcon' - +import getAppSettings from './utils/getAppSettings' + interface ItemType { id: string quantity: number @@ -34,7 +35,7 @@ const UploadBlock: FunctionComponent< componentOnly, intl, alwaysShowAddToCart = true, - checkoutUrl + }: any) => { let productsArray: any = [] const [state, setState] = useState({ @@ -43,6 +44,9 @@ const UploadBlock: FunctionComponent< showAddToCart: false, }) + const appSettings = getAppSettings() + const checkoutUrl = appSettings?.checkoutUrl ?? "/checkout#/cart" + const [showValidateButton, setShowValidateButton] = useState(false) const [refidLoading, setRefIdLoading] = useState() diff --git a/react/queries/getSettings.gql b/react/queries/getSettings.gql new file mode 100644 index 00000000..1ccbdc33 --- /dev/null +++ b/react/queries/getSettings.gql @@ -0,0 +1,6 @@ +query getSettings($version: String!) { + publicSettingsForApp(app: "vtex.quickorder", version: $version) + @context(provider: "vtex.apps-graphql") { + message + } +} diff --git a/react/utils/getAppSettings.ts b/react/utils/getAppSettings.ts new file mode 100644 index 00000000..8742277e --- /dev/null +++ b/react/utils/getAppSettings.ts @@ -0,0 +1,32 @@ +import { useQuery } from 'react-apollo' +import AppSettings from '../queries/getSettings.gql' +import { useEffect, useState } from 'react' +import { pathOr } from 'ramda' + +const useAppSettings = () => { + const { data: appSettingsData } = useQuery(AppSettings, { + variables: { + version: process.env.VTEX_APP_VERSION, + }, + ssr: false, + }) + + const [appSettings, setAppSettings] = useState({ checkoutUrl: "/checkout#/cart" }) + + useEffect(() => { + if (appSettingsData) { + const settingsString = pathOr(`""`, ['publicSettingsForApp', 'message'], appSettingsData) + + try { + const parsedAppSettings = JSON.parse(settingsString) + setAppSettings(parsedAppSettings) + } catch (error) { + console.error("Error parsing app settings:", error) + } + } + }, [appSettingsData]) + + return appSettings +} + +export default useAppSettings From 24ef77a43c748c8d674b69e47fbe0e18672a0f97 Mon Sep 17 00:00:00 2001 From: Emanuel Ramos <78380713+Emanuel-Ramos@users.noreply.github.com> Date: Thu, 31 Oct 2024 11:44:38 -0300 Subject: [PATCH 2/4] fix: changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2218a9f9..6688b47f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ 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] +## [3.15.10] - 2024-10-02 +### Changed + +- Changed the checkoutUrl prop to admin app settings ## [3.15.9] - 2024-10-02 From ed71c8cc17dde41ee3ec8af28e5267819aab92fa Mon Sep 17 00:00:00 2001 From: Wender Date: Thu, 31 Oct 2024 11:24:18 -0400 Subject: [PATCH 3/4] Update CHANGELOG.md --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6688b47f..061f5dc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,7 @@ 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] -## [3.15.10] - 2024-10-02 -### Changed +### Added - Changed the checkoutUrl prop to admin app settings From c039493c615037955895c48b7c6ca1acfe5dc803 Mon Sep 17 00:00:00 2001 From: Everton Ataide Date: Thu, 7 Nov 2024 09:26:02 -0300 Subject: [PATCH 4/4] Fix lint --- react/AutocompleteBlock.tsx | 6 ++-- react/CategoryBlock.tsx | 6 ++-- react/TextAreaBlock.tsx | 4 ++- react/UploadBlock.tsx | 10 +++--- react/utils/getAppSettings.ts | 57 ++++++++++++++++++++--------------- 5 files changed, 48 insertions(+), 35 deletions(-) diff --git a/react/AutocompleteBlock.tsx b/react/AutocompleteBlock.tsx index 86d19aa2..6e8d8176 100644 --- a/react/AutocompleteBlock.tsx +++ b/react/AutocompleteBlock.tsx @@ -25,7 +25,7 @@ const AutocompleteBlock: FunctionComponent = ({ text, description, componentOnly, - intl + intl, }) => { const client = useApolloClient() const { showToast } = useContext(ToastContext) @@ -36,8 +36,8 @@ const AutocompleteBlock: FunctionComponent = ({ }) const appSettings = getAppSettings() - const checkoutUrl = appSettings?.checkoutUrl ?? "/checkout#/cart" - + const checkoutUrl = appSettings?.checkoutUrl ?? '/checkout#/cart' + const [addToCart, { error, loading }] = useMutation< { addToCart: OrderFormType }, { items: [] } diff --git a/react/CategoryBlock.tsx b/react/CategoryBlock.tsx index b00e524b..72bd9b89 100644 --- a/react/CategoryBlock.tsx +++ b/react/CategoryBlock.tsx @@ -25,13 +25,13 @@ import { categoryMessages as messages } from './utils/messages' import getCategories from './queries/categoriesQuery.gql' import SearchByCategory from './queries/productsByCategory.gql' import getAppSettings from './utils/getAppSettings' + const CategoryBlock: FunctionComponent = ({ text, description, componentOnly, intl, data: { categories }, - }) => { const [state, setState] = useState({ categoryItems: {}, @@ -40,9 +40,9 @@ const CategoryBlock: FunctionComponent = ({ // All the items with their respective units unitMultiplierList: {}, }) - + const appSettings = getAppSettings() - const checkoutUrl = appSettings?.checkoutUrl ?? "/checkout#/cart" + const checkoutUrl = appSettings?.checkoutUrl ?? '/checkout#/cart' const { showToast } = useContext(ToastContext) diff --git a/react/TextAreaBlock.tsx b/react/TextAreaBlock.tsx index b52191a7..a949467e 100644 --- a/react/TextAreaBlock.tsx +++ b/react/TextAreaBlock.tsx @@ -17,6 +17,7 @@ import { categoryMessages as messages } from './utils/messages' import ReviewBlock from './components/ReviewBlock' import { ParseText, GetText } from './utils' import getAppSettings from './utils/getAppSettings' + interface ItemType { id: string quantity: number @@ -31,8 +32,9 @@ const TextAreaBlock: FunctionComponent< textAreaValue: value || '', reviewItems: [], }) + const appSettings = getAppSettings() - const checkoutUrl = appSettings?.checkoutUrl ?? "/checkout#/cart" + const checkoutUrl = appSettings?.checkoutUrl ?? '/checkout#/cart' const [refidLoading, setRefIdLoading] = useState() const { textAreaValue, reviewItems, reviewState, showAddToCart } = state diff --git a/react/UploadBlock.tsx b/react/UploadBlock.tsx index 28864dd5..ab1173e5 100644 --- a/react/UploadBlock.tsx +++ b/react/UploadBlock.tsx @@ -19,7 +19,7 @@ import { ParseText, GetText } from './utils' import ReviewBlock from './components/ReviewBlock' import { DropzoneIcon } from './assets/DropZoneIcon' import getAppSettings from './utils/getAppSettings' - + interface ItemType { id: string quantity: number @@ -35,7 +35,6 @@ const UploadBlock: FunctionComponent< componentOnly, intl, alwaysShowAddToCart = true, - }: any) => { let productsArray: any = [] const [state, setState] = useState({ @@ -45,7 +44,7 @@ const UploadBlock: FunctionComponent< }) const appSettings = getAppSettings() - const checkoutUrl = appSettings?.checkoutUrl ?? "/checkout#/cart" + const checkoutUrl = appSettings?.checkoutUrl ?? '/checkout#/cart' const [showValidateButton, setShowValidateButton] = useState(false) @@ -89,7 +88,10 @@ const UploadBlock: FunctionComponent< const action = success ? { label: translateMessage(messages.seeCart), - href: typeof checkoutUrl === "string" && checkoutUrl !== "" ? checkoutUrl : '/checkout/#/cart', + href: + typeof checkoutUrl === 'string' && checkoutUrl !== '' + ? checkoutUrl + : '/checkout/#/cart', } : undefined diff --git a/react/utils/getAppSettings.ts b/react/utils/getAppSettings.ts index 8742277e..1cff9fae 100644 --- a/react/utils/getAppSettings.ts +++ b/react/utils/getAppSettings.ts @@ -1,32 +1,41 @@ import { useQuery } from 'react-apollo' -import AppSettings from '../queries/getSettings.gql' import { useEffect, useState } from 'react' +/* eslint-disable no-restricted-imports */ import { pathOr } from 'ramda' +import AppSettings from '../queries/getSettings.gql' + const useAppSettings = () => { - const { data: appSettingsData } = useQuery(AppSettings, { - variables: { - version: process.env.VTEX_APP_VERSION, - }, - ssr: false, - }) - - const [appSettings, setAppSettings] = useState({ checkoutUrl: "/checkout#/cart" }) - - useEffect(() => { - if (appSettingsData) { - const settingsString = pathOr(`""`, ['publicSettingsForApp', 'message'], appSettingsData) - - try { - const parsedAppSettings = JSON.parse(settingsString) - setAppSettings(parsedAppSettings) - } catch (error) { - console.error("Error parsing app settings:", error) - } - } - }, [appSettingsData]) - - return appSettings + const { data: appSettingsData } = useQuery(AppSettings, { + variables: { + version: process.env.VTEX_APP_VERSION, + }, + ssr: false, + }) + + const [appSettings, setAppSettings] = useState({ + checkoutUrl: '/checkout#/cart', + }) + + useEffect(() => { + if (appSettingsData) { + const settingsString = pathOr( + `""`, + ['publicSettingsForApp', 'message'], + appSettingsData + ) + + try { + const parsedAppSettings = JSON.parse(settingsString) + + setAppSettings(parsedAppSettings) + } catch (error) { + console.error('Error parsing app settings:', error) + } + } + }, [appSettingsData]) + + return appSettings } export default useAppSettings