Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.

Commit e1a61c8

Browse files
author
Diogo Soares
committed
style delegate table and show edit/remove buttons
1 parent 7c0fd70 commit e1a61c8

File tree

3 files changed

+196
-30
lines changed

3 files changed

+196
-30
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { TableCellProps } from '@material-ui/core/TableCell/TableCell'
2+
3+
export const DELEGATE_ADDRESS_ID = 'delegate'
4+
export const DELEGATOR_ADDRESS_ID = 'delegator'
5+
export const DELEGATE_LABEL_ID = 'label'
6+
export const ACTIONS_ID = 'actions'
7+
export const EDIT_DELEGATE_BUTTON = 'edit-entry-btn'
8+
export const REMOVE_DELEGATE_BUTTON = 'remove-entry-btn'
9+
10+
type DelegatesTableColumn = {
11+
id: string
12+
label: string
13+
width?: number
14+
custom?: boolean
15+
align?: TableCellProps['align']
16+
}
17+
18+
export const generateColumns = (): Array<DelegatesTableColumn> => {
19+
const delegateColumn = {
20+
id: DELEGATE_ADDRESS_ID,
21+
label: 'Delegate',
22+
width: 150,
23+
custom: false,
24+
align: 'left',
25+
}
26+
27+
const delegatorColumn = {
28+
id: DELEGATOR_ADDRESS_ID,
29+
label: 'Delegator',
30+
width: 150,
31+
custom: false,
32+
align: 'left',
33+
}
34+
35+
const labelColumn = {
36+
id: DELEGATE_LABEL_ID,
37+
label: 'Label',
38+
custom: false,
39+
}
40+
41+
const actionsColumn = {
42+
id: ACTIONS_ID,
43+
label: '',
44+
custom: true,
45+
}
46+
47+
return [delegateColumn, delegatorColumn, labelColumn, actionsColumn]
48+
}

src/routes/safe/components/Settings/Delegates/index.tsx

Lines changed: 87 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
1-
import { ReactElement, useCallback, useEffect, useMemo, useState } from 'react'
1+
import { ReactElement, useCallback, useEffect, useState } from 'react'
22
import { useSelector } from 'react-redux'
33
import styled from 'styled-components'
4-
import { ButtonLink, Table, TableHeader, TableRow, Text } from '@gnosis.pm/safe-react-components'
4+
import { makeStyles, TableCell, TableContainer, TableRow } from '@material-ui/core'
5+
import { ButtonLink, Icon } from '@gnosis.pm/safe-react-components'
6+
import { keccak256, fromAscii } from 'web3-utils'
7+
import cn from 'classnames'
58

69
import Block from 'src/components/layout/Block'
710
import Heading from 'src/components/layout/Heading'
811
import Paragraph from 'src/components/layout/Paragraph/index'
912
import { lg } from 'src/theme/variables'
1013
import { currentSafeWithNames } from 'src/logic/safe/store/selectors'
11-
import { getChainInfo } from 'src/config'
14+
import { getChainInfo, getExplorerInfo } from 'src/config'
1215
import { checksumAddress } from 'src/utils/checksumAddress'
1316
import { getWeb3 } from 'src/logic/wallets/getWeb3'
1417
import { AddDelegateModal } from 'src/routes/safe/components/Settings/Delegates/AddDelegateModal'
1518
import { userAccountSelector } from 'src/logic/wallets/store/selectors'
16-
import { keccak256, fromAscii } from 'web3-utils'
19+
import Table from 'src/components/Table'
20+
import { cellWidth } from 'src/components/Table/TableHead'
21+
import { DELEGATE_ADDRESS_ID, DELEGATOR_ADDRESS_ID, generateColumns } from './columns'
22+
import { styles } from './style'
23+
import PrefixedEthHashInfo from 'src/components/PrefixedEthHashInfo'
24+
import Row from 'src/components/layout/Row'
25+
import ButtonHelper from 'src/components/ButtonHelper'
26+
import { grantedSelector } from 'src/routes/safe/container/selector'
1727

