feat(widget-sessions): improve session filtering logic
- Refactored session filtering logic to handle nested filters properly. - Enhanced `fetchSessions` to ensure null checks and avoid errors. - Updated `loadData` to handle `USER_PATH` and `HEATMAP` metric types. - Improved UI consistency by adjusting spacing and formatting. - Replaced redundant code with cleaner, more maintainable patterns. This change improves the reliability and readability of the session filtering and loading logic in the WidgetSessions component.
This commit is contained in:
parent
80a7817e7d
commit
30ce37896c
1 changed files with 353 additions and 334 deletions
|
|
@ -1,376 +1,395 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { NoContent, Loader, Pagination } from 'UI';
|
||||
import { Button, Tag, Tooltip, Dropdown, message } from 'antd';
|
||||
import { UndoOutlined, DownOutlined } from '@ant-design/icons';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {NoContent, Loader, Pagination} from 'UI';
|
||||
import {Button, Tag, Tooltip, Dropdown, message} from 'antd';
|
||||
import {UndoOutlined, DownOutlined} from '@ant-design/icons';
|
||||
import cn from 'classnames';
|
||||
import { useStore } from 'App/mstore';
|
||||
import {useStore} from 'App/mstore';
|
||||
import SessionItem from 'Shared/SessionItem';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { DateTime } from 'luxon';
|
||||
import { debounce, numberWithCommas } from 'App/utils';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import {DateTime} from 'luxon';
|
||||
import {debounce, numberWithCommas} from 'App/utils';
|
||||
import useIsMounted from 'App/hooks/useIsMounted';
|
||||
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
||||
import { HEATMAP, USER_PATH, FUNNEL } from 'App/constants/card';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import AnimatedSVG, {ICONS} from 'Shared/AnimatedSVG/AnimatedSVG';
|
||||
import {HEATMAP, USER_PATH, FUNNEL} from 'App/constants/card';
|
||||
import {useTranslation} from 'react-i18next';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function WidgetSessions(props: Props) {
|
||||
const { t } = useTranslation();
|
||||
const listRef = React.useRef<HTMLDivElement>(null);
|
||||
const { className = '' } = props;
|
||||
const [activeSeries, setActiveSeries] = useState('all');
|
||||
const [data, setData] = useState<any>([]);
|
||||
const isMounted = useIsMounted();
|
||||
const [loading, setLoading] = useState(false);
|
||||
// all filtering done through series now
|
||||
const filteredSessions = getListSessionsBySeries(data, 'all');
|
||||
const { dashboardStore, metricStore, sessionStore, customFieldStore } =
|
||||
useStore();
|
||||
const focusedSeries = metricStore.focusedSeriesName;
|
||||
const filter = dashboardStore.drillDownFilter;
|
||||
const widget = metricStore.instance;
|
||||
const startTime = DateTime.fromMillis(filter.startTimestamp).toFormat(
|
||||
'LLL dd, yyyy HH:mm',
|
||||
);
|
||||
const endTime = DateTime.fromMillis(filter.endTimestamp).toFormat(
|
||||
'LLL dd, yyyy HH:mm',
|
||||
);
|
||||
const [seriesOptions, setSeriesOptions] = useState([
|
||||
{ label: t('All'), value: 'all' },
|
||||
]);
|
||||
const hasFilters =
|
||||
filter.filters.length > 0 ||
|
||||
filter.startTimestamp !== dashboardStore.drillDownPeriod.start ||
|
||||
filter.endTimestamp !== dashboardStore.drillDownPeriod.end;
|
||||
const filterText = filter.filters.length > 0 ? filter.filters[0].value : '';
|
||||
const metaList = customFieldStore.list.map((i: any) => i.key);
|
||||
const {t} = useTranslation();
|
||||
const listRef = React.useRef<HTMLDivElement>(null);
|
||||
const {className = ''} = props;
|
||||
const [activeSeries, setActiveSeries] = useState('all');
|
||||
const [data, setData] = useState<any>([]);
|
||||
const isMounted = useIsMounted();
|
||||
const [loading, setLoading] = useState(false);
|
||||
// all filtering done through series now
|
||||
const filteredSessions = getListSessionsBySeries(data, 'all');
|
||||
const {dashboardStore, metricStore, sessionStore, customFieldStore} =
|
||||
useStore();
|
||||
const focusedSeries = metricStore.focusedSeriesName;
|
||||
const filter = dashboardStore.drillDownFilter;
|
||||
const widget = metricStore.instance;
|
||||
const startTime = DateTime.fromMillis(filter.startTimestamp).toFormat(
|
||||
'LLL dd, yyyy HH:mm',
|
||||
);
|
||||
const endTime = DateTime.fromMillis(filter.endTimestamp).toFormat(
|
||||
'LLL dd, yyyy HH:mm',
|
||||
);
|
||||
const [seriesOptions, setSeriesOptions] = useState([
|
||||
{label: t('All'), value: 'all'},
|
||||
]);
|
||||
const hasFilters =
|
||||
filter.filters.length > 0 ||
|
||||
filter.startTimestamp !== dashboardStore.drillDownPeriod.start ||
|
||||
filter.endTimestamp !== dashboardStore.drillDownPeriod.end;
|
||||
const filterText = filter.filters.length > 0 ? filter.filters[0].value : '';
|
||||
const metaList = customFieldStore.list.map((i: any) => i.key);
|
||||
|
||||
const seriesDropdownItems = seriesOptions.map((option) => ({
|
||||
key: option.value,
|
||||
label: (
|
||||
<div onClick={() => setActiveSeries(option.value)}>{option.label}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (!widget.series) return;
|
||||
const seriesOptions = widget.series.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.seriesId ?? item.name,
|
||||
const seriesDropdownItems = seriesOptions.map((option) => ({
|
||||
key: option.value,
|
||||
label: (
|
||||
<div onClick={() => setActiveSeries(option.value)}>{option.label}</div>
|
||||
),
|
||||
}));
|
||||
setSeriesOptions([{ label: t('All'), value: 'all' }, ...seriesOptions]);
|
||||
}, [widget.series.length]);
|
||||
|
||||
const fetchSessions = (metricId: any, filter: any) => {
|
||||
if (!isMounted()) return;
|
||||
setLoading(true);
|
||||
delete filter.eventsOrderSupport;
|
||||
if (widget.metricType === FUNNEL) {
|
||||
if (filter.series[0].filter.filters.length === 0) {
|
||||
setLoading(false);
|
||||
return setData([]);
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
if (!widget.series) return;
|
||||
const seriesOptions = widget.series.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.seriesId ?? item.name,
|
||||
}));
|
||||
setSeriesOptions([{label: t('All'), value: 'all'}, ...seriesOptions]);
|
||||
}, [widget.series.length]);
|
||||
|
||||
widget
|
||||
.fetchSessions(metricId, filter)
|
||||
.then((res: any) => {
|
||||
setData(res);
|
||||
if (metricStore.drillDown) {
|
||||
setTimeout(() => {
|
||||
message.info(t('Sessions Refreshed!'));
|
||||
listRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
metricStore.setDrillDown(false);
|
||||
}, 0);
|
||||
const fetchSessions = (metricId: any, filter: any) => {
|
||||
if (!isMounted()) return;
|
||||
|
||||
if (widget.metricType === FUNNEL) {
|
||||
if (filter.series[0].filter.filters.length === 0) {
|
||||
setLoading(false);
|
||||
return setData([]);
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
const fetchClickmapSessions = (customFilters: Record<string, any>) => {
|
||||
sessionStore.getSessions(customFilters).then((data) => {
|
||||
setData([{ ...data, seriesId: 1, seriesName: 'Clicks' }]);
|
||||
});
|
||||
};
|
||||
const debounceRequest: any = React.useCallback(
|
||||
debounce(fetchSessions, 1000),
|
||||
[],
|
||||
);
|
||||
const debounceClickMapSearch = React.useCallback(
|
||||
debounce(fetchClickmapSessions, 1000),
|
||||
[],
|
||||
);
|
||||
|
||||
const depsString = JSON.stringify(widget.series);
|
||||
|
||||
const loadData = () => {
|
||||
if (widget.metricType === HEATMAP && metricStore.clickMapSearch) {
|
||||
const clickFilter = {
|
||||
value: [metricStore.clickMapSearch],
|
||||
type: 'CLICK',
|
||||
operator: 'onSelector',
|
||||
isEvent: true,
|
||||
// @ts-ignore
|
||||
filters: [],
|
||||
};
|
||||
const timeRange = {
|
||||
rangeValue: dashboardStore.drillDownPeriod.rangeValue,
|
||||
startDate: dashboardStore.drillDownPeriod.start,
|
||||
endDate: dashboardStore.drillDownPeriod.end,
|
||||
};
|
||||
const customFilter = {
|
||||
...filter,
|
||||
...timeRange,
|
||||
filters: [...sessionStore.userFilter.filters, clickFilter],
|
||||
};
|
||||
debounceClickMapSearch(customFilter);
|
||||
} else {
|
||||
const hasStartPoint =
|
||||
!!widget.startPoint && widget.metricType === USER_PATH;
|
||||
const onlyFocused = focusedSeries
|
||||
? widget.series.filter((s) => s.name === focusedSeries)
|
||||
: widget.series;
|
||||
const activeSeries = metricStore.disabledSeries.length
|
||||
? onlyFocused.filter(
|
||||
(s) => !metricStore.disabledSeries.includes(s.name),
|
||||
)
|
||||
: onlyFocused;
|
||||
const seriesJson = activeSeries.map((s) => s.toJson());
|
||||
if (hasStartPoint) {
|
||||
seriesJson[0].filter.filters.push(widget.startPoint.toJson());
|
||||
}
|
||||
if (widget.metricType === USER_PATH) {
|
||||
if (
|
||||
seriesJson[0].filter.filters[0].value[0] === '' &&
|
||||
widget.data.nodes
|
||||
) {
|
||||
seriesJson[0].filter.filters[0].value = widget.data.nodes[0].name;
|
||||
} else if (
|
||||
seriesJson[0].filter.filters[0].value[0] === '' &&
|
||||
!widget.data.nodes?.length
|
||||
) {
|
||||
// no point requesting if we don't have starting point picked by api
|
||||
return;
|
||||
setLoading(true);
|
||||
const filterCopy = {...filter};
|
||||
delete filterCopy.eventsOrderSupport;
|
||||
|
||||
try {
|
||||
// Handle filters properly with null checks
|
||||
if (filterCopy.filters && filterCopy.filters.length > 0) {
|
||||
// Ensure the nested path exists before pushing
|
||||
if (filterCopy.series?.[0]?.filter) {
|
||||
if (!filterCopy.series[0].filter.filters) {
|
||||
filterCopy.series[0].filter.filters = [];
|
||||
}
|
||||
filterCopy.series[0].filter.filters.push(...filterCopy.filters);
|
||||
}
|
||||
filterCopy.filters = [];
|
||||
}
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
debounceRequest(widget.metricId, {
|
||||
...filter,
|
||||
series: seriesJson,
|
||||
page: metricStore.sessionsPage,
|
||||
limit: metricStore.sessionsPageSize,
|
||||
});
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
metricStore.updateKey('sessionsPage', 1);
|
||||
loadData();
|
||||
}, [
|
||||
filter.startTimestamp,
|
||||
filter.endTimestamp,
|
||||
filter.filters,
|
||||
depsString,
|
||||
metricStore.clickMapSearch,
|
||||
focusedSeries,
|
||||
widget.startPoint,
|
||||
widget.data.nodes,
|
||||
metricStore.disabledSeries.length,
|
||||
]);
|
||||
useEffect(loadData, [metricStore.sessionsPage]);
|
||||
useEffect(() => {
|
||||
if (activeSeries === 'all') {
|
||||
metricStore.setFocusedSeriesName(null);
|
||||
} else {
|
||||
metricStore.setFocusedSeriesName(
|
||||
seriesOptions.find((option) => option.value === activeSeries)?.label,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}, [activeSeries]);
|
||||
useEffect(() => {
|
||||
if (focusedSeries) {
|
||||
setActiveSeries(
|
||||
seriesOptions.find((option) => option.label === focusedSeries)?.value ||
|
||||
'all',
|
||||
);
|
||||
} else {
|
||||
setActiveSeries('all');
|
||||
}
|
||||
}, [focusedSeries]);
|
||||
widget
|
||||
.fetchSessions(metricId, filterCopy)
|
||||
.then((res: any) => {
|
||||
setData(res);
|
||||
if (metricStore.drillDown) {
|
||||
setTimeout(() => {
|
||||
message.info(t('Sessions Refreshed!'));
|
||||
listRef.current?.scrollIntoView({behavior: 'smooth'});
|
||||
metricStore.setDrillDown(false);
|
||||
}, 0);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
const fetchClickmapSessions = (customFilters: Record<string, any>) => {
|
||||
sessionStore.getSessions(customFilters).then((data) => {
|
||||
setData([{...data, seriesId: 1, seriesName: 'Clicks'}]);
|
||||
});
|
||||
};
|
||||
const debounceRequest: any = React.useCallback(
|
||||
debounce(fetchSessions, 1000),
|
||||
[],
|
||||
);
|
||||
const debounceClickMapSearch = React.useCallback(
|
||||
debounce(fetchClickmapSessions, 1000),
|
||||
[],
|
||||
);
|
||||
|
||||
const clearFilters = () => {
|
||||
metricStore.updateKey('sessionsPage', 1);
|
||||
dashboardStore.resetDrillDownFilter();
|
||||
};
|
||||
const depsString = JSON.stringify(widget.series);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
className,
|
||||
'bg-white p-3 pb-0 rounded-xl shadow-sm border mt-3',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<h2 className="text-xl">
|
||||
{metricStore.clickMapSearch ? t('Clicks') : t('Sessions')}
|
||||
</h2>
|
||||
<div className="ml-2 color-gray-medium">
|
||||
{metricStore.clickMapLabel
|
||||
? `on "${metricStore.clickMapLabel}" `
|
||||
: null}
|
||||
{t('between')}{' '}
|
||||
<span className="font-medium color-gray-darkest">
|
||||
const loadData = () => {
|
||||
if (widget.metricType === HEATMAP && metricStore.clickMapSearch) {
|
||||
const clickFilter = {
|
||||
value: [metricStore.clickMapSearch],
|
||||
type: 'CLICK',
|
||||
operator: 'onSelector',
|
||||
isEvent: true,
|
||||
// @ts-ignore
|
||||
filters: [],
|
||||
};
|
||||
const timeRange = {
|
||||
rangeValue: dashboardStore.drillDownPeriod.rangeValue,
|
||||
startDate: dashboardStore.drillDownPeriod.start,
|
||||
endDate: dashboardStore.drillDownPeriod.end,
|
||||
};
|
||||
const customFilter = {
|
||||
...filter,
|
||||
...timeRange,
|
||||
filters: [...sessionStore.userFilter.filters, clickFilter],
|
||||
};
|
||||
debounceClickMapSearch(customFilter);
|
||||
} else {
|
||||
const hasStartPoint =
|
||||
!!widget.startPoint && widget.metricType === USER_PATH;
|
||||
const onlyFocused = focusedSeries
|
||||
? widget.series.filter((s) => s.name === focusedSeries)
|
||||
: widget.series;
|
||||
const activeSeries = metricStore.disabledSeries.length
|
||||
? onlyFocused.filter(
|
||||
(s) => !metricStore.disabledSeries.includes(s.name),
|
||||
)
|
||||
: onlyFocused;
|
||||
const seriesJson = activeSeries.map((s) => s.toJson());
|
||||
if (hasStartPoint) {
|
||||
seriesJson[0].filter.filters.push(widget.startPoint.toJson());
|
||||
}
|
||||
if (widget.metricType === USER_PATH) {
|
||||
if (
|
||||
seriesJson[0].filter.filters[0].value[0] === '' &&
|
||||
widget.data.nodes
|
||||
) {
|
||||
seriesJson[0].filter.filters[0].value = widget.data.nodes[0].name;
|
||||
} else if (
|
||||
seriesJson[0].filter.filters[0].value[0] === '' &&
|
||||
!widget.data.nodes?.length
|
||||
) {
|
||||
// no point requesting if we don't have starting point picked by api
|
||||
return;
|
||||
}
|
||||
}
|
||||
debounceRequest(widget.metricId, {
|
||||
...filter,
|
||||
series: seriesJson,
|
||||
page: metricStore.sessionsPage,
|
||||
limit: metricStore.sessionsPageSize,
|
||||
});
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
metricStore.updateKey('sessionsPage', 1);
|
||||
loadData();
|
||||
}, [
|
||||
filter.startTimestamp,
|
||||
filter.endTimestamp,
|
||||
filter.filters,
|
||||
depsString,
|
||||
metricStore.clickMapSearch,
|
||||
focusedSeries,
|
||||
widget.startPoint,
|
||||
widget.data.nodes,
|
||||
metricStore.disabledSeries.length,
|
||||
]);
|
||||
useEffect(loadData, [metricStore.sessionsPage]);
|
||||
useEffect(() => {
|
||||
if (activeSeries === 'all') {
|
||||
metricStore.setFocusedSeriesName(null);
|
||||
} else {
|
||||
metricStore.setFocusedSeriesName(
|
||||
seriesOptions.find((option) => option.value === activeSeries)?.label,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}, [activeSeries]);
|
||||
useEffect(() => {
|
||||
if (focusedSeries) {
|
||||
setActiveSeries(
|
||||
seriesOptions.find((option) => option.label === focusedSeries)?.value ||
|
||||
'all',
|
||||
);
|
||||
} else {
|
||||
setActiveSeries('all');
|
||||
}
|
||||
}, [focusedSeries]);
|
||||
|
||||
const clearFilters = () => {
|
||||
metricStore.updateKey('sessionsPage', 1);
|
||||
dashboardStore.resetDrillDownFilter();
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
className,
|
||||
'bg-white p-3 pb-0 rounded-xl shadow-sm border mt-3',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<h2 className="text-xl">
|
||||
{metricStore.clickMapSearch ? t('Clicks') : t('Sessions')}
|
||||
</h2>
|
||||
<div className="ml-2 color-gray-medium">
|
||||
{metricStore.clickMapLabel
|
||||
? `on "${metricStore.clickMapLabel}" `
|
||||
: null}
|
||||
{t('between')}{' '}
|
||||
<span className="font-medium color-gray-darkest">
|
||||
{startTime}
|
||||
</span>{' '}
|
||||
{t('and')}{' '}
|
||||
<span className="font-medium color-gray-darkest">
|
||||
{t('and')}{' '}
|
||||
<span className="font-medium color-gray-darkest">
|
||||
{endTime}
|
||||
</span>{' '}
|
||||
</div>
|
||||
{hasFilters && (
|
||||
<Tooltip title={t('Clear Drilldown')} placement="top">
|
||||
<Button type="text" size="small" onClick={clearFilters}>
|
||||
<UndoOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{hasFilters && (
|
||||
<Tooltip title={t('Clear Drilldown')} placement="top">
|
||||
<Button type="text" size="small" onClick={clearFilters}>
|
||||
<UndoOutlined/>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasFilters && widget.metricType === 'table' && (
|
||||
<div className="py-2">
|
||||
<Tag
|
||||
closable
|
||||
onClose={clearFilters}
|
||||
className="truncate max-w-44 rounded-lg"
|
||||
>
|
||||
{filterText}
|
||||
</Tag>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{hasFilters && widget.metricType === 'table' && (
|
||||
<div className="py-2">
|
||||
<Tag
|
||||
closable
|
||||
onClose={clearFilters}
|
||||
className="truncate max-w-44 rounded-lg"
|
||||
>
|
||||
{filterText}
|
||||
</Tag>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
{widget.metricType !== 'table' && widget.metricType !== HEATMAP && (
|
||||
<div className="flex items-center ml-6">
|
||||
<div className="flex items-center gap-4">
|
||||
{widget.metricType !== 'table' && widget.metricType !== HEATMAP && (
|
||||
<div className="flex items-center ml-6">
|
||||
<span className="mr-2 color-gray-medium">
|
||||
{t('Filter by Series')}
|
||||
</span>
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: seriesDropdownItems,
|
||||
selectable: true,
|
||||
selectedKeys: [activeSeries],
|
||||
}}
|
||||
trigger={['click']}
|
||||
>
|
||||
<Button type="text" size="small">
|
||||
{seriesOptions.find((option) => option.value === activeSeries)
|
||||
?.label || t('Select Series')}
|
||||
<DownOutlined />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3">
|
||||
<Loader loading={loading}>
|
||||
<NoContent
|
||||
title={
|
||||
<div className="flex items-center justify-center flex-col">
|
||||
<AnimatedSVG name={ICONS.NO_SESSIONS} size={60} />
|
||||
<div className="mt-4" />
|
||||
<div className="text-center">
|
||||
{t('No relevant sessions found for the selected time period')}
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: seriesDropdownItems,
|
||||
selectable: true,
|
||||
selectedKeys: [activeSeries],
|
||||
}}
|
||||
trigger={['click']}
|
||||
>
|
||||
<Button type="text" size="small">
|
||||
{seriesOptions.find((option) => option.value === activeSeries)
|
||||
?.label || t('Select Series')}
|
||||
<DownOutlined/>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
show={filteredSessions.sessions.length === 0}
|
||||
>
|
||||
{filteredSessions.sessions.map((session: any) => (
|
||||
<React.Fragment key={session.sessionId}>
|
||||
<SessionItem
|
||||
disableUser
|
||||
session={session}
|
||||
metaList={metaList}
|
||||
/>
|
||||
<div className="border-b" />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flex items-center justify-between p-5"
|
||||
ref={listRef}
|
||||
>
|
||||
<div>
|
||||
{t('Showing')}{' '}
|
||||
<span className="font-medium">
|
||||
<div className="mt-3">
|
||||
<Loader loading={loading}>
|
||||
<NoContent
|
||||
title={
|
||||
<div className="flex items-center justify-center flex-col">
|
||||
<AnimatedSVG name={ICONS.NO_SESSIONS} size={60}/>
|
||||
<div className="mt-4"/>
|
||||
<div className="text-center">
|
||||
{t('No relevant sessions found for the selected time period')}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
show={filteredSessions.sessions.length === 0}
|
||||
>
|
||||
{filteredSessions.sessions.map((session: any) => (
|
||||
<React.Fragment key={session.sessionId}>
|
||||
<SessionItem
|
||||
disableUser
|
||||
session={session}
|
||||
metaList={metaList}
|
||||
/>
|
||||
<div className="border-b"/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
<div
|
||||
className="flex items-center justify-between p-5"
|
||||
ref={listRef}
|
||||
>
|
||||
<div>
|
||||
{t('Showing')}{' '}
|
||||
<span className="font-medium">
|
||||
{(metricStore.sessionsPage - 1) *
|
||||
metricStore.sessionsPageSize +
|
||||
1}
|
||||
metricStore.sessionsPageSize +
|
||||
1}
|
||||
</span>{' '}
|
||||
{t('to')}{' '}
|
||||
<span className="font-medium">
|
||||
{t('to')}{' '}
|
||||
<span className="font-medium">
|
||||
{(metricStore.sessionsPage - 1) *
|
||||
metricStore.sessionsPageSize +
|
||||
filteredSessions.sessions.length}
|
||||
metricStore.sessionsPageSize +
|
||||
filteredSessions.sessions.length}
|
||||
</span>{' '}
|
||||
{t('of')}{' '}
|
||||
<span className="font-medium">
|
||||
{t('of')}{' '}
|
||||
<span className="font-medium">
|
||||
{numberWithCommas(filteredSessions.total)}
|
||||
</span>{' '}
|
||||
{t('sessions.')}
|
||||
</div>
|
||||
<Pagination
|
||||
page={metricStore.sessionsPage}
|
||||
total={filteredSessions.total}
|
||||
onPageChange={(page: any) =>
|
||||
metricStore.updateKey('sessionsPage', page)
|
||||
}
|
||||
limit={metricStore.sessionsPageSize}
|
||||
debounceRequest={500}
|
||||
/>
|
||||
{t('sessions.')}
|
||||
</div>
|
||||
<Pagination
|
||||
page={metricStore.sessionsPage}
|
||||
total={filteredSessions.total}
|
||||
onPageChange={(page: any) =>
|
||||
metricStore.updateKey('sessionsPage', page)
|
||||
}
|
||||
limit={metricStore.sessionsPageSize}
|
||||
debounceRequest={500}
|
||||
/>
|
||||
</div>
|
||||
</NoContent>
|
||||
</Loader>
|
||||
</div>
|
||||
</NoContent>
|
||||
</Loader>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const getListSessionsBySeries = (data: any, seriesId: any) => {
|
||||
const arr = data.reduce(
|
||||
(arr: any, element: any) => {
|
||||
if (seriesId === 'all') {
|
||||
const sessionIds = arr.sessions.map((i: any) => i.sessionId);
|
||||
const sessions = element.sessions.filter(
|
||||
(i: any) => !sessionIds.includes(i.sessionId),
|
||||
);
|
||||
arr.sessions.push(...sessions);
|
||||
} else if (element.seriesId === seriesId) {
|
||||
const sessionIds = arr.sessions.map((i: any) => i.sessionId);
|
||||
const sessions = element.sessions.filter(
|
||||
(i: any) => !sessionIds.includes(i.sessionId),
|
||||
);
|
||||
const duplicates = element.sessions.length - sessions.length;
|
||||
arr.sessions.push(...sessions);
|
||||
arr.total = element.total - duplicates;
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
{ sessions: [] },
|
||||
);
|
||||
arr.total =
|
||||
seriesId === 'all'
|
||||
? Math.max(...data.map((i: any) => i.total))
|
||||
: data.find((i: any) => i.seriesId === seriesId).total;
|
||||
return arr;
|
||||
const arr = data.reduce(
|
||||
(arr: any, element: any) => {
|
||||
if (seriesId === 'all') {
|
||||
const sessionIds = arr.sessions.map((i: any) => i.sessionId);
|
||||
const sessions = element.sessions.filter(
|
||||
(i: any) => !sessionIds.includes(i.sessionId),
|
||||
);
|
||||
arr.sessions.push(...sessions);
|
||||
} else if (element.seriesId === seriesId) {
|
||||
const sessionIds = arr.sessions.map((i: any) => i.sessionId);
|
||||
const sessions = element.sessions.filter(
|
||||
(i: any) => !sessionIds.includes(i.sessionId),
|
||||
);
|
||||
const duplicates = element.sessions.length - sessions.length;
|
||||
arr.sessions.push(...sessions);
|
||||
arr.total = element.total - duplicates;
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
{sessions: []},
|
||||
);
|
||||
arr.total =
|
||||
seriesId === 'all'
|
||||
? Math.max(...data.map((i: any) => i.total))
|
||||
: data.find((i: any) => i.seriesId === seriesId).total;
|
||||
return arr;
|
||||
};
|
||||
|
||||
export default observer(WidgetSessions);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue