Skip to content

Commit

Permalink
Merge pull request #251 from CityOfZion/CU-86a5uwf4g
Browse files Browse the repository at this point in the history
CU-86a5uwf4g-NEON3 - Implement Help Feature
  • Loading branch information
thiagocbalducci authored Dec 11, 2024
2 parents dcb8c12 + 93dd5f6 commit 7fb8f8a
Show file tree
Hide file tree
Showing 17 changed files with 278 additions and 64 deletions.
124 changes: 83 additions & 41 deletions src/renderer/src/components/ActionPopover.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -9,52 +10,93 @@ const Root = RadixPopover.Root

const Trigger = RadixPopover.Trigger

const Content = forwardRef<
ElementRef<typeof RadixPopover.Content>,
ComponentPropsWithoutRef<typeof RadixPopover.Content>
>(({ className, side = 'right', children, ...props }, ref) => (
<RadixPopover.Portal>
<RadixPopover.Content
ref={ref}
className={StyleHelper.mergeStyles('relative group', className)}
side={side}
align="center"
sideOffset={32}
{...props}
>
<div
className={StyleHelper.mergeStyles('bg-gray-900 flex flex-col rounded overflow-hidden', {
'border-r-4 border-r-neon': side === 'right',
'border-l-4 border-l-neon': side === 'left',
})}
>
{children}
</div>
type TContentProps = ComponentPropsWithoutRef<typeof RadixPopover.Content> & {
contentClassName?: string
pointerClassName?: string
color?: 'neon' | 'yellow'
}

const Content = forwardRef<ElementRef<typeof RadixPopover.Content>, 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'

<div
className={StyleHelper.mergeStyles('flex items-center absolute top-2/4 -translate-y-2/4 ', {
'right-0 translate-x-full flex-row-reverse': side === 'right',
'left-0 -translate-x-full flex-row': side === 'left',
})}
>
<div className="w-2 h-2 bg-neon rounded-full" />
return (
<RadixPopover.Portal>
<RadixPopover.Content
ref={ref}
className={StyleHelper.mergeStyles('relative group', className)}
side={side}
align="center"
sideOffset={32}
{...props}
>
<div
className={StyleHelper.mergeStyles(
'bg-gray-900 flex flex-col rounded overflow-hidden',
{
'border-r-4': isRightSide,
'border-l-4': isLeftSide,
'border-t-4': isTopSide,
'border-neon': isNeonColor,
'border-yellow': isYellowColor,
},
contentClassName
)}
>
{children}
</div>

<div className="w-5 h-px bg-neon" />
</div>
</RadixPopover.Content>
</RadixPopover.Portal>
))
<div
className={StyleHelper.mergeStyles(
'flex items-center absolute',
{
'right-0 top-2/4 -translate-y-2/4 translate-x-full flex-row-reverse': isRightSide,
'left-0 top-2/4 -translate-y-2/4 -translate-x-full flex-row': isLeftSide,
'left-[50%] top-0 -translate-y-4 -translate-x-[50%] rotate-90 flex-row': isTopSide,
},
pointerClassName
)}
>
<div
className={StyleHelper.mergeStyles('w-2 h-2 rounded-full', {
'bg-neon': isNeonColor,
'bg-yellow': isYellowColor,
})}
/>

<div
className={StyleHelper.mergeStyles('w-5 h-px', { 'bg-neon': isNeonColor, 'bg-yellow': isYellowColor })}
/>
</div>
</RadixPopover.Content>
</RadixPopover.Portal>
)
}
)

