:root{ | |
--text-primary:#000; | |
--bgPrimary:#fff; | |
--bgSecondary: #F9F9F9; | |
--pink: #0071bd; | |
--light-blue: #e6f7ff; | |
--border: #d9d9d9; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
a:hover{ | |
color: var(--pink) !important; | |
} | |
.app{ | |
display: flex; | |
overflow: hidden; | |
} | |
.navbar{ | |
flex: 0.2; | |
background-color: rgb(0, 21, 41); | |
} | |
.main{ | |
flex: 0.8; | |
width: 100%; | |
} | |
.routes{ | |
padding: 20px; | |
} | |
.nav-container{ | |
position: fixed; | |
left: 0; | |
margin: 10px; | |
height: 100vh; | |
margin: 0px; | |
background-color: rgb(0, 21, 41); | |
} | |
.logo-container{ | |
background-color: #001529; | |
display: flex; | |
padding: 20px; | |
align-items: center; | |
width: 100%; | |
} | |
.logo{ | |
margin:0 0 0 15px; | |
} | |
.logo a{ | |
color: white; | |
} | |
.menu-control-container{ | |
display: none !important; | |
position: absolute !important; | |
right: 10px !important; | |
top: 25px !important; | |
font-size: 1.2rem !important; | |
background-color: var(--bgSecondary) !important; | |
border: none !important; | |
} | |
.loader{ | |
height: 81vh; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
@media screen and (max-width:1300px){ | |
.main{ | |
margin-left: 50px; | |
} | |
} | |
@media screen and (max-width:1170px){ | |
.main{ | |
margin-left: 50px; | |
} | |
} | |
@media screen and (max-width:1000px){ | |
.main{ | |
margin-left: 100px; | |
} | |
} | |
@media screen and (max-width:800px){ | |
.app{ | |
flex-direction: column; | |
overflow: hidden; | |
} | |
.navbar{ | |
flex: 1; | |
} | |
.main{ | |
flex: 1; | |
margin-top: 90px; | |
margin-left: 0px; | |
margin-right: 10px; | |
} | |
.nav-container{ | |
height: 8vh; | |
position:fixed; | |
width: 100%; | |
z-index: 100; | |
background-color: var(--bgSecondary); | |
} | |
.menu-control-container{ | |
display: block !important; | |
} | |
.ant-menu{ | |
position: absolute; | |
right: 0px; | |
} | |
.home-title{ | |
font-size: 1.4rem !important; | |
} | |
.show-more{ | |
font-size: 1.3rem !important; | |
} | |
} | |
.coin-detail-container{ | |
margin: 30px; | |
} | |
.coin-heading-container{ | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
flex-direction: column; | |
border-bottom: 1px solid var(--border); | |
padding-top: 20px; | |
padding-bottom: 20px; | |
gap: 10px; | |
} | |
.coin-heading-container .coin-name{ | |
font-weight: 900; | |
color: var(--pink); | |
} | |
.coin-heading-container p{ | |
font-size: 1rem; | |
opacity: 0.9; | |
margin-bottom: 20px; | |
} | |
.stats-container{ | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
gap: 40px; | |
} | |
.stats-container h2{ | |
font-weight: 700; | |
font-size: 1.4rem; | |
margin-top: 20px; | |
color: var(--pink); | |
} | |
.coin-details-heading{ | |
font-weight: 700 !important; | |
margin-top: 20px !important; | |
color: var(--pink) !important; | |
} | |
.coin-stats{ | |
display: flex; | |
justify-content: space-between; | |
border-bottom: 1px solid var(--border); | |
font-size: 1rem; | |
opacity: 0.9; | |
padding: 20px; | |
} | |
.coin-stats-name{ | |
display: flex; | |
gap: 10px; | |
font-size: 1rem; | |
} | |
.stats{ | |
font-weight: 800; | |
} | |
.coin-value-statistics-heading p{ | |
font-size: 1rem; | |
opacity: 0.9; | |
} | |
.coin-desc-link{ | |
display: flex; | |
gap: 40px; | |
margin-top: 40px; | |
padding-top: 20px; | |
} | |
.coin-desc-link h2{ | |
font-weight: 700; | |
color: var(--pink); | |
} | |
.coin-desc-link p{ | |
font-size: 1rem; | |
opacity: 0.9; | |
} | |
.coin-desc-link a{ | |
color: var(--pink); | |
} | |
.coin-desc-link h3{ | |
font-weight: 700; | |
} | |
.coin-desc{ | |
flex: 0.5; | |
} | |
.coin-links{ | |
padding: 0px 20px; | |
flex: 0.5; | |
} | |
.coin-link{ | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
border-bottom: 1px solid var(--border); | |
padding: 20px; | |
} | |
.link-name{ | |
text-transform: capitalize; | |
font-size: 1rem; | |
} | |
.coin-link a{ | |
color: var(--pink); | |
font-weight: 700; | |
font-size: 1rem; | |
} | |
.coin-link:hover, .coin-stats:hover{ | |
background-color: var(--bgSecondary); | |
} | |
@media screen and (max-width:1000px){ | |
.stats-container{ | |
flex-direction: column; | |
} | |
.coin-desc-link{ | |
flex-direction: column; | |
} | |
.stats-container h2{ | |
margin-top: 0px; | |
} | |
} | |
@media screen and (max-width: 500px){ | |
.coin-links{ | |
padding: 0px; | |
} | |
.coin-detail-container{ | |
margin: 0; | |
} | |
} | |
@media screen and (max-width: 500px){ | |
.heading{ | |
margin-top: 20px; | |
} | |
} | |
.select-news{ | |
width: 180px; | |
} | |
.news-card{ | |
min-height: 300px !important; | |
} | |
.news-image-container{ | |
display: flex !important; | |
justify-content: space-between !important; | |
} | |
.news-title{ | |
width: 70%; | |
} | |
.news-image-container .img{ | |
width:100px; | |
height:100px; | |
} | |
.news-card p{ | |
color: black; | |
margin: 10px 0px !important; | |
} | |
.provider-container{ | |
display: flex; | |
justify-content: space-between; | |
} | |
.provider-name{ | |
margin-left: 10px; | |
} | |
.chart-header{ | |
display: flex; | |
justify-content: space-between; | |
gap: 50px; | |
color: #0071bd; | |
} | |
.chart-title{ | |
color: #0071bd !important; | |
} | |
.price-container{ | |
display: flex !important; | |
gap: 20px !important; | |
align-items: center !important; | |
flex-wrap: wrap !important; | |
} | |
.price-change{ | |
font-weight: 900 !important; | |
} | |
.current-price{ | |
margin-top: 0px !important; | |
font-weight: 900 !important; | |
} | |
.home-heading-container{ | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-top: 40px; | |
} | |
.show-more{ | |
margin-top: 0px !important; | |
} | |
.exchange-image{ | |
margin: 0px 10px !important; | |
} | |
.search-crypto{ | |
margin: 20px auto 30px auto; | |
width: 250px; | |
} | |
.crypto-card-container{ | |
min-height: 65vh !important; | |
} | |
.crypto-card{ | |
min-width: 250px; | |
} | |
.crypto-card .crypto-image{ | |
width:35px; | |
} | |
.select-timeperiod{ | |
width: 200px !important; | |
margin-top: 20px !important; | |
} | |
.footer { | |
background-color: #001529; | |
display: flex; | |
flex-direction: column; | |
padding: 20px; | |
align-items: center; | |
} |
import React, { useState } from 'react'; | |
import HTMLReactParser from 'html-react-parser'; | |
import { useParams } from 'react-router-dom'; | |
import millify from 'millify'; | |
import { Col, Row, Typography, Select } from 'antd'; | |
import { MoneyCollectOutlined, DollarCircleOutlined, FundOutlined, ExclamationCircleOutlined, StopOutlined, TrophyOutlined, CheckOutlined, NumberOutlined, ThunderboltOutlined } from '@ant-design/icons'; | |
import { useGetCryptoDetailsQuery, useGetCryptoHistoryQuery } from '../services/cryptoApi'; | |
import Loader from './Loader'; | |
import LineChart from './LineChart'; | |
const { Title, Text } = Typography; | |
const { Option } = Select; | |
const CryptoDetails = () => { | |
const { coinId } = useParams(); | |
const [timeperiod, setTimeperiod] = useState('7d'); | |
const { data, isFetching } = useGetCryptoDetailsQuery(coinId); | |
const { data: coinHistory } = useGetCryptoHistoryQuery({ coinId, timeperiod }); | |
const cryptoDetails = data?.data?.coin; | |
if (isFetching) return <Loader />; | |
const time = ['3h', '24h', '7d', '30d', '1y', '3m', '3y', '5y']; | |
const stats = [ | |
{ title: 'Price to USD', value: `$ ${cryptoDetails.price && millify(cryptoDetails.price)}`, icon: <DollarCircleOutlined /> }, | |
{ title: 'Rank', value: cryptoDetails.rank, icon: <NumberOutlined /> }, | |
{ title: '24h Volume', value: `$ ${cryptoDetails.volume && millify(cryptoDetails.volume)}`, icon: <ThunderboltOutlined /> }, | |
{ title: 'Market Cap', value: `$ ${cryptoDetails.marketCap && millify(cryptoDetails.marketCap)}`, icon: <DollarCircleOutlined /> }, | |
{ title: 'All-time-high(daily avg.)', value: `$ ${millify(cryptoDetails.allTimeHigh.price)}`, icon: <TrophyOutlined /> }, | |
]; | |
const genericStats = [ | |
{ title: 'Number Of Markets', value: cryptoDetails.numberOfMarkets, icon: <FundOutlined /> }, | |
{ title: 'Number Of Exchanges', value: cryptoDetails.numberOfExchanges, icon: <MoneyCollectOutlined /> }, | |
{ title: 'Aprroved Supply', value: cryptoDetails.approvedSupply ? <CheckOutlined /> : <StopOutlined />, icon: <ExclamationCircleOutlined /> }, | |
{ title: 'Total Supply', value: `$ ${millify(cryptoDetails.totalSupply)}`, icon: <ExclamationCircleOutlined /> }, | |
{ title: 'Circulating Supply', value: `$ ${millify(cryptoDetails.circulatingSupply)}`, icon: <ExclamationCircleOutlined /> }, | |
]; | |
return ( | |
<Col className="coin-detail-container"> | |
<Col className="coin-heading-container"> | |
<Title level={2} className="coin-name"> | |
{data?.data?.coin.name} ({data?.data?.coin.slug}) Price | |
</Title> | |
<p>{cryptoDetails.name} live price in US Dollar (USD). View value statistics, market cap and supply.</p> | |
</Col> | |
<Select defaultValue="7d" className="select-timeperiod" placeholder="Select Timeperiod" onChange={(value) => setTimeperiod(value)}> | |
{time.map((date) => <Option key={date}>{date}</Option>)} | |
</Select> | |
<LineChart coinHistory={coinHistory} currentPrice={millify(cryptoDetails.price)} coinName={cryptoDetails.name} /> | |
<Col className="stats-container"> | |
<Col className="coin-value-statistics"> | |
<Col className="coin-value-statistics-heading"> | |
<Title level={3} className="coin-details-heading">{cryptoDetails.name} Value Statistics</Title> | |
<p>An overview showing the statistics of {cryptoDetails.name}, such as the base and quote currency, the rank, and trading volume.</p> | |
</Col> | |
{stats.map(({ icon, title, value }) => ( | |
<Col className="coin-stats"> | |
<Col className="coin-stats-name"> | |
<Text>{icon}</Text> | |
<Text>{title}</Text> | |
</Col> | |
<Text className="stats">{value}</Text> | |
</Col> | |
))} | |
</Col> | |
<Col className="other-stats-info"> | |
<Col className="coin-value-statistics-heading"> | |
<Title level={3} className="coin-details-heading">Other Stats Info</Title> | |
<p>An overview showing the statistics of {cryptoDetails.name}, such as the base and quote currency, the rank, and trading volume.</p> | |
</Col> | |
{genericStats.map(({ icon, title, value }) => ( | |
<Col className="coin-stats"> | |
<Col className="coin-stats-name"> | |
<Text>{icon}</Text> | |
<Text>{title}</Text> | |
</Col> | |
<Text className="stats">{value}</Text> | |
</Col> | |
))} | |
</Col> | |
</Col> | |
<Col className="coin-desc-link"> | |
<Row className="coin-desc"> | |
<Title level={3} className="coin-details-heading">What is {cryptoDetails.name}?</Title> | |
{HTMLReactParser(cryptoDetails.description)} | |
</Row> | |
<Col className="coin-links"> | |
<Title level={3} className="coin-details-heading">{cryptoDetails.name} Links</Title> | |
{cryptoDetails.links?.map((link) => ( | |
<Row className="coin-link" key={link.name}> | |
<Title level={5} className="link-name">{link.type}</Title> | |
<a href={link.url} target="_blank" rel="noreferrer">{link.name}</a> | |
</Row> | |
))} | |
</Col> | |
</Col> | |
</Col> | |
); | |
}; | |
export default CryptoDetails; |
import React from 'react'; | |
import millify from 'millify'; | |
import { Collapse, Row, Col, Typography, Avatar } from 'antd'; | |
import HTMLReactParser from 'html-react-parser'; | |
import { useGetExchangesQuery } from '../services/cryptoApi'; | |
import Loader from './Loader'; | |
const { Text } = Typography; | |
const { Panel } = Collapse; | |
const Exchanges = () => { | |
const { data, isFetching } = useGetExchangesQuery(); | |
const exchangesList = data?.data?.exchanges; | |
if (isFetching) return <Loader />; | |
return ( | |
<> | |
<Row> | |
<Col span={6}>Exchanges</Col> | |
<Col span={6}>24h Trade Volume</Col> | |
<Col span={6}>Markets</Col> | |
<Col span={6}>Change</Col> | |
</Row> | |
<Row> | |
{exchangesList.map((exchange) => ( | |
<Col span={24}> | |
<Collapse> | |
<Panel | |
key={exchange.id} | |
showArrow={false} | |
header={( | |
<Row key={exchange.id}> | |
<Col span={6}> | |
<Text><strong>{exchange.rank}.</strong></Text> | |
<Avatar className="exchange-image" src={exchange.iconUrl} /> | |
<Text><strong>{exchange.name}</strong></Text> | |
</Col> | |
<Col span={6}>${millify(exchange.volume)}</Col> | |
<Col span={6}>{millify(exchange.numberOfMarkets)}</Col> | |
<Col span={6}>{millify(exchange.marketShare)}%</Col> | |
</Row> | |
)} | |
> | |
{HTMLReactParser(exchange.description || '')} | |
</Panel> | |
</Collapse> | |
</Col> | |
))} | |
</Row> | |
</> | |
); | |
}; | |
export default Exchanges; |
import React from 'react'; | |
import { Line } from 'react-chartjs-2'; | |
import { Col, Row, Typography } from 'antd'; | |
const { Title } = Typography; | |
const LineChart = ({ coinHistory, currentPrice, coinName }) => { | |
const coinPrice = []; | |
const coinTimestamp = []; | |
for (let i = 0; i < coinHistory?.data?.history?.length; i += 1) { | |
coinPrice.push(coinHistory?.data?.history[i].price); | |
} | |
for (let i = 0; i < coinHistory?.data?.history?.length; i += 1) { | |
coinTimestamp.push(new Date(coinHistory?.data?.history[i].timestamp).toLocaleDateString()); | |
} | |
const data = { | |
labels: coinTimestamp, | |
datasets: [ | |
{ | |
label: 'Price In USD', | |
data: coinPrice, | |
fill: false, | |
backgroundColor: '#0071bd', | |
borderColor: '#0071bd', | |
}, | |
], | |
}; | |
const options = { | |
scales: { | |
yAxes: [ | |
{ | |
ticks: { | |
beginAtZero: true, | |
}, | |
}, | |
], | |
}, | |
}; | |
return ( | |
<> | |
<Row className="chart-header"> | |
<Title level={2} className="chart-title">{coinName} Price Chart </Title> | |
<Col className="price-container"> | |
<Title level={5} className="price-change">Change: {coinHistory?.data?.change}%</Title> | |
<Title level={5} className="current-price">Current {coinName} Price: $ {currentPrice}</Title> | |
</Col> | |
</Row> | |
<Line data={data} options={options} /> | |
</> | |
); | |
}; | |
export default LineChart; |
Can someone please help me with this error?
The particular lines above GIVING ERROR BELOWUncaught runtime errors:
×
ERROR
Cannot read properties of undefined (reading 'total')
TypeError: Cannot read properties of undefined (reading 'total')
at Homepage (http://localhost:3000/main.e7235f78e0ce46c0d4d8.hot-update.js:60:30)
at renderWithHooks (http://localhost:3000/static/js/bundle.js:57449:22)
at updateFunctionComponent (http://localhost:3000/static/js/bundle.js:61016:24)
at beginWork (http://localhost:3000/static/js/bundle.js:62735:20)
at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:47705:18)
at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:47749:20)
at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:47806:35)
at beginWork$1 (http://localhost:3000/static/js/bundle.js:67704:11)
at performUnitOfWork (http://localhost:3000/static/js/bundle.js:66952:16)
at workLoopSync (http://localhost:3000/static/js/bundle.js:66875:9)
I am not able to fetch api even i write the same code i checked host key and url many times still not able to resolve problem
It is due to difference between the version of React router, the newer version of react router has made it easier
you can simply use instead of for nesting your components.