<commit_before>/* global Chart */
import Component from '@ember/component';
import moment from 'moment';
import {action} from '@ember/object';
import {computed, get} from '@ember/object';
import {getSymbol} from 'ghost-admin/utils/currency';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';

const DATE_FORMAT = 'D MMM YYYY';

export default Component.extend({
    ajax: service(),
    membersStats: service(),

    // public attrs
    nightShift: false,
    lineColor: '#14b8ff',

    stats: null,
    tagName: '',
    chartStats: null,
    chartData: null,
    chartOptions: null,
    showSummary: true,
    showRange: true,
    chartType: '',
    chartSize: '',
    chartHeading: 'Total members',

    isSmall: computed('chartSize', function () {
        if (this.chartSize === 'small') {
            return true;
        }
        return false;
    }),

    startDateLabel: computed('membersStats.stats', function () {
        if (!this.membersStats?.stats?.total_on_date) {
            return '';
        }

        let firstDate = Object.keys(this.membersStats.stats.total_on_date)[0];
        return moment(firstDate).format(DATE_FORMAT);
    }),

    selectedRange: computed('membersStats.days', function () {
        const availableRanges = this.availableRanges;
        return availableRanges.findBy('days', this.membersStats.days);
    }),

    availableRanges: computed(function () {
        return [{
            name: '30 days',
            days: '30'
        }, {
            name: '90 days',
            days: '90'
        }, {
            name: '365 days',
            days: '365'
        }, {
            name: 'All time',
            days: 'all-time'
        }];
    }),

    // Lifecycle ---------------------------------------------------------------

    init() {
        this._super(...arguments);
        this.setChartJSDefaults();
    },

    didReceiveAttrs() {
        if (this.chartStats) {
            const {options, data, title, stats} = this.chartStats;

            this.set('stats', stats);
            this.set('chartHeading', title);
            this.setChartData(data);
            this.setChartOptions(options);
        }

        if (this._lastNightShift !== undefined && this.nightShift !== this._lastNightShift) {
            const {options = {}} = this.chartStats;

            this.setChartOptions(options);
        }
        this._lastNightShift = this.nightShift;
    },

    // Actions -----------------------------------------------------------------

    changeDateRange: action(function (range) {
        this.membersStats.days = get(range, 'days');
        this.fetchStatsTask.perform();
    }),

    // Tasks -------------------------------------------------------------------

    fetchStatsTask: task(function* () {
        let stats;
        if (!this.chartType) {
            this.set('stats', null);
            stats = yield this.membersStats.fetch();
            this.setOriginalChartData(stats);
        }
    }),

    setOriginalChartData(stats) {
        if (stats) {
            this.set('stats', stats);

            this.setChartOptions({
                rangeInDays: Object.keys(stats.total_on_date).length
            });

            this.setChartData({
                dateLabels: Object.keys(stats.total_on_date),
                dateValues: Object.values(stats.total_on_date)
            });
        }
    },

    // Internal ----------------------------------------------------------------

    setChartData({dateLabels, dateValues, label = 'Total Members'}) {
        let backgroundColors = this.lineColor;

        if (this.chartType === 'open-rate') {
            backgroundColors = dateLabels.map((val) => {
                if (val) {
                    return this.lineColor;
                } else {
                    return (this.nightShift ? '#7C8B9A' : '#CED4D9');
                }
            });
        }

        this.set('chartData', {
            labels: dateLabels,
            datasets: [{
                label: label,
                cubicInterpolationMode: 'monotone',
                data: dateValues,
                fill: false,
                backgroundColor: backgroundColors,
                pointRadius: 0,
                pointHitRadius: 10,
                borderColor: this.lineColor,
                borderJoinStyle: 'miter',
                maxBarThickness: 20,
                minBarLength: 2
            }]
        });
    },

    setChartOptions({rangeInDays}) {
        let maxTicksAllowed = this.isSmall ? 3 : this.getTicksForRange(rangeInDays);

        if (this.chartType === 'open-rate') {
            maxTicksAllowed = 0;
        }

        this.setChartJSDefaults();
        let options = {
            responsive: true,
            responsiveAnimationDuration: 5,
            maintainAspectRatio: false,
            layout: {
                padding: {
                    top: (this.isSmall ? 20 : 5), // Needed otherwise the top dot is cut
                    right: 10,
                    bottom: (this.isSmall ? 20 : 5),
                    left: 10
                }
            },
            title: {
                display: false
            },
            tooltips: {
                intersect: false,
                mode: 'index',
                displayColors: false,
                backgroundColor: '#15171A',
                xPadding: 7,
                yPadding: 7,
                cornerRadius: 5,
                caretSize: 7,
                caretPadding: 5,
                bodyFontSize: 12.5,
                titleFontSize: 12,
                titleFontStyle: 'normal',
                titleFontColor: 'rgba(255, 255, 255, 0.7)',
                titleMarginBottom: 3,
                filter: (tooltipItems, data) => {
                    if (this.chartType === 'open-rate') {
                        let label = data.labels[tooltipItems.index];
                        if (label === '') {
                            return false;
                        }
                    }
                    return true;
                },
                callbacks: {
                    label: (tooltipItems, data) => {
                        const labelText = data.datasets[tooltipItems.datasetIndex].label;
                        let valueText = data.datasets[tooltipItems.datasetIndex].data[tooltipItems.index].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                        if (this.chartType === 'mrr') {
                            const currency = getSymbol(this.stats.currency);
                            valueText = `${currency}${valueText}`;
                        }
                        if (this.chartType === 'open-rate') {
                            valueText = `${valueText}%`;
                        }
                        return `${labelText}: ${valueText}`;
                    },
                    title: (tooltipItems) => {
                        if (this.chartType === 'open-rate') {
                            if (tooltipItems.length) {
                                return tooltipItems[0].xLabel;
                            } else {
                                return '';
                            }
                        }
                        return moment(tooltipItems[0].xLabel).format(DATE_FORMAT);
                    }
                }
            },
            hover: {
                mode: 'index',
                intersect: false,
                animationDuration: 120
            },
            legend: {
                display: false
            },
            scales: {
                xAxes: [{
                    labelString: 'Date',
                    gridLines: {
                        drawTicks: false,
                        color: (this.nightShift ? '#333F44' : '#DDE1E5'),
                        zeroLineColor: (this.nightShift ? '#333F44' : '#DDE1E5')
                    },
                    ticks: {
                        display: false,
                        maxRotation: 0,
                        minRotation: 0,
                        padding: 6,
                        autoSkip: false,
                        fontColor: '#626D79',
                        maxTicksLimit: 10,
                        callback: (value, index, values) => {
                            let step = (values.length - 1) / (maxTicksAllowed);
                            let steps = [];
                            for (let i = 0; i < maxTicksAllowed; i++) {
                                steps.push(Math.ceil(i * step));
                            }

                            if (index === 0) {
                                return value;
                            }
                            if (index === (values.length - 1) && this.chartType !== 'open-rate') {
                                return 'Today';
                            }

                            if (steps.includes(index)) {
                                return '';
                            }
                        }
                    }
                }],
                yAxes: [{
                    gridLines: {
                        drawTicks: false,
                        display: false,
                        drawBorder: false
                    },
                    ticks: {
                        maxTicksLimit: 5,
                        fontColor: '#7C8B9A',
                        padding: 8,
                        precision: 0,
                        callback: (value) => {
                            const currency = this.chartType === 'mrr' ? getSymbol(this.stats.currency) : '';
                            if (parseInt(value) >= 1000) {
                                return currency + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                            } else {
                                return currency + value;
                            }
                        }
                    }
                }]
            }
        };

        if (this.chartType === 'mrr') {
            const chartData = this.get('chartData').datasets[0].data;
            let allZeros = true;
            for (let i = 0; i < chartData.length; i++) {
                const element = chartData[i];
                if (element !== 0) {
                    allZeros = false;
                    break;
                }
            }
            if (allZeros) {
                options.scales.yAxes[0].ticks.suggestedMin = 0;
                options.scales.yAxes[0].ticks.suggestedMax = 100;
            }
        }

        if (this.chartType === 'all-members' || this.chartType === 'open-rate') {
            options.scales.yAxes[0].ticks.suggestedMin = 0;
        }
        if (this.isSmall) {
            options.scales.yAxes[0].ticks.display = false;
            options.scales.xAxes[0].gridLines.display = true;
        }
        this.set('chartOptions', options);
    },

    getTicksForRange(rangeInDays) {
        if (rangeInDays <= 30) {
            return 5;
        } else if (rangeInDays <= 90) {
            return 10;
        } else {
            return 15;
        }
    },

    setChartJSDefaults() {
        Chart.defaults.LineWithLine = Chart.defaults.line;
        Chart.controllers.LineWithLine = Chart.controllers.line.extend({
            draw: function (ease) {
                Chart.controllers.line.prototype.draw.call(this, ease);

                if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
                    let activePoint = this.chart.tooltip._active[0];
                    let ctx = this.chart.ctx;
                    let x = activePoint.tooltipPosition().x;
                    let topY = this.chart.scales['y-axis-0'].top;
                    let bottomY = this.chart.scales['y-axis-0'].bottom;

                    // draw line
                    ctx.save();
                    ctx.beginPath();
                    ctx.moveTo(x, topY);
                    ctx.lineTo(x, bottomY);
                    ctx.lineWidth = 1;
                    ctx.strokeStyle = (this.nightShift ? 'rgba(62, 176, 239, 0.65)' : 'rgba(62, 176, 239, 0.1)');
                    ctx.stroke();
                    ctx.restore();
                }
            }
        });
    }
});
<commit_msg>Refined no-data chart for total members<commit_after>/* global Chart */
import Component from '@ember/component';
import moment from 'moment';
import {action} from '@ember/object';
import {computed, get} from '@ember/object';
import {getSymbol} from 'ghost-admin/utils/currency';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';

