Progress
Report modal style fix, chat updates, statusserializer revert, display name truncation
This commit is contained in:
parent
7ec426e3d8
commit
67eb9d5890
|
@ -9,7 +9,6 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||
@statuses = load_statuses
|
||||
render json: @statuses,
|
||||
each_serializer: REST::StatusSerializer,
|
||||
account_id: params[:account_id],
|
||||
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||
end
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ class Api::V1::ChatConversationController < Api::BaseController
|
|||
# check if chat blocked
|
||||
# check if allow anyone to message then create with approved:true
|
||||
# unique account id, participants
|
||||
|
||||
chat_conversation_account = find_or_create_conversation
|
||||
render json: chat_conversation_account, each_serializer: REST::ChatConversationAccountSerializer
|
||||
end
|
||||
|
@ -67,7 +68,6 @@ class Api::V1::ChatConversationController < Api::BaseController
|
|||
else
|
||||
@expires_at = nil
|
||||
end
|
||||
puts "tilly @expires_at: " + @expires_at.inspect
|
||||
@chat_conversation_account.chat_message_expiration_policy = @expires_at
|
||||
@chat_conversation_account.save!
|
||||
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
|
||||
|
|
|
@ -13,7 +13,7 @@ class Api::V1::Timelines::GroupController < Api::BaseController
|
|||
if current_user
|
||||
render json: @statuses,
|
||||
each_serializer: REST::StatusSerializer,
|
||||
group_id: params[:id],
|
||||
group_id: params[:id], # : todo :
|
||||
relationships: StatusRelationshipsPresenter.new(@statuses, current_user.account_id, group_id: @group.id)
|
||||
else
|
||||
render json: @statuses, each_serializer: REST::StatusSerializer
|
||||
|
|
|
@ -10,7 +10,7 @@ class Api::V1::Timelines::PreviewCardController < Api::BaseController
|
|||
def show
|
||||
render json: @statuses,
|
||||
each_serializer: REST::StatusSerializer,
|
||||
preview_card_id: params[:id],
|
||||
preview_card_id: params[:id], # : todo :
|
||||
relationships: StatusRelationshipsPresenter.new(@statuses, current_user.account_id)
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::Web::ChatSettingsController < Api::Web::BaseController
|
||||
before_action :require_user!
|
||||
|
||||
def update
|
||||
setting.data = params[:data]
|
||||
setting.save!
|
||||
|
||||
# todo validate all data objects
|
||||
|
||||
render_empty_success
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def setting
|
||||
@_setting ||= ::Web::Setting.where(user: current_user).first_or_initialize(user: current_user)
|
||||
end
|
||||
end
|
|
@ -162,7 +162,6 @@ export const followAccount = (id, reblogs = true) => (dispatch, getState) => {
|
|||
dispatch(followAccountRequest(id, locked))
|
||||
|
||||
api(getState).post(`/api/v1/accounts/${id}/follow`, { reblogs }).then((response) => {
|
||||
console.log("response:", response)
|
||||
dispatch(followAccountSuccess(response.data, alreadyFollowing))
|
||||
}).catch((error) => {
|
||||
dispatch(followAccountFail(error, locked))
|
||||
|
|
|
@ -258,7 +258,6 @@ export const deleteChatConversation = (chatConversationId) => (dispatch, getStat
|
|||
dispatch(deleteChatConversationRequest(conversationId))
|
||||
|
||||
api(getState).delete(`/api/v1/chat_conversation/${chatConversationId}`).then((response) => {
|
||||
console.log("chat_conversations delete response: ", response)
|
||||
dispatch(deleteChatConversationSuccess())
|
||||
}).catch((error) => {
|
||||
dispatch(deleteChatConversationFail(error))
|
||||
|
|
|
@ -62,11 +62,9 @@ const sendChatMessageFail = (error) => ({
|
|||
export const manageIncomingChatMessage = (chatMessage) => (dispatch, getState) => {
|
||||
if (!chatMessage) return
|
||||
|
||||
console.log("chatMessage:", chatMessage)
|
||||
dispatch(sendChatMessageSuccess(chatMessage))
|
||||
|
||||
const isOnline = getState().getIn(['chat_conversation_messages', chatMessage.chat_conversation_id, 'online'])
|
||||
console.log("isOnline: ", isOnline)
|
||||
|
||||
// : todo :
|
||||
// Check if is online for conversation, if not increase total/convo unread count
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import api from '../api'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { me } from '../initial_state'
|
||||
|
||||
export const CHAT_SETTING_CHANGE = 'CHAT_SETTING_CHANGE'
|
||||
export const CHAT_SETTING_SAVE = 'CHAT_SETTING_SAVE'
|
||||
|
||||
export const changeChatSetting = (path, value) => (dispatch) => {
|
||||
dispatch({
|
||||
type: CHAT_SETTING_CHANGE,
|
||||
path,
|
||||
value,
|
||||
})
|
||||
|
||||
dispatch(saveChatSettings())
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const saveChatSettings = () => (dispatch, getState) => {
|
||||
debouncedChatSettingsSave(dispatch, getState)
|
||||
}
|
||||
|
||||
const debouncedChatSettingsSave = debounce((dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
if (getState().getIn(['chat_settings', 'saved'])) return
|
||||
|
||||
const data = getState().get('chat_settings').filter((_, path) => path !== 'saved').toJS()
|
||||
|
||||
api().put('/api/web/chat_settings', { data })
|
||||
.then(() => dispatch({ type: CHAT_SETTING_SAVE }))
|
||||
.catch(() => { /* */ })
|
||||
}, 350, { trailing: true })
|
|
@ -151,7 +151,6 @@ export const expandTimeline = (timelineId, path, params = {}, done = noop) => (d
|
|||
dispatch(expandTimelineRequest(timelineId, isLoadingMore))
|
||||
|
||||
api(getState).get(path, { params }).then((response) => {
|
||||
console.log("response:", response)
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedStatuses(response.data))
|
||||
dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.code === 206, isLoadingRecent, isLoadingMore))
|
||||
|
|
|
@ -106,8 +106,7 @@ class DisplayName extends ImmutablePureComponent {
|
|||
const usernameClasses = CX({
|
||||
text: 1,
|
||||
displayFlex: 1,
|
||||
flexNormal: 1,
|
||||
flexShrink1: 1,
|
||||
flexShrink0: 1,
|
||||
overflowWrapBreakWord: 1,
|
||||
textOverflowEllipsis: 1,
|
||||
cSecondary: 1,
|
||||
|
@ -131,17 +130,10 @@ class DisplayName extends ImmutablePureComponent {
|
|||
const isFollowedBy = (me !== accountId && account.getIn(['relationship', 'followed_by']))
|
||||
|
||||
if (isFollowedBy) {
|
||||
relationshipLabel = 'Follows you'//intl.formatMessage(messages.accountFollowsYou)
|
||||
relationshipLabel = 'Follows you'
|
||||
}
|
||||
}
|
||||
|
||||
// {
|
||||
// /* : todo : audio-mute, bot
|
||||
// account.getIn(['relationship', 'muting'])
|
||||
// */
|
||||
// }
|
||||
// bot: { id: 'account.badges.bot', defaultMessage: 'Bot' },
|
||||
|
||||
return (
|
||||
<div
|
||||
className={containerClassName}
|
||||
|
@ -149,7 +141,7 @@ class DisplayName extends ImmutablePureComponent {
|
|||
onMouseLeave={noHover ? undefined : this.handleMouseLeave}
|
||||
ref={this.setRef}
|
||||
>
|
||||
<span className={[_s.d, _s.flexRow, _s.aiCenter, _s.maxW100PC].join(' ')}>
|
||||
<span className={[_s.d, _s.flexRow, _s.aiCenter, _s.maxW100PC, _s.flexShrink1, _s.overflowHidden].join(' ')}>
|
||||
<bdi className={[_s.text, _s.whiteSpaceNoWrap, _s.textOverflowEllipsis].join(' ')}>
|
||||
<strong
|
||||
className={displayNameClasses}
|
||||
|
|
|
@ -55,6 +55,7 @@ class ReportModal extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<ModalLayout
|
||||
width={760}
|
||||
noPadding
|
||||
title={intl.formatMessage(messages.target, {
|
||||
target: account.get('acct')
|
||||
|
@ -67,7 +68,7 @@ class ReportModal extends ImmutablePureComponent {
|
|||
classNamesSmall={[_s.d, _s.flexColumnReverse].join(' ')}
|
||||
>
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.d, _s.w50PC, _s.py10, _s.px15, _s.borderRight1PX, _s.borderColorSecondary].join(' ')}
|
||||
classNames={[_s.d, _s.maxW320PX, _s.py10, _s.px15, _s.borderRight1PX, _s.borderColorSecondary].join(' ')}
|
||||
classNamesSmall={[_s.d, _s.w100PC, _s.py10, _s.px15, _s.borderTop1PX, _s.borderColorSecondary].join(' ')}
|
||||
>
|
||||
<Text color='secondary' size='small'>
|
||||
|
@ -95,13 +96,13 @@ class ReportModal extends ImmutablePureComponent {
|
|||
</ResponsiveClassesComponent>
|
||||
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.d, _s.w50PC, _s.maxH80VH].join(' ')}
|
||||
classNames={[_s.d, _s.flexNormal, _s.maxH80VH].join(' ')}
|
||||
classNamesSmall={[_s.d, _s.w100PC, _s.h260PX].join(' ')}
|
||||
>
|
||||
<div className={[_s.d, _s.h100PC, _s.overflowYScroll, _s.pr15, _s.py10].join(' ')}>
|
||||
<div className={[_s.d, _s.h100PC, _s.overflowYScroll].join(' ')}>
|
||||
{
|
||||
statusIds.map(statusId => (
|
||||
<StatusCheckBox id={statusId} key={statusId} disabled={isSubmitting} />
|
||||
statusIds.map((statusId) => (
|
||||
<StatusCheckBox id={statusId} key={`reporting-${statusId}`} disabled={isSubmitting} />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -33,6 +33,9 @@ class ChatNavigationBar extends React.PureComponent {
|
|||
const otherAccounts = chatConversation ? chatConversation.get('other_accounts') : null
|
||||
const nameHTML = !!otherAccounts ? otherAccounts.get(0).get('display_name_html') : ''
|
||||
|
||||
// : todo :
|
||||
// fix padding on mobile device
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.z4, _s.h53PX, _s.w100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.h53PX, _s.bgNavigation, _s.aiCenter, _s.z3, _s.top0, _s.right0, _s.left0, _s.posFixed].join(' ')} >
|
||||
|
@ -46,23 +49,29 @@ class ChatNavigationBar extends React.PureComponent {
|
|||
iconClassName={[_s.mr5, _s.fillNavigation].join(' ')}
|
||||
/>
|
||||
|
||||
<div className={[_s.d, _s.h53PX, _s.flexRow, _s.jcCenter, _s.aiCenter, _s.mrAuto].join(' ')}>
|
||||
<AvatarGroup accounts={otherAccounts} size={35} noHover />
|
||||
<Heading size='h1'>
|
||||
<div className={[_s.dangerousContent, _s.colorNavigation, _s.pl10, _s.fs19PX].join(' ')} dangerouslySetInnerHTML={{ __html: nameHTML }} />
|
||||
</Heading>
|
||||
<div className={[_s.d, _s.minH53PX, _s.flexRow, _s.aiCenter, _s.mrAuto, _s.flex1, _s.overflowHidden].join(' ')}>
|
||||
<div className={[_s.d, _s.minH53PX, _s.jcCenter, _s.w100PC, _s.flexShrink1].join(' ')}>
|
||||
<Heading size='h1'>
|
||||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
<span
|
||||
className={[_s.w100PC, _s.textOverflowEllipsis, _s.colorNavigation].join(' ')}
|
||||
dangerouslySetInnerHTML={{ __html: nameHTML }}
|
||||
/>
|
||||
</div>
|
||||
</Heading>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.h53PX, _s.mlAuto, _s.aiCenter, _s.jcCenter, _s.mr15].join(' ')}>
|
||||
<Button
|
||||
isNarrow
|
||||
backgroundColor='tertiary'
|
||||
backgroundColor='none'
|
||||
color='primary'
|
||||
onClick={this.handleOnOpenChatConversationOptionsPopover}
|
||||
className={[_s.px5].join(' ')}
|
||||
icon='ellipsis'
|
||||
iconClassName={[_s.cSecondary, _s.px5, _s.py5].join(' ')}
|
||||
iconSize='15px'
|
||||
iconClassName={[_s.colorNavigation, _s.px5, _s.py5].join(' ')}
|
||||
iconSize='26px'
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ class ProfileNavigationBar extends React.PureComponent {
|
|||
render() {
|
||||
const { titleHTML } = this.props
|
||||
|
||||
// : todo :
|
||||
// fix padding on mobile device
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.z4, _s.minH53PX, _s.w100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.minH53PX, _s.bgNavigation, _s.aiCenter, _s.z3, _s.top0, _s.right0, _s.left0, _s.posFixed].join(' ')} >
|
||||
|
@ -36,12 +39,17 @@ class ProfileNavigationBar extends React.PureComponent {
|
|||
iconClassName={[_s.mr5, _s.fillNavigation].join(' ')}
|
||||
/>
|
||||
|
||||
<div className={[_s.d, _s.minH53PX, _s.jcCenter, _s.mrAuto].join(' ')}>
|
||||
<Heading size='h1'>
|
||||
<span className={[_s.textOverflowEllipsis, _s.colorNavigation].join(' ')}>
|
||||
<div dangerouslySetInnerHTML={{ __html: titleHTML }} />
|
||||
</span>
|
||||
</Heading>
|
||||
<div className={[_s.d, _s.minH53PX, _s.mrAuto, _s.flex1, _s.overflowHidden].join(' ')}>
|
||||
<div className={[_s.d, _s.minH53PX, _s.jcCenter, _s.w100PC].join(' ')}>
|
||||
<Heading size='h1'>
|
||||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
<span
|
||||
className={[_s.w100PC, _s.textOverflowEllipsis, _s.colorNavigation].join(' ')}
|
||||
dangerouslySetInnerHTML={{ __html: titleHTML }}
|
||||
/>
|
||||
</div>
|
||||
</Heading>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.minH53PX, _s.jcCenter, _s.mr15].join(' ')}>
|
||||
|
|
|
@ -35,7 +35,6 @@ class ChatConversationExpirationOptionsPopover extends React.PureComponent {
|
|||
isXS,
|
||||
} = this.props
|
||||
|
||||
console.log("expiresAtValue:", expiresAtValue)
|
||||
if (!chatConversationId) return <div/>
|
||||
|
||||
const listItems = [
|
||||
|
|
|
@ -6,6 +6,7 @@ import { connect } from 'react-redux'
|
|||
import { closePopover } from '../../actions/popover'
|
||||
import { openModal } from '../../actions/modal'
|
||||
import { hideChatConversation } from '../../actions/chat_conversations'
|
||||
import { setChatConversationSelected } from '../../actions/chats'
|
||||
import {
|
||||
muteChatConversation,
|
||||
unmuteChatConversation,
|
||||
|
@ -107,6 +108,7 @@ const mapDispatchToProps = (dispatch, { chatConversationId }) => ({
|
|||
},
|
||||
onHide() {
|
||||
dispatch(hideChatConversation(chatConversationId))
|
||||
dispatch(setChatConversationSelected(null))
|
||||
},
|
||||
onMute() {
|
||||
dispatch(muteChatConversation(chatConversationId))
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import PopoverLayout from './popover_layout'
|
||||
import List from '../list'
|
||||
|
||||
class ChatSettingsPopover extends React.PureComponent {
|
||||
|
||||
handleOnClosePopover = () => {
|
||||
this.props.onClose()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, isXS } = this.props
|
||||
|
||||
return (
|
||||
<PopoverLayout width={240} isXS={isXS}>
|
||||
<List
|
||||
size={isXS ? 'large' : 'small'}
|
||||
scrollKey='profile_options'
|
||||
items={[
|
||||
{
|
||||
title: 'Preferences',
|
||||
to: '/messages/settings',
|
||||
onClick: () => this.handleOnClosePopover(),
|
||||
},
|
||||
{
|
||||
title: 'Message Requests',
|
||||
to: '/messages/requests',
|
||||
onClick: () => this.handleOnClosePopover(),
|
||||
},
|
||||
{
|
||||
title: 'Blocked Chat Messengers',
|
||||
to: '/messages/blocks',
|
||||
onClick: () => this.handleOnClosePopover(),
|
||||
},
|
||||
{
|
||||
title: 'Muted Conversations',
|
||||
to: '/messages/muted_conversations',
|
||||
onClick: () => this.handleOnClosePopover(),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</PopoverLayout>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ChatSettingsPopover.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
isXS: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default ChatSettingsPopover
|
|
@ -70,7 +70,7 @@ class DatePickerPopover extends React.PureComponent {
|
|||
<div className={[_s.d, _s.aiCenter, _s.flexRow, _s.px10, _s.py10, _s.borderTop1PX, _s.borderColorSecondary].join(' ')}>
|
||||
<Text size='extraSmall' color='secondary'>
|
||||
<FormattedMessage id='scheduled_for_datetime' defaultMessage='Scheduled for {datetime}' values={{
|
||||
datetime: moment.utc(date).format('lll'),
|
||||
datetime: moment(date).format('lll'),
|
||||
}}/>
|
||||
</Text>
|
||||
<div className={_s.mlAuto}>
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
POPOVER_CHAT_CONVERSATION_EXPIRATION_OPTIONS,
|
||||
POPOVER_CHAT_CONVERSATION_OPTIONS,
|
||||
POPOVER_CHAT_MESSAGE_OPTIONS,
|
||||
POPOVER_CHAT_SETTINGS,
|
||||
POPOVER_COMMENT_SORTING_OPTIONS,
|
||||
POPOVER_COMPOSE_POST_DESTINATION,
|
||||
POPOVER_DATE_PICKER,
|
||||
|
@ -27,6 +28,7 @@ import {
|
|||
ChatConversationExpirationOptionsPopover,
|
||||
ChatConversationOptionsPopover,
|
||||
ChatMessageOptionsPopover,
|
||||
ChatSettingsPopover,
|
||||
CommentSortingOptionsPopover,
|
||||
ComposePostDesinationPopover,
|
||||
DatePickerPopover,
|
||||
|
@ -65,6 +67,7 @@ const POPOVER_COMPONENTS = {
|
|||
[POPOVER_CHAT_CONVERSATION_EXPIRATION_OPTIONS]: ChatConversationExpirationOptionsPopover,
|
||||
[POPOVER_CHAT_CONVERSATION_OPTIONS]: ChatConversationOptionsPopover,
|
||||
[POPOVER_CHAT_MESSAGE_OPTIONS]: ChatMessageOptionsPopover,
|
||||
[POPOVER_CHAT_SETTINGS]: ChatSettingsPopover,
|
||||
[POPOVER_COMMENT_SORTING_OPTIONS]: CommentSortingOptionsPopover,
|
||||
[POPOVER_COMPOSE_POST_DESTINATION]: ComposePostDesinationPopover,
|
||||
[POPOVER_DATE_PICKER]: DatePickerPopover,
|
||||
|
@ -161,7 +164,7 @@ class PopoverRoot extends React.PureComponent {
|
|||
renderDelay={150}
|
||||
>
|
||||
{
|
||||
(Component) => <Component innerRef={this.setRef} isXS={isXS} {...props} />
|
||||
(Component) => <Component innerRef={this.setRef} isXS={isXS} onClose={onClose} {...props} />
|
||||
}
|
||||
</Bundle>
|
||||
}
|
||||
|
|
|
@ -310,12 +310,15 @@ class Status extends ImmutablePureComponent {
|
|||
commentSortingType,
|
||||
onOpenProModal,
|
||||
isDeckConnected,
|
||||
statusId,
|
||||
} = this.props
|
||||
// const { height } = this.state
|
||||
|
||||
let { status } = this.props
|
||||
|
||||
if (!status) return null
|
||||
if (!status) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (isComment && !ancestorStatus && !isChild) {
|
||||
// Wait to load...
|
||||
|
@ -331,7 +334,7 @@ class Status extends ImmutablePureComponent {
|
|||
if (ancestorStatus) {
|
||||
status = ancestorStatus
|
||||
} else {
|
||||
if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {
|
||||
if (status.get('reblog', null) !== null) {
|
||||
rebloggedByText = intl.formatMessage(
|
||||
{ id: 'status.reposted_by', defaultMessage: '{name} reposted' },
|
||||
{ name: status.getIn(['account', 'acct']) }
|
||||
|
|
|
@ -46,17 +46,27 @@ class StatusCheckBox extends ImmutablePureComponent {
|
|||
} else {
|
||||
media = (
|
||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery} >
|
||||
{Component => <Component media={status.get('media_attachments')} sensitive={status.get('sensitive')} onOpenMedia={noop} />}
|
||||
{Component => (
|
||||
<Component
|
||||
media={status.get('media_attachments')}
|
||||
sensitive={status.get('sensitive')}
|
||||
onOpenMedia={noop}
|
||||
width={239}
|
||||
height={110}
|
||||
/>
|
||||
)}
|
||||
</Bundle>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.flexRow].join(' ')}>
|
||||
<div className={[_s.d].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.flexWrap, _s.borderBottom1PX, _s.borderColorSecondary, _s.aiStart, _s.mb5, _s.pr15, _s.pt5, _s.w100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.pt5, _s.maxW100PC].join(' ')}>
|
||||
<StatusContent status={status} />
|
||||
{media}
|
||||
<div className={_s.pl15}>
|
||||
{media}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.mlAuto].join(' ')}>
|
||||
|
|
|
@ -79,7 +79,8 @@ class StatusHeader extends ImmutablePureComponent {
|
|||
const textContainerClasses = CX({
|
||||
d: 1,
|
||||
aiStart: 1,
|
||||
flexGrow1 :1,
|
||||
flex1: 1,
|
||||
overflowHidden: 1,
|
||||
mt5: !isCompact,
|
||||
})
|
||||
|
||||
|
@ -100,13 +101,15 @@ class StatusHeader extends ImmutablePureComponent {
|
|||
|
||||
<div className={textContainerClasses}>
|
||||
|
||||
<div className={[_s.d, _s.flexRow, _s.w100PC, _s.aiStart].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.w100PC, _s.aiStart, _s.overflowHidden].join(' ')}>
|
||||
<NavLink
|
||||
className={[_s.d, _s.flexRow, _s.aiStart, _s.noUnderline].join(' ')}
|
||||
className={[_s.d, _s.flexRow, _s.aiStart, _s.noUnderline, _s.flex1, _s.maxW100PC30PX].join(' ')}
|
||||
to={`/${status.getIn(['account', 'acct'])}`}
|
||||
title={status.getIn(['account', 'acct'])}
|
||||
>
|
||||
<DisplayName account={status.get('account')} noRelationship />
|
||||
<div className={[_s.d, _s.w100PC, _s.overflowHidden].join(' ')}>
|
||||
<DisplayName account={status.get('account')} noRelationship />
|
||||
</div>
|
||||
</NavLink>
|
||||
|
||||
{
|
||||
|
@ -118,7 +121,7 @@ class StatusHeader extends ImmutablePureComponent {
|
|||
icon='ellipsis'
|
||||
iconSize='20px'
|
||||
iconClassName={_s.cSecondary}
|
||||
className={_s.mlAuto}
|
||||
className={[_s.mlAuto].join(' ')}
|
||||
onClick={this.handleOpenStatusOptionsPopover}
|
||||
buttonRef={this.setStatusOptionsButton}
|
||||
/>
|
||||
|
|
|
@ -44,7 +44,7 @@ class UserSuggestionsInjection extends ImmutablePureComponent {
|
|||
id={injectionId}
|
||||
title={title}
|
||||
buttonLink='/suggestions'
|
||||
buttonTitle='See more reccomendations'
|
||||
buttonTitle='See more recommendations'
|
||||
isXS={isXS}
|
||||
>
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ export const PLACEHOLDER_MISSING_HEADER_SRC = '/original/missing.png'
|
|||
export const POPOVER_CHAT_CONVERSATION_OPTIONS = 'CHAT_CONVERSATION_OPTIONS'
|
||||
export const POPOVER_CHAT_MESSAGE_OPTIONS = 'CHAT_MESSAGE_OPTIONS'
|
||||
export const POPOVER_CHAT_CONVERSATION_EXPIRATION_OPTIONS = 'CHAT_CONVERSATION_EXPIRATION_OPTIONS'
|
||||
export const POPOVER_CHAT_SETTINGS = 'CHAT_SETTINGS'
|
||||
export const POPOVER_COMMENT_SORTING_OPTIONS = 'COMMENT_SORTING_OPTIONS'
|
||||
export const POPOVER_COMPOSE_POST_DESTINATION = 'COMPOSE_POST_DESTINATION'
|
||||
export const POPOVER_DATE_PICKER = 'DATE_PICKER'
|
||||
|
|
|
@ -37,31 +37,33 @@ class ChatConversationCreate extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<Form>
|
||||
<div className={[_s.d, _s.px15, _s.pt10].join(' ')}>
|
||||
<Input
|
||||
title='Search for a user'
|
||||
value={query}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
<div className={[_s.d, _s.bgPrimary, _s.w100PC, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
|
||||
<div className={[_s.d, _s.px15, _s.pt10].join(' ')}>
|
||||
<Input
|
||||
title='Search for a user'
|
||||
value={query}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.pt10].join(' ')}>
|
||||
<div className={[_s.d].join(' ')}>
|
||||
<Text weight='bold' size='small' color='secondary' className={[_s.d, _s.px15, _s.ml15, _s.mt5, _s.mb15].join(' ')}>
|
||||
Search results ({suggestionsIds.size})
|
||||
</Text>
|
||||
{
|
||||
suggestionsIds &&
|
||||
suggestionsIds.map((accountId) => (
|
||||
<Account
|
||||
compact
|
||||
key={`chat-conversation-account-create-${accountId}`}
|
||||
id={accountId}
|
||||
onActionClick={() => this.handleOnCreateChatConversation(accountId)}
|
||||
actionIcon='add'
|
||||
/>
|
||||
))
|
||||
}
|
||||
<div className={[_s.d, _s.pt10].join(' ')}>
|
||||
<div className={[_s.d].join(' ')}>
|
||||
<Text weight='bold' size='small' color='secondary' className={[_s.d, _s.px15, _s.ml15, _s.mt5, _s.mb15].join(' ')}>
|
||||
Search results ({suggestionsIds.size})
|
||||
</Text>
|
||||
{
|
||||
suggestionsIds &&
|
||||
suggestionsIds.map((accountId) => (
|
||||
<Account
|
||||
compact
|
||||
key={`chat-conversation-account-create-${accountId}`}
|
||||
id={accountId}
|
||||
onActionClick={() => this.handleOnCreateChatConversation(accountId)}
|
||||
actionIcon='add'
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import BlockHeading from '../components/block_heading'
|
||||
import ChatConversationsList from './messages/components/chat_conversations_list'
|
||||
|
||||
class ChatConversationMutes extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={[_s.d, _s.w100PC, _s.boxShadowNone].join(' ')}>
|
||||
<div className={[_s.d, _s.h60PX, _s.w100PC, _s.px10, _s.py10, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
|
||||
<BlockHeading title={'Muted Chat Conversations'} />
|
||||
</div>
|
||||
<ChatConversationsList source='mutes' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ChatConversationMutes
|
|
@ -62,23 +62,20 @@ class GroupMembers extends ImmutablePureComponent {
|
|||
<Block>
|
||||
<BlockHeading title='Group Members' />
|
||||
|
||||
{
|
||||
/* : todo :
|
||||
<div className={[_s.d, _s.jcCenter, _s.px15, _s.my5, _s.borderBottom1PX, _s.borderColorSecondary, _s.pt5, _s.pb15].join(' ')}>
|
||||
<Input
|
||||
id='group-member-search'
|
||||
placeholder='Search group members'
|
||||
prependIcon='search'
|
||||
// value={value}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
onChange={this.handleOnChange}
|
||||
onFocus={this.handleOnFocus}
|
||||
onBlur={this.handleOnBlur}
|
||||
autoComplete='off'
|
||||
/>
|
||||
</div>
|
||||
*/
|
||||
}
|
||||
<div className={[_s.d, _s.jcCenter, _s.px15, _s.my5, _s.borderBottom1PX, _s.borderColorSecondary, _s.pt5, _s.pb15].join(' ')}>
|
||||
<Input
|
||||
id='group-member-search'
|
||||
placeholder='Search group members'
|
||||
prependIcon='search'
|
||||
// value={value}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
onChange={this.handleOnChange}
|
||||
onFocus={this.handleOnFocus}
|
||||
onBlur={this.handleOnBlur}
|
||||
autoComplete='off'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={[_s.d].join(' ')}>
|
||||
<ScrollableList
|
||||
scrollKey='group-members'
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
import { FormattedMessage } from 'react-intl'
|
||||
import Account from '../components/account'
|
||||
import Block from '../components/block'
|
||||
import Input from '../components/input'
|
||||
import BlockHeading from '../components/block_heading'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
import ScrollableList from '../components/scrollable_list'
|
||||
|
@ -49,6 +50,19 @@ class GroupRemovedAccounts extends ImmutablePureComponent {
|
|||
return (
|
||||
<Block>
|
||||
<BlockHeading title='Removed Accounts' />
|
||||
<div className={[_s.d, _s.jcCenter, _s.px15, _s.my5, _s.borderBottom1PX, _s.borderColorSecondary, _s.pt5, _s.pb15].join(' ')}>
|
||||
<Input
|
||||
id='group-member-search'
|
||||
placeholder='Search removed group members'
|
||||
prependIcon='search'
|
||||
// value={value}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
onChange={this.handleOnChange}
|
||||
onFocus={this.handleOnFocus}
|
||||
onBlur={this.handleOnBlur}
|
||||
autoComplete='off'
|
||||
/>
|
||||
</div>
|
||||
<ScrollableList
|
||||
scrollKey='removed_accounts'
|
||||
hasMore={hasMore}
|
||||
|
|
|
@ -27,6 +27,8 @@ class ChatMessagesComposeForm extends React.PureComponent {
|
|||
|
||||
handleOnSendChatMessage = () => {
|
||||
this.props.onSendChatMessage(this.state.value, this.props.chatConversationId)
|
||||
document.querySelector('#gabsocial').focus()
|
||||
this.onBlur()
|
||||
this.setState({ value: '' })
|
||||
}
|
||||
|
||||
|
@ -93,7 +95,7 @@ class ChatMessagesComposeForm extends React.PureComponent {
|
|||
expiresAtValue,
|
||||
chatConversationId,
|
||||
} = this.props
|
||||
const { value } = this.state
|
||||
const { focused, value } = this.state
|
||||
const disabled = false
|
||||
|
||||
const textareaClasses = CX({
|
||||
|
@ -141,6 +143,7 @@ class ChatMessagesComposeForm extends React.PureComponent {
|
|||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
onKeyDown={this.onKeyDown}
|
||||
focused={focused}
|
||||
aria-autocomplete='list'
|
||||
maxLength={1600}
|
||||
/>
|
||||
|
@ -170,11 +173,11 @@ class ChatMessagesComposeForm extends React.PureComponent {
|
|||
|
||||
if (isXS) {
|
||||
return (
|
||||
<div className={[_s.d, _s.z4, _s.minH58PX, _s.w100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.z4, _s.minH58PX, _s.w100PC, _s.mtAuto].join(' ')}>
|
||||
<div className={[_s.d, _s.minH58PX, _s.bgPrimary, _s.aiCenter, _s.z3, _s.bottom0, _s.right0, _s.left0, _s.posFixed].join(' ')} >
|
||||
<div className={[_s.d, _s.w100PC, _s.pb5, _s.px15, _s.aiCenter, _s.jcCenter, _s.saveAreaInsetPB, _s.saveAreaInsetPL, _s.saveAreaInsetPR, _s.w100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.minH58PX, _s.w100PC, _s.borderTop1PX, _s.borderColorSecondary, _s.px10].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.radiusRounded, _s.border1PX, _s.borderColorSecondary, _s.overflowHidden].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.flexGrow1, _s.radiusRounded, _s.border1PX, _s.borderColorSecondary, _s.overflowHidden].join(' ')}>
|
||||
<div className={_s.d}>
|
||||
{expiresBtn}
|
||||
</div>
|
||||
|
@ -182,7 +185,7 @@ class ChatMessagesComposeForm extends React.PureComponent {
|
|||
{textarea}
|
||||
</div>
|
||||
</div>
|
||||
<div className={[_s.d, _s.h100PC, _s.aiCenter, _s.jcCenter].join(' ')}>
|
||||
<div className={[_s.d, _s.pl10, _s.h100PC, _s.aiCenter, _s.jcCenter].join(' ')}>
|
||||
{button}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -39,6 +39,7 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
|||
componentDidMount () {
|
||||
const { chatConversationId } = this.props
|
||||
this.props.onExpandChatMessages(chatConversationId)
|
||||
this.scrollToBottom()
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -63,10 +64,10 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
if (prevProps.chatMessageIds.size === 0 && this.props.chatMessageIds.size > 0 && this.scrollContainerRef) {
|
||||
this.scrollContainerRef.scrollTop = this.scrollContainerRef.scrollHeight
|
||||
this.scrollToBottom()
|
||||
this.props.onReadChatConversation(this.props.chatConversationId)
|
||||
} else if (prevProps.chatMessageIds.size < this.props.chatMessageIds.size && this.scrollContainerRef) {
|
||||
this.scrollContainerRef.scrollTop = this.scrollContainerRef.scrollHeight
|
||||
// this.setScrollTop(this.scrollContainerRef.scrollHeight)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,10 +115,15 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
|||
if (!this.scrollContainerRef) return
|
||||
if (this.scrollContainerRef.scrollTop !== newScrollTop) {
|
||||
this.lastScrollWasSynthetic = true
|
||||
console.log("newScrollTop:", newScrollTop)
|
||||
this.scrollContainerRef.scrollTop = newScrollTop
|
||||
}
|
||||
}
|
||||
|
||||
scrollToBottom = () => {
|
||||
this.messagesEnd.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
|
||||
_selectChild(index, align_top) {
|
||||
const container = this.node.node
|
||||
const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`)
|
||||
|
@ -163,6 +169,7 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
|||
|
||||
handleWheel = throttle(() => {
|
||||
this.scrollToTopOnMouseIdle = false
|
||||
this.handleScroll()
|
||||
}, 150, {
|
||||
trailing: true,
|
||||
})
|
||||
|
@ -190,7 +197,7 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
|||
|
||||
handleMouseIdle = () => {
|
||||
if (this.scrollToTopOnMouseIdle) {
|
||||
this.setScrollTop(0)
|
||||
this.setScrollTop(this.scrollContainerRef.scrollHeight)
|
||||
}
|
||||
|
||||
this.mouseMovedRecently = false
|
||||
|
@ -320,6 +327,10 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
|||
</IntersectionObserverArticle>
|
||||
))
|
||||
}
|
||||
<div
|
||||
style={{ float: 'left', clear: 'both' }}
|
||||
ref={(el) => { this.messagesEnd = el }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -38,7 +38,7 @@ class MessagesSettings extends ImmutablePureComponent {
|
|||
<BlockHeading title={'Chat Preferences'} />
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.px15, _s.py15].join(' ')}>
|
||||
<div className={[_s.d, _s.px15, _s.py15, _s.overflowHidden].join(' ')}>
|
||||
<Form>
|
||||
<Switch
|
||||
label='Restrict messages from people you dont follow'
|
||||
|
|
|
@ -61,6 +61,7 @@ const mapStateToProps = (state, props) => {
|
|||
const statusId = props.id || props.params.statusId
|
||||
|
||||
return {
|
||||
statusId,
|
||||
status: state.getIn(['statuses', statusId]),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ import {
|
|||
ChatConversationCreate,
|
||||
ChatConversationRequests,
|
||||
ChatConversationBlockedAccounts,
|
||||
ChatConversationMutes,
|
||||
CommunityTimeline,
|
||||
Compose,
|
||||
Deck,
|
||||
|
@ -221,7 +222,7 @@ class SwitchingArea extends React.PureComponent {
|
|||
<WrappedRoute path='/messages/settings' exact page={MessagesPage} component={MessagesSettings} content={children} componentParams={{ isSettings: true }} />
|
||||
<WrappedRoute path='/messages/requests' exact page={MessagesPage} component={ChatConversationRequests} content={children} componentParams={{ isSettings: true, source: 'requested' }} />
|
||||
<WrappedRoute path='/messages/blocks' exact page={MessagesPage} component={ChatConversationBlockedAccounts} content={children} componentParams={{ isSettings: true }} />
|
||||
<WrappedRoute path='/messages/muted_conversations' exact page={MessagesPage} component={ChatConversationBlockedAccounts} content={children} componentParams={{ isSettings: true }} />
|
||||
<WrappedRoute path='/messages/muted_conversations' exact page={MessagesPage} component={ChatConversationMutes} content={children} componentParams={{ isSettings: true }} />
|
||||
<WrappedRoute path='/messages/:chatConversationId' exact page={MessagesPage} component={Messages} content={children} componentParams={{ source: 'approved' }} />
|
||||
|
||||
<WrappedRoute path='/timeline/all' exact page={CommunityPage} component={CommunityTimeline} content={children} componentParams={{ title: 'Community Feed' }} />
|
||||
|
|
|
@ -25,7 +25,9 @@ export function ChatConversationDeleteModal() { return import(/* webpackChunkNam
|
|||
export function ChatConversationOptionsPopover() { return import(/* webpackChunkName: "components/chat_conversation_options_popover" */'../../../components/popover/chat_conversation_options_popover') }
|
||||
export function ChatConversationRequests() { return import(/* webpackChunkName: "features/chat_conversation_requests" */'../../chat_conversation_requests') }
|
||||
export function ChatConversationExpirationOptionsPopover() { return import(/* webpackChunkName: "components/chat_conversation_expiration_options_popover" */'../../../components/popover/chat_conversation_expiration_options_popover') }
|
||||
export function ChatConversationMutes() { return import(/* webpackChunkName: "features/chat_conversation_mutes" */'../../chat_conversation_mutes') }
|
||||
export function ChatMessageOptionsPopover() { return import(/* webpackChunkName: "components/chat_message_options_popover" */'../../../components/popover/chat_message_options_popover') }
|
||||
export function ChatSettingsPopover() { return import(/* webpackChunkName: "components/chat_settings_popover" */'../../../components/popover/chat_settings_popover') }
|
||||
export function CommentSortingOptionsPopover() { return import(/* webpackChunkName: "components/comment_sorting_options_popover" */'../../../components/popover/comment_sorting_options_popover') }
|
||||
export function CommunityTimeline() { return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline') }
|
||||
export function Compose() { return import(/* webpackChunkName: "features/compose" */'../../compose') }
|
||||
|
|
|
@ -43,15 +43,6 @@ class WrappedRoute extends React.PureComponent {
|
|||
...rest
|
||||
} = this.props
|
||||
|
||||
// : todo :
|
||||
// api().get('/api/v1/accounts/verify_credentials')
|
||||
// .then((res) => {
|
||||
// console.log("res:", res)
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.log("err:", err)
|
||||
// })
|
||||
|
||||
if (!publicRoute && !me) {
|
||||
const actualUrl = encodeURIComponent(this.props.computedMatch.url)
|
||||
return <Route path={this.props.path} component={() => {
|
||||
|
|
|
@ -3,9 +3,11 @@ import PropTypes from 'prop-types'
|
|||
import { connect } from 'react-redux'
|
||||
import { me } from '../initial_state'
|
||||
import { openModal } from '../actions/modal'
|
||||
import { openPopover } from '../actions/popover'
|
||||
import {
|
||||
CX,
|
||||
BREAKPOINT_EXTRA_SMALL,
|
||||
POPOVER_CHAT_SETTINGS,
|
||||
MODAL_CHAT_CONVERSATION_CREATE,
|
||||
} from '../constants'
|
||||
import { getWindowDimension } from '../utils/is_mobile'
|
||||
|
@ -43,6 +45,10 @@ class MessagesLayout extends React.PureComponent {
|
|||
this.setState({ width })
|
||||
}
|
||||
|
||||
handleOpenSettingsOptionsPopover = () => {
|
||||
this.props.onOpenSettingsOptionsPopover()
|
||||
}
|
||||
|
||||
onClickAdd = () => {
|
||||
this.props.onOpenChatConversationCreateModal()
|
||||
}
|
||||
|
@ -74,12 +80,12 @@ class MessagesLayout extends React.PureComponent {
|
|||
},
|
||||
{
|
||||
icon: 'cog',
|
||||
to: '/messages/settings',
|
||||
onClick: this.handleOpenSettingsOptionsPopover,
|
||||
}
|
||||
]}
|
||||
title={title}
|
||||
/>
|
||||
<main role='main' className={[_s.d, _s.w100PC].join(' ')}>
|
||||
<main role='main' className={[_s.d, _s.w100PC, _s.flexGrow1, _s.bgPrimary, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC, _s.flexRow, _s.pb15].join(' ')}>
|
||||
{
|
||||
(isSettings || currentConversationIsRequest) &&
|
||||
|
@ -98,7 +104,7 @@ class MessagesLayout extends React.PureComponent {
|
|||
return (
|
||||
<div className={[_s.d, _s.w100PC, _s.minH100VH, _s.bgTertiary].join(' ')}>
|
||||
<ChatNavigationBar chatConversationId={selectedChatConversationId} />
|
||||
<main role='main' className={[_s.d, _s.w100PC].join(' ')}>
|
||||
<main role='main' className={[_s.d, _s.w100PC, _s.flexGrow1, _s.bgPrimary, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
|
||||
<ChatMessageScrollingList chatConversationId={selectedChatConversationId} isXS={isXS} />
|
||||
</main>
|
||||
{ currentConversationIsRequest && <ChatConversationRequestApproveBar /> }
|
||||
|
@ -106,7 +112,17 @@ class MessagesLayout extends React.PureComponent {
|
|||
</div>
|
||||
)
|
||||
} else {
|
||||
//settings
|
||||
return (
|
||||
<div className={[_s.d, _s.w100PC, _s.minH100VH, _s.bgTertiary].join(' ')}>
|
||||
<DefaultNavigationBar showBackBtn title={title} />
|
||||
<main role='main' className={[_s.d, _s.w100PC, _s.bgPrimary, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC, _s.flexRow, _s.pb15].join(' ')}>
|
||||
{children}
|
||||
</div>
|
||||
<FooterBar />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +190,10 @@ const mapStateToProps = (state) => {
|
|||
const mapDispatchToProps = (dispatch) => ({
|
||||
onOpenChatConversationCreateModal() {
|
||||
dispatch(openModal(MODAL_CHAT_CONVERSATION_CREATE))
|
||||
}
|
||||
},
|
||||
onOpenSettingsOptionsPopover() {
|
||||
dispatch(openPopover(POPOVER_CHAT_SETTINGS))
|
||||
},
|
||||
})
|
||||
|
||||
MessagesLayout.propTypes = {
|
||||
|
|
|
@ -19,6 +19,7 @@ class ModalPage extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<DefaultLayout
|
||||
noComposeButton
|
||||
title={title}
|
||||
page={page}
|
||||
showBackBtn
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import { SETTING_CHANGE, SETTING_SAVE } from '../actions/settings'
|
||||
import {
|
||||
CHAT_SETTING_CHANGE,
|
||||
CHAT_SETTING_SAVE,
|
||||
} from '../actions/chat_settings'
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'
|
||||
import uuid from '../utils/uuid'
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
saved: false,
|
||||
restrict_non_followers: true,
|
||||
show_active: false,
|
||||
read_receipts: false,
|
||||
sounds: true,
|
||||
})
|
||||
|
||||
export default function chat_settings(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case CHAT_SETTING_CHANGE:
|
||||
return state
|
||||
.setIn(action.path, action.value)
|
||||
.set('saved', false)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import chat_conversation_lists from './chat_conversation_lists'
|
|||
import chat_conversation_messages from './chat_conversation_messages'
|
||||
import chat_conversations from './chat_conversations'
|
||||
import chat_messages from './chat_messages'
|
||||
import chat_settings from './chat_settings'
|
||||
import compose from './compose'
|
||||
import contexts from './contexts'
|
||||
import custom_emojis from './custom_emojis'
|
||||
|
@ -60,6 +61,7 @@ const reducers = {
|
|||
chat_conversation_messages,
|
||||
chat_conversations,
|
||||
chat_messages,
|
||||
chat_settings,
|
||||
compose,
|
||||
contexts,
|
||||
custom_emojis,
|
||||
|
|
|
@ -14,7 +14,6 @@ const initialState = ImmutableList([])
|
|||
export default function toasts(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case TOAST_SHOW:
|
||||
console.log("action:", action)
|
||||
return state.set(state.size, ImmutableMap({
|
||||
key: state.size > 0 ? state.last().get('key') + 1 : 0,
|
||||
message: makeMessageFromData(action.toastData),
|
||||
|
|
|
@ -166,9 +166,6 @@ export const makeGetStatus = () => {
|
|||
quotedStatus = quotedStatus.set('account', accountQuoted);
|
||||
}
|
||||
|
||||
|
||||
// console.log("group:", group)
|
||||
|
||||
//Find ancestor status
|
||||
|
||||
const regex = (accountRepost || accountBase).get('id') !== me && regexFromFilters(filters);
|
||||
|
@ -247,14 +244,11 @@ export const getListOfGroups = createSelector([
|
|||
(state) => state.get('groups'),
|
||||
(state, { type }) => state.getIn(['group_lists', type, 'items']),
|
||||
], (groups, groupIds) => {
|
||||
console.log("groupIds:", groupIds)
|
||||
let list = ImmutableList()
|
||||
groupIds.forEach((id, i) => {
|
||||
const group = groups.get(`${id}`)
|
||||
console.log("groupIds:", id, i, group)
|
||||
list = list.set(i, group)
|
||||
})
|
||||
console.log("list:", list)
|
||||
|
||||
return list
|
||||
})
|
|
@ -1,5 +1,5 @@
|
|||
// https://gist.github.com/andjosh/6764939
|
||||
export const scrollTo = (element, to, duration) => {
|
||||
export const scrollTo = (element, to, duration = 0) => {
|
||||
var start = element.scrollTop,
|
||||
change = to - start,
|
||||
currentTime = 0,
|
||||
|
|
|
@ -314,6 +314,7 @@ pre {
|
|||
|
||||
.flex1 { flex: 1; }
|
||||
.flexGrow1 { flex-grow: 1; }
|
||||
.flexShrink0 { flex-shrink: 0; }
|
||||
.flexShrink1 { flex-shrink: 1; }
|
||||
|
||||
.flexRow { flex-direction: row; }
|
||||
|
@ -597,6 +598,8 @@ pre {
|
|||
.maxW100PC130PX { max-width: calc(100% - 130px); }
|
||||
.maxW100PC86PX { max-width: calc(100% - 86px); }
|
||||
.maxW100PC42PX { max-width: calc(100% - 42px); }
|
||||
.maxW100PC30PX { max-width: calc(100% - 30px); }
|
||||
.maxW320PX { max-width: 320px; }
|
||||
.maxW212PX { max-width: 212px; }
|
||||
|
||||
.minW330PX { min-width: 330px; }
|
||||
|
@ -1314,6 +1317,13 @@ pre {
|
|||
width: 100px !important;
|
||||
}
|
||||
|
||||
:global(.react-datepicker__day--disabled),
|
||||
:global(.react-datepicker__month-text--disabled),
|
||||
:global(.react-datepicker__quarter-text--disabled) {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.2 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
:global(.react-datepicker) {
|
||||
flex-direction: column !important;
|
||||
|
|
|
@ -38,6 +38,8 @@ class ChatConversationAccount < ApplicationRecord
|
|||
belongs_to :chat_conversation
|
||||
belongs_to :last_chat_message, class_name: 'ChatMessage', optional: true
|
||||
|
||||
validate :validate_total_limit
|
||||
|
||||
def participant_accounts
|
||||
if participant_account_ids.empty?
|
||||
[account]
|
||||
|
@ -47,4 +49,10 @@ class ChatConversationAccount < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_total_limit
|
||||
# errors.add(:base, I18n.t('scheduled_statuses.over_total_limit', limit: PER_ACCOUNT_APPROVED_LIMIT)) if account.scheduled_statuses.count >= PER_ACCOUNT_APPROVED_LIMIT
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -18,7 +18,6 @@ class HomeFeed < Feed
|
|||
private
|
||||
|
||||
def from_database(limit, max_id, since_id, min_id)
|
||||
puts "tilly from_database"
|
||||
Status.as_home_timeline(@account)
|
||||
.paginate_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
|
||||
.reject { |status| FeedManager.instance.filter?(:home, status, @account.id) }
|
||||
|
|
|
@ -9,10 +9,6 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
|||
attribute :favourited, if: :current_user?
|
||||
attribute :reblogged, if: :current_user?
|
||||
|
||||
attribute :account_id, if: :account_id?
|
||||
attribute :group_id, if: :group_id?
|
||||
attribute :preview_card_id, if: :preview_card_id?
|
||||
|
||||
attribute :content, unless: :source_requested?
|
||||
attribute :rich_content, unless: :source_requested?
|
||||
attribute :plain_markdown, unless: :source_requested?
|
||||
|
@ -20,15 +16,15 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
|||
|
||||
belongs_to :reblog, serializer: REST::StatusSerializer
|
||||
belongs_to :quote, serializer: REST::StatusSerializer
|
||||
belongs_to :account, serializer: REST::AccountSerializer, unless: :account_id?
|
||||
belongs_to :group, serializer: REST::GroupSerializer, unless: :group_id?
|
||||
belongs_to :account, serializer: REST::AccountSerializer
|
||||
belongs_to :group, serializer: REST::GroupSerializer
|
||||
|
||||
has_many :media_attachments, serializer: REST::MediaAttachmentSerializer
|
||||
has_many :ordered_mentions, key: :mentions
|
||||
has_many :tags
|
||||
has_many :emojis, serializer: REST::CustomEmojiSerializer
|
||||
|
||||
has_one :preview_card, key: :card, serializer: REST::PreviewCardSerializer, unless: :preview_card_id?
|
||||
has_one :preview_card, key: :card, serializer: REST::PreviewCardSerializer
|
||||
has_one :preloadable_poll, key: :poll, serializer: REST::PollSerializer
|
||||
|
||||
def id
|
||||
|
@ -51,30 +47,6 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
|||
!current_user.nil?
|
||||
end
|
||||
|
||||
def account_id
|
||||
instance_options[:account_id]
|
||||
end
|
||||
|
||||
def account_id?
|
||||
!instance_options[:account_id].nil?
|
||||
end
|
||||
|
||||
def group_id
|
||||
instance_options[:group_id]
|
||||
end
|
||||
|
||||
def group_id?
|
||||
!instance_options[:group_id].nil?
|
||||
end
|
||||
|
||||
def preview_card_id
|
||||
instance_options[:preview_card_id]
|
||||
end
|
||||
|
||||
def preview_card_id?
|
||||
!instance_options[:preview_card_id].nil?
|
||||
end
|
||||
|
||||
def visibility
|
||||
# This visibility is masked behind "private"
|
||||
# to avoid API changes because there are no
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
%tr
|
||||
%td
|
||||
= admin_account_link_to(account)
|
||||
- if account.is_flagged_as_spam
|
||||
%span SPAM
|
||||
%td
|
||||
- if account.user_current_sign_in_ip
|
||||
%samp.ellipsized-ip{ title: account.user_current_sign_in_ip }= account.user_current_sign_in_ip
|
||||
|
|
|
@ -28,6 +28,7 @@ SimpleNavigation::Configuration.run do |navigation|
|
|||
n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_url, if: -> { current_user.staff? }
|
||||
|
||||
n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), admin_reports_url, if: proc { current_user.staff? } do |s|
|
||||
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts|/admin/pending_accounts}
|
||||
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_url
|
||||
s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports}
|
||||
s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? }
|
||||
|
|
|
@ -382,6 +382,7 @@ Rails.application.routes.draw do
|
|||
|
||||
namespace :web do
|
||||
resource :settings, only: [:update]
|
||||
resource :chat_settings, only: [:update]
|
||||
resource :embed, only: [:create]
|
||||
resources :push_subscriptions, only: [:create] do
|
||||
member do
|
||||
|
|
Loading…
Reference in New Issue