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.

256 lines
6.2 KiB

  1. /*
  2. `<StatusContainer>`
  3. ===================
  4. Original file by @gargron@mastodon.social et al as part of
  5. tootsuite/mastodon. Documentation by @kibi@glitch.social. The code
  6. detecting reblogs has been moved here from <Status>.
  7. */
  8. /* * * * */
  9. /*
  10. Imports:
  11. --------
  12. */
  13. // Package imports //
  14. import React from 'react';
  15. import { connect } from 'react-redux';
  16. import {
  17. defineMessages,
  18. injectIntl,
  19. FormattedMessage,
  20. } from 'react-intl';
  21. // Mastodon imports //
  22. import { makeGetStatus } from '../../../mastodon/selectors';
  23. import {
  24. replyCompose,
  25. mentionCompose,
  26. } from '../../../mastodon/actions/compose';
  27. import {
  28. reblog,
  29. favourite,
  30. unreblog,
  31. unfavourite,
  32. } from '../../../mastodon/actions/interactions';
  33. import {
  34. blockAccount,
  35. muteAccount,
  36. } from '../../../mastodon/actions/accounts';
  37. import {
  38. muteStatus,
  39. unmuteStatus,
  40. deleteStatus,
  41. } from '../../../mastodon/actions/statuses';
  42. import { initReport } from '../../../mastodon/actions/reports';
  43. import { openModal } from '../../../mastodon/actions/modal';
  44. import { deleteNotification } from '../../../mastodon/actions/notifications';
  45. // Our imports //
  46. import Status from '.';
  47. /* * * * */
  48. /*
  49. Inital setup:
  50. -------------
  51. The `messages` constant is used to define any messages that we will
  52. need in our component. In our case, these are the various confirmation
  53. messages used with statuses.
  54. */
  55. const messages = defineMessages({
  56. deleteConfirm : {
  57. id : 'confirmations.delete.confirm',
  58. defaultMessage : 'Delete',
  59. },
  60. deleteMessage : {
  61. id : 'confirmations.delete.message',
  62. defaultMessage : 'Are you sure you want to delete this status?',
  63. },
  64. blockConfirm : {
  65. id : 'confirmations.block.confirm',
  66. defaultMessage : 'Block',
  67. },
  68. muteConfirm : {
  69. id : 'confirmations.mute.confirm',
  70. defaultMessage : 'Mute',
  71. },
  72. });
  73. /* * * * */
  74. /*
  75. State mapping:
  76. --------------
  77. The `mapStateToProps()` function maps various state properties to the
  78. props of our component. We wrap this in a `makeMapStateToProps()`
  79. function to give us closure and preserve `getStatus()` across function
  80. calls.
  81. */
  82. const makeMapStateToProps = () => {
  83. const getStatus = makeGetStatus();
  84. const mapStateToProps = (state, ownProps) => {
  85. let status = getStatus(state, ownProps.id);
  86. let reblogStatus = status.get('reblog', null);
  87. let account = undefined;
  88. let prepend = undefined;
  89. /*
  90. Here we process reblogs. If our status is a reblog, then we create a
  91. `prependMessage` to pass along to our `<Status>` along with the
  92. reblogger's `account`, and set `coreStatus` (the one we will actually
  93. render) to the status which has been reblogged.
  94. */
  95. if (reblogStatus !== null && typeof reblogStatus === 'object') {
  96. account = status.get('account');
  97. status = reblogStatus;
  98. prepend = 'reblogged_by';
  99. }
  100. /*
  101. Here are the props we pass to `<Status>`.
  102. */
  103. return {
  104. status : status,
  105. account : account || ownProps.account,
  106. me : state.getIn(['meta', 'me']),
  107. settings : state.get('local_settings'),
  108. prepend : prepend || ownProps.prepend,
  109. reblogModal : state.getIn(['meta', 'boost_modal']),
  110. deleteModal : state.getIn(['meta', 'delete_modal']),
  111. autoPlayGif : state.getIn(['meta', 'auto_play_gif']),
  112. };
  113. };
  114. return mapStateToProps;
  115. };
  116. /* * * * */
  117. /*
  118. Dispatch mapping:
  119. -----------------
  120. The `mapDispatchToProps()` function maps dispatches to our store to the
  121. various props of our component. We need to provide dispatches for all
  122. of the things you can do with a status: reply, reblog, favourite, et
  123. cetera.
  124. For a few of these dispatches, we open up confirmation modals; the rest
  125. just immediately execute their corresponding actions.
  126. */
  127. const mapDispatchToProps = (dispatch, { intl }) => ({
  128. onReply (status, router) {
  129. dispatch(replyCompose(status, router));
  130. },
  131. onModalReblog (status) {
  132. dispatch(reblog(status));
  133. },
  134. onReblog (status, e) {
  135. if (status.get('reblogged')) {
  136. dispatch(unreblog(status));
  137. } else {
  138. if (e.shiftKey || !this.reblogModal) {
  139. this.onModalReblog(status);
  140. } else {
  141. dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
  142. }
  143. }
  144. },
  145. onFavourite (status) {
  146. if (status.get('favourited')) {
  147. dispatch(unfavourite(status));
  148. } else {
  149. dispatch(favourite(status));
  150. }
  151. },
  152. onDelete (status) {
  153. if (!this.deleteModal) {
  154. dispatch(deleteStatus(status.get('id')));
  155. } else {
  156. dispatch(openModal('CONFIRM', {
  157. message: intl.formatMessage(messages.deleteMessage),
  158. confirm: intl.formatMessage(messages.deleteConfirm),
  159. onConfirm: () => dispatch(deleteStatus(status.get('id'))),
  160. }));
  161. }
  162. },
  163. onMention (account, router) {
  164. dispatch(mentionCompose(account, router));
  165. },
  166. onOpenMedia (media, index) {
  167. dispatch(openModal('MEDIA', { media, index }));
  168. },
  169. onOpenVideo (media, time) {
  170. dispatch(openModal('VIDEO', { media, time }));
  171. },
  172. onBlock (account) {
  173. dispatch(openModal('CONFIRM', {
  174. message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
  175. confirm: intl.formatMessage(messages.blockConfirm),
  176. onConfirm: () => dispatch(blockAccount(account.get('id'))),
  177. }));
  178. },
  179. onReport (status) {
  180. dispatch(initReport(status.get('account'), status));
  181. },
  182. onMute (account) {
  183. dispatch(openModal('CONFIRM', {
  184. message: <FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
  185. confirm: intl.formatMessage(messages.muteConfirm),
  186. onConfirm: () => dispatch(muteAccount(account.get('id'))),
  187. }));
  188. },
  189. onMuteConversation (status) {
  190. if (status.get('muted')) {
  191. dispatch(unmuteStatus(status.get('id')));
  192. } else {
  193. dispatch(muteStatus(status.get('id')));
  194. }
  195. },
  196. onDeleteNotification (id) {
  197. dispatch(deleteNotification(id));
  198. },
  199. });
  200. export default injectIntl(
  201. connect(makeMapStateToProps, mapDispatchToProps)(Status)
  202. );