From 988ec95cac401e0b67d21f30e8422ae099a3b89b Mon Sep 17 00:00:00 2001 From: escapemanuele Date: Thu, 18 Jan 2024 17:54:29 +0100 Subject: [PATCH 1/3] Add invite button in calypso --- .../people/people-list-item/index.jsx | 41 ++++++++++++++++++- .../people/people-list-item/style.scss | 4 ++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/client/my-sites/people/people-list-item/index.jsx b/client/my-sites/people/people-list-item/index.jsx index a08fbf5c55502..5cbc2d52f299d 100644 --- a/client/my-sites/people/people-list-item/index.jsx +++ b/client/my-sites/people/people-list-item/index.jsx @@ -7,7 +7,7 @@ import { PureComponent } from 'react'; import { connect } from 'react-redux'; import PeopleProfile from 'calypso/my-sites/people/people-profile'; import { recordGoogleEvent } from 'calypso/state/analytics/actions'; -import { resendInvite } from 'calypso/state/invites/actions'; +import { sendInvites, resendInvite } from 'calypso/state/invites/actions'; import { isRequestingInviteResend, didInviteResendSucceed, @@ -55,6 +55,20 @@ class PeopleListItem extends PureComponent { ); }; + canReceiveInvite = () => { + const site = this.props.site; + const user = this.props.user; + return ( + user && + user.roles && + user.email && + ! user.linked_user_ID && + site && + site.slug && + ! this.props.isSelectable + ); + }; + canLinkToSubscriberProfile = () => { const { site, user } = this.props; @@ -106,6 +120,15 @@ class PeopleListItem extends PureComponent { this.props.resendInvite( siteId, inviteKey ); }; + onSendInvite = ( event ) => { + const { siteId, user } = this.props; + // Prevents navigation to invite-details screen and onClick event. + event.preventDefault(); + event.stopPropagation(); + + this.props.sendInvites( siteId, [ user.email ], user.roles[ 0 ], '', false ); + }; + renderInviteStatus = () => { const { type, invite, translate, requestingResend, resendSuccess, RevokeClearBtn } = this.props; const { isPending } = invite; @@ -135,6 +158,16 @@ class PeopleListItem extends PureComponent { ); }; + renderInviteButton = () => { + const { translate } = this.props; + + return ( +
+ +
+ ); + }; + render() { const { className, @@ -149,6 +182,7 @@ class PeopleListItem extends PureComponent { } = this.props; const isInvite = invite && ( 'invite' === type || 'invite-details' === type ); + const isLinkedUser = user && user.linked_user_ID; if ( isInvite && inviteWasDeleted ) { // After an invite is deleted and the user is returned to the @@ -163,10 +197,12 @@ class PeopleListItem extends PureComponent { { 'is-invite': isInvite, 'is-invite-details': type === 'invite-details', + 'is-not-linked-user': ! isLinkedUser && ! isInvite, }, className ); const canLinkToProfile = this.canLinkToProfile(); + const canReceiveInvite = this.canReceiveInvite(); const tagName = canLinkToProfile ? 'a' : 'span'; return ( @@ -187,6 +223,7 @@ class PeopleListItem extends PureComponent { /> + { canReceiveInvite && ! isInvite && this.renderInviteButton() } { isInvite && showStatus && this.renderInviteStatus() } { onRemove && ( @@ -225,5 +262,5 @@ export default connect( inviteWasDeleted, }; }, - { resendInvite, recordGoogleEvent } + { sendInvites, resendInvite, recordGoogleEvent } )( localize( PeopleListItem ) ); diff --git a/client/my-sites/people/people-list-item/style.scss b/client/my-sites/people/people-list-item/style.scss index a8bd8fbd98ce9..21c879d9c3d9a 100644 --- a/client/my-sites/people/people-list-item/style.scss +++ b/client/my-sites/people/people-list-item/style.scss @@ -49,6 +49,10 @@ } } +.people-list-item.is-not-linked-user { + background: var(--studio-gray-10); +} + .people-list-item__invite-status { align-self: center; flex-shrink: 0; From 8b62fedea564cb58d19d9a33e431c3a0a391569f Mon Sep 17 00:00:00 2001 From: escapemanuele Date: Fri, 19 Jan 2024 16:47:48 +0100 Subject: [PATCH 2/3] Filter our when invite has been sent --- .../my-sites/people/people-list-item/index.jsx | 18 +++++++++++++++--- .../people/people-list-item/style.scss | 3 ++- client/my-sites/people/team-members/index.tsx | 12 ++++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/client/my-sites/people/people-list-item/index.jsx b/client/my-sites/people/people-list-item/index.jsx index 5cbc2d52f299d..d729ce7d86b51 100644 --- a/client/my-sites/people/people-list-item/index.jsx +++ b/client/my-sites/people/people-list-item/index.jsx @@ -12,6 +12,7 @@ import { isRequestingInviteResend, didInviteResendSucceed, didInviteDeletionSucceed, + getSendInviteState, } from 'calypso/state/invites/selectors'; import './style.scss'; @@ -121,11 +122,15 @@ class PeopleListItem extends PureComponent { }; onSendInvite = ( event ) => { - const { siteId, user } = this.props; + const { requestingSend, siteId, user } = this.props; // Prevents navigation to invite-details screen and onClick event. event.preventDefault(); event.stopPropagation(); + if ( requestingSend?.progress ) { + return null; + } + this.props.sendInvites( siteId, [ user.email ], user.roles[ 0 ], '', false ); }; @@ -159,11 +164,17 @@ class PeopleListItem extends PureComponent { }; renderInviteButton = () => { - const { translate } = this.props; + const { translate, requestingSend } = this.props; return (
- +
); }; @@ -257,6 +268,7 @@ export default connect( return { requestingResend: isRequestingInviteResend( state, siteId, inviteKey ), resendSuccess: didInviteResendSucceed( state, siteId, inviteKey ), + requestingSend: getSendInviteState( state ), siteId, inviteKey, inviteWasDeleted, diff --git a/client/my-sites/people/people-list-item/style.scss b/client/my-sites/people/people-list-item/style.scss index 21c879d9c3d9a..c844843091f27 100644 --- a/client/my-sites/people/people-list-item/style.scss +++ b/client/my-sites/people/people-list-item/style.scss @@ -90,7 +90,8 @@ } .people-list-item__invite-resend.button, -.people-list-item__invite-revoke.button { +.people-list-item__invite-revoke.button, +.people-list-item__invite-send { vertical-align: baseline; margin-left: 0.75rem; diff --git a/client/my-sites/people/team-members/index.tsx b/client/my-sites/people/team-members/index.tsx index dcef31d67754b..f580106f069da 100644 --- a/client/my-sites/people/team-members/index.tsx +++ b/client/my-sites/people/team-members/index.tsx @@ -4,6 +4,7 @@ import InfiniteList from 'calypso/components/infinite-list'; import NoResults from 'calypso/my-sites/no-results'; import PeopleListItem from 'calypso/my-sites/people/people-list-item'; import { useSelector } from 'calypso/state'; +import { getPendingInvitesForSite } from 'calypso/state/invites/selectors'; import { getSelectedSite } from 'calypso/state/ui/selectors'; import PeopleListSectionHeader from '../people-list-section-header'; import type { UsersQuery } from './types'; @@ -20,12 +21,19 @@ function TeamMembers( props: Props ) { const translate = useTranslate(); const { search, usersQuery, showAddTeamMembersBtn = true } = props; const site = useSelector( ( state ) => getSelectedSite( state ) ); + const siteId = site?.ID as number; + const pendingInvites = useSelector( ( state ) => getPendingInvitesForSite( state, siteId ) ); + const pendingInvitesMails = pendingInvites?.map( ( invite ) => invite.user?.email ); const listKey = [ 'team-members', site?.ID, search ].join( '-' ); const { data, fetchNextPage, isLoading, isFetchingNextPage, hasNextPage } = usersQuery; const members = data?.users || []; - const membersTotal = data?.total; + const filteredMembers = members.filter( + ( member ) => ! pendingInvitesMails?.includes( member?.email ) + ); + + const membersTotal = filteredMembers.length; const addTeamMemberLink = `/people/new/${ site?.slug }`; @@ -89,7 +97,7 @@ function TeamMembers( props: Props ) { { isLoading && renderLoadingPeople() } Date: Tue, 23 Jan 2024 18:19:01 +0100 Subject: [PATCH 3/3] CSS for button --- client/my-sites/people/people-list-item/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/my-sites/people/people-list-item/index.jsx b/client/my-sites/people/people-list-item/index.jsx index d729ce7d86b51..3f8183d796409 100644 --- a/client/my-sites/people/people-list-item/index.jsx +++ b/client/my-sites/people/people-list-item/index.jsx @@ -167,7 +167,7 @@ class PeopleListItem extends PureComponent { const { translate, requestingSend } = this.props; return ( -
+