diff --git a/src/app/(main)/reports/journey/JourneyView.module.css b/src/app/(main)/reports/journey/JourneyView.module.css index dcc1e467..d5c779b6 100644 --- a/src/app/(main)/reports/journey/JourneyView.module.css +++ b/src/app/(main)/reports/journey/JourneyView.module.css @@ -104,10 +104,6 @@ background: var(--primary400); } -.item.active .count { - background: var(--primary600); -} - .behind { color: var(--base400); } @@ -130,11 +126,15 @@ background: var(--base200); } -.selected .count { +.item.selected .count { color: var(--base50); background: var(--base800); } +.item.selected.active .count { + background: var(--primary600); +} + .line { position: absolute; bottom: 0; diff --git a/src/app/(main)/reports/journey/JourneyView.tsx b/src/app/(main)/reports/journey/JourneyView.tsx index 08a51ce2..7a529543 100644 --- a/src/app/(main)/reports/journey/JourneyView.tsx +++ b/src/app/(main)/reports/journey/JourneyView.tsx @@ -28,66 +28,114 @@ export default function JourneyView() { const selectedPaths = selectedNode?.paths ?? []; const activePaths = activeNode?.paths ?? []; + const columns = []; - return Array(Number(parameters.steps)) - .fill(undefined) - .map((nodes = {}, index) => { - data.forEach(({ items, count }) => { - const name = items[index]; + for (let columnIndex = 0; columnIndex < +parameters.steps; columnIndex++) { + const nodes = {}; - if (name) { - const selected = !!selectedPaths.find(path => path.items[index] === name); - const active = selected && !!activePaths.find(path => path.items[index] === name); + data.forEach(({ items, count }: any, nodeIndex: any) => { + const name = items[columnIndex]; - if (!nodes[name]) { - const paths = data.filter((d, i) => { - return i !== index && d.items[index] === name; - }); + if (name) { + const selected = !!selectedPaths.find(path => path.items[columnIndex] === name); + const active = selected && !!activePaths.find(path => path.items[columnIndex] === name); - const from = - index > 0 && - selected && - paths.reduce((obj, path) => { - const { items, count } = path; - const name = items[index - 1]; + if (!nodes[name]) { + const paths = data.filter((d, i) => { + return i !== columnIndex && d.items[columnIndex] === name; + }); - if (!obj[name]) { - obj[name] = { name, count }; - } else { - obj[name].count += count; - } + const from = + columnIndex > 0 && + selected && + paths.reduce((obj, path) => { + const { items, count } = path; + const name = items[columnIndex - 1]; - return obj; - }, {}); + if (!obj[name]) { + obj[name] = { name, count }; + } else { + obj[name].count += count; + } - nodes[name] = { - name, - count, - total: count, - columnIndex: index, - selected, - active, - paths, - from: objectToArray(from), - }; - } else { - nodes[name].total += count; - } + return obj; + }, {}); + + nodes[name] = { + name, + count, + totalCount: count, + nodeIndex, + columnIndex, + selected, + active, + paths, + from: objectToArray(from), + }; + } else { + nodes[name].totalCount += count; } - }); - - const nodesArray = objectToArray(nodes).sort(firstBy('total', -1)); - - return { - nodes: nodesArray, - visitors: nodesArray.reduce((sum, { selected, total }) => { - if (!selectedNode || (selectedNode && selected)) { - sum += total; - } - return sum; - }, 0), - }; + } }); + + columns.push({ + nodes: objectToArray(nodes).sort(firstBy('total', -1)), + }); + } + + columns.forEach((column, columnIndex) => { + const nodes = column.nodes.map((node, nodeIndex) => { + const { from, totalCount } = node; + const previousNodes = columns[columnIndex - 1]?.nodes; + let selectedCount = from?.length ? 0 : totalCount; + let activeCount = selectedCount; + + const lines = from?.reduce((arr: any[][], { name, count }: any) => { + const fromIndex = previousNodes.findIndex((node: { name: any; selected: any }) => { + return node.name === name && node.selected; + }); + + if (fromIndex > -1) { + arr.push([fromIndex, nodeIndex]); + selectedCount += count; + } + + if ( + previousNodes.findIndex(node => { + return node.name === name && node.active; + }) > -1 + ) { + activeCount += count; + } + + return arr; + }, []); + + return { ...node, selectedCount, activeCount, lines }; + }); + + const visitorCount = nodes.reduce( + (sum: number, { selected, selectedCount, active, activeCount, totalCount }) => { + if (!selectedNode) { + sum += totalCount; + } else if (!activeNode && selected) { + sum += selectedCount; + } else if (active) { + sum += activeCount; + } + return sum; + }, + 0, + ); + + const previousTotal = columns[columnIndex - 1]?.visitorCount ?? 0; + const dropOff = + previousTotal > 0 ? ((visitorCount - previousTotal) / previousTotal) * 100 : 0; + + Object.assign(column, { nodes, visitorCount, dropOff }); + }); + + return columns; }, [data, selectedNode, activeNode]); const handleClick = (name: string, index: number, paths: any[]) => { @@ -95,8 +143,8 @@ export default function JourneyView() { setSelectedNode({ name, index, paths }); } else { setSelectedNode(null); - setActiveNode(null); } + setActiveNode(null); }; if (!data) { @@ -107,110 +155,96 @@ export default function JourneyView() {