kopia lustrzana https://github.com/bugout-dev/moonstream
move object forming in to card, remove switch
rodzic
e279e8268c
commit
6e9d5ef6ec
|
@ -4,192 +4,28 @@ import { Spinner, Flex, Heading, Stack } from "@chakra-ui/react";
|
|||
import Scrollable from "../src/components/Scrollable";
|
||||
import useNFTs from "../src/core/hooks/useNFTs";
|
||||
import RangeSelector from "../src/components/RangeSelector";
|
||||
import { TIME_RANGE_SECONDS } from "../src/core/constants";
|
||||
import StatsCard from "../src/components/StatsCard";
|
||||
import web3 from "web3";
|
||||
|
||||
const TIME_PERIOD = {
|
||||
current: 0,
|
||||
previous: 1,
|
||||
};
|
||||
const HOUR_KEY = "Hourly";
|
||||
const DAY_KEY = "Daily";
|
||||
const WEEK_KEY = "Weekly";
|
||||
let timeMap = {};
|
||||
timeMap[HOUR_KEY] = "hour";
|
||||
timeMap[DAY_KEY] = "day";
|
||||
timeMap[WEEK_KEY] = "week";
|
||||
|
||||
const Analytics = () => {
|
||||
const fromNNCtoDWM = (range) => {
|
||||
const timeMap = {
|
||||
"1h": "hour",
|
||||
"24h": "day",
|
||||
"7d": "week",
|
||||
"28d": "month",
|
||||
};
|
||||
|
||||
return timeMap[`${range}`];
|
||||
};
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
document.title = `Analytics: Page under construction`;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const [timeRange, setTimeRange] = useState("24h");
|
||||
const { nftCache } = useNFTs(TIME_RANGE_SECONDS[fromNNCtoDWM(timeRange)]);
|
||||
const [timeRange, setTimeRange] = useState(HOUR_KEY);
|
||||
const { nftCache } = useNFTs();
|
||||
|
||||
if (nftCache.isLoading) return <Spinner />;
|
||||
|
||||
const StatCardsData = {};
|
||||
|
||||
Object.keys(nftCache.data[TIME_PERIOD.current]).map((key) => {
|
||||
let value, prevValue, valueChange, share, prevShare, shareChange;
|
||||
if (key !== "crawled_at") {
|
||||
switch (key) {
|
||||
case "blocks":
|
||||
value =
|
||||
Number(
|
||||
nftCache.data[TIME_PERIOD.current][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].end
|
||||
) -
|
||||
Number(
|
||||
nftCache.data[TIME_PERIOD.current][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].start
|
||||
);
|
||||
prevValue =
|
||||
Number(
|
||||
nftCache.data[TIME_PERIOD.previous][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].end
|
||||
) -
|
||||
Number(
|
||||
nftCache.data[TIME_PERIOD.previous][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].start
|
||||
);
|
||||
valueChange = (Math.abs(value - prevValue) * 100) / prevValue;
|
||||
StatCardsData[`${key}`] = {
|
||||
valueChange,
|
||||
value,
|
||||
label: `Blocks mined`,
|
||||
valueLabel: `${key}`,
|
||||
changeLabel: `${timeRange}%`,
|
||||
dimension: "#",
|
||||
netLabel: "Ethereum mainnet",
|
||||
};
|
||||
break;
|
||||
case "transactions":
|
||||
value = Number(
|
||||
nftCache.data[TIME_PERIOD.current][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].amount
|
||||
);
|
||||
prevValue = Number(
|
||||
nftCache.data[TIME_PERIOD.previous][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].amount
|
||||
);
|
||||
valueChange = (Math.abs(value - prevValue) * 100) / prevValue;
|
||||
value = value.toExponential(2);
|
||||
|
||||
share = Number(
|
||||
nftCache.data[TIME_PERIOD.current][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].percentage
|
||||
);
|
||||
|
||||
prevShare = Number(
|
||||
nftCache.data[TIME_PERIOD.previous][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].percentage
|
||||
);
|
||||
|
||||
shareChange = prevShare - share;
|
||||
|
||||
StatCardsData[`${key}`] = {
|
||||
valueChange,
|
||||
value,
|
||||
label: `Number of transactions`,
|
||||
valueLabel: `${key}`,
|
||||
changeLabel: `${timeRange}%`,
|
||||
dimension: "#",
|
||||
share,
|
||||
shareChange,
|
||||
netLabel: "Ethereum mainnet",
|
||||
};
|
||||
break;
|
||||
case "values":
|
||||
value = Number(
|
||||
web3.utils.fromWei(
|
||||
nftCache.data[TIME_PERIOD.current][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].amount,
|
||||
"ether"
|
||||
)
|
||||
);
|
||||
prevValue = Number(
|
||||
web3.utils.fromWei(
|
||||
nftCache.data[TIME_PERIOD.previous][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].amount,
|
||||
"ether"
|
||||
)
|
||||
);
|
||||
|
||||
share = Number(
|
||||
nftCache.data[TIME_PERIOD.current][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].percentage
|
||||
);
|
||||
|
||||
prevShare = Number(
|
||||
nftCache.data[TIME_PERIOD.previous][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].percentage
|
||||
);
|
||||
|
||||
shareChange = prevShare - share;
|
||||
|
||||
valueChange = (Math.abs(value - prevValue) * 100) / prevValue;
|
||||
|
||||
value = value.toExponential(2);
|
||||
StatCardsData[`${key}`] = {
|
||||
valueChange,
|
||||
value,
|
||||
label: `Value of transactions`,
|
||||
valueLabel: `${key}`,
|
||||
changeLabel: `${timeRange}%`,
|
||||
dimension: "Eth",
|
||||
share,
|
||||
shareChange,
|
||||
netLabel: "Ethereum mainnet",
|
||||
};
|
||||
break;
|
||||
case "mints":
|
||||
value = Number(
|
||||
nftCache.data[TIME_PERIOD.current][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].amount
|
||||
);
|
||||
prevValue = Number(
|
||||
nftCache.data[TIME_PERIOD.previous][`${key}`][
|
||||
fromNNCtoDWM(timeRange)
|
||||
].amount
|
||||
);
|
||||
valueChange = (Math.abs(value - prevValue) * 100) / prevValue;
|
||||
value = value.toExponential(2);
|
||||
StatCardsData[`${key}`] = {
|
||||
valueChange,
|
||||
value,
|
||||
label: `NFTs minted`,
|
||||
valueLabel: `${key}`,
|
||||
changeLabel: `${timeRange}%`,
|
||||
dimension: "#",
|
||||
netLabel: "Ethereum mainnet",
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<Scrollable>
|
||||
<Flex
|
||||
|
@ -207,25 +43,39 @@ const Analytics = () => {
|
|||
<RangeSelector
|
||||
placeSelf="flex-start"
|
||||
initialRange={timeRange}
|
||||
ranges={["1h", "24h", "7d"]}
|
||||
ranges={Object.keys(timeMap)}
|
||||
onChange={(e) => setTimeRange(e)}
|
||||
/>
|
||||
<Stack
|
||||
direction="row"
|
||||
wrap="wrap"
|
||||
w="100%"
|
||||
py={12}
|
||||
wrap="wrap"
|
||||
my={12}
|
||||
h="auto"
|
||||
spacing={6}
|
||||
direction="row"
|
||||
minW="240px"
|
||||
spacing={[2, 0, null]}
|
||||
boxShadow="md"
|
||||
borderRadius="lg"
|
||||
bgColor="gray.100"
|
||||
>
|
||||
{Object.keys(StatCardsData).map((key, idx) => {
|
||||
return (
|
||||
<StatsCard
|
||||
key={`nft-stat-card-${key}-${idx}`}
|
||||
{...StatCardsData[`${key}`]}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<StatsCard
|
||||
labelKey="transactions"
|
||||
timeRange={timeMap[timeRange]}
|
||||
netLabel="Ethereum mainnet"
|
||||
label="Number of transactions"
|
||||
/>
|
||||
<StatsCard
|
||||
labelKey="values"
|
||||
timeRange={timeMap[timeRange]}
|
||||
netLabel="Ethereum mainnet"
|
||||
label="Value of transactions"
|
||||
/>
|
||||
<StatsCard
|
||||
labelKey="mints"
|
||||
timeRange={timeMap[timeRange]}
|
||||
netLabel="Ethereum mainnet"
|
||||
label="Minted NFTs"
|
||||
/>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Scrollable>
|
||||
|
|
|
@ -1,32 +1,105 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Stack, Text, chakra, Box, SimpleGrid } from "@chakra-ui/react";
|
||||
import { Stack, Text, chakra, Box, SimpleGrid, Link } from "@chakra-ui/react";
|
||||
import { TriangleDownIcon, TriangleUpIcon } from "@chakra-ui/icons";
|
||||
import useNFTs from "../core/hooks/useNFTs";
|
||||
import web3 from "web3";
|
||||
|
||||
const StatsCard_ = ({
|
||||
className,
|
||||
value,
|
||||
valueChange,
|
||||
label,
|
||||
netLabel,
|
||||
dimension,
|
||||
share,
|
||||
shareChange,
|
||||
}) => {
|
||||
const [isValueIncrease, setIsValueIncrease] = useState(
|
||||
Number(valueChange) > 0 ? true : false
|
||||
);
|
||||
const [isShareIncrease, setIsShareIncrease] = useState(
|
||||
Number(shareChange) > 0 ? true : false
|
||||
);
|
||||
const TIME_PERIOD = {
|
||||
current: 0,
|
||||
previous: 1,
|
||||
};
|
||||
|
||||
const isNumberNotZero = (str) => {
|
||||
if (isNaN(Number(str) || Number(str) == 0)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const getEthValue = (string) => {
|
||||
const ether = web3.utils.fromWei(string, "ether");
|
||||
return nFormatter(ether, 3);
|
||||
};
|
||||
|
||||
const nFormatter = (num, digits) => {
|
||||
const lookup = [
|
||||
{ value: 1, symbol: "" },
|
||||
{ value: 1e3, symbol: "k" },
|
||||
{ value: 1e6, symbol: "M" },
|
||||
{ value: 1e9, symbol: "G" },
|
||||
{ value: 1e12, symbol: "T" },
|
||||
{ value: 1e15, symbol: "P" },
|
||||
{ value: 1e18, symbol: "E" },
|
||||
];
|
||||
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||
var item = lookup
|
||||
.slice()
|
||||
.reverse()
|
||||
.find(function (item) {
|
||||
return num >= item.value;
|
||||
});
|
||||
return item
|
||||
? (num / item.value).toFixed(digits).replace(rx, "$1") + item.symbol
|
||||
: "0";
|
||||
};
|
||||
|
||||
const getChange = (a, b) => {
|
||||
if (isNumberNotZero(a) && isNumberNotZero(b)) {
|
||||
let retval = (Math.abs(Number(a) - Number(b)) * 100) / Number(b);
|
||||
retval = retval > 9999 ? nFormatter(retval, 3) : retval;
|
||||
return retval.toFixed(2);
|
||||
} else {
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
|
||||
const getDiff = (a, b) => {
|
||||
if (isNaN(a) || isNaN(b)) {
|
||||
return "-";
|
||||
} else {
|
||||
return Number(a) - Number(b);
|
||||
}
|
||||
};
|
||||
|
||||
const getSign = (a) => {
|
||||
if (isNaN(a)) return "-";
|
||||
return Number(a) >= 0 ? true : false;
|
||||
};
|
||||
const StatsCard_ = ({ className, label, netLabel, labelKey, timeRange }) => {
|
||||
const { nftCache } = useNFTs();
|
||||
|
||||
const [nftData, setData] = useState();
|
||||
|
||||
useEffect(() => {
|
||||
setIsValueIncrease(Number(valueChange) > 0 ? true : false);
|
||||
}, [valueChange]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsShareIncrease(Number(shareChange) > 0 ? true : false);
|
||||
}, [shareChange]);
|
||||
if (nftCache.data[TIME_PERIOD.current][labelKey][timeRange]) {
|
||||
const cacheData = nftCache.data[TIME_PERIOD.current][labelKey][timeRange];
|
||||
const prevCacheData =
|
||||
nftCache.data[TIME_PERIOD.previous][labelKey][timeRange];
|
||||
const valueChange = getChange(cacheData.amount, prevCacheData.amount);
|
||||
const share = isNaN(cacheData.percentage)
|
||||
? "-"
|
||||
: Number(cacheData.percentage).toFixed(2);
|
||||
const shareChange = getDiff(
|
||||
cacheData.percentage,
|
||||
prevCacheData.percentage
|
||||
);
|
||||
|
||||
setData({
|
||||
dimension: labelKey === "values" ? "Eth" : "#",
|
||||
isValueIncrease: getSign(valueChange),
|
||||
isShareIncrease: getSign(shareChange),
|
||||
valueChange,
|
||||
shareChange,
|
||||
share,
|
||||
value:
|
||||
labelKey === "values"
|
||||
? getEthValue(cacheData.amount)
|
||||
: nFormatter(cacheData.amount, 3),
|
||||
});
|
||||
}
|
||||
}, [nftCache?.data, nftCache.isLoading, labelKey, timeRange]);
|
||||
if (nftCache.isLoading || !nftData) return "";
|
||||
|
||||
return (
|
||||
<Stack className={className}>
|
||||
|
@ -34,7 +107,6 @@ const StatsCard_ = ({
|
|||
w="full"
|
||||
borderTopRadius="inherit"
|
||||
fontWeight="600"
|
||||
autoCapitalize
|
||||
bgColor="gray.200"
|
||||
px={4}
|
||||
textAlign="center"
|
||||
|
@ -57,8 +129,17 @@ const StatsCard_ = ({
|
|||
// alignItems="center"
|
||||
h="100%"
|
||||
>
|
||||
<Text>
|
||||
{dimension} {value}
|
||||
<Link
|
||||
textDecorationLine="underline"
|
||||
textDecorationStyle="dashed"
|
||||
textUnderlineOffset={2}
|
||||
boxDecorationBreak="slice"
|
||||
textDecorationThickness="1px"
|
||||
>
|
||||
{nftData.value}
|
||||
</Link>
|
||||
<Text pl={2} display="inline-block">
|
||||
{nftData.dimension}
|
||||
</Text>
|
||||
</Box>
|
||||
<Stack
|
||||
|
@ -68,16 +149,15 @@ const StatsCard_ = ({
|
|||
placeContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
{isValueIncrease && <TriangleUpIcon color="suggested.900" />}
|
||||
{!isValueIncrease && <TriangleDownIcon color="unsafe.900" />}
|
||||
<Text textColor={isValueIncrease ? "suggested.900" : "unsafe.900"}>
|
||||
{Math.abs(valueChange) > 9999
|
||||
? valueChange.toExponential(2)
|
||||
: Math.round((valueChange + Number.EPSILON) * 100) / 100}
|
||||
%
|
||||
{nftData.isValueIncrease && <TriangleUpIcon color="suggested.900" />}
|
||||
{!nftData.isValueIncrease && <TriangleDownIcon color="unsafe.900" />}
|
||||
<Text
|
||||
textColor={nftData.isValueIncrease ? "suggested.900" : "unsafe.900"}
|
||||
>
|
||||
{Math.abs(nftData.valueChange)}%
|
||||
</Text>
|
||||
</Stack>
|
||||
{share && shareChange && (
|
||||
{nftData.share !== "-" && nftData.shareChange !== "-" && (
|
||||
<>
|
||||
<Text
|
||||
w="100%"
|
||||
|
@ -89,19 +169,20 @@ const StatsCard_ = ({
|
|||
>
|
||||
Total share in {netLabel}
|
||||
</Text>
|
||||
<Text>
|
||||
{(Math.round((share + Number.EPSILON) * 100) / 100).toFixed(2)}%
|
||||
</Text>
|
||||
<Text>{nftData.share}%</Text>
|
||||
<Stack direction="row" placeContent="center" alignItems="center">
|
||||
{isShareIncrease && <TriangleUpIcon color="suggested.900" />}
|
||||
{!isShareIncrease && <TriangleDownIcon color="unsafe.900" />}
|
||||
{nftData.isShareIncrease && (
|
||||
<TriangleUpIcon color="suggested.900" />
|
||||
)}
|
||||
{!nftData.isShareIncrease && (
|
||||
<TriangleDownIcon color="unsafe.900" />
|
||||
)}
|
||||
<Text
|
||||
textColor={isShareIncrease ? "suggested.900" : "unsafe.900"}
|
||||
textColor={
|
||||
nftData.isShareIncrease ? "suggested.900" : "unsafe.900"
|
||||
}
|
||||
>
|
||||
{(
|
||||
Math.round((shareChange + Number.EPSILON) * 100) / 100
|
||||
).toFixed(2)}
|
||||
%
|
||||
{nftData.shareChange}%
|
||||
</Text>
|
||||
</Stack>
|
||||
</>
|
||||
|
@ -113,11 +194,13 @@ const StatsCard_ = ({
|
|||
|
||||
const StatsCard = chakra(StatsCard_, {
|
||||
baseStyle: {
|
||||
boxShadow: "md",
|
||||
borderRadius: "lg",
|
||||
bgColor: "gray.100",
|
||||
borderStyle: "solid",
|
||||
borderRightWidth: "1px",
|
||||
borderRightColor: "gray.600",
|
||||
w: "240px",
|
||||
minW: "240px",
|
||||
flexBasis: "240px",
|
||||
flexGrow: 1,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue