diff --git a/components/channel_view/channel_view.jsx b/components/channel_view/channel_view.jsx
index a457b142891e..4bbfdc9a2f32 100644
--- a/components/channel_view/channel_view.jsx
+++ b/components/channel_view/channel_view.jsx
@@ -29,12 +29,15 @@ export default class ChannelView extends React.PureComponent {
}).isRequired,
showTutorial: PropTypes.bool.isRequired,
showNextSteps: PropTypes.bool.isRequired,
+ showNextStepsTips: PropTypes.bool.isRequired,
+ isOnboardingHidden: PropTypes.bool.isRequired,
showNextStepsEphemeral: PropTypes.bool.isRequired,
channelIsArchived: PropTypes.bool.isRequired,
viewArchivedChannels: PropTypes.bool.isRequired,
actions: PropTypes.shape({
goToLastViewedChannel: PropTypes.func.isRequired,
setShowNextStepsView: PropTypes.func.isRequired,
+ getProfiles: PropTypes.func.isRequired,
}),
isCloud: PropTypes.bool.isRequired,
};
@@ -97,8 +100,9 @@ export default class ChannelView extends React.PureComponent {
this.props.actions.goToLastViewedChannel();
}
- componentDidMount() {
- if (this.props.showNextSteps) {
+ async componentDidMount() {
+ await this.props.actions.getProfiles();
+ if ((this.props.showNextSteps || this.props.showNextStepsTips) && !this.props.isOnboardingHidden) {
this.props.actions.setShowNextStepsView(true);
}
}
diff --git a/components/channel_view/channel_view.test.jsx b/components/channel_view/channel_view.test.jsx
index 2b2b219f1ffd..13c3556de357 100644
--- a/components/channel_view/channel_view.test.jsx
+++ b/components/channel_view/channel_view.test.jsx
@@ -17,6 +17,8 @@ describe('components/channel_view', () => {
},
showTutorial: false,
showNextSteps: false,
+ showNextStepsTips: false,
+ isOnboardingHidden: true,
showNextStepsEphemeral: false,
channelIsArchived: false,
viewArchivedChannels: false,
@@ -24,6 +26,7 @@ describe('components/channel_view', () => {
actions: {
goToLastViewedChannel: jest.fn(),
setShowNextStepsView: jest.fn(),
+ getProfiles: jest.fn(),
},
};
diff --git a/components/channel_view/index.js b/components/channel_view/index.js
index e48c36275654..040cee1f45ba 100644
--- a/components/channel_view/index.js
+++ b/components/channel_view/index.js
@@ -12,12 +12,14 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {withRouter} from 'react-router-dom';
+import {getProfiles} from 'mattermost-redux/actions/users';
+
import {getDirectTeammate} from 'utils/utils.jsx';
import {TutorialSteps, Preferences} from 'utils/constants';
import {goToLastViewedChannel} from 'actions/views/channel';
import {setShowNextStepsView} from 'actions/views/next_steps';
-import {showNextSteps} from 'components/next_steps_view/steps';
+import {isOnboardingHidden, showNextSteps, showNextStepsTips} from 'components/next_steps_view/steps';
import ChannelView from './channel_view.jsx';
@@ -60,6 +62,8 @@ function mapStateToProps(state) {
deactivatedChannel: channel ? getDeactivatedChannel(state, channel.id) : false,
showTutorial: enableTutorial && tutorialStep <= TutorialSteps.INTRO_SCREENS,
showNextSteps: showNextSteps(state),
+ showNextStepsTips: showNextStepsTips(state),
+ isOnboardingHidden: isOnboardingHidden(state),
showNextStepsEphemeral: state.views.nextSteps.show,
channelIsArchived: channel ? channel.delete_at !== 0 : false,
viewArchivedChannels,
@@ -72,6 +76,7 @@ function mapDispatchToProps(dispatch) {
actions: bindActionCreators({
setShowNextStepsView,
goToLastViewedChannel,
+ getProfiles,
}, dispatch),
};
}
diff --git a/components/main_menu/index.jsx b/components/main_menu/index.jsx
index 93424ea4eccd..74251dd624c0 100644
--- a/components/main_menu/index.jsx
+++ b/components/main_menu/index.jsx
@@ -4,7 +4,7 @@
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
-import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
+import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {
getMyTeams,
getJoinableTeamIds,
@@ -24,7 +24,11 @@ import {showMentions, showFlaggedPosts, closeRightHandSide, closeMenu as closeRh
import {openModal} from 'actions/views/modals';
import {getRhsState} from 'selectors/rhs';
-import {nextStepsNotFinished} from 'components/next_steps_view/steps';
+import {
+ showOnboarding,
+ showNextStepsTips,
+ showNextSteps,
+} from 'components/next_steps_view/steps';
import MainMenu from './main_menu.jsx';
@@ -32,7 +36,6 @@ function mapStateToProps(state) {
const config = getConfig(state);
const currentTeam = getCurrentTeam(state);
const currentUser = getCurrentUser(state);
- const license = getLicense(state);
const appDownloadLink = config.AppDownloadLink;
const enableCommands = config.EnableCommands === 'true';
@@ -92,13 +95,14 @@ function mapStateToProps(state) {
currentUser,
isMentionSearch: rhsState === RHSStates.MENTION,
teamIsGroupConstrained: Boolean(currentTeam.group_constrained),
- isLicensedForLDAPGroups: state.entities.general.license.LDAPGroups === 'true',
+ isLicensedForLDAPGroups:
+ state.entities.general.license.LDAPGroups === 'true',
userLimit: getConfig(state).ExperimentalCloudUserLimit,
currentUsers: state.entities.admin.analytics.TOTAL_USERS,
- userIsAdmin: isAdmin(
- getMyTeamMember(state, currentTeam.id).roles,
- ),
- showGettingStarted: !state.views.nextSteps.show && nextStepsNotFinished(state) && license.Cloud === 'true',
+ userIsAdmin: isAdmin(getMyTeamMember(state, currentTeam.id).roles),
+ showGettingStarted: showOnboarding(state),
+ showNextStepsTips: showNextStepsTips(state),
+ showNextSteps: showNextSteps(state),
};
}
diff --git a/components/main_menu/main_menu.jsx b/components/main_menu/main_menu.jsx
index 0ab0780fade5..233911df10a6 100644
--- a/components/main_menu/main_menu.jsx
+++ b/components/main_menu/main_menu.jsx
@@ -65,6 +65,7 @@ class MainMenu extends React.PureComponent {
userIsAdmin: PropTypes.bool,
showGettingStarted: PropTypes.bool.isRequired,
intl: intlShape.isRequired,
+ showNextStepsTips: PropTypes.bool,
actions: PropTypes.shape({
openModal: PropTypes.func.isRequred,
showMentions: PropTypes.func,
@@ -371,7 +372,7 @@ class MainMenu extends React.PureComponent {
id='gettingStarted'
show={this.props.showGettingStarted}
onClick={() => this.props.actions.unhideNextSteps()}
- text={formatMessage({id: 'navbar_dropdown.gettingStarted', defaultMessage: 'Getting Started'})}
+ text={formatMessage({id: this.props.showNextStepsTips ? 'sidebar_next_steps.tipsAndNextSteps' : 'navbar_dropdown.gettingStarted', defaultMessage: this.props.showNextStepsTips ? 'Tips & Next Steps' : 'Getting Started'})}
/>
{
const wrapper = shallow(
,
);
+ wrapper.setState({show: true});
expect(wrapper).toMatchSnapshot();
});
diff --git a/components/next_steps_view/next_steps_view.tsx b/components/next_steps_view/next_steps_view.tsx
index a9b8068334d7..068a9a629111 100644
--- a/components/next_steps_view/next_steps_view.tsx
+++ b/components/next_steps_view/next_steps_view.tsx
@@ -12,7 +12,7 @@ import {pageVisited, trackEvent} from 'actions/diagnostics_actions';
import Accordion from 'components/accordion';
import Card from 'components/card/card';
import {getAnalyticsCategory} from 'components/next_steps_view/step_helpers';
-import {Preferences} from 'utils/constants';
+import {Preferences, RecommendedNextSteps} from 'utils/constants';
import loadingIcon from 'images/spinner-48x48-blue.apng';
@@ -43,31 +43,37 @@ type State = {
showFinalScreen: boolean;
showTransitionScreen: boolean;
animating: boolean;
+ show: boolean;
}
export default class NextStepsView extends React.PureComponent {
constructor(props: Props) {
super(props);
-
this.state = {
showFinalScreen: false,
showTransitionScreen: false,
animating: false,
+ show: false,
};
}
async componentDidMount() {
await this.props.actions.getProfiles();
- pageVisited(getAnalyticsCategory(this.props.isFirstAdmin), 'pageview_welcome');
- // If all steps are complete, don't render this and skip to the tips screen
- if (this.getIncompleteStep() === null) {
+ // If all steps are complete, or user has skipped, don't render this and skip to the tips screen
+ if (this.getIncompleteStep() === null || this.checkStepsSkipped()) {
this.showFinalScreenNoAnimation();
}
-
+ // eslint-disable-next-line react/no-did-mount-set-state
+ this.setState({show: true});
+ pageVisited(getAnalyticsCategory(this.props.isFirstAdmin), 'pageview_welcome');
this.props.actions.closeRightHandSide();
}
+ checkStepsSkipped = () => {
+ return this.props.preferences.some((pref) => pref.name === RecommendedNextSteps.SKIP && pref.value === 'true');
+ }
+
getStartingStep = () => {
for (let i = 0; i < this.props.steps.length; i++) {
if (!this.isStepComplete(this.props.steps[i].id)) {
@@ -102,6 +108,16 @@ export default class NextStepsView extends React.PureComponent {
};
}
+ onSkipAll = async () => {
+ this.showFinalScreen();
+ this.props.actions.savePreferences(this.props.currentUser.id, [{
+ user_id: this.props.currentUser.id,
+ category: Preferences.RECOMMENDED_NEXT_STEPS,
+ name: RecommendedNextSteps.SKIP,
+ value: 'true',
+ }]);
+ }
+
onFinish = (setExpanded: (expandedKey: string) => void) => {
return async (id: string) => {
const stepIndex = this.getStepNumberFromId(id);
@@ -120,7 +136,7 @@ export default class NextStepsView extends React.PureComponent {
showFinalScreenNoAnimation = () => {
pageVisited(getAnalyticsCategory(this.props.isFirstAdmin), 'pageview_tips_next_steps');
- this.setState({showFinalScreen: true});
+ this.setState({showFinalScreen: true, animating: false});
}
showFinalScreen = () => {
@@ -287,7 +303,7 @@ export default class NextStepsView extends React.PureComponent {