summaryrefslogtreecommitdiffstats
path: root/webapp/components/tutorial
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2016-03-14 08:50:46 -0400
committerChristopher Speller <crspeller@gmail.com>2016-03-16 18:02:55 -0400
commit12896bd23eeba79884245c1c29fdc568cf21a7fa (patch)
tree4e7f83d3e2564b9b89d669e9f7905ff11768b11a /webapp/components/tutorial
parent29fe6a3d13c9c7aa490fffebbe5d1b5fdf1e3090 (diff)
downloadchat-12896bd23eeba79884245c1c29fdc568cf21a7fa.tar.gz
chat-12896bd23eeba79884245c1c29fdc568cf21a7fa.tar.bz2
chat-12896bd23eeba79884245c1c29fdc568cf21a7fa.zip
Converting to Webpack. Stage 1.
Diffstat (limited to 'webapp/components/tutorial')
-rw-r--r--webapp/components/tutorial/tutorial_intro_screens.jsx241
-rw-r--r--webapp/components/tutorial/tutorial_tip.jsx160
2 files changed, 401 insertions, 0 deletions
diff --git a/webapp/components/tutorial/tutorial_intro_screens.jsx b/webapp/components/tutorial/tutorial_intro_screens.jsx
new file mode 100644
index 000000000..5db45523e
--- /dev/null
+++ b/webapp/components/tutorial/tutorial_intro_screens.jsx
@@ -0,0 +1,241 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import UserStore from 'stores/user_store.jsx';
+import ChannelStore from 'stores/channel_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
+import PreferenceStore from 'stores/preference_store.jsx';
+import * as Utils from 'utils/utils.jsx';
+import * as AsyncClient from 'utils/async_client.jsx';
+
+import Constants from 'utils/constants.jsx';
+
+import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
+
+const Preferences = Constants.Preferences;
+
+const NUM_SCREENS = 3;
+
+import React from 'react';
+
+export default class TutorialIntroScreens extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleNext = this.handleNext.bind(this);
+ this.createScreen = this.createScreen.bind(this);
+ this.createCircles = this.createCircles.bind(this);
+
+ this.state = {currentScreen: 0};
+ }
+ handleNext() {
+ if (this.state.currentScreen < 2) {
+ this.setState({currentScreen: this.state.currentScreen + 1});
+ return;
+ }
+
+ Utils.switchChannel(ChannelStore.getByName(Constants.DEFAULT_CHANNEL));
+
+ 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]);
+ }
+ skipTutorial(e) {
+ e.preventDefault();
+ const preference = PreferenceStore.setPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), '999');
+ AsyncClient.savePreferences([preference]);
+ }
+ createScreen() {
+ switch (this.state.currentScreen) {
+ case 0:
+ return this.createScreenOne();
+ case 1:
+ return this.createScreenTwo();
+ case 2:
+ return this.createScreenThree();
+ }
+ return null;
+ }
+ createScreenOne() {
+ const circles = this.createCircles();
+
+ return (
+ <div>
+ <FormattedHTMLMessage
+ id='tutorial_intro.screenOne'
+ defaultMessage='<h3>Welcome to:</h3>
+ <h1>Mattermost</h1>
+ <p>Your team communication all in one place, instantly searchable and available anywhere</p>
+ <p>Keep your team connected to help them achieve what matters most.</p>'
+ />
+ {circles}
+ </div>
+ );
+ }
+ createScreenTwo() {
+ const circles = this.createCircles();
+
+ return (
+ <div>
+ <FormattedHTMLMessage
+ id='tutorial_intro.screenTwo'
+ defaultMessage='<h3>How Mattermost works:</h3>
+ <p>Communication happens in public discussion channels, private groups and direct messages.</p>
+ <p>Everything is archived and searchable from any web-enabled desktop, laptop or phone.</p>'
+ />
+ {circles}
+ </div>
+ );
+ }
+ createScreenThree() {
+ const team = TeamStore.getCurrent();
+ let inviteModalLink;
+ if (team.type === Constants.INVITE_TEAM) {
+ inviteModalLink = (
+ <a
+ className='intro-links'
+ href='#'
+ data-toggle='modal'
+ data-target='#invite_member'
+ >
+ <FormattedMessage
+ id='tutorial_intro.invite'
+ defaultMessage='Invite teammates'
+ />
+ </a>
+ );
+ } else {
+ inviteModalLink = (
+ <a
+ className='intro-links'
+ href='#'
+ data-toggle='modal'
+ data-target='#get_link'
+ data-title='Team Invite'
+ data-value={Utils.getWindowLocationOrigin() + '/signup_user_complete/?id=' + team.id}
+ >
+ <FormattedMessage
+ id='tutorial_intro.teamInvite'
+ defaultMessage='Team Invite'
+ />
+ </a>
+ );
+ }
+
+ const circles = this.createCircles();
+
+ let supportInfo = null;
+ if (global.window.mm_config.SupportEmail) {
+ supportInfo = (
+ <p>
+ <FormattedMessage
+ id='tutorial_intro.support'
+ defaultMessage='Need anything, just email us at '
+ />
+ <a
+ href={'mailto:' + global.window.mm_config.SupportEmail}
+ target='_blank'
+ >
+ {global.window.mm_config.SupportEmail}
+ </a>
+ {'.'}
+ </p>
+ );
+ }
+
+ return (
+ <div>
+ <h3>
+ <FormattedMessage
+ id='tutorial_intro.allSet'
+ defaultMessage='You’re all set'
+ />
+ </h3>
+ <p>
+ {inviteModalLink}
+ <FormattedMessage
+ id='tutorial_intro.whenReady'
+ defaultMessage=' when you’re ready.'
+ />
+ </p>
+ {supportInfo}
+ <FormattedMessage
+ id='tutorial_intro.end'
+ defaultMessage='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.'
+ />
+ {circles}
+ </div>
+ );
+ }
+ createCircles() {
+ const circles = [];
+ for (let i = 0; i < NUM_SCREENS; i++) {
+ let className = 'circle';
+ if (i === this.state.currentScreen) {
+ className += ' active';
+ }
+
+ circles.push(
+ <a
+ href='#'
+ key={'circle' + i}
+ className={className}
+ onClick={(e) => { //eslint-disable-line no-loop-func
+ e.preventDefault();
+ this.setState({currentScreen: i});
+ }}
+ />
+ );
+ }
+
+ return (
+ <div className='tutorial__circles'>
+ {circles}
+ </div>
+ );
+ }
+ render() {
+ const height = Utils.windowHeight() - 100;
+ const screen = this.createScreen();
+
+ return (
+ <div
+ className='tutorials__scroll'
+ style={{height}}
+ >
+ <div className='tutorial-steps__container'>
+ <div className='tutorial__content'>
+ <div className='tutorial__steps'>
+ {screen}
+ <div className='tutorial__footer'>
+ <button
+ className='btn btn-primary'
+ tabIndex='1'
+ onClick={this.handleNext}
+ >
+ <FormattedMessage
+ id='tutorial_intro.next'
+ defaultMessage='Next'
+ />
+ </button>
+ <a
+ className='tutorial-skip'
+ href='#'
+ onClick={this.skipTutorial}
+ >
+ <FormattedMessage
+ id='tutorial_intro.skip'
+ defaultMessage='Skip tutorial'
+ />
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
diff --git a/webapp/components/tutorial/tutorial_tip.jsx b/webapp/components/tutorial/tutorial_tip.jsx
new file mode 100644
index 000000000..ab49d4b04
--- /dev/null
+++ b/webapp/components/tutorial/tutorial_tip.jsx
@@ -0,0 +1,160 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import UserStore from 'stores/user_store.jsx';
+import PreferenceStore from 'stores/preference_store.jsx';
+import * as AsyncClient from 'utils/async_client.jsx';
+
+import Constants from 'utils/constants.jsx';
+
+import {FormattedMessage} from 'react-intl';
+
+const Preferences = Constants.Preferences;
+
+import {Overlay} from 'react-bootstrap';
+
+import React from 'react';
+
+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 ? (
+ <FormattedMessage
+ id='tutorial_tip.ok'
+ defaultMessage='Okay'
+ />
+ ) : (
+ <FormattedMessage
+ id='tutorial_tip.next'
+ defaultMessage='Next'
+ />
+ );
+
+ const dots = [];
+ if (this.props.screens.length > 1) {
+ for (let i = 0; i < this.props.screens.length; i++) {
+ let className = 'circle';
+ if (i === this.state.currentScreen) {
+ className += ' active';
+ }
+
+ dots.push(
+ <a
+ href='#'
+ key={'dotactive' + i}
+ className={className}
+ onClick={(e) => { //eslint-disable-line no-loop-func
+ e.preventDefault();
+ this.setState({currentScreen: i});
+ }}
+ />
+ );
+ }
+ }
+
+ var tipColor = '';
+ if (this.props.overlayClass === 'tip-overlay--header' || this.props.overlayClass === 'tip-overlay--sidebar') {
+ tipColor = 'White';
+ }
+
+ return (
+ <div className={'tip-div ' + this.props.overlayClass}>
+ <img
+ className='tip-button'
+ src={'/static/images/tutorialTip' + tipColor + '.gif'}
+ width='35'
+ onClick={this.toggle}
+ ref='target'
+ />
+
+ <Overlay
+ show={this.state.show}
+ >
+ <div className='tip-backdrop'/>
+ </Overlay>
+
+ <Overlay
+ placement={this.props.placement}
+ show={this.state.show}
+ rootClose={true}
+ onHide={this.toggle}
+ target={() => this.refs.target}
+ >
+ <div className={'tip-overlay ' + this.props.overlayClass}>
+ <div className='arrow'></div>
+ {this.props.screens[this.state.currentScreen]}
+ <div className='tutorial__footer'>
+ <div className='tutorial__circles'>{dots}</div>
+ <div className='text-right'>
+ <button
+ className='btn btn-primary'
+ onClick={this.handleNext}
+ >
+ {buttonText}
+ </button>
+ <div className='tip-opt'>
+ <FormattedMessage
+ id='tutorial_tip.seen'
+ defaultMessage='Seen this before? '
+ />
+ <a
+ href='#'
+ onClick={this.skipTutorial}
+ >
+ <FormattedMessage
+ id='tutorial_tip.out'
+ defaultMessage='Opt out of these tips.'
+ />
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </Overlay>
+ </div>
+ );
+ }
+}
+
+TutorialTip.defaultProps = {
+ overlayClass: ''
+};
+
+TutorialTip.propTypes = {
+ screens: React.PropTypes.array.isRequired,
+ placement: React.PropTypes.string.isRequired,
+ overlayClass: React.PropTypes.string
+};