import { ChevronRight } from 'lucide-react' import Link from 'next/link' import { useMemo } from 'react' import { cn, HoverCard, HoverCardContent, HoverCardTrigger } from 'ui' import { billingMetricUnit, formatUsage } from '../helpers' import { Metric, USAGE_APPROACHING_THRESHOLD } from './BillingBreakdown.constants' import { UpgradePlanButton } from '@/components/ui/UpgradePlanButton' import { PricingMetric } from '@/data/analytics/org-daily-stats-query' import type { OrgSubscription } from '@/data/subscriptions/types' import type { OrgUsageResponse } from '@/data/usage/org-usage-query' import { formatCurrency } from '@/lib/helpers' export interface BillingMetricProps { idx: number slug?: string metric: Metric usage: OrgUsageResponse subscription: OrgSubscription relativeToSubscription: boolean className?: string } export const BillingMetric = ({ slug, metric, usage, subscription, relativeToSubscription, className, }: BillingMetricProps) => { const usageMeta = usage.usages.find((x) => x.metric === metric.key) const usageLabel = useMemo(() => { if (!usageMeta) return '' if (relativeToSubscription && usageMeta.available_in_plan === false) { return 'Unavailable in plan' } else if ( (usageMeta.cost && usageMeta.cost > 0) || !relativeToSubscription || usageMeta.unlimited || usageMeta.pricing_free_units === 0 ) { return metric.units === 'bytes' || metric.units === 'gigabytes' ? `${usageMeta.usage.toLocaleString() ?? 0} GB` : usageMeta.usage.toLocaleString() + (metric.unitName ? ` ${metric.unitName}` : '') } else { return metric.units === 'bytes' || metric.units === 'gigabytes' ? `${usageMeta.usage.toLocaleString() ?? 0} / ${usageMeta.pricing_free_units ?? 0} GB` : `${usageMeta.usage.toLocaleString()} / ${usageMeta.pricing_free_units?.toLocaleString()}` + (metric.unitName ? ` ${metric.unitName}` : '') } }, [usageMeta, relativeToSubscription, metric]) const sortedProjectAllocations = useMemo(() => { if (!usageMeta || !usageMeta.project_allocations) return [] return usageMeta.project_allocations.sort((a, b) => b.usage - a.usage) }, [usageMeta]) if (!usageMeta) return null const usageRatio = usageMeta.usage === 0 ? 0 : usageMeta.usage / (usageMeta.pricing_free_units ?? 0) const isUsageBillingEnabled = subscription?.usage_billing_enabled === true const hasLimit = !!usageMeta.unlimited === false const isApproachingLimit = hasLimit && usageRatio >= USAGE_APPROACHING_THRESHOLD const isExceededLimit = relativeToSubscription && hasLimit && usageRatio >= 1 const unit = billingMetricUnit(usageMeta.metric as PricingMetric) const percentageLabel = usageMeta.usage === 0 || usageMeta.pricing_free_units === 0 ? '' : usageRatio < 0.01 ? '(<1%)' : `(${(+(usageRatio * 100).toFixed(0)).toLocaleString()}%)` return (
{metric.anchor ? (

{metric.name}

{usageMeta.available_in_plan && ( )}
{usageLabel}  {relativeToSubscription && usageMeta.cost && usageMeta.cost > 0 ? ( ({formatCurrency(usageMeta.cost)}) ) : usageMeta.available_in_plan && usageMeta.pricing_free_units !== 0 && !usageMeta.unlimited && relativeToSubscription ? ( {percentageLabel} ) : null} ) : (

{metric.name}

{usageLabel}  {relativeToSubscription && usageMeta.cost && usageMeta.cost > 0 ? ( ({formatCurrency(usageMeta.cost)}) ) : usageMeta.available_in_plan && usageMeta.pricing_free_units !== 0 && !usageMeta.unlimited && relativeToSubscription ? ( {percentageLabel} ) : null}
)} {usageMeta.available_in_plan ? (
{relativeToSubscription && !usageMeta.unlimited && usageMeta.pricing_free_units !== 0 ? ( ) : null}
) : (
Upgrade
)}
{usageMeta.available_in_plan && (

{usageMeta.unit_price_desc}

{metric.tip && (

{metric.tip}{' '} {metric.docLink && ( {metric.docLink.title} )}

)} {subscription.usage_billing_enabled === false && relativeToSubscription && (isApproachingLimit || isExceededLimit) && (

Exceeding your plans included usage will lead to restrictions to your project. Upgrade to a usage-based plan or disable the spend cap to avoid restrictions.

)} {sortedProjectAllocations && sortedProjectAllocations.length > 0 && ( {sortedProjectAllocations.map((allocation) => ( ))}
Project Usage
{allocation.name} {formatUsage(usageMeta.metric as PricingMetric, allocation)}
Total{unit && ({unit})} {formatUsage(usageMeta.metric as PricingMetric, { usage: usageMeta.usage_original, })}{' '}
)}
)}
) }