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

feat: Dashboard grid layout #3795

Merged
merged 16 commits into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 20 additions & 18 deletions src/components/Dashboard/CreateSafe.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ReactElement } from 'react'
import styled from 'styled-components'
import { Button, Title, Text } from '@gnosis.pm/safe-react-components'
import { Button, Text } from '@gnosis.pm/safe-react-components'
import Link from 'src/components/layout/Link'
import Track from 'src/components/Track'
import { OPEN_SAFE_ROUTE } from 'src/routes/routes'
import { CREATE_SAFE_EVENTS } from 'src/utils/events/createLoadSafe'
import { Card, WidgetBody, WidgetContainer, WidgetTitle } from 'src/components/Dashboard/styled'

export const CardContentContainer = styled.div`
display: flex;
Expand All @@ -19,24 +20,25 @@ export const CardDescriptionContainer = styled.div`

const CreateSafeWidget = (): ReactElement => {
return (
<CardContentContainer>
<Title size="sm" strong withoutMargin>
Create Safe
</Title>
<WidgetContainer>
<WidgetTitle>Create Safe</WidgetTitle>
<WidgetBody>
<Card>
<CardDescriptionContainer>
<Text size="xl">Create a new Safe that is controlled by one or multiple owners.</Text>
<Text size="xl">You will be required to pay a network fee for creating your new Safe.</Text>
</CardDescriptionContainer>

<CardDescriptionContainer>
<Text size="xl">Create a new Safe that is controlled by one or multiple owners.</Text>
<Text size="xl">You will be required to pay a network fee for creating your new Safe.</Text>
</CardDescriptionContainer>

<Track {...CREATE_SAFE_EVENTS.CREATE_BUTTON}>
<Button size="lg" color="primary" variant="contained" component={Link} to={OPEN_SAFE_ROUTE}>
<Text size="xl" color="white">
+ Create new Safe
</Text>
</Button>
</Track>
</CardContentContainer>
<Track {...CREATE_SAFE_EVENTS.CREATE_BUTTON}>
<Button size="lg" color="primary" variant="contained" component={Link} to={OPEN_SAFE_ROUTE}>
<Text size="xl" color="white">
+ Create new Safe
</Text>
</Button>
</Track>
</Card>
</WidgetBody>
</WidgetContainer>
)
}

Expand Down
53 changes: 29 additions & 24 deletions src/components/Dashboard/FeaturedApps/FeaturedApps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import { ReactElement, useMemo } from 'react'
import Row from 'src/components/layout/Row'
import Col from 'src/components/layout/Col'
import styled from 'styled-components'
import { Card, WidgetBody, WidgetContainer, WidgetTitle } from 'src/components/Dashboard/styled'

const FEATURED_APPS_TAGS = 'dashboard-widgets'

const StyledImage = styled.img`
max-width: 64px;
max-height: 64px;
width: 64px;
height: 64px;
`

const StyledLink = styled(Link)`
Expand All @@ -25,6 +26,7 @@ const StyledLink = styled(Link)`
const StyledRow = styled(Row)`
gap: 24px;
flex-wrap: inherit;
align-items: center;
`

export const FeaturedApps = (): ReactElement => {
Expand All @@ -38,27 +40,30 @@ export const FeaturedApps = (): ReactElement => {
}

return (
<>
{featuredApps.map((app) => {
const appRoute = getSafeAppUrl(app.url, routesSlug)
return (
<StyledRow key={app.id} margin="lg">
<Col xs={2}>
<StyledImage src={app.iconUrl} alt={app.name} />
</Col>
<Col xs={10} layout="column">
<Text size="lg" strong>
{app.description}
</Text>
<StyledLink to={appRoute}>
<Text color="primary" size="lg" strong>
Use {app.name}
</Text>
</StyledLink>
</Col>
</StyledRow>
)
})}
</>
<WidgetContainer>
<WidgetTitle>Safe Apps</WidgetTitle>
<WidgetBody>
{featuredApps.map((app) => {
const appRoute = getSafeAppUrl(app.url, routesSlug)
return (
<Card key={app.id}>
<StyledRow>
<Col xs={2}>
<StyledImage src={app.iconUrl} alt={app.name} />
</Col>
<Col xs={10} layout="column">
<Text size="xl">{app.description}</Text>
<StyledLink to={appRoute}>
<Text color="primary" size="lg" strong>
Use {app.name}
</Text>
</StyledLink>
</Col>
</StyledRow>
</Card>
)
})}
</WidgetBody>
</WidgetContainer>
)
}
91 changes: 50 additions & 41 deletions src/components/Dashboard/Overview/Overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { primaryLite, primaryActive, smallFontSize, md } from 'src/theme/variabl
import NetworkLabel from 'src/components/NetworkLabel/NetworkLabel'
import { nftLoadedSelector, nftTokensSelector } from 'src/logic/collectibles/store/selectors'
import { Skeleton } from '@material-ui/lab'
import { Card } from 'src/components/Dashboard/styled'
import { WidgetBody, WidgetContainer, WidgetTitle } from 'src/components/Dashboard/styled'

