import {useMemo} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import capitalize from 'lodash/capitalize'; import {Button} from 'sentry/components/button'; import ExternalLink from 'sentry/components/links/externalLink'; import {Tooltip} from 'sentry/components/tooltip'; import {IconAdd} from 'sentry/icons'; import {t, tct} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {DataCategory} from 'sentry/types/core'; import {PlanTier, type Subscription} from 'getsentry/types'; import {displayPrice} from 'getsentry/views/amCheckout/utils'; import {Card, HalvedGrid} from './components/styles'; import type {SpendAllocation} from './components/types'; import {bigNumFormatter, BigNumUnits} from './utils'; type Props = { createRootAllocation: (e: React.MouseEvent) => void; selectedMetric: string; subscription: Subscription; rootAllocation?: SpendAllocation; }; function RootAllocationCard({ createRootAllocation, rootAllocation, selectedMetric, subscription, }: Props) { const theme = useTheme(); const availableEvents = useMemo(() => { return rootAllocation ? Math.max(rootAllocation.reservedQuantity - rootAllocation.consumedQuantity, 0) : 0; }, [rootAllocation]); const metricUnit = useMemo(() => { return selectedMetric === DataCategory.ATTACHMENTS ? BigNumUnits.KILO_BYTES : BigNumUnits.NUMBERS; }, [selectedMetric]); return ( {!rootAllocation && ( There is currently no organization-level allocation for this billing metric.

An organization-level allocation is required to distribute allocations to projects.

Click the button to create one and to enable spend allocation for{' '} {selectedMetric}.
)} {rootAllocation && (
{t('Un-Allocated ')} {capitalize(selectedMetric)}  {t('Pool')}
{tct( `The un-allocated pool represents the remaining Reserved Volume available for your projects. Excess project consumption will first consume events from your un-allocated pool, and then from your [odLink] volume, if available`, { odLink: ( {subscription.planTier === PlanTier.AM3 ? 'Pay-as-you-go' : 'On-Demand'} ), } )}
$ SpendEvent VolumeAvailable {rootAllocation.costPerItem === 0 ? ( -- ) : ( displayPrice({ cents: rootAllocation.costPerItem * availableEvents, }) )} {bigNumFormatter(availableEvents, 2, metricUnit)} Consumed {/* TODO: include OD costs if enabled */} {rootAllocation.costPerItem === 0 ? ( -- ) : ( displayPrice({ cents: rootAllocation.costPerItem * Math.min( rootAllocation.reservedQuantity, rootAllocation.consumedQuantity ), }) )} {bigNumFormatter( Math.min( rootAllocation.reservedQuantity, rootAllocation.consumedQuantity ), 2, metricUnit )} {rootAllocation.consumedQuantity > rootAllocation.reservedQuantity && (   ( {bigNumFormatter( rootAllocation.consumedQuantity - rootAllocation.reservedQuantity, 2, metricUnit )}{' '} over) )}
)}
); } export default RootAllocationCard; const Header = styled('div')` display: flex; color: ${p => p.theme.gray400}; font-weight: 600; font-size: ${p => p.theme.fontSizeLarge}; padding: ${space(1)}; `; const Body = styled('div')` padding: ${space(1)}; `; const RootAllocation = styled('div')` margin: ${space(2)} 0; `; const CreateRoot = styled('div')` display: flex; justify-content: space-between; `; const EnableRoot = styled('div')` grid-column: -auto / span 1; grid-area: bt; display: flex; justify-content: center; align-items: center; `; const NoRootInfo = styled('div')` margin-right: ${space(2)}; `; const Table = styled('table')` tr:nth-child(even) { background-color: ${p => p.theme.bodyBackground}; } `; const THead = styled('th')` padding: ${space(1)}; `; const Cell = styled('td')` padding: ${space(1)}; `;