From 0e801a4e70f3d9c8e3cf929aa2f7ac201ca87b52 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Wed, 28 Oct 2015 15:04:17 -0400 Subject: Add tutorial intro screens for new users. --- .../components/tutorial/tutorial_intro_screens.jsx | 150 +++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 web/react/components/tutorial/tutorial_intro_screens.jsx (limited to 'web/react/components/tutorial') diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx new file mode 100644 index 000000000..d7568e4cd --- /dev/null +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -0,0 +1,150 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +const UserStore = require('../../stores/user_store.jsx'); +const ChannelStore = require('../../stores/channel_store.jsx'); +const TeamStore = require('../../stores/team_store.jsx'); +const PreferenceStore = require('../../stores/preference_store.jsx'); +const Utils = require('../../utils/utils.jsx'); +const AsyncClient = require('../../utils/async_client.jsx'); + +const Constants = require('../../utils/constants.jsx'); +const Preferences = Constants.Preferences; + +export default class TutorialIntroScreens extends React.Component { + constructor(props) { + super(props); + + this.handleNext = this.handleNext.bind(this); + this.createScreen = this.createScreen.bind(this); + + this.state = {screen: 0}; + } + handleNext() { + if (this.state.screen < 2) { + this.setState({screen: this.state.screen + 1}); + return; + } + + Utils.switchChannel(ChannelStore.getByName(Constants.DEFAULT_CHANNEL)); + + const preference = PreferenceStore.setPreference(Preferences.TUTORIAL_INTRO_COMPLETE, UserStore.getCurrentId(), 'true'); + AsyncClient.savePreferences([preference]); + } + createScreen() { + switch (this.state.screen) { + case 0: + return this.createScreenOne(); + case 1: + return this.createScreenTwo(); + case 2: + return this.createScreenThree(); + } + } + createScreenOne() { + return ( +
+

{'Welcome to:'}

+

{'Mattermost'}

+
+ {'Your team communications all in one place,'} +
+ {'instantly searchable and available anywhere.'} +

+ {'Keep your team connected to help them'} +
+ {'achieve what matters most.'} +

+ {'[ x ][ ][ ]'} +
+ ); + } + createScreenTwo() { + return ( +
+

{'How Mattermost works:'}

+
+ {'Communication happens in public discussion channels,'} +
+ {'private groups and direct messages.'} +

+ {'Everything is archived and searchable from'} +
+ {'any web-enabled laptop, tablet or phone.'} +

+ {'[ ][ x ][ ]'} +
+ ); + } + createScreenThree() { + const team = TeamStore.getCurrent(); + let inviteModalLink; + if (team.type === Constants.INVITE_TEAM) { + inviteModalLink = ( + + {'Invite teammates'} + + ); + } else { + inviteModalLink = ( + + ); + } + + return ( +
+

{'You’re all set'}

+
+ {inviteModalLink} + {' when you’re ready.'} +

+ {'Need anything, just email us at '} +
+ {'feedback@mattermost.com.'} + +

+ {'Click “Next” to enter Town Square. This is the first channel'} +
+ {'teammates see when they sign up - use it for posting updates'} +
+ {'everyone needs to know.'} +

+ {'[ ][ ][ x ]'} +
+ ); + } + render() { + const screen = this.createScreen(); + + return ( +
+ {screen} +

+ +
+ ); + } +} -- cgit v1.2.3-1-g7c22 From 97449a102e5592358a4f7f22d6720a9af21286a1 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 30 Oct 2015 11:35:16 -0400 Subject: Add tutorial popovers --- .../components/tutorial/tutorial_intro_screens.jsx | 14 ++- web/react/components/tutorial/tutorial_tip.jsx | 108 +++++++++++++++++++++ 2 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 web/react/components/tutorial/tutorial_tip.jsx (limited to 'web/react/components/tutorial') diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx index d7568e4cd..d423b4f1b 100644 --- a/web/react/components/tutorial/tutorial_intro_screens.jsx +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -18,21 +18,25 @@ export default class TutorialIntroScreens extends React.Component { this.handleNext = this.handleNext.bind(this); this.createScreen = this.createScreen.bind(this); - this.state = {screen: 0}; + this.state = {currentScreen: 0}; } handleNext() { - if (this.state.screen < 2) { - this.setState({screen: this.state.screen + 1}); + if (this.state.currentScreen < 2) { + this.setState({currentScreen: this.state.currentScreen + 1}); return; } Utils.switchChannel(ChannelStore.getByName(Constants.DEFAULT_CHANNEL)); - const preference = PreferenceStore.setPreference(Preferences.TUTORIAL_INTRO_COMPLETE, UserStore.getCurrentId(), 'true'); + let preference = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); + + const newValue = (parseInt(preference.value, 10) + 1).toString(); + + preference = PreferenceStore.setPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), newValue); AsyncClient.savePreferences([preference]); } createScreen() { - switch (this.state.screen) { + switch (this.state.currentScreen) { case 0: return this.createScreenOne(); case 1: diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx new file mode 100644 index 000000000..166d10d8a --- /dev/null +++ b/web/react/components/tutorial/tutorial_tip.jsx @@ -0,0 +1,108 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +const UserStore = require('../../stores/user_store.jsx'); +const PreferenceStore = require('../../stores/preference_store.jsx'); +const AsyncClient = require('../../utils/async_client.jsx'); + +const Constants = require('../../utils/constants.jsx'); +const Preferences = Constants.Preferences; + +const Overlay = ReactBootstrap.Overlay; + +export default class TutorialTip extends React.Component { + constructor(props) { + super(props); + + this.handleNext = this.handleNext.bind(this); + this.toggle = this.toggle.bind(this); + + this.state = {currentScreen: 0, show: false}; + } + toggle() { + const show = !this.state.show; + this.setState({show}); + + if (!show && this.state.currentScreen >= this.props.screens.length - 1) { + let preference = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); + + const newValue = (parseInt(preference.value, 10) + 1).toString(); + + preference = PreferenceStore.setPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), newValue); + AsyncClient.savePreferences([preference]); + } + } + handleNext() { + if (this.state.currentScreen < this.props.screens.length - 1) { + this.setState({currentScreen: this.state.currentScreen + 1}); + return; + } + + this.toggle(); + } + skipTutorial(e) { + e.preventDefault(); + const preference = PreferenceStore.setPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), '999'); + AsyncClient.savePreferences([preference]); + } + render() { + const buttonText = this.state.currentScreen === this.props.screens.length - 1 ? 'Okay' : 'Next'; + + const dots = []; + if (this.props.screens.length > 1) { + for (let i = 0; i < this.props.screens.length; i++) { + if (i === this.state.currentScreen) { + dots.push({'[ x ]'}); + } else { + dots.push({'[ ]'}); + } + } + } + + return ( +
+ + + this.refs.target} + > +
+ {this.props.screens[this.state.currentScreen]} +
+ {dots} + +
+ + {'Seen this before? '} + + {'Opt out of these tips.'} + + +
+
+
+ ); + } +} + +TutorialTip.propTypes = { + screens: React.PropTypes.array.isRequired, + placement: React.PropTypes.string.isRequired +}; -- cgit v1.2.3-1-g7c22 From 393d253021e6b119ec35b92f9eeaa6f2d255008f Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Mon, 2 Nov 2015 11:40:53 +0500 Subject: Updating tutorial screens --- .../components/tutorial/tutorial_intro_screens.jsx | 107 +++++++++++---------- web/react/components/tutorial/tutorial_tip.jsx | 51 ++++++---- 2 files changed, 85 insertions(+), 73 deletions(-) (limited to 'web/react/components/tutorial') diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx index d423b4f1b..b37aac27c 100644 --- a/web/react/components/tutorial/tutorial_intro_screens.jsx +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -20,6 +20,10 @@ export default class TutorialIntroScreens extends React.Component { this.state = {currentScreen: 0}; } + componentDidMount() { + const height = $(window).outerHeight() - 120; + $('.tutorial-steps__container').css('height', `${height}px`); + } handleNext() { if (this.state.currentScreen < 2) { this.setState({currentScreen: this.state.currentScreen + 1}); @@ -48,35 +52,29 @@ export default class TutorialIntroScreens extends React.Component { createScreenOne() { return (
-

{'Welcome to:'}

-

{'Mattermost'}

-
- {'Your team communications all in one place,'} -
- {'instantly searchable and available anywhere.'} -

- {'Keep your team connected to help them'} -
- {'achieve what matters most.'} -

- {'[ x ][ ][ ]'} +

{'Welcome to:'}

+

{'Mattermost'}

+

{'Your team communications all in one place, instantly searchable and available anywhere.'}

+

{'Keep your team connected to help them achieve what matters most.'}

+
+
+
+
+
); } createScreenTwo() { return (
-

{'How Mattermost works:'}

-
- {'Communication happens in public discussion channels,'} -
- {'private groups and direct messages.'} -

- {'Everything is archived and searchable from'} -
- {'any web-enabled laptop, tablet or phone.'} -

- {'[ ][ x ][ ]'} +

{'How Mattermost works:'}

+

{'Communication happens in public discussion channels, private groups and direct messages.'}

+

{'Everything is archived and searchable from any web-enabled laptop, tablet or phone.'}

+
+
+
+
+
); } @@ -111,26 +109,26 @@ export default class TutorialIntroScreens extends React.Component { return (
-

{'You’re all set'}

-
- {inviteModalLink} - {' when you’re ready.'} -

- {'Need anything, just email us at '} - - {'feedback@mattermost.com.'} - -

- {'Click “Next” to enter Town Square. This is the first channel'} -
- {'teammates see when they sign up - use it for posting updates'} -
- {'everyone needs to know.'} -

- {'[ ][ ][ x ]'} +

{'You’re all set'}

+

+ {inviteModalLink} + {' when you’re ready.'} +

+

+ {'Need anything, just email us at '} + + {'feedback@mattermost.com.'} + +

+ {'Click “Next” to enter Town Square. This is the first channel teammates see when they sign up - use it for posting updates everyone needs to know.'} +
+
+
+
+
); } @@ -138,16 +136,19 @@ export default class TutorialIntroScreens extends React.Component { const screen = this.createScreen(); return ( -
- {screen} -

- +
+
+
+ {screen} + +
+
); } diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx index 166d10d8a..3482a7cfa 100644 --- a/web/react/components/tutorial/tutorial_tip.jsx +++ b/web/react/components/tutorial/tutorial_tip.jsx @@ -52,9 +52,19 @@ export default class TutorialTip extends React.Component { if (this.props.screens.length > 1) { for (let i = 0; i < this.props.screens.length; i++) { if (i === this.state.currentScreen) { - dots.push({'[ x ]'}); + dots.push( +
+ ); } else { - dots.push({'[ ]'}); + dots.push( +
+ ); } } } @@ -63,7 +73,8 @@ export default class TutorialTip extends React.Component {
@@ -77,24 +88,24 @@ export default class TutorialTip extends React.Component { >
{this.props.screens[this.state.currentScreen]} -
- {dots} - -
- - {'Seen this before? '} - {dots}
+
+ +
+ {'Seen this before? '} + + {'Opt out of these tips.'} + +
+
-- cgit v1.2.3-1-g7c22 From dedbc122c666a68de4759be7b7c70e698e3e2c28 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 2 Nov 2015 09:21:08 -0500 Subject: Overlay fixes and added class prop for tips --- web/react/components/tutorial/tutorial_tip.jsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'web/react/components/tutorial') diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx index 3482a7cfa..118209599 100644 --- a/web/react/components/tutorial/tutorial_tip.jsx +++ b/web/react/components/tutorial/tutorial_tip.jsx @@ -79,6 +79,12 @@ export default class TutorialTip extends React.Component { ref='target' /> + +
+ + this.refs.target} > -
+
{this.props.screens[this.state.currentScreen]}
{dots}
@@ -113,7 +119,12 @@ export default class TutorialTip extends React.Component { } } +TutorialTip.defaultProps = { + overlayClass: '' +}; + TutorialTip.propTypes = { screens: React.PropTypes.array.isRequired, - placement: React.PropTypes.string.isRequired + placement: React.PropTypes.string.isRequired, + overlayClass: React.PropTypes.string }; -- cgit v1.2.3-1-g7c22 From 4c5c42e37415df75d398027b6c2a6ea39e138688 Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Mon, 2 Nov 2015 20:57:23 +0500 Subject: Updating tutorials UI --- web/react/components/tutorial/tutorial_tip.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'web/react/components/tutorial') diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx index 118209599..c85acb346 100644 --- a/web/react/components/tutorial/tutorial_tip.jsx +++ b/web/react/components/tutorial/tutorial_tip.jsx @@ -70,7 +70,7 @@ export default class TutorialTip extends React.Component { } return ( -
+
this.refs.target} >
+
{this.props.screens[this.state.currentScreen]}
{dots}
-- cgit v1.2.3-1-g7c22 From 95da41257155e4d1d8201471e7ae1f5d96450189 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 2 Nov 2015 11:13:21 -0500 Subject: Move period out of link --- web/react/components/tutorial/tutorial_intro_screens.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'web/react/components/tutorial') diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx index b37aac27c..0f3050156 100644 --- a/web/react/components/tutorial/tutorial_intro_screens.jsx +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -120,8 +120,9 @@ export default class TutorialIntroScreens extends React.Component { href='mailto:feedback@mattermost.com' target='_blank' > - {'feedback@mattermost.com.'} + {'feedback@mattermost.com'} + {'.'}

{'Click “Next” to enter Town Square. This is the first channel teammates see when they sign up - use it for posting updates everyone needs to know.'}
-- cgit v1.2.3-1-g7c22 From 35b11e0e61fd3c7130c3f54601ba05dd0b52fba3 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 2 Nov 2015 15:10:46 -0500 Subject: Fix merge issues --- web/react/components/tutorial/tutorial_intro_screens.jsx | 4 ---- 1 file changed, 4 deletions(-) (limited to 'web/react/components/tutorial') diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx index 0f3050156..c7abccae3 100644 --- a/web/react/components/tutorial/tutorial_intro_screens.jsx +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -20,10 +20,6 @@ export default class TutorialIntroScreens extends React.Component { this.state = {currentScreen: 0}; } - componentDidMount() { - const height = $(window).outerHeight() - 120; - $('.tutorial-steps__container').css('height', `${height}px`); - } handleNext() { if (this.state.currentScreen < 2) { this.setState({currentScreen: this.state.currentScreen + 1}); -- cgit v1.2.3-1-g7c22