Skip to content
This repository has been archived by the owner on Feb 2, 2024. It is now read-only.

Commit

Permalink
Merge d406fba into a09da3b
Browse files Browse the repository at this point in the history
  • Loading branch information
henrypalacios authored Apr 22, 2022
2 parents a09da3b + d406fba commit c26717b
Show file tree
Hide file tree
Showing 18 changed files with 487 additions and 97 deletions.
178 changes: 178 additions & 0 deletions src/apps/explorer/components/SummaryCardsWidget/SummaryCards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import React from 'react'
import styled, { css } from 'styled-components'
import { media } from 'theme/styles/media'
import { formatDistanceToNowStrict } from 'date-fns'

import { Card, CardContent } from 'components/common/Card'
import { CardRow } from 'components/common/CardRow'
import { TotalSummaryResponse } from '.'
import { abbreviateString } from 'utils'
import { useMediaBreakpoint } from 'hooks/useMediaBreakPoint'
import { CopyButton } from 'components/common/CopyButton'
import { LinkWithPrefixNetwork } from 'components/common/LinkWithPrefixNetwork'

const BatchInfoHeight = '19.6rem'
const DESKTOP_TEXT_SIZE = 1.8 // rem
const MOBILE_TEXT_SIZE = 1.65 // rem

const WrapperCardRow = styled(CardRow)`
max-width: 70%;
${media.mobile} {
max-width: 100%;
}
`

const DoubleContentSize = css`
min-height: ${BatchInfoHeight};
`
const WrapperColumn = styled.div`
/* Equivalent to use lg={8} MUI grid system */
flex-grow: 0;
max-width: 66.666667%;
flex-basis: 66.666667%;
padding-right: 2rem;
> div {
margin: 1rem;
max-height: ${BatchInfoHeight};
}
${media.mediumDownMd} {
flex-grow: 0;
max-width: 100%;
flex-basis: 100%;
}
`
const DoubleCardStyle = css`
${DoubleContentSize}
${media.mediumDownMd} {
min-height: 16rem;
}
`
const WrappedDoubleCard = styled(Card)`
${DoubleCardStyle}
`

const CardTransactions = styled(Card)`
${media.mediumDownMd} {
${DoubleCardStyle}
}
`

const WrapperDoubleContent = styled.div`
display: flex;
flex-direction: column;
gap: 3rem;
${media.mediumDownMd} {
gap: 2rem;
}
`

interface SummaryCardsProps {
summaryData: TotalSummaryResponse | undefined
children: React.ReactNode
}

function calcDiff(a: number, b: number): number {
return (a - b === 0 ? 0 : (100 * (a - b)) / b) || 0
}

function getColorBySign(n: number): string {
if (n > 0) {
return 'green'
} else if (n < 0) {
return 'red1'
}

return 'grey'
}

export function SummaryCards({ summaryData, children }: SummaryCardsProps): JSX.Element {
const { batchInfo, dailyTransactions, totalTokens, dailyFees, isLoading } = summaryData || {}
const isDesktop = useMediaBreakpoint(['xl', 'lg'])
const valueTextSize = isDesktop ? DESKTOP_TEXT_SIZE : MOBILE_TEXT_SIZE
const rowsByCard = isDesktop ? '2row' : '3row'
const diffTransactions = (dailyTransactions && calcDiff(dailyTransactions.now, dailyTransactions.before)) || 0
const diffFees = (dailyFees && calcDiff(dailyFees.now, dailyFees.before)) || 0

return (
<WrapperCardRow>
<>
<WrapperColumn>{children}</WrapperColumn>
<WrappedDoubleCard xs={6} lg={4}>
<WrapperDoubleContent>
<CardContent
variant="3row"
label1="Last Batch"
value1={batchInfo && formatDistanceToNowStrict(batchInfo.lastBatchDate)}
loading={isLoading}
valueSize={valueTextSize}
/>
<CardContent
variant={rowsByCard}
label1="Batch ID"
value1={
batchInfo && (
<>
<LinkWithPrefixNetwork to={`/tx/${batchInfo.batchId}`}>
{abbreviateString(batchInfo?.batchId, 6, 4)}
</LinkWithPrefixNetwork>
<CopyButton heightIcon={1.35} text={batchInfo?.batchId || ''} />
</>
)
}
loading={isLoading}
valueSize={valueTextSize}
/>
</WrapperDoubleContent>
</WrappedDoubleCard>
<CardTransactions xs={6} lg={4}>
<CardContent
variant={rowsByCard}
label1="24h Transactions"
value1={dailyTransactions?.now}
caption1={`${diffTransactions.toFixed(2)}%`}
captionColor={getColorBySign(diffTransactions)}
loading={isLoading}
valueSize={valueTextSize}
/>
</CardTransactions>
<Card xs={6} lg={4}>
<CardContent
variant="2row"
label1="Total Tokens"
value1={totalTokens}
loading={isLoading}
valueSize={valueTextSize}
/>
</Card>
<Card xs={6} lg={4}>
<CardContent
variant={rowsByCard}
label1="24h Fees"
value1={`$${dailyFees?.now.toFixed(2)}`}
caption1={`${diffFees.toFixed(2)}%`}
captionColor={getColorBySign(diffFees)}
loading={isLoading}
valueSize={valueTextSize}
/>
</Card>
{/** Surplus is not yet available */}
{/* <Card>
<CardContent
variant="2row"
label1="30d Surplus"
value1={monthSurplus.now}
caption1={monthSurplus.before}
captionColor="green"
loading={isLoading}
valueSize={valueTextSize}
/>
</Card> */}
</>
</WrapperCardRow>
)
}
81 changes: 81 additions & 0 deletions src/apps/explorer/components/SummaryCardsWidget/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import { SummaryCards } from './SummaryCards'

import summaryData from './summaryGraphResp.json'

const DELAY_SECONDS = 3 // Emulating API request

export interface BatchInfo {
lastBatchDate: Date
batchId: string
}

interface PastAndPresentValue {
now: number
before: number
}

interface TotalSummary {
batchInfo?: BatchInfo
dailyTransactions?: PastAndPresentValue
totalTokens?: number
dailyFees?: PastAndPresentValue
}

type RawTotalSummary = Omit<TotalSummary, 'batchInfo'> & {
batchInfo: { lastBatchDate: number; batchId: string }
}

function buildSummary(data: RawTotalSummary): TotalSummary {
return {
...data,
batchInfo: {
...data.batchInfo,
lastBatchDate: new Date(data.batchInfo.lastBatchDate * 1000),
},
}
}

export type TotalSummaryResponse = TotalSummary & {
isLoading: boolean
}

function useGetTotalSummary(): TotalSummaryResponse | undefined {
const [summary, setSummary] = useState<TotalSummaryResponse | undefined>()

useEffect(() => {
setSummary((prevState) => {
return { ...prevState, isLoading: true }
})
const timer = setTimeout(() => setSummary({ ...buildSummary(summaryData), isLoading: false }), DELAY_SECONDS * 1000)

return (): void => clearTimeout(timer)
}, [])

return summary
}

const Wrapper = styled.div`
display: flex;
flex: 1;
justify-content: center;
`
const VolumeChart = styled.div`
background: #28f3282c;
border-radius: 0.4rem;
height: 19.6rem;
width: 100%;
`

export function StatsSummaryCardsWidget(): JSX.Element {
const summary = useGetTotalSummary()

return (
<Wrapper>
<SummaryCards summaryData={summary}>
<VolumeChart />
</SummaryCards>
</Wrapper>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"batchInfo": { "lastBatchDate": 1649881035, "batchId": "0x0003723b9eb1598e12d15c69206bf13c971be0310fa5744cf9601ed79f89e29c" },
"dailyTransactions": {"now": 612, "before": 912},
"totalTokens": 193,
"dailyFees": {"now": 55225.61205047748511254485049406426, "before": 40361.20651840192742698089787142249}
}
30 changes: 30 additions & 0 deletions src/apps/explorer/components/common/ShimmerBar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import styled, { keyframes } from 'styled-components'

const ShimmerKeyframe = keyframes`
0% {
background-position: 0px top;
}
90% {
background-position: 300px top;
}
100% {
background-position: 300px top;
}
`

const ShimmerBar = styled.div`
width: 100%;
height: 12px;
border-radius: 2px;
color: white;
background: ${({ theme }): string =>
`${theme.greyOpacity} -webkit-gradient(linear, 100% 0, 0 0, from(${theme.greyOpacity}), color-stop(0.5, ${theme.borderPrimary}), to(${theme.gradient1}))`};
background-position: -5rem top;
background-repeat: no-repeat;
-webkit-animation-name: ${ShimmerKeyframe};
-webkit-animation-duration: 1.3s;
-webkit-animation-iteration-count: infinite;
-webkit-background-size: 5rem 100%;
`

export default ShimmerBar
16 changes: 15 additions & 1 deletion src/apps/explorer/pages/Home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { Search } from 'apps/explorer/components/common/Search'
import { Wrapper as WrapperMod } from 'apps/explorer/pages/styled'
import styled from 'styled-components'
import { media } from 'theme/styles/media'
import { StatsSummaryCardsWidget } from 'apps/explorer/components/SummaryCardsWidget'

const Wrapper = styled(WrapperMod)`
max-width: 140rem;
flex-flow: column wrap;
justify-content: center;
justify-content: flex-start;
display: flex;
padding-top: 10rem;
> h1 {
justify-content: center;
Expand All @@ -23,11 +25,23 @@ const Wrapper = styled(WrapperMod)`
}
`

const SummaryWrapper = styled.section`
display: flex;
padding-top: 10rem;
${media.mobile} {
padding-top: 4rem;
}
`

export const Home: React.FC = () => {
return (
<Wrapper>
<h1>Search on CoW Protocol Explorer</h1>
<Search className="home" />
<SummaryWrapper>
<StatsSummaryCardsWidget />
</SummaryWrapper>
</Wrapper>
)
}
Expand Down
Loading

0 comments on commit c26717b

Please sign in to comment.