mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Fixed path counts. Updated number display.
This commit is contained in:
parent
45d6b16b0d
commit
f56849a431
@ -1,6 +1,7 @@
|
|||||||
.menu {
|
.menu {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
padding-top: 20px;
|
||||||
padding-inline-end: 20px;
|
padding-inline-end: 20px;
|
||||||
border-inline-end: 1px solid var(--base300);
|
border-inline-end: 1px solid var(--base300);
|
||||||
grid-row: 2 / 3;
|
grid-row: 2 / 3;
|
||||||
@ -9,6 +10,7 @@
|
|||||||
|
|
||||||
.button {
|
.button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
place-content: center;
|
place-content: center;
|
||||||
|
@ -80,7 +80,7 @@
|
|||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.node {
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
@ -89,37 +89,35 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
min-width: 300px;
|
width: 300px;
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
min-height: 60px;
|
height: 60px;
|
||||||
|
max-height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item:hover:not(.selected) {
|
.node:hover:not(.selected) {
|
||||||
color: var(--base900);
|
color: var(--base900);
|
||||||
background: var(--base100);
|
background: var(--base100);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item.selected {
|
.node.selected {
|
||||||
color: var(--base75);
|
color: var(--base75);
|
||||||
background: var(--base900);
|
background: var(--base900);
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item.active {
|
.node.active {
|
||||||
color: var(--light50);
|
color: var(--light50);
|
||||||
background: var(--primary400);
|
background: var(--primary400);
|
||||||
}
|
}
|
||||||
|
|
||||||
.behind {
|
.node.selected .count {
|
||||||
color: var(--base400);
|
color: var(--base50);
|
||||||
|
background: var(--base800);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ahead {
|
.node.selected.active .count {
|
||||||
color: var(--base400);
|
background: var(--primary600);
|
||||||
}
|
|
||||||
|
|
||||||
.current {
|
|
||||||
color: var(--base500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
@ -132,20 +130,12 @@
|
|||||||
background: var(--base200);
|
background: var(--base200);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item.selected .count {
|
|
||||||
color: var(--base50);
|
|
||||||
background: var(--base800);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item.selected.active .count {
|
|
||||||
background: var(--primary600);
|
|
||||||
}
|
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: -100px;
|
left: -100px;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line.up {
|
.line.up {
|
||||||
@ -230,8 +220,8 @@
|
|||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
border: 3px solid var(--journey-line-color);
|
border: 3px solid var(--journey-line-color);
|
||||||
background: var(--light50);
|
background: var(--light50);
|
||||||
width: 13px;
|
width: 14px;
|
||||||
height: 13px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line:not(.active) .start:before,
|
.line:not(.active) .start:before,
|
||||||
|
@ -5,8 +5,8 @@ import classNames from 'classnames';
|
|||||||
import { useEscapeKey, useMessages } from 'components/hooks';
|
import { useEscapeKey, useMessages } from 'components/hooks';
|
||||||
import { objectToArray } from 'lib/data';
|
import { objectToArray } from 'lib/data';
|
||||||
import { ReportContext } from '../[reportId]/Report';
|
import { ReportContext } from '../[reportId]/Report';
|
||||||
// eslint-disable-next-line css-modules/no-unused-class
|
|
||||||
import styles from './JourneyView.module.css';
|
import styles from './JourneyView.module.css';
|
||||||
|
import { formatLongNumber } from 'lib/format';
|
||||||
|
|
||||||
const NODE_HEIGHT = 60;
|
const NODE_HEIGHT = 60;
|
||||||
const NODE_GAP = 10;
|
const NODE_GAP = 10;
|
||||||
@ -37,27 +37,11 @@ export default function JourneyView() {
|
|||||||
const name = items[columnIndex];
|
const name = items[columnIndex];
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
const selected = !!selectedPaths.find(path => path.items[columnIndex] === name);
|
const selected = !!selectedPaths.find(({ items }) => items[columnIndex] === name);
|
||||||
const active = selected && !!activePaths.find(path => path.items[columnIndex] === name);
|
const active = selected && !!activePaths.find(({ items }) => items[columnIndex] === name);
|
||||||
|
|
||||||
if (!nodes[name]) {
|
if (!nodes[name]) {
|
||||||
const paths = data.filter(d => d.items[columnIndex] === name);
|
const paths = data.filter(({ items }) => items[columnIndex] === name);
|
||||||
|
|
||||||
const from =
|
|
||||||
columnIndex > 0 &&
|
|
||||||
selected &&
|
|
||||||
paths.reduce((obj, path) => {
|
|
||||||
const { items, count } = path;
|
|
||||||
const name = items[columnIndex - 1];
|
|
||||||
|
|
||||||
if (!obj[name]) {
|
|
||||||
obj[name] = { name, count };
|
|
||||||
} else {
|
|
||||||
obj[name].count += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
nodes[name] = {
|
nodes[name] = {
|
||||||
name,
|
name,
|
||||||
@ -68,7 +52,9 @@ export default function JourneyView() {
|
|||||||
selected,
|
selected,
|
||||||
active,
|
active,
|
||||||
paths,
|
paths,
|
||||||
from: objectToArray(from),
|
pathMap: paths.map(({ items, count }) => ({
|
||||||
|
[`${columnIndex}:${items.join(':')}`]: count,
|
||||||
|
})),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
nodes[name].totalCount += count;
|
nodes[name].totalCount += count;
|
||||||
@ -82,43 +68,45 @@ export default function JourneyView() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
columns.forEach((column, columnIndex) => {
|
columns.forEach((column, columnIndex) => {
|
||||||
const nodes = column.nodes.map((node, nodeIndex) => {
|
const nodes = column.nodes.map((currentNode, currentNodeIndex) => {
|
||||||
const { from, totalCount } = node;
|
|
||||||
const previousNodes = columns[columnIndex - 1]?.nodes;
|
const previousNodes = columns[columnIndex - 1]?.nodes;
|
||||||
let selectedCount = from?.length ? 0 : totalCount;
|
let selectedCount = previousNodes ? 0 : currentNode.totalCount;
|
||||||
let activeCount = selectedCount;
|
let activeCount = selectedCount;
|
||||||
|
|
||||||
const lines = from?.reduce((arr: any[][], { name, count }: any) => {
|
const lines =
|
||||||
const fromIndex = previousNodes.findIndex((node: { name: any; selected: any }) => {
|
previousNodes?.reduce((arr: any[][], previousNode: any, previousNodeIndex: number) => {
|
||||||
return node.name === name && node.selected;
|
const fromCount = selectedNode?.paths.reduce((sum, path) => {
|
||||||
});
|
if (
|
||||||
|
previousNode.name === path.items[columnIndex - 1] &&
|
||||||
|
currentNode.name === path.items[columnIndex]
|
||||||
|
) {
|
||||||
|
sum += path.count;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
if (fromIndex > -1) {
|
if (currentNode.selected && previousNode.selected && fromCount) {
|
||||||
arr.push([fromIndex, nodeIndex]);
|
arr.push([previousNodeIndex, currentNodeIndex]);
|
||||||
selectedCount += count;
|
selectedCount += fromCount;
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (previousNode.active) {
|
||||||
previousNodes.findIndex(node => {
|
activeCount += fromCount;
|
||||||
return node.name === name && node.active;
|
}
|
||||||
}) > -1
|
}
|
||||||
) {
|
|
||||||
activeCount += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
}, []);
|
}, []) || [];
|
||||||
|
|
||||||
return { ...node, selectedCount, activeCount, lines };
|
return { ...currentNode, selectedCount, activeCount, lines };
|
||||||
});
|
});
|
||||||
|
|
||||||
const visitorCount = nodes.reduce(
|
const visitorCount = nodes.reduce(
|
||||||
(sum: number, { selected, selectedCount, active, activeCount, totalCount }) => {
|
(sum: number, { selected, selectedCount, active, activeCount, totalCount }) => {
|
||||||
if (!selectedNode) {
|
if (!selectedNode) {
|
||||||
sum += totalCount;
|
sum += totalCount;
|
||||||
} else if (!activeNode && selected) {
|
} else if (!activeNode && selectedNode && selected) {
|
||||||
sum += selectedCount;
|
sum += selectedCount;
|
||||||
} else if (active) {
|
} else if (activeNode && active) {
|
||||||
sum += activeCount;
|
sum += activeCount;
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
@ -136,9 +124,9 @@ export default function JourneyView() {
|
|||||||
return columns;
|
return columns;
|
||||||
}, [data, selectedNode, activeNode]);
|
}, [data, selectedNode, activeNode]);
|
||||||
|
|
||||||
const handleClick = (name: string, index: number, paths: any[]) => {
|
const handleClick = (name: string, columnIndex: number, paths: any[]) => {
|
||||||
if (name !== selectedNode?.name || index !== selectedNode?.index) {
|
if (name !== selectedNode?.name || columnIndex !== selectedNode?.columnIndex) {
|
||||||
setSelectedNode({ name, index, paths });
|
setSelectedNode({ name, columnIndex, paths });
|
||||||
} else {
|
} else {
|
||||||
setSelectedNode(null);
|
setSelectedNode(null);
|
||||||
}
|
}
|
||||||
@ -165,8 +153,8 @@ export default function JourneyView() {
|
|||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<div className={styles.num}>{columnIndex + 1}</div>
|
<div className={styles.num}>{columnIndex + 1}</div>
|
||||||
<div className={styles.stats}>
|
<div className={styles.stats}>
|
||||||
<div className={styles.visitors}>
|
<div className={styles.visitors} title={column.visitorCount}>
|
||||||
{column.visitorCount} {formatMessage(labels.visitors)}
|
{formatLongNumber(column.visitorCount)} {formatMessage(labels.visitors)}
|
||||||
</div>
|
</div>
|
||||||
{columnIndex > 0 && <div className={styles.dropoff}>{dropOffPercent}</div>}
|
{columnIndex > 0 && <div className={styles.dropoff}>{dropOffPercent}</div>}
|
||||||
</div>
|
</div>
|
||||||
@ -183,6 +171,12 @@ export default function JourneyView() {
|
|||||||
selectedCount,
|
selectedCount,
|
||||||
lines,
|
lines,
|
||||||
}) => {
|
}) => {
|
||||||
|
const nodeCount = selected
|
||||||
|
? active
|
||||||
|
? activeCount
|
||||||
|
: selectedCount
|
||||||
|
: totalCount;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={name}
|
key={name}
|
||||||
@ -191,7 +185,7 @@ export default function JourneyView() {
|
|||||||
onMouseLeave={() => selected && setActiveNode(null)}
|
onMouseLeave={() => selected && setActiveNode(null)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={classNames(styles.item, {
|
className={classNames(styles.node, {
|
||||||
[styles.selected]: selected,
|
[styles.selected]: selected,
|
||||||
[styles.active]: active,
|
[styles.active]: active,
|
||||||
})}
|
})}
|
||||||
@ -199,8 +193,8 @@ export default function JourneyView() {
|
|||||||
>
|
>
|
||||||
<div className={styles.name}>{name}</div>
|
<div className={styles.name}>{name}</div>
|
||||||
<TooltipPopup label={dropOffPercent} disabled={!selected}>
|
<TooltipPopup label={dropOffPercent} disabled={!selected}>
|
||||||
<div className={styles.count}>
|
<div className={styles.count} title={nodeCount}>
|
||||||
{selected ? (active ? activeCount : selectedCount) : totalCount}
|
{formatLongNumber(nodeCount)}
|
||||||
</div>
|
</div>
|
||||||
</TooltipPopup>
|
</TooltipPopup>
|
||||||
{columnIndex < columns.length &&
|
{columnIndex < columns.length &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user