root.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import React from 'react'; // jshint ignore:line
  2. import { connect } from 'react-redux';
  3. import BanDetails from './ban-details'; // jshint ignore:line
  4. import { Posts, Threads } from './feed'; // jshint ignore:line
  5. import Followers from './followers'; // jshint ignore:line
  6. import Follows from './follows'; // jshint ignore:line
  7. import UsernameHistory from './username-history'; // jshint ignore:line
  8. import Header from './header'; // jshint ignore:line
  9. import ModerationNav from './moderation/nav'; // jshint ignore:line
  10. import { SideNav, CompactNav } from './navs'; // jshint ignore:line
  11. import Avatar from 'misago/components/avatar'; // jshint ignore:line
  12. import WithDropdown from 'misago/components/with-dropdown';
  13. import misago from 'misago';
  14. import { hydrate } from 'misago/reducers/profile'; // jshint ignore:line
  15. import polls from 'misago/services/polls';
  16. import store from 'misago/services/store'; // jshint ignore:line
  17. export default class extends WithDropdown {
  18. constructor(props) {
  19. super(props);
  20. this.startPolling(props.profile.api_url.root);
  21. }
  22. startPolling(api) {
  23. polls.start({
  24. poll: 'user-profile',
  25. url: api,
  26. frequency: 90 * 1000,
  27. update: this.update
  28. });
  29. }
  30. /* jshint ignore:start */
  31. update = (data) => {
  32. store.dispatch(hydrate(data));
  33. };
  34. toggleNav = () => {
  35. if (this.state.dropdown === 'pages') {
  36. this.setState({
  37. dropdown: false
  38. });
  39. } else {
  40. this.setState({
  41. dropdown: 'pages'
  42. });
  43. }
  44. };
  45. toggleModeration = () => {
  46. if (this.state.dropdown === 'moderation') {
  47. this.setState({
  48. dropdown: false
  49. });
  50. } else {
  51. this.setState({
  52. dropdown: 'moderation'
  53. });
  54. }
  55. };
  56. /* jshint ignore:end */
  57. getNavDropdown() {
  58. if (this.state.dropdown === 'pages') {
  59. /* jshint ignore:start */
  60. return <CompactNav pages={misago.get('PROFILE_PAGES')}
  61. baseUrl={misago.get('PROFILE').absolute_url}
  62. profile={this.props.profile}
  63. toggleModeration={this.toggleModeration}
  64. hideNav={this.hideNav} />;
  65. /* jshint ignore:end */
  66. } else if (this.state.dropdown === 'moderation') {
  67. /* jshint ignore:start */
  68. return <ModerationNav profile={this.props.profile}
  69. toggleNav={this.toggleNav}
  70. hideNav={this.hideNav} />;
  71. /* jshint ignore:end */
  72. } else {
  73. return null;
  74. }
  75. }
  76. getClassName() {
  77. const baseClass = 'page page-user-profile';
  78. if (false && this.props.profile.rank.css_class) {
  79. return baseClass + ' page-user-profile-' + this.props.profile.rank.css_class;
  80. } else {
  81. return baseClass;
  82. }
  83. }
  84. render() {
  85. /* jshint ignore:start */
  86. const pages = misago.get('PROFILE_PAGES');
  87. return (
  88. <div className={this.getClassName()}>
  89. <Header
  90. user={this.props.user}
  91. profile={this.props.profile}
  92. toggleNav={this.toggleNav}
  93. toggleModeration={this.toggleModeration}
  94. />
  95. <div className="page-header page-header-followup visible-sm-block">
  96. <div className="container">
  97. <CompactNav
  98. className="nav nav-pills"
  99. pages={pages}
  100. baseUrl={misago.get('PROFILE').absolute_url}
  101. profile={this.props.profile}
  102. />
  103. </div>
  104. </div>
  105. <div className="page-header page-header-followup visible-xs-block">
  106. <div className="container">
  107. <div className="dropdown">
  108. <button
  109. aria-expanded="true"
  110. aria-haspopup="true"
  111. className="btn btn-default dropdown-toggle btn-block"
  112. data-toggle="dropdown"
  113. type="button"
  114. >
  115. <span className="material-icon">
  116. menu
  117. </span>
  118. {gettext("Menu")}
  119. </button>
  120. <CompactNav
  121. pages={pages}
  122. baseUrl={misago.get('PROFILE').absolute_url}
  123. profile={this.props.profile}
  124. />
  125. </div>
  126. </div>
  127. </div>
  128. <div className="container">
  129. <div className="row">
  130. <div className="col-md-3 hidden-xs hidden-sm">
  131. <div className="profile-side-avatar">
  132. <Avatar user={this.props.profile} size="400" />
  133. </div>
  134. <SideNav
  135. pages={pages}
  136. baseUrl={misago.get('PROFILE').absolute_url}
  137. profile={this.props.profile}
  138. />
  139. </div>
  140. <div className="col-md-9">
  141. {this.props.children}
  142. </div>
  143. </div>
  144. </div>
  145. </div>
  146. );
  147. /* jshint ignore:end */
  148. }
  149. }
  150. export function select(store) {
  151. return {
  152. 'tick': store.tick.tick,
  153. 'user': store.auth.user,
  154. 'users': store.users,
  155. 'posts': store.posts,
  156. 'profile': store.profile,
  157. 'username-history': store['username-history']
  158. };
  159. }
  160. const COMPONENTS = {
  161. 'posts': Posts,
  162. 'threads': Threads,
  163. 'followers': Followers,
  164. 'follows': Follows,
  165. 'username-history': UsernameHistory,
  166. 'ban-details': BanDetails
  167. };
  168. export function paths() {
  169. let paths = [];
  170. misago.get('PROFILE_PAGES').forEach(function(item) {
  171. paths.push(Object.assign({}, item, {
  172. path: misago.get('PROFILE').absolute_url + item.component + '/',
  173. component: connect(select)(COMPONENTS[item.component]),
  174. }));
  175. });
  176. return paths;
  177. }