const DATE_FORMAT = 'D MMM YYYY';

export default Component.extend({
    ajax: service(),
    membersStats: service(),

    // public attrs
    nightShift: false,
    lineColor: '#14b8ff',

    stats: null,
    tagName: '',
    chartStats: null,
    chartData: null,
    chartOptions: null,
    showSummary: true,
    showRange: true,
    chartType: '',
    chartSize: '',
    chartHeading: 'Total members',

    isSmall: computed('chartSize', function () {
        if (this.chartSize === 'small') {
            return true;
        }
        return false;
    }),

    startDateLabel: computed('membersStats.stats', function () {
        if (!this.membersStats?.stats?.total_on_date) {
            return '';
        }

        let firstDate = Object.keys(this.membersStats.stats.total_on_date)[0];
        return moment(firstDate).format(DATE_FORMAT);
    }),

    selectedRange: computed('membersStats.days', function () {
        const availableRanges = this.availableRanges;
        return availableRanges.findBy('days', this.membersStats.days);
    }),

    availableRanges: computed(function () {
        return [{
            name: '30 days',
            days: '30'
        }, {
            name: '90 days',
            days: '90'
        }, {
            name: '365 days',
            days: '365'
        }, {
            name: 'All time',
            days: 'all-time'
        }];
    }),

    // Lifecycle ---------------------------------------------------------------

    init() {
        this._super(...arguments);
        this.setChartJSDefaults();
    },

    didReceiveAttrs() {
        if (this.chartStats) {
            const {options, data, title, stats} = this.chartStats;

            this.set('stats', stats);
            this.set('chartHeading', title);
            this.setChartData(data);
            this.setChartOptions(options);
        }

        if (this._lastNightShift !== undefined && this.nightShift !== this._lastNightShift) {
            const {options = {}} = this.chartStats;

            this.setChartOptions(options);
        }
        this._lastNightShift = this.nightShift;
    },

    // Actions -----------------------------------------------------------------

    changeDateRange: action(function (range) {
        this.membersStats.days = get(range, 'days');
        this.fetchStatsTask.perform();
    }),

    // Tasks -------------------------------------------------------------------

    fetchStatsTask: task(function* () {
        let stats;
        if (!this.chartType) {
            this.set('stats', null);
            stats = yield this.membersStats.fetch();
            this.setOriginalChartData(stats);
        }
    }),

    setOriginalChartData(stats) {
        if (stats) {
            this.set('stats', stats);

            this.setChartOptions({
                rangeInDays: Object.keys(stats.total_on_date).length
            });

            this.setChartData({
                dateLabels: Object.keys(stats.total_on_date),
                dateValues: Object.values(stats.total_on_date)
            });
        }
    },

    // Internal ----------------------------------------------------------------

    setChartData({dateLabels, dateValues, label = 'Total Members'}) {
        let backgroundColors = this.lineColor;

        if (this.chartType === 'open-rate') {
            backgroundColors = dateLabels.map((val) => {
                if (val) {
                    return this.lineColor;
                } else {
                    return (this.nightShift ? '#7C8B9A' : '#CED4D9');
                }
            });
        }

        this.set('chartData', {
            labels: dateLabels,
            datasets: [{
                label: label,
                cubicInterpolationMode: 'monotone',
                data: dateValues,
                fill: false,
                backgroundColor: backgroundColors,
                pointRadius: 0,
                pointHitRadius: 10,
                borderColor: this.lineColor,
                borderJoinStyle: 'miter',
                maxBarThickness: 20,
                minBarLength: 2
            }]
        });
    },

    setChartOptions({rangeInDays}) {
        let maxTicksAllowed = this.isSmall ? 3 : this.getTicksForRange(rangeInDays);

        if (this.chartType === 'open-rate') {
            maxTicksAllowed = 0;
        }

        this.setChartJSDefaults();
        let options = {
            responsive: true,
            responsiveAnimationDuration: 5,
            maintainAspectRatio: false,
            layout: {
                padding: {
                    top: (this.isSmall ? 20 : 5), // Needed otherwise the top dot is cut
                    right: 10,
                    bottom: (this.isSmall ? 20 : 5),
                    left: 10
                }
            },
            title: {
                display: false
            },
            tooltips: {
                intersect: false,
                mode: 'index',
                displayColors: false,
                backgroundColor: '#15171A',
                xPadding: 7,
                yPadding: 7,
                cornerRadius: 5,
                caretSize: 7,
                caretPadding: 5,
                bodyFontSize: 12.5,
                titleFontSize: 12,
                titleFontStyle: 'normal',
                titleFontColor: 'rgba(255, 255, 255, 0.7)',
                titleMarginBottom: 3,
                filter: (tooltipItems, data) => {
                    if (this.chartType === 'open-rate') {
                        let label = data.labels[tooltipItems.index];
                        if (label === '') {
                            return false;
                        }
                    }
                    return true;
                },
                callbacks: {
                    label: (tooltipItems, data) => {
                        const labelText = data.datasets[tooltipItems.datasetIndex].label;
                        let valueText = data.datasets[tooltipItems.datasetIndex].data[tooltipItems.index].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                        if (this.chartType === 'mrr') {
                            const currency = getSymbol(this.stats.currency);
                            valueText = `${currency}${valueText}`;
                        }
                        if (this.chartType === 'open-rate') {
                            valueText = `${valueText}%`;
                        }
                        return `${labelText}: ${valueText}`;
                    },
                    title: (tooltipItems) => {
                        if (this.chartType === 'open-rate') {
                            if (tooltipItems.length) {
                                return tooltipItems[0].xLabel;
                            } else {
                                return '';
                            }
                        }
                        return moment(tooltipItems[0].xLabel).format(DATE_FORMAT);
                    }
                }
            },
            hover: {
                mode: 'index',
                intersect: false,
                animationDuration: 120
            },
            legend: {
                display: false
            },
            scales: {
                xAxes: [{
                    labelString: 'Date',
                    gridLines: {
                        drawTicks: false,
                        color: (this.nightShift ? '#333F44' : '#DDE1E5'),
                        zeroLineColor: (this.nightShift ? '#333F44' : '#DDE1E5')
                    },
                    ticks: {
                        display: false,
                        maxRotation: 0,
                        minRotation: 0,
                        padding: 6,
                        autoSkip: false,
                        fontColor: '#626D79',
                        maxTicksLimit: 10,
                        callback: (value, index, values) => {
                            let step = (values.length - 1) / (maxTicksAllowed);
                            let steps = [];
                            for (let i = 0; i < maxTicksAllowed; i++) {
                                steps.push(Math.ceil(i * step));
                            }

                            if (index === 0) {
                                return value;
                            }
                            if (index === (values.length - 1) && this.chartType !== 'open-rate') {
                                return 'Today';
                            }

                            if (steps.includes(index)) {
                                return '';
                            }
                        }
                    }
                }],
                yAxes: [{
                    gridLines: {
                        drawTicks: false,
                        display: false,
                        drawBorder: false
                    },
                    ticks: {
                        maxTicksLimit: 5,
                        fontColor: '#7C8B9A',
                        padding: 8,
                        precision: 0,
                        callback: (value) => {
                            const currency = this.chartType === 'mrr' ? getSymbol(this.stats.currency) : '';
                            if (parseInt(value) >= 1000) {
                                return currency + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                            } else {
                                return currency + value;
                            }
                        }
                    }
                }]
            }
        };

        if (this.chartType === 'mrr' || this.chartType === 'all-members') {
            const chartData = this.get('chartData').datasets[0].data;
            let allZeros = true;
            for (let i = 0; i < chartData.length; i++) {
                const element = chartData[i];
                if (element !== 0) {
                    allZeros = false;
                    break;
                }
            }
            if (allZeros) {
                options.scales.yAxes[0].ticks.suggestedMin = 0;
                options.scales.yAxes[0].ticks.suggestedMax = 100;
            }
        }

        if (this.chartType === 'open-rate') {
            options.scales.yAxes[0].ticks.suggestedMin = 0;
        }

        if (this.isSmall) {
            options.scales.yAxes[0].ticks.display = false;
            options.scales.xAxes[0].gridLines.display = true;
        }
        this.set('chartOptions', options);
    },

    getTicksForRange(rangeInDays) {
        if (rangeInDays <= 30) {
            return 5;
        } else if (rangeInDays <= 90) {
            return 10;
        } else {
            return 15;
        }
    },

    setChartJSDefaults() {
        Chart.defaults.LineWithLine = Chart.defaults.line;
        Chart.controllers.LineWithLine = Chart.controllers.line.extend({
            draw: function (ease) {
                Chart.controllers.line.prototype.draw.call(this, ease);

                if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
                    let activePoint = this.chart.tooltip._active[0];
                    let ctx = this.chart.ctx;
                    let x = activePoint.tooltipPosition().x;
                    let topY = this.chart.scales['y-axis-0'].top;
                    let bottomY = this.chart.scales['y-axis-0'].bottom;

                    // draw line
                    ctx.save();
                    ctx.beginPath();
                    ctx.moveTo(x, topY);
                    ctx.lineTo(x, bottomY);
                    ctx.lineWidth = 1;
                    ctx.strokeStyle = (this.nightShift ? 'rgba(62, 176, 239, 0.65)' : 'rgba(62, 176, 239, 0.1)');
                    ctx.stroke();
                    ctx.restore();
                }
            }
        });
    }
});
<|endoftext|>


