Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Introduce ActionButton #2452

Merged
merged 5 commits into from
Nov 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions src/renderer/components/pool/PoolTitle.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,6 @@ export const RowItem = styled(A.Col)`
align-items: center;
`

export const ButtonActions = styled.div`
display: flex;
align-items: center;
justify-content: center;
> :not(:first-child) {
margin-left: 10px;
}
`

export const TitleContainer = styled.div`
display: flex;
flex-direction: row;
Expand Down
76 changes: 45 additions & 31 deletions src/renderer/components/pool/PoolTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { useMemo } from 'react'

import * as RD from '@devexperts/remote-data-ts'
import { Asset, AssetAmount, assetToString, formatAssetAmount } from '@xchainjs/xchain-util'
import { Asset, AssetAmount, AssetRuneNative, assetToString, formatAssetAmount } from '@xchainjs/xchain-util'
import { Grid } from 'antd'
import * as FP from 'fp-ts/lib/function'
import { useIntl } from 'react-intl'
import { useNavigate } from 'react-router-dom'

import { Network } from '../../../shared/api/types'
import { Action as ActionButtonAction, ActionButton } from '../../components/uielements/button/ActionButton'
import { loadingString } from '../../helpers/stringHelper'
import * as poolsRoutes from '../../routes/pools'
import { AssetIcon } from '../uielements/assets/assetIcon'
import { SwapButton, ManageButton } from '../uielements/button'
import * as Styled from './PoolTitle.styles'

export type Props = {
Expand Down Expand Up @@ -41,6 +44,9 @@ export const PoolTitle: React.FC<Props> = ({
}) => {
const isDesktopView = Grid.useBreakpoint()?.md ?? false

const intl = useIntl()
const navigate = useNavigate()

const title = useMemo(() => {
const Star = watched ? Styled.StarFilled : Styled.StarOutlined
const starClickHandler = watched ? unwatch : watch
Expand Down Expand Up @@ -68,43 +74,51 @@ export const PoolTitle: React.FC<Props> = ({
[priceRD]
)

const buttons = useMemo(
() => (
<Styled.ButtonActions>
<ManageButton
disabled={disableAllPoolActions || disablePoolActions || walletLocked}
asset={asset}
size="normal"
isTextView={isDesktopView}
/>
{isAvailablePool && (
<SwapButton
disabled={disableAllPoolActions || disableTradingPoolAction}
size="normal"
asset={asset}
isTextView={isDesktopView}
/>
)}
</Styled.ButtonActions>
),
[
disableAllPoolActions,
disablePoolActions,
walletLocked,
asset,
isDesktopView,
isAvailablePool,
disableTradingPoolAction
const actionButton = useMemo(() => {
const actions: ActionButtonAction[] = [
{
label: intl.formatMessage({ id: 'common.swap' }),
disabled: !isAvailablePool || disableAllPoolActions || disableTradingPoolAction,
callback: () => {
navigate(poolsRoutes.swap.path({ source: assetToString(AssetRuneNative), target: assetToString(asset) }))
}
},
{
label: intl.formatMessage({ id: 'common.manage' }),
disabled: disableAllPoolActions || disablePoolActions || walletLocked,
callback: () => {
navigate(poolsRoutes.deposit.path({ asset: assetToString(asset) }))
}
},
{
label: intl.formatMessage({ id: 'common.savers' }),
disabled: !isAvailablePool || disableAllPoolActions || disableTradingPoolAction,
callback: () => {
navigate(poolsRoutes.savers.path({ asset: assetToString(asset) }))
}
}
]
)

return <ActionButton size={isDesktopView ? 'large' : 'normal'} actions={actions} />
}, [
intl,
isAvailablePool,
disableAllPoolActions,
disableTradingPoolAction,
disablePoolActions,
walletLocked,
isDesktopView,
navigate,
asset
])

return (
<Styled.Container>
<Styled.RowItem>
<Styled.TitleContainer>{title}</Styled.TitleContainer>
<Styled.Price>{priceStr}</Styled.Price>
</Styled.RowItem>
<Styled.RowItem>{buttons}</Styled.RowItem>
<Styled.RowItem>{actionButton}</Styled.RowItem>
</Styled.Container>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ export const Icon = styled.img<IconProps>`
width: ${({ size, isSynth }) => `${sizes[size] - (isSynth ? 2 : 0) * borders[size]}px`};
height: ${({ size, isSynth }) => `${sizes[size] - (isSynth ? 2 : 0) * borders[size]}px`};
border-radius: 50%;
max-width: auto; // overridden to avoid max-w-100% (default)
`
75 changes: 75 additions & 0 deletions src/renderer/components/uielements/button/ActionButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { ComponentMeta, StoryFn } from '@storybook/react'

import { ActionButton as Component, Props } from './ActionButton'

const Template: StoryFn<Props> = (args) => <Component {...args} />
export const Default = Template.bind({})

const meta: ComponentMeta<typeof Component> = {
title: 'Components/button/ActionButton',
argTypes: {
size: {
control: {
type: 'select',
options: ['small', 'medium', 'normal', 'large']
}
}
},
args: {
actions: [
{
label: 'swap',
callback: () => {
console.log('swap')
},
disabled: false
},
{
label: 'manage',
callback: () => {
console.log('manage')
},
disabled: false
},
{
label: 'savers',
callback: () => {
console.log('savers')
},
disabled: true
},
{
label: 'send',
callback: () => {
console.log('send')
},
disabled: false
},
{
label: 'deposit',
callback: () => {
console.log('deposit')
},
disabled: false
},
{
label: 'upgrade',
callback: () => {
console.log('upgrade')
},
disabled: true
}
],
disabled: false,
size: 'normal'
},
decorators: [
(Story) => (
<div className="flex h-full w-full items-center justify-center">
<Story />
</div>
)
]
}

export default meta
66 changes: 66 additions & 0 deletions src/renderer/components/uielements/button/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react'

import { Popover } from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/24/outline'
import * as A from 'fp-ts/lib/Array'
import * as FP from 'fp-ts/lib/function'
import { useIntl } from 'react-intl'

import type { Props as ButtonProps } from './FlatButton'
import { TextButton, FlatButton } from './index'

export type Action = { label: string; callback: FP.Lazy<void>; disabled?: boolean }
export type Props = Omit<ButtonProps, 'onClick'> & {
actions: Action[]
isTextView?: boolean
}

export const ActionButton: React.FC<Props> = (props): JSX.Element => {
const { size, actions, isTextView = true, disabled = false } = props

const intl = useIntl()

return (
<Popover className="relative">
<Popover.Button as="div" className="group">
{({ open }) => (
<FlatButton size={size} disabled={disabled}>
<span className={`${isTextView ? 'mr-10px' : 'hidden'}`}>
{intl.formatMessage({ id: 'common.action' })}
</span>
<ChevronDownIcon
className={`ease h-[20px] w-[20px] text-inherit group-hover:rotate-180 ${
open ? 'rotate-180' : 'rotate-0'
}`}
/>
</FlatButton>
)}
</Popover.Button>
<Popover.Panel className="absolute left-[50%] z-[2000] min-w-[100%] translate-x-[-50%] bg-bg0 shadow-full dark:bg-bg0d dark:shadow-fulld ">
{({ close }) => (
<div>
{FP.pipe(
actions,
A.mapWithIndex((index, { label, callback, disabled = false }) => (
<TextButton
className={`w-full hover:bg-bg2 dark:hover:bg-bg2d`}
disabled={disabled}
size={size}
color="neutral"
key={index}
onClick={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
event.preventDefault()
event.stopPropagation()
callback()
close()
}}>
{label}
</TextButton>
))
)}
</div>
)}
</Popover.Panel>
</Popover>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const meta: ComponentMeta<typeof Component> = {
size: {
control: {
type: 'select',
options: ['small', 'normal', 'large']
options: ['small', 'medium', 'normal', 'large']
}
}
},
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/de/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const common: CommonMessages = {
'common.searchAsset': 'Suche Asset',
'common.retry': 'Wiederholen',
'common.reload': 'Neuladen',
'common.action': 'Aktion',
'common.add': 'Einzahlen',
'common.swap': 'Swap',
'common.savers': 'Savers',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/en/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const common: CommonMessages = {
'common.searchAsset': 'Search Asset',
'common.retry': 'Retry',
'common.reload': 'Reload',
'common.action': 'Action',
'common.add': 'Add',
'common.swap': 'Swap',
'common.savers': 'Savers',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/fr/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const common: CommonMessages = {
'common.searchAsset': 'Rechercher un actif',
'common.retry': 'Réessayer',
'common.reload': 'Recharger',
'common.action': 'Action - FR',
'common.add': 'Ajouter',
'common.swap': 'Échanger',
'common.savers': 'Savers - FR',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/ru/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const common: CommonMessages = {
'common.searchAsset': 'Поиск актива',
'common.retry': 'Повторить',
'common.reload': 'Обновить',
'common.action': 'Action - RU',
'common.add': 'Добавить',
'common.swap': 'Обмен',
'common.savers': 'Savers - RU',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export type CommonMessageKey =
| 'common.searchAsset'
| 'common.retry'
| 'common.reload'
| 'common.action'
| 'common.add'
| 'common.swap'
| 'common.savers'
Expand Down
Loading