-
-
Notifications
You must be signed in to change notification settings - Fork 251
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
856 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React, { useState } from 'react'; | ||
import Animated, { FadeInLeft, FadeOutLeft } from 'react-native-reanimated'; | ||
|
||
import { Box, Button } from '@suite-native/atoms'; | ||
import { Icon } from '@suite-native/icons'; | ||
import { Translation } from '@suite-native/intl'; | ||
import { useFormContext } from '@suite-native/forms'; | ||
|
||
import { CustomFeeBottomSheet } from './CustomFeeBottomSheet'; | ||
import { SendFeesFormValues } from '../sendFeesFormSchema'; | ||
import { CustomFeeCard } from './CustomFeeCard'; | ||
import { NativeSupportedFeeLevel } from '../types'; | ||
|
||
export const CustomFee = () => { | ||
const [isBottomSheetVisible, setIsBottomSheetVisible] = useState(false); | ||
const [previousSelectedFeeLevelLabel, setPreviousSelectedFeeLevelLabel] = | ||
useState<NativeSupportedFeeLevel>('normal'); | ||
const { watch, setValue, getValues } = useFormContext<SendFeesFormValues>(); | ||
|
||
const isCustomFeeSelected = watch('feeLevel') === 'custom'; | ||
|
||
const openCustomFeeBottomSheet = () => { | ||
setIsBottomSheetVisible(true); | ||
|
||
const currentSelectedFeeLevelLabel = getValues('feeLevel'); | ||
if (currentSelectedFeeLevelLabel !== 'custom') | ||
setPreviousSelectedFeeLevelLabel(currentSelectedFeeLevelLabel); | ||
}; | ||
|
||
const closeCustomFeeBottomSheet = () => { | ||
setIsBottomSheetVisible(false); | ||
}; | ||
|
||
const cancelCustomFee = () => { | ||
setValue('feeLevel', previousSelectedFeeLevelLabel); | ||
setIsBottomSheetVisible(false); | ||
}; | ||
|
||
return ( | ||
<Box flex={1}> | ||
{isCustomFeeSelected ? ( | ||
<CustomFeeCard onEdit={openCustomFeeBottomSheet} onCancel={cancelCustomFee} /> | ||
) : ( | ||
<Animated.View entering={FadeInLeft.delay(300)} exiting={FadeOutLeft}> | ||
<Box alignSelf="center"> | ||
<Button | ||
colorScheme="tertiaryElevation0" | ||
size="small" | ||
viewLeft={<Icon name="plus" size="mediumLarge" />} | ||
onPress={openCustomFeeBottomSheet} | ||
> | ||
<Translation id="moduleSend.fees.custom.addButton" /> | ||
</Button> | ||
</Box> | ||
</Animated.View> | ||
)} | ||
|
||
<CustomFeeBottomSheet | ||
isVisible={isBottomSheetVisible} | ||
onClose={closeCustomFeeBottomSheet} | ||
/> | ||
</Box> | ||
); | ||
}; |
114 changes: 114 additions & 0 deletions
114
suite-native/module-send/src/components/CustomFeeBottomSheet.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { useSelector } from 'react-redux'; | ||
import Animated, { | ||
FadeInDown, | ||
FadeOutDown, | ||
SlideInDown, | ||
SlideOutDown, | ||
useAnimatedStyle, | ||
withTiming, | ||
} from 'react-native-reanimated'; | ||
|
||
import { useRoute } from '@react-navigation/native'; | ||
|
||
import { AlertBox, BottomSheet, Button, HStack, Text, VStack } from '@suite-native/atoms'; | ||
import { Translation } from '@suite-native/intl'; | ||
import { useFormContext } from '@suite-native/forms'; | ||
import { CryptoAmountFormatter, CryptoToFiatAmountFormatter } from '@suite-native/formatters'; | ||
import { AccountsRootState, selectAccountNetworkSymbol } from '@suite-common/wallet-core'; | ||
import { SendStackParamList, SendStackRoutes, StackProps } from '@suite-native/navigation'; | ||
|
||
import { SendFeesFormValues } from '../sendFeesFormSchema'; | ||
import { CustomFeeInputs } from './CustomFeeInputs'; | ||
import { useCustomFee } from '../hooks/useCustomFee'; | ||
|
||
type CustomFeeBottomSheetProps = { | ||
isVisible: boolean; | ||
onClose: () => void; | ||
}; | ||
|
||
type RouteProps = StackProps<SendStackParamList, SendStackRoutes.SendAddressReview>['route']; | ||
|
||
export const CustomFeeBottomSheet = ({ isVisible, onClose }: CustomFeeBottomSheetProps) => { | ||
const route = useRoute<RouteProps>(); | ||
const { accountKey, tokenContract } = route.params; | ||
|
||
const { feeValue, isFeeLoading, isSubmittable, isErrorBoxVisible } = useCustomFee({ | ||
accountKey, | ||
tokenContract, | ||
}); | ||
|
||
const networkSymbol = useSelector((state: AccountsRootState) => | ||
selectAccountNetworkSymbol(state, accountKey), | ||
); | ||
|
||
const { setValue, handleSubmit } = useFormContext<SendFeesFormValues>(); | ||
|
||
const handleSetCustomFee = handleSubmit(() => { | ||
setValue('feeLevel', 'custom'); | ||
onClose(); | ||
}); | ||
|
||
const animatedButtonContainerStyle = useAnimatedStyle( | ||
() => ({ | ||
height: withTiming(isSubmittable && isVisible ? 50 : 0), | ||
}), | ||
[isSubmittable, isVisible], | ||
); | ||
|
||
if (!networkSymbol) return null; | ||
|
||
return ( | ||
<BottomSheet | ||
isVisible={isVisible} | ||
onClose={onClose} | ||
title={<Translation id="moduleSend.fees.custom.bottomSheet.title" />} | ||
> | ||
<VStack spacing="sp24" justifyContent="space-between" flex={1}> | ||
<CustomFeeInputs networkSymbol={networkSymbol} /> | ||
<HStack | ||
flex={1} | ||
justifyContent="space-between" | ||
alignItems="center" | ||
paddingHorizontal="sp1" | ||
> | ||
<Text variant="highlight"> | ||
<Translation id="moduleSend.fees.custom.bottomSheet.total" /> | ||
</Text> | ||
<VStack alignItems="flex-end"> | ||
<CryptoToFiatAmountFormatter | ||
value={feeValue} | ||
isLoading={isFeeLoading} | ||
network={networkSymbol} | ||
/> | ||
<CryptoAmountFormatter | ||
value={feeValue} | ||
network={networkSymbol} | ||
variant="body" | ||
isLoading={isFeeLoading} | ||
isBalance={false} | ||
/> | ||
</VStack> | ||
</HStack> | ||
{isErrorBoxVisible && ( | ||
<Animated.View entering={FadeInDown} exiting={FadeOutDown}> | ||
<AlertBox | ||
variant="error" | ||
title={<Translation id="moduleSend.fees.error" />} | ||
contentColor="textDefault" | ||
/> | ||
</Animated.View> | ||
)} | ||
|
||
<Animated.View style={animatedButtonContainerStyle}> | ||
{isSubmittable && ( | ||
<Animated.View entering={SlideInDown} exiting={SlideOutDown}> | ||
<Button onPress={handleSetCustomFee}> | ||
<Translation id="moduleSend.fees.custom.bottomSheet.confirmButton" /> | ||
</Button> | ||
</Animated.View> | ||
)} | ||
</Animated.View> | ||
</VStack> | ||
</BottomSheet> | ||
); | ||
}; |
123 changes: 123 additions & 0 deletions
123
suite-native/module-send/src/components/CustomFeeCard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { useSelector } from 'react-redux'; | ||
import Animated, { FadeInLeft, FadeOutLeft } from 'react-native-reanimated'; | ||
|
||
import { useRoute } from '@react-navigation/native'; | ||
|
||
import { Card, HStack, VStack, Text, Box, Button } from '@suite-native/atoms'; | ||
import { useFormContext } from '@suite-native/forms'; | ||
import { Translation } from '@suite-native/intl'; | ||
import { CryptoAmountFormatter, CryptoToFiatAmountFormatter } from '@suite-native/formatters'; | ||
import { AccountsRootState, selectAccountNetworkSymbol } from '@suite-common/wallet-core'; | ||
import { getFeeUnits } from '@suite-common/wallet-utils'; | ||
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; | ||
import { SendStackParamList, SendStackRoutes, StackProps } from '@suite-native/navigation'; | ||
import { networks, NetworkType } from '@suite-common/wallet-config'; | ||
import { isFinalPrecomposedTransaction } from '@suite-common/wallet-types'; | ||
|
||
import { SendFeesFormValues } from '../sendFeesFormSchema'; | ||
import { selectFeeLevels } from '../sendFormSlice'; | ||
|
||
type CustomFeeCardProps = { | ||
onEdit: () => void; | ||
onCancel: () => void; | ||
}; | ||
|
||
const cardStyle = prepareNativeStyle(utils => ({ | ||
...utils.boxShadows.none, | ||
})); | ||
|
||
type RouteProps = StackProps<SendStackParamList, SendStackRoutes.SendAddressReview>['route']; | ||
|
||
const CustomFeeLabel = ({ networkType }: { networkType: NetworkType }) => { | ||
const feeUnits = getFeeUnits(networkType); | ||
|
||
const { watch } = useFormContext<SendFeesFormValues>(); | ||
const { customFeeLimit, customFeePerUnit } = watch(); | ||
|
||
const formattedFeePerUnit = `${customFeePerUnit} ${feeUnits}`; | ||
|
||
if (networkType === 'ethereum') { | ||
return ( | ||
<VStack spacing="sp2" flex={1}> | ||
<Text variant="highlight"> | ||
<Translation id="moduleSend.fees.custom.card.label" /> | ||
</Text> | ||
<Text variant="hint" color="textSubdued" numberOfLines={1} adjustsFontSizeToFit> | ||
<Translation | ||
id="moduleSend.fees.custom.card.ethereumValues" | ||
values={{ gasPrice: formattedFeePerUnit, gasLimit: customFeeLimit }} | ||
/> | ||
</Text> | ||
</VStack> | ||
); | ||
} | ||
|
||
return ( | ||
<Text variant="highlight"> | ||
<Translation id="moduleSend.fees.custom.card.label" /> | ||
{' • '} | ||
<Text color="textSubdued">{formattedFeePerUnit}</Text> | ||
</Text> | ||
); | ||
}; | ||
|
||
export const CustomFeeCard = ({ onEdit, onCancel }: CustomFeeCardProps) => { | ||
const { applyStyle } = useNativeStyles(); | ||
const route = useRoute<RouteProps>(); | ||
const { accountKey } = route.params; | ||
|
||
const feeLevels = useSelector(selectFeeLevels); | ||
|
||
const customFeeTransaction = feeLevels.custom; | ||
|
||
const networkSymbol = useSelector((state: AccountsRootState) => | ||
selectAccountNetworkSymbol(state, accountKey), | ||
); | ||
|
||
if (!isFinalPrecomposedTransaction(customFeeTransaction) || !networkSymbol) { | ||
return null; | ||
} | ||
|
||
const { networkType } = networks[networkSymbol]; | ||
|
||
return ( | ||
<Animated.View entering={FadeInLeft.delay(300)} exiting={FadeOutLeft}> | ||
<Card style={applyStyle(cardStyle)}> | ||
<VStack spacing="sp16"> | ||
<VStack> | ||
<HStack flex={1} justifyContent="space-between" alignItems="center"> | ||
<CustomFeeLabel networkType={networkType} /> | ||
<VStack alignItems="flex-end" spacing={0}> | ||
<CryptoToFiatAmountFormatter | ||
value={customFeeTransaction.fee} | ||
network={networkSymbol} | ||
variant="body" | ||
/> | ||
<CryptoAmountFormatter | ||
value={customFeeTransaction?.fee} | ||
network={networkSymbol} | ||
isBalance={false} | ||
variant="hint" | ||
numberOfLines={1} | ||
adjustsFontSizeToFit | ||
/> | ||
</VStack> | ||
</HStack> | ||
</VStack> | ||
<HStack flex={1} justifyContent="space-between"> | ||
<Box flex={1 / 3}> | ||
<Button onPress={onCancel} colorScheme="redElevation1"> | ||
<Translation id="generic.buttons.cancel" /> | ||
</Button> | ||
</Box> | ||
<Box flex={2 / 3}> | ||
<Button onPress={onEdit} colorScheme="tertiaryElevation1"> | ||
<Translation id="generic.buttons.edit" /> | ||
</Button> | ||
</Box> | ||
</HStack> | ||
</VStack> | ||
</Card> | ||
</Animated.View> | ||
); | ||
}; |
Oops, something went wrong.