Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 48 additions & 20 deletions clients/apps/web/src/components/Benefit/LicenseKeysPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import {
TabsList,
TabsTrigger,
} from '@polar-sh/ui/components/atoms/Tabs'
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@polar-sh/ui/components/ui/tooltip'
import { RowSelectionState } from '@tanstack/react-table'
import { useRouter, useSearchParams } from 'next/navigation'
import { useCallback, useState } from 'react'
Expand Down Expand Up @@ -176,30 +181,53 @@ export const LicenseKeysPage = ({
</div>
<div className="flex flex-row gap-x-4">
{['disabled', 'revoked'].includes(selectedLicenseKey.status) && (
<Button
onClick={() => handleToggleLicenseKeyStatus('granted')}
loading={statusLoading}
>
Enable
</Button>
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => handleToggleLicenseKeyStatus('granted')}
loading={statusLoading}
>
Enable
</Button>
</TooltipTrigger>
<TooltipContent>
Re-activate this license key to allow validation
</TooltipContent>
</Tooltip>
)}
{selectedLicenseKey.status === 'granted' && (
<Button
onClick={() => handleToggleLicenseKeyStatus('disabled')}
variant="secondary"
loading={statusLoading}
>
Disable
</Button>
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => handleToggleLicenseKeyStatus('disabled')}
variant="secondary"
loading={statusLoading}
>
Disable
</Button>
</TooltipTrigger>
<TooltipContent>
Temporarily deactivate this key. Can be re-enabled later. Use this
for pausing access without permanent revocation.
</TooltipContent>
</Tooltip>
)}
{selectedLicenseKey.status === 'granted' && (
<Button
onClick={() => handleToggleLicenseKeyStatus('revoked')}
loading={statusLoading}
variant="destructive"
>
Revoke
</Button>
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => handleToggleLicenseKeyStatus('revoked')}
loading={statusLoading}
variant="destructive"
>
Revoke
</Button>
</TooltipTrigger>
<TooltipContent>
Permanently revoke this key due to subscription cancellation or
policy violation. Can be re-enabled if needed.
</TooltipContent>
</Tooltip>
)}
</div>
</div>
Expand Down
19 changes: 19 additions & 0 deletions docs/features/benefits/license-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@ Customers can:
* See usage left (if applicable)
* Deactivate activations (if enabled)

Manage License Keys
--------------------------

As an organization administrator, you can manage license keys from your Benefits dashboard. Each license key can have one of three statuses:

### License Key Statuses

* **Granted**: The license key is active and can be validated by the customer
* **Disabled**: The license key is temporarily deactivated. Use this when you need to pause a customer's access without permanently revoking it. The key can be re-enabled at any time. This is useful for:
* Temporary account suspensions
* Payment issues that may be resolved
* Testing and debugging scenarios
* **Revoked**: The license key is deactivated, typically due to subscription cancellation or policy violations. While technically it can be re-enabled, this status indicates a more permanent action tied to the benefit lifecycle. This is typically used when:
* A subscription or purchase is cancelled
* A refund is issued
* Terms of service violations occur

Both **Disabled** and **Revoked** keys will fail validation, preventing customers from using the associated benefits. The key difference is the intent: Disable is for temporary pauses, while Revoke is for permanent or lifecycle-related deactivation.

Integrate API
--------------------

Expand Down
Loading