status_container.jsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
  2. import { connect } from 'react-redux';
  3. import {
  4. unmuteAccount,
  5. unblockAccount,
  6. } from '../actions/accounts';
  7. import { showAlertForError } from '../actions/alerts';
  8. import { initBlockModal } from '../actions/blocks';
  9. import { initBoostModal } from '../actions/boosts';
  10. import {
  11. replyCompose,
  12. mentionCompose,
  13. directCompose,
  14. } from '../actions/compose';
  15. import {
  16. blockDomain,
  17. unblockDomain,
  18. } from '../actions/domain_blocks';
  19. import {
  20. initAddFilter,
  21. } from '../actions/filters';
  22. import {
  23. reblog,
  24. favourite,
  25. bookmark,
  26. unreblog,
  27. unfavourite,
  28. unbookmark,
  29. pin,
  30. unpin,
  31. } from '../actions/interactions';
  32. import { openModal } from '../actions/modal';
  33. import { initMuteModal } from '../actions/mutes';
  34. import { deployPictureInPicture } from '../actions/picture_in_picture';
  35. import { initReport } from '../actions/reports';
  36. import {
  37. muteStatus,
  38. unmuteStatus,
  39. deleteStatus,
  40. hideStatus,
  41. revealStatus,
  42. toggleStatusCollapse,
  43. editStatus,
  44. translateStatus,
  45. undoStatusTranslation,
  46. } from '../actions/statuses';
  47. import Status from '../components/status';
  48. import { boostModal, deleteModal } from '../initial_state';
  49. import { makeGetStatus, makeGetPictureInPicture } from '../selectors';
  50. const messages = defineMessages({
  51. deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
  52. deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
  53. redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
  54. redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.' },
  55. replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
  56. replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
  57. editConfirm: { id: 'confirmations.edit.confirm', defaultMessage: 'Edit' },
  58. editMessage: { id: 'confirmations.edit.message', defaultMessage: 'Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
  59. blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
  60. });
  61. const makeMapStateToProps = () => {
  62. const getStatus = makeGetStatus();
  63. const getPictureInPicture = makeGetPictureInPicture();
  64. const mapStateToProps = (state, props) => ({
  65. status: getStatus(state, props),
  66. nextInReplyToId: props.nextId ? state.getIn(['statuses', props.nextId, 'in_reply_to_id']) : null,
  67. pictureInPicture: getPictureInPicture(state, props),
  68. });
  69. return mapStateToProps;
  70. };
  71. const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
  72. onReply (status, router) {
  73. dispatch((_, getState) => {
  74. let state = getState();
  75. if (state.getIn(['compose', 'text']).trim().length !== 0) {
  76. dispatch(openModal({
  77. modalType: 'CONFIRM',
  78. modalProps: {
  79. message: intl.formatMessage(messages.replyMessage),
  80. confirm: intl.formatMessage(messages.replyConfirm),
  81. onConfirm: () => dispatch(replyCompose(status, router)) },
  82. }));
  83. } else {
  84. dispatch(replyCompose(status, router));
  85. }
  86. });
  87. },
  88. onModalReblog (status, privacy) {
  89. if (status.get('reblogged')) {
  90. dispatch(unreblog(status));
  91. } else {
  92. dispatch(reblog(status, privacy));
  93. }
  94. },
  95. onReblog (status, e) {
  96. if ((e && e.shiftKey) || !boostModal) {
  97. this.onModalReblog(status);
  98. } else {
  99. dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
  100. }
  101. },
  102. onFavourite (status) {
  103. if (status.get('favourited')) {
  104. dispatch(unfavourite(status));
  105. } else {
  106. dispatch(favourite(status));
  107. }
  108. },
  109. onBookmark (status) {
  110. if (status.get('bookmarked')) {
  111. dispatch(unbookmark(status));
  112. } else {
  113. dispatch(bookmark(status));
  114. }
  115. },
  116. onPin (status) {
  117. if (status.get('pinned')) {
  118. dispatch(unpin(status));
  119. } else {
  120. dispatch(pin(status));
  121. }
  122. },
  123. onEmbed (status) {
  124. dispatch(openModal({
  125. modalType: 'EMBED',
  126. modalProps: {
  127. id: status.get('id'),
  128. onError: error => dispatch(showAlertForError(error)),
  129. },
  130. }));
  131. },
  132. onDelete (status, history, withRedraft = false) {
  133. if (!deleteModal) {
  134. dispatch(deleteStatus(status.get('id'), history, withRedraft));
  135. } else {
  136. dispatch(openModal({
  137. modalType: 'CONFIRM',
  138. modalProps: {
  139. message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
  140. confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
  141. onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),
  142. },
  143. }));
  144. }
  145. },
  146. onEdit (status, history) {
  147. dispatch((_, getState) => {
  148. let state = getState();
  149. if (state.getIn(['compose', 'text']).trim().length !== 0) {
  150. dispatch(openModal({
  151. modalType: 'CONFIRM',
  152. modalProps: {
  153. message: intl.formatMessage(messages.editMessage),
  154. confirm: intl.formatMessage(messages.editConfirm),
  155. onConfirm: () => dispatch(editStatus(status.get('id'), history)),
  156. },
  157. }));
  158. } else {
  159. dispatch(editStatus(status.get('id'), history));
  160. }
  161. });
  162. },
  163. onTranslate (status) {
  164. if (status.get('translation')) {
  165. dispatch(undoStatusTranslation(status.get('id'), status.get('poll')));
  166. } else {
  167. dispatch(translateStatus(status.get('id')));
  168. }
  169. },
  170. onDirect (account, router) {
  171. dispatch(directCompose(account, router));
  172. },
  173. onMention (account, router) {
  174. dispatch(mentionCompose(account, router));
  175. },
  176. onOpenMedia (statusId, media, index, lang) {
  177. dispatch(openModal({
  178. modalType: 'MEDIA',
  179. modalProps: { statusId, media, index, lang },
  180. }));
  181. },
  182. onOpenVideo (statusId, media, lang, options) {
  183. dispatch(openModal({
  184. modalType: 'VIDEO',
  185. modalProps: { statusId, media, lang, options },
  186. }));
  187. },
  188. onBlock (status) {
  189. const account = status.get('account');
  190. dispatch(initBlockModal(account));
  191. },
  192. onUnblock (account) {
  193. dispatch(unblockAccount(account.get('id')));
  194. },
  195. onReport (status) {
  196. dispatch(initReport(status.get('account'), status));
  197. },
  198. onAddFilter (status) {
  199. dispatch(initAddFilter(status, { contextType }));
  200. },
  201. onMute (account) {
  202. dispatch(initMuteModal(account));
  203. },
  204. onUnmute (account) {
  205. dispatch(unmuteAccount(account.get('id')));
  206. },
  207. onMuteConversation (status) {
  208. if (status.get('muted')) {
  209. dispatch(unmuteStatus(status.get('id')));
  210. } else {
  211. dispatch(muteStatus(status.get('id')));
  212. }
  213. },
  214. onToggleHidden (status) {
  215. if (status.get('hidden')) {
  216. dispatch(revealStatus(status.get('id')));
  217. } else {
  218. dispatch(hideStatus(status.get('id')));
  219. }
  220. },
  221. onToggleCollapsed (status, isCollapsed) {
  222. dispatch(toggleStatusCollapse(status.get('id'), isCollapsed));
  223. },
  224. onBlockDomain (domain) {
  225. dispatch(openModal({
  226. modalType: 'CONFIRM',
  227. modalProps: {
  228. message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
  229. confirm: intl.formatMessage(messages.blockDomainConfirm),
  230. onConfirm: () => dispatch(blockDomain(domain)),
  231. },
  232. }));
  233. },
  234. onUnblockDomain (domain) {
  235. dispatch(unblockDomain(domain));
  236. },
  237. deployPictureInPicture (status, type, mediaProps) {
  238. dispatch(deployPictureInPicture(status.get('id'), status.getIn(['account', 'id']), type, mediaProps));
  239. },
  240. onInteractionModal (type, status) {
  241. dispatch(openModal({
  242. modalType: 'INTERACTION',
  243. modalProps: {
  244. type,
  245. accountId: status.getIn(['account', 'id']),
  246. url: status.get('uri'),
  247. },
  248. }));
  249. },
  250. });
  251. export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status));