Progress
This commit is contained in:
parent
d1ff39bb81
commit
8f94ffad9c
|
@ -1,60 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::ChatConversationAccounts::MutedChatAccountsController < Api::BaseController
|
||||
before_action -> { doorkeeper_authorize! :follow, :'read:mutes' }
|
||||
before_action :require_user!
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
def show
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_accounts
|
||||
paginated_mutes.map(&:target_account)
|
||||
end
|
||||
|
||||
def paginated_mutes
|
||||
@paginated_mutes ||= ChatMute.eager_load(target_account: :account_stat)
|
||||
.where(account: current_account)
|
||||
.paginate_by_max_id(
|
||||
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||
params[:max_id],
|
||||
params[:since_id]
|
||||
)
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
||||
def next_path
|
||||
if records_continue?
|
||||
api_v1_chat_conversation_accounts_muted_chat_accounts_url pagination_params(max_id: pagination_max_id)
|
||||
end
|
||||
end
|
||||
|
||||
def prev_path
|
||||
unless paginated_mutes.empty?
|
||||
api_v1_chat_conversation_accounts_muted_chat_accounts_url pagination_params(since_id: pagination_since_id)
|
||||
end
|
||||
end
|
||||
|
||||
def pagination_max_id
|
||||
paginated_mutes.last.id
|
||||
end
|
||||
|
||||
def pagination_since_id
|
||||
paginated_mutes.first.id
|
||||
end
|
||||
|
||||
def records_continue?
|
||||
paginated_mutes.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:limit).permit(:limit).merge(core_params)
|
||||
end
|
||||
end
|
|
@ -7,37 +7,31 @@ class Api::V1::ChatConversationAccountsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
before_action :set_account
|
||||
|
||||
def is_messenger_blocked
|
||||
#
|
||||
end
|
||||
|
||||
def is_messenger_muted
|
||||
#
|
||||
end
|
||||
|
||||
def block_messenger
|
||||
BlockMessengerService.new.call(current_user.account, @account)
|
||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||
end
|
||||
|
||||
def mute_messenger
|
||||
MuteMessengerService.new.call(current_user.account, @account)
|
||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||
end
|
||||
|
||||
def unblock_messenger
|
||||
UnblockMessengerService.new.call(current_user.account, @account)
|
||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||
end
|
||||
|
||||
def unmute_messenger
|
||||
UnmuteMessegerService.new.call(current_user.account, @account)
|
||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||
def mute_chat_conversation
|
||||
@chat_conversation_account.is_muted = true
|
||||
@chat_conversation_account.save!
|
||||
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
|
||||
end
|
||||
|
||||
def unmute_chat_conversation
|
||||
@chat_conversation_account.is_muted = false
|
||||
@chat_conversation_account.save!
|
||||
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
|
||||
end
|
||||
|
||||
def set_expiration_policy
|
||||
if current_user.account.is_pro
|
||||
#
|
||||
# : todo :
|
||||
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
|
||||
else
|
||||
render json: { error: 'You need to be a GabPRO member to access this' }, status: 422
|
||||
|
@ -50,6 +44,14 @@ class Api::V1::ChatConversationAccountsController < Api::BaseController
|
|||
@account = Account.find(params[:id])
|
||||
end
|
||||
|
||||
def set_chat_conversation
|
||||
@chat_conversation = ChatConversation.find(params[:id])
|
||||
@chat_conversation_account = ChatConversationAccount.where(
|
||||
account: current_account,
|
||||
chat_conversation: @chat_conversation
|
||||
).first
|
||||
end
|
||||
|
||||
def check_account_suspension
|
||||
gone if @account.suspended?
|
||||
end
|
||||
|
|
|
@ -7,6 +7,8 @@ class Api::Web::SettingsController < Api::Web::BaseController
|
|||
setting.data = params[:data]
|
||||
setting.save!
|
||||
|
||||
# todo validate all data objects
|
||||
|
||||
render_empty_success
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||
before_action :set_cache_headers, only: [:edit, :update]
|
||||
|
||||
def new
|
||||
super(&:build_invite_request)
|
||||
super
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
|
@ -24,79 +24,92 @@ export const BOOKMARK_COLLECTIONS_REMOVE_REQUEST = 'BOOKMARK_COLLECTIONS_REMOVE_
|
|||
export const BOOKMARK_COLLECTIONS_REMOVE_SUCCESS = 'BOOKMARK_COLLECTIONS_REMOVE_SUCCESS'
|
||||
export const BOOKMARK_COLLECTIONS_REMOVE_FAIL = 'BOOKMARK_COLLECTIONS_REMOVE_FAIL'
|
||||
|
||||
//
|
||||
|
||||
export const UPDATE_BOOKMARK_COLLECTION_FAIL = 'UPDATE_BOOKMARK_COLLECTION_FAIL'
|
||||
export const UPDATE_BOOKMARK_COLLECTION_REQUEST = 'UPDATE_BOOKMARK_COLLECTION_REQUEST'
|
||||
export const UPDATE_BOOKMARK_COLLECTION_SUCCESS = 'UPDATE_BOOKMARK_COLLECTION_SUCCESS'
|
||||
|
||||
export const UPDATE_BOOKMARK_COLLECTION_STATUS_FAIL = 'UPDATE_BOOKMARK_COLLECTION_STATUS_FAIL'
|
||||
export const UPDATE_BOOKMARK_COLLECTION_STATUS_REQUEST = 'UPDATE_BOOKMARK_COLLECTION_STATUS_REQUEST'
|
||||
export const UPDATE_BOOKMARK_COLLECTION_STATUS_SUCCESS = 'UPDATE_BOOKMARK_COLLECTION_STATUS_SUCCESS'
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const fetchBookmarkedStatuses = () => (dispatch, getState) => {
|
||||
export const fetchBookmarkedStatuses = (bookmarkCollectionId) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
if (getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) {
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(fetchBookmarkedStatusesRequest())
|
||||
dispatch(fetchBookmarkedStatusesRequest(bookmarkCollectionId))
|
||||
|
||||
api(getState).get('/api/v1/bookmarks').then((response) => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedStatuses(response.data))
|
||||
dispatch(fetchBookmarkedStatusesSuccess(response.data, next ? next.uri : null))
|
||||
dispatch(fetchBookmarkedStatusesSuccess(response.data, bookmarkCollectionId, next ? next.uri : null))
|
||||
}).catch((error) => {
|
||||
dispatch(fetchBookmarkedStatusesFail(error))
|
||||
dispatch(fetchBookmarkedStatusesFail(bookmarkCollectionId, error))
|
||||
})
|
||||
}
|
||||
|
||||
const fetchBookmarkedStatusesRequest = () => ({
|
||||
const fetchBookmarkedStatusesRequest = (bookmarkCollectionId) => ({
|
||||
type: BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||
})
|
||||
|
||||
const fetchBookmarkedStatusesSuccess = (statuses, next) => ({
|
||||
const fetchBookmarkedStatusesSuccess = (statuses, bookmarkCollectionId, next) => ({
|
||||
type: BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
||||
bookmarkCollectionId,
|
||||
statuses,
|
||||
next,
|
||||
})
|
||||
|
||||
const fetchBookmarkedStatusesFail = (error) => ({
|
||||
const fetchBookmarkedStatusesFail = (bookmarkCollectionId, error) => ({
|
||||
type: BOOKMARKED_STATUSES_FETCH_FAIL,
|
||||
showToast: true,
|
||||
bookmarkCollectionId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandBookmarkedStatuses = () => (dispatch, getState) => {
|
||||
export const expandBookmarkedStatuses = (bookmarkCollectionId) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
const url = getState().getIn(['status_lists', 'bookmarks', 'next'], null)
|
||||
const url = getState().getIn(['status_lists', 'bookmarks', bookmarkCollectionId, 'next'], null)
|
||||
|
||||
if (url === null || getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) {
|
||||
if (url === null || getState().getIn(['status_lists', 'bookmarks', bookmarkCollectionId, 'isLoading'])) {
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(expandBookmarkedStatusesRequest())
|
||||
dispatch(expandBookmarkedStatusesRequest(bookmarkCollectionId))
|
||||
|
||||
api(getState).get(url).then((response) => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedStatuses(response.data))
|
||||
dispatch(expandBookmarkedStatusesSuccess(response.data, next ? next.uri : null))
|
||||
dispatch(expandBookmarkedStatusesSuccess(response.data, bookmarkCollectionId, next ? next.uri : null))
|
||||
}).catch((error) => {
|
||||
dispatch(expandBookmarkedStatusesFail(error))
|
||||
dispatch(expandBookmarkedStatusesFail(bookmarkCollectionId, error))
|
||||
})
|
||||
}
|
||||
|
||||
const expandBookmarkedStatusesRequest = () => ({
|
||||
const expandBookmarkedStatusesRequest = (bookmarkCollectionId) => ({
|
||||
type: BOOKMARKED_STATUSES_EXPAND_REQUEST,
|
||||
})
|
||||
|
||||
const expandBookmarkedStatusesSuccess = (statuses, next) => ({
|
||||
const expandBookmarkedStatusesSuccess = (statuses, bookmarkCollectionId, next) => ({
|
||||
type: BOOKMARKED_STATUSES_EXPAND_SUCCESS,
|
||||
statuses,
|
||||
next,
|
||||
})
|
||||
|
||||
const expandBookmarkedStatusesFail = (error) => ({
|
||||
const expandBookmarkedStatusesFail = (bookmarkCollectionId, error) => ({
|
||||
type: BOOKMARKED_STATUSES_EXPAND_FAIL,
|
||||
showToast: true,
|
||||
bookmarkCollectionId,
|
||||
error,
|
||||
})
|
||||
|
||||
|
@ -191,3 +204,63 @@ const removeBookmarkCollectionFail = (error) => ({
|
|||
showToast: true,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const updateBookmarkCollection = (bookmarkCollectionId, title) => (dispatch, getState) => {
|
||||
if (!me || !statusId) return
|
||||
|
||||
dispatch(updateBookmarkCollectionRequest())
|
||||
|
||||
api(getState).post('/api/v1/bookmark_collections', { title }).then((response) => {
|
||||
dispatch(updateBookmarkCollectionSuccess(response.data))
|
||||
}).catch((error) => {
|
||||
dispatch(updateBookmarkCollectionFail(error))
|
||||
})
|
||||
}
|
||||
|
||||
const updateBookmarkCollectionRequest = () => ({
|
||||
type: UPDATE_BOOKMARK_COLLECTION_REQUEST,
|
||||
})
|
||||
|
||||
const updateBookmarkCollectionSuccess = (bookmarkCollection) => ({
|
||||
type: UPDATE_BOOKMARK_COLLECTION_SUCCESS,
|
||||
bookmarkCollection,
|
||||
})
|
||||
|
||||
const updateBookmarkCollectionFail = (error) => ({
|
||||
type: UPDATE_BOOKMARK_COLLECTION_FAIL,
|
||||
showToast: true,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const updateBookmarkCollectionStatus = (statusId, bookmarkCollectionId) => (dispatch, getState) => {
|
||||
if (!me || !statusId) return
|
||||
|
||||
dispatch(updateBookmarkCollectionStatusRequest())
|
||||
|
||||
api(getState).post('/api/v1/bookmark_collections', { title }).then((response) => {
|
||||
dispatch(updateBookmarkCollectionStatusSuccess(response.data))
|
||||
}).catch((error) => {
|
||||
dispatch(updateBookmarkCollectionStatusFail(error))
|
||||
})
|
||||
}
|
||||
|
||||
const updateBookmarkCollectionStatusRequest = () => ({
|
||||
type: UPDATE_BOOKMARK_COLLECTION_STATUS_REQUEST,
|
||||
})
|
||||
|
||||
const updateBookmarkCollectionStatusSuccess = (bookmarkCollection) => ({
|
||||
type: UPDATE_BOOKMARK_COLLECTION_STATUS_SUCCESS,
|
||||
bookmarkCollection,
|
||||
})
|
||||
|
||||
const updateBookmarkCollectionStatusFail = (error) => ({
|
||||
type: UPDATE_BOOKMARK_COLLECTION_STATUS_FAIL,
|
||||
showToast: true,
|
||||
error,
|
||||
})
|
||||
|
|
|
@ -24,23 +24,13 @@ export const IS_CHAT_MESSENGER_BLOCKED_SUCCESS = 'IS_CHAT_MESSENGER_BLOCKED_SUCC
|
|||
|
||||
//
|
||||
|
||||
export const CHAT_MESSENGER_MUTES_FETCH_REQUEST = 'CHAT_MESSENGER_MUTES_FETCH_REQUEST'
|
||||
export const CHAT_MESSENGER_MUTES_FETCH_SUCCESS = 'CHAT_MESSENGER_MUTES_FETCH_SUCCESS'
|
||||
export const CHAT_MESSENGER_MUTES_FETCH_FAIL = 'CHAT_MESSENGER_MUTES_FETCH_FAIL'
|
||||
export const MUTE_CHAT_CONVERSATION_REQUEST = 'MUTE_CHAT_CONVERSATION_REQUEST'
|
||||
export const MUTE_CHAT_CONVERSATION_SUCCESS = 'MUTE_CHAT_CONVERSATION_SUCCESS'
|
||||
export const MUTE_CHAT_CONVERSATION_FAIL = 'MUTE_CHAT_CONVERSATION_FAIL'
|
||||
|
||||
export const CHAT_MESSENGER_MUTES_EXPAND_REQUEST = 'CHAT_MESSENGER_MUTES_EXPAND_REQUEST'
|
||||
export const CHAT_MESSENGER_MUTES_EXPAND_SUCCESS = 'CHAT_MESSENGER_MUTES_EXPAND_SUCCESS'
|
||||
export const CHAT_MESSENGER_MUTES_EXPAND_FAIL = 'CHAT_MESSENGER_MUTES_EXPAND_FAIL'
|
||||
|
||||
export const MUTE_CHAT_MESSAGER_REQUEST = 'MUTE_CHAT_MESSAGER_REQUEST'
|
||||
export const MUTE_CHAT_MESSAGER_SUCCESS = 'MUTE_CHAT_MESSAGER_SUCCESS'
|
||||
export const MUTE_CHAT_MESSAGER_FAIL = 'MUTE_CHAT_MESSAGER_FAIL'
|
||||
|
||||
export const UNMUTE_CHAT_MESSAGER_REQUEST = 'UNMUTE_CHAT_MESSAGER_REQUEST'
|
||||
export const UNMUTE_CHAT_MESSAGER_SUCCESS = 'UNMUTE_CHAT_MESSAGER_SUCCESS'
|
||||
export const UNMUTE_CHAT_MESSAGER_FAIL = 'UNMUTE_CHAT_MESSAGER_FAIL'
|
||||
|
||||
export const IS_CHAT_MESSENGER_MUTED_SUCCESS = 'IS_CHAT_MESSENGER_MUTED_SUCCESS'
|
||||
export const UNMUTE_CHAT_CONVERSATION_REQUEST = 'UNMUTE_CHAT_CONVERSATION_REQUEST'
|
||||
export const UNMUTE_CHAT_CONVERSATION_SUCCESS = 'UNMUTE_CHAT_CONVERSATION_SUCCESS'
|
||||
export const UNMUTE_CHAT_CONVERSATION_FAIL = 'UNMUTE_CHAT_CONVERSATION_FAIL'
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -96,12 +86,12 @@ const unblockChatMessengerRequest = (accountId) => ({
|
|||
})
|
||||
|
||||
const unblockChatMessengerSuccess = () => ({
|
||||
type: UNBLOCK_CHAT_MESSAGER_REQUEST,
|
||||
type: UNBLOCK_CHAT_MESSAGER_SUCCESS,
|
||||
showToast: true,
|
||||
})
|
||||
|
||||
const unblockChatMessengerFail = (accountId, error) => ({
|
||||
type: UNBLOCK_CHAT_MESSAGER_REQUEST,
|
||||
type: UNBLOCK_CHAT_MESSAGER_FAIL,
|
||||
showToast: true,
|
||||
accountId,
|
||||
error,
|
||||
|
@ -195,147 +185,64 @@ export const expandChatMessengerBlocksFail = (error) => ({
|
|||
/**
|
||||
*
|
||||
*/
|
||||
export const muteChatMessenger = (accountId) => (dispatch, getState) => {
|
||||
if (!me || !accountId) return
|
||||
export const muteChatConversation = (chatConversationId) => (dispatch, getState) => {
|
||||
if (!me || !chatConversationId) return
|
||||
|
||||
dispatch(muteChatMessengerRequest(accountId))
|
||||
dispatch(muteChatConversationRequest(chatConversationId))
|
||||
|
||||
api(getState).post(`/api/v1/chat_conversation_accounts/${accountId}/mute_messenger`).then((response) => {
|
||||
dispatch(muteChatMessengerSuccess())
|
||||
api(getState).post(`/api/v1/chat_conversation_accounts/${chatConversationId}/mute_chat_conversation`).then((response) => {
|
||||
dispatch(muteChatConversationSuccess(response.data))
|
||||
}).catch((error) => {
|
||||
dispatch(muteChatMessengerFail(accountId, error))
|
||||
dispatch(muteChatMessengerFail(error))
|
||||
})
|
||||
}
|
||||
|
||||
const muteChatMessengerRequest = (accountId) => ({
|
||||
type: MUTE_CHAT_MESSAGER_REQUEST,
|
||||
const muteChatConversationRequest = (accountId) => ({
|
||||
type: MUTE_CHAT_CONVERSATION_REQUEST,
|
||||
accountId,
|
||||
})
|
||||
|
||||
const muteChatMessengerSuccess = () => ({
|
||||
type: MUTE_CHAT_MESSAGER_SUCCESS,
|
||||
const muteChatConversationSuccess = (chatConversation) => ({
|
||||
type: MUTE_CHAT_CONVERSATION_SUCCESS,
|
||||
chatConversation,
|
||||
showToast: true,
|
||||
})
|
||||
|
||||
const muteChatMessengerFail = (accountId, error) => ({
|
||||
type: MUTE_CHAT_MESSAGER_FAIL,
|
||||
const muteChatConversationFail = (error) => ({
|
||||
type: MUTE_CHAT_CONVERSATION_FAIL,
|
||||
showToast: true,
|
||||
accountId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const unmuteChatMessenger = (accountId) => (dispatch, getState) => {
|
||||
if (!me || !accountId) return
|
||||
export const unmuteChatConversation = (chatConversationId) => (dispatch, getState) => {
|
||||
if (!me || !chatConversationId) return
|
||||
|
||||
dispatch(unmuteChatMessengerRequest(accountId))
|
||||
dispatch(unmuteChatConversationRequest(chatConversationId))
|
||||
|
||||
api(getState).post(`/api/v1/chat_conversation_accounts/${accountId}/unmute_messenger`).then((response) => {
|
||||
dispatch(unmuteChatMessengerSuccess())
|
||||
api(getState).post(`/api/v1/chat_conversation_accounts/${chatConversationId}/unmute_chat_conversation`).then((response) => {
|
||||
dispatch(unmuteChatConversationSuccess(response.data))
|
||||
}).catch((error) => {
|
||||
dispatch(unmuteChatMessengerFail(accountId, error))
|
||||
dispatch(unmuteChatConversationFail(error))
|
||||
})
|
||||
}
|
||||
|
||||
const unmuteChatMessengerRequest = (accountId) => ({
|
||||
type: UNMUTE_CHAT_MESSAGER_REQUEST,
|
||||
const unmuteChatConversationRequest = (accountId) => ({
|
||||
type: UNMUTE_CHAT_CONVERSATION_REQUEST,
|
||||
accountId,
|
||||
})
|
||||
|
||||
const unmuteChatMessengerSuccess = () => ({
|
||||
type: UNMUTE_CHAT_MESSAGER_REQUEST,
|
||||
const unmuteChatConversationSuccess = (chatConversation) => ({
|
||||
type: UNMUTE_CHAT_CONVERSATION_SUCCESS,
|
||||
chatConversation,
|
||||
showToast: true,
|
||||
})
|
||||
|
||||
const unmuteChatMessengerFail = (accountId, error) => ({
|
||||
type: UNMUTE_CHAT_MESSAGER_REQUEST,
|
||||
const unmuteChatConversationFail = (accountId, error) => ({
|
||||
type: UNMUTE_CHAT_CONVERSATION_FAIL,
|
||||
showToast: true,
|
||||
accountId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
* @description Check if a chat messenger is muted by the current user account.
|
||||
* @param {String} accountId
|
||||
*/
|
||||
export const isChatMessengerMuted = (accountId) => (dispatch, getState) => {
|
||||
if (!me || !accountId) return
|
||||
|
||||
api(getState).post(`/api/v1/chat_conversation_accounts/${accountId}/is_messenger_muted`).then((response) => {
|
||||
dispatch(isChatMessengerMutedSuccess(response.data))
|
||||
})
|
||||
}
|
||||
|
||||
const isChatMessengerMutedSuccess = (data) => ({
|
||||
type: IS_CHAT_MESSENGER_MUTED_SUCCESS,
|
||||
data,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const fetchChatMessengerMutes = () => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
dispatch(fetchChatMessengerMutesRequest())
|
||||
|
||||
api(getState).get('/api/v1/chat_conversation_accounts/muted_chat_accounts').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(fetchChatMessengerMutesSuccess(response.data, next ? next.uri : null))
|
||||
}).catch(error => dispatch(fetchChatMessengerMutesFail(error)))
|
||||
}
|
||||
|
||||
export const fetchChatMessengerMutesRequest = () => ({
|
||||
type: CHAT_MESSENGER_MUTES_FETCH_REQUEST,
|
||||
})
|
||||
|
||||
export const fetchChatMessengerMutesSuccess = (accounts, next) => ({
|
||||
type: CHAT_MESSENGER_MUTES_FETCH_SUCCESS,
|
||||
accounts,
|
||||
next,
|
||||
})
|
||||
|
||||
export const fetchChatMessengerMutesFail = (error) => ({
|
||||
type: CHAT_MESSENGER_MUTES_FETCH_FAIL,
|
||||
showToast: true,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandChatMessengerMutes = () => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
const url = getState().getIn(['user_lists', 'chat_mutes', me, 'next'])
|
||||
const isLoading = getState().getIn(['user_lists', 'chat_mutes', me, 'isLoading'])
|
||||
|
||||
if (url === null || isLoading) return
|
||||
|
||||
dispatch(expandChatMessengerMutesRequest())
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(expandChatMessengerMutesSuccess(response.data, next ? next.uri : null))
|
||||
}).catch(error => dispatch(expandChatMessengerMutesFail(error)))
|
||||
}
|
||||
|
||||
export const expandChatMessengerMutesRequest = () => ({
|
||||
type: CHAT_MESSENGER_MUTES_EXPAND_REQUEST,
|
||||
})
|
||||
|
||||
export const expandChatMessengerMutesSuccess = (accounts, next) => ({
|
||||
type: CHAT_MESSENGER_MUTES_EXPAND_SUCCESS,
|
||||
accounts,
|
||||
next,
|
||||
})
|
||||
|
||||
export const expandChatMessengerMutesFail = (error) => ({
|
||||
type: CHAT_MESSENGER_MUTES_EXPAND_FAIL,
|
||||
error,
|
||||
})
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ export const SET_CHAT_CONVERSATION_SELECTED = 'SET_CHAT_CONVERSATION_SELECTED'
|
|||
*
|
||||
*/
|
||||
export const fetchChatConversationAccountSuggestions = (query) => throttle((dispatch, getState) => {
|
||||
if (!query) return
|
||||
|
||||
api(getState).get('/api/v1/accounts/search', {
|
||||
params: {
|
||||
q: query,
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { CX } from '../constants'
|
||||
import Button from './button'
|
||||
import Icon from './icon'
|
||||
import Image from './image'
|
||||
import Text from './text'
|
||||
|
||||
class Album extends React.PureComponent {
|
||||
|
||||
handleOnClick = (e) => {
|
||||
//
|
||||
}
|
||||
|
||||
render() {
|
||||
const { album } = this.props
|
||||
|
||||
return (
|
||||
<Button
|
||||
to={to}
|
||||
href={href}
|
||||
onClick={this.handleOnClick}
|
||||
noClasses
|
||||
>
|
||||
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Album.propTypes = {
|
||||
album: ImmutablePropTypes.map,
|
||||
isAddable: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default Album
|
|
@ -0,0 +1,29 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ModalLayout from './modal_layout'
|
||||
import BookmarkCollectionCreate from '../../features/bookmark_collection_create'
|
||||
|
||||
class BookmarkCollectionCreateModal extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const { onClose } = this.props
|
||||
|
||||
return (
|
||||
<ModalLayout
|
||||
title='Create Bookmark Collection'
|
||||
width={500}
|
||||
onClose={onClose}
|
||||
>
|
||||
<BookmarkCollectionCreate isModal />
|
||||
</ModalLayout>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BookmarkCollectionCreateModal.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default BookmarkCollectionCreateModal
|
|
@ -1,88 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { changeSetting, saveSettings } from '../../actions/settings'
|
||||
import ModalLayout from './modal_layout'
|
||||
import Button from '../button'
|
||||
import SettingSwitch from '../setting_switch'
|
||||
import Text from '../text'
|
||||
|
||||
class CommunityTimelineSettingsModal extends ImmutablePureComponent {
|
||||
|
||||
handleSaveAndClose = () => {
|
||||
this.props.onSave()
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
intl,
|
||||
settings,
|
||||
onChange,
|
||||
onClose,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<ModalLayout
|
||||
onClose={onClose}
|
||||
width={320}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
>
|
||||
|
||||
<div className={[_s.d, _s.pb10].join(' ')}>
|
||||
<SettingSwitch
|
||||
prefix='community_timeline'
|
||||
settings={settings}
|
||||
settingPath={['shows', 'onlyMedia']}
|
||||
onChange={onChange}
|
||||
label={intl.formatMessage(messages.onlyMedia)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
backgroundColor='brand'
|
||||
color='white'
|
||||
className={_s.jcCenter}
|
||||
onClick={this.handleSaveAndClose}
|
||||
>
|
||||
<Text color='inherit' weight='bold' align='center'>
|
||||
{intl.formatMessage(messages.saveAndClose)}
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
</ModalLayout>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'community_timeline_settings', defaultMessage: 'Community Feed Settings' },
|
||||
saveAndClose: { id: 'saveClose', defaultMessage: 'Save & Close' },
|
||||
onlyMedia: { id: 'community.column_settings.media_only', defaultMessage: 'Media Only' },
|
||||
})
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
settings: state.getIn(['settings', 'community']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, { onClose }) => ({
|
||||
onChange(key, checked) {
|
||||
dispatch(changeSetting(['community', ...key], checked))
|
||||
},
|
||||
onSave() {
|
||||
dispatch(saveSettings())
|
||||
onClose()
|
||||
},
|
||||
})
|
||||
|
||||
CommunityTimelineSettingsModal.propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onSave: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(CommunityTimelineSettingsModal))
|
|
@ -1,36 +1,138 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { connect } from 'react-redux'
|
||||
import { openModal } from '../../actions/modal'
|
||||
import { setDeckColumnAtIndex } from '../../actions/deck'
|
||||
import { getOrderedLists, getListOfGroups } from '../../selectors'
|
||||
import { fetchLists } from '../../actions/lists'
|
||||
import { fetchGroupsByTab } from '../../actions/groups'
|
||||
import { MODAL_DECK_COLUMN_ADD } from '../../constants'
|
||||
import Heading from '../heading'
|
||||
import Button from '../button'
|
||||
import Block from '../block'
|
||||
import Input from '../input'
|
||||
import List from '../list'
|
||||
|
||||
class DeckColumnAddOptionsModal extends React.PureComponent {
|
||||
class DeckColumnAddOptionsModal extends ImmutablePureComponent {
|
||||
|
||||
state = {
|
||||
selectedItem: null,
|
||||
hashtagValue: '',
|
||||
usernameValue: '',
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
switch (this.props.column) {
|
||||
case 'list':
|
||||
this.props.onFetchLists()
|
||||
break
|
||||
case 'group':
|
||||
this.props.onFetchMemberGroups()
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
onClickClose = () => {
|
||||
this.props.onClose()
|
||||
this.props.dispatch(openModal(MODAL_DECK_COLUMN_ADD))
|
||||
this.props.onOpenDeckColumnAddModal()
|
||||
}
|
||||
|
||||
handleAdd = () => {
|
||||
//
|
||||
handleAdd = (id) => {
|
||||
this.props.onSetDeckColumn(id)
|
||||
this.props.onClose()
|
||||
}
|
||||
|
||||
handleAddHashtag = () => {
|
||||
this.handleAdd(`hashtag.${this.state.hashtagValue}`)
|
||||
this.setState({ hashtagValue: '' })
|
||||
}
|
||||
|
||||
onChangeHashtagValue = (hashtagValue) => {
|
||||
this.setState({ hashtagValue })
|
||||
}
|
||||
|
||||
onChangeUsernameValue = (usernameValue) => {
|
||||
this.setState({ usernameValue })
|
||||
}
|
||||
|
||||
getContentForColumn = () => {
|
||||
const { column, lists, groups, accounts } = this.props
|
||||
const { hashtagValue } = this.state
|
||||
|
||||
if (column === 'hashtag') {
|
||||
return (
|
||||
<div className={[_s.d, _s.px15, _s.py10].join(' ')}>
|
||||
<Input
|
||||
type='text'
|
||||
value={hashtagValue}
|
||||
placeholder='gabfam'
|
||||
id='hashtag-deck'
|
||||
title='Enter hashtag'
|
||||
onChange={this.onChangeHashtagValue}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
} else if (column === 'list') {
|
||||
const listItems = lists.map((list) => ({
|
||||
onClick: () => this.handleAdd(`list.${list.get('id')}`),
|
||||
title: list.get('title'),
|
||||
}))
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.maxH340PX, _s.overflowYScroll].join(' ')}>
|
||||
<List
|
||||
scrollKey='lists-deck-add'
|
||||
showLoading={lists.size === 0}
|
||||
emptyMessage="You don't have any lists yet."
|
||||
items={listItems}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
} else if (column === 'group') {
|
||||
const listItems = groups.map((group) => ({
|
||||
onClick: () => this.handleAdd(`group.${group.get('id')}`),
|
||||
title: group.get('title'),
|
||||
}))
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.maxH340PX, _s.overflowYScroll].join(' ')}>
|
||||
<List
|
||||
scrollKey='groups-deck-add'
|
||||
showLoading={groups.size === 0}
|
||||
emptyMessage="You are not a member of any groups yet."
|
||||
items={listItems}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
} else if (column === 'group') {
|
||||
return (
|
||||
<div className={[_s.d, _s.px15, _s.py10].join(' ')}>
|
||||
<Input
|
||||
type='text'
|
||||
value={usernameValue}
|
||||
placeholder=''
|
||||
id='user-deck'
|
||||
title='Enter username'
|
||||
onChange={this.onChangeUsernameValue}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
const { column } = this.props
|
||||
const { selectedItem } = this.state
|
||||
|
||||
// user, hashtag, list, groups
|
||||
const { hashtagValue } = this.state
|
||||
|
||||
if (!column) return <div />
|
||||
const title = `Select a ${column}`
|
||||
|
||||
const content = this.getContentForColumn()
|
||||
|
||||
return (
|
||||
<div style={{width: '520px'}} className={[_s.d, _s.modal].join(' ')}>
|
||||
<Block>
|
||||
|
@ -49,16 +151,19 @@ class DeckColumnAddOptionsModal extends React.PureComponent {
|
|||
{title}
|
||||
</Heading>
|
||||
<div className={[_s.d, _s.w115PX, _s.aiEnd, _s.jcCenter, _s.mlAuto].join(' ')}>
|
||||
<Button
|
||||
isDisabled={!selectedItem}
|
||||
onClick={this.handleAdd}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
{
|
||||
column === 'hashtag' &&
|
||||
<Button
|
||||
isDisabled={!hashtagValue}
|
||||
onClick={this.handleAddHashtag}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className={[_s.d].join(' ')}>
|
||||
test
|
||||
{content}
|
||||
</div>
|
||||
</Block>
|
||||
</div>
|
||||
|
@ -67,9 +172,33 @@ class DeckColumnAddOptionsModal extends React.PureComponent {
|
|||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
lists: getOrderedLists(state),
|
||||
groups: getListOfGroups(state, { type: 'member' }),
|
||||
accounts: [],
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onFetchLists() {
|
||||
dispatch(fetchLists())
|
||||
},
|
||||
onFetchMemberGroups() {
|
||||
dispatch(fetchGroupsByTab('member'))
|
||||
},
|
||||
onSetDeckColumn(id) {
|
||||
dispatch(setDeckColumnAtIndex(id))
|
||||
},
|
||||
onOpenDeckColumnAddModal() {
|
||||
dispatch(openModal(MODAL_DECK_COLUMN_ADD))
|
||||
},
|
||||
})
|
||||
|
||||
DeckColumnAddOptionsModal.propTypes = {
|
||||
groupIds: ImmutablePropTypes.list,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onFetchLists: PropTypes.func.isRequired,
|
||||
onSetDeckColumn: PropTypes.func.isRequired,
|
||||
column: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export default connect()(DeckColumnAddOptionsModal)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DeckColumnAddOptionsModal)
|
|
@ -1,88 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { changeSetting, saveSettings } from '../../actions/settings'
|
||||
import ModalLayout from './modal_layout'
|
||||
import Button from '../button'
|
||||
import SettingSwitch from '../setting_switch'
|
||||
import Text from '../text'
|
||||
|
||||
class HashtagTimelineSettingsModal extends ImmutablePureComponent {
|
||||
|
||||
handleSaveAndClose = () => {
|
||||
this.props.onSave()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, settings, onChange, onClose } = this.props
|
||||
|
||||
// : todo :
|
||||
|
||||
return (
|
||||
<ModalLayout
|
||||
width={320}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onClose={onClose}
|
||||
>
|
||||
|
||||
<div className={[_s.d, _s.pb10].join(' ')}>
|
||||
<SettingSwitch
|
||||
prefix='community_timeline'
|
||||
settings={settings}
|
||||
settingPath={['shows', 'inSidebar']}
|
||||
onChange={onChange}
|
||||
label={intl.formatMessage(messages.showInSidebar)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
backgroundColor='brand'
|
||||
color='white'
|
||||
className={_s.jcCenter}
|
||||
onClick={this.handleSaveAndClose}
|
||||
>
|
||||
<Text color='inherit' weight='bold' align='center'>
|
||||
{intl.formatMessage(messages.saveAndClose)}
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
</ModalLayout>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'hashtag_timeline_settings', defaultMessage: 'Hashtag Timeline Settings' },
|
||||
saveAndClose: { id: 'saveClose', defaultMessage: 'Save & Close' },
|
||||
onlyMedia: { id: 'community.column_settings.media_only', defaultMessage: 'Media Only' },
|
||||
showInSidebar: { id: 'show_in_sidebar', defaultMessage: 'Show in Sidebar' },
|
||||
})
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
settings: state.getIn(['settings', 'community']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, { onClose }) => {
|
||||
return {
|
||||
onChange(key, checked) {
|
||||
dispatch(changeSetting(['community', ...key], checked))
|
||||
},
|
||||
onSave() {
|
||||
dispatch(saveSettings())
|
||||
onClose()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
HasttagTimelineSettingsModal.propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSave: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(HashtagTimelineSettingsModal))
|
|
@ -8,11 +8,12 @@ import ModalBase from './modal_base'
|
|||
import BundleErrorModal from './bundle_error_modal'
|
||||
import LoadingModal from './loading_modal'
|
||||
import {
|
||||
MODAL_ALBUM_CREATE,
|
||||
MODAL_BLOCK_ACCOUNT,
|
||||
MODAL_BOOKMARK_COLLECTION_CREATE,
|
||||
MODAL_BOOST,
|
||||
MODAL_CHAT_CONVERSATION_CREATE,
|
||||
MODAL_CHAT_CONVERSATION_DELETE,
|
||||
MODAL_COMMUNITY_TIMELINE_SETTINGS,
|
||||
MODAL_COMPOSE,
|
||||
MODAL_CONFIRM,
|
||||
MODAL_DECK_COLUMN_ADD,
|
||||
|
@ -24,7 +25,6 @@ import {
|
|||
MODAL_GROUP_CREATE,
|
||||
MODAL_GROUP_DELETE,
|
||||
MODAL_GROUP_PASSWORD,
|
||||
MODAL_HASHTAG_TIMELINE_SETTINGS,
|
||||
MODAL_HOME_TIMELINE_SETTINGS,
|
||||
MODAL_HOTKEYS,
|
||||
MODAL_LIST_ADD_USER,
|
||||
|
@ -44,11 +44,12 @@ import {
|
|||
MODAL_VIDEO,
|
||||
} from '../../constants'
|
||||
import {
|
||||
AlbumCreateModal,
|
||||
BlockAccountModal,
|
||||
BookmarkCollectionCreateModal,
|
||||
BoostModal,
|
||||
ChatConversationCreateModal,
|
||||
ChatConversationDeleteModal,
|
||||
CommunityTimelineSettingsModal,
|
||||
ComposeModal,
|
||||
ConfirmationModal,
|
||||
DeckColumnAddModal,
|
||||
|
@ -62,7 +63,6 @@ import {
|
|||
GroupMembersModal,
|
||||
GroupPasswordModal,
|
||||
GroupRemovedAccountsModal,
|
||||
HashtagTimelineSettingsModal,
|
||||
HomeTimelineSettingsModal,
|
||||
HotkeysModal,
|
||||
ListAddUserModal,
|
||||
|
@ -83,11 +83,12 @@ import {
|
|||
} from '../../features/ui/util/async_components'
|
||||
|
||||
const MODAL_COMPONENTS = {
|
||||
[MODAL_ALBUM_CREATE]: AlbumCreateModal,
|
||||
[MODAL_BLOCK_ACCOUNT]: BlockAccountModal,
|
||||
[MODAL_BOOKMARK_COLLECTION_CREATE]: BookmarkCollectionCreateModal,
|
||||
[MODAL_BOOST]: BoostModal,
|
||||
[MODAL_CHAT_CONVERSATION_CREATE]: ChatConversationCreateModal,
|
||||
[MODAL_CHAT_CONVERSATION_DELETE]: ChatConversationDeleteModal,
|
||||
[MODAL_COMMUNITY_TIMELINE_SETTINGS]: CommunityTimelineSettingsModal,
|
||||
[MODAL_COMPOSE]: ComposeModal,
|
||||
[MODAL_CONFIRM]: ConfirmationModal,
|
||||
[MODAL_DECK_COLUMN_ADD]: DeckColumnAddModal,
|
||||
|
@ -99,7 +100,6 @@ const MODAL_COMPONENTS = {
|
|||
[MODAL_GROUP_CREATE]: GroupCreateModal,
|
||||
[MODAL_GROUP_DELETE]: GroupDeleteModal,
|
||||
[MODAL_GROUP_PASSWORD]: GroupPasswordModal,
|
||||
[MODAL_HASHTAG_TIMELINE_SETTINGS]: HashtagTimelineSettingsModal,
|
||||
[MODAL_HOME_TIMELINE_SETTINGS]: HomeTimelineSettingsModal,
|
||||
[MODAL_HOTKEYS]: HotkeysModal,
|
||||
[MODAL_LIST_ADD_USER]: ListAddUserModal,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import BackButton from '../back_button'
|
||||
import Button from '../button'
|
||||
import Heading from '../heading'
|
||||
|
||||
class ProfileNavigationBar extends React.PureComponent {
|
||||
|
@ -28,6 +29,19 @@ class ProfileNavigationBar extends React.PureComponent {
|
|||
</Heading>
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.minH53PX, _s.jcCenter, _s.mr15].join(' ')}>
|
||||
<Button
|
||||
icon='ellipsis'
|
||||
iconSize='26px'
|
||||
iconClassName={_s.inheritFill}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.jcCenter, _s.aiCenter, _s.ml10, _s.px10].join(' ')}
|
||||
onClick={this.handleOpenMore}
|
||||
buttonRef={this.setOpenMoreNodeRef}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -61,7 +61,7 @@ class MediaGalleryPanel extends ImmutablePureComponent {
|
|||
noPadding
|
||||
title={intl.formatMessage(messages.title)}
|
||||
headerButtonTitle={!!account ? intl.formatMessage(messages.show_all) : undefined}
|
||||
headerButtonTo={!!account ? `/${account.get('acct')}/photos` : undefined}
|
||||
headerButtonTo={!!account ? `/${account.get('acct')}/albums` : undefined}
|
||||
>
|
||||
<div className={[_s.d, _s.flexRow, _s.flexWrap, _s.px10, _s.py10].join(' ')}>
|
||||
{
|
||||
|
|
|
@ -32,35 +32,27 @@ class ProfileStatsPanel extends ImmutablePureComponent {
|
|||
!!account &&
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.d, _s.flexRow].join(' ')}
|
||||
classNamesXS={[_s.d, _s.flexRow, _s.mt15, _s.pt10].join(' ')}
|
||||
classNamesXS={[_s.d, _s.flexRow, _s.mt15, _s.flexWrap].join(' ')}
|
||||
>
|
||||
<UserStat
|
||||
title={intl.formatMessage(messages.gabs)}
|
||||
value={shortNumberFormat(account.get('statuses_count'))}
|
||||
to={`/${account.get('acct')}`}
|
||||
isCentered={noPanel}
|
||||
isInline={noPanel}
|
||||
/>
|
||||
<UserStat
|
||||
title={intl.formatMessage(messages.followers)}
|
||||
value={shortNumberFormat(account.get('followers_count'))}
|
||||
to={`/${account.get('acct')}/followers`}
|
||||
isCentered={noPanel}
|
||||
isInline={noPanel}
|
||||
/>
|
||||
<UserStat
|
||||
isLast
|
||||
title={intl.formatMessage(messages.follows)}
|
||||
value={shortNumberFormat(account.get('following_count'))}
|
||||
to={`/${account.get('acct')}/following`}
|
||||
isCentered={noPanel}
|
||||
isInline={noPanel}
|
||||
/>
|
||||
{
|
||||
account.get('id') === me &&
|
||||
<UserStat
|
||||
title={intl.formatMessage(messages.likes)}
|
||||
value={shortNumberFormat(0)}
|
||||
to={`/${account.get('acct')}/likes`}
|
||||
isCentered={noPanel}
|
||||
/>
|
||||
}
|
||||
</ResponsiveClassesComponent>
|
||||
}
|
||||
</Wrapper>
|
||||
|
|
|
@ -53,6 +53,12 @@ class ChatConversationOptionsPopover extends ImmutablePureComponent {
|
|||
subtitle: 'Hide until next message',
|
||||
onClick: () => this.handleOnHide(),
|
||||
},
|
||||
{
|
||||
hideArrow: true,
|
||||
title: 'Mute Conversation',
|
||||
subtitle: "Don't get notified of new messages",
|
||||
onClick: () => this.handleOnHide(),
|
||||
},
|
||||
{},
|
||||
{
|
||||
hideArrow: true,
|
||||
|
|
|
@ -4,14 +4,11 @@ import { connect } from 'react-redux'
|
|||
import { closePopover } from '../../actions/popover'
|
||||
import { deleteChatMessage } from '../../actions/chat_messages'
|
||||
import {
|
||||
isChatMessengerBlocked,
|
||||
isChatMessengerMuted,
|
||||
blockChatMessenger,
|
||||
unblockChatMessenger,
|
||||
muteChatMessenger,
|
||||
unmuteChatMessenger,
|
||||
reportChatMessage,
|
||||
} from '../../actions/chat_conversation_accounts'
|
||||
import { fetchRelationships } from '../../actions/accounts'
|
||||
import { makeGetChatMessage } from '../../selectors'
|
||||
import { me } from '../../initial_state'
|
||||
import PopoverLayout from './popover_layout'
|
||||
|
@ -21,6 +18,12 @@ import Text from '../text'
|
|||
|
||||
class ChatMessageOptionsPopover extends React.PureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.isMine) {
|
||||
this.props.onFetchRelationships(this.props.fromAccountId)
|
||||
}
|
||||
}
|
||||
|
||||
handleOnDelete = () => {
|
||||
this.props.onDeleteChatMessage(this.props.chatMessageId)
|
||||
}
|
||||
|
@ -31,17 +34,9 @@ class ChatMessageOptionsPopover extends React.PureComponent {
|
|||
|
||||
handleOnBlock = () => {
|
||||
if (this.props.isBlocked) {
|
||||
this.props.unblockChatMessenger(this.props.fromAccountId)
|
||||
this.props.onUnblock(this.props.fromAccountId)
|
||||
} else {
|
||||
this.props.blockChatMessenger(this.props.fromAccountId)
|
||||
}
|
||||
}
|
||||
|
||||
handleOnMute = () => {
|
||||
if (this.props.isMuted) {
|
||||
this.props.unmuteChatMessenger(this.props.fromAccountId)
|
||||
} else {
|
||||
this.props.muteChatMessenger(this.props.fromAccountId)
|
||||
this.props.onBlock(this.props.fromAccountId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,7 +48,6 @@ class ChatMessageOptionsPopover extends React.PureComponent {
|
|||
const {
|
||||
isXS,
|
||||
isMine,
|
||||
isMuted,
|
||||
isBlocked,
|
||||
} = this.props
|
||||
|
||||
|
@ -76,12 +70,6 @@ class ChatMessageOptionsPopover extends React.PureComponent {
|
|||
subtitle: isBlocked ? '' : 'The messenger will not be able to message you.',
|
||||
onClick: () => this.handleOnBlock(),
|
||||
},
|
||||
{
|
||||
hideArrow: true,
|
||||
title: isMuted ? 'Unmute Messenger' : 'Mute Messenger',
|
||||
subtitle: isMuted ? '' : 'You will not be notified of new messsages',
|
||||
onClick: () => this.handleOnMute(),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
|
@ -96,12 +84,15 @@ class ChatMessageOptionsPopover extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, { chatMessageId }) => ({
|
||||
isMine: state.getIn(['chat_messages', chatMessageId, 'from_account_id']) === me,
|
||||
fromAccountId: state.getIn(['chat_messages', chatMessageId, 'from_account_id']),
|
||||
isBlocked: state.getIn(['chat_messages', chatMessageId, 'from_account_id']),
|
||||
isMuted: state.getIn(['chat_messages', chatMessageId, 'from_account_id']),
|
||||
})
|
||||
const mapStateToProps = (state, { chatMessageId }) => {
|
||||
const fromAccountId = state.getIn(['chat_messages', chatMessageId, 'from_account_id'])
|
||||
|
||||
return {
|
||||
fromAccountId,
|
||||
isMine: fromAccountId === me,
|
||||
isBlocked: state.getIn(['relationships', fromAccountId, 'chat_blocked_by'], false),
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onDeleteChatMessage(chatMessageId) {
|
||||
|
@ -114,15 +105,12 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
onUnblock(accountId) {
|
||||
dispatch(unblockChatMessenger(accountId))
|
||||
},
|
||||
onMute(accountId) {
|
||||
dispatch(muteChatMessenger(accountId))
|
||||
},
|
||||
onUnmute(accountId) {
|
||||
dispatch(unmuteChatMessenger(accountId))
|
||||
},
|
||||
onReportChatMessage(chatMessageId) {
|
||||
dispatch(reportChatMessage(chatMessageId))
|
||||
},
|
||||
onFetchRelationships(accountId) {
|
||||
// dispatch(fetchRelationships(accountId))
|
||||
},
|
||||
onClosePopover() {
|
||||
dispatch(closePopover())
|
||||
},
|
||||
|
@ -130,9 +118,9 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
|
||||
ChatMessageOptionsPopover.propTypes = {
|
||||
isXS: PropTypes.bool,
|
||||
isMine: PropTypes.bool,
|
||||
chatMessageId: PropTypes.string.isRequired,
|
||||
isBlocked: PropTypes.bool.isRequired,
|
||||
isMuted: PropTypes.bool.isRequired,
|
||||
onDeleteChatMessage: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { connect } from 'react-redux'
|
|||
import { closePopover } from '../../actions/popover'
|
||||
import PopoverLayout from './popover_layout'
|
||||
import List from '../list'
|
||||
import Button from '../button'
|
||||
import Text from '../text'
|
||||
|
||||
class ComposePostDesinationPopover extends React.PureComponent {
|
||||
|
@ -38,8 +39,20 @@ class ComposePostDesinationPopover extends React.PureComponent {
|
|||
isXS={isXS}
|
||||
onClose={this.handleOnClosePopover}
|
||||
>
|
||||
<Text className={[_s.d, _s.px15, _s.py10, _s.bgSecondary].join(' ')}>Post to:</Text>
|
||||
<List items={items} />
|
||||
<div className={[_s.d]}>
|
||||
<Text className={[_s.d, _s.px15, _s.py10, _s.bgSecondary].join(' ')}>Post to:</Text>
|
||||
<List items={items} />
|
||||
</div>
|
||||
<div>
|
||||
<Text className={[_s.d, _s.px15, _s.py10, _s.bgSecondary].join(' ')}>
|
||||
<Button
|
||||
isText
|
||||
icon='back'
|
||||
/>
|
||||
Select group:
|
||||
</Text>
|
||||
<List items={items} />
|
||||
</div>
|
||||
</PopoverLayout>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ class StatusOptionsPopover extends ImmutablePureComponent {
|
|||
handleGroupRemoveAccount = () => {
|
||||
const { status } = this.props
|
||||
|
||||
// : todo : check
|
||||
this.props.onGroupRemoveAccount(status.getIn(['group', 'id']), status.getIn(['account', 'id']))
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
title: intl.formatMessage(messages.comments),
|
||||
},
|
||||
{
|
||||
to: `/${account.get('acct')}/photos`,
|
||||
to: `/${account.get('acct')}/albums`,
|
||||
title: intl.formatMessage(messages.photos),
|
||||
},
|
||||
{
|
||||
|
@ -119,7 +119,11 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
const isMyProfile = !account ? false : account.get('id') === me
|
||||
if (isMyProfile) {
|
||||
tabs.push({
|
||||
to: `/${account.get('acct')}/bookmarks`,
|
||||
to: `/${account.get('acct')}/likes`,
|
||||
title: 'Likes',
|
||||
})
|
||||
tabs.push({
|
||||
to: `/${account.get('acct')}/bookmark_collections`,
|
||||
title: intl.formatMessage(messages.bookmarks),
|
||||
})
|
||||
}
|
||||
|
@ -149,21 +153,12 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
displayNone: stickied,
|
||||
})
|
||||
|
||||
const mobileAvatarContainerClasses = CX({
|
||||
d: 1,
|
||||
circle: 1,
|
||||
boxShadowProfileAvatar: 1,
|
||||
mtNeg50PX: !headerMissing,
|
||||
})
|
||||
|
||||
const mobileDescriptionContainerClasses = CX({
|
||||
d: 1,
|
||||
w100PC: 1,
|
||||
px15: 1,
|
||||
mt5: !!me,
|
||||
mb10: 1,
|
||||
pt15: !!me,
|
||||
pb10: 1,
|
||||
})
|
||||
|
||||
return (
|
||||
|
@ -174,10 +169,10 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
{
|
||||
!headerMissing &&
|
||||
<div className={[_s.d, _s.h200PX, _s.px10, _s.w100PC, _s.mt10, _s.overflowHidden].join(' ')}>
|
||||
<div className={[_s.d, _s.h172PX, _s.w100PC, _s.overflowHidden].join(' ')}>
|
||||
<Image
|
||||
alt={intl.formatMessage(messages.headerPhoto)}
|
||||
className={[_s.topRightRadiusSmall, _s.topLeftRadiusSmall, _s.h100PC].join(' ')}
|
||||
className={_s.h100PC}
|
||||
src={headerSrc}
|
||||
expandOnClick
|
||||
/>
|
||||
|
@ -185,85 +180,80 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||
}
|
||||
{
|
||||
headerMissing &&
|
||||
<div className={[_s.d, _s.h20PX, _s.w100PC].join(' ')} />
|
||||
<div className={[_s.d, _s.h122PX, _s.w100PC, _s.bgSecondary].join(' ')} />
|
||||
}
|
||||
|
||||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
|
||||
<div className={[_s.d, _s.aiCenter, _s.px15, _s.mb5].join(' ')}>
|
||||
<div className={mobileAvatarContainerClasses}>
|
||||
<Avatar size={100} account={account} noHover expandOnClick />
|
||||
<div className={[_s.d, _s.px15].join(' ')}>
|
||||
<div class={[_s.d, _s.flexRow].join(' ')}>
|
||||
<div className={[_s.d, _s.circle, _s.boxShadowProfileAvatar, _s.mtNeg32PX].join(' ')}>
|
||||
<Avatar size={88} account={account} noHover expandOnClick />
|
||||
</div>
|
||||
{
|
||||
account && account.get('id') === me &&
|
||||
<div className={[_s.d, _s.flexRow, _s.pt10, _s.flexGrow1, _s.h40PX, _s.jcEnd].join(' ')}>
|
||||
<Button
|
||||
isOutline
|
||||
backgroundColor='none'
|
||||
color='brand'
|
||||
className={[_s.jcCenter, _s.aiCenter, _s.h40PX].join(' ')}
|
||||
onClick={this.handleOnEditProfile}
|
||||
>
|
||||
<Text color='inherit' weight='bold' size='medium' className={_s.px15}>
|
||||
{intl.formatMessage(messages.editProfile)}
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
account && account.get('id') !== me && !!me &&
|
||||
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.pt15, _s.flexGrow1, _s.h40PX, _s.jcEnd].join(' ')}>
|
||||
<Button
|
||||
icon={isShortcut ? 'star' : 'star-outline'}
|
||||
iconSize='18px'
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.jcCenter, _s.aiCenter, _s.px10, _s.mr10].join(' ')}
|
||||
onClick={this.handleToggleShortcut}
|
||||
/>
|
||||
<div className={[_s.d, _s.flexRow, _s.h40PX].join(' ')}>
|
||||
<Button
|
||||
isOutline
|
||||
icon='chat'
|
||||
iconSize='18px'
|
||||
iconClassName={_s.inheritFill}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10].join(' ')}
|
||||
onClick={this.handleOpenMore}
|
||||
buttonRef={this.setOpenMoreNodeRef}
|
||||
/>
|
||||
</div>
|
||||
<div className={[_s.d, _s.flexRow, _s.h40PX].join(' ')}>
|
||||
<AccountActionButton account={account} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.flexRow, _s.flexNormal, _s.py10].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.flexNormal, _s.pt10].join(' ')}>
|
||||
<DisplayName
|
||||
account={account}
|
||||
isMultiline
|
||||
isLarge
|
||||
isCentered
|
||||
noHover
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={[_s.d, _s.bgPrimary, _s.aiCenter].join(' ')}>
|
||||
{
|
||||
account && account.get('id') === me &&
|
||||
<div className={[_s.d,_s.py5].join(' ')}>
|
||||
<Button
|
||||
isOutline
|
||||
backgroundColor='none'
|
||||
color='brand'
|
||||
className={[_s.jcCenter, _s.aiCenter].join(' ')}
|
||||
onClick={this.handleOnEditProfile}
|
||||
>
|
||||
<Text color='inherit' weight='bold' size='medium' className={_s.px15}>
|
||||
{intl.formatMessage(messages.editProfile)}
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
account && account.get('id') !== me && !!me &&
|
||||
<div className={[_s.d, _s.flexRow, _s.py5].join(' ')}>
|
||||
|
||||
<Button
|
||||
icon={isShortcut ? 'star' : 'star-outline'}
|
||||
iconSize='18px'
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.jcCenter, _s.aiCenter, _s.px10, _s.mr15].join(' ')}
|
||||
onClick={this.handleToggleShortcut}
|
||||
/>
|
||||
|
||||
<div className={[_s.d, _s.flexRow, _s.mr15].join(' ')}>
|
||||
<AccountActionButton account={account} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button
|
||||
isOutline
|
||||
icon='ellipsis'
|
||||
iconSize='18px'
|
||||
iconClassName={_s.inheritFill}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.jcCenter, _s.aiCenter, _s.ml10, _s.px10].join(' ')}
|
||||
onClick={this.handleOpenMore}
|
||||
buttonRef={this.setOpenMoreNodeRef}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className={mobileDescriptionContainerClasses}>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.mt10, _s.mb10, _s.pt5, _s.w100PC, _s.pr10].join(' ')}>
|
||||
<div className={[_s.d, _s.mt10, _s.mb10, _s.pt5, _s.w100PC].join(' ')}>
|
||||
<Pills pills={tabs} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -89,18 +89,12 @@ class DeckSidebar extends ImmutablePureComponent {
|
|||
|
||||
<div className={[_s.d, _s.aiCenter, _s.jcCenter].join(' ')}>
|
||||
{
|
||||
/*
|
||||
!!gabDeckOrder && gabDeckOrder.map((item, i) => (
|
||||
<Button
|
||||
isText
|
||||
key={`gab-deck-sidebar-dot-${i}`}
|
||||
onClick={this.scrollToItem}
|
||||
backgroundColor='secondary'
|
||||
className={[_s.mt5, _s.mb5, _s.px10, _s.py10, _s.circle].join(' ')}
|
||||
icon='notifications'
|
||||
iconClassName={_s.cPrimary}
|
||||
/>
|
||||
|
||||
))
|
||||
}
|
||||
*/
|
||||
}
|
||||
</div>
|
||||
|
||||
<Divider isSmall />
|
||||
|
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
|
|||
import { NavLink } from 'react-router-dom'
|
||||
import { CX } from '../constants'
|
||||
import Text from './text'
|
||||
import DotTextSeperator from './dot_text_seperator'
|
||||
|
||||
/**
|
||||
* Renders a user stat component
|
||||
|
@ -30,17 +31,29 @@ class UserStat extends React.PureComponent {
|
|||
title,
|
||||
value,
|
||||
isCentered,
|
||||
isInline,
|
||||
isLast,
|
||||
} = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
const align = isCentered ? 'center' : 'left'
|
||||
const titleSize = isInline ? 'normal' : 'extraLarge'
|
||||
const subtitleSize = isInline ? 'normal' : 'small'
|
||||
|
||||
const containerClasses = CX({
|
||||
d: 1,
|
||||
cursorPointer: 1,
|
||||
noUnderline: 1,
|
||||
flexNormal: isCentered,
|
||||
flexGrow1: !isCentered,
|
||||
pr15: !isCentered,
|
||||
flexGrow1: !isCentered && !isInline,
|
||||
flexRow: isInline,
|
||||
aiCenter: isInline,
|
||||
pr15: !isCentered && !isInline,
|
||||
pr10: !isCentered && isInline,
|
||||
})
|
||||
const subtitleClasses = CX({
|
||||
pr5: isInline,
|
||||
pl5: isInline,
|
||||
})
|
||||
|
||||
return (
|
||||
|
@ -51,12 +64,13 @@ class UserStat extends React.PureComponent {
|
|||
onMouseEnter={this.handleOnMouseEnter}
|
||||
onMouseLeave={this.handleOnMouseLeave}
|
||||
>
|
||||
<Text size='extraLarge' weight='bold' color='brand' align={align}>
|
||||
<Text size={titleSize} weight='bold' color='brand' align={align}>
|
||||
{value}
|
||||
</Text>
|
||||
<Text size='small' weight='medium' color='secondary' hasUnderline={hovering} align={align}>
|
||||
<Text size={subtitleSize} weight='medium' color='secondary' hasUnderline={hovering} align={align} className={subtitleClasses}>
|
||||
{title}
|
||||
</Text>
|
||||
{ !isLast && isInline && <DotTextSeperator /> }
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
|
@ -72,6 +86,8 @@ UserStat.propTypes = {
|
|||
PropTypes.object,
|
||||
]).isRequired,
|
||||
isCentered: PropTypes.bool,
|
||||
isInline: PropTypes.bool,
|
||||
isLast: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default UserStat
|
|
@ -46,11 +46,12 @@ export const POPOVER_TIMELINE_INJECTION_OPTIONS = 'TIMELINE_INJECTION_OPTIONS'
|
|||
export const POPOVER_USER_INFO = 'USER_INFO'
|
||||
export const POPOVER_VIDEO_STATS = 'VIDEO_STATS'
|
||||
|
||||
export const MODAL_ALBUM_CREATE = 'ALBUM_CREATE'
|
||||
export const MODAL_BLOCK_ACCOUNT = 'BLOCK_ACCOUNT'
|
||||
export const MODAL_BOOKMARK_COLLECTION_CREATE = 'BOOKMARK_COLLECTION_CREATE'
|
||||
export const MODAL_BOOST = 'BOOST'
|
||||
export const MODAL_CHAT_CONVERSATION_CREATE = 'CHAT_CONVERSATION_CREATE'
|
||||
export const MODAL_CHAT_CONVERSATION_DELETE = 'CHAT_CONVERSATION_DELETE'
|
||||
export const MODAL_COMMUNITY_TIMELINE_SETTINGS = 'COMMUNITY_TIMELINE_SETTINGS'
|
||||
export const MODAL_COMPOSE = 'COMPOSE'
|
||||
export const MODAL_CONFIRM = 'CONFIRM'
|
||||
export const MODAL_DECK_COLUMN_ADD = 'DECK_COLUMN_ADD'
|
||||
|
@ -62,7 +63,6 @@ export const MODAL_EMAIL_CONFIRMATION_REMINDER = 'EMAIL_CONFIRMATION_REMINDER'
|
|||
export const MODAL_GROUP_CREATE = 'GROUP_CREATE'
|
||||
export const MODAL_GROUP_DELETE = 'GROUP_DELETE'
|
||||
export const MODAL_GROUP_PASSWORD = 'GROUP_PASSWORD'
|
||||
export const MODAL_HASHTAG_TIMELINE_SETTINGS = 'HASHTAG_TIMELINE_SETTINGS'
|
||||
export const MODAL_HOME_TIMELINE_SETTINGS = 'HOME_TIMELINE_SETTINGS'
|
||||
export const MODAL_HOTKEYS = 'HOTKEYS'
|
||||
export const MODAL_LIST_ADD_USER = 'LIST_ADD_USER'
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import { expandAccountMediaTimeline } from '../actions/timelines'
|
||||
import { getAccountGallery } from '../selectors'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
import MediaItem from '../components/media_item'
|
||||
import LoadMore from '../components/load_more'
|
||||
import Block from '../components/block'
|
||||
import MediaGalleryPlaceholder from '../components/placeholder/media_gallery_placeholder'
|
||||
|
||||
class AccountAlbums extends ImmutablePureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
const { accountId, mediaType } = this.props
|
||||
|
||||
if (accountId && accountId !== -1) {
|
||||
this.props.dispatch(expandAccountMediaTimeline(accountId, { mediaType }))
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (
|
||||
(nextProps.accountId && nextProps.accountId !== this.props.accountId) ||
|
||||
(nextProps.accountId && nextProps.mediaType !== this.props.mediaType)
|
||||
) {
|
||||
this.props.dispatch(expandAccountMediaTimeline(nextProps.accountId, {
|
||||
mediaType: nextProps.mediaType,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
handleScrollToBottom = () => {
|
||||
if (this.props.hasMore) {
|
||||
this.handleLoadMore(this.props.attachments.size > 0 ? this.props.attachments.last().getIn(['status', 'id']) : undefined)
|
||||
}
|
||||
}
|
||||
|
||||
handleScroll = (e) => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.target
|
||||
const offset = scrollHeight - scrollTop - clientHeight
|
||||
|
||||
if (150 > offset && !this.props.isLoading) {
|
||||
this.handleScrollToBottom()
|
||||
}
|
||||
}
|
||||
|
||||
handleLoadMore = (maxId) => {
|
||||
if (this.props.accountId && this.props.accountId !== -1) {
|
||||
this.props.dispatch(expandAccountMediaTimeline(this.props.accountId, {
|
||||
maxId,
|
||||
mediaType: this.props.mediaType,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
handleLoadOlder = (e) => {
|
||||
e.preventDefault()
|
||||
this.handleScrollToBottom()
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
attachments,
|
||||
isLoading,
|
||||
hasMore,
|
||||
intl,
|
||||
account,
|
||||
} = this.props
|
||||
|
||||
if (!account) return null
|
||||
|
||||
return (
|
||||
<Block>
|
||||
<div
|
||||
role='feed'
|
||||
onScroll={this.handleScroll}
|
||||
className={[_s.d, _s.flexRow, _s.flexWrap, _s.py5, _s.px5].join(' ')}
|
||||
>
|
||||
|
||||
{
|
||||
attachments.map((attachment, i) => (
|
||||
<MediaItem
|
||||
key={attachment.get('id')}
|
||||
attachment={attachment}
|
||||
account={account}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
{
|
||||
isLoading && attachments.size === 0 &&
|
||||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
<MediaGalleryPlaceholder />
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!isLoading && attachments.size === 0 &&
|
||||
<ColumnIndicator type='error' message={intl.formatMessage(messages.none)} />
|
||||
}
|
||||
</div>
|
||||
|
||||
{
|
||||
hasMore && !(isLoading && attachments.size === 0) &&
|
||||
<LoadMore visible={!isLoading} onClick={this.handleLoadOlder} />
|
||||
}
|
||||
</Block>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
none: { id: 'account_gallery.none', defaultMessage: 'No media to show.' },
|
||||
})
|
||||
|
||||
const mapStateToProps = (state, { account, mediaType }) => {
|
||||
const accountId = !!account ? account.get('id') : -1
|
||||
|
||||
return {
|
||||
accountId,
|
||||
attachments: getAccountGallery(state, accountId, mediaType),
|
||||
isLoading: state.getIn(['timelines', `account:${accountId}:media`, 'isLoading']),
|
||||
hasMore: state.getIn(['timelines', `account:${accountId}:media`, 'hasMore']),
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
})
|
||||
|
||||
AccountAlbums.propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
account: ImmutablePropTypes.map,
|
||||
accountId: PropTypes.string,
|
||||
attachments: ImmutablePropTypes.list.isRequired,
|
||||
isLoading: PropTypes.bool,
|
||||
hasMore: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
mediaType: PropTypes.oneOf([
|
||||
'photo',
|
||||
'video',
|
||||
]),
|
||||
}
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(AccountAlbums))
|
|
@ -0,0 +1,73 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import { changeListEditorTitle, submitListEditor } from '../actions/lists'
|
||||
import { closeModal } from '../actions/modal'
|
||||
import { MODAL_LIST_CREATE } from '../constants'
|
||||
import Button from '../components/button'
|
||||
import Input from '../components/input'
|
||||
import Form from '../components/form'
|
||||
import Text from '../components/text'
|
||||
|
||||
class BookmarkCollectionCreate extends React.PureComponent {
|
||||
|
||||
state = {
|
||||
value: '',
|
||||
}
|
||||
|
||||
onChange = (value) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
handleOnSubmit = () => {
|
||||
this.props.onSubmit()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { disabled, isModal } = this.props
|
||||
const { value } = this.state
|
||||
|
||||
const isDisabled = !value || disabled
|
||||
|
||||
return (
|
||||
<Form>
|
||||
<Input
|
||||
title='Title'
|
||||
placeholder='Bookmark collection title'
|
||||
value={value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
|
||||
<Button
|
||||
isDisabled={isDisabled}
|
||||
onClick={this.handleOnSubmit}
|
||||
className={[_s.mt10].join(' ')}
|
||||
>
|
||||
<Text color='inherit' align='center'>
|
||||
Create
|
||||
</Text>
|
||||
</Button>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
disabled: state.getIn(['listEditor', 'isSubmitting']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, { isModal }) => ({
|
||||
onSubmit() {
|
||||
if (isModal) dispatch(closeModal(MODAL_LIST_CREATE))
|
||||
dispatch(submitListEditor(true))
|
||||
},
|
||||
})
|
||||
|
||||
BookmarkCollectionCreate.propTypes = {
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
isModal: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(BookmarkCollectionCreate)
|
|
@ -3,8 +3,18 @@ import PropTypes from 'prop-types'
|
|||
import { connect } from 'react-redux'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import {
|
||||
MODAL_BOOKMARK_COLLECTION_CREATE,
|
||||
} from '../constants'
|
||||
import {
|
||||
meUsername,
|
||||
} from '../initial_state'
|
||||
import { fetchBookmarkCollections } from '../actions/bookmarks'
|
||||
import { openModal } from '../actions/modal'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
import Block from '../components/block'
|
||||
import Button from '../components/button'
|
||||
import Text from '../components/text'
|
||||
import List from '../components/list'
|
||||
|
||||
class BookmarkCollections extends ImmutablePureComponent {
|
||||
|
@ -13,6 +23,10 @@ class BookmarkCollections extends ImmutablePureComponent {
|
|||
this.props.onFetchBookmarkCollections()
|
||||
}
|
||||
|
||||
handleOpenModal = () => {
|
||||
this.props.onOpenModal()
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
isLoading,
|
||||
|
@ -24,19 +38,32 @@ class BookmarkCollections extends ImmutablePureComponent {
|
|||
return <ColumnIndicator type='error' message='Error fetching bookmark collections' />
|
||||
}
|
||||
|
||||
const listItems = shortcuts.map((s) => ({
|
||||
const listItems = [{ to: `/${meUsername}/bookmark_collections/bookmarks`, title: 'Bookmarks' }].concat(!!bookmarkCollections ? bookmarkCollections.map((s) => ({
|
||||
to: s.get('to'),
|
||||
title: s.get('title'),
|
||||
image: s.get('image'),
|
||||
}))
|
||||
})) : [])
|
||||
|
||||
return (
|
||||
<List
|
||||
scrollKey='bookmark-collections'
|
||||
emptyMessage='You have no bookmark collections'
|
||||
items={listItems}
|
||||
showLoading={isLoading}
|
||||
/>
|
||||
<Block>
|
||||
<div className={[_s.d, _s.px15, _s.py10].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.aiCenter].join(' ')}>
|
||||
<Text size='extraLarge' weight='bold'>Bookmark Collections</Text>
|
||||
<Button
|
||||
className={[_s.px10, _s.mlAuto].join(' ')}
|
||||
onClick={this.handleOpenModal}
|
||||
backgroundColor='tertiary'
|
||||
color='tertiary'
|
||||
icon='add'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<List
|
||||
scrollKey='bookmark-collections'
|
||||
emptyMessage='You have no bookmark collections'
|
||||
items={listItems}
|
||||
showLoading={isLoading}
|
||||
/>
|
||||
</Block>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -49,6 +76,9 @@ const mapStateToProps = (state) => ({
|
|||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onOpenModal() {
|
||||
dispatch(openModal(MODAL_BOOKMARK_COLLECTION_CREATE))
|
||||
},
|
||||
onFetchBookmarkCollections() {
|
||||
dispatch(fetchBookmarkCollections())
|
||||
},
|
||||
|
@ -58,6 +88,7 @@ BookmarkCollections.propTypes = {
|
|||
isLoading: PropTypes.bool.isRequired,
|
||||
isError: PropTypes.bool.isRequired,
|
||||
onFetchBookmarkCollections: PropTypes.func.isRequired,
|
||||
onOpenModal: PropTypes.func.isRequired,
|
||||
bookmarkCollections: ImmutablePropTypes.list,
|
||||
}
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@ import ColumnIndicator from '../components/column_indicator'
|
|||
class BookmarkedStatuses extends ImmutablePureComponent {
|
||||
|
||||
componentWillMount() {
|
||||
this.props.dispatch(fetchBookmarkedStatuses())
|
||||
this.props.dispatch(fetchBookmarkedStatuses(this.props.bookmarkCollectionId))
|
||||
}
|
||||
|
||||
handleLoadMore = debounce(() => {
|
||||
this.props.dispatch(expandBookmarkedStatuses())
|
||||
this.props.dispatch(expandBookmarkedStatuses(this.props.bookmarkCollectionId))
|
||||
}, 300, { leading: true })
|
||||
|
||||
render() {
|
||||
|
@ -46,14 +46,13 @@ class BookmarkedStatuses extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, { params: { username } }) => {
|
||||
return {
|
||||
isMyAccount: (username.toLowerCase() === meUsername.toLowerCase()),
|
||||
statusIds: state.getIn(['status_lists', 'bookmarks', 'items']),
|
||||
isLoading: state.getIn(['status_lists', 'bookmarks', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['status_lists', 'bookmarks', 'next']),
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state, { params: { username, bookmarkCollectionId } }) => ({
|
||||
bookmarkCollectionId,
|
||||
isMyAccount: (username.toLowerCase() === meUsername.toLowerCase()),
|
||||
statusIds: state.getIn(['status_lists', 'bookmarks', 'items']),
|
||||
isLoading: state.getIn(['status_lists', 'bookmarks', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['status_lists', 'bookmarks', 'next']),
|
||||
})
|
||||
|
||||
BookmarkedStatuses.propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
|
|
|
@ -21,7 +21,6 @@ class ChatConversationCreate extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleOnCreateChatConversation = (accountId) => {
|
||||
console.log("handleOnCreateChatConversation:", accountId)
|
||||
this.props.onCreateChatConversation(accountId)
|
||||
}
|
||||
|
||||
|
@ -69,7 +68,6 @@ const mapStateToProps = (state) => ({
|
|||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onChange: (value) => {
|
||||
console.log("value", value)
|
||||
dispatch(fetchChatConversationAccountSuggestions(value))
|
||||
},
|
||||
onCreateChatConversation: (accountId) => {
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { injectIntl, FormattedMessage } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { me } from '../initial_state'
|
||||
import {
|
||||
fetchChatMessengerMutes,
|
||||
expandChatMessengerMutes,
|
||||
unmuteChatMessenger,
|
||||
} from '../actions/chat_conversation_accounts'
|
||||
import Account from '../components/account'
|
||||
import Block from '../components/block'
|
||||
import BlockHeading from '../components/block_heading'
|
||||
import ScrollableList from '../components/scrollable_list'
|
||||
|
||||
class ChatConversationMutedAccounts extends ImmutablePureComponent {
|
||||
|
||||
componentWillMount() {
|
||||
this.props.onFetchMutes()
|
||||
}
|
||||
|
||||
handleLoadMore = debounce(() => {
|
||||
this.props.onExpandMutes()
|
||||
}, 300, { leading: true })
|
||||
|
||||
render() {
|
||||
const {
|
||||
accountIds,
|
||||
hasMore,
|
||||
isLoading,
|
||||
} = this.props
|
||||
|
||||
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={<FormattedMessage id='navigation_bar.chat_mutes' defaultMessage='Muted chat users' />} />
|
||||
</div>
|
||||
<ScrollableList
|
||||
scrollKey='chat_muted_accounts'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
hasMore={hasMore}
|
||||
isLoading={isLoading}
|
||||
emptyMessage={<FormattedMessage id='empty_column.chat_mutes' defaultMessage="You haven't muted any chat users yet." />}
|
||||
>
|
||||
{
|
||||
accountIds && accountIds.map((id) =>
|
||||
<Account
|
||||
key={`mutes-${id}`}
|
||||
id={id}
|
||||
compact
|
||||
actionIcon='subtract'
|
||||
onActionClick={() => this.props.onRemove(id)}
|
||||
actionTitle='Remove'
|
||||
/>
|
||||
)
|
||||
}
|
||||
</ScrollableList>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
accountIds: state.getIn(['user_lists', 'chat_mutes', me, 'items']),
|
||||
hasMore: !!state.getIn(['user_lists', 'chat_mutes', me, 'next']),
|
||||
isLoading: state.getIn(['user_lists', 'chat_mutes', me, 'isLoading']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onFetchMutes: () => dispatch(fetchChatMessengerMutes()),
|
||||
onExpandMutes: () => dispatch(expandChatMessengerMutes()),
|
||||
onRemove: (accountId) => dispatch(unmuteChatMessenger(accountId)),
|
||||
})
|
||||
|
||||
ChatConversationMutedAccounts.propTypes = {
|
||||
accountIds: ImmutablePropTypes.list,
|
||||
hasMore: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
onExpandMutes: PropTypes.func.isRequired,
|
||||
onFetchMutes: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ChatConversationMutedAccounts))
|
|
@ -30,34 +30,38 @@ class ComposeDestinationHeader extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { account, isModal } = this.props
|
||||
const { account, isModal, formLocation } = this.props
|
||||
|
||||
const isIntroduction = formLocation === 'introduction'
|
||||
const title = 'Post to timeline'
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.bgPrimary, _s.w100PC, _s.h40PX, _s.pr15].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.pl15, _s.flexGrow1, _s.mrAuto, _s.h40PX].join(' ')}>
|
||||
<Avatar account={account} size={28} />
|
||||
<div className={[_s.ml15].join(' ')}>
|
||||
<Button
|
||||
isNarrow
|
||||
isOutline
|
||||
radiusSmall
|
||||
buttonRef={this.setDestinationBtn}
|
||||
backgroundColor='secondary'
|
||||
color='primary'
|
||||
onClick={this.handleOnClick}
|
||||
className={[_s.border1PX, _s.borderColorPrimary].join(' ')}
|
||||
>
|
||||
<Text color='inherit' size='small' className={_s.jcCenter}>
|
||||
{title}
|
||||
<Icon id='caret-down' size='8px' className={_s.ml5} />
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
{
|
||||
!isIntroduction &&
|
||||
<div className={[_s.ml15].join(' ')}>
|
||||
<Button
|
||||
isNarrow
|
||||
isOutline
|
||||
radiusSmall
|
||||
buttonRef={this.setDestinationBtn}
|
||||
backgroundColor='secondary'
|
||||
color='primary'
|
||||
onClick={this.handleOnClick}
|
||||
className={[_s.border1PX, _s.borderColorPrimary].join(' ')}
|
||||
>
|
||||
<Text color='inherit' size='small' className={_s.jcCenter}>
|
||||
{title}
|
||||
<Icon id='caret-down' size='8px' className={_s.ml5} />
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{
|
||||
!isModal &&
|
||||
!isModal && !isIntroduction &&
|
||||
<Button
|
||||
isText
|
||||
isNarrow
|
||||
|
@ -89,6 +93,7 @@ ComposeDestinationHeader.propTypes = {
|
|||
isModal: PropTypes.bool,
|
||||
onOpenModal: PropTypes.func.isRequired,
|
||||
onOpenPopover: PropTypes.func.isRequired,
|
||||
formLocation: PropTypes.string,
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ComposeDestinationHeader)
|
|
@ -57,6 +57,7 @@ class ComposeExtraButtonList extends React.PureComponent {
|
|||
const isXS = width <= BREAKPOINT_EXTRA_SMALL
|
||||
const isStandalone = formLocation === 'standalone'
|
||||
const isTimeline = formLocation === 'timeline'
|
||||
const isIntroduction = formLocation === 'introduction'
|
||||
const small = (!isModal && isXS && !isStandalone) || isTimeline
|
||||
|
||||
console.log("small, formLocation:", small, formLocation)
|
||||
|
@ -84,8 +85,8 @@ class ComposeExtraButtonList extends React.PureComponent {
|
|||
<UploadButton small={small} />
|
||||
<EmojiPickerButton isMatch={isMatch} small={small} />
|
||||
{ !edit && <PollButton small={small} /> }
|
||||
<StatusVisibilityButton small={small} />
|
||||
<SpoilerButton small={small} />
|
||||
{ !isIntroduction && <StatusVisibilityButton small={small} /> }
|
||||
{ !isIntroduction && <SpoilerButton small={small} /> }
|
||||
{ !hidePro && !edit && <SchedulePostButton small={small} /> }
|
||||
{ !hidePro && !edit && <ExpiresPostButton small={small} /> }
|
||||
{ !hidePro && !isXS && <RichTextEditorButton small={small} /> }
|
||||
|
|
|
@ -273,7 +273,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
<div className={[_s.d, _s.calcMaxH410PX, _s.overflowYScroll].join(' ')}>
|
||||
|
||||
<Responsive min={BREAKPOINT_EXTRA_SMALL}>
|
||||
<ComposeDestinationHeader account={account} isModal={isModalOpen} />
|
||||
<ComposeDestinationHeader formLocation={formLocation} account={account} isModal={isModalOpen} />
|
||||
</Responsive>
|
||||
|
||||
<div className={containerClasses} ref={this.setForm} onClick={this.handleClick}>
|
||||
|
|
|
@ -25,7 +25,9 @@ import Text from '../components/text'
|
|||
import {
|
||||
AccountTimeline,
|
||||
Compose,
|
||||
GroupTimeline,
|
||||
LikedStatuses,
|
||||
ListTimeline,
|
||||
HomeTimeline,
|
||||
Notifications,
|
||||
HashtagTimeline,
|
||||
|
@ -73,7 +75,7 @@ class Deck extends React.PureComponent {
|
|||
|
||||
let Component = null
|
||||
let componentParams = {}
|
||||
let title, icon = ''
|
||||
let title, subtitle, icon = ''
|
||||
|
||||
switch (deckColumn) {
|
||||
case 'notifications':
|
||||
|
@ -123,18 +125,32 @@ class Deck extends React.PureComponent {
|
|||
break
|
||||
}
|
||||
|
||||
// : todo :
|
||||
if (!Component) {
|
||||
if (deckColumn.indexOf('user.') > -1) {
|
||||
|
||||
} else if (deckColumn.indexOf('list.') > -1) {
|
||||
|
||||
const listId = deckColumn.replace('list.', '')
|
||||
title = 'List'
|
||||
subtitle = listId
|
||||
icon = 'list'
|
||||
Component = ListTimeline
|
||||
componentParams = { params: { id: listId }}
|
||||
} else if (deckColumn.indexOf('group.') > -1) {
|
||||
|
||||
const groupId = deckColumn.replace('group.', '')
|
||||
title = 'Group'
|
||||
subtitle = groupId
|
||||
icon = 'group'
|
||||
Component = GroupTimeline
|
||||
componentParams = { params: { id: groupId }}
|
||||
} else if (deckColumn.indexOf('news.') > -1) {
|
||||
|
||||
// : todo :
|
||||
} else if (deckColumn.indexOf('hashtag.') > -1) {
|
||||
|
||||
const hashtag = deckColumn.replace('hashtag.', '')
|
||||
title = 'Hashtag'
|
||||
subtitle = hashtag
|
||||
icon = 'apps'
|
||||
Component = HashtagTimeline
|
||||
componentParams = { params: { id: hashtag }}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +162,7 @@ class Deck extends React.PureComponent {
|
|||
index={index}
|
||||
sortIndex={index}
|
||||
>
|
||||
<DeckColumn title={title} icon={icon} index={index}>
|
||||
<DeckColumn title={title} subtitle={subtitle} icon={icon} index={index}>
|
||||
<WrappedBundle component={Component} componentParams={componentParams} />
|
||||
</DeckColumn>
|
||||
</SortableItem>
|
||||
|
@ -158,6 +174,8 @@ class Deck extends React.PureComponent {
|
|||
|
||||
const isEmpty = gabDeckOrder.size === 0
|
||||
|
||||
console.log("gabDeckOrder:", gabDeckOrder)
|
||||
|
||||
return (
|
||||
<SortableContainer
|
||||
axis='x'
|
||||
|
|
|
@ -22,10 +22,6 @@ class ListTimeline extends ImmutablePureComponent {
|
|||
this.handleConnect(this.props.params.id)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.handleDisconnect()
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.params.id !== this.props.params.id) {
|
||||
this.handleConnect(nextProps.params.id)
|
||||
|
|
|
@ -193,4 +193,4 @@ ChatMessagesComposeForm.propTypes = {
|
|||
onSendMessage: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default connect(mapDispatchToProps)(ChatMessagesComposeForm)
|
||||
export default connect(null, mapDispatchToProps)(ChatMessagesComposeForm)
|
|
@ -30,10 +30,6 @@ class ChatSettingsSidebar extends React.PureComponent {
|
|||
title: 'Blocked Chats',
|
||||
to: '/messages/blocks',
|
||||
},
|
||||
{
|
||||
title: 'Muted Chats',
|
||||
to: '/messages/mutes',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</ResponsiveClassesComponent>
|
||||
|
|
|
@ -56,16 +56,17 @@ import {
|
|||
AccountGallery,
|
||||
AccountTimeline,
|
||||
AccountCommentsTimeline,
|
||||
AlbumCreate,
|
||||
Assets,
|
||||
BlockedAccounts,
|
||||
BookmarkCollections,
|
||||
BookmarkCollectionCreate,
|
||||
BookmarkedStatuses,
|
||||
CaliforniaConsumerProtection,
|
||||
CaliforniaConsumerProtectionContact,
|
||||
ChatConversationCreate,
|
||||
ChatConversationRequests,
|
||||
ChatConversationBlockedAccounts,
|
||||
ChatConversationMutedAccounts,
|
||||
CommunityTimeline,
|
||||
Compose,
|
||||
Deck,
|
||||
|
@ -219,7 +220,6 @@ 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/mutes' exact page={MessagesPage} component={ChatConversationMutedAccounts} 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' }} />
|
||||
|
@ -278,9 +278,13 @@ class SwitchingArea extends React.PureComponent {
|
|||
<WrappedRoute path='/:username/videos' page={ProfilePage} component={AccountGallery} content={children} componentParams={{ noSidebar: true, mediaType: 'video' }} />
|
||||
<WrappedRoute path='/:username/albums' page={ProfilePage} component={AccountAlbums} content={children} componentParams={{ noSidebar: true, mediaType: 'photo' }} />
|
||||
|
||||
<WrappedRoute path='/:username/album_create' page={ModalPage} component={AlbumCreate} content={children} componentParams={{ title: 'Create Album', page: 'create-album' }} />
|
||||
<WrappedRoute path='/:username/album_edit/:albumId' page={ModalPage} component={AlbumCreate} content={children} componentParams={{ title: 'Create Album', page: 'edit-album' }} />
|
||||
|
||||
<WrappedRoute path='/:username/likes' page={ProfilePage} component={LikedStatuses} content={children} />
|
||||
<WrappedRoute path='/:username/bookmarks' page={ProfilePage} component={BookmarkCollections} content={children} />
|
||||
<WrappedRoute path='/:username/:bookmarkCollectionId/bookmarks' page={ProfilePage} component={BookmarkedStatuses} content={children} />
|
||||
<WrappedRoute path='/:username/bookmark_collections' page={ProfilePage} component={BookmarkCollections} content={children} />
|
||||
<WrappedRoute path='/:username/bookmark_collections/create' page={ModalPage} component={BookmarkCollectionCreate} content={children} componentParams={{ title: 'Create Bookmark Collection', page: 'create-bookmark-collection' }} />
|
||||
<WrappedRoute path='/:username/bookmark_collections/:bookmarkCollectionId' page={ProfilePage} component={BookmarkedStatuses} content={children} />
|
||||
|
||||
<WrappedRoute path='/:username/posts/:statusId' publicRoute exact page={BasicPage} component={StatusFeature} content={children} componentParams={{ title: 'Status', page: 'status' }} />
|
||||
|
||||
|
|
|
@ -3,10 +3,14 @@ export function AboutSidebar() { return import(/* webpackChunkName: "components/
|
|||
export function AccountTimeline() { return import(/* webpackChunkName: "features/account_timeline" */'../../account_timeline') }
|
||||
export function AccountCommentsTimeline() { return import(/* webpackChunkName: "features/account_comments_timeline" */'../../account_comments_timeline') }
|
||||
export function AccountGallery() { return import(/* webpackChunkName: "features/account_gallery" */'../../account_gallery') }
|
||||
export function AlbumCreate() { return import(/* webpackChunkName: "features/album_create" */'../../album_create') }
|
||||
export function AlbumCreateModal() { return import(/* webpackChunkName: "components/album_create_modal" */'../../../components/modal/album_create_modal') }
|
||||
export function Assets() { return import(/* webpackChunkName: "features/about/assets" */'../../about/assets') }
|
||||
export function BlockAccountModal() { return import(/* webpackChunkName: "components/block_account_modal" */'../../../components/modal/block_account_modal') }
|
||||
export function BlockedAccounts() { return import(/* webpackChunkName: "features/blocked_accounts" */'../../blocked_accounts') }
|
||||
export function BookmarkCollections() { return import(/* webpackChunkName: "features/bookmark_collections" */'../../bookmark_collections') }
|
||||
export function BookmarkCollectionCreate() { return import(/* webpackChunkName: "features/bookmark_collection_create" */'../../bookmark_collection_create') }
|
||||
export function BookmarkCollectionCreateModal() { return import(/* webpackChunkName: "components/bookmark_collection_create_modal" */'../../../components/modal/bookmark_collection_create_modal') }
|
||||
export function BookmarkedStatuses() { return import(/* webpackChunkName: "features/bookmarked_statuses" */'../../bookmarked_statuses') }
|
||||
export function BoostModal() { return import(/* webpackChunkName: "components/boost_modal" */'../../../components/modal/boost_modal') }
|
||||
export function CaliforniaConsumerProtection() { return import(/* webpackChunkName: "features/california_consumer_protection" */'../../about/california_consumer_protection') }
|
||||
|
@ -15,13 +19,11 @@ export function ChatConversationBlockedAccounts() { return import(/* webpackChun
|
|||
export function ChatConversationCreate() { return import(/* webpackChunkName: "features/chat_conversation_create" */'../../chat_conversation_create') }
|
||||
export function ChatConversationCreateModal() { return import(/* webpackChunkName: "components/chat_conversation_create_modal" */'../../../components/modal/chat_conversation_create_modal') }
|
||||
export function ChatConversationDeleteModal() { return import(/* webpackChunkName: "components/chat_conversation_delete_modal" */'../../../components/modal/chat_conversation_delete_modal') }
|
||||
export function ChatConversationMutedAccounts() { return import(/* webpackChunkName: "features/chat_conversation_muted_accounts" */'../../chat_conversation_muted_accounts') }
|
||||
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 ChatMessageOptionsPopover() { return import(/* webpackChunkName: "components/chat_message_options_popover" */'../../../components/popover/chat_message_options_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 CommunityTimelineSettingsModal() { return import(/* webpackChunkName: "components/community_timeline_settings_modal" */'../../../components/modal/community_timeline_settings_modal') }
|
||||
export function Compose() { return import(/* webpackChunkName: "features/compose" */'../../compose') }
|
||||
export function ComposeForm() { return import(/* webpackChunkName: "components/compose_form" */'../../compose/components/compose_form') }
|
||||
export function ComposeModal() { return import(/* webpackChunkName: "components/compose_modal" */'../../../components/modal/compose_modal') }
|
||||
|
@ -70,7 +72,6 @@ export function GroupsCategories() { return import(/* webpackChunkName: "feature
|
|||
export function GroupCategory() { return import(/* webpackChunkName: "features/group_category" */'../../group_category') }
|
||||
export function GroupTag() { return import(/* webpackChunkName: "features/group_tag" */'../../group_tag') }
|
||||
export function HashtagTimeline() { return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline') }
|
||||
export function HashtagTimelineSettingsModal() { return import(/* webpackChunkName: "components/hashtag_timeline_settings_modal" */'../../../components/modal/hashtag_timeline_settings_modal') }
|
||||
export function HomeTimeline() { return import(/* webpackChunkName: "features/home_timeline" */'../../home_timeline') }
|
||||
export function HomeTimelineSettingsModal() { return import(/* webpackChunkName: "components/home_timeline_settings_modal" */'../../../components/modal/home_timeline_settings_modal') }
|
||||
export function HotkeysModal() { return import(/* webpackChunkName: "components/hotkeys_modal" */'../../../components/modal/hotkeys_modal') }
|
||||
|
|
|
@ -41,7 +41,7 @@ class DeckLayout extends React.PureComponent {
|
|||
|
||||
if (isXS) {
|
||||
return (
|
||||
<div className={[_s.d, _s.aiCenter, _s.jcCenter, _s.w100PC, _s.h100VH, _s.bgTertiary].join(' ')}>
|
||||
<div className={[_s.d, _s.aiCenter, _s.jcCenter, _s.w100PC, _s.h100VH, _s.bgTertiary, _s.px15, _s.py15].join(' ')}>
|
||||
<Text className={_s.mb10}>Gab Deck is not available on mobile or tablet devices. Please only access using a desktop computer.</Text>
|
||||
<Button to='/home'>Return home</Button>
|
||||
</div>
|
||||
|
|
|
@ -110,7 +110,7 @@ class ProfileLayout extends ImmutablePureComponent {
|
|||
|
||||
<div className={[_s.d, _s.w100PC, , _s.flexRow, _s.jcEnd, _s.py15].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC, _s.z1].join(' ')}>
|
||||
<div className={_s.d}>
|
||||
<div className={[_s.d, _s.boxShadowNone].join(' ')}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import { openModal } from '../actions/modal'
|
||||
import PageTitle from '../features/ui/util/page_title'
|
||||
import DefaultLayout from '../layouts/default_layout'
|
||||
import { MODAL_COMMUNITY_TIMELINE_SETTINGS } from '../constants'
|
||||
import {
|
||||
LinkFooter,
|
||||
GroupsPanel,
|
||||
|
@ -16,10 +13,6 @@ import {
|
|||
|
||||
class CommunityPage extends React.PureComponent {
|
||||
|
||||
onOpenCommunityPageSettingsModal = () => {
|
||||
this.props.dispatch(openModal(MODAL_COMMUNITY_TIMELINE_SETTINGS))
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, intl } = this.props
|
||||
|
||||
|
@ -29,12 +22,6 @@ class CommunityPage extends React.PureComponent {
|
|||
<DefaultLayout
|
||||
title={title}
|
||||
page='community'
|
||||
actions={[
|
||||
{
|
||||
icon: 'ellipsis',
|
||||
onClick: this.onOpenCommunityPageSettingsModal,
|
||||
},
|
||||
]}
|
||||
layout={[
|
||||
ProgressPanel,
|
||||
TrendsBreakingPanel,
|
||||
|
@ -60,4 +47,4 @@ CommunityPage.propTypes = {
|
|||
intl: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
export default injectIntl(connect()(CommunityPage))
|
||||
export default injectIntl(CommunityPage)
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { openModal } from '../actions/modal'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import isObject from 'lodash.isobject'
|
||||
import PageTitle from '../features/ui/util/page_title'
|
||||
import DefaultLayout from '../layouts/default_layout'
|
||||
import { MODAL_HASHTAG_TIMELINE_SETTINGS } from '../constants'
|
||||
import {
|
||||
LinkFooter,
|
||||
ProgressPanel,
|
||||
|
@ -16,17 +13,6 @@ import {
|
|||
|
||||
class HashtagPage extends React.PureComponent {
|
||||
|
||||
onOpenHashtagPageSettingsModal = () => {
|
||||
const { params } = this.props
|
||||
|
||||
const hashtag = isObject(params) ? params.id : ''
|
||||
if (!hashtag) return
|
||||
|
||||
this.props.dispatch(openModal(MODAL_HASHTAG_TIMELINE_SETTINGS, {
|
||||
hashtag,
|
||||
}))
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
|
@ -41,12 +27,6 @@ class HashtagPage extends React.PureComponent {
|
|||
showBackBtn
|
||||
title={intl.formatMessage(messages.hashtagTimeline)}
|
||||
page={`hashtag.${hashtag}`}
|
||||
actions={[
|
||||
{
|
||||
icon: 'ellipsis',
|
||||
onClick: this.onOpenHashtagPageSettingsModal,
|
||||
},
|
||||
]}
|
||||
layout={[
|
||||
ProgressPanel,
|
||||
TrendsBreakingPanel,
|
||||
|
@ -73,4 +53,4 @@ HashtagPage.propTypes = {
|
|||
params: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
export default injectIntl(connect()(HashtagPage))
|
||||
export default injectIntl(HashtagPage)
|
|
@ -10,41 +10,47 @@ import {
|
|||
ACCOUNT_MUTE_SUCCESS,
|
||||
ACCOUNT_UNMUTE_SUCCESS,
|
||||
RELATIONSHIPS_FETCH_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
} from '../actions/accounts'
|
||||
import {
|
||||
BLOCK_CHAT_MESSAGER_SUCCESS,
|
||||
UNBLOCK_CHAT_MESSAGER_SUCCESS,
|
||||
} from '../actions/chat_conversation_accounts'
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable'
|
||||
|
||||
const normalizeRelationship = (state, relationship) => state.set(relationship.id, fromJS(relationship));
|
||||
const normalizeRelationship = (state, relationship) => state.set(relationship.id, fromJS(relationship))
|
||||
|
||||
const normalizeRelationships = (state, relationships) => {
|
||||
relationships.forEach(relationship => {
|
||||
state = normalizeRelationship(state, relationship);
|
||||
});
|
||||
state = normalizeRelationship(state, relationship)
|
||||
})
|
||||
|
||||
return state;
|
||||
};
|
||||
return state
|
||||
}
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
const initialState = ImmutableMap()
|
||||
|
||||
export default function relationships(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case ACCOUNT_FOLLOW_REQUEST:
|
||||
return state.setIn([action.id, action.locked ? 'requested' : 'following'], true);
|
||||
return state.setIn([action.id, action.locked ? 'requested' : 'following'], true)
|
||||
case ACCOUNT_FOLLOW_FAIL:
|
||||
return state.setIn([action.id, action.locked ? 'requested' : 'following'], false);
|
||||
return state.setIn([action.id, action.locked ? 'requested' : 'following'], false)
|
||||
case ACCOUNT_UNFOLLOW_REQUEST:
|
||||
return state.setIn([action.id, 'following'], false);
|
||||
return state.setIn([action.id, 'following'], false)
|
||||
case ACCOUNT_UNFOLLOW_FAIL:
|
||||
return state.setIn([action.id, 'following'], true);
|
||||
return state.setIn([action.id, 'following'], true)
|
||||
case ACCOUNT_FOLLOW_SUCCESS:
|
||||
case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
case ACCOUNT_BLOCK_SUCCESS:
|
||||
case ACCOUNT_UNBLOCK_SUCCESS:
|
||||
case ACCOUNT_MUTE_SUCCESS:
|
||||
case ACCOUNT_UNMUTE_SUCCESS:
|
||||
return normalizeRelationship(state, action.relationship);
|
||||
case BLOCK_CHAT_MESSAGER_SUCCESS:
|
||||
case UNBLOCK_CHAT_MESSAGER_SUCCESS:
|
||||
return normalizeRelationship(state, action.relationship)
|
||||
case RELATIONSHIPS_FETCH_SUCCESS:
|
||||
return normalizeRelationships(state, action.relationships);
|
||||
return normalizeRelationships(state, action.relationships)
|
||||
default:
|
||||
return state;
|
||||
return state
|
||||
}
|
||||
};
|
||||
}
|
|
@ -50,18 +50,12 @@ const initialState = ImmutableMap({
|
|||
theme: 'white',
|
||||
}),
|
||||
|
||||
home: ImmutableMap({
|
||||
shows: ImmutableMap({
|
||||
reply: true,
|
||||
repost: true,
|
||||
}),
|
||||
}),
|
||||
|
||||
community: ImmutableMap({
|
||||
shows: ImmutableMap({
|
||||
onlyMedia: false,
|
||||
}),
|
||||
}),
|
||||
// home: ImmutableMap({
|
||||
// shows: ImmutableMap({
|
||||
// reply: true,
|
||||
// repost: true,
|
||||
// }),
|
||||
// }),
|
||||
})
|
||||
|
||||
const defaultColumns = fromJS([
|
||||
|
|
|
@ -5,14 +5,19 @@ import {
|
|||
} from '../actions/toasts'
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable'
|
||||
|
||||
const makeMessageFromData = (data) => {
|
||||
return `${data.type}`.split('_').join(' ').toLowerCase()
|
||||
}
|
||||
|
||||
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: 'action.message',
|
||||
message: makeMessageFromData(action.toastData),
|
||||
type: action.toastType,
|
||||
}))
|
||||
case TOAST_DISMISS:
|
||||
|
|
|
@ -62,13 +62,6 @@ import {
|
|||
CHAT_MESSENGER_BLOCKS_EXPAND_REQUEST,
|
||||
CHAT_MESSENGER_BLOCKS_EXPAND_SUCCESS,
|
||||
CHAT_MESSENGER_BLOCKS_EXPAND_FAIL,
|
||||
|
||||
CHAT_MESSENGER_MUTES_FETCH_REQUEST,
|
||||
CHAT_MESSENGER_MUTES_FETCH_SUCCESS,
|
||||
CHAT_MESSENGER_MUTES_FETCH_FAIL,
|
||||
CHAT_MESSENGER_MUTES_EXPAND_REQUEST,
|
||||
CHAT_MESSENGER_MUTES_EXPAND_SUCCESS,
|
||||
CHAT_MESSENGER_MUTES_EXPAND_FAIL,
|
||||
} from '../actions/chat_conversation_accounts'
|
||||
import {
|
||||
GROUP_MEMBERS_FETCH_SUCCESS,
|
||||
|
@ -243,17 +236,6 @@ export default function userLists(state = initialState, action) {
|
|||
case CHAT_MESSENGER_BLOCKS_EXPAND_FAIL:
|
||||
return setListFailed(state, 'chat_blocks', me)
|
||||
|
||||
case CHAT_MESSENGER_MUTES_FETCH_REQUEST:
|
||||
case CHAT_MESSENGER_MUTES_EXPAND_REQUEST:
|
||||
return state.setIn(['chat_mutes', me, 'isLoading'], true)
|
||||
case CHAT_MESSENGER_MUTES_FETCH_SUCCESS:
|
||||
return normalizeList(state, 'chat_mutes', me, action.accounts, action.next)
|
||||
case CHAT_MESSENGER_MUTES_EXPAND_SUCCESS:
|
||||
return appendToList(state, 'chat_mutes', me, action.accounts, action.next)
|
||||
case CHAT_MESSENGER_MUTES_FETCH_FAIL:
|
||||
case CHAT_MESSENGER_MUTES_EXPAND_FAIL:
|
||||
return setListFailed(state, 'chat_mutes', me)
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ export const getToasts = createSelector([
|
|||
|
||||
let arr = []
|
||||
|
||||
base.forEach(item => {
|
||||
base.forEach((item) => {
|
||||
arr.push({
|
||||
message: item.get('message'),
|
||||
type: item.get('type'),
|
||||
|
@ -242,3 +242,19 @@ export const getToasts = createSelector([
|
|||
|
||||
return arr
|
||||
})
|
||||
|
||||
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
|
||||
})
|
|
@ -576,6 +576,7 @@ pre {
|
|||
.h220PX { height: 220px; }
|
||||
.h215PX { height: 215px; }
|
||||
.h200PX { height: 200px; }
|
||||
.h172PX { height: 172px; }
|
||||
.h158PX { height: 158px; }
|
||||
.h122PX { height: 122px; }
|
||||
.h60PX { height: 60px; }
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# updated_at :datetime not null
|
||||
# unread_count :bigint(8) default(0), not null
|
||||
# chat_message_expiration_policy :string
|
||||
# is_muted :boolean default(FALSE), not null
|
||||
#
|
||||
|
||||
# : todo : expires
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: chat_mutes
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# account_id :integer not null
|
||||
# target_account_id :integer not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
|
||||
class ChatMute < ApplicationRecord
|
||||
include Paginable
|
||||
include RelationshipCacheable
|
||||
|
||||
belongs_to :account
|
||||
belongs_to :target_account, class_name: 'Account'
|
||||
|
||||
validates :account_id, uniqueness: { scope: :target_account_id }
|
||||
|
||||
after_commit :remove_blocking_cache
|
||||
|
||||
private
|
||||
|
||||
def remove_blocking_cache
|
||||
Rails.cache.delete("exclude_chat_account_ids_for:#{account_id}")
|
||||
end
|
||||
end
|
|
@ -22,6 +22,9 @@ class LinkBlock < ApplicationRecord
|
|||
Addressable::URI.parse(array[0]).normalize
|
||||
}
|
||||
url = urls.first
|
||||
|
||||
return false if url.nil?
|
||||
|
||||
link_for_fetch = TagManager.instance.normalize_link(url)
|
||||
link_for_fetch = link_for_fetch.chomp("/")
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ class AccountRelationshipsPresenter
|
|||
|
||||
private
|
||||
|
||||
# : todo :
|
||||
# chat muting, chat blocking
|
||||
|
||||
def cached
|
||||
return @cached if defined?(@cached)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class REST::ChatConversationAccountSerializer < ActiveModel::Serializer
|
||||
attributes :id, :is_hidden, :is_approved, :unread_count,
|
||||
:is_unread, :chat_conversation_id, :created_at,
|
||||
:is_blocked, :is_muted, :chat_message_expiration_policy
|
||||
:is_muted, :chat_message_expiration_policy
|
||||
|
||||
has_many :participant_accounts, key: :other_accounts, serializer: REST::AccountSerializer
|
||||
has_one :last_chat_message, serializer: REST::ChatMessageSerializer, unless: :last_chat_message_id?
|
||||
|
@ -24,12 +24,4 @@ class REST::ChatConversationAccountSerializer < ActiveModel::Serializer
|
|||
object.unread_count > 0
|
||||
end
|
||||
|
||||
def is_blocked
|
||||
false
|
||||
end
|
||||
|
||||
def is_muted
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MuteChatMessengerService < BaseService
|
||||
def call(account, target_account)
|
||||
return if account.id == target_account.id
|
||||
mute = account.chat_mute!(target_account)
|
||||
mute
|
||||
end
|
||||
end
|
|
@ -52,16 +52,17 @@ class PostChatMessageService < BaseService
|
|||
@chat_conversation_recipients_accounts = ChatConversationAccount.where(chat_conversation: @chat_conversation)
|
||||
@chat_conversation_recipients_accounts.each do |recipient|
|
||||
recipient.last_chat_message_id = @chat.id
|
||||
recipient.is_hidden = false # reset to show unless blocked
|
||||
recipient.is_hidden = false # : todo : reset to show unless blocked
|
||||
|
||||
# Get not mine
|
||||
if @account_conversation.id != recipient.id
|
||||
recipient.unread_count = recipient.unread_count + 1
|
||||
|
||||
# : todo :
|
||||
# check if muting, redis
|
||||
payload = InlineRenderer.render(@chat, recipient.account, :chat_message)
|
||||
Redis.current.publish("chat_messages:#{recipient.account.id}", Oj.dump(event: :notification, payload: payload))
|
||||
# check if muting
|
||||
unless recipient.is_muted
|
||||
payload = InlineRenderer.render(@chat, recipient.account, :chat_message)
|
||||
Redis.current.publish("chat_messages:#{recipient.account.id}", Oj.dump(event: :notification, payload: payload))
|
||||
end
|
||||
else
|
||||
recipient.unread_count = 0
|
||||
end
|
||||
|
@ -80,8 +81,10 @@ class PostChatMessageService < BaseService
|
|||
raise ActiveRecord::RecordInvalid
|
||||
end
|
||||
|
||||
def set_message_expiration_date
|
||||
case @account_conversation.expiration_policy
|
||||
def set_message_expiration_date!
|
||||
@expires_at = nil
|
||||
|
||||
case @account_conversation.chat_message_expiration_policy
|
||||
when :five_minutes
|
||||
@expires_at = 5.minutes
|
||||
when :sixty_minutes
|
||||
|
|
|
@ -111,6 +111,8 @@ class PostStatusService < BaseService
|
|||
return if group_id.blank?
|
||||
return if @autoJoinGroup
|
||||
|
||||
# : todo : check removedaccounts if exist dont allow
|
||||
|
||||
raise GabSocial::ValidationError, I18n.t('statuses.not_a_member_of_group') if not GroupAccount.where(account: @account, group_id: group_id).exists?
|
||||
end
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UnmuteChatMessengerService < BaseService
|
||||
def call(account, target_account)
|
||||
return unless account.chat_muting?(target_account)
|
||||
account.chat_unmute!(target_account)
|
||||
end
|
||||
end
|
|
@ -228,15 +228,14 @@ Rails.application.routes.draw do
|
|||
|
||||
resource :chat_conversation_accounts, only: :show do
|
||||
resource :blocked_chat_accounts, only: :show, controller: 'chat_conversation_accounts/blocked_chat_accounts'
|
||||
resource :muted_chat_accounts, only: :show, controller: 'chat_conversation_accounts/muted_chat_accounts'
|
||||
|
||||
member do
|
||||
get :is_messenger_blocked
|
||||
get :is_messenger_muted
|
||||
post :block_messenger
|
||||
post :unblock_messenger
|
||||
post :mute_messenger
|
||||
post :unmute_messenger
|
||||
post :mute_chat_conversation
|
||||
post :unmute_chat_conversation
|
||||
post :set_expiration_policy
|
||||
end
|
||||
end
|
||||
|
@ -392,6 +391,13 @@ Rails.application.routes.draw do
|
|||
|
||||
get '/', to: 'react#react', as: :homepage
|
||||
|
||||
get '/about', to: 'react#react'
|
||||
get '/about/tos', to: 'react#react'
|
||||
get '/about/privacy', to: 'react#react'
|
||||
get '/about/investors', to: 'react#react'
|
||||
get '/about/dmca', to: 'react#react'
|
||||
get '/about/sales', to: 'react#react'
|
||||
|
||||
match '*unmatched_route',
|
||||
via: :all,
|
||||
to: 'application#raise_not_found',
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
class AddIsMutedToChatConversationAccounts < ActiveRecord::Migration[5.2]
|
||||
def up
|
||||
safety_assured { add_column :chat_conversation_accounts, :is_muted, :bool, default: false, null: false }
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :chat_conversation_accounts, :is_muted
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class RemoveChatMutes < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
drop_table :chat_mutes
|
||||
end
|
||||
end
|
11
db/schema.rb
11
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_12_15_203113) do
|
||||
ActiveRecord::Schema.define(version: 2020_12_16_051551) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
|
@ -214,6 +214,7 @@ ActiveRecord::Schema.define(version: 2020_12_15_203113) do
|
|||
t.datetime "updated_at", null: false
|
||||
t.bigint "unread_count", default: 0, null: false
|
||||
t.string "chat_message_expiration_policy"
|
||||
t.boolean "is_muted", default: false, null: false
|
||||
t.index ["account_id"], name: "index_chat_conversation_accounts_on_account_id"
|
||||
t.index ["chat_conversation_id"], name: "index_chat_conversation_accounts_on_chat_conversation_id"
|
||||
end
|
||||
|
@ -234,14 +235,6 @@ ActiveRecord::Schema.define(version: 2020_12_15_203113) do
|
|||
t.index ["from_account_id", "chat_conversation_id"], name: "index_chat_messages_on_from_account_id_and_chat_conversation_id"
|
||||
end
|
||||
|
||||
create_table "chat_mutes", force: :cascade do |t|
|
||||
t.integer "account_id", null: false
|
||||
t.integer "target_account_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["account_id", "target_account_id"], name: "index_chat_mutes_on_account_id_and_target_account_id", unique: true
|
||||
end
|
||||
|
||||
create_table "conversations", force: :cascade do |t|
|
||||
t.string "uri"
|
||||
t.datetime "created_at", null: false
|
||||
|
|
Loading…
Reference in New Issue