2017-05-03 02:04:16 +02:00
import React from 'react' ;
2017-04-16 20:32:00 +02:00
import { connect } from 'react-redux' ;
2017-04-21 20:05:35 +02:00
import PropTypes from 'prop-types' ;
2017-04-16 20:32:00 +02:00
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
import Permalink from '../../../components/permalink' ;
import { TransitionMotion , spring } from 'react-motion' ;
import ComposeForm from '../../compose/components/compose_form' ;
import Search from '../../compose/components/search' ;
import NavigationBar from '../../compose/components/navigation_bar' ;
import ColumnHeader from './column_header' ;
import Immutable from 'immutable' ;
2017-05-19 20:58:12 +02:00
const noop = ( ) => { } ;
2017-04-16 20:32:00 +02:00
const messages = defineMessages ( {
home _title : { id : 'column.home' , defaultMessage : 'Home' } ,
notifications _title : { id : 'column.notifications' , defaultMessage : 'Notifications' } ,
local _title : { id : 'column.community' , defaultMessage : 'Local timeline' } ,
federated _title : { id : 'column.public' , defaultMessage : 'Federated timeline' }
} ) ;
const PageOne = ( { acct , domain } ) => (
< div className = 'onboarding-modal__page onboarding-modal__page-one' >
< div style = { { flex : '0 0 auto' } } >
< div className = 'onboarding-modal__page-one__elephant-friend' / >
< / d i v >
< div >
< h1 > < FormattedMessage id = 'onboarding.page_one.welcome' defaultMessage = 'Welcome to Mastodon!' / > < / h 1 >
2017-04-28 01:58:45 +02:00
< p > < FormattedMessage id = 'onboarding.page_one.federation' defaultMessage = 'Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.' / > < / p >
2017-04-20 18:20:40 +02:00
< p > < FormattedMessage id = 'onboarding.page_one.handle' defaultMessage = 'You are on {domain}, so your full handle is {handle}' values = { { domain , handle : < strong > { acct } @ { domain } < /strong> }}/ > < / p >
2017-04-16 20:32:00 +02:00
< / d i v >
< / d i v >
) ;
PageOne . propTypes = {
2017-04-21 20:05:35 +02:00
acct : PropTypes . string . isRequired ,
domain : PropTypes . string . isRequired
2017-04-16 20:32:00 +02:00
} ;
2017-04-26 15:15:47 +02:00
const PageTwo = ( { me } ) => (
2017-04-16 20:32:00 +02:00
< div className = 'onboarding-modal__page onboarding-modal__page-two' >
< div className = 'figure non-interactive' >
2017-04-26 15:15:47 +02:00
< div className = 'pseudo-drawer' >
2017-04-20 18:20:40 +02:00
< NavigationBar account = { me } / >
2017-04-26 15:15:47 +02:00
< / d i v >
2017-04-16 20:32:00 +02:00
< ComposeForm
text = 'Awoo! #introductions'
suggestions = { Immutable . List ( ) }
mentionedDomains = { [ ] }
2017-04-20 13:22:54 +02:00
spoiler = { false }
2017-05-19 20:58:12 +02:00
onChange = { noop }
onSubmit = { noop }
onPaste = { noop }
onPickEmoji = { noop }
onChangeSpoilerText = { noop }
onClearSuggestions = { noop }
onFetchSuggestions = { noop }
onSuggestionSelected = { noop }
2017-04-16 20:32:00 +02:00
/ >
< / d i v >
< p > < FormattedMessage id = 'onboarding.page_two.compose' defaultMessage = 'Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.' / > < / p >
< / d i v >
) ;
2017-04-26 15:15:47 +02:00
PageTwo . propTypes = {
me : ImmutablePropTypes . map . isRequired ,
} ;
2017-04-16 20:32:00 +02:00
const PageThree = ( { me , domain } ) => (
< div className = 'onboarding-modal__page onboarding-modal__page-three' >
< div className = 'figure non-interactive' >
< Search
value = ''
2017-05-19 20:58:12 +02:00
onChange = { noop }
onSubmit = { noop }
onClear = { noop }
onShow = { noop }
2017-04-16 20:32:00 +02:00
/ >
< div className = 'pseudo-drawer' >
< NavigationBar account = { me } / >
< / d i v >
< / d i v >
< p > < FormattedMessage id = 'onboarding.page_three.search' defaultMessage = 'Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.' values = { { illustration : < Permalink to = '/timelines/tag/illustration' href = '/tags/illustration' > # illustration < / P e r m a l i n k > , i n t r o d u c t i o n s : < P e r m a l i n k t o = ' / t i m e l i n e s / t a g / i n t r o d u c t i o n s ' h r e f = ' / t a g s / i n t r o d u c t i o n s ' > # i n t r o d u c t i o n s < / P e r m a l i n k > } } / > < / p >
< p > < FormattedMessage id = 'onboarding.page_three.profile' defaultMessage = 'Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.' / > < / p >
< / d i v >
) ;
PageThree . propTypes = {
me : ImmutablePropTypes . map . isRequired ,
2017-04-21 20:05:35 +02:00
domain : PropTypes . string . isRequired
2017-04-16 20:32:00 +02:00
} ;
const PageFour = ( { domain , intl } ) => (
< div className = 'onboarding-modal__page onboarding-modal__page-four' >
< div className = 'onboarding-modal__page-four__columns' >
< div className = 'row' >
< div >
< div className = 'figure non-interactive' > < ColumnHeader icon = 'home' type = { intl . formatMessage ( messages . home _title ) } / > < / d i v >
2017-04-20 18:20:40 +02:00
< p > < FormattedMessage id = 'onboarding.page_four.home' defaultMessage = 'The home timeline shows posts from people you follow.' / > < / p >
2017-04-16 20:32:00 +02:00
< / d i v >
< div >
< div className = 'figure non-interactive' > < ColumnHeader icon = 'bell' type = { intl . formatMessage ( messages . notifications _title ) } / > < / d i v >
2017-04-20 18:20:40 +02:00
< p > < FormattedMessage id = 'onboarding.page_four.notifications' defaultMessage = 'The notifications column shows when someone interacts with you.' / > < / p >
2017-04-16 20:32:00 +02:00
< / d i v >
< / d i v >
< div className = 'row' >
< div >
2017-04-20 18:20:40 +02:00
< div className = 'figure non-interactive' style = { { marginBottom : 0 } } > < ColumnHeader icon = 'users' type = { intl . formatMessage ( messages . local _title ) } / > < / d i v >
2017-04-16 20:32:00 +02:00
< / d i v >
< div >
2017-04-20 18:20:40 +02:00
< div className = 'figure non-interactive' style = { { marginBottom : 0 } } > < ColumnHeader icon = 'globe' type = { intl . formatMessage ( messages . federated _title ) } / > < / d i v >
2017-04-16 20:32:00 +02:00
< / d i v >
< / d i v >
2017-04-20 18:20:40 +02:00
< p > < FormattedMessage id = 'onboarding.page_five.public_timelines' defaultMessage = 'The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.' values = { { domain } } / > < / p >
2017-04-16 20:32:00 +02:00
< / d i v >
< / d i v >
) ;
PageFour . propTypes = {
2017-04-21 20:05:35 +02:00
domain : PropTypes . string . isRequired ,
intl : PropTypes . object . isRequired
2017-04-16 20:32:00 +02:00
} ;
2017-04-26 14:54:12 +02:00
const PageSix = ( { admin , domain } ) => {
2017-04-16 20:32:00 +02:00
let adminSection = '' ;
if ( admin ) {
adminSection = (
< p >
< FormattedMessage id = 'onboarding.page_six.admin' defaultMessage = "Your instance's admin is {admin}." values = { { admin : < Permalink href = { admin . get ( 'url' ) } to = { ` /accounts/ ${ admin . get ( 'id' ) } ` } > @ { admin . get ( 'acct' ) } < /Permalink> }} / >
< br / >
2017-04-20 18:20:40 +02:00
< FormattedMessage id = 'onboarding.page_six.read_guidelines' defaultMessage = "Please read {domain}'s {guidelines}!" values = { { domain , guidelines : < a href = '/about/more' target = '_blank' > < FormattedMessage id = 'onboarding.page_six.guidelines' defaultMessage = 'community guidelines' / > < /a> }}/ >
2017-04-16 20:32:00 +02:00
< / p >
) ;
}
return (
< div className = 'onboarding-modal__page onboarding-modal__page-six' >
< h1 > < FormattedMessage id = 'onboarding.page_six.almost_done' defaultMessage = 'Almost done...' / > < / h 1 >
{ adminSection }
< p > < FormattedMessage id = 'onboarding.page_six.github' defaultMessage = 'Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.' values = { { github : < a href = 'https://github.com/tootsuite/mastodon' target = '_blank' rel = 'noopener' > GitHub < /a> }} / > < / p >
2017-04-20 18:20:40 +02:00
< p > < FormattedMessage id = 'onboarding.page_six.apps_available' defaultMessage = 'There are {apps} available for iOS, Android and other platforms.' values = { { apps : < a href = 'https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' target = '_blank' rel = 'noopener' > < FormattedMessage id = 'onboarding.page_six.various_app' defaultMessage = 'mobile apps' / > < /a> }} / > < / p >
< p > < em > < FormattedMessage id = 'onboarding.page_six.appetoot' defaultMessage = 'Bon Appetoot!' / > < / e m > < / p >
2017-04-16 20:32:00 +02:00
< / d i v >
) ;
} ;
PageSix . propTypes = {
2017-04-26 14:54:12 +02:00
admin : ImmutablePropTypes . map ,
domain : PropTypes . string . isRequired
2017-04-16 20:32:00 +02:00
} ;
const mapStateToProps = state => ( {
me : state . getIn ( [ 'accounts' , state . getIn ( [ 'meta' , 'me' ] ) ] ) ,
admin : state . getIn ( [ 'accounts' , state . getIn ( [ 'meta' , 'admin' ] ) ] ) ,
domain : state . getIn ( [ 'meta' , 'domain' ] )
} ) ;
2017-04-21 20:05:35 +02:00
class OnboardingModal extends React . PureComponent {
2017-04-16 20:32:00 +02:00
2017-05-12 14:44:10 +02:00
static propTypes = {
onClose : PropTypes . func . isRequired ,
intl : PropTypes . object . isRequired ,
me : ImmutablePropTypes . map . isRequired ,
domain : PropTypes . string . isRequired ,
admin : ImmutablePropTypes . map
} ;
state = {
currentIndex : 0
} ;
handleSkip = ( e ) => {
2017-04-16 20:32:00 +02:00
e . preventDefault ( ) ;
this . props . onClose ( ) ;
2017-04-21 20:05:35 +02:00
}
2017-04-16 20:32:00 +02:00
2017-05-19 20:58:12 +02:00
handleDot = ( e ) => {
const i = Number ( e . currentTarget . getAttribute ( 'data-index' ) ) ;
2017-04-16 20:32:00 +02:00
e . preventDefault ( ) ;
this . setState ( { currentIndex : i } ) ;
2017-04-21 20:05:35 +02:00
}
2017-04-16 20:32:00 +02:00
2017-05-19 20:58:12 +02:00
handleNext = ( e ) => {
const maxNum = Number ( e . currentTarget . getAttribute ( 'data-length' ) ) ;
2017-04-16 20:32:00 +02:00
e . preventDefault ( ) ;
if ( this . state . currentIndex < maxNum - 1 ) {
this . setState ( { currentIndex : this . state . currentIndex + 1 } ) ;
} else {
this . props . onClose ( ) ;
}
2017-04-21 20:05:35 +02:00
}
2017-04-16 20:32:00 +02:00
render ( ) {
const { me , admin , domain , intl } = this . props ;
const pages = [
< PageOne acct = { me . get ( 'acct' ) } domain = { domain } / > ,
2017-04-26 15:15:47 +02:00
< PageTwo me = { me } / > ,
2017-04-16 20:32:00 +02:00
< PageThree me = { me } domain = { domain } / > ,
< PageFour domain = { domain } intl = { intl } / > ,
2017-04-26 14:54:12 +02:00
< PageSix admin = { admin } domain = { domain } / >
2017-04-16 20:32:00 +02:00
] ;
const { currentIndex } = this . state ;
const hasMore = currentIndex < pages . length - 1 ;
let nextOrDoneBtn ;
if ( hasMore ) {
2017-05-19 20:58:12 +02:00
nextOrDoneBtn = < a href = '#' data - length = { pages . length } onClick = { this . handleNext } className = 'onboarding-modal__nav onboarding-modal__next' > < FormattedMessage id = 'onboarding.next' defaultMessage = 'Next' / > < / a > ;
2017-04-16 20:32:00 +02:00
} else {
2017-05-19 20:58:12 +02:00
nextOrDoneBtn = < a href = '#' data - length = { pages . length } onClick = { this . handleNext } className = 'onboarding-modal__nav onboarding-modal__done' > < FormattedMessage id = 'onboarding.done' defaultMessage = 'Done' / > < / a > ;
2017-04-16 20:32:00 +02:00
}
const styles = pages . map ( ( page , i ) => ( {
2017-04-20 13:22:54 +02:00
key : ` page- ${ i } ` ,
2017-04-16 20:32:00 +02:00
style : { opacity : spring ( i === currentIndex ? 1 : 0 ) }
} ) ) ;
return (
< div className = 'modal-root__modal onboarding-modal' >
< TransitionMotion styles = { styles } >
{ interpolatedStyles =>
< div className = 'onboarding-modal__pager' >
{ pages . map ( ( page , i ) =>
2017-04-20 13:22:54 +02:00
< div key = { ` page- ${ i } ` } style = { { opacity : interpolatedStyles [ i ] . style . opacity , pointerEvents : i === currentIndex ? 'auto' : 'none' } } > { page } < / d i v >
2017-04-16 20:32:00 +02:00
) }
< / d i v >
}
< / T r a n s i t i o n M o t i o n >
< div className = 'onboarding-modal__paginator' >
< div >
< a href = '#' className = 'onboarding-modal__skip' onClick = { this . handleSkip } > < FormattedMessage id = 'onboarding.skip' defaultMessage = 'Skip' / > < / a >
< / d i v >
< div className = 'onboarding-modal__dots' >
2017-05-19 20:58:12 +02:00
{ pages . map ( ( _ , i ) => < div key = { i } role = 'button' tabIndex = '0' data - index = { i } onClick = { this . handleDot } className = { ` onboarding-modal__dot ${ i === currentIndex ? 'active' : '' } ` } / > ) }
2017-04-16 20:32:00 +02:00
< / d i v >
< div >
{ nextOrDoneBtn }
< / d i v >
< / d i v >
< / d i v >
) ;
}
2017-04-21 20:05:35 +02:00
}
2017-04-16 20:32:00 +02:00
export default connect ( mapStateToProps ) ( injectIntl ( OnboardingModal ) ) ;