Skip to content

Commit

Permalink
feat: first PR for Usage dashboard (#26807)
Browse files Browse the repository at this point in the history
  • Loading branch information
patricio-posthog authored Jan 3, 2025
1 parent c40b194 commit 1b9aa47
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 3 deletions.
11 changes: 9 additions & 2 deletions frontend/src/layout/navigation/TopBar/AccountPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import {
import { LemonButtonPropsBase } from '@posthog/lemon-ui'
import clsx from 'clsx'
import { useActions, useValues } from 'kea'
import { FEATURE_FLAGS } from 'lib/constants'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { ProfilePicture } from 'lib/lemon-ui/ProfilePicture'
import { UploadedLogo } from 'lib/lemon-ui/UploadedLogo'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import { inviteLogic } from 'scenes/settings/organization/inviteLogic'
import { ThemeSwitcher } from 'scenes/settings/user/ThemeSwitcher'
Expand Down Expand Up @@ -212,6 +214,7 @@ export function AccountPopoverOverlay(): JSX.Element {
const { openSidePanel } = useActions(sidePanelStateLogic)
const { preflight, isCloudOrDev, isCloud } = useValues(preflightLogic)
const { closeAccountPopover } = useActions(navigationLogic)
const { featureFlags } = useValues(featureFlagLogic)

return (
<>
Expand All @@ -223,12 +226,16 @@ export function AccountPopoverOverlay(): JSX.Element {
{isCloudOrDev ? (
<LemonButton
onClick={closeAccountPopover}
to={urls.organizationBilling()}
to={
featureFlags[FEATURE_FLAGS.BILLING_USAGE_DASHBOARD]
? urls.organizationBillingSection('overview')
: urls.organizationBilling()
}
icon={<IconReceipt />}
fullWidth
data-attr="top-menu-item-billing"
>
Billing
{featureFlags[FEATURE_FLAGS.BILLING_USAGE_DASHBOARD] ? 'Billing & Usage' : 'Billing'}
</LemonButton>
) : null}
<InviteMembersButton />
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export const FEATURE_FLAGS = {
BILLING_SKIP_FORECASTING: 'billing-skip-forecasting', // owner: @zach
EXPERIMENT_STATS_V2: 'experiment-stats-v2', // owner: @danielbachhuber #team-experiments
WEB_ANALYTICS_PERIOD_COMPARISON: 'web-analytics-period-comparison', // owner: @rafaeelaudibert #team-web-analytics
BILLING_USAGE_DASHBOARD: 'billing-usage-dashboard', // owner: @pato
WEB_ANALYTICS_CONVERSION_GOAL_FILTERS: 'web-analytics-conversion-goal-filters', // owner: @rafaeelaudibert #team-web-analytics
CDP_ACTIVITY_LOG_NOTIFICATIONS: 'cdp-activity-log-notifications', // owner: #team-cdp
COOKIELESS_SERVER_HASH_MODE_SETTING: 'cookieless-server-hash-mode-setting', // owner: @robbie-c #team-web-analytics
Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/appScenes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const appScenes: Record<Scene, () => any> = {
[Scene.Signup]: () => import('./authentication/signup/SignupContainer'),
[Scene.InviteSignup]: () => import('./authentication/InviteSignup'),
[Scene.Billing]: () => import('./billing/Billing'),
[Scene.BillingSection]: () => import('./billing/BillingSection'),
[Scene.BillingAuthorizationStatus]: () => import('./billing/AuthorizationStatus'),
[Scene.Login]: () => import('./authentication/Login'),
[Scene.Login2FA]: () => import('./authentication/Login2FA'),
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/scenes/billing/BillingOverview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { LemonBanner } from '@posthog/lemon-ui'

export function BillingOverview(): JSX.Element {
return (
<div>
<h2>Billing Overview</h2>
<LemonBanner type="info">Overview section under construction</LemonBanner>
</div>
)
}
62 changes: 62 additions & 0 deletions frontend/src/scenes/billing/BillingSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import './Billing.scss'

import { LemonButton } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { router } from 'kea-router'
import { useEffect } from 'react'
import { SceneExport } from 'scenes/sceneTypes'
import { urls } from 'scenes/urls'

import { billingLogic } from './billingLogic'
import { BillingOverview } from './BillingOverview'
import { BillingUsage } from './BillingUsage'

export const scene: SceneExport = {
component: BillingSection,
logic: billingLogic,
}

export function BillingSection(): JSX.Element {
const { location } = useValues(router)
const { push } = useActions(router)

const activeSection = location.pathname.endsWith('/usage') ? 'usage' : 'overview'

useEffect(() => {
if (location.pathname === '/organization/billing') {
push(urls.organizationBillingSection('overview'))
}
}, [location.pathname])

return (
<div className="flex gap-8 items-start mt-0">
<div className="sticky top-16 flex-shrink-0 w-1/5 min-w-56 max-w-80 [.SidePanel3000_&]:top-0">
<ul className="space-y-px">
<li>
<LemonButton
onClick={() => push(urls.organizationBillingSection('overview'))}
active={activeSection === 'overview'}
size="small"
fullWidth
>
Overview
</LemonButton>
</li>
<li>
<LemonButton
onClick={() => push(urls.organizationBillingSection('usage'))}
active={activeSection === 'usage'}
size="small"
fullWidth
>
Usage
</LemonButton>
</li>
</ul>
</div>
<div className="flex-1 w-full space-y-2 min-w-0">
{activeSection === 'overview' ? <BillingOverview /> : <BillingUsage />}
</div>
</div>
)
}
10 changes: 10 additions & 0 deletions frontend/src/scenes/billing/BillingUsage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { LemonBanner } from '@posthog/lemon-ui'

export function BillingUsage(): JSX.Element {
return (
<div>
<h2>Usage Details</h2>
<LemonBanner type="info">Usage section under construction</LemonBanner>
</div>
)
}
2 changes: 2 additions & 0 deletions frontend/src/scenes/billing/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ export type BillingGaugeItemType = {
value: number
top: boolean
}

export type BillingSectionId = 'overview' | 'usage'
1 change: 1 addition & 0 deletions frontend/src/scenes/sceneTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export enum Scene {
AsyncMigrations = 'AsyncMigrations',
DeadLetterQueue = 'DeadLetterQueue',
Billing = 'Billing',
BillingSection = 'BillingSection',
BillingAuthorizationStatus = 'BillingAuthorizationStatus',
SavedInsights = 'SavedInsights',
ToolbarLaunch = 'ToolbarLaunch',
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/scenes/scenes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
ReplayTabs,
} from '~/types'

import { BillingSectionId } from './billing/types'
export const emptySceneParams = { params: {}, searchParams: {}, hashParams: {} }

export const preloadedScenes: Record<string, LoadedScene> = {
Expand Down Expand Up @@ -375,6 +376,11 @@ export const sceneConfigurations: Record<Scene, SceneConfig> = {
organizationBased: true,
defaultDocsPath: '/pricing',
},
[Scene.BillingSection]: {
name: 'Billing',
hideProjectNotice: true,
organizationBased: true,
},
[Scene.BillingAuthorizationStatus]: {
hideProjectNotice: true,
organizationBased: true,
Expand Down Expand Up @@ -592,6 +598,7 @@ export const routes: Record<string, Scene> = {
[urls.max()]: Scene.Max,
[urls.projectCreateFirst()]: Scene.ProjectCreateFirst,
[urls.organizationBilling()]: Scene.Billing,
[urls.organizationBillingSection(':section' as BillingSectionId)]: Scene.BillingSection,
[urls.billingAuthorizationStatus()]: Scene.BillingAuthorizationStatus,
[urls.organizationCreateFirst()]: Scene.OrganizationCreateFirst,
[urls.organizationCreationConfirm()]: Scene.OrganizationCreationConfirm,
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/scenes/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import {
SDKKey,
} from '~/types'

import { BillingSectionId } from './billing/types'
import { OnboardingStepKey } from './onboarding/onboardingLogic'
import { SettingId, SettingLevelId, SettingSectionId } from './settings/types'
import { SurveysTabs } from './surveys/surveysLogic'

/**
* To add a new URL to the front end:
* - add a URL function here
Expand Down Expand Up @@ -210,6 +210,8 @@ export const urls = {
// Cloud only
organizationBilling: (products?: ProductKey[]): string =>
`/organization/billing${products && products.length ? `?products=${products.join(',')}` : ''}`,
organizationBillingSection: (section: BillingSectionId = 'overview'): string =>
combineUrl(`/organization/billing/${section}`).url,
billingAuthorizationStatus: (): string => `/billing/authorization_status`,
// Self-hosted only
instanceStatus: (): string => '/instance/status',
Expand Down

0 comments on commit 1b9aa47

Please sign in to comment.