cse112-sp20/Team-Potato

View on GitHub
src/components/PopupFocusMode.jsx

Summary

Maintainability
B
5 hrs
Test Coverage
/**
 *  @fileOverview Component for the Focus Mode Popup, which includes the timer,
 *                buttons to start and end focus mode, and current tabgroup.
 *
 *  @author       Gary Chew
 *  @author       Christopher Yeh
 *  @author       Stephen Cheung
 *  @author       Chau Vu
 *  @author       David Dai
 *
 *  @requires     NPM:react,prop-types,react-compound-timer
 *  @requires     ../styles/PopupFocusMode.css
 */

import React from 'react';
import PropTypes from 'prop-types';
import Timer from 'react-compound-timer';
import ReactSlider from 'react-slider';
import '../styles/PopupFocusMode.css';

/**
 * @description  The class of popup behavior to setup focusmode settings
 * @class
 */
class PopupFocusMode extends React.Component {
  /**
   * @constructor
   *
   * @type  {string} tabGroupName: the name of the focused group
   * @type  {array} tabGroupUrls: the tabgroup urls for the focused group
   * @type  {func} hideFocusMode: function to hide focusMode option for other tabgroups
   */
  constructor() {
    super();
    /**
     * those states are the intial default state
     * @type {boolean} isFocusModeEnables: whether the focus mode has started or not
     * @type {number} defaultTime: the default time for the length of focusmode
     * @type {number} passedTime: the amount of time passed since start focusmode
     */
    this.state = {
      isFocusModeEnabled: false,
      shouldDisplaySlider: true,
      defaultTime: 3600000,
      passedTime: 0,
      whitelistUrls: ['https://www.google.com/'],
    };

    PopupFocusMode.propTypes = {
      tabGroupName: PropTypes.string.isRequired,
      tabGroupUrls: PropTypes.arrayOf(PropTypes.string).isRequired,
      hideFocusMode: PropTypes.func.isRequired,
    };
    /** set the default props */
    PopupFocusMode.defaultProps = {};
  }

  /**
   * @description Method called to render at the beginning of the initial rendering
   */
  componentDidMount = () => {
    /** set the state that focusMode is started or not */
    chrome.storage.sync.get('isFocusModeEnabled', (obj) => {
      this.setState({ isFocusModeEnabled: obj.isFocusModeEnabled });
      if (obj.isFocusModeEnabled) {
        this.setState({ shouldDisplaySlider: false });
      }
    });
    /** start the clocktime to be the initclocktime */
    chrome.storage.sync.get('initClockTime', (obj) => {
      this.setState({ initClockTime: obj.initClockTime });
    });
  };

  /**
   * @description Function of when the focus mode decided to be luanched from the popup
   */
  launchFocusMode = () => {
    /** first get all the tabs */
    chrome.tabs.query({}, (currentTabs) => {
      const { tabGroupUrls } = this.props;
      // Open tabs in tab group
      /** for each tab in the tabgroup, open a seperate window */
      tabGroupUrls.forEach((tabUrl) => {
        chrome.tabs.create({ url: tabUrl });
      });
      /** Save current tabs */
      chrome.storage.sync.set({ savedTabs: currentTabs });
      /** Close current tabs */
      currentTabs.forEach((tab) => {
        chrome.tabs.remove(tab.id);
      });
    });
  };

  /**
   * @description render the popup focus part to initiate focus mode
   * @returns {*}
   */
  render() {
    /** set the following to be props
     * tabGroupname: the name of the tabgroup to launch focus mode
     * tabGroupUrls: the urls stored in the tabgroup which is to be launched into focus mode
     * hideFocusMode: forbidden other tabgroups to start focus mode
     */
    const { tabGroupName, tabGroupUrls, hideFocusMode } = this.props;
    /** set the following to be the current state
     * isFocusModeEnabled: decide whether the focus mode start or end
     * defaultime: the 1 hour default value for focus mode
     * initClockTime: the time when the focus mode is launched
     * passedTime: the amount of time passed by
     */
    const {
      isFocusModeEnabled,
      shouldDisplaySlider,
      defaultTime,
      initClockTime,
      passedTime,
      whitelistUrls,
    } = this.state;
    const buttonText = isFocusModeEnabled ? 'End\nFocus' : 'Start\nFocus';

    /**
     * @description end the focus mode by setting urls and enabled boolen to empty and false
     */
    const endFocusMode = () => {
      chrome.storage.sync.set({ focusedTabGroupUrls: [] });
      this.setState({ isFocusModeEnabled: false });
      chrome.storage.sync.set({ isFocusModeEnabled: false });
      chrome.runtime.sendMessage({ msg: 'end' });
    };

    /**
     * @description the set of actions to update state and so forth when focus
     *              mode is launched
     * @param {number} clock  the initial time of the clock
     */
    const startFocusMode = (clock) => {
      /** set the urls to the tabgroupRuls */
      const focusedTabGroupUrls = tabGroupUrls.concat(whitelistUrls);
      chrome.storage.sync.set({ focusedTabGroupUrls });
      /** update the state and set chrome storage to start focus mode */
      this.setState({ isFocusModeEnabled: true });
      chrome.storage.sync.set({ shouldDisplayFocusMode: true });
      chrome.storage.sync.set({ isFocusModeEnabled: true });
      /** pass in the time for the initial time of the clock */
      chrome.storage.sync.set({ initClockTime: clock });
      /** set chrome storage to start focus mode */
      chrome.runtime.sendMessage({ msg: 'start' });
      /** launch the focus mode */
      this.launchFocusMode();
    };

    /**
     * @description get the starting time
     */
    const getStartingTime = () => {
      /** How much time to start clock with */
      if (isFocusModeEnabled) {
        return initClockTime;
      }
      return defaultTime;
    };

    /**
     * @description get the passed time updating for the focuspopup
     * @returns {number}  return the starting time
     */
    const getPassedTime = () => {
      /** get the passed time */
      chrome.runtime.sendMessage({ msg: 'get' }, (response) => {
        if (response) this.setState({ passedTime: response.time });
      });

      /** update the clock time */
      const newClockTime = initClockTime - passedTime;
      if (newClockTime > 0) {
        return newClockTime;
      }
      return 0;
    };

    return (
      <div className="popupFocusMode">
        <div className="popupFocusModeTitle">
          <h2>
            <strong>Focus Mode</strong>
          </h2>
        </div>
        <Timer
          // Note this is only set ONCE
          initialTime={getStartingTime()} /** get the starting time */
          direction="backward"
          startImmediately={false}
          formatValue={(value) => `${value < 10 ? `0${value}` : value}`}
        >
          {({ start, stop, setTime, getTime }) => (
            <>
              <div className="popupFocusModeBodyContainer">
                <div className="popupFocusModeTabGroupName">{tabGroupName}</div>
                <button
                  className="popupFocusModeTimer"
                  type="button"
                  onClick={() => {
                    // Clicking timer will allow user to set custom time.
                    if (!isFocusModeEnabled && !shouldDisplaySlider) {
                      this.setState({ shouldDisplaySlider: true });
                    } else {
                      this.setState({ shouldDisplaySlider: false });
                    }
                  }}
                  data-testid="timer-button"
                >
                  <Timer.Hours formatValue={(value) => `${value}`} />
                  :
                  <Timer.Minutes />
                  :
                  <Timer.Seconds />
                </button>
                {shouldDisplaySlider ? (
                  <ReactSlider
                    className="horizontal-slider"
                    thumbClassName="sliderThumb"
                    defaultValue={60}
                    min={5}
                    step={5}
                    max={180}
                    snapDragDisabled={false}
                    renderThumb={(props, state) => (
                      <div {...props}>{[setTime(60000 * state.valueNow)]}</div>
                    )}
                  />
                ) : null}
              </div>
              <div className="popupFocusModeBtnContainer">
                <button
                  className="popupFocusModeButton btn"
                  type="button"
                  onClick={() => {
                    if (isFocusModeEnabled) {
                      stop();
                      endFocusMode();
                      hideFocusMode();
                    } else {
                      start();
                      // Set initial time so we can set a new time when popup is reopened
                      startFocusMode(getTime());
                    }
                  }}
                >
                  {buttonText}
                </button>
                <br />
                {isFocusModeEnabled ? (
                  [start(), setTime(getPassedTime())] // Where we get time from background
                ) : (
                  <button
                    type="button"
                    className="popupFocusModeBackButton btn"
                    onClick={() => {
                      hideFocusMode();
                    }}
                  >
                    Go Back
                  </button>
                )}
                <br />
              </div>
            </>
          )}
        </Timer>
      </div>
    );
  }
}
export default PopupFocusMode;