Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f4cb8e9
clients/web: Add manual credit granting to customer meters
strandhvilliam Oct 13, 2026
9f75d21
clients/web: Add credits from customer usage table rows
strandhvilliam Oct 13, 2026
086d17b
clients/web: Simplify the add credits panel
strandhvilliam Oct 13, 2026
82f08b8
clients/web: Tidy the add credits panel
strandhvilliam Oct 13, 2026
f0ddaf4
clients/web: Name the duplicate credit check in the add credits panel
strandhvilliam Oct 13, 2026
9846e67
clients/web: Tighten the add credits panel UX
strandhvilliam Oct 13, 2026
1714c23
clients/web: Keep the add credits summary a fixed height
strandhvilliam Oct 13, 2026
f25a626
clients/web: Name the customer in the add credits panel
strandhvilliam Oct 13, 2026
bf00935
modify customer-meter header aligment
strandhvilliam Oct 13, 2026
00bfc24
clients/web: Right-align the add credits panel buttons
strandhvilliam Oct 13, 2026
ea1a673
Poll for changes
strandhvilliam Oct 14, 2026
36d7aa6
clients/web: Match the usage table's subscription and wait for pricin…
strandhvilliam Oct 14, 2026
ad0a7d8
clients/web: Wrap the customer meter toolbar and keep the customer fa…
strandhvilliam Oct 14, 2026
d200195
clients/web: Use the split credit request schema
cursoragent Oct 14, 2026
453730c
remove polling and config_as_code flag
strandhvilliam Oct 14, 2026
19427d6
copy update
strandhvilliam Oct 15, 2026
afe1322
server/customer_meter: Balance the customer meter when crediting
pieterbeulque Oct 15, 2026
0169da5
server/customer_meter: Re-balance after crediting a locked customer m…
pieterbeulque Oct 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client'

import { AddCreditsButton } from '@/components/Customer/AddCredits/AddCreditsButton'
import { MasterDetailLayoutContent } from '@/components/Layout/MasterDetailLayout'
import DateRangePicker, {
DateRangeInterval,
Expand All @@ -25,7 +26,6 @@ import { formatCurrency } from '@polar-sh/currency'
import FormattedInterval from '@polar-sh/ui/components/atoms/FormattedInterval'
import ShadowBox from '@polar-sh/ui/components/atoms/ShadowBox'
import { endOfMonth, startOfMonth, subMonths } from 'date-fns'
import { Button } from '@polar-sh/orbit'
import {
Card,
CardContent,
Expand All @@ -35,7 +35,8 @@ import Link from 'next/link'
import { parseAsIsoDateTime, parseAsStringLiteral, useQueryState } from 'nuqs'
import { useInViewport } from '@/hooks/utils'
import { useCallback, useEffect, useMemo } from 'react'
import { Avatar } from '@polar-sh/orbit'
import { Text } from '@polar-sh/orbit'
import { Box } from '@polar-sh/orbit/Box'

interface CustomerMeterPageProps {
organization: schemas['Organization']
Expand Down Expand Up @@ -166,69 +167,69 @@ const CustomerMeterPage = ({
}
}, [customerMeter, unitPrice])

const addCreditsButton = (
<AddCreditsButton
organization={organization}
customer={customer}
meterId={meter.id}
/>
)

return (
<MasterDetailLayoutContent
header={
<>
<div className="flex flex-row items-center gap-4">
<Box alignItems="center" columnGap="l" minWidth={0}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fucking linter rule

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the linter really wanted it, so I made a drive-by divs-to-box refactor 🤷‍♂️

<Link
href={`/dashboard/${organization.slug}/customers/${customer.id}`}
className="dark:text-polar-500 shrink-0 text-gray-400 transition-colors hover:text-gray-900 dark:hover:text-white"
>
<ArrowBackOutlined fontSize="small" />
</Link>
<div className="flex flex-row items-center gap-x-4">
<p className="truncate text-lg font-medium">{meter.name}</p>
{subscription && (
<span className="dark:text-polar-500 text-lg text-gray-500">
{subscription.product.name}
</span>
)}
</div>
</div>
<div className="flex flex-row gap-6">
<Link
href={`/dashboard/${organization.slug}/products/meters/${meter.id}`}
<Box flexDirection="column" minWidth={0}>
<Link
href={`/dashboard/${organization.slug}/products/meters/${meter.id}`}
className="truncate hover:underline"
>
<Text variant="heading-xxs" as="h1">
{meter.name}
</Text>
</Link>
<Text color="muted">
{customer.name || customer.email || 'Customer'}
{subscription && ` · ${subscription.product.name}`}
</Text>
</Box>
<Box
display={{ base: 'flex', md: 'none' }}
marginLeft="auto"
flexShrink={0}
>
<Button>View Meter</Button>
</Link>
<div className="flex flex-row gap-2">
<div>
<IntervalPicker
interval={interval}
onChange={setInterval}
startDate={startDate}
endDate={endDate}
/>
</div>
<DateRangePicker
date={{ from: startDate, to: endDate }}
onDateChange={onDateChange}
additionalIntervals={
billingPeriodInterval ? [billingPeriodInterval] : undefined
}
{addCreditsButton}
</Box>
</Box>
<Box alignItems="center" flexWrap="wrap" gap="s">
<div>
<IntervalPicker
interval={interval}
onChange={setInterval}
startDate={startDate}
endDate={endDate}
/>
</div>
</div>
<DateRangePicker
date={{ from: startDate, to: endDate }}
onDateChange={onDateChange}
additionalIntervals={
billingPeriodInterval ? [billingPeriodInterval] : undefined
}
/>
<Box display={{ base: 'none', md: 'flex' }}>{addCreditsButton}</Box>
</Box>
</>
}
>
<div className="flex flex-col gap-y-8">
<div className="flex flex-row items-center gap-6">
<Avatar
avatar_url={customer.avatar_url}
name={customer.name || customer.email || 'Customer'}
className="h-16 w-16"
/>
<div className="flex flex-col">
<p className="text-lg">
{(customer.name?.length ?? 0) > 0 ? customer.name : '—'}
</p>
<div className="dark:text-polar-500 flex flex-row items-center text-base text-gray-500">
<span>{customer.email ?? '—'}</span>
</div>
</div>
</div>
{customerMeter && (
<div className="flex flex-row flex-wrap gap-4">
{subscription?.current_period_end && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client'

import { useModal } from '@/components/Modal/useModal'
import { useHasPermission } from '@/hooks/permissions'
import { schemas } from '@polar-sh/client'
import { Button, InlineModal } from '@polar-sh/orbit'
import { AddCreditsModal } from './AddCreditsModal'

export const AddCreditsButton = ({
organization,
customer,
meterId,
}: {
organization: schemas['Organization']
customer: schemas['Customer']
meterId: string
}) => {
const { show, hide, isShown } = useModal()
const canManageCustomers = useHasPermission(
organization.id,
'customers:manage',
)

if (!canManageCustomers) return null

return (
<>
<Button onClick={show}>Add credits</Button>
<InlineModal
isShown={isShown}
hide={hide}
modalContent={
<AddCreditsModal
organization={organization}
customer={customer}
meterId={meterId}
onClose={hide}
/>
}
/>
</>
)
}
Loading
Loading