Commit 58b25d29 authored by Mike Grabowski's avatar Mike Grabowski Committed by GitHub

feat: expand settings by default when custom values are set (#6603)

feat: expand by default
parent a2db3e27
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Expand renders correctly 1`] = `
<DocumentFragment>
.c1 {
box-sizing: border-box;
margin: 0;
min-width: 0;
}
.c2 {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
padding: 0;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
}
.c3 {
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
}
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
gap: 12px;
}
.c4 {
cursor: pointer;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
-ms-flex-pack: end;
justify-content: flex-end;
width: unset;
}
.c5 {
color: #7780A0;
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
-webkit-transition: -webkit-transform 250ms;
-webkit-transition: transform 250ms;
transition: transform 250ms;
}
<div
class="c0"
>
<div
class="c1 c2 c3"
>
<span>
Header
</span>
<div
aria-expanded="false"
class="c1 c2 c4"
>
<span>
Button
</span>
<svg
class="c5"
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="6 9 12 15 18 9"
/>
</svg>
</div>
</div>
</div>
</DocumentFragment>
`;
import { fireEvent, render, screen } from 'test-utils/render' import { fireEvent, render, screen } from 'test-utils/render'
import noop from 'utils/noop'
import Expand from './index' import Expand from './index'
describe('Expand', () => { describe('Expand', () => {
it('renders correctly', () => { it('does not render children when closed', () => {
const { asFragment } = render( render(
<Expand header={<span>Header</span>} button={<span>Button</span>}> <Expand header={<span>Header</span>} isOpen={false} onToggle={noop} button={<span>Button</span>}>
Body Body
</Expand> </Expand>
) )
expect(asFragment()).toMatchSnapshot() expect(screen.queryByText('Body')).not.toBeInTheDocument()
}) })
it('toggles children on button press', () => { it('renders children when open', () => {
render( render(
<Expand header={<span>Header</span>} button={<span>Button</span>}> <Expand header={<span>Header</span>} isOpen={true} onToggle={noop} button={<span>Button</span>}>
Body Body
</Expand> </Expand>
) )
expect(screen.queryByText('Body')).toBeInTheDocument()
})
const button = screen.getByText('Button') it('calls `onToggle` when button is pressed', () => {
const onToggle = jest.fn()
render(
<Expand header={<span>Header</span>} isOpen={false} onToggle={onToggle} button={<span>Button</span>}>
Body
</Expand>
)
fireEvent.click(button) const button = screen.getByText('Button')
expect(screen.queryByText('Body')).not.toBeNull()
fireEvent.click(button) fireEvent.click(button)
expect(screen.queryByText('Body')).toBeNull() expect(onToggle).toHaveBeenCalled()
}) })
}) })
import Column from 'components/Column' import Column from 'components/Column'
import React, { PropsWithChildren, ReactElement, useState } from 'react' import React, { PropsWithChildren, ReactElement } from 'react'
import { ChevronDown } from 'react-feather' import { ChevronDown } from 'react-feather'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
...@@ -11,9 +11,9 @@ const ButtonContainer = styled(Row)` ...@@ -11,9 +11,9 @@ const ButtonContainer = styled(Row)`
width: unset; width: unset;
` `
const ExpandIcon = styled(ChevronDown)<{ $isExpanded: boolean }>` const ExpandIcon = styled(ChevronDown)<{ $isOpen: boolean }>`
color: ${({ theme }) => theme.textSecondary}; color: ${({ theme }) => theme.textSecondary};
transform: ${({ $isExpanded }) => ($isExpanded ? 'rotate(180deg)' : 'rotate(0deg)')}; transform: ${({ $isOpen }) => ($isOpen ? 'rotate(180deg)' : 'rotate(0deg)')};
transition: transform ${({ theme }) => theme.transition.duration.medium}; transition: transform ${({ theme }) => theme.transition.duration.medium};
` `
...@@ -22,22 +22,25 @@ export default function Expand({ ...@@ -22,22 +22,25 @@ export default function Expand({
button, button,
children, children,
testId, testId,
isOpen,
onToggle,
}: PropsWithChildren<{ }: PropsWithChildren<{
header: ReactElement header: ReactElement
button: ReactElement button: ReactElement
testId?: string testId?: string
isOpen: boolean
onToggle: () => void
}>) { }>) {
const [isExpanded, setExpanded] = useState(false)
return ( return (
<Column gap="md"> <Column gap="md">
<RowBetween> <RowBetween>
{header} {header}
<ButtonContainer data-testid={testId} onClick={() => setExpanded(!isExpanded)} aria-expanded={isExpanded}> <ButtonContainer data-testid={testId} onClick={onToggle} aria-expanded={isOpen}>
{button} {button}
<ExpandIcon $isExpanded={isExpanded} /> <ExpandIcon $isOpen={isOpen} />
</ButtonContainer> </ButtonContainer>
</RowBetween> </RowBetween>
{isExpanded && children} {isOpen && children}
</Column> </Column>
) )
} }
...@@ -8,8 +8,12 @@ import MaxSlippageSettings from '.' ...@@ -8,8 +8,12 @@ import MaxSlippageSettings from '.'
const AUTO_SLIPPAGE = new Percent(5, 10_000) const AUTO_SLIPPAGE = new Percent(5, 10_000)
const renderAndExpandSlippageSettings = () => { const renderSlippageSettings = () => {
render(<MaxSlippageSettings autoSlippage={AUTO_SLIPPAGE} />) render(<MaxSlippageSettings autoSlippage={AUTO_SLIPPAGE} />)
}
const renderAndExpandSlippageSettings = () => {
renderSlippageSettings()
// By default, the button to expand Slippage component and show `input` will have `Auto` label // By default, the button to expand Slippage component and show `input` will have `Auto` label
fireEvent.click(screen.getByText('Auto')) fireEvent.click(screen.getByText('Auto'))
...@@ -20,7 +24,7 @@ const switchToCustomSlippage = () => { ...@@ -20,7 +24,7 @@ const switchToCustomSlippage = () => {
fireEvent.click(screen.getByText('Custom')) fireEvent.click(screen.getByText('Custom'))
} }
const getSlippageInput = () => screen.getByTestId('slippage-input') as HTMLInputElement const getSlippageInput = () => screen.queryByTestId('slippage-input') as HTMLInputElement
describe('MaxSlippageSettings', () => { describe('MaxSlippageSettings', () => {
describe('input', () => { describe('input', () => {
...@@ -28,6 +32,15 @@ describe('MaxSlippageSettings', () => { ...@@ -28,6 +32,15 @@ describe('MaxSlippageSettings', () => {
beforeEach(() => { beforeEach(() => {
store.dispatch(updateUserSlippageTolerance({ userSlippageTolerance: SlippageTolerance.Auto })) store.dispatch(updateUserSlippageTolerance({ userSlippageTolerance: SlippageTolerance.Auto }))
}) })
it('is not expanded by default', () => {
renderSlippageSettings()
expect(getSlippageInput()).not.toBeInTheDocument()
})
it('is expanded by default when custom slippage is set', () => {
store.dispatch(updateUserSlippageTolerance({ userSlippageTolerance: 10 }))
renderSlippageSettings()
expect(getSlippageInput()).toBeInTheDocument()
})
it('does not render auto slippage as a value, but a placeholder', () => { it('does not render auto slippage as a value, but a placeholder', () => {
renderAndExpandSlippageSettings() renderAndExpandSlippageSettings()
switchToCustomSlippage() switchToCustomSlippage()
......
...@@ -53,6 +53,9 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe ...@@ -53,6 +53,9 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
const [slippageInput, setSlippageInput] = useState(defaultSlippageInputValue) const [slippageInput, setSlippageInput] = useState(defaultSlippageInputValue)
const [slippageError, setSlippageError] = useState<SlippageError | false>(false) const [slippageError, setSlippageError] = useState<SlippageError | false>(false)
// If user has previously entered a custom slippage, we want to show the settings expanded by default.
const [isOpen, setIsOpen] = useState(defaultSlippageInputValue.length > 0)
const parseSlippageInput = (value: string) => { const parseSlippageInput = (value: string) => {
// Do not allow non-numerical characters in the input field or more than two decimals // Do not allow non-numerical characters in the input field or more than two decimals
if (value.length > 0 && !NUMBER_WITH_MAX_TWO_DECIMAL_PLACES.test(value)) { if (value.length > 0 && !NUMBER_WITH_MAX_TWO_DECIMAL_PLACES.test(value)) {
...@@ -93,6 +96,8 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe ...@@ -93,6 +96,8 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
return ( return (
<Expand <Expand
testId="max-slippage-settings" testId="max-slippage-settings"
isOpen={isOpen}
onToggle={() => setIsOpen(!isOpen)}
header={ header={
<Row width="auto"> <Row width="auto">
<ThemedText.BodySecondary> <ThemedText.BodySecondary>
......
...@@ -5,14 +5,18 @@ import { fireEvent, render, screen } from 'test-utils/render' ...@@ -5,14 +5,18 @@ import { fireEvent, render, screen } from 'test-utils/render'
import TransactionDeadlineSettings from '.' import TransactionDeadlineSettings from '.'
const renderAndExpandTransactionDeadlineSettings = () => { const renderTransactionDeadlineSettings = () => {
render(<TransactionDeadlineSettings />) render(<TransactionDeadlineSettings />)
}
const renderAndExpandTransactionDeadlineSettings = () => {
renderTransactionDeadlineSettings()
// By default, the button to expand Slippage component and show `input` will have `<deadline>m` label // By default, the button to expand Slippage component and show `input` will have `<deadline>m` label
fireEvent.click(screen.getByText(`${DEFAULT_DEADLINE_FROM_NOW / 60}m`)) fireEvent.click(screen.getByText(`${DEFAULT_DEADLINE_FROM_NOW / 60}m`))
} }
const getDeadlineInput = () => screen.getByTestId('deadline-input') as HTMLInputElement const getDeadlineInput = () => screen.queryByTestId('deadline-input') as HTMLInputElement
describe('TransactionDeadlineSettings', () => { describe('TransactionDeadlineSettings', () => {
describe('input', () => { describe('input', () => {
...@@ -20,6 +24,15 @@ describe('TransactionDeadlineSettings', () => { ...@@ -20,6 +24,15 @@ describe('TransactionDeadlineSettings', () => {
beforeEach(() => { beforeEach(() => {
store.dispatch(updateUserDeadline({ userDeadline: DEFAULT_DEADLINE_FROM_NOW })) store.dispatch(updateUserDeadline({ userDeadline: DEFAULT_DEADLINE_FROM_NOW }))
}) })
it('is not expanded by default', () => {
renderTransactionDeadlineSettings()
expect(getDeadlineInput()).not.toBeInTheDocument()
})
it('is expanded by default when custom deadline is set', () => {
store.dispatch(updateUserDeadline({ userDeadline: DEFAULT_DEADLINE_FROM_NOW * 2 }))
renderTransactionDeadlineSettings()
expect(getDeadlineInput()).toBeInTheDocument()
})
it('does not render default deadline as a value, but a placeholder', () => { it('does not render default deadline as a value, but a placeholder', () => {
renderAndExpandTransactionDeadlineSettings() renderAndExpandTransactionDeadlineSettings()
expect(getDeadlineInput().value).toBe('') expect(getDeadlineInput().value).toBe('')
......
...@@ -26,6 +26,9 @@ export default function TransactionDeadlineSettings() { ...@@ -26,6 +26,9 @@ export default function TransactionDeadlineSettings() {
const [deadlineInput, setDeadlineInput] = useState(defaultInputValue) const [deadlineInput, setDeadlineInput] = useState(defaultInputValue)
const [deadlineError, setDeadlineError] = useState<DeadlineError | false>(false) const [deadlineError, setDeadlineError] = useState<DeadlineError | false>(false)
// If user has previously entered a custom deadline, we want to show the settings expanded by default.
const [isOpen, setIsOpen] = useState(defaultInputValue.length > 0)
function parseCustomDeadline(value: string) { function parseCustomDeadline(value: string) {
// Do not allow non-numerical characters in the input field // Do not allow non-numerical characters in the input field
if (value.length > 0 && !NUMBERS_ONLY.test(value)) { if (value.length > 0 && !NUMBERS_ONLY.test(value)) {
...@@ -56,6 +59,8 @@ export default function TransactionDeadlineSettings() { ...@@ -56,6 +59,8 @@ export default function TransactionDeadlineSettings() {
return ( return (
<Expand <Expand
isOpen={isOpen}
onToggle={() => setIsOpen(!isOpen)}
testId="transaction-deadline-settings" testId="transaction-deadline-settings"
header={ header={
<Row width="auto"> <Row width="auto">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment