From c1d19bfce7abe347eb3be35cf541863c8584758f Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 11 Dec 2024 14:36:14 +0100 Subject: [PATCH] fix(ui): funnel - filter sessions by step --- .../Funnels/FunnelWidget/FunnelWidget.tsx | 288 ++++++++++-------- 1 file changed, 156 insertions(+), 132 deletions(-) diff --git a/frontend/app/components/Funnels/FunnelWidget/FunnelWidget.tsx b/frontend/app/components/Funnels/FunnelWidget/FunnelWidget.tsx index ffe3a2efc..11df5f487 100644 --- a/frontend/app/components/Funnels/FunnelWidget/FunnelWidget.tsx +++ b/frontend/app/components/Funnels/FunnelWidget/FunnelWidget.tsx @@ -1,163 +1,187 @@ import React, { useEffect } from 'react'; import Widget from 'App/mstore/types/widget'; -import Funnelbar, { UxTFunnelBar } from "./FunnelBar"; +import Funnelbar, { UxTFunnelBar } from './FunnelBar'; import cn from 'classnames'; import stl from './FunnelWidget.module.css'; import { observer } from 'mobx-react-lite'; import { NoContent, Icon } from 'UI'; import { Tag, Tooltip } from 'antd'; import { useModal } from 'App/components/Modal'; +import { useStore } from '@/mstore'; +import Filter from '@/mstore/types/filter'; interface Props { - metric?: Widget; - isWidget?: boolean; - data: any; + metric?: Widget; + isWidget?: boolean; + data: any; } + function FunnelWidget(props: Props) { - const [focusedFilter, setFocusedFilter] = React.useState(null); - const { isWidget = false, data, metric } = props; - const funnel = data.funnel || { stages: [] }; - const totalSteps = funnel.stages.length; - const stages = isWidget ? [...funnel.stages.slice(0, 1), funnel.stages[funnel.stages.length - 1]] : funnel.stages; - const hasMoreSteps = funnel.stages.length > 2; - const lastStage = funnel.stages[funnel.stages.length - 1]; - const remainingSteps = totalSteps - 2; - const { hideModal } = useModal(); - const metricLabel = metric?.metricFormat == 'userCount' ? 'Users' : 'Sessions'; + const { dashboardStore, searchStore } = useStore(); + const [focusedFilter, setFocusedFilter] = React.useState(null); + const { isWidget = false, data, metric } = props; + const funnel = data.funnel || { stages: [] }; + const totalSteps = funnel.stages.length; + const stages = isWidget ? [...funnel.stages.slice(0, 1), funnel.stages[funnel.stages.length - 1]] : funnel.stages; + const hasMoreSteps = funnel.stages.length > 2; + const lastStage = funnel.stages[funnel.stages.length - 1]; + const remainingSteps = totalSteps - 2; + const { hideModal } = useModal(); + const metricLabel = metric?.metricFormat == 'userCount' ? 'Users' : 'Sessions'; + const drillDownFilter = dashboardStore.drillDownFilter; + const drillDownPeriod = dashboardStore.drillDownPeriod; + const metricFilters = metric?.series[0]?.filter.filters || []; - useEffect(() => { - return () => { - if (isWidget) return; - hideModal(); + const applyDrillDown = (index: number) => { + const filter = new Filter().fromData({ filters: metricFilters.slice(0, index + 1) }); + const periodTimestamps = drillDownPeriod.toTimestamps(); + drillDownFilter.merge({ + filters: filter.toJson().filters, + startTimestamp: periodTimestamps.startTimestamp, + endTimestamp: periodTimestamps.endTimestamp + }); + }; + + useEffect(() => { + return () => { + if (isWidget) return; + hideModal(); + }; + }, []); + + const focusStage = (index: number) => { + funnel.stages.forEach((s, i) => { + // turning on all filters if one was focused already + if (focusedFilter === index) { + s.updateKey('isActive', true); + setFocusedFilter(null); + } else { + setFocusedFilter(index); + if (i === index) { + s.updateKey('isActive', true); + } else { + s.updateKey('isActive', false); } - }, []); + } + }); - const focusStage = (index: number) => { - funnel.stages.forEach((s, i) => { - // turning on all filters if one was focused already - if (focusedFilter === index) { - s.updateKey('isActive', true) - setFocusedFilter(null) - } else { - setFocusedFilter(index) - if (i === index) { - s.updateKey('isActive', true) - } else { - s.updateKey('isActive', false) - } - } - }) - } + applyDrillDown(focusedFilter === index ? -1 : index); + }; - return ( - - - No data available for the selected period. - - } - show={!stages || stages.length === 0} - > -
- { !isWidget && ( - stages.map((filter: any, index: any) => ( - - )) - )} + return ( + + + No data available for the selected period. +
+ } + show={!stages || stages.length === 0} + > +
+ {!isWidget && ( + stages.map((filter: any, index: any) => ( + + )) + )} - { isWidget && ( - <> - + {isWidget && ( + <> + - { hasMoreSteps && ( - <> - - - )} + {hasMoreSteps && ( + <> + + + )} - {funnel.stages.length > 1 && ( - - )} - - )} -
-
-
- Lost conversion - - - {funnel.lostConversions} - - -
-
-
- Total conversion - - - {funnel.totalConversions} - - -
-
- {funnel.totalDropDueToIssues > 0 &&
{funnel.totalDropDueToIssues} sessions dropped due to issues.
} - - ); + {funnel.stages.length > 1 && ( + + )} + + )} +
+
+
+ Lost conversion + + + {funnel.lostConversions} + + +
+
+
+ Total conversion + + + {funnel.totalConversions} + + +
+
+ {funnel.totalDropDueToIssues > 0 &&
{funnel.totalDropDueToIssues} sessions dropped due to issues.
} + + ); } export const EmptyStage = observer(({ total }: any) => { - return ( -
- -
- {`+${total} ${total > 1 ? 'steps' : 'step'}`} -
-
-
- ) -}) + return ( +
+ +
+ {`+${total} ${total > 1 ? 'steps' : 'step'}`} +
+
+
+ ); +}); export const Stage = observer(({ metricLabel, stage, index, isWidget, uxt, focusStage, focusedFilter }: any) => { - return stage ? ( -
- - {!uxt ? : } - {/*{!isWidget && !uxt && }*/} -
- ) : ( - <> - ) -}) + return stage ? ( +
+ + {!uxt ? : } + {/*{!isWidget && !uxt && }*/} +
+ ) : ( + <> + ); +}); export const IndexNumber = observer(({ index }: any) => { - return ( -
- {index === 0 ? : index} -
- ); -}) + return ( +
+ {index === 0 ? : index} +
+ ); +}); const BarActions = observer(({ bar }: any) => { - return ( -
- -
- ) -}) + return ( +
+ +
+ ); +}); export default observer(FunnelWidget);