more progress, math still broken though

This commit is contained in:
KraXen72
2025-08-09 19:45:34 +02:00
parent c55c205ae4
commit 052f8a540a
4 changed files with 184 additions and 135 deletions
+3 -7
View File
@@ -1,10 +1,6 @@
{
"[javascriptreact][typescriptreact]": {
"[javascriptreact][typescriptreact][javascript][typescript]": {
"editor.insertSpaces": true,
"editor.tabSize": 2
},
"[javascript][typescript]": {
"editor.insertSpaces": true,
"editor.tabSize": 2
}
"editor.tabSize": 4
}
}
+159 -101
View File
@@ -1,121 +1,179 @@
import React from 'react'
import { View, ViewStyle, TextInput } from 'react-native'
import { AmountInput } from "./AmountInput"
import { CurrencyAmount } from '../screens/Wallet/CurrencyAmount'
import { Text, Icon } from './'
import { spacing, useThemeColor } from '../theme'
import { verticalScale } from '@gocodingnow/rn-size-matters'
import { TransactionStatus } from '../models/Transaction'
import { MintUnit, CurrencyCode, getCurrency, convertToFromSats } from '../services/wallet/currency'
import React, { useState } from 'react'
import { TextInput, TextStyle, TouchableOpacity, View, ViewStyle } from 'react-native'
import { useStores } from '../models'
import type { Mint } from '../models/Mint'
import { TransactionStatus } from '../models/Transaction'
import { MintHeader } from '../screens/Mints/MintHeader'
import { CurrencyAmount } from '../screens/Wallet/CurrencyAmount'
import { convertToFromSats, convertToSatsFrom, CurrencyCode, getCurrency, getCurrencyByCode, MintUnit } from '../services/wallet/currency'
import { spacing, useThemeColor } from '../theme'
import { round, toNumber } from '../utils/number'
import { AmountInput, Icon, Text } from './index'
import { log } from '../services'
interface IAmountInputHeaderProps {
amountInputRef: React.RefObject<TextInput>
amountToSend: string
setAmountToSend: (amount: string) => void
unit: MintUnit
onAmountEndEditing?: () => void
transactionStatus?: TransactionStatus
isCashuPrWithAmount?: boolean
lockedPubkey?: string
unitRef: React.RefObject<MintUnit>
amountInputRef: React.RefObject<TextInput>
amountToSend: string
setAmountToSend: (amount: string) => void
unit: MintUnit
onAmountEndEditing?: () => void
transactionStatus?: TransactionStatus
isCashuPrWithAmount?: boolean
lockedPubkey?: string
unitRef: React.RefObject<MintUnit>
mintHeaderMint: Mint
}
const $amountContainer: ViewStyle = {
alignItems: 'center',
justifyContent: 'center',
alignItems: 'center',
justifyContent: 'center',
}
const $headerContainer: TextStyle = {
alignItems: 'center',
padding: spacing.extraSmall,
paddingTop: 0,
height: spacing.screenHeight * 0.30,
}
const $pubKey: ViewStyle = {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginTop: -spacing.extraSmall
}
export function AmountInputHeader(props: IAmountInputHeaderProps) {
const { userSettingsStore, walletStore } = useStores()
const { userSettingsStore, walletStore } = useStores()
const [isFiatMode, setIsFiatMode] = useState(false)
const amountInputColor = useThemeColor('amountInput');
const convertedAmountColor = useThemeColor('headerSubTitle');
const amountInputColor = useThemeColor('amountInput');
const convertedAmountColor = useThemeColor('headerSubTitle');
const headerBg = useThemeColor('header')
const {
amountInputRef,
amountToSend,
setAmountToSend,
unit,
onAmountEndEditing,
transactionStatus,
isCashuPrWithAmount,
lockedPubkey,
unitRef
} = props
const {
amountInputRef,
amountToSend,
setAmountToSend,
unit,
onAmountEndEditing,
transactionStatus,
isCashuPrWithAmount,
lockedPubkey,
unitRef,
mintHeaderMint
} = props
const isConvertedAmountVisible = () => {
return (
walletStore.exchangeRate &&
(userSettingsStore.exchangeCurrency === getCurrency(unit).code ||
unit === 'sat') &&
getConvertedAmount() !== undefined
)
}
const fiatCurrency = userSettingsStore.exchangeCurrency
const isFiatSupported = fiatCurrency === CurrencyCode.USD || fiatCurrency === CurrencyCode.EUR
const canUseFiatMode = isFiatSupported && walletStore.exchangeRate && unit === 'sat'
const getConvertedAmount = () => {
if (!walletStore.exchangeRate) return undefined;
const getFiatUnit = () => {
const currencyData = getCurrencyByCode(fiatCurrency)
return currencyData?.mintUnit || 'sat'
}
const precision = getCurrency(unitRef.current).precision
return convertToFromSats(
round(toNumber(amountToSend) * precision, 0) || 0,
getCurrency(unitRef.current).code,
walletStore.exchangeRate
)
}
// Convert FIAT amount to display units (e.g., sats to mBTC)
const FIATtoSATS = (inputAmount: string) => {
if (!walletStore.exchangeRate) return undefined;
log.trace("er:", walletStore.exchangeRate)
return <View style={$amountContainer}>
<AmountInput
ref={amountInputRef}
value={amountToSend}
onChangeText={amount => setAmountToSend(amount)}
unit={unit}
onEndEditing={transactionStatus !== TransactionStatus.PENDING ? onAmountEndEditing : undefined}
editable={!(transactionStatus === TransactionStatus.PENDING || isCashuPrWithAmount)}
style={{ color: amountInputColor }}
/>
{isConvertedAmountVisible() && (
<CurrencyAmount
amount={getConvertedAmount() ?? 0}
currencyCode={unit === 'sat' ? userSettingsStore.exchangeCurrency : CurrencyCode.SAT}
symbolStyle={{ color: convertedAmountColor, marginTop: spacing.tiny, fontSize: verticalScale(10) }}
amountStyle={{ color: convertedAmountColor, lineHeight: spacing.medium }}
size='medium'
containerStyle={{ justifyContent: 'center' }}
/>
)}
{lockedPubkey ? (
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginTop: isConvertedAmountVisible() ? -spacing.extraSmall : undefined
}}
>
<Icon
icon="faLock"
size={spacing.small}
color={amountInputColor}
/>
<Text
size='xs'
tx="sendLocked"
style={{ color: amountInputColor, marginLeft: spacing.tiny }}
const precision = getCurrency(unitRef.current).precision
return convertToSatsFrom(
round(toNumber(inputAmount) * precision, 0) || 0,
getCurrency(unitRef.current).code,
walletStore.exchangeRate
)
}
// Convert display units to FIAT amount
const SATStoFIAT = (inputAmount: string) => {
if (!walletStore.exchangeRate) return undefined;
log.trace("er:", walletStore.exchangeRate)
const precision = getCurrency(unitRef.current).precision
return convertToFromSats(
round(toNumber(inputAmount) * precision, 0) || 0,
getCurrency(unitRef.current).code,
walletStore.exchangeRate
)
}
const isConvertedAmountVisible = () => {
return canUseFiatMode && walletStore.exchangeRate
}
const handleAmountChange = (amount: string) => {
if (isFiatMode) {
setAmountToSend(FIATtoSATS(amount).toString())
} else {
setAmountToSend(amount)
}
}
return <View style={[$headerContainer, { backgroundColor: headerBg }]}>
<MintHeader
mint={mintHeaderMint}
unit={isFiatMode && canUseFiatMode ? getFiatUnit() : unitRef.current}
/>
<View style={$amountContainer}>
{isFiatMode && canUseFiatMode ? (
<AmountInput
value={SATStoFIAT(amountToSend).toString()}
onChangeText={amount => setAmountToSend(FIATtoSATS(amount).toString())}
unit={getFiatUnit()}
onEndEditing={transactionStatus !== TransactionStatus.PENDING ? onAmountEndEditing : undefined}
style={{ color: amountInputColor }}
/>
) : (
<AmountInput
ref={amountInputRef}
value={amountToSend}
onChangeText={handleAmountChange}
unit={unit}
onEndEditing={transactionStatus !== TransactionStatus.PENDING ? onAmountEndEditing : undefined}
editable={!(transactionStatus === TransactionStatus.PENDING || isCashuPrWithAmount)}
style={{ color: amountInputColor }}
/>
)}
{isConvertedAmountVisible() && (
<TouchableOpacity onPress={() => canUseFiatMode && setIsFiatMode(!isFiatMode)}>
<CurrencyAmount
amount={isFiatMode ? toNumber(amountToSend) * getCurrency(unitRef.current).precision : SATStoFIAT(amountToSend)}
currencyCode={isFiatMode ? CurrencyCode.SAT : fiatCurrency}
symbolStyle={{ color: convertedAmountColor, marginTop: spacing.tiny, fontSize: verticalScale(10) }}
amountStyle={{ color: convertedAmountColor, lineHeight: spacing.medium }}
size='medium'
containerStyle={{ justifyContent: 'center' }}
/>
</TouchableOpacity>
)}
{lockedPubkey ? (
<View style={$pubKey}>
<Icon
icon="faLock"
size={spacing.small}
color={amountInputColor}
/>
<Text
size='xs'
tx="sendLocked"
style={{ color: amountInputColor, marginLeft: spacing.tiny }}
/>
</View>
) : (
<Text
size='xs'
tx='amountSend'
style={{
color: amountInputColor,
textAlign: 'center',
marginTop: isConvertedAmountVisible() ? -spacing.extraSmall : undefined
}}
/>
)}
</View>
</View>
) : (
<Text
size='xs'
tx='amountSend'
style={{
color: amountInputColor,
textAlign: 'center',
marginTop: isConvertedAmountVisible() ? -spacing.extraSmall : undefined
}}
/>
)}
</View>
</View>
}
+3 -27
View File
@@ -1000,7 +1000,6 @@ export const SendScreen = observer(function SendScreen({ route }: Props) {
setError(e)
}
const headerBg = useThemeColor('header')
const hintColor = useThemeColor('textDim')
const inputText = useThemeColor('text')
const inputBg = useThemeColor('background')
@@ -1032,12 +1031,7 @@ export const SendScreen = observer(function SendScreen({ route }: Props) {
return (
<Screen preset="fixed" contentContainerStyle={$screen}>
<MintHeader
mint={mintBalanceToSendFrom ? mintsStore.findByUrl(mintBalanceToSendFrom?.mintUrl) : undefined}
unit={unitRef.current}
/>
<View style={[$headerContainer, { backgroundColor: headerBg}]}>
<AmountInputHeader
<AmountInputHeader
amountInputRef={amountInputRef}
amountToSend={amountToSend}
setAmountToSend={setAmountToSend}
@@ -1047,8 +1041,8 @@ export const SendScreen = observer(function SendScreen({ route }: Props) {
isCashuPrWithAmount={isCashuPrWithAmount}
lockedPubkey={lockedPubkey}
unitRef={unitRef}
/>
</View>
mintHeaderMint={mintBalanceToSendFrom ? mintsStore.findByUrl(mintBalanceToSendFrom?.mintUrl) : undefined}
/>
<View style={$contentContainer}>
{!encodedTokenToSend && (
<MemoInputCard
@@ -1766,14 +1760,6 @@ const $screen: ViewStyle = {
flex: 1,
}
const $headerContainer: TextStyle = {
alignItems: 'center',
padding: spacing.extraSmall,
paddingTop: 0,
height: spacing.screenHeight * 0.20,
}
const $pubkeyInput: TextStyle = {
flex: 1,
// borderRadius: 0,
@@ -1785,16 +1771,6 @@ const $pubkeyInput: TextStyle = {
// borderWidth: 1,
}
const $amountInput: TextStyle = {
borderRadius: spacing.small,
margin: 0,
padding: 0,
fontSize: verticalScale(48),
fontFamily: typography.primary?.medium,
textAlign: 'center',
color: 'white',
}
const $contentContainer: TextStyle = {
flex: 1,
padding: spacing.extraSmall,
+19
View File
@@ -155,6 +155,15 @@ export const getCurrency = (unit: MintUnit) => {
return currencyData as CurrencyData
}
export const getCurrencyByCode = (code: CurrencyCode): CurrencyData | undefined => {
for (const [currencyCode, currencyData] of Object.entries(Currencies)) {
if (currencyCode === code && currencyData) {
return currencyData satisfies CurrencyData
}
}
return void 0;
}
export const convertToFromSats = (amount: number, currencyFrom: CurrencyCode, satExchangeRate: ExchangeRate) => {
// exchangeRate is always 1 fiat precision unit (cent) in SAT {currency: 'EUR', rate: 15.69}
@@ -163,5 +172,15 @@ export const convertToFromSats = (amount: number, currencyFrom: CurrencyCode, sa
}
return amount * satExchangeRate.rate
}
export const convertToSatsFrom = (amount: number, currencyFrom: CurrencyCode, satExchangeRate: ExchangeRate) => {
// exchangeRate is always 1 fiat precision unit (cent) in SAT {currency: 'EUR', rate: 15.69}
if(currencyFrom === CurrencyCode.SAT) {
return amount * satExchangeRate.rate
}
return amount / satExchangeRate.rate
}