From 062e07454b80dc977c09416113d69ae6493410d2 Mon Sep 17 00:00:00 2001 From: polishq Date: Thu, 26 May 2022 17:11:39 -0400 Subject: [PATCH 1/2] [B2BORG-114] Autocomplete organization selector --- CHANGELOG.md | 10 + messages/context.json | 1 + messages/en.json | 3 +- .../components/OrganizationsAutocomplete.tsx | 101 +++++ react/components/customers-admin.tsx | 413 ++++++++++-------- react/mutations/deleteUser.gql | 8 + react/package.json | 13 +- react/queries/getOrganization.graphql | 19 + react/typings/graphql.d.ts | 13 + react/yarn.lock | 324 ++++++++++++-- 10 files changed, 680 insertions(+), 225 deletions(-) create mode 100644 react/components/OrganizationsAutocomplete.tsx create mode 100644 react/mutations/deleteUser.gql create mode 100644 react/queries/getOrganization.graphql create mode 100644 react/typings/graphql.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b618284..562737c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added + +- Autocomplete input to select an organization +- Button to remove a user's B2B info +- Heading and border for B2B info section + ## [0.0.8] - 2022-02-18 ### Added @@ -18,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.0.7] - 2022-01-10 ### Removed + - Can Impersonate - Console logs @@ -26,10 +33,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.0.5] - 2021-12-28 ### Added + - Allow cleanup Organization selection ### Fixed + - Cost Center not cleaning up after organization is changed + ## [0.0.4] - 2021-11-10 ## [0.0.3] - 2021-11-03 diff --git a/messages/context.json b/messages/context.json index a945be5..130d85d 100644 --- a/messages/context.json +++ b/messages/context.json @@ -1,4 +1,5 @@ { + "admin/storefront-permissions.b2bInfo.title": "admin/storefront-permissions.b2bInfo.title", "admin/storefront-permissions.button.cancel": "admin/storefront-permissions.button.cancel", "admin/storefront-permissions.button.delete": "admin/storefront-permissions.button.delete", "admin/storefront-permissions.button.save": "admin/storefront-permissions.button.save", diff --git a/messages/en.json b/messages/en.json index 1539264..c545388 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1,6 +1,7 @@ { + "admin/storefront-permissions.b2bInfo.title": "B2B Information", "admin/storefront-permissions.button.cancel": "Cancel", - "admin/storefront-permissions.button.delete": "Delete", + "admin/storefront-permissions.button.delete": "Remove B2B Info", "admin/storefront-permissions.button.save": "Save", "admin/storefront-permissions.description": "Roles and User management", "admin/storefront-permissions.navigation.keywords": "b2b, Roles, Profiles", diff --git a/react/components/OrganizationsAutocomplete.tsx b/react/components/OrganizationsAutocomplete.tsx new file mode 100644 index 0000000..9146c8f --- /dev/null +++ b/react/components/OrganizationsAutocomplete.tsx @@ -0,0 +1,101 @@ +import React, { useEffect, useState } from 'react' +import { useQuery } from 'react-apollo' +import { AutocompleteInput } from 'vtex.styleguide' + +import GET_ORGANIZATIONS from '../queries/listOrganizations.gql' +import GET_ORGANIZATION_BY_ID from '../queries/getOrganization.graphql' + +const initialState = { + status: ['active', 'on-hold', 'inactive'], + search: '', + page: 1, + pageSize: 25, + sortOrder: 'ASC', + sortedBy: 'name', +} + +interface Props { + onChange: (value: { value: string | null; label: string }) => void + organizationId: string +} + +const OrganizationsAutocomplete = ({ onChange, organizationId }: Props) => { + const [term, setTerm] = useState('') + const [hasChanged, setHasChanged] = useState(false) + const [values, setValues] = useState([] as any) + const { data, loading, refetch } = useQuery(GET_ORGANIZATIONS, { + variables: initialState, + ssr: false, + notifyOnNetworkStatusChange: true, + }) + + const { data: organization } = useQuery(GET_ORGANIZATION_BY_ID, { + variables: { id: organizationId }, + ssr: false, + fetchPolicy: 'network-only', + notifyOnNetworkStatusChange: true, + skip: !organizationId, + }) + + const options = { + onSelect: (value: any) => onChange(value), + loading, + value: values, + } + + const onClear = () => { + if (!hasChanged) return + setTerm('') + onChange({ value: null, label: '' }) + } + + useEffect(() => { + if (!organization) { + return + } + + const { name, id } = organization.getOrganizationById + + setTerm(name) + setHasChanged(true) + onChange({ value: id, label: name }) + }, [organization]) + + useEffect(() => { + if (data?.getOrganizations?.data) { + setValues( + data.getOrganizations.data.map((item: any) => { + return { + value: item.id, + label: item.name, + } + }) + ) + } + }, [data]) + + useEffect(() => { + if (term && term.length > 2) { + setHasChanged(true) + refetch({ + ...initialState, + search: term, + }) + } else if (term === '') { + onClear() + } + }, [term]) + + const input = { + onChange: (_term: string) => { + setTerm(_term) + }, + onClear, + placeholder: 'Search organization...', + value: term, + } + + return +} + +export default OrganizationsAutocomplete diff --git a/react/components/customers-admin.tsx b/react/components/customers-admin.tsx index 5e4327f..7b6879d 100644 --- a/react/components/customers-admin.tsx +++ b/react/components/customers-admin.tsx @@ -1,26 +1,22 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import type { FC } from 'react' import React, { useState } from 'react' -import type { WrappedComponentProps } from 'react-intl' -import { injectIntl, defineMessages } from 'react-intl' +import { useIntl, defineMessages } from 'react-intl' import { useQuery, useMutation, useLazyQuery } from 'react-apollo' -import { - Button, - Dropdown, - Alert, - ButtonWithIcon, - IconClear, -} from 'vtex.styleguide' +import { Card, Button, Dropdown, Alert, Spinner } from 'vtex.styleguide' +import OrganizationsAutocomplete from './OrganizationsAutocomplete' import GET_USER from '../queries/getUser.gql' import GET_ROLES from '../queries/ListRoles.gql' -import GET_ORG from '../queries/listOrganizations.gql' import GET_COST from '../queries/costCentersByOrg.gql' import SAVE_USER from '../mutations/saveUser.gql' - -const remove = +import DELETE_USER from '../mutations/deleteUser.gql' const messages = defineMessages({ + b2bInfo: { + id: 'admin/storefront-permissions.b2bInfo.title', + defaultMessage: 'B2B Information', + }, role: { id: 'admin/storefront-permissions.tab.roles.name.label', defaultMessage: 'Role', @@ -57,6 +53,10 @@ const messages = defineMessages({ id: 'admin/storefront-permissions.button.save', defaultMessage: 'Save', }, + delete: { + id: 'admin/storefront-permissions.button.delete', + defaultMessage: 'Remove B2B Info', + }, success: { id: 'admin/storefront-permissions.tab.users.success', defaultMessage: 'B2B info saved', @@ -73,39 +73,60 @@ const messages = defineMessages({ }) const parseOptions = (options: any) => { - const ret = - options?.data.map((org: any) => { + return ( + options?.data?.map((orgOrCostCenter: any) => { return { - value: org.id, - label: org.name, + value: orgOrCostCenter.id, + label: orgOrCostCenter.name, } }) ?? [] + ) +} - return ret +const initialState = { + message: null, + id: null, + roleId: null, + orgId: null, + costId: null, + userId: null, + clId: null, + name: null, + email: null, + canImpersonate: false, } -const UserEdit: FC = (props: any) => { - const { intl, id, showName, showEmail, showCancel, onCancel, onSave } = props +const UserEdit: FC = (props: any) => { + const { formatMessage } = useIntl() + const { + id, + name = null, + email = null, + showName, + showEmail, + showCancel, + onCancel, + onSave, + } = props const [state, setState] = useState({ - message: null, - id: null, - roleId: null, - orgId: null, - costId: null, - userId: null, + ...initialState, clId: id, - name: props.name ?? null, - email: props.email ?? null, - canImpersonate: false, + name, + email, }) - const { loading } = useQuery(GET_USER, { + const { + data: userData, + loading, + refetch, + } = useQuery(GET_USER, { skip: !id, variables: { id, }, fetchPolicy: 'network-only', + notifyOnNetworkStatusChange: true, onCompleted: (res: any) => { setState({ ...state, @@ -114,40 +135,24 @@ const UserEdit: FC = (props: any) => { }, }) - const { data: orgData } = useQuery(GET_ORG, { - variables: { - pageSize: 999, - }, - }) + const { loading: loadingRoles, data: dataRoles } = useQuery(GET_ROLES) - const [saveUser, { loading: saveUserLoading }] = useMutation(SAVE_USER, { - onCompleted(res: any) { - if (onSave) { - onSave() - } + const [saveUser, { loading: saveUserLoading }] = useMutation(SAVE_USER) - setState({ - ...state, - id: state.id ?? res?.saveUser?.id, - message: 'success', - }) - }, - - onError: () => { - setState({ - ...state, - message: 'error', - }) - }, - }) - - const { loading: loadingRoles, data: dataRoles } = useQuery(GET_ROLES) + const [deleteUser, { loading: deleteUserLoading }] = useMutation(DELETE_USER) const [getCostCenter, { data: dataCostCenter, called }] = useLazyQuery(GET_COST) + const onMutationError = () => { + setState({ + ...state, + message: 'error', + }) + } + const handleSaveUser = () => { - const variables: any = { + const variables = { id: state.id, clId: state.clId, userId: state.userId, @@ -159,26 +164,62 @@ const UserEdit: FC = (props: any) => { canImpersonate: state.canImpersonate, } - if (state.id) { - variables.id = state.id - } - saveUser({ variables, }) + .then((res) => { + if (onSave) { + onSave() + } + + setState({ + ...state, + id: state.id ?? res?.data?.saveUser?.id, + message: 'success', + }) + }) + .catch(onMutationError) } - const handleClear = () => { - setState({ - ...state, - orgId: null, - costId: null, + const handleDeleteUser = () => { + const variables = { + id: state.id, + userId: state.userId, + email: state.email, + } + + deleteUser({ + variables, }) + .then((res) => { + if (onSave) { + onSave() + } + + setState({ + ...state, + roleId: null, + orgId: null, + costId: null, + id: state.id ?? res?.data?.deleteUser?.id, + message: 'success', + }) + refetch() + }) + .catch(onMutationError) } - const optionsOrg = parseOptions(orgData?.getOrganizations) ?? [] - const optionsCost = - parseOptions(dataCostCenter?.getCostCentersByOrganizationId) ?? [] + const optionsCost = parseOptions( + dataCostCenter?.getCostCentersByOrganizationId + ) + + const roleOptions = + dataRoles?.listRoles?.map((role: any) => { + return { + value: role.id, + label: role.name, + } + }) ?? [] if (state.costId && !called) { getCostCenter({ @@ -188,126 +229,152 @@ const UserEdit: FC = (props: any) => { }) } + if (loading || loadingRoles) { + return ( +
+ +
+ ) + } + return (
- {showName &&
{state.name}
} - {showEmail &&
{state.email}
} -
- { - return { - value: role.id, - label: role.name, - } - }) ?? [] - } - value={state.roleId} - onChange={(_: any, v: any) => { - setState({ ...state, roleId: v }) - }} - /> -
+ +
+ {formatMessage(messages.b2bInfo)} +
+ {showName &&
{state.name}
} + {showEmail &&
{state.email}
} + {roleOptions.length > 1 && ( +
+ { + setState({ + ...state, + roleId: v, + }) + }} + /> +
+ )} - {dataRoles && ( -
-
-
- { - setState({ ...state, orgId, costId: null }) - getCostCenter({ - variables: { - id: orgId, - }, - }) - }} - /> -
- {state.orgId && ( -
- { - handleClear() - }} - /> + {dataRoles && state.roleId && ( +
+
+
+
- )} +
-
- )} + )} - {state.orgId && ( -
- { - setState({ ...state, costId }) - }} - /> -
- )} + {state.orgId && ( +
+ { + setState({ ...state, costId }) + }} + /> +
+ )} - {state.orgId && !state.costId ? ( -
- {intl.formatMessage(messages.alertPick)} -
- ) : null} + {state.orgId && !state.costId ? ( +
+ {formatMessage(messages.alertPick)} +
+ ) : null} -
- {showCancel && onCancel && ( +
+ {showCancel && onCancel && ( +
+ +
+ )} + {userData?.getUser?.roleId && ( +
+ +
+ )} +
+ {state.message && ( + { + setState({ ...state, message: null }) + }} + > + {state.message === 'success' + ? formatMessage(messages.success) + : formatMessage(messages.error)} + )} - -
- {state.message && ( - { - setState({ ...state, message: null }) - }} - > - {state.message === 'success' - ? intl.formatMessage(messages.success) - : intl.formatMessage(messages.error)} - - )} +
) } -export default injectIntl(UserEdit) +export default UserEdit diff --git a/react/mutations/deleteUser.gql b/react/mutations/deleteUser.gql new file mode 100644 index 0000000..d1dea83 --- /dev/null +++ b/react/mutations/deleteUser.gql @@ -0,0 +1,8 @@ +mutation DeleteUser($id: ID!, $userId: ID, $email: String!) { + deleteUser(id: $id, userId: $userId, email: $email) + @context(provider: "vtex.storefront-permissions") { + id + status + message + } +} diff --git a/react/package.json b/react/package.json index 5952d6c..e94ec8f 100644 --- a/react/package.json +++ b/react/package.json @@ -5,15 +5,13 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "devDependencies": { + "@types/faker": "^4.1.5", "@types/node": "^11.12.1", "@types/react": "^16.8.10", - "@types/react-intl": "^2.3.17", + "@types/react-intl": "^3.0.0", "apollo-client": "^2.4.7", "graphql": "^14.0.2", "prop-types": "^15.7.2", - "react": "^16.8.6", - "react-dom": "^16.8.6", - "react-intl": "^2.7.2", "typescript": "3.9.7", "vtex.admin-customers-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.admin-customers-graphql@3.0.1/public/@types/vtex.admin-customers-graphql", "vtex.b2b-organizations-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.b2b-organizations-graphql@0.9.1/public/@types/vtex.b2b-organizations-graphql", @@ -21,7 +19,10 @@ "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.145.2/public/@types/vtex.styleguide" }, "dependencies": { - "@types/faker": "^4.1.5", - "faker": "^4.1.0" + "faker": "^4.1.0", + "react": "^16.8.6", + "react-apollo": "^3.1.5", + "react-dom": "^16.8.6", + "react-intl": "^5.13.4" } } diff --git a/react/queries/getOrganization.graphql b/react/queries/getOrganization.graphql new file mode 100644 index 0000000..bffddf8 --- /dev/null +++ b/react/queries/getOrganization.graphql @@ -0,0 +1,19 @@ +query GetOrganization($id: ID) { + getOrganizationById(id: $id) + @context(provider: "vtex.b2b-organizations-graphql") { + id + name + status + created + collections { + id + name + } + paymentTerms { + id + name + } + priceTables + costCenters + } +} diff --git a/react/typings/graphql.d.ts b/react/typings/graphql.d.ts new file mode 100644 index 0000000..169f32a --- /dev/null +++ b/react/typings/graphql.d.ts @@ -0,0 +1,13 @@ +declare module '*.graphql' { + import type { DocumentNode } from 'graphql' + + const value: DocumentNode + export default value +} + +declare module '*.gql' { + import type { DocumentNode } from 'graphql' + + const value: DocumentNode + export default value +} diff --git a/react/yarn.lock b/react/yarn.lock index aa63f59..b17e30a 100644 --- a/react/yarn.lock +++ b/react/yarn.lock @@ -2,11 +2,208 @@ # yarn lockfile v1 +"@apollo/react-common@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@apollo/react-common/-/react-common-3.1.4.tgz#ec13c985be23ea8e799c9ea18e696eccc97be345" + integrity sha512-X5Kyro73bthWSCBJUC5XYQqMnG0dLWuDZmVkzog9dynovhfiVCV4kPSdgSIkqnb++cwCzOVuQ4rDKVwo2XRzQA== + dependencies: + ts-invariant "^0.4.4" + tslib "^1.10.0" + +"@apollo/react-components@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@apollo/react-components/-/react-components-3.1.5.tgz#040d2f35ce4947747efe16f76d59dcbd797ffdaf" + integrity sha512-c82VyUuE9VBnJB7bnX+3dmwpIPMhyjMwyoSLyQWPHxz8jK4ak30XszJtqFf4eC4hwvvLYa+Ou6X73Q8V8e2/jg== + dependencies: + "@apollo/react-common" "^3.1.4" + "@apollo/react-hooks" "^3.1.5" + prop-types "^15.7.2" + ts-invariant "^0.4.4" + tslib "^1.10.0" + +"@apollo/react-hoc@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@apollo/react-hoc/-/react-hoc-3.1.5.tgz#6552d2fb4aafc59fdc8f4e353358b98b89cfab6f" + integrity sha512-jlZ2pvEnRevLa54H563BU0/xrYSgWQ72GksarxUzCHQW85nmn9wQln0kLBX7Ua7SBt9WgiuYQXQVechaaCulfQ== + dependencies: + "@apollo/react-common" "^3.1.4" + "@apollo/react-components" "^3.1.5" + hoist-non-react-statics "^3.3.0" + ts-invariant "^0.4.4" + tslib "^1.10.0" + +"@apollo/react-hooks@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@apollo/react-hooks/-/react-hooks-3.1.5.tgz#7e710be52461255ae7fc0b3b9c2ece64299c10e6" + integrity sha512-y0CJ393DLxIIkksRup4nt+vSjxalbZBXnnXxYbviq/woj+zKa431zy0yT4LqyRKpFy9ahMIwxBnBwfwIoupqLQ== + dependencies: + "@apollo/react-common" "^3.1.4" + "@wry/equality" "^0.1.9" + ts-invariant "^0.4.4" + tslib "^1.10.0" + +"@apollo/react-ssr@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@apollo/react-ssr/-/react-ssr-3.1.5.tgz#53703cd493afcde567acc6d5512cab03dafce6de" + integrity sha512-wuLPkKlctNn3u8EU8rlECyktpOUCeekFfb0KhIKknpGY6Lza2Qu0bThx7D9MIbVEzhKadNNrzLcpk0Y8/5UuWg== + dependencies: + "@apollo/react-common" "^3.1.4" + "@apollo/react-hooks" "^3.1.5" + tslib "^1.10.0" + +"@formatjs/ecma402-abstract@1.11.4": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz#b962dfc4ae84361f9f08fbce411b4e4340930eda" + integrity sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw== + dependencies: + "@formatjs/intl-localematcher" "0.2.25" + tslib "^2.1.0" + +"@formatjs/ecma402-abstract@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.6.tgz#0e828ddfed6fb3413ae379e48fb7170fb0795db5" + integrity sha512-6TcI+IroIK+GTWXBJ643LBJklmCBsqLt1sUTGWfzdBcI5Y6b1L1iamrJB1B5OAQLnhzWveLbmzPYHYsFEZfeig== + dependencies: + "@formatjs/intl-localematcher" "0.2.27" + tslib "2.4.0" + +"@formatjs/fast-memoize@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz#e6f5aee2e4fd0ca5edba6eba7668e2d855e0fc21" + integrity sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg== + dependencies: + tslib "^2.1.0" + +"@formatjs/fast-memoize@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.3.tgz#5c950bd64c4959e30bbd16b22a17040fbeb9c4d2" + integrity sha512-RVI3e4M7mIxAhKbbyS78H8++fsoiSRZgxh0zReHfvV6p1cpfgG2/k2qJYhJq0RXh6orVtUEsQ3xK9i4tDfsOSg== + dependencies: + tslib "2.4.0" + +"@formatjs/icu-messageformat-parser@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz#a54293dd7f098d6a6f6a084ab08b6d54a3e8c12d" + integrity sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/icu-skeleton-parser" "1.3.6" + tslib "^2.1.0" + +"@formatjs/icu-messageformat-parser@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.2.tgz#9ff4dfc4f1ed613cca2c188b29f299854b86b7f8" + integrity sha512-FYQ2pkgbDJxJlst/U5MU2H7+bR9HrZ4x8J4c0etrya24pJzQxYguVlAhc2S6NoEImlQ2LmIIGsURaBQu9bCtew== + dependencies: + "@formatjs/ecma402-abstract" "1.11.6" + "@formatjs/icu-skeleton-parser" "1.3.8" + tslib "2.4.0" + +"@formatjs/icu-skeleton-parser@1.3.6": + version "1.3.6" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz#4ce8c0737d6f07b735288177049e97acbf2e8964" + integrity sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + tslib "^2.1.0" + +"@formatjs/icu-skeleton-parser@1.3.8": + version "1.3.8" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.8.tgz#3d150fcb45b4867c1db84237ca1f1f701d598918" + integrity sha512-CVdsPMs/KvrIDKhMDw8bSq/Zst2bhdn/bTUfVCHi/c/bj462lChIJmW/JP/FaGKgZzdG8slGyVIFLonpG4uqFA== + dependencies: + "@formatjs/ecma402-abstract" "1.11.6" + tslib "2.4.0" + +"@formatjs/intl-displaynames@5.4.3": + version "5.4.3" + resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-5.4.3.tgz#e468586694350c722c7efab1a31fcde68aeaed8b" + integrity sha512-4r12A3mS5dp5hnSaQCWBuBNfi9Amgx2dzhU4lTFfhSxgb5DOAiAbMpg6+7gpWZgl4ahsj3l2r/iHIjdmdXOE2Q== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/intl-localematcher" "0.2.25" + tslib "^2.1.0" + +"@formatjs/intl-displaynames@6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.0.1.tgz#b4bf890d440a19da03203a5e7f1bff1460b2b859" + integrity sha512-KPfB+mOIzcptAzpNIciDc+rK4kRCg5aTCXPr5feIWNxvd/H1Wr3cVVDV2YGdPn+Woo9b1K4cnUi3b1IvBFQ/5g== + dependencies: + "@formatjs/ecma402-abstract" "1.11.6" + "@formatjs/intl-localematcher" "0.2.27" + tslib "2.4.0" + +"@formatjs/intl-listformat@6.5.3": + version "6.5.3" + resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-6.5.3.tgz#f29da613a8062dc3e4e3d847ba890c3ea745f051" + integrity sha512-ozpz515F/+3CU+HnLi5DYPsLa6JoCfBggBSSg/8nOB5LYSFW9+ZgNQJxJ8tdhKYeODT+4qVHX27EeJLoxLGLNg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/intl-localematcher" "0.2.25" + tslib "^2.1.0" + +"@formatjs/intl-listformat@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.0.1.tgz#9b7f0d46a6eb04138dde5d57c898222315f87334" + integrity sha512-sgE4B9+mu3ZF77vhZB0tR8O3evvcPA//WbA/8UJ21XOrSzfY6RXhSbvDfSd7Y5iEeBu+2C+5YxDuAwLnvq2SnQ== + dependencies: + "@formatjs/ecma402-abstract" "1.11.6" + "@formatjs/intl-localematcher" "0.2.27" + tslib "2.4.0" + +"@formatjs/intl-localematcher@0.2.25": + version "0.2.25" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz#60892fe1b271ec35ba07a2eb018a2dd7bca6ea3a" + integrity sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA== + dependencies: + tslib "^2.1.0" + +"@formatjs/intl-localematcher@0.2.27": + version "0.2.27" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.27.tgz#8a837ddca17a55d86e4ab68bcbb25b15f547d61d" + integrity sha512-XHYcVas2ebDTh3VtfdluvbTjqyMUHqFHARnuJo5KYF/0MKOTmozVSK7PJGnu1IEHdmRdTWuG6TB+2RnkasaxVw== + dependencies: + tslib "2.4.0" + +"@formatjs/intl@2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.2.1.tgz#6daf4dabed055b17f467f0aa1bc073a626bc9189" + integrity sha512-vgvyUOOrzqVaOFYzTf2d3+ToSkH2JpR7x/4U1RyoHQLmvEaTQvXJ7A2qm1Iy3brGNXC/+/7bUlc3lpH+h/LOJA== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/fast-memoize" "1.2.1" + "@formatjs/icu-messageformat-parser" "2.1.0" + "@formatjs/intl-displaynames" "5.4.3" + "@formatjs/intl-listformat" "6.5.3" + intl-messageformat "9.13.0" + tslib "^2.1.0" + +"@formatjs/intl@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.2.5.tgz#888f42750eacdcfb836a062eb889cb429d13f7f7" + integrity sha512-b0+5Bjsl3KDAII2frBPRO7ck9Ec/xqZ25BoiJATJhe//e4n6FOvVXk5QKYwBQPDt3JPu/Qa14oqHDiZlZmVdSg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.6" + "@formatjs/fast-memoize" "1.2.3" + "@formatjs/icu-messageformat-parser" "2.1.2" + "@formatjs/intl-displaynames" "6.0.1" + "@formatjs/intl-listformat" "7.0.1" + intl-messageformat "10.0.1" + tslib "2.4.0" + "@types/faker@^4.1.5": version "4.1.12" resolved "https://registry.yarnpkg.com/@types/faker/-/faker-4.1.12.tgz#065d37343677df1aa757c622650bd14666c42602" integrity sha512-0MEyzJrLLs1WaOCx9ULK6FzdCSj2EuxdSP9kvuxxdBEGujZYUOZ4vkPXdgu3dhyg/pOdn7VCatelYX7k0YShlA== +"@types/hoist-non-react-statics@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/node@^11.12.1": version "11.15.54" resolved "https://registry.yarnpkg.com/@types/node/-/node-11.15.54.tgz#59ed60e7b0d56905a654292e8d73275034eb6283" @@ -17,10 +214,21 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== -"@types/react-intl@^2.3.17": - version "2.3.18" - resolved "https://registry.yarnpkg.com/@types/react-intl/-/react-intl-2.3.18.tgz#fd2d8b7f4d0a1dd05b5f1784ab0d7fe1786a690d" - integrity sha512-DVNJs49zUxKRZng8VuILE886Yihdsf3yLr5vHk9zJrmF8SyRSK3sxNSvikAKxNkv9hX55XBTJShz6CkJnbNjgg== +"@types/react-intl@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/react-intl/-/react-intl-3.0.0.tgz#a2cce0024b6cfe403be28ccf67f49d720fa810ec" + integrity sha512-k8F3d05XQGEqSWIfK97bBjZe4z9RruXU9Wa7OZ2iUC5pdeIpzuQDZe/9C2J3Xir5//ZtAkhcv08Wfx3n5TBTQg== + dependencies: + react-intl "*" + +"@types/react@*", "@types/react@16 || 17 || 18": + version "18.0.9" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.9.tgz#d6712a38bd6cd83469603e7359511126f122e878" + integrity sha512-9bjbg1hJHUm4De19L1cHiW0Jvx3geel6Qczhjd0qY5VKVE2X5+x77YxAepuCwVh4vrgZJdgEJw48zrhRIeF4Nw== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" "@types/react@^16.8.10": version "16.14.8" @@ -41,7 +249,7 @@ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71" integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg== -"@wry/equality@^0.1.2": +"@wry/equality@^0.1.2", "@wry/equality@^0.1.9": version "0.1.11" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" integrity sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA== @@ -112,43 +320,32 @@ graphql@^14.0.2: dependencies: iterall "^1.2.2" -hoist-non-react-statics@^3.3.0: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== dependencies: react-is "^16.7.0" -intl-format-cache@^2.0.5: - version "2.2.9" - resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.2.9.tgz#fb560de20c549cda20b569cf1ffb6dc62b5b93b4" - integrity sha512-Zv/u8wRpekckv0cLkwpVdABYST4hZNTDaX7reFetrYTJwxExR2VyTqQm+l0WmL0Qo8Mjb9Tf33qnfj0T7pjxdQ== - -intl-messageformat-parser@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075" - integrity sha1-tD1FqXRoytvkQzHXS7Ho3qRPwHU= - -intl-messageformat@^2.0.0, intl-messageformat@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc" - integrity sha1-NFvNRt5jC3aDMwwuUhd/9eq0hPw= +intl-messageformat@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.0.1.tgz#dae7ae81a477e92ea8691dd73c60d5eb5003f866" + integrity sha512-oZWDsNbauuWmPd98+zLEfNojuJkBdVpEWIcWQVCTxSJrhag2/czZnwKBsYa8NcVf4t0fWo0k77v+CBCudKEcjw== dependencies: - intl-messageformat-parser "1.4.0" - -intl-relativeformat@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-2.2.0.tgz#6aca95d019ec8d30b6c5653b6629f9983ea5b6c5" - integrity sha512-4bV/7kSKaPEmu6ArxXf9xjv1ny74Zkwuey8Pm01NH4zggPP7JHwg2STk8Y3JdspCKRDriwIyLRfEXnj2ZLr4Bw== + "@formatjs/ecma402-abstract" "1.11.6" + "@formatjs/fast-memoize" "1.2.3" + "@formatjs/icu-messageformat-parser" "2.1.2" + tslib "2.4.0" + +intl-messageformat@9.13.0: + version "9.13.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-9.13.0.tgz#97360b73bd82212e4f6005c712a4a16053165468" + integrity sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw== dependencies: - intl-messageformat "^2.0.0" - -invariant@^2.1.1: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/fast-memoize" "1.2.1" + "@formatjs/icu-messageformat-parser" "2.1.0" + tslib "^2.1.0" iterall@^1.2.2: version "1.3.0" @@ -160,7 +357,7 @@ iterall@^1.2.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -181,6 +378,17 @@ prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" +react-apollo@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-3.1.5.tgz#36692d393c47e7ccc37f0a885c7cc5a8b4961c91" + integrity sha512-xOxMqxORps+WHrUYbjVHPliviomefOpu5Sh35oO3osuOyPTxvrljdfTLGCggMhcXBsDljtS5Oy4g+ijWg3D4JQ== + dependencies: + "@apollo/react-common" "^3.1.4" + "@apollo/react-components" "^3.1.5" + "@apollo/react-hoc" "^3.1.5" + "@apollo/react-hooks" "^3.1.5" + "@apollo/react-ssr" "^3.1.5" + react-dom@^16.8.6: version "16.14.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" @@ -191,16 +399,37 @@ react-dom@^16.8.6: prop-types "^15.6.2" scheduler "^0.19.1" -react-intl@^2.7.2: - version "2.9.0" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.9.0.tgz#c97c5d17d4718f1575fdbd5a769f96018a3b1843" - integrity sha512-27jnDlb/d2A7mSJwrbOBnUgD+rPep+abmoJE511Tf8BnoONIAUehy/U1zZCHGO17mnOwMWxqN4qC0nW11cD6rA== +react-intl@*: + version "6.0.3" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.0.3.tgz#eb5857f2fd525c83255bf6c8339562a7fea9f970" + integrity sha512-c6wHOnYjOBTbqIt+6TVV2QwdKrqYiFP713tMsw/sJWYgzfaRTjsvGkcxOXhX3SoBrqbUhKTEzjdniuwpAN/qKA== dependencies: - hoist-non-react-statics "^3.3.0" - intl-format-cache "^2.0.5" - intl-messageformat "^2.1.0" - intl-relativeformat "^2.1.0" - invariant "^2.1.1" + "@formatjs/ecma402-abstract" "1.11.6" + "@formatjs/icu-messageformat-parser" "2.1.2" + "@formatjs/intl" "2.2.5" + "@formatjs/intl-displaynames" "6.0.1" + "@formatjs/intl-listformat" "7.0.1" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/react" "16 || 17 || 18" + hoist-non-react-statics "^3.3.2" + intl-messageformat "10.0.1" + tslib "2.4.0" + +react-intl@^5.13.4: + version "5.25.1" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.25.1.tgz#68a73aefc485c9bf70062381ae7f6f4791680879" + integrity sha512-pkjdQDvpJROoXLMltkP/5mZb0/XqrqLoPGKUCfbdkP8m6U9xbK40K51Wu+a4aQqTEvEK5lHBk0fWzUV72SJ3Hg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/icu-messageformat-parser" "2.1.0" + "@formatjs/intl" "2.2.1" + "@formatjs/intl-displaynames" "5.4.3" + "@formatjs/intl-listformat" "6.5.3" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/react" "16 || 17 || 18" + hoist-non-react-statics "^3.3.2" + intl-messageformat "9.13.0" + tslib "^2.1.0" react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" @@ -229,13 +458,18 @@ symbol-observable@^1.0.2: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -ts-invariant@^0.4.0: +ts-invariant@^0.4.0, ts-invariant@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86" integrity sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA== dependencies: tslib "^1.9.3" +tslib@2.4.0, tslib@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.10.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" From b77cf5a53d030751cb3dd110f71e9b9d0ca6832c Mon Sep 17 00:00:00 2001 From: polishq Date: Fri, 27 May 2022 09:49:06 -0400 Subject: [PATCH 2/2] Add intl message --- messages/context.json | 3 ++- messages/en.json | 3 ++- react/components/OrganizationsAutocomplete.tsx | 5 ++++- react/components/customers-admin.tsx | 6 +++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/messages/context.json b/messages/context.json index 130d85d..11a764b 100644 --- a/messages/context.json +++ b/messages/context.json @@ -20,5 +20,6 @@ "admin/storefront-permissions.tab.users.name.label": "admin/storefront-permissions.tab.users.name.label", "admin/storefront-permissions.tab.users.success": "admin/storefront-permissions.tab.users.success", "admin/storefront-permissions.title": "admin/storefront-permissions.title", - "admin/storefront-permissions.alert-pick": "admin/storefront-permissions.alert-pick" + "admin/storefront-permissions.alert-pick": "admin/storefront-permissions.alert-pick", + "admin/storefront-permissions.searchOrganizations": "admin/storefront-permissions.searchOrganizations" } diff --git a/messages/en.json b/messages/en.json index c545388..f085b7c 100644 --- a/messages/en.json +++ b/messages/en.json @@ -20,5 +20,6 @@ "admin/storefront-permissions.tab.users.name.label": "Name", "admin/storefront-permissions.tab.users.success": "B2B info saved", "admin/storefront-permissions.title": "Storefront Permissions", - "admin/storefront-permissions.alert-pick": "You need to pick a cost center before you can save changes" + "admin/storefront-permissions.alert-pick": "You need to pick a cost center before you can save changes", + "admin/storefront-permissions.searchOrganizations": "Search organizations..." } diff --git a/react/components/OrganizationsAutocomplete.tsx b/react/components/OrganizationsAutocomplete.tsx index 9146c8f..1b3e065 100644 --- a/react/components/OrganizationsAutocomplete.tsx +++ b/react/components/OrganizationsAutocomplete.tsx @@ -1,7 +1,9 @@ import React, { useEffect, useState } from 'react' import { useQuery } from 'react-apollo' import { AutocompleteInput } from 'vtex.styleguide' +import { useIntl } from 'react-intl' +import { messages } from './customers-admin' import GET_ORGANIZATIONS from '../queries/listOrganizations.gql' import GET_ORGANIZATION_BY_ID from '../queries/getOrganization.graphql' @@ -20,6 +22,7 @@ interface Props { } const OrganizationsAutocomplete = ({ onChange, organizationId }: Props) => { + const { formatMessage } = useIntl() const [term, setTerm] = useState('') const [hasChanged, setHasChanged] = useState(false) const [values, setValues] = useState([] as any) @@ -91,7 +94,7 @@ const OrganizationsAutocomplete = ({ onChange, organizationId }: Props) => { setTerm(_term) }, onClear, - placeholder: 'Search organization...', + placeholder: formatMessage(messages.searchOrganizations), value: term, } diff --git a/react/components/customers-admin.tsx b/react/components/customers-admin.tsx index 7b6879d..dd5ee05 100644 --- a/react/components/customers-admin.tsx +++ b/react/components/customers-admin.tsx @@ -12,7 +12,7 @@ import GET_COST from '../queries/costCentersByOrg.gql' import SAVE_USER from '../mutations/saveUser.gql' import DELETE_USER from '../mutations/deleteUser.gql' -const messages = defineMessages({ +export const messages = defineMessages({ b2bInfo: { id: 'admin/storefront-permissions.b2bInfo.title', defaultMessage: 'B2B Information', @@ -70,6 +70,10 @@ const messages = defineMessages({ id: 'admin/storefront-permissions.tab.users.error', defaultMessage: 'Error saving B2B info', }, + searchOrganizations: { + id: 'admin/storefront-permissions.searchOrganizations', + defaultMessage: 'Search organizations...', + }, }) const parseOptions = (options: any) => {