import { PermissionAction } from '@supabase/shared-types/out/constants' import { useParams } from 'common' import dayjs from 'dayjs' import { Check, ChevronDown } from 'lucide-react' import Link from 'next/link' import { useQueryState } from 'nuqs' import { useMemo, useState } from 'react' import { Button, cn, CommandGroup, CommandItem } from 'ui' import { Admonition } from 'ui-patterns' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' import { Restriction } from '../BillingSettings/Restriction' import ActiveCompute from './ActiveCompute' import Activity from './Activity' import Compute from './Compute' import Egress from './Egress' import OrgLogUsage from './OrgLogUsage' import SizeAndCounts from './SizeAndCounts' import { TotalUsage } from './TotalUsage' import { ScaffoldContainer, ScaffoldHeader, ScaffoldSection, ScaffoldTitle, } from '@/components/layouts/Scaffold' import AlertError from '@/components/ui/AlertError' import DateRangePicker from '@/components/ui/DateRangePicker' import NoPermission from '@/components/ui/NoPermission' import { OrganizationProjectSelector } from '@/components/ui/OrganizationProjectSelector' import { useOrgDailyStatsQuery } from '@/data/analytics/org-daily-stats-query' import { useProjectDetailQuery } from '@/data/projects/project-detail-query' import { useOrgSubscriptionQuery } from '@/data/subscriptions/org-subscription-query' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' import { TIME_PERIODS_BILLING, TIME_PERIODS_REPORTS } from '@/lib/constants/metrics' export const Usage = () => { const { slug } = useParams() const [dateRange, setDateRange] = useState() const [selectedProjectRef, setSelectedProjectRef] = useQueryState('projectRef') const [openProjectSelector, setOpenProjectSelector] = useState(false) const { can: canReadSubscriptions, isLoading: isLoadingPermissions } = useAsyncCheckPermissions( PermissionAction.BILLING_READ, 'stripe.subscriptions' ) const { data: subscription, error: subscriptionError, isPending: isLoadingSubscription, isError: isErrorSubscription, isSuccess: isSuccessSubscription, } = useOrgSubscriptionQuery({ orgSlug: slug }) const { data: selectedProject } = useProjectDetailQuery({ ref: selectedProjectRef ?? undefined, }) const billingCycleStart = useMemo(() => { return dayjs.unix(subscription?.current_period_start ?? 0).utc() }, [subscription]) const billingCycleEnd = useMemo(() => { return dayjs.unix(subscription?.current_period_end ?? 0).utc() }, [subscription]) const currentBillingCycleSelected = useMemo(() => { // Selected by default if (!dateRange?.period_start || !dateRange?.period_end) return true return ( dayjs(dateRange.period_start.date).isSame(billingCycleStart) && dayjs(dateRange.period_end.date).isSame(billingCycleEnd) ) }, [dateRange, billingCycleStart, billingCycleEnd]) const startDate = useMemo(() => { // If end date is in future, set end date to now if (!dateRange?.period_start?.date) { return undefined } else { // LF seems to have an issue with the milliseconds, causes infinite loading sometimes return new Date(dateRange?.period_start?.date).toISOString().slice(0, -5) + 'Z' } // eslint-disable-next-line react-hooks/exhaustive-deps }, [dateRange, subscription]) const endDate = useMemo(() => { // If end date is in future, set end date to end of current day if (dateRange?.period_end?.date && dayjs(dateRange.period_end.date).isAfter(dayjs())) { // LF seems to have an issue with the milliseconds, causes infinite loading sometimes // In order to have full days from Prometheus metrics when using 1d interval, // the time needs to be greater or equal than the time of the start date return dayjs().endOf('day').toISOString().slice(0, -5) + 'Z' } else if (dateRange?.period_end?.date) { // LF seems to have an issue with the milliseconds, causes infinite loading sometimes return new Date(dateRange.period_end.date).toISOString().slice(0, -5) + 'Z' } // eslint-disable-next-line react-hooks/exhaustive-deps }, [dateRange, subscription]) const { data: orgDailyStats, error: orgDailyStatsError, isPending: isLoadingOrgDailyStats, isError: isErrorOrgDailyStats, } = useOrgDailyStatsQuery({ orgSlug: slug, projectRef: selectedProjectRef ?? undefined, startDate, endDate, }) return ( <> Usage
{isLoadingSubscription || isLoadingPermissions ? (
) : !canReadSubscriptions ? ( ) : null} {isErrorSubscription && ( )} {isSuccessSubscription && (
{ setSelectedProjectRef(project.ref) }} renderTrigger={({ listboxId, open }) => { return ( ) }} renderRow={(project) => { const isSelected = selectedProjectRef === project.ref return (
{project.name} {isSelected && }
) }} renderActions={() => ( { setOpenProjectSelector(false) setSelectedProjectRef(null) }} onClick={() => { setOpenProjectSelector(false) setSelectedProjectRef(null) }} > All projects {!selectedProjectRef && } )} />

Organization is on the{' '} {subscription.plan.name} Plan

{billingCycleStart.format('DD MMM YYYY')} -{' '} {billingCycleEnd.format('DD MMM YYYY')}

)}
{isErrorOrgDailyStats && ( )} {selectedProject ? ( You are currently viewing usage for the{' '} {selectedProject?.name || selectedProjectRef} {' '} project. Briven uses{' '} organization-level billing {' '} and quotas. For billing purposes, we sum up usage from all your projects. To view your usage quota, set the project filter above back to "All Projects". } /> ) : ( )} {subscription?.plan.id !== 'free' && ( )} {subscription?.plan.id === 'platform' && ( )} {subscription?.plan.id === 'platform' && ( )} ) }