<commit_before>define(["./_WidgetBase"], function(_WidgetBase){

/*=====
	var _WidgetBase = dijit._WidgetBase;
====*/

	// module:
	//		dijit/_BidiSupport
	// summary:
	//		Module that deals with BIDI, special with the auto
	//		direction if needed without changing the GUI direction.
	//		Including this module will extend _WidgetBase with BIDI related methods.
	// description:
	//		There's a special need for displaying BIDI text in rtl direction
	//		in ltr GUI, sometimes needed auto support.
	//		In creation of widget, if it's want to activate this class,
	//		the widget should define the "textDir".

	_WidgetBase.extend({

		getTextDir: function(/*String*/ text){
			// summary:
			//		Gets the right direction of text.
			// description:
			// 		If textDir is ltr or rtl returns the value.
			//		If it's auto, calls to another function that responsible
			//		for checking the value, and defining the direction.
			//	tags:
			//		protected.
			return this.textDir == "auto" ? this._checkContextual(text) : this.textDir;
		},

		_checkContextual: function(text){
			// summary:
			//		Finds the first strong (directional) character, return ltr if isLatin
			//		or rtl if isBidiChar.
			//	tags:
			//		private.

			// look for strong (directional) characters
			var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text);
			// if found return the direction that defined by the character, else return widgets dir as defult.
			return fdc ? ( fdc[0] <= 'z' ? "ltr" : "rtl" ) : this.dir ? this.dir : this.isLeftToRight() ? "ltr" : "rtl";
		},

		applyTextDir: function(/*Object*/ element, /*String*/ text){
			// summary:
			//		Set element.dir according to this.textDir
			// element:
			//		The text element to be set. Should have dir property.
			// text:
			//		Used in case this.textDir is "auto", for calculating the right transformation
			// description:
			// 		If textDir is ltr or rtl returns the value.
			//		If it's auto, calls to another function that responsible
			//		for checking the value, and defining the direction.
			//	tags:
			//		protected.

			var textDir = this.textDir == "auto" ? this._checkContextual(text) : this.textDir;
			// update only when there's a difference
			if(element.dir != textDir){
				element.dir = textDir;
			}
		}
	});

	return _WidgetBase;
});
<commit_msg>Set svn:eol-style to 'native' on files missing it. refs #7776 !strict<commit_after>define(["./_WidgetBase"], function(_WidgetBase){

/*=====
	var _WidgetBase = dijit._WidgetBase;
====*/

	// module:
	//		dijit/_BidiSupport
	// summary:
	//		Module that deals with BIDI, special with the auto
	//		direction if needed without changing the GUI direction.
	//		Including this module will extend _WidgetBase with BIDI related methods.
	// description:
	//		There's a special need for displaying BIDI text in rtl direction
	//		in ltr GUI, sometimes needed auto support.
	//		In creation of widget, if it's want to activate this class,
	//		the widget should define the "textDir".

	_WidgetBase.extend({

		getTextDir: function(/*String*/ text){
			// summary:
			//		Gets the right direction of text.
			// description:
			// 		If textDir is ltr or rtl returns the value.
			//		If it's auto, calls to another function that responsible
			//		for checking the value, and defining the direction.
			//	tags:
			//		protected.
			return this.textDir == "auto" ? this._checkContextual(text) : this.textDir;
		},

		_checkContextual: function(text){
			// summary:
			//		Finds the first strong (directional) character, return ltr if isLatin
			//		or rtl if isBidiChar.
			//	tags:
			//		private.

			// look for strong (directional) characters
			var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text);
			// if found return the direction that defined by the character, else return widgets dir as defult.
			return fdc ? ( fdc[0] <= 'z' ? "ltr" : "rtl" ) : this.dir ? this.dir : this.isLeftToRight() ? "ltr" : "rtl";
		},

		applyTextDir: function(/*Object*/ element, /*String*/ text){
			// summary:
			//		Set element.dir according to this.textDir
			// element:
			//		The text element to be set. Should have dir property.
			// text:
			//		Used in case this.textDir is "auto", for calculating the right transformation
			// description:
			// 		If textDir is ltr or rtl returns the value.
			//		If it's auto, calls to another function that responsible
			//		for checking the value, and defining the direction.
			//	tags:
			//		protected.

			var textDir = this.textDir == "auto" ? this._checkContextual(text) : this.textDir;
			// update only when there's a difference
			if(element.dir != textDir){
				element.dir = textDir;
			}
		}
	});

	return _WidgetBase;
});
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Marco Grätsch
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 *
 * @param {jQuery} $
 */
