Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Earn protocol WIP #22 #561

Merged
merged 10 commits into from
Nov 7, 2024
14 changes: 13 additions & 1 deletion apps/earn-protocol/app/earn/portfolio/[walletAddress]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { parseServerResponseToClient } from '@summerfi/app-utils'
import { type IArmadaPosition } from '@summerfi/sdk-client-react'

import { portfolioPositionsHandler } from '@/app/server-handlers/portfolio/portfolio-positions-handler'
import { portfolioRewardsHandler } from '@/app/server-handlers/portfolio/portfolio-rewards-handler'
import { portfolioWalletAssetsHandler } from '@/app/server-handlers/portfolio/portfolio-wallet-assets-handler'
import { getUserPositions } from '@/app/server-handlers/sdk/get-user-positions'
Expand All @@ -20,9 +24,17 @@ const PortfolioPage = async ({ params }: PortfolioPageProps) => {
])
const rewardsData = portfolioRewardsHandler(walletAddress)

const positionsJsonSafe = positions
? parseServerResponseToClient<IArmadaPosition[]>(positions)
: []

const positionsList = positionsJsonSafe.map((position) =>
portfolioPositionsHandler({ position, vaultsList: vaults }),
)

return (
<PortfolioPageView
positions={positions ?? []}
positions={positionsList}
walletAddress={walletAddress}
walletData={walletData}
rewardsData={rewardsData}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { type SDKVaultsListType } from '@summerfi/app-types'
import { type IArmadaPosition } from '@summerfi/sdk-client-react'

export type PortfolioPositionsDataParams = {
position: IArmadaPosition
vaultsList: SDKVaultsListType // not vaultish, this is the list, not the vault "details"
}

// since we dont have vault details on the positions list
// we need to merge the vault details with the position
export const portfolioPositionsHandler = ({
position,
vaultsList,
}: PortfolioPositionsDataParams) => {
const vaultData = vaultsList.find((vault) => vault.id === position.pool.id.fleetAddress.value)

if (!vaultData) {
throw new Error(`Vault not found for position ${position.pool.id.fleetAddress.value}`)
}

return {
positionData: position,
vaultData,
}
}

export type PortfolioPositionsList = ReturnType<typeof portfolioPositionsHandler>
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import { type FC } from 'react'
import { TabBar } from '@summerfi/app-earn-ui'
import { type SDKVaultsListType } from '@summerfi/app-types'
import { type IArmadaPosition } from '@summerfi/sdk-client-react'

import { type PortfolioPositionsList } from '@/app/server-handlers/portfolio/portfolio-positions-handler'
import { type PortfolioRewardsRawData } from '@/app/server-handlers/portfolio/portfolio-rewards-handler'
import { type PortfolioAssetsResponse } from '@/app/server-handlers/portfolio/portfolio-wallet-assets-handler'
import { PortfolioHeader } from '@/features/portfolio/components/PortfolioHeader/PortfolioHeader'
Expand All @@ -18,7 +18,7 @@ interface PortfolioPageViewProps {
walletData: PortfolioAssetsResponse
rewardsData: PortfolioRewardsRawData[]
vaultsList: SDKVaultsListType
positions: IArmadaPosition[]
positions: PortfolioPositionsList[]
}

export const PortfolioPageView: FC<PortfolioPageViewProps> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const ComparisonChart = ({ data, dataNames, colors, compare }: Comparison
dataName === 'Summer Strategy' ? (
<Area
key={dataName}
type="natural"
type="basis"
animationDuration={300}
animationBegin={dataIndex * 50}
animationEasing="ease-out"
Expand All @@ -72,7 +72,7 @@ export const ComparisonChart = ({ data, dataNames, colors, compare }: Comparison
animationDuration={300}
animationBegin={dataIndex * 50}
animationEasing="ease-out"
type="natural"
type="basis"
dataKey={dataName}
strokeDasharray="3 3"
stroke={colors[`${dataName}-color` as keyof typeof colors]}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { type TimeframesType } from '@summerfi/app-types'
import {
Area,
ComposedChart,
Legend,
Line,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts'

type YieldsChartProps = {
data: unknown[]
dataNames: string[]
colors: { [key: string]: string }
timeframe: TimeframesType
}

export const YieldsChart = ({ data, dataNames, colors }: YieldsChartProps) => {
return (
<div style={{ width: '100%', height: '400px' }}>
<ResponsiveContainer width="100%" height="90%">
<ComposedChart
data={data}
margin={{
top: 50,
right: 0,
left: 0,
bottom: 0,
}}
>
<defs>
<linearGradient id="summerYieldGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#FF49A4" stopOpacity={0.8} />
<stop offset="100%" stopColor="#333333" stopOpacity={0.4} />
</linearGradient>
</defs>

<XAxis dataKey="name" fontSize={12} interval={5} tickMargin={10} />
<YAxis strokeWidth={0} width={45} tickFormatter={(label: string) => `${label}%`} />
<Tooltip
formatter={(val) => `${Number(val).toFixed(2)}`}
useTranslate3d
contentStyle={{
zIndex: 1000,
backgroundColor: 'var(--color-surface-subtler)',
borderRadius: '5px',
padding: '20px 30px',
border: 'none',
}}
/>
{dataNames.map((dataName, dataIndex) =>
dataName === 'Summer Strategy' ? (
<Area
key={dataName}
type="basis"
animationDuration={300}
animationBegin={dataIndex * 50}
animationEasing="ease-out"
dataKey={dataName}
strokeWidth={1}
stroke={colors[`${dataName}-color` as keyof typeof colors]}
fillOpacity={1}
fill="url(#summerYieldGradient)"
/>
) : (
<Line
key={dataName}
animationId={dataIndex}
animationDuration={300}
animationBegin={dataIndex * 50}
animationEasing="ease-out"
type="basis"
dataKey={dataName}
strokeDasharray="3 3"
stroke={colors[`${dataName}-color` as keyof typeof colors]}
strokeWidth={0}
dot={false}
connectNulls
/>
),
)}
<Legend iconType="circle" iconSize={8} align="center" layout="horizontal" height={60} />
</ComposedChart>
</ResponsiveContainer>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
'use client'

import { useMemo, useState } from 'react'
import { Card } from '@summerfi/app-earn-ui'
import { type CardVariant } from '@summerfi/app-earn-ui/dist/types/src/components/atoms/Card/Card'
import { type TimeframesType } from '@summerfi/app-types'
import BigNumber from 'bignumber.js'
import dayjs from 'dayjs'

import { ChartHeader } from '@/components/organisms/Charts/ChartHeader'
import { ComparisonChart } from '@/components/organisms/Charts/ComparisonChart'
import { YieldsChart } from '@/components/organisms/Charts/DumbCharts/YieldsChart'

const dataNames = ['Summer Strategy']

const colors = {
'Summer Strategy-color': '#FF49A4',
}

export const HistoricalYieldChart = ({
aprHourlyList,
cardVariant = 'cardSecondary',
}: {
cardVariant?: CardVariant
aprHourlyList: string[]
}) => {
const [compare, setCompare] = useState(true)
export const HistoricalYieldChart = ({ aprHourlyList }: { aprHourlyList: string[] }) => {
const [timeframe, setTimeframe] = useState<TimeframesType>('90d')
const _unused = setTimeframe

Expand All @@ -40,23 +30,6 @@ export const HistoricalYieldChart = ({
}, [aprHourlyList])

return (
<Card
variant={cardVariant}
style={{ marginTop: 'var(--spacing-space-medium)', flexDirection: 'column' }}
>
<ChartHeader
compare={compare}
setCompare={setCompare}
timeframe={timeframe}
setTimeframe={(_nextTimeFrame) => null}
/>
<ComparisonChart
timeframe={timeframe}
colors={colors}
data={parsedData}
compare={compare}
dataNames={dataNames}
/>
</Card>
<YieldsChart timeframe={timeframe} colors={colors} data={parsedData} dataNames={dataNames} />
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { type TimeframesType } from '@summerfi/app-types'
import { memoize, random } from 'lodash-es'

import { ChartHeader } from '@/components/organisms/Charts/ChartHeader'
import { ComparisonChart } from '@/components/organisms/Charts/ComparisonChart'
import { ComparisonChart } from '@/components/organisms/Charts/DumbCharts/ComparisonChart'

const dataNames = [
'Median Defi Yield',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Card, DataBlock, Text, WithArrow } from '@summerfi/app-earn-ui'
import { Card, DataBlock, PortfolioPosition, Text, WithArrow } from '@summerfi/app-earn-ui'
import { type SDKVaultsListType } from '@summerfi/app-types'
import { type IArmadaPosition } from '@summerfi/sdk-client-react'
import Link from 'next/link'

import { MockedLineChart } from '@/components/organisms/Charts/MockedLineChart'
import { type PortfolioPositionsList } from '@/app/server-handlers/portfolio/portfolio-positions-handler'
import { HistoricalYieldChart } from '@/components/organisms/Charts/HistoricalYieldChart'
import { CryptoUtilities } from '@/features/crypto-utilities/components/CryptoUtilities/CryptoUtilities'
import { NewsAndUpdates } from '@/features/news-and-updates/components/NewsAndUpdates/NewsAndUpdates'
import { PortfolioVaultsCarousel } from '@/features/portfolio/components/PortfolioVaultsCarousel/PortfolioVaultsCarousel'
Expand Down Expand Up @@ -57,7 +57,7 @@ const dataBlocks = [

type PortfolioOverviewProps = {
vaultsList: SDKVaultsListType
positions: IArmadaPosition[]
positions: PortfolioPositionsList[]
}

export const PortfolioOverview = ({ vaultsList, positions }: PortfolioOverviewProps) => {
Expand Down Expand Up @@ -86,15 +86,28 @@ export const PortfolioOverview = ({ vaultsList, positions }: PortfolioOverviewPr
<Text as="h5" variant="h5">
Positions
</Text>
<MockedLineChart />
{positions.length > 0 ? (
positions.map((position) => (
<PortfolioPosition
key={`Position_${position.positionData.id.id}`}
position={position}
positionGraph={
<HistoricalYieldChart aprHourlyList={position.vaultData.aprValues} />
}
/>
))
) : (
<Text as="p" variant="p1semi">
No positions
</Text>
)}
<PortfolioVaultsCarousel
vaultsList={vaultsList}
style={{ marginTop: 'var(--general-space-24)' }}
/>
</Card>
<NewsAndUpdates items={dummyNewsAndUpdatesItems} />
<CryptoUtilities />
<pre>{JSON.stringify(positions, null, 2)}</pre>
</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { type FC, type ReactNode, useMemo, useState } from 'react'
import { Table, type TableSortedColumn } from '@summerfi/app-earn-ui'
import { Table, type TableSortedColumn, useMobileCheck } from '@summerfi/app-earn-ui'
import { type SDKGlobalRebalancesType } from '@summerfi/app-types'

import { rebalancingActivityColumns } from '@/features/rebalance-activity/table/columns'
import {
rebalancingActivityColumns,
rebalancingActivityColumnsHiddenOnMobile,
} from '@/features/rebalance-activity/table/columns'
import { rebalancingActivityMapper } from '@/features/rebalance-activity/table/mapper'

interface RebalanceActivityTableProps {
Expand All @@ -22,19 +25,22 @@ export const RebalanceActivityTable: FC<RebalanceActivityTableProps> = ({
rowsToDisplay,
}) => {
const [sortConfig, setSortConfig] = useState<TableSortedColumn<string>>()
const { isMobile } = useMobileCheck()

const rows = useMemo(
() => rebalancingActivityMapper(rebalancesList, sortConfig),
[rebalancesList, sortConfig],
)

const resolvedHiddenColumns = isMobile ? rebalancingActivityColumnsHiddenOnMobile : hiddenColumns

return (
<Table
rows={rows.slice(0, rowsToDisplay)}
columns={rebalancingActivityColumns}
customRow={customRow}
handleSort={(_sortConfig) => setSortConfig(_sortConfig)}
hiddenColumns={hiddenColumns}
hiddenColumns={resolvedHiddenColumns}
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@

.filtersWrapper {
display: flex;
justify-content: flex-start;
flex-direction: column;
gap: var(--general-space-16);
flex-wrap: wrap;
margin-bottom: var(--general-space-24);

@media screen and (min-width: 768px) {
flex-direction: row;
justify-content: flex-start;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
HeadingWithCards,
TableCarousel,
useCurrentUrl,
useMobileCheck,
useQueryParams,
} from '@summerfi/app-earn-ui'
import { type SDKGlobalRebalancesType, type SDKVaultsListType } from '@summerfi/app-types'
Expand Down Expand Up @@ -42,6 +43,7 @@ export const RebalanceActivityView: FC<RebalanceActivityViewProps> = ({
const [tokenFilter, setTokenFilter] = useState<string[]>(searchParams?.tokens ?? [])
const [protocolFilter, setProtocolFilter] = useState<string[]>(searchParams?.protocols ?? [])
const currentUrl = useCurrentUrl()
const { isMobile } = useMobileCheck()

const [current, setCurrent] = useState(initialRows)

Expand Down Expand Up @@ -134,6 +136,7 @@ export const RebalanceActivityView: FC<RebalanceActivityViewProps> = ({
label={filter.label}
onChange={filter.onChange}
initialValues={filter.initialValues}
style={{ width: isMobile ? '100%' : 'fit-content' }}
/>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@ export const rebalancingActivityColumns = [
sortable: false,
},
]

export const rebalancingActivityColumnsHiddenOnMobile = [
'amount',
'strategy',
'timestamp',
'provider',
]
Loading
Loading