Skip to content

Commit

Permalink
clients/usage: add usage benefit form under feature flag
Browse files Browse the repository at this point in the history
  • Loading branch information
emilwidlund committed Jan 23, 2025
1 parent 8ac9ab2 commit 582176e
Show file tree
Hide file tree
Showing 12 changed files with 641 additions and 187 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
'use client'

import { CustomerContextView } from '@/components/Customer/CustomerContextView'
import { CustomerUsageView } from '@/components/Customer/CustomerUsageView'
import { DashboardBody } from '@/components/Layout/DashboardLayout'
import MetricChart from '@/components/Metrics/MetricChart'
import { InlineModal } from '@/components/Modal/InlineModal'
import { useModal } from '@/components/Modal/useModal'
import AmountLabel from '@/components/Shared/AmountLabel'
import { SubscriptionModal } from '@/components/Subscriptions/SubscriptionModal'
import { SubscriptionStatusLabel } from '@/components/Subscriptions/utils'
import { usePostHog } from '@/hooks/posthog'
import { useListSubscriptions, useMetrics } from '@/hooks/queries'
import { useOrders } from '@/hooks/queries/orders'
import { Customer, Organization } from '@polar-sh/api'
import Button from '@polar-sh/ui/components/atoms/Button'
import { DataTable } from '@polar-sh/ui/components/atoms/DataTable'
import FormattedDateTime from '@polar-sh/ui/components/atoms/FormattedDateTime'
import ShadowBox from '@polar-sh/ui/components/atoms/ShadowBox'
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from '@polar-sh/ui/components/atoms/Tabs'
import { RowSelectionState } from '@tanstack/react-table'
import Link from 'next/link'
import React, { useEffect, useState } from 'react'
Expand Down Expand Up @@ -77,6 +85,8 @@ const ClientPage: React.FC<ClientPageProps> = ({ organization, customer }) => {
}
}, [selectedSubscription, showSubscriptionModal, hideSubscriptionModal])

const { isFeatureEnabled } = usePostHog()

