Skip to content

Commit

Permalink
Implement budget alerts & limit (#551)
Browse files Browse the repository at this point in the history
Adds the ability for teams to set up a budget limit and a budget alert.

The following two sections were added under the dashboards `Usage` tab:
1. Section for setting a `Billing Limit` in `$ (USD)` which blocks the
team when reached & sends notifications along the way to the teams
primary email address
2. Section for settings a `Billing Alert` in `$ (USD)` which sends a
notification to the teams primary email address when reached
  • Loading branch information
ben-fornefeld authored Jan 24, 2025
2 parents 4520df8 + 04f223f commit fb0dcb7
Show file tree
Hide file tree
Showing 8 changed files with 554 additions and 129 deletions.
24 changes: 21 additions & 3 deletions apps/web/src/app/(dashboard)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Suspense, useEffect, useState } from 'react'
import { useLocalStorage } from 'usehooks-ts'

import {
ArrowUpRight,
BarChart,
CreditCard,
FileText,
Expand All @@ -27,6 +28,7 @@ import { PersonalContent } from '@/components/Dashboard/Personal'
import { TemplatesContent } from '@/components/Dashboard/Templates'
import { SandboxesContent } from '@/components/Dashboard/Sandboxes'
import { DeveloperContent } from '@/components/Dashboard/Developer'
import { Button } from '@/components/Button'

function redirectToCurrentURL() {
const url = typeof window !== 'undefined' ? window.location.href : undefined
Expand Down Expand Up @@ -149,11 +151,25 @@ const Dashboard = ({ user }) => {
currentTeam={currentTeam}
setCurrentTeam={setCurrentTeam}
setTeams={setTeams}
domainState={domainState}
/>
<div className="flex-1 md:pl-10 pb-16">
<h2 className="text-2xl mb-2 font-bold">
{selectedItem[0].toUpperCase() + selectedItem.slice(1)}
</h2>
<div className="flex flex-col w-full">
<h2 className="text-2xl mb-2 font-bold">
{selectedItem[0].toUpperCase() + selectedItem.slice(1)}
</h2>
{currentTeam.is_blocked && (
<Button
onClick={() => setSelectedItem('usage')}
variant="desctructive"
className="mb-3 dark:ring-0 w-fit dark:bg-red-900/20 whitespace-break-spaces rounded-lg h-8 items-center text-xs"
>
Usage is blocked: {currentTeam.blocked_reason}.
<ArrowUpRight className="w-4 h-4" />
</Button>
)}
</div>

<div className="border border-white/5 w-full h-[1px] mb-10" />
<MainContent
selectedItem={selectedItem}
Expand All @@ -178,6 +194,7 @@ const Sidebar = ({
currentTeam,
setCurrentTeam,
setTeams,
domainState,
}) => (
<div className="md:h-full md:w-48 space-y-2 pb-10 md:pb-0">
<AccountSelector
Expand All @@ -186,6 +203,7 @@ const Sidebar = ({
currentTeam={currentTeam}
setCurrentTeam={setCurrentTeam}
setTeams={setTeams}
domainState={domainState}
/>

<div className="flex flex-row justify-center space-x-4 md:space-x-0 md:space-y-2 md:flex-col">
Expand Down
8 changes: 5 additions & 3 deletions apps/web/src/components/Dashboard/AccountSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@ import {
} from '../ui/alert-dialog'
import { useState } from 'react'
import { Button } from '../Button'

const createTeamUrl = `${process.env.NEXT_PUBLIC_BILLING_API_URL}/teams`
import { getBillingUrl } from '@/app/(dashboard)/dashboard/utils'

export const AccountSelector = ({
teams,
user,
currentTeam,
setCurrentTeam,
setTeams,
domainState,
}) => {
const [domain] = domainState

const [isDialogOpen, setIsDialogOpen] = useState(false)
const [teamName, setTeamName] = useState('')
const closeDialog = () => setIsDialogOpen(false)

const createNewTeam = async () => {
const res = await fetch(createTeamUrl, {
const res = await fetch(getBillingUrl(domain, '/teams'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
Loading

0 comments on commit fb0dcb7

Please sign in to comment.