-
Notifications
You must be signed in to change notification settings - Fork 326
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial Support for paywalls (#10202)
This PR introduces: 1. Set of Paywall components: PaywallButton, PaywallDialog 2. Adds Devtools 3. Implement Paywall Configuration This PR partially depends on #10199
- Loading branch information
1 parent
1b7b24f
commit 04551f4
Showing
26 changed files
with
1,084 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,3 +37,17 @@ export const ALL_PATHS_REGEX = new RegExp( | |
// === Constants related to URLs === | ||
|
||
export const SEARCH_PARAMS_PREFIX = 'cloud-ide_' | ||
|
||
/** | ||
* Build a Subscription URL for a given plan. | ||
*/ | ||
export function getUpgradeURL(plan: string): string { | ||
return SUBSCRIBE_PATH + '?plan=' + plan | ||
} | ||
|
||
/** | ||
* Build a Subscription URL for contacting sales. | ||
*/ | ||
export function getContactSalesURL(): string { | ||
return 'mailto:[email protected]?subject=Upgrading%20to%20Organization%20Plan' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
app/ide-desktop/lib/dashboard/src/components/Paywall/ContextMenuEntry.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/** | ||
* @file | ||
* | ||
* A context menu entry that opens a paywall dialog. | ||
*/ | ||
|
||
import * as React from 'react' | ||
|
||
import LockIcon from 'enso-assets/lock.svg' | ||
|
||
import type * as billingHooks from '#/hooks/billing' | ||
|
||
import * as modalProvider from '#/providers/ModalProvider' | ||
|
||
import type * as contextMenuEntry from '#/components/ContextMenuEntry' | ||
import ContextMenuEntryBase from '#/components/ContextMenuEntry' | ||
|
||
import * as paywallDialog from './PaywallDialog' | ||
|
||
/** | ||
* Props for {@link ContextMenuEntry}. | ||
*/ | ||
export interface ContextMenuEntryProps | ||
extends Omit<contextMenuEntry.ContextMenuEntryProps, 'doAction' | 'isDisabled'> { | ||
readonly feature: billingHooks.PaywallFeatureName | ||
} | ||
|
||
/** | ||
* A context menu entry that opens a paywall dialog. | ||
*/ | ||
export function ContextMenuEntry(props: ContextMenuEntryProps) { | ||
const { feature, ...rest } = props | ||
const { setModal } = modalProvider.useSetModal() | ||
|
||
return ( | ||
<> | ||
<ContextMenuEntryBase | ||
{...rest} | ||
icon={LockIcon} | ||
doAction={() => { | ||
setModal( | ||
<paywallDialog.PaywallDialog modalProps={{ defaultOpen: true }} feature={feature} /> | ||
) | ||
}} | ||
/> | ||
</> | ||
) | ||
} |
67 changes: 67 additions & 0 deletions
67
app/ide-desktop/lib/dashboard/src/components/Paywall/PaywallAlert.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** | ||
* @file | ||
* | ||
* A paywall alert. | ||
*/ | ||
|
||
import * as React from 'react' | ||
|
||
import clsx from 'clsx' | ||
|
||
import LockIcon from 'enso-assets/lock.svg' | ||
|
||
import type * as billingHooks from '#/hooks/billing' | ||
|
||
import * as ariaComponents from '#/components/AriaComponents' | ||
import * as paywall from '#/components/Paywall' | ||
import SvgMask from '#/components/SvgMask' | ||
|
||
/** | ||
* Props for {@link PaywallAlert}. | ||
*/ | ||
export interface PaywallAlertProps extends Omit<ariaComponents.AlertProps, 'children'> { | ||
readonly feature: billingHooks.PaywallFeatureName | ||
readonly label: string | ||
readonly showUpgradeButton?: boolean | ||
readonly upgradeButtonProps?: Omit<paywall.UpgradeButtonProps, 'feature'> | ||
} | ||
|
||
/** | ||
* A paywall alert. | ||
*/ | ||
export function PaywallAlert(props: PaywallAlertProps) { | ||
const { | ||
label, | ||
showUpgradeButton = true, | ||
feature, | ||
upgradeButtonProps, | ||
className, | ||
...alertProps | ||
} = props | ||
|
||
return ( | ||
<ariaComponents.Alert | ||
variant="outline" | ||
size="small" | ||
rounded="large" | ||
className={clsx('border border-primary/20', className)} | ||
{...alertProps} | ||
> | ||
<div className="flex items-center gap-2"> | ||
<SvgMask src={LockIcon} className="h-5 w-5 flex-none text-primary" /> | ||
|
||
<ariaComponents.Text> | ||
{label}{' '} | ||
{showUpgradeButton && ( | ||
<paywall.UpgradeButton | ||
feature={feature} | ||
variant="link" | ||
size="small" | ||
{...upgradeButtonProps} | ||
/> | ||
)} | ||
</ariaComponents.Text> | ||
</div> | ||
</ariaComponents.Alert> | ||
) | ||
} |
54 changes: 54 additions & 0 deletions
54
app/ide-desktop/lib/dashboard/src/components/Paywall/PaywallDialog.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/** | ||
* @file | ||
* | ||
* A dialog that prompts the user to upgrade to a paid plan. | ||
*/ | ||
|
||
import * as React from 'react' | ||
|
||
import * as billingHooks from '#/hooks/billing' | ||
|
||
import * as textProvider from '#/providers/TextProvider' | ||
|
||
import * as ariaComponents from '#/components/AriaComponents' | ||
|
||
import * as components from './components' | ||
import * as upgradeButton from './UpgradeButton' | ||
|
||
/** | ||
* Props for a {@link PaywallDialog}. | ||
*/ | ||
export interface PaywallDialogProps extends ariaComponents.DialogProps { | ||
readonly feature: billingHooks.PaywallFeatureName | ||
} | ||
|
||
/** | ||
* A dialog that prompts the user to upgrade to a paid plan. | ||
*/ | ||
export function PaywallDialog(props: PaywallDialogProps) { | ||
const { feature, type = 'modal', title, ...dialogProps } = props | ||
|
||
const { getText } = textProvider.useText() | ||
const { getFeature } = billingHooks.usePaywallFeatures() | ||
|
||
const { bulletPointsTextId, label, descriptionTextId } = getFeature(feature) | ||
|
||
return ( | ||
<ariaComponents.Dialog type={type} title={title ?? getText(label)} {...dialogProps}> | ||
<div className="flex flex-col"> | ||
<components.PaywallLock feature={feature} className="mb-2" /> | ||
|
||
<ariaComponents.Text variant="subtitle">{getText(descriptionTextId)}</ariaComponents.Text> | ||
|
||
<components.PaywallBulletPoints bulletPointsTextId={bulletPointsTextId} className="my-2" /> | ||
|
||
<upgradeButton.UpgradeButton | ||
feature={feature} | ||
rounded="xlarge" | ||
className="mt-2" | ||
size="large" | ||
/> | ||
</div> | ||
</ariaComponents.Dialog> | ||
) | ||
} |
36 changes: 36 additions & 0 deletions
36
app/ide-desktop/lib/dashboard/src/components/Paywall/PaywallDialogButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/** | ||
* @file | ||
* | ||
* A button that opens a paywall dialog when clicked. | ||
*/ | ||
|
||
import * as React from 'react' | ||
|
||
import * as ariaComponents from '#/components/AriaComponents' | ||
|
||
import * as components from './components' | ||
import * as paywallDialog from './PaywallDialog' | ||
|
||
/** | ||
* Props for a {@link PaywallDialogButton}. | ||
*/ | ||
// eslint-disable-next-line no-restricted-syntax | ||
export type PaywallDialogButtonProps = components.PaywallButtonProps & { | ||
readonly dialogProps?: paywallDialog.PaywallDialogProps | ||
readonly dialogTriggerProps?: ariaComponents.DialogTriggerProps | ||
} | ||
|
||
/** | ||
* A button that opens a paywall dialog when clicked | ||
*/ | ||
export function PaywallDialogButton(props: PaywallDialogButtonProps) { | ||
const { feature, dialogProps, dialogTriggerProps, ...buttonProps } = props | ||
|
||
return ( | ||
<ariaComponents.DialogTrigger {...dialogTriggerProps}> | ||
<components.PaywallButton feature={feature} {...buttonProps} /> | ||
|
||
<paywallDialog.PaywallDialog feature={feature} {...dialogProps} /> | ||
</ariaComponents.DialogTrigger> | ||
) | ||
} |
56 changes: 56 additions & 0 deletions
56
app/ide-desktop/lib/dashboard/src/components/Paywall/PaywallScreen.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* @file | ||
* | ||
* A screen that shows a paywall. | ||
*/ | ||
|
||
import * as React from 'react' | ||
|
||
import * as tw from 'tailwind-merge' | ||
|
||
import * as billingHooks from '#/hooks/billing' | ||
|
||
import * as textProvider from '#/providers/TextProvider' | ||
|
||
import * as ariaComponents from '#/components/AriaComponents' | ||
|
||
import * as components from './components' | ||
import * as upgradeButton from './UpgradeButton' | ||
|
||
/** | ||
* Props for a {@link PaywallScreen}. | ||
*/ | ||
export interface PaywallScreenProps { | ||
readonly feature: billingHooks.PaywallFeatureName | ||
readonly className?: string | ||
} | ||
|
||
/** | ||
* A screen that shows a paywall. | ||
*/ | ||
export function PaywallScreen(props: PaywallScreenProps) { | ||
const { feature, className } = props | ||
const { getText } = textProvider.useText() | ||
|
||
const { getFeature } = billingHooks.usePaywallFeatures() | ||
|
||
const { bulletPointsTextId, descriptionTextId } = getFeature(feature) | ||
|
||
return ( | ||
<div className={tw.twMerge('flex flex-col items-start', className)}> | ||
<components.PaywallLock feature={feature} /> | ||
|
||
<ariaComponents.Text.Heading level="2"> | ||
{getText('paywallScreenTitle')} | ||
</ariaComponents.Text.Heading> | ||
|
||
<ariaComponents.Text balance variant="subtitle" className="mt-1 max-w-[720px]"> | ||
{getText(descriptionTextId)} | ||
</ariaComponents.Text> | ||
|
||
<components.PaywallBulletPoints bulletPointsTextId={bulletPointsTextId} className="my-3" /> | ||
|
||
<upgradeButton.UpgradeButton feature={feature} className="mt-0.5 min-w-36" /> | ||
</div> | ||
) | ||
} |
Oops, something went wrong.