import { PermissionAction } from '@supabase/shared-types/out/constants' import dayjs from 'dayjs' import Link from 'next/link' import { useEffect, useMemo, useState } from 'react' import { useParams } from 'common' import { ScaffoldContainer, ScaffoldContainerLegacy, ScaffoldTitle, } from 'components/layouts/Scaffold' import AlertError from 'components/ui/AlertError' import DateRangePicker from 'components/ui/DateRangePicker' import NoPermission from 'components/ui/NoPermission' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useProjectsQuery } from 'data/projects/projects-query' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { TIME_PERIODS_BILLING, TIME_PERIODS_REPORTS } from 'lib/constants/metrics' import { cn, Listbox } from 'ui' import { Admonition } from 'ui-patterns' import { Restriction } from '../BillingSettings/Restriction' import Activity from './Activity' import Compute from './Compute' import Egress from './Egress' import SizeAndCounts from './SizeAndCounts' import { TotalUsage } from './TotalUsage' const Usage = () => { const { slug, projectRef } = useParams() const [dateRange, setDateRange] = useState() const [selectedProjectRef, setSelectedProjectRef] = useState() const canReadSubscriptions = useCheckPermissions( PermissionAction.BILLING_READ, 'stripe.subscriptions' ) const { data: organization } = useSelectedOrganizationQuery() const { data, isSuccess } = useProjectsQuery() const { data: subscription, error: subscriptionError, isLoading: isLoadingSubscription, isError: isErrorSubscription, isSuccess: isSuccessSubscription, } = useOrgSubscriptionQuery({ orgSlug: slug }) const orgProjects = (data?.projects ?? []).filter( (project) => project.organization_id === organization?.id ) useEffect(() => { if (projectRef && isSuccess && orgProjects !== undefined) { if (orgProjects.find((project) => project.ref === projectRef)) { setSelectedProjectRef(projectRef) } } // [Joshen] Since we're already looking at isSuccess // eslint-disable-next-line react-hooks/exhaustive-deps }, [projectRef, isSuccess]) 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 selectedProject = selectedProjectRef ? orgProjects?.find((it) => it.ref === selectedProjectRef) : undefined if (!canReadSubscriptions) { return ( ) } return ( <> Usage
{isLoadingSubscription && } {isErrorSubscription && ( )} {isSuccessSubscription && ( <> { if (value === 'all-projects') setSelectedProjectRef(undefined) else setSelectedProjectRef(value) }} > All projects {orgProjects?.map((project) => ( {project.name} ))}

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

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

)}
{selectedProjectRef ? ( You are currently viewing usage for the {selectedProject?.name || selectedProjectRef} project. Supabase 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' && ( )} ) } export default Usage