All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.js.components.Chart.js Maven / Gradle / Ivy

There is a newer version: 2.0.101
Show newest version
/**
 * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
 * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
 */

import ClayLoadingIndicator from '@clayui/loading-indicator';
import {useIsMounted} from '@liferay/frontend-js-react-web';
import className from 'classnames';
import PropTypes from 'prop-types';
import React, {useContext, useEffect, useMemo} from 'react';
import {
	CartesianGrid,
	Legend,
	Line,
	LineChart,
	ReferenceDot,
	Tooltip,
	XAxis,
	YAxis,
} from 'recharts';

import {
	ChartDispatchContext,
	ChartStateContext,
	useIsPreviousPeriodButtonDisabled,
} from '../context/ChartStateContext';
import ConnectionContext from '../context/ConnectionContext';
import {StoreDispatchContext, StoreStateContext} from '../context/StoreContext';
import {generateDateFormatters as dateFormat} from '../utils/dateFormat';
import {numberFormat} from '../utils/numberFormat';
import {ActiveDot as CustomActiveDot, Dot as CustomDot} from './CustomDots';
import CustomTooltip from './CustomTooltip';

const CHART_COLORS = {
	analyticsReportsHistoricalReads: '#50D2A0',
	analyticsReportsHistoricalViews: '#4B9BFF',
	cartesianGrid: '#E7E7ED',
	publishDate: '#2E5AAC',
};

const CHART_SIZES = {
	dotRadius: 4,
	fill: 'white',
	height: 220,
	lineWidth: 2,
	width: 280,
	yAxisWidth: 40,
};

const DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
const HOUR_IN_MILLISECONDS = 60 * 60 * 1000;

const LAST_24_HOURS = 'last-24-hours';

const METRICS_STATIC_VALUES = {
	analyticsReportsHistoricalReads: {
		color: CHART_COLORS.analyticsReportsHistoricalReads,
		iconType: 'square',
		langKey: Liferay.Language.get('reads-metric'),
	},
	analyticsReportsHistoricalViews: {
		color: CHART_COLORS.analyticsReportsHistoricalViews,
		iconType: 'circle',
		langKey: Liferay.Language.get('views-metric'),
	},
};

function keyToTranslatedLabelValue(key) {
	return METRICS_STATIC_VALUES[key]?.langKey ?? key;
}

function keyToHexColor(key) {
	return METRICS_STATIC_VALUES[key]?.color ?? '#666666';
}

function keyToIconType(key) {
	return METRICS_STATIC_VALUES[key]?.iconType ?? 'line';
}

/*
 * If a number is bigger than 1000 it will transform it to kilos
 *
 * 4 => 4
 * 4000 => '4K'
 */
function thousandsToKilosFormater(value) {
	if (value > 1000) {
		return value / 1000 + 'K';
	}

	return value;
}

function legendFormatterGenerator(
	totals,
	languageTag,
	publishedToday,
	validAnalyticsConnection
) {
	return (value) => {
		const preformattedNumber = totals[value];

		return (
			
				

				
					{keyToTranslatedLabelValue(value)}
				

				
					{validAnalyticsConnection &&
					preformattedNumber !== null &&
					!publishedToday
						? numberFormat(languageTag, preformattedNumber)
						: '-'}
				
			
		);
	};
}

