You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
7.7 KiB

  1. import React from 'react';
  2. import Column from '../ui/components/column';
  3. import ColumnLink from '../ui/components/column_link';
  4. import ColumnSubheading from '../ui/components/column_subheading';
  5. import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
  6. import { connect } from 'react-redux';
  7. import PropTypes from 'prop-types';
  8. import ImmutablePropTypes from 'react-immutable-proptypes';
  9. import ImmutablePureComponent from 'react-immutable-pure-component';
  10. import { me } from '../../initial_state';
  11. import { fetchFollowRequests } from '../../actions/accounts';
  12. import { List as ImmutableList } from 'immutable';
  13. import { Link } from 'react-router-dom';
  14. import { fetchTrends } from '../../actions/trends';
  15. import Hashtag from '../../components/hashtag';
  16. import NavigationBar from '../compose/components/navigation_bar';
  17. const messages = defineMessages({
  18. home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
  19. notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
  20. public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
  21. settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },
  22. community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
  23. direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' },
  24. preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
  25. follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
  26. favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
  27. blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
  28. domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
  29. mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
  30. pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
  31. lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
  32. refresh_trends: { id: 'trends.refresh', defaultMessage: 'Refresh' },
  33. discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' },
  34. personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' },
  35. security: { id: 'navigation_bar.security', defaultMessage: 'Security' },
  36. });
  37. const mapStateToProps = state => ({
  38. myAccount: state.getIn(['accounts', me]),
  39. unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,
  40. trends: state.get('trends'),
  41. });
  42. const mapDispatchToProps = dispatch => ({
  43. fetchFollowRequests: () => dispatch(fetchFollowRequests()),
  44. fetchTrends: () => dispatch(fetchTrends()),
  45. });
  46. const badgeDisplay = (number, limit) => {
  47. if (number === 0) {
  48. return undefined;
  49. } else if (limit && number >= limit) {
  50. return `${limit}+`;
  51. } else {
  52. return number;
  53. }
  54. };
  55. @connect(mapStateToProps, mapDispatchToProps)
  56. @injectIntl
  57. export default class GettingStarted extends ImmutablePureComponent {
  58. static propTypes = {
  59. intl: PropTypes.object.isRequired,
  60. myAccount: ImmutablePropTypes.map.isRequired,
  61. columns: ImmutablePropTypes.list,
  62. multiColumn: PropTypes.bool,
  63. fetchFollowRequests: PropTypes.func.isRequired,
  64. unreadFollowRequests: PropTypes.number,
  65. unreadNotifications: PropTypes.number,
  66. trends: ImmutablePropTypes.list,
  67. };
  68. componentDidMount () {
  69. const { myAccount, fetchFollowRequests } = this.props;
  70. if (myAccount.get('locked')) {
  71. fetchFollowRequests();
  72. }
  73. setTimeout(() => this.props.fetchTrends(), 5000);
  74. }
  75. render () {
  76. const { intl, myAccount, multiColumn, unreadFollowRequests, trends } = this.props;
  77. const navItems = [];
  78. if (multiColumn) {
  79. navItems.push(
  80. <ColumnSubheading key='1' text={intl.formatMessage(messages.discover)} />,
  81. <ColumnLink key='2' icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />,
  82. <ColumnLink key='3' icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />,
  83. <ColumnSubheading key='8' text={intl.formatMessage(messages.personal)} />
  84. );
  85. }
  86. navItems.push(
  87. <ColumnLink key='4' icon='envelope' text={intl.formatMessage(messages.direct)} to='/timelines/direct' />,
  88. <ColumnLink key='5' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,
  89. <ColumnLink key='6' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' />
  90. );
  91. if (myAccount.get('locked')) {
  92. navItems.push(<ColumnLink key='7' icon='users' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
  93. }
  94. if (!multiColumn) {
  95. navItems.push(
  96. <ColumnSubheading key='9' text={intl.formatMessage(messages.settings_subheading)} />,
  97. <ColumnLink key='6' icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />,
  98. <ColumnLink key='6' icon='lock' text={intl.formatMessage(messages.security)} href='/auth/edit' />
  99. );
  100. }
  101. return (
  102. <Column>
  103. {multiColumn && <div className='column-header__wrapper'>
  104. <h1 className='column-header'>
  105. <button>
  106. <i className='fa fa-bars fa-fw column-header__icon' />
  107. <FormattedMessage id='getting_started.heading' defaultMessage='Getting started' />
  108. </button>
  109. </h1>
  110. </div>}
  111. <div className='getting-started__wrapper'>
  112. {!multiColumn && <NavigationBar account={myAccount} />}
  113. {navItems}
  114. </div>
  115. {multiColumn && trends && <div className='getting-started__trends'>
  116. <div className='column-header__wrapper'>
  117. <h1 className='column-header'>
  118. <button>
  119. <i className='fa fa-fire fa-fw' />
  120. <FormattedMessage id='trends.header' defaultMessage='Trending now' />
  121. </button>
  122. <div className='column-header__buttons'>
  123. <button className='column-header__button' title={intl.formatMessage(messages.refresh_trends)} aria-label={intl.formatMessage(messages.refresh_trends)}><i className='fa fa-refresh' /></button>
  124. </div>
  125. </h1>
  126. </div>
  127. <div className='getting-started__scrollable'>{trends.take(3).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}</div>
  128. </div>}
  129. {!multiColumn && <div className='flex-spacer' />}
  130. <div className='getting-started getting-started__footer'>
  131. <ul>
  132. {multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
  133. <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this instance' /></a> · </li>
  134. <li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
  135. <li><a href='https://github.com/tootsuite/documentation#documentation' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
  136. <li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
  137. </ul>
  138. <p>
  139. <FormattedMessage
  140. id='getting_started.open_source_notice'
  141. defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
  142. values={{ github: <a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> }}
  143. />
  144. </p>
  145. </div>
  146. </Column>
  147. );
  148. }
  149. }