return (
<DashboardBody
title={
Expand All @@ -88,154 +98,166 @@ const ClientPage: React.FC<ClientPageProps> = ({ organization, customer }) => {
</div>
}
contextView={<CustomerContextView customer={customer} />}
className="gap-12"
>
{metrics.data?.metrics && (
<div className="dark:border-polar-700 rounded-4xl flex flex-col gap-4 border border-gray-200 p-12">
<div className="flex flex-row items-center justify-between gap-4">
<div className="flex flex-col">
<h3 className="text-xl">Revenue</h3>
<span className="dark:text-polar-500 text-gray-500">
Since Customer first was seen
</span>
<Tabs defaultValue="overview" className="flex flex-col">
<TabsList className="mb-8">
<TabsTrigger value="overview">Overview</TabsTrigger>
{isFeatureEnabled('usage_based_billing') && (
<TabsTrigger value="usage">Usage</TabsTrigger>
)}
</TabsList>
<TabsContent value="overview" className="flex flex-col gap-y-12">
{metrics.data?.metrics && (
<div className="dark:border-polar-700 rounded-4xl flex flex-col gap-4 border border-gray-200 p-12">
<div className="flex flex-row items-center justify-between gap-4">
<div className="flex flex-col gap-1">
<h3 className="text-xl">Revenue</h3>
<span className="dark:text-polar-500 text-gray-500">
Since Customer first was seen
</span>
</div>
<h3 className="text-xl">
<AmountLabel
amount={
metrics.data.periods[metrics.data.periods.length - 1]
.cumulative_revenue
}
currency="USD"
/>
</h3>
</div>
<MetricChart
data={metrics.data.periods}
metric={metrics.data.metrics.revenue}
interval="month"
height={300}
/>
</div>
<h3 className="text-xl">
<AmountLabel
amount={
metrics.data.periods[metrics.data.periods.length - 1]
.cumulative_revenue
}
currency="USD"
)}
<ShadowBox className="dark:divide-polar-700 flex flex-col divide-y divide-gray-200 border-gray-200 bg-gray-100 bg-transparent p-0">
<div className="flex flex-col gap-4 p-12">
<h3 className="text-lg">Subscriptions</h3>
<DataTable
data={subscriptions?.items ?? []}
columns={[
{
header: 'Product Name',
accessorKey: 'product.name',
cell: ({ row: { original } }) => (
<span>{original.product.name}</span>
),
},
{
header: 'Status',
accessorKey: 'status',
cell: ({ row: { original } }) => (
<SubscriptionStatusLabel
className="text-xs"
subscription={original}
/>
),
},
{
header: 'Amount',
accessorKey: 'amount',
cell: ({ row: { original } }) =>
original.amount && original.currency ? (
<AmountLabel
amount={original.amount}
currency={original.currency}
interval={original.recurring_interval}
/>
) : (
<span></span>
),
},
]}
isLoading={subscriptionsLoading}
className="text-sm"
onRowSelectionChange={(row) => {
setSelectedSubscriptionState(row)
}}
rowSelection={selectedSubscriptionState}
getRowId={(row) => row.id.toString()}
enableRowSelection
/>
</h3>
</div>
<MetricChart
data={metrics.data.periods}
metric={metrics.data.metrics.revenue}
interval="month"
height={300}
/>
</div>
)}
<ShadowBox className="dark:divide-polar-700 flex flex-col divide-y divide-gray-200 border-gray-200 bg-gray-100 bg-transparent p-0">
<div className="flex flex-col gap-4 p-12">
<h3 className="text-lg">Subscriptions</h3>
<DataTable
data={subscriptions?.items ?? []}
columns={[
{
header: 'Product Name',
accessorKey: 'product.name',
cell: ({ row: { original } }) => (
<span>{original.product.name}</span>
),
},
{
header: 'Status',
accessorKey: 'status',
cell: ({ row: { original } }) => (
<SubscriptionStatusLabel
className="text-xs"
subscription={original}
<InlineModal
modalContent={
<SubscriptionModal
organization={organization}
subscription={selectedSubscription}
/>
),
},
{
header: 'Amount',
accessorKey: 'amount',
cell: ({ row: { original } }) =>
original.amount && original.currency ? (
<AmountLabel
amount={original.amount}
currency={original.currency}
interval={original.recurring_interval}
/>
) : (
<span></span>
),
},
]}
isLoading={subscriptionsLoading}
className="text-sm"
onRowSelectionChange={(row) => {
setSelectedSubscriptionState(row)
}}
rowSelection={selectedSubscriptionState}
getRowId={(row) => row.id.toString()}
enableRowSelection
/>
<InlineModal
modalContent={
<SubscriptionModal
organization={organization}
subscription={selectedSubscription}
}
isShown={isSubscriptionModalShown}
hide={() => {
setSelectedSubscriptionState({})
hideSubscriptionModal()
}}
/>
}
isShown={isSubscriptionModalShown}
hide={() => {
setSelectedSubscriptionState({})
hideSubscriptionModal()
}}
/>
</div>
<div className="flex flex-col gap-4 p-12">
<h3 className="text-lg">Orders</h3>
</div>
<div className="flex flex-col gap-4 p-12">
<h3 className="text-lg">Orders</h3>

<DataTable
data={orders?.items ?? []}
columns={[
{
header: 'Product Name',
accessorKey: 'product.name',
cell: ({ row: { original } }) => (
<Link
href={`/dashboard/${organization?.slug}/sales/${original.id}`}
key={original.id}
>
<span>{original.product.name}</span>
</Link>
),
},
{
header: 'Created At',
accessorKey: 'created_at',
cell: ({ row: { original } }) => (
<span className="dark:text-polar-500 text-xs text-gray-500">
<FormattedDateTime datetime={original.created_at} />
</span>
),
},
{
header: 'Amount',
accessorKey: 'amount',
cell: ({ row: { original } }) => (
<AmountLabel
amount={original.amount}
currency={original.currency}
/>
),
},
{
header: '',
accessorKey: 'action',
cell: ({ row: { original } }) => (
<div className="flex justify-end">
<Link
href={`/dashboard/${organization.slug}/sales/${original.id}`}
>
<Button variant="secondary" size="sm">
View
</Button>
</Link>
</div>
),
},
]}
isLoading={ordersLoading}
className="text-sm"
/>
</div>
</ShadowBox>
<DataTable
data={orders?.items ?? []}
columns={[
{
header: 'Product Name',
accessorKey: 'product.name',
cell: ({ row: { original } }) => (
<Link
href={`/dashboard/${organization?.slug}/sales/${original.id}`}
key={original.id}
>
<span>{original.product.name}</span>
</Link>
),
},
{
header: 'Created At',
accessorKey: 'created_at',
cell: ({ row: { original } }) => (
<span className="dark:text-polar-500 text-xs text-gray-500">
<FormattedDateTime datetime={original.created_at} />
</span>
),
},
{
header: 'Amount',
accessorKey: 'amount',
cell: ({ row: { original } }) => (
<AmountLabel
amount={original.amount}
currency={original.currency}
/>
),
},
{
header: '',
accessorKey: 'action',
cell: ({ row: { original } }) => (
<div className="flex justify-end">
<Link
href={`/dashboard/${organization.slug}/sales/${original.id}`}
>
<Button variant="secondary" size="sm">
View
</Button>
</Link>
</div>
),
},
]}
isLoading={ordersLoading}
className="text-sm"
/>
</div>
</ShadowBox>
</TabsContent>
{isFeatureEnabled('usage_based_billing') && (
<CustomerUsageView customer={customer} />
)}
</Tabs>
</DashboardBody>
)
}
Expand Down
13 changes: 12 additions & 1 deletion clients/apps/web/src/components/Benefit/BenefitForm.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { usePostHog } from '@/hooks/posthog'
import { useDiscordGuild } from '@/hooks/queries'
import { getBotDiscordAuthorizeURL } from '@/utils/auth'
import {
Expand Down Expand Up @@ -35,6 +36,7 @@ import { useFormContext } from 'react-hook-form'
import { DownloadablesBenefitForm } from './Downloadables/BenefitForm'
import { GitHubRepositoryBenefitForm } from './GitHubRepositoryBenefitForm'
import { LicenseKeysBenefitForm } from './LicenseKeys/BenefitForm'
import { UsageBenefitForm } from './Usage/UsageBenefitForm'
import { benefitsDisplayNames } from './utils'

export const NewBenefitForm = ({
Expand Down Expand Up @@ -62,7 +64,7 @@ export const UpdateBenefitForm = ({

interface BenefitFormProps {
organization: Organization
type: BenefitType
type: BenefitType | 'usage'
update?: boolean
}

Expand Down Expand Up @@ -108,6 +110,7 @@ export const BenefitForm = ({
/>

{!update ? <BenefitTypeSelect /> : null}
{type === 'usage' && <UsageBenefitForm update={update} />}
{type === 'custom' && <CustomBenefitForm update={update} />}
{type === 'ads' && <AdsBenefitForm />}
{type === 'discord' && <DiscordBenefitForm />}
Expand Down Expand Up @@ -333,6 +336,9 @@ export const DiscordBenefitForm = () => {

const BenefitTypeSelect = ({}) => {
const { control } = useFormContext<BenefitCustomCreate>()

const { isFeatureEnabled } = usePostHog()

return (
<FormField
control={control}
Expand All @@ -355,6 +361,11 @@ const BenefitTypeSelect = ({}) => {
{benefitsDisplayNames[value]}
</SelectItem>
))}
{isFeatureEnabled('usage_benefits') && (
<SelectItem key="usage" value="usage">
Usage
</SelectItem>
)}
</SelectContent>
</Select>
</FormControl>
Expand Down
Loading

0 comments on commit 582176e

Please sign in to comment.