const IdenticonContainer = styled.div`
position: relative;
Expand Down Expand Up @@ -66,47 +68,54 @@ const Overview = (): ReactElement => {
const nftLoaded = useSelector(nftLoadedSelector)

return (
<Container>
<Row margin="md">
<Col layout="column">
<IdenticonContainer>
{loaded ? (
<>
<SafeThreshold>
{threshold}/{owners.length}
</SafeThreshold>
<Identicon address={address} size="lg" />
</>
) : (
<Skeleton variant="circle" width="40px" height="40px" />
)}
</IdenticonContainer>
<Text size="xl" strong>
{loaded ? name : <Skeleton variant="text" />}
</Text>
{loaded ? <PrefixedEthHashInfo hash={address} textSize="lg" /> : <Skeleton variant="text" />}
</Col>
<Col end="xs">
<NetworkLabelContainer>
<NetworkLabel />
</NetworkLabelContainer>
</Col>
</Row>
<Row>
<Col layout="column" xs={3}>
<Text color="inputDefault" size="md">
Tokens
</Text>
<StyledText size="xl">{loaded ? balances.length : ValueSkeleton}</StyledText>
</Col>
<Col layout="column" xs={3}>
<Text color="inputDefault" size="md">
NFTs
</Text>
{nftTokens && <StyledText size="xl">{nftLoaded ? nftTokens.length : ValueSkeleton}</StyledText>}
</Col>
</Row>
</Container>
<WidgetContainer>
<WidgetTitle>Dashboard</WidgetTitle>
<WidgetBody>
<Card>
<Container>
<Row margin="lg">
<Col layout="column">
<IdenticonContainer>
{loaded ? (
<>
<SafeThreshold>
{threshold}/{owners.length}
</SafeThreshold>
<Identicon address={address} size="lg" />
</>
) : (
<Skeleton variant="circle" width="40px" height="40px" />
)}
</IdenticonContainer>
<Text size="xl" strong>
{loaded ? name : <Skeleton variant="text" />}
</Text>
{loaded ? <PrefixedEthHashInfo hash={address} textSize="lg" /> : <Skeleton variant="text" />}
</Col>
<Col end="xs">
<NetworkLabelContainer>
<NetworkLabel />
</NetworkLabelContainer>
</Col>
</Row>
<Row>
<Col layout="column" xs={3}>
<Text color="inputDefault" size="md">
Tokens
</Text>
<StyledText size="xl">{loaded ? balances.length : ValueSkeleton}</StyledText>
</Col>
<Col layout="column" xs={3}>
<Text color="inputDefault" size="md">
NFTs
</Text>
{nftTokens && <StyledText size="xl">{nftLoaded ? nftTokens.length : ValueSkeleton}</StyledText>}
</Col>
</Row>
</Container>
</Card>
</WidgetBody>
</WidgetContainer>
)
}

Expand Down
10 changes: 5 additions & 5 deletions src/components/Dashboard/PendingTxs/PendingTxListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,27 @@ import { useAssetInfo } from 'src/routes/safe/components/Transactions/TxList/hoo
import { useKnownAddress } from 'src/routes/safe/components/Transactions/TxList/hooks/useKnownAddress'
import { useTransactionType } from 'src/routes/safe/components/Transactions/TxList/hooks/useTransactionType'
import { getTxTo } from 'src/routes/safe/components/Transactions/TxList/utils'
import { boldFont, grey400, primary200, sm, smallFontSize } from 'src/theme/variables'
import { boldFont, grey400, primary200, smallFontSize } from 'src/theme/variables'
import { isMultisigExecutionInfo } from 'src/logic/safe/store/models/types/gateway.d'
import Spacer from 'src/components/Spacer'
import { CustomIconText } from 'src/components/CustomIconText'
import { TxInfo } from 'src/routes/safe/components/Transactions/TxList/TxCollapsed'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'

const TransactionToConfirm = styled(Link)`
min-width: 270px;
height: 40px;
width: 100%;
display: grid;
align-items: center;
grid-template-columns: 25px 1fr 1fr auto;
gap: 4px;
margin: ${sm} auto;
padding: 4px 16px;
margin: 0 auto;
padding: 8px 16px;
text-decoration: none;
background-color: ${({ theme }) => theme.colors.white};
border: 2px solid ${grey400};
color: ${({ theme }) => theme.colors.text};
border-radius: 8px;
box-sizing: border-box;
`

const StyledConfirmationsCount = styled.div`
Expand Down
62 changes: 43 additions & 19 deletions src/components/Dashboard/PendingTxs/PendingTxsList.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
import { ReactElement, useMemo } from 'react'
import { List } from '@material-ui/core'
import styled from 'styled-components'
import { useSelector } from 'react-redux'
import Skeleton from '@material-ui/lab/Skeleton/Skeleton'

