From 38b597441039f25de05b928c49e99f82220eddc7 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Fri, 24 May 2024 12:04:47 -0400 Subject: [PATCH] Remove t from invite-related code (#27053) * Remove t from actions/invite_actions * Remove t from components/invitation_modal and related code * Remove t from components/channel_invite_modal * Re-add the ability for reason to be a string * Address feedback --- .../src/actions/invite_actions.test.ts | 168 ++++++++---- webapp/channels/src/actions/invite_actions.ts | 245 ++++++++++++++---- .../team_warning_banner.tsx | 10 +- .../invitation_modal.test.tsx | 4 +- .../invitation_modal/invitation_modal.tsx | 29 ++- .../invitation_modal/invite_view.tsx | 77 +++--- .../invitation_modal/result_table.test.tsx | 10 +- .../invitation_modal/result_table.tsx | 25 +- .../invitation_modal/result_view.tsx | 27 +- .../preparing_workspace/invite_members.tsx | 22 +- .../inputs/users_emails_input.test.tsx | 6 +- .../widgets/inputs/users_emails_input.tsx | 52 ++-- 12 files changed, 468 insertions(+), 207 deletions(-) diff --git a/webapp/channels/src/actions/invite_actions.test.ts b/webapp/channels/src/actions/invite_actions.test.ts index b104609bc8..f9af7505fe 100644 --- a/webapp/channels/src/actions/invite_actions.test.ts +++ b/webapp/channels/src/actions/invite_actions.test.ts @@ -37,11 +37,11 @@ jest.mock('mattermost-redux/actions/teams', () => ({ getTeamMembersByIds: () => ({type: 'MOCK_RECEIVED_ME'}), sendEmailInvitesToTeamGracefully: (team: string, emails: string[]) => { if (team === 'incorrect-default-smtp') { - return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: 'SMTP is not configured in System Console.', id: 'api.team.invite_members.unable_to_send_email_with_defaults.app_error'}}))}); + return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: '(From server) SMTP is not configured in System Console.', id: 'api.team.invite_members.unable_to_send_email_with_defaults.app_error'}}))}); } else if (emails.length > 21) { // Poor attempt to mock rate limiting. - return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: 'Invite emails rate limit exceeded.'}}))}); + return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: '(From server) Invite emails rate limit exceeded.'}}))}); } else if (team === 'error') { - return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: 'Unable to add the user to the team.'}}))}); + return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: '(From server) Unable to add the user to the team.'}}))}); } // team === 'correct' i.e no error @@ -50,11 +50,11 @@ jest.mock('mattermost-redux/actions/teams', () => ({ // eslint-disable-next-line @typescript-eslint/no-unused-vars sendEmailGuestInvitesToChannelsGracefully: (teamId: string, _channelIds: string[], emails: string[], _message: string) => { if (teamId === 'incorrect-default-smtp') { - return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: 'SMTP is not configured in System Console.', id: 'api.team.invite_members.unable_to_send_email_with_defaults.app_error'}}))}); + return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: '(From server) SMTP is not configured in System Console.', id: 'api.team.invite_members.unable_to_send_email_with_defaults.app_error'}}))}); } else if (emails.length > 21) { // Poor attempt to mock rate limiting. - return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: 'Invite emails rate limit exceeded.'}}))}); + return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: '(From server) Invite emails rate limit exceeded.'}}))}); } else if (teamId === 'error') { - return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: 'Unable to add the guest to the channels.'}}))}); + return ({type: 'MOCK_RECEIVED_ME', data: emails.map((email) => ({email, error: {message: '(From server) Unable to add the guest to the channels.'}}))}); } // teamId === 'correct' i.e no error @@ -141,15 +141,24 @@ describe('actions/invite_actions', () => { sent: [ { email: 'email-one@email-one.com', - reason: 'An invitation email has been sent.', + reason: { + id: 'invite.members.invite-sent', + defaultMessage: 'An invitation email has been sent.', + }, }, { email: 'email-two@email-two.com', - reason: 'An invitation email has been sent.', + reason: { + id: 'invite.members.invite-sent', + defaultMessage: 'An invitation email has been sent.', + }, }, { email: 'email-three@email-three.com', - reason: 'An invitation email has been sent.', + reason: { + id: 'invite.members.invite-sent', + defaultMessage: 'An invitation email has been sent.', + }, }, ], }, @@ -165,15 +174,15 @@ describe('actions/invite_actions', () => { notSent: [ { email: 'email-one@email-one.com', - reason: 'Unable to add the user to the team.', + reason: '(From server) Unable to add the user to the team.', }, { email: 'email-two@email-two.com', - reason: 'Unable to add the user to the team.', + reason: '(From server) Unable to add the user to the team.', }, { email: 'email-three@email-three.com', - reason: 'Unable to add the user to the team.', + reason: '(From server) Unable to add the user to the team.', }, ], }, @@ -192,7 +201,10 @@ describe('actions/invite_actions', () => { data: { sent: [ { - reason: 'This member has been added to the team.', + reason: { + id: 'invite.members.added-to-team', + defaultMessage: 'This member has been added to the team.', + }, user: { id: 'other-user', roles: 'system_user', @@ -201,21 +213,30 @@ describe('actions/invite_actions', () => { ], notSent: [ { - reason: 'This person is already a team member.', + reason: { + id: 'invite.members.already-member', + defaultMessage: 'This person is already a team member.', + }, user: { id: 'user1', roles: 'system_user', }, }, { - reason: 'Contact your admin to make this guest a full member.', + reason: { + id: 'invite.members.user-is-guest', + defaultMessage: 'Contact your admin to make this guest a full member.', + }, user: { id: 'guest1', roles: 'system_guest', }, }, { - reason: 'Contact your admin to make this guest a full member.', + reason: { + id: 'invite.members.user-is-guest', + defaultMessage: 'Contact your admin to make this guest a full member.', + }, user: { id: 'other-guest', roles: 'system_guest', @@ -236,24 +257,44 @@ describe('actions/invite_actions', () => { const response = await store.dispatch(sendMembersInvites('error', users, [])); expect(response).toEqual({ data: { - sent: [{user: {id: 'other-user', roles: 'system_user'}, reason: 'This member has been added to the team.'}], + sent: [ + { + reason: { + id: 'invite.members.added-to-team', + defaultMessage: 'This member has been added to the team.', + }, + user: { + id: 'other-user', + roles: 'system_user', + }, + }, + ], notSent: [ { - reason: 'This person is already a team member.', + reason: { + id: 'invite.members.already-member', + defaultMessage: 'This person is already a team member.', + }, user: { id: 'user1', roles: 'system_user', }, }, { - reason: 'Contact your admin to make this guest a full member.', + reason: { + id: 'invite.members.user-is-guest', + defaultMessage: 'Contact your admin to make this guest a full member.', + }, user: { id: 'guest1', roles: 'system_guest', }, }, { - reason: 'Contact your admin to make this guest a full member.', + reason: { + id: 'invite.members.user-is-guest', + defaultMessage: 'Contact your admin to make this guest a full member.', + }, user: { id: 'other-guest', roles: 'system_guest', @@ -271,7 +312,7 @@ describe('actions/invite_actions', () => { emails.push('email-' + i + '@example.com'); expectedNotSent.push({ email: 'email-' + i + '@example.com', - reason: 'Invite emails rate limit exceeded.', + reason: '(From server) Invite emails rate limit exceeded.', }); } const response = await store.dispatch(sendMembersInvites('correct', [], emails)); @@ -293,7 +334,7 @@ describe('actions/invite_actions', () => { email: 'email-one@email-one.com', reason: { id: 'admin.environment.smtp.smtpFailure', - message: 'SMTP is not configured in System Console. Can be configured here.', + defaultMessage: 'SMTP is not configured in System Console. Can be configured here.', }, path: ConsolePages.SMTP, }], @@ -324,15 +365,24 @@ describe('actions/invite_actions', () => { sent: [ { email: 'email-one@email-one.com', - reason: 'An invitation email has been sent.', + reason: { + id: 'invite.guests.added-to-channel', + defaultMessage: 'An invitation email has been sent.', + }, }, { email: 'email-two@email-two.com', - reason: 'An invitation email has been sent.', + reason: { + id: 'invite.guests.added-to-channel', + defaultMessage: 'An invitation email has been sent.', + }, }, { email: 'email-three@email-three.com', - reason: 'An invitation email has been sent.', + reason: { + id: 'invite.guests.added-to-channel', + defaultMessage: 'An invitation email has been sent.', + }, }, ], }, @@ -349,15 +399,15 @@ describe('actions/invite_actions', () => { notSent: [ { email: 'email-one@email-one.com', - reason: 'Unable to add the guest to the channels.', + reason: '(From server) Unable to add the guest to the channels.', }, { email: 'email-two@email-two.com', - reason: 'Unable to add the guest to the channels.', + reason: '(From server) Unable to add the guest to the channels.', }, { email: 'email-three@email-three.com', - reason: 'Unable to add the guest to the channels.', + reason: '(From server) Unable to add the guest to the channels.', }, ], }, @@ -379,7 +429,7 @@ describe('actions/invite_actions', () => { { reason: { id: 'invite.guests.new-member', - message: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', + defaultMessage: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', values: {count: channels.length}, }, user: { @@ -390,7 +440,7 @@ describe('actions/invite_actions', () => { { reason: { id: 'invite.guests.new-member', - message: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', + defaultMessage: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', values: {count: channels.length}, }, user: { @@ -401,14 +451,20 @@ describe('actions/invite_actions', () => { ], notSent: [ { - reason: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + reason: { + id: 'invite.members.user-is-not-guest', + defaultMessage: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + }, user: { id: 'user1', roles: 'system_user', }, }, { - reason: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + reason: { + id: 'invite.members.user-is-not-guest', + defaultMessage: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + }, user: { id: 'other-user', roles: 'system_user', @@ -430,14 +486,20 @@ describe('actions/invite_actions', () => { sent: [], notSent: [ { - reason: 'This person is already a member of all the channels.', + reason: { + id: 'invite.guests.already-all-channels-member', + defaultMessage: 'This person is already a member of all the channels.', + }, user: { id: 'guest2', roles: 'system_guest', }, }, { - reason: 'This person is already a member of some of the channels.', + reason: { + id: 'invite.guests.already-some-channels-member', + defaultMessage: 'This person is already a member of some of the channels.', + }, user: { id: 'guest3', roles: 'system_guest', @@ -467,7 +529,7 @@ describe('actions/invite_actions', () => { }, reason: { id: 'invite.guests.new-member', - message: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', + defaultMessage: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', values: { count: 1, }, @@ -480,7 +542,7 @@ describe('actions/invite_actions', () => { }, reason: { id: 'invite.guests.new-member', - message: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', + defaultMessage: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', values: { count: 1, }, @@ -489,14 +551,20 @@ describe('actions/invite_actions', () => { ], notSent: [ { - reason: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + reason: { + id: 'invite.members.user-is-not-guest', + defaultMessage: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + }, user: { id: 'user1', roles: 'system_user', }, }, { - reason: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + reason: { + id: 'invite.members.user-is-not-guest', + defaultMessage: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + }, user: { id: 'other-user', roles: 'system_user', @@ -520,28 +588,40 @@ describe('actions/invite_actions', () => { sent: [], notSent: [ { - reason: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + reason: { + id: 'invite.members.user-is-not-guest', + defaultMessage: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + }, user: { id: 'user1', roles: 'system_user', }, }, { - reason: 'Unable to add the guest to the channels.', + reason: { + id: 'invite.guests.unable-to-add-the-user-to-the-channels', + defaultMessage: 'Unable to add the guest to the channels.', + }, user: { id: 'guest1', roles: 'system_guest', }, }, { - reason: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + reason: { + id: 'invite.members.user-is-not-guest', + defaultMessage: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + }, user: { id: 'other-user', roles: 'system_user', }, }, { - reason: 'Unable to add the guest to the channels.', + reason: { + id: 'invite.guests.unable-to-add-the-user-to-the-channels', + defaultMessage: 'Unable to add the guest to the channels.', + }, user: { id: 'other-guest', roles: 'system_guest', @@ -559,7 +639,7 @@ describe('actions/invite_actions', () => { emails.push('email-' + i + '@example.com'); expectedNotSent.push({ email: 'email-' + i + '@example.com', - reason: 'Invite emails rate limit exceeded.', + reason: '(From server) Invite emails rate limit exceeded.', }); } @@ -582,7 +662,7 @@ describe('actions/invite_actions', () => { email: 'email-one@email-one.com', reason: { id: 'admin.environment.smtp.smtpFailure', - message: 'SMTP is not configured in System Console. Can be configured here.', + defaultMessage: 'SMTP is not configured in System Console. Can be configured here.', }, path: ConsolePages.SMTP, }], diff --git a/webapp/channels/src/actions/invite_actions.ts b/webapp/channels/src/actions/invite_actions.ts index d9468444f3..6fd4a18520 100644 --- a/webapp/channels/src/actions/invite_actions.ts +++ b/webapp/channels/src/actions/invite_actions.ts @@ -1,6 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import {defineMessage} from 'react-intl'; + import type {Channel, ChannelMembership} from '@mattermost/types/channels'; import type {TeamMemberWithError, TeamInviteWithError} from '@mattermost/types/teams'; import type {UserProfile} from '@mattermost/types/users'; @@ -16,11 +18,10 @@ import {isGuest} from 'mattermost-redux/utils/user_utils'; import {addUsersToTeam} from 'actions/team_actions'; +import type {InviteResult} from 'components/invitation_modal/result_table'; import type {InviteResults} from 'components/invitation_modal/result_view'; import {ConsolePages} from 'utils/constants'; -import {t} from 'utils/i18n'; -import {localizeMessage} from 'utils/utils'; export function sendMembersInvites(teamId: string, users: UserProfile[], emails: string[]): ActionFuncAsync { return async (dispatch, getState) => { @@ -34,9 +35,21 @@ export function sendMembersInvites(teamId: string, users: UserProfile[], emails: for (const user of users) { const member = getTeamMember(state, teamId, user.id); if (isGuest(user.roles)) { - notSent.push({user, reason: localizeMessage('invite.members.user-is-guest', 'Contact your admin to make this guest a full member.')}); + notSent.push({ + user, + reason: defineMessage({ + id: 'invite.members.user-is-guest', + defaultMessage: 'Contact your admin to make this guest a full member.', + }), + }); } else if (member) { - notSent.push({user, reason: localizeMessage('invite.members.already-member', 'This person is already a team member.')}); + notSent.push({ + user, + reason: defineMessage({ + id: 'invite.members.already-member', + defaultMessage: 'This person is already a team member.', + }), + }); } else { usersToAdd.push(user); } @@ -52,9 +65,18 @@ export function sendMembersInvites(teamId: string, users: UserProfile[], emails: for (const userToAdd of usersToAdd) { const memberWithError = members.find((m: TeamMemberWithError) => m.user_id === userToAdd.id && m.error); if (memberWithError) { - notSent.push({user: userToAdd, reason: memberWithError.error.message}); + notSent.push({ + user: userToAdd, + reason: memberWithError.error.message, + }); } else { - sent.push({user: userToAdd, reason: localizeMessage('invite.members.added-to-team', 'This member has been added to the team.')}); + sent.push({ + user: userToAdd, + reason: defineMessage({ + id: 'invite.members.added-to-team', + defaultMessage: 'This member has been added to the team.', + }), + }); } } } @@ -67,17 +89,28 @@ export function sendMembersInvites(teamId: string, users: UserProfile[], emails: response = { data: emails.map((email) => ({ email, - error: {error: localizeMessage('invite.members.unable-to-add-the-user-to-the-team', 'Unable to add the user to the team.')}, + error: { + error: defineMessage({ + id: 'invite.members.unable-to-add-the-user-to-the-team', + defaultMessage: 'Unable to add the user to the team.', + }), + }, })) as unknown as TeamInviteWithError[], }; } const invitesWithErrors = response.data || []; if (response.error) { if (response.error.server_error_id === 'app.email.rate_limit_exceeded.app_error') { - response.error.message = localizeMessage('invite.rate-limit-exceeded', 'Invite emails rate limit exceeded.'); + response.error.message = defineMessage({ + id: 'invite.rate-limit-exceeded', + defaultMessage: 'Invite emails rate limit exceeded.', + }); } for (const email of emails) { - notSent.push({email, reason: response.error.message}); + notSent.push({ + email, + reason: response.error.message, + }); } } else { for (const email of emails) { @@ -85,16 +118,25 @@ export function sendMembersInvites(teamId: string, users: UserProfile[], emails: if (inviteWithError && inviteWithError.error.id === 'api.team.invite_members.unable_to_send_email_with_defaults.app_error' && isCurrentUserSystemAdmin(state)) { notSent.push({ email, - reason: { - id: t('admin.environment.smtp.smtpFailure'), - message: 'SMTP is not configured in System Console. Can be configured here.', - }, + reason: defineMessage({ + id: 'admin.environment.smtp.smtpFailure', + defaultMessage: 'SMTP is not configured in System Console. Can be configured here.', + }), path: ConsolePages.SMTP, }); } else if (inviteWithError) { - notSent.push({email, reason: inviteWithError.error.message}); + notSent.push({ + email, + reason: inviteWithError.error.message, + }); } else { - sent.push({email, reason: localizeMessage('invite.members.invite-sent', 'An invitation email has been sent.')}); + sent.push({ + email, + reason: defineMessage({ + id: 'invite.members.invite-sent', + defaultMessage: 'An invitation email has been sent.', + }), + }); } } } @@ -114,9 +156,17 @@ export async function sendGuestInviteForUser( teamId: string, channels: Channel[], members: RelationOneToOne>, -) { +): Promise<({sent: InviteResult} | {notSent: InviteResult})> { if (!isGuest(user.roles)) { - return {notSent: {user, reason: localizeMessage('invite.members.user-is-not-guest', 'This person is already a member of the workspace. Invite them as a member instead of a guest.')}}; + return { + notSent: { + user, + reason: defineMessage({ + id: 'invite.members.user-is-not-guest', + defaultMessage: 'This person is already a member of the workspace. Invite them as a member instead of a guest.', + }), + }, + }; } let memberOfAll = true; let memberOfAny = false; @@ -131,7 +181,15 @@ export async function sendGuestInviteForUser( } if (memberOfAll) { - return {notSent: {user, reason: localizeMessage('invite.guests.already-all-channels-member', 'This person is already a member of all the channels.')}}; + return { + notSent: { + user, + reason: defineMessage({ + id: 'invite.guests.already-all-channels-member', + defaultMessage: 'This person is already a member of all the channels.', + }), + }, + }; } try { @@ -143,13 +201,40 @@ export async function sendGuestInviteForUser( } } } catch (e) { - return {notSent: {user, reason: localizeMessage('invite.guests.unable-to-add-the-user-to-the-channels', 'Unable to add the guest to the channels.')}}; + return { + notSent: { + user, + reason: defineMessage({ + id: 'invite.guests.unable-to-add-the-user-to-the-channels', + defaultMessage: 'Unable to add the guest to the channels.', + }), + }, + }; } if (memberOfAny) { - return {notSent: {user, reason: localizeMessage('invite.guests.already-some-channels-member', 'This person is already a member of some of the channels.')}}; + return { + notSent: { + user, + reason: defineMessage({ + id: 'invite.guests.already-some-channels-member', + defaultMessage: 'This person is already a member of some of the channels.', + }), + }, + }; } - return {sent: {user, reason: {id: t('invite.guests.new-member'), message: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', values: {count: channels.length}}}}; + return { + sent: { + user, + reason: defineMessage({ + id: 'invite.guests.new-member', + defaultMessage: 'This guest has been added to the team and {count, plural, one {channel} other {channels}}.', + values: { + count: channels.length, + }, + }), + }, + }; } export function sendGuestsInvites( @@ -167,10 +252,10 @@ export function sendGuestsInvites( const results = await Promise.all(users.map((user) => sendGuestInviteForUser(dispatch, user, teamId, channels, members))); for (const result of results) { - if (result.sent) { + if ('sent' in result && result.sent) { sent.push(result.sent); } - if (result.notSent) { + if ('notSent' in result && result.notSent) { notSent.push(result.notSent); } } @@ -183,17 +268,28 @@ export function sendGuestsInvites( response = { data: emails.map((email) => ({ email, - error: {error: localizeMessage('invite.guests.unable-to-add-the-user-to-the-channels', 'Unable to add the guest to the channels.')}, + error: { + error: defineMessage({ + id: 'invite.guests.unable-to-add-the-user-to-the-channels', + defaultMessage: 'Unable to add the guest to the channels.', + }), + }, })) as unknown as TeamInviteWithError[], }; } if (response.error) { if (response.error.server_error_id === 'app.email.rate_limit_exceeded.app_error') { - response.error.message = localizeMessage('invite.rate-limit-exceeded', 'Invite emails rate limit exceeded.'); + response.error.message = defineMessage({ + id: 'invite.rate-limit-exceeded', + defaultMessage: 'Invite emails rate limit exceeded.', + }); } for (const email of emails) { - notSent.push({email, reason: response.error.message}); + notSent.push({ + email, + reason: response.error.message, + }); } } else { for (const res of (response.data || [])) { @@ -201,22 +297,36 @@ export function sendGuestsInvites( if (res.error.id === 'api.team.invite_members.unable_to_send_email_with_defaults.app_error' && isCurrentUserSystemAdmin(state)) { notSent.push({ email: res.email, - reason: { - id: t('admin.environment.smtp.smtpFailure'), - message: 'SMTP is not configured in System Console. Can be configured here.', - }, + reason: defineMessage({ + id: 'admin.environment.smtp.smtpFailure', + defaultMessage: 'SMTP is not configured in System Console. Can be configured here.', + }), path: ConsolePages.SMTP, }); } else { - notSent.push({email: res.email, reason: res.error.message}); + notSent.push({ + email: res.email, + reason: res.error.message, + }); } } else { - sent.push({email: res.email, reason: localizeMessage('invite.guests.added-to-channel', 'An invitation email has been sent.')}); + sent.push({ + email: res.email, + reason: defineMessage({ + id: 'invite.guests.added-to-channel', + defaultMessage: 'An invitation email has been sent.', + }), + }); } } } } - return {data: {sent, notSent}}; + return { + data: { + sent, + notSent, + }, + }; }; } @@ -240,9 +350,21 @@ export function sendMembersInvitesToChannels( for (const user of users) { const member = getTeamMember(state, teamId, user.id); if (isGuest(user.roles)) { - notSent.push({user, reason: localizeMessage('invite.members.user-is-guest', 'Contact your admin to make this guest a full member.')}); + notSent.push({ + user, + reason: defineMessage({ + id: 'invite.members.user-is-guest', + defaultMessage: 'Contact your admin to make this guest a full member.', + }), + }); } else if (member) { - notSent.push({user, reason: localizeMessage('invite.members.already-member', 'This person is already a team member.')}); + notSent.push({ + user, + reason: defineMessage({ + id: 'invite.members.already-member', + defaultMessage: 'This person is already a team member.', + }), + }); } else { usersToAdd.push(user); } @@ -252,15 +374,27 @@ export function sendMembersInvitesToChannels( const members = response.data || []; if (response.error) { for (const userToAdd of usersToAdd) { - notSent.push({user: userToAdd, reason: response.error.message}); + notSent.push({ + user: userToAdd, + reason: response.error.message, + }); } } else { for (const userToAdd of usersToAdd) { const memberWithError = members.find((m: TeamMemberWithError) => m.user_id === userToAdd.id && m.error); if (memberWithError) { - notSent.push({user: userToAdd, reason: memberWithError.error.message}); + notSent.push({ + user: userToAdd, + reason: memberWithError.error.message, + }); } else { - sent.push({user: userToAdd, reason: localizeMessage('invite.members.added-to-team', 'This member has been added to the team.')}); + sent.push({ + user: userToAdd, + reason: defineMessage({ + id: 'invite.members.added-to-team', + defaultMessage: 'This member has been added to the team.', + }), + }); } } } @@ -280,17 +414,25 @@ export function sendMembersInvitesToChannels( response = { data: emails.map((email) => ({ email, - error: {error: localizeMessage('invite.members.unable-to-add-the-user-to-the-team', 'Unable to add the user to the team.')}, + error: { + error: defineMessage({ + id: 'invite.members.unable-to-add-the-user-to-the-team', + defaultMessage: 'Unable to add the user to the team.', + }), + }, })) as unknown as TeamInviteWithError[], }; } const invitesWithErrors = response.data || []; if (response.error) { if (response.error.server_error_id === 'app.email.rate_limit_exceeded.app_error') { - response.error.message = localizeMessage('invite.rate-limit-exceeded', 'Invite emails rate limit exceeded.'); + response.error.message = defineMessage({id: 'invite.rate-limit-exceeded', defaultMessage: 'Invite emails rate limit exceeded.'}); } for (const email of emails) { - notSent.push({email, reason: response.error.message}); + notSent.push({ + email, + reason: response.error.message, + }); } } else { for (const email of emails) { @@ -299,17 +441,26 @@ export function sendMembersInvitesToChannels( if (inviteWithError.error.id === 'api.team.invite_members.unable_to_send_email_with_defaults.app_error' && isCurrentUserSystemAdmin(state)) { notSent.push({ email, - reason: { - id: t('admin.environment.smtp.smtpFailure'), - message: 'SMTP is not configured in System Console. Can be configured here.', - }, + reason: defineMessage({ + id: 'admin.environment.smtp.smtpFailure', + defaultMessage: 'SMTP is not configured in System Console. Can be configured here.', + }), path: ConsolePages.SMTP, }); } else { - notSent.push({email, reason: inviteWithError.error.message}); + notSent.push({ + email, + reason: inviteWithError.error.message, + }); } } else { - sent.push({email, reason: localizeMessage('invite.members.invite-sent', 'An invitation email has been sent.')}); + sent.push({ + email, + reason: defineMessage({ + id: 'invite.members.invite-sent', + defaultMessage: 'An invitation email has been sent.', + }), + }); } } } diff --git a/webapp/channels/src/components/channel_invite_modal/team_warning_banner/team_warning_banner.tsx b/webapp/channels/src/components/channel_invite_modal/team_warning_banner/team_warning_banner.tsx index 6683c732ae..8e619644f1 100644 --- a/webapp/channels/src/components/channel_invite_modal/team_warning_banner/team_warning_banner.tsx +++ b/webapp/channels/src/components/channel_invite_modal/team_warning_banner/team_warning_banner.tsx @@ -15,8 +15,6 @@ import AtMention from 'components/at_mention'; import type {Value} from 'components/multiselect/multiselect'; import SimpleTooltip from 'components/widgets/simple_tooltip'; -import {t} from 'utils/i18n'; - type UserProfileValue = Value & UserProfile; export type Props = { @@ -53,7 +51,7 @@ const TeamWarningBanner = (props: Props) => { return ( formatMessage( { - id: t('channel_invite.invite_team_members.guests.messageOverflow'), + id: 'channel_invite.invite_team_members.guests.messageOverflow', defaultMessage: '{firstUser} and {others} are guest users and need to first be invited to the team before you can add them to the channel. Once they\'ve joined the team, you can add them to this channel.', }, { @@ -98,7 +96,7 @@ const TeamWarningBanner = (props: Props) => { return ( formatMessage( { - id: t('channel_invite.invite_team_members.guests.message'), + id: 'channel_invite.invite_team_members.guests.message', defaultMessage: '{count, plural, =1 {{firstUser} is a guest user and needs} other {{users} are guest users and need}} to first be invited to the team before you can add them to the channel. Once they\'ve joined the team, you can add them to this channel.', }, { @@ -123,7 +121,7 @@ const TeamWarningBanner = (props: Props) => { if (users.length > 10) { return formatMessage( { - id: t('channel_invite.invite_team_members.messageOverflow'), + id: 'channel_invite.invite_team_members.messageOverflow', defaultMessage: 'You can add {firstUser} and {others} to this channel once they are members of the {team} team.', }, { @@ -168,7 +166,7 @@ const TeamWarningBanner = (props: Props) => { return ( formatMessage( { - id: t('channel_invite.invite_team_members.message'), + id: 'channel_invite.invite_team_members.message', defaultMessage: 'You can add {count, plural, =1 {{firstUser}} other {{users}}} to this channel once they are members of the {team} team.', }, { diff --git a/webapp/channels/src/components/invitation_modal/invitation_modal.test.tsx b/webapp/channels/src/components/invitation_modal/invitation_modal.test.tsx index ba8bc1654f..6136cca255 100644 --- a/webapp/channels/src/components/invitation_modal/invitation_modal.test.tsx +++ b/webapp/channels/src/components/invitation_modal/invitation_modal.test.tsx @@ -16,7 +16,7 @@ import {SelfHostedProducts} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; import {generateId} from 'utils/utils'; -import InvitationModal, {View, InvitationModal as BaseInvitationModal} from './invitation_modal'; +import InvitationModal, {View} from './invitation_modal'; import type {Props} from './invitation_modal'; import InviteView from './invite_view'; import NoPermissionsView from './no_permissions_view'; @@ -129,7 +129,7 @@ describe('InvitationModal', () => { , ); - wrapper.find(BaseInvitationModal).at(0).setState({view: View.RESULT}); + wrapper.find(InvitationModal).at(0).setState({view: View.RESULT}); wrapper.update(); expect(wrapper.find(ResultView).length).toBe(1); diff --git a/webapp/channels/src/components/invitation_modal/invitation_modal.tsx b/webapp/channels/src/components/invitation_modal/invitation_modal.tsx index 160d90ac6d..0d97fa3193 100644 --- a/webapp/channels/src/components/invitation_modal/invitation_modal.tsx +++ b/webapp/channels/src/components/invitation_modal/invitation_modal.tsx @@ -3,8 +3,7 @@ import React from 'react'; import {Modal} from 'react-bootstrap'; -import {injectIntl} from 'react-intl'; -import type {IntlShape} from 'react-intl'; +import {defineMessages} from 'react-intl'; import type {Channel} from '@mattermost/types/channels'; import type {Team} from '@mattermost/types/teams'; @@ -31,6 +30,17 @@ import './invitation_modal.scss'; // false means no backdrop type Backdrop = 'static' | boolean +const messages = defineMessages({ + notValidChannel: { + id: 'invitation-modal.confirm.not-valid-channel', + defaultMessage: 'Does not match a valid channel name.', + }, + notValidUserOrEmail: { + id: 'invitation-modal.confirm.not-valid-user-or-email', + defaultMessage: 'Does not match a valid user or email.', + }, +}); + export type Props = { actions: { searchChannels: (teamId: string, term: string) => Promise>; @@ -66,7 +76,6 @@ export type Props = { isCloud: boolean; canAddUsers: boolean; canInviteGuests: boolean; - intl: IntlShape; onExited: () => void; channelToInvite?: Channel; initialValue?: string; @@ -89,7 +98,7 @@ type State = { show: boolean; }; -export class InvitationModal extends React.PureComponent { +export default class InvitationModal extends React.PureComponent { defaultState: State = deepFreeze({ view: View.INVITE, termWithoutResults: null, @@ -206,20 +215,14 @@ export class InvitationModal extends React.PureComponent { if (this.state.invite.usersEmailsSearch !== '') { invites.notSent.push({ text: this.state.invite.usersEmailsSearch, - reason: this.props.intl.formatMessage({ - id: 'invitation-modal.confirm.not-valid-user-or-email', - defaultMessage: 'Does not match a valid user or email.', - }), + reason: messages.notValidUserOrEmail, }); } if (inviteAs === InviteType.GUEST && this.state.invite.inviteChannels.search !== '') { invites.notSent.push({ text: this.state.invite.inviteChannels.search, - reason: this.props.intl.formatMessage({ - id: 'invitation-modal.confirm.not-valid-channel', - defaultMessage: 'Does not match a valid channel name.', - }), + reason: messages.notValidChannel, }); } @@ -431,5 +434,3 @@ export class InvitationModal extends React.PureComponent { ); } } - -export default injectIntl(InvitationModal); diff --git a/webapp/channels/src/components/invitation_modal/invite_view.tsx b/webapp/channels/src/components/invitation_modal/invite_view.tsx index 95aaa5c517..b43240e4c5 100644 --- a/webapp/channels/src/components/invitation_modal/invite_view.tsx +++ b/webapp/channels/src/components/invitation_modal/invite_view.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames'; import React, {useEffect, useMemo} from 'react'; import {Modal} from 'react-bootstrap'; -import {FormattedMessage, useIntl} from 'react-intl'; +import {FormattedMessage, defineMessages, useIntl} from 'react-intl'; import {useSelector} from 'react-redux'; import type {Channel} from '@mattermost/types/channels'; @@ -20,7 +20,6 @@ import {getAnalyticsCategory} from 'components/onboarding_tasks'; import UsersEmailsInput from 'components/widgets/inputs/users_emails_input'; import {Constants} from 'utils/constants'; -import {t} from 'utils/i18n'; import {getSiteURL} from 'utils/url'; import {getTrackFlowRole, getRoleForTrackFlow, getSourceForTrackFlow} from 'utils/utils'; @@ -133,42 +132,37 @@ export default function InviteView(props: Props) { const errorProperties = { showError: false, - errorMessageId: '', - errorMessageDefault: '', + errorMessage: messages.exceededMaxBatch, errorMessageValues: { - text: '', + text: Constants.MAX_ADD_MEMBERS_BATCH.toString(), }, - extraErrorText: '', }; if (props.usersEmails.length > Constants.MAX_ADD_MEMBERS_BATCH) { errorProperties.showError = true; - errorProperties.errorMessageId = t( - 'invitation_modal.invite_members.exceeded_max_add_members_batch', - ); - errorProperties.errorMessageDefault = 'No more than **{text}** people can be invited at once'; - errorProperties.errorMessageValues.text = Constants.MAX_ADD_MEMBERS_BATCH.toString(); } - let placeholder = formatMessage({ - id: 'invite_modal.add_invites', - defaultMessage: 'Enter a name or email address', - }); - let noMatchMessageId = t( - 'invitation_modal.members.users_emails_input.no_user_found_matching', - ); - let noMatchMessageDefault = - 'No one found matching **{text}**. Enter their email to invite them.'; - - if (!props.emailInvitationsEnabled) { + let placeholder; + let noMatchMessage; + if (props.emailInvitationsEnabled) { + placeholder = formatMessage({ + id: 'invite_modal.add_invites', + defaultMessage: 'Enter a name or email address', + }); + noMatchMessage = messages.noUserFound; + } else { placeholder = formatMessage({ id: 'invitation_modal.members.search-and-add.placeholder-email-disabled', defaultMessage: 'Add members', }); - noMatchMessageId = t( - 'invitation_modal.members.users_emails_input.no_user_found_matching-email-disabled', - ); - noMatchMessageDefault = 'No one found matching **{text}**'; + noMatchMessage = messages.noUserFoundEmailDisabled; + } + + let validAddressMessage; + if (props.inviteType === InviteType.MEMBER) { + validAddressMessage = messages.validAddressMember; + } else { + validAddressMessage = messages.validAddressGuest; } const isInviteValid = useMemo(() => { @@ -233,12 +227,8 @@ export default function InviteView(props: Props) { props.onChangeUsersEmails(usersEmails); }} value={props.usersEmails} - validAddressMessageId={props.inviteType === InviteType.MEMBER ? t( - 'invitation_modal.members.users_emails_input.valid_email', - ) : t('invitation_modal.guests.users_emails_input.valid_email')} - validAddressMessageDefault={props.inviteType === InviteType.MEMBER ? 'Invite **{email}** as a team member' : 'Invite **{email}** as a guest'} - noMatchMessageId={noMatchMessageId} - noMatchMessageDefault={noMatchMessageDefault} + validAddressMessage={validAddressMessage} + noMatchMessage={noMatchMessage} onInputChange={props.onUsersInputChange} inputValue={props.usersEmailsSearch} emailInvitationsEnabled={props.emailInvitationsEnabled} @@ -287,3 +277,26 @@ export default function InviteView(props: Props) { ); } + +const messages = defineMessages({ + exceededMaxBatch: { + id: 'invitation_modal.invite_members.exceeded_max_add_members_batch', + defaultMessage: 'No more than **{text}** people can be invited at once', + }, + noUserFound: { + id: 'invitation_modal.members.users_emails_input.no_user_found_matching', + defaultMessage: 'No one found matching **{text}**. Enter their email to invite them.', + }, + noUserFoundEmailDisabled: { + id: 'invitation_modal.members.users_emails_input.no_user_found_matching-email-disabled', + defaultMessage: 'No one found matching **{text}**', + }, + validAddressGuest: { + id: 'invitation_modal.guests.users_emails_input.valid_email', + defaultMessage: 'Invite **{email}** as a guest', + }, + validAddressMember: { + id: 'invitation_modal.members.users_emails_input.valid_email', + defaultMessage: 'Invite **{email}** as a team member', + }, +}); diff --git a/webapp/channels/src/components/invitation_modal/result_table.test.tsx b/webapp/channels/src/components/invitation_modal/result_table.test.tsx index ed8d08b510..f6f92cd5a6 100644 --- a/webapp/channels/src/components/invitation_modal/result_table.test.tsx +++ b/webapp/channels/src/components/invitation_modal/result_table.test.tsx @@ -73,7 +73,7 @@ describe('ResultTable', () => { test('emails render as email', () => { props.rows = [{ email: 'aa@aa.aa', - reason: 'some reason', + reason: {id: 'some_reason', defaultMessage: 'some reason'}, }]; const wrapper = shallow(); expect(wrapper.find(EmailIcon).length).toBe(1); @@ -82,7 +82,7 @@ describe('ResultTable', () => { test('unsent invites render as unsent invites', () => { props.rows = [{ text: '@incomplete_userna', - reason: 'This was not a complete user', + reason: {id: 'incomplete_user', defaultMessage: 'This was not a complete user'}, }]; const wrapper = shallow(); expect(wrapper.find(AlertIcon).length).toBe(1); @@ -91,7 +91,7 @@ describe('ResultTable', () => { test('user invites render as users', () => { props.rows = [{ user: defaultUser, - reason: 'added successfuly', + reason: {id: 'success', defaultMessage: 'added successfully'}, }]; const wrapper = shallow(); expect(wrapper.find(Avatar).length).toBe(1); @@ -105,7 +105,7 @@ describe('ResultTable', () => { ...defaultUser, is_bot: true, }, - reason: 'added successfuly', + reason: {id: 'success', defaultMessage: 'added successfully'}, }]; const wrapper = shallow(); expect(wrapper.find(Avatar).length).toBe(1); @@ -119,7 +119,7 @@ describe('ResultTable', () => { ...defaultUser, roles: 'system_guest', }, - reason: 'added successfuly', + reason: {id: 'success', defaultMessage: 'added successfully'}, }]; const wrapper = shallow(); expect(wrapper.find(Avatar).length).toBe(1); diff --git a/webapp/channels/src/components/invitation_modal/result_table.tsx b/webapp/channels/src/components/invitation_modal/result_table.tsx index a0924c9780..da63468966 100644 --- a/webapp/channels/src/components/invitation_modal/result_table.tsx +++ b/webapp/channels/src/components/invitation_modal/result_table.tsx @@ -32,7 +32,7 @@ type InviteUser = { type I18nLike = { id: string; - message: string; + defaultMessage: string; values?: Record; } @@ -69,12 +69,9 @@ export default function ResultTable(props: Props) { ); } - function messageWithLink(reason: any, link: any) { + function messageWithLink(reason: I18nLike, link: string) { return intl.formatMessage( - { - id: reason.id, - defaultMessage: reason.message, - }, + reason, { a: (chunks: React.ReactNode | React.ReactNodeArray) => ( ); - } else if (invitation.path && invitation.reason) { - reason = messageWithLink(invitation.reason, invitation.path); } return ( diff --git a/webapp/channels/src/components/invitation_modal/result_view.tsx b/webapp/channels/src/components/invitation_modal/result_view.tsx index a871f4650b..249f877490 100644 --- a/webapp/channels/src/components/invitation_modal/result_view.tsx +++ b/webapp/channels/src/components/invitation_modal/result_view.tsx @@ -3,12 +3,10 @@ import React from 'react'; import {Modal} from 'react-bootstrap'; -import {FormattedMessage, useIntl} from 'react-intl'; +import {FormattedMessage} from 'react-intl'; import deepFreeze from 'mattermost-redux/utils/deep_freeze'; -import {t} from 'utils/i18n'; - import {InviteType} from './invite_as'; import ResultTable from './result_table'; import type {InviteResult} from './result_table'; @@ -40,7 +38,23 @@ type Props = { } & ResultState; export default function ResultView(props: Props) { - const {formatMessage} = useIntl(); + let inviteType; + if (props.inviteType === InviteType.MEMBER) { + inviteType = ( + + ); + } else { + inviteType = ( + + ); + } + return ( <> @@ -52,10 +66,7 @@ export default function ResultView(props: Props) { id='invite_modal.invited' defaultMessage='{inviteType} invited to {team_name}' values={{ - inviteType: formatMessage({ - id: props.inviteType === InviteType.MEMBER ? t('invite_modal.invited_members') : t('invite_modal.invited_guests'), - defaultMessage: props.inviteType === InviteType.MEMBER ? 'Members' : 'Guests', - }), + inviteType, team_name: props.currentTeamName, }} /> diff --git a/webapp/channels/src/components/preparing_workspace/invite_members.tsx b/webapp/channels/src/components/preparing_workspace/invite_members.tsx index 6fbf910e35..86b8ce04dd 100644 --- a/webapp/channels/src/components/preparing_workspace/invite_members.tsx +++ b/webapp/channels/src/components/preparing_workspace/invite_members.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {useState, useMemo, useEffect} from 'react'; -import {FormattedMessage, useIntl} from 'react-intl'; +import {FormattedMessage, defineMessages, useIntl} from 'react-intl'; import {CSSTransition} from 'react-transition-group'; import type {UserProfile} from '@mattermost/types/users'; @@ -10,7 +10,6 @@ import type {UserProfile} from '@mattermost/types/users'; import UsersEmailsInput from 'components/widgets/inputs/users_emails_input'; import {Constants} from 'utils/constants'; -import {t} from 'utils/i18n'; import Description from './description'; import InviteMembersLink from './invite_members_link'; @@ -64,10 +63,7 @@ const InviteMembers = (props: Props) => { }); const errorProperties = { showError: false, - errorMessageId: t( - 'invitation_modal.invite_members.exceeded_max_add_members_batch', - ), - errorMessageDefault: 'No more than **{text}** people can be invited at once', + errorMessage: messages.exceededMaxBatch, errorMessageValues: { text: Constants.MAX_ADD_MEMBERS_BATCH.toString(), }, @@ -115,8 +111,7 @@ const InviteMembers = (props: Props) => { inputValue={email} emailInvitationsEnabled={true} autoFocus={true} - validAddressMessageId={t('invitation_modal.members.users_emails_input.valid_email')} - validAddressMessageDefault={'Invite **{email}** as a team member'} + validAddressMessage={messages.validAddress} suppressNoOptionsMessage={suppressNoOptionsMessage} /> ); @@ -242,4 +237,15 @@ const InviteMembers = (props: Props) => { ); }; +const messages = defineMessages({ + exceededMaxBatch: { + id: 'invitation_modal.invite_members.exceeded_max_add_members_batch', + defaultMessage: 'No more than **{text}** people can be invited at once', + }, + validAddress: { + id: 'invitation_modal.members.users_emails_input.valid_email', + defaultMessage: 'Invite **{email}** as a team member', + }, +}); + export default InviteMembers; diff --git a/webapp/channels/src/components/widgets/inputs/users_emails_input.test.tsx b/webapp/channels/src/components/widgets/inputs/users_emails_input.test.tsx index 7dcb145f01..84c5e49d2b 100644 --- a/webapp/channels/src/components/widgets/inputs/users_emails_input.test.tsx +++ b/webapp/channels/src/components/widgets/inputs/users_emails_input.test.tsx @@ -25,8 +25,10 @@ describe('components/widgets/inputs/UsersEmailsInput', () => { last_name: 'user', } as UserProfile, ]} - errorMessageId='errorMessageId' - errorMessageDefault='errorMessageDefault' + errorMessage={{ + id: 'errorMessageId', + defaultMessage: 'errorMessageDefault', + }} onInputChange={jest.fn()} inputValue='' emailInvitationsEnabled={false} diff --git a/webapp/channels/src/components/widgets/inputs/users_emails_input.tsx b/webapp/channels/src/components/widgets/inputs/users_emails_input.tsx index 32bbdfa62c..2602dd6cdb 100644 --- a/webapp/channels/src/components/widgets/inputs/users_emails_input.tsx +++ b/webapp/channels/src/components/widgets/inputs/users_emails_input.tsx @@ -4,7 +4,8 @@ import classNames from 'classnames'; import React from 'react'; import type {RefObject} from 'react'; -import {FormattedMessage} from 'react-intl'; +import type {MessageDescriptor} from 'react-intl'; +import {FormattedMessage, defineMessages} from 'react-intl'; import {components} from 'react-select'; import type {FormatOptionLabelMeta, InputActionMeta, InputProps, OptionsType, Styles, ValueType} from 'react-select'; import AsyncCreatable from 'react-select/async-creatable'; @@ -24,7 +25,6 @@ import BotTag from 'components/widgets/tag/bot_tag'; import GuestTag from 'components/widgets/tag/guest_tag'; import Avatar from 'components/widgets/users/avatar'; -import {t} from 'utils/i18n'; import {getDisplayName, getLongDisplayNameParts, imageURLForUser} from 'utils/utils'; import './users_emails_input.scss'; @@ -37,18 +37,14 @@ type Props = { onBlur?: () => void; onChange: (change: Array) => void; showError?: boolean; - errorMessageId: string; - errorMessageDefault: string; + errorMessage?: MessageDescriptor; errorMessageValues?: Record; value: Array; onInputChange: (change: string) => void; inputValue: string; - noMatchMessageId?: string; - noMatchMessageDefault?: string; - validAddressMessageId?: string; - validAddressMessageDefault?: string; - loadingMessageId?: string; - loadingMessageDefault?: string; + noMatchMessage?: MessageDescriptor; + validAddressMessage?: MessageDescriptor; + loadingMessage?: MessageDescriptor; emailInvitationsEnabled: boolean; extraErrorText?: React.ReactNode; autoFocus?: boolean; @@ -67,14 +63,26 @@ type State = { const multipleValuesDelimiter = /[\s,;]+/; +const messages = defineMessages({ + loadingDefault: { + id: 'widgets.users_emails_input.loading', + defaultMessage: 'Loading', + }, + noMatchDefault: { + id: 'widgets.users_emails_input.no_user_found_matching', + defaultMessage: 'No one found matching **{text}**. Enter their email to invite them.', + }, + validAddressDefault: { + id: 'widgets.users_emails_input.valid_email', + defaultMessage: 'Add **{email}**', + }, +}); + export default class UsersEmailsInput extends React.PureComponent { static defaultProps = { - noMatchMessageId: t('widgets.users_emails_input.no_user_found_matching'), - noMatchMessageDefault: 'No one found matching **{text}**. Enter their email to invite them.', - validAddressMessageId: t('widgets.users_emails_input.valid_email'), - validAddressMessageDefault: 'Add **{email}**', - loadingMessageId: t('widgets.users_emails_input.loading'), - loadingMessageDefault: 'Loading', + noMatchMessage: messages.noMatchDefault, + validAddress: messages.validAddressDefault, + loadingMessage: messages.loadingDefault, showError: false, }; private selectRef: RefObject & { handleInputChange: (newValue: string, actionMeta: InputActionMeta | { action: 'custom' }) => string }>; @@ -110,8 +118,7 @@ export default class UsersEmailsInput extends React.PureComponent loadingMessage = (): string => { const text = ( ); @@ -200,8 +207,7 @@ export default class UsersEmailsInput extends React.PureComponent @@ -242,8 +248,7 @@ export default class UsersEmailsInput extends React.PureComponent
@@ -518,8 +523,7 @@ export default class UsersEmailsInput extends React.PureComponent