Skip to content

Commit 8865dfc

Browse files
authored
Merge pull request #45 from lidofinance/feature/settings-remove-admins
Add opportunity to remove admins in settings
2 parents 317a4dc + 534a0db commit 8865dfc

File tree

21 files changed

+738
-165
lines changed

21 files changed

+738
-165
lines changed

features/overview/contexts/vault-provider.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type VaultContextType = {
1818
isLoadingVault?: boolean;
1919
error: Error | null;
2020
refetch: () => void;
21+
isRefetching: boolean;
2122
};
2223

2324
const VaultContext = createContext<VaultContextType | null>(null);
@@ -46,13 +47,15 @@ export const VaultProvider: FC<PropsWithChildren> = ({ children }) => {
4647
isLoadingVault: query.isPending,
4748
error: query.error,
4849
refetch: query.refetch,
50+
isRefetching: query.isRefetching,
4951
}),
5052
[
5153
sanitizedVaultAddress,
5254
query.data,
5355
query.isPending,
5456
query.error,
5557
query.refetch,
58+
query.isRefetching,
5659
],
5760
);
5861

features/settings/main/components/controllers/data-field.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { FC } from 'react';
22
import { ReadonlyInput } from './readonly-input';
3-
import { DisplayAddress } from './display-address';
43
import { GroupWrapper } from './styles';
54

65
import type { MainSettingsOverview } from 'features/settings/main/types';
@@ -17,13 +16,11 @@ export const DataField: FC<InputResolverProps> = ({
1716
label,
1817
editLabel,
1918
name,
20-
dataType,
2119
title,
2220
actionText = 'Initiate a change',
2321
vaultKey,
2422
canEditRole,
2523
}) => {
26-
const isTypeAddress = dataType === 'address';
2724
const isConfirmingRoles = canEditRole === 'confirmingRoles';
2825
const { hasConfirmingRole } = useVaultConfirmingRoles();
2926
const { hasPermission } = useVaultPermissions(
@@ -36,8 +33,7 @@ export const DataField: FC<InputResolverProps> = ({
3633
<Text size="xs" strong>
3734
{title}
3835
</Text>
39-
{isTypeAddress && <DisplayAddress name={name} vaultKey={vaultKey} />}
40-
{!isTypeAddress && <ReadonlyInput label={label} vaultKey={vaultKey} />}
36+
<ReadonlyInput label={label} vaultKey={vaultKey} />
4137
{isEditable && (
4238
<EditProperty
4339
editLabel={editLabel}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { FC } from 'react';
2+
import { DisplayAddress } from './display-address';
3+
import { GroupWrapper } from './styles';
4+
5+
import {
6+
MainSettingsOverview,
7+
ManagersKeys,
8+
} from 'features/settings/main/types';
9+
import { EditPropertyAddress } from './edit-property-address';
10+
import { Text } from '@lidofinance/lido-ui';
11+
import {
12+
useVaultConfirmingRoles,
13+
useVaultPermissions,
14+
} from 'modules/vaults/hooks/use-vault-permissions';
15+
16+
type InputResolverProps = MainSettingsOverview;
17+
18+
export const DataManagerField: FC<InputResolverProps> = ({
19+
editLabel,
20+
name,
21+
title,
22+
vaultKey,
23+
canEditRole,
24+
}) => {
25+
const isConfirmingRoles = canEditRole === 'confirmingRoles';
26+
const { hasConfirmingRole } = useVaultConfirmingRoles();
27+
const { hasPermission } = useVaultPermissions(
28+
isConfirmingRoles ? undefined : canEditRole,
29+
);
30+
31+
const isEditable = hasConfirmingRole || hasPermission;
32+
return (
33+
<GroupWrapper>
34+
<Text size="xs" strong>
35+
{title}
36+
</Text>
37+
<DisplayAddress isEditable={isEditable} vaultKey={vaultKey} />
38+
{isEditable && (
39+
<EditPropertyAddress
40+
editLabel={editLabel}
41+
name={name as ManagersKeys}
42+
/>
43+
)}
44+
</GroupWrapper>
45+
);
46+
};
Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
1-
import { FC, useMemo } from 'react';
2-
import { Address } from 'viem';
1+
import { FC } from 'react';
32

4-
import { useVaultInfo } from 'features/overview/contexts';
53
import { VaultInfo } from 'types';
64
import { RoleAddress } from './role-address';
5+
import { RoleFieldSchema } from '../../../types';
6+
import { useFormContext } from 'react-hook-form';
77

88
interface DisplayAddressProps {
9-
name: string;
109
vaultKey: keyof VaultInfo;
10+
isEditable: boolean;
1111
}
1212

13-
export const DisplayAddress: FC<DisplayAddressProps> = ({ vaultKey }) => {
14-
const { activeVault } = useVaultInfo();
15-
const renderData = useMemo(() => {
16-
return activeVault?.[vaultKey] as Address[] | Address | undefined;
17-
}, [activeVault, vaultKey]);
13+
export const DisplayAddress: FC<DisplayAddressProps> = ({
14+
isEditable,
15+
vaultKey,
16+
}) => {
17+
const { watch } = useFormContext();
18+
const roles = watch(vaultKey) as RoleFieldSchema[];
1819

19-
if (Array.isArray(renderData)) {
20-
return (
21-
<>
22-
{renderData.map((address) => (
23-
<RoleAddress key={address} address={address} />
24-
))}
25-
</>
26-
);
27-
}
28-
29-
return <RoleAddress address={renderData} />;
20+
return (
21+
<>
22+
{!!roles &&
23+
roles.map((role, index) => {
24+
return (
25+
<RoleAddress
26+
key={role.value}
27+
role={role}
28+
roles={roles}
29+
index={index}
30+
vaultKey={vaultKey}
31+
isEditable={isEditable}
32+
/>
33+
);
34+
})}
35+
</>
36+
);
3037
};
Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,56 @@
11
import { FC } from 'react';
2-
import { Address } from 'viem';
32

43
import { AddressBadge } from 'shared/components';
54
import { AddressWrapper } from './styles';
5+
import { RoleFieldSchema } from 'features/settings/main/types';
6+
import { useFormContext } from 'react-hook-form';
7+
import { VaultInfo } from 'types';
68

79
interface RoleAddressProps {
8-
address: Address | undefined;
10+
vaultKey: keyof VaultInfo;
11+
index: number;
12+
isEditable: boolean;
13+
role: RoleFieldSchema;
14+
roles: RoleFieldSchema[];
915
}
1016

11-
export const RoleAddress: FC<RoleAddressProps> = ({ address }) => (
12-
<AddressWrapper>
13-
<AddressBadge weight={400} address={address} symbols={21} />
14-
</AddressWrapper>
15-
);
17+
export const RoleAddress: FC<RoleAddressProps> = ({
18+
vaultKey,
19+
index,
20+
isEditable,
21+
role,
22+
roles,
23+
}) => {
24+
const { getValues, setValue } = useFormContext();
25+
const itemFormKey = `${vaultKey}.${index}`;
26+
if (!('isGranted' in role)) {
27+
return null;
28+
}
29+
30+
const toRemove = role.state === 'remove';
31+
const bgColor = toRemove ? 'error' : 'default';
32+
const isLast = roles.filter((role) => role.state === 'display').length === 1;
33+
const canToggle = (roles.length > 1 && !isLast) || toRemove;
34+
const onToggle = () => {
35+
const { state, ...rest } = getValues(itemFormKey) as RoleFieldSchema;
36+
const updatedItem = {
37+
...rest,
38+
state: state === 'display' ? 'remove' : 'display',
39+
};
40+
41+
setValue(itemFormKey, updatedItem, { shouldDirty: true });
42+
};
43+
44+
return (
45+
<AddressWrapper>
46+
<AddressBadge
47+
weight={400}
48+
address={role.value}
49+
crossedText={toRemove}
50+
bgColor={bgColor}
51+
symbols={21}
52+
onToggle={canToggle && isEditable ? () => onToggle() : undefined}
53+
/>
54+
</AddressWrapper>
55+
);
56+
};
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { FC, useEffect } from 'react';
2+
3+
import { useFieldArray, useForm, useFormContext } from 'react-hook-form';
4+
5+
import { Plus } from '@lidofinance/lido-ui';
6+
import { InputItem } from './input-item';
7+
import { ButtonContainer, EditWrapper } from './styles';
8+
import {
9+
ManagersKeys,
10+
ManagersNewAddresses,
11+
} from 'features/settings/main/types';
12+
import { Address } from 'viem';
13+
import { validateManagers } from 'features/settings/main/consts';
14+
import { useVaultInfo } from 'features/overview/contexts';
15+
16+
interface EditPropertyAddressProps {
17+
name: ManagersKeys;
18+
editLabel: string;
19+
}
20+
21+
export const EditPropertyAddress: FC<EditPropertyAddressProps> = ({
22+
name,
23+
editLabel,
24+
}) => {
25+
const { isRefetching } = useVaultInfo();
26+
const { getValues } = useFormContext();
27+
const {
28+
control,
29+
register,
30+
trigger,
31+
watch,
32+
formState: { errors },
33+
} = useForm<ManagersNewAddresses>({
34+
defaultValues: {
35+
addresses: {
36+
[name]: [],
37+
},
38+
},
39+
resolver: validateManagers(getValues),
40+
mode: 'all',
41+
});
42+
const { append, fields, remove } = useFieldArray({
43+
control,
44+
name: `addresses.${name}`,
45+
});
46+
47+
useEffect(() => {
48+
if (isRefetching) {
49+
remove();
50+
}
51+
}, [remove, isRefetching]);
52+
53+
return (
54+
<EditWrapper>
55+
{fields.map((field, index) => {
56+
return (
57+
<InputItem
58+
name={name}
59+
editLabel={editLabel}
60+
key={field.id}
61+
register={register}
62+
remove={remove}
63+
trigger={trigger}
64+
watch={watch}
65+
error={errors.addresses?.[name]}
66+
index={index}
67+
/>
68+
);
69+
})}
70+
<ButtonContainer
71+
color="primary"
72+
icon={<Plus />}
73+
size="md"
74+
variant="ghost"
75+
type="button"
76+
onClick={() => append({ value: '' as Address, state: 'grant' })}
77+
>
78+
Add new address
79+
</ButtonContainer>
80+
</EditWrapper>
81+
);
82+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { EditPropertyAddress } from './edit-property-address';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { InputItem } from './input-item';

0 commit comments

Comments
 (0)