Skip to content

Commit

Permalink
Billing Page iteration one (#10497)
Browse files Browse the repository at this point in the history
#### Tl;dr
Closes: enso-org/cloud-v2#1158
This PR adds a redirect to the stripe page where the user can manage his subscription

<details><summary>Demo Presentation</summary>
<p>

https://github.com/enso-org/enso/assets/61194245/360fdc7e-46ff-49fa-9936-e5c61fe6f917

</p>
</details>

---

#### Context:
Our first iteration was to add our billing page but after a few iterations, we decided to postpone it in favor of more important features.

#### This Change:
1. creates a link for a private user session
2. redirect the user to that page (open in a new tab) when the user clicks on the billing tab

#### Test Plan:
Go over how you plan to test it. Your test plan should be more thorough the riskier the change is. For major changes, I like to describe how I E2E tested it and will monitor the rollout.

---
  • Loading branch information
MrFlashAccount authored Jul 23, 2024
1 parent 256a01a commit db669a6
Show file tree
Hide file tree
Showing 18 changed files with 165 additions and 64 deletions.
1 change: 0 additions & 1 deletion app/dashboard/e2e/assetsTableFeatures.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ test.test('extra columns should stick to top of scroll container', async ({ page
}
},
})
await actions.reload({ page })

await actions.locateAccessedByProjectsColumnToggle(page).click()
await actions.locateAccessedDataColumnToggle(page).click()
Expand Down
1 change: 1 addition & 0 deletions app/dashboard/src/assets/credit_card.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions app/dashboard/src/components/AriaComponents/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export interface BaseButtonProps<Render>
* Handler that is called when the press is released over the target.
* If the handler returns a promise, the button will be in a loading state until the promise resolves.
*/
readonly onPress?: (event: aria.PressEvent) => Promise<void> | void
readonly onPress?: ((event: aria.PressEvent) => Promise<void> | void) | null | undefined
readonly contentClassName?: string
readonly testId?: string
readonly isDisabled?: boolean
Expand Down Expand Up @@ -244,7 +244,7 @@ export const BUTTON_STYLES = twv.tv({
wrapper: 'relative block',
loader: 'absolute inset-0 flex items-center justify-center',
content: 'flex items-center gap-[0.5em]',
text: 'inline-flex items-center justify-center gap-1',
text: 'inline-flex items-center justify-center gap-1 w-full',
icon: 'h-[1.906cap] w-[1.906cap] flex-none aspect-square flex items-center justify-center',
},
defaultVariants: {
Expand Down Expand Up @@ -364,7 +364,7 @@ export const Button = React.forwardRef(function Button(

const handlePress = (event: aria.PressEvent): void => {
if (!isDisabled) {
const result = onPress(event)
const result = onPress?.(event)

if (result instanceof Promise) {
setImplicitlyLoading(true)
Expand Down
46 changes: 27 additions & 19 deletions app/dashboard/src/components/AriaComponents/CopyBlock/CopyBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import * as React from 'react'

import * as copyHook from '#/hooks/copyHooks'

import * as textProvider from '#/providers/TextProvider'

import * as ariaComponents from '#/components/AriaComponents'

import * as twv from '#/utilities/tailwindVariants'
Expand All @@ -11,30 +15,25 @@ import * as twv from '#/utilities/tailwindVariants'
// =================

const COPY_BLOCK_STYLES = twv.tv({
base: 'relative grid grid-cols-[minmax(0,_1fr)_auto] max-w-full bg-primary/10 items-center',
base: ariaComponents.TEXT_STYLE({
class: 'max-w-full bg-primary/5 border-primary/10',
}),
variants: {
size: {
small: 'py-2 pl-2 pr-1',
medium: 'py-3 pl-3 pr-2',
large: 'py-4 pl-4 pr-2.5',
small: 'py-[1.5px] px-[5.5px]',
medium: 'py-[3.5px] px-[7.5px]',
large: 'py-[5.5px] px-[11.5px]',
},
roundings: {
rounded: {
custom: '',
small: 'rounded-sm',
medium: 'rounded-md',
large: 'rounded-lg',
full: 'rounded-full',
},
},
slots: {
titleBlock: 'col-span-1 text-sm text-primary/60',
copyTextBlock: 'flex-auto text-sm text-primary/60 text-nowrap overflow-x-auto scroll-hidden',
copyButton: 'flex-none',
},
defaultVariants: {
size: 'medium',
roundings: 'medium',
},
slots: { copyTextBlock: 'flex-auto text-nowrap overflow-x-auto scroll-hidden w-full' },
defaultVariants: { size: 'medium', rounded: 'full' },
})

// =================
Expand All @@ -52,12 +51,21 @@ export interface CopyBlockProps {
/** A block of text with a copy button. */
export function CopyBlock(props: CopyBlockProps) {
const { copyText, className, onCopy = () => {} } = props
const { copyTextBlock, base, copyButton } = COPY_BLOCK_STYLES()

const { getText } = textProvider.useText()
const { mutateAsync, isSuccess } = copyHook.useCopy({ copyText, onCopy })

const { copyTextBlock, base } = COPY_BLOCK_STYLES()

return (
<div className={base({ className })}>
<div className={copyTextBlock()}>{copyText}</div>
<ariaComponents.CopyButton copyText={copyText} onCopy={onCopy} className={copyButton()} />
</div>
<ariaComponents.Button
variant="custom"
size="custom"
onPress={() => mutateAsync()}
tooltip={isSuccess ? getText('copied') : getText('copy')}
className={base({ className })}
>
<span className={copyTextBlock()}>{copyText}</span>
</ariaComponents.Button>
)
}
2 changes: 1 addition & 1 deletion app/dashboard/src/components/Result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const STATUS_ICON_MAP: Readonly<Record<Status, StatusIcon>> = {
}

const RESULT_STYLES = twv.tv({
base: 'flex flex-col items-center justify-center px-6 py-4 text-center h-[max-content]',
base: 'flex flex-col items-center justify-center max-w-full px-6 py-4 text-center h-[max-content]',
variants: {
centered: {
horizontal: 'mx-auto',
Expand Down
8 changes: 4 additions & 4 deletions app/dashboard/src/components/styled/SidebarTabButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/** @file A styled button representing a tab on a sidebar. */
import * as React from 'react'

import type * as aria from '#/components/aria'
import * as ariaComponent from '#/components/AriaComponents'

// ========================
Expand All @@ -17,7 +16,7 @@ export interface SidebarTabButtonProps {
readonly active?: boolean
readonly icon: string
readonly label: string
readonly onPress: (event: aria.PressEvent) => void
readonly onPress: ariaComponent.ButtonProps['onPress']
}

/** A styled button representing a tab on a sidebar. */
Expand All @@ -26,11 +25,12 @@ export default function SidebarTabButton(props: SidebarTabButtonProps) {

return (
<ariaComponent.Button
onPress={onPress}
icon={icon}
variant="ghost"
loaderPosition="icon"
size="medium"
onPress={onPress}
isDisabled={isDisabled}
icon={icon}
rounded="full"
className={active ? 'bg-white opacity-100' : ''}
>
Expand Down
1 change: 1 addition & 0 deletions app/dashboard/src/layouts/AssetProjectSession.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function AssetProjectSession(props: AssetProjectSessionProps) {
<div className="flex items-center gap-1">
<ariaComponents.DialogTrigger isOpen={isOpen} onOpenChange={setIsOpen}>
<Button active image={LogsIcon} alt={getText('showLogs')} onPress={() => {}} />

<ProjectLogsModal
isOpen={isOpen}
backend={backend}
Expand Down
9 changes: 6 additions & 3 deletions app/dashboard/src/layouts/AssetProjectSessions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as reactQuery from '@tanstack/react-query'

import AssetProjectSession from '#/layouts/AssetProjectSession'

import * as errorBoundary from '#/components/ErrorBoundary'
import * as loader from '#/components/Loader'

import type * as backendModule from '#/services/Backend'
Expand All @@ -25,9 +26,11 @@ export interface AssetProjectSessionsProps {
/** A list of previous versions of an asset. */
export default function AssetProjectSessions(props: AssetProjectSessionsProps) {
return (
<React.Suspense fallback={<loader.Loader />}>
<AssetProjectSessionsInternal {...props} />
</React.Suspense>
<errorBoundary.ErrorBoundary>
<React.Suspense fallback={<loader.Loader />}>
<AssetProjectSessionsInternal {...props} />
</React.Suspense>
</errorBoundary.ErrorBoundary>
)
}

Expand Down
9 changes: 7 additions & 2 deletions app/dashboard/src/layouts/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface SettingsProps {

/** Settings screen. */
export default function Settings() {
const backend = backendProvider.useRemoteBackend()
const backend = backendProvider.useRemoteBackendStrict()
const localBackend = backendProvider.useLocalBackend()
const [tab, setTab] = searchParamsState.useSearchParamsState(
'SettingsTab',
Expand All @@ -58,6 +58,7 @@ export default function Settings() {
const organization = backendHooks.useBackendGetOrganization(backend)
const isQueryBlank = !/\S/.test(query)

const client = reactQuery.useQueryClient()
const updateUserMutation = backendHooks.useBackendMutation(backend, 'updateUser', {
meta: { invalidates: [authQueryKey], awaitInvalidates: true },
})
Expand All @@ -75,6 +76,7 @@ export default function Settings() {
},
meta: { invalidates: [[localBackend?.type, 'listDirectory']], awaitInvalidates: true },
})

const updateLocalRootPath = updateLocalRootPathMutation.mutateAsync

const context = React.useMemo<settingsData.SettingsContext>(
Expand All @@ -89,6 +91,7 @@ export default function Settings() {
updateLocalRootPath,
toastAndLog,
getText,
queryClient: client,
}),
[
accessToken,
Expand All @@ -101,6 +104,7 @@ export default function Settings() {
updateOrganization,
updateUser,
user,
client,
]
)

Expand Down Expand Up @@ -197,8 +201,9 @@ export default function Settings() {
/>
</aria.Popover>
</aria.MenuTrigger>

<ariaComponents.Text variant="h1" className="font-bold">
<span>{getText('settingsFor')}</span>
{getText('settingsFor')}
</ariaComponents.Text>

<ariaComponents.Text
Expand Down
2 changes: 1 addition & 1 deletion app/dashboard/src/layouts/Settings/SettingsTabType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ enum SettingsTabType {
local = 'local',
// features = 'features',
// notifications = 'notifications',
// billingAndPlans = 'billing-and-plans',
billingAndPlans = 'billing-and-plans',
members = 'members',
userGroups = 'user-groups',
// appearance = 'appearance',
Expand Down
Loading

0 comments on commit db669a6

Please sign in to comment.