From 674ad349eedb88d4f5279b5dfc01e6fd3bd4abb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 14 Jun 2024 02:38:48 +0200 Subject: [PATCH 01/71] add dropdown --- src/components/assetsView/views/AssetGrid.tsx | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index c794c38..6e43a9d 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -2,7 +2,14 @@ import { FC, useEffect, useMemo, useState } from 'react' import { useRouter } from 'next/router' -import { Grid, Group, Pagination } from '@mantine/core' +import { + Combobox, + Grid, + Group, + InputBase, + Pagination, + useCombobox, +} from '@mantine/core' import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' @@ -28,6 +35,30 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { // Go to first page when data changes (e.g. search, filter, order, ...) useEffect(() => setPage(1), [props.realtokens]) + const combobox = useCombobox({ + onDropdownClose: () => combobox.resetSelectedOption(), + }) + + const values = [24, 48, 96, 192, 384, 768, 1536] + + const [search, setSearch] = useState('') + const [value, setValue] = useState('24') + const [data, setData] = useState( + values.map((item) => item.toString()), + ) + + const exactOptionMatch = data.some((item) => item === search) + const filteredOptions = exactOptionMatch + ? data + : data.filter((item) => + item.toLowerCase().includes(search.toLowerCase().trim()), + ) + const options = filteredOptions.map((item) => ( + + {item} + + )) + return ( <> @@ -55,6 +86,45 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { size={'sm'} onChange={onPageChange} /> + { + if (val === '$create') { + setData((current) => [...current, search]) + setValue(search) + } else { + setValue(val) + setSearch(val) + } + + combobox.closeDropdown() + }} + > + + } + value={search} + onChange={(event) => { + combobox.openDropdown() + combobox.updateSelectedOptionIndex() + setSearch(event.currentTarget.value) + }} + onClick={() => combobox.openDropdown()} + onFocus={() => combobox.openDropdown()} + onBlur={() => { + combobox.closeDropdown() + setSearch(value || '') + }} + placeholder={'Search value'} + rightSectionPointerEvents={'none'} + /> + + + + {options} + + ) From f668dd58ba18f83844bfd77adf2287b0a5bf71d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 14 Jun 2024 03:16:12 +0200 Subject: [PATCH 02/71] simplify selector and add all token option --- src/components/assetsView/views/AssetGrid.tsx | 47 +++++++------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index 6e43a9d..a182d4f 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -18,7 +18,7 @@ import { AssetCard } from '../../cards' export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { const router = useRouter() const [page, setPage] = useState(1) - const pageSize = 24 + const [pageSize, setPageSize] = useState(20) function onPageChange(page: number) { setPage(page) @@ -39,25 +39,18 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { onDropdownClose: () => combobox.resetSelectedOption(), }) - const values = [24, 48, 96, 192, 384, 768, 1536] + const values = [20, 40, 100, 200] - const [search, setSearch] = useState('') - const [value, setValue] = useState('24') - const [data, setData] = useState( - values.map((item) => item.toString()), - ) - - const exactOptionMatch = data.some((item) => item === search) - const filteredOptions = exactOptionMatch - ? data - : data.filter((item) => - item.toLowerCase().includes(search.toLowerCase().trim()), - ) - const options = filteredOptions.map((item) => ( - - {item} - - )) + const options = [ + + {'All'} + , + ...values.map((item) => ( + + {item} + + )), + ] return ( <> @@ -90,13 +83,8 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { store={combobox} withinPortal={false} onOptionSubmit={(val) => { - if (val === '$create') { - setData((current) => [...current, search]) - setValue(search) - } else { - setValue(val) - setSearch(val) - } + if (val === 'All') return setPageSize(props.realtokens.length) + setPageSize(Number(val)) combobox.closeDropdown() }} @@ -104,17 +92,16 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { } - value={search} - onChange={(event) => { + value={pageSize == props.realtokens.length ? 'All' : pageSize} + type={'button'} + onChange={() => { combobox.openDropdown() combobox.updateSelectedOptionIndex() - setSearch(event.currentTarget.value) }} onClick={() => combobox.openDropdown()} onFocus={() => combobox.openDropdown()} onBlur={() => { combobox.closeDropdown() - setSearch(value || '') }} placeholder={'Search value'} rightSectionPointerEvents={'none'} From d778d54ee9adc53a8739c83681ec8e46bd30f391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Wed, 31 Jul 2024 09:37:06 +0200 Subject: [PATCH 03/71] feat: change allPage value to Infinity --- src/components/assetsView/views/AssetGrid.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index a182d4f..2af0527 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -27,13 +27,16 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { } const paginationOffers: UserRealtoken[] = useMemo(() => { + console.log({ realtokens: props.realtokens }) + if (pageSize === Infinity) return props.realtokens + const start = (page - 1) * pageSize const end = start + pageSize return props.realtokens.slice(start, end) }, [props.realtokens, page, pageSize]) // Go to first page when data changes (e.g. search, filter, order, ...) - useEffect(() => setPage(1), [props.realtokens]) + // useEffect(() => setPage(1), [props.realtokens]) const combobox = useCombobox({ onDropdownClose: () => combobox.resetSelectedOption(), @@ -73,7 +76,11 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { > = (props) => { store={combobox} withinPortal={false} onOptionSubmit={(val) => { - if (val === 'All') return setPageSize(props.realtokens.length) + if (val === 'All') return setPageSize(Infinity) setPageSize(Number(val)) combobox.closeDropdown() @@ -92,7 +99,7 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { } - value={pageSize == props.realtokens.length ? 'All' : pageSize} + value={pageSize == Infinity ? 'All' : pageSize} type={'button'} onChange={() => { combobox.openDropdown() From ca241d3980f35dbde91bcbdf0d8fd786ebb1f546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 8 Aug 2024 21:33:16 +0200 Subject: [PATCH 04/71] feat: estimate the fully rented rent --- src/components/cards/main/PropertiesCard.tsx | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/components/cards/main/PropertiesCard.tsx b/src/components/cards/main/PropertiesCard.tsx index 1556e15..6f02df2 100644 --- a/src/components/cards/main/PropertiesCard.tsx +++ b/src/components/cards/main/PropertiesCard.tsx @@ -23,6 +23,42 @@ import { const RentedUnitsField: FC<{ label: string; realtokens: UserRealtoken[] }> = ( props, ) => { + console.log({ realtokens: props.realtokens }) + console.log({ + units: props.realtokens + .filter((r) => r.rentedUnits !== r.totalUnits) + .map((r) => { + if (r.history.length > 0) { + let propInfo = r.history[0].values + const history = r.history.map((h) => { + return { ...propInfo, ...h.values } + }) + + // Find last rent from history where property was fully rented + for (const h of history.reverse()) { + if (h.rentedUnits === r.totalTokens && h.netRentYear) { + return { + total: r.totalUnits, + rented: r.rentedUnits, + yearlyRentPerTokenIfFullyRented: h.netRentYear / r.totalTokens, + } + } + } + } + + // If no history, use current values + // please note that this estimation is most of the time underestimating the real value + // because maintenance cost is take into account but not shared between all the units + return { + total: r.totalUnits, + rented: r.rentedUnits, + netRentYearPerToken: r.netRentYearPerToken, + yearlyRentPerTokenIfFullyRented: r.rentedUnits + ? (r.netRentYearPerToken * r.totalUnits) / r.rentedUnits + : NaN, + } + }), + }) const { t } = useTranslation('common', { keyPrefix: 'numbers' }) const totalValue = _sumBy(props.realtokens, 'totalUnits') From c779b47d938e12db9779316bc83dde1e624bdb07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 8 Aug 2024 21:55:11 +0200 Subject: [PATCH 05/71] feat: add fully rented estimation to asset cards --- src/components/cards/AssetCard.tsx | 33 ++++++++++++++++++ src/components/cards/main/PropertiesCard.tsx | 36 -------------------- src/i18next/locales/en/common.json | 1 + src/i18next/locales/fr/common.json | 1 + 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 9d3dc84..6d70d10 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -150,6 +150,13 @@ const AssetCardComponent: FC = (props) => { +
+
{t('fullyRentedEstimation')}*
+
+ {useCurrencyValue(fullyRentedRentEstimation(props.value))} +
+
+
@@ -158,4 +165,30 @@ const AssetCardComponent: FC = (props) => { ) } +const fullyRentedRentEstimation = (token: UserRealtoken) => { + const rentPerToken = () => { + if (token.history.length > 0) { + let propInfo = token.history[0].values + const history = token.history.map((h) => { + return { ...propInfo, ...h.values } + }) + + // Find last rent from history where property was fully rented + for (const h of history.reverse()) { + if (h.rentedUnits === token.totalTokens && h.netRentYear) { + return h.netRentYear / token.totalTokens + } + } + } + + // If no history, use current values + // please note that this estimation is most of the time underestimating the real value + // because maintenance cost is take into account but not shared between all the units + return token.rentedUnits + ? (token.netRentYearPerToken * token.totalUnits) / token.rentedUnits + : NaN + } + return rentPerToken() * token.amount +} + export const AssetCard = memo(AssetCardComponent) diff --git a/src/components/cards/main/PropertiesCard.tsx b/src/components/cards/main/PropertiesCard.tsx index 6f02df2..1556e15 100644 --- a/src/components/cards/main/PropertiesCard.tsx +++ b/src/components/cards/main/PropertiesCard.tsx @@ -23,42 +23,6 @@ import { const RentedUnitsField: FC<{ label: string; realtokens: UserRealtoken[] }> = ( props, ) => { - console.log({ realtokens: props.realtokens }) - console.log({ - units: props.realtokens - .filter((r) => r.rentedUnits !== r.totalUnits) - .map((r) => { - if (r.history.length > 0) { - let propInfo = r.history[0].values - const history = r.history.map((h) => { - return { ...propInfo, ...h.values } - }) - - // Find last rent from history where property was fully rented - for (const h of history.reverse()) { - if (h.rentedUnits === r.totalTokens && h.netRentYear) { - return { - total: r.totalUnits, - rented: r.rentedUnits, - yearlyRentPerTokenIfFullyRented: h.netRentYear / r.totalTokens, - } - } - } - } - - // If no history, use current values - // please note that this estimation is most of the time underestimating the real value - // because maintenance cost is take into account but not shared between all the units - return { - total: r.totalUnits, - rented: r.rentedUnits, - netRentYearPerToken: r.netRentYearPerToken, - yearlyRentPerTokenIfFullyRented: r.rentedUnits - ? (r.netRentYearPerToken * r.totalUnits) / r.rentedUnits - : NaN, - } - }), - }) const { t } = useTranslation('common', { keyPrefix: 'numbers' }) const totalValue = _sumBy(props.realtokens, 'totalUnits') diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index d6c4a1b..f048918 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -187,6 +187,7 @@ "rentedUnits": "Rented units", "propertyValue": "Property value", "rentStartDate": "Rent Start", + "fullyRentedEstimation": "Estimated annual rent if fully rented", "rentNotStarted": "Rent not started yet", "isRmmAvailable": "RMM", "rentStatus": { diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index 7513492..6521c57 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -187,6 +187,7 @@ "rentedUnits": "Logements loués", "propertyValue": "Valeur de la propriété", "rentStartDate": "Date du premier loyer", + "fullyRentedEstimation": "Estimation loyer annuel si loué à 100%", "rentNotStarted": "Le loyer n'a pas débuté", "isRmmAvailable": "RMM", "rentStatus": { From 554c16a03ce3174e59d737c1eda8163e5fc0e889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 8 Aug 2024 22:11:35 +0200 Subject: [PATCH 06/71] refactor: move hook calls to top of the page --- src/components/cards/AssetCard.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 6d70d10..c4c60b6 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -48,6 +48,10 @@ const AssetCardComponent: FC = (props) => { const yearlyAmount = props.value.amount * props.value.netRentYearPerToken const totalInvestment = props.value.totalInvestment + const fullyRentedRentEstimationValue = useCurrencyValue( + fullyRentedRentEstimation(props.value), + ) + return ( = (props) => {
{t('fullyRentedEstimation')}*
-
- {useCurrencyValue(fullyRentedRentEstimation(props.value))} -
+
{fullyRentedRentEstimationValue}
From 0b9d73296a880aba5d6d14f9dc809f9a95d0281d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 8 Aug 2024 22:20:45 +0200 Subject: [PATCH 07/71] fix: propInfo definition --- src/components/cards/AssetCard.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index c4c60b6..a0c20c5 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -172,7 +172,8 @@ const fullyRentedRentEstimation = (token: UserRealtoken) => { if (token.history.length > 0) { let propInfo = token.history[0].values const history = token.history.map((h) => { - return { ...propInfo, ...h.values } + propInfo = { ...propInfo, ...h.values } + return propInfo }) // Find last rent from history where property was fully rented From bcd085b42eb62023b43b04bb972f708fe5b44617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 8 Aug 2024 23:23:16 +0200 Subject: [PATCH 08/71] fix: last rent condition --- src/components/cards/AssetCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index a0c20c5..af7d7c0 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -178,7 +178,7 @@ const fullyRentedRentEstimation = (token: UserRealtoken) => { // Find last rent from history where property was fully rented for (const h of history.reverse()) { - if (h.rentedUnits === token.totalTokens && h.netRentYear) { + if (h.rentedUnits === token.totalUnits && h.netRentYear) { return h.netRentYear / token.totalTokens } } From d8586f49afe365064978907eef60cb65202fd47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 9 Aug 2024 00:18:28 +0200 Subject: [PATCH 09/71] feat: add estimation for property with not fully rented history --- src/components/cards/AssetCard.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index af7d7c0..464ac41 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -182,6 +182,14 @@ const fullyRentedRentEstimation = (token: UserRealtoken) => { return h.netRentYear / token.totalTokens } } + + // If no fully rented history, use last history + const lastHistory = history.reverse()[0] + if (lastHistory.netRentYear && lastHistory.rentedUnits) + return ( + (lastHistory.netRentYear * token.totalUnits) / + (token.totalTokens * lastHistory.rentedUnits) + ) } // If no history, use current values From 6860e2bbfad03d8b93f8a6e1992bd976824495b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 9 Aug 2024 01:13:50 +0200 Subject: [PATCH 10/71] feat: get fully rented APR --- src/components/cards/AssetCard.tsx | 58 ++++++++++++++++++++---------- src/i18next/locales/en/common.json | 2 +- src/i18next/locales/fr/common.json | 2 +- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 464ac41..23a4e6d 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -48,9 +48,8 @@ const AssetCardComponent: FC = (props) => { const yearlyAmount = props.value.amount * props.value.netRentYearPerToken const totalInvestment = props.value.totalInvestment - const fullyRentedRentEstimationValue = useCurrencyValue( - fullyRentedRentEstimation(props.value), - ) + const fullyRentedRentEstimationValue = + Math.floor(fullyRentedRentEstimation(props.value) * 100) / 100 return ( = (props) => {
{t('fullyRentedEstimation')}*
-
{fullyRentedRentEstimationValue}
+
{fullyRentedRentEstimationValue} %
@@ -168,7 +167,15 @@ const AssetCardComponent: FC = (props) => { } const fullyRentedRentEstimation = (token: UserRealtoken) => { - const rentPerToken = () => { + if (token.rentedUnits === 0 && token.annualPercentageYield !== 0) { + return token.annualPercentageYield + } + + if (token.rentedUnits !== 0 && token.annualPercentageYield !== 0) { + return (token.annualPercentageYield * token.totalUnits) / token.rentedUnits + } + + const APREstimation = () => { if (token.history.length > 0) { let propInfo = token.history[0].values const history = token.history.map((h) => { @@ -178,28 +185,41 @@ const fullyRentedRentEstimation = (token: UserRealtoken) => { // Find last rent from history where property was fully rented for (const h of history.reverse()) { - if (h.rentedUnits === token.totalUnits && h.netRentYear) { - return h.netRentYear / token.totalTokens + if ( + h.rentedUnits === token.totalUnits && + h.netRentYear && + h.tokenPrice + ) { + return (h.netRentYear / (token.totalTokens * h.tokenPrice)) * 100 } } // If no fully rented history, use last history - const lastHistory = history.reverse()[0] - if (lastHistory.netRentYear && lastHistory.rentedUnits) + const lastHistory = history + .reverse() + .find( + (h) => + h.netRentYear && + h.rentedUnits && + h.tokenPrice && + token.rentedUnits !== 0, + ) + if ( + lastHistory && + lastHistory.netRentYear && + lastHistory.rentedUnits != 0 && + lastHistory.tokenPrice + ) return ( - (lastHistory.netRentYear * token.totalUnits) / - (token.totalTokens * lastHistory.rentedUnits) + (token.totalUnits / token.rentedUnits) * + (lastHistory.netRentYear / + (token.totalTokens * lastHistory.tokenPrice)) * + 100 ) } - - // If no history, use current values - // please note that this estimation is most of the time underestimating the real value - // because maintenance cost is take into account but not shared between all the units - return token.rentedUnits - ? (token.netRentYearPerToken * token.totalUnits) / token.rentedUnits - : NaN } - return rentPerToken() * token.amount + + return APREstimation() || 0 } export const AssetCard = memo(AssetCardComponent) diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index f048918..9a83d0d 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -187,7 +187,7 @@ "rentedUnits": "Rented units", "propertyValue": "Property value", "rentStartDate": "Rent Start", - "fullyRentedEstimation": "Estimated annual rent if fully rented", + "fullyRentedEstimation": "Fully rented APR", "rentNotStarted": "Rent not started yet", "isRmmAvailable": "RMM", "rentStatus": { diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index 6521c57..e0aa856 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -187,7 +187,7 @@ "rentedUnits": "Logements loués", "propertyValue": "Valeur de la propriété", "rentStartDate": "Date du premier loyer", - "fullyRentedEstimation": "Estimation loyer annuel si loué à 100%", + "fullyRentedEstimation": "Rendement 100% loué", "rentNotStarted": "Le loyer n'a pas débuté", "isRmmAvailable": "RMM", "rentStatus": { From aafdb192f30c0e8683033ee7e4d8490c3be0233f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 9 Aug 2024 21:29:39 +0200 Subject: [PATCH 11/71] apply max APR method --- src/components/cards/AssetCard.tsx | 60 ++++++++++++------------------ 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 23a4e6d..23f79be 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -167,12 +167,12 @@ const AssetCardComponent: FC = (props) => { } const fullyRentedRentEstimation = (token: UserRealtoken) => { - if (token.rentedUnits === 0 && token.annualPercentageYield !== 0) { + if (token.rentedUnits === token.totalUnits) { return token.annualPercentageYield } - if (token.rentedUnits !== 0 && token.annualPercentageYield !== 0) { - return (token.annualPercentageYield * token.totalUnits) / token.rentedUnits + if (token.rentedUnits === 0 && token.annualPercentageYield !== 0) { + return token.annualPercentageYield } const APREstimation = () => { @@ -183,43 +183,31 @@ const fullyRentedRentEstimation = (token: UserRealtoken) => { return propInfo }) - // Find last rent from history where property was fully rented - for (const h of history.reverse()) { - if ( - h.rentedUnits === token.totalUnits && - h.netRentYear && - h.tokenPrice - ) { - return (h.netRentYear / (token.totalTokens * h.tokenPrice)) * 100 - } - } - - // If no fully rented history, use last history - const lastHistory = history - .reverse() - .find( - (h) => - h.netRentYear && + const previousAPR = history + .map((h) => { + if ( h.rentedUnits && - h.tokenPrice && - token.rentedUnits !== 0, - ) - if ( - lastHistory && - lastHistory.netRentYear && - lastHistory.rentedUnits != 0 && - lastHistory.tokenPrice - ) - return ( - (token.totalUnits / token.rentedUnits) * - (lastHistory.netRentYear / - (token.totalTokens * lastHistory.tokenPrice)) * - 100 - ) + h.rentedUnits !== 0 && + h.netRentYear && + h.tokenPrice + ) { + return ( + ((h.netRentYear * token.totalUnits) / + (token.totalTokens * h.tokenPrice * h.rentedUnits)) * + 100 + ) + } + return 0 + }) + .filter((apr) => apr !== undefined) + + return Math.max(...previousAPR) + } else { + return 0 } } - return APREstimation() || 0 + return APREstimation() } export const AssetCard = memo(AssetCardComponent) From 7d79682b1c4b028a6ddec4d266fb302861c3a617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 9 Aug 2024 21:37:56 +0200 Subject: [PATCH 12/71] rename variable and functions --- src/components/cards/AssetCard.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 23f79be..4fcd666 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -48,8 +48,8 @@ const AssetCardComponent: FC = (props) => { const yearlyAmount = props.value.amount * props.value.netRentYearPerToken const totalInvestment = props.value.totalInvestment - const fullyRentedRentEstimationValue = - Math.floor(fullyRentedRentEstimation(props.value) * 100) / 100 + const fullyRentedAPR = + Math.floor(fullyRentedAPREstimation(props.value) * 100) / 100 return ( = (props) => {
{t('fullyRentedEstimation')}*
-
{fullyRentedRentEstimationValue} %
+
{fullyRentedAPR} %
@@ -166,7 +166,7 @@ const AssetCardComponent: FC = (props) => { ) } -const fullyRentedRentEstimation = (token: UserRealtoken) => { +const fullyRentedAPREstimation = (token: UserRealtoken) => { if (token.rentedUnits === token.totalUnits) { return token.annualPercentageYield } From 403f1e40a42d4c8229d15c07b9fe38843d2aa800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Mon, 12 Aug 2024 19:27:35 +0200 Subject: [PATCH 13/71] feat: add RWA token --- src/components/assetsView/views/AssetGrid.tsx | 33 +++++++-- src/components/cards/AssetCard.tsx | 23 +++++- src/components/cards/RWACard.tsx | 72 +++++++++++++++++++ src/hooks/useRWA.ts | 34 +++++++++ src/store/features/wallets/walletsSelector.ts | 10 +++ 5 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 src/components/cards/RWACard.tsx create mode 100644 src/hooks/useRWA.ts diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index c794c38..8e2f0e6 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -1,10 +1,17 @@ import { FC, useEffect, useMemo, useState } from 'react' +import { useSelector } from 'react-redux' import { useRouter } from 'next/router' import { Grid, Group, Pagination } from '@mantine/core' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import useRWA from 'src/hooks/useRWA' +import getRWA from 'src/hooks/useRWA' +import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { AssetCard } from '../../cards' @@ -19,11 +26,25 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { document.getElementsByClassName('asset-grid')[0]?.scrollIntoView() } - const paginationOffers: UserRealtoken[] = useMemo(() => { - const start = (page - 1) * pageSize - const end = start + pageSize - return props.realtokens.slice(start, end) - }, [props.realtokens, page, pageSize]) + const [paginationOffers, setPaginationOffers] = useState< + (UserRealtoken | RWARealtoken)[] + >([]) + + const addressList = useSelector(selectUserAddressList) + + useEffect(() => { + if (addressList.length === 0) return + + const fetchData = async () => { + const start = (page - 1) * pageSize + const end = start + pageSize + const rwa = await getRWA(addressList) + const items = [...props.realtokens, rwa] + setPaginationOffers(items.slice(start, end)) + } + + fetchData() + }, [props.realtokens, page, pageSize, addressList]) // Go to first page when data changes (e.g. search, filter, order, ...) useEffect(() => setPage(1), [props.realtokens]) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 9d3dc84..49121cd 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -6,11 +6,15 @@ import Image from 'next/image' import { Badge, Card, Group } from '@mantine/core' +import { es } from 'date-fns/locale' import moment from 'moment' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' import { selectUserRentCalculation } from 'src/store/features/settings/settingsSelector' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { RentCalculationState } from 'src/types/RentCalculation' import { @@ -20,13 +24,19 @@ import { SubsidyStatusTag, } from '../commons' import styles from './AssetCard.module.sass' +import { RWACard } from './RWACard' interface AssetCardProps { + value: UserRealtoken | RWARealtoken + onClick?: (id: string) => unknown +} + +interface PropertyCardProps { value: UserRealtoken onClick?: (id: string) => unknown } -const AssetCardComponent: FC = (props) => { +const PropertyCardComponent: FC = (props) => { const { t: tNumbers } = useTranslation('common', { keyPrefix: 'numbers' }) const { t } = useTranslation('common', { keyPrefix: 'assetCard' }) @@ -158,4 +168,11 @@ const AssetCardComponent: FC = (props) => { ) } -export const AssetCard = memo(AssetCardComponent) +export const AssetCard: FC = (props) => { + const isAProperty = props.value && props.value.hasOwnProperty('rentStatus') + if (isAProperty) { + return + } else { + return + } +} diff --git a/src/components/cards/RWACard.tsx b/src/components/cards/RWACard.tsx new file mode 100644 index 0000000..d922f1d --- /dev/null +++ b/src/components/cards/RWACard.tsx @@ -0,0 +1,72 @@ +import { FC, memo } from 'react' +import { useTranslation } from 'react-i18next' + +import Image from 'next/image' + +import { Badge, Card, Group } from '@mantine/core' + +import { RWARealtoken } from 'src/store/features/wallets/walletsSelector' + +import { + Divider, + RentStatusTag, + RmmStatusTag, + SubsidyStatusTag, +} from '../commons' +import styles from './AssetCard.module.sass' + +interface RWACardProps { + value: RWARealtoken + onClick?: (id: string) => unknown +} + +const RWACardComponent: FC = (props) => { + const { t: tNumbers } = useTranslation('common', { keyPrefix: 'numbers' }) + const { t } = useTranslation('common', { keyPrefix: 'assetCard' }) + + return ( + props.onClick?.(props.value.id)} + > + +
+ {props.value.fullName} +
+
+ + +
{props.value.shortName}
+ +
+ + + +
+
{t('tokens')}
+
+ {tNumbers('decimal', { value: props.value.amount })} + {' / '} + {tNumbers('integer', { value: props.value.totalTokens })} +
+
+ +
+ + +
{props.value.fullName}
+ + ) +} + +export const RWACard = memo(RWACardComponent) diff --git a/src/hooks/useRWA.ts b/src/hooks/useRWA.ts new file mode 100644 index 0000000..d7e20c8 --- /dev/null +++ b/src/hooks/useRWA.ts @@ -0,0 +1,34 @@ +import { ethers } from 'ethers' + +import { GnosisRpcProvider } from 'src/repositories/RpcProvider' +import { RWARealtoken } from 'src/store/features/wallets/walletsSelector' + +const tokenDecimals = 9 + +const getRWA = async (addressList: string[]): Promise => { + let totalAmount = 0 + + for (let i = 0; i < addressList.length; i++) { + const RWAContract = new ethers.Contract( + '0x0675e8F4A52eA6c845CB6427Af03616a2af42170', + ['function balanceOf(address) view returns (uint)'], + GnosisRpcProvider, + ) + const RWAContractBalance = await RWAContract.balanceOf(addressList[i]) + totalAmount += Number(RWAContractBalance) + } + + return { + id: '0', + fullName: 'RWA Holdings SA, Neuchatel, NE, Suisse', + shortName: 'RWA', + amount: totalAmount / 10 ** tokenDecimals, + totalTokens: 100_000, + imageLink: [ + 'https://realt.co/wp-content/uploads/2024/02/Equity_FinalDesign-2000px-800x542.png', + ], + isRmmAvailable: false, + } +} + +export default getRWA diff --git a/src/store/features/wallets/walletsSelector.ts b/src/store/features/wallets/walletsSelector.ts index 9060ddf..a8ca587 100644 --- a/src/store/features/wallets/walletsSelector.ts +++ b/src/store/features/wallets/walletsSelector.ts @@ -37,6 +37,16 @@ export interface UserRealtoken extends RealToken { > } +export interface RWARealtoken { + id: string + fullName: string + shortName: string + amount: number + totalTokens: number + imageLink: string[] + isRmmAvailable: boolean +} + const DAYS_PER_YEAR = 365 const MONTHS_PER_YEAR = 12 const AVG_DAYS_PER_MONTH = DAYS_PER_YEAR / MONTHS_PER_YEAR From f720c4a940d0dd9f362f5af2ef74113428888f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Mon, 12 Aug 2024 19:31:07 +0200 Subject: [PATCH 14/71] feat: re-enable property onClick --- src/components/cards/AssetCard.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 49121cd..5f2b4d4 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -171,7 +171,12 @@ const PropertyCardComponent: FC = (props) => { export const AssetCard: FC = (props) => { const isAProperty = props.value && props.value.hasOwnProperty('rentStatus') if (isAProperty) { - return + return ( + + ) } else { return } From 5d4064a6958d701373c566b4dd9711823bc1c06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Mon, 12 Aug 2024 19:55:32 +0200 Subject: [PATCH 15/71] feat: add rwa valuation on the rwa card --- src/components/cards/RWACard.tsx | 12 +++++++++++- src/hooks/useRWA.ts | 13 +++++++++++-- src/store/features/wallets/walletsSelector.ts | 3 +++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/components/cards/RWACard.tsx b/src/components/cards/RWACard.tsx index d922f1d..4775b9e 100644 --- a/src/components/cards/RWACard.tsx +++ b/src/components/cards/RWACard.tsx @@ -5,6 +5,7 @@ import Image from 'next/image' import { Badge, Card, Group } from '@mantine/core' +import { useCurrencyValue } from 'src/hooks/useCurrencyValue' import { RWARealtoken } from 'src/store/features/wallets/walletsSelector' import { @@ -24,6 +25,10 @@ const RWACardComponent: FC = (props) => { const { t: tNumbers } = useTranslation('common', { keyPrefix: 'numbers' }) const { t } = useTranslation('common', { keyPrefix: 'assetCard' }) + // In Dollars + const value = props.value.value + const totalInvestment = props.value.totalInvestment + return ( = (props) => {
{props.value.shortName}
- + {useCurrencyValue(value)}
@@ -61,6 +66,11 @@ const RWACardComponent: FC = (props) => {
+
+
{t('propertyValue')}
+
{useCurrencyValue(totalInvestment)}
+
+
diff --git a/src/hooks/useRWA.ts b/src/hooks/useRWA.ts index d7e20c8..a0579bc 100644 --- a/src/hooks/useRWA.ts +++ b/src/hooks/useRWA.ts @@ -18,16 +18,25 @@ const getRWA = async (addressList: string[]): Promise => { totalAmount += Number(RWAContractBalance) } + const totalTokens = 100_000 + const amount = totalAmount / 10 ** tokenDecimals + const unitPriceCost = 50 + + const value = unitPriceCost * amount + const totalInvestment = totalTokens * unitPriceCost + return { id: '0', fullName: 'RWA Holdings SA, Neuchatel, NE, Suisse', shortName: 'RWA', - amount: totalAmount / 10 ** tokenDecimals, - totalTokens: 100_000, + amount, + totalTokens, imageLink: [ 'https://realt.co/wp-content/uploads/2024/02/Equity_FinalDesign-2000px-800x542.png', ], isRmmAvailable: false, + value, + totalInvestment, } } diff --git a/src/store/features/wallets/walletsSelector.ts b/src/store/features/wallets/walletsSelector.ts index a8ca587..31cd257 100644 --- a/src/store/features/wallets/walletsSelector.ts +++ b/src/store/features/wallets/walletsSelector.ts @@ -42,9 +42,12 @@ export interface RWARealtoken { fullName: string shortName: string amount: number + value: number + totalInvestment: number totalTokens: number imageLink: string[] isRmmAvailable: boolean + unitPriceCost: number } const DAYS_PER_YEAR = 365 From 82235e562c85a5f183853b8c447836c985235c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Mon, 12 Aug 2024 20:00:45 +0200 Subject: [PATCH 16/71] fix: missing property --- src/hooks/useRWA.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/useRWA.ts b/src/hooks/useRWA.ts index a0579bc..ffb04ae 100644 --- a/src/hooks/useRWA.ts +++ b/src/hooks/useRWA.ts @@ -37,6 +37,7 @@ const getRWA = async (addressList: string[]): Promise => { isRmmAvailable: false, value, totalInvestment, + unitPriceCost, } } From ab1c08505faf1826f3c0459946bc4371ac9f34a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Mon, 12 Aug 2024 20:19:50 +0200 Subject: [PATCH 17/71] feat: add rwa to summary card --- src/components/cards/main/SummaryCard.tsx | 15 ++++++++++++++- src/i18next/locales/en/common.json | 3 ++- src/i18next/locales/fr/common.json | 3 ++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/components/cards/main/SummaryCard.tsx b/src/components/cards/main/SummaryCard.tsx index 6fb4ed0..eff5c48 100644 --- a/src/components/cards/main/SummaryCard.tsx +++ b/src/components/cards/main/SummaryCard.tsx @@ -1,9 +1,12 @@ -import { FC } from 'react' +import { FC, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' import { Box, Card, Text, Title } from '@mantine/core' +import { useCurrencyValue } from 'src/hooks/useCurrencyValue' +import getRWA from 'src/hooks/useRWA' +import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' import { selectTransfersIsLoaded } from 'src/store/features/transfers/transfersSelector' import { selectOwnedRealtokensValue, @@ -18,6 +21,15 @@ export const SummaryCard: FC = () => { const realtokensValue = useSelector(selectOwnedRealtokensValue) const rmmDetails = useSelector(selectRmmDetails) const transfersIsLoaded = useSelector(selectTransfersIsLoaded) + const addressList = useSelector(selectUserAddressList) + const [rwaValue, setRwaValue] = useState(0) + + useEffect(() => { + ;(async () => { + const { value } = await getRWA(addressList) + setRwaValue(value as number) // warning it's dollar value + })() + }, [addressList]) const stableDepositValue = rmmDetails.stableDeposit const stableDebtValue = rmmDetails.stableDebt @@ -43,6 +55,7 @@ export const SummaryCard: FC = () => { ) : null} + ) diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index 87059e2..93081e2 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -358,7 +358,8 @@ "netRentMonth": "Net monthly", "grossRentMonth": "Gross monthly", "yield": "Yield", - "rentedUnits": "Rented units" + "rentedUnits": "Rented units", + "rwa": "RWA value" }, "filter": { "field": "Filter", diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index e7fb852..705a53b 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -68,7 +68,8 @@ "realtokenValue": "RealTokens", "totalPriceCost": "Prix d'achat estimé", "stableDeposit": "Dépôt RMM", - "stableBorrow": "Emprunt RMM" + "stableBorrow": "Emprunt RMM", + "rwa": "RWA" }, "worthCard": { "title": "RealTokens", From 2fb3ecc326843018e71903d40624b472e46051cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 01:04:32 +0200 Subject: [PATCH 18/71] define useRWA --- src/components/assetsView/views/AssetGrid.tsx | 28 ++++++------------- src/components/cards/main/SummaryCard.tsx | 13 ++------- src/hooks/useRWA.ts | 18 +++++++++++- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index 8e2f0e6..62d9f24 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -5,8 +5,7 @@ import { useRouter } from 'next/router' import { Grid, Group, Pagination } from '@mantine/core' -import useRWA from 'src/hooks/useRWA' -import getRWA from 'src/hooks/useRWA' +import { useRWA } from 'src/hooks/useRWA' import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' import { RWARealtoken, @@ -26,25 +25,16 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { document.getElementsByClassName('asset-grid')[0]?.scrollIntoView() } - const [paginationOffers, setPaginationOffers] = useState< - (UserRealtoken | RWARealtoken)[] - >([]) + const rwa = useRWA() - const addressList = useSelector(selectUserAddressList) + const paginationOffers = useMemo(() => { + if (!rwa) return [] - useEffect(() => { - if (addressList.length === 0) return - - const fetchData = async () => { - const start = (page - 1) * pageSize - const end = start + pageSize - const rwa = await getRWA(addressList) - const items = [...props.realtokens, rwa] - setPaginationOffers(items.slice(start, end)) - } - - fetchData() - }, [props.realtokens, page, pageSize, addressList]) + const start = (page - 1) * pageSize + const end = start + pageSize + const items = [...props.realtokens, rwa] + return items.slice(start, end) + }, [props.realtokens, page, pageSize, rwa]) // Go to first page when data changes (e.g. search, filter, order, ...) useEffect(() => setPage(1), [props.realtokens]) diff --git a/src/components/cards/main/SummaryCard.tsx b/src/components/cards/main/SummaryCard.tsx index eff5c48..b826b94 100644 --- a/src/components/cards/main/SummaryCard.tsx +++ b/src/components/cards/main/SummaryCard.tsx @@ -5,7 +5,7 @@ import { useSelector } from 'react-redux' import { Box, Card, Text, Title } from '@mantine/core' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' -import getRWA from 'src/hooks/useRWA' +import { useRWA } from 'src/hooks/useRWA' import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' import { selectTransfersIsLoaded } from 'src/store/features/transfers/transfersSelector' import { @@ -21,15 +21,8 @@ export const SummaryCard: FC = () => { const realtokensValue = useSelector(selectOwnedRealtokensValue) const rmmDetails = useSelector(selectRmmDetails) const transfersIsLoaded = useSelector(selectTransfersIsLoaded) - const addressList = useSelector(selectUserAddressList) - const [rwaValue, setRwaValue] = useState(0) - useEffect(() => { - ;(async () => { - const { value } = await getRWA(addressList) - setRwaValue(value as number) // warning it's dollar value - })() - }, [addressList]) + const rwa = useRWA() const stableDepositValue = rmmDetails.stableDeposit const stableDebtValue = rmmDetails.stableDebt @@ -55,7 +48,7 @@ export const SummaryCard: FC = () => { ) : null} - + ) diff --git a/src/hooks/useRWA.ts b/src/hooks/useRWA.ts index ffb04ae..c4a9a43 100644 --- a/src/hooks/useRWA.ts +++ b/src/hooks/useRWA.ts @@ -1,7 +1,11 @@ +import { useEffect, useState } from 'react' + import { ethers } from 'ethers' import { GnosisRpcProvider } from 'src/repositories/RpcProvider' import { RWARealtoken } from 'src/store/features/wallets/walletsSelector' +import { useSelector } from 'react-redux' +import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' const tokenDecimals = 9 @@ -41,4 +45,16 @@ const getRWA = async (addressList: string[]): Promise => { } } -export default getRWA +export const useRWA = () => { + const [rwa, setRwa] = useState(null) + const addressList = useSelector(selectUserAddressList) + + useEffect(() => { + (async () => { + const rwa_ = await getRWA(addressList) + setRwa(rwa_) + })() + }, [addressList]) + + return rwa +} From 50840ed173f718d09b92ca7e2f2a39e97519ac2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 01:09:42 +0200 Subject: [PATCH 19/71] take into account user currency --- src/hooks/useRWA.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/hooks/useRWA.ts b/src/hooks/useRWA.ts index c4a9a43..2abc263 100644 --- a/src/hooks/useRWA.ts +++ b/src/hooks/useRWA.ts @@ -1,15 +1,19 @@ import { useEffect, useState } from 'react' +import { useSelector } from 'react-redux' import { ethers } from 'ethers' import { GnosisRpcProvider } from 'src/repositories/RpcProvider' -import { RWARealtoken } from 'src/store/features/wallets/walletsSelector' -import { useSelector } from 'react-redux' +import { selectUserCurrency } from 'src/store/features/currencies/currenciesSelector' import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' +import { RWARealtoken } from 'src/store/features/wallets/walletsSelector' const tokenDecimals = 9 -const getRWA = async (addressList: string[]): Promise => { +const getRWA = async ( + addressList: string[], + rate: number, +): Promise => { let totalAmount = 0 for (let i = 0; i < addressList.length; i++) { @@ -24,7 +28,7 @@ const getRWA = async (addressList: string[]): Promise => { const totalTokens = 100_000 const amount = totalAmount / 10 ** tokenDecimals - const unitPriceCost = 50 + const unitPriceCost = 50 / rate const value = unitPriceCost * amount const totalInvestment = totalTokens * unitPriceCost @@ -49,9 +53,12 @@ export const useRWA = () => { const [rwa, setRwa] = useState(null) const addressList = useSelector(selectUserAddressList) + const { rate } = useSelector(selectUserCurrency) + useEffect(() => { - (async () => { - const rwa_ = await getRWA(addressList) + ;(async () => { + const rwa_ = await getRWA(addressList, rate) + setRwa(rwa_) })() }, [addressList]) From b67a48e33e308f5a231c38c5abb0c5370fa9fa63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 01:16:27 +0200 Subject: [PATCH 20/71] feat: add RWA value to net value calculation --- src/components/cards/main/SummaryCard.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/cards/main/SummaryCard.tsx b/src/components/cards/main/SummaryCard.tsx index b826b94..ec79d3c 100644 --- a/src/components/cards/main/SummaryCard.tsx +++ b/src/components/cards/main/SummaryCard.tsx @@ -26,8 +26,9 @@ export const SummaryCard: FC = () => { const stableDepositValue = rmmDetails.stableDeposit const stableDebtValue = rmmDetails.stableDebt + const rwaValue = rwa?.value ?? 0 const totalNetValue = - realtokensValue.total + stableDepositValue - stableDebtValue + realtokensValue.total + stableDepositValue + rwaValue - stableDebtValue return ( @@ -48,7 +49,7 @@ export const SummaryCard: FC = () => { ) : null} - + ) From 89da9f64f5cfa768f39a6f9dd288810a21117684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 01:19:47 +0200 Subject: [PATCH 21/71] remove comment --- src/components/cards/RWACard.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/cards/RWACard.tsx b/src/components/cards/RWACard.tsx index 4775b9e..2972f6a 100644 --- a/src/components/cards/RWACard.tsx +++ b/src/components/cards/RWACard.tsx @@ -25,7 +25,6 @@ const RWACardComponent: FC = (props) => { const { t: tNumbers } = useTranslation('common', { keyPrefix: 'numbers' }) const { t } = useTranslation('common', { keyPrefix: 'assetCard' }) - // In Dollars const value = props.value.value const totalInvestment = props.value.totalInvestment From 7dfe62000a42a2b37213c5f8e93617972d75bb23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 01:21:00 +0200 Subject: [PATCH 22/71] refactor: clean imports --- src/components/cards/AssetCard.tsx | 2 +- src/components/cards/RWACard.tsx | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 5f2b4d4..0d91f6e 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -1,4 +1,4 @@ -import { FC, memo } from 'react' +import { FC} from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' diff --git a/src/components/cards/RWACard.tsx b/src/components/cards/RWACard.tsx index 2972f6a..2367578 100644 --- a/src/components/cards/RWACard.tsx +++ b/src/components/cards/RWACard.tsx @@ -8,12 +8,7 @@ import { Badge, Card, Group } from '@mantine/core' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' import { RWARealtoken } from 'src/store/features/wallets/walletsSelector' -import { - Divider, - RentStatusTag, - RmmStatusTag, - SubsidyStatusTag, -} from '../commons' +import { Divider } from '../commons' import styles from './AssetCard.module.sass' interface RWACardProps { From 231ea30bc5d14c367d31c70a79f3f256fb41fcf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 01:37:10 +0200 Subject: [PATCH 23/71] feat: include RWA on Ethereum --- src/hooks/useRWA.ts | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/hooks/useRWA.ts b/src/hooks/useRWA.ts index 2abc263..d09c8c3 100644 --- a/src/hooks/useRWA.ts +++ b/src/hooks/useRWA.ts @@ -3,9 +3,15 @@ import { useSelector } from 'react-redux' import { ethers } from 'ethers' -import { GnosisRpcProvider } from 'src/repositories/RpcProvider' +import { + EthereumRpcProvider, + GnosisRpcProvider, +} from 'src/repositories/RpcProvider' import { selectUserCurrency } from 'src/store/features/currencies/currenciesSelector' -import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' +import { + selectUserAddressList, + selectUserIncludesEth, +} from 'src/store/features/settings/settingsSelector' import { RWARealtoken } from 'src/store/features/wallets/walletsSelector' const tokenDecimals = 9 @@ -13,17 +19,27 @@ const tokenDecimals = 9 const getRWA = async ( addressList: string[], rate: number, + includeETH: boolean = false, ): Promise => { let totalAmount = 0 + let providers = [GnosisRpcProvider] + + if (includeETH) { + providers.push(EthereumRpcProvider) + } + for (let i = 0; i < addressList.length; i++) { - const RWAContract = new ethers.Contract( - '0x0675e8F4A52eA6c845CB6427Af03616a2af42170', - ['function balanceOf(address) view returns (uint)'], - GnosisRpcProvider, - ) - const RWAContractBalance = await RWAContract.balanceOf(addressList[i]) - totalAmount += Number(RWAContractBalance) + for (let j = 0; j < providers.length; j++) { + const RPCProvider = providers[j] + const RWAContract = new ethers.Contract( + '0x0675e8F4A52eA6c845CB6427Af03616a2af42170', + ['function balanceOf(address) view returns (uint)'], + RPCProvider, + ) + const RWAContractBalance = await RWAContract.balanceOf(addressList[i]) + totalAmount += Number(RWAContractBalance) + } } const totalTokens = 100_000 @@ -54,10 +70,11 @@ export const useRWA = () => { const addressList = useSelector(selectUserAddressList) const { rate } = useSelector(selectUserCurrency) + const includeETH = useSelector(selectUserIncludesEth) useEffect(() => { ;(async () => { - const rwa_ = await getRWA(addressList, rate) + const rwa_ = await getRWA(addressList, rate, includeETH) setRwa(rwa_) })() From 787bf7c2a058db012a8b768a7ce8dd44d5b3413c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 01:39:14 +0200 Subject: [PATCH 24/71] fix: en communs --- src/i18next/locales/en/common.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index 93081e2..743d6c4 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -68,7 +68,8 @@ "realtokenValue": "RealTokens", "totalPriceCost": "Estimated price cost", "stableDeposit": "RMM deposit", - "stableBorrow": "RMM borrow" + "stableBorrow": "RMM borrow", + "rwa": "RWA" }, "worthCard": { "title": "RealTokens", From 1e4e44e8a1c5c510a5a9136d9a6c1b97a5660e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 02:11:56 +0200 Subject: [PATCH 25/71] feat: update filter to support RWA token --- src/components/assetsView/AssetsView.tsx | 10 ++-- .../assetsView/AssetsViewSearch.tsx | 11 +++-- .../filters/AssetsViewRentStatusFilter.tsx | 14 ++++-- .../filters/AssetsViewRmmStatusFilter.tsx | 12 +++-- .../assetsView/filters/AssetsViewSort.tsx | 47 ++++++++++++------- .../filters/AssetsViewSubsidyFilter.tsx | 24 ++++++---- .../filters/AssetsViewUserProtocolFilter.tsx | 18 ++++--- .../filters/AssetsViewUserStatusFilter.tsx | 18 ++++--- .../assetsView/filters/useFilters.ts | 9 +++- src/components/assetsView/views/AssetGrid.tsx | 15 ++---- .../assetsView/views/AssetTable.tsx | 20 ++++++-- src/components/cards/main/SummaryCard.tsx | 4 +- 12 files changed, 124 insertions(+), 78 deletions(-) diff --git a/src/components/assetsView/AssetsView.tsx b/src/components/assetsView/AssetsView.tsx index c8b81d7..fff92fb 100644 --- a/src/components/assetsView/AssetsView.tsx +++ b/src/components/assetsView/AssetsView.tsx @@ -3,6 +3,7 @@ import { useSelector } from 'react-redux' import { Grid } from '@mantine/core' +import { useRWA } from 'src/hooks/useRWA' import { selectUserRealtokens } from 'src/store/features/wallets/walletsSelector' import { AssetsViewSearch, useAssetsViewSearch } from './AssetsViewSearch' @@ -19,11 +20,12 @@ export const AssetsView: FC = () => { const { choosenAssetView } = useAssetsViewSelect() const realtokens = useSelector(selectUserRealtokens) + const rwa = useRWA() - const data = useMemo( - () => assetsViewFilterFunction(realtokens.filter(assetSearchFunction)), - [realtokens, assetSearchFunction, assetsViewFilterFunction], - ) + const data = useMemo(() => { + const assets = rwa ? [...realtokens, rwa] : realtokens + return assetsViewFilterFunction(assets.filter(assetSearchFunction)) + }, [realtokens, rwa, assetSearchFunction, assetsViewFilterFunction]) return realtokens.length ? ( <> diff --git a/src/components/assetsView/AssetsViewSearch.tsx b/src/components/assetsView/AssetsViewSearch.tsx index fb1403c..8b6bd41 100644 --- a/src/components/assetsView/AssetsViewSearch.tsx +++ b/src/components/assetsView/AssetsViewSearch.tsx @@ -3,7 +3,10 @@ import { useTranslation } from 'react-i18next' import { TextInput } from '@mantine/core' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { useInputStyles } from '../inputs/useInputStyles' @@ -36,11 +39,11 @@ export function useAssetsViewSearch() { [assetSearch], ) - function assetSearchFunction(realtoken: UserRealtoken) { + function assetSearchFunction(asset: UserRealtoken | RWARealtoken) { return ( !cleanSearch || - realtoken.shortName.toLowerCase().includes(cleanSearch) || - realtoken.fullName.toLowerCase().includes(cleanSearch) + asset.shortName.toLowerCase().includes(cleanSearch) || + asset.fullName.toLowerCase().includes(cleanSearch) ) } diff --git a/src/components/assetsView/filters/AssetsViewRentStatusFilter.tsx b/src/components/assetsView/filters/AssetsViewRentStatusFilter.tsx index e72e802..5ac9650 100644 --- a/src/components/assetsView/filters/AssetsViewRentStatusFilter.tsx +++ b/src/components/assetsView/filters/AssetsViewRentStatusFilter.tsx @@ -3,7 +3,10 @@ import { useTranslation } from 'react-i18next' import { Select } from '@mantine/core' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { useInputStyles } from '../../inputs/useInputStyles' import { AssetRentStatusType } from '../types' @@ -58,16 +61,17 @@ AssetsViewRentStatusFilter.displayName = 'AssetsViewRentStatusFilter' export function useAssetsViewRentStatusFilter( filter: AssetsViewRentStatusFilterModel, ) { - function assetRentStatusFilterFunction(asset: UserRealtoken) { + function assetRentStatusFilterFunction(asset: UserRealtoken | RWARealtoken) { + const Asset = asset as UserRealtoken switch (filter.rentStatus) { case AssetRentStatusType.ALL: return true case AssetRentStatusType.RENTED: - return asset.rentStatus === 'full' + return Asset.rentStatus === 'full' case AssetRentStatusType.PARTIALLY_RENTED: - return asset.rentStatus === 'partial' + return Asset.rentStatus === 'partial' case AssetRentStatusType.NOT_RENTED: - return asset.rentStatus === 'none' + return Asset.rentStatus === 'none' } } diff --git a/src/components/assetsView/filters/AssetsViewRmmStatusFilter.tsx b/src/components/assetsView/filters/AssetsViewRmmStatusFilter.tsx index c01742b..f73949d 100644 --- a/src/components/assetsView/filters/AssetsViewRmmStatusFilter.tsx +++ b/src/components/assetsView/filters/AssetsViewRmmStatusFilter.tsx @@ -3,7 +3,10 @@ import { useTranslation } from 'react-i18next' import { Select } from '@mantine/core' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { useInputStyles } from '../../inputs/useInputStyles' import { AssetRmmStatusType } from '../types' @@ -53,14 +56,15 @@ AssetsViewRmmStatusFilter.displayName = 'AssetsViewRmmStatusFilter' export function useAssetsViewRmmStatusFilter( filter: AssetsViewRmmStatusFilterModel, ) { - function assetRmmStatusFilterFunction(asset: UserRealtoken) { + function assetRmmStatusFilterFunction(asset: UserRealtoken | RWARealtoken) { + const Asset = asset as UserRealtoken switch (filter.rmmStatus) { case AssetRmmStatusType.ALL: return true case AssetRmmStatusType.AVAILABLE: - return asset.isRmmAvailable + return Asset.isRmmAvailable case AssetRmmStatusType.NOT_AVAILABLE: - return !asset.isRmmAvailable + return !Asset.isRmmAvailable } } diff --git a/src/components/assetsView/filters/AssetsViewSort.tsx b/src/components/assetsView/filters/AssetsViewSort.tsx index 1ffeabf..08f5a6c 100644 --- a/src/components/assetsView/filters/AssetsViewSort.tsx +++ b/src/components/assetsView/filters/AssetsViewSort.tsx @@ -5,7 +5,10 @@ import { useSelector } from 'react-redux' import { Grid, Select, Switch } from '@mantine/core' import { selectTransfersIsLoaded } from 'src/store/features/transfers/transfersSelector' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { useInputStyles } from '../../inputs/useInputStyles' import { AssetSortType } from '../types' @@ -90,42 +93,50 @@ export const AssetsViewSort: FC = ({ AssetsViewSort.displayName = 'AssetsViewSort' export function useAssetsViewSort(filter: AssetsViewSortFilter) { - function assetSortFunction(a: UserRealtoken, b: UserRealtoken) { + function assetSortFunction( + a: UserRealtoken | RWARealtoken, + b: UserRealtoken | RWARealtoken, + ) { const value = getAssetSortValue(a, b) return filter.sortReverse ? value * -1 : value } - function getAssetSortValue(a: UserRealtoken, b: UserRealtoken) { + function getAssetSortValue( + a: UserRealtoken | RWARealtoken, + b: UserRealtoken | RWARealtoken, + ) { + const A = a as UserRealtoken + const B = b as UserRealtoken switch (filter.sortBy) { case AssetSortType.VALUE: - return b.value - a.value + return B.value - A.value case AssetSortType.APR: - return b.annualPercentageYield - a.annualPercentageYield + return B.annualPercentageYield - A.annualPercentageYield case AssetSortType.RENT: - return b.amount * b.netRentDayPerToken - a.amount * a.netRentDayPerToken + return B.amount * B.netRentDayPerToken - A.amount * A.netRentDayPerToken case AssetSortType.RENT_START: - return b.rentStartDate.date.localeCompare(a.rentStartDate.date) + return B.rentStartDate.date.localeCompare(A.rentStartDate.date) case AssetSortType.NAME: - return a.shortName.localeCompare(b.shortName) + return A.shortName.localeCompare(b.shortName) case AssetSortType.SUPPLY: - return b.totalInvestment - a.totalInvestment + return B.totalInvestment - A.totalInvestment case AssetSortType.TOKEN: - return b.amount - a.amount + return B.amount - A.amount case AssetSortType.TOTAL_UNIT: - return b.totalUnits - a.totalUnits + return B.totalUnits - A.totalUnits case AssetSortType.RENTED_UNIT: - return b.rentedUnits - a.rentedUnits + return B.rentedUnits - A.rentedUnits case AssetSortType.OCCUPANCY: - return b.rentedUnits / b.totalUnits - a.rentedUnits / a.totalUnits + return B.rentedUnits / B.totalUnits - A.rentedUnits / A.totalUnits case AssetSortType.INITIAL_LAUNCH: - return b.initialLaunchDate?.date.localeCompare( - a.initialLaunchDate?.date, + return B.initialLaunchDate?.date.localeCompare( + A.initialLaunchDate?.date, ) case AssetSortType.UNIT_PRICE_COST: - return (b.unitPriceCost ?? 0) - (a.unitPriceCost ?? 0) + return (B.unitPriceCost ?? 0) - (A.unitPriceCost ?? 0) case AssetSortType.UNREALIZED_CAPITAL_GAIN: - return (b.unrealizedCapitalGain ?? 0) - (a.unrealizedCapitalGain ?? 0) + return (B.unrealizedCapitalGain ?? 0) - (A.unrealizedCapitalGain ?? 0) case AssetSortType.LAST_CHANGE: - return b.lastChanges.localeCompare(a.lastChanges) ?? 0 + return B.lastChanges.localeCompare(A.lastChanges) ?? 0 } } diff --git a/src/components/assetsView/filters/AssetsViewSubsidyFilter.tsx b/src/components/assetsView/filters/AssetsViewSubsidyFilter.tsx index b38c557..fb46586 100644 --- a/src/components/assetsView/filters/AssetsViewSubsidyFilter.tsx +++ b/src/components/assetsView/filters/AssetsViewSubsidyFilter.tsx @@ -3,7 +3,10 @@ import { useTranslation } from 'react-i18next' import { Select } from '@mantine/core' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { useInputStyles } from '../../inputs/useInputStyles' import { AssetSubsidyType } from '../types' @@ -73,27 +76,28 @@ AssetsViewSubsidyFilter.displayName = 'AssetsViewSubsidyFilter' export function useAssetsViewSubsidyFilter( filter: AssetsViewSubsidyFilterModel, ) { - function assetSubsidyFilterFunction(asset: UserRealtoken) { + function assetSubsidyFilterFunction(asset: UserRealtoken | RWARealtoken) { + const Asset = asset as UserRealtoken switch (filter.subsidy) { case AssetSubsidyType.ALL: return true case AssetSubsidyType.SUBSIDIZED: - return asset.subsidyStatus !== 'no' + return Asset.subsidyStatus !== 'no' case AssetSubsidyType.FULLY_SUBSIDIZED: - return asset.subsidyStatus === 'yes' && !!asset.subsidyStatusValue + return Asset.subsidyStatus === 'yes' && !!Asset.subsidyStatusValue case AssetSubsidyType.PARTIALLY_SUBSIDIZED: - return asset.subsidyStatus !== 'no' && !!asset.subsidyStatusValue + return Asset.subsidyStatus !== 'no' && !!Asset.subsidyStatusValue case AssetSubsidyType.SECTION_8: - return asset.subsidyStatus !== 'no' && asset.subsidyBy === 'Section 8' + return Asset.subsidyStatus !== 'no' && Asset.subsidyBy === 'Section 8' case AssetSubsidyType.SECTION_42: - return asset.subsidyStatus !== 'no' && asset.subsidyBy === 'Section 42' + return Asset.subsidyStatus !== 'no' && Asset.subsidyBy === 'Section 42' case AssetSubsidyType.OTHER_SUBSIDY: return ( - asset.subsidyStatus !== 'no' && - !['Section 8', 'Section 42'].includes(asset.subsidyBy ?? '') + Asset.subsidyStatus !== 'no' && + !['Section 8', 'Section 42'].includes(Asset.subsidyBy ?? '') ) case AssetSubsidyType.NOT_SUBSIDIZED: - return !asset.subsidyStatus || asset.subsidyStatus === 'no' + return !Asset.subsidyStatus || Asset.subsidyStatus === 'no' } } diff --git a/src/components/assetsView/filters/AssetsViewUserProtocolFilter.tsx b/src/components/assetsView/filters/AssetsViewUserProtocolFilter.tsx index 329b24e..8072b35 100644 --- a/src/components/assetsView/filters/AssetsViewUserProtocolFilter.tsx +++ b/src/components/assetsView/filters/AssetsViewUserProtocolFilter.tsx @@ -3,7 +3,10 @@ import { useTranslation } from 'react-i18next' import { Select } from '@mantine/core' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { useInputStyles } from '../../inputs/useInputStyles' import { AssetUserProtocolType } from '../types' @@ -62,18 +65,21 @@ AssetsViewUserProtocolFilter.displayName = 'AssetsViewUserProtocolFilter' export function useAssetsViewUserProtocolFilter( filter: AssetsViewUserProtocolFilterModel, ) { - function assetUserProtocolFilterFunction(asset: UserRealtoken) { + function assetUserProtocolFilterFunction( + asset: UserRealtoken | RWARealtoken, + ) { + const Asset = asset as UserRealtoken switch (filter.userProtocol) { case AssetUserProtocolType.ALL: return true case AssetUserProtocolType.ETHEREUM: - return asset.balance.ethereum.amount > 0 + return Asset.balance.ethereum.amount > 0 case AssetUserProtocolType.GNOSIS: - return asset.balance.gnosis.amount > 0 + return Asset.balance.gnosis.amount > 0 case AssetUserProtocolType.RMM: - return asset.balance.rmm.amount > 0 + return Asset.balance.rmm.amount > 0 case AssetUserProtocolType.LEVINSWAP: - return asset.balance.levinSwap.amount > 0 + return Asset.balance.levinSwap.amount > 0 } } diff --git a/src/components/assetsView/filters/AssetsViewUserStatusFilter.tsx b/src/components/assetsView/filters/AssetsViewUserStatusFilter.tsx index 8a3d930..635ff06 100644 --- a/src/components/assetsView/filters/AssetsViewUserStatusFilter.tsx +++ b/src/components/assetsView/filters/AssetsViewUserStatusFilter.tsx @@ -3,7 +3,10 @@ import { useTranslation } from 'react-i18next' import { Select } from '@mantine/core' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { useInputStyles } from '../../inputs/useInputStyles' import { AssetUserStatusType } from '../types' @@ -66,20 +69,21 @@ AssetsViewUserStatusFilter.displayName = 'AssetsViewUserStatusFilter' export function useAssetsViewUserStatusFilter( filter: AssetsViewUserStatusFilterModel, ) { - function assetUserStatusFilterFunction(asset: UserRealtoken) { + function assetUserStatusFilterFunction(asset: UserRealtoken | RWARealtoken) { + const Asset = asset as UserRealtoken switch (filter.userStatus) { case AssetUserStatusType.ALL: return true case AssetUserStatusType.OWNED: - return asset.amount > 0 + return Asset.amount > 0 case AssetUserStatusType.WHITELISTED: - return asset.isWhitelisted + return Asset.isWhitelisted case AssetUserStatusType.WHITELISTED_NOT_OWNED: - return asset.isWhitelisted && asset.amount === 0 + return Asset.isWhitelisted && Asset.amount === 0 case AssetUserStatusType.NOT_OWNED: - return asset.amount === 0 + return Asset.amount === 0 case AssetUserStatusType.NOT_WHITELISTED: - return !asset.isWhitelisted + return !Asset.isWhitelisted } } diff --git a/src/components/assetsView/filters/useFilters.ts b/src/components/assetsView/filters/useFilters.ts index 2cb2a05..dae6dc0 100644 --- a/src/components/assetsView/filters/useFilters.ts +++ b/src/components/assetsView/filters/useFilters.ts @@ -1,7 +1,10 @@ import { useAtom } from 'jotai' import { assetsViewDefaultFilter, assetsViewFilterAtom } from 'src/states' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' import { useAssetsViewRentStatusFilter } from './AssetsViewRentStatusFilter' import { useAssetsViewRmmStatusFilter } from './AssetsViewRmmStatusFilter' @@ -26,7 +29,9 @@ export function useAssetsViewFilters() { const { assetUserProtocolFilterFunction } = useAssetsViewUserProtocolFilter(activeFilter) - function assetsViewFilterFunction(tokenList: UserRealtoken[]) { + function assetsViewFilterFunction( + tokenList: (UserRealtoken | RWARealtoken)[], + ) { return tokenList .filter(assetUserStatusFilterFunction) .filter(assetUserProtocolFilterFunction) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index 62d9f24..26a7cf3 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -5,8 +5,6 @@ import { useRouter } from 'next/router' import { Grid, Group, Pagination } from '@mantine/core' -import { useRWA } from 'src/hooks/useRWA' -import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' import { RWARealtoken, UserRealtoken, @@ -14,7 +12,9 @@ import { import { AssetCard } from '../../cards' -export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { +export const AssetGrid: FC<{ realtokens: (UserRealtoken | RWARealtoken)[] }> = ( + props, +) => { const router = useRouter() const [page, setPage] = useState(1) const pageSize = 24 @@ -25,16 +25,11 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { document.getElementsByClassName('asset-grid')[0]?.scrollIntoView() } - const rwa = useRWA() - const paginationOffers = useMemo(() => { - if (!rwa) return [] - const start = (page - 1) * pageSize const end = start + pageSize - const items = [...props.realtokens, rwa] - return items.slice(start, end) - }, [props.realtokens, page, pageSize, rwa]) + return props.realtokens.slice(start, end) + }, [props.realtokens, page, pageSize]) // Go to first page when data changes (e.g. search, filter, order, ...) useEffect(() => setPage(1), [props.realtokens]) diff --git a/src/components/assetsView/views/AssetTable.tsx b/src/components/assetsView/views/AssetTable.tsx index 98f2a68..6e9f95b 100644 --- a/src/components/assetsView/views/AssetTable.tsx +++ b/src/components/assetsView/views/AssetTable.tsx @@ -10,9 +10,15 @@ import moment from 'moment' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' import { selectTransfersIsLoaded } from 'src/store/features/transfers/transfersSelector' -import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { + RWARealtoken, + UserRealtoken, +} from 'src/store/features/wallets/walletsSelector' +import { RealToken } from 'src/types/RealToken' -export const AssetTable: FC<{ realtokens: UserRealtoken[] }> = (props) => { +export const AssetTable: FC<{ + realtokens: (UserRealtoken | RWARealtoken)[] +}> = (props) => { return ( @@ -21,9 +27,13 @@ export const AssetTable: FC<{ realtokens: UserRealtoken[] }> = (props) => { - {props.realtokens.map((item) => ( - - ))} + {props.realtokens.map((item, index) => { + const isAProperty = item.hasOwnProperty('rentStatus') + if (!isAProperty) { + return + } + return + })}
diff --git a/src/components/cards/main/SummaryCard.tsx b/src/components/cards/main/SummaryCard.tsx index ec79d3c..a500d04 100644 --- a/src/components/cards/main/SummaryCard.tsx +++ b/src/components/cards/main/SummaryCard.tsx @@ -1,12 +1,10 @@ -import { FC, useEffect, useState } from 'react' +import { FC } from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' import { Box, Card, Text, Title } from '@mantine/core' -import { useCurrencyValue } from 'src/hooks/useCurrencyValue' import { useRWA } from 'src/hooks/useRWA' -import { selectUserAddressList } from 'src/store/features/settings/settingsSelector' import { selectTransfersIsLoaded } from 'src/store/features/transfers/transfersSelector' import { selectOwnedRealtokensValue, From aa6f3d73089818564b7348f9c19aed980a24f6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 02:20:13 +0200 Subject: [PATCH 26/71] fix: prettier --- src/hooks/useRWA.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useRWA.ts b/src/hooks/useRWA.ts index d09c8c3..d8c6a02 100644 --- a/src/hooks/useRWA.ts +++ b/src/hooks/useRWA.ts @@ -73,7 +73,7 @@ export const useRWA = () => { const includeETH = useSelector(selectUserIncludesEth) useEffect(() => { - ;(async () => { + (async () => { const rwa_ = await getRWA(addressList, rate, includeETH) setRwa(rwa_) From 60908dad9595e1c78354f0e5cd29fde3a6eac716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 02:33:04 +0200 Subject: [PATCH 27/71] fix: other prettier errors --- .prettierrc.js | 2 +- next.config.js | 6 +++--- postcss.config.cjs | 2 +- src/components/cards/AssetCard.tsx | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.prettierrc.js b/.prettierrc.js index 18c42b9..c3ab6c8 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -14,7 +14,7 @@ module.exports = { '^i18next(.*)', '^(?!(src|../|./))(.*)', '^src(.*)$', - '^(.*)$' + '^(.*)$', ], importOrderSeparation: true, importOrderSortSpecifiers: true, diff --git a/next.config.js b/next.config.js index ca1d6f7..369bee8 100644 --- a/next.config.js +++ b/next.config.js @@ -11,11 +11,11 @@ const nextConfig = { outputStandalone: true, }, images: { - domains: ['realt.co'] + domains: ['realt.co'], }, publicRuntimeConfig: { version, }, -}; +} -module.exports = nextConfig; +module.exports = nextConfig diff --git a/postcss.config.cjs b/postcss.config.cjs index c759b74..6a68362 100644 --- a/postcss.config.cjs +++ b/postcss.config.cjs @@ -11,4 +11,4 @@ module.exports = { }, }, }, -}; \ No newline at end of file +} diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 0d91f6e..fe9e4d2 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -1,4 +1,4 @@ -import { FC} from 'react' +import { FC } from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' From c7dd3d6d319ff2b99d3bc51868f9f338c6226e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 02:44:43 +0200 Subject: [PATCH 28/71] let prettier add strange semi-column --- src/hooks/useRWA.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useRWA.ts b/src/hooks/useRWA.ts index d8c6a02..d09c8c3 100644 --- a/src/hooks/useRWA.ts +++ b/src/hooks/useRWA.ts @@ -73,7 +73,7 @@ export const useRWA = () => { const includeETH = useSelector(selectUserIncludesEth) useEffect(() => { - (async () => { + ;(async () => { const rwa_ = await getRWA(addressList, rate, includeETH) setRwa(rwa_) From 3d51ee62b89f5c10389a467a68ba5984c6223530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 02:48:42 +0200 Subject: [PATCH 29/71] fix: imports --- src/components/assetsView/views/AssetGrid.tsx | 1 - src/components/assetsView/views/AssetTable.tsx | 1 - src/components/cards/AssetCard.tsx | 1 - 3 files changed, 3 deletions(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index 26a7cf3..01c7f93 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -1,5 +1,4 @@ import { FC, useEffect, useMemo, useState } from 'react' -import { useSelector } from 'react-redux' import { useRouter } from 'next/router' diff --git a/src/components/assetsView/views/AssetTable.tsx b/src/components/assetsView/views/AssetTable.tsx index 6e9f95b..3e85df8 100644 --- a/src/components/assetsView/views/AssetTable.tsx +++ b/src/components/assetsView/views/AssetTable.tsx @@ -14,7 +14,6 @@ import { RWARealtoken, UserRealtoken, } from 'src/store/features/wallets/walletsSelector' -import { RealToken } from 'src/types/RealToken' export const AssetTable: FC<{ realtokens: (UserRealtoken | RWARealtoken)[] diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index fe9e4d2..36523bb 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -6,7 +6,6 @@ import Image from 'next/image' import { Badge, Card, Group } from '@mantine/core' -import { es } from 'date-fns/locale' import moment from 'moment' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' From 6462260fc09ca0f0caafac25c14f2fe553c7cb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 21:53:11 +0200 Subject: [PATCH 30/71] use hook --- src/components/cards/AssetCard.tsx | 52 +++------------------------ src/hooks/useFullyRentedAPR.ts | 58 ++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 47 deletions(-) create mode 100644 src/hooks/useFullyRentedAPR.ts diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index 4fcd666..f479b51 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -9,6 +9,7 @@ import { Badge, Card, Group } from '@mantine/core' import moment from 'moment' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' +import { useFullyRentedAPR } from 'src/hooks/useFullyRentedAPR' import { selectUserRentCalculation } from 'src/store/features/settings/settingsSelector' import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' import { RentCalculationState } from 'src/types/RentCalculation' @@ -48,8 +49,7 @@ const AssetCardComponent: FC = (props) => { const yearlyAmount = props.value.amount * props.value.netRentYearPerToken const totalInvestment = props.value.totalInvestment - const fullyRentedAPR = - Math.floor(fullyRentedAPREstimation(props.value) * 100) / 100 + const fullyRentedAPR = useFullyRentedAPR(props.value) return ( = (props) => {
{t('fullyRentedEstimation')}*
-
{fullyRentedAPR} %
+
+ {tNumbers('percent', { value: fullyRentedAPR })} +
@@ -166,48 +168,4 @@ const AssetCardComponent: FC = (props) => { ) } -const fullyRentedAPREstimation = (token: UserRealtoken) => { - if (token.rentedUnits === token.totalUnits) { - return token.annualPercentageYield - } - - if (token.rentedUnits === 0 && token.annualPercentageYield !== 0) { - return token.annualPercentageYield - } - - const APREstimation = () => { - if (token.history.length > 0) { - let propInfo = token.history[0].values - const history = token.history.map((h) => { - propInfo = { ...propInfo, ...h.values } - return propInfo - }) - - const previousAPR = history - .map((h) => { - if ( - h.rentedUnits && - h.rentedUnits !== 0 && - h.netRentYear && - h.tokenPrice - ) { - return ( - ((h.netRentYear * token.totalUnits) / - (token.totalTokens * h.tokenPrice * h.rentedUnits)) * - 100 - ) - } - return 0 - }) - .filter((apr) => apr !== undefined) - - return Math.max(...previousAPR) - } else { - return 0 - } - } - - return APREstimation() -} - export const AssetCard = memo(AssetCardComponent) diff --git a/src/hooks/useFullyRentedAPR.ts b/src/hooks/useFullyRentedAPR.ts new file mode 100644 index 0000000..b36dab0 --- /dev/null +++ b/src/hooks/useFullyRentedAPR.ts @@ -0,0 +1,58 @@ +import { useEffect, useState } from 'react' + +import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' + +const fullyRentedAPREstimation = (token: UserRealtoken) => { + // Case of fully rented property + if (token.rentedUnits === token.totalUnits) { + return token.annualPercentageYield + } + + // Case of property with no rented unit but with APR (e.g. RMM or rent paid by inssurance) + if (token.rentedUnits === 0 && token.annualPercentageYield !== 0) { + return token.annualPercentageYield + } + + if (token.history.length > 0) { + let propInfo = token.history[0].values + const history = token.history.map((h) => { + propInfo = { ...propInfo, ...h.values } + return propInfo + }) + + const previousAPR = history + .map((h) => { + if ( + h.rentedUnits && + h.rentedUnits !== 0 && + h.netRentYear && + h.tokenPrice + ) { + return ( + ((h.netRentYear * token.totalUnits) / + (token.totalTokens * h.tokenPrice * h.rentedUnits)) * + 100 + ) + } + return 0 + }) + .filter((apr) => apr !== undefined) + + // Assuming the highest APR is the most accurate + return Math.max(...previousAPR, token.annualPercentageYield) + } + + return Math.max(token.annualPercentageYield, 0) +} + +export const useFullyRentedAPR = (token: UserRealtoken) => { + const [fullyRentedAPR, setFullyRentedAPR] = useState( + fullyRentedAPREstimation(token), + ) + + useEffect(() => { + setFullyRentedAPR(fullyRentedAPREstimation(token)) + }, [token]) + + return fullyRentedAPR +} From 86cfeb24829f4a661aa432d555bbd4973bf37ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 22:11:05 +0200 Subject: [PATCH 31/71] add fallback --- src/components/cards/AssetCard.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/cards/AssetCard.tsx b/src/components/cards/AssetCard.tsx index f479b51..eb4f351 100644 --- a/src/components/cards/AssetCard.tsx +++ b/src/components/cards/AssetCard.tsx @@ -156,7 +156,9 @@ const AssetCardComponent: FC = (props) => {
{t('fullyRentedEstimation')}*
- {tNumbers('percent', { value: fullyRentedAPR })} + {fullyRentedAPR + ? tNumbers('percent', { value: fullyRentedAPR }) + : '-'}
From 3e0787abef5759e5ea552c03534abb90405ab7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 22:22:23 +0200 Subject: [PATCH 32/71] switch for a useMemo --- src/hooks/useFullyRentedAPR.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/hooks/useFullyRentedAPR.ts b/src/hooks/useFullyRentedAPR.ts index b36dab0..d4e08c3 100644 --- a/src/hooks/useFullyRentedAPR.ts +++ b/src/hooks/useFullyRentedAPR.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react' +import { useMemo } from 'react' import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' @@ -46,13 +46,7 @@ const fullyRentedAPREstimation = (token: UserRealtoken) => { } export const useFullyRentedAPR = (token: UserRealtoken) => { - const [fullyRentedAPR, setFullyRentedAPR] = useState( - fullyRentedAPREstimation(token), - ) - - useEffect(() => { - setFullyRentedAPR(fullyRentedAPREstimation(token)) - }, [token]) + const fullyRentedAPR = useMemo(() => fullyRentedAPREstimation(token), [token]) return fullyRentedAPR } From 175d3ff5ea766fadf3e040312eb5f98199a0dfed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 22:55:19 +0200 Subject: [PATCH 33/71] feat: add real time fully rented APR --- src/hooks/useFullyRentedAPR.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/hooks/useFullyRentedAPR.ts b/src/hooks/useFullyRentedAPR.ts index d4e08c3..b7ff331 100644 --- a/src/hooks/useFullyRentedAPR.ts +++ b/src/hooks/useFullyRentedAPR.ts @@ -1,6 +1,11 @@ import { useMemo } from 'react' +import { useSelector } from 'react-redux' +import moment from 'moment' + +import { selectUserRentCalculation } from 'src/store/features/settings/settingsSelector' import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' +import { RentCalculationState } from 'src/types/RentCalculation' const fullyRentedAPREstimation = (token: UserRealtoken) => { // Case of fully rented property @@ -46,7 +51,17 @@ const fullyRentedAPREstimation = (token: UserRealtoken) => { } export const useFullyRentedAPR = (token: UserRealtoken) => { - const fullyRentedAPR = useMemo(() => fullyRentedAPREstimation(token), [token]) + const rentCalculation = useSelector(selectUserRentCalculation) + + const fullyRentedAPR = useMemo(() => { + const realtimeDate = moment(new Date(rentCalculation.date)) + const rentStartDate = new Date(token.rentStartDate.date) + const isDisabled = + rentCalculation.state === RentCalculationState.Realtime && + rentStartDate > realtimeDate.toDate() + if (isDisabled) return 0 + return fullyRentedAPREstimation(token) + }, [token, rentCalculation]) return fullyRentedAPR } From d00acd306d246f6851874fbe84f612e1d6168b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 23:38:49 +0200 Subject: [PATCH 34/71] feat: add gloabl metric fully rented APR --- src/components/cards/main/RentsCard.tsx | 9 +++++ src/hooks/useFullyRentedAPR.ts | 44 +++++++++++++++++++++---- src/i18next/locales/en/common.json | 1 + src/i18next/locales/fr/common.json | 1 + 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/components/cards/main/RentsCard.tsx b/src/components/cards/main/RentsCard.tsx index 2f1f188..20df43e 100644 --- a/src/components/cards/main/RentsCard.tsx +++ b/src/components/cards/main/RentsCard.tsx @@ -4,7 +4,9 @@ import { useSelector } from 'react-redux' import { Box, Card, Title } from '@mantine/core' +import { useGeneralFullyRentedAPR } from 'src/hooks/useFullyRentedAPR' import { + selectOwnedRealtokens, selectOwnedRealtokensAPY, selectOwnedRealtokensRents, } from 'src/store/features/wallets/walletsSelector' @@ -16,6 +18,7 @@ export const RentsCard: FC = () => { const rents = useSelector(selectOwnedRealtokensRents) const apy = useSelector(selectOwnedRealtokensAPY) + const realtokens = useSelector(selectOwnedRealtokens) // In Dollars const dailyRents = rents.daily @@ -23,11 +26,17 @@ export const RentsCard: FC = () => { const monthlyRents = rents.monthly const yearlyRents = rents.yearly + const fullyRentedAPR = useGeneralFullyRentedAPR(realtokens) + return ( {t('title')} + diff --git a/src/hooks/useFullyRentedAPR.ts b/src/hooks/useFullyRentedAPR.ts index b7ff331..15519b3 100644 --- a/src/hooks/useFullyRentedAPR.ts +++ b/src/hooks/useFullyRentedAPR.ts @@ -5,7 +5,10 @@ import moment from 'moment' import { selectUserRentCalculation } from 'src/store/features/settings/settingsSelector' import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' -import { RentCalculationState } from 'src/types/RentCalculation' +import { + RentCalculation, + RentCalculationState, +} from 'src/types/RentCalculation' const fullyRentedAPREstimation = (token: UserRealtoken) => { // Case of fully rented property @@ -54,14 +57,43 @@ export const useFullyRentedAPR = (token: UserRealtoken) => { const rentCalculation = useSelector(selectUserRentCalculation) const fullyRentedAPR = useMemo(() => { - const realtimeDate = moment(new Date(rentCalculation.date)) - const rentStartDate = new Date(token.rentStartDate.date) - const isDisabled = - rentCalculation.state === RentCalculationState.Realtime && - rentStartDate > realtimeDate.toDate() + const isDisabled = APRDisabled(rentCalculation, token) if (isDisabled) return 0 return fullyRentedAPREstimation(token) }, [token, rentCalculation]) return fullyRentedAPR } + +export const useGeneralFullyRentedAPR = (tokens: UserRealtoken[]) => { + const rentCalculation = useSelector(selectUserRentCalculation) + // Fully rented APR average using valuation ponderation + const fullyRentedAPR = useMemo(() => { + const totalValue = tokens.reduce((acc, token) => { + const isDisabled = APRDisabled(rentCalculation, token) + if (isDisabled) return acc + return acc + token.value + }, 0) + const totalAPR = tokens.reduce((acc, token) => { + const isDisabled = APRDisabled(rentCalculation, token) + if (isDisabled) return acc + return acc + token.value * fullyRentedAPREstimation(token) + }, 0) + console.log({ totalValue, totalAPR, fullyRentedAPR: totalAPR / totalValue }) + return totalAPR / totalValue + }, [tokens, rentCalculation]) + + return fullyRentedAPR +} + +const APRDisabled = ( + rentCalculation: RentCalculation, + token: UserRealtoken, +) => { + const realtimeDate = moment(new Date(rentCalculation.date)) + const rentStartDate = new Date(token.rentStartDate.date) + const isDisabled = + rentCalculation.state === RentCalculationState.Realtime && + rentStartDate > realtimeDate.toDate() + return isDisabled +} diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index 9a83d0d..fe13057 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -81,6 +81,7 @@ "rentsCard": { "title": "Rents", "apr": "APR", + "fullyRentedAPR": "Fully rented APR *", "daily": "Daily", "weekly": "Weekly", "monthly": "Monthly", diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index e0aa856..211783c 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -81,6 +81,7 @@ "rentsCard": { "title": "Loyers", "apr": "Rendement annuel", + "fullyRentedAPR": "Rendement 100% loué *", "daily": "Journaliers", "weekly": "Hebdomadaires", "monthly": "Mensuels", From 8cded5da8c597ebe9446a2e1e8344054884b7f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Thu, 15 Aug 2024 23:52:02 +0200 Subject: [PATCH 35/71] feat: add disclaimer --- src/components/assetsView/views/AssetGrid.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index c794c38..edfbb81 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -2,7 +2,7 @@ import { FC, useEffect, useMemo, useState } from 'react' import { useRouter } from 'next/router' -import { Grid, Group, Pagination } from '@mantine/core' +import { Grid, Group, Pagination, Text } from '@mantine/core' import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' @@ -56,6 +56,12 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { onChange={onPageChange} /> + + * This is a beta estimation done by RealT community. Please report any + issues. Please note that is an indicative value and not a guarantee. + RealT community does not take any responsibility for the accuracy of + this information. + ) } From cdc615fdfabb7f0bbaa66b21a32513236556f255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 16 Aug 2024 00:11:42 +0200 Subject: [PATCH 36/71] feat: add disclaimer --- src/components/assetsView/views/AssetGrid.tsx | 8 ++------ .../commons/others/FullyRentedAPRDisclaimer.tsx | 14 ++++++++++++++ src/i18next/locales/en/common.json | 3 +++ src/i18next/locales/fr/common.json | 3 +++ 4 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 src/components/commons/others/FullyRentedAPRDisclaimer.tsx diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index edfbb81..cf430f8 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -4,6 +4,7 @@ import { useRouter } from 'next/router' import { Grid, Group, Pagination, Text } from '@mantine/core' +import FullyRentedAPRDisclaimer from 'src/components/commons/others/FullyRentedAPRDisclaimer' import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' import { AssetCard } from '../../cards' @@ -55,13 +56,8 @@ export const AssetGrid: FC<{ realtokens: UserRealtoken[] }> = (props) => { size={'sm'} onChange={onPageChange} /> + - - * This is a beta estimation done by RealT community. Please report any - issues. Please note that is an indicative value and not a guarantee. - RealT community does not take any responsibility for the accuracy of - this information. - ) } diff --git a/src/components/commons/others/FullyRentedAPRDisclaimer.tsx b/src/components/commons/others/FullyRentedAPRDisclaimer.tsx new file mode 100644 index 0000000..8a977cd --- /dev/null +++ b/src/components/commons/others/FullyRentedAPRDisclaimer.tsx @@ -0,0 +1,14 @@ +import { useTranslation } from 'react-i18next' + +import { Text } from '@mantine/core' + +const FullyRentedAPRDisclaimer = () => { + const { t } = useTranslation('common', { keyPrefix: 'disclaimer' }) + return ( + + *{t('fullyRentedAPR')} + + ) +} + +export default FullyRentedAPRDisclaimer diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index fe13057..ceb12ce 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -372,5 +372,8 @@ "initialTransfersLoader": { "title": "Initial data loading", "description": "Retrieving your transactions in progress. This loading can take some time depending on the number of transactions performed (10-20 seconds / 1000 transactions). On your next visits, only new transactions will be retrieved." + }, + "disclaimer":{ + "fullyRentedAPR": "This is a beta estimation done by RealT community. Please report any issues. Please note that is an indicative value and not a guarantee. RealT community does not take any responsibility for the accuracy of this information." } } diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index 211783c..88de786 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -374,5 +374,8 @@ "initialTransfersLoader": { "title": "Chargement initial des données", "description": "Récupération de vos transactions en cours. Ce chargement peut prendre un certain temps en fonction du nombre de transactions effecutées (10-20 secondes / 1000 transactions). Lors de vos prochaines visites, seul les nouvelles transactions seront récupérées." + }, + "disclaimer":{ + "fullyRentedAPR": "Cette estimation est en phase bêta et a été développée par la communauté RealT. Nous vous invitons à signaler tout problème éventuel. Les informations fournies sont à titre indicatif uniquement. La communauté RealT ne peut être tenu responsable en cas d'inexactitude des données." } } From 1ae5788c6f416cd3b5ecd823ad36cf3451661f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 16 Aug 2024 00:13:03 +0200 Subject: [PATCH 37/71] feat: update disclaimer message --- src/i18next/locales/en/common.json | 2 +- src/i18next/locales/fr/common.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index ceb12ce..ee2690e 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -374,6 +374,6 @@ "description": "Retrieving your transactions in progress. This loading can take some time depending on the number of transactions performed (10-20 seconds / 1000 transactions). On your next visits, only new transactions will be retrieved." }, "disclaimer":{ - "fullyRentedAPR": "This is a beta estimation done by RealT community. Please report any issues. Please note that is an indicative value and not a guarantee. RealT community does not take any responsibility for the accuracy of this information." + "fullyRentedAPR": "This is a beta estimation done by RealT community. Please report any issues. Please note that is an indicative value and not a guarantee. RealT community or RealT does not take any responsibility for the accuracy of this information." } } diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index 88de786..deda98b 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -376,6 +376,6 @@ "description": "Récupération de vos transactions en cours. Ce chargement peut prendre un certain temps en fonction du nombre de transactions effecutées (10-20 secondes / 1000 transactions). Lors de vos prochaines visites, seul les nouvelles transactions seront récupérées." }, "disclaimer":{ - "fullyRentedAPR": "Cette estimation est en phase bêta et a été développée par la communauté RealT. Nous vous invitons à signaler tout problème éventuel. Les informations fournies sont à titre indicatif uniquement. La communauté RealT ne peut être tenu responsable en cas d'inexactitude des données." + "fullyRentedAPR": "Cette estimation est en phase bêta et a été développée par la communauté RealT ou RealT. Nous vous invitons à signaler tout problème éventuel. Les informations fournies sont à titre indicatif uniquement. La communauté RealT ne peut être tenu responsable en cas d'inexactitude des données." } } From 72abe3171ee53c4d88858006a720793db0eee0e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 16 Aug 2024 00:16:05 +0200 Subject: [PATCH 38/71] fix: disclaimer message --- src/i18next/locales/fr/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index deda98b..f5f81b8 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -376,6 +376,6 @@ "description": "Récupération de vos transactions en cours. Ce chargement peut prendre un certain temps en fonction du nombre de transactions effecutées (10-20 secondes / 1000 transactions). Lors de vos prochaines visites, seul les nouvelles transactions seront récupérées." }, "disclaimer":{ - "fullyRentedAPR": "Cette estimation est en phase bêta et a été développée par la communauté RealT ou RealT. Nous vous invitons à signaler tout problème éventuel. Les informations fournies sont à titre indicatif uniquement. La communauté RealT ne peut être tenu responsable en cas d'inexactitude des données." + "fullyRentedAPR": "Cette estimation est en phase bêta et a été développée par la communauté RealT. Nous vous invitons à signaler tout problème éventuel. Les informations fournies sont à titre indicatif uniquement. La communauté RealT ou RealT ne peut être tenu responsable en cas d'inexactitude des données." } } From 417c0381ff84f72bb69f14b03f41db9671e62e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Fri, 16 Aug 2024 00:18:19 +0200 Subject: [PATCH 39/71] improve message --- src/i18next/locales/en/common.json | 2 +- src/i18next/locales/fr/common.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index ee2690e..0a0861b 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -374,6 +374,6 @@ "description": "Retrieving your transactions in progress. This loading can take some time depending on the number of transactions performed (10-20 seconds / 1000 transactions). On your next visits, only new transactions will be retrieved." }, "disclaimer":{ - "fullyRentedAPR": "This is a beta estimation done by RealT community. Please report any issues. Please note that is an indicative value and not a guarantee. RealT community or RealT does not take any responsibility for the accuracy of this information." + "fullyRentedAPR": "This is a beta estimation done by RealT community. Please report any issues. Please note that is an indicative value and not a guarantee. RealT community or RealT does not take any responsibility for user actions based on this value." } } diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index f5f81b8..dc9094a 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -376,6 +376,6 @@ "description": "Récupération de vos transactions en cours. Ce chargement peut prendre un certain temps en fonction du nombre de transactions effecutées (10-20 secondes / 1000 transactions). Lors de vos prochaines visites, seul les nouvelles transactions seront récupérées." }, "disclaimer":{ - "fullyRentedAPR": "Cette estimation est en phase bêta et a été développée par la communauté RealT. Nous vous invitons à signaler tout problème éventuel. Les informations fournies sont à titre indicatif uniquement. La communauté RealT ou RealT ne peut être tenu responsable en cas d'inexactitude des données." + "fullyRentedAPR": "Cette estimation est en phase bêta et a été développée par la communauté RealT. Nous vous invitons à signaler tout problème éventuel. Les informations fournies sont à titre indicatif uniquement. La communauté RealT ou RealT ne peut être tenu responsable en cas de décision prise à partir de données inexactites." } } From 6beb363162e26b37c96bdf9dde410f709a15472b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 18:02:44 +0200 Subject: [PATCH 40/71] feat: create yam statics stics page --- src/components/layouts/Header.tsx | 6 ++++++ src/pages/yamStatistics.tsx | 36 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/pages/yamStatistics.tsx diff --git a/src/components/layouts/Header.tsx b/src/components/layouts/Header.tsx index 0fedc02..c76fc3c 100644 --- a/src/components/layouts/Header.tsx +++ b/src/components/layouts/Header.tsx @@ -78,6 +78,12 @@ export const Header: FC = () => { onClick={() => router.push('/histories').then(() => close())} /> + } + onClick={() => router.push('/yamStatistics').then(() => close())} + /> +
{ + return ( +
+

Yam Statistics

+ + + + + + + + + + + + + + + + + + + + + + +
Token PriceYam PriceYam Difference (30 days)Yam Volume
Token PriceYam PriceYam DifferenceYam Volume
+ +
Token PriceYam PriceYam DifferenceYam Volume
+
+ ) +} + +export default YamStatistics From 0b29e7deda53b739446ba12e3b0c0627dcc18802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 19:32:06 +0200 Subject: [PATCH 41/71] feat: add yam statistics for all RealT Tokens on Gnosis (who have Gnosis chain contract prop) --- src/pages/yamStatistics.tsx | 111 +++++++++++++++---- src/repositories/yamStatistics.repository.ts | 13 ++- 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index c0a4118..4532dde 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -1,6 +1,88 @@ +import { useEffect, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useSelector } from 'react-redux' + import { Divider } from '@mantine/core' -const YamStatistics = () => { +import { useCurrencyValue } from 'src/hooks/useCurrencyValue' +import { GetYamStatistics, YamStatistics } from 'src/repositories' +import { + UserRealtoken, + selectAllUserRealtokens, +} from 'src/store/features/wallets/walletsSelector' + +const YamStatisticsRow: React.FC<{ + statistics: YamStatistics + realtoken: UserRealtoken +}> = ({ statistics, realtoken }) => { + const { t: tNumbers } = useTranslation('common', { keyPrefix: 'numbers' }) + const yamPrice = statistics.volume / statistics.quantity + const yamDifference = yamPrice - realtoken.tokenPrice + const yamDifferencePercent = (yamDifference / realtoken.tokenPrice) * 100 + + const yamPriceValue = useCurrencyValue(yamPrice) + const yamDifferenceValue = useCurrencyValue(yamDifference) + const volumeValue = useCurrencyValue(statistics.volume) + + return ( + <> + + {realtoken.tokenPrice} + {yamPriceValue} + + {yamDifferenceValue} ( + {tNumbers('percent', { value: yamDifferencePercent })}) + + {volumeValue} + + + + + + + + + ) +} + +const YamStatisticsPage = () => { + const realtokens = useSelector(selectAllUserRealtokens) + + const [yamStatistics, setYamStatistics] = useState( + realtokens.map(() => { + return { + quantity: 0, + volume: 0, + days: [], + } + }), + ) + + const [isLoading, setIsLoading] = useState(true) + + const yamStatisticsPromise: Promise = useMemo(async () => { + console.log({ realtokens }) + if (!realtokens.length) return Promise.resolve([]) + const statsPromises = realtokens.map((realtoken) => + GetYamStatistics({ realtoken }), + ) + const data = await Promise.all(statsPromises) + return data + }, [realtokens]) + + useEffect(() => { + setIsLoading(true) + yamStatisticsPromise.then((data) => { + setYamStatistics(data) + setIsLoading(false) + console.log({ data }) + }) + }, [yamStatisticsPromise]) + + if (isLoading) { + return
Loading...
+ } + return (

Yam Statistics

@@ -11,26 +93,17 @@ const YamStatistics = () => { Yam Difference (30 days) Yam Volume - - Token Price - Yam Price - Yam Difference - Yam Volume - - - - - - - - Token Price - Yam Price - Yam Difference - Yam Volume - + {yamStatistics && + yamStatistics.map((statistics, index) => ( + + ))}
) } -export default YamStatistics +export default YamStatisticsPage diff --git a/src/repositories/yamStatistics.repository.ts b/src/repositories/yamStatistics.repository.ts index bb4bdea..260e735 100644 --- a/src/repositories/yamStatistics.repository.ts +++ b/src/repositories/yamStatistics.repository.ts @@ -18,8 +18,17 @@ export interface YamStatistics { export async function GetYamStatistics(params: { realtoken: APIRealToken }): Promise { - const address = - params.realtoken.blockchainAddresses.xDai.contract.toLowerCase() + const address = params.realtoken.blockchainAddresses.xDai.contract + ? params.realtoken.blockchainAddresses.xDai.contract.toLowerCase() + : null + + if (!address) { + return { + quantity: 0, + volume: 0, + days: [], + } + } const volumes = await getRealtokenYamStatistics(address) From 7568a40a893b8931d1324f09fb857268172b6d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 19:37:52 +0200 Subject: [PATCH 42/71] feat: mask tokens with no volume --- src/pages/yamStatistics.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index 4532dde..e9b35f2 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -20,11 +20,12 @@ const YamStatisticsRow: React.FC<{ const yamDifference = yamPrice - realtoken.tokenPrice const yamDifferencePercent = (yamDifference / realtoken.tokenPrice) * 100 - const yamPriceValue = useCurrencyValue(yamPrice) - const yamDifferenceValue = useCurrencyValue(yamDifference) - const volumeValue = useCurrencyValue(statistics.volume) + const fallback = '-' + const yamPriceValue = useCurrencyValue(yamPrice, fallback) + const yamDifferenceValue = useCurrencyValue(yamDifference, fallback) + const volumeValue = useCurrencyValue(statistics.volume, fallback) - return ( + return yamPriceValue !== fallback ? ( <> {realtoken.tokenPrice} @@ -42,7 +43,7 @@ const YamStatisticsRow: React.FC<{ - ) + ) : null } const YamStatisticsPage = () => { From e3c048df8ee27bea3a04d6084c9bcc07bc5e4098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 19:39:19 +0200 Subject: [PATCH 43/71] fix: add token name --- src/pages/yamStatistics.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index e9b35f2..9c023fd 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -28,6 +28,7 @@ const YamStatisticsRow: React.FC<{ return yamPriceValue !== fallback ? ( <> + {realtoken.shortName} {realtoken.tokenPrice} {yamPriceValue} @@ -89,6 +90,7 @@ const YamStatisticsPage = () => {

Yam Statistics

+ From 31bf8c922e5a79632146ee980eb0657f50a17a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 19:56:11 +0200 Subject: [PATCH 44/71] feat: add pagination --- src/pages/yamStatistics.tsx | 52 +++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index 9c023fd..4c7dd7e 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' -import { Divider } from '@mantine/core' +import { Divider, Pagination } from '@mantine/core' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' import { GetYamStatistics, YamStatistics } from 'src/repositories' @@ -49,9 +49,14 @@ const YamStatisticsRow: React.FC<{ const YamStatisticsPage = () => { const realtokens = useSelector(selectAllUserRealtokens) + const realtokensWithYam = useMemo(() => { + return realtokens.filter( + (realtoken) => realtoken.blockchainAddresses.xDai.contract, + ) + }, [realtokens]) const [yamStatistics, setYamStatistics] = useState( - realtokens.map(() => { + realtokensWithYam.map(() => { return { quantity: 0, volume: 0, @@ -59,18 +64,26 @@ const YamStatisticsPage = () => { } }), ) + const [page, setPage] = useState(1) + const pageSize = 25 const [isLoading, setIsLoading] = useState(true) + function onPageChange(page: number) { + setPage(page) + // Scroll to top of grid + document.getElementsByClassName('history-list')[0]?.scrollIntoView() + } + const yamStatisticsPromise: Promise = useMemo(async () => { console.log({ realtokens }) - if (!realtokens.length) return Promise.resolve([]) - const statsPromises = realtokens.map((realtoken) => + if (!realtokensWithYam.length) return Promise.resolve([]) + const statsPromises = realtokensWithYam.map((realtoken) => GetYamStatistics({ realtoken }), ) const data = await Promise.all(statsPromises) return data - }, [realtokens]) + }, [realtokensWithYam]) useEffect(() => { setIsLoading(true) @@ -81,6 +94,12 @@ const YamStatisticsPage = () => { }) }, [yamStatisticsPromise]) + const paginationYamStatistics: YamStatistics[] = useMemo(() => { + const start = (page - 1) * pageSize + const end = start + pageSize + return yamStatistics.slice(start, end) + }, [yamStatistics, page, pageSize]) + if (isLoading) { return
Loading...
} @@ -96,15 +115,22 @@ const YamStatisticsPage = () => {
- {yamStatistics && - yamStatistics.map((statistics, index) => ( - - ))} + {paginationYamStatistics.map((statistics, index) => ( + + ))}
Token Token Price Yam Price Yam Difference (30 days)Yam Difference (30 days) Yam Volume
+
) } From 0a3d7e812e2329408a712a57f81d268bb3a549b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 20:05:44 +0200 Subject: [PATCH 45/71] feat: improve style --- src/i18next/locales/en/common.json | 4 ++ src/i18next/locales/fr/common.json | 4 ++ src/pages/yamStatistics.tsx | 87 ++++++++++++++++++++---------- 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index 87059e2..d344a87 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -370,6 +370,10 @@ "ownedRent": "My rents" } }, + "yamStatisticsPage": { + "home": "Home", + "title": "Secondary market statistics (Yam)" + }, "initialTransfersLoader": { "title": "Initial data loading", "description": "Retrieving your transactions in progress. This loading can take some time depending on the number of transactions performed (10-20 seconds / 1000 transactions). On your next visits, only new transactions will be retrieved." diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index e7fb852..961ed5c 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -372,6 +372,10 @@ "ownedRent": "Mes changements de loyers" } }, + "yamStatisticsPage": { + "home": "Accueil", + "title": "Statistiques marché secondaire (Yam)" + }, "initialTransfersLoader": { "title": "Chargement initial des données", "description": "Récupération de vos transactions en cours. Ce chargement peut prendre un certain temps en fonction du nombre de transactions effecutées (10-20 secondes / 1000 transactions). Lors de vos prochaines visites, seul les nouvelles transactions seront récupérées." diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index 4c7dd7e..8955b15 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -2,7 +2,16 @@ import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' -import { Divider, Pagination } from '@mantine/core' +import { useRouter } from 'next/router' + +import { + Anchor, + Breadcrumbs, + Divider, + Flex, + Group, + Pagination, +} from '@mantine/core' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' import { GetYamStatistics, YamStatistics } from 'src/repositories' @@ -48,6 +57,8 @@ const YamStatisticsRow: React.FC<{ } const YamStatisticsPage = () => { + const { t } = useTranslation('common', { keyPrefix: 'yamStatisticsPage' }) + const router = useRouter() const realtokens = useSelector(selectAllUserRealtokens) const realtokensWithYam = useMemo(() => { return realtokens.filter( @@ -105,33 +116,53 @@ const YamStatisticsPage = () => { } return ( -
-

Yam Statistics

- - - - - - - - - {paginationYamStatistics.map((statistics, index) => ( - - ))} -
TokenToken PriceYam PriceYam Difference (30 days)Yam Volume
- -
+ +
+ + router.push('/')}>{t('home')} + {t('title')} + +

{`${t('title')}`}

+ +
+ + + + + + + + + {paginationYamStatistics.map((statistics, index) => ( + + ))} +
TokenToken PriceYam PriceYam Difference (30 days)Yam Volume
+ + + +
+
+
) } From ddfc70a29a02763391abb07ddff8443da01519a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 20:07:06 +0200 Subject: [PATCH 46/71] feat: change token per page to 100 --- src/pages/yamStatistics.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index 8955b15..e130f6b 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -76,7 +76,7 @@ const YamStatisticsPage = () => { }), ) const [page, setPage] = useState(1) - const pageSize = 25 + const pageSize = 100 const [isLoading, setIsLoading] = useState(true) From 94102b83b367a34ddb985f8a19acee2a8eebf6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 23:08:30 +0200 Subject: [PATCH 47/71] feat: add fully rented APR to asset grid --- src/components/assetsView/views/AssetTable.tsx | 13 +++++++++++++ src/i18next/locales/en/common.json | 1 + src/i18next/locales/fr/common.json | 1 + 3 files changed, 15 insertions(+) diff --git a/src/components/assetsView/views/AssetTable.tsx b/src/components/assetsView/views/AssetTable.tsx index 3e85df8..f125cc5 100644 --- a/src/components/assetsView/views/AssetTable.tsx +++ b/src/components/assetsView/views/AssetTable.tsx @@ -9,6 +9,7 @@ import { Anchor, ScrollArea, Table } from '@mantine/core' import moment from 'moment' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' +import { useFullyRentedAPR } from 'src/hooks/useFullyRentedAPR' import { selectTransfersIsLoaded } from 'src/store/features/transfers/transfersSelector' import { RWARealtoken, @@ -62,6 +63,7 @@ const AssetTableHeader: FC = () => { ) : null} {t('ownedTokens')} {t('apr')} + {t('fullyRentedAPR')} {t('weeklyRents')} {t('yearlyRents')} {t('rentedUnits')} @@ -85,6 +87,10 @@ const AssetTableRow: FC<{ value: UserRealtoken }> = (props) => { const weeklyAmount = props.value.amount * props.value.netRentDayPerToken * 7 const yearlyAmount = props.value.amount * props.value.netRentYearPerToken const totalInvestment = props.value.totalInvestment + const isAProperty = props.value.hasOwnProperty('rentStatus') + const fullyRentedAPR = isAProperty + ? useFullyRentedAPR(props.value as UserRealtoken) + : null return ( @@ -121,6 +127,13 @@ const AssetTableRow: FC<{ value: UserRealtoken }> = (props) => { {t('percent', { value: props.value.annualPercentageYield })} + {isAProperty ? ( + + {t('percent', { value: fullyRentedAPR })} + + ) : ( + + )} {useCurrencyValue(weeklyAmount)} diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index 4c6fd71..53105be 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -215,6 +215,7 @@ "unitPriceCost": "Unit price cost", "unrealizedCapitalGain": "Capital gain", "apr": "Yield", + "fullyRentedAPR":"Fully rented APR *", "weeklyRents": "Weekly rents", "yearlyRents": "Yearly rents", "rentedUnits": "Rented units", diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index eb6998b..65e42cb 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -215,6 +215,7 @@ "tokenPrice": "Prix du token", "unitPriceCost": "Prix de revient", "apr": "Rendement annuel", + "fullyRentedAPR":"Rendement 100% loué *", "weeklyRents": "Loyer hebdo", "yearlyRents": "Loyer annuel", "rentedUnits": "Logements loués", From 791ef7716d48eeba8f406e96ad75cd3c5e1ae408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 23:09:56 +0200 Subject: [PATCH 48/71] refactor: remove logs --- src/components/assetsView/views/AssetGrid.tsx | 1 - src/hooks/useFullyRentedAPR.ts | 1 - src/pages/yamStatistics.tsx | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index 94964ea..930c9a6 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -33,7 +33,6 @@ export const AssetGrid: FC<{ realtokens: (UserRealtoken | RWARealtoken)[] }> = ( } const paginationOffers: (UserRealtoken | RWARealtoken)[] = useMemo(() => { - console.log({ realtokens: props.realtokens }) if (pageSize === Infinity) return props.realtokens const start = (page - 1) * pageSize const end = start + pageSize diff --git a/src/hooks/useFullyRentedAPR.ts b/src/hooks/useFullyRentedAPR.ts index 15519b3..08f166a 100644 --- a/src/hooks/useFullyRentedAPR.ts +++ b/src/hooks/useFullyRentedAPR.ts @@ -79,7 +79,6 @@ export const useGeneralFullyRentedAPR = (tokens: UserRealtoken[]) => { if (isDisabled) return acc return acc + token.value * fullyRentedAPREstimation(token) }, 0) - console.log({ totalValue, totalAPR, fullyRentedAPR: totalAPR / totalValue }) return totalAPR / totalValue }, [tokens, rentCalculation]) diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index e130f6b..86f7cd8 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -87,7 +87,6 @@ const YamStatisticsPage = () => { } const yamStatisticsPromise: Promise = useMemo(async () => { - console.log({ realtokens }) if (!realtokensWithYam.length) return Promise.resolve([]) const statsPromises = realtokensWithYam.map((realtoken) => GetYamStatistics({ realtoken }), @@ -101,7 +100,6 @@ const YamStatisticsPage = () => { yamStatisticsPromise.then((data) => { setYamStatistics(data) setIsLoading(false) - console.log({ data }) }) }, [yamStatisticsPromise]) From 86b991d0056c5fcf2287f21178abf4a1bd097729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sat, 17 Aug 2024 23:48:45 +0200 Subject: [PATCH 49/71] feat: add fully rented APR to property details --- src/components/assetPage/assetPagePropertyTab.tsx | 7 +++++++ src/i18next/locales/en/common.json | 1 + src/i18next/locales/fr/common.json | 1 + src/pages/asset/[assetId].tsx | 2 ++ 4 files changed, 11 insertions(+) diff --git a/src/components/assetPage/assetPagePropertyTab.tsx b/src/components/assetPage/assetPagePropertyTab.tsx index 49f6dfb..b3f58a6 100644 --- a/src/components/assetPage/assetPagePropertyTab.tsx +++ b/src/components/assetPage/assetPagePropertyTab.tsx @@ -2,6 +2,7 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' +import { useFullyRentedAPR } from 'src/hooks/useFullyRentedAPR' import { UserRealtoken } from 'src/store/features/wallets/walletsSelector' import { RealTokenRentalType } from 'src/types/RealToken' @@ -44,6 +45,8 @@ export const AssetPagePropertyTab: FC<{ const propertyStories = realtoken.propertyStories ? tNumbers('integer', { value: realtoken.propertyStories }) : '-' + const fullyRentedAPR = useFullyRentedAPR(realtoken) + const fullyRentedAPRValue = tNumbers('percent', { value: fullyRentedAPR }) return ( <> @@ -106,6 +109,10 @@ export const AssetPagePropertyTab: FC<{ label: t('annualYield'), value: annualYield, }, + { + label: t('fullyRentedAPR'), + value: fullyRentedAPRValue, + }, ]} /> diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index 53105be..f5facca 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -264,6 +264,7 @@ "grossRentMonth": "Gross monthly rent", "netRentMonth": "Net monthly rent", "annualYield": "Annual yield", + "fullyRentedAPR": "Fully rented APR *", "constructionYear": "Construction year", "propertyStories": "Number of stories", "propertyUnits": "Number of units", diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index 65e42cb..f5bdbfa 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -264,6 +264,7 @@ "grossRentMonth": "Loyer brut mensuel", "netRentMonth": "Loyer net mensuel", "annualYield": "Rendement annuel", + "fullyRentedAPR": "Rendement 100% loué *", "constructionYear": "Année de construction", "propertyStories": "Nombre d'étages", "propertyUnits": "Nombre de logements", diff --git a/src/pages/asset/[assetId].tsx b/src/pages/asset/[assetId].tsx index 2d2a1ad..9c93d54 100644 --- a/src/pages/asset/[assetId].tsx +++ b/src/pages/asset/[assetId].tsx @@ -14,6 +14,7 @@ import { AssetPageMainTab } from 'src/components/assetPage/assetPageMainTab' import { AssetPagePropertyTab } from 'src/components/assetPage/assetPagePropertyTab' import { AssetPageTransfersTab } from 'src/components/assetPage/assetPageTransfersTab' import { AssetPageYamStatisticsTab } from 'src/components/assetPage/assetPageYamStatisticsTab' +import FullyRentedAPRDisclaimer from 'src/components/commons/others/FullyRentedAPRDisclaimer' import { selectIsLoading } from 'src/store/features/settings/settingsSelector' import { selectTransfersIsLoaded } from 'src/store/features/transfers/transfersSelector' import { selectAllUserRealtokens } from 'src/store/features/wallets/walletsSelector' @@ -158,6 +159,7 @@ const AssetPage: NextPage = () => {
+ ) } From d3aacda7045cb8479a8e852cbc62824bed458d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sun, 18 Aug 2024 23:04:10 +0200 Subject: [PATCH 50/71] fix: reset current page when tokens changed --- src/components/assetsView/views/AssetGrid.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index 930c9a6..57fd96f 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -40,7 +40,7 @@ export const AssetGrid: FC<{ realtokens: (UserRealtoken | RWARealtoken)[] }> = ( }, [props.realtokens, page, pageSize]) // Go to first page when data changes (e.g. search, filter, order, ...) - // useEffect(() => setPage(1), [props.realtokens]) + useEffect(() => setPage(1), [props.realtokens]) const combobox = useCombobox({ onDropdownClose: () => combobox.resetSelectedOption(), From ce1b280e85ee578086eebdbab668cfb068acded7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sun, 18 Aug 2024 23:10:14 +0200 Subject: [PATCH 51/71] fix: reset current page when user change page size --- src/components/assetsView/views/AssetGrid.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/assetsView/views/AssetGrid.tsx b/src/components/assetsView/views/AssetGrid.tsx index 57fd96f..167d124 100644 --- a/src/components/assetsView/views/AssetGrid.tsx +++ b/src/components/assetsView/views/AssetGrid.tsx @@ -40,7 +40,7 @@ export const AssetGrid: FC<{ realtokens: (UserRealtoken | RWARealtoken)[] }> = ( }, [props.realtokens, page, pageSize]) // Go to first page when data changes (e.g. search, filter, order, ...) - useEffect(() => setPage(1), [props.realtokens]) + useEffect(() => setPage(1), [props.realtokens, pageSize]) const combobox = useCombobox({ onDropdownClose: () => combobox.resetSelectedOption(), From 7169d017038b1edfa455d8ab81bdf3ae5309f22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sun, 18 Aug 2024 23:22:29 +0200 Subject: [PATCH 52/71] feat: add translation for YAM statistics hearder label --- src/i18next/locales/en/common.json | 1 + src/i18next/locales/fr/common.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index f5facca..c90d266 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -3,6 +3,7 @@ "title": "Realtoken Dashboard", "transactions": "My transactions", "histories": "Changes history", + "yamStatistics": "Secondary market statistics (Yam)", "documentation": "Community Wiki", "home": "Home", "realt": "RealT", diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index f5bdbfa..9ab94c8 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -3,6 +3,7 @@ "title": "Realtoken Dashboard", "transactions": "Mes transactions", "histories": "Historique des changements", + "yamStatistics": "Statistiques marché secondaire (Yam)", "documentation": "Wiki communautaire", "home": "Accueil", "realt": "RealT", From 60708c676b67691bfed3dad46f409e481198f0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Sun, 18 Aug 2024 23:47:07 +0200 Subject: [PATCH 53/71] fix: yamStatistics: use selected currency for token price --- src/pages/yamStatistics.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index 86f7cd8..981d3fd 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -30,6 +30,7 @@ const YamStatisticsRow: React.FC<{ const yamDifferencePercent = (yamDifference / realtoken.tokenPrice) * 100 const fallback = '-' + const tokenPriceValue = useCurrencyValue(realtoken.tokenPrice, fallback) const yamPriceValue = useCurrencyValue(yamPrice, fallback) const yamDifferenceValue = useCurrencyValue(yamDifference, fallback) const volumeValue = useCurrencyValue(statistics.volume, fallback) @@ -38,7 +39,7 @@ const YamStatisticsRow: React.FC<{ <> {realtoken.shortName} - {realtoken.tokenPrice} + {tokenPriceValue} {yamPriceValue} {yamDifferenceValue} ( From b93d813879d798fdfc2874e1424cc794bc86b6a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nandy=20B=C3=A2?= Date: Mon, 19 Aug 2024 00:38:45 +0200 Subject: [PATCH 54/71] feat: yamStatistics: add owned | all filter --- src/i18next/locales/en/common.json | 7 ++- src/i18next/locales/fr/common.json | 7 ++- src/pages/yamStatistics.tsx | 75 ++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/i18next/locales/en/common.json b/src/i18next/locales/en/common.json index c90d266..4016f65 100644 --- a/src/i18next/locales/en/common.json +++ b/src/i18next/locales/en/common.json @@ -379,7 +379,12 @@ }, "yamStatisticsPage": { "home": "Home", - "title": "Secondary market statistics (Yam)" + "title": "Secondary market statistics (Yam)", + "filter": { + "field": "Filter", + "all": "All", + "owned": "My properties" + } }, "initialTransfersLoader": { "title": "Initial data loading", diff --git a/src/i18next/locales/fr/common.json b/src/i18next/locales/fr/common.json index 9ab94c8..1abfb01 100644 --- a/src/i18next/locales/fr/common.json +++ b/src/i18next/locales/fr/common.json @@ -380,7 +380,12 @@ }, "yamStatisticsPage": { "home": "Accueil", - "title": "Statistiques marché secondaire (Yam)" + "title": "Statistiques marché secondaire (Yam)", + "filter": { + "field": "Filtre", + "all": "Toutes les propriétés", + "owned": "Mes propriétés" + } }, "initialTransfersLoader": { "title": "Chargement initial des données", diff --git a/src/pages/yamStatistics.tsx b/src/pages/yamStatistics.tsx index 981d3fd..89008e3 100644 --- a/src/pages/yamStatistics.tsx +++ b/src/pages/yamStatistics.tsx @@ -11,8 +11,10 @@ import { Flex, Group, Pagination, + Select, } from '@mantine/core' +import { useInputStyles } from 'src/components/inputs/useInputStyles' import { useCurrencyValue } from 'src/hooks/useCurrencyValue' import { GetYamStatistics, YamStatistics } from 'src/repositories' import { @@ -79,6 +81,12 @@ const YamStatisticsPage = () => { const [page, setPage] = useState(1) const pageSize = 100 + const [currentFilter, setCurrentFilter] = + useState('owned') + const filteredRealtokens = useMemo(() => { + return getFilteredRealtokens(currentFilter, realtokensWithYam) + }, [realtokensWithYam, currentFilter]) + const [isLoading, setIsLoading] = useState(true) function onPageChange(page: number) { @@ -88,13 +96,14 @@ const YamStatisticsPage = () => { } const yamStatisticsPromise: Promise = useMemo(async () => { - if (!realtokensWithYam.length) return Promise.resolve([]) - const statsPromises = realtokensWithYam.map((realtoken) => + if (!filteredRealtokens.length) return Promise.resolve([]) + + const statsPromises = filteredRealtokens.map((realtoken) => GetYamStatistics({ realtoken }), ) const data = await Promise.all(statsPromises) return data - }, [realtokensWithYam]) + }, [filteredRealtokens, currentFilter]) useEffect(() => { setIsLoading(true) @@ -126,6 +135,8 @@ const YamStatisticsPage = () => {

{`${t('title')}`}

+ +
@@ -139,7 +150,7 @@ const YamStatisticsPage = () => { ))}
@@ -165,4 +176,60 @@ const YamStatisticsPage = () => { ) } +const getFilteredRealtokens = ( + filter: YamStatisticsPageFilterValue, + realtokens: UserRealtoken[], +) => { + switch (filter) { + case 'all': + return realtokens + case 'owned': + return realtokens.filter((realtoken) => realtoken.amount > 0) + default: + return realtokens + } +} + +type YamStatisticsPageFilterValue = 'all' | 'owned' + +const YamStatisticsPageFilter = ({ + currentFilter, + setCurrentFilter, +}: { + currentFilter: YamStatisticsPageFilterValue + setCurrentFilter: (value: YamStatisticsPageFilterValue) => void +}) => { + const { t } = useTranslation('common', { + keyPrefix: 'yamStatisticsPage.filter', + }) + const { classes: inputClasses } = useInputStyles() + + const filterOptions: { + value: YamStatisticsPageFilterValue + label: string + }[] = [ + { value: 'all', label: t('all') }, + { value: 'owned', label: t('owned') }, + ] + + return ( + +
+