import { Transaction } from 'src/logic/safe/store/models/types/gateway.d'
import { sm } from 'src/theme/variables'
import { currentChainId } from 'src/logic/config/store/selectors'
import { generateSafeRoute, SAFE_ROUTES } from 'src/routes/routes'
import { getChainById } from 'src/config'
import PendingTxListItem from 'src/components/Dashboard/PendingTxs/PendingTxListItem'
import { currentSafe } from 'src/logic/safe/store/selectors'
import { pendingTransactions } from 'src/logic/safe/store/selectors/gatewayTransactions'
import { Card, WidgetBody, WidgetContainer, WidgetTitle } from 'src/components/Dashboard/styled'
import { Text } from '@gnosis.pm/safe-react-components'

const SkeletonWrapper = styled.div`
margin: ${sm} auto;
border-radius: 8px;
overflow: hidden;
`

const StyledList = styled.div`
display: flex;
flex-direction: column;
gap: 12px;
width: 100%;
`

const EmptyState = (
<Card>
<Text size="xl">This Safe has no queued transactions</Text>
</Card>
)

const PendingTxsList = ({ size = 5 }: { size?: number }): ReactElement | null => {
const { address } = useSelector(currentSafe)
const chainId = useSelector(currentChainId)

const queueTxns = useSelector(pendingTransactions)
const { shortName } = getChainById(chainId)
const url = generateSafeRoute(SAFE_ROUTES.TRANSACTIONS_QUEUE, { safeAddress: address, shortName })

const queuedTxsToDisplay: Transaction[] = useMemo(() => {
if (!queueTxns) return []
Expand All @@ -37,30 +50,41 @@ const PendingTxsList = ({ size = 5 }: { size?: number }): ReactElement | null =>
)
}, [queueTxns, size])

if (!queueTxns) {
return (
<List component="div">
const LoadingState = useMemo(
() => (
<StyledList>
{Array.from(Array(size).keys()).map((key) => (
<SkeletonWrapper key={key}>
<Skeleton variant="rect" height={52} />
</SkeletonWrapper>
))}
</List>
)
}
</StyledList>
),
[size],
)

if (!queuedTxsToDisplay?.length) {
return <h3>This Safe has no queued transactions</h3>
const ResultState = useMemo(
() => (
<StyledList>
{queuedTxsToDisplay?.map((transaction) => (
<PendingTxListItem transaction={transaction} url={url} key={transaction.id} />
))}
</StyledList>
),
[queuedTxsToDisplay, url],
)

const getWidgetBody = () => {
if (!queueTxns) return LoadingState
if (!queuedTxsToDisplay?.length) return EmptyState
return ResultState
}

const { shortName } = getChainById(chainId)
const url = generateSafeRoute(SAFE_ROUTES.TRANSACTIONS_QUEUE, { safeAddress: address, shortName })
return (
<List component="div">
{queuedTxsToDisplay?.map((transaction) => (
<PendingTxListItem transaction={transaction} url={url} key={transaction.id} />
))}
</List>
<WidgetContainer>
<WidgetTitle>Transactions to Sign</WidgetTitle>
<WidgetBody>{getWidgetBody()}</WidgetBody>
</WidgetContainer>
)
}

Expand Down
Loading