address feedback

This commit is contained in:
saml33 2022-12-29 21:59:56 +11:00
parent d8658574f7
commit 9f57d84349
15 changed files with 381 additions and 314 deletions

View File

@ -0,0 +1,85 @@
import { XMarkIcon } from '@heroicons/react/20/solid'
import { useTranslation } from 'next-i18next'
import { useEffect, useState } from 'react'
import mangoStore from '@store/mangoStore'
import ButtonGroup from '../forms/ButtonGroup'
import Input from '../forms/Input'
import Button, { IconButton, LinkButton } from '../shared/Button'
const slippagePresets = ['0.1', '0.5', '1', '2']
const SlippageSettings = ({ onClose }: { onClose: () => void }) => {
const { t } = useTranslation('common')
const slippage = mangoStore((s) => s.swap.slippage)
const set = mangoStore((s) => s.set)
const [showCustomSlippageForm, setShowCustomSlippageForm] = useState(false)
const [inputValue, setInputValue] = useState(slippage.toString())
const handleSetSlippage = (slippage: string) => {
set((s) => {
s.swap.slippage = parseFloat(slippage)
})
}
useEffect(() => {
if (!slippagePresets.includes(slippage.toString())) {
setShowCustomSlippageForm(true)
}
}, [])
return (
<>
<h3 className="mb-3">{t('swap:slippage')}</h3>
<IconButton
className="absolute top-2 right-2 text-th-fgd-3"
onClick={onClose}
hideBg
>
<XMarkIcon className="h-6 w-6" />
</IconButton>
<div className="mt-4">
<div className="mb-2 flex justify-between">
<p className="text-th-fgd-2">{`${t('max')} ${t('swap:slippage')}`}</p>
<LinkButton
onClick={() => setShowCustomSlippageForm(!showCustomSlippageForm)}
>
{showCustomSlippageForm ? 'Preset' : t('settings:custom')}
</LinkButton>
</div>
{showCustomSlippageForm ? (
<>
<Input
type="text"
placeholder="0.00"
value={inputValue}
onChange={(e: any) => setInputValue(e.target.value)}
suffix="%"
/>
<Button
disabled={
!inputValue ||
isNaN(Number(inputValue)) ||
parseFloat(inputValue) <= 0
}
className="mt-4"
onClick={() => handleSetSlippage(inputValue)}
>
{t('save')}
</Button>
</>
) : (
<ButtonGroup
activeValue={slippage.toString()}
className="h-10 font-mono"
onChange={(v) => handleSetSlippage(v)}
unit="%"
values={slippagePresets}
/>
)}
</div>
</>
)
}
export default SlippageSettings

View File

@ -1,11 +1,10 @@
import { useState, useCallback, useEffect, useMemo } from 'react'
import { PublicKey } from '@solana/web3.js'
import {
AdjustmentsHorizontalIcon,
ArrowDownIcon,
Cog8ToothIcon,
ExclamationCircleIcon,
LinkIcon,
PencilIcon,
} from '@heroicons/react/20/solid'
import NumberFormat, {
NumberFormatValues,
@ -20,11 +19,11 @@ import useDebounce from '../shared/useDebounce'
import { useTranslation } from 'next-i18next'
import SwapFormTokenList from './SwapFormTokenList'
import { Transition } from '@headlessui/react'
import Button, { IconButton } from '../shared/Button'
import Button from '../shared/Button'
import Loading from '../shared/Loading'
import { EnterBottomExitBottom } from '../shared/Transitions'
import useJupiterRoutes from './useJupiterRoutes'
import SwapSettings from './SwapSettings'
import SlippageSettings from './SlippageSettings'
import SheenLoader from '../shared/SheenLoader'
import { HealthType } from '@blockworks-foundation/mango-v4'
import {
@ -45,8 +44,8 @@ import SwapSlider from './SwapSlider'
import TokenVaultWarnings from '@components/shared/TokenVaultWarnings'
import MaxSwapAmount from './MaxSwapAmount'
import PercentageSelectButtons from './PercentageSelectButtons'
import Tooltip from '@components/shared/Tooltip'
import useIpAddress from 'hooks/useIpAddress'
import Checkbox from '@components/forms/Checkbox'
const MAX_DIGITS = 11
export const withValueLimit = (values: NumberFormatValues): boolean => {
@ -262,13 +261,19 @@ const SwapForm = () => {
return !!amountInAsDecimal.toNumber() && connected && !selectedRoute
}, [amountInAsDecimal, connected, selectedRoute])
const handleSetMargin = () => {
set((s) => {
s.swap.margin = !s.swap.margin
})
}
return (
<ContentBox
hidePadding
// showBackground
className="relative overflow-hidden border-x-0 md:border-l md:border-r-0 md:border-t-0 md:border-b-0"
>
<div className="px-6 pb-8 pt-3">
<div className="">
<Transition
className="absolute top-0 left-0 z-10 h-full w-full bg-th-bkg-1 pb-0"
show={showConfirm}
@ -286,8 +291,6 @@ const SwapForm = () => {
routes={routes}
selectedRoute={selectedRoute}
setSelectedRoute={setSelectedRoute}
maintProjectedHealth={maintProjectedHealth}
setShowSettings={setShowSettings}
/>
</Transition>
<EnterBottomExitBottom
@ -309,162 +312,164 @@ const SwapForm = () => {
className="thin-scroll absolute bottom-0 left-0 z-10 h-full w-full overflow-auto bg-th-bkg-1 p-6 pb-0"
show={showSettings}
>
<SwapSettings onClose={() => setShowSettings(false)} />
<SlippageSettings onClose={() => setShowSettings(false)} />
</EnterBottomExitBottom>
<div className="flex items-center justify-end">
<div id="swap-step-one">
<IconButton
className="-mr-2 text-th-fgd-3"
hideBg
onClick={() => setShowSettings(true)}
size="small"
>
<Cog8ToothIcon className="h-4 w-4" />
</IconButton>
</div>
</div>
<div className="mb-2 flex items-end justify-between">
<p className="text-th-fgd-2 lg:text-base">{t('swap:pay')}</p>
<MaxSwapAmount
useMargin={useMargin}
setAmountIn={(v) => setAmountInFormValue(v, true)}
/>
</div>
<div className="mb-3 grid grid-cols-2" id="swap-step-two">
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-input-border bg-th-input-bkg">
<TokenSelect
bank={
inputBank || group?.banksMapByName.get(INPUT_TOKEN_DEFAULT)?.[0]
}
showTokenList={setShowTokenSelect}
type="input"
<div className="p-6">
<div className="mb-2 flex items-end justify-between">
<p className="text-th-fgd-2 lg:text-base">{t('swap:pay')}</p>
<MaxSwapAmount
useMargin={useMargin}
setAmountIn={(v) => setAmountInFormValue(v, true)}
/>
</div>
<div className="col-span-1 flex h-[54px]">
<NumberFormat
inputMode="decimal"
thousandSeparator=","
allowNegative={false}
isNumericString={true}
decimalScale={inputBank?.mintDecimals || 6}
name="amountIn"
id="amountIn"
className="w-full rounded-l-none rounded-r-lg border border-th-input-border bg-th-input-bkg p-3 text-right font-mono text-base font-bold text-th-fgd-1 focus:outline-none lg:text-lg xl:text-xl"
placeholder="0.00"
value={amountInFormValue}
onValueChange={handleAmountInChange}
isAllowed={withValueLimit}
/>
</div>
</div>
<div className="-mb-2 flex justify-center">
<button
className="rounded-full border border-th-bkg-4 p-1.5 text-th-fgd-3 md:hover:text-th-active"
onClick={handleSwitchTokens}
>
<ArrowDownIcon
className="h-5 w-5"
style={
animateSwitchArrow % 2 == 0
? { transform: 'rotate(0deg)' }
: { transform: 'rotate(360deg)' }
}
/>
</button>
</div>
<p className="mb-2 text-th-fgd-2 lg:text-base">{t('swap:receive')}</p>
<div id="swap-step-three" className="mb-3 grid grid-cols-2">
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-input-border bg-th-input-bkg">
<TokenSelect
bank={
outputBank ||
group?.banksMapByName.get(OUTPUT_TOKEN_DEFAULT)?.[0]
}
showTokenList={setShowTokenSelect}
type="output"
/>
</div>
<div className="flex h-[54px] w-full items-center justify-end rounded-r-lg border border-th-input-border text-right text-lg font-bold text-th-fgd-3 xl:text-xl">
{loadingSwapDetails ? (
<div className="w-full">
<SheenLoader className="flex flex-1 rounded-l-none">
<div className="h-[52px] w-full rounded-r-lg bg-th-bkg-4" />
</SheenLoader>
</div>
) : (
<div className="mb-3 grid grid-cols-2" id="swap-step-two">
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-input-border bg-th-input-bkg">
<TokenSelect
bank={
inputBank ||
group?.banksMapByName.get(INPUT_TOKEN_DEFAULT)?.[0]
}
showTokenList={setShowTokenSelect}
type="input"
/>
</div>
<div className="col-span-1 flex h-[54px]">
<NumberFormat
inputMode="decimal"
thousandSeparator=","
allowNegative={false}
isNumericString={true}
decimalScale={outputBank?.mintDecimals || 6}
name="amountOut"
id="amountOut"
className="w-full rounded-l-none rounded-r-lg bg-th-input-bkg p-3 text-right font-mono text-base font-bold text-th-fgd-1 focus:outline-none lg:text-lg xl:text-xl"
decimalScale={inputBank?.mintDecimals || 6}
name="amountIn"
id="amountIn"
className="w-full rounded-l-none rounded-r-lg border border-th-input-border bg-th-input-bkg p-3 text-right font-mono text-base font-bold text-th-fgd-1 focus:outline-none lg:text-lg xl:text-xl"
placeholder="0.00"
value={amountOutFormValue}
onValueChange={handleAmountOutChange}
value={amountInFormValue}
onValueChange={handleAmountInChange}
isAllowed={withValueLimit}
/>
)}
</div>
</div>
{swapFormSizeUi === 'slider' ? (
<SwapSlider
useMargin={useMargin}
amount={amountInAsDecimal.toNumber()}
onChange={(v) => setAmountInFormValue(v, true)}
step={1 / 10 ** (inputBank?.mintDecimals || 6)}
/>
) : (
<PercentageSelectButtons
amountIn={amountInAsDecimal.toString()}
setAmountIn={(v) => setAmountInFormValue(v, true)}
useMargin={useMargin}
/>
)}
{ipAllowed ? (
<SwapFormSubmitButton
loadingSwapDetails={loadingSwapDetails}
useMargin={useMargin}
setShowConfirm={setShowConfirm}
amountIn={amountInAsDecimal}
inputSymbol={inputBank?.name}
amountOut={
selectedRoute ? amountOutAsDecimal.toNumber() : undefined
}
/>
) : (
<div className="mt-6 mb-4 flex-grow">
<div className="flex">
<Button disabled className="flex-grow">
<span>
{t('country-not-allowed', {
country: ipCountry ? `(${ipCountry})` : '(Unknown)',
})}
</span>
</Button>
</div>
</div>
)}
{group && inputBank ? <TokenVaultWarnings bank={inputBank} /> : null}
<div className="space-y-2">
<div id="swap-step-four">
<HealthImpact maintProjectedHealth={maintProjectedHealth} />
</div>
<div className="flex justify-between">
<Tooltip content={t('swap:tooltip-max-slippage')} delay={250}>
<p className="tooltip-underline text-sm text-th-fgd-3">
{`${t('max')} ${t('swap:slippage')}`}
</p>
</Tooltip>
<div className="flex items-center">
<p className="text-right font-mono text-sm text-th-fgd-2">
{slippage}%
</p>
<PencilIcon
className="default-transition ml-2 h-4 w-4 md:hover:cursor-pointer md:hover:text-th-active"
onClick={() => setShowSettings(true)}
<div className="-mb-2 flex justify-center">
<button
className="rounded-full border border-th-bkg-4 p-1.5 text-th-fgd-3 md:hover:text-th-active"
onClick={handleSwitchTokens}
>
<ArrowDownIcon
className="h-5 w-5"
style={
animateSwitchArrow % 2 == 0
? { transform: 'rotate(0deg)' }
: { transform: 'rotate(360deg)' }
}
/>
</button>
</div>
<p className="mb-2 text-th-fgd-2 lg:text-base">{t('swap:receive')}</p>
<div id="swap-step-three" className="mb-3 grid grid-cols-2">
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-input-border bg-th-input-bkg">
<TokenSelect
bank={
outputBank ||
group?.banksMapByName.get(OUTPUT_TOKEN_DEFAULT)?.[0]
}
showTokenList={setShowTokenSelect}
type="output"
/>
</div>
<div className="flex h-[54px] w-full items-center justify-end rounded-r-lg border border-th-input-border text-right text-lg font-bold text-th-fgd-3 xl:text-xl">
{loadingSwapDetails ? (
<div className="w-full">
<SheenLoader className="flex flex-1 rounded-l-none">
<div className="h-[52px] w-full rounded-r-lg bg-th-bkg-4" />
</SheenLoader>
</div>
) : (
<NumberFormat
inputMode="decimal"
thousandSeparator=","
allowNegative={false}
isNumericString={true}
decimalScale={outputBank?.mintDecimals || 6}
name="amountOut"
id="amountOut"
className="w-full rounded-l-none rounded-r-lg bg-th-input-bkg p-3 text-right font-mono text-base font-bold text-th-fgd-1 focus:outline-none lg:text-lg xl:text-xl"
placeholder="0.00"
value={amountOutFormValue}
onValueChange={handleAmountOutChange}
/>
)}
</div>
</div>
{swapFormSizeUi === 'slider' ? (
<SwapSlider
useMargin={useMargin}
amount={amountInAsDecimal.toNumber()}
onChange={(v) => setAmountInFormValue(v, true)}
step={1 / 10 ** (inputBank?.mintDecimals || 6)}
/>
) : (
<PercentageSelectButtons
amountIn={amountInAsDecimal.toString()}
setAmountIn={(v) => setAmountInFormValue(v, true)}
useMargin={useMargin}
/>
)}
{ipAllowed ? (
<SwapFormSubmitButton
loadingSwapDetails={loadingSwapDetails}
useMargin={useMargin}
setShowConfirm={setShowConfirm}
amountIn={amountInAsDecimal}
inputSymbol={inputBank?.name}
amountOut={
selectedRoute ? amountOutAsDecimal.toNumber() : undefined
}
/>
) : (
<div className="mt-6 mb-4 flex-grow">
<div className="flex">
<Button disabled className="flex-grow">
<span>
{t('country-not-allowed', {
country: ipCountry ? `(${ipCountry})` : '(Unknown)',
})}
</span>
</Button>
</div>
</div>
)}
{group && inputBank ? <TokenVaultWarnings bank={inputBank} /> : null}
<div className="space-y-2">
<div id="swap-step-four">
<HealthImpact maintProjectedHealth={maintProjectedHealth} />
</div>
<div className="flex justify-between">
<p className="text-sm text-th-fgd-3">{t('swap:price-impact')}</p>
<p className="text-right font-mono text-sm text-th-fgd-2">
{selectedRoute?.priceImpactPct
? selectedRoute?.priceImpactPct * 100 < 0.1
? '<0.1%'
: `${(selectedRoute?.priceImpactPct * 100).toFixed(2)}%`
: ''}
</p>
</div>
</div>
</div>
<div className="flex items-center justify-between border-t border-th-bkg-3 px-6 py-4">
<p>{`${t('swap')} ${t('settings')}`}</p>
<div className="flex items-center space-x-5">
<Checkbox checked={useMargin} onChange={handleSetMargin}>
<span className="text-xs text-th-fgd-3">{t('trade:margin')}</span>
</Checkbox>
<div id="swap-step-one">
<button
className="default-transition flex items-center text-th-fgd-3 focus:outline-none md:hover:text-th-active"
onClick={() => setShowSettings(true)}
>
<AdjustmentsHorizontalIcon className="mr-1.5 h-4 w-4" />
<span className="text-xs">{slippage}%</span>
</button>
</div>
</div>
</div>

View File

@ -39,18 +39,16 @@ import useLocalStorageState from 'hooks/useLocalStorageState'
import { Howl } from 'howler'
import { INITIAL_SOUND_SETTINGS } from '@components/settings/SoundSettings'
import Tooltip from '@components/shared/Tooltip'
import HealthImpact from '@components/shared/HealthImpact'
import { Disclosure } from '@headlessui/react'
import RoutesModal from './RoutesModal'
type JupiterRouteInfoProps = {
amountIn: Decimal
maintProjectedHealth: number
onClose: () => void
routes: RouteInfo[] | undefined
selectedRoute: RouteInfo | undefined
setSelectedRoute: Dispatch<SetStateAction<RouteInfo | undefined>>
slippage: number
setShowSettings: (x: boolean) => void
}
const deserializeJupiterIxAndAlt = async (
@ -147,14 +145,14 @@ const successSound = new Howl({
const SwapReviewRouteInfo = ({
amountIn,
maintProjectedHealth,
onClose,
routes,
selectedRoute,
setShowSettings,
setSelectedRoute,
}: JupiterRouteInfoProps) => {
const { t } = useTranslation(['common', 'trade'])
const slippage = mangoStore((s) => s.swap.slippage)
const [showRoutesModal, setShowRoutesModal] = useState<boolean>(false)
const [swapRate, setSwapRate] = useState<boolean>(false)
const [feeValue] = useState<number | null>(null)
const [submitting, setSubmitting] = useState(false)
@ -336,7 +334,7 @@ const SwapReviewRouteInfo = ({
</div>
<div className="space-y-2 overflow-auto px-6">
<div className="flex justify-between">
<p className="text-sm text-th-fgd-3">{t('swap:rate')}</p>
<p className="text-sm text-th-fgd-3">{t('price')}</p>
<div>
<div className="flex items-center justify-end">
<p className="text-right font-mono text-sm text-th-fgd-2">
@ -390,67 +388,111 @@ const SwapReviewRouteInfo = ({
</div>
</div>
</div>
<HealthImpact maintProjectedHealth={maintProjectedHealth} />
<div className="flex justify-between">
<Tooltip content={t('swap:tooltip-max-slippage')} delay={250}>
<p className="tooltip-underline text-sm text-th-fgd-3">{`${t(
'max'
)} ${t('swap:slippage')}`}</p>
</Tooltip>
<div className="flex items-center">
{slippage}%
<PencilIcon
className="default-transition ml-2 h-4 w-4 md:hover:cursor-pointer md:hover:text-th-active"
onClick={() => setShowSettings(true)}
/>
</div>
<p className="text-sm text-th-fgd-3">
{t('swap:minimum-received')}
</p>
{outputTokenInfo?.decimals ? (
<p className="text-right font-mono text-sm text-th-fgd-2">
{formatDecimal(
selectedRoute?.otherAmountThreshold /
10 ** outputTokenInfo.decimals || 1,
outputTokenInfo.decimals
)}{' '}
<span className="font-body tracking-wide">
{outputTokenInfo?.symbol}
</span>
</p>
) : null}
</div>
<div className="flex justify-between">
<p className="text-sm text-th-fgd-3">{t('swap:price-impact')}</p>
<p className="text-right font-mono text-sm text-th-fgd-2">
{selectedRoute?.priceImpactPct * 100 < 0.1
? '<0.1%'
: `${(selectedRoute?.priceImpactPct * 100).toFixed(2)}%`}
</p>
</div>
{borrowAmount ? (
<>
<div className="flex justify-between">
<Tooltip
content={
balance
? t('swap:tooltip-borrow-balance', {
balance: formatFixedDecimals(balance),
borrowAmount: formatFixedDecimals(borrowAmount),
token: inputTokenInfo?.symbol,
})
: t('swap:tooltip-borrow-no-balance', {
borrowAmount: formatFixedDecimals(borrowAmount),
token: inputTokenInfo?.symbol,
})
}
>
<p className="tooltip-underline text-sm text-th-fgd-3">
{t('borrow-amount')}
</p>
</Tooltip>
<p className="text-right font-mono text-sm text-th-fgd-2">
~{formatFixedDecimals(borrowAmount)}{' '}
<span className="font-body tracking-wide">
{inputTokenInfo?.symbol}
</span>
<div className="flex justify-between">
<Tooltip
content={
balance
? t('swap:tooltip-borrow-balance', {
balance: formatFixedDecimals(balance),
borrowAmount: formatFixedDecimals(borrowAmount),
token: inputTokenInfo?.symbol,
rate: formatDecimal(inputBank!.getBorrowRateUi(), 2, {
fixed: true,
}),
})
: t('swap:tooltip-borrow-no-balance', {
borrowAmount: formatFixedDecimals(borrowAmount),
token: inputTokenInfo?.symbol,
rate: formatDecimal(inputBank!.getBorrowRateUi(), 2, {
fixed: true,
}),
})
}
delay={250}
>
<p className="tooltip-underline text-sm text-th-fgd-3">
{t('borrow-amount')}
</p>
</div>
<div className="flex justify-between">
<Tooltip content={t('tooltip-borrow-rate')}>
<p className="tooltip-underline text-sm text-th-fgd-3">
{t('borrow-rate')}
</p>
</Tooltip>
<p className="text-right font-mono text-sm text-th-down">
{formatDecimal(inputBank!.getBorrowRateUi(), 2, {
fixed: true,
})}
%
</p>
</div>
</>
</Tooltip>
<p className="text-right font-mono text-sm text-th-fgd-2">
~{formatFixedDecimals(borrowAmount)}{' '}
<span className="font-body tracking-wide">
{inputTokenInfo?.symbol}
</span>
</p>
</div>
) : null}
<div className="flex items-center justify-between">
<p className="text-sm text-th-fgd-3">{t('swap:swap-route')}</p>
<div
className="flex items-center text-th-fgd-2 md:hover:cursor-pointer md:hover:text-th-fgd-3"
role="button"
onClick={() => setShowRoutesModal(true)}
>
<span className="overflow-ellipsis whitespace-nowrap">
{selectedRoute?.marketInfos.map((info, index) => {
let includeSeparator = false
if (
selectedRoute?.marketInfos.length > 1 &&
index !== selectedRoute?.marketInfos.length - 1
) {
includeSeparator = true
}
return (
<span key={index}>{`${info?.label} ${
includeSeparator ? 'x ' : ''
}`}</span>
)
})}
</span>
<PencilIcon className="ml-2 h-4 w-4 hover:text-th-active" />
</div>
</div>
</div>
</div>
<div className="p-6">
<div className="mb-4 flex items-center justify-center">
<Button
onClick={onSwap}
className="flex w-full items-center justify-center text-base"
size="large"
>
{submitting ? (
<Loading className="mr-2 h-5 w-5" />
) : (
<div className="flex items-center">
<ArrowsRightLeftIcon className="mr-2 h-5 w-5" />
{t('swap')}
</div>
)}
</Button>
</div>
<div className="rounded-md bg-th-bkg-2">
<Disclosure>
{({ open }) => (
@ -466,7 +508,10 @@ const SwapReviewRouteInfo = ({
<Disclosure.Panel className="space-y-2 p-3 pt-0">
{borrowAmount ? (
<div className="flex justify-between">
<Tooltip content={t('loan-origination-fee-tooltip')}>
<Tooltip
content={t('loan-origination-fee-tooltip')}
delay={250}
>
<p className="tooltip-underline text-sm text-th-fgd-3">
{t('loan-origination-fee')}
</p>
@ -480,7 +525,12 @@ const SwapReviewRouteInfo = ({
)}{' '}
<span className="font-body tracking-wide">
{inputBank!.name}
</span>
</span>{' '}
(
{formatFixedDecimals(
inputBank!.loanOriginationFeeRate.toNumber() * 100
)}
%)
</p>
</div>
) : null}
@ -533,23 +583,18 @@ const SwapReviewRouteInfo = ({
)}
</Disclosure>
</div>
<div className="mt-4 flex items-center justify-center">
<Button
onClick={onSwap}
className="flex w-full items-center justify-center text-base"
size="large"
>
{submitting ? (
<Loading className="mr-2 h-5 w-5" />
) : (
<div className="flex items-center">
<ArrowsRightLeftIcon className="mr-2 h-5 w-5" />
{t('swap')}
</div>
)}
</Button>
</div>
</div>
{showRoutesModal ? (
<RoutesModal
show={showRoutesModal}
onClose={() => setShowRoutesModal(false)}
setSelectedRoute={setSelectedRoute}
selectedRoute={selectedRoute}
routes={routes}
inputTokenSymbol={inputTokenInfo!.name}
outputTokenInfo={outputTokenInfo}
/>
) : null}
</div>
) : null
}

View File

@ -1,78 +0,0 @@
import { XMarkIcon } from '@heroicons/react/20/solid'
import { useTranslation } from 'next-i18next'
import { useState } from 'react'
import mangoStore from '@store/mangoStore'
import ButtonGroup from '../forms/ButtonGroup'
import Input from '../forms/Input'
import Switch from '../forms/Switch'
import { IconButton } from '../shared/Button'
const slippagePresets = ['0.1', '0.5', '1', '2']
const SwapSettings = ({ onClose }: { onClose: () => void }) => {
const { t } = useTranslation('common')
const margin = mangoStore((s) => s.swap.margin)
const slippage = mangoStore((s) => s.swap.slippage)
const set = mangoStore((s) => s.set)
const [showCustomSlippageForm] = useState(false)
const [inputValue, setInputValue] = useState('')
const handleSetMargin = () => {
set((s) => {
s.swap.margin = !s.swap.margin
})
}
const handleSetSlippage = (slippage: string) => {
set((s) => {
s.swap.slippage = parseFloat(slippage)
})
}
return (
<>
<h3 className="mb-3">{t('settings')}</h3>
<IconButton
className="absolute top-2 right-2 text-th-fgd-3"
onClick={onClose}
hideBg
>
<XMarkIcon className="h-6 w-6" />
</IconButton>
<div className="mt-4">
<p className="mb-2 text-th-fgd-2">{`${t('max')} ${t(
'swap:slippage'
)}`}</p>
{showCustomSlippageForm ? (
<Input
type="text"
placeholder="0.00"
value={inputValue}
onChange={(e: any) => setInputValue(e.target.value)}
suffix="%"
/>
) : (
<ButtonGroup
activeValue={slippage.toString()}
className="h-10 font-mono"
onChange={(v) => handleSetSlippage(v)}
unit="%"
values={slippagePresets}
/>
)}
</div>
<div className="mt-6 flex items-center justify-between rounded-md bg-th-bkg-2 p-3">
<p className="text-th-fgd-2">{t('swap:use-margin')}</p>
<Switch
className="text-th-fgd-3"
checked={margin}
onChange={handleSetMargin}
/>
</div>
</>
)
}
export default SwapSettings

View File

@ -237,7 +237,7 @@ const SwapTokenChart = () => {
)}
</div>
</div>
<div className="mt-2 h-40 w-auto md:h-72">
<div className="mt-2 h-40 w-auto md:h-80">
<div className="absolute top-[2px] right-0 -mb-2 flex justify-end">
<ChartRangeButtons
activeValue={daysToShow}

View File

@ -10,14 +10,16 @@
"minimum-received": "Minimum Received",
"no-history": "No swap history",
"pay": "You Pay",
"price-impact": "Price Impact",
"rate": "Rate",
"receive": "You Receive",
"review-swap": "Review Swap",
"show-fees": "Show Fees",
"slippage": "Slippage",
"swap-history": "Swap History",
"tooltip-borrow-balance": "You'll use your {{balance}} {{token}} balance and borrow {{borrowAmount}} {{token}} to execute this swap",
"swap-route": "Swap Route",
"tooltip-borrow-balance": "You'll use your {{balance}} {{token}} balance and borrow {{borrowAmount}} {{token}} to execute this swap. The current {{token}} variable borrow rate is {{rate}}%",
"tooltip-borrow-no-balance": "You'll borrow {{borrowAmount}} {{token}} to execute this swap. The current {{token}} variable borrow rate is {{rate}}%",
"tooltip-max-slippage": "If price slips beyond your maximum slippage your swap will not be executed",
"tooltip-borrow-no-balance": "You'll borrow {{borrowAmount}} {{token}} to execute this swap",
"use-margin": "Allow Margin"
}

View File

@ -38,7 +38,7 @@
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-slippage": "An estimate of the differnece between the current price and the price your trade will be executed at",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"trade-sounds-tooltip": "Play a sound alert for every new trade",
"trades": "Trades",
"unsettled": "Unsettled"

View File

@ -10,12 +10,14 @@
"minimum-received": "Minimum Received",
"no-history": "No swap history",
"pay": "You Pay",
"price-impact": "Price Impact",
"rate": "Rate",
"receive": "You Receive",
"review-swap": "Review Swap",
"show-fees": "Show Fees",
"slippage": "Slippage",
"swap-history": "Swap History",
"swap-route": "Swap Route",
"tooltip-borrow-balance": "You'll use your {{balance}} {{token}} balance and borrow {{borrowAmount}} {{token}} to execute this swap",
"tooltip-borrow-no-balance": "You'll borrow {{borrowAmount}} {{token}} to execute this swap",
"tooltip-max-slippage": "If price slips beyond your maximum slippage your swap will not be executed",

View File

@ -38,7 +38,7 @@
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-slippage": "An estimate of the differnece between the current price and the price your trade will be executed at",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"trade-sounds-tooltip": "Play a sound alert for every new trade",
"trades": "Trades",
"unsettled": "Unsettled"

View File

@ -10,12 +10,14 @@
"minimum-received": "Minimum Received",
"no-history": "No swap history",
"pay": "You Pay",
"price-impact": "Price Impact",
"rate": "Rate",
"receive": "You Receive",
"review-swap": "Review Swap",
"show-fees": "Show Fees",
"slippage": "Slippage",
"swap-history": "Swap History",
"swap-route": "Swap Route",
"tooltip-borrow-balance": "You'll use your {{balance}} {{token}} balance and borrow {{borrowAmount}} {{token}} to execute this swap",
"tooltip-borrow-no-balance": "You'll borrow {{borrowAmount}} {{token}} to execute this swap",
"tooltip-max-slippage": "If price slips beyond your maximum slippage your swap will not be executed",

View File

@ -38,7 +38,7 @@
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-slippage": "An estimate of the differnece between the current price and the price your trade will be executed at",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"trade-sounds-tooltip": "Play a sound alert for every new trade",
"trades": "Trades",
"unsettled": "Unsettled"

View File

@ -10,12 +10,14 @@
"minimum-received": "Minimum Received",
"no-history": "No swap history",
"pay": "You Pay",
"price-impact": "Price Impact",
"rate": "Rate",
"receive": "You Receive",
"review-swap": "Review Swap",
"show-fees": "Show Fees",
"slippage": "Slippage",
"swap-history": "Swap History",
"swap-route": "Swap Route",
"tooltip-borrow-balance": "You'll use your {{balance}} {{token}} balance and borrow {{borrowAmount}} {{token}} to execute this swap",
"tooltip-borrow-no-balance": "You'll borrow {{borrowAmount}} {{token}} to execute this swap",
"tooltip-max-slippage": "If price slips beyond your maximum slippage your swap will not be executed",

View File

@ -38,7 +38,7 @@
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-slippage": "An estimate of the differnece between the current price and the price your trade will be executed at",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"trade-sounds-tooltip": "Play a sound alert for every new trade",
"trades": "Trades",
"unsettled": "Unsettled"

View File

@ -10,12 +10,14 @@
"minimum-received": "Minimum Received",
"no-history": "No swap history",
"pay": "You Pay",
"price-impact": "Price Impact",
"rate": "Rate",
"receive": "You Receive",
"review-swap": "Review Swap",
"show-fees": "Show Fees",
"slippage": "Slippage",
"swap-history": "Swap History",
"swap-route": "Swap Route",
"tooltip-borrow-balance": "You'll use your {{balance}} {{token}} balance and borrow {{borrowAmount}} {{token}} to execute this swap",
"tooltip-borrow-no-balance": "You'll borrow {{borrowAmount}} {{token}} to execute this swap",
"tooltip-max-slippage": "If price slips beyond your maximum slippage your swap will not be executed",

View File

@ -38,7 +38,7 @@
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-slippage": "An estimate of the differnece between the current price and the price your trade will be executed at",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"trade-sounds-tooltip": "Play a sound alert for every new trade",
"trades": "Trades",
"unsettled": "Unsettled"