sforkowany z mirror/soapbox
Merge branch 'quote-posts' into 'develop'
Show quoted statuses list See merge request soapbox-pub/soapbox!1457ads-account
commit
0c16ffeb02
|
@ -0,0 +1,15 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"id": "ABDSjI3Q0R8aDaz1U0"
|
||||||
|
},
|
||||||
|
"content": "quoast",
|
||||||
|
"id": "AJsajx9hY4Q7IKQXEe",
|
||||||
|
"pleroma": {
|
||||||
|
"quote": {
|
||||||
|
"content": "<p>10</p>",
|
||||||
|
"id": "AJmoVikzI3SkyITyim"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,150 @@
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
|
import { __stub } from 'soapbox/api';
|
||||||
|
import { mockStore, rootState } from 'soapbox/jest/test-helpers';
|
||||||
|
import { StatusListRecord } from 'soapbox/reducers/status-lists';
|
||||||
|
|
||||||
|
import { fetchStatusQuotes, expandStatusQuotes } from '../status-quotes';
|
||||||
|
|
||||||
|
const status = {
|
||||||
|
account: {
|
||||||
|
id: 'ABDSjI3Q0R8aDaz1U0',
|
||||||
|
},
|
||||||
|
content: 'quoast',
|
||||||
|
id: 'AJsajx9hY4Q7IKQXEe',
|
||||||
|
pleroma: {
|
||||||
|
quote: {
|
||||||
|
content: '<p>10</p>',
|
||||||
|
id: 'AJmoVikzI3SkyITyim',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusId = 'AJmoVikzI3SkyITyim';
|
||||||
|
|
||||||
|
describe('fetchStatusQuotes()', () => {
|
||||||
|
let store: ReturnType<typeof mockStore>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootState.set('me', '1234');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const quotes = require('soapbox/__fixtures__/status-quotes.json');
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/pleroma/statuses/${statusId}/quotes`).reply(200, quotes, {
|
||||||
|
link: `<https://example.com/api/v1/pleroma/statuses/${statusId}/quotes?since_id=1>; rel='prev'`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch quotes from the API', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'STATUS_QUOTES_FETCH_REQUEST', statusId },
|
||||||
|
{ type: 'POLLS_IMPORT', polls: [] },
|
||||||
|
{ type: 'ACCOUNTS_IMPORT', accounts: [status.account] },
|
||||||
|
{ type: 'STATUSES_IMPORT', statuses: [status], expandSpoilers: false },
|
||||||
|
{ type: 'STATUS_QUOTES_FETCH_SUCCESS', statusId, statuses: [status], next: null },
|
||||||
|
];
|
||||||
|
await store.dispatch(fetchStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/pleroma/statuses/${statusId}/quotes`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch failed action', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'STATUS_QUOTES_FETCH_REQUEST', statusId },
|
||||||
|
{ type: 'STATUS_QUOTES_FETCH_FAIL', statusId, error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(fetchStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('expandStatusQuotes()', () => {
|
||||||
|
let store: ReturnType<typeof mockStore>;
|
||||||
|
|
||||||
|
describe('without a url', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootState
|
||||||
|
.set('me', '1234')
|
||||||
|
.set('status_lists', ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: null }) }));
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(expandStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a url', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootState.set('me', '1234')
|
||||||
|
.set('status_lists', ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: 'example' }) }));
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const quotes = require('soapbox/__fixtures__/status-quotes.json');
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet('example').reply(200, quotes, {
|
||||||
|
link: `<https://example.com/api/v1/pleroma/statuses/${statusId}/quotes?since_id=1>; rel='prev'`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch quotes from the API', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'STATUS_QUOTES_EXPAND_REQUEST', statusId },
|
||||||
|
{ type: 'POLLS_IMPORT', polls: [] },
|
||||||
|
{ type: 'ACCOUNTS_IMPORT', accounts: [status.account] },
|
||||||
|
{ type: 'STATUSES_IMPORT', statuses: [status], expandSpoilers: false },
|
||||||
|
{ type: 'STATUS_QUOTES_EXPAND_SUCCESS', statusId, statuses: [status], next: null },
|
||||||
|
];
|
||||||
|
await store.dispatch(expandStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet('example').networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch failed action', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'STATUS_QUOTES_EXPAND_REQUEST', statusId },
|
||||||
|
{ type: 'STATUS_QUOTES_EXPAND_FAIL', statusId, error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(expandStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,75 @@
|
||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import { importFetchedStatuses } from './importer';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
export const STATUS_QUOTES_FETCH_REQUEST = 'STATUS_QUOTES_FETCH_REQUEST';
|
||||||
|
export const STATUS_QUOTES_FETCH_SUCCESS = 'STATUS_QUOTES_FETCH_SUCCESS';
|
||||||
|
export const STATUS_QUOTES_FETCH_FAIL = 'STATUS_QUOTES_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const STATUS_QUOTES_EXPAND_REQUEST = 'STATUS_QUOTES_EXPAND_REQUEST';
|
||||||
|
export const STATUS_QUOTES_EXPAND_SUCCESS = 'STATUS_QUOTES_EXPAND_SUCCESS';
|
||||||
|
export const STATUS_QUOTES_EXPAND_FAIL = 'STATUS_QUOTES_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const noOp = () => new Promise(f => f(null));
|
||||||
|
|
||||||
|
export const fetchStatusQuotes = (statusId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (getState().status_lists.getIn([`quotes:${statusId}`, 'isLoading'])) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
statusId,
|
||||||
|
type: STATUS_QUOTES_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
return api(getState).get(`/api/v1/pleroma/statuses/${statusId}/quotes`).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
return dispatch({
|
||||||
|
type: STATUS_QUOTES_FETCH_SUCCESS,
|
||||||
|
statusId,
|
||||||
|
statuses: response.data,
|
||||||
|
next: next ? next.uri : null,
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({
|
||||||
|
type: STATUS_QUOTES_FETCH_FAIL,
|
||||||
|
statusId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const expandStatusQuotes = (statusId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const url = getState().status_lists.getIn([`quotes:${statusId}`, 'next'], null) as string | null;
|
||||||
|
|
||||||
|
if (url === null || getState().status_lists.getIn([`quotes:${statusId}`, 'isLoading'])) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: STATUS_QUOTES_EXPAND_REQUEST,
|
||||||
|
statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch({
|
||||||
|
type: STATUS_QUOTES_EXPAND_SUCCESS,
|
||||||
|
statusId,
|
||||||
|
statuses: response.data,
|
||||||
|
next: next ? next.uri : null,
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({
|
||||||
|
type: STATUS_QUOTES_EXPAND_FAIL,
|
||||||
|
statusId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { expandStatusQuotes, fetchStatusQuotes } from 'soapbox/actions/status-quotes';
|
||||||
|
import StatusList from 'soapbox/components/status-list';
|
||||||
|
import { Column } from 'soapbox/components/ui';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.quotes', defaultMessage: 'Post quotes' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLoadMore = debounce((statusId: string, dispatch: React.Dispatch<any>) =>
|
||||||
|
dispatch(expandStatusQuotes(statusId)), 300, { leading: true });
|
||||||
|
|
||||||
|
const Quotes: React.FC = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const intl = useIntl();
|
||||||
|
const { statusId } = useParams<{ statusId: string }>();
|
||||||
|
|
||||||
|
const statusIds = useAppSelector((state) => state.status_lists.getIn([`quotes:${statusId}`, 'items'], ImmutableOrderedSet<string>()));
|
||||||
|
const isLoading = useAppSelector((state) => state.status_lists.getIn([`quotes:${statusId}`, 'isLoading'], true));
|
||||||
|
const hasMore = useAppSelector((state) => !!state.status_lists.getIn([`quotes:${statusId}`, 'next']));
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
dispatch(fetchStatusQuotes(statusId));
|
||||||
|
}, [statusId]);
|
||||||
|
|
||||||
|
const handleRefresh = async() => {
|
||||||
|
await dispatch(fetchStatusQuotes(statusId));
|
||||||
|
};
|
||||||
|
|
||||||
|
const emptyMessage = <FormattedMessage id='empty_column.quotes' defaultMessage='This post has not been quoted yet.' />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column label={intl.formatMessage(messages.heading)} transparent>
|
||||||
|
<StatusList
|
||||||
|
statusIds={statusIds as ImmutableOrderedSet<string>}
|
||||||
|
scrollKey={`quotes:${statusId}`}
|
||||||
|
hasMore={hasMore}
|
||||||
|
isLoading={typeof isLoading === 'boolean' ? isLoading : true}
|
||||||
|
onLoadMore={() => handleLoadMore(statusId, dispatch)}
|
||||||
|
onRefresh={handleRefresh}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
divideType='space'
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Quotes;
|
|
@ -3,6 +3,7 @@ import { List as ImmutableList } from 'immutable';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import { openModal } from 'soapbox/actions/modals';
|
import { openModal } from 'soapbox/actions/modals';
|
||||||
import { HStack, Text, Emoji } from 'soapbox/components/ui';
|
import { HStack, Text, Emoji } from 'soapbox/components/ui';
|
||||||
|
@ -16,6 +17,8 @@ interface IStatusInteractionBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.Element | null => {
|
const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.Element | null => {
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
const me = useAppSelector(({ me }) => me);
|
const me = useAppSelector(({ me }) => me);
|
||||||
const { allowedEmoji } = useSoapboxConfig();
|
const { allowedEmoji } = useSoapboxConfig();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
@ -81,6 +84,28 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const navigateToQuotes: React.EventHandler<React.MouseEvent> = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
history.push(`/@${status.getIn(['account', 'acct'])}/posts/${status.id}/quotes`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getQuotes = () => {
|
||||||
|
if (status.quotes_count) {
|
||||||
|
return (
|
||||||
|
<InteractionCounter count={status.quotes_count} onClick={navigateToQuotes}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.interactions.quotes'
|
||||||
|
defaultMessage='{count, plural, one {Quote} other {Quotes}}'
|
||||||
|
values={{ count: status.quotes_count }}
|
||||||
|
/>
|
||||||
|
</InteractionCounter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
const handleOpenFavouritesModal: React.EventHandler<React.MouseEvent<HTMLButtonElement>> = (e) => {
|
const handleOpenFavouritesModal: React.EventHandler<React.MouseEvent<HTMLButtonElement>> = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -142,6 +167,7 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.
|
||||||
return (
|
return (
|
||||||
<HStack space={3}>
|
<HStack space={3}>
|
||||||
{getReposts()}
|
{getReposts()}
|
||||||
|
{getQuotes()}
|
||||||
{features.emojiReacts ? getEmojiReacts() : getFavourites()}
|
{features.emojiReacts ? getEmojiReacts() : getFavourites()}
|
||||||
</HStack>
|
</HStack>
|
||||||
);
|
);
|
||||||
|
|
|
@ -109,6 +109,7 @@ import {
|
||||||
TestTimeline,
|
TestTimeline,
|
||||||
LogoutPage,
|
LogoutPage,
|
||||||
AuthTokenList,
|
AuthTokenList,
|
||||||
|
Quotes,
|
||||||
ServiceWorkerInfo,
|
ServiceWorkerInfo,
|
||||||
} from './util/async-components';
|
} from './util/async-components';
|
||||||
import { WrappedRoute } from './util/react-router-helpers';
|
import { WrappedRoute } from './util/react-router-helpers';
|
||||||
|
@ -265,6 +266,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
|
||||||
<WrappedRoute path='/@:username/favorites' component={FavouritedStatuses} page={ProfilePage} content={children} />
|
<WrappedRoute path='/@:username/favorites' component={FavouritedStatuses} page={ProfilePage} content={children} />
|
||||||
<WrappedRoute path='/@:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
|
<WrappedRoute path='/@:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
|
||||||
<WrappedRoute path='/@:username/posts/:statusId' publicRoute exact page={StatusPage} component={Status} content={children} />
|
<WrappedRoute path='/@:username/posts/:statusId' publicRoute exact page={StatusPage} component={Status} content={children} />
|
||||||
|
<WrappedRoute path='/@:username/posts/:statusId/quotes' publicRoute page={StatusPage} component={Quotes} content={children} />
|
||||||
<Redirect from='/@:username/:statusId' to='/@:username/posts/:statusId' />
|
<Redirect from='/@:username/:statusId' to='/@:username/posts/:statusId' />
|
||||||
|
|
||||||
<WrappedRoute path='/statuses/new' page={DefaultPage} component={NewStatus} content={children} exact />
|
<WrappedRoute path='/statuses/new' page={DefaultPage} component={NewStatus} content={children} exact />
|
||||||
|
|
|
@ -505,3 +505,7 @@ export function FamiliarFollowersModal() {
|
||||||
export function AnnouncementsPanel() {
|
export function AnnouncementsPanel() {
|
||||||
return import(/* webpackChunkName: "features/announcements" */'../../../components/announcements/announcements-panel');
|
return import(/* webpackChunkName: "features/announcements" */'../../../components/announcements/announcements-panel');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function Quotes() {
|
||||||
|
return import(/*webpackChunkName: "features/quotes" */'../../quotes');
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ export const StatusRecord = ImmutableRecord({
|
||||||
pleroma: ImmutableMap<string, any>(),
|
pleroma: ImmutableMap<string, any>(),
|
||||||
poll: null as EmbeddedEntity<Poll>,
|
poll: null as EmbeddedEntity<Poll>,
|
||||||
quote: null as EmbeddedEntity<any>,
|
quote: null as EmbeddedEntity<any>,
|
||||||
|
quotes_count: 0,
|
||||||
reblog: null as EmbeddedEntity<any>,
|
reblog: null as EmbeddedEntity<any>,
|
||||||
reblogged: false,
|
reblogged: false,
|
||||||
reblogs_count: 0,
|
reblogs_count: 0,
|
||||||
|
@ -142,6 +143,8 @@ const fixQuote = (status: ImmutableMap<string, any>) => {
|
||||||
return status.withMutations(status => {
|
return status.withMutations(status => {
|
||||||
status.update('quote', quote => quote || status.getIn(['pleroma', 'quote']) || null);
|
status.update('quote', quote => quote || status.getIn(['pleroma', 'quote']) || null);
|
||||||
status.deleteIn(['pleroma', 'quote']);
|
status.deleteIn(['pleroma', 'quote']);
|
||||||
|
status.update('quotes_count', quotes_count => quotes_count || status.getIn(['pleroma', 'quotes_count'], 0));
|
||||||
|
status.deleteIn(['pleroma', 'quotes_count']);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,15 @@ import {
|
||||||
Record as ImmutableRecord,
|
Record as ImmutableRecord,
|
||||||
} from 'immutable';
|
} from 'immutable';
|
||||||
|
|
||||||
|
import {
|
||||||
|
STATUS_QUOTES_EXPAND_FAIL,
|
||||||
|
STATUS_QUOTES_EXPAND_REQUEST,
|
||||||
|
STATUS_QUOTES_EXPAND_SUCCESS,
|
||||||
|
STATUS_QUOTES_FETCH_FAIL,
|
||||||
|
STATUS_QUOTES_FETCH_REQUEST,
|
||||||
|
STATUS_QUOTES_FETCH_SUCCESS,
|
||||||
|
} from 'soapbox/actions/status-quotes';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BOOKMARKED_STATUSES_FETCH_REQUEST,
|
BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||||
BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
||||||
|
@ -51,7 +60,7 @@ import {
|
||||||
import type { AnyAction } from 'redux';
|
import type { AnyAction } from 'redux';
|
||||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
const StatusListRecord = ImmutableRecord({
|
export const StatusListRecord = ImmutableRecord({
|
||||||
next: null as string | null,
|
next: null as string | null,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
isLoading: null as boolean | null,
|
isLoading: null as boolean | null,
|
||||||
|
@ -168,6 +177,16 @@ export default function statusLists(state = initialState, action: AnyAction) {
|
||||||
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
||||||
case SCHEDULED_STATUS_CANCEL_SUCCESS:
|
case SCHEDULED_STATUS_CANCEL_SUCCESS:
|
||||||
return removeOneFromList(state, 'scheduled_statuses', action.id || action.status.id);
|
return removeOneFromList(state, 'scheduled_statuses', action.id || action.status.id);
|
||||||
|
case STATUS_QUOTES_FETCH_REQUEST:
|
||||||
|
case STATUS_QUOTES_EXPAND_REQUEST:
|
||||||
|
return setLoading(state, `quotes:${action.statusId}`, true);
|
||||||
|
case STATUS_QUOTES_FETCH_FAIL:
|
||||||
|
case STATUS_QUOTES_EXPAND_FAIL:
|
||||||
|
return setLoading(state, `quotes:${action.statusId}`, false);
|
||||||
|
case STATUS_QUOTES_FETCH_SUCCESS:
|
||||||
|
return normalizeList(state, `quotes:${action.statusId}`, action.statuses, action.next);
|
||||||
|
case STATUS_QUOTES_EXPAND_SUCCESS:
|
||||||
|
return appendToList(state, `quotes:${action.statusId}`, action.statuses, action.next);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue