bokuweb/tsukiakari

View on GitHub
src/renderer/src/reducers/tweets.js

Summary

Maintainability
F
3 days
Test Coverage
import { handleActions } from 'redux-actions';
import uuid from 'uuid';

const defaultState = {
  timeline: {},
  columns: [],
  filterQueries: [],
};

const iconSelector = {
  Home: 'lnr lnr-home',
  Favorite: 'lnr lnr-heart',
  Mention: 'fa fa-at',
  Search: 'lnr lnr-magnifier',
};

const createNewColumns = (state, results, key) => (
  state.columns.map(column => {
    const newColumn = { ...column };
    column.contents.forEach(content => {
      if (`${content.account.id}:${content.type}` === key
          || `${content.subTitle}:${content.type}` === key) {
        newColumn.results = results.map(result => ({ key, id: result }));
      }
    });
    return newColumn;
  })
);

/**
 * @param  {object}   state
 * @param  {object}   action
 * @return {object}
 */
const updateTweet = (state, action) => {
  const { account: { id }, tweet } = action.payload;
  const { timeline } = state;
  Object.keys(timeline).forEach(key => {
    if (key.indexOf(id) !== -1) {
      timeline[key].entities.tweets[tweet.id_str] = tweet;
    }
  });
  return {
    ...state,
    timeline: {
      ...timeline,
    },
  };
};

const updateTweetProperty = (accountId, tweetId, timeline, props) => {
  Object.keys(timeline).forEach(key => {
    if (key.indexOf(accountId) !== -1) {
      timeline[key].entities.tweets[tweetId] = {
        ...timeline[key].entities.tweets[tweetId],
        ...props,
      };
    }
  });
  return timeline;
};

export default handleActions({
  RECIEVE_TWEET: (state, action) => {
    // TODO: refactor
    let results;
    const { account: { id_str }, tweet, type, q } = action.payload;
    const key = type === 'Search' ? `${q}:${type}` : `${id_str}:${type}`;
    const contents = state.columns.filter(column => column.contents[0].key === key);
    if (contents.length === 0) return state;
    const timeline = state.timeline[key] || { entities: { tweets: { } } };

    if (!(timeline.entities && timeline.entities.tweets[tweet.result])) {
      const result = [tweet.result];
      Array.prototype.push.apply(result, timeline.results);
      results = result;
    } else {
      results = timeline.results || [];
    }
    const entities = { ...timeline.entities.tweets, ...tweet.entities.tweets };
    const columns = createNewColumns(state, results, key);
    return {
      ...state,
      timeline: {
        ...state.timeline,
        [key]: {
          results,
          entities: {
            tweets: entities,
          },
        },
      },
      columns,
    };
  },
  FETCH_TIMELINE_SUCCESS: (state, action) => {
    // TODO: refactor
    const { account: { id }, tweets, type, params } = action.payload;
    const key = type === 'Search'
            ? `${params.q}:${type}`
            : `${id}:${type}`;
    const timeline = state.timeline[key] || { entities: {} };
    const results = tweets.result
            .filter(result => !(timeline.entities && timeline.entities[result]))
            .concat(state.timeline.results || []);
    const entities = { ...timeline.entities, ...tweets.entities };
    const columns = createNewColumns(state, results, key);
    return { ...state, timeline: { ...state.timeline, [key]: { results, entities } }, columns };
  },
  CREATE_FAVORITE_REQUEST: (state, action) => {
    const { account: { id }, tweet } = action.payload;
    const { timeline } = state;
    Object.keys(timeline).forEach(key => {
      if (key.indexOf(id) !== -1) {
        timeline[key].entities.tweets[tweet.id_str] = {
          ...timeline[key].entities.tweets[tweet.id_str],
          favorited: true,
        };
      }
    });
    return {
      ...state,
      timeline: {
        ...timeline,
      },
    };
  },
  CREATE_FAVORITE_SUCCESS: updateTweet,
  DESTROY_FAVORITE_REQUEST: (state, action) => {
    const { account: { id }, tweet } = action.payload;
    const { timeline } = state;
    Object.keys(timeline).forEach(key => {
      if (key.indexOf(id) !== -1) {
        timeline[key].entities.tweets[tweet.id_str] = {
          ...timeline[key].entities.tweets[tweet.id_str],
          favorited: false,
        };
      }
    });
    return {
      ...state,
      timeline: {
        ...timeline,
      },
    };
  },
  DESTROY_FAVORITE_SUCCESS: updateTweet,
  CREATE_RETWEET_REQUEST: (state, action) => {
    const { account: { id }, tweet } = action.payload;
    const { timeline } = state;
    Object.keys(timeline).forEach(key => {
      if (key.indexOf(id) !== -1) {
        timeline[key].entities.tweets[tweet.id_str] = {
          ...timeline[key].entities.tweets[tweet.id_str],
          retweeted: true,
        };
      }
    });
    return {
      ...state,
      timeline: {
        ...timeline,
      },
    };
  },
  CREATE_RETWEET_SUCCESS: updateTweet,
  REQUEST_DESTROY_RETWEET: (state, action) => {
    const { account: { id }, tweet } = action.payload;
    const { timeline } = state;
    Object.keys(timeline).forEach(key => {
      if (key.indexOf(id) !== -1) {
        timeline[key].entities.tweets[tweet.id_str] = {
          ...timeline[key].entities.tweets[tweet.id_str],
          retweeted: false,
        };
      }
    });
    return {
      ...state,
      timeline: {
        ...timeline,
      },
    };
  },
  ADD_COLUMN: (state, action) => {
    const { account, type, params } = action.payload;
    const id = uuid.v4();
    const title = type; // TODO: If mixed columns, custom timeline
    const icon = iconSelector[type];
    const key = type === 'Search'
            ? `${params.q}:${type}`
            : `${account.id}:${type}`;

    const timeline = state.timeline[key] || { results: [] }; // TODO: implement mixed timeline
    const { columns } = state;
    const subTitle = type === 'Search'
            ? params.q
            : `@${account.screen_name}`;
    columns.unshift({
      id,
      title,
      subTitle,
      icon,
      type,
      params,
      contents: [{ account, type, key, subTitle }],
      results: timeline.results.map(result => ({ key, id: result })),
    });
    return {
      ...state,
      columns: [...columns],
    };
  }, 
  DELETE_COLUMN: (state, action) => {
    const { id, type, params } = action.payload;
    const queries = [...state.filterQueries];
    console.log(params.q);
    if (type === 'Search') {
      for (let i = 0; i < queries.length; i++) {
        if (params.q === queries[i]) {
          queries.splice(i, 1);
          break;
        }
      }
    }
    const columns = state.columns.filter(column => column.id !== id);
    return {
      ...state,
      columns,
      filterQueries: queries || [],
    };
  },
  CONNECT_FILTER_STREAM: (state, action) => {
    const { params } = action.payload;
    return {
      ...state,
      filterQueries: state.filterQueries.concat([params.q]),
    };
  },
  SHOW_FULLSCREEN_VIDEO: (state, action) => {
    const { soueces, currentTime } = action.payload;
    return {
      ...state,
      
    };
  },
}, defaultState);