-
Notifications
You must be signed in to change notification settings - Fork 49
feat(web): extra statistic on homepage #1671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
7b615f4
feat(web): extra statistic on homepage
nikhilverma360 0bc4fd4
fix(web): fix HomePageExtraStatsTypes
nikhilverma360 8e5b49d
Merge branch 'dev' into feat(web)/Extra-statistics-on-the-Home-page
kemuru 0d0a60e
feat: styling according to figma
kemuru 154ea0c
fix: slight styling, and most cases fetching optimiz, delete ineffici…
kemuru 9da8250
fix: one week in seconds
kemuru 80912c4
chore: better naming for clarity
kemuru a774c26
feat: courtesy of green, activity stats, most drawing chance, most re…
kemuru 20a27f8
fix: random style fix for margin bottom in case cards title skeletons
kemuru 09ef75d
feat: change number of disputes for number of votes, subgraph changes…
kemuru e614e6c
fix: add missing number votes fields
kemuru 7a648af
feat: add selector according to figma of past blocks and times
kemuru 0dfb08a
feat: add support for all time filtering, add skeletons for styling,
kemuru be37823
chore: add staletime to the query, comment older days
kemuru 0448987
fix: few code smells
kemuru 56af5a7
chore: add subgraph endpoint back
kemuru 0ec4f0f
chore: bump subgraph package json version
kemuru a1361c1
feat: add effectivestake to the subgraph, modify hook
kemuru 48d7869
chore: add my subgraph endpoint for local testing
kemuru db1b451
chore: changed tosorted to prevent array mutations
kemuru c2d85fa
fix: always iterate through presentcourts and check if pastcourt exists
kemuru 9ddd81a
fix: remove one unnecessary loop and move the variables to the return…
kemuru 0075331
chore: update subgraph version
kemuru 781c226
chore(web): add config to use sorting without mutation on arrays
alcercu e85461b
refactor(web): extra stats block query algorithm improvement
alcercu 82d8e7a
chore: readd correct subgraph endpoint
kemuru 94c4074
Merge branch 'dev' into feat(web)/Extra-statistics-on-the-Home-page
kemuru File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import React from "react"; | ||
import styled from "styled-components"; | ||
|
||
import { StyledSkeleton } from "components/StyledSkeleton"; | ||
import { isUndefined } from "utils/index"; | ||
|
||
const Container = styled.div` | ||
display: flex; | ||
gap: 8px; | ||
align-items: center; | ||
margin-top: 24px; | ||
`; | ||
|
||
const SVGContainer = styled.div` | ||
display: flex; | ||
height: 14px; | ||
width: 14px; | ||
align-items: center; | ||
justify-content: center; | ||
svg { | ||
fill: ${({ theme }) => theme.secondaryPurple}; | ||
} | ||
`; | ||
|
||
const TextContainer = styled.div` | ||
display: flex; | ||
align-items: center; | ||
gap: 8px; | ||
flex-wrap: wrap; | ||
justify-content: center; | ||
`; | ||
|
||
const StyledP = styled.p` | ||
font-size: 14px; | ||
font-weight: 600; | ||
margin: 0; | ||
`; | ||
|
||
const StyledExtraStatTitleSkeleton = styled(StyledSkeleton)` | ||
width: 100px; | ||
`; | ||
|
||
export interface IExtraStatsDisplay { | ||
title: string; | ||
icon: React.FunctionComponent<React.SVGAttributes<SVGElement>>; | ||
content?: React.ReactNode; | ||
text?: string; | ||
} | ||
|
||
const ExtraStatsDisplay: React.FC<IExtraStatsDisplay> = ({ title, text, content, icon: Icon, ...props }) => { | ||
return ( | ||
<Container {...props}> | ||
<SVGContainer>{<Icon />}</SVGContainer> | ||
<TextContainer> | ||
<label>{title}:</label> | ||
{content ? content : <StyledP>{!isUndefined(text) ? text : <StyledExtraStatTitleSkeleton />}</StyledP>} | ||
</TextContainer> | ||
</Container> | ||
); | ||
}; | ||
|
||
export default ExtraStatsDisplay; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { arbitrum, arbitrumSepolia } from "viem/chains"; | ||
|
||
export const averageBlockTimeInSeconds = { [arbitrum.id]: 0.26, [arbitrumSepolia.id]: 0.268 }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { useQuery } from "@tanstack/react-query"; | ||
|
||
import { useGraphqlBatcher } from "context/GraphqlBatcher"; | ||
import { isUndefined } from "utils/index"; | ||
|
||
import { graphql } from "src/graphql"; | ||
import { HomePageBlockQuery } from "src/graphql/graphql"; | ||
export type { HomePageBlockQuery }; | ||
|
||
const homePageBlockQuery = graphql(` | ||
query HomePageBlock($blockNumber: Int) { | ||
presentCourts: courts(orderBy: id, orderDirection: asc) { | ||
id | ||
parent { | ||
id | ||
} | ||
name | ||
numberDisputes | ||
numberVotes | ||
feeForJuror | ||
effectiveStake | ||
} | ||
pastCourts: courts(orderBy: id, orderDirection: asc, block: { number: $blockNumber }) { | ||
id | ||
parent { | ||
id | ||
} | ||
name | ||
numberDisputes | ||
numberVotes | ||
feeForJuror | ||
effectiveStake | ||
} | ||
} | ||
`); | ||
|
||
type Court = HomePageBlockQuery["presentCourts"][number]; | ||
type CourtWithTree = Court & { | ||
numberDisputes: number; | ||
numberVotes: number; | ||
feeForJuror: bigint; | ||
effectiveStake: bigint; | ||
treeNumberDisputes: number; | ||
treeNumberVotes: number; | ||
votesPerPnk: number; | ||
treeVotesPerPnk: number; | ||
expectedRewardPerPnk: number; | ||
treeExpectedRewardPerPnk: number; | ||
}; | ||
|
||
export type HomePageBlockStats = { | ||
mostDisputedCourt: CourtWithTree; | ||
bestDrawingChancesCourt: CourtWithTree; | ||
bestExpectedRewardCourt: CourtWithTree; | ||
courts: CourtWithTree[]; | ||
}; | ||
|
||
export const useHomePageBlockQuery = (blockNumber: number | undefined, allTime: boolean) => { | ||
const isEnabled = !isUndefined(blockNumber) || allTime; | ||
const { graphqlBatcher } = useGraphqlBatcher(); | ||
|
||
return useQuery<HomePageBlockStats>({ | ||
queryKey: [`homePageBlockQuery${blockNumber}-${allTime}`], | ||
enabled: isEnabled, | ||
staleTime: Infinity, | ||
queryFn: async () => { | ||
const data = await graphqlBatcher.fetch({ | ||
id: crypto.randomUUID(), | ||
document: homePageBlockQuery, | ||
variables: { blockNumber }, | ||
}); | ||
|
||
return processData(data, allTime); | ||
}, | ||
}); | ||
}; | ||
|
||
const processData = (data: HomePageBlockQuery, allTime: boolean) => { | ||
const presentCourts = data.presentCourts; | ||
const pastCourts = data.pastCourts; | ||
const processedCourts: CourtWithTree[] = Array(presentCourts.length); | ||
const processed = new Set(); | ||
|
||
const processCourt = (id: number): CourtWithTree => { | ||
if (processed.has(id)) return processedCourts[id]; | ||
|
||
processed.add(id); | ||
const court = | ||
!allTime && id < data.pastCourts.length | ||
? addTreeValuesWithDiff(presentCourts[id], pastCourts[id]) | ||
: addTreeValues(presentCourts[id]); | ||
const parentIndex = court.parent ? Number(court.parent.id) - 1 : 0; | ||
|
||
if (id === parentIndex) { | ||
processedCourts[id] = court; | ||
return court; | ||
} | ||
|
||
processedCourts[id] = { | ||
...court, | ||
treeNumberDisputes: court.treeNumberDisputes + processCourt(parentIndex).treeNumberDisputes, | ||
treeNumberVotes: court.treeNumberVotes + processCourt(parentIndex).treeNumberVotes, | ||
treeVotesPerPnk: court.treeVotesPerPnk + processCourt(parentIndex).treeVotesPerPnk, | ||
treeExpectedRewardPerPnk: court.treeExpectedRewardPerPnk + processCourt(parentIndex).treeExpectedRewardPerPnk, | ||
}; | ||
|
||
return processedCourts[id]; | ||
}; | ||
|
||
for (const court of presentCourts.toReversed()) { | ||
processCourt(Number(court.id) - 1); | ||
} | ||
|
||
processedCourts.reverse(); | ||
|
||
return { | ||
mostDisputedCourt: getCourtMostDisputes(processedCourts), | ||
bestDrawingChancesCourt: getCourtBestDrawingChances(processedCourts), | ||
bestExpectedRewardCourt: getBestExpectedRewardCourt(processedCourts), | ||
courts: processedCourts, | ||
}; | ||
}; | ||
|
||
const addTreeValues = (court: Court): CourtWithTree => { | ||
const votesPerPnk = Number(court.numberVotes) / (Number(court.effectiveStake) / 1e18); | ||
const expectedRewardPerPnk = votesPerPnk * (Number(court.feeForJuror) / 1e18); | ||
return { | ||
...court, | ||
numberDisputes: Number(court.numberDisputes), | ||
numberVotes: Number(court.numberVotes), | ||
feeForJuror: BigInt(court.feeForJuror) / BigInt(1e18), | ||
effectiveStake: BigInt(court.effectiveStake), | ||
treeNumberDisputes: Number(court.numberDisputes), | ||
treeNumberVotes: Number(court.numberVotes), | ||
votesPerPnk, | ||
treeVotesPerPnk: votesPerPnk, | ||
expectedRewardPerPnk, | ||
treeExpectedRewardPerPnk: expectedRewardPerPnk, | ||
}; | ||
}; | ||
|
||
const addTreeValuesWithDiff = (presentCourt: Court, pastCourt: Court): CourtWithTree => { | ||
const presentCourtWithTree = addTreeValues(presentCourt); | ||
const pastCourtWithTree = addTreeValues(pastCourt); | ||
const diffNumberVotes = presentCourtWithTree.numberVotes - pastCourtWithTree.numberVotes; | ||
const avgEffectiveStake = (presentCourtWithTree.effectiveStake + pastCourtWithTree.effectiveStake) / 2n; | ||
const votesPerPnk = diffNumberVotes / Number(avgEffectiveStake); | ||
const expectedRewardPerPnk = votesPerPnk * Number(presentCourt.feeForJuror); | ||
return { | ||
...presentCourt, | ||
numberDisputes: presentCourtWithTree.numberDisputes - pastCourtWithTree.numberDisputes, | ||
treeNumberDisputes: presentCourtWithTree.treeNumberDisputes - pastCourtWithTree.treeNumberDisputes, | ||
numberVotes: diffNumberVotes, | ||
treeNumberVotes: presentCourtWithTree.treeNumberVotes - pastCourtWithTree.treeNumberVotes, | ||
effectiveStake: avgEffectiveStake, | ||
votesPerPnk, | ||
treeVotesPerPnk: votesPerPnk, | ||
expectedRewardPerPnk, | ||
treeExpectedRewardPerPnk: expectedRewardPerPnk, | ||
}; | ||
}; | ||
|
||
const getCourtMostDisputes = (courts: CourtWithTree[]) => | ||
courts.toSorted((a: CourtWithTree, b: CourtWithTree) => b.numberDisputes - a.numberDisputes)[0]; | ||
const getCourtBestDrawingChances = (courts: CourtWithTree[]) => | ||
courts.toSorted((a, b) => b.treeVotesPerPnk - a.treeVotesPerPnk)[0]; | ||
const getBestExpectedRewardCourt = (courts: CourtWithTree[]) => | ||
courts.toSorted((a, b) => b.treeExpectedRewardPerPnk - a.treeExpectedRewardPerPnk)[0]; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.