(function($) {
    'use strict';

    var filterMode = 'unlink',
        elementClass = 'lsr-link',
        parentClass = 'lsr-link-parent',
        warningClass = 'lsr-warning',
        domainlist = (JSON.parse(localStorage.getItem('domainlist')) || []),
        lang = {},
        debug = false,

        /**
         * Predefined filters
         */
        filters = {
            unlink: function($el, $parent, url, domain) {
                if ($parent && $parent.length && !$parent.hasClass(parentClass)) {
                    $parent.addClass(parentClass);
                }
                var $span = $('').text($el.text());
                $span.addClass(elementClass);
                $el.replaceWith($span);
            },
            remove: function($el, $parent, url, domain) {
                if ($parent && $parent.length) {
                    $parent.replaceWith('');
                    return;
                }
                $el.replaceWith('');
            },
            marker: function($el, $parent, url, domain) {
                if ($parent && $parent.length && !$parent.hasClass(parentClass)) {
                    $parent.addClass(parentClass);
                }
                if (!$el.hasClass(elementClass)) {
                    $el.addClass(elementClass);
                }
            },
            confirm: function($el, $parent, url, domain) {
                $el.off('click').on('click', function(ev) {
                    ev.preventDefault();
                    if (confirm(replaceVars(lang.confirm, domain, url))) {
                        window.location = url;
                    }
                });
            },
            warning: function($el, $parent, url, domain) {
                var $warning = $('

');
                $parent = $parent || $el.closest('div');

                $warning.addClass(warningClass).text(replaceVars(lang.warning, domain, url));
                $parent.not('has-' + warningClass)
                    .addClass('has-' + warningClass)
                    .prepend($warning);
            }
        },

        /**
         * Update List Handler
         *
         * @param {String} url
         * @param {Function} cb
         */
        updateList = function(url, cb) {
            $.get(url, {}, function(data, status, jqXHR) {
                var ts = Math.round(Date.now()/1000);
                localStorage.setItem('domainlist', JSON.stringify(data));
                localStorage.setItem('last-update', ts);
                domainlist = data;
                cb(data, ts, url, status);
            }, 'json');
        },

        /**
         * Check if an update should be performed
         *
         * @param {String} interval
         * @return {Boolean}
         */
        checkUpdates = function(interval) {
            var lastUpdate = localStorage.getItem('last-update') || null,
                intervalTime = 0,
                now = Math.round(Date.now()/1000);

            if (interval === 'off') {
                if (!localStorage.getItem('domainlist')) {
                    return true;
                }
                return false;
            }

            if (!localStorage.getItem('domainlist')) {
                return true;
            }
            if (!lastUpdate) {
                return true;
            }

            switch (interval) {
                case 'hourly':
                    intervalTime = (60*60);
                    break;

                case 'daily':
                    intervalTime = (60*60*24);
                    break;

                case 'weekly':
                    intervalTime = (60*60*24*7);
                    break;

                case 'monthly':
                    intervalTime = (60*60*24*30);
                    break;
            }

            if (now >= lastUpdate + intervalTime) {
                return true;
            }
            return false;
        },

        /**
         * Replace variables in strings
         *
         * @param {String} text
         * @param {String} domain
         * @param {String} url
         * @return {String}
         */
        replaceVars = function(text, domain, url) {
            return text.replace('##domain##', domain).replace('##url##', url);
        },

        /**
         * Check if the URL is a link to a specific domain
         *
         * @param {String} url
         * @param {String} domain
         * @return {Boolean}
         */
        match = function(url, domain) {
            if (url.indexOf('.' + domain) !== -1 || url.indexOf('//' + domain) !== -1) {
                return true;
            }
            return false;
        },

        /**
         * Filter an element
         *
         * @param {jQuery} $el
         * @param {jQuery} $parent
         * @param {String} domain
         * @param {Function} cb
         */
        filter = function($el, $parent, domain, cb) {
            var url = $el.attr('href');
            if (url) {
                if (match(url, domain)) {
                    cb($el, $parent, url, domain);
                }
                return;
            }

            $el.find('a,link').each(function() {
                filter($(this), $el, domain, cb);
            });
        },

        /**
         * Default onUpdateList-Handler
         *
         * @param {Array} data
         * @param {Number} ts
         * @param {String} url
         * @param {String} status
         */
        onUpdateList = function(data, ts, url, status) {
            if (debug) {
                console.log('Blacklist updated at ' + (new Date(ts*1000)).toLocaleString() + ' from ' + url);
                console.log('List contains actually ' + data.length + ' domains');
            }
        },

        /**
         * Default onFilterMatch-Handler
         *
         * @param {jQuery} $el
         * @param {jQuery} $parent
         * @param {String} url
         * @param {String} domain
         */
        onFilterMatch = function($el, $parent, url, domain) {
            if (!filters[filterMode]) {
                if (debug) {
                    console.log('Invalid filter-mode: ' + filterMode);
                }
                return;
            }
            filters[filterMode]($el, $parent, url, domain);
        },

        /**
         * Default Options
         */
        defaultOptions = {
            domainlist: 'https://cdn.rawgit.com/magdev/leistungsschutzgelderpresser/master/domains.json',
            updateInterval: 'weekly',
            forceUpdate: false,
            debug: false,
            onFilterMatch: onFilterMatch,
            onUpdateList: onUpdateList,
            filterMode: 'unlink',
            parentSelector: null,
            elementClass: 'lsr-link',
            parentClass: 'lsr-link-parent',
            warningClass: 'lsr-warning',
            lang: {
                link_removed: 'Link removed',
                warning: 'WARNING! Contains LSR-related Links',
                confirm: 'The link goes to ##domain##! Are you sure you want to follow this link?'
            }
        };

    /**
     * jQuery LSR-Filter
     *
     * @param {Object} options
     * @return {jQuery}
     */
    $.fn.lsr = function(options) {
        var opts = $.extend(defaultOptions, options);

        filterMode = opts.filterMode;
        elementClass = opts.elementClass;
        parentClass = opts.parentClass;
        warningClass = opts.warningClass;
        lang = opts.lang;
        debug = opts.debug;

        if (checkUpdates(opts.updateInterval) || opts.forceUpdate) {
            updateList(opts.domainlist, opts.onUpdateList);
        }

        return this.each(function() {
            var $this = $(this),
                $parent = $(this).closest(opts.parentSelector);

            domainlist.forEach(function(domain) {
                filter($this, $parent, domain, opts.onFilterMatch);
            });
        });
    };

    // Apply filter to elements using data-attributes
    $('[data-filter="lsr"]').each(function() {
        $(this).lsr(this.dataset);
    });

})(jQuery);<commit_msg>log matching links in debug-mode<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Marco Grätsch
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 *
 * @param {jQuery} $
 */
(function($) {
    'use strict';

    var filterMode = 'unlink',
        elementClass = 'lsr-link',
        parentClass = 'lsr-link-parent',
        warningClass = 'lsr-warning',
        domainlist = (JSON.parse(localStorage.getItem('domainlist')) || []),
        lang = {},
        debug = false,

        /**
         * Predefined filters
         */
        filters = {
            unlink: function($el, $parent, url, domain) {
                if ($parent && $parent.length && !$parent.hasClass(parentClass)) {
                    $parent.addClass(parentClass);
                }
                var $span = $('').text($el.text());
                $span.addClass(elementClass);
                $el.replaceWith($span);
            },
            remove: function($el, $parent, url, domain) {
                if ($parent && $parent.length) {
                    $parent.replaceWith('');
                    return;
                }
                $el.replaceWith('');
            },
            marker: function($el, $parent, url, domain) {
                if ($parent && $parent.length && !$parent.hasClass(parentClass)) {
                    $parent.addClass(parentClass);
                }
                if (!$el.hasClass(elementClass)) {
                    $el.addClass(elementClass);
                }
            },
            confirm: function($el, $parent, url, domain) {
                $el.off('click').on('click', function(ev) {
                    ev.preventDefault();
                    if (confirm(replaceVars(lang.confirm, domain, url))) {
                        window.location = url;
                    }
                });
            },
            warning: function($el, $parent, url, domain) {
                var $warning = $('

');
                $parent = $parent || $el.closest('div');

                $warning.addClass(warningClass).text(replaceVars(lang.warning, domain, url));
                $parent.not('has-' + warningClass)
                    .addClass('has-' + warningClass)
                    .prepend($warning);
            }
        },

        /**
         * Update List Handler
         *
         * @param {String} url
         * @param {Function} cb
         */
        updateList = function(url, cb) {
            $.get(url, {}, function(data, status, jqXHR) {
                var ts = Math.round(Date.now()/1000);
                localStorage.setItem('domainlist', JSON.stringify(data));
                localStorage.setItem('last-update', ts);
                domainlist = data;
                cb(data, ts, url, status);
            }, 'json');
        },

        /**
         * Check if an update should be performed
         *
         * @param {String} interval
         * @return {Boolean}
         */
        checkUpdates = function(interval) {
            var lastUpdate = localStorage.getItem('last-update') || null,
                intervalTime = 0,
                now = Math.round(Date.now()/1000);

            if (interval === 'off') {
                if (!localStorage.getItem('domainlist')) {
                    return true;
                }
                return false;
            }

            if (!localStorage.getItem('domainlist')) {
                return true;
            }
            if (!lastUpdate) {
                return true;
            }

            switch (interval) {
                case 'hourly':
                    intervalTime = (60*60);
                    break;

                case 'daily':
                    intervalTime = (60*60*24);
                    break;

                case 'weekly':
                    intervalTime = (60*60*24*7);
                    break;

                case 'monthly':
                    intervalTime = (60*60*24*30);
                    break;
            }

            if (now >= lastUpdate + intervalTime) {
                return true;
            }
            return false;
        },

        /**
         * Replace variables in strings
         *
         * @param {String} text
         * @param {String} domain
         * @param {String} url
         * @return {String}
         */
        replaceVars = function(text, domain, url) {
            return text.replace('##domain##', domain).replace('##url##', url);
        },

        /**
         * Check if the URL is a link to a specific domain
         *
         * @param {String} url
         * @param {String} domain
         * @return {Boolean}
         */
        match = function(url, domain) {
            if (url.indexOf('.' + domain) !== -1 || url.indexOf('//' + domain) !== -1) {
                if (debug) {
                    console.log('Match found: Domain: ' + domain + ', URL: ' + url);
                }
                return true;
            }
            return false;
        },

        /**
         * Filter an element
         *
         * @param {jQuery} $el
         * @param {jQuery} $parent
         * @param {String} domain
         * @param {Function} cb
         */
        filter = function($el, $parent, domain, cb) {
            var url = $el.attr('href');
            if (url) {
                if (match(url, domain)) {
                    cb($el, $parent, url, domain);
                }
                return;
            }

            $el.find('a,link').each(function() {
                filter($(this), $el, domain, cb);
            });
        },

        /**
         * Default onUpdateList-Handler
         *
         * @param {Array} data
         * @param {Number} ts
         * @param {String} url
         * @param {String} status
         */
        onUpdateList = function(data, ts, url, status) {
            if (debug) {
                console.log('Blacklist updated at ' + (new Date(ts*1000)).toLocaleString() + ' from ' + url);
                console.log('List contains actually ' + data.length + ' domains');
            }
        },

        /**
         * Default onFilterMatch-Handler
         *
         * @param {jQuery} $el
         * @param {jQuery} $parent
         * @param {String} url
         * @param {String} domain
         */
        onFilterMatch = function($el, $parent, url, domain) {
            if (!filters[filterMode]) {
                if (debug) {
                    console.log('Invalid filter-mode: ' + filterMode);
                }
                return;
            }
            filters[filterMode]($el, $parent, url, domain);
        },

        /**
         * Default Options
         */
        defaultOptions = {
            domainlist: 'https://cdn.rawgit.com/magdev/leistungsschutzgelderpresser/master/domains.json',
            updateInterval: 'weekly',
            forceUpdate: false,
            debug: false,
            onFilterMatch: onFilterMatch,
            onUpdateList: onUpdateList,
            filterMode: 'unlink',
            parentSelector: null,
            elementClass: 'lsr-link',
            parentClass: 'lsr-link-parent',
            warningClass: 'lsr-warning',
            lang: {
                link_removed: 'Link removed',
                warning: 'WARNING! Contains LSR-related Links',
                confirm: 'The link goes to ##domain##! Are you sure you want to follow this link?'
            }
        };

    /**
     * jQuery LSR-Filter
     *
     * @param {Object} options
     * @return {jQuery}
     */
    $.fn.lsr = function(options) {
        var opts = $.extend(defaultOptions, options);

        filterMode = opts.filterMode;
        elementClass = opts.elementClass;
        parentClass = opts.parentClass;
        warningClass = opts.warningClass;
        lang = opts.lang;
        debug = opts.debug;

        if (checkUpdates(opts.updateInterval) || opts.forceUpdate) {
            updateList(opts.domainlist, opts.onUpdateList);
        }

        return this.each(function() {
            var $this = $(this),
                $parent = $(this).closest(opts.parentSelector);

            domainlist.forEach(function(domain) {
                filter($this, $parent, domain, opts.onFilterMatch);
            });
        });
    };

    // Apply filter to elements using data-attributes
    $('[data-filter="lsr"]').each(function() {
        $(this).lsr(this.dataset);
    });

})(jQuery);<|endoftext|>


<commit_before>"use strict";

const Memcached = require('memcached');

const memcached = new Memcached('127.0.0.1:11211');

const INSTALLATION_STORE_KEY = 'installationStore';
const ACCESS_TOKEN_STORE_KEY = 'accessTokenStore';

function getFromStore(key) {
  return new Promise((resolve, reject) => {
    memcached.get(key, (err, data) => {
      if (err) {
        return reject(err);
      }
      resolve(data);
    })
  });
}

function createInStore(key, value) {
  return new Promise((resolve, reject) => {
    memcached.set(key, value, 0, err => {
      if (err) {
        return reject(err);
      }
      resolve(value);
    })
  });
}

function createInstallationStore() {
  return createInStore(INSTALLATION_STORE_KEY, {});
}

function createAccessTokenStore() {
  return createInStore(ACCESS_TOKEN_STORE_KEY, {});
}

function getInstallationStore() {
  return getFromStore(INSTALLATION_STORE_KEY).then(store => {
    if (!store) {
      return createInstallationStore();
    }
    return store;
  });
}

function getAccessTokenStore() {
  return getFromStore(ACCESS_TOKEN_STORE_KEY).then(store => {
    if (!store) {
      return createAccessTokenStore();
    }
    return store;
  });
}

module.exports = {
  addInstallation(installation) {
    return getInstallationStore().then(store => store[installation['oauthId']] = installation);
  },

  getInstallation(oauthId) {
    return getInstallationStore().then(store => store[oauthId]);
  },

  removeInstallation(installation) {
    return getInstallationStore().then(store => {
      delete store[installation['oauthId']];
      memcached.replace('INSTALLATION_STORE_KEY', store, 0, err => {
        if (err) {
          return Promise.reject(err);
        }
        return Promise.resolve();
      });
    });
  },

  addAccessToken(oauthId, token) {
    return getAccessTokenStore().then(store => store[oauthId] = token);
  },

  getAccessToken(oauthId) {
    return getAccessTokenStore().then(store => store[oauthId]);
  },

  removeAccessToken(oauthId) {
    return getAccessTokenStore().then(store => {
      delete store[oauthId];
      memcached.replace('ACCESS_TOKEN_STORE_KEY', store, 0, err => {
        if (err) {
          return Promise.reject(err);
        }
        return Promise.resolve();
      });
    });
  }
};
<commit_msg>fix add to store<commit_after>"use strict";

const Memcached = require('memcached');

const memcached = new Memcached('127.0.0.1:11211');

const INSTALLATION_STORE_KEY = 'installationStore';
const ACCESS_TOKEN_STORE_KEY = 'accessTokenStore';

function getFromStore(key) {
  return new Promise((resolve, reject) => {
    memcached.get(key, (err, data) => {
      if (err) {
        return reject(err);
      }
      resolve(data);
    })
  });
}

function createInStore(key, value) {
  return new Promise((resolve, reject) => {
    memcached.set(key, value, 0, err => {
      if (err) {
        return reject(err);
      }
      resolve(value);
    })
  });
}

function updateStore(key, value) {
  return new Promise((resolve, reject) => {
    memcached.replace(key, value, 0, err => {
      if (err) {
        return reject(err);
      }
      resolve(value);
    })
  });
}

function createInstallationStore() {
  return createInStore(INSTALLATION_STORE_KEY, {});
}

function createAccessTokenStore() {
  return createInStore(ACCESS_TOKEN_STORE_KEY, {});
}

function getInstallationStore() {
  return getFromStore(INSTALLATION_STORE_KEY).then(store => {
    if (!store) {
      return createInstallationStore();
    }
    return store;
  });
}

function getAccessTokenStore() {
  return getFromStore(ACCESS_TOKEN_STORE_KEY).then(store => {
    if (!store) {
      return createAccessTokenStore();
    }
    return store;
  });
}

module.exports = {
  addInstallation(installation) {
    return getInstallationStore().then(store => {
      store[installation['oauthId']] = installation;
      return updateStore(INSTALLATION_STORE_KEY, store);
    });
  },

  getInstallation(oauthId) {
    return getInstallationStore().then(store => store[oauthId]);
  },

  removeInstallation(installation) {
    return getInstallationStore().then(store => {
      delete store[installation['oauthId']];
      return updateStore(INSTALLATION_STORE_KEY, store);
    });
  },

  addAccessToken(oauthId, token) {
    return getAccessTokenStore().then(store => {
      store[oauthId] = token;
      return updateStore(ACCESS_TOKEN_STORE_KEY, store);
    });
  },

  getAccessToken(oauthId) {
    return getAccessTokenStore().then(store => store[oauthId]);
  },

  removeAccessToken(oauthId) {
    return getAccessTokenStore().then(store => {
      delete store[oauthId];
      return updateStore(ACCESS_TOKEN_STORE_KEY, store);
    });
  }
};
<|endoftext|>


<commit_before>import 'angular';
export default angular.module('filters', [])
    .filter('youtubeTime', function() {
        return function(input) {
            var parts = [],
                seconds = input.match(/(\d+)S/),
                minutes = input.match(/(\d+)M/),
                hours = input.match(/(\d+)H/);

            if (hours) parts.push(hours[1]);

            if (!minutes) parts.push('00');
            else if (minutes[1].length === 1 && hours)
                parts.push('0' + minutes[1]);
            else parts.push(minutes[1]);

            if (!seconds) parts.push('00');
            else if (seconds[1].length === 1) parts.push('0' + seconds[1]);
            else parts.push(seconds[1]);

            if (!hours && !minutes && !seconds)
                return '--:--';

            return parts.join(':');
        };
    })
    .filter('formatTime', function() {
        return function(input) {
            if (isNaN(input) || input === '') return '--:--';
            let time = Math.floor(input);
            let hours = Math.floor(time / 3600);
            let minutes = Math.floor((time % 3600) / 60);
            let seconds = Math.floor((time % 3600) % 60);
            let parts = [];

            if (hours) parts.push(hours);

            if (!minutes) parts.push('00');
            else if (minutes < 10 && hours)
                parts.push('0' + minutes);
            else parts.push(minutes);

            if (!seconds) parts.push('00');
            else if (seconds < 10) parts.push('0' + seconds);
            else parts.push(seconds);

            if (!hours && !minutes && !seconds)
                return '--:--';

            return parts.join(':');
        };
    })
    .filter('commaNum', function() {
        return function(input) {
            var str = [],
                i;
            for (i = input.length - 1; i >= 0; i--) {
                str.unshift(input.charAt(i));
                if ((i) % 3 === 0) {
                    str.unshift(',');
                }
            }

            return input.replace(/(\d)(?=(\d{3})+$)/g, '$1,');
        };
    })
    .filter('machineRead', function() {
        return function(input) {
            var str = input.toString(),
                lc = str.toLowerCase();
            let output = lc.replace(/\s+/g, '-');

            return output;
        };
    });
<commit_msg>Refactor the youtubeTime filter to use the formatTime filter for consistency<commit_after>import 'angular';
export default angular.module('filters', [])
    .filter('youtubeTime', ['$filter', function($filter) {
        return function(input) {
            let seconds = input.match(/(\d+)S/);
            let minutes = input.match(/(\d+)M/);
            let hours = input.match(/(\d+)H/);

            if (seconds) seconds = parseInt(seconds, 10);
            if (minutes) minutes = parseInt(minutes, 10);
            if (hours) hours = parseInt(hours, 10);

            let time = seconds + (minutes * 60) + (hours * 60 * 60);

            return $filter('formatTime')(time);
        };
    }])
    .filter('formatTime', function() {
        return function(input) {
            if (isNaN(input) || input === '') return '--:--';
            let time = Math.floor(input);
            let hours = Math.floor(time / 3600);
            let minutes = Math.floor((time % 3600) / 60);
            let seconds = Math.floor((time % 3600) % 60);
            let parts = [];

            if (hours) parts.push(hours);

            if (!minutes) parts.push('00');
            else if (minutes < 10 && hours)
                parts.push('0' + minutes);
            else parts.push(minutes);

            if (!seconds) parts.push('00');
            else if (seconds < 10) parts.push('0' + seconds);
            else parts.push(seconds);

            if (!hours && !minutes && !seconds)
                return '--:--';

            return parts.join(':');
        };
    })
    .filter('commaNum', function() {
        return function(input) {
            var str = [],
                i;
            for (i = input.length - 1; i >= 0; i--) {
                str.unshift(input.charAt(i));
                if ((i) % 3 === 0) {
                    str.unshift(',');
                }
            }

            return input.replace(/(\d)(?=(\d{3})+$)/g, '$1,');
        };
    })
    .filter('machineRead', function() {
        return function(input) {
            var str = input.toString(),
                lc = str.toLowerCase();
            let output = lc.replace(/\s+/g, '-');

            return output;
        };
    });
<|endoftext|>


<commit_before>import React from 'react';
import axios from '../axios-config';

import Header from './header/Header';
import Sidebar from './sidebar/Sidebar';
import DenounceBox from './DenounceBox';

import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import injectTapEventPlugin from 'react-tap-event-plugin';

injectTapEventPlugin();

export default class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            currentAuth: null,
            currentLudoId: '',
            currentLudoReportData: [],
            currentTargetCommentId: '',
            currentTargetLudoId: '',
            currentTargetReportId: '',
            currentUserId: '',
            denounceType: 100,
            hasGotNewReport: false,
            isDenounceBoxOpen: false,
            isHoveringSidebar: false,
            isLoggedIn: false,
            isOpeningActivePage: false,
            isOpeningLudoListPage: false,
            isOpeningProfilePage: false,
            lastEvaluatedKey: {},
            ludoList: [],
            shouldLudoListUpdate: false,
            shouldProfileUpdate: false,
            shouldReportUpdate: false,
            shouldUserBasicDataUpdate: false,
            profileWillLudoData: [],
            profileLudoingData: [],
            profileDidLudoData: [],
            userBasicData: {},
            userProfileData: {}
        };
        this.clearCurrentFormValue = this.clearCurrentFormValue.bind(this);
        this.getUserBasicData = this.getUserBasicData.bind(this);
        this.getCurrentLudoData = this.getCurrentLudoData.bind(this);
        this.getFilteredLudoList = this.getFilteredLudoList.bind(this);
        this.getLatestLudoList = this.getLatestLudoList.bind(this);
        this.getProfileData = this.getProfileData.bind(this);
        this.getProfileWillLudoData = this.getProfileWillLudoData.bind(this);
        this.getProfileLudoingData = this.getProfileLudoingData.bind(this);
        this.getProfileDidLudoData = this.getProfileDidLudoData.bind(this);
        this.getReportOfCurrentLudo = this.getReportOfCurrentLudo.bind(this);
        this.handleDenounceBoxRequestClose = this.handleDenounceBoxRequestClose.bind(this);
        this.handleDenounceBoxOpen = this.handleDenounceBoxOpen.bind(this);
        this.handleHasGotNewReport = this.handleHasGotNewReport.bind(this);
        this.handleIsHoveringSidebar = this.handleIsHoveringSidebar.bind(this);
        this.handleIsOpeningActivePage = this.handleIsOpeningActivePage.bind(this);
        this.handleIsOpeningLudoListPage = this.handleIsOpeningLudoListPage.bind(this);
        this.handleIsOpeningProfilePage = this.handleIsOpeningProfilePage.bind(this);
        this.handleShouldLudoListUpdate = this.handleShouldLudoListUpdate.bind(this);
        this.handleShouldProfileUpdate = this.handleShouldProfileUpdate.bind(this);
        this.handleShouldReportUpdate = this.handleShouldReportUpdate.bind(this);
        this.handleShouldUserBasicDataUpdate = this.handleShouldUserBasicDataUpdate.bind(this);
        this.updateCurrentFormValue = this.updateCurrentFormValue.bind(this);
    }

    componentDidMount() {
        this.handleShouldProfileUpdate(true);
        this.getUserBasicData();
    }

    componentDidUpdate() {
        const { currentUserId, isLoggedIn, isOpeningLudoListPage, isOpeningProfilePage,
            shouldLudoListUpdate, shouldProfileUpdate, shouldUserBasicDataUpdate
        } = this.state;
        if (isOpeningLudoListPage && shouldLudoListUpdate) {
            this.getLatestLudoList();
            this.handleShouldLudoListUpdate(false);
        }
        if (currentUserId && isLoggedIn && shouldProfileUpdate) {
            /*
             * Update profile data after the user did some ludo action and is going to open profile page
             */
            if (isOpeningProfilePage) {
                this.getProfileData();
                this.getProfileWillLudoData(currentUserId);
                this.getProfileLudoingData(currentUserId);
                this.getProfileDidLudoData(currentUserId);
                this.handleShouldProfileUpdate(false);
            }
        }

        const { isOpeningActivePage, shouldReportUpdate } = this.state;
        if (isOpeningActivePage && shouldReportUpdate) {
            this.getReportOfCurrentLudo(this.props.params.ludo_id);
            this.handleShouldReportUpdate(false);
        }

        if (shouldUserBasicDataUpdate) {
            this.getUserBasicData();
            this.handleShouldUserBasicDataUpdate(false);
        }
    }

    clearCurrentFormValue() {
        this.setState({
            currentAuth: null,
            currentFormValue: {
                category_id: 0,
                checkpoint: [],
                duration: 0,
                introduction: '',
                marbles: 0,
                tags: [],
                title: ''
            }
        });
    }

    getChildContext() {
        return { muiTheme: getMuiTheme(baseTheme) };
    }

    getUserBasicData() {
        axios.get('/apis/user')
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    userBasicData: response.data.user,
                    currentUserId: response.data.user.user_id,
                    isLoggedIn: true
                });
            } else {
                // console.error('app getUserBasicData else response from server: ', response);
                // console.error('app getUserBasicData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('user error', error);
        });
    }

    getCurrentLudoData(ludo_id) {
        axios.get(`/apis/ludo/${ludo_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    currentAuth: response.data.auth,
                    currentFormValue: response.data.ludo,
                    currentLudoId: ludo_id
                });
            } else {
                console.error('app getCurrentLudoData else response from server: ', response);
                console.error('app getCurrentLudoData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getCurrentLudoData error', error);
        });
    }

    getFilteredLudoList(stage) {
        axios.get(`/apis/ludo?stage=${stage}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    ludoList: response.data.ludoList.Items
                });
            } else {
                console.error('app getFilteredLudoList else response from server: ', response);
                console.error('app getFilteredLudoList else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getFilteredLudoList error', error);
        });
    }

    getLatestLudoList() {
        axios.get('/apis/ludo')
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    lastEvaluatedKey: response.data.ludoList.LastEvaluatedKey,
                    ludoList: response.data.ludoList.Items
                });
            } else {
                console.error('app getLatestLudoList else response from server: ', response);
                console.error('app getLatestLudoList else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getLatestLudoList error', error);
        });
    }

    getProfileData() {
        axios.get('/apis/profile')
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    userProfileData: response.data.user
                });
            } else {
                console.error('app getProfileData else response from server: ', response);
                console.error('app getProfileData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getProfileData error', error);
        });
    }

    getProfileWillLudoData(user_id) {
        axios.get(`apis/ludo?stage=1&user_id=${user_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    profileWillLudoData: response.data.ludoList.Items
                });
            } else {
                console.error('app getProfileWillLudoData else response from server: ', response);
                console.error('app getProfileWillLudoData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getProfileWillLudoData error', error);
        });
    }

    getProfileLudoingData(user_id) {
        axios.get(`apis/ludo?stage=2&user_id=${user_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    profileLudoingData: response.data.ludoList.Items
                });
            } else {
                console.error('app getProfileLudoingData else response from server: ', response);
                console.error('app getProfileLudoingData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getProfileLudoingData error', error);
        });
    }

    getProfileDidLudoData(user_id) {
        axios.get(`apis/ludo?stage=3&user_id=${user_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    profileDidLudoData: response.data.ludoList.Items
                });
            } else {
                console.error('app getProfileDidLudoData else response from server: ', response);
                console.error('app getProfileDidLudoData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getProfileDidLudoData error', error);
        });
    }

    getReportOfCurrentLudo(ludo_id) {
        axios.get(`/apis/report?ludo_id=${ludo_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    currentLudoReportData: response.data.reportList,
                    hasGotNewReport: true
                });
            } else {
                console.error('app getReportOfCurrentLudo else response from server: ', response);
                console.error('app getReportOfCurrentLudo else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error(error);
        });
    }

    handleDenounceBoxRequestClose() {
        this.setState({
            isDenounceBoxOpen: false
        });
    }

    handleDenounceBoxOpen(currentTargetObject) {
        const { currentTargetCommentId, currentTargetLudoId, currentTargetReportId } = currentTargetObject;
        if (currentTargetLudoId) {
            this.setState({
                currentTargetLudoId,
                denounceType: 0,
                isDenounceBoxOpen: true
            });
        } else if (currentTargetReportId && !currentTargetCommentId) {
            this.setState({
                currentTargetReportId,
                denounceType: 1,
                isDenounceBoxOpen: true
            });
        } else if (currentTargetReportId && currentTargetCommentId) {
            this.setState({
                currentTargetCommentId,
                currentTargetReportId,
                denounceType: 2,
                isDenounceBoxOpen: true
            });
        } else {
            console.error('handleDenounceBoxOpen id error');
        }
    }

    handleDenounceComment(event) {
        this.setState({
            currentTargetCommentId
        });
    }

    handleDenounceLudo(event) {
        this.setState({
            currentTargetLudoId
        });
    }

    handleDenounceReport(event) {
        this.setState({
            currentTargetReportId
        });
    }

    handleHasGotNewReport(boolean) {
        this.setState({
            hasGotNewReport: boolean
        });
    }

    handleIsHoveringSidebar(boolean) {
        this.setState({
            isHoveringSidebar: boolean
        });
    }

    handleIsOpeningActivePage(boolean) {
        this.setState({
            isOpeningActivePage: boolean
        });
    }

    handleIsOpeningLudoListPage(boolean) {
        this.setState({
            isOpeningLudoListPage: boolean
        });
    }

    handleIsOpeningProfilePage(boolean) {
        this.setState({
            isOpeningProfilePage: boolean
        });
    }

    handleShouldLudoListUpdate(boolean) {
        this.setState({
            shouldLudoListUpdate: boolean
        });
    }

    handleShouldProfileUpdate(boolean) {
        this.setState({
            shouldProfileUpdate: boolean
        });
    }

    handleShouldReportUpdate(boolean) {
        this.setState({
            shouldReportUpdate: boolean
        });
    }

    handleShouldUserBasicDataUpdate(boolean) {
        this.setState({
            shouldUserBasicDataUpdate: boolean
        });
    }

    updateCurrentFormValue(ludoForm) {
        this.setState({
            currentFormValue: ludoForm
        });
    }

    render() {
        const { isHoveringSidebar } = this.state;
        const { router_currentFormValue } = this.props;
        return (

                <Sidebar
                    currentUserId={this.state.currentUserId}
                    handleIsHoveringSidebar={this.handleIsHoveringSidebar}
                    isHoveringSidebar={isHoveringSidebar}
                />
                {/* layout/main-container */}

                    {
                        React.cloneElement(this.props.children,
                            {
                                ...this.state,
                                router_currentFormValue,
                                clearCurrentFormValue: this.clearCurrentFormValue,
                                getUserBasicData: this.getUserBasicData,
                                getCurrentLudoData: this.getCurrentLudoData,
                                getLatestLudoList: this.getLatestLudoList,
                                getProfileData: this.getProfileData,
                                getProfileWillLudoData: this.getProfileWillLudoData,
                                getProfileLudoingData: this.getProfileLudoingData,
                                getProfileDidLudoData: this.getProfileDidLudoData,
                                getReportOfCurrentLudo: this.getReportOfCurrentLudo,
                                handleDenounceBoxOpen: this.handleDenounceBoxOpen,
                                handleHasGotNewReport: this.handleHasGotNewReport,
                                handleIsHoveringSidebar: this.handleIsHoveringSidebar,
                                handleIsOpeningActivePage: this.handleIsOpeningActivePage,
                                handleIsOpeningLudoListPage: this.handleIsOpeningLudoListPage,
                                handleIsOpeningProfilePage: this.handleIsOpeningProfilePage,
                                handleShouldLudoListUpdate: this.handleShouldLudoListUpdate,
                                handleShouldProfileUpdate: this.handleShouldProfileUpdate,
                                handleShouldReportUpdate: this.handleShouldReportUpdate,
                                handleShouldUserBasicDataUpdate: this.handleShouldUserBasicDataUpdate,
                                updateCurrentFormValue: this.updateCurrentFormValue
                            }
                        )
                    }

                <DenounceBox
                    currentTargetCommentId={this.state.currentTargetCommentId}
                    currentTargetLudoId={this.state.currentTargetLudoId}
                    currentTargetReportId={this.state.currentTargetReportId}
                    denounceType={this.state.denounceType}
                    isDenounceBoxOpen={this.state.isDenounceBoxOpen}
                    onRequestClose={this.handleDenounceBoxRequestClose}
                />

        );
    }
}