1828
// TODO: these types will come from the Client GW SDK once #72 is merged
1929
type Page<T> = {
@@ -40,22 +50,19 @@ const StyledHeading = styled(Heading)`
4050
padding-bottom: 0;
4151
`
4252

53+
const useStyles = makeStyles(styles)
54+
4355
const Delegates = (): ReactElement => {
4456
const { address: safeAddress } = useSelector(currentSafeWithNames)
4557
const userAccount = useSelector(userAccountSelector)
58+
const granted = useSelector(grantedSelector)
4659
const { transactionService } = getChainInfo()
4760
const [delegatesList, setDelegatesList] = useState<DelegateResponse['results']>([])
4861
const [addDelegateModalOpen, setAddDelegateModalOpen] = useState<boolean>(false)
62+
const columns = generateColumns()
63+
const autoColumns = columns.filter(({ custom }) => !custom)
4964

50-
const headerCells: TableHeader[] = useMemo(
51-
() => [
52-
{ id: 'delegate', label: 'Delegate' },
53-
{ id: 'delegator', label: 'Delegator' },
54-
{ id: 'label', label: 'Label' },
55-
],
56-
[],
57-
)
58-
const rows: TableRow[] = useMemo(() => [], [])
65+
const classes = useStyles(styles)
5966

6067
const fetchDelegates = useCallback(() => {
6168
const url = `${transactionService}/api/v1/safes/${safeAddress}/delegates/`
@@ -82,22 +89,6 @@ const Delegates = (): ReactElement => {
8289
fetchDelegates()
8390
}, [fetchDelegates, safeAddress, transactionService])
8491

85-
useEffect(() => {
86-
if (delegatesList.length) {
87-
let index = 0
88-
for (const obj of delegatesList) {
89-
rows.push({
90-
id: `${index++}`,
91-
cells: [
92-
{ id: 'delegate', content: <Text size="xl">{checksumAddress(obj.delegate)}</Text> },
93-
{ id: 'delegator', content: <Text size="xl">{checksumAddress(obj.delegator)}</Text> },
94-
{ id: 'label', content: <Text size="xl">{obj.label}</Text> },
95-
],
96-
})
97-
}
98-
}
99-
}, [delegatesList, rows])
100-
10192
const handleAddDelegate = async ({ address, label }) => {
10293
// close Add delegate modal
10394
setAddDelegateModalOpen(false)
@@ -140,7 +131,73 @@ const Delegates = (): ReactElement => {
140131
Add delegate
141132
</ButtonLink>
142133
<pre>{JSON.stringify(delegatesList, undefined, 2)}</pre>
143-
<Table headers={headerCells} rows={rows} />
134+
<TableContainer>
135+
<Table columns={columns} data={delegatesList} defaultFixed disableLoadingOnEmptyTable disablePagination>
136+
{(data) =>
137+
data.map((row, index) => {
138+
const hideBorderBottom = index >= 3 && index === data.size - 1 && classes.noBorderBottom
139+
return (
140+
<TableRow className={cn(classes.hide, hideBorderBottom)} key={index}>
141+
{autoColumns.map((column) => {
142+
const displayEthHash = [DELEGATE_ADDRESS_ID, DELEGATOR_ADDRESS_ID].includes(column.id)
143+
return (
144+
<TableCell component="td" key={column.id} style={cellWidth(column.width)}>
145+
{displayEthHash ? (
146+
<Block justify="left">
147+
<PrefixedEthHashInfo
148+
hash={row[column.id]}
149+
shortenHash={4}
150+
showCopyBtn
151+
showAvatar
152+
explorerUrl={getExplorerInfo(row[column.id])}
153+
/>
154+
</Block>
155+
) : (
156+
row[column.id]
157+
)}
158+
</TableCell>
159+
)
160+
})}
161+
<TableCell component="td">
162+
<Row align="end" className={classes.actions}>
163+
<ButtonHelper
164+
onClick={() => {
165+
// setSelectedEntry({
166+
// entry: row,
167+
// isOwnerAddress: userOwner,
168+
// })
169+
// setEditCreateEntryModalOpen(true)
170+
}}
171+
>
172+
<Icon
173+
size="sm"
174+
type="edit"
175+
tooltip="Edit delegate"
176+
className={granted ? classes.editEntryButton : classes.editEntryButtonNonOwner}
177+
/>
178+
</ButtonHelper>
179+
<ButtonHelper
180+
onClick={() => {
181+
// setSelectedEntry({ entry: row })
182+
// setDeleteEntryModalOpen(true)
183+
}}
184+
>
185+
<Icon
186+
size="sm"
187+
type="delete"
188+
color="error"
189+
tooltip="Remove delegate"
190+
className={granted ? classes.removeEntryButton : classes.removeEntryButtonNonOwner}
191+
/>
192+
</ButtonHelper>
193+
</Row>
194+
</TableCell>
195+
</TableRow>
196+
)
197+
})
198+
}
199+
</Table>
200+
</TableContainer>
144201
<AddDelegateModal
145202
isOpen={addDelegateModalOpen}
146203
onClose={() => setAddDelegateModalOpen(false)}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { background, lg, md, sm } from 'src/theme/variables'
2+
import { createStyles } from '@material-ui/core'
3+
4+
export const styles = createStyles({
5+
formContainer: {
6+
minHeight: '250px',
7+
},
8+
title: {
9+
padding: lg,
10+
paddingBottom: 0,
11+
},
12+
annotation: {
13+
paddingLeft: lg,
14+
},
15+
hide: {
16+
'&:hover': {
17+
backgroundColor: `${background}`,
18+
},
19+
'&:hover $actions': {
20+
visibility: 'initial',
21+
},
22+
},
23+
actions: {
24+
justifyContent: 'flex-end',
25+
alignItems: 'center',
26+
visibility: 'hidden',
27+
minWidth: '100px',
28+
gap: md,
29+
},
30+
noBorderBottom: {
31+
'& > td': {
32+
borderBottom: 'none',
33+
},
34+
},
35+
controlsRow: {
36+
backgroundColor: 'white',
37+
padding: lg,
38+
borderRadius: sm,
39+
},
40+
editEntryButton: {
41+
cursor: 'pointer',
42+
},
43+
editEntryButtonNonOwner: {
44+
cursor: 'pointer',
45+
},
46+
removeEntryButton: {
47+
cursor: 'pointer',
48+
},
49+
removeEntryButtonDisabled: {
50+
cursor: 'default',
51+
},
52+
removeEntryButtonNonOwner: {
53+
cursor: 'pointer',
54+
},
55+
leftIcon: {
56+
marginRight: sm,
57+
},
58+
iconSmall: {
59+
fontSize: 16,
60+
},
61+
})

0 commit comments

Comments
 (0)