Skip to content

Commit 968ba24

Browse files
committed
feat: hints for overview
1 parent 00f1a52 commit 968ba24

14 files changed

Lines changed: 313 additions & 263 deletions

File tree

features/overview/components/balance/balance.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,12 @@ import { appPaths } from 'consts/routing';
44

55
const sectionPayloadList: SectionPayload[] = [
66
{
7-
title: 'Available to withdraw',
87
key: 'withdrawableEth',
9-
actionText: 'Withdraw ETH',
108
actionRole: 'withdrawer',
119
actionLink: (vault) => appPaths.vaults.vault(vault).eth('withdraw'),
1210
},
1311
{
14-
title: 'Idle capital',
1512
key: 'balanceEth',
16-
actionText: 'Supply ETH',
1713
actionRole: 'supplier',
1814
actionLink: (vault) => appPaths.vaults.vault(vault).eth('supply'),
1915
},
@@ -23,28 +19,26 @@ const sectionPayloadList: SectionPayload[] = [
2319
// key: 'depositedToValidators',
2420
// },
2521
{
26-
title: 'Total locked',
2722
key: 'totalLocked',
2823
},
2924
{
30-
title: 'Collateral',
3125
key: 'collateral',
3226
},
3327
{
34-
title: 'Pending unlock',
3528
key: 'pendingUnlockEth',
3629
},
3730
];
3831

3932
export const Balance = () => {
4033
const { getVaultDataToRender } = useVaultOverview();
41-
const renderData = getVaultDataToRender(sectionPayloadList);
4234

4335
return (
4436
<OverviewSection title="Balance overview">
45-
{renderData.map((item) => (
46-
<OverviewItem {...item} key={item.key} content={item.payload} />
47-
))}
37+
{sectionPayloadList.map((sectionItem) => {
38+
const { key, ...rest } = getVaultDataToRender(sectionItem);
39+
40+
return <OverviewItem key={key} {...rest} />;
41+
})}
4842
</OverviewSection>
4943
);
5044
};

features/overview/components/capacity/capacity.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,29 @@ import { getUtilizationRatioColor } from 'utils';
44

55
const sectionPayloadList: SectionPayload[] = [
66
{
7-
title: 'Utilization ratio',
87
key: 'utilizationRatio',
98
},
109
{
11-
title: 'stETH liability',
1210
key: 'liabilityStETH',
1311
},
1412
{
15-
title: 'Total minting capacity',
1613
key: 'totalMintingCapacityStETH',
1714
},
1815
];
1916

2017
export const Capacity = () => {
2118
const { getVaultDataToRender } = useVaultOverview();
22-
const renderData = getVaultDataToRender(sectionPayloadList);
2319

2420
return (
2521
<OverviewSection title="stETH capacity utilization">
26-
{renderData.map((item) => {
27-
const isUtilizationRatio = item.key === 'utilizationRatio';
22+
{sectionPayloadList.map((sectionItem) => {
23+
const { key, ...item } = getVaultDataToRender(sectionItem);
24+
const isUtilizationRatio = key === 'utilizationRatio';
2825
const color = isUtilizationRatio
2926
? getUtilizationRatioColor(String(item.payload))
3027
: undefined;
3128

32-
return (
33-
<OverviewItem
34-
{...item}
35-
key={item.key}
36-
content={item.payload}
37-
color={color}
38-
/>
39-
);
29+
return <OverviewItem {...item} key={key} color={color} />;
4030
})}
4131
</OverviewSection>
4232
);

features/overview/components/general/general.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,27 @@ import { OverviewItem, OverviewSection } from 'features/overview/shared';
22
import { AddressSection } from 'features/overview/components/general/address-section';
33
import {
44
useVaultOverview,
5-
SectionPayload,
5+
SectionData,
66
} from 'features/overview/contexts/vault-overview';
77

8-
const sectionPayloadList: SectionPayload[] = [
8+
const sectionPayloadList: SectionData[] = [
99
{
10-
title: 'Total value',
1110
key: 'totalValue',
1211
},
1312
{
14-
title: 'Reserve ratio',
1513
key: 'reserveRatio',
1614
},
1715
];
1816

1917
export const General = () => {
2018
const { getVaultDataToRender } = useVaultOverview();
21-
const renderData = getVaultDataToRender(sectionPayloadList);
2219

2320
return (
2421
<OverviewSection titleContent={<AddressSection />}>
25-
{renderData.map((item) => (
26-
<OverviewItem {...item} key={item.key} content={item.payload} />
27-
))}
22+
{sectionPayloadList.map((item) => {
23+
const { key, ...rest } = getVaultDataToRender(item);
24+
return <OverviewItem key={key} {...rest} />;
25+
})}
2826
</OverviewSection>
2927
);
3028
};

features/overview/components/health/heath.tsx

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,39 @@ import { formatPercent, getHealthFactorColor } from 'utils';
44

55
const sectionPayloadList: SectionPayload[] = [
66
{
7-
title: 'Health factor',
87
key: 'healthFactorNumber',
98
},
109
{
11-
title: 'Total value',
1210
key: 'totalValue',
1311
},
1412
{
15-
title: 'stETH liability',
1613
key: 'liabilityStETH',
1714
},
1815
{
19-
title: 'Forced rebalance threshold',
2016
key: 'rebalanceThreshold',
2117
},
2218
];
2319

2420
export const Health = () => {
2521
const { getVaultDataToRender } = useVaultOverview();
26-
const renderData = getVaultDataToRender(sectionPayloadList);
2722

2823
return (
2924
<OverviewSection title="Vault health" titleTooltip="Lorem Ipsum">
30-
{renderData.map((item) => {
31-
const isHealthy = item.key === 'healthFactorNumber';
32-
const color = isHealthy
33-
? getHealthFactorColor(item.payload)
25+
{sectionPayloadList.map((sectionEntry) => {
26+
const { key, payload, ...item } = getVaultDataToRender(sectionEntry);
27+
const isHealthFactor = key === 'healthFactorNumber';
28+
const color = isHealthFactor
29+
? getHealthFactorColor(payload)
3430
: undefined;
35-
const value = isHealthy
36-
? formatPercent.format(Number(item.payload) / 100)
37-
: item.payload;
31+
const formattedPayload = isHealthFactor
32+
? formatPercent.format(Number(payload) / 100)
33+
: payload;
3834

3935
return (
4036
<OverviewItem
4137
{...item}
42-
key={item.key}
43-
content={value}
38+
key={key}
39+
payload={formattedPayload}
4440
color={color}
4541
/>
4642
);

features/overview/components/node-operator/node-operator.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,24 @@ import { appPaths } from 'consts/routing';
44

55
const sectionPayloadList: SectionPayload[] = [
66
{
7-
title: 'Reward share',
87
key: 'nodeOperatorFee',
98
},
109
{
11-
title: 'Accumulated',
1210
key: 'accumulatedFee',
1311
actionLink: (vault) => appPaths.vaults.vault(vault).claim,
14-
actionText: 'Claim',
1512
actionRole: 'nodeOperatorFeeClaimer',
1613
},
1714
];
1815

1916
export const NodeOperator = () => {
2017
const { getVaultDataToRender } = useVaultOverview();
21-
const renderData = getVaultDataToRender(sectionPayloadList);
2218

2319
return (
2420
<OverviewSection title="Node operator reward share">
25-
{renderData.map((item) => (
26-
<OverviewItem {...item} key={item.key} content={item.payload} />
27-
))}
21+
{sectionPayloadList.map((sectionItem) => {
22+
const { key, ...item } = getVaultDataToRender(sectionItem);
23+
return <OverviewItem key={key} {...item} />;
24+
})}
2825
</OverviewSection>
2926
);
3027
};

features/overview/contexts/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ export {
33
useVaultOverview,
44
type VaultOverviewContextType,
55
type VaultOverviewContextKeys,
6-
type SectionPayload,
6+
type SectionData as SectionPayload,
77
} from './vault-overview';

features/overview/contexts/vault-overview.tsx

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
createContext,
55
useContext,
66
useMemo,
7-
useCallback,
87
} from 'react';
98
import { Address } from 'viem';
109
import invariant from 'tiny-invariant';
@@ -13,9 +12,27 @@ import { calculateOverview } from '@lidofinance/lsv-cli/dist/utils/calculate-ove
1312
import { formatBalance, formatPercent } from 'utils';
1413

1514
import { useVaultInfo } from 'modules/vaults/vault-context';
16-
import { VAULT_TOTAL_BASIS_POINTS, VAULTS_ALL_ROLES } from 'modules/vaults';
15+
import {
16+
VAULT_TOTAL_BASIS_POINTS,
17+
VAULTS_ALL_ROLES,
18+
vaultTexts,
19+
} from 'modules/vaults';
20+
21+
export type SectionData = {
22+
key: VaultOverviewContextKeys;
23+
actionRole?: VAULTS_ALL_ROLES;
24+
actionLink?: (vaultAddress: Address) => string;
25+
};
26+
27+
export type SectionPayload = SectionData & {
28+
title: string;
29+
hint?: string;
30+
action?: string;
31+
isLoading?: boolean;
32+
payload: string | Address | number;
33+
};
1734

18-
export interface VaultOverviewContextType {
35+
export type VaultOverviewContextType = {
1936
values: {
2037
address: Address;
2138
nodeOperator: Address;
@@ -37,28 +54,33 @@ export interface VaultOverviewContextType {
3754
pendingUnlockEth: string;
3855
};
3956
isLoadingVault?: boolean;
40-
getVaultDataToRender: (
41-
payload: SectionPayload[],
42-
) => (SectionPayload & { payload: string | Address | number })[];
43-
}
57+
getVaultDataToRender: (payload: SectionData) => SectionPayload;
58+
};
4459

4560
export type VaultOverviewContextKeys = keyof VaultOverviewContextType['values'];
46-
export type SectionPayload = {
61+
62+
type MetricText = {
4763
title: string;
48-
key: VaultOverviewContextKeys;
49-
actionText?: string;
50-
actionRole?: VAULTS_ALL_ROLES;
51-
actionLink?: (vaultAddress: Address) => string;
52-
isLoading?: boolean;
64+
hint?: string;
65+
action?: string;
5366
};
5467

5568
const VaultOverviewContext = createContext<VaultOverviewContextType | null>(
5669
null,
5770
);
71+
VaultOverviewContext.displayName = 'VaultOverviewContext';
5872

5973
const toEthValue = (value: bigint) => `${formatBalance(value).trimmed} ETH`;
6074
const toStethValue = (value: bigint) => `${formatBalance(value).trimmed} stETH`;
6175

76+
const getMetricTexts = (key: VaultOverviewContextKeys): MetricText => {
77+
const metric = vaultTexts.metrics[
78+
key as keyof typeof vaultTexts.metrics
79+
] as MetricText;
80+
invariant(metric, `Metric text for ${key} not found`);
81+
return metric;
82+
};
83+
6284
export const VaultOverviewProvider: FC<PropsWithChildren> = ({ children }) => {
6385
const { activeVault, isLoadingVault } = useVaultInfo();
6486

@@ -147,21 +169,20 @@ export const VaultOverviewProvider: FC<PropsWithChildren> = ({ children }) => {
147169
return {} as VaultOverviewContextType['values'];
148170
}, [activeVault, isLoadingVault]);
149171

150-
const getVaultDataToRender = useCallback(
151-
(sectionPayloadList: SectionPayload[]) => {
152-
return sectionPayloadList.map((item) => {
153-
return {
154-
...item,
155-
payload: values[item.key],
156-
isLoading: isLoadingVault,
157-
};
158-
});
159-
},
160-
[values, isLoadingVault],
161-
);
172+
const value = useMemo(() => {
173+
return {
174+
values,
175+
getVaultDataToRender: (sectionEntry: SectionData) => ({
176+
...sectionEntry,
177+
...getMetricTexts(sectionEntry.key),
178+
payload: values[sectionEntry.key],
179+
isLoading: isLoadingVault,
180+
}),
181+
};
182+
}, [isLoadingVault, values]);
162183

163184
return (
164-
<VaultOverviewContext.Provider value={{ values, getVaultDataToRender }}>
185+
<VaultOverviewContext.Provider value={value}>
165186
{children}
166187
</VaultOverviewContext.Provider>
167188
);

features/overview/shared/overview-item/overview-item.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@ import { useVaultInfo, useVaultPermission } from 'modules/vaults';
88
import { OverviewItemValue } from './overview-item-value';
99
import { ItemWrapper, Title } from './styles';
1010

11-
import type { SectionPayload } from 'features/overview/contexts';
11+
import type { SectionPayload } from 'features/overview/contexts/vault-overview';
12+
import { Hint } from 'shared/components';
1213

1314
export type ItemProps = {
14-
content: string | Address | number;
15+
payload: string | Address | number;
1516
color?: string;
1617
} & Omit<SectionPayload, 'key'>;
1718

1819
export const OverviewItem: FC<ItemProps> = ({
1920
title,
20-
content,
21+
payload,
2122
actionLink,
2223
actionRole,
23-
actionText,
24+
action,
25+
hint,
2426
isLoading,
2527
color,
2628
}) => {
@@ -32,7 +34,7 @@ export const OverviewItem: FC<ItemProps> = ({
3234
// 1. all data is provided
3335
(
3436
actionLink &&
35-
actionText &&
37+
action &&
3638
vaultAddress &&
3739
// 2. user has permission for it (if actionRole is provided)
3840
(!actionRole || hasPermission)
@@ -46,10 +48,11 @@ export const OverviewItem: FC<ItemProps> = ({
4648
<Title>
4749
<Text color="secondary" size="xxs">
4850
{title}
51+
<Hint text={hint} />
4952
</Text>
5053
</Title>
5154
<OverviewItemValue
52-
content={content}
55+
content={payload}
5356
isLoading={isLoading}
5457
color={color}
5558
/>
@@ -59,7 +62,7 @@ export const OverviewItem: FC<ItemProps> = ({
5962
variant="translucent"
6063
onClick={() => router.push(actionLink(vaultAddress))}
6164
>
62-
{actionText}
65+
{action}
6366
</Button>
6467
)}
6568
</ItemWrapper>

0 commit comments

Comments
 (0)