about summary refs log tree commit diff
path: root/app/assets/javascripts/components/reducers
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2017-05-03 02:04:16 +0200
committerGitHub <noreply@github.com>2017-05-03 02:04:16 +0200
commitf5bf5ebb82e3af420dcd23d602b1be6cc86838e1 (patch)
tree92eef08642a038cf44ccbc6d16a884293e7a0814 /app/assets/javascripts/components/reducers
parent26bc5915727e0a0173c03cb49f5193dd612fb888 (diff)
Replace sprockets/browserify with Webpack (#2617)
* Replace browserify with webpack

* Add react-intl-translations-manager

* Do not minify in development, add offline-plugin for ServiceWorker background cache updates

* Adjust tests and dependencies

* Fix production deployments

* Fix tests

* More optimizations

* Improve travis cache for npm stuff

* Re-run travis

* Add back support for custom.scss as before

* Remove offline-plugin and babili

* Fix issue with Immutable.List().unshift(...values) not working as expected

* Make travis load schema instead of running all migrations in sequence

* Fix missing React import in WarningContainer. Optimize rendering performance by using ImmutablePureComponent instead of
React.PureComponent. ImmutablePureComponent uses Immutable.is() to compare props. Replace dynamic callback bindings in
<UI />

* Add react definitions to places that use JSX

* Add Procfile.dev for running rails, webpack and streaming API at the same time
Diffstat (limited to 'app/assets/javascripts/components/reducers')
-rw-r--r--app/assets/javascripts/components/reducers/accounts.jsx131
-rw-r--r--app/assets/javascripts/components/reducers/alerts.jsx25
-rw-r--r--app/assets/javascripts/components/reducers/cards.jsx14
-rw-r--r--app/assets/javascripts/components/reducers/compose.jsx232
-rw-r--r--app/assets/javascripts/components/reducers/index.jsx36
-rw-r--r--app/assets/javascripts/components/reducers/meta.jsx17
-rw-r--r--app/assets/javascripts/components/reducers/modal.jsx18
-rw-r--r--app/assets/javascripts/components/reducers/notifications.jsx104
-rw-r--r--app/assets/javascripts/components/reducers/relationships.jsx38
-rw-r--r--app/assets/javascripts/components/reducers/reports.jsx60
-rw-r--r--app/assets/javascripts/components/reducers/search.jsx96
-rw-r--r--app/assets/javascripts/components/reducers/settings.jsx48
-rw-r--r--app/assets/javascripts/components/reducers/status_lists.jsx39
-rw-r--r--app/assets/javascripts/components/reducers/statuses.jsx124
-rw-r--r--app/assets/javascripts/components/reducers/timelines.jsx317
-rw-r--r--app/assets/javascripts/components/reducers/user_lists.jsx80
16 files changed, 0 insertions, 1379 deletions
diff --git a/app/assets/javascripts/components/reducers/accounts.jsx b/app/assets/javascripts/components/reducers/accounts.jsx
deleted file mode 100644
index 60d283b0f..000000000
--- a/app/assets/javascripts/components/reducers/accounts.jsx
+++ /dev/null
@@ -1,131 +0,0 @@
-import {
-  ACCOUNT_FETCH_SUCCESS,
-  FOLLOWERS_FETCH_SUCCESS,
-  FOLLOWERS_EXPAND_SUCCESS,
-  FOLLOWING_FETCH_SUCCESS,
-  FOLLOWING_EXPAND_SUCCESS,
-  ACCOUNT_TIMELINE_FETCH_SUCCESS,
-  ACCOUNT_TIMELINE_EXPAND_SUCCESS,
-  FOLLOW_REQUESTS_FETCH_SUCCESS,
-  FOLLOW_REQUESTS_EXPAND_SUCCESS,
-  ACCOUNT_FOLLOW_SUCCESS,
-  ACCOUNT_UNFOLLOW_SUCCESS
-} from '../actions/accounts';
-import {
-  BLOCKS_FETCH_SUCCESS,
-  BLOCKS_EXPAND_SUCCESS
-} from '../actions/blocks';
-import {
-  MUTES_FETCH_SUCCESS,
-  MUTES_EXPAND_SUCCESS
-} from '../actions/mutes';
-import { COMPOSE_SUGGESTIONS_READY } from '../actions/compose';
-import {
-  REBLOG_SUCCESS,
-  UNREBLOG_SUCCESS,
-  FAVOURITE_SUCCESS,
-  UNFAVOURITE_SUCCESS,
-  REBLOGS_FETCH_SUCCESS,
-  FAVOURITES_FETCH_SUCCESS
-} from '../actions/interactions';
-import {
-  TIMELINE_REFRESH_SUCCESS,
-  TIMELINE_UPDATE,
-  TIMELINE_EXPAND_SUCCESS
-} from '../actions/timelines';
-import {
-  STATUS_FETCH_SUCCESS,
-  CONTEXT_FETCH_SUCCESS
-} from '../actions/statuses';
-import { SEARCH_FETCH_SUCCESS } from '../actions/search';
-import {
-  NOTIFICATIONS_UPDATE,
-  NOTIFICATIONS_REFRESH_SUCCESS,
-  NOTIFICATIONS_EXPAND_SUCCESS
-} from '../actions/notifications';
-import {
-  FAVOURITED_STATUSES_FETCH_SUCCESS,
-  FAVOURITED_STATUSES_EXPAND_SUCCESS
-} from '../actions/favourites';
-import { STORE_HYDRATE } from '../actions/store';
-import Immutable from 'immutable';
-
-const normalizeAccount = (state, account) => state.set(account.id, Immutable.fromJS(account));
-
-const normalizeAccounts = (state, accounts) => {
-  accounts.forEach(account => {
-    state = normalizeAccount(state, account);
-  });
-
-  return state;
-};
-
-const normalizeAccountFromStatus = (state, status) => {
-  state = normalizeAccount(state, status.account);
-
-  if (status.reblog && status.reblog.account) {
-    state = normalizeAccount(state, status.reblog.account);
-  }
-
-  return state;
-};
-
-const normalizeAccountsFromStatuses = (state, statuses) => {
-  statuses.forEach(status => {
-    state = normalizeAccountFromStatus(state, status);
-  });
-
-  return state;
-};
-
-const initialState = Immutable.Map();
-
-export default function accounts(state = initialState, action) {
-  switch(action.type) {
-  case STORE_HYDRATE:
-    return state.merge(action.state.get('accounts'));
-  case ACCOUNT_FETCH_SUCCESS:
-  case NOTIFICATIONS_UPDATE:
-    return normalizeAccount(state, action.account);
-  case FOLLOWERS_FETCH_SUCCESS:
-  case FOLLOWERS_EXPAND_SUCCESS:
-  case FOLLOWING_FETCH_SUCCESS:
-  case FOLLOWING_EXPAND_SUCCESS:
-  case REBLOGS_FETCH_SUCCESS:
-  case FAVOURITES_FETCH_SUCCESS:
-  case COMPOSE_SUGGESTIONS_READY:
-  case FOLLOW_REQUESTS_FETCH_SUCCESS:
-  case FOLLOW_REQUESTS_EXPAND_SUCCESS:
-  case BLOCKS_FETCH_SUCCESS:
-  case BLOCKS_EXPAND_SUCCESS:
-  case MUTES_FETCH_SUCCESS:
-  case MUTES_EXPAND_SUCCESS:
-    return normalizeAccounts(state, action.accounts);
-  case NOTIFICATIONS_REFRESH_SUCCESS:
-  case NOTIFICATIONS_EXPAND_SUCCESS:
-  case SEARCH_FETCH_SUCCESS:
-    return normalizeAccountsFromStatuses(normalizeAccounts(state, action.accounts), action.statuses);
-  case TIMELINE_REFRESH_SUCCESS:
-  case TIMELINE_EXPAND_SUCCESS:
-  case ACCOUNT_TIMELINE_FETCH_SUCCESS:
-  case ACCOUNT_TIMELINE_EXPAND_SUCCESS:
-  case CONTEXT_FETCH_SUCCESS:
-  case FAVOURITED_STATUSES_FETCH_SUCCESS:
-  case FAVOURITED_STATUSES_EXPAND_SUCCESS:
-    return normalizeAccountsFromStatuses(state, action.statuses);
-  case REBLOG_SUCCESS:
-  case FAVOURITE_SUCCESS:
-  case UNREBLOG_SUCCESS:
-  case UNFAVOURITE_SUCCESS:
-    return normalizeAccountFromStatus(state, action.response);
-  case TIMELINE_UPDATE:
-  case STATUS_FETCH_SUCCESS:
-    return normalizeAccountFromStatus(state, action.status);
-  case ACCOUNT_FOLLOW_SUCCESS:
-    return state.updateIn([action.relationship.id, 'followers_count'], num => num + 1);
-  case ACCOUNT_UNFOLLOW_SUCCESS:
-    return state.updateIn([action.relationship.id, 'followers_count'], num => Math.max(0, num - 1));
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/alerts.jsx b/app/assets/javascripts/components/reducers/alerts.jsx
deleted file mode 100644
index dc0145824..000000000
--- a/app/assets/javascripts/components/reducers/alerts.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import {
-  ALERT_SHOW,
-  ALERT_DISMISS,
-  ALERT_CLEAR
-} from '../actions/alerts';
-import Immutable from 'immutable';
-
-const initialState = Immutable.List([]);
-
-export default function alerts(state = initialState, action) {
-  switch(action.type) {
-  case ALERT_SHOW:
-    return state.push(Immutable.Map({
-      key: state.size > 0 ? state.last().get('key') + 1 : 0,
-      title: action.title,
-      message: action.message
-    }));
-  case ALERT_DISMISS:
-    return state.filterNot(item => item.get('key') === action.alert.key);
-  case ALERT_CLEAR:
-    return state.clear();
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/cards.jsx b/app/assets/javascripts/components/reducers/cards.jsx
deleted file mode 100644
index 3c9395011..000000000
--- a/app/assets/javascripts/components/reducers/cards.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { STATUS_CARD_FETCH_SUCCESS } from '../actions/cards';
-
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map();
-
-export default function cards(state = initialState, action) {
-  switch(action.type) {
-  case STATUS_CARD_FETCH_SUCCESS:
-    return state.set(action.id, Immutable.fromJS(action.card));
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/compose.jsx b/app/assets/javascripts/components/reducers/compose.jsx
deleted file mode 100644
index c87384780..000000000
--- a/app/assets/javascripts/components/reducers/compose.jsx
+++ /dev/null
@@ -1,232 +0,0 @@
-import {
-  COMPOSE_MOUNT,
-  COMPOSE_UNMOUNT,
-  COMPOSE_CHANGE,
-  COMPOSE_REPLY,
-  COMPOSE_REPLY_CANCEL,
-  COMPOSE_MENTION,
-  COMPOSE_SUBMIT_REQUEST,
-  COMPOSE_SUBMIT_SUCCESS,
-  COMPOSE_SUBMIT_FAIL,
-  COMPOSE_UPLOAD_REQUEST,
-  COMPOSE_UPLOAD_SUCCESS,
-  COMPOSE_UPLOAD_FAIL,
-  COMPOSE_UPLOAD_UNDO,
-  COMPOSE_UPLOAD_PROGRESS,
-  COMPOSE_SUGGESTIONS_CLEAR,
-  COMPOSE_SUGGESTIONS_READY,
-  COMPOSE_SUGGESTION_SELECT,
-  COMPOSE_SENSITIVITY_CHANGE,
-  COMPOSE_SPOILERNESS_CHANGE,
-  COMPOSE_SPOILER_TEXT_CHANGE,
-  COMPOSE_VISIBILITY_CHANGE,
-  COMPOSE_LISTABILITY_CHANGE,
-  COMPOSE_EMOJI_INSERT
-} from '../actions/compose';
-import { TIMELINE_DELETE } from '../actions/timelines';
-import { STORE_HYDRATE } from '../actions/store';
-import Immutable from 'immutable';
-import uuid from '../uuid';
-
-const initialState = Immutable.Map({
-  mounted: false,
-  sensitive: false,
-  spoiler: false,
-  spoiler_text: '',
-  privacy: null,
-  text: '',
-  focusDate: null,
-  preselectDate: null,
-  in_reply_to: null,
-  is_submitting: false,
-  is_uploading: false,
-  progress: 0,
-  media_attachments: Immutable.List(),
-  suggestion_token: null,
-  suggestions: Immutable.List(),
-  me: null,
-  default_privacy: 'public',
-  resetFileKey: Math.floor((Math.random() * 0x10000)),
-  idempotencyKey: null
-});
-
-function statusToTextMentions(state, status) {
-  let set = Immutable.OrderedSet([]);
-  let me  = state.get('me');
-
-  if (status.getIn(['account', 'id']) !== me) {
-    set = set.add(`@${status.getIn(['account', 'acct'])} `);
-  }
-
-  return set.union(status.get('mentions').filterNot(mention => mention.get('id') === me).map(mention => `@${mention.get('acct')} `)).join('');
-};
-
-function clearAll(state) {
-  return state.withMutations(map => {
-    map.set('text', '');
-    map.set('spoiler', false);
-    map.set('spoiler_text', '');
-    map.set('is_submitting', false);
-    map.set('in_reply_to', null);
-    map.set('privacy', state.get('default_privacy'));
-    map.set('sensitive', false);
-    map.update('media_attachments', list => list.clear());
-    map.set('idempotencyKey', uuid());
-  });
-};
-
-function appendMedia(state, media) {
-  return state.withMutations(map => {
-    map.update('media_attachments', list => list.push(media));
-    map.set('is_uploading', false);
-    map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
-    map.update('text', oldText => `${oldText.trim()} ${media.get('text_url')}`);
-    map.set('focusDate', new Date());
-    map.set('idempotencyKey', uuid());
-  });
-};
-
-function removeMedia(state, mediaId) {
-  const media    = state.get('media_attachments').find(item => item.get('id') === mediaId);
-  const prevSize = state.get('media_attachments').size;
-
-  return state.withMutations(map => {
-    map.update('media_attachments', list => list.filterNot(item => item.get('id') === mediaId));
-    map.update('text', text => text.replace(media.get('text_url'), '').trim());
-    map.set('idempotencyKey', uuid());
-
-    if (prevSize === 1) {
-      map.set('sensitive', false);
-    }
-  });
-};
-
-const insertSuggestion = (state, position, token, completion) => {
-  return state.withMutations(map => {
-    map.update('text', oldText => `${oldText.slice(0, position)}${completion} ${oldText.slice(position + token.length)}`);
-    map.set('suggestion_token', null);
-    map.update('suggestions', Immutable.List(), list => list.clear());
-    map.set('focusDate', new Date());
-    map.set('idempotencyKey', uuid());
-  });
-};
-
-const insertEmoji = (state, position, emojiData) => {
-  const emoji = emojiData.shortname;
-
-  return state.withMutations(map => {
-    map.update('text', oldText => `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`);
-    map.set('focusDate', new Date());
-    map.set('idempotencyKey', uuid());
-  });
-};
-
-const privacyPreference = (a, b) => {
-  if (a === 'direct' || b === 'direct') {
-    return 'direct';
-  } else if (a === 'private' || b === 'private') {
-    return 'private';
-  } else if (a === 'unlisted' || b === 'unlisted') {
-    return 'unlisted';
-  } else {
-    return 'public';
-  }
-};
-
-export default function compose(state = initialState, action) {
-  switch(action.type) {
-  case STORE_HYDRATE:
-    return clearAll(state.merge(action.state.get('compose')));
-  case COMPOSE_MOUNT:
-    return state.set('mounted', true);
-  case COMPOSE_UNMOUNT:
-    return state.set('mounted', false);
-  case COMPOSE_SENSITIVITY_CHANGE:
-    return state
-      .set('sensitive', !state.get('sensitive'))
-      .set('idempotencyKey', uuid());
-  case COMPOSE_SPOILERNESS_CHANGE:
-    return state.withMutations(map => {
-      map.set('spoiler_text', '');
-      map.set('spoiler', !state.get('spoiler'));
-      map.set('idempotencyKey', uuid());
-    });
-  case COMPOSE_SPOILER_TEXT_CHANGE:
-    return state
-      .set('spoiler_text', action.text)
-      .set('idempotencyKey', uuid());
-  case COMPOSE_VISIBILITY_CHANGE:
-    return state
-      .set('privacy', action.value)
-      .set('idempotencyKey', uuid());
-  case COMPOSE_CHANGE:
-    return state
-      .set('text', action.text)
-      .set('idempotencyKey', uuid());
-  case COMPOSE_REPLY:
-    return state.withMutations(map => {
-      map.set('in_reply_to', action.status.get('id'));
-      map.set('text', statusToTextMentions(state, action.status));
-      map.set('privacy', privacyPreference(action.status.get('visibility'), state.get('default_privacy')));
-      map.set('focusDate', new Date());
-      map.set('preselectDate', new Date());
-      map.set('idempotencyKey', uuid());
-
-      if (action.status.get('spoiler_text').length > 0) {
-        map.set('spoiler', true);
-        map.set('spoiler_text', action.status.get('spoiler_text'));
-      } else {
-        map.set('spoiler', false);
-        map.set('spoiler_text', '');
-      }
-    });
-  case COMPOSE_REPLY_CANCEL:
-    return state.withMutations(map => {
-      map.set('in_reply_to', null);
-      map.set('text', '');
-      map.set('spoiler', false);
-      map.set('spoiler_text', '');
-      map.set('privacy', state.get('default_privacy'));
-      map.set('idempotencyKey', uuid());
-    });
-  case COMPOSE_SUBMIT_REQUEST:
-    return state.set('is_submitting', true);
-  case COMPOSE_SUBMIT_SUCCESS:
-    return clearAll(state);
-  case COMPOSE_SUBMIT_FAIL:
-    return state.set('is_submitting', false);
-  case COMPOSE_UPLOAD_REQUEST:
-    return state.withMutations(map => {
-      map.set('is_uploading', true);
-    });
-  case COMPOSE_UPLOAD_SUCCESS:
-    return appendMedia(state, Immutable.fromJS(action.media));
-  case COMPOSE_UPLOAD_FAIL:
-    return state.set('is_uploading', false);
-  case COMPOSE_UPLOAD_UNDO:
-    return removeMedia(state, action.media_id);
-  case COMPOSE_UPLOAD_PROGRESS:
-    return state.set('progress', Math.round((action.loaded / action.total) * 100));
-  case COMPOSE_MENTION:
-    return state
-      .update('text', text => `${text}@${action.account.get('acct')} `)
-      .set('focusDate', new Date())
-      .set('idempotencyKey', uuid());
-  case COMPOSE_SUGGESTIONS_CLEAR:
-    return state.update('suggestions', Immutable.List(), list => list.clear()).set('suggestion_token', null);
-  case COMPOSE_SUGGESTIONS_READY:
-    return state.set('suggestions', Immutable.List(action.accounts.map(item => item.id))).set('suggestion_token', action.token);
-  case COMPOSE_SUGGESTION_SELECT:
-    return insertSuggestion(state, action.position, action.token, action.completion);
-  case TIMELINE_DELETE:
-    if (action.id === state.get('in_reply_to')) {
-      return state.set('in_reply_to', null);
-    } else {
-      return state;
-    }
-  case COMPOSE_EMOJI_INSERT:
-    return insertEmoji(state, action.position, action.emoji);
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/index.jsx b/app/assets/javascripts/components/reducers/index.jsx
deleted file mode 100644
index 147030cca..000000000
--- a/app/assets/javascripts/components/reducers/index.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { combineReducers } from 'redux-immutable';
-import timelines from './timelines';
-import meta from './meta';
-import compose from './compose';
-import alerts from './alerts';
-import { loadingBarReducer } from 'react-redux-loading-bar';
-import modal from './modal';
-import user_lists from './user_lists';
-import accounts from './accounts';
-import statuses from './statuses';
-import relationships from './relationships';
-import search from './search';
-import notifications from './notifications';
-import settings from './settings';
-import status_lists from './status_lists';
-import cards from './cards';
-import reports from './reports';
-
-export default combineReducers({
-  timelines,
-  meta,
-  compose,
-  alerts,
-  loadingBar: loadingBarReducer,
-  modal,
-  user_lists,
-  status_lists,
-  accounts,
-  statuses,
-  relationships,
-  search,
-  notifications,
-  settings,
-  cards,
-  reports
-});
diff --git a/app/assets/javascripts/components/reducers/meta.jsx b/app/assets/javascripts/components/reducers/meta.jsx
deleted file mode 100644
index acf6d4be1..000000000
--- a/app/assets/javascripts/components/reducers/meta.jsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { STORE_HYDRATE } from '../actions/store';
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map({
-  streaming_api_base_url: null,
-  access_token: null,
-  me: null
-});
-
-export default function meta(state = initialState, action) {
-  switch(action.type) {
-  case STORE_HYDRATE:
-    return state.merge(action.state.get('meta'));
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/modal.jsx b/app/assets/javascripts/components/reducers/modal.jsx
deleted file mode 100644
index 3566820ef..000000000
--- a/app/assets/javascripts/components/reducers/modal.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { MODAL_OPEN, MODAL_CLOSE } from '../actions/modal';
-import Immutable from 'immutable';
-
-const initialState = {
-  modalType: null,
-  modalProps: {}
-};
-
-export default function modal(state = initialState, action) {
-  switch(action.type) {
-  case MODAL_OPEN:
-    return { modalType: action.modalType, modalProps: action.modalProps };
-  case MODAL_CLOSE:
-    return initialState;
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/notifications.jsx b/app/assets/javascripts/components/reducers/notifications.jsx
deleted file mode 100644
index 1406a388a..000000000
--- a/app/assets/javascripts/components/reducers/notifications.jsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import {
-  NOTIFICATIONS_UPDATE,
-  NOTIFICATIONS_REFRESH_SUCCESS,
-  NOTIFICATIONS_EXPAND_SUCCESS,
-  NOTIFICATIONS_REFRESH_REQUEST,
-  NOTIFICATIONS_EXPAND_REQUEST,
-  NOTIFICATIONS_REFRESH_FAIL,
-  NOTIFICATIONS_EXPAND_FAIL,
-  NOTIFICATIONS_CLEAR,
-  NOTIFICATIONS_SCROLL_TOP
-} from '../actions/notifications';
-import { ACCOUNT_BLOCK_SUCCESS } from '../actions/accounts';
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map({
-  items: Immutable.List(),
-  next: null,
-  top: true,
-  unread: 0,
-  loaded: false,
-  isLoading: true
-});
-
-const notificationToMap = notification => Immutable.Map({
-  id: notification.id,
-  type: notification.type,
-  account: notification.account.id,
-  status: notification.status ? notification.status.id : null
-});
-
-const normalizeNotification = (state, notification) => {
-  if (!state.get('top')) {
-    state = state.update('unread', unread => unread + 1);
-  }
-
-  return state.update('items', list => list.unshift(notificationToMap(notification)));
-};
-
-const normalizeNotifications = (state, notifications, next) => {
-  let items    = Immutable.List();
-  const loaded = state.get('loaded');
-
-  notifications.forEach((n, i) => {
-    items = items.set(i, notificationToMap(n));
-  });
-
-  if (state.get('next') === null) {
-    state = state.set('next', next);
-  }
-
-  return state
-    .update('items', list => loaded ? list.unshift(...items) : list.push(...items))
-    .set('loaded', true)
-    .set('isLoading', false);
-};
-
-const appendNormalizedNotifications = (state, notifications, next) => {
-  let items = Immutable.List();
-
-  notifications.forEach((n, i) => {
-    items = items.set(i, notificationToMap(n));
-  });
-
-  return state
-    .update('items', list => list.push(...items))
-    .set('next', next)
-    .set('isLoading', false);
-};
-
-const filterNotifications = (state, relationship) => {
-  return state.update('items', list => list.filterNot(item => item.get('account') === relationship.id));
-};
-
-const updateTop = (state, top) => {
-  if (top) {
-    state = state.set('unread', 0);
-  }
-
-  return state.set('top', top);
-};
-
-export default function notifications(state = initialState, action) {
-  switch(action.type) {
-  case NOTIFICATIONS_REFRESH_REQUEST:
-  case NOTIFICATIONS_EXPAND_REQUEST:
-  case NOTIFICATIONS_REFRESH_FAIL:
-  case NOTIFICATIONS_EXPAND_FAIL:
-    return state.set('isLoading', true);
-  case NOTIFICATIONS_SCROLL_TOP:
-    return updateTop(state, action.top);
-  case NOTIFICATIONS_UPDATE:
-    return normalizeNotification(state, action.notification);
-  case NOTIFICATIONS_REFRESH_SUCCESS:
-    return normalizeNotifications(state, action.notifications, action.next);
-  case NOTIFICATIONS_EXPAND_SUCCESS:
-    return appendNormalizedNotifications(state, action.notifications, action.next);
-  case ACCOUNT_BLOCK_SUCCESS:
-    return filterNotifications(state, action.relationship);
-  case NOTIFICATIONS_CLEAR:
-    return state.set('items', Immutable.List()).set('next', null);
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/relationships.jsx b/app/assets/javascripts/components/reducers/relationships.jsx
deleted file mode 100644
index c65c48b43..000000000
--- a/app/assets/javascripts/components/reducers/relationships.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import {
-  ACCOUNT_FOLLOW_SUCCESS,
-  ACCOUNT_UNFOLLOW_SUCCESS,
-  ACCOUNT_BLOCK_SUCCESS,
-  ACCOUNT_UNBLOCK_SUCCESS,
-  ACCOUNT_MUTE_SUCCESS,
-  ACCOUNT_UNMUTE_SUCCESS,
-  RELATIONSHIPS_FETCH_SUCCESS
-} from '../actions/accounts';
-import Immutable from 'immutable';
-
-const normalizeRelationship = (state, relationship) => state.set(relationship.id, Immutable.fromJS(relationship));
-
-const normalizeRelationships = (state, relationships) => {
-  relationships.forEach(relationship => {
-    state = normalizeRelationship(state, relationship);
-  });
-
-  return state;
-};
-
-const initialState = Immutable.Map();
-
-export default function relationships(state = initialState, action) {
-  switch(action.type) {
-  case ACCOUNT_FOLLOW_SUCCESS:
-  case ACCOUNT_UNFOLLOW_SUCCESS:
-  case ACCOUNT_BLOCK_SUCCESS:
-  case ACCOUNT_UNBLOCK_SUCCESS:
-  case ACCOUNT_MUTE_SUCCESS:
-  case ACCOUNT_UNMUTE_SUCCESS:
-    return normalizeRelationship(state, action.relationship);
-  case RELATIONSHIPS_FETCH_SUCCESS:
-    return normalizeRelationships(state, action.relationships);
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/reports.jsx b/app/assets/javascripts/components/reducers/reports.jsx
deleted file mode 100644
index eab004377..000000000
--- a/app/assets/javascripts/components/reducers/reports.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import {
-  REPORT_INIT,
-  REPORT_SUBMIT_REQUEST,
-  REPORT_SUBMIT_SUCCESS,
-  REPORT_SUBMIT_FAIL,
-  REPORT_CANCEL,
-  REPORT_STATUS_TOGGLE,
-  REPORT_COMMENT_CHANGE
-} from '../actions/reports';
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map({
-  new: Immutable.Map({
-    isSubmitting: false,
-    account_id: null,
-    status_ids: Immutable.Set(),
-    comment: ''
-  })
-});
-
-export default function reports(state = initialState, action) {
-  switch(action.type) {
-  case REPORT_INIT:
-    return state.withMutations(map => {
-      map.setIn(['new', 'isSubmitting'], false);
-      map.setIn(['new', 'account_id'], action.account.get('id'));
-
-      if (state.getIn(['new', 'account_id']) !== action.account.get('id')) {
-        map.setIn(['new', 'status_ids'], action.status ? Immutable.Set([action.status.getIn(['reblog', 'id'], action.status.get('id'))]) : Immutable.Set());
-        map.setIn(['new', 'comment'], '');
-      } else {
-        map.updateIn(['new', 'status_ids'], Immutable.Set(), set => set.add(action.status.getIn(['reblog', 'id'], action.status.get('id'))));
-      }
-    });
-  case REPORT_STATUS_TOGGLE:
-    return state.updateIn(['new', 'status_ids'], Immutable.Set(), set => {
-      if (action.checked) {
-        return set.add(action.statusId);
-      }
-
-      return set.remove(action.statusId);
-    });
-  case REPORT_COMMENT_CHANGE:
-    return state.setIn(['new', 'comment'], action.comment);
-  case REPORT_SUBMIT_REQUEST:
-    return state.setIn(['new', 'isSubmitting'], true);
-  case REPORT_SUBMIT_FAIL:
-    return state.setIn(['new', 'isSubmitting'], false);
-  case REPORT_CANCEL:
-  case REPORT_SUBMIT_SUCCESS:
-    return state.withMutations(map => {
-      map.setIn(['new', 'account_id'], null);
-      map.setIn(['new', 'status_ids'], Immutable.Set());
-      map.setIn(['new', 'comment'], '');
-      map.setIn(['new', 'isSubmitting'], false);
-    });
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/search.jsx b/app/assets/javascripts/components/reducers/search.jsx
deleted file mode 100644
index b3fe6c7be..000000000
--- a/app/assets/javascripts/components/reducers/search.jsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import {
-  SEARCH_CHANGE,
-  SEARCH_CLEAR,
-  SEARCH_FETCH_SUCCESS,
-  SEARCH_SHOW
-} from '../actions/search';
-import { COMPOSE_MENTION, COMPOSE_REPLY } from '../actions/compose';
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map({
-  value: '',
-  submitted: false,
-  hidden: false,
-  results: Immutable.Map()
-});
-
-const normalizeSuggestions = (state, value, accounts, hashtags, statuses) => {
-  let newSuggestions = [];
-
-  if (accounts.length > 0) {
-    newSuggestions.push({
-      title: 'account',
-      items: accounts.map(item => ({
-        type: 'account',
-        id: item.id,
-        value: item.acct
-      }))
-    });
-  }
-
-  if (value.indexOf('@') === -1 && value.indexOf(' ') === -1 || hashtags.length > 0) {
-    let hashtagItems = hashtags.map(item => ({
-      type: 'hashtag',
-      id: item,
-      value: `#${item}`
-    }));
-
-    if (value.indexOf('@') === -1 && value.indexOf(' ') === -1 && !value.startsWith('http://') && !value.startsWith('https://') && hashtags.indexOf(value) === -1) {
-      hashtagItems.unshift({
-        type: 'hashtag',
-        id: value,
-        value: `#${value}`
-      });
-    }
-
-    if (hashtagItems.length > 0) {
-      newSuggestions.push({
-        title: 'hashtag',
-        items: hashtagItems
-      });
-    }
-  }
-
-  if (statuses.length > 0) {
-    newSuggestions.push({
-      title: 'status',
-      items: statuses.map(item => ({
-        type: 'status',
-        id: item.id,
-        value: item.id
-      }))
-    });
-  }
-
-  return state.withMutations(map => {
-    map.set('suggestions', newSuggestions);
-    map.set('loaded_value', value);
-  });
-};
-
-export default function search(state = initialState, action) {
-  switch(action.type) {
-  case SEARCH_CHANGE:
-    return state.set('value', action.value);
-  case SEARCH_CLEAR:
-    return state.withMutations(map => {
-      map.set('value', '');
-      map.set('results', Immutable.Map());
-      map.set('submitted', false);
-      map.set('hidden', false);
-    });
-  case SEARCH_SHOW:
-    return state.set('hidden', false);
-  case COMPOSE_REPLY:
-  case COMPOSE_MENTION:
-    return state.set('hidden', true);
-  case SEARCH_FETCH_SUCCESS:
-    return state.set('results', Immutable.Map({
-      accounts: Immutable.List(action.results.accounts.map(item => item.id)),
-      statuses: Immutable.List(action.results.statuses.map(item => item.id)),
-      hashtags: Immutable.List(action.results.hashtags)
-    })).set('submitted', true);
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/settings.jsx b/app/assets/javascripts/components/reducers/settings.jsx
deleted file mode 100644
index 820af99ed..000000000
--- a/app/assets/javascripts/components/reducers/settings.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { SETTING_CHANGE } from '../actions/settings';
-import { STORE_HYDRATE } from '../actions/store';
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map({
-  onboarded: false,
-
-  home: Immutable.Map({
-    shows: Immutable.Map({
-      reblog: true,
-      reply: true
-    })
-  }),
-
-  notifications: Immutable.Map({
-    alerts: Immutable.Map({
-      follow: true,
-      favourite: true,
-      reblog: true,
-      mention: true
-    }),
-
-    shows: Immutable.Map({
-      follow: true,
-      favourite: true,
-      reblog: true,
-      mention: true
-    }),
-
-    sounds: Immutable.Map({
-      follow: true,
-      favourite: true,
-      reblog: true,
-      mention: true
-    })
-  })
-});
-
-export default function settings(state = initialState, action) {
-  switch(action.type) {
-  case STORE_HYDRATE:
-    return state.mergeDeep(action.state.get('settings'));
-  case SETTING_CHANGE:
-    return state.setIn(action.key, action.value);
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/status_lists.jsx b/app/assets/javascripts/components/reducers/status_lists.jsx
deleted file mode 100644
index b883b1c58..000000000
--- a/app/assets/javascripts/components/reducers/status_lists.jsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import {
-  FAVOURITED_STATUSES_FETCH_SUCCESS,
-  FAVOURITED_STATUSES_EXPAND_SUCCESS
-} from '../actions/favourites';
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map({
-  favourites: Immutable.Map({
-    next: null,
-    loaded: false,
-    items: Immutable.List()
-  })
-});
-
-const normalizeList = (state, listType, statuses, next) => {
-  return state.update(listType, listMap => listMap.withMutations(map => {
-    map.set('next', next);
-    map.set('loaded', true);
-    map.set('items', Immutable.List(statuses.map(item => item.id)));
-  }));
-};
-
-const appendToList = (state, listType, statuses, next) => {
-  return state.update(listType, listMap => listMap.withMutations(map => {
-    map.set('next', next);
-    map.set('items', map.get('items').push(...statuses.map(item => item.id)));
-  }));
-};
-
-export default function statusLists(state = initialState, action) {
-  switch(action.type) {
-  case FAVOURITED_STATUSES_FETCH_SUCCESS:
-    return normalizeList(state, 'favourites', action.statuses, action.next);
-  case FAVOURITED_STATUSES_EXPAND_SUCCESS:
-    return appendToList(state, 'favourites', action.statuses, action.next);
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/statuses.jsx b/app/assets/javascripts/components/reducers/statuses.jsx
deleted file mode 100644
index 2002d2223..000000000
--- a/app/assets/javascripts/components/reducers/statuses.jsx
+++ /dev/null
@@ -1,124 +0,0 @@
-import {
-  REBLOG_REQUEST,
-  REBLOG_SUCCESS,
-  REBLOG_FAIL,
-  UNREBLOG_SUCCESS,
-  FAVOURITE_REQUEST,
-  FAVOURITE_SUCCESS,
-  FAVOURITE_FAIL,
-  UNFAVOURITE_SUCCESS
-} from '../actions/interactions';
-import {
-  STATUS_FETCH_SUCCESS,
-  CONTEXT_FETCH_SUCCESS
-} from '../actions/statuses';
-import {
-  TIMELINE_REFRESH_SUCCESS,
-  TIMELINE_UPDATE,
-  TIMELINE_DELETE,
-  TIMELINE_EXPAND_SUCCESS
-} from '../actions/timelines';
-import {
-  ACCOUNT_TIMELINE_FETCH_SUCCESS,
-  ACCOUNT_TIMELINE_EXPAND_SUCCESS,
-  ACCOUNT_BLOCK_SUCCESS
-} from '../actions/accounts';
-import {
-  NOTIFICATIONS_UPDATE,
-  NOTIFICATIONS_REFRESH_SUCCESS,
-  NOTIFICATIONS_EXPAND_SUCCESS
-} from '../actions/notifications';
-import {
-  FAVOURITED_STATUSES_FETCH_SUCCESS,
-  FAVOURITED_STATUSES_EXPAND_SUCCESS
-} from '../actions/favourites';
-import { SEARCH_FETCH_SUCCESS } from '../actions/search';
-import Immutable from 'immutable';
-
-const normalizeStatus = (state, status) => {
-  if (!status) {
-    return state;
-  }
-
-  const normalStatus   = { ...status };
-  normalStatus.account = status.account.id;
-
-  if (status.reblog && status.reblog.id) {
-    state               = normalizeStatus(state, status.reblog);
-    normalStatus.reblog = status.reblog.id;
-  }
-
-  const linebreakComplemented = status.content.replace(/<br \/>/g, '\n').replace(/<\/p><p>/g, '\n\n');
-  normalStatus.unescaped_content = new DOMParser().parseFromString(linebreakComplemented, 'text/html').documentElement.textContent;
-
-  return state.update(status.id, Immutable.Map(), map => map.mergeDeep(Immutable.fromJS(normalStatus)));
-};
-
-const normalizeStatuses = (state, statuses) => {
-  statuses.forEach(status => {
-    state = normalizeStatus(state, status);
-  });
-
-  return state;
-};
-
-const deleteStatus = (state, id, references) => {
-  references.forEach(ref => {
-    state = deleteStatus(state, ref[0], []);
-  });
-
-  return state.delete(id);
-};
-
-const filterStatuses = (state, relationship) => {
-  state.forEach(status => {
-    if (status.get('account') !== relationship.id) {
-      return;
-    }
-
-    state = deleteStatus(state, status.get('id'), state.filter(item => item.get('reblog') === status.get('id')));
-  });
-
-  return state;
-};
-
-const initialState = Immutable.Map();
-
-export default function statuses(state = initialState, action) {
-  switch(action.type) {
-  case TIMELINE_UPDATE:
-  case STATUS_FETCH_SUCCESS:
-  case NOTIFICATIONS_UPDATE:
-    return normalizeStatus(state, action.status);
-  case REBLOG_SUCCESS:
-  case UNREBLOG_SUCCESS:
-  case FAVOURITE_SUCCESS:
-  case UNFAVOURITE_SUCCESS:
-    return normalizeStatus(state, action.response);
-  case FAVOURITE_REQUEST:
-    return state.setIn([action.status.get('id'), 'favourited'], true);
-  case FAVOURITE_FAIL:
-    return state.setIn([action.status.get('id'), 'favourited'], false);
-  case REBLOG_REQUEST:
-    return state.setIn([action.status.get('id'), 'reblogged'], true);
-  case REBLOG_FAIL:
-    return state.setIn([action.status.get('id'), 'reblogged'], false);
-  case TIMELINE_REFRESH_SUCCESS:
-  case TIMELINE_EXPAND_SUCCESS:
-  case ACCOUNT_TIMELINE_FETCH_SUCCESS:
-  case ACCOUNT_TIMELINE_EXPAND_SUCCESS:
-  case CONTEXT_FETCH_SUCCESS:
-  case NOTIFICATIONS_REFRESH_SUCCESS:
-  case NOTIFICATIONS_EXPAND_SUCCESS:
-  case FAVOURITED_STATUSES_FETCH_SUCCESS:
-  case FAVOURITED_STATUSES_EXPAND_SUCCESS:
-  case SEARCH_FETCH_SUCCESS:
-    return normalizeStatuses(state, action.statuses);
-  case TIMELINE_DELETE:
-    return deleteStatus(state, action.id, action.references);
-  case ACCOUNT_BLOCK_SUCCESS:
-    return filterStatuses(state, action.relationship);
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/timelines.jsx b/app/assets/javascripts/components/reducers/timelines.jsx
deleted file mode 100644
index fa9863250..000000000
--- a/app/assets/javascripts/components/reducers/timelines.jsx
+++ /dev/null
@@ -1,317 +0,0 @@
-import {
-  TIMELINE_REFRESH_REQUEST,
-  TIMELINE_REFRESH_SUCCESS,
-  TIMELINE_REFRESH_FAIL,
-  TIMELINE_UPDATE,
-  TIMELINE_DELETE,
-  TIMELINE_EXPAND_SUCCESS,
-  TIMELINE_EXPAND_REQUEST,
-  TIMELINE_EXPAND_FAIL,
-  TIMELINE_SCROLL_TOP,
-  TIMELINE_CONNECT,
-  TIMELINE_DISCONNECT
-} from '../actions/timelines';
-import {
-  REBLOG_SUCCESS,
-  UNREBLOG_SUCCESS,
-  FAVOURITE_SUCCESS,
-  UNFAVOURITE_SUCCESS
-} from '../actions/interactions';
-import {
-  ACCOUNT_TIMELINE_FETCH_REQUEST,
-  ACCOUNT_TIMELINE_FETCH_SUCCESS,
-  ACCOUNT_TIMELINE_FETCH_FAIL,
-  ACCOUNT_TIMELINE_EXPAND_REQUEST,
-  ACCOUNT_TIMELINE_EXPAND_SUCCESS,
-  ACCOUNT_TIMELINE_EXPAND_FAIL,
-  ACCOUNT_BLOCK_SUCCESS,
-  ACCOUNT_MUTE_SUCCESS
-} from '../actions/accounts';
-import {
-  CONTEXT_FETCH_SUCCESS
-} from '../actions/statuses';
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map({
-  home: Immutable.Map({
-    path: () => '/api/v1/timelines/home',
-    next: null,
-    isLoading: false,
-    online: false,
-    loaded: false,
-    top: true,
-    unread: 0,
-    items: Immutable.List()
-  }),
-
-  public: Immutable.Map({
-    path: () => '/api/v1/timelines/public',
-    next: null,
-    isLoading: false,
-    online: false,
-    loaded: false,
-    top: true,
-    unread: 0,
-    items: Immutable.List()
-  }),
-
-  community: Immutable.Map({
-    path: () => '/api/v1/timelines/public',
-    next: null,
-    params: { local: true },
-    isLoading: false,
-    online: false,
-    loaded: false,
-    top: true,
-    unread: 0,
-    items: Immutable.List()
-  }),
-
-  tag: Immutable.Map({
-    path: (id) => `/api/v1/timelines/tag/${id}`,
-    next: null,
-    isLoading: false,
-    id: null,
-    loaded: false,
-    top: true,
-    unread: 0,
-    items: Immutable.List()
-  }),
-
-  accounts_timelines: Immutable.Map(),
-  ancestors: Immutable.Map(),
-  descendants: Immutable.Map()
-});
-
-const normalizeStatus = (state, status) => {
-  const replyToId = status.get('in_reply_to_id');
-  const id        = status.get('id');
-
-  if (replyToId) {
-    if (!state.getIn(['descendants', replyToId], Immutable.List()).includes(id)) {
-      state = state.updateIn(['descendants', replyToId], Immutable.List(), set => set.push(id));
-    }
-
-    if (!state.getIn(['ancestors', id], Immutable.List()).includes(replyToId)) {
-      state = state.updateIn(['ancestors', id], Immutable.List(), set => set.push(replyToId));
-    }
-  }
-
-  return state;
-};
-
-const normalizeTimeline = (state, timeline, statuses, next) => {
-  let ids      = Immutable.List();
-  const loaded = state.getIn([timeline, 'loaded']);
-
-  statuses.forEach((status, i) => {
-    state = normalizeStatus(state, status);
-    ids   = ids.set(i, status.get('id'));
-  });
-
-  state = state.setIn([timeline, 'loaded'], true);
-  state = state.setIn([timeline, 'isLoading'], false);
-
-  if (state.getIn([timeline, 'next']) === null) {
-    state = state.setIn([timeline, 'next'], next);
-  }
-
-  return state.updateIn([timeline, 'items'], Immutable.List(), list => (loaded ? list.unshift(...ids) : ids));
-};
-
-const appendNormalizedTimeline = (state, timeline, statuses, next) => {
-  let moreIds = Immutable.List();
-
-  statuses.forEach((status, i) => {
-    state   = normalizeStatus(state, status);
-    moreIds = moreIds.set(i, status.get('id'));
-  });
-
-  state = state.setIn([timeline, 'isLoading'], false);
-  state = state.setIn([timeline, 'next'], next);
-
-  return state.updateIn([timeline, 'items'], Immutable.List(), list => list.push(...moreIds));
-};
-
-const normalizeAccountTimeline = (state, accountId, statuses, replace = false) => {
-  let ids = Immutable.List();
-
-  statuses.forEach((status, i) => {
-    state = normalizeStatus(state, status);
-    ids   = ids.set(i, status.get('id'));
-  });
-
-  return state.updateIn(['accounts_timelines', accountId], Immutable.Map(), map => map
-    .set('isLoading', false)
-    .set('loaded', true)
-    .set('next', true)
-    .update('items', Immutable.List(), list => (replace ? ids : list.unshift(...ids))));
-};
-
-const appendNormalizedAccountTimeline = (state, accountId, statuses, next) => {
-  let moreIds = Immutable.List([]);
-
-  statuses.forEach((status, i) => {
-    state   = normalizeStatus(state, status);
-    moreIds = moreIds.set(i, status.get('id'));
-  });
-
-  return state.updateIn(['accounts_timelines', accountId], Immutable.Map(), map => map
-    .set('isLoading', false)
-    .set('next', next)
-    .update('items', list => list.push(...moreIds)));
-};
-
-const updateTimeline = (state, timeline, status, references) => {
-  const top = state.getIn([timeline, 'top']);
-
-  state = normalizeStatus(state, status);
-
-  if (!top) {
-    state = state.updateIn([timeline, 'unread'], unread => unread + 1);
-  }
-
-  state = state.updateIn([timeline, 'items'], Immutable.List(), list => {
-    if (top && list.size > 40) {
-      list = list.take(20);
-    }
-
-    if (list.includes(status.get('id'))) {
-      return list;
-    }
-
-    const reblogOfId = status.getIn(['reblog', 'id'], null);
-
-    if (reblogOfId !== null) {
-      list = list.filterNot(itemId => references.includes(itemId));
-    }
-
-    return list.unshift(status.get('id'));
-  });
-
-  return state;
-};
-
-const deleteStatus = (state, id, accountId, references, reblogOf) => {
-  if (reblogOf) {
-    // If we are deleting a reblog, just replace reblog with its original
-    return state.updateIn(['home', 'items'], list => list.map(item => item === id ? reblogOf : item));
-  }
-
-  // Remove references from timelines
-  ['home', 'public', 'community', 'tag'].forEach(function (timeline) {
-    state = state.updateIn([timeline, 'items'], list => list.filterNot(item => item === id));
-  });
-
-  // Remove references from account timelines
-  state = state.updateIn(['accounts_timelines', accountId, 'items'], Immutable.List([]), list => list.filterNot(item => item === id));
-
-  // Remove references from context
-  state.getIn(['descendants', id], Immutable.List()).forEach(descendantId => {
-    state = state.updateIn(['ancestors', descendantId], Immutable.List(), list => list.filterNot(itemId => itemId === id));
-  });
-
-  state.getIn(['ancestors', id], Immutable.List()).forEach(ancestorId => {
-    state = state.updateIn(['descendants', ancestorId], Immutable.List(), list => list.filterNot(itemId => itemId === id));
-  });
-
-  state = state.deleteIn(['descendants', id]).deleteIn(['ancestors', id]);
-
-  // Remove reblogs of deleted status
-  references.forEach(ref => {
-    state = deleteStatus(state, ref[0], ref[1], []);
-  });
-
-  return state;
-};
-
-const filterTimelines = (state, relationship, statuses) => {
-  let references;
-
-  statuses.forEach(status => {
-    if (status.get('account') !== relationship.id) {
-      return;
-    }
-
-    references = statuses.filter(item => item.get('reblog') === status.get('id')).map(item => [item.get('id'), item.get('account')]);
-    state = deleteStatus(state, status.get('id'), status.get('account'), references);
-  });
-
-  return state;
-};
-
-const normalizeContext = (state, id, ancestors, descendants) => {
-  const ancestorsIds   = ancestors.map(ancestor => ancestor.get('id'));
-  const descendantsIds = descendants.map(descendant => descendant.get('id'));
-
-  return state.withMutations(map => {
-    map.setIn(['ancestors', id], ancestorsIds);
-    map.setIn(['descendants', id], descendantsIds);
-  });
-};
-
-const resetTimeline = (state, timeline, id) => {
-  if (timeline === 'tag' && typeof id !== 'undefined' && state.getIn([timeline, 'id']) !== id) {
-    state = state.update(timeline, map => map
-        .set('id', id)
-        .set('isLoading', true)
-        .set('loaded', false)
-        .set('next', null)
-        .set('top', true)
-        .update('items', list => list.clear()));
-  } else {
-    state = state.setIn([timeline, 'isLoading'], true);
-  }
-
-  return state;
-};
-
-const updateTop = (state, timeline, top) => {
-  if (top) {
-    state = state.setIn([timeline, 'unread'], 0);
-  }
-
-  return state.setIn([timeline, 'top'], top);
-};
-
-export default function timelines(state = initialState, action) {
-  switch(action.type) {
-  case TIMELINE_REFRESH_REQUEST:
-  case TIMELINE_EXPAND_REQUEST:
-    return resetTimeline(state, action.timeline, action.id);
-  case TIMELINE_REFRESH_FAIL:
-  case TIMELINE_EXPAND_FAIL:
-    return state.setIn([action.timeline, 'isLoading'], false);
-  case TIMELINE_REFRESH_SUCCESS:
-    return normalizeTimeline(state, action.timeline, Immutable.fromJS(action.statuses), action.next);
-  case TIMELINE_EXPAND_SUCCESS:
-    return appendNormalizedTimeline(state, action.timeline, Immutable.fromJS(action.statuses), action.next);
-  case TIMELINE_UPDATE:
-    return updateTimeline(state, action.timeline, Immutable.fromJS(action.status), action.references);
-  case TIMELINE_DELETE:
-    return deleteStatus(state, action.id, action.accountId, action.references, action.reblogOf);
-  case CONTEXT_FETCH_SUCCESS:
-    return normalizeContext(state, action.id, Immutable.fromJS(action.ancestors), Immutable.fromJS(action.descendants));
-  case ACCOUNT_TIMELINE_FETCH_REQUEST:
-  case ACCOUNT_TIMELINE_EXPAND_REQUEST:
-    return state.updateIn(['accounts_timelines', action.id], Immutable.Map(), map => map.set('isLoading', true));
-  case ACCOUNT_TIMELINE_FETCH_FAIL:
-  case ACCOUNT_TIMELINE_EXPAND_FAIL:
-    return state.updateIn(['accounts_timelines', action.id], Immutable.Map(), map => map.set('isLoading', false));
-  case ACCOUNT_TIMELINE_FETCH_SUCCESS:
-    return normalizeAccountTimeline(state, action.id, Immutable.fromJS(action.statuses), action.replace);
-  case ACCOUNT_TIMELINE_EXPAND_SUCCESS:
-    return appendNormalizedAccountTimeline(state, action.id, Immutable.fromJS(action.statuses), action.next);
-  case ACCOUNT_BLOCK_SUCCESS:
-  case ACCOUNT_MUTE_SUCCESS:
-    return filterTimelines(state, action.relationship, action.statuses);
-  case TIMELINE_SCROLL_TOP:
-    return updateTop(state, action.timeline, action.top);
-  case TIMELINE_CONNECT:
-    return state.setIn([action.timeline, 'online'], true);
-  case TIMELINE_DISCONNECT:
-    return state.setIn([action.timeline, 'online'], false);
-  default:
-    return state;
-  }
-};
diff --git a/app/assets/javascripts/components/reducers/user_lists.jsx b/app/assets/javascripts/components/reducers/user_lists.jsx
deleted file mode 100644
index 7f55c3641..000000000
--- a/app/assets/javascripts/components/reducers/user_lists.jsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import {
-  FOLLOWERS_FETCH_SUCCESS,
-  FOLLOWERS_EXPAND_SUCCESS,
-  FOLLOWING_FETCH_SUCCESS,
-  FOLLOWING_EXPAND_SUCCESS,
-  FOLLOW_REQUESTS_FETCH_SUCCESS,
-  FOLLOW_REQUESTS_EXPAND_SUCCESS,
-  FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
-  FOLLOW_REQUEST_REJECT_SUCCESS
-} from '../actions/accounts';
-import {
-  REBLOGS_FETCH_SUCCESS,
-  FAVOURITES_FETCH_SUCCESS
-} from '../actions/interactions';
-import {
-  BLOCKS_FETCH_SUCCESS,
-  BLOCKS_EXPAND_SUCCESS
-} from '../actions/blocks';
-import {
-  MUTES_FETCH_SUCCESS,
-  MUTES_EXPAND_SUCCESS
-} from '../actions/mutes';
-import Immutable from 'immutable';
-
-const initialState = Immutable.Map({
-  followers: Immutable.Map(),
-  following: Immutable.Map(),
-  reblogged_by: Immutable.Map(),
-  favourited_by: Immutable.Map(),
-  follow_requests: Immutable.Map(),
-  blocks: Immutable.Map(),
-  mutes: Immutable.Map()
-});
-
-const normalizeList = (state, type, id, accounts, next) => {
-  return state.setIn([type, id], Immutable.Map({
-    next,
-    items: Immutable.List(accounts.map(item => item.id))
-  }));
-};
-
-const appendToList = (state, type, id, accounts, next) => {
-  return state.updateIn([type, id], map => {
-    return map.set('next', next).update('items', list => list.push(...accounts.map(item => item.id)));
-  });
-};
-
-export default function userLists(state = initialState, action) {
-  switch(action.type) {
-  case FOLLOWERS_FETCH_SUCCESS:
-    return normalizeList(state, 'followers', action.id, action.accounts, action.next);
-  case FOLLOWERS_EXPAND_SUCCESS:
-    return appendToList(state, 'followers', action.id, action.accounts, action.next);
-  case FOLLOWING_FETCH_SUCCESS:
-    return normalizeList(state, 'following', action.id, action.accounts, action.next);
-  case FOLLOWING_EXPAND_SUCCESS:
-    return appendToList(state, 'following', action.id, action.accounts, action.next);
-  case REBLOGS_FETCH_SUCCESS:
-    return state.setIn(['reblogged_by', action.id], Immutable.List(action.accounts.map(item => item.id)));
-  case FAVOURITES_FETCH_SUCCESS:
-    return state.setIn(['favourited_by', action.id], Immutable.List(action.accounts.map(item => item.id)));
-  case FOLLOW_REQUESTS_FETCH_SUCCESS:
-    return state.setIn(['follow_requests', 'items'], Immutable.List(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next);
-  case FOLLOW_REQUESTS_EXPAND_SUCCESS:
-    return state.updateIn(['follow_requests', 'items'], list => list.push(...action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next);
-  case FOLLOW_REQUEST_AUTHORIZE_SUCCESS:
-  case FOLLOW_REQUEST_REJECT_SUCCESS:
-    return state.updateIn(['follow_requests', 'items'], list => list.filterNot(item => item === action.id));
-  case BLOCKS_FETCH_SUCCESS:
-    return state.setIn(['blocks', 'items'], Immutable.List(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next);
-  case BLOCKS_EXPAND_SUCCESS:
-    return state.updateIn(['blocks', 'items'], list => list.push(...action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next);
-  case MUTES_FETCH_SUCCESS:
-    return state.setIn(['mutes', 'items'], Immutable.List(action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next);
-  case MUTES_EXPAND_SUCCESS:
-    return state.updateIn(['mutes', 'items'], list => list.push(...action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next);
-  default:
-    return state;
-  }
-};