Wip: bookmark categories
This commit is contained in:
parent
020e50d0c5
commit
f6bdd9b6de
13 changed files with 866 additions and 1 deletions
379
app/javascript/mastodon/actions/bookmark_categories.js
Normal file
379
app/javascript/mastodon/actions/bookmark_categories.js
Normal file
|
@ -0,0 +1,379 @@
|
||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import { importFetchedStatuses } from './importer';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_FETCH_REQUEST = 'BOOKMARK_CATEGORY_FETCH_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_FETCH_SUCCESS = 'BOOKMARK_CATEGORY_FETCH_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_FETCH_FAIL = 'BOOKMARK_CATEGORY_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORIES_FETCH_REQUEST = 'BOOKMARK_CATEGORIES_FETCH_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORIES_FETCH_SUCCESS = 'BOOKMARK_CATEGORIES_FETCH_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORIES_FETCH_FAIL = 'BOOKMARK_CATEGORIES_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_TITLE_CHANGE = 'BOOKMARK_CATEGORY_EDITOR_TITLE_CHANGE';
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_RESET = 'BOOKMARK_CATEGORY_EDITOR_RESET';
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_SETUP = 'BOOKMARK_CATEGORY_EDITOR_SETUP';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_CREATE_REQUEST = 'BOOKMARK_CATEGORY_CREATE_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_CREATE_SUCCESS = 'BOOKMARK_CATEGORY_CREATE_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_CREATE_FAIL = 'BOOKMARK_CATEGORY_CREATE_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_UPDATE_REQUEST = 'BOOKMARK_CATEGORY_UPDATE_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_UPDATE_SUCCESS = 'BOOKMARK_CATEGORY_UPDATE_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_UPDATE_FAIL = 'BOOKMARK_CATEGORY_UPDATE_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_DELETE_REQUEST = 'BOOKMARK_CATEGORY_DELETE_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_DELETE_SUCCESS = 'BOOKMARK_CATEGORY_DELETE_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_DELETE_FAIL = 'BOOKMARK_CATEGORY_DELETE_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_STATUSES_FETCH_REQUEST = 'BOOKMARK_CATEGORY_STATUSES_FETCH_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_STATUSES_FETCH_SUCCESS = 'BOOKMARK_CATEGORY_STATUSES_FETCH_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_STATUSES_FETCH_FAIL = 'BOOKMARK_CATEGORY_STATUSES_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_ADD_REQUEST = 'BOOKMARK_CATEGORY_EDITOR_ADD_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_ADD_SUCCESS = 'BOOKMARK_CATEGORY_EDITOR_ADD_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_ADD_FAIL = 'BOOKMARK_CATEGORY_EDITOR_ADD_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_REMOVE_REQUEST = 'BOOKMARK_CATEGORY_EDITOR_REMOVE_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_REMOVE_SUCCESS = 'BOOKMARK_CATEGORY_EDITOR_REMOVE_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_EDITOR_REMOVE_FAIL = 'BOOKMARK_CATEGORY_EDITOR_REMOVE_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_ADDER_RESET = 'BOOKMARK_CATEGORY_ADDER_RESET';
|
||||||
|
export const BOOKMARK_CATEGORY_ADDER_SETUP = 'BOOKMARK_CATEGORY_ADDER_SETUP';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_REQUEST = 'BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_SUCCESS = 'BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_FAIL = 'BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const BOOKMARK_CATEGORY_STATUSES_EXPAND_REQUEST = 'BOOKMARK_CATEGORY_STATUSES_EXPAND_REQUEST';
|
||||||
|
export const BOOKMARK_CATEGORY_STATUSES_EXPAND_SUCCESS = 'BOOKMARK_CATEGORY_STATUSES_EXPAND_SUCCESS';
|
||||||
|
export const BOOKMARK_CATEGORY_STATUSES_EXPAND_FAIL = 'BOOKMARK_CATEGORY_STATUSES_EXPAND_FAIL';
|
||||||
|
|
||||||
|
export const fetchBookmarkCategory = id => (dispatch, getState) => {
|
||||||
|
if (getState().getIn(['bookmark_categories', id])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchBookmarkCategoryRequest(id));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/bookmark_categories/${id}`)
|
||||||
|
.then(({ data }) => dispatch(fetchBookmarkCategorySuccess(data)))
|
||||||
|
.catch(err => dispatch(fetchBookmarkCategoryFail(id, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoryRequest = id => ({
|
||||||
|
type: BOOKMARK_CATEGORY_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchBookmarkCategorySuccess = bookmarkCategory => ({
|
||||||
|
type: BOOKMARK_CATEGORY_FETCH_SUCCESS,
|
||||||
|
bookmarkCategory,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoryFail = (id, error) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchBookmarkCategories = () => (dispatch, getState) => {
|
||||||
|
dispatch(fetchBookmarkCategoriesRequest());
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/bookmark_categories')
|
||||||
|
.then(({ data }) => dispatch(fetchBookmarkCategoriesSuccess(data)))
|
||||||
|
.catch(err => dispatch(fetchBookmarkCategoriesFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoriesRequest = () => ({
|
||||||
|
type: BOOKMARK_CATEGORIES_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoriesSuccess = bookmarkCategories => ({
|
||||||
|
type: BOOKMARK_CATEGORIES_FETCH_SUCCESS,
|
||||||
|
bookmarkCategories,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoriesFail = error => ({
|
||||||
|
type: BOOKMARK_CATEGORIES_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submitBookmarkCategoryEditor = shouldReset => (dispatch, getState) => {
|
||||||
|
const bookmarkCategoryId = getState().getIn(['bookmarkCategoryEditor', 'bookmarkCategoryId']);
|
||||||
|
const title = getState().getIn(['bookmarkCategoryEditor', 'title']);
|
||||||
|
|
||||||
|
if (bookmarkCategoryId === null) {
|
||||||
|
dispatch(createBookmarkCategory(title, shouldReset));
|
||||||
|
} else {
|
||||||
|
dispatch(updateBookmarkCategory(bookmarkCategoryId, title, shouldReset));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setupBookmarkCategoryEditor = bookmarkCategoryId => (dispatch, getState) => {
|
||||||
|
dispatch({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_SETUP,
|
||||||
|
bookmarkCategory: getState().getIn(['bookmarkCategories', bookmarkCategoryId]),
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(fetchBookmarkCategoryStatuses(bookmarkCategoryId));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const changeBookmarkCategoryEditorTitle = value => ({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_TITLE_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createBookmarkCategory = (title, shouldReset) => (dispatch, getState) => {
|
||||||
|
dispatch(createBookmarkCategoryRequest());
|
||||||
|
|
||||||
|
api(getState).post('/api/v1/bookmark_categories', { title }).then(({ data }) => {
|
||||||
|
dispatch(createBookmarkCategorySuccess(data));
|
||||||
|
|
||||||
|
if (shouldReset) {
|
||||||
|
dispatch(resetBookmarkCategoryEditor());
|
||||||
|
}
|
||||||
|
}).catch(err => dispatch(createBookmarkCategoryFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createBookmarkCategoryRequest = () => ({
|
||||||
|
type: BOOKMARK_CATEGORY_CREATE_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createBookmarkCategorySuccess = bookmarkCategory => ({
|
||||||
|
type: BOOKMARK_CATEGORY_CREATE_SUCCESS,
|
||||||
|
bookmarkCategory,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createBookmarkCategoryFail = error => ({
|
||||||
|
type: BOOKMARK_CATEGORY_CREATE_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const updateBookmarkCategory = (id, title, shouldReset, isExclusive, replies_policy) => (dispatch, getState) => {
|
||||||
|
dispatch(updateBookmarkCategoryRequest(id));
|
||||||
|
|
||||||
|
api(getState).put(`/api/v1/bookmark_categories/${id}`, { title, replies_policy, exclusive: typeof isExclusive === 'undefined' ? undefined : !!isExclusive }).then(({ data }) => {
|
||||||
|
dispatch(updateBookmarkCategorySuccess(data));
|
||||||
|
|
||||||
|
if (shouldReset) {
|
||||||
|
dispatch(resetBookmarkCategoryEditor());
|
||||||
|
}
|
||||||
|
}).catch(err => dispatch(updateBookmarkCategoryFail(id, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateBookmarkCategoryRequest = id => ({
|
||||||
|
type: BOOKMARK_CATEGORY_UPDATE_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const updateBookmarkCategorySuccess = bookmarkCategory => ({
|
||||||
|
type: BOOKMARK_CATEGORY_UPDATE_SUCCESS,
|
||||||
|
bookmarkCategory,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const updateBookmarkCategoryFail = (id, error) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_UPDATE_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const resetBookmarkCategoryEditor = () => ({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_RESET,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const deleteBookmarkCategory = id => (dispatch, getState) => {
|
||||||
|
dispatch(deleteBookmarkCategoryRequest(id));
|
||||||
|
|
||||||
|
api(getState).delete(`/api/v1/bookmark_categories/${id}`)
|
||||||
|
.then(() => dispatch(deleteBookmarkCategorySuccess(id)))
|
||||||
|
.catch(err => dispatch(deleteBookmarkCategoryFail(id, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteBookmarkCategoryRequest = id => ({
|
||||||
|
type: BOOKMARK_CATEGORY_DELETE_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const deleteBookmarkCategorySuccess = id => ({
|
||||||
|
type: BOOKMARK_CATEGORY_DELETE_SUCCESS,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const deleteBookmarkCategoryFail = (id, error) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_DELETE_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoryStatuses = bookmarkCategoryId => (dispatch, getState) => {
|
||||||
|
dispatch(fetchBookmarkCategoryStatusesRequest(bookmarkCategoryId));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/bookmark_categories/${bookmarkCategoryId}/statuses`, { params: { limit: 0 } }).then(({ data }) => {
|
||||||
|
dispatch(importFetchedStatuses(data));
|
||||||
|
dispatch(fetchBookmarkCategoryStatusesSuccess(bookmarkCategoryId, data));
|
||||||
|
}).catch(err => dispatch(fetchBookmarkCategoryStatusesFail(bookmarkCategoryId, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoryStatusesRequest = id => ({
|
||||||
|
type: BOOKMARK_CATEGORY_STATUSES_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoryStatusesSuccess = (id, statuses, next) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_STATUSES_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchBookmarkCategoryStatusesFail = (id, error) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_STATUSES_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addToBookmarkCategory = (bookmarkCategoryId, statusId) => (dispatch, getState) => {
|
||||||
|
dispatch(addToBookmarkCategoryRequest(bookmarkCategoryId, statusId));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/bookmark_categories/${bookmarkCategoryId}/statuses`, { status_ids: [statusId] })
|
||||||
|
.then(() => dispatch(addToBookmarkCategorySuccess(bookmarkCategoryId, statusId)))
|
||||||
|
.catch(err => dispatch(addToBookmarkCategoryFail(bookmarkCategoryId, statusId, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addToBookmarkCategoryRequest = (bookmarkCategoryId, statusId) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_ADD_REQUEST,
|
||||||
|
bookmarkCategoryId,
|
||||||
|
statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addToBookmarkCategorySuccess = (bookmarkCategoryId, statusId) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_ADD_SUCCESS,
|
||||||
|
bookmarkCategoryId,
|
||||||
|
statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addToBookmarkCategoryFail = (bookmarkCategoryId, statusId, error) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_ADD_FAIL,
|
||||||
|
bookmarkCategoryId,
|
||||||
|
statusId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const removeFromBookmarkCategory = (bookmarkCategoryId, statusId) => (dispatch, getState) => {
|
||||||
|
dispatch(removeFromBookmarkCategoryRequest(bookmarkCategoryId, statusId));
|
||||||
|
|
||||||
|
api(getState).delete(`/api/v1/bookmark_categories/${bookmarkCategoryId}/statuses`, { params: { status_ids: [statusId] } })
|
||||||
|
.then(() => dispatch(removeFromBookmarkCategorySuccess(bookmarkCategoryId, statusId)))
|
||||||
|
.catch(err => dispatch(removeFromBookmarkCategoryFail(bookmarkCategoryId, statusId, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeFromBookmarkCategoryRequest = (bookmarkCategoryId, statusId) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_REMOVE_REQUEST,
|
||||||
|
bookmarkCategoryId,
|
||||||
|
statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const removeFromBookmarkCategorySuccess = (bookmarkCategoryId, statusId) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_REMOVE_SUCCESS,
|
||||||
|
bookmarkCategoryId,
|
||||||
|
statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const removeFromBookmarkCategoryFail = (bookmarkCategoryId, statusId, error) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_EDITOR_REMOVE_FAIL,
|
||||||
|
bookmarkCategoryId,
|
||||||
|
statusId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const resetBookmarkCategoryAdder = () => ({
|
||||||
|
type: BOOKMARK_CATEGORY_ADDER_RESET,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setupBookmarkCategoryAdder = statusId => (dispatch, getState) => {
|
||||||
|
dispatch({
|
||||||
|
type: BOOKMARK_CATEGORY_ADDER_SETUP,
|
||||||
|
status: getState().getIn(['statuses', statusId]),
|
||||||
|
});
|
||||||
|
dispatch(fetchBookmarkCategories());
|
||||||
|
dispatch(fetchStatusBookmarkCategories(statusId));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchStatusBookmarkCategories = statusId => (dispatch, getState) => {
|
||||||
|
dispatch(fetchStatusBookmarkCategoriesRequest(statusId));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/statuses/${statusId}/bookmark_categories`)
|
||||||
|
.then(({ data }) => dispatch(fetchStatusBookmarkCategoriesSuccess(statusId, data)))
|
||||||
|
.catch(err => dispatch(fetchStatusBookmarkCategoriesFail(statusId, err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchStatusBookmarkCategoriesRequest = id => ({
|
||||||
|
type:BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchStatusBookmarkCategoriesSuccess = (id, bookmarkCategories) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
bookmarkCategories,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchStatusBookmarkCategoriesFail = (id, err) => ({
|
||||||
|
type: BOOKMARK_CATEGORY_ADDER_BOOKMARK_CATEGORIES_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addToBookmarkCategoryAdder = bookmarkCategoryId => (dispatch, getState) => {
|
||||||
|
dispatch(addToBookmarkCategory(bookmarkCategoryId, getState().getIn(['bookmarkCategoryAdder', 'statusId'])));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeFromBookmarkCategoryAdder = bookmarkCategoryId => (dispatch, getState) => {
|
||||||
|
dispatch(removeFromBookmarkCategory(bookmarkCategoryId, getState().getIn(['bookmarkCategoryAdder', 'statusId'])));
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandBookmarkCategoryStatuses(bookmarkCategoryId) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const url = getState().getIn(['bookmark_categories', bookmarkCategoryId, 'next'], null);
|
||||||
|
|
||||||
|
if (url === null || getState().getIn(['bookmark_categories', bookmarkCategoryId, 'isLoading'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandBookmarkCategoryStatusesRequest(bookmarkCategoryId));
|
||||||
|
|
||||||
|
api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch(expandBookmarkCategoryStatusesSuccess(bookmarkCategoryId, response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandBookmarkCategoryStatusesFail(bookmarkCategoryId, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expandBookmarkCategoryStatusesRequest(id) {
|
||||||
|
return {
|
||||||
|
type: BOOKMARK_CATEGORY_STATUSES_EXPAND_REQUEST,
|
||||||
|
id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expandBookmarkCategoryStatusesSuccess(id, statuses, next) {
|
||||||
|
return {
|
||||||
|
type: BOOKMARK_CATEGORY_STATUSES_EXPAND_SUCCESS,
|
||||||
|
id,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expandBookmarkCategoryStatusesFail(id, error) {
|
||||||
|
return {
|
||||||
|
type: BOOKMARK_CATEGORY_STATUSES_EXPAND_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { PureComponent } from 'react';
|
||||||
|
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { changeBookmarkCategoryEditorTitle, submitBookmarkCategoryEditor } from 'mastodon/actions/bookmark_categories';
|
||||||
|
import Button from 'mastodon/components/button';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
label: { id: 'bookmark_categories.new.title_placeholder', defaultMessage: 'New category title' },
|
||||||
|
title: { id: 'bookmark_categories.new.create', defaultMessage: 'Add category' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
value: state.getIn(['bookmarkCategoryEditor', 'title']),
|
||||||
|
disabled: state.getIn(['bookmarkCategoryEditor', 'isSubmitting']),
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
onChange: value => dispatch(changeBookmarkCategoryEditorTitle(value)),
|
||||||
|
onSubmit: () => dispatch(submitBookmarkCategoryEditor(true)),
|
||||||
|
});
|
||||||
|
|
||||||
|
class NewBookmarkCategoryForm extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.string.isRequired,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
onSubmit: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = e => {
|
||||||
|
this.props.onChange(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSubmit = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onSubmit();
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClick = () => {
|
||||||
|
this.props.onSubmit();
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { value, disabled, intl } = this.props;
|
||||||
|
|
||||||
|
const label = intl.formatMessage(messages.label);
|
||||||
|
const title = intl.formatMessage(messages.title);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className='column-inline-form' onSubmit={this.handleSubmit}>
|
||||||
|
<label>
|
||||||
|
<span style={{ display: 'none' }}>{label}</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
className='setting-text'
|
||||||
|
value={value}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
placeholder={label}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
disabled={disabled || !value}
|
||||||
|
text={title}
|
||||||
|
onClick={this.handleClick}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(NewBookmarkCategoryForm));
|
|
@ -0,0 +1,93 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Helmet } from 'react-helmet';
|
||||||
|
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
import { fetchBookmarkCategories } from 'mastodon/actions/bookmark_categories';
|
||||||
|
import Column from 'mastodon/components/column';
|
||||||
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
|
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||||
|
import ColumnLink from 'mastodon/features/ui/components/column_link';
|
||||||
|
import ColumnSubheading from 'mastodon/features/ui/components/column_subheading';
|
||||||
|
|
||||||
|
import NewListForm from './components/new_list_form';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.bookmark_categories', defaultMessage: 'Bookmark categories' },
|
||||||
|
subheading: { id: 'bookmark_categories_ex.subheading', defaultMessage: 'Your categories' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const getOrderedCategories = createSelector([state => state.get('bookmark_categories')], categories => {
|
||||||
|
if (!categories) {
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
return categories.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title')));
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
categories: getOrderedCategories(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
class BookmarkCategories extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
params: PropTypes.object.isRequired,
|
||||||
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
categories: ImmutablePropTypes.list,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
multiColumn: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
UNSAFE_componentWillMount () {
|
||||||
|
this.props.dispatch(fetchBookmarkCategories());
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { intl, categories, multiColumn } = this.props;
|
||||||
|
|
||||||
|
if (!categories) {
|
||||||
|
return (
|
||||||
|
<Column>
|
||||||
|
<LoadingIndicator />
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyMessage = <FormattedMessage id='empty_column.bookmark_categories' defaultMessage="You don't have any categories yet. When you create one, it will show up here." />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.heading)}>
|
||||||
|
<ColumnHeader title={intl.formatMessage(messages.heading)} icon='list-ul' multiColumn={multiColumn} />
|
||||||
|
|
||||||
|
<NewListForm />
|
||||||
|
|
||||||
|
<ScrollableList
|
||||||
|
scrollKey='bookmark_categories'
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
prepend={<ColumnSubheading text={intl.formatMessage(messages.subheading)} />}
|
||||||
|
bindToDocument={!multiColumn}
|
||||||
|
>
|
||||||
|
{categories.map(category =>
|
||||||
|
<ColumnLink key={category.get('id')} to={`/bookmark_categories/${category.get('id')}`} icon='bookmark' text={category.get('title')} />,
|
||||||
|
)}
|
||||||
|
</ScrollableList>
|
||||||
|
|
||||||
|
<Helmet>
|
||||||
|
<title>{intl.formatMessage(messages.heading)}</title>
|
||||||
|
<meta name='robots' content='noindex' />
|
||||||
|
</Helmet>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(injectIntl(BookmarkCategories));
|
|
@ -0,0 +1,132 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Helmet } from 'react-helmet';
|
||||||
|
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
|
||||||
|
import { expandBookmarkCategoryStatuses, fetchBookmarkCategory, fetchBookmarkCategoryStatuses } from 'mastodon/actions/bookmark_categories';
|
||||||
|
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
|
||||||
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
|
import StatusList from 'mastodon/components/status_list';
|
||||||
|
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||||
|
import Column from 'mastodon/features/ui/components/column';
|
||||||
|
import { getBookmarkCategoryStatusList } from 'mastodon/selectors';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapStateToProps = (state, { params }) => ({
|
||||||
|
bookmarkCategory: state.getIn(['bookmark_categories', params.id]),
|
||||||
|
statusIds: getBookmarkCategoryStatusList(state, params.id),
|
||||||
|
isLoading: state.getIn(['bookmark_categories', params.id, 'isLoading'], true),
|
||||||
|
hasMore: !!state.getIn(['bookmark_categories', params.id, 'next']),
|
||||||
|
});
|
||||||
|
|
||||||
|
class BookmarkCategoryStatuses extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
params: PropTypes.object.isRequired,
|
||||||
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
statusIds: ImmutablePropTypes.list.isRequired,
|
||||||
|
bookmarkCategory: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]),
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
columnId: PropTypes.string,
|
||||||
|
multiColumn: PropTypes.bool,
|
||||||
|
hasMore: PropTypes.bool,
|
||||||
|
isLoading: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
UNSAFE_componentWillMount () {
|
||||||
|
this.props.dispatch(fetchBookmarkCategory(this.props.params.id));
|
||||||
|
this.props.dispatch(fetchBookmarkCategoryStatuses(this.props.params.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePin = () => {
|
||||||
|
const { columnId, dispatch } = this.props;
|
||||||
|
|
||||||
|
if (columnId) {
|
||||||
|
dispatch(removeColumn(columnId));
|
||||||
|
} else {
|
||||||
|
dispatch(addColumn('BOOKMARKS_EX', {}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleMove = (dir) => {
|
||||||
|
const { columnId, dispatch } = this.props;
|
||||||
|
dispatch(moveColumn(columnId, dir));
|
||||||
|
};
|
||||||
|
|
||||||
|
handleHeaderClick = () => {
|
||||||
|
this.column.scrollTop();
|
||||||
|
};
|
||||||
|
|
||||||
|
setRef = c => {
|
||||||
|
this.column = c;
|
||||||
|
};
|
||||||
|
|
||||||
|
handleLoadMore = debounce(() => {
|
||||||
|
this.props.dispatch(expandBookmarkCategoryStatuses());
|
||||||
|
}, 300, { leading: true });
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { intl, bookmarkCategory, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props;
|
||||||
|
const pinned = !!columnId;
|
||||||
|
|
||||||
|
if (typeof bookmarkCategory === 'undefined') {
|
||||||
|
return (
|
||||||
|
<Column>
|
||||||
|
<div className='scrollable'>
|
||||||
|
<LoadingIndicator />
|
||||||
|
</div>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
} else if (bookmarkCategory === false) {
|
||||||
|
return (
|
||||||
|
<BundleColumnError multiColumn={multiColumn} errorType='routing' />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyMessage = <FormattedMessage id='empty_column.bookmarked_statuses' defaultMessage="You don't have any bookmarked posts yet. When you bookmark one, it will show up here." />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>
|
||||||
|
<ColumnHeader
|
||||||
|
icon='bookmark_ex'
|
||||||
|
title={intl.formatMessage(messages.heading)}
|
||||||
|
onPin={this.handlePin}
|
||||||
|
onMove={this.handleMove}
|
||||||
|
onClick={this.handleHeaderClick}
|
||||||
|
pinned={pinned}
|
||||||
|
multiColumn={multiColumn}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StatusList
|
||||||
|
trackScroll={!pinned}
|
||||||
|
statusIds={statusIds}
|
||||||
|
scrollKey={`bookmark_ex_statuses-${columnId}`}
|
||||||
|
hasMore={hasMore}
|
||||||
|
isLoading={isLoading}
|
||||||
|
onLoadMore={this.handleLoadMore}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
bindToDocument={!multiColumn}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Helmet>
|
||||||
|
<title>{intl.formatMessage(messages.heading)}</title>
|
||||||
|
<meta name='robots' content='noindex' />
|
||||||
|
</Helmet>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(injectIntl(BookmarkCategoryStatuses));
|
|
@ -117,7 +117,7 @@ class NavigationPanel extends Component {
|
||||||
|
|
||||||
{signedIn && (
|
{signedIn && (
|
||||||
<>
|
<>
|
||||||
<ColumnLink transparent to='/bookmarks' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} />
|
<ColumnLink transparent to='/bookmark_categories' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} />
|
||||||
<ColumnLink transparent to='/favourites' icon='star' text={intl.formatMessage(messages.favourites)} />
|
<ColumnLink transparent to='/favourites' icon='star' text={intl.formatMessage(messages.favourites)} />
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,8 @@ import {
|
||||||
FavouritedStatuses,
|
FavouritedStatuses,
|
||||||
EmojiReactedStatuses,
|
EmojiReactedStatuses,
|
||||||
BookmarkedStatuses,
|
BookmarkedStatuses,
|
||||||
|
BookmarkCategories,
|
||||||
|
BookmarkCategoryStatuses,
|
||||||
FollowedTags,
|
FollowedTags,
|
||||||
ListTimeline,
|
ListTimeline,
|
||||||
Blocks,
|
Blocks,
|
||||||
|
@ -218,6 +220,8 @@ class SwitchingColumnsArea extends PureComponent {
|
||||||
<WrappedRoute path='/emoji_reactions' component={EmojiReactedStatuses} content={children} />
|
<WrappedRoute path='/emoji_reactions' component={EmojiReactedStatuses} content={children} />
|
||||||
|
|
||||||
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
|
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
|
||||||
|
<WrappedRoute path='/bookmark_categories/:id' component={BookmarkCategoryStatuses} content={children} />
|
||||||
|
<WrappedRoute path='/bookmark_categories' component={BookmarkCategories} content={children} />
|
||||||
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
|
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
|
||||||
|
|
||||||
<WrappedRoute path='/reaction_deck' component={ReactionDeck} content={children} />
|
<WrappedRoute path='/reaction_deck' component={ReactionDeck} content={children} />
|
||||||
|
|
|
@ -122,6 +122,14 @@ export function BookmarkedStatuses () {
|
||||||
return import(/* webpackChunkName: "features/bookmarked_statuses" */'../../bookmarked_statuses');
|
return import(/* webpackChunkName: "features/bookmarked_statuses" */'../../bookmarked_statuses');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function BookmarkCategories () {
|
||||||
|
return import(/* webpackChunkName: "features/bookmark_categories" */'../../bookmark_categories');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BookmarkCategoryStatuses () {
|
||||||
|
return import(/* webpackChunkName: "features/bookmark_category_statuses" */'../../bookmark_category_statuses');
|
||||||
|
}
|
||||||
|
|
||||||
export function Blocks () {
|
export function Blocks () {
|
||||||
return import(/* webpackChunkName: "features/blocks" */'../../blocks');
|
return import(/* webpackChunkName: "features/blocks" */'../../blocks');
|
||||||
}
|
}
|
||||||
|
|
71
app/javascript/mastodon/reducers/bookmark_categories.js
Normal file
71
app/javascript/mastodon/reducers/bookmark_categories.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import { Map as ImmutableMap, fromJS, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BOOKMARK_CATEGORY_FETCH_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_FETCH_FAIL,
|
||||||
|
BOOKMARK_CATEGORIES_FETCH_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_CREATE_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_UPDATE_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_DELETE_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_STATUSES_FETCH_REQUEST,
|
||||||
|
BOOKMARK_CATEGORY_STATUSES_FETCH_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_STATUSES_FETCH_FAIL,
|
||||||
|
BOOKMARK_CATEGORY_STATUSES_EXPAND_REQUEST,
|
||||||
|
BOOKMARK_CATEGORY_STATUSES_EXPAND_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_STATUSES_EXPAND_FAIL,
|
||||||
|
} from '../actions/bookmark_categories';
|
||||||
|
|
||||||
|
const initialState = ImmutableMap();
|
||||||
|
|
||||||
|
const normalizeBookmarkCategory = (state, category) => state.set(category.id, fromJS(category));
|
||||||
|
|
||||||
|
const normalizeBookmarkCategories = (state, bookmarkCategories) => {
|
||||||
|
bookmarkCategories.forEach(bookmarkCategory => {
|
||||||
|
state = normalizeBookmarkCategory(state, bookmarkCategory);
|
||||||
|
});
|
||||||
|
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeBookmarkCategoryStatuses = (state, bookmaryCategoryId, statuses, next) => {
|
||||||
|
return state.updateIn([bookmaryCategoryId, 'items'], listMap => listMap.withMutations(map => {
|
||||||
|
map.set('next', next);
|
||||||
|
map.set('loaded', true);
|
||||||
|
map.set('isLoading', false);
|
||||||
|
map.set('items', ImmutableOrderedSet(statuses.map(item => item.id)));
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const appendToBookmarkCategoryStatuses = (state, bookmarkCategoryId, statuses, next) => {
|
||||||
|
return state.updateIn([bookmarkCategoryId, 'items'], listMap => listMap.withMutations(map => {
|
||||||
|
map.set('next', next);
|
||||||
|
map.set('isLoading', false);
|
||||||
|
map.set('items', map.get('items').union(statuses.map(item => item.id)));
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function bookmarkCategories(state = initialState, action) {
|
||||||
|
switch(action.type) {
|
||||||
|
case BOOKMARK_CATEGORY_FETCH_SUCCESS:
|
||||||
|
case BOOKMARK_CATEGORY_CREATE_SUCCESS:
|
||||||
|
case BOOKMARK_CATEGORY_UPDATE_SUCCESS:
|
||||||
|
return normalizeBookmarkCategory(state, action.bookmarkCategory);
|
||||||
|
case BOOKMARK_CATEGORIES_FETCH_SUCCESS:
|
||||||
|
return normalizeBookmarkCategories(state, action.bookmarkCategories);
|
||||||
|
case BOOKMARK_CATEGORY_DELETE_SUCCESS:
|
||||||
|
case BOOKMARK_CATEGORY_FETCH_FAIL:
|
||||||
|
return state.set(action.id, false);
|
||||||
|
case BOOKMARK_CATEGORY_STATUSES_FETCH_REQUEST:
|
||||||
|
case BOOKMARK_CATEGORY_STATUSES_EXPAND_REQUEST:
|
||||||
|
return state.setIn([action.id, 'isLoading'], true);
|
||||||
|
case BOOKMARK_CATEGORY_STATUSES_FETCH_FAIL:
|
||||||
|
case BOOKMARK_CATEGORY_STATUSES_EXPAND_FAIL:
|
||||||
|
return state.setIn([action.id, 'isLoading'], false);
|
||||||
|
case BOOKMARK_CATEGORY_STATUSES_FETCH_SUCCESS:
|
||||||
|
return normalizeBookmarkCategoryStatuses(state, action.id, action.statuses, action.next);
|
||||||
|
case BOOKMARK_CATEGORY_STATUSES_EXPAND_SUCCESS:
|
||||||
|
return appendToBookmarkCategoryStatuses(state, action.id, action.statuses, action.next);
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
74
app/javascript/mastodon/reducers/bookmark_category_editor.js
Normal file
74
app/javascript/mastodon/reducers/bookmark_category_editor.js
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BOOKMARK_CATEGORY_CREATE_REQUEST,
|
||||||
|
BOOKMARK_CATEGORY_CREATE_FAIL,
|
||||||
|
BOOKMARK_CATEGORY_CREATE_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_UPDATE_REQUEST,
|
||||||
|
BOOKMARK_CATEGORY_UPDATE_FAIL,
|
||||||
|
BOOKMARK_CATEGORY_UPDATE_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_EDITOR_RESET,
|
||||||
|
BOOKMARK_CATEGORY_EDITOR_SETUP,
|
||||||
|
BOOKMARK_CATEGORY_EDITOR_TITLE_CHANGE,
|
||||||
|
BOOKMARK_CATEGORY_EDITOR_ADD_SUCCESS,
|
||||||
|
BOOKMARK_CATEGORY_EDITOR_REMOVE_SUCCESS,
|
||||||
|
} from '../actions/bookmark_categories';
|
||||||
|
|
||||||
|
const initialState = ImmutableMap({
|
||||||
|
bookmaryCategoryId: null,
|
||||||
|
isSubmitting: false,
|
||||||
|
isChanged: false,
|
||||||
|
title: '',
|
||||||
|
isExclusive: false,
|
||||||
|
|
||||||
|
statuses: ImmutableMap({
|
||||||
|
items: ImmutableList(),
|
||||||
|
loaded: false,
|
||||||
|
isLoading: false,
|
||||||
|
}),
|
||||||
|
|
||||||
|
suggestions: ImmutableMap({
|
||||||
|
value: '',
|
||||||
|
items: ImmutableList(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function bookmaryCategoryEditorReducer(state = initialState, action) {
|
||||||
|
switch(action.type) {
|
||||||
|
case BOOKMARK_CATEGORY_EDITOR_RESET:
|
||||||
|
return initialState;
|
||||||
|
case BOOKMARK_CATEGORY_EDITOR_SETUP:
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.set('bookmaryCategoryId', action.bookmaryCategory.get('id'));
|
||||||
|
map.set('title', action.bookmaryCategory.get('title'));
|
||||||
|
map.set('isExclusive', action.bookmaryCategory.get('is_exclusive'));
|
||||||
|
map.set('isSubmitting', false);
|
||||||
|
});
|
||||||
|
case BOOKMARK_CATEGORY_EDITOR_TITLE_CHANGE:
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.set('title', action.value);
|
||||||
|
map.set('isChanged', true);
|
||||||
|
});
|
||||||
|
case BOOKMARK_CATEGORY_CREATE_REQUEST:
|
||||||
|
case BOOKMARK_CATEGORY_UPDATE_REQUEST:
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.set('isSubmitting', true);
|
||||||
|
map.set('isChanged', false);
|
||||||
|
});
|
||||||
|
case BOOKMARK_CATEGORY_CREATE_FAIL:
|
||||||
|
case BOOKMARK_CATEGORY_UPDATE_FAIL:
|
||||||
|
return state.set('isSubmitting', false);
|
||||||
|
case BOOKMARK_CATEGORY_CREATE_SUCCESS:
|
||||||
|
case BOOKMARK_CATEGORY_UPDATE_SUCCESS:
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.set('isSubmitting', false);
|
||||||
|
map.set('bookmaryCategoryId', action.bookmaryCategory.id);
|
||||||
|
});
|
||||||
|
case BOOKMARK_CATEGORY_EDITOR_ADD_SUCCESS:
|
||||||
|
return state.updateIn(['accounts', 'items'], bookmaryCategory => bookmaryCategory.unshift(action.accountId));
|
||||||
|
case BOOKMARK_CATEGORY_EDITOR_REMOVE_SUCCESS:
|
||||||
|
return state.updateIn(['accounts', 'items'], bookmaryCategory => bookmaryCategory.filterNot(item => item === action.accountId));
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,8 @@ import antennaAdder from './antenna_adder';
|
||||||
import antennaEditor from './antenna_editor';
|
import antennaEditor from './antenna_editor';
|
||||||
import antennas from './antennas';
|
import antennas from './antennas';
|
||||||
import blocks from './blocks';
|
import blocks from './blocks';
|
||||||
|
import bookmark_categories from './bookmark_categories';
|
||||||
|
import bookmarkCategoryEditor from './bookmark_category_editor';
|
||||||
import boosts from './boosts';
|
import boosts from './boosts';
|
||||||
import circleAdder from './circle_adder';
|
import circleAdder from './circle_adder';
|
||||||
import circleEditor from './circle_editor';
|
import circleEditor from './circle_editor';
|
||||||
|
@ -89,6 +91,8 @@ const reducers = {
|
||||||
circles,
|
circles,
|
||||||
circleEditor,
|
circleEditor,
|
||||||
circleAdder,
|
circleAdder,
|
||||||
|
bookmark_categories,
|
||||||
|
bookmarkCategoryEditor,
|
||||||
filters,
|
filters,
|
||||||
conversations,
|
conversations,
|
||||||
suggestions,
|
suggestions,
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||||
|
|
||||||
|
import { ANTENNA_DELETE_SUCCESS, ANTENNA_FETCH_FAIL } from 'mastodon/actions/antennas';
|
||||||
|
import { CIRCLE_DELETE_SUCCESS, CIRCLE_FETCH_FAIL } from 'mastodon/actions/circles';
|
||||||
|
|
||||||
import { COLUMN_ADD, COLUMN_REMOVE, COLUMN_MOVE, COLUMN_PARAMS_CHANGE } from '../actions/columns';
|
import { COLUMN_ADD, COLUMN_REMOVE, COLUMN_MOVE, COLUMN_PARAMS_CHANGE } from '../actions/columns';
|
||||||
import { EMOJI_USE } from '../actions/emojis';
|
import { EMOJI_USE } from '../actions/emojis';
|
||||||
import { LANGUAGE_USE } from '../actions/languages';
|
import { LANGUAGE_USE } from '../actions/languages';
|
||||||
|
@ -142,6 +145,10 @@ const updateFrequentLanguages = (state, language) => state.update('frequentlyUse
|
||||||
|
|
||||||
const filterDeadListColumns = (state, listId) => state.update('columns', columns => columns.filterNot(column => column.get('id') === 'LIST' && column.get('params').get('id') === listId));
|
const filterDeadListColumns = (state, listId) => state.update('columns', columns => columns.filterNot(column => column.get('id') === 'LIST' && column.get('params').get('id') === listId));
|
||||||
|
|
||||||
|
const filterDeadAntennaColumns = (state, antennaId) => state.update('columns', columns => columns.filterNot(column => column.get('id') === 'ANTENNA' && column.get('params').get('id') === antennaId));
|
||||||
|
|
||||||
|
const filterDeadCircleColumns = (state, circleId) => state.update('columns', columns => columns.filterNot(column => column.get('id') === 'CIRCLE' && column.get('params').get('id') === circleId));
|
||||||
|
|
||||||
export default function settings(state = initialState, action) {
|
export default function settings(state = initialState, action) {
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case STORE_HYDRATE:
|
case STORE_HYDRATE:
|
||||||
|
@ -173,6 +180,14 @@ export default function settings(state = initialState, action) {
|
||||||
return action.error.response.status === 404 ? filterDeadListColumns(state, action.id) : state;
|
return action.error.response.status === 404 ? filterDeadListColumns(state, action.id) : state;
|
||||||
case LIST_DELETE_SUCCESS:
|
case LIST_DELETE_SUCCESS:
|
||||||
return filterDeadListColumns(state, action.id);
|
return filterDeadListColumns(state, action.id);
|
||||||
|
case ANTENNA_FETCH_FAIL:
|
||||||
|
return action.error.response.status === 404 ? filterDeadAntennaColumns(state, action.id) : state;
|
||||||
|
case ANTENNA_DELETE_SUCCESS:
|
||||||
|
return filterDeadAntennaColumns(state, action.id);
|
||||||
|
case CIRCLE_FETCH_FAIL:
|
||||||
|
return action.error.response.status === 404 ? filterDeadCircleColumns(state, action.id) : state;
|
||||||
|
case CIRCLE_DELETE_SUCCESS:
|
||||||
|
return filterDeadCircleColumns(state, action.id);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,3 +131,7 @@ export const getAccountHidden = createSelector([
|
||||||
export const getStatusList = createSelector([
|
export const getStatusList = createSelector([
|
||||||
(state, type) => state.getIn(['status_lists', type, 'items']),
|
(state, type) => state.getIn(['status_lists', type, 'items']),
|
||||||
], (items) => items.toList());
|
], (items) => items.toList());
|
||||||
|
|
||||||
|
export const getBookmarkCategoryStatusList = createSelector([
|
||||||
|
(state, bookmarkCategoryId) => state.getIn(['bookmark_categories', bookmarkCategoryId, 'items']),
|
||||||
|
], (items) => items ? items.toList() : ImmutableList());
|
||||||
|
|
|
@ -23,6 +23,7 @@ Rails.application.routes.draw do
|
||||||
/favourites
|
/favourites
|
||||||
/emoji_reactions
|
/emoji_reactions
|
||||||
/bookmarks
|
/bookmarks
|
||||||
|
/bookmark_categories/(*any)
|
||||||
/pinned
|
/pinned
|
||||||
/reaction_deck
|
/reaction_deck
|
||||||
/start
|
/start
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue