Skip to content

Commit

Permalink
feat: USD price conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasmagnus committed Feb 29, 2024
1 parent 18485da commit d3d82d3
Show file tree
Hide file tree
Showing 11 changed files with 296 additions and 105 deletions.
73 changes: 43 additions & 30 deletions frontend/src/app/core/pages/cost-center/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ export const CostCenter: React.FC = () => {
const [historyTransactions, setHistoryTransactions] = useState<
Hooks.UseHorizonTypes.ITransactions[]
>([])
const [USDPrice, setUSDPrice] =
useState<Hooks.UseAssetsTypes.IPriceConversion>()

const { userPermissions, getUserPermissions } = useAuth()
const { getSponsorPK } = useTransactions()
const { getTransactions, getAccount, loadingHorizon } = useHorizon()
const { getVaults } = useVaults()
const { getAssets } = useAssets()
const { getAssets, getUSDPrice } = useAssets()

useEffect(() => {
GAService.GAPageView('Coast center')
Expand All @@ -63,22 +65,12 @@ export const CostCenter: React.FC = () => {
}, [getVaults])

useEffect(() => {
getAssets(true).then(assets => setAssets(assets))
}, [getAssets])
getUSDPrice().then(USDPrice => setUSDPrice(USDPrice))
}, [getUSDPrice])

useEffect(() => {
if (sponsorAccount) {
getTransactions(sponsorAccount).then(transactions => {
setTransactions(transactions)
setLatestFeeCharged(
transactions?._embedded.records.reduce(
(total, transaction) => total + Number(transaction.fee_charged),
0
)
)
})
}
}, [sponsorAccount, getTransactions])
getAssets(true).then(assets => setAssets(assets))
}, [getAssets])

