Commiting
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -33,20 +33,17 @@ export const fetchBookmarkedStatuses = () => (dispatch, getState) => {
|
||||
|
||||
const fetchBookmarkedStatusesRequest = () => ({
|
||||
type: BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
const fetchBookmarkedStatusesSuccess = (statuses, next) => ({
|
||||
type: BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
||||
statuses,
|
||||
next,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
const fetchBookmarkedStatusesFail = (error) => ({
|
||||
type: BOOKMARKED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
28
app/javascript/gabsocial/actions/chat_compose.js
Normal file
28
app/javascript/gabsocial/actions/chat_compose.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import api from '../api'
|
||||
import { me } from '../initial_state'
|
||||
|
||||
export const MESSAGE_INPUT_CHANGE = 'MESSAGE_INPUT_CHANGE'
|
||||
export const MESSAGE_INPUT_RESET = 'MESSAGE_INPUT_RESET'
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const messageInputChange = (text) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
//Ensure has conversation
|
||||
const conversationId = getState().getIn(['chat_conversations', 'current', 'conversation_id'], null)
|
||||
if (!conversationId) return
|
||||
|
||||
dispatch({
|
||||
type: MESSAGE_INPUT_CHANGE,
|
||||
text,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const messageInputReset = (dispatch) => {
|
||||
dispatch({ type: MESSAGE_INPUT_RESET })
|
||||
}
|
||||
189
app/javascript/gabsocial/actions/chat_conversations.js
Normal file
189
app/javascript/gabsocial/actions/chat_conversations.js
Normal file
@@ -0,0 +1,189 @@
|
||||
import api, { getLinks } from '../api'
|
||||
import { fetchRelationships } from './accounts'
|
||||
import { importFetchedAccounts } from './importer'
|
||||
import { me } from '../initial_state'
|
||||
|
||||
export const CONVERSATION_BLOCKS_FETCH_REQUEST = 'CONVERSATION_BLOCKS_FETCH_REQUEST'
|
||||
export const CONVERSATION_BLOCKS_FETCH_SUCCESS = 'CONVERSATION_BLOCKS_FETCH_SUCCESS'
|
||||
export const CONVERSATION_BLOCKS_FETCH_FAIL = 'CONVERSATION_BLOCKS_FETCH_FAIL'
|
||||
|
||||
export const CONVERSATION_BLOCKS_EXPAND_REQUEST = 'CONVERSATION_BLOCKS_EXPAND_REQUEST'
|
||||
export const CONVERSATION_BLOCKS_EXPAND_SUCCESS = 'CONVERSATION_BLOCKS_EXPAND_SUCCESS'
|
||||
export const CONVERSATION_BLOCKS_EXPAND_FAIL = 'CONVERSATION_BLOCKS_EXPAND_FAIL'
|
||||
|
||||
export const BLOCK_MESSAGER_REQUEST = 'BLOCK_MESSAGER_REQUEST'
|
||||
export const BLOCK_MESSAGER_SUCCESS = 'BLOCK_MESSAGER_SUCCESS'
|
||||
export const BLOCK_MESSAGER_FAIL = 'BLOCK_MESSAGER_FAIL'
|
||||
|
||||
export const UNBLOCK_MESSAGER_REQUEST = 'UNBLOCK_MESSAGER_REQUEST'
|
||||
export const UNBLOCK_MESSAGER_SUCCESS = 'UNBLOCK_MESSAGER_SUCCESS'
|
||||
export const UNBLOCK_MESSAGER_FAIL = 'UNBLOCK_MESSAGER_FAIL'
|
||||
|
||||
//
|
||||
|
||||
export const CONVERSATION_MUTES_FETCH_REQUEST = 'CONVERSATION_MUTES_FETCH_REQUEST'
|
||||
export const CONVERSATION_MUTES_FETCH_SUCCESS = 'CONVERSATION_MUTES_FETCH_SUCCESS'
|
||||
export const CONVERSATION_MUTES_FETCH_FAIL = 'CONVERSATION_MUTES_FETCH_FAIL'
|
||||
|
||||
export const CONVERSATION_MUTES_EXPAND_REQUEST = 'CONVERSATION_MUTES_EXPAND_REQUEST'
|
||||
export const CONVERSATION_MUTES_EXPAND_SUCCESS = 'CONVERSATION_MUTES_EXPAND_SUCCESS'
|
||||
export const CONVERSATION_MUTES_EXPAND_FAIL = 'CONVERSATION_MUTES_EXPAND_FAIL'
|
||||
|
||||
export const MUTE_MESSAGER_REQUEST = 'BLOCK_MESSAGER_REQUEST'
|
||||
export const MUTE_MESSAGER_SUCCESS = 'BLOCK_MESSAGER_SUCCESS'
|
||||
export const MUTE_MESSAGER_FAIL = 'BLOCK_MESSAGER_FAIL'
|
||||
|
||||
export const UNMUTE_MESSAGER_REQUEST = 'UNMUTE_MESSAGER_REQUEST'
|
||||
export const UNMUTE_MESSAGER_SUCCESS = 'UNMUTE_MESSAGER_SUCCESS'
|
||||
export const UNMUTE_MESSAGER_FAIL = 'UNMUTE_MESSAGER_FAIL'
|
||||
|
||||
//
|
||||
|
||||
export const CONVERSATION_REQUEST_APPROVE_SUCCESS = 'CONVERSATION_REQUEST_APPROVE_SUCCESS'
|
||||
export const CONVERSATION_REQUEST_APPROVE_FAIL = 'CONVERSATION_REQUEST_APPROVE_FAIL'
|
||||
|
||||
export const CONVERSATION_REQUEST_REJECT_SUCCESS = 'CONVERSATION_REQUEST_REJECT_SUCCESS'
|
||||
export const CONVERSATION_REQUEST_REJECT_FAIL = 'CONVERSATION_REQUEST_REJECT_FAIL'
|
||||
|
||||
export const CONVERSATION_DELETE_REQUEST = 'CONVERSATION_DELETE_REQUEST'
|
||||
export const CONVERSATION_DELETE_SUCCESS = 'CONVERSATION_DELETE_SUCCESS'
|
||||
export const CONVERSATION_DELETE_FAIL = 'CONVERSATION_DELETE_FAIL'
|
||||
|
||||
//
|
||||
|
||||
export const CONVERSATIONS_FETCH_REQUEST = 'CONVERSATIONS_FETCH_REQUEST'
|
||||
export const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS'
|
||||
export const CONVERSATIONS_FETCH_FAIL = 'CONVERSATIONS_FETCH_FAIL'
|
||||
|
||||
export const CONVERSATIONS_EXPAND_REQUEST = 'CONVERSATIONS_EXPAND_REQUEST'
|
||||
export const CONVERSATIONS_EXPAND_SUCCESS = 'CONVERSATIONS_EXPAND_SUCCESS'
|
||||
export const CONVERSATIONS_EXPAND_FAIL = 'CONVERSATIONS_EXPAND_FAIL'
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const blockMessenger = (accountId) => (dispatch, getState) => {
|
||||
if (!accountId) return
|
||||
|
||||
dispatch(blockMessengerRequest(accountId))
|
||||
|
||||
api(getState).post(`/api/v1/messages/accounts/${accountId}/block`).then((response) => {
|
||||
dispatch(blockMessengerSuccess(response.data))
|
||||
}).catch((error) => {
|
||||
dispatch(blockMessengerFail(accountId, error))
|
||||
})
|
||||
}
|
||||
|
||||
const blockMessengerRequest = (accountId) => ({
|
||||
type: BLOCK_MESSAGER_REQUEST,
|
||||
accountId,
|
||||
})
|
||||
|
||||
const blockMessengerSuccess = (data) => ({
|
||||
type: BLOCK_MESSAGER_REQUEST,
|
||||
data,
|
||||
})
|
||||
|
||||
const blockMessengerFail = (accountId, error) => ({
|
||||
type: BLOCK_MESSAGER_REQUEST,
|
||||
accountId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const unblockMessenger = (accountId) => (dispatch, getState) => {
|
||||
if (!accountId) return
|
||||
|
||||
dispatch(unblockMessengerRequest(accountId))
|
||||
|
||||
api(getState).post(`/api/v1/messages/accounts/${accountId}/unblock`).then((response) => {
|
||||
dispatch(unblockMessengerSuccess(response.data))
|
||||
}).catch((error) => {
|
||||
dispatch(unblockMessengerFail(accountId, error))
|
||||
})
|
||||
}
|
||||
|
||||
const unblockMessengerRequest = (accountId) => ({
|
||||
type: UNBLOCK_MESSAGER_REQUEST,
|
||||
accountId,
|
||||
})
|
||||
|
||||
const blockMessengerSuccess = (data) => ({
|
||||
type: UNBLOCK_MESSAGER_REQUEST,
|
||||
data,
|
||||
})
|
||||
|
||||
const blockMessengerFail = (accountId, error) => ({
|
||||
type: UNBLOCK_MESSAGER_REQUEST,
|
||||
accountId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const fetchBlocks = () => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
dispatch(fetchBlocksRequest())
|
||||
|
||||
api(getState).get('/api/v1/blocks').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null))
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)))
|
||||
}).catch(error => dispatch(fetchBlocksFail(error)))
|
||||
}
|
||||
|
||||
export const fetchBlocksRequest = () => ({
|
||||
type: BLOCKS_FETCH_REQUEST,
|
||||
})
|
||||
|
||||
export const fetchBlocksSuccess = (accounts, next) => ({
|
||||
type: BLOCKS_FETCH_SUCCESS,
|
||||
accounts,
|
||||
next,
|
||||
})
|
||||
|
||||
export const fetchBlocksFail = (error) => ({
|
||||
type: BLOCKS_FETCH_FAIL,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandBlocks = () => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
const url = getState().getIn(['user_lists', 'blocks', me, 'next'])
|
||||
const isLoading = getState().getIn(['user_lists', 'blocks', me, 'isLoading'])
|
||||
|
||||
if (url === null || isLoading) return
|
||||
|
||||
dispatch(expandBlocksRequest())
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(expandBlocksSuccess(response.data, next ? next.uri : null))
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)))
|
||||
}).catch(error => dispatch(expandBlocksFail(error)))
|
||||
}
|
||||
|
||||
export const expandBlocksRequest = () => ({
|
||||
type: BLOCKS_EXPAND_REQUEST,
|
||||
})
|
||||
|
||||
export const expandBlocksSuccess = (accounts, next) => ({
|
||||
type: BLOCKS_EXPAND_SUCCESS,
|
||||
accounts,
|
||||
next,
|
||||
})
|
||||
|
||||
export const expandBlocksFail = (error) => ({
|
||||
type: BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
})
|
||||
86
app/javascript/gabsocial/actions/chat_messages.js
Normal file
86
app/javascript/gabsocial/actions/chat_messages.js
Normal file
@@ -0,0 +1,86 @@
|
||||
import api from '../api'
|
||||
import { me } from '../initial_state'
|
||||
|
||||
export const MESSAGE_SEND_REQUEST = 'MESSAGE_SEND_REQUEST'
|
||||
export const MESSAGE_SEND_SUCCESS = 'MESSAGE_SEND_SUCCESS'
|
||||
export const MESSAGE_SEND_FAIL = 'MESSAGE_SEND_FAIL'
|
||||
|
||||
export const MESSAGE_DELETE_REQUEST = 'MESSAGE_DELETE_REQUEST'
|
||||
export const MESSAGE_DELETE_SUCCESS = 'MESSAGE_DELETE_SUCCESS'
|
||||
export const MESSAGE_DELETE_FAIL = 'MESSAGE_DELETE_FAIL'
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const sendMessage = (text, conversationId) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
// : todo :
|
||||
// let text = getState().getIn(['chat_messages', 'text'], '')
|
||||
// let conversationId = getState().getIn(['chat_messags', 'conversation_id'], '')
|
||||
|
||||
dispatch(sendMessageRequest())
|
||||
|
||||
api(getState).put('/api/v1/messages/chat', {
|
||||
text,
|
||||
conversationId,
|
||||
}, {
|
||||
headers: {
|
||||
'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
|
||||
},
|
||||
}).then((response) => {
|
||||
sendMessageSuccess(response)
|
||||
}).catch((error) => {
|
||||
dispatch(sendMessageFail(error))
|
||||
})
|
||||
}
|
||||
|
||||
const sendMessageRequest = (text, conversationId) => ({
|
||||
type: MESSAGE_SEND_REQUEST,
|
||||
text,
|
||||
conversationId,
|
||||
})
|
||||
|
||||
const sendMessageSuccess = () => ({
|
||||
type: MESSAGE_SEND_SUCCESS,
|
||||
})
|
||||
|
||||
const sendMessageFail = (error) => ({
|
||||
type: MESSAGE_SEND_FAIL,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const deleteMessage = (messageId) => (dispatch, getState) => {
|
||||
if (!me || !messageId) return
|
||||
|
||||
// : todo :
|
||||
|
||||
dispatch(sendMessageRequest())
|
||||
|
||||
api(getState).delete(`/api/v1/messages/chat/${messageId}`, {}, {
|
||||
headers: {
|
||||
'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
|
||||
},
|
||||
}).then((response) => {
|
||||
sendMessageSuccess(response)
|
||||
}).catch((error) => {
|
||||
dispatch(sendMessageFail(error))
|
||||
})
|
||||
}
|
||||
|
||||
const deleteMessageRequest = (messageId) => ({
|
||||
type: MESSAGE_DELETE_REQUEST,
|
||||
messageId,
|
||||
})
|
||||
|
||||
const deleteMessageSuccess = () => ({
|
||||
type: MESSAGE_DELETE_SUCCESS,
|
||||
})
|
||||
|
||||
const deleteMessageFail = (error) => ({
|
||||
type: MESSAGE_DELETE_FAIL,
|
||||
error,
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,17 +16,14 @@ export const fetchCustomEmojis = () => (dispatch, getState) => {
|
||||
|
||||
const fetchCustomEmojisRequest = () => ({
|
||||
type: CUSTOM_EMOJIS_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
const fetchCustomEmojisSuccess = (custom_emojis) => ({
|
||||
type: CUSTOM_EMOJIS_FETCH_SUCCESS,
|
||||
custom_emojis,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
const fetchCustomEmojisFail = (error) => ({
|
||||
type: CUSTOM_EMOJIS_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
@@ -33,20 +33,17 @@ export const fetchFavoritedStatuses = () => (dispatch, getState) => {
|
||||
|
||||
const fetchFavoritedStatusesRequest = () => ({
|
||||
type: FAVORITED_STATUSES_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
const fetchFavoritedStatusesSuccess = (statuses, next) => ({
|
||||
type: FAVORITED_STATUSES_FETCH_SUCCESS,
|
||||
statuses,
|
||||
next,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
const fetchFavoritedStatusesFail = (error) => ({
|
||||
type: FAVORITED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,18 +23,15 @@ export const fetchFilters = () => (dispatch, getState) => {
|
||||
|
||||
const fetchFiltersRequest = () => ({
|
||||
type: FILTERS_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
const fetchFiltersSuccess = (filters) => ({
|
||||
type: FILTERS_FETCH_SUCCESS,
|
||||
filters,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
const fetchFiltersFail = (err) => ({
|
||||
type: FILTERS_FETCH_FAIL,
|
||||
err,
|
||||
skipLoading: true,
|
||||
skipAlert: true,
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,10 @@ export const STATUSES_IMPORT = 'STATUSES_IMPORT'
|
||||
export const POLLS_IMPORT = 'POLLS_IMPORT'
|
||||
export const ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP = 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP'
|
||||
|
||||
function pushUnique(array, object) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const pushUnique = (array, object) => {
|
||||
if (array.every(element => element.id !== object.id)) {
|
||||
array.push(object);
|
||||
}
|
||||
|
||||
@@ -5,20 +5,26 @@ import { expandSpoilers } from '../../initial_state'
|
||||
|
||||
const domParser = new DOMParser()
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
|
||||
obj[`:${emoji.shortcode}:`] = emoji;
|
||||
return obj;
|
||||
}, {});
|
||||
obj[`:${emoji.shortcode}:`] = emoji
|
||||
return obj
|
||||
}, {})
|
||||
|
||||
export function normalizeAccount(account) {
|
||||
account = { ...account };
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const normalizeAccount = (account) => {
|
||||
account = { ...account }
|
||||
|
||||
const emojiMap = makeEmojiMap(account);
|
||||
const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name;
|
||||
const emojiMap = makeEmojiMap(account)
|
||||
const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name
|
||||
|
||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
|
||||
account.display_name_plain = emojify(escapeTextContentForBrowser(displayName), emojiMap, true);
|
||||
account.note_emojified = emojify(account.note, emojiMap);
|
||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap)
|
||||
account.display_name_plain = emojify(escapeTextContentForBrowser(displayName), emojiMap, true)
|
||||
account.note_emojified = emojify(account.note, emojiMap)
|
||||
account.note_plain = unescapeHTML(account.note)
|
||||
|
||||
if (account.fields) {
|
||||
@@ -27,67 +33,73 @@ export function normalizeAccount(account) {
|
||||
name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
|
||||
value_emojified: emojify(pair.value, emojiMap),
|
||||
value_plain: unescapeHTML(pair.value),
|
||||
}));
|
||||
}))
|
||||
}
|
||||
|
||||
if (account.moved) {
|
||||
account.moved = account.moved.id;
|
||||
account.moved = account.moved.id
|
||||
}
|
||||
|
||||
return account;
|
||||
return account
|
||||
}
|
||||
|
||||
export function normalizeStatus(status, normalOldStatus) {
|
||||
const normalStatus = { ...status };
|
||||
normalStatus.account = status.account_id || status.account.id;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const normalizeStatus = (status, normalOldStatus) => {
|
||||
const normalStatus = { ...status }
|
||||
normalStatus.account = status.account_id || status.account.id
|
||||
|
||||
if (status.reblog && status.reblog.id) {
|
||||
normalStatus.reblog = status.reblog.id;
|
||||
normalStatus.reblog = status.reblog.id
|
||||
}
|
||||
|
||||
if (status.quote && status.quote.id) {
|
||||
normalStatus.quote = status.quote.id;
|
||||
normalStatus.quote = status.quote.id
|
||||
}
|
||||
|
||||
if (status.poll && status.poll.id) {
|
||||
normalStatus.poll = status.poll.id;
|
||||
normalStatus.poll = status.poll.id
|
||||
}
|
||||
|
||||
if (!!status.group || !!status.group_id) {
|
||||
normalStatus.group = status.group_id || status.group.id;
|
||||
normalStatus.group = status.group_id || status.group.id
|
||||
}
|
||||
|
||||
// Only calculate these values when status first encountered
|
||||
// Otherwise keep the ones already in the reducer
|
||||
if (normalOldStatus && normalOldStatus.get('content') === normalStatus.content && normalOldStatus.get('spoiler_text') === normalStatus.spoiler_text) {
|
||||
normalStatus.search_index = normalOldStatus.get('search_index');
|
||||
normalStatus.contentHtml = normalOldStatus.get('contentHtml');
|
||||
normalStatus.spoilerHtml = normalOldStatus.get('spoilerHtml');
|
||||
normalStatus.hidden = normalOldStatus.get('hidden');
|
||||
normalStatus.search_index = normalOldStatus.get('search_index')
|
||||
normalStatus.contentHtml = normalOldStatus.get('contentHtml')
|
||||
normalStatus.spoilerHtml = normalOldStatus.get('spoilerHtml')
|
||||
normalStatus.hidden = normalOldStatus.get('hidden')
|
||||
} else {
|
||||
const spoilerText = normalStatus.spoiler_text || '';
|
||||
const searchContent = [spoilerText, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
|
||||
const emojiMap = makeEmojiMap(normalStatus);
|
||||
const theContent = !!normalStatus.rich_content ? normalStatus.rich_content : normalStatus.content;
|
||||
const spoilerText = normalStatus.spoiler_text || ''
|
||||
const searchContent = [spoilerText, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n')
|
||||
const emojiMap = makeEmojiMap(normalStatus)
|
||||
const theContent = !!normalStatus.rich_content ? normalStatus.rich_content : normalStatus.content
|
||||
|
||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
|
||||
normalStatus.contentHtml = emojify(theContent, emojiMap, false, true);
|
||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
|
||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent
|
||||
normalStatus.contentHtml = emojify(theContent, emojiMap, false, true)
|
||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap)
|
||||
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive
|
||||
}
|
||||
|
||||
return normalStatus;
|
||||
return normalStatus
|
||||
}
|
||||
|
||||
export function normalizePoll(poll) {
|
||||
const normalPoll = { ...poll };
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const normalizePoll = (poll) => {
|
||||
const normalPoll = { ...poll }
|
||||
|
||||
const emojiMap = makeEmojiMap(normalPoll);
|
||||
const emojiMap = makeEmojiMap(normalPoll)
|
||||
|
||||
normalPoll.options = poll.options.map(option => ({
|
||||
normalPoll.options = poll.options.map((option) => ({
|
||||
...option,
|
||||
title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap),
|
||||
}));
|
||||
}))
|
||||
|
||||
return normalPoll;
|
||||
return normalPoll
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import api from '../api'
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer'
|
||||
import api, { getLinks } from '../api'
|
||||
import {
|
||||
importFetchedAccounts,
|
||||
importFetchedStatus,
|
||||
} from './importer'
|
||||
import { fetchRelationships } from './accounts'
|
||||
import { updateStatusStats } from './statuses'
|
||||
import { me } from '../initial_state'
|
||||
|
||||
@@ -23,6 +27,10 @@ export const REPOSTS_FETCH_REQUEST = 'REPOSTS_FETCH_REQUEST'
|
||||
export const REPOSTS_FETCH_SUCCESS = 'REPOSTS_FETCH_SUCCESS'
|
||||
export const REPOSTS_FETCH_FAIL = 'REPOSTS_FETCH_FAIL'
|
||||
|
||||
export const REPOSTS_EXPAND_REQUEST = 'REPOSTS_EXPAND_REQUEST'
|
||||
export const REPOSTS_EXPAND_SUCCESS = 'REPOSTS_EXPAND_SUCCESS'
|
||||
export const REPOSTS_EXPAND_FAIL = 'REPOSTS_EXPAND_FAIL'
|
||||
|
||||
export const PIN_REQUEST = 'PIN_REQUEST'
|
||||
export const PIN_SUCCESS = 'PIN_SUCCESS'
|
||||
export const PIN_FAIL = 'PIN_FAIL'
|
||||
@@ -31,6 +39,10 @@ export const UNPIN_REQUEST = 'UNPIN_REQUEST'
|
||||
export const UNPIN_SUCCESS = 'UNPIN_SUCCESS'
|
||||
export const UNPIN_FAIL = 'UNPIN_FAIL'
|
||||
|
||||
export const IS_PIN_REQUEST = 'IS_PIN_REQUEST'
|
||||
export const IS_PIN_SUCCESS = 'IS_PIN_SUCCESS'
|
||||
export const IS_PIN_FAIL = 'IS_PIN_FAIL'
|
||||
|
||||
export const BOOKMARK_REQUEST = 'BOOKMARK_REQUEST'
|
||||
export const BOOKMARK_SUCCESS = 'BOOKMARK_SUCCESS'
|
||||
export const BOOKMARK_FAIL = 'BOOKMARK_FAIL'
|
||||
@@ -39,342 +51,512 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARK_REQUEST'
|
||||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARK_SUCCESS'
|
||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARK_FAIL'
|
||||
|
||||
export const IS_BOOKMARK_REQUEST = 'IS_BOOKMARK_REQUEST'
|
||||
export const IS_BOOKMARK_SUCCESS = 'IS_BOOKMARK_SUCCESS'
|
||||
export const IS_BOOKMARK_FAIL = 'IS_BOOKMARK_FAIL'
|
||||
|
||||
export const LIKES_FETCH_REQUEST = 'LIKES_FETCH_REQUEST'
|
||||
export const LIKES_FETCH_SUCCESS = 'LIKES_FETCH_SUCCESS'
|
||||
export const LIKES_FETCH_FAIL = 'LIKES_FETCH_FAIL'
|
||||
|
||||
export const LIKES_EXPAND_REQUEST = 'LIKES_EXPAND_REQUEST'
|
||||
export const LIKES_EXPAND_SUCCESS = 'LIKES_EXPAND_SUCCESS'
|
||||
export const LIKES_EXPAND_FAIL = 'LIKES_EXPAND_FAIL'
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Repost the given status. Set status to status.reblogged:true and
|
||||
* increment status.reblogs_count by 1 on success.
|
||||
* @param {ImmutableMap} status
|
||||
*/
|
||||
export const repost = (status) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
if (!me || !status) return
|
||||
|
||||
dispatch(repostRequest(status))
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then((response) => {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
dispatch(importFetchedStatus(response.data.reblog))
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(repostSuccess(status))
|
||||
}).catch((error) => {
|
||||
dispatch(repostFail(status, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const repostRequest = (status) => ({
|
||||
const repostRequest = (status) => ({
|
||||
type: REPOST_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
status,
|
||||
})
|
||||
|
||||
export const repostSuccess = (status) => ({
|
||||
const repostSuccess = (status) => ({
|
||||
type: REPOST_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
status,
|
||||
})
|
||||
|
||||
export const repostFail = (status, error) => ({
|
||||
const repostFail = (status, error) => ({
|
||||
type: REPOST_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
status,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Unrepost the given status. Set status to status.reblogged:false and
|
||||
* decrement status.reblogs_count by 1 on success.
|
||||
* @param {ImmutableMap} status
|
||||
*/
|
||||
export const unrepost = (status) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
if (!me || !status) return
|
||||
|
||||
dispatch(unrepostRequest(status))
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then((response) => {
|
||||
dispatch(importFetchedStatus(response.data))
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(unrepostSuccess(status))
|
||||
}).catch((error) => {
|
||||
dispatch(unrepostFail(status, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const unrepostRequest = (status) => ({
|
||||
const unrepostRequest = (status) => ({
|
||||
type: UNREPOST_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
status,
|
||||
})
|
||||
|
||||
export const unrepostSuccess = (status) => ({
|
||||
const unrepostSuccess = (status) => ({
|
||||
type: UNREPOST_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
status,
|
||||
})
|
||||
|
||||
export const unrepostFail = (status, error) => ({
|
||||
const unrepostFail = (status, error) => ({
|
||||
type: UNREPOST_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
status,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Favorite the given status. Set status to status.favourited:true and
|
||||
* increment status.favourites_count by 1 on success.
|
||||
* @param {ImmutableMap} status
|
||||
*/
|
||||
export const favorite = (status) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
if (!me || !status) return
|
||||
|
||||
dispatch(favoriteRequest(status))
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then((response) => {
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(favoriteSuccess(status))
|
||||
dispatch(favoriteSuccess(response.data))
|
||||
}).catch((error) => {
|
||||
dispatch(favoriteFail(status, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const favoriteRequest = (status) => ({
|
||||
const favoriteRequest = (status) => ({
|
||||
type: FAVORITE_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
status,
|
||||
})
|
||||
|
||||
export const favoriteSuccess = (status) => ({
|
||||
const favoriteSuccess = (data) => ({
|
||||
type: FAVORITE_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
data,
|
||||
})
|
||||
|
||||
export const favoriteFail = (status, error) => ({
|
||||
const favoriteFail = (status, error) => ({
|
||||
type: FAVORITE_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
status,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Unfavorite the given status. Set status to status.favourited:false and
|
||||
* decrement status.favourites_count by 1 on success.
|
||||
* @param {ImmutableMap} status
|
||||
*/
|
||||
export const unfavorite = (status) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
if (!me || !status) return
|
||||
|
||||
dispatch(unfavoriteRequest(status))
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then((response) => {
|
||||
dispatch(importFetchedStatus(response.data))
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(unfavoriteSuccess(status))
|
||||
}).catch((error) => {
|
||||
dispatch(unfavoriteFail(status, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const unfavoriteRequest = (status) => ({
|
||||
const unfavoriteRequest = (status) => ({
|
||||
type: UNFAVORITE_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
status,
|
||||
})
|
||||
|
||||
export const unfavoriteSuccess = (status) => ({
|
||||
const unfavoriteSuccess = (status) => ({
|
||||
type: UNFAVORITE_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
status,
|
||||
})
|
||||
|
||||
export const unfavoriteFail = (status, error) => ({
|
||||
const unfavoriteFail = (status, error) => ({
|
||||
type: UNFAVORITE_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const fetchReposts = (id) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
dispatch(fetchRepostsRequest(id))
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then((response) => {
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(fetchRepostsSuccess(id, response.data))
|
||||
}).catch((error) => {
|
||||
dispatch(fetchRepostsFail(id, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchRepostsRequest = (id) => ({
|
||||
type: REPOSTS_FETCH_REQUEST,
|
||||
id,
|
||||
})
|
||||
|
||||
export const fetchRepostsSuccess = (id, accounts) => ({
|
||||
type: REPOSTS_FETCH_SUCCESS,
|
||||
id,
|
||||
accounts,
|
||||
})
|
||||
|
||||
export const fetchRepostsFail = (id, error) => ({
|
||||
type: REPOSTS_FETCH_FAIL,
|
||||
status,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Pin the given status to your profile. Set status to status.pinned:true
|
||||
* on success.
|
||||
* @param {ImmutableMap} status
|
||||
*/
|
||||
export const pin = (status) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
if (!me || !status) return
|
||||
|
||||
dispatch(pinRequest(status))
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then((response) => {
|
||||
dispatch(importFetchedStatus(response.data))
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(pinSuccess(status))
|
||||
}).catch((error) => {
|
||||
dispatch(pinFail(status, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const pinRequest = (status) => ({
|
||||
const pinRequest = (status) => ({
|
||||
type: PIN_REQUEST,
|
||||
status,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
export const pinSuccess = (status) => ({
|
||||
const pinSuccess = (status) => ({
|
||||
type: PIN_SUCCESS,
|
||||
status,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
export const pinFail = (status, error) => ({
|
||||
const pinFail = (status, error) => ({
|
||||
type: PIN_FAIL,
|
||||
status,
|
||||
error,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Unpin the given status from your profile. Set status to status.pinned:false
|
||||
* on success and remove from account pins in timeline reducer.
|
||||
* @param {ImmutableMap} status
|
||||
*/
|
||||
export const unpin = (status) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
if (!me || !status) return
|
||||
|
||||
dispatch(unpinRequest(status))
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then((response) => {
|
||||
dispatch(importFetchedStatus(response.data))
|
||||
dispatch(unpinSuccess(status))
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(unpinSuccess(status, response.data.account_id))
|
||||
}).catch((error) => {
|
||||
dispatch(unpinFail(status, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const unpinRequest = (status) => ({
|
||||
const unpinRequest = (status) => ({
|
||||
type: UNPIN_REQUEST,
|
||||
status,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
export const unpinSuccess = (status) => ({
|
||||
const unpinSuccess = (status, accountId) => ({
|
||||
type: UNPIN_SUCCESS,
|
||||
accountId,
|
||||
status,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
export const unpinFail = (status, error) => ({
|
||||
const unpinFail = (status, error) => ({
|
||||
type: UNPIN_FAIL,
|
||||
status,
|
||||
error,
|
||||
skipLoading: true,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Check if a status is pinned to the current user account.
|
||||
* @param {String} statusId
|
||||
*/
|
||||
export const fetchLikes = (id) => (dispatch, getState) => {
|
||||
dispatch(fetchLikesRequest(id))
|
||||
export const isPin = (statusId) => (dispatch, getState) => {
|
||||
if (!me || !statusId) return
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then((response) => {
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(fetchLikesSuccess(id, response.data))
|
||||
dispatch(isPinRequest(statusId))
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${statusId}/pin`).then((response) => {
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(isPinSuccess(statusId))
|
||||
}).catch((error) => {
|
||||
dispatch(fetchLikesFail(id, error))
|
||||
dispatch(isPinFail(statusId, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchLikesRequest = (id) => ({
|
||||
type: LIKES_FETCH_REQUEST,
|
||||
id,
|
||||
const isPinRequest = (statusId) => ({
|
||||
type: IS_PIN_REQUEST,
|
||||
statusId,
|
||||
})
|
||||
|
||||
export const fetchLikesSuccess = (id, accounts) => ({
|
||||
type: LIKES_FETCH_SUCCESS,
|
||||
id,
|
||||
accounts,
|
||||
const isPinSuccess = (statusId) => ({
|
||||
type: IS_PIN_SUCCESS,
|
||||
statusId,
|
||||
})
|
||||
|
||||
export const fetchLikesFail = (id, error) => ({
|
||||
type: LIKES_FETCH_FAIL,
|
||||
const isPinFail = (statusId, error) => ({
|
||||
type: IS_PIN_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Bookmark the given status in your profile if PRO. Set status to
|
||||
* status.bookmarked:true on success.
|
||||
* @param {ImmutableMap} status
|
||||
*/
|
||||
export const bookmark = (status) => (dispatch, getState) => {
|
||||
if (!me || !status) return
|
||||
|
||||
dispatch(bookmarkRequest(status))
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then((response) => {
|
||||
dispatch(importFetchedStatus(response.data))
|
||||
dispatch(bookmarkSuccess(status, response.data))
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(bookmarkSuccess(status))
|
||||
}).catch((error) => {
|
||||
dispatch(bookmarkFail(status, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const bookmarkRequest = (status) => ({
|
||||
const bookmarkRequest = (status) => ({
|
||||
type: BOOKMARK_REQUEST,
|
||||
status: status,
|
||||
status,
|
||||
})
|
||||
|
||||
export const bookmarkSuccess = (status, response) => ({
|
||||
const bookmarkSuccess = (status) => ({
|
||||
type: BOOKMARK_SUCCESS,
|
||||
status: status,
|
||||
response: response,
|
||||
status,
|
||||
})
|
||||
|
||||
export const bookmarkFail = (status, error) => ({
|
||||
const bookmarkFail = (status, error) => ({
|
||||
type: BOOKMARK_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
status,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Unbookmark the given status in your profile if PRO. Set status to
|
||||
* status.bookmarked:false on success.
|
||||
* @param {ImmutableMap} status
|
||||
*/
|
||||
export const unbookmark = (status) => (dispatch, getState) => {
|
||||
if (!me || !status) return
|
||||
|
||||
dispatch(unbookmarkRequest(status))
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then((response) => {
|
||||
dispatch(importFetchedStatus(response.data))
|
||||
dispatch(unbookmarkSuccess(status, response.data))
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(unbookmarkSuccess(status))
|
||||
}).catch((error) => {
|
||||
dispatch(unbookmarkFail(status, error))
|
||||
})
|
||||
}
|
||||
|
||||
export const unbookmarkRequest = (status) => ({
|
||||
const unbookmarkRequest = (status) => ({
|
||||
type: UNBOOKMARK_REQUEST,
|
||||
status: status,
|
||||
status,
|
||||
})
|
||||
|
||||
export const unbookmarkSuccess = (status, response) => ({
|
||||
const unbookmarkSuccess = (status) => ({
|
||||
type: UNBOOKMARK_SUCCESS,
|
||||
status: status,
|
||||
response: response,
|
||||
status,
|
||||
})
|
||||
|
||||
export const unbookmarkFail = (status, error) => ({
|
||||
const unbookmarkFail = (status, error) => ({
|
||||
type: UNBOOKMARK_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
})
|
||||
status,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
* @description Check if a status is bookmarked to the current user account.
|
||||
* @param {String} statusId
|
||||
*/
|
||||
export const isBookmark = (statusId) => (dispatch, getState) => {
|
||||
if (!me || !statusId) return
|
||||
|
||||
dispatch(isBookmarkRequest(statusId))
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${statusId}/bookmark`).then((response) => {
|
||||
dispatch(updateStatusStats(response.data))
|
||||
dispatch(isBookmarkSuccess(statusId))
|
||||
}).catch((error) => {
|
||||
dispatch(isBookmarkFail(statusId, error))
|
||||
})
|
||||
}
|
||||
|
||||
const isBookmarkRequest = (statusId) => ({
|
||||
type: IS_BOOKMARK_REQUEST,
|
||||
statusId,
|
||||
})
|
||||
|
||||
const isBookmarkSuccess = (statusId) => ({
|
||||
type: IS_BOOKMARK_SUCCESS,
|
||||
statusId,
|
||||
})
|
||||
|
||||
const isBookmarkFail = (statusId, error) => ({
|
||||
type: IS_BOOKMARK_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
* @description Fetch reposts for the given statusId and imports paginated accounts
|
||||
* and sets in user_lists reducer.
|
||||
* @param {String} statusId
|
||||
*/
|
||||
export const fetchReposts = (statusId) => (dispatch, getState) => {
|
||||
if (!me || !statusId) return
|
||||
|
||||
dispatch(fetchRepostsRequest(statusId))
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${statusId}/reblogged_by`).then((response) => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(fetchRepostsSuccess(statusId, response.data, next ? next.uri : null))
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)))
|
||||
}).catch((error) => {
|
||||
dispatch(fetchRepostsFail(statusId, error))
|
||||
})
|
||||
}
|
||||
|
||||
const fetchRepostsRequest = (statusId) => ({
|
||||
type: REPOSTS_FETCH_REQUEST,
|
||||
statusId,
|
||||
})
|
||||
|
||||
const fetchRepostsSuccess = (statusId, accounts, next) => ({
|
||||
type: REPOSTS_FETCH_SUCCESS,
|
||||
statusId,
|
||||
accounts,
|
||||
next,
|
||||
})
|
||||
|
||||
const fetchRepostsFail = (statusId, error) => ({
|
||||
type: REPOSTS_FETCH_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
* @description Expand reposts for the given statusId and imports paginated accounts
|
||||
* and sets in user_lists reducer.
|
||||
* @param {String} statusId
|
||||
*/
|
||||
export const expandReposts = (statusId) => (dispatch, getState) => {
|
||||
if (!me || !statusId) return
|
||||
|
||||
const url = getState().getIn(['user_lists', 'reblogged_by', statusId, 'next'])
|
||||
const isLoading = getState().getIn(['user_lists', 'reblogged_by', statusId, 'isLoading'])
|
||||
|
||||
if (url === null || isLoading) return
|
||||
|
||||
dispatch(expandRepostsRequest(statusId))
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(expandRepostsSuccess(statusId, response.data, next ? next.uri : null))
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)))
|
||||
}).catch(error => dispatch(expandRepostsFail(error)))
|
||||
}
|
||||
|
||||
const expandRepostsRequest = (statusId) => ({
|
||||
type: REPOSTS_EXPAND_REQUEST,
|
||||
statusId,
|
||||
})
|
||||
|
||||
const expandRepostsSuccess = (statusId, accounts, next) => ({
|
||||
type: REPOSTS_EXPAND_SUCCESS,
|
||||
statusId,
|
||||
accounts,
|
||||
next,
|
||||
})
|
||||
|
||||
const expandRepostsFail = (statusId, error) => ({
|
||||
type: REPOSTS_EXPAND_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @description Fetch likes for the given statusId and imports paginated accounts
|
||||
* and sets in user_lists reducer.
|
||||
* @param {String} statusId
|
||||
*/
|
||||
export const fetchLikes = (statusId) => (dispatch, getState) => {
|
||||
if (!me || !statusId) return
|
||||
|
||||
dispatch(fetchLikesRequest(statusId))
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${statusId}/favourited_by`).then((response) => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(fetchLikesSuccess(statusId, response.data, next ? next.uri : null))
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)))
|
||||
}).catch((error) => {
|
||||
dispatch(fetchLikesFail(statusId, error))
|
||||
})
|
||||
}
|
||||
|
||||
const fetchLikesRequest = (statusId) => ({
|
||||
type: LIKES_FETCH_REQUEST,
|
||||
statusId,
|
||||
})
|
||||
|
||||
const fetchLikesSuccess = (statusId, accounts, next) => ({
|
||||
type: LIKES_FETCH_SUCCESS,
|
||||
statusId,
|
||||
accounts,
|
||||
next,
|
||||
})
|
||||
|
||||
const fetchLikesFail = (statusId, error) => ({
|
||||
type: LIKES_FETCH_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
* @description Expand likes for the given statusId and imports paginated accounts
|
||||
* and sets in user_lists reducer.
|
||||
* @param {String} statusId
|
||||
*/
|
||||
export const expandLikes = (statusId) => (dispatch, getState) => {
|
||||
if (!me || !statusId) return
|
||||
|
||||
const url = getState().getIn(['user_lists', 'liked_by', statusId, 'next'])
|
||||
const isLoading = getState().getIn(['user_lists', 'liked_by', statusId, 'isLoading'])
|
||||
|
||||
if (url === null || isLoading) return
|
||||
|
||||
dispatch(expandLikesRequest(statusId))
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next')
|
||||
dispatch(importFetchedAccounts(response.data))
|
||||
dispatch(expandLikesSuccess(statusId, response.data, next ? next.uri : null))
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)))
|
||||
}).catch(error => dispatch(expandLikesFail(error)))
|
||||
}
|
||||
|
||||
const expandLikesRequest = (statusId) => ({
|
||||
type: LIKES_EXPAND_REQUEST,
|
||||
statusId,
|
||||
})
|
||||
|
||||
const expandLikesSuccess = (statusId, accounts, next) => ({
|
||||
type: LIKES_EXPAND_SUCCESS,
|
||||
statusId,
|
||||
accounts,
|
||||
next,
|
||||
})
|
||||
|
||||
const expandLikesFail = (statusId, error) => ({
|
||||
type: LIKES_EXPAND_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import api, { getLinks } from '../api'
|
||||
import IntlMessageFormat from 'intl-messageformat'
|
||||
import noop from 'lodash.noop'
|
||||
import { fetchRelationships } from './accounts'
|
||||
import {
|
||||
importFetchedAccount,
|
||||
@@ -49,8 +50,6 @@ const excludeTypesFromFilter = filter => {
|
||||
return allTypes.filterNot(item => item === filter).toJS()
|
||||
}
|
||||
|
||||
const noOp = () => {}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -159,7 +158,7 @@ export const dequeueNotifications = () => (dispatch, getState) => {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandNotifications = ({ maxId } = {}, done = noOp) => (dispatch, getState) => {
|
||||
export const expandNotifications = ({ maxId } = {}, done = noop) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
const onlyVerified = getState().getIn(['notifications', 'filter', 'onlyVerified'])
|
||||
@@ -204,19 +203,19 @@ export const expandNotifications = ({ maxId } = {}, done = noOp) => (dispatch, g
|
||||
})
|
||||
}
|
||||
|
||||
export const expandNotificationsRequest = (isLoadingMore) => ({
|
||||
const expandNotificationsRequest = (isLoadingMore) => ({
|
||||
type: NOTIFICATIONS_EXPAND_REQUEST,
|
||||
skipLoading: !isLoadingMore,
|
||||
})
|
||||
|
||||
export const expandNotificationsSuccess = (notifications, next, isLoadingMore) => ({
|
||||
const expandNotificationsSuccess = (notifications, next, isLoadingMore) => ({
|
||||
type: NOTIFICATIONS_EXPAND_SUCCESS,
|
||||
notifications,
|
||||
next,
|
||||
skipLoading: !isLoadingMore,
|
||||
})
|
||||
|
||||
export const expandNotificationsFail = (error, isLoadingMore) => ({
|
||||
const expandNotificationsFail = (error, isLoadingMore) => ({
|
||||
type: NOTIFICATIONS_EXPAND_FAIL,
|
||||
error,
|
||||
skipLoading: !isLoadingMore,
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import api from '../api'
|
||||
|
||||
export const STATUS_REVISIONS_LOAD = 'STATUS_REVISIONS_LOAD'
|
||||
export const STATUS_REVISIONS_LOAD_REQUEST = 'STATUS_REVISIONS_LOAD_REQUEST'
|
||||
export const STATUS_REVISIONS_LOAD_SUCCESS = 'STATUS_REVISIONS_SUCCESS'
|
||||
export const STATUS_REVISIONS_LOAD_FAIL = 'STATUS_REVISIONS_FAIL'
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const loadStatusRevisions = (statusId) => (dispatch, getState) => {
|
||||
dispatch(loadStatusRevisionsRequest())
|
||||
api(getState).get(`/api/v1/statuses/${statusId}/revisions`)
|
||||
.then(res => dispatch(loadStatusRevisionsSuccess(res.data)))
|
||||
.catch(() => dispatch(loadStatusRevisionsFail()))
|
||||
}
|
||||
|
||||
const loadStatusRevisionsRequest = () => ({
|
||||
type: STATUS_REVISIONS_LOAD_REQUEST,
|
||||
})
|
||||
|
||||
const loadStatusRevisionsSuccess = (data) => ({
|
||||
type: STATUS_REVISIONS_LOAD_SUCCESS,
|
||||
revisions: data,
|
||||
|
||||
@@ -1,304 +1,292 @@
|
||||
import api from '../api';
|
||||
import openDB from '../storage/db';
|
||||
import { evictStatus } from '../storage/modifier';
|
||||
import { deleteFromTimelines } from './timelines';
|
||||
import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer';
|
||||
import { openModal } from './modal';
|
||||
import { me } from '../initial_state';
|
||||
import api from '../api'
|
||||
import openDB from '../storage/db'
|
||||
import { evictStatus } from '../storage/modifier'
|
||||
import { deleteFromTimelines } from './timelines'
|
||||
import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer'
|
||||
import { openModal } from './modal'
|
||||
import { me } from '../initial_state'
|
||||
|
||||
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
|
||||
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS';
|
||||
export const STATUS_FETCH_FAIL = 'STATUS_FETCH_FAIL';
|
||||
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'
|
||||
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'
|
||||
export const STATUS_FETCH_FAIL = 'STATUS_FETCH_FAIL'
|
||||
|
||||
export const STATUS_DELETE_REQUEST = 'STATUS_DELETE_REQUEST';
|
||||
export const STATUS_DELETE_SUCCESS = 'STATUS_DELETE_SUCCESS';
|
||||
export const STATUS_DELETE_FAIL = 'STATUS_DELETE_FAIL';
|
||||
export const STATUS_DELETE_REQUEST = 'STATUS_DELETE_REQUEST'
|
||||
export const STATUS_DELETE_SUCCESS = 'STATUS_DELETE_SUCCESS'
|
||||
export const STATUS_DELETE_FAIL = 'STATUS_DELETE_FAIL'
|
||||
|
||||
export const CONTEXT_FETCH_REQUEST = 'CONTEXT_FETCH_REQUEST';
|
||||
export const CONTEXT_FETCH_SUCCESS = 'CONTEXT_FETCH_SUCCESS';
|
||||
export const CONTEXT_FETCH_FAIL = 'CONTEXT_FETCH_FAIL';
|
||||
export const CONTEXT_FETCH_REQUEST = 'CONTEXT_FETCH_REQUEST'
|
||||
export const CONTEXT_FETCH_SUCCESS = 'CONTEXT_FETCH_SUCCESS'
|
||||
export const CONTEXT_FETCH_FAIL = 'CONTEXT_FETCH_FAIL'
|
||||
|
||||
export const COMMENTS_FETCH_REQUEST = 'COMMENTS_FETCH_REQUEST';
|
||||
export const COMMENTS_FETCH_SUCCESS = 'COMMENTS_FETCH_SUCCESS';
|
||||
export const COMMENTS_FETCH_FAIL = 'COMMENTS_FETCH_FAIL';
|
||||
export const COMMENTS_FETCH_REQUEST = 'COMMENTS_FETCH_REQUEST'
|
||||
export const COMMENTS_FETCH_SUCCESS = 'COMMENTS_FETCH_SUCCESS'
|
||||
export const COMMENTS_FETCH_FAIL = 'COMMENTS_FETCH_FAIL'
|
||||
|
||||
export const STATUS_REVEAL = 'STATUS_REVEAL';
|
||||
export const STATUS_HIDE = 'STATUS_HIDE';
|
||||
export const STATUS_REVEAL = 'STATUS_REVEAL'
|
||||
export const STATUS_HIDE = 'STATUS_HIDE'
|
||||
|
||||
export const STATUS_EDIT = 'STATUS_EDIT';
|
||||
export const STATUS_EDIT = 'STATUS_EDIT'
|
||||
|
||||
export const UPDATE_STATUS_STATS = 'UPDATE_STATUS_STATS'
|
||||
|
||||
export function fetchStatusRequest(id, skipLoading) {
|
||||
return {
|
||||
type: STATUS_FETCH_REQUEST,
|
||||
id,
|
||||
skipLoading,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function getFromDB(dispatch, getState, accountIndex, index, id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = index.get(id);
|
||||
const request = index.get(id)
|
||||
|
||||
request.onerror = reject;
|
||||
request.onerror = reject
|
||||
|
||||
request.onsuccess = () => {
|
||||
const promises = [];
|
||||
const promises = []
|
||||
|
||||
if (!request.result) {
|
||||
reject();
|
||||
return;
|
||||
reject()
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(importStatus(request.result));
|
||||
dispatch(importStatus(request.result))
|
||||
|
||||
if (getState().getIn(['accounts', request.result.account], null) === null) {
|
||||
promises.push(new Promise((accountResolve, accountReject) => {
|
||||
const accountRequest = accountIndex.get(request.result.account);
|
||||
const accountRequest = accountIndex.get(request.result.account)
|
||||
|
||||
accountRequest.onerror = accountReject;
|
||||
accountRequest.onerror = accountReject
|
||||
accountRequest.onsuccess = () => {
|
||||
if (!request.result) {
|
||||
accountReject();
|
||||
return;
|
||||
accountReject()
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(importAccount(accountRequest.result));
|
||||
accountResolve();
|
||||
};
|
||||
}));
|
||||
dispatch(importAccount(accountRequest.result))
|
||||
accountResolve()
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
if (request.result.reblog && getState().getIn(['statuses', request.result.reblog], null) === null) {
|
||||
promises.push(getFromDB(dispatch, getState, accountIndex, index, request.result.reblog));
|
||||
promises.push(getFromDB(dispatch, getState, accountIndex, index, request.result.reblog))
|
||||
}
|
||||
|
||||
resolve(Promise.all(promises));
|
||||
};
|
||||
});
|
||||
resolve(Promise.all(promises))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchStatus(id) {
|
||||
return (dispatch, getState) => {
|
||||
const skipLoading = getState().getIn(['statuses', id], null) !== null;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const fetchStatus = (id) => (dispatch, getState) => {
|
||||
const skipLoading = getState().getIn(['statuses', id], null) !== null
|
||||
if (skipLoading) return
|
||||
|
||||
if (skipLoading) {
|
||||
return;
|
||||
dispatch(fetchStatusRequest(id, skipLoading))
|
||||
|
||||
openDB().then((db) => {
|
||||
const transaction = db.transaction(['accounts', 'statuses'], 'read')
|
||||
const accountIndex = transaction.objectStore('accounts').index('id')
|
||||
const index = transaction.objectStore('statuses').index('id')
|
||||
|
||||
return getFromDB(dispatch, getState, accountIndex, index, id).then(() => {
|
||||
db.close()
|
||||
}, (error) => {
|
||||
db.close()
|
||||
throw error
|
||||
})
|
||||
}).then(() => {
|
||||
dispatch(fetchStatusSuccess(skipLoading))
|
||||
}, () => api(getState).get(`/api/v1/statuses/${id}`).then((response) => {
|
||||
dispatch(importFetchedStatus(response.data))
|
||||
dispatch(fetchStatusSuccess(skipLoading))
|
||||
})).catch((error) => {
|
||||
dispatch(fetchStatusFail(id, error, skipLoading))
|
||||
})
|
||||
}
|
||||
|
||||
const fetchStatusRequest = (id, skipLoading) => ({
|
||||
type: STATUS_FETCH_REQUEST,
|
||||
id,
|
||||
skipLoading,
|
||||
})
|
||||
|
||||
const fetchStatusSuccess = (skipLoading) => ({
|
||||
type: STATUS_FETCH_SUCCESS,
|
||||
skipLoading,
|
||||
})
|
||||
|
||||
const fetchStatusFail = (id, error, skipLoading) => ({
|
||||
type: STATUS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
skipLoading,
|
||||
skipAlert: true,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const editStatus = (status) => (dispatch) => {
|
||||
dispatch({
|
||||
type: STATUS_EDIT,
|
||||
status,
|
||||
})
|
||||
|
||||
dispatch(openModal('COMPOSE'))
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const deleteStatus = (id, routerHistory) => (dispatch, getState) => {
|
||||
if (!me) return
|
||||
|
||||
let status = getState().getIn(['statuses', id])
|
||||
|
||||
if (status.get('poll')) {
|
||||
status = status.set('poll', getState().getIn(['polls', status.get('poll')]))
|
||||
}
|
||||
|
||||
dispatch(deleteStatusRequest(id))
|
||||
|
||||
api(getState).delete(`/api/v1/statuses/${id}`).then((response) => {
|
||||
evictStatus(id)
|
||||
dispatch(deleteStatusSuccess(id))
|
||||
dispatch(deleteFromTimelines(id))
|
||||
}).catch((error) => {
|
||||
dispatch(deleteStatusFail(id, error))
|
||||
})
|
||||
}
|
||||
|
||||
const deleteStatusRequest = (id) => ({
|
||||
type: STATUS_DELETE_REQUEST,
|
||||
id: id,
|
||||
})
|
||||
|
||||
const deleteStatusSuccess = (id) => ({
|
||||
type: STATUS_DELETE_SUCCESS,
|
||||
id: id,
|
||||
})
|
||||
|
||||
const deleteStatusFail = (id, error) => ({
|
||||
type: STATUS_DELETE_FAIL,
|
||||
id: id,
|
||||
error,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const fetchContext = (id, ensureIsReply) => (dispatch, getState) => {
|
||||
if (ensureIsReply) {
|
||||
const isReply = !!getState().getIn(['statuses', id, 'in_reply_to_id'], null)
|
||||
if (!isReply) return
|
||||
}
|
||||
|
||||
dispatch(fetchContextRequest(id))
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/context`).then((response) => {
|
||||
dispatch(importFetchedStatuses(response.data.ancestors.concat(response.data.descendants)))
|
||||
dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants))
|
||||
}).catch((error) => {
|
||||
if (error.response && error.response.status === 404) {
|
||||
dispatch(deleteFromTimelines(id))
|
||||
}
|
||||
dispatch(fetchContextFail(id, error))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const fetchContextRequest = (id) => ({
|
||||
type: CONTEXT_FETCH_REQUEST,
|
||||
id,
|
||||
})
|
||||
|
||||
const fetchContextSuccess = (id, ancestors, descendants) => ({
|
||||
type: CONTEXT_FETCH_SUCCESS,
|
||||
id,
|
||||
ancestors,
|
||||
descendants,
|
||||
statuses: ancestors.concat(descendants),
|
||||
})
|
||||
|
||||
const fetchContextFail = (id, error) => ({
|
||||
type: CONTEXT_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
skipAlert: true,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const fetchComments = (id) => (dispatch, getState) => {
|
||||
dispatch(fetchCommentsRequest(id))
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/comments`).then((response) => {
|
||||
dispatch(importFetchedStatuses(response.data.descendants))
|
||||
dispatch(fetchCommentsSuccess(id, response.data.descendants))
|
||||
}).catch((error) => {
|
||||
if (error.response && error.response.status === 404) {
|
||||
dispatch(deleteFromTimelines(id))
|
||||
}
|
||||
|
||||
dispatch(fetchStatusRequest(id, skipLoading));
|
||||
dispatch(fetchCommentsFail(id, error))
|
||||
})
|
||||
}
|
||||
|
||||
openDB().then(db => {
|
||||
const transaction = db.transaction(['accounts', 'statuses'], 'read');
|
||||
const accountIndex = transaction.objectStore('accounts').index('id');
|
||||
const index = transaction.objectStore('statuses').index('id');
|
||||
const fetchCommentsRequest = (id) => ({
|
||||
type: COMMENTS_FETCH_REQUEST,
|
||||
id,
|
||||
})
|
||||
|
||||
return getFromDB(dispatch, getState, accountIndex, index, id).then(() => {
|
||||
db.close();
|
||||
}, error => {
|
||||
db.close();
|
||||
throw error;
|
||||
});
|
||||
}).then(() => {
|
||||
dispatch(fetchStatusSuccess(skipLoading));
|
||||
}, () => api(getState).get(`/api/v1/statuses/${id}`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(fetchStatusSuccess(skipLoading));
|
||||
})).catch(error => {
|
||||
dispatch(fetchStatusFail(id, error, skipLoading));
|
||||
});
|
||||
};
|
||||
};
|
||||
const fetchCommentsSuccess = (id, descendants) => ({
|
||||
type: COMMENTS_FETCH_SUCCESS,
|
||||
id,
|
||||
descendants,
|
||||
})
|
||||
|
||||
export function fetchStatusSuccess(skipLoading) {
|
||||
return {
|
||||
type: STATUS_FETCH_SUCCESS,
|
||||
skipLoading,
|
||||
};
|
||||
};
|
||||
const fetchCommentsFail = (id, error) => ({
|
||||
type: COMMENTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
skipAlert: true,
|
||||
})
|
||||
|
||||
export function fetchStatusFail(id, error, skipLoading) {
|
||||
return {
|
||||
type: STATUS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
skipLoading,
|
||||
skipAlert: true,
|
||||
};
|
||||
};
|
||||
|
||||
export function editStatus(status) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: STATUS_EDIT,
|
||||
status,
|
||||
});
|
||||
|
||||
dispatch(openModal('COMPOSE'));
|
||||
};
|
||||
};
|
||||
|
||||
export function deleteStatus(id, routerHistory) {
|
||||
return (dispatch, getState) => {
|
||||
if (!me) return;
|
||||
|
||||
let status = getState().getIn(['statuses', id]);
|
||||
|
||||
if (status.get('poll')) {
|
||||
status = status.set('poll', getState().getIn(['polls', status.get('poll')]));
|
||||
}
|
||||
|
||||
dispatch(deleteStatusRequest(id));
|
||||
|
||||
api(getState).delete(`/api/v1/statuses/${id}`).then(response => {
|
||||
evictStatus(id);
|
||||
dispatch(deleteStatusSuccess(id));
|
||||
dispatch(deleteFromTimelines(id));
|
||||
}).catch(error => {
|
||||
dispatch(deleteStatusFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function deleteStatusRequest(id) {
|
||||
return {
|
||||
type: STATUS_DELETE_REQUEST,
|
||||
id: id,
|
||||
};
|
||||
};
|
||||
|
||||
export function deleteStatusSuccess(id) {
|
||||
return {
|
||||
type: STATUS_DELETE_SUCCESS,
|
||||
id: id,
|
||||
};
|
||||
};
|
||||
|
||||
export function deleteStatusFail(id, error) {
|
||||
return {
|
||||
type: STATUS_DELETE_FAIL,
|
||||
id: id,
|
||||
error: error,
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchContext(id, ensureIsReply) {
|
||||
return (dispatch, getState) => {
|
||||
if (ensureIsReply) {
|
||||
const isReply = !!getState().getIn(['statuses', id, 'in_reply_to_id'], null)
|
||||
if (!isReply) return;
|
||||
}
|
||||
|
||||
dispatch(fetchContextRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/context`).then(response => {
|
||||
dispatch(importFetchedStatuses(response.data.ancestors.concat(response.data.descendants)));
|
||||
dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants));
|
||||
|
||||
}).catch(error => {
|
||||
if (error.response && error.response.status === 404) {
|
||||
dispatch(deleteFromTimelines(id));
|
||||
}
|
||||
|
||||
dispatch(fetchContextFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchComments(id) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchCommentsRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/comments`).then(response => {
|
||||
dispatch(importFetchedStatuses(response.data.descendants));
|
||||
dispatch(fetchCommentsSuccess(id, response.data.descendants));
|
||||
|
||||
}).catch(error => {
|
||||
if (error.response && error.response.status === 404) {
|
||||
dispatch(deleteFromTimelines(id));
|
||||
}
|
||||
|
||||
dispatch(fetchCommentsFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchContextRequest(id) {
|
||||
return {
|
||||
type: CONTEXT_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchContextSuccess(id, ancestors, descendants) {
|
||||
return {
|
||||
type: CONTEXT_FETCH_SUCCESS,
|
||||
id,
|
||||
ancestors,
|
||||
descendants,
|
||||
statuses: ancestors.concat(descendants),
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchContextFail(id, error) {
|
||||
return {
|
||||
type: CONTEXT_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
skipAlert: true,
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchCommentsRequest(id) {
|
||||
return {
|
||||
type: COMMENTS_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchCommentsSuccess(id, descendants) {
|
||||
return {
|
||||
type: COMMENTS_FETCH_SUCCESS,
|
||||
id,
|
||||
descendants,
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchCommentsFail(id, error) {
|
||||
return {
|
||||
type: COMMENTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
skipAlert: true,
|
||||
};
|
||||
};
|
||||
|
||||
export function hideStatus(ids) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const hideStatus = (ids) => {
|
||||
if (!Array.isArray(ids)) {
|
||||
ids = [ids];
|
||||
ids = [ids]
|
||||
}
|
||||
|
||||
return {
|
||||
type: STATUS_HIDE,
|
||||
ids,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function revealStatus(ids) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const revealStatus = (ids) => {
|
||||
if (!Array.isArray(ids)) {
|
||||
ids = [ids];
|
||||
ids = [ids]
|
||||
}
|
||||
|
||||
return {
|
||||
type: STATUS_REVEAL,
|
||||
ids,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function updateStatusStats(data) {
|
||||
return {
|
||||
type: UPDATE_STATUS_STATS,
|
||||
data,
|
||||
};
|
||||
};
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const updateStatusStats = (data) => ({
|
||||
type: UPDATE_STATUS_STATS,
|
||||
data,
|
||||
})
|
||||
@@ -71,3 +71,20 @@ export const connectStatusUpdateStream = () => {
|
||||
*
|
||||
*/
|
||||
export const connectUserStream = () => connectTimelineStream('home', 'user')
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const connectMessageStream = () => {
|
||||
|
||||
return connectStream('chat_messages', null, (dispatch, getState) => {
|
||||
|
||||
return {
|
||||
onConnect() {},
|
||||
onDisconnect() {},
|
||||
onReceive (data) {
|
||||
//
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -44,20 +44,17 @@ const fetchSuggestions = (suggestionType, dispatch, getState, unlimited = false)
|
||||
|
||||
const fetchSuggestionsRequest = (suggestionType) => ({
|
||||
type: SUGGESTIONS_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
suggestionType,
|
||||
})
|
||||
|
||||
const fetchSuggestionsSuccess = (accounts, suggestionType) => ({
|
||||
type: SUGGESTIONS_FETCH_SUCCESS,
|
||||
skipLoading: true,
|
||||
accounts,
|
||||
suggestionType
|
||||
})
|
||||
|
||||
const fetchSuggestionsFail = (error, suggestionType) => ({
|
||||
type: SUGGESTIONS_FETCH_FAIL,
|
||||
skipLoading: true,
|
||||
skipAlert: true,
|
||||
error,
|
||||
suggestionType,
|
||||
|
||||
@@ -1,133 +1,139 @@
|
||||
import { Map as ImmutableMap, List as ImmutableList, toJS } from 'immutable';
|
||||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||
import api, { getLinks } from '../api';
|
||||
import { Map as ImmutableMap, List as ImmutableList, toJS } from 'immutable'
|
||||
import noop from 'lodash.noop'
|
||||
import { importFetchedStatus, importFetchedStatuses } from './importer'
|
||||
import api, { getLinks } from '../api'
|
||||
import { fetchRelationships } from './accounts'
|
||||
|
||||
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
|
||||
export const TIMELINE_DELETE = 'TIMELINE_DELETE';
|
||||
export const TIMELINE_CLEAR = 'TIMELINE_CLEAR';
|
||||
export const TIMELINE_UPDATE_QUEUE = 'TIMELINE_UPDATE_QUEUE';
|
||||
export const TIMELINE_DEQUEUE = 'TIMELINE_DEQUEUE';
|
||||
export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';
|
||||
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE'
|
||||
export const TIMELINE_DELETE = 'TIMELINE_DELETE'
|
||||
export const TIMELINE_CLEAR = 'TIMELINE_CLEAR'
|
||||
export const TIMELINE_UPDATE_QUEUE = 'TIMELINE_UPDATE_QUEUE'
|
||||
export const TIMELINE_DEQUEUE = 'TIMELINE_DEQUEUE'
|
||||
export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP'
|
||||
|
||||
export const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST';
|
||||
export const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS';
|
||||
export const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL';
|
||||
export const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST'
|
||||
export const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS'
|
||||
export const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL'
|
||||
|
||||
export const TIMELINE_CONNECT = 'TIMELINE_CONNECT';
|
||||
export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
|
||||
export const TIMELINE_CONNECT = 'TIMELINE_CONNECT'
|
||||
export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'
|
||||
|
||||
export const MAX_QUEUED_ITEMS = 40;
|
||||
|
||||
export function updateTimeline(timeline, status, accept) {
|
||||
return dispatch => {
|
||||
if (typeof accept === 'function' && !accept(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(importFetchedStatus(status));
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_UPDATE,
|
||||
timeline,
|
||||
status,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function updateTimelineQueue(timeline, status, accept) {
|
||||
return dispatch => {
|
||||
if (typeof accept === 'function' && !accept(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_UPDATE_QUEUE,
|
||||
timeline,
|
||||
status,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function forceDequeueTimeline(timeline) {
|
||||
return (dispatch) => {
|
||||
dispatch({
|
||||
type: TIMELINE_DEQUEUE,
|
||||
timeline,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function dequeueTimeline(timeline, expandFunc, optionalExpandArgs) {
|
||||
return (dispatch, getState) => {
|
||||
const queuedItems = getState().getIn(['timelines', timeline, 'queuedItems'], ImmutableList());
|
||||
const totalQueuedItemsCount = getState().getIn(['timelines', timeline, 'totalQueuedItemsCount'], 0);
|
||||
|
||||
let shouldDispatchDequeue = true;
|
||||
|
||||
if (totalQueuedItemsCount === 0) {
|
||||
return;
|
||||
} else if (totalQueuedItemsCount > 0 && totalQueuedItemsCount <= MAX_QUEUED_ITEMS) {
|
||||
queuedItems.forEach(status => {
|
||||
dispatch(updateTimeline(timeline, status.toJS(), null));
|
||||
});
|
||||
} else {
|
||||
if (typeof expandFunc === 'function') {
|
||||
dispatch(clearTimeline(timeline));
|
||||
expandFunc();
|
||||
} else {
|
||||
if (timeline === 'home') {
|
||||
dispatch(clearTimeline(timeline));
|
||||
dispatch(expandHomeTimeline(optionalExpandArgs));
|
||||
} else if (timeline === 'community') {
|
||||
dispatch(clearTimeline(timeline));
|
||||
dispatch(expandCommunityTimeline(optionalExpandArgs));
|
||||
} else {
|
||||
shouldDispatchDequeue = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldDispatchDequeue) return;
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_DEQUEUE,
|
||||
timeline,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function deleteFromTimelines(id) {
|
||||
return (dispatch, getState) => {
|
||||
const accountId = getState().getIn(['statuses', id, 'account']);
|
||||
const references = getState().get('statuses').filter(status => status.get('reblog') === id).map(status => [status.get('id'), status.get('account')]);
|
||||
const reblogOf = getState().getIn(['statuses', id, 'reblog'], null);
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_DELETE,
|
||||
id,
|
||||
accountId,
|
||||
references,
|
||||
reblogOf,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function clearTimeline(timeline) {
|
||||
return (dispatch) => {
|
||||
dispatch({ type: TIMELINE_CLEAR, timeline });
|
||||
};
|
||||
};
|
||||
|
||||
const noOp = () => { };
|
||||
export const MAX_QUEUED_ITEMS = 40
|
||||
|
||||
const parseTags = (tags = {}, mode) => {
|
||||
return (tags[mode] || []).map((tag) => {
|
||||
return tag.value;
|
||||
});
|
||||
};
|
||||
return (tags[mode] || []).map((tag) => tag.value)
|
||||
}
|
||||
|
||||
export const expandTimeline = (timelineId, path, params = {}, done = noOp) => (dispatch, getState) => {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const updateTimeline = (timeline, status, accept) => (dispatch) => {
|
||||
if (typeof accept === 'function' && !accept(status)) return
|
||||
|
||||
dispatch(importFetchedStatus(status))
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_UPDATE,
|
||||
timeline,
|
||||
status,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const updateTimelineQueue = (timeline, status, accept) => (dispatch) => {
|
||||
if (typeof accept === 'function' && !accept(status)) return
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_UPDATE_QUEUE,
|
||||
timeline,
|
||||
status,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const forceDequeueTimeline = (timeline) => (dispatch) => {
|
||||
dispatch({
|
||||
type: TIMELINE_DEQUEUE,
|
||||
timeline,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const dequeueTimeline = (timeline, expandFunc, optionalExpandArgs) => (dispatch, getState) => {
|
||||
const queuedItems = getState().getIn(['timelines', timeline, 'queuedItems'], ImmutableList())
|
||||
const totalQueuedItemsCount = getState().getIn(['timelines', timeline, 'totalQueuedItemsCount'], 0)
|
||||
|
||||
let shouldDispatchDequeue = true
|
||||
|
||||
if (totalQueuedItemsCount === 0) return
|
||||
|
||||
|
||||
if (totalQueuedItemsCount > 0 && totalQueuedItemsCount <= MAX_QUEUED_ITEMS) {
|
||||
queuedItems.forEach((status) => {
|
||||
dispatch(updateTimeline(timeline, status.toJS(), null))
|
||||
})
|
||||
} else {
|
||||
if (typeof expandFunc === 'function') {
|
||||
dispatch(clearTimeline(timeline))
|
||||
expandFunc()
|
||||
} else {
|
||||
if (timeline === 'home') {
|
||||
dispatch(clearTimeline(timeline))
|
||||
dispatch(expandHomeTimeline(optionalExpandArgs))
|
||||
} else if (timeline === 'community') {
|
||||
dispatch(clearTimeline(timeline))
|
||||
dispatch(expandCommunityTimeline(optionalExpandArgs))
|
||||
} else {
|
||||
shouldDispatchDequeue = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldDispatchDequeue) return
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_DEQUEUE,
|
||||
timeline,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const deleteFromTimelines = (id) => (dispatch, getState) => {
|
||||
const accountId = getState().getIn(['statuses', id, 'account'])
|
||||
const references = getState().get('statuses').filter(status => status.get('reblog') === id).map(status => [status.get('id'), status.get('account')])
|
||||
const reblogOf = getState().getIn(['statuses', id, 'reblog'], null)
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_DELETE,
|
||||
id,
|
||||
accountId,
|
||||
references,
|
||||
reblogOf,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const clearTimeline = (timeline) => (dispatch) => {
|
||||
dispatch({
|
||||
type: TIMELINE_CLEAR,
|
||||
timeline
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandTimeline = (timelineId, path, params = {}, done = noop) => (dispatch, getState) => {
|
||||
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap())
|
||||
const isLoadingMore = !!params.max_id
|
||||
|
||||
@@ -156,74 +162,179 @@ export const expandTimeline = (timelineId, path, params = {}, done = noOp) => (d
|
||||
})
|
||||
}
|
||||
|
||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
||||
export const expandExploreTimeline = ({ maxId, sortBy } = {}, done = noOp) => expandTimeline('explore', '/api/v1/timelines/explore', { max_id: maxId, sort_by: sortBy }, done);
|
||||
export const expandProTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('pro', '/api/v1/timelines/pro', { max_id: maxId }, done);
|
||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandAccountTimeline = (accountId, { maxId, withReplies, commentsOnly } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${commentsOnly ? ':comments_only' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { only_comments: commentsOnly, exclude_replies: (!withReplies && !commentsOnly), max_id: maxId });
|
||||
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
||||
export const expandAccountMediaTimeline = (accountId, { maxId, limit, mediaType } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: limit || 20, media_type: mediaType });
|
||||
export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done);
|
||||
export const expandGroupTimeline = (id, { sortBy, maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`group:${id}`, `/api/v1/timelines/group/${id}`, { sort_by: sortBy, max_id: maxId, only_media: onlyMedia }, done);
|
||||
export const expandGroupFeaturedTimeline = (groupId, done = noOp) => expandTimeline(`group:${groupId}:pinned`, `/api/v1/timelines/group_pins/${groupId}`, {}, done);
|
||||
export const expandGroupCollectionTimeline = (collectionType, { sortBy, maxId } = {}, done = noOp) => expandTimeline(`group_collection:${collectionType}`, `/api/v1/timelines/group_collection/${collectionType}`, { sort_by: sortBy, max_id: maxId }, done);
|
||||
export const expandLinkTimeline = (linkId, { maxId } = {}, done = noOp) => expandTimeline(`link:${linkId}`, `/api/v1/timelines/preview_card/${linkId}`, { max_id: maxId }, done);
|
||||
export const expandHashtagTimeline = (hashtag, { maxId, tags } = {}, done = noOp) => {
|
||||
const expandTimelineRequest = (timeline, isLoadingMore) => ({
|
||||
type: TIMELINE_EXPAND_REQUEST,
|
||||
timeline,
|
||||
skipLoading: !isLoadingMore,
|
||||
})
|
||||
|
||||
const expandTimelineSuccess = (timeline, statuses, next, partial, isLoadingRecent, isLoadingMore) => ({
|
||||
type: TIMELINE_EXPAND_SUCCESS,
|
||||
timeline,
|
||||
statuses,
|
||||
next,
|
||||
partial,
|
||||
isLoadingRecent,
|
||||
skipLoading: !isLoadingMore,
|
||||
})
|
||||
|
||||
const expandTimelineFail = (timeline, error, isLoadingMore) => ({
|
||||
type: TIMELINE_EXPAND_FAIL,
|
||||
timeline,
|
||||
error,
|
||||
skipLoading: !isLoadingMore,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const scrollTopTimeline = (timeline, top) => ({
|
||||
type: TIMELINE_SCROLL_TOP,
|
||||
timeline,
|
||||
top,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const connectTimeline = (timeline) => ({
|
||||
type: TIMELINE_CONNECT,
|
||||
timeline,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const disconnectTimeline = (timeline) => ({
|
||||
type: TIMELINE_DISCONNECT,
|
||||
timeline,
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandHomeTimeline = ({ maxId } = {}, done = noop) => {
|
||||
return expandTimeline('home', '/api/v1/timelines/home', {
|
||||
max_id: maxId,
|
||||
}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandExploreTimeline = ({ maxId, sortBy } = {}, done = noop) => {
|
||||
return expandTimeline('explore', '/api/v1/timelines/explore', {
|
||||
max_id: maxId,
|
||||
sort_by: sortBy,
|
||||
}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandProTimeline = ({ maxId } = {}, done = noop) => {
|
||||
return expandTimeline('pro', '/api/v1/timelines/pro', {
|
||||
max_id: maxId,
|
||||
}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noop) => {
|
||||
return expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', {
|
||||
max_id: maxId,
|
||||
only_media: !!onlyMedia,
|
||||
}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandAccountTimeline = (accountId, { maxId, withReplies, commentsOnly } = {}) => {
|
||||
let key = `account:${accountId}${withReplies ? ':with_replies' : ''}${commentsOnly ? ':comments_only' : ''}`
|
||||
return expandTimeline(key, `/api/v1/accounts/${accountId}/statuses`, {
|
||||
only_comments: commentsOnly,
|
||||
exclude_replies: (!withReplies && !commentsOnly),
|
||||
max_id: maxId,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandAccountFeaturedTimeline = (accountId) => {
|
||||
return expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, {
|
||||
pinned: true,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandAccountMediaTimeline = (accountId, { maxId, limit, mediaType } = {}) => {
|
||||
return expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, {
|
||||
max_id: maxId,
|
||||
only_media: true,
|
||||
limit: limit || 20,
|
||||
media_type: mediaType
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandListTimeline = (id, { maxId } = {}, done = noop) => {
|
||||
return expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, {
|
||||
max_id: maxId,
|
||||
}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandGroupTimeline = (id, { sortBy, maxId, onlyMedia } = {}, done = noop) => {
|
||||
return expandTimeline(`group:${id}`, `/api/v1/timelines/group/${id}`, {
|
||||
sort_by: sortBy,
|
||||
max_id: maxId,
|
||||
only_media: onlyMedia
|
||||
}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandGroupFeaturedTimeline = (groupId, done = noop) => {
|
||||
return expandTimeline(`group:${groupId}:pinned`, `/api/v1/timelines/group_pins/${groupId}`, {}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandGroupCollectionTimeline = (collectionType, { sortBy, maxId } = {}, done = noop) => {
|
||||
return expandTimeline(`group_collection:${collectionType}`, `/api/v1/timelines/group_collection/${collectionType}`, {
|
||||
sort_by: sortBy,
|
||||
max_id: maxId,
|
||||
}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandLinkTimeline = (linkId, { maxId } = {}, done = noop) => {
|
||||
return expandTimeline(`link:${linkId}`, `/api/v1/timelines/preview_card/${linkId}`, {
|
||||
max_id: maxId,
|
||||
}, done)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export const expandHashtagTimeline = (hashtag, { maxId, tags } = {}, done = noop) => {
|
||||
return expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, {
|
||||
max_id: maxId,
|
||||
any: parseTags(tags, 'any'),
|
||||
all: parseTags(tags, 'all'),
|
||||
none: parseTags(tags, 'none'),
|
||||
}, done);
|
||||
};
|
||||
|
||||
export function expandTimelineRequest(timeline, isLoadingMore) {
|
||||
return {
|
||||
type: TIMELINE_EXPAND_REQUEST,
|
||||
timeline,
|
||||
skipLoading: !isLoadingMore,
|
||||
};
|
||||
};
|
||||
|
||||
export function expandTimelineSuccess(timeline, statuses, next, partial, isLoadingRecent, isLoadingMore) {
|
||||
return {
|
||||
type: TIMELINE_EXPAND_SUCCESS,
|
||||
timeline,
|
||||
statuses,
|
||||
next,
|
||||
partial,
|
||||
isLoadingRecent,
|
||||
skipLoading: !isLoadingMore,
|
||||
};
|
||||
};
|
||||
|
||||
export function expandTimelineFail(timeline, error, isLoadingMore) {
|
||||
return {
|
||||
type: TIMELINE_EXPAND_FAIL,
|
||||
timeline,
|
||||
error,
|
||||
skipLoading: !isLoadingMore,
|
||||
};
|
||||
};
|
||||
|
||||
export function connectTimeline(timeline) {
|
||||
return {
|
||||
type: TIMELINE_CONNECT,
|
||||
timeline,
|
||||
};
|
||||
};
|
||||
|
||||
export function disconnectTimeline(timeline) {
|
||||
return {
|
||||
type: TIMELINE_DISCONNECT,
|
||||
timeline,
|
||||
};
|
||||
};
|
||||
|
||||
export function scrollTopTimeline(timeline, top) {
|
||||
return {
|
||||
type: TIMELINE_SCROLL_TOP,
|
||||
timeline,
|
||||
top,
|
||||
};
|
||||
};
|
||||
}, done)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class Account extends ImmutablePureComponent {
|
||||
</Button>
|
||||
) : <AccountActionButton account={account} isSmall />
|
||||
|
||||
const avatarSize = compact ? 42 : 52
|
||||
const avatarSize = compact ? 40 : 52
|
||||
const dismissBtn = !showDismiss ? null : (
|
||||
<Button
|
||||
isNarrow
|
||||
|
||||
@@ -230,7 +230,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
onOpenStatusOptions(targetRef, status) {
|
||||
dispatch(openPopover('STATUS_OPTIONS', {
|
||||
targetRef,
|
||||
status,
|
||||
statusId: status.get('id'),
|
||||
position: 'top',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -126,7 +126,7 @@ const messages = defineMessages({
|
||||
down: { id: 'keyboard_shortcuts.down', defaultMessage: 'move down in the list' },
|
||||
column: { id: 'keyboard_shortcuts.column', defaultMessage: 'focus a status in one of the columns' },
|
||||
compose: { id: 'keyboard_shortcuts.compose', defaultMessage: 'focus the compose textarea' },
|
||||
gab: { id: 'keyboard_shortcuts.toot', defaultMessage: 'start a brand new gab' },
|
||||
gab: { id: 'keyboard_shortcuts.gab', defaultMessage: 'start a brand new gab' },
|
||||
back: { id: 'keyboard_shortcuts.back', defaultMessage: 'navigate back' },
|
||||
search: { id: 'keyboard_shortcuts.search', defaultMessage: 'focus search' },
|
||||
unfocus: { id: 'keyboard_shortcuts.unfocus', defaultMessage: 'un-focus compose textarea/search' },
|
||||
|
||||
@@ -4,7 +4,7 @@ import { connect } from 'react-redux'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import { fetchGroups } from '../../actions/groups'
|
||||
import { fetchGroupsByTab } from '../../actions/groups'
|
||||
import PanelLayout from './panel_layout'
|
||||
import GroupListItem from '../group_list_item'
|
||||
import ScrollableList from '../scrollable_list'
|
||||
@@ -26,13 +26,13 @@ class GroupsPanel extends ImmutablePureComponent {
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (!prevState.fetched && this.state.fetched) {
|
||||
this.props.onFetchGroups(this.props.groupType)
|
||||
this.props.onFetchGroupsByTab(this.props.groupType)
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.isLazy) {
|
||||
this.props.onFetchGroups(this.props.groupType)
|
||||
this.props.onFetchGroupsByTab(this.props.groupType)
|
||||
this.setState({ fetched: true })
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,7 @@ const mapStateToProps = (state, { groupType }) => ({
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onFetchGroups: (type) => dispatch(fetchGroups(type))
|
||||
onFetchGroupsByTab: (type) => dispatch(fetchGroupsByTab(type))
|
||||
})
|
||||
|
||||
GroupsPanel.propTypes = {
|
||||
|
||||
@@ -5,13 +5,16 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'
|
||||
import { me, isStaff, boostModal, deleteModal } from '../../initial_state'
|
||||
import { makeGetStatus } from '../../selectors'
|
||||
import {
|
||||
repost,
|
||||
unrepost,
|
||||
pin,
|
||||
unpin,
|
||||
isPin,
|
||||
bookmark,
|
||||
unbookmark,
|
||||
isBookmark,
|
||||
} from '../../actions/interactions';
|
||||
import {
|
||||
deleteStatus,
|
||||
@@ -24,6 +27,7 @@ import {
|
||||
groupRemoveStatus,
|
||||
pinGroupStatus,
|
||||
unpinGroupStatus,
|
||||
isPinnedGroupStatus,
|
||||
} from '../../actions/groups'
|
||||
import { initReport } from '../../actions/reports'
|
||||
import { openModal } from '../../actions/modal'
|
||||
@@ -51,11 +55,23 @@ class StatusOptionsPopover extends ImmutablePureComponent {
|
||||
]
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
status,
|
||||
statusId,
|
||||
groupRelationships,
|
||||
} = this.props
|
||||
|
||||
if (status.get('pinnable')) {
|
||||
this.props.fetchIsPin(statusId)
|
||||
}
|
||||
this.props.fetchIsBookmark(statusId)
|
||||
|
||||
if (!!status.get('group')) {
|
||||
this.props.fetchIsPinnedGroupStatus(status.getIn(['group', 'id'], null), statusId)
|
||||
}
|
||||
|
||||
if (!this.props.groupRelationships && this.props.groupId) {
|
||||
this.props.onFetchGroupRelationships(this.props.groupId)
|
||||
// : todo :
|
||||
// check if pin
|
||||
// check if bookmark
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,11 +147,15 @@ class StatusOptionsPopover extends ImmutablePureComponent {
|
||||
isXS,
|
||||
} = this.props
|
||||
|
||||
if (!status) return <div />
|
||||
|
||||
const mutingConversation = status.get('muted')
|
||||
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'))
|
||||
const isReply = !!status.get('in_reply_to_id')
|
||||
const withGroupAdmin = !!groupRelationships ? (groupRelationships.get('admin') || groupRelationships.get('moderator')) : false
|
||||
|
||||
console.log("publicStatus:", status, publicStatus)
|
||||
|
||||
let menu = []
|
||||
|
||||
if (me) {
|
||||
@@ -296,13 +316,15 @@ const messages = defineMessages({
|
||||
share: { id: 'status.share_gab', defaultMessage: 'Share gab' },
|
||||
})
|
||||
|
||||
const mapStateToProps = (state, { status }) => {
|
||||
const mapStateToProps = (state, { statusId }) => {
|
||||
if (!me) return null
|
||||
|
||||
|
||||
const status = statusId ? makeGetStatus()(state, { id: statusId }) : undefined
|
||||
const groupId = status ? status.getIn(['group', 'id']) : undefined
|
||||
const groupRelationships = state.getIn(['group_relationships', groupId])
|
||||
|
||||
return {
|
||||
status,
|
||||
groupId,
|
||||
groupRelationships,
|
||||
isPro: state.getIn(['accounts', me, 'is_pro']),
|
||||
@@ -311,6 +333,18 @@ const mapStateToProps = (state, { status }) => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
fetchIsPin(statusId) {
|
||||
dispatch(isPin(statusId))
|
||||
},
|
||||
|
||||
fetchIsBookmark(statusId) {
|
||||
dispatch(isBookmark(statusId))
|
||||
},
|
||||
|
||||
fetchIsPinnedGroupStatus(groupId, statusId) {
|
||||
dispatch(isPinnedGroupStatus(groupId, statusId))
|
||||
},
|
||||
|
||||
onPin(status) {
|
||||
dispatch(closePopover())
|
||||
|
||||
@@ -440,7 +474,8 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
})
|
||||
|
||||
StatusOptionsPopover.propTypes = {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
status: ImmutablePropTypes.map,
|
||||
statusId: PropTypes.string.isRequired,
|
||||
groupRelationships: ImmutablePropTypes.map,
|
||||
groupId: PropTypes.string,
|
||||
onQuote: PropTypes.func.isRequired,
|
||||
@@ -454,6 +489,9 @@ StatusOptionsPopover.propTypes = {
|
||||
onFetchGroupRelationships: PropTypes.func.isRequired,
|
||||
onOpenProUpgradeModal: PropTypes.func.isRequired,
|
||||
onClosePopover: PropTypes.func.isRequired,
|
||||
fetchIsPinnedGroupStatus: PropTypes.func.isRequired,
|
||||
fetchIsBookmark: PropTypes.func.isRequired,
|
||||
fetchIsPin: PropTypes.func.isRequired,
|
||||
isXS: PropTypes.bool,
|
||||
isPro: PropTypes.bool,
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { CX } from '../constants'
|
||||
|
||||
class StatusActionBar extends ImmutablePureComponent {
|
||||
|
||||
updateOnProps = ['status']
|
||||
// updateOnProps = ['status']
|
||||
|
||||
handleShareClick = () => {
|
||||
this.props.onShare(this.shareButton, this.props.status)
|
||||
|
||||
@@ -4,7 +4,7 @@ import { connect } from 'react-redux'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { Set as ImmutableSet } from 'immutable';
|
||||
import noop from 'lodash/noop';
|
||||
import noop from 'lodash.noop'
|
||||
import { toggleStatusReport } from '../actions/reports';
|
||||
import { MediaGallery, Video } from '../features/ui/util/async_components';
|
||||
import Bundle from '../features/ui/util/bundle';
|
||||
|
||||
@@ -216,7 +216,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
onOpenStatusOptionsPopover(targetRef, status) {
|
||||
dispatch(openPopover('STATUS_OPTIONS', {
|
||||
targetRef,
|
||||
status,
|
||||
statusId: status.get('id'),
|
||||
position: 'left-start',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { fetchGroups } from '../../actions/groups'
|
||||
import { fetchGroupsByTab } from '../../actions/groups'
|
||||
import GroupCollectionItem from '../group_collection_item'
|
||||
import TimelineInjectionLayout from './timeline_injection_layout'
|
||||
|
||||
@@ -11,7 +11,7 @@ class FeaturedGroupsInjection extends ImmutablePureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.isFetched) {
|
||||
this.props.onFetchGroups('featured')
|
||||
this.props.onFetchGroupsByTap('featured')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,14 +59,14 @@ const mapStateToProps = (state) => ({
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onFetchGroups: (tab) => dispatch(fetchGroups(tab)),
|
||||
onFetchGroupsByTap: (tab) => dispatch(fetchGroupsByTab(tab)),
|
||||
})
|
||||
|
||||
FeaturedGroupsInjection.propTypes = {
|
||||
groupIds: ImmutablePropTypes.list,
|
||||
isFetched: PropTypes.bool.isRequired,
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
onFetchGroups: PropTypes.func.isRequired,
|
||||
onFetchGroupsByTab: PropTypes.func.isRequired,
|
||||
injectionId: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,8 @@ export const GROUP_TIMELINE_SORTING_TYPE_NEWEST = 'newest'
|
||||
export const GROUP_TIMELINE_SORTING_TYPE_RECENT_ACTIVITY = 'recent'
|
||||
export const GROUP_TIMELINE_SORTING_TYPE_TOP = 'top'
|
||||
|
||||
export const ACCEPTED_GROUP_TABS = ['new', 'featured', 'member', 'admin']
|
||||
|
||||
export const GROUP_TIMELINE_SORTING_TYPE_TOP_OPTION_TODAY = 'today'
|
||||
export const GROUP_TIMELINE_SORTING_TYPE_TOP_OPTION_WEEKLY = 'weekly'
|
||||
export const GROUP_TIMELINE_SORTING_TYPE_TOP_OPTION_MONTHLY = 'monthly'
|
||||
|
||||
@@ -11,6 +11,7 @@ import Account from '../components/account'
|
||||
import Block from '../components/block'
|
||||
import BlockHeading from '../components/block_heading'
|
||||
import ScrollableList from '../components/scrollable_list'
|
||||
import AccountPlaceholder from '../components/placeholder/account_placeholder'
|
||||
|
||||
class Blocks extends ImmutablePureComponent {
|
||||
|
||||
@@ -40,16 +41,19 @@ class Blocks extends ImmutablePureComponent {
|
||||
onLoadMore={this.handleLoadMore}
|
||||
hasMore={hasMore}
|
||||
isLoading={isLoading}
|
||||
showLoading={isLoading}
|
||||
emptyMessage={emptyMessage}
|
||||
placeholderComponent={AccountPlaceholder}
|
||||
placeholderCount={3}
|
||||
>
|
||||
{
|
||||
accountIds && accountIds.map((id) =>
|
||||
accountIds && accountIds.map((id) => (
|
||||
<Account
|
||||
key={`blocked-accounts-${id}`}
|
||||
id={id}
|
||||
compact
|
||||
/>
|
||||
)
|
||||
))
|
||||
}
|
||||
</ScrollableList>
|
||||
</Block>
|
||||
|
||||
@@ -4,7 +4,7 @@ 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 { fetchGroups } from '../actions/groups'
|
||||
import { fetchGroupsByTab } from '../actions/groups'
|
||||
import { openPopover } from '../actions/popover'
|
||||
import { POPOVER_GROUP_LIST_SORT_OPTIONS } from '../constants'
|
||||
import Block from '../components/block'
|
||||
@@ -16,12 +16,12 @@ import GroupListItem from '../components/group_list_item'
|
||||
class GroupsCollection extends ImmutablePureComponent {
|
||||
|
||||
componentWillMount() {
|
||||
this.props.onFetchGroups(this.props.activeTab)
|
||||
this.props.onFetchGroupsByTab(this.props.activeTab)
|
||||
}
|
||||
|
||||
componentDidUpdate(oldProps) {
|
||||
if (this.props.activeTab && this.props.activeTab !== oldProps.activeTab) {
|
||||
this.props.onFetchGroups(this.props.activeTab)
|
||||
this.props.onFetchGroupsByTab(this.props.activeTab)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ const mapStateToProps = (state, { activeTab }) => ({
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onFetchGroups: (tab) => dispatch(fetchGroups(tab)),
|
||||
onFetchGroupsByTab: (tab) => dispatch(fetchGroupsByTab(tab)),
|
||||
onOpenSortPopover(tab, targetRef) {
|
||||
dispatch(openPopover(POPOVER_GROUP_LIST_SORT_OPTIONS, {
|
||||
targetRef,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '../constants'
|
||||
import { me } from '../initial_state'
|
||||
import { saveShownOnboarding } from '../actions/settings'
|
||||
import { fetchGroups } from '../actions/groups'
|
||||
import { fetchGroupsByTab } from '../actions/groups'
|
||||
import { saveUserProfileInformation } from '../actions/user'
|
||||
import { makeGetAccount } from '../selectors'
|
||||
import Button from '../components/button'
|
||||
@@ -414,7 +414,7 @@ const mapStateToProps = (state) => ({
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onSaveShownOnboarding: () => dispatch(saveShownOnboarding()),
|
||||
onFetchFeaturedGroups: () => dispatch(fetchGroups('featured')),
|
||||
onFetchFeaturedGroups: () => dispatch(fetchGroupsByTab('featured')),
|
||||
onSaveUserProfileInformation(data) {
|
||||
dispatch(saveUserProfileInformation(data))
|
||||
},
|
||||
|
||||
@@ -4,45 +4,65 @@ import { connect } from 'react-redux'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { FormattedMessage } from 'react-intl'
|
||||
import { fetchLikes } from '../actions/interactions'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { fetchLikes, expandLikes } from '../actions/interactions'
|
||||
import { fetchStatus } from '../actions/statuses'
|
||||
import { makeGetStatus } from '../selectors'
|
||||
import Account from '../components/account'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
import ScrollableList from '../components/scrollable_list'
|
||||
import AccountPlaceholder from '../components/placeholder/account_placeholder'
|
||||
|
||||
class StatusLikes extends ImmutablePureComponent {
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchLikes(this.props.statusId))
|
||||
this.props.dispatch(fetchStatus(this.props.statusId))
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.statusId !== this.props.statusId && nextProps.statusId) {
|
||||
this.props.dispatch(fetchLikes(nextProps.statusId))
|
||||
this.props.dispatch(fetchStatus(nextProps.statusId))
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { accountIds, status } = this.props
|
||||
handleLoadMore = debounce(() => {
|
||||
this.props.dispatch(expandLikes(this.props.statusId))
|
||||
}, 300, { leading: true })
|
||||
|
||||
if (!accountIds) {
|
||||
return <ColumnIndicator type='loading' />
|
||||
} else if (!status) {
|
||||
render () {
|
||||
const {
|
||||
accountIds,
|
||||
isLoading,
|
||||
hasMore,
|
||||
list,
|
||||
statusId,
|
||||
} = this.props
|
||||
|
||||
if (!statusId) {
|
||||
return <ColumnIndicator type='missing' />
|
||||
}
|
||||
|
||||
const accountIdCount = !!accountIds ? accountIds.count() : 0
|
||||
|
||||
return (
|
||||
<ScrollableList
|
||||
scrollKey='likes'
|
||||
emptyMessage={<FormattedMessage id='status.likes.empty' defaultMessage='No one has liked this gab yet. When someone does, they will show up here.' />}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
hasMore={hasMore}
|
||||
isLoading={isLoading && accountIdCount === 0}
|
||||
showLoading={isLoading && accountIdCount === 0}
|
||||
placeholderComponent={AccountPlaceholder}
|
||||
placeholderCount={3}
|
||||
>
|
||||
{
|
||||
accountIds.map(id =>
|
||||
<Account key={id} id={id} />
|
||||
)
|
||||
accountIdCount > 0 && accountIds.map((id) => (
|
||||
<Account
|
||||
compact
|
||||
key={`liked-by-${id}`}
|
||||
id={id}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</ScrollableList>
|
||||
)
|
||||
@@ -52,24 +72,17 @@ class StatusLikes extends ImmutablePureComponent {
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const statusId = props.params ? props.params.statusId : props.statusId
|
||||
|
||||
const getStatus = makeGetStatus()
|
||||
const status = getStatus(state, {
|
||||
id: statusId
|
||||
})
|
||||
|
||||
return {
|
||||
status,
|
||||
statusId,
|
||||
accountIds: state.getIn(['user_lists', 'liked_by', statusId]),
|
||||
accountIds: state.getIn(['user_lists', 'liked_by', statusId, 'items']),
|
||||
hasMore: !!state.getIn(['user_lists', 'liked_by', statusId, 'next']),
|
||||
isLoading: state.getIn(['user_lists', 'liked_by', statusId, 'isLoading']),
|
||||
}
|
||||
}
|
||||
|
||||
StatusLikes.propTypes = {
|
||||
accountIds: ImmutablePropTypes.list,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
status: ImmutablePropTypes.map,
|
||||
statusId: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(StatusLikes)
|
||||
export default connect(mapStateToProps)(StatusLikes)
|
||||
|
||||
@@ -4,45 +4,65 @@ import { connect } from 'react-redux'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { FormattedMessage } from 'react-intl'
|
||||
import { fetchReposts } from '../actions/interactions'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { fetchReposts, expandReposts } from '../actions/interactions'
|
||||
import { fetchStatus } from '../actions/statuses'
|
||||
import { makeGetStatus } from '../selectors'
|
||||
import Account from '../components/account'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
import ScrollableList from '../components/scrollable_list'
|
||||
import AccountPlaceholder from '../components/placeholder/account_placeholder'
|
||||
|
||||
class StatusReposts extends ImmutablePureComponent {
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchReposts(this.props.statusId))
|
||||
this.props.dispatch(fetchStatus(this.props.statusId))
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.statusId !== this.props.statusId && nextProps.statusId) {
|
||||
this.props.dispatch(fetchReposts(nextProps.statusId))
|
||||
this.props.dispatch(fetchStatus(nextProps.statusId))
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { accountIds, status } = this.props
|
||||
handleLoadMore = debounce(() => {
|
||||
this.props.dispatch(expandReposts(this.props.statusId))
|
||||
}, 300, { leading: true })
|
||||
|
||||
if (!accountIds) {
|
||||
return <ColumnIndicator type='loading' />
|
||||
} else if (!status) {
|
||||
render () {
|
||||
const {
|
||||
accountIds,
|
||||
isLoading,
|
||||
hasMore,
|
||||
list,
|
||||
statusId,
|
||||
} = this.props
|
||||
|
||||
if (!statusId) {
|
||||
return <ColumnIndicator type='missing' />
|
||||
}
|
||||
|
||||
const accountIdCount = !!accountIds ? accountIds.count() : 0
|
||||
|
||||
return (
|
||||
<ScrollableList
|
||||
scrollKey='reposts'
|
||||
emptyMessage={<FormattedMessage id='status.reposts.empty' defaultMessage='No one has reposted this gab yet. When someone does, they will show up here.' />}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
hasMore={hasMore}
|
||||
isLoading={isLoading && accountIdCount === 0}
|
||||
showLoading={isLoading && accountIdCount === 0}
|
||||
placeholderComponent={AccountPlaceholder}
|
||||
placeholderCount={3}
|
||||
>
|
||||
{
|
||||
accountIds.map(id =>
|
||||
<Account key={id} id={id} />
|
||||
)
|
||||
accountIdCount > 0 && accountIds.map((id) => (
|
||||
<Account
|
||||
compact
|
||||
key={`reposted-by-${id}`}
|
||||
id={id}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</ScrollableList>
|
||||
)
|
||||
@@ -52,25 +72,17 @@ class StatusReposts extends ImmutablePureComponent {
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const statusId = props.params ? props.params.statusId : props.statusId
|
||||
|
||||
const getStatus = makeGetStatus()
|
||||
const status = getStatus(state, {
|
||||
id: statusId,
|
||||
// username: props.params.username,
|
||||
})
|
||||
|
||||
return {
|
||||
status,
|
||||
statusId,
|
||||
accountIds: state.getIn(['user_lists', 'reblogged_by', statusId]),
|
||||
accountIds: state.getIn(['user_lists', 'reblogged_by', statusId, 'items']),
|
||||
hasMore: !!state.getIn(['user_lists', 'reblogged_by', statusId, 'next']),
|
||||
isLoading: state.getIn(['user_lists', 'reblogged_by', statusId, 'isLoading']),
|
||||
}
|
||||
}
|
||||
|
||||
StatusReposts.propTypes = {
|
||||
accountIds: ImmutablePropTypes.list,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
status: ImmutablePropTypes.map,
|
||||
statusId: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(StatusReposts)
|
||||
export default connect(mapStateToProps)(StatusReposts)
|
||||
|
||||
@@ -55,7 +55,6 @@ import {
|
||||
AccountTimeline,
|
||||
Assets,
|
||||
BlockedAccounts,
|
||||
BlockedDomains,
|
||||
BookmarkedStatuses,
|
||||
CommunityTimeline,
|
||||
Compose,
|
||||
|
||||
@@ -77,6 +77,7 @@ export function ListTimelineSettingsModal() { return import(/* webpackChunkName:
|
||||
export function MediaGallery() { return import(/* webpackChunkName: "components/media_gallery" */'../../../components/media_gallery') }
|
||||
export function MediaGalleryPanel() { return import(/* webpackChunkName: "components/media_gallery_panel" */'../../../components/panel/media_gallery_panel') }
|
||||
export function MediaModal() { return import(/* webpackChunkName: "components/media_modal" */'../../../components/modal/media_modal') }
|
||||
export function Messages() { return import(/* webpackChunkName: "features/messages" */'../../messages') }
|
||||
export function Mutes() { return import(/* webpackChunkName: "features/mutes" */'../../mutes') }
|
||||
export function MuteModal() { return import(/* webpackChunkName: "modals/mute_modal" */'../../../components/modal/mute_modal') }
|
||||
export function NavSettingsPopover() { return import(/* webpackChunkName: "modals/nav_settings_popover" */'../../../components/popover/nav_settings_popover') }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import noop from 'lodash.noop'
|
||||
import {
|
||||
fetchBundleRequest,
|
||||
fetchBundleSuccess,
|
||||
@@ -8,7 +9,6 @@ import {
|
||||
} from '../../../actions/bundles'
|
||||
|
||||
const emptyComponent = () => null
|
||||
const noop = () => { }
|
||||
|
||||
class Bundle extends React.PureComponent {
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ const defaultFailSuffix = 'FAIL';
|
||||
|
||||
export default function errorsMiddleware() {
|
||||
return ({ dispatch }) => next => action => {
|
||||
// : todo : use skipAlert!
|
||||
if (action.type && !action.skipAlert) {
|
||||
const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ export default function loadingBarMiddleware(config = {}) {
|
||||
const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypeSuffixes
|
||||
|
||||
return ({ dispatch }) => next => (action) => {
|
||||
if (action.type && !action.skipLoading) {
|
||||
if (action.type && action.type.indexOf('TIMELINE') > -1) {
|
||||
const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes
|
||||
|
||||
const isPending = new RegExp(`${PENDING}$`, 'g')
|
||||
|
||||
@@ -18,7 +18,7 @@ class MessagesPage extends React.PureComponent {
|
||||
title={title}
|
||||
>
|
||||
<PageTitle path={title} />
|
||||
{children}
|
||||
|
||||
</MessagesLayout>
|
||||
)
|
||||
}
|
||||
|
||||
43
app/javascript/gabsocial/reducers/chat_compose.js
Normal file
43
app/javascript/gabsocial/reducers/chat_compose.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
MESSAGE_INPUT_CHANGE,
|
||||
MESSAGE_INPUT_RESET,
|
||||
MESSAGE_SEND_REQUEST,
|
||||
MESSAGE_SEND_SUCCESS,
|
||||
MESSAGE_SEND_FAIL,
|
||||
MESSAGE_DELETE_REQUEST,
|
||||
MESSAGE_DELETE_SUCCESS,
|
||||
MESSAGE_DELETE_FAIL,
|
||||
} from '../actions/lists'
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable'
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
text: '',
|
||||
conversationId: null,
|
||||
idempotencyKey: null,
|
||||
})
|
||||
|
||||
const normalizeList = (state, list) => state.set(list.id, fromJS(list))
|
||||
|
||||
const normalizeLists = (state, lists) => {
|
||||
lists.forEach(list => {
|
||||
state = normalizeList(state, list)
|
||||
})
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
export default function lists(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case LIST_FETCH_SUCCESS:
|
||||
case LIST_CREATE_SUCCESS:
|
||||
case LIST_UPDATE_SUCCESS:
|
||||
return normalizeList(state, action.list);
|
||||
case LISTS_FETCH_SUCCESS:
|
||||
return normalizeLists(state, action.lists);
|
||||
case LIST_DELETE_SUCCESS:
|
||||
case LIST_FETCH_FAIL:
|
||||
return state.set(action.id, false);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
84
app/javascript/gabsocial/reducers/chat_messages.js
Normal file
84
app/javascript/gabsocial/reducers/chat_messages.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import {
|
||||
REPOST_REQUEST,
|
||||
UNREPOST_REQUEST,
|
||||
REPOST_FAIL,
|
||||
FAVORITE_REQUEST,
|
||||
FAVORITE_FAIL,
|
||||
UNFAVORITE_REQUEST,
|
||||
} from '../actions/interactions';
|
||||
import {
|
||||
STATUS_REVEAL,
|
||||
STATUS_HIDE,
|
||||
UPDATE_STATUS_STATS,
|
||||
} from '../actions/statuses';
|
||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
||||
const importStatus = (state, status) => state.set(status.id, fromJS(status));
|
||||
|
||||
const importStatuses = (state, statuses) =>
|
||||
state.withMutations(mutable => statuses.forEach(status => importStatus(mutable, status)));
|
||||
|
||||
const deleteStatus = (state, id, references) => {
|
||||
references.forEach(ref => {
|
||||
state = deleteStatus(state, ref[0], []);
|
||||
});
|
||||
|
||||
return state.delete(id);
|
||||
};
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
export default function statuses(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case STATUS_IMPORT:
|
||||
return importStatus(state, action.status);
|
||||
case STATUSES_IMPORT:
|
||||
return importStatuses(state, action.statuses);
|
||||
case FAVORITE_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'favourited'], true);
|
||||
case FAVORITE_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'favourited'], false);
|
||||
case UNFAVORITE_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'favourited'], false);
|
||||
case REPOST_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], true);
|
||||
case UNREPOST_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||
case REPOST_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||
case STATUS_REVEAL:
|
||||
return state.withMutations((map) => {
|
||||
action.ids.forEach(id => {
|
||||
if (!(state.get(id) === undefined)) {
|
||||
map.setIn([id, 'hidden'], false);
|
||||
}
|
||||
});
|
||||
});
|
||||
case STATUS_HIDE:
|
||||
return state.withMutations((map) => {
|
||||
action.ids.forEach(id => {
|
||||
if (!(state.get(id) === undefined)) {
|
||||
map.setIn([id, 'hidden'], true);
|
||||
}
|
||||
});
|
||||
});
|
||||
case TIMELINE_DELETE:
|
||||
return deleteStatus(state, action.id, action.references);
|
||||
case UPDATE_STATUS_STATS:
|
||||
const { status_id } = action.data
|
||||
return state.withMutations((map) => {
|
||||
if (action.data.favourited !== undefined) map.setIn([status_id, 'favourited'], action.data.favourited)
|
||||
if (action.data.favourites_count !== undefined) map.setIn([status_id, 'favourites_count'], action.data.favourites_count)
|
||||
if (action.data.reblogged !== undefined) map.setIn([status_id, 'reblogged'], action.data.reblogged)
|
||||
if (action.data.reblogs_count !== undefined) map.setIn([status_id, 'reblogs_count'], action.data.reblogs_count)
|
||||
if (action.data.replies_count !== undefined) map.setIn([status_id, 'replies_count'], action.data.replies_count)
|
||||
if (action.data.pinned !== undefined) map.setIn([status_id, 'pinned'], action.data.pinned)
|
||||
if (action.data.pinned_by_group !== undefined) map.setIn([status_id, 'pinned_by_group'], action.data.pinned_by_group)
|
||||
if (action.data.bookmarked !== undefined) map.setIn([status_id, 'bookmarked'], action.data.bookmarked)
|
||||
})
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
@@ -21,11 +21,10 @@ import {
|
||||
GROUP_TIMELINE_SORTING_TYPE_TOP,
|
||||
GROUP_TIMELINE_SORTING_TYPE_NEWEST,
|
||||
GROUP_TIMELINE_SORTING_TYPE_TOP_OPTION_TODAY,
|
||||
ACCEPTED_GROUP_TABS,
|
||||
} from '../constants'
|
||||
import slugify from '../utils/slugify'
|
||||
|
||||
const tabs = ['new', 'featured', 'member', 'admin']
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
sortByValue: GROUP_TIMELINE_SORTING_TYPE_NEWEST,
|
||||
sortByTopValue: '',
|
||||
|
||||
@@ -4,11 +4,11 @@ import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
const normalizeRelationship = (state, relationship) => state.set(relationship.id, fromJS(relationship));
|
||||
|
||||
const normalizeRelationships = (state, relationships) => {
|
||||
relationships.forEach(relationship => {
|
||||
state = normalizeRelationship(state, relationship);
|
||||
});
|
||||
relationships.forEach(relationship => {
|
||||
state = normalizeRelationship(state, relationship);
|
||||
});
|
||||
|
||||
return state;
|
||||
return state
|
||||
};
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
@@ -30,7 +30,7 @@ export default function groups(state = initialState, action) {
|
||||
case GROUPS_FETCH_SUCCESS:
|
||||
return normalizeGroups(state, action.groups)
|
||||
case GROUP_FETCH_FAIL:
|
||||
return state.set(action.id, false)
|
||||
return state.set(action.groupId, false)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ import { combineReducers } from 'redux-immutable'
|
||||
import { loadingBarReducer } from 'react-redux-loading-bar'
|
||||
import accounts from './accounts'
|
||||
import accounts_counters from './accounts_counters'
|
||||
import chat_compose from './chat_compose'
|
||||
import chat_conversations from './chat_conversations'
|
||||
import chat_messages from './chat_messages'
|
||||
import compose from './compose'
|
||||
import contexts from './contexts'
|
||||
import custom_emojis from './custom_emojis'
|
||||
@@ -46,6 +49,8 @@ import user_lists from './user_lists'
|
||||
const reducers = {
|
||||
accounts,
|
||||
accounts_counters,
|
||||
chat_conversations,
|
||||
chat_messages,
|
||||
compose,
|
||||
contexts,
|
||||
custom_emojis,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'
|
||||
import {
|
||||
STATUS_REVISIONS_LOAD,
|
||||
STATUS_REVISIONS_LOAD_REQUEST,
|
||||
STATUS_REVISIONS_LOAD_SUCCESS,
|
||||
STATUS_REVISIONS_LOAD_FAIL
|
||||
} from '../actions/status_revisions'
|
||||
@@ -13,15 +13,17 @@ const initialState = ImmutableMap({
|
||||
|
||||
export default function statusRevisions(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case STATUS_REVISIONS_LOAD:
|
||||
return initialState
|
||||
case STATUS_REVISIONS_LOAD_REQUEST:
|
||||
return state.withMutations((mutable) => {
|
||||
mutable.set('loading', true)
|
||||
})
|
||||
case STATUS_REVISIONS_LOAD_SUCCESS:
|
||||
return state.withMutations(mutable => {
|
||||
return state.withMutations((mutable) => {
|
||||
mutable.set('loading', false)
|
||||
mutable.set('revisions', fromJS(action.revisions).reverse())
|
||||
})
|
||||
case STATUS_REVISIONS_LOAD_FAIL:
|
||||
return state.withMutations(mutable => {
|
||||
return state.withMutations((mutable) => {
|
||||
mutable.set('loading', false)
|
||||
mutable.set('error', action.error)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
REPOST_REQUEST,
|
||||
UNREPOST_REQUEST,
|
||||
REPOST_FAIL,
|
||||
FAVORITE_REQUEST,
|
||||
FAVORITE_FAIL,
|
||||
@@ -43,10 +44,12 @@ export default function statuses(state = initialState, action) {
|
||||
return state.setIn([action.status.get('id'), 'favourited'], false);
|
||||
case REPOST_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], true);
|
||||
case UNREPOST_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||
case REPOST_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||
case STATUS_REVEAL:
|
||||
return state.withMutations(map => {
|
||||
return state.withMutations((map) => {
|
||||
action.ids.forEach(id => {
|
||||
if (!(state.get(id) === undefined)) {
|
||||
map.setIn([id, 'hidden'], false);
|
||||
@@ -54,7 +57,7 @@ export default function statuses(state = initialState, action) {
|
||||
});
|
||||
});
|
||||
case STATUS_HIDE:
|
||||
return state.withMutations(map => {
|
||||
return state.withMutations((map) => {
|
||||
action.ids.forEach(id => {
|
||||
if (!(state.get(id) === undefined)) {
|
||||
map.setIn([id, 'hidden'], true);
|
||||
@@ -64,8 +67,17 @@ export default function statuses(state = initialState, action) {
|
||||
case TIMELINE_DELETE:
|
||||
return deleteStatus(state, action.id, action.references);
|
||||
case UPDATE_STATUS_STATS:
|
||||
// : todo :
|
||||
return state;
|
||||
const { status_id } = action.data
|
||||
return state.withMutations((map) => {
|
||||
if (action.data.favourited !== undefined) map.setIn([status_id, 'favourited'], action.data.favourited)
|
||||
if (action.data.favourites_count !== undefined) map.setIn([status_id, 'favourites_count'], action.data.favourites_count)
|
||||
if (action.data.reblogged !== undefined) map.setIn([status_id, 'reblogged'], action.data.reblogged)
|
||||
if (action.data.reblogs_count !== undefined) map.setIn([status_id, 'reblogs_count'], action.data.reblogs_count)
|
||||
if (action.data.replies_count !== undefined) map.setIn([status_id, 'replies_count'], action.data.replies_count)
|
||||
if (action.data.pinned !== undefined) map.setIn([status_id, 'pinned'], action.data.pinned)
|
||||
if (action.data.pinned_by_group !== undefined) map.setIn([status_id, 'pinned_by_group'], action.data.pinned_by_group)
|
||||
if (action.data.bookmarked !== undefined) map.setIn([status_id, 'bookmarked'], action.data.bookmarked)
|
||||
})
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'
|
||||
import compareId from '../utils/compare_id'
|
||||
import {
|
||||
TIMELINE_UPDATE,
|
||||
TIMELINE_DELETE,
|
||||
@@ -11,17 +13,19 @@ import {
|
||||
TIMELINE_DEQUEUE,
|
||||
MAX_QUEUED_ITEMS,
|
||||
TIMELINE_SCROLL_TOP,
|
||||
} from '../actions/timelines';
|
||||
} from '../actions/timelines'
|
||||
import {
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
ACCOUNT_MUTE_SUCCESS,
|
||||
ACCOUNT_UNFOLLOW_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
||||
import compareId from '../utils/compare_id';
|
||||
import { GROUP_REMOVE_STATUS_SUCCESS } from '../actions/groups';
|
||||
} from '../actions/accounts'
|
||||
import {
|
||||
GROUP_REMOVE_STATUS_SUCCESS,
|
||||
GROUP_UNPIN_STATUS_SUCCESS,
|
||||
} from '../actions/groups'
|
||||
import { UNPIN_SUCCESS } from '../actions/interactions'
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
const initialState = ImmutableMap()
|
||||
|
||||
const initialTimeline = ImmutableMap({
|
||||
unread: 0,
|
||||
@@ -33,14 +37,14 @@ const initialTimeline = ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
queuedItems: ImmutableList(), //max= MAX_QUEUED_ITEMS
|
||||
totalQueuedItemsCount: 0, //used for queuedItems overflow for MAX_QUEUED_ITEMS+
|
||||
});
|
||||
})
|
||||
|
||||
const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, isLoadingRecent) => {
|
||||
return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {
|
||||
mMap.set('isLoading', false);
|
||||
mMap.set('isPartial', isPartial);
|
||||
return state.update(timeline, initialTimeline, map => map.withMutations((mMap) => {
|
||||
mMap.set('isLoading', false)
|
||||
mMap.set('isPartial', isPartial)
|
||||
|
||||
if (!next && !isLoadingRecent) mMap.set('hasMore', false);
|
||||
if (!next && !isLoadingRecent) mMap.set('hasMore', false)
|
||||
|
||||
if (!statuses.isEmpty()) {
|
||||
mMap.update('items', ImmutableList(), oldIds => {
|
||||
@@ -160,8 +164,16 @@ const filterTimeline = (timeline, state, relationship, statuses) =>
|
||||
));
|
||||
|
||||
const removeStatusFromGroup = (state, groupId, statusId) => {
|
||||
return state.updateIn([`group:${groupId}`, 'items'], list => list.filterNot(item => item === statusId));
|
||||
};
|
||||
return state.updateIn([`group:${groupId}`, 'items'], list => list.filterNot(item => item === statusId))
|
||||
}
|
||||
|
||||
const removeStatusFromGroupPins = (state, groupId, statusId) => {
|
||||
return state.updateIn([`group:${groupId}:pinned`, 'items'], list => list.filterNot(item => item === statusId))
|
||||
}
|
||||
|
||||
const removeStatusFromAccountPins = (state, accountId, statusId) => {
|
||||
return state.updateIn([`account:${accountId}:pinned`, 'items'], list => list.filterNot(item => item === statusId))
|
||||
}
|
||||
|
||||
export default function timelines(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
@@ -201,10 +213,14 @@ export default function timelines(state = initialState, action) {
|
||||
action.timeline,
|
||||
initialTimeline,
|
||||
map => map.set('online', false).update('items', items => items.first() ? items.unshift(null) : items)
|
||||
);
|
||||
)
|
||||
case UNPIN_SUCCESS:
|
||||
return removeStatusFromAccountPins(state, action.accountId, action.status.get('id'))
|
||||
case GROUP_REMOVE_STATUS_SUCCESS:
|
||||
return removeStatusFromGroup(state, action.groupId, action.id)
|
||||
return removeStatusFromGroup(state, action.groupId, action.statusId)
|
||||
case GROUP_UNPIN_STATUS_SUCCESS:
|
||||
return removeStatusFromGroupPins(state, action.groupId, action.statusId)
|
||||
default:
|
||||
return state;
|
||||
return state
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -23,8 +23,18 @@ import {
|
||||
FOLLOW_REQUEST_REJECT_SUCCESS,
|
||||
} from '../actions/accounts'
|
||||
import {
|
||||
REPOSTS_FETCH_REQUEST,
|
||||
REPOSTS_FETCH_SUCCESS,
|
||||
REPOSTS_FETCH_FAIL,
|
||||
REPOSTS_EXPAND_REQUEST,
|
||||
REPOSTS_EXPAND_SUCCESS,
|
||||
REPOSTS_EXPAND_FAIL,
|
||||
LIKES_FETCH_REQUEST,
|
||||
LIKES_FETCH_SUCCESS,
|
||||
LIKES_FETCH_FAIL,
|
||||
LIKES_EXPAND_REQUEST,
|
||||
LIKES_EXPAND_SUCCESS,
|
||||
LIKES_EXPAND_FAIL,
|
||||
} from '../actions/interactions'
|
||||
import {
|
||||
BLOCKS_FETCH_REQUEST,
|
||||
@@ -52,6 +62,7 @@ import {
|
||||
GROUP_JOIN_REQUESTS_EXPAND_SUCCESS,
|
||||
GROUP_JOIN_REQUESTS_APPROVE_SUCCESS,
|
||||
GROUP_JOIN_REQUESTS_REJECT_SUCCESS,
|
||||
GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS,
|
||||
} from '../actions/groups'
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
@@ -119,12 +130,28 @@ export default function userLists(state = initialState, action) {
|
||||
case FOLLOWING_EXPAND_FAIL:
|
||||
return state.setIn(['following', action.id, 'isLoading'], false);
|
||||
|
||||
case REPOSTS_FETCH_REQUEST:
|
||||
case REPOSTS_EXPAND_REQUEST:
|
||||
return state.setIn(['reblogged_by', action.statusId, 'isLoading'], true)
|
||||
case REPOSTS_FETCH_SUCCESS:
|
||||
return state.setIn(['reblogged_by', action.id], ImmutableList(action.accounts.map(item => item.id)));
|
||||
return normalizeList(state, 'reblogged_by', action.statusId, action.accounts, action.next)
|
||||
case REPOSTS_EXPAND_SUCCESS:
|
||||
return appendToList(state, 'reblogged_by', action.statusId, action.accounts, action.next)
|
||||
case REPOSTS_FETCH_FAIL:
|
||||
case REPOSTS_EXPAND_FAIL:
|
||||
return setListFailed(state, 'reblogged_by', action.statusId)
|
||||
|
||||
case LIKES_FETCH_REQUEST:
|
||||
case LIKES_EXPAND_REQUEST:
|
||||
return state.setIn(['liked_by', action.statusId, 'isLoading'], true)
|
||||
case LIKES_FETCH_SUCCESS:
|
||||
return state.setIn(['liked_by', action.id], ImmutableList(action.accounts.map(item => item.id)));
|
||||
|
||||
return normalizeList(state, 'liked_by', action.statusId, action.accounts, action.next)
|
||||
case LIKES_EXPAND_SUCCESS:
|
||||
return appendToList(state, 'liked_by', action.statusId, action.accounts, action.next)
|
||||
case LIKES_FETCH_FAIL:
|
||||
case LIKES_EXPAND_FAIL:
|
||||
return setListFailed(state, 'liked_by', action.statusId)
|
||||
|
||||
case FOLLOW_REQUESTS_FETCH_SUCCESS:
|
||||
return normalizeList(state, 'follow_requests', me, action.accounts, action.next);
|
||||
case FOLLOW_REQUESTS_EXPAND_SUCCESS:
|
||||
@@ -162,21 +189,24 @@ export default function userLists(state = initialState, action) {
|
||||
return setListFailed(state, 'mutes', me)
|
||||
|
||||
case GROUP_MEMBERS_FETCH_SUCCESS:
|
||||
return normalizeList(state, 'groups', action.id, action.accounts, action.next);
|
||||
return normalizeList(state, 'groups', action.groupId, action.accounts, action.next);
|
||||
case GROUP_MEMBERS_EXPAND_SUCCESS:
|
||||
return appendToList(state, 'groups', action.id, action.accounts, action.next);
|
||||
return appendToList(state, 'groups', action.groupId, action.accounts, action.next);
|
||||
|
||||
case GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS:
|
||||
return state.updateIn(['groups', action.groupId, 'items'], list => list.filterNot(item => item === action.accountId));
|
||||
|
||||
case GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS:
|
||||
return normalizeList(state, 'group_removed_accounts', action.id, action.accounts, action.next);
|
||||
return normalizeList(state, 'group_removed_accounts', action.groupId, action.accounts, action.next);
|
||||
case GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS:
|
||||
return appendToList(state, 'group_removed_accounts', action.id, action.accounts, action.next);
|
||||
return appendToList(state, 'group_removed_accounts', action.groupId, action.accounts, action.next);
|
||||
case GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS:
|
||||
return state.updateIn(['group_removed_accounts', action.groupId, 'items'], list => list.filterNot(item => item === action.id));
|
||||
return state.updateIn(['group_removed_accounts', action.groupId, 'items'], list => list.filterNot(item => item === action.accountId));
|
||||
|
||||
case GROUP_JOIN_REQUESTS_FETCH_SUCCESS:
|
||||
return normalizeList(state, 'group_join_requests', action.id, action.accounts, action.next);
|
||||
return normalizeList(state, 'group_join_requests', action.groupId, action.accounts, action.next);
|
||||
case GROUP_JOIN_REQUESTS_EXPAND_SUCCESS:
|
||||
return appendToList(state, 'group_join_requests', action.id, action.accounts, action.next);
|
||||
return appendToList(state, 'group_join_requests', action.groupId, action.accounts, action.next);
|
||||
case GROUP_JOIN_REQUESTS_APPROVE_SUCCESS:
|
||||
case GROUP_JOIN_REQUESTS_REJECT_SUCCESS:
|
||||
return state.updateIn(['group_join_requests', action.groupId, 'items'], list => list.filterNot(item => item === action.accountId));
|
||||
|
||||
@@ -124,7 +124,7 @@ export const makeGetStatus = () => {
|
||||
}
|
||||
|
||||
|
||||
console.log("group:", group)
|
||||
// console.log("group:", group)
|
||||
|
||||
//Find ancestor status
|
||||
|
||||
|
||||
@@ -31,15 +31,3 @@ delegate(document, '.media-spoiler-hide-button', 'click', () => {
|
||||
});
|
||||
});
|
||||
|
||||
delegate(document, '#domain_block_severity', 'change', ({ target }) => {
|
||||
const rejectMediaDiv = document.querySelector('.input.with_label.domain_block_reject_media');
|
||||
const rejectReportsDiv = document.querySelector('.input.with_label.domain_block_reject_reports');
|
||||
|
||||
if (rejectMediaDiv) {
|
||||
rejectMediaDiv.style.display = (target.value === 'suspend') ? 'none' : 'block';
|
||||
}
|
||||
|
||||
if (rejectReportsDiv) {
|
||||
rejectReportsDiv.style.display = (target.value === 'suspend') ? 'none' : 'block';
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user