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 noop from 'utils/noop'
import Expand from './index'
describe('Expand', () => {
it('renders correctly', () => {
const { asFragment } = render(
<Expand header={<span>Header</span>} button={<span>Button</span>}>
it('does not render children when closed', () => {
render(
<Expand header={<span>Header</span>} isOpen={false} onToggle={noop} button={<span>Button</span>}>
Body
</Expand>
)
expect(asFragment()).toMatchSnapshot()
expect(screen.queryByText('Body')).not.toBeInTheDocument()
})
it('toggles children on button press', () => {
it('renders children when open', () => {
render(
<Expand header={<span>Header</span>} button={<span>Button</span>}>
<Expand header={<span>Header</span>} isOpen={true} onToggle={noop} button={<span>Button</span>}>
Body
</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)
expect(screen.queryByText('Body')).not.toBeNull()
const button = screen.getByText('Button')
fireEvent.click(button)
expect(screen.queryByText('Body')).toBeNull()
expect(onToggle).toHaveBeenCalled()
})
})
import Column from 'components/Column'
import React, { PropsWithChildren, ReactElement, useState } from 'react'
import React, { PropsWithChildren, ReactElement } from 'react'
import { ChevronDown } from 'react-feather'
import styled from 'styled-components/macro'
......@@ -11,9 +11,9 @@ const ButtonContainer = styled(Row)`
width: unset;
`
const ExpandIcon = styled(ChevronDown)<{ $isExpanded: boolean }>`
const ExpandIcon = styled(ChevronDown)<{ $isOpen: boolean }>`
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};
`
......@@ -22,22 +22,25 @@ export default function Expand({
button,
children,
testId,
isOpen,
onToggle,
}: PropsWithChildren<{
header: ReactElement
button: ReactElement
testId?: string
isOpen: boolean
onToggle: () => void
}>) {
const [isExpanded, setExpanded] = useState(false)
return (
<Column gap="md">
<RowBetween>
{header}
<ButtonContainer data-testid={testId} onClick={() => setExpanded(!isExpanded)} aria-expanded={isExpanded}>
<ButtonContainer data-testid={testId} onClick={onToggle} aria-expanded={isOpen}>
{button}
<ExpandIcon $isExpanded={isExpanded} />
<ExpandIcon $isOpen={isOpen} />
</ButtonContainer>
</RowBetween>
{isExpanded && children}
{isOpen && children}
</Column>
)
}
......@@ -8,8 +8,12 @@ import MaxSlippageSettings from '.'
const AUTO_SLIPPAGE = new Percent(5, 10_000)
const renderAndExpandSlippageSettings = () => {
const renderSlippageSettings = () => {
render(<MaxSlippageSettings autoSlippage={AUTO_SLIPPAGE} />)
}
const renderAndExpandSlippageSettings = () => {
renderSlippageSettings()
// By default, the button to expand Slippage component and show `input` will have `Auto` label
fireEvent.click(screen.getByText('Auto'))
......@@ -20,7 +24,7 @@ const switchToCustomSlippage = () => {
fireEvent.click(screen.getByText('Custom'))
}
const getSlippageInput = () => screen.getByTestId('slippage-input') as HTMLInputElement
const getSlippageInput = () => screen.queryByTestId('slippage-input') as HTMLInputElement
describe('MaxSlippageSettings', () => {
describe('input', () => {
......@@ -28,6 +32,15 @@ describe('MaxSlippageSettings', () => {
beforeEach(() => {
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', () => {
renderAndExpandSlippageSettings()
switchToCustomSlippage()
......
......@@ -53,6 +53,9 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
const [slippageInput, setSlippageInput] = useState(defaultSlippageInputValue)
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) => {
// 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)) {
......@@ -93,6 +96,8 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
return (
<Expand
testId="max-slippage-settings"
isOpen={isOpen}
onToggle={() => setIsOpen(!isOpen)}
header={
<Row width="auto">
<ThemedText.BodySecondary>
......
......@@ -5,14 +5,18 @@ import { fireEvent, render, screen } from 'test-utils/render'
import TransactionDeadlineSettings from '.'
const renderAndExpandTransactionDeadlineSettings = () => {
const renderTransactionDeadlineSettings = () => {
render(<TransactionDeadlineSettings />)
}
const renderAndExpandTransactionDeadlineSettings = () => {
renderTransactionDeadlineSettings()
// 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`))
}
const getDeadlineInput = () => screen.getByTestId('deadline-input') as HTMLInputElement
const getDeadlineInput = () => screen.queryByTestId('deadline-input') as HTMLInputElement
describe('TransactionDeadlineSettings', () => {
describe('input', () => {
......@@ -20,6 +24,15 @@ describe('TransactionDeadlineSettings', () => {
beforeEach(() => {
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', () => {
renderAndExpandTransactionDeadlineSettings()
expect(getDeadlineInput().value).toBe('')
......
......@@ -26,6 +26,9 @@ export default function TransactionDeadlineSettings() {
const [deadlineInput, setDeadlineInput] = useState(defaultInputValue)
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) {
// Do not allow non-numerical characters in the input field
if (value.length > 0 && !NUMBERS_ONLY.test(value)) {
......@@ -56,6 +59,8 @@ export default function TransactionDeadlineSettings() {
return (
<Expand
isOpen={isOpen}
onToggle={() => setIsOpen(!isOpen)}
testId="transaction-deadline-settings"
header={
<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