App.childContextTypes = {
    muiTheme: React.PropTypes.object.isRequired,
};<commit_msg>[Add] infinite scroll to load ludos in database<commit_after>import React from 'react';
import axios from '../axios-config';

import Header from './header/Header';
import Sidebar from './sidebar/Sidebar';
import DenounceBox from './DenounceBox';

import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import injectTapEventPlugin from 'react-tap-event-plugin';

injectTapEventPlugin();

export default class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            currentAuth: null,
            currentLudoId: '',
            currentLudoReportData: [],
            currentTargetCommentId: '',
            currentTargetLudoId: '',
            currentTargetReportId: '',
            currentUserId: '',
            denounceType: 100,
            hasGotNewReport: false,
            isDenounceBoxOpen: false,
            isHoveringSidebar: false,
            isInfiniteLoading: false,
            isLoggedIn: false,
            isOpeningActivePage: false,
            isOpeningLudoListPage: false,
            isOpeningProfilePage: false,
            lastEvaluatedKey: {},
            ludoList: [],
            shouldLudoListUpdate: false,
            shouldProfileUpdate: false,
            shouldReportUpdate: false,
            shouldUserBasicDataUpdate: false,
            profileWillLudoData: [],
            profileLudoingData: [],
            profileDidLudoData: [],
            userBasicData: {},
            userProfileData: {}
        };
        this.clearCurrentFormValue = this.clearCurrentFormValue.bind(this);
        this.getUserBasicData = this.getUserBasicData.bind(this);
        this.getCurrentLudoData = this.getCurrentLudoData.bind(this);
        this.getFilteredLudoList = this.getFilteredLudoList.bind(this);
        this.getLatestLudoList = this.getLatestLudoList.bind(this);
        this.getProfileData = this.getProfileData.bind(this);
        this.getProfileWillLudoData = this.getProfileWillLudoData.bind(this);
        this.getProfileLudoingData = this.getProfileLudoingData.bind(this);
        this.getProfileDidLudoData = this.getProfileDidLudoData.bind(this);
        this.getReportOfCurrentLudo = this.getReportOfCurrentLudo.bind(this);
        this.handleDenounceBoxRequestClose = this.handleDenounceBoxRequestClose.bind(this);
        this.handleDenounceBoxOpen = this.handleDenounceBoxOpen.bind(this);
        this.handleHasGotNewReport = this.handleHasGotNewReport.bind(this);
        this.handleIsHoveringSidebar = this.handleIsHoveringSidebar.bind(this);
        this.handleIsOpeningActivePage = this.handleIsOpeningActivePage.bind(this);
        this.handleIsOpeningLudoListPage = this.handleIsOpeningLudoListPage.bind(this);
        this.handleIsOpeningProfilePage = this.handleIsOpeningProfilePage.bind(this);
        this.handleScrollEvent = this.handleScrollEvent.bind(this);
        this.handleShouldLudoListUpdate = this.handleShouldLudoListUpdate.bind(this);
        this.handleShouldProfileUpdate = this.handleShouldProfileUpdate.bind(this);
        this.handleShouldReportUpdate = this.handleShouldReportUpdate.bind(this);
        this.handleShouldUserBasicDataUpdate = this.handleShouldUserBasicDataUpdate.bind(this);
        this.updateCurrentFormValue = this.updateCurrentFormValue.bind(this);
    }

    clearCurrentFormValue() {
        this.setState({
            currentAuth: null,
            currentFormValue: {
                category_id: 0,
                checkpoint: [],
                duration: 0,
                introduction: '',
                marbles: 0,
                tags: [],
                title: ''
            }
        });
    }

    componentDidMount() {
        this.handleShouldProfileUpdate(true);
        this.getUserBasicData();
        window.addEventListener('scroll', this.handleScrollEvent);
    }

    componentDidUpdate() {
        const { currentUserId, isLoggedIn, isOpeningLudoListPage, isOpeningProfilePage,
            shouldLudoListUpdate, shouldProfileUpdate, shouldUserBasicDataUpdate
        } = this.state;
        if (isOpeningLudoListPage && shouldLudoListUpdate) {
            this.getLatestLudoList();
            this.handleShouldLudoListUpdate(false);
        }
        if (currentUserId && isLoggedIn && shouldProfileUpdate) {
            /*
             * Update profile data after the user did some ludo action and is going to open profile page
             */
            if (isOpeningProfilePage) {
                this.getProfileData();
                this.getProfileWillLudoData(currentUserId);
                this.getProfileLudoingData(currentUserId);
                this.getProfileDidLudoData(currentUserId);
                this.handleShouldProfileUpdate(false);
            }
        }

        const { isOpeningActivePage, shouldReportUpdate } = this.state;
        if (isOpeningActivePage && shouldReportUpdate) {
            this.getReportOfCurrentLudo(this.props.params.ludo_id);
            this.handleShouldReportUpdate(false);
        }

        if (shouldUserBasicDataUpdate) {
            this.getUserBasicData();
            this.handleShouldUserBasicDataUpdate(false);
        }
    }

    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScrollEvent);
    }

    getChildContext() {
        return { muiTheme: getMuiTheme(baseTheme) };
    }

    getUserBasicData() {
        axios.get('/apis/user')
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    userBasicData: response.data.user,
                    currentUserId: response.data.user.user_id,
                    isLoggedIn: true
                });
            } else {
                console.error('app getUserBasicData else response from server: ', response);
                console.error('app getUserBasicData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('user error', error);
        });
    }

    getCurrentLudoData(ludo_id) {
        axios.get(`/apis/ludo/${ludo_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    currentAuth: response.data.auth,
                    currentFormValue: response.data.ludo,
                    currentLudoId: ludo_id
                });
            } else {
                console.error('app getCurrentLudoData else response from server: ', response);
                console.error('app getCurrentLudoData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getCurrentLudoData error', error);
        });
    }

    getFilteredLudoList(stage) {
        axios.get(`/apis/ludo?stage=${stage}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    ludoList: response.data.ludoList.Items
                });
            } else {
                console.error('app getFilteredLudoList else response from server: ', response);
                console.error('app getFilteredLudoList else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getFilteredLudoList error', error);
        });
    }

    getLatestLudoList() {
        axios.get('/apis/ludo')
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    lastEvaluatedKey: response.data.ludoList.LastEvaluatedKey,
                    ludoList: response.data.ludoList.Items
                });
            } else {
                console.error('app getLatestLudoList else response from server: ', response);
                console.error('app getLatestLudoList else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getLatestLudoList error', error);
        });
    }

    getProfileData() {
        axios.get('/apis/profile')
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    userProfileData: response.data.user
                });
            } else {
                console.error('app getProfileData else response from server: ', response);
                console.error('app getProfileData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getProfileData error', error);
        });
    }

    getProfileWillLudoData(user_id) {
        axios.get(`apis/ludo?stage=1&user_id=${user_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    profileWillLudoData: response.data.ludoList.Items
                });
            } else {
                console.error('app getProfileWillLudoData else response from server: ', response);
                console.error('app getProfileWillLudoData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getProfileWillLudoData error', error);
        });
    }

    getProfileLudoingData(user_id) {
        axios.get(`apis/ludo?stage=2&user_id=${user_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    profileLudoingData: response.data.ludoList.Items
                });
            } else {
                console.error('app getProfileLudoingData else response from server: ', response);
                console.error('app getProfileLudoingData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getProfileLudoingData error', error);
        });
    }

    getProfileDidLudoData(user_id) {
        axios.get(`apis/ludo?stage=3&user_id=${user_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    profileDidLudoData: response.data.ludoList.Items
                });
            } else {
                console.error('app getProfileDidLudoData else response from server: ', response);
                console.error('app getProfileDidLudoData else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error('app getProfileDidLudoData error', error);
        });
    }

    getReportOfCurrentLudo(ludo_id) {
        axios.get(`/apis/report?ludo_id=${ludo_id}`)
        .then((response) => {
            if(response.data.status === '200') {
                this.setState({
                    currentLudoReportData: response.data.reportList,
                    hasGotNewReport: true
                });
            } else {
                console.error('app getReportOfCurrentLudo else response from server: ', response);
                console.error('app getReportOfCurrentLudo else message from server: ', response.data.message);
            }
        })
        .catch((error) => {
            console.error(error);
        });
    }

    handleDenounceBoxRequestClose() {
        this.setState({
            isDenounceBoxOpen: false
        });
    }

    handleDenounceBoxOpen(currentTargetObject) {
        const { currentTargetCommentId, currentTargetLudoId, currentTargetReportId } = currentTargetObject;
        if (currentTargetLudoId) {
            this.setState({
                currentTargetLudoId,
                denounceType: 0,
                isDenounceBoxOpen: true
            });
        } else if (currentTargetReportId && !currentTargetCommentId) {
            this.setState({
                currentTargetReportId,
                denounceType: 1,
                isDenounceBoxOpen: true
            });
        } else if (currentTargetReportId && currentTargetCommentId) {
            this.setState({
                currentTargetCommentId,
                currentTargetReportId,
                denounceType: 2,
                isDenounceBoxOpen: true
            });
        } else {
            console.error('handleDenounceBoxOpen id error');
        }
    }

    handleDenounceComment(event) {
        this.setState({
            currentTargetCommentId
        });
    }

    handleDenounceLudo(event) {
        this.setState({
            currentTargetLudoId
        });
    }

    handleDenounceReport(event) {
        this.setState({
            currentTargetReportId
        });
    }

    handleHasGotNewReport(boolean) {
        this.setState({
            hasGotNewReport: boolean
        });
    }

    handleIsHoveringSidebar(boolean) {
        this.setState({
            isHoveringSidebar: boolean
        });
    }

    handleIsOpeningActivePage(boolean) {
        this.setState({
            isOpeningActivePage: boolean
        });
    }

    handleIsOpeningLudoListPage(boolean) {
        this.setState({
            isOpeningLudoListPage: boolean
        });
    }

    handleIsOpeningProfilePage(boolean) {
        this.setState({
            isOpeningProfilePage: boolean
        });
    }

    handleScrollEvent(event) {
        const edgeOffsetY = 250;
        const { isInfiniteLoading, lastEvaluatedKey } = this.state;
        const lastEvaluatedKeyString = JSON.stringify(lastEvaluatedKey);
        if (!isInfiniteLoading &&
            lastEvaluatedKeyString &&
            document.body.scrollTop + edgeOffsetY >= document.body.scrollHeight - window.innerHeight) {
            this.setState({
                isInfiniteLoading: true
            });
            axios.get(`/apis/ludo?startkey=${lastEvaluatedKeyString}`)
            .then((response) => {
                if(response.data.status === '200') {
                    const newLudoList = [];
                    newLudoList.push.apply(newLudoList, this.state.ludoList);
                    newLudoList.push.apply(newLudoList, response.data.ludoList.Items);
                    this.setState({
                        isInfiniteLoading: false,
                        lastEvaluatedKey: response.data.ludoList.LastEvaluatedKey,
                        ludoList: newLudoList
                    });
                } else {
                    this.setState({
                        isInfiniteLoading: false
                    });
                    console.error('app getLatestLudoList else response from server: ', response);
                    console.error('app getLatestLudoList else message from server: ', response.data.message);
                }
            })
            .catch((error) => {
                this.setState({
                    isInfiniteLoading: false
                });
                console.error('app getLatestLudoList error', error);
            });
        }
    }

    handleShouldLudoListUpdate(boolean) {
        this.setState({
            shouldLudoListUpdate: boolean
        });
    }

    handleShouldProfileUpdate(boolean) {
        this.setState({
            shouldProfileUpdate: boolean
        });
    }

    handleShouldReportUpdate(boolean) {
        this.setState({
            shouldReportUpdate: boolean
        });
    }

    handleShouldUserBasicDataUpdate(boolean) {
        this.setState({
            shouldUserBasicDataUpdate: boolean
        });
    }

    updateCurrentFormValue(ludoForm) {
        this.setState({
            currentFormValue: ludoForm
        });
    }

    render() {
        const { isHoveringSidebar } = this.state;
        const { router_currentFormValue } = this.props;
        return (

                <Sidebar
                    currentUserId={this.state.currentUserId}
                    handleIsHoveringSidebar={this.handleIsHoveringSidebar}
                    isHoveringSidebar={isHoveringSidebar}
                />
                {/* layout/main-container */}

                    {
                        React.cloneElement(this.props.children,
                            {
                                ...this.state,
                                router_currentFormValue,
                                clearCurrentFormValue: this.clearCurrentFormValue,
                                getUserBasicData: this.getUserBasicData,
                                getCurrentLudoData: this.getCurrentLudoData,
                                getLatestLudoList: this.getLatestLudoList,
                                getProfileData: this.getProfileData,
                                getProfileWillLudoData: this.getProfileWillLudoData,
                                getProfileLudoingData: this.getProfileLudoingData,
                                getProfileDidLudoData: this.getProfileDidLudoData,
                                getReportOfCurrentLudo: this.getReportOfCurrentLudo,
                                handleDenounceBoxOpen: this.handleDenounceBoxOpen,
                                handleHasGotNewReport: this.handleHasGotNewReport,
                                handleIsHoveringSidebar: this.handleIsHoveringSidebar,
                                handleIsOpeningActivePage: this.handleIsOpeningActivePage,
                                handleIsOpeningLudoListPage: this.handleIsOpeningLudoListPage,
                                handleIsOpeningProfilePage: this.handleIsOpeningProfilePage,
                                handleShouldLudoListUpdate: this.handleShouldLudoListUpdate,
                                handleShouldProfileUpdate: this.handleShouldProfileUpdate,
                                handleShouldReportUpdate: this.handleShouldReportUpdate,
                                handleShouldUserBasicDataUpdate: this.handleShouldUserBasicDataUpdate,
                                updateCurrentFormValue: this.updateCurrentFormValue
                            }
                        )
                    }

                <DenounceBox
                    currentTargetCommentId={this.state.currentTargetCommentId}
                    currentTargetLudoId={this.state.currentTargetLudoId}
                    currentTargetReportId={this.state.currentTargetReportId}
                    denounceType={this.state.denounceType}
                    isDenounceBoxOpen={this.state.isDenounceBoxOpen}
                    onRequestClose={this.handleDenounceBoxRequestClose}
                />

        );
    }
}

App.childContextTypes = {
    muiTheme: React.PropTypes.object.isRequired,
};<|endoftext|>


<commit_before>var githubAppConfig = {
	'form': {
		'login': {
			'entries': [
				{
					'name': 'provider',
					'label': translation.accountProvider[LANG],
					'type': 'select',
					'value': [{'v': 'github', 'l': 'GitHub', 'selected': true}],
					'tooltip': translation.chooseAccountProvider[LANG],
					'required': true
				},
				{
					'name': 'label',
					'label': translation.accountName[LANG],
					'type': 'text',
					'value': '',
					'tooltip': translation.chooseAccountName[LANG],
					'placeholder': translation.exampleMyAccount[LANG],
					'required': true
				},
				{
					'name': 'username',
					'label': translation.username[LANG],
					'type': 'text',
					'value': '',
					'placeholder': translation.yourUsername[LANG],
					'required': true
				},
				{
					"name": "tokenMessage",
					"type": "html",
					"value": "
" + translation.loginMessagePermissionsPartOne[LANG] + "

" + translation.loginMessagePermissionsPartTwo[LANG] + "

" + translation.loginMessagePermissionsPartThree[LANG] + "

" + translation.loginMessagePermissionsPartFour[LANG] + "
"
				}
			]
		},
		'logout': {
			'entries': [
				{
					'name': 'password',
					'label': translation.pleaseProvidePassword[LANG],
					'type': 'password',
					'value': '',
					'placeholder': translation.gitPassword[LANG],
					'required': true
				}
			]
		},
		'selectConfigBranch': {
			'entries': [
				{
					'name': 'branch',
					'label': translation.pleaseSpecifyConfigBranch[LANG],
					'type': 'select',
					'value': [],
					'required': true
				}
			]
		}
	},
	'permissions': {
		listAccounts: ['dashboard', '/github/accounts/list'],
		deleteAccount: ['dashboard', '/github/accounts/delete'],
		updateAccount: ['dashboard', '/github/accounts/update'],
		login: ['dashboard', '/github/login'],
		listRepos: ['dashboard', '/github/getRepos']
	}
};<commit_msg>updated git accounts module, blacklisted jsconfbeirut.<commit_after>var githubAppConfig = {
	'form': {
		'login': {
			'entries': [
				{
					'name': 'provider',
					'label': translation.accountProvider[LANG],
					'type': 'select',
					'value': [{'v': 'github', 'l': 'GitHub', 'selected': true}],
					'tooltip': translation.chooseAccountProvider[LANG],
					'required': true
				},
				{
					'name': 'label',
					'label': translation.accountName[LANG],
					'type': 'text',
					'value': '',
					'tooltip': translation.chooseAccountName[LANG],
					'placeholder': translation.exampleMyAccount[LANG],
					'required': true
				},
				{
					'name': 'username',
					'label': translation.username[LANG],
					'type': 'text',
					'value': '',
					'placeholder': translation.yourUsername[LANG],
					'required': true
				},
				{
					"name": "tokenMessage",
					"type": "html",
					"value": "
" + translation.loginMessagePermissionsPartOne[LANG] + "

" + translation.loginMessagePermissionsPartTwo[LANG] + "

" + translation.loginMessagePermissionsPartThree[LANG] + "

" + translation.loginMessagePermissionsPartFour[LANG] + "
"
				}
			]
		},
		'logout': {
			'entries': [
				{
					'name': 'password',
					'label': translation.pleaseProvidePassword[LANG],
					'type': 'password',
					'value': '',
					'placeholder': translation.gitPassword[LANG],
					'required': true
				}
			]
		},
		'selectConfigBranch': {
			'entries': [
				{
					'name': 'branch',
					'label': translation.pleaseSpecifyConfigBranch[LANG],
					'type': 'select',
					'value': [],
					'required': true
				}
			]
		}
	},
	'permissions': {
		listAccounts: ['dashboard', '/github/accounts/list'],
		deleteAccount: ['dashboard', '/github/accounts/delete'],
		updateAccount: ['dashboard', '/github/accounts/update'],
		login: ['dashboard', '/github/login'],
		listRepos: ['dashboard', '/github/getRepos']
	},

	"blacklistedRepos": [
		'soajs/connect-mongo-soajs',
		'soajs/soajs',
		'soajs/soajs.agent',
		'soajs/soajs.composer',
		'soajs/soajs.dash.example',
		'soajs/soajs.gcs',
		'soajs/soajs.mongodb.data',
		'soajs/soajs.utilities',
		'soajs/soajs.website.contactus',
		'soajs/soajs.jsconfbeirut'
	]
};<|endoftext|>