From db669a67fb5e3f194412e1caf128a9151e49921b Mon Sep 17 00:00:00 2001 From: Sergei Garin Date: Tue, 23 Jul 2024 22:10:21 +0300 Subject: [PATCH] Billing Page iteration one (#10497) #### Tl;dr Closes: enso-org/cloud-v2#1158 This PR adds a redirect to the stripe page where the user can manage his subscription
Demo Presentation

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

--- #### 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. --- --- app/dashboard/e2e/assetsTableFeatures.spec.ts | 1 - app/dashboard/src/assets/credit_card.svg | 1 + .../AriaComponents/Button/Button.tsx | 6 +- .../AriaComponents/CopyBlock/CopyBlock.tsx | 46 ++++++++------ app/dashboard/src/components/Result.tsx | 2 +- .../components/styled/SidebarTabButton.tsx | 10 ++-- .../src/layouts/AssetProjectSession.tsx | 1 + .../src/layouts/AssetProjectSessions.tsx | 9 ++- app/dashboard/src/layouts/Settings.tsx | 9 ++- .../src/layouts/Settings/SettingsTabType.ts | 2 +- .../src/layouts/Settings/settingsData.tsx | 60 +++++++++++++------ app/dashboard/src/layouts/SettingsSidebar.tsx | 12 +++- .../src/providers/BackendProvider.tsx | 18 +++--- app/dashboard/src/services/LocalBackend.ts | 7 +++ app/dashboard/src/services/RemoteBackend.ts | 16 +++++ .../src/services/remoteBackendPaths.ts | 14 +++++ .../common/src/services/Backend.ts | 15 +++++ app/ide-desktop/common/src/text/english.json | 2 + 18 files changed, 166 insertions(+), 65 deletions(-) create mode 100644 app/dashboard/src/assets/credit_card.svg diff --git a/app/dashboard/e2e/assetsTableFeatures.spec.ts b/app/dashboard/e2e/assetsTableFeatures.spec.ts index 36349a0e460..eec21db13f3 100644 --- a/app/dashboard/e2e/assetsTableFeatures.spec.ts +++ b/app/dashboard/e2e/assetsTableFeatures.spec.ts @@ -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() diff --git a/app/dashboard/src/assets/credit_card.svg b/app/dashboard/src/assets/credit_card.svg new file mode 100644 index 00000000000..6e51431751b --- /dev/null +++ b/app/dashboard/src/assets/credit_card.svg @@ -0,0 +1 @@ + diff --git a/app/dashboard/src/components/AriaComponents/Button/Button.tsx b/app/dashboard/src/components/AriaComponents/Button/Button.tsx index ea26c3efd92..775cb40637a 100644 --- a/app/dashboard/src/components/AriaComponents/Button/Button.tsx +++ b/app/dashboard/src/components/AriaComponents/Button/Button.tsx @@ -59,7 +59,7 @@ export interface BaseButtonProps * 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 + readonly onPress?: ((event: aria.PressEvent) => Promise | void) | null | undefined readonly contentClassName?: string readonly testId?: string readonly isDisabled?: boolean @@ -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: { @@ -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) diff --git a/app/dashboard/src/components/AriaComponents/CopyBlock/CopyBlock.tsx b/app/dashboard/src/components/AriaComponents/CopyBlock/CopyBlock.tsx index 4a79797f24a..97b9b2aafd2 100644 --- a/app/dashboard/src/components/AriaComponents/CopyBlock/CopyBlock.tsx +++ b/app/dashboard/src/components/AriaComponents/CopyBlock/CopyBlock.tsx @@ -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' @@ -11,14 +15,16 @@ 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', @@ -26,15 +32,8 @@ const COPY_BLOCK_STYLES = twv.tv({ 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' }, }) // ================= @@ -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 ( -
-
{copyText}
- -
+ mutateAsync()} + tooltip={isSuccess ? getText('copied') : getText('copy')} + className={base({ className })} + > + {copyText} + ) } diff --git a/app/dashboard/src/components/Result.tsx b/app/dashboard/src/components/Result.tsx index 405223864e0..2ea69c7a01d 100644 --- a/app/dashboard/src/components/Result.tsx +++ b/app/dashboard/src/components/Result.tsx @@ -35,7 +35,7 @@ const STATUS_ICON_MAP: Readonly> = { } 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', diff --git a/app/dashboard/src/components/styled/SidebarTabButton.tsx b/app/dashboard/src/components/styled/SidebarTabButton.tsx index 2ac673256ca..39da5adb9b0 100644 --- a/app/dashboard/src/components/styled/SidebarTabButton.tsx +++ b/app/dashboard/src/components/styled/SidebarTabButton.tsx @@ -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' // ======================== @@ -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. */ @@ -26,11 +25,12 @@ export default function SidebarTabButton(props: SidebarTabButtonProps) { return ( diff --git a/app/dashboard/src/layouts/AssetProjectSession.tsx b/app/dashboard/src/layouts/AssetProjectSession.tsx index 6279157f963..afa80e6d1fe 100644 --- a/app/dashboard/src/layouts/AssetProjectSession.tsx +++ b/app/dashboard/src/layouts/AssetProjectSession.tsx @@ -42,6 +42,7 @@ export default function AssetProjectSession(props: AssetProjectSessionProps) {