const Item = ({ clickableProps, ...props }: ComponentProps<typeof Button>) => (
<Button
clickableProps={{ className: 'rounded-none h-10 px-4 justify-start', ...clickableProps }}
className="w-full"
variant="text"
flat
{...props}
/>
type TItemProps = { actionPopoverItemType?: 'button' | 'link' } & (
| ComponentProps<typeof Button>
| ComponentProps<typeof Link>
)

const Item = ({ actionPopoverItemType = 'button', clickableProps, ...props }: TItemProps) => {
const Component = actionPopoverItemType === 'button' ? Button : Link

return (
<Component
variant="text"
flat
className="w-full"
clickableProps={{ className: 'rounded-none h-10 px-4 justify-start', ...clickableProps }}
{...props}
/>
)
}

export const ActionPopover = {
Root,
Trigger,
Expand Down
58 changes: 58 additions & 0 deletions src/renderer/src/components/HelpButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useTranslation } from 'react-i18next'
import { TbAlertTriangle, TbHelp, TbMessage } from 'react-icons/tb'
import { ActionPopover } from '@renderer/components/ActionPopover'
import { IconButton } from '@renderer/components/IconButton'
import { DISCORD_LINK, HELP_LINK } from '@renderer/constants/urls'
import { TestHelper } from '@renderer/helpers/TestHelper'

export const HelpButton = () => {
const { t } = useTranslation('components', { keyPrefix: 'helpButton' })

return (
<ActionPopover.Root>
<ActionPopover.Trigger asChild>
<IconButton
text={t('text')}
className="hover:bg-yellow/15 hover:enabled:bg-yellow/15 aria-selected:bg-yellow/15 aria-selected:hover:bg-yellow/15 aria-expanded:bg-yellow/15 aria-expanded:hover:bg-yellow/15 min-w-16"
colorSchema="yellow"
size="md"
icon={<TbHelp aria-hidden="true" />}
{...TestHelper.buildTestObject('help-button')}
/>
</ActionPopover.Trigger>

<ActionPopover.Content
side="top"
color="yellow"
className="mr-4 mt-[-10px]"
contentClassName="bg-gray-900/50 backdrop-blur-sm"
pointerClassName="left-[100%] -translate-x-[58px]"
{...TestHelper.buildTestObject('help-content')}
>
<ActionPopover.Item
actionPopoverItemType="link"
label={t('list.chatWithUs')}
to={DISCORD_LINK}
target="_blank"
colorSchema="white"
iconsOnEdge={false}
leftIcon={<TbMessage aria-hidden="true" className="text-yellow" />}
{...TestHelper.buildTestObject('help-chat-with-us')}
/>

<ActionPopover.Separator className="h-[2px] mx-2 w-[calc(100%_-_2)]" />

<ActionPopover.Item
actionPopoverItemType="link"
label={t('list.reportProblem')}
to={HELP_LINK}
target="_blank"
colorSchema="white"
iconsOnEdge={false}
leftIcon={<TbAlertTriangle aria-hidden="true" className="text-yellow" />}
{...TestHelper.buildTestObject('help-report-problem')}
/>
</ActionPopover.Content>
</ActionPopover.Root>
)
}
3 changes: 2 additions & 1 deletion src/renderer/src/components/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type TProps = {
text?: string
size?: 'xs' | 'sm' | 'md'
compacted?: boolean
colorSchema?: 'neon' | 'gray' | 'white'
colorSchema?: 'neon' | 'gray' | 'white' | 'yellow'
} & ComponentProps<'button'>

export const IconButton = forwardRef<HTMLButtonElement, TProps>(
Expand All @@ -27,6 +27,7 @@ export const IconButton = forwardRef<HTMLButtonElement, TProps>(
'text-neon ': colorSchema === 'neon',
'text-gray-100 ': colorSchema === 'gray',
'text-white': colorSchema === 'white',
'text-yellow': colorSchema === 'yellow',
},
props.className
)}
Expand Down
2 changes: 0 additions & 2 deletions src/renderer/src/constants/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,3 @@ export const SWAP_NETWORK_BY_BLOCKCHAIN_AND_NETWORK_ID: {
'47763': [''],
},
}

export const SWAP_DISCORD_LINK = 'https://discord.gg/zW26BZC5ku'
2 changes: 2 additions & 0 deletions src/renderer/src/constants/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export const MOBILE_APP_APPSTORE_LINK = 'https://apps.apple.com/my/app/neon-wall
export const MOBILE_APP_PLAYSTORE_LINK =
'https://play.google.com/store/apps/details?id=io.cityofzion.neon&hl=en_US&gl=US'
export const LATEST_RELEASE_URL = 'https://github.com/CityOfZion/neon-wallet-desktop/releases/latest'
export const DISCORD_LINK = 'https://discord.gg/zW26BZC5ku'
export const HELP_LINK = 'https://app.pipefy.com/public/form/wUJ8xQoC'
13 changes: 11 additions & 2 deletions src/renderer/src/layouts/ContentLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type TMainLayoutProps = {
titleIcon?: JSX.Element
contentClassName?: string
headerClassName?: string
rightComponent?: ReactNode
} & ComponentProps<'div'>

export const ContentLayout = ({
Expand All @@ -21,6 +22,7 @@ export const ContentLayout = ({
contentClassName,
headerClassName,
className,
rightComponent,
...props
}: TMainLayoutProps): JSX.Element => {
const navigate = useNavigate()
Expand All @@ -45,19 +47,26 @@ export const ContentLayout = ({
)}
>
<header
className={StyleHelper.mergeStyles('border-b border-b-gray-300/30 min-h-12 flex pb-4', headerClassName)}
className={StyleHelper.mergeStyles(
'border-b border-b-gray-300/30 min-h-12 flex',
{ 'pb-2': !!rightComponent, 'pb-4': !rightComponent },
headerClassName
)}
>
<button type="button" onClick={handleBackClick}>
<TbArrowLeft className="w-5 h-5 text-gray-100" />
</button>
<div className="flex items-center mx-auto pr-6 gap-x-2">

<div className={StyleHelper.mergeStyles('flex items-center mx-auto gap-x-2', { 'pr-6': !rightComponent })}>
{titleIcon &&
cloneElement(titleIcon, {
className: StyleHelper.mergeStyles('text-neon', titleIconClassName),
...titleIconProps,
})}
<h1 className="text-sm">{title}</h1>
</div>

{rightComponent}
</header>

<main className={StyleHelper.mergeStyles('flex w-full flex-col flex-grow min-h-0 pt-5', contentClassName)}>
Expand Down
9 changes: 8 additions & 1 deletion src/renderer/src/locales/en/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,12 @@
},
"transactionFeeActionStep": {
"title": "Transaction Fee"
},
"helpButton": {
"text": "Help",
"list": {
"chatWithUs": "Chat with us",
"reportProblem": "Report a problem"
}
}
}
}
4 changes: 2 additions & 2 deletions src/renderer/src/routes/modals/SwapDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -204,7 +204,7 @@ export const SwapDetailsModal = () => {
</Details.Root>

<Link
to={SWAP_DISCORD_LINK}
to={DISCORD_LINK}
target="_blank"
className="mt-8"
label={t('helpButtonLabel')}
Expand Down
21 changes: 13 additions & 8 deletions src/renderer/src/routes/pages/Contacts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TbPencil, TbPlus } from 'react-icons/tb'
import { Button } from '@renderer/components/Button'
import { ContactAddressTable } from '@renderer/components/ContactAddressTable'
import { ContactList } from '@renderer/components/ContactList'
import { HelpButton } from '@renderer/components/HelpButton'
import { IconButton } from '@renderer/components/IconButton'
import { Separator } from '@renderer/components/Separator'
import { StringHelper } from '@renderer/helpers/StringHelper'
Expand Down Expand Up @@ -32,14 +33,18 @@ export const ContactsPage = () => {
<MainLayout
heading={t('title')}
rightComponent={
<IconButton
icon={<TbPlus className="text-neon" />}
size="md"
className="text-neon"
text={t('buttonAddContactLabel')}
onClick={modalNavigateWrapper('persist-contact')}
{...TestHelper.buildTestObject('add-contact-action')}
/>
<div className="flex gap-x-2">
<IconButton
icon={<TbPlus className="text-neon" />}
size="md"
className="text-neon"
text={t('buttonAddContactLabel')}
onClick={modalNavigateWrapper('persist-contact')}
{...TestHelper.buildTestObject('add-contact-action')}
/>

<HelpButton />
</div>
}
>
<section className="bg-gray-800 w-full h-full flex rounded">
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/src/routes/pages/Portfolio/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -37,6 +38,8 @@ export const PortfolioPage = () => {
onClick={modalNavigateWrapper('import')}
/>
<IconButton icon={<TbFileExport />} size="md" text={t('exportButtonLabel')} disabled />

<HelpButton />
</div>
}
contentClassName="flex-row gap-x-3"
Expand Down
11 changes: 9 additions & 2 deletions src/renderer/src/routes/pages/Receive/index.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -15,12 +16,18 @@ export const ReceiveYourAddress = () => {
const { t } = useTranslation('pages', { keyPrefix: 'receive' })
const { state } = useLocation() as Location<TLocationState>

const rightComponent = (
<div className="flex gap-x-2">
<HelpButton />
</div>
)

return state?.account ? (
<ContentLayout title={t('title')} titleIcon={<TbStepInto />}>
<ContentLayout title={t('title')} titleIcon={<TbStepInto />} rightComponent={rightComponent}>
<ReceivePageContent account={state?.account} />
</ContentLayout>
) : (
<MainLayout heading={t('title')}>
<MainLayout heading={t('title')} rightComponent={rightComponent}>
<ReceivePageContent />
</MainLayout>
)
Expand Down
Loading

0 comments on commit 7fb8f8a

Please sign in to comment.