export default function Chart({dataProviders = [], publishDate}) {
	const {validAnalyticsConnection} = useContext(ConnectionContext);

	const storeDispatch = useContext(StoreDispatchContext);

	const chartDispatch = useContext(ChartDispatchContext);

	const {languageTag, publishedToday} = useContext(StoreStateContext);

	const {dataSet, lineChartLoading, timeRange, timeSpanKey, timeSpanOffset} =
		useContext(ChartStateContext);

	const isPreviousPeriodButtonDisabled = useIsPreviousPeriodButtonDisabled();

	const dateFormatters = useMemo(
		() => dateFormat(languageTag),
		[languageTag]
	);

	const isMounted = useIsMounted();

	useEffect(() => {
		let gone = false;

		const timeSpanComparator =
			timeSpanKey === LAST_24_HOURS
				? HOUR_IN_MILLISECONDS
				: DAY_IN_MILLISECONDS;

		const keys = new Set(['analyticsReportsHistoricalViews']);

		if (dataProviders.length === 2) {
			keys.add('analyticsReportsHistoricalReads');
		}

		if (validAnalyticsConnection) {
			const promises = dataProviders.map((getter) => {
				return getter();
			});

			allSettled(promises).then((data) => {
				if (gone || !isMounted()) {
					return;
				}

				let dataSetItems = {};

				for (let i = 0; i < data.length; i++) {
					if (data[i].status === 'fulfilled') {
						dataSetItems = {
							...dataSetItems,
							...data[i].value,
						};
					}
					else {
						storeDispatch({type: 'ADD_WARNING'});
					}
				}

				chartDispatch({
					payload: {
						dataSetItems,
						keys,
						timeSpanComparator,
					},
					type: 'ADD_DATA_SET_ITEMS',
					validAnalyticsConnection,
				});
			});
		}
		else {
			chartDispatch({
				payload: {
					keys,
					timeSpanComparator,
				},
				type: 'ADD_DATA_SET_ITEMS',
				validAnalyticsConnection,
			});
		}

		return () => {
			gone = true;
		};

		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [timeSpanKey, timeSpanOffset]);

	const {histogram, keyList} = dataSet;

	const referenceDotPosition = useMemo(() => {
		const publishDateISOString = new Date(publishDate).toISOString();

		return timeSpanKey === LAST_24_HOURS
			? publishDateISOString.split(':')[0].concat(':00:00')
			: publishDateISOString.split('T')[0].concat('T00:00:00');
	}, [timeSpanKey, publishDate]);

	const legendFormatter =
		dataSet &&
		legendFormatterGenerator(
			dataSet.totals,
			languageTag,
			publishedToday,
			validAnalyticsConnection
		);

	const xAxisFormatter =
		timeSpanKey === LAST_24_HOURS
			? dateFormatters.formatNumericHour
			: dateFormatters.formatNumericDay;

	const lineChartWrapperClasses = className('line-chart-wrapper', {
		'line-chart-wrapper--loading': lineChartLoading,
	});

	return (
		<>
			{dataSet ? (
				
{lineChartLoading && ( )}
{ return validAnalyticsConnection && histogram.length !== 0 ? xAxisFormatter(value) : value; }} tickLine={false} type={ validAnalyticsConnection && histogram.length !== 0 ? 'category' : 'number' } /> {!validAnalyticsConnection || publishedToday || !histogram.length ? ( ) : ( )} {validAnalyticsConnection && !publishedToday && ( } cursor={ validAnalyticsConnection && histogram.length !== 0 && !publishedToday } formatter={(value, name) => { return [ numberFormat(languageTag, value), keyToTranslatedLabelValue(name), keyToIconType(name), ]; }} labelFormatter={ dateFormatters.formatLongDate } separator=": " /> )} {keyList.map((keyName) => { const color = keyToHexColor(keyName); const shape = keyToIconType(keyName); return ( } dataKey={keyName} dot={} fill={color} isAnimationActive={false} key={keyName} stroke={color} strokeWidth={CHART_SIZES.lineWidth} type="monotone" /> ); })} {validAnalyticsConnection && !publishedToday && ( )}
) : null} ); } function allSettled(promises) { return Promise.all( promises.map((promise) => { return promise .then((value) => { return {status: 'fulfilled', value}; }) .catch((reason) => { return {reason, status: 'rejected'}; }); }) ); } Chart.propTypes = { dataProviders: PropTypes.arrayOf(PropTypes.func).isRequired, publishDate: PropTypes.string.isRequired, timeSpanOptions: PropTypes.arrayOf( PropTypes.shape({ key: PropTypes.string.isRequired, label: PropTypes.string.isRequired, }) ).isRequired, };




© 2015 - 2024 Weber Informatics LLC | Privacy Policy