header.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /* jshint ignore:start */
  2. import React from 'react';
  3. import Controls from './controls';
  4. import Select from './select';
  5. import {StatusIcon, getStatusClassName, getStatusDescription} from 'misago/components/user-status';
  6. import PostChangelog from 'misago/components/post-changelog';
  7. import modal from 'misago/services/modal';
  8. export default function(props) {
  9. return (
  10. <div className="panel-heading post-heading">
  11. <PosterStatus {...props} />
  12. <Poster {...props} />
  13. <PosterRank {...props} />
  14. <PostedOn {...props} />
  15. <Select {...props} />
  16. <Controls {...props} />
  17. <PostEdits {...props} />
  18. <ProtectedLabel {...props} />
  19. <UnreadLabel {...props} />
  20. </div>
  21. );
  22. }
  23. export function PosterStatus(props) {
  24. if (!props.post.poster) {
  25. return null;
  26. }
  27. return (
  28. <div
  29. className={getStatusClassName(props.post.poster.status)}
  30. title={getStatusDescription(props.post.poster, props.post.poster.status)}
  31. >
  32. <StatusIcon
  33. status={props.post.poster.status}
  34. user={props.post.poster}
  35. />
  36. </div>
  37. );
  38. }
  39. export function Poster(props) {
  40. if (props.post.poster) {
  41. return (
  42. <a className="item-title" href={props.post.poster.absolute_url}>
  43. {props.post.poster.username}
  44. </a>
  45. );
  46. } else {
  47. return (
  48. <strong className="item-title">{props.post.poster_name}</strong>
  49. );
  50. }
  51. }
  52. export function PosterRank(props) {
  53. if (props.post.poster) {
  54. if (!props.post.poster.rank.is_default) {
  55. const rankClass = 'label-' + (props.post.poster.rank.css_class || 'default');
  56. if (props.post.poster.rank.is_tab) {
  57. return <a href={props.post.poster.rank.absolute_url} className={'label ' + rankClass}>
  58. {props.post.poster.short_title}
  59. </a>;
  60. } else {
  61. return <span className={'label ' + rankClass}>
  62. {props.post.poster.short_title}
  63. </span>;
  64. }
  65. } else {
  66. return null; // we don't display default ranks
  67. }
  68. } else {
  69. return <span className="rank-name item-title">
  70. {gettext("Unregistered")}
  71. </span>;
  72. }
  73. }
  74. export function PostedOn(props) {
  75. const tooltip = interpolate(gettext("posted %(posted_on)s"), {
  76. 'posted_on': props.post.posted_on.format('LL, LT')
  77. }, true);
  78. const message = interpolate(gettext("posted %(posted_on)s"), {
  79. 'posted_on': props.post.posted_on.fromNow()
  80. }, true);
  81. return <a href={props.post.url.index} className="posted-on" title={tooltip}>
  82. {message}
  83. </a>;
  84. }
  85. export class PostEdits extends React.Component {
  86. onClick = () => {
  87. modal.show(
  88. <PostChangelog post={this.props.post} />
  89. )
  90. };
  91. render() {
  92. const isHidden = this.props.post.is_hidden && !this.props.post.acl.can_see_hidden;
  93. const isUnedited = this.props.post.edits === 0;
  94. if (isHidden || isUnedited) return null;
  95. const message = ngettext(
  96. "This post was edited %(edits)s time.",
  97. "This post was edited %(edits)s times.",
  98. this.props.post.edits
  99. );
  100. const title = interpolate(message, {
  101. 'edits': this.props.post.edits
  102. }, true);
  103. return (
  104. <button
  105. className="btn btn-default btn-sm pull-right"
  106. onClick={this.onClick}
  107. title={title}
  108. type="button"
  109. >
  110. <span className="material-icon">
  111. edit
  112. </span>
  113. {this.props.post.edits}
  114. </button>
  115. )
  116. }
  117. }
  118. export function UnreadLabel(props) {
  119. if (!props.post.is_read) {
  120. return <span className="label label-warning pull-right">
  121. {gettext("New")}
  122. </span>;
  123. } else {
  124. return null;
  125. }
  126. }
  127. export function ProtectedLabel(props) {
  128. const postAuthor = props.post.poster && props.post.poster.id === props.user.id;
  129. const hasAcl = props.post.acl.can_protect;
  130. const isVisible = props.user.id && props.post.is_protected && (postAuthor || hasAcl);
  131. if (!isVisible) {
  132. return null;
  133. }
  134. return (
  135. <span
  136. className="label label-default pull-right"
  137. title={gettext("This post is protected and may not be edited.")}
  138. >
  139. {gettext("Protected")}
  140. </span>
  141. );
  142. }