import { ChevronRight } from 'lucide-react' import Link from 'next/link' import { cn } from 'ui' import { UpgradePlanButton } from '@/components/ui/UpgradePlanButton' import { PricingMetric } from '@/data/analytics/org-daily-stats-query' import { OrgMetricsUsage, useOrgUsageQuery } from '@/data/usage/org-usage-query' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { useTrack } from '@/lib/telemetry/track' type MetricUnit = 'gigabytes' | 'count' type MetricConfig = { key: PricingMetric label: string unit: MetricUnit /** Anchor id of the matching section on the org usage page. */ anchor: string } const METRICS: MetricConfig[] = [ { key: PricingMetric.EGRESS, label: 'Egress', unit: 'gigabytes', anchor: 'egress' }, { key: PricingMetric.DATABASE_SIZE, label: 'Database size', unit: 'gigabytes', anchor: 'databaseSize', }, { key: PricingMetric.MONTHLY_ACTIVE_USERS, label: 'Monthly active users', unit: 'count', anchor: 'mau', }, { key: PricingMetric.STORAGE_SIZE, label: 'File storage', unit: 'gigabytes', anchor: 'storageSize', }, ] const formatGigabytes = (value: number) => { if (value === 0) return '0 GB' if (value < 1) return `${(value * 1000).toFixed(0)} MB` return `${value.toFixed(value < 10 ? 2 : 1)} GB` } const formatGigabyteLimit = (limit: number) => { if (limit < 1) return `${(limit * 1000).toFixed(0)} MB` return `${limit} GB` } // Show counts in full with thousands separators (e.g. `50,000`) rather than abbreviated // (`50k`), to match the pricing page and avoid ambiguity around plan limits. const formatCount = (value: number) => value.toLocaleString() const formatValue = (value: number, unit: MetricUnit) => unit === 'gigabytes' ? formatGigabytes(value) : formatCount(value) const formatLimit = (limit: number, unit: MetricUnit) => unit === 'gigabytes' ? formatGigabyteLimit(limit) : formatCount(limit) const RING_RADIUS = 7 const RING_CIRCUMFERENCE = 2 * Math.PI * RING_RADIUS const ProgressRing = ({ ratio, isOver, isApproaching, }: { ratio: number isOver: boolean isApproaching: boolean }) => { const clamped = Math.max(0, Math.min(1, ratio)) const offset = RING_CIRCUMFERENCE * (1 - clamped) return ( ) } // The upgrade CTA placement experiment variant this card represents. Used as the telemetry // `source` + `placement` value. Kept as a constant so the tracking stays explicit. const PLACEMENT = 'org_projects_list' const CompactMetricRow = ({ usageItem, config, orgSlug, }: { usageItem: OrgMetricsUsage config: MetricConfig orgSlug: string }) => { const current = usageItem.usage ?? 0 const limit = usageItem.pricing_free_units ?? 0 const ratio = limit > 0 ? current / limit : 0 const isOver = limit > 0 && current >= limit const isApproaching = limit > 0 && ratio >= 0.8 && !isOver return (
Current billing cycle