useEffect(() => {
if (sponsorAccount) {
Expand Down Expand Up @@ -255,26 +247,46 @@ export const CostCenter: React.FC = () => {
[assets, walletToName]
)

useEffect(() => {
const counter: Record<string, number> = {}
const getMostRepeatedType = useCallback(
(transactions: Hooks.UseHorizonTypes.ITransactions | undefined): void => {
const counter: Record<string, number> = {}

transactions?._embedded.records.forEach(transaction => {
const transactionData = getTransactionData(transaction)
counter[transactionData.type] = (counter[transactionData.type] || 0) + 1
})
transactions?._embedded.records.forEach(transaction => {
const transactionData = getTransactionData(transaction)
counter[transactionData.type] = (counter[transactionData.type] || 0) + 1
})

let mostRepeatedType: string | undefined
let maxOccurrences = 0
let mostRepeatedType: string | undefined
let maxOccurrences = 0

for (const type in counter) {
if (counter[type] > maxOccurrences) {
maxOccurrences = counter[type]
mostRepeatedType = type
for (const type in counter) {
if (counter[type] > maxOccurrences) {
maxOccurrences = counter[type]
mostRepeatedType = type
}
}
}

setMostRepeatedType(mostRepeatedType)
}, [transactions, assets, vaults, getTransactionData])
setMostRepeatedType(mostRepeatedType)
},
[getTransactionData]
)

useEffect(() => {
if (sponsorAccount) {
getTransactions(sponsorAccount).then(
(transactions: Hooks.UseHorizonTypes.ITransactions | undefined) => {
setTransactions(transactions)
setLatestFeeCharged(
transactions?._embedded.records.reduce(
(total, transaction) => total + Number(transaction.fee_charged),
0
)
)
getMostRepeatedType(transactions)
}
)
}
}, [sponsorAccount, getTransactions, getMostRepeatedType])

return (
<Flex>
Expand All @@ -298,6 +310,7 @@ export const CostCenter: React.FC = () => {
isPrevDisabled={historyTransactions.length === 0}
mostRepeatedType={mostRepeatedType}
loadingHorizon={loadingHorizon}
USDPrice={USDPrice}
getTransactionsByLink={getTransactionsByLink}
getTransactionData={getTransactionData}
/>
Expand Down
Binary file added frontend/src/app/core/resources/usa-flag.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions frontend/src/components/icons/fonts/xlm.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions frontend/src/components/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import { ReactComponent as TrustlineIcon } from './fonts/trustline.svg'
import { ReactComponent as UsdcIcon } from './fonts/usdc.svg'
import { ReactComponent as VaultIcon } from './fonts/vault.svg'
import { ReactComponent as WalletIcon } from './fonts/wallet.svg'
import { ReactComponent as XLMIcon } from './fonts/xlm.svg'

export {
MenuIcon,
Expand Down Expand Up @@ -124,4 +125,5 @@ export {
TrustlineIcon,
ContractInvokeIcon,
ContractRestoreIcon,
XLMIcon,
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
import { Container, Flex, Progress, Text } from '@chakra-ui/react'
import { LinkIcon } from 'components/icons'
import {
Container,
Flex,
FocusLock,
Img,
Popover,
PopoverArrow,
PopoverContent,
PopoverTrigger,
Tag,
Text,
useDisclosure,
} from '@chakra-ui/react'
import React from 'react'
import { ChevronDown, Copy, Repeat } from 'react-feather'
import USA_FLAG from 'app/core/resources/usa-flag.png'

import { SPONSORED_RESERVES_LINK } from 'utils/constants/constants'
import { toCrypto } from 'utils/formatter'

import { LinkIcon, XLMIcon } from 'components/icons'

interface IOpexCard {
accountData: Hooks.UseHorizonTypes.IAccount | undefined
latestFeeCharged: number | undefined
mostRepeatedType: string | undefined
USDPrice: Hooks.UseAssetsTypes.IPriceConversion | undefined
}

export const OpexCard: React.FC<IOpexCard> = ({
accountData,
latestFeeCharged,
mostRepeatedType,
USDPrice,
}) => {
const BASE_RESERVE = 0.5

const getNativeBalance = (): Hooks.UseHorizonTypes.IBalance | undefined => {
return accountData?.balances.find(
balance => balance.asset_type === 'native'
)
}
const { onOpen, onClose, isOpen } = useDisclosure()

const getReserved = (): number => {
const subentry =
Number(accountData?.subentry_count || 0) +
Number(accountData?.num_sponsoring || 0)
const lockedReserves = subentry * BASE_RESERVE + 1
return lockedReserves
}

const getProgress = (): number => {
const totalBalance = Number(getNativeBalance()?.balance || 0)
const reserved = getReserved()
const result = ((totalBalance - reserved) / totalBalance) * 100
return result
const convertToUSD = (value: number): string => {
return toCrypto(value * (USDPrice?.USD || 1), undefined, true)
}

return (
Expand All @@ -45,35 +45,76 @@ export const OpexCard: React.FC<IOpexCard> = ({
<div></div>
) : (
<Container variant="primary" mb="1rem" p={4} w="full" maxW="full">
<Text fontSize="md">Sandbox Expenses account</Text>
<Text fontSize="sm" mt="1rem">
Operating expenses account
</Text>
<Text fontSize="xs" mt="0.25rem" opacity={0.75}>
{accountData.account_id || '-'}
</Text>
<Text fontSize="sm" mt="1rem">
Account balance
<Flex justifyContent="space-between" w="full">
<Text fontSize="md">Sandbox Expenses account</Text>
<Popover
trigger={'hover'}
isOpen={isOpen}
closeOnBlur={false}
onOpen={onOpen}
onClose={onClose}
>
<PopoverTrigger>
<Flex cursor="pointer">
<Text fontSize="sm" fontWeight="700">
Operating Expenses Account
</Text>
<ChevronDown />
</Flex>
</PopoverTrigger>
<PopoverContent p={5} _dark={{ bg: 'black.700' }}>
<FocusLock persistentFocus={false}>
<PopoverArrow />
<Text
fontSize="xs"
fontWeight="700"
color="text.secondary"
bg="gray.50"
p="0.75rem"
borderRadius={8}
>
{accountData.account_id}
</Text>
<Flex
gap={2}
cursor="pointer"
justifyContent="flex-end"
alignItems="center"
mt="0.5rem"
onClick={(): void => {
navigator.clipboard.writeText(accountData.account_id)
}}
>
<Text fontSize="xs" fontWeight="bold" color="gray">
Copy
</Text>
<Copy color="gray" size="12px" />
</Flex>
</FocusLock>
</PopoverContent>
</Popover>
</Flex>
<Text fontSize="sm" mt="2rem">
Cost of the last 10 transactions
</Text>

<Flex flexDir="column" alignItems="center" w="full">
<Text fontSize="sm" mt="1rem">
{`${toCrypto(
Number(getNativeBalance()?.balance) - getReserved()
)} XLM avaliable / ${toCrypto(getReserved())} XLM reserved`}
</Text>
<Progress
value={getProgress()}
h="1rem"
w="full"
borderRadius="0.5rem"
mt="0.25rem"
/>
<Text fontSize="sm" mt="0.25rem">
{`Total balance ${toCrypto(
Number(getNativeBalance()?.balance)
)} XLM`}
</Text>
<Flex
alignItems="center"
w="full"
justifyContent="center"
gap={6}
pt={8}
pb={4}
>
<Tag variant="value" gap={3}>
<XLMIcon />
{`${toCrypto(latestFeeCharged || 0, undefined, true)} XLM`}
</Tag>
<Repeat color="gray" />
<Tag variant="value" gap={3}>
<Img src={USA_FLAG} w="1.5rem"/>
{`$${convertToUSD(latestFeeCharged || 0)}`}
</Tag>
</Flex>

<Flex
Expand All @@ -96,7 +137,7 @@ export const OpexCard: React.FC<IOpexCard> = ({
alignItems="center"
gap={1}
>
Total sponsored reserves <LinkIcon/>
Total sponsored reserves <LinkIcon />
</Text>
<Text fontSize="sm" mt="0.25rem" fontWeight="700">
{accountData.num_sponsoring}
Expand Down
Loading

0 comments on commit d3d82d3

Please sign in to comment.