Fixed journey calculations.

This commit is contained in:
Mike Cao 2025-06-07 11:28:35 -07:00
parent fd7dddb43a
commit 28e872f219
5 changed files with 29 additions and 18 deletions

View file

@ -33,7 +33,6 @@
justify-content: flex-start; justify-content: flex-start;
gap: 10px; gap: 10px;
width: 100%; width: 100%;
height: 60px;
} }
.visitors { .visitors {

View file

@ -1,5 +1,5 @@
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { TooltipTrigger, Tooltip, Focusable, Icon, Text, Row } from '@umami/react-zen'; import { TooltipTrigger, Tooltip, Focusable, Icon, Text, Row, Column } from '@umami/react-zen';
import { firstBy } from 'thenby'; import { firstBy } from 'thenby';
import classNames from 'classnames'; import classNames from 'classnames';
import { useEscapeKey, useMessages, useResultQuery } from '@/components/hooks'; import { useEscapeKey, useMessages, useResultQuery } from '@/components/hooks';
@ -169,8 +169,7 @@ export function Journey({
<LoadingPanel isEmpty={!data} isLoading={isLoading} error={error}> <LoadingPanel isEmpty={!data} isLoading={isLoading} error={error}>
<div className={styles.container}> <div className={styles.container}>
<div className={styles.view}> <div className={styles.view}>
{columns.map((column, columnIndex) => { {columns.map(({ visitorCount, nodes }, columnIndex) => {
const dropOffPercent = `${~~column.dropOff}%`;
return ( return (
<div <div
key={columnIndex} key={columnIndex}
@ -182,16 +181,13 @@ export function Journey({
<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} title={column.visitorCount}> <div className={styles.visitors} title={visitorCount}>
{formatLongNumber(column.visitorCount)} {formatMessage(labels.visitors)} {formatLongNumber(visitorCount)} {formatMessage(labels.visitors)}
</div>
<div>
{columnIndex > 0 && <div className={styles.dropoff}>{dropOffPercent}</div>}
</div> </div>
</div> </div>
</div> </div>
<div className={styles.nodes}> <div className={styles.nodes}>
{column.nodes.map( {nodes.map(
({ ({
name, name,
totalCount, totalCount,
@ -208,6 +204,13 @@ export function Journey({
: selectedCount : selectedCount
: totalCount; : totalCount;
const remaining =
columnIndex > 0
? Math.round((nodeCount / columns[columnIndex - 1]?.visitorCount) * 100)
: 0;
const dropped = 100 - remaining;
return ( return (
<div <div
key={name} key={name}
@ -229,12 +232,22 @@ export function Journey({
<Text truncate>{name}</Text> <Text truncate>{name}</Text>
</Row> </Row>
<div className={styles.count} title={nodeCount}> <div className={styles.count} title={nodeCount}>
<TooltipTrigger delay={0} isDisabled={columnIndex === 0}> <TooltipTrigger
delay={0}
isDisabled={columnIndex === 0 || (selectedNode && !selected)}
>
<Focusable> <Focusable>
<div>{formatLongNumber(nodeCount)}</div> <div>{formatLongNumber(nodeCount)}</div>
</Focusable> </Focusable>
<Tooltip placement="right" offset={10}> <Tooltip placement="top" offset={20} showArrow>
{dropOffPercent} <Text transform="lowercase" color="ruby">
{`${dropped}% ${formatMessage(labels.dropoff)}`}
</Text>
<Column>
<Text transform="lowercase">
{`${remaining}% ${formatMessage(labels.conversion)}`}
</Text>
</Column>
</Tooltip> </Tooltip>
</TooltipTrigger> </TooltipTrigger>
</div> </div>

View file

@ -21,6 +21,7 @@ const fullscreenStyles = {
height: '100%', height: '100%',
top: 0, top: 0,
left: 0, left: 0,
border: 'none',
zIndex: 9999, zIndex: 9999,
} as any; } as any;

View file

@ -15,7 +15,7 @@ export function MenuButton({
return ( return (
<DialogTrigger> <DialogTrigger>
<Button variant="outline"> <Button variant="quiet">
<Icon> <Icon>
<Ellipsis /> <Ellipsis />
</Icon> </Icon>

View file

@ -260,10 +260,6 @@ export const labels = defineMessages({
id: 'message.triggered-event', id: 'message.triggered-event',
defaultMessage: 'Triggered event', defaultMessage: 'Triggered event',
}, },
visitorsDroppedOff: {
id: 'message.visitors-dropped-off',
defaultMessage: 'Visitors dropped off',
},
utm: { id: 'label.utm', defaultMessage: 'UTM' }, utm: { id: 'label.utm', defaultMessage: 'UTM' },
utmDescription: { utmDescription: {
id: 'label.utm-description', id: 'label.utm-description',
@ -325,6 +321,8 @@ export const labels = defineMessages({
addBoard: { id: 'label.add-board', defaultMessage: 'Add board' }, addBoard: { id: 'label.add-board', defaultMessage: 'Add board' },
cohort: { id: 'label.cohort', defaultMessage: 'Cohort' }, cohort: { id: 'label.cohort', defaultMessage: 'Cohort' },
expand: { id: 'label.expand', defaultMessage: 'Expand' }, expand: { id: 'label.expand', defaultMessage: 'Expand' },
remaining: { id: 'label.remaining', defaultMessage: 'Remaining' },
conversion: { id: 'label.converstion', defaultMessage: 'Conversion' },
}); });
export const messages = defineMessages({ export const messages = defineMessages({