Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • webapp/webapp_l02_grp15
1 result
Show changes
Commits on Source (9)
......@@ -16,7 +16,7 @@ import PropTypes from "prop-types";
*/
function ToggleButton({ children, setActive, active, id, className, tooltip }) {
return (
<div className="has-tooltip flex flex-col items-center">
<div className="has-tooltip flex flex-col items-center relative">
<Button
className={classNames(
"px-3 py-2 rounded-md font-light",
......@@ -35,7 +35,7 @@ function ToggleButton({ children, setActive, active, id, className, tooltip }) {
{tooltip && (
<span
className={classNames(
"tooltip absolute rounded-lg shadow-lg px-3 py-2 mt-11",
"tooltip absolute rounded-lg shadow-lg px-3 py-2 mt-11 w-max",
{
"bg-dark-900 dark:bg-white text-gray-100 dark:text-gray-800":
active === id,
......
......@@ -31,12 +31,14 @@ const reorderCandlestickData = (data) => {
return newData;
};
function CompareChart() {
function CompareChart({ singleChart, selectionDisabled, selectedCurrency }) {
const [timerange, setTimerange] = useState("6month");
const [chartType, setChartType] = useState("line");
const chartRef = useRef(null);
const listOfCoins = useCryptoList("usd", 21, false);
const [firstCrypto, setFirstCrypto] = useState("solana");
const [firstCrypto, setFirstCrypto] = useState(
selectedCurrency ? selectedCurrency : "solana"
);
const [secondCrypto, setSecondCrypto] = useState("avalanche-2");
const cryptoQuery = useCryptoTimeSeriesRangeData(
firstCrypto,
......@@ -110,20 +112,20 @@ function CompareChart() {
itemStyle:
chartType === "candlestick"
? {
color: "rgba(85, 69, 255, 1)",
color0: "rgba(255, 114, 147, 1)",
borderColor: "rgba(85, 69, 255, 1)",
borderColor0: "rgba(255, 114, 147, 1)",
color0: "#DE5E57",
color: "#51A49A",
borderColor0: "#DE5E57",
borderColor: "#51A49A",
}
: undefined,
},
{
type: chartType,
data:
chartType === "candlestick" && cryptoQuery2.data
? reorderCandlestickData(cryptoQuery2.data)
: cryptoQuery2.data?.prices,
data: singleChart
? null
: chartType === "candlestick" && cryptoQuery2.data
? reorderCandlestickData(cryptoQuery2.data)
: cryptoQuery2.data?.prices,
name: secondCrypto,
smooth: true,
symbol: chartType === "scatter" ? "circle" : "none",
......@@ -139,10 +141,10 @@ function CompareChart() {
itemStyle:
chartType === "candlestick"
? {
color0: "#c23531",
color: "rgba(0, 235, 82, 1)",
borderColor0: "#c23531",
borderColor: "rgba(0, 235, 82, 1)",
color: "rgba(85, 69, 255, 1)",
color0: "#EE7147",
borderColor: "rgba(85, 69, 255, 1)",
borderColor0: "#EE7147",
}
: undefined,
},
......@@ -237,22 +239,23 @@ function CompareChart() {
<FcCandleSticks size={"1.6em"} />
</ToggleButton>
</div>
<div className="flex flex-row space-x-3 sm:space-x-6 md:space-x-10 xl:space-x-3 items-center">
<Dropdown
list={listOfCoins.isLoading ? [] : listOfCoins.data}
value={firstCrypto}
setValue={setFirstCrypto}
disabled={[secondCrypto]}
/>
<ChevronDoubleRightIcon className="w-5 h-5 dark:text-gray-300" />
<Dropdown
list={listOfCoins.isLoading ? [] : listOfCoins.data}
value={secondCrypto}
setValue={setSecondCrypto}
disabled={[firstCrypto]}
/>
</div>
{!selectionDisabled && (
<div className="flex flex-row space-x-3 sm:space-x-6 md:space-x-10 xl:space-x-3 items-center">
<Dropdown
list={listOfCoins.isLoading ? [] : listOfCoins.data}
value={firstCrypto}
setValue={setFirstCrypto}
disabled={[secondCrypto]}
/>
<ChevronDoubleRightIcon className="w-5 h-5 dark:text-gray-300" />
<Dropdown
list={listOfCoins.isLoading ? [] : listOfCoins.data}
value={secondCrypto}
setValue={setSecondCrypto}
disabled={[firstCrypto]}
/>
</div>
)}
</div>
<div className="h-[600px] mt-10">
<ReactECharts
......
......@@ -4,6 +4,7 @@ import Link from "next/link";
import React, { useState } from "react";
import classnames from "classnames";
import { useRouter } from "next/router";
import classNames from "classnames";
function Navbar() {
const [open, setOpen] = useState(false);
......@@ -19,15 +20,34 @@ function Navbar() {
>
<div className="container flex flex-wrap justify-between items-center mx-auto pl-1 pr-2">
<Link href="/">
<a>
<Image
src="/crypto_mobile_logo.png"
width="50%"
height="40%"
objectFit="contain"
alt="CryptoMetrics Icon"
priority={true}
/>
<a className="relative h-10 w-10">
<span className="absolute left-0">
<Image
src="/usd_side.png"
width="100%"
height="100%"
objectFit="contain"
alt="CryptoMetrics Icon"
priority={true}
className={classNames("transition-all duration-200", {
"opacity-100": open,
"opacity-0": !open,
})}
/>
</span>
<span className="absolute left-0">
<Image
src="/usd_front.png"
width="100%"
height="100%"
objectFit="contain"
alt="CryptoMetrics Icon"
priority={true}
className={classNames("transition-all duration-200", {
"opacity-0": open,
})}
/>
</span>
</a>
</Link>
<button onClick={() => setOpen((open) => !open)}>
......
......@@ -24,6 +24,7 @@
"react-apexcharts": "^1.3.9",
"react-dom": "17.0.2",
"react-highlight-words": "^0.17.0",
"react-html-parser": "^2.0.2",
"react-icons": "^4.3.1",
"react-query": "^3.34.15",
"react-transition-group": "^4.4.2",
......
import React from "react";
import Head from "next/head";
import Sidebar from "../../components/sidebar/Sidebar";
import axios from "axios";
import Navbar from "../../components/navbar/Navbar";
import Wrapper from "../../components/content/Wrapper";
import BoldGradientHeading from "../../components/titles/BoldGradientHeading";
import ErrorPage from "next/error";
import Main from "../../components/content/Main";
import Container from "../../components/content/Container";
import { useCryptoDetail } from "../../queries";
import CompareChart from "../../components/charts/CompareChart";
import ReactHtmlParser from "react-html-parser";
import numeral from "numeral";
import classNames from "classnames";
import PlaceholderSkeleton from "../../components/skeletons/PlaceholderSkeleton";
export default function DetailPage({ errorStatus, cryptocurrency }) {
const coinDetail = useCryptoDetail(cryptocurrency);
if (errorStatus) {
return <ErrorPage statusCode={errorStatus} />;
}
return (
<div>
<Head>
<title>CryptoMetrics</title>
<meta name="description" content="CryptoMetrics" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Navbar />
<Wrapper>
<Sidebar />
<Main>
<Container>
{/* Header */}
<div className="flex flex-row justify-between mb-4">
{/* Main Project Title */}
<BoldGradientHeading>
{coinDetail.data?.name ? (
coinDetail.data?.name
) : (
<PlaceholderSkeleton className="h-7 w-52" />
)}
</BoldGradientHeading>
</div>
<div className="flex flex-row flex-wrap justify-around xl:flex-nowrap bg-white dark:bg-dark-600 shadow-lg rounded-3xl py-4 px-4 space-x-4 font-poppins mb-4">
<div className="flex flex-col hover:bg-gray-100 dark:hover:bg-dark-900 justify-center items-center p-4 rounded-2xl w-[10%] min-w-fit">
<p className="dark:text-white text-3xl font-semibold">
{coinDetail.data?.name ? (
coinDetail.data?.symbol?.toUpperCase()
) : (
<PlaceholderSkeleton className="h-7 w-20" />
)}
</p>
<p className="dark:text-white text-sm font-light">
{coinDetail.data?.name ? (
coinDetail.data?.name
) : (
<PlaceholderSkeleton className="h-3 w-16" />
)}
</p>
</div>
<div className="flex flex-col hover:bg-gray-100 dark:hover:bg-dark-900 justify-center items-center p-4 rounded-2xl w-[20%] min-w-fit">
<p className="dark:text-indigo-500 text-3xl font-semibold">
{coinDetail.data?.market_data?.current_price?.usd ? (
numeral(
coinDetail.data?.market_data?.current_price?.usd
).format("$0,0.[0000000]")
) : (
<PlaceholderSkeleton className="h-7 w-32" />
)}
</p>
<p className="dark:text-white text-sm font-light">USD</p>
</div>
<div className="flex flex-col hover:bg-gray-100 dark:hover:bg-dark-900 justify-center items-center p-4 rounded-2xl w-[20%] min-w-fit">
<p
className={classNames("text-3xl font-semibold", {
"text-green-500":
coinDetail.data?.market_data
?.price_change_percentage_24h >= 0,
"text-red-500":
coinDetail.data?.market_data
?.price_change_percentage_24h < 0,
})}
>
{coinDetail.data?.market_data ? (
numeral(
coinDetail.data?.market_data?.price_change_percentage_24h
).format("+0.0[00]%")
) : (
<PlaceholderSkeleton className="h-7 w-32" />
)}
</p>
<p className="dark:text-white text-sm font-light">
24h change %
</p>
</div>
<div className="flex flex-col hover:bg-gray-100 dark:hover:bg-dark-900 justify-center items-center p-4 rounded-2xl w-[20%] min-w-fit">
<p
className={classNames("text-3xl font-semibold", {
"text-green-500":
coinDetail.data?.market_data?.price_change_24h >= 0,
"text-red-500":
coinDetail.data?.market_data?.price_change_24h < 0,
})}
>
{coinDetail.data?.market_data?.price_change_24h ? (
numeral(
coinDetail.data?.market_data?.price_change_24h
).format("$0,0.[0000]")
) : (
<PlaceholderSkeleton className="h-7 w-32" />
)}
</p>
<p className="dark:text-white text-sm font-light">
24h change in $
</p>
</div>
<div className="flex flex-col hover:bg-gray-100 dark:hover:bg-dark-900 justify-center items-center p-4 rounded-2xl w-[30%] min-w-fit">
<p className="dark:text-white text-3xl font-semibold">
{coinDetail.data?.market_data?.total_volume?.usd ? (
numeral(
coinDetail.data?.market_data?.total_volume?.usd
).format("$0,0.[0000000]")
) : (
<PlaceholderSkeleton className="h-7 w-52" />
)}
</p>
<p className="dark:text-white text-sm font-light">
Total volume
</p>
</div>
</div>
<div className="text-white mb-4 bg-white dark:bg-dark-600 rounded-3xl p-4 shadow-lg">
<p className="text-black dark:text-white text-2xl font-semibold font-poppins px-4 pb-4">
Description
</p>
<p
className="text-black dark:text-white px-4"
id="crypto-description"
>
{coinDetail.data?.description?.en ? (
ReactHtmlParser(
coinDetail.data?.description?.en.replaceAll(
"https://www.coingecko.com/en/coins/",
"/coins/"
)
)
) : (
<span className="flex flex-col space-y-2">
<PlaceholderSkeleton className="h-7 w-full" />
<PlaceholderSkeleton className="h-7 w-11/12" />
<PlaceholderSkeleton className="h-7 w-10/12" />
<PlaceholderSkeleton className="h-7 w-9/12" />
</span>
)}
</p>
</div>
<CompareChart
singleChart={true}
selectionDisabled={true}
selectedCurrency={cryptocurrency}
/>
</Container>
</Main>
</Wrapper>
</div>
);
}
DetailPage.getInitialProps = async ({ query }) => {
let errorStatus = null;
const queryCoin = await axios
.get(
`https://api.coingecko.com/api/v3/coins/${query.coin}?localization=false&tickers=false&market_data=false&community_data=false&developer_data=false&sparkline=false`
)
.catch((err) => {
errorStatus = 404;
});
return {
cryptocurrency: query.coin,
errorStatus: errorStatus,
};
};
src/cryptometrics/public/usd_front.png

56.6 KiB

src/cryptometrics/public/usd_side.png

52.2 KiB

......@@ -72,3 +72,20 @@ export function useCryptoList(
}
);
}
export function useCryptoDetail(currencyId) {
return useQuery(
`${currencyId}-detail`,
() => {
return axios
.get(
`https://api.coingecko.com/api/v3/coins/${currencyId}?localization=false&tickers=false&market_data=true&community_data=false&developer_data=false&sparkline=false`
)
.then((res) => res.data);
},
{
refetchOnWindowFocus: false,
staleTime: 5 * 60000, // 5 minutes,
}
);
}
......@@ -48,6 +48,9 @@
transform: translateX(100%);
}
}
#crypto-description > a {
@apply text-blue-500 hover:text-blue-600;
}
}
#nprogress .bar {
......
......@@ -2221,6 +2221,14 @@ dom-helpers@^5.0.1:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
dom-serializer@0:
version "0.2.2"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==
dependencies:
domelementtype "^2.0.1"
entities "^2.0.0"
dom-serializer@^1.0.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
......@@ -2230,11 +2238,23 @@ dom-serializer@^1.0.1:
domhandler "^4.2.0"
entities "^2.0.0"
domelementtype@1, domelementtype@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
domelementtype@^2.0.1, domelementtype@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
domhandler@^2.3.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
dependencies:
domelementtype "1"
domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626"
......@@ -2242,6 +2262,14 @@ domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.0:
dependencies:
domelementtype "^2.2.0"
domutils@^1.5.1:
version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==
dependencies:
dom-serializer "0"
domelementtype "1"
domutils@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
......@@ -2319,6 +2347,11 @@ enquirer@^2.3.6:
dependencies:
ansi-colors "^4.1.1"
entities@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
entities@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
......@@ -3055,6 +3088,18 @@ htmlnano@^2.0.0:
posthtml "^0.16.5"
timsort "^0.3.0"
htmlparser2@^3.9.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
dependencies:
domelementtype "^1.3.1"
domhandler "^2.3.0"
domutils "^1.5.1"
entities "^1.1.1"
inherits "^2.0.1"
readable-stream "^3.1.1"
htmlparser2@^7.1.1:
version "7.2.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5"
......@@ -3130,7 +3175,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
......@@ -3749,16 +3794,16 @@ mdurl@^1.0.1:
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
memoize-one@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.1.0.tgz#a2387c58c03fff27ca390c31b764a79addf3f906"
integrity sha512-2GApq0yI/b22J2j9rhbrAlsHb0Qcz+7yWxeLG8h+95sl1XPUgeLimQSOdur4Vw7cUhrBHwaUZxWFZueojqNRzA==
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
merge2@^1.3.0, merge2@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
......@@ -4851,6 +4896,14 @@ react-highlight-words@^0.17.0:
highlight-words-core "^1.2.0"
memoize-one "^4.0.0"
prop-types "^15.5.8"
react-html-parser@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/react-html-parser/-/react-html-parser-2.0.2.tgz#6dbe1ddd2cebc1b34ca15215158021db5fc5685e"
integrity sha512-XeerLwCVjTs3njZcgCOeDUqLgNIt/t+6Jgi5/qPsO/krUWl76kWKXMeVs2LhY2gwM6X378DkhLjur0zUQdpz0g==
dependencies:
htmlparser2 "^3.9.0"
react-icons@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.3.1.tgz#2fa92aebbbc71f43d2db2ed1aed07361124e91ca"
......