Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new swap page #102

Merged
merged 3 commits into from
Oct 3, 2024
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
3 changes: 2 additions & 1 deletion client/src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export const PrimaryButton = styled.button`
font-weight: 485;

&:disabled {
background-color: ${({ theme }) => theme.surface};
background-color: ${({ theme }) => theme.bg3};
color: ${({ theme }) => theme.neutral2};
cursor: default;
}
`
Expand Down
24 changes: 24 additions & 0 deletions client/src/components/ChipButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ThemedText } from 'src/theme/components'
import styled from 'styled-components'

const StyledChipButton = styled(ThemedText.BodySecondary)<{ active?: boolean }>`
background-color: ${({ theme }) => theme.bg3};
color: ${({ theme, active }) => (active ? theme.neutral1 : theme.neutral2)};
border: none;
border-radius: 99px;
padding: 8px 16px;
cursor: pointer;
transition: background-color 0.2s ease;

&:hover {
background-color: ${({ theme }) => theme.bg2};
}
`

interface ChipButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
active?: boolean
}

export function ChipButton({ active, ...props }: ChipButtonProps) {
return <StyledChipButton as="button" active={active} {...props} />
}
8 changes: 6 additions & 2 deletions client/src/components/CurrencyButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Currency } from 'src/constants/currencies'
import { ThemedText } from 'src/theme/components'
import { ChevronDown } from 'src/theme/components/icons'
import styled from 'styled-components'

import { Row } from '../Flex'
Expand All @@ -20,15 +21,18 @@ const CurrencyCard = styled(Row)`
`

interface CurrencyButtonProps {
className?: string
selectedCurrency: Currency
}

export function CurrencyButton({ selectedCurrency }: CurrencyButtonProps) {
export function CurrencyButton({ className, selectedCurrency }: CurrencyButtonProps) {
return (
<CurrencyCard as="button" gap={4}>
<CurrencyCard as="button" gap={4} className={className}>
<img src={selectedCurrency.img} alt={selectedCurrency.name} />

<ThemedText.BodyPrimary fontWeight={500}>{selectedCurrency.name}</ThemedText.BodyPrimary>

<ChevronDown width={14} height={14} />
</CurrencyCard>
)
}
18 changes: 11 additions & 7 deletions client/src/components/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@ interface CurrencyInputProps {
}

const StyledInput = styled.input`
box-sizing: border-box;
width: 100%;
padding: 2px;
border: none;
background-color: transparent;
color: ${({ theme }) => theme.neutral1};
border: none;
border-radius: 4px;
font-size: 26px;
width: 100%;
box-sizing: border-box;
color: white;
font-family: 'Inter';
font-size: 72px;
font-weight: 600;
text-align: center;
outline: none;

&:focus {
outline: none;
&::placeholder {
color: ${({ theme }) => theme.neutral2};
}
`

Expand Down
68 changes: 68 additions & 0 deletions client/src/components/SelectAccountModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { useCloseModal, useSelectAccountModal } from 'src/hooks/useModal'
import { ThemedText } from 'src/theme/components'
import { RevolutLogo, VenmoLogo } from 'src/theme/components/icons'
import styled from 'styled-components'

import { PrimaryButton } from '../Button'
import { Column, Row } from '../Flex'
import Content from '../Modal/Content'
import Overlay from '../Modal/Overlay'
import Portal from '../Portal'

const AccountButtons = styled(Column)`
width: 100%;
`

const StyledAccountModal = styled(Row)`
width: 100%;
justify-content: space-between;
padding: 16px;
background-color: ${({ theme }) => theme.bg3};
color: ${({ theme }) => theme.neutral1};
border: none;
border-radius: 12px;
cursor: pointer;
`

interface AccountButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
Logo: React.FC<React.SVGProps<SVGSVGElement>>
name: string
currencies: string[]
}

const AccountButton = ({ Logo, name, currencies, ...props }: AccountButtonProps) => {
return (
<StyledAccountModal as="button" {...props}>
<Row gap={16}>
<Logo width={22} height={22} />

<ThemedText.HeadlineSmall>{name}</ThemedText.HeadlineSmall>
</Row>

<ThemedText.BodySecondary>{currencies.join(', ')}</ThemedText.BodySecondary>
</StyledAccountModal>
)
}

export default function SelectAccountModal() {
// modal
const [isOpen] = useSelectAccountModal()
const close = useCloseModal()

if (!isOpen) return null

return (
<Portal>
<Content title="Select account" close={close}>
<AccountButtons gap={16}>
<AccountButton Logo={RevolutLogo} name="Revolut" currencies={['EUR', 'USD']} />
<AccountButton Logo={VenmoLogo} name="Venmo" currencies={['USD']} />
</AccountButtons>

<PrimaryButton>Register new account</PrimaryButton>
</Content>

<Overlay onClick={close} />
</Portal>
)
}
2 changes: 2 additions & 0 deletions client/src/constants/currencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ export const FIAT_CURRENCIES = {
EUR: {
img: EURLogo,
name: 'EUR',
symbol: '€',
},
}

export const TOKEN_CURRENCIES = {
USDC: {
img: USDCLogo,
name: 'USDC',
symbol: 'USDC',
},
}
2 changes: 2 additions & 0 deletions client/src/hooks/useModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ export const useWalletConnectModal = () => useModal(ModalType.WALLET_CONNECT)
export const useWalletOverviewModal = () => useModal(ModalType.WALLET_OVERVIEW)

export const useProofGenerationModal = () => useModal(ModalType.PROOF_GENERATION)

export const useSelectAccountModal = () => useModal(ModalType.SELECT_ACCOUNT)
142 changes: 86 additions & 56 deletions client/src/pages/Swap.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,89 @@
import { ChangeEvent, useState } from 'react'
import { PrimaryButton } from 'src/components/Button'
import { ChipButton } from 'src/components/ChipButton'
import { CurrencyButton } from 'src/components/CurrencyButton'
import { Column, Row } from 'src/components/Flex'
import { CurrencyInput } from 'src/components/Input'
import SelectAccountModal from 'src/components/SelectAccountModal'
import { FIAT_CURRENCIES, TOKEN_CURRENCIES } from 'src/constants/currencies'
import { useSelectAccountModal } from 'src/hooks/useModal'
import { ThemedText } from 'src/theme/components'
import { ArrowDown } from 'src/theme/components/icons'
import { ChevronDown } from 'src/theme/components/icons'
import { styled } from 'styled-components'

const Content = styled(Column)`
max-width: 460px;
width: 100%;
align-items: normal;
gap: 24px;
margin: 0 auto;
margin-top: 120px;
`

const SwapCard = styled(Row)`
const SwapCard = styled(Column)`
width: 100%;
background-color: ${({ theme }) => theme.bg3};
border-radius: 12px;
padding: 12px 16px;
background-color: ${({ theme }) => theme.bg3};
border-top-left-radius: 12px;
border-top-right-radius: 12px;
`

const FiatCurrenyCard = styled(Row)`
width: 100%;
justify-content: space-between;
`

const SwapCardContent = styled(Column)`
flex: 1;
align-items: flex-start;

input {
width: 100%;
padding-top: 12px;
padding-bottom: 24px;
font-size: 42px;
font-weight: 600;
color: ${({ theme }) => theme.neutral1};

&::placeholder {
color: ${({ theme }) => theme.neutral2};
}
width: 100%;
padding: 34px 0 42px 0;
`

const TokenCurrencyButton = styled(CurrencyButton)`
gap: 8px;
background-color: transparent;
border: none;
margin: 8px 0 12px 0;

img {
width: 18px;
height: 18px;
}
`

const SwitchButton = styled.button`
display: flex;
align-items: center;
justify-content: center;
const PresetAmountButton = styled(ChipButton)`
background-color: ${({ theme }) => theme.bg1};
color: ${({ theme }) => theme.neutral1};
border: 1px solid ${({ theme }) => theme.border};
padding: 6px 12px;
`

const RampCard = styled(Row)`
justify-content: space-between;
width: 100%;
padding: 12px 16px;
background-color: ${({ theme }) => theme.bg3};
border: 4px solid ${({ theme }) => theme.bg1};
border-radius: 6px;
cursor: pointer;
height: 32px;
width: 32px;
box-sizing: content-box;
margin: -18px 0;
z-index: 1;
padding: 0;
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
`

const AccountButton = styled(PrimaryButton)`
width: auto;
align-items: center;
gap: 4px;
padding: 8px;
`

export default function SwapPage() {
const [rampMode, setRampMode] = useState<'on' | 'off'>('on')

Check warning on line 77 in client/src/pages/Swap.tsx

View workflow job for this annotation

GitHub Actions / lint

'rampMode' is assigned a value but never used

Check warning on line 77 in client/src/pages/Swap.tsx

View workflow job for this annotation

GitHub Actions / lint

'setRampMode' is assigned a value but never used
const [fiatCurrency, setFiatCurrency] = useState(FIAT_CURRENCIES['EUR'])

Check warning on line 78 in client/src/pages/Swap.tsx

View workflow job for this annotation

GitHub Actions / lint

'setFiatCurrency' is assigned a value but never used
const [tokenCurrency, setTokenCurrency] = useState(TOKEN_CURRENCIES['USDC'])

Check warning on line 79 in client/src/pages/Swap.tsx

View workflow job for this annotation

GitHub Actions / lint

'setTokenCurrency' is assigned a value but never used

const [inputSendValue, setInputSendValue] = useState('')
const [inputReceiveValue, setInputReceiveValue] = useState('')

Check warning on line 82 in client/src/pages/Swap.tsx

View workflow job for this annotation

GitHub Actions / lint

'inputReceiveValue' is assigned a value but never used

const [, toggleSelectAccountModal] = useSelectAccountModal()

const handleReceiveChange = (event: ChangeEvent<HTMLInputElement>) => {

Check warning on line 86 in client/src/pages/Swap.tsx

View workflow job for this annotation

GitHub Actions / lint

'handleReceiveChange' is assigned a value but never used
const inputValue = event.target.value
const numericValue = inputValue.replace(/[^0-9]/g, '')
setInputReceiveValue(numericValue)
Expand All @@ -77,43 +95,55 @@
setInputSendValue(numericValue)
}

const handleChangeClick = () => {
setRampMode((state) => (state == 'off' ? 'on' : 'off'))
setInputSendValue(inputReceiveValue)
setInputReceiveValue(inputSendValue)
}

return (
<Content>
<ThemedText.HeadlineLarge>Swap</ThemedText.HeadlineLarge>
<Content gap={24}>
<Row gap={16}>
<ChipButton active>Buy</ChipButton>
<ChipButton>Sell</ChipButton>
</Row>

<Column gap={12}>
<Column>
<Column gap={2}>
<SwapCard as="label">
<SwapCardContent>
<ThemedText.Subtitle fontSize={12}>Send</ThemedText.Subtitle>
<CurrencyInput placeholder="0.0" value={inputSendValue} onChange={handleSendChange} />
</SwapCardContent>
<FiatCurrenyCard>
<ThemedText.Subtitle fontSize={14} color="neutral1">
You&apos;re buying
</ThemedText.Subtitle>

<CurrencyButton selectedCurrency={rampMode === 'on' ? FIAT_CURRENCIES['EUR'] : TOKEN_CURRENCIES['USDC']} />
</SwapCard>

<SwitchButton onClick={handleChangeClick}>
<ArrowDown width={18} height={18} />
</SwitchButton>
<CurrencyButton selectedCurrency={fiatCurrency} />
</FiatCurrenyCard>

<SwapCard as="label">
<SwapCardContent>
<ThemedText.Subtitle>Receive</ThemedText.Subtitle>
<CurrencyInput placeholder="0.0" value={inputReceiveValue} onChange={handleReceiveChange} />
<CurrencyInput
placeholder={`0${fiatCurrency.symbol}`}
value={inputSendValue}
onChange={handleSendChange}
/>

<TokenCurrencyButton selectedCurrency={tokenCurrency} />

<Row gap={8}>
<PresetAmountButton>100{fiatCurrency.symbol}</PresetAmountButton>
<PresetAmountButton>300{fiatCurrency.symbol}</PresetAmountButton>
<PresetAmountButton>1000{fiatCurrency.symbol}</PresetAmountButton>
</Row>
</SwapCardContent>

<CurrencyButton selectedCurrency={rampMode === 'off' ? FIAT_CURRENCIES['EUR'] : TOKEN_CURRENCIES['USDC']} />
</SwapCard>

<RampCard>
<ThemedText.BodyPrimary>From</ThemedText.BodyPrimary>

<AccountButton onClick={toggleSelectAccountModal}>
<span>Select account</span>
<ChevronDown width={14} height={14} />
</AccountButton>
</RampCard>
</Column>

<PrimaryButton>Swap</PrimaryButton>
<PrimaryButton disabled>Enter amount</PrimaryButton>
</Column>

<SelectAccountModal />
</Content>
)
}
1 change: 1 addition & 0 deletions client/src/state/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum ModalType {
WALLET_CONNECT,
WALLET_OVERVIEW,
PROOF_GENERATION,
SELECT_ACCOUNT,
}

export type ApplicationSlice = State & Actions
Expand Down
Loading
Loading