Home Reference Source

src/components/TimersDashboard.js

import React from 'react';
import helpers from '../helpers';
import ServerCommunication from '../helpers/serverCommunication';

import EditableTimerList from './EditableTimerList';
import ToggleableTimerForm from './ToggleableTimerForm';

const Client = new ServerCommunication();

/**
 * This is the main component, it shows a list of editable timers and a button/box to create a new timer
 * It also handle all the logic and communication with the server
 */
export default class TimersDashboard extends React.Component {

    state = {
        timers: []
    };

    handleEditFormSubmit = (attrs) => {
        this.updateTimer(attrs);
    };

    handleStartClick = (timerId) => {
        this.startTimer(timerId);
    };

    handleStopClick = (timerId) => {
        this.stopTimer(timerId);
    };

    /**
     * Return a function for filter/find in an array an element with the specified id
     * @param {string} searched_id
     * @returns {function(arg : {id: string}): boolean}
     */
    static byId(searched_id) {
        return ({id}) => id === searched_id;
    }

    /**
     * Update a timer using the defined id
     * @param {string} id
     * @param {APITimer} attrs
     */
    updateTimerById(id, attrs) {
        const timers = this.state.timers.slice();
        const timerPos = timers.findIndex(TimersDashboard.byId(id));
        if (~timerPos) {
            timers[timerPos] = Object.assign({}, timers[timerPos], attrs);
            this.setState({
                timers
            });
        }
    }

    /**
     * Update a timer
     * @param {APITimer} attrs
     */
    updateTimer(attrs) {
        this.updateTimerById(attrs.id, {
            title: attrs.title,
            project: attrs.project
        });
        Client.updateTimer(attrs);
    }

    /**
     * Start a timer
     * @param {string} timerId
     */
    startTimer(timerId) {
        this.updateTimerById(timerId, {
            runningSince: Date.now()
        });
        Client.startTimer({
            id: timerId
        });
    }

    /**
     * Stop a timer
     * @param {string} timerId
     */
    stopTimer(timerId) {
        const timer = this.state.timers.find(TimersDashboard.byId(timerId));
        if (timer) {
            this.updateTimerById(timerId, {
                elapsed: timer.elapsed + Date.now() - timer.runningSince,
                runningSince: null
            });
            Client.stopTimer({
                id: timerId
            });
        }
    }

    handleCreateFormSubmit = (timer) => {
        this.createTimer(timer);
    };

    /**
     * Create a new timer
     * @param {APITimer} timer
     */
    createTimer(timer) {
        const t = helpers.newTimer(timer);
        this.setState({
            timers: this.state.timers.concat(t)
        });
        Client.createTimer(timer)
    }

    handleTrashClick = (timerId) => {
        this.deleteTimer(timerId);
    };

    /**
     * Delete the specified timerId from the server
     * @param {string} timerId
     */
    deleteTimer(timerId) {
        this.setState({
            timers: this.state.timers.filter(({id}) => id !== timerId)
        });
        Client.deleteTimer( timerId );
    }

    loadTimersFromServer = async() => {
        try {
            const timers = await Client.getTimers();
            this.setState({
                timers
            });
        } catch (err) {
            console.error(err);
        }
    }

    /**
     * Reload the data from the server every 5s
     */
    componentDidMount() {
        this.loadTimersFromServer();
        /**
         * Ref of the setInterval
         * This variable is used to clear the interval when the element is unmounted
         * @type {number}
         */
        this.ajaxInterval = setInterval(this.loadTimersFromServer, 5000);
    }

    /**
     * Stop loading the data from the server
     */
    componentWillUnmount() {
        clearInterval(this.ajaxInterval);
    }

    /**
     * Render
     * @returns {XML}
     */
    render() {
        return (
            <div className='ui three column centered grid'>
                <div className='column'>
                    <EditableTimerList
                        onFormSubmit={this.handleEditFormSubmit}
                        onTrashClick={this.handleTrashClick}
                        onStartClick={this.handleStartClick}
                        onStopClick={this.handleStopClick}
                        timers={this.state.timers}
                    />
                    <ToggleableTimerForm
                        onFormSubmit={this.handleCreateFormSubmit}
                        isOpen={true}/>
                </div>
            </div>
        );
    }
}