@@ -2,9 +2,28 @@ import React from 'react';
22import PropTypes from 'prop-types' ;
33import ImmutablePropTypes from 'react-immutable-proptypes' ;
44import ImmutablePureComponent from 'react-immutable-pure-component' ;
5- import StatusContainer from '../../../containers/status_container' ;
5+ import StatusContent from 'mastodon/components/status_content' ;
6+ import AttachmentList from 'mastodon/components/attachment_list' ;
7+ import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
8+ import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container' ;
9+ import AvatarComposite from 'mastodon/components/avatar_composite' ;
10+ import Permalink from 'mastodon/components/permalink' ;
11+ import IconButton from 'mastodon/components/icon_button' ;
12+ import RelativeTimestamp from 'mastodon/components/relative_timestamp' ;
13+ import { HotKeys } from 'react-hotkeys' ;
614
7- export default class Conversation extends ImmutablePureComponent {
15+ const messages = defineMessages ( {
16+ more : { id : 'status.more' , defaultMessage : 'More' } ,
17+ open : { id : 'conversation.open' , defaultMessage : 'View conversation' } ,
18+ reply : { id : 'status.reply' , defaultMessage : 'Reply' } ,
19+ markAsRead : { id : 'conversation.mark_as_read' , defaultMessage : 'Mark as read' } ,
20+ delete : { id : 'conversation.delete' , defaultMessage : 'Delete conversation' } ,
21+ muteConversation : { id : 'status.mute_conversation' , defaultMessage : 'Mute conversation' } ,
22+ unmuteConversation : { id : 'status.unmute_conversation' , defaultMessage : 'Unmute conversation' } ,
23+ } ) ;
24+
25+ export default @injectIntl
26+ class Conversation extends ImmutablePureComponent {
827
928 static contextTypes = {
1029 router : PropTypes . object ,
@@ -13,25 +32,38 @@ export default class Conversation extends ImmutablePureComponent {
1332 static propTypes = {
1433 conversationId : PropTypes . string . isRequired ,
1534 accounts : ImmutablePropTypes . list . isRequired ,
16- lastStatusId : PropTypes . string ,
35+ lastStatus : ImmutablePropTypes . map ,
1736 unread :PropTypes . bool . isRequired ,
1837 onMoveUp : PropTypes . func ,
1938 onMoveDown : PropTypes . func ,
2039 markRead : PropTypes . func . isRequired ,
40+ intl : PropTypes . object . isRequired ,
2141 } ;
2242
2343 handleClick = ( ) => {
2444 if ( ! this . context . router ) {
2545 return ;
2646 }
2747
28- const { lastStatusId , unread, markRead } = this . props ;
48+ const { lastStatus , unread, markRead } = this . props ;
2949
3050 if ( unread ) {
3151 markRead ( ) ;
3252 }
3353
34- this . context . router . history . push ( `/statuses/${ lastStatusId } ` ) ;
54+ this . context . router . history . push ( `/statuses/${ lastStatus . get ( 'id' ) } ` ) ;
55+ }
56+
57+ handleMarkAsRead = ( ) => {
58+ this . props . markRead ( ) ;
59+ }
60+
61+ handleReply = ( ) => {
62+ this . props . reply ( this . props . lastStatus , this . context . router . history ) ;
63+ }
64+
65+ handleDelete = ( ) => {
66+ this . props . delete ( ) ;
3567 }
3668
3769 handleHotkeyMoveUp = ( ) => {
@@ -42,22 +74,88 @@ export default class Conversation extends ImmutablePureComponent {
4274 this . props . onMoveDown ( this . props . conversationId ) ;
4375 }
4476
77+ handleConversationMute = ( ) => {
78+ this . props . onMute ( this . props . lastStatus ) ;
79+ }
80+
81+ handleShowMore = ( ) => {
82+ this . props . onToggleHidden ( this . props . lastStatus ) ;
83+ }
84+
4585 render ( ) {
46- const { accounts, lastStatusId , unread } = this . props ;
86+ const { accounts, lastStatus , unread, intl } = this . props ;
4787
48- if ( lastStatusId === null ) {
88+ if ( lastStatus === null ) {
4989 return null ;
5090 }
5191
92+ const menu = [
93+ { text : intl . formatMessage ( messages . open ) , action : this . handleClick } ,
94+ null ,
95+ ] ;
96+
97+ menu . push ( { text : intl . formatMessage ( lastStatus . get ( 'muted' ) ? messages . unmuteConversation : messages . muteConversation ) , action : this . handleConversationMute } ) ;
98+
99+ if ( unread ) {
100+ menu . push ( { text : intl . formatMessage ( messages . markAsRead ) , action : this . handleMarkAsRead } ) ;
101+ menu . push ( null ) ;
102+ }
103+
104+ menu . push ( { text : intl . formatMessage ( messages . delete ) , action : this . handleDelete } ) ;
105+
106+ const names = accounts . map ( a => < Permalink to = { `/accounts/${ a . get ( 'id' ) } ` } href = { a . get ( 'url' ) } key = { a . get ( 'id' ) } title = { a . get ( 'acct' ) } > < bdi > < strong className = 'display-name__html' dangerouslySetInnerHTML = { { __html : a . get ( 'display_name_html' ) } } /> </ bdi > </ Permalink > ) . reduce ( ( prev , cur ) => [ prev , ', ' , cur ] ) ;
107+
108+ const handlers = {
109+ reply : this . handleReply ,
110+ open : this . handleClick ,
111+ moveUp : this . handleHotkeyMoveUp ,
112+ moveDown : this . handleHotkeyMoveDown ,
113+ toggleHidden : this . handleShowMore ,
114+ } ;
115+
52116 return (
53- < StatusContainer
54- id = { lastStatusId }
55- unread = { unread }
56- otherAccounts = { accounts }
57- onMoveUp = { this . handleHotkeyMoveUp }
58- onMoveDown = { this . handleHotkeyMoveDown }
59- onClick = { this . handleClick }
60- />
117+ < HotKeys handlers = { handlers } >
118+ < div className = 'conversation focusable muted' tabIndex = '0' >
119+ < div className = 'conversation__avatar' >
120+ < AvatarComposite accounts = { accounts } size = { 48 } />
121+ </ div >
122+
123+ < div className = 'conversation__content' >
124+ < div className = 'conversation__content__info' >
125+ < div className = 'conversation__content__relative-time' >
126+ < RelativeTimestamp timestamp = { lastStatus . get ( 'created_at' ) } />
127+ </ div >
128+
129+ < div className = 'conversation__content__names' >
130+ < FormattedMessage id = 'conversation.with' defaultMessage = 'With {names}' values = { { names : < span > { names } </ span > } } />
131+ </ div >
132+ </ div >
133+
134+ < StatusContent
135+ status = { lastStatus }
136+ onClick = { this . handleClick }
137+ expanded = { ! lastStatus . get ( 'hidden' ) }
138+ onExpandedToggle = { this . handleShowMore }
139+ collapsable
140+ />
141+
142+ { lastStatus . get ( 'media_attachments' ) . size > 0 && (
143+ < AttachmentList
144+ compact
145+ media = { lastStatus . get ( 'media_attachments' ) }
146+ />
147+ ) }
148+
149+ < div className = 'status__action-bar' >
150+ < IconButton className = 'status__action-bar-button' title = { intl . formatMessage ( messages . reply ) } icon = 'reply' onClick = { this . handleReply } />
151+
152+ < div className = 'status__action-bar-dropdown' >
153+ < DropdownMenuContainer status = { lastStatus } items = { menu } icon = 'ellipsis-h' size = { 18 } direction = 'right' title = { intl . formatMessage ( messages . more ) } />
154+ </ div >
155+ </ div >
156+ </ div >
157+ </ div >
158+ </ HotKeys >
61159 ) ;
62160 }
63161
0 commit comments