From 7285fec704a41766a5a8a285a4aa0ff994cfccf8 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 6 Jan 2023 13:21:16 +0000 Subject: [PATCH] Vault performance chart adjustments and readme. --- .../front-end/src/components/VaultChart.tsx | 144 ------------------ .../src/components/VaultPerformance.tsx | 11 -- .../src/components/VaultPerformance/README.md | 5 + .../VaultPerformance/VaultPerformance.tsx | 94 ++++++++++++ .../VaultPerformance.types.ts | 30 ++++ .../VaultPerformance/subcomponents/Chart.tsx | 67 ++++++++ .../subcomponents/Disclaimer.tsx | 11 ++ .../VaultPerformance/subcomponents/Error.tsx | 3 + .../subcomponents/FadeWrapper.tsx | 16 ++ .../subcomponents/Loading.tsx | 7 + .../VaultPerformance/subcomponents/Stats.tsx | 6 + .../front-end/src/components/VaultStats.tsx | 94 ------------ packages/front-end/src/utils/rounding.ts | 3 + 13 files changed, 242 insertions(+), 249 deletions(-) delete mode 100644 packages/front-end/src/components/VaultChart.tsx delete mode 100644 packages/front-end/src/components/VaultPerformance.tsx create mode 100644 packages/front-end/src/components/VaultPerformance/README.md create mode 100644 packages/front-end/src/components/VaultPerformance/VaultPerformance.tsx create mode 100644 packages/front-end/src/components/VaultPerformance/VaultPerformance.types.ts create mode 100644 packages/front-end/src/components/VaultPerformance/subcomponents/Chart.tsx create mode 100644 packages/front-end/src/components/VaultPerformance/subcomponents/Disclaimer.tsx create mode 100644 packages/front-end/src/components/VaultPerformance/subcomponents/Error.tsx create mode 100644 packages/front-end/src/components/VaultPerformance/subcomponents/FadeWrapper.tsx create mode 100644 packages/front-end/src/components/VaultPerformance/subcomponents/Loading.tsx create mode 100644 packages/front-end/src/components/VaultPerformance/subcomponents/Stats.tsx delete mode 100644 packages/front-end/src/components/VaultStats.tsx create mode 100644 packages/front-end/src/utils/rounding.ts diff --git a/packages/front-end/src/components/VaultChart.tsx b/packages/front-end/src/components/VaultChart.tsx deleted file mode 100644 index d28e083237..0000000000 --- a/packages/front-end/src/components/VaultChart.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import React, { useState } from "react"; -import { gql, useQuery } from "@apollo/client"; -import NumberFormat from "react-number-format"; -import { - LineChart, - Line, - CartesianGrid, - XAxis, - YAxis, - Tooltip, - ResponsiveContainer, - Legend, -} from "recharts"; - -interface CustomTooltipT { - active?: boolean; - payload?: Array<{ - value: string; - length: number; - payload: { epoch: Array }; - }>; - label?: string; -} - -const CustomTooltip = ({ active, payload, label }: CustomTooltipT) => { - if (label && active && payload && payload.length) { - const date = new Date(parseInt(label) * 1000); - return ( -
-

- {date.toLocaleString("default", { - month: "short", - day: "2-digit", - year: "2-digit", - })} -

-

- Yield :{" "} - -

-

Epoch : {payload[0].payload.epoch.toString()}

-
- ); - } - - return null; -}; - -export const VaultChart = () => { - const [pricePerShares, setPricePerShares] = useState(); - - useQuery( - gql` - query { - pricePerShares(first: 1000) { - id - epoch - value - growthSinceFirstEpoch - timestamp - } - } - `, - { - onCompleted: (data) => { - const refinedData: any = - data?.pricePerShares?.length > 0 - ? new Array(data.pricePerShares.length) - : []; - - data.pricePerShares.map((ppsEpoch: any) => { - const dateLocale = new Date( - parseInt(ppsEpoch.timestamp) * 1000 - ).toLocaleString("default", { - month: "numeric", - day: "numeric", - year: "numeric", - }); - - refinedData[+ppsEpoch.id - 1] = { - epoch: ppsEpoch.id, - // @reminder: For presentation it's ok but reminder that number of float decimals is 17 - growthSinceFirstEpoch: parseFloat(ppsEpoch.growthSinceFirstEpoch), - timestamp: ppsEpoch.timestamp, - dateLocale, - }; - }); - - setPricePerShares(refinedData); - }, - onError: (err) => { - console.log(err); - }, - } - ); - - return ( -
-
- - - - - { - const date = new Date(parseInt(value) * 1000); - return date.toLocaleString("default", { - month: "short", - day: "2-digit", - }); - }} - /> - - } /> - "Cumulative Yield"} - /> - - -
-
- ); -}; diff --git a/packages/front-end/src/components/VaultPerformance.tsx b/packages/front-end/src/components/VaultPerformance.tsx deleted file mode 100644 index 6cb69d4bf5..0000000000 --- a/packages/front-end/src/components/VaultPerformance.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { VaultStats } from "./VaultStats"; -import { VaultChart } from "./VaultChart"; - -export const VaultPerformance = () => { - return ( -
- - -
- ); -}; diff --git a/packages/front-end/src/components/VaultPerformance/README.md b/packages/front-end/src/components/VaultPerformance/README.md new file mode 100644 index 0000000000..9d75591b8e --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/README.md @@ -0,0 +1,5 @@ +# Vault performance chart component + +The vault performance chart is made up of a series of subcomponents with a single graph query at the top. This query accesses the `pricePerShares` graph data, skipping the first two entries. This is because the first two epochs were used for testing and pre-public launch. + +An effect in the main `VaultPerformance` component handles adjusting each of the epoch nodes by deducting the growth percentage at the third epoch from each subsequent epoch. This allows us to display chart data from the public launch, corrected as if the third epoch were zero percent. diff --git a/packages/front-end/src/components/VaultPerformance/VaultPerformance.tsx b/packages/front-end/src/components/VaultPerformance/VaultPerformance.tsx new file mode 100644 index 0000000000..fe7ccd523d --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/VaultPerformance.tsx @@ -0,0 +1,94 @@ +import type { QueryData, ChartData } from "./VaultPerformance.types"; + +import { gql, useQuery } from "@apollo/client"; +import { captureException } from "@sentry/react"; +import { useState, useEffect } from "react"; +import { AnimatePresence } from "framer-motion"; + +import { toTwoDecimalPlaces } from "src/utils/rounding"; + +import { Chart } from "./subcomponents/Chart"; +import { Disclaimer } from "./subcomponents/Disclaimer"; +import { Error } from "./subcomponents/Error"; +import { Loading } from "./subcomponents/Loading"; +import { FadeWrapper } from "./subcomponents/FadeWrapper"; +import { Stats } from "./subcomponents/Stats"; + +export const VaultPerformance = () => { + const [chartData, setChartData] = useState([]); + + const { loading, error, data } = useQuery( + gql` + query { + pricePerShares( + orderBy: "epoch" + orderDirection: "asc" + first: 1000 + skip: 2 + ) { + epoch + growthSinceFirstEpoch + timestamp + } + } + `, + { + onError: (err) => { + captureException(err); + console.error(err); + }, + } + ); + + useEffect(() => { + if (data) { + const { pricePerShares } = data; + + const publicLaunchOffset = parseFloat( + pricePerShares[0].growthSinceFirstEpoch + ); + + const adjustedChartData = pricePerShares.map((pricePoint) => { + const pricePointGrowth = parseFloat(pricePoint.growthSinceFirstEpoch); + const growthSinceFirstEpoch = toTwoDecimalPlaces( + pricePointGrowth - publicLaunchOffset + ); + + return { + ...pricePoint, + growthSinceFirstEpoch, + }; + }); + + setChartData(adjustedChartData); + } + }, [data]); + + return ( + + {loading && ( + + + + )} + + {error && ( + + + + )} + + {data && ( + + + + + + )} + + ); +}; diff --git a/packages/front-end/src/components/VaultPerformance/VaultPerformance.types.ts b/packages/front-end/src/components/VaultPerformance/VaultPerformance.types.ts new file mode 100644 index 0000000000..f2f4673583 --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/VaultPerformance.types.ts @@ -0,0 +1,30 @@ +interface PricePerShareEpoch { + epoch: string; + growthSinceFirstEpoch: string; + timestamp: string; + __typename: string; +} + +export interface QueryData { + pricePerShares: PricePerShareEpoch[]; +} + +export interface ChartData + extends Omit { + growthSinceFirstEpoch: number; +} + +export interface CustomTooltipProps { + active?: boolean; + payload?: [ + { + value: string; + payload: { epoch: string }; + } + ]; + label?: string; +} + +export interface ChartProps { + chartData: ChartData[]; +} diff --git a/packages/front-end/src/components/VaultPerformance/subcomponents/Chart.tsx b/packages/front-end/src/components/VaultPerformance/subcomponents/Chart.tsx new file mode 100644 index 0000000000..4d598e9780 --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/subcomponents/Chart.tsx @@ -0,0 +1,67 @@ +import type { ChartProps, CustomTooltipProps } from "../VaultPerformance.types"; + +import dayjs from "dayjs"; +import { + LineChart, + Line, + CartesianGrid, + XAxis, + YAxis, + Tooltip, + ResponsiveContainer, + Legend, +} from "recharts"; + +const CustomTooltip = ({ active, payload, label }: CustomTooltipProps) => { + if (label && active && payload && payload.length) { + return ( +
+

{dayjs.unix(parseInt(label)).format("DD MMM YY")}

+

{`Yield: ${payload[0].value}%`}

+

{`Epoch: ${payload[0].payload.epoch}`}

+
+ ); + } + + return null; +}; + +export const Chart = ({ chartData }: ChartProps) => ( +
+ + + + + + dayjs.unix(parseInt(value)).format("DD MMM") + } + /> + `${value}%`} /> + } /> + "Cumulative Yield"} /> + + +
+); diff --git a/packages/front-end/src/components/VaultPerformance/subcomponents/Disclaimer.tsx b/packages/front-end/src/components/VaultPerformance/subcomponents/Disclaimer.tsx new file mode 100644 index 0000000000..1d237358df --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/subcomponents/Disclaimer.tsx @@ -0,0 +1,11 @@ +import { DHV_NAME } from "src/config/constants"; +import { DISCORD_LINK } from "src/config/links"; + +export const Disclaimer = () => ( + + {`This chart shows the ${DHV_NAME} share price change since the third epoch (Alpha public launch). Data before this is the result of testing and is excluded. If you have any questions, feel free to `} + + {`reach out to us via our Discord.`} + + +); diff --git a/packages/front-end/src/components/VaultPerformance/subcomponents/Error.tsx b/packages/front-end/src/components/VaultPerformance/subcomponents/Error.tsx new file mode 100644 index 0000000000..d73556dd3b --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/subcomponents/Error.tsx @@ -0,0 +1,3 @@ +export const Error = () => ( +

{`Sorry but we're having difficult fetching that data right now. Please try again later.`}

+); diff --git a/packages/front-end/src/components/VaultPerformance/subcomponents/FadeWrapper.tsx b/packages/front-end/src/components/VaultPerformance/subcomponents/FadeWrapper.tsx new file mode 100644 index 0000000000..ce8324a7a6 --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/subcomponents/FadeWrapper.tsx @@ -0,0 +1,16 @@ +import type { PropsWithChildren } from "react"; + +import { motion } from "framer-motion"; + +const FadeInOut = { + initial: { opacity: 0 }, + animate: { + opacity: 1, + transition: { duration: 0.3, ease: [0.0, 0.0, 0.2, 1] }, + }, + exit: { opacity: 0, transition: { duration: 0.25, ease: [0.4, 0.0, 1, 1] } }, +}; + +export const FadeWrapper = ({ children }: PropsWithChildren) => ( + {children} +); diff --git a/packages/front-end/src/components/VaultPerformance/subcomponents/Loading.tsx b/packages/front-end/src/components/VaultPerformance/subcomponents/Loading.tsx new file mode 100644 index 0000000000..a1e869b3a5 --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/subcomponents/Loading.tsx @@ -0,0 +1,7 @@ +import { Loader } from "src/components/Loader"; + +export const Loading = () => ( +
+ +
+); diff --git a/packages/front-end/src/components/VaultPerformance/subcomponents/Stats.tsx b/packages/front-end/src/components/VaultPerformance/subcomponents/Stats.tsx new file mode 100644 index 0000000000..8dee479779 --- /dev/null +++ b/packages/front-end/src/components/VaultPerformance/subcomponents/Stats.tsx @@ -0,0 +1,6 @@ +export const Stats = ({ cumulativeYield = 0 }: { cumulativeYield: number }) => ( +
+

{`Cumulative Yield: ${cumulativeYield}%`}

+

{`Projected APY: Soon™️`}

+
+); diff --git a/packages/front-end/src/components/VaultStats.tsx b/packages/front-end/src/components/VaultStats.tsx deleted file mode 100644 index fc895457c3..0000000000 --- a/packages/front-end/src/components/VaultStats.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React, { useState } from "react"; -import NumberFormat from "react-number-format"; -// import { Card } from "./shared/Card"; -// import ReactTooltip from "react-tooltip"; -import { RyskTooltip } from "./RyskTooltip"; -import { DHV_NAME } from "../config/constants"; -import { gql, useQuery } from "@apollo/client"; - -export const VaultStats = () => { - const [cumulativePricePerShares, setCumulativeSinceFirstEpoch] = - useState(); - - // TODO Could remove as We are also querying all of the price per shares in Vault Chart - useQuery( - gql` - query { - pricePerShares(orderBy: "timestamp", orderDirection: "desc", first: 1) { - id - epoch - value - growthSinceFirstEpoch - timestamp - } - } - `, - { - onCompleted: (data) => { - const growthSinceFirstEpoch = data?.pricePerShares[0] - ? data.pricePerShares[0].growthSinceFirstEpoch - : 0; - growthSinceFirstEpoch && - setCumulativeSinceFirstEpoch(parseFloat(growthSinceFirstEpoch)); - }, - onError: (err) => { - console.log(err); - }, - } - ); - return ( -
-
-
-

- Cumulative Yield:{" "} - - -

- {/* - Learn more - */} -
-
-

- Projected APY: {/** // TODO clean up if not used */} - {/* - */} - Soon™️ -

- {/* - Learn more - */} -
-
-
- ); -}; diff --git a/packages/front-end/src/utils/rounding.ts b/packages/front-end/src/utils/rounding.ts new file mode 100644 index 0000000000..2670db8bd2 --- /dev/null +++ b/packages/front-end/src/utils/rounding.ts @@ -0,0 +1,3 @@ +export const toTwoDecimalPlaces = (number: number) => { + return Math.round(number * 100) / 100; +};