This repository has been archived by the owner on Mar 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
MM-37299 - invite members ab testing #8491
Merged
Merged
Changes from 4 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
1cad17a
MM-37299 - invite members ab testing
pvev ecb7bde
Merge branch 'master' into MM-37299-invite-members-ab-testing
mattermod a9ad706
add suggested UX changes
pvev 4c38f18
fix linter
pvev c6f93ae
final changes to UX
pvev eac4746
fix linter
pvev 54e0e81
fix snapshot
pvev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
components/sidebar/__snapshots__/invite_members.test.tsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`components/sidebar/invite_members_button should match snapshot 1`] = ` | ||
<InviteMembersButton | ||
buttonType="none" | ||
/> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
|
||
import React from 'react'; | ||
|
||
import {Provider} from 'react-redux'; | ||
import configureStore from 'redux-mock-store'; | ||
|
||
import {mountWithIntl} from 'tests/helpers/intl-test-helper'; | ||
|
||
import {InviteMembersBtnLocations} from 'mattermost-redux/constants/config'; | ||
|
||
import InviteMembersButton from 'components/sidebar/invite_members_button'; | ||
|
||
import * as preferences from 'mattermost-redux/selectors/entities/preferences'; | ||
|
||
describe('components/sidebar/invite_members_button', () => { | ||
// required state to mount using the provider | ||
const state = { | ||
entities: { | ||
general: { | ||
config: { | ||
FeatureFlagInviteMembersButton: 'user_icon', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
const mockStore = configureStore(); | ||
const store = mockStore(state); | ||
|
||
test('should match snapshot', () => { | ||
const wrapper = mountWithIntl( | ||
<InviteMembersButton buttonType={InviteMembersBtnLocations.NONE}/>, | ||
); | ||
|
||
expect(wrapper).toMatchSnapshot(); | ||
}); | ||
|
||
test('should return the user icon button when button type is USER_ICON', () => { | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
//@ts-ignore | ||
preferences.getInviteMembersButtonLocation = jest.fn().mockReturnValue('user_icon'); | ||
|
||
const wrapper = mountWithIntl( | ||
<Provider store={store}> | ||
<InviteMembersButton buttonType={InviteMembersBtnLocations.USER_ICON}/> | ||
</Provider>, | ||
); | ||
expect(wrapper.find('i').prop('className')).toBe('icon-account-plus-outline'); | ||
}); | ||
|
||
test('should return the left hand side button when button type is LHS_BUTTON', () => { | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
//@ts-ignore | ||
preferences.getInviteMembersButtonLocation = jest.fn().mockReturnValue('lhs_button'); | ||
const wrapper = mountWithIntl( | ||
<Provider store={store}> | ||
<InviteMembersButton buttonType={InviteMembersBtnLocations.LHS_BUTTON}/> | ||
</Provider>, | ||
); | ||
expect(wrapper.find('i').prop('className')).toBe('icon-plus-box'); | ||
}); | ||
|
||
test('should return the sticky to the bottom button when button type is STICKY', () => { | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
//@ts-ignore | ||
preferences.getInviteMembersButtonLocation = jest.fn().mockReturnValue('sticky_button'); | ||
const wrapper = mountWithIntl( | ||
<Provider store={store}> | ||
<InviteMembersButton buttonType={InviteMembersBtnLocations.STICKY}/> | ||
</Provider>, | ||
); | ||
expect(wrapper.find('i').prop('className')).toBe('icon-account-plus-outline'); | ||
}); | ||
|
||
test('should returnnothing when button type is NONE', () => { | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
//@ts-ignore | ||
preferences.getInviteMembersButtonLocation = jest.fn().mockReturnValue('none'); | ||
const wrapper = mountWithIntl( | ||
<Provider store={store}> | ||
<InviteMembersButton buttonType={InviteMembersBtnLocations.NONE}/> | ||
</Provider>, | ||
); | ||
expect(wrapper.find('i').exists()).toBeFalsy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
|
||
import React from 'react'; | ||
import {Tooltip} from 'react-bootstrap'; | ||
import {useIntl, FormattedMessage} from 'react-intl'; | ||
|
||
import store from 'stores/redux_store.jsx'; | ||
|
||
import {InviteMembersBtnLocations} from 'mattermost-redux/constants/config'; | ||
|
||
import OverlayTrigger from 'components/overlay_trigger'; | ||
import ToggleModalButtonRedux from 'components/toggle_modal_button_redux'; | ||
import InvitationModal from 'components/invitation_modal'; | ||
|
||
import {trackEvent} from 'actions/telemetry_actions.jsx'; | ||
|
||
import {ModalIdentifiers} from 'utils/constants'; | ||
|
||
import {getInviteMembersButtonLocation} from 'mattermost-redux/selectors/entities/preferences'; | ||
|
||
type Props = { | ||
buttonType: string; | ||
}; | ||
|
||
const InviteMembersButton: React.FC<Props> = (props: Props): JSX.Element | null => { | ||
const intl = useIntl(); | ||
const inviteMembersButtonLocation = getInviteMembersButtonLocation(store.getState()); | ||
|
||
const tooltip = ( | ||
<Tooltip | ||
id='new-group-tooltip' | ||
className='hidden-xs' | ||
> | ||
<FormattedMessage | ||
id={'sidebar_left.inviteUsers'} | ||
defaultMessage='Invite Users' | ||
/> | ||
</Tooltip> | ||
); | ||
|
||
const addTelemetry = () => { | ||
trackEvent('invite_members_button', props.buttonType); | ||
}; | ||
|
||
const OpenModal = (props: {children: React.ReactNode}) => { | ||
return ( | ||
<ToggleModalButtonRedux | ||
accessibilityLabel={intl.formatMessage({id: 'sidebar_left.inviteUsers', defaultMessage: 'Invite Users'})} | ||
id='introTextInvite' | ||
className='intro-links color--link cursor--pointer' | ||
modalId={ModalIdentifiers.INVITATION} | ||
dialogType={InvitationModal} | ||
onClick={addTelemetry} | ||
> | ||
{props.children} | ||
</ToggleModalButtonRedux> | ||
); | ||
}; | ||
|
||
const userIcon = ( | ||
<OverlayTrigger | ||
delayShow={500} | ||
placement='top' | ||
overlay={tooltip} | ||
> | ||
<OpenModal> | ||
<div | ||
className='SidebarChannelNavigator_inviteUsers' | ||
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.inviteUsers', defaultMessage: 'Invite Users'})} | ||
> | ||
<i className='icon-account-plus-outline'/> | ||
</div> | ||
</OpenModal> | ||
</OverlayTrigger> | ||
); | ||
|
||
const lhsButton = ( | ||
<OpenModal> | ||
<li | ||
className='SidebarChannelNavigator_inviteMembersLhsButton' | ||
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.inviteUsers', defaultMessage: 'Invite Members'})} | ||
> | ||
<i className='icon-plus-box'/> | ||
<FormattedMessage | ||
id={'sidebar_left.inviteMembers'} | ||
defaultMessage='Invite Members' | ||
/> | ||
</li> | ||
</OpenModal> | ||
); | ||
|
||
const stickyButton = ( | ||
<div | ||
className='SidebarChannelNavigator_inviteUsersSticky' | ||
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.inviteUsers', defaultMessage: 'Invite Members'})} | ||
> | ||
<OpenModal> | ||
<i className='icon-account-plus-outline'/> | ||
<FormattedMessage | ||
id={'sidebar_left.inviteMembers'} | ||
defaultMessage='Invite Members' | ||
/> | ||
</OpenModal> | ||
</div> | ||
); | ||
|
||
let inviteButton; | ||
|
||
switch (props.buttonType) { | ||
case InviteMembersBtnLocations.USER_ICON: | ||
inviteButton = userIcon; | ||
break; | ||
case InviteMembersBtnLocations.STICKY: | ||
inviteButton = stickyButton; | ||
break; | ||
case InviteMembersBtnLocations.LHS_BUTTON: | ||
inviteButton = lhsButton; | ||
break; | ||
default: | ||
inviteButton = null; | ||
break; | ||
} | ||
|
||
if (inviteMembersButtonLocation !== props.buttonType || inviteMembersButtonLocation === InviteMembersBtnLocations.NONE) { | ||
inviteButton = null; | ||
} | ||
|
||
return ( | ||
<> | ||
{inviteButton} | ||
</> | ||
); | ||
}; | ||
|
||
export default InviteMembersButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,14 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
export const enum CollapsedThreads { | ||
export enum CollapsedThreads { | ||
DISABLED = 'disabled', | ||
DEFAULT_ON = 'default_on', | ||
DEFAULT_OFF = 'default_off', | ||
} | ||
|
||
export enum InviteMembersBtnLocations { | ||
NONE = 'none', | ||
STICKY = 'sticky_button', | ||
LHS_BUTTON = 'lhs_button', | ||
USER_ICON = 'user_icon', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -284,3 +284,7 @@ export function isTimedDNDEnabled(state: GlobalState): boolean { | |
getFeatureFlagValue(state, 'TimedDND') === 'true' | ||
); | ||
} | ||
|
||
export function getInviteMembersButtonLocation(state: GlobalState): string | undefined { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this return |
||
return getFeatureFlagValue(state, 'InviteMembersButton'); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add some unit tests for this new component