import { VStack, Tag, Text, Tooltip, useColorModeValue, theme, } from '@chakra-ui/react' import { useTypebot } from '@/features/editor/providers/TypebotProvider' import { useWorkspace } from '@/features/workspace/WorkspaceProvider' import React, { useMemo } from 'react' import { useEndpoints } from '../../providers/EndpointsProvider' import { useGroupsCoordinates } from '../../providers/GroupsCoordinateProvider' import { hasProPerks } from '@/features/billing/helpers/hasProPerks' import { computeDropOffPath } from '../../helpers/computeDropOffPath' import { computeSourceCoordinates } from '../../helpers/computeSourceCoordinates' import { TotalAnswersInBlock } from '@typebot.io/schemas/features/analytics' import { computePreviousTotalAnswers } from '@/features/analytics/helpers/computePreviousTotalAnswers' import { blockHasItems } from '@typebot.io/lib' export const dropOffBoxDimensions = { width: 100, height: 55, } export const dropOffSegmentLength = 80 const dropOffSegmentMinWidth = 2 const dropOffSegmentMaxWidth = 20 export const dropOffStubLength = 30 type Props = { totalAnswersInBlocks: TotalAnswersInBlock[] blockId: string onUnlockProPlanClick?: () => void } export const DropOffEdge = ({ totalAnswersInBlocks, blockId, onUnlockProPlanClick, }: Props) => { const dropOffColor = useColorModeValue( theme.colors.red[500], theme.colors.red[400] ) const { workspace } = useWorkspace() const { groupsCoordinates } = useGroupsCoordinates() const { sourceEndpointYOffsets: sourceEndpoints } = useEndpoints() const { publishedTypebot } = useTypebot() const currentBlock = useMemo( () => totalAnswersInBlocks.reduce( (block, totalAnswersInBlock) => { if (totalAnswersInBlock.blockId === blockId) { return block ? { ...block, total: block.total + totalAnswersInBlock.total } : totalAnswersInBlock } return block }, undefined ), [blockId, totalAnswersInBlocks] ) const isWorkspaceProPlan = hasProPerks(workspace) const { totalDroppedUser, dropOffRate } = useMemo(() => { if (!publishedTypebot || currentBlock?.total === undefined) return { previousTotal: undefined, dropOffRate: undefined } const totalAnswers = currentBlock.total const previousTotal = computePreviousTotalAnswers( publishedTypebot, currentBlock.blockId, totalAnswersInBlocks ) if (previousTotal === 0) return { previousTotal: undefined, dropOffRate: undefined } const totalDroppedUser = previousTotal - totalAnswers return { totalDroppedUser, dropOffRate: Math.round((totalDroppedUser / previousTotal) * 100), } }, [ currentBlock?.blockId, currentBlock?.total, publishedTypebot, totalAnswersInBlocks, ]) const sourceTop = useMemo(() => { const blockTop = currentBlock?.blockId ? sourceEndpoints.get(currentBlock.blockId)?.y : undefined if (blockTop) return blockTop const block = publishedTypebot?.groups .flatMap((group) => group.blocks) .find((block) => block.id === currentBlock?.blockId) if (!block || !blockHasItems(block)) return 0 const itemId = block.items.at(-1)?.id if (!itemId) return 0 return sourceEndpoints.get(itemId)?.y }, [currentBlock?.blockId, publishedTypebot?.groups, sourceEndpoints]) const endpointCoordinates = useMemo(() => { const groupId = publishedTypebot?.groups.find((group) => group.blocks.some((block) => block.id === currentBlock?.blockId) )?.id if (!groupId) return undefined const coordinates = groupsCoordinates[groupId] if (!coordinates) return undefined return computeSourceCoordinates(coordinates, sourceTop ?? 0) }, [ publishedTypebot?.groups, groupsCoordinates, sourceTop, currentBlock?.blockId, ]) const isLastBlock = useMemo(() => { if (!publishedTypebot) return false const lastBlock = publishedTypebot.groups .find((group) => group.blocks.some((block) => block.id === currentBlock?.blockId) ) ?.blocks.at(-1) return lastBlock?.id === currentBlock?.blockId }, [publishedTypebot, currentBlock?.blockId]) if (!endpointCoordinates) return null return ( <> 1 ? 's' : '' } left. This represents ${dropOffRate}% of the users who saw this input.` : 'Upgrade your plan to PRO to reveal drop-off rate.' } placement="top" > {isWorkspaceProPlan ? ( dropOffRate ) : ( X )} % {isWorkspaceProPlan ? ( totalDroppedUser ) : ( NN )}{' '} user{(totalDroppedUser ?? 2) > 1 ? 's' : ''} ) }