From 93dd5f6095eceb4c98429894f54890e325a65730 Mon Sep 17 00:00:00 2001 From: hotequil Date: Tue, 10 Dec 2024 11:49:19 -0300 Subject: [PATCH] CU-86a5uwf4g-NEON3 - Implement Help Feature --- src/renderer/src/components/ActionPopover.tsx | 124 ++++++++++++------ src/renderer/src/components/HelpButton.tsx | 58 ++++++++ src/renderer/src/components/IconButton.tsx | 3 +- src/renderer/src/constants/swap.ts | 2 - src/renderer/src/constants/urls.ts | 2 + src/renderer/src/layouts/ContentLayout.tsx | 13 +- src/renderer/src/locales/en/components.json | 9 +- .../src/routes/modals/SwapDetails/index.tsx | 4 +- .../src/routes/pages/Contacts/index.tsx | 21 +-- .../src/routes/pages/Portfolio/index.tsx | 3 + .../src/routes/pages/Receive/index.tsx | 11 +- src/renderer/src/routes/pages/Send/index.tsx | 11 +- .../src/routes/pages/Settings/index.tsx | 10 +- src/renderer/src/routes/pages/Swap/index.tsx | 11 +- .../src/routes/pages/Wallets/index.tsx | 3 + src/shared/@types/i18next-resources.d.ts | 7 + tests/e2e/toolbar/help-button.spec.ts | 50 +++++++ 17 files changed, 278 insertions(+), 64 deletions(-) create mode 100644 src/renderer/src/components/HelpButton.tsx create mode 100644 tests/e2e/toolbar/help-button.spec.ts diff --git a/src/renderer/src/components/ActionPopover.tsx b/src/renderer/src/components/ActionPopover.tsx index 5e7827d0..fd2288b5 100644 --- a/src/renderer/src/components/ActionPopover.tsx +++ b/src/renderer/src/components/ActionPopover.tsx @@ -1,5 +1,6 @@ import { ComponentProps, ComponentPropsWithoutRef, ElementRef, forwardRef } from 'react' import * as RadixPopover from '@radix-ui/react-popover' +import { Link } from '@renderer/components/Link' import { StyleHelper } from '@renderer/helpers/StyleHelper' import { Button } from './Button' @@ -9,52 +10,93 @@ const Root = RadixPopover.Root const Trigger = RadixPopover.Trigger -const Content = forwardRef< - ElementRef, - ComponentPropsWithoutRef ->(({ className, side = 'right', children, ...props }, ref) => ( - - -
- {children} -
+type TContentProps = ComponentPropsWithoutRef & { + contentClassName?: string + pointerClassName?: string + color?: 'neon' | 'yellow' +} + +const Content = forwardRef, TContentProps>( + ({ className, contentClassName, pointerClassName, side = 'right', color = 'neon', children, ...props }, ref) => { + const isRightSide = side === 'right' + const isLeftSide = side === 'left' + const isTopSide = side === 'top' + const isNeonColor = color === 'neon' + const isYellowColor = color === 'yellow' -
-
+ return ( + + +
+ {children} +
-
-
-
-
-)) +
+
+ +
+
+ + + ) + } +) -const Item = ({ clickableProps, ...props }: ComponentProps) => ( - -
+ +
{titleIcon && cloneElement(titleIcon, { className: StyleHelper.mergeStyles('text-neon', titleIconClassName), @@ -58,6 +65,8 @@ export const ContentLayout = ({ })}

{title}

+ + {rightComponent}
diff --git a/src/renderer/src/locales/en/components.json b/src/renderer/src/locales/en/components.json index 3ca6d142..96a336d8 100644 --- a/src/renderer/src/locales/en/components.json +++ b/src/renderer/src/locales/en/components.json @@ -157,5 +157,12 @@ }, "transactionFeeActionStep": { "title": "Transaction Fee" + }, + "helpButton": { + "text": "Help", + "list": { + "chatWithUs": "Chat with us", + "reportProblem": "Report a problem" + } } -} \ No newline at end of file +} diff --git a/src/renderer/src/routes/modals/SwapDetails/index.tsx b/src/renderer/src/routes/modals/SwapDetails/index.tsx index 52e3246d..d824bb6a 100644 --- a/src/renderer/src/routes/modals/SwapDetails/index.tsx +++ b/src/renderer/src/routes/modals/SwapDetails/index.tsx @@ -8,7 +8,7 @@ import { Details } from '@renderer/components/Details' import { Link } from '@renderer/components/Link' import { Separator } from '@renderer/components/Separator' import { Stepper, TStepperCurrentState } from '@renderer/components/Stepper' -import { SWAP_DISCORD_LINK } from '@renderer/constants/swap' +import { DISCORD_LINK } from '@renderer/constants/urls' import { StringHelper } from '@renderer/helpers/StringHelper' import { useModalState } from '@renderer/hooks/useModalRouter' import { useAppDispatch } from '@renderer/hooks/useRedux' @@ -204,7 +204,7 @@ export const SwapDetailsModal = () => { { } - size="md" - className="text-neon" - text={t('buttonAddContactLabel')} - onClick={modalNavigateWrapper('persist-contact')} - {...TestHelper.buildTestObject('add-contact-action')} - /> +
+ } + size="md" + className="text-neon" + text={t('buttonAddContactLabel')} + onClick={modalNavigateWrapper('persist-contact')} + {...TestHelper.buildTestObject('add-contact-action')} + /> + + +
} >
diff --git a/src/renderer/src/routes/pages/Portfolio/index.tsx b/src/renderer/src/routes/pages/Portfolio/index.tsx index 530fbe94..70b390fc 100644 --- a/src/renderer/src/routes/pages/Portfolio/index.tsx +++ b/src/renderer/src/routes/pages/Portfolio/index.tsx @@ -2,6 +2,7 @@ import { useTranslation } from 'react-i18next' import { MdAdd } from 'react-icons/md' import { TbFileExport, TbFileImport } from 'react-icons/tb' import { Outlet, useMatch } from 'react-router-dom' +import { HelpButton } from '@renderer/components/HelpButton' import { IconButton } from '@renderer/components/IconButton' import { Separator } from '@renderer/components/Separator' import { SidebarMenuButton } from '@renderer/components/SidebarMenuButton' @@ -37,6 +38,8 @@ export const PortfolioPage = () => { onClick={modalNavigateWrapper('import')} /> } size="md" text={t('exportButtonLabel')} disabled /> + +
} contentClassName="flex-row gap-x-3" diff --git a/src/renderer/src/routes/pages/Receive/index.tsx b/src/renderer/src/routes/pages/Receive/index.tsx index add71124..2a9a1714 100644 --- a/src/renderer/src/routes/pages/Receive/index.tsx +++ b/src/renderer/src/routes/pages/Receive/index.tsx @@ -1,6 +1,7 @@ import { useTranslation } from 'react-i18next' import { TbStepInto } from 'react-icons/tb' import { Location, useLocation } from 'react-router-dom' +import { HelpButton } from '@renderer/components/HelpButton' import { ContentLayout } from '@renderer/layouts/ContentLayout' import { MainLayout } from '@renderer/layouts/Main' import { IAccountState } from '@shared/@types/store' @@ -15,12 +16,18 @@ export const ReceiveYourAddress = () => { const { t } = useTranslation('pages', { keyPrefix: 'receive' }) const { state } = useLocation() as Location + const rightComponent = ( +
+ +
+ ) + return state?.account ? ( - }> + } rightComponent={rightComponent}> ) : ( - + ) diff --git a/src/renderer/src/routes/pages/Send/index.tsx b/src/renderer/src/routes/pages/Send/index.tsx index edf8db29..f6c0472e 100644 --- a/src/renderer/src/routes/pages/Send/index.tsx +++ b/src/renderer/src/routes/pages/Send/index.tsx @@ -1,6 +1,7 @@ import { useTranslation } from 'react-i18next' import { TbStepOut } from 'react-icons/tb' import { Location, useLocation } from 'react-router-dom' +import { HelpButton } from '@renderer/components/HelpButton' import { ContentLayout } from '@renderer/layouts/ContentLayout' import { MainLayout } from '@renderer/layouts/Main' import { IAccountState } from '@shared/@types/store' @@ -16,12 +17,18 @@ export const SendPage = () => { const { t } = useTranslation('pages', { keyPrefix: 'send' }) const { state } = useLocation() as Location + const rightComponent = ( +
+ +
+ ) + return state?.account || state?.recipient ? ( - }> + } rightComponent={rightComponent}> ) : ( - + ) diff --git a/src/renderer/src/routes/pages/Settings/index.tsx b/src/renderer/src/routes/pages/Settings/index.tsx index 80f8cca7..5a6cce81 100644 --- a/src/renderer/src/routes/pages/Settings/index.tsx +++ b/src/renderer/src/routes/pages/Settings/index.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { Outlet, useLocation, useNavigate } from 'react-router-dom' +import { HelpButton } from '@renderer/components/HelpButton' import { Tabs } from '@renderer/components/Tabs' import { TestHelper } from '@renderer/helpers/TestHelper' import { useCurrentLoginSessionSelector } from '@renderer/hooks/useAuthSelector' @@ -43,7 +44,14 @@ export const SettingsPage = () => { }, [pathname]) return ( - + + +
+ } + >
diff --git a/src/renderer/src/routes/pages/Swap/index.tsx b/src/renderer/src/routes/pages/Swap/index.tsx index 70e16b9d..b8277ccb 100644 --- a/src/renderer/src/routes/pages/Swap/index.tsx +++ b/src/renderer/src/routes/pages/Swap/index.tsx @@ -1,6 +1,7 @@ import { useTranslation } from 'react-i18next' import { TbReplace } from 'react-icons/tb' import { Location, useLocation } from 'react-router-dom' +import { HelpButton } from '@renderer/components/HelpButton' import { ContentLayout } from '@renderer/layouts/ContentLayout' import { MainLayout } from '@renderer/layouts/Main' import { IAccountState } from '@shared/@types/store' @@ -15,12 +16,18 @@ export const SwapPage = () => { const { state } = useLocation() as Location const { t } = useTranslation('pages', { keyPrefix: 'swap' }) + const rightComponent = ( +
+ +
+ ) + return state?.account ? ( - }> + } rightComponent={rightComponent}> ) : ( - + ) diff --git a/src/renderer/src/routes/pages/Wallets/index.tsx b/src/renderer/src/routes/pages/Wallets/index.tsx index f937e69b..8bc73b50 100644 --- a/src/renderer/src/routes/pages/Wallets/index.tsx +++ b/src/renderer/src/routes/pages/Wallets/index.tsx @@ -6,6 +6,7 @@ import { Outlet, useNavigate, useParams } from 'react-router-dom' import { hasNft } from '@cityofzion/blockchain-service' import { ActionPopover } from '@renderer/components/ActionPopover' import { Button } from '@renderer/components/Button' +import { HelpButton } from '@renderer/components/HelpButton' import { IconButton } from '@renderer/components/IconButton' import { Separator } from '@renderer/components/Separator' import { SidebarMenuButton } from '@renderer/components/SidebarMenuButton' @@ -171,6 +172,8 @@ export const WalletsPage = () => { disabled={!isPasswordLogin || hasHardwareAccount} {...TestHelper.buildTestObject('connect-hardware-wallet')} /> + +
} contentClassName="flex-row gap-x-3" diff --git a/src/shared/@types/i18next-resources.d.ts b/src/shared/@types/i18next-resources.d.ts index 19a9c6d3..98efdcd6 100644 --- a/src/shared/@types/i18next-resources.d.ts +++ b/src/shared/@types/i18next-resources.d.ts @@ -206,6 +206,13 @@ interface Resources { transactionFeeActionStep: { title: 'Transaction Fee' } + helpButton: { + text: 'Help' + list: { + chatWithUs: 'Chat with us' + reportProblem: 'Report a problem' + } + } } hooks: { useImportAction: { diff --git a/tests/e2e/toolbar/help-button.spec.ts b/tests/e2e/toolbar/help-button.spec.ts new file mode 100644 index 00000000..0d1805ce --- /dev/null +++ b/tests/e2e/toolbar/help-button.spec.ts @@ -0,0 +1,50 @@ +import { expect, Locator, Page, test } from '@playwright/test' + +import { createNewWallet, launch } from '../index' + +test.describe('Help button', () => { + let window: Page + let helpButton: Locator + + test.beforeEach(async () => { + window = await launch() + + await createNewWallet(window) + + helpButton = window.getByTestId('help-button') + }) + + test.afterEach(async () => { + await window.close() + }) + + test('Should not show the popover', async () => { + await expect(window.getByTestId('help-content')).not.toBeVisible() + }) + + test('Should click on "Help" button and open the popover', async () => { + await expect(helpButton).toBeVisible() + + await helpButton.click() + + await expect(window.getByTestId('help-content')).toBeVisible() + }) + + // Skipped because it opens a link in the browser every time + test.skip('Should click on "Chat with us" button and open the Discord link on browser', async () => { + await expect(helpButton).toBeVisible() + + await helpButton.click() + + await window.getByTestId('help-chat-with-us').click() + }) + + // Skipped because it opens a link in the browser every time + test.skip('Should click on "Report a problem" button and open the Pipefy link on browser', async () => { + await expect(helpButton).toBeVisible() + + await helpButton.click() + + await window.getByTestId('help-report-problem').click() + }) +})