openreplay/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx
2022-06-23 12:35:50 +02:00

184 lines
7.5 KiB
TypeScript

import React, { useState, useRef, useEffect, useCallback } from 'react';
import CustomMetriLineChart from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart';
import CustomMetricPercentage from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage';
import CustomMetricTable from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable';
import CustomMetricPieChart from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart';
import { Styles } from 'App/components/Dashboard/Widgets/common';
import { observer, useObserver } from 'mobx-react-lite';
import { Loader } from 'UI';
import { useStore } from 'App/mstore';
import WidgetPredefinedChart from '../WidgetPredefinedChart';
import CustomMetricOverviewChart from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricOverviewChart';
import { getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper';
import { debounce } from 'App/utils';
import useIsMounted from 'App/hooks/useIsMounted'
import { FilterKey } from 'Types/filter/filterType';
import FunnelWidget from 'App/components/Funnels/FunnelWidget';
import ErrorsWidget from '../Errors/ErrorsWidget';
import SessionWidget from '../Sessions/SessionWidget';
import CustomMetricTableSessions from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTableSessions';
import CustomMetricTableErrors from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTableErrors';
interface Props {
metric: any;
isWidget?: boolean;
isTemplate?: boolean;
}
function WidgetChart(props: Props) {
const { isWidget = false, metric, isTemplate } = props;
const { dashboardStore, metricStore } = useStore();
const _metric: any = useObserver(() => metricStore.instance);
const period = useObserver(() => dashboardStore.period);
const drillDownPeriod = useObserver(() => dashboardStore.drillDownPeriod);
const drillDownFilter = useObserver(() => dashboardStore.drillDownFilter);
const colors = Styles.customMetricColors;
const [loading, setLoading] = useState(true)
const isOverviewWidget = metric.metricType === 'predefined' && metric.viewType === 'overview';
const params = { density: isOverviewWidget ? 7 : 70 }
const metricParams = { ...params }
const prevMetricRef = useRef<any>();
const isMounted = useIsMounted();
const [data, setData] = useState<any>(metric.data);
const isTableWidget = metric.metricType === 'table' && metric.viewType === 'table';
const isPieChart = metric.metricType === 'table' && metric.viewType === 'pieChart';
const onChartClick = (event: any) => {
if (event) {
if (isTableWidget || isPieChart) { // get the filter of clicked row
const periodTimestamps = period.toTimestamps()
drillDownFilter.merge({
filters: event,
startTimestamp: periodTimestamps.startTimestamp,
endTimestamp: periodTimestamps.endTimestamp,
});
} else { // get the filter of clicked chart point
const payload = event.activePayload[0].payload;
const timestamp = payload.timestamp;
const periodTimestamps = getStartAndEndTimestampsByDensity(timestamp, period.start, period.end, params.density);
drillDownFilter.merge({
startTimestamp: periodTimestamps.startTimestamp,
endTimestamp: periodTimestamps.endTimestamp,
});
}
}
}
const depsString = JSON.stringify(_metric.series);
const fetchMetricChartData = (metric: any, payload: any, isWidget: any) => {
if (!isMounted()) return;
setLoading(true)
dashboardStore.fetchMetricChartData(metric, payload, isWidget).then((res: any) => {
if (isMounted()) setData(res);
}).finally(() => {
setLoading(false);
});
}
const debounceRequest: any = React.useCallback(debounce(fetchMetricChartData, 500), []);
useEffect(() => {
if (prevMetricRef.current && prevMetricRef.current.name !== metric.name) {
prevMetricRef.current = metric;
return
};
prevMetricRef.current = metric;
const timestmaps = drillDownPeriod.toTimestamps();
const payload = isWidget ? { ...params } : { ...metricParams, ...timestmaps, ...metric.toJson() };
debounceRequest(metric, payload, isWidget);
}, [drillDownPeriod, period, depsString, _metric.page, metric.metricType, metric.metricOf, metric.viewType]);
const renderChart = () => {
const { metricType, viewType, metricOf } = metric;
if (metricType === 'sessions') {
return <SessionWidget metric={metric} />
}
if (metricType === 'errors') {
return <ErrorsWidget metric={metric} />
}
if (metricType === 'funnel') {
return <FunnelWidget metric={metric} isWidget={isWidget || isTemplate} />
}
if (metricType === 'predefined') {
if (isOverviewWidget) {
return <CustomMetricOverviewChart data={data} />
}
return <WidgetPredefinedChart isTemplate={isTemplate} metric={metric} data={data} predefinedKey={metric.predefinedKey} />
}
if (metricType === 'timeseries') {
if (viewType === 'lineChart') {
return (
<CustomMetriLineChart
data={data}
colors={colors}
params={params}
onClick={onChartClick}
/>
)
} else if (viewType === 'progress') {
return (
<CustomMetricPercentage
data={data[0]}
colors={colors}
params={params}
/>
)
}
}
if (metricType === 'table') {
if (metricOf === FilterKey.SESSIONS) {
return (
<CustomMetricTableSessions
metric={metric}
isTemplate={isTemplate}
isEdit={!isWidget && !isTemplate}
/>
)
}
if (metricOf === FilterKey.ERRORS) {
return (
<CustomMetricTableErrors
metric={metric}
isTemplate={isTemplate}
isEdit={!isWidget && !isTemplate}
/>
)
}
if (viewType === 'table') {
return (
<CustomMetricTable
metric={metric} data={data[0]}
onClick={onChartClick}
isTemplate={isTemplate}
/>
)
} else if (viewType === 'pieChart') {
return (
<CustomMetricPieChart
metric={metric}
data={data[0]}
colors={colors}
// params={params}
onClick={onChartClick}
/>
)
}
}
return <div>Unknown</div>;
}
return useObserver(() => (
<Loader loading={loading} style={{ height: `${isOverviewWidget ? 100 : 240}px` }}>
{renderChart()}
</Loader>
));
}
export default observer(WidgetChart);