ResultadosDigitais/matrix

View on GitHub
frontend/src/morpheus/store/reducers.js

Summary

Maintainability
C
7 hrs
Test Coverage
import {
  ADD_ERROR,
  SET_CURRENT_USER,
  SET_CURRENT_ROOM,
  ADD_ROOMS,
  SYNC_OFFICE,
  CHANGE_OFFICE_FILTER,
  CHANGE_USERS_FILTER,
  ADD_USER,
  REMOVE_USER,
  USER_ENTER_MEETING,
  USER_LEFT_MEETING,
  CHANGE_SYSTEM_SETTING,
  CHANGE_MEETING_SETTING,
  TOGGLE_MESSAGE_DIALOG,
  TOGGLE_THEME,
  OPEN_LOGOUT_CONFIRM_DIALOG,
  CLOSE_LOGOUT_CONFIRM_DIALOG
} from "./actions";
import storage from "./storage";
import { getDefaultTheme, toggleTheme } from "../Themes";
import ResolutionLevels from "../../constants/ResolutionLevels";

export const initialState = {
  theme: storage.getTheme(getDefaultTheme()),
  currentUser: {},
  currentRoom: {},
  rooms: [],
  usersInRoom: [],
  users: [],
  usersFilter: {
    search: ""
  },
  office: [],
  officeFilter: {
    onlyFullRoom: false,
    search: ""
  },
  systemSettings: {
    notificationDisabled: false
  },
  meetingSettings: storage.getMeetingSettings({
    micEnabled: true,
    videoEnabled: true,
    resolution: `${ResolutionLevels.sd}`,
    enableFirefoxSimulcast: false
  }),
  error: null,
  messageDialog: {
    isOpen: false,
    title: undefined,
    message: undefined
  },
  logoutDialog: {
    isOpen: false
  }
};

// Removes accents from a string and makes it lowercase.
const normalize = str => str.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();

// Creates a filter function normalizing both the field value and query
const normalizedFilter = (field, query) => (
  (item) => normalize(item[field]).includes(normalize(query))
);

const buildOfficeState = state => {
  const { rooms, usersInRoom, officeFilter } = state;

  let office = rooms.map(room => ({
    id: room.id,
    name: room.name,
    description: room.description,
    meetingEnabled: !room.disableMeeting,
    externalMeetUrl: room.externalMeetUrl,
    users: usersInRoom.filter(u => u.room === room.id).map(u => u.user)
  }));

  if (officeFilter.onlyFullRoom) {
    office = office.filter(o => o.users.length > 0);
  }
  if (officeFilter.search) {
    const { search } = officeFilter;
    office = office.filter(normalizedFilter("name", search));
  }

  return {
    ...state,
    office
  };
};

const buildUsersState = state => {
  const { usersInRoom, usersFilter, rooms } = state;

  let users = usersInRoom.map(u => {
    const room = rooms.find(r => r.id === u.room);

    return {
      id: u.user.id,
      name: u.user.name,
      avatar: u.user.imageUrl,
      inMeet: !!u.user.inMeet,
      roomId: room ? room.id : "",
      roomName: room ? room.name : ""
    };
  });

  if (usersFilter.search) {
    const { search } = usersFilter;
    users = users.filter(normalizedFilter("name", search));
  }

  return {
    ...state,
    users
  };
};

const buildInMeetState = (state, action, inMeet) => {
  const { id } = action.user;
  const currentUser = { ...state.currentUser };

  if (currentUser.id === id) {
    currentUser.inMeet = inMeet;
  }

  const usersInRoom = state.usersInRoom.map(item => {
    if (item.user.id === id) {
      return {
        ...item,
        user: {
          ...item.user,
          inMeet
        }
      };
    }

    return item;
  });

  return buildUsersState(
    buildOfficeState({
      ...state,
      currentUser,
      usersInRoom
    })
  );
};

const reducers = (state = initialState, action) => {
  switch (action.type) {
    case SET_CURRENT_USER:
      return {
        ...state,
        currentUser: action.user
      };
    case SET_CURRENT_ROOM:
      return {
        ...state,
        currentRoom: action.room
      };
    case ADD_ROOMS:
      return buildOfficeState({
        ...state,
        rooms: action.rooms
      });
    case CHANGE_OFFICE_FILTER:
      return buildOfficeState({
        ...state,
        officeFilter: {
          ...state.officeFilter,
          [action.key]: action.value
        }
      });
    case SYNC_OFFICE:
      return buildUsersState(
        buildOfficeState({
          ...state,
          usersInRoom: Object.values(action.usersInRoom)
        })
      );
    case CHANGE_USERS_FILTER:
      return buildUsersState({
        ...state,
        usersFilter: {
          ...state.usersFilter,
          [action.key]: action.value
        }
      });
    case CHANGE_SYSTEM_SETTING:
      return {
        ...state,
        systemSettings: {
          ...state.systemSettings,
          [action.key]: action.value
        }
      };
    case CHANGE_MEETING_SETTING: {
      const meetingSettings = {
        ...state.meetingSettings,
        [action.key]: action.value
      };

      storage.setMeetingSettings(meetingSettings);

      return { ...state, meetingSettings };
    }
    case ADD_USER: {
      const index = state.usersInRoom.findIndex(
        u => u.user.id === action.user.id
      );
      let usersInRoom;

      if (index === -1) {
        usersInRoom = [].concat(state.usersInRoom, {
          room: action.roomId,
          user: action.user
        });
      } else {
        usersInRoom = state.usersInRoom.slice(0);
        usersInRoom[index].room = action.roomId;
      }

      return buildUsersState(
        buildOfficeState({
          ...state,
          usersInRoom
        })
      );
    }
    case REMOVE_USER:
      return buildUsersState(
        buildOfficeState({
          ...state,
          usersInRoom: state.usersInRoom.filter(
            x => x.user.id !== action.userId
          )
        })
      );
    case USER_ENTER_MEETING:
      return buildInMeetState(state, action, true);
    case USER_LEFT_MEETING:
      return buildInMeetState(state, action, false);
    case ADD_ERROR:
      return {
        ...state,
        error: {
          message: action.message
        }
      };
    case TOGGLE_MESSAGE_DIALOG:
      return {
        ...state,
        messageDialog: action.props
      };
    case TOGGLE_THEME: {
      const theme = toggleTheme(state.theme);

      storage.setTheme(theme);

      return {
        ...state,
        theme
      };
    }
    case OPEN_LOGOUT_CONFIRM_DIALOG:
      return {
        ...state,
        logoutDialog: {
          isOpen: true
        }
      };
    case CLOSE_LOGOUT_CONFIRM_DIALOG:
      return {
        ...state,
        logoutDialog: {
          isOpen: false
        }
      };
    default:
      return state;
  }
};

export default reducers;