Skip to content

Commit

Permalink
Integrate centrifuge dashboard to subsquare, #4081 (#4083)
Browse files Browse the repository at this point in the history
* Integrate centrifuge dashboard to subsquare, #4081

* Update summary section, add supply data, #4081

* Add token price chart, #4081

* Show chart loading, #4081

* fix: color, #4081

* fix: icon size, #4081

* Clean up

* fix: price display, #4081

* fix: github CI

* fix: text

* fix: price chart loading

* fix: price chart loading

* Clean unused code, #4081

* Rename function, #4081
  • Loading branch information
hyifeng authored Apr 8, 2024
1 parent 6c34715 commit 99a91f8
Show file tree
Hide file tree
Showing 34 changed files with 1,201 additions and 16 deletions.
2 changes: 1 addition & 1 deletion packages/kintsugi-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@interlay/monetary-js": "^0.5.3",
"@next/env": "^13.3.0",
"@osn/icons": "^1.80.0",
"@osn/icons": "^1.85.0",
"@svgr/webpack": "^7.0.0",
"bignumber.js": "^9.0.2",
"clsx": "^1.2.1",
Expand Down
18 changes: 18 additions & 0 deletions packages/next-common/components/overview/centrifugeOverview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import AccountInfo from "./accountInfo";
import RecentProposals from "./recentProposals";
import { useChainSettings } from "next-common/context/chain";
import CentrifugeStats from "./centrifugeStats";

export default function CentrifugeOverview() {
const { showAccountManagementTab } = useChainSettings();

return (
<div className="space-y-6">
<AccountInfo hideManageAccountLink={showAccountManagementTab === false} />

<CentrifugeStats />

<RecentProposals />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { SecondaryCard } from "next-common/components/styled/containers/secondaryCard";
import CardHeader from "./cardHeader";
import { DetailList, DetailRow } from "./detailRow";
import TokenValue from "./tokenValue";
import { useBasicData } from "next-common/context/centrifuge/basicData";
import { bnToLocaleString } from "next-common/utils/bn";

export default function BlockRewardsCard() {
const { data = {} } = useBasicData();
const { rewards = {} } = data;
const { total = 0, collator = 0, treasury = 0 } = rewards;

return (
<SecondaryCard>
<div className="flex flex-col gap-[16px]">
<CardHeader
title="Block Rewards"
value={<TokenValue value={bnToLocaleString(total)} />}
/>
<DetailList>
<DetailRow
title="Collator"
value={<TokenValue value={bnToLocaleString(collator)} />}
/>
<DetailRow
title="Treasury"
value={<TokenValue value={bnToLocaleString(treasury)} />}
/>
</DetailList>
</div>
</SecondaryCard>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default function CardHeader({ title, value }) {
return (
<div className="flex flex-col gap-[4px]">
<div className="text12Medium text-textTertiary">{title}</div>
<div className="text16Bold text-textPrimary">{value}</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import tw from "tailwind-styled-components";

export const DetailList = tw.div`
flex
flex-col
[&>div]:border-b
[&>div]:border-dashed
[&>div]:border-neutral300
`;

export function DetailRow({ title, value }) {
return (
<div className="flex items-center justify-between py-[8px] text14Medium">
<div className="text-textSecondary">{title}</div>
<div className="text-textPrimary">{value}</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { SecondaryCard } from "next-common/components/styled/containers/secondaryCard";
import CardHeader from "./cardHeader";
import { DetailList, DetailRow } from "./detailRow";
import TokenValue from "./tokenValue";
import { useBasicData } from "next-common/context/centrifuge/basicData";
import { bnToLocaleString } from "next-common/utils/bn";
import Tooltip from "next-common/components/tooltip";

export default function GovernanceCard() {
const { data = {} } = useBasicData();
const { governanceToken = {} } = data;
const { onChain = 0, offChain = 0 } = governanceToken;

return (
<SecondaryCard>
<div className="flex flex-col gap-[16px]">
<CardHeader
title={
<div className="flex gap-[4px] items-center">
<span>Tokens Used in Governance</span>
<Tooltip content="Average turnout of the latest 10 proposals" />
</div>
}
value={<TokenValue value={bnToLocaleString(onChain)} />}
/>
<DetailList>
<DetailRow
title="On chain"
value={<TokenValue value={bnToLocaleString(onChain)} />}
/>
<DetailRow
title="Off chain"
value={<TokenValue value={bnToLocaleString(offChain)} />}
/>
</DetailList>
</div>
</SecondaryCard>
);
}
27 changes: 27 additions & 0 deletions packages/next-common/components/overview/centrifugeStats/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { SecondaryCard } from "next-common/components/styled/containers/secondaryCard";
import { TitleContainer } from "next-common/components/styled/containers/titleContainer";
import TreasurySummary from "next-common/components/summary/treasurySummary";
import TransactionsCard from "./transactionsCard";
import TokenHoldersCard from "./tokenHoldersCard";
import BlockRewardsCard from "./blockRewardsCard";
import GovernanceCard from "./governanceCard";

export default function CentrifugeStats() {
return (
<div>
<TitleContainer className="mb-4">Stats</TitleContainer>

<div className="flex flex-col gap-[16px]">
<div className="grid grid-cols-4 max-lg:grid-cols-2 max-sm:grid-cols-1 gap-[16px]">
<TransactionsCard />
<TokenHoldersCard />
<BlockRewardsCard />
<GovernanceCard />
</div>
<SecondaryCard>
<TreasurySummary />
</SecondaryCard>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import CardHeader from "./cardHeader";
import { SecondaryCard } from "next-common/components/styled/containers/secondaryCard";
import { DetailList, DetailRow } from "./detailRow";
import { useBasicData } from "next-common/context/centrifuge/basicData";
import { bnToLocaleString } from "next-common/utils/bn";
import Tooltip from "next-common/components/tooltip";

export default function TokenHoldersCard() {
const { data = {} } = useBasicData();
const { holders = {} } = data;
const { all = 0, whales = 0, dolphins = 0 } = holders;

return (
<SecondaryCard>
<div className="flex flex-col gap-[16px]">
<CardHeader
title={
<div className="flex gap-[4px] items-center">
<span>Total Token Holders</span>
<Tooltip
content={
<div className="flex flex-col">
<span>{"🐋 Whales: >= 1M CFG"}</span>
<span>{"🐬 Dolphins: 100K - 1M CFG"}</span>
</div>
}
/>
</div>
}
value={bnToLocaleString(all)}
/>
<DetailList>
<DetailRow title="Whales" value={bnToLocaleString(whales)} />
<DetailRow title="Dolphins" value={bnToLocaleString(dolphins)} />
</DetailList>
</div>
</SecondaryCard>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useChainSettings } from "next-common/context/chain";

export default function TokenValue({ value }) {
const { symbol } = useChainSettings();
return (
<div className="flex gap-[4px]">
<span className="text-textPrimary">{value}</span>
<span className="text-textSecondary">{symbol}</span>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { SecondaryCard } from "next-common/components/styled/containers/secondaryCard";
import CardHeader from "./cardHeader";
import { Bar } from "react-chartjs-2";
import "chart.js/auto";
import { useBasicData } from "next-common/context/centrifuge/basicData";
import { useDailyExtrinsics } from "next-common/context/centrifuge/DailyExtrinsics";
import { bnToLocaleString } from "next-common/utils/bn";
import dayjs from "dayjs";
import Loading from "next-common/components/loading";
import { useThemeSetting } from "next-common/context/theme";

function BarChart({ data }) {
const options = {
responsive: true,
maintainAspectRatio: false,
interaction: {
intersect: false,
mode: "index",
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
plugins: {
legend: {
display: false,
},
},
};

return <Bar data={data} options={options} />;
}

export default function TransactionsCard() {
const { data: { signedExtrinsicCount = 0 } = {} } = useBasicData();
const { data: dailyExtrinsics = [], loading: isLoading } =
useDailyExtrinsics();
const themeSettings = useThemeSetting();

const chartContent = (
<div className="relative h-[72px]">
<BarChart
data={{
labels: dailyExtrinsics.map((extrinsic, index) => {
const label = dayjs(extrinsic.startTime * 1000).format(
"YYYY-MM-DD HH:mm",
);

if (index === dailyExtrinsics.length - 1) {
return label + " ~ now";
} else {
return (
label +
" ~ " +
dayjs(dailyExtrinsics[index + 1].startTime * 1000).format(
"YYYY-MM-DD HH:mm",
)
);
}
}),
datasets: [
{
label: "Signed extrinsics",
data: dailyExtrinsics.map((extrinsic) => extrinsic.count),
backgroundColor: themeSettings.theme500,
barPercentage: 0.5,
},
],
}}
/>
</div>
);

const loadingContent = (
<div className="flex justify-center items-center grow w-full">
<Loading size={24} />
</div>
);

return (
<SecondaryCard>
<div className="flex flex-col gap-[16px] h-full">
<CardHeader
title="Transactions"
value={bnToLocaleString(signedExtrinsicCount)}
/>
{isLoading ? loadingContent : chartContent}
</div>
</SecondaryCard>
);
}
Loading

0 comments on commit 99a91f8

Please sign in to comment.