Skip to content
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
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
- When creating commits, follow the Git Safety Protocol (see session notes)
- Main branch is `develop` - use this for PRs
- Branch naming: Use descriptive names (e.g., `feat_gridplus`, `fix_wallet_connect`)
- When opening PRs (via `gh`, Aviator `av`, or any CLI tool), ALWAYS use the `.github/PULL_REQUEST_TEMPLATE.md` template as the base for the PR body

### UI/UX Standards
- Account for light/dark mode using `useColorModeValue` hook
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@
"balance": "Balance",
"netWorth": "Net Worth",
"loadingAccounts": "Loaded %{portfolioAccountsLoaded} accounts",
"loadingMorePositions": "More DeFi positions are still loading",
"walletBalanceChange24Hr": "24-hour change",
"earnBody": "Earn passive income by staking your assets or depositing them into a DeFi strategy.",
"noAccountsOpportunities": "You have no accounts for this asset, so staking opportunities are currently unavailable.",
Expand Down
44 changes: 44 additions & 0 deletions src/components/CryptoAmountInput/CryptoAmountInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Input } from '@chakra-ui/react'
import type { ChangeEvent } from 'react'
import { memo, useMemo } from 'react'

const INPUT_LENGTH_BREAKPOINTS = {
FOR_XS_FONT: 22,
FOR_SM_FONT: 14,
FOR_MD_FONT: 10,
} as const

const getInputFontSize = (length: number): string => {
if (length >= INPUT_LENGTH_BREAKPOINTS.FOR_XS_FONT) return '24px'
if (length >= INPUT_LENGTH_BREAKPOINTS.FOR_SM_FONT) return '30px'
if (length >= INPUT_LENGTH_BREAKPOINTS.FOR_MD_FONT) return '38px'
return '48px'
}

export type CryptoAmountInputProps = {
value?: string
onChange?: (e: ChangeEvent<HTMLInputElement>) => void
placeholder?: string
[key: string]: unknown
}

export const CryptoAmountInput = memo((props: CryptoAmountInputProps) => {
const valueLength = useMemo(() => (props.value ? String(props.value).length : 0), [props.value])
const fontSize = useMemo(() => getInputFontSize(valueLength), [valueLength])

return (
<Input
size='lg'
fontSize={fontSize}
lineHeight={fontSize}
fontWeight='medium'
textAlign='center'
border='none'
borderRadius='lg'
bg='transparent'
variant='unstyled'
color={props.value ? 'text.base' : 'text.subtle'}
{...props}
/>
)
})
79 changes: 61 additions & 18 deletions src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Avatar, Box, Button, Flex, HStack, Skeleton, Text, VStack } from '@chakra-ui/react'
import { memo, useCallback, useEffect, useMemo } from 'react'
import { memo, useCallback, useEffect, useMemo, useRef } from 'react'
import { useTranslate } from 'react-polyglot'
import { useNavigate } from 'react-router-dom'

Expand Down Expand Up @@ -33,11 +33,13 @@ import {
selectSelectedYieldId,
selectSellAccountId,
} from '@/state/slices/tradeEarnInputSlice/selectors'
import { useAppSelector } from '@/state/store'
import { tradeEarnInput } from '@/state/slices/tradeEarnInputSlice/tradeEarnInputSlice'
import { useAppDispatch, useAppSelector } from '@/state/store'

export const EarnConfirm = memo(() => {
const translate = useTranslate()
const navigate = useNavigate()
const dispatch = useAppDispatch()

const sellAsset = useAppSelector(selectInputSellAsset)
const sellAmountCryptoPrecision = useAppSelector(selectInputSellAmountCryptoPrecision)
Expand Down Expand Up @@ -141,6 +143,19 @@ export const EarnConfirm = memo(() => {
accountId: accountIdToUse,
})

// Track step in ref for cleanup
const stepRef = useRef(step)
stepRef.current = step

// Clear Redux when unmounting from success state to prevent re-access
useEffect(() => {
return () => {
if (stepRef.current === ModalStep.Success) {
dispatch(tradeEarnInput.actions.clear())
}
}
}, [dispatch])

// Align loading states with YieldEnterModal
const isQuoteActive = isQuoteLoading || isAllowanceCheckPending
const isLoading = isLoadingYields || isQuoteActive
Expand Down Expand Up @@ -193,21 +208,13 @@ export const EarnConfirm = memo(() => {
return null
}, [selectedValidator, selectedYield, providers])

if (!selectedYield) {
return (
<SharedConfirm
bodyContent={
<VStack spacing={4} p={6} flex={1} justify='center'>
<Text>{translate('earn.selectYieldOpportunity')}</Text>
<Button onClick={handleBack}>{translate('common.goBack')}</Button>
</VStack>
}
footerContent={null}
onBack={handleBack}
headerTranslation='earn.confirmEarn'
/>
)
}
const handleViewPosition = useCallback(() => {
if (!selectedYieldId) return
const params = new URLSearchParams()
if (accountIdToUse) params.set('accountId', accountIdToUse)
const queryString = params.toString()
navigate(queryString ? `/yield/${selectedYieldId}?${queryString}` : `/yield/${selectedYieldId}`)
}, [selectedYieldId, accountIdToUse, navigate])

if (step === ModalStep.Success) {
return (
Expand All @@ -221,16 +228,52 @@ export const EarnConfirm = memo(() => {
transactionSteps={transactionSteps}
yieldId={selectedYieldId}
onDone={handleBack}
showButtons={false}
/>
</Flex>
}
footerContent={null}
footerContent={
<Box p={4}>
<VStack spacing={3} width='full'>
{selectedYieldId && (
<Button colorScheme='blue' size='lg' width='full' onClick={handleViewPosition}>
{translate('yieldXYZ.viewPosition')}
</Button>
)}
<Button
variant={selectedYieldId ? 'ghost' : 'solid'}
colorScheme={selectedYieldId ? undefined : 'blue'}
size='lg'
width='full'
onClick={handleBack}
>
{translate('common.close')}
</Button>
</VStack>
</Box>
}
onBack={handleBack}
headerTranslation='yieldXYZ.success'
/>
)
}

if (!selectedYield) {
return (
<SharedConfirm
bodyContent={
<VStack spacing={4} p={6} flex={1} justify='center'>
<Text>{translate('earn.selectYieldOpportunity')}</Text>
<Button onClick={handleBack}>{translate('common.goBack')}</Button>
</VStack>
}
footerContent={null}
onBack={handleBack}
headerTranslation='earn.confirmEarn'
/>
)
}

const bodyContent = (
<Flex direction='column' width='full' flex={1}>
<Box px={6}>
Expand Down
Loading