: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; |
https://cryptoworld2022.netlify.app/ for some reason the site link keeps getting deleted. If you cant see it here check my profile.
Hellow My time on the graph is alway showing 1970. I have tried to log the date that the new Date(timestamp) is getting and I am seeing it is also showing 1970. What is wrong?
Did you solved the issue??
Did anyone solve this please?
This issue didn't come in my site: https://reactjscryptoapp.netlify.app
You can check out my repo link: https://github.com/Technical-Shubham-tech/crypto-app
Thanks!
Please help As local host 3000/ is not rendering page on this stage
Uncaught TypeError: globalStats is undefined
import React from 'react'; import {millify} from 'millify'; import { Typography, Row, Col, Statistic } from 'antd'; import { Link } from 'react-router-dom';
import { useGetCryptosQuery } from '../services/cryptoApi'; // ready to fetch
const {Title}= Typography;
const Homepage = () => { const { data, isFetching } = useGetCryptosQuery(); // after import in step-2 const globalStats = data?.data?.stats; if(isFetching) return 'Loading ...'; return ( <> <Title level={2} className="heading">Global Crypto State</Title> </> ) } export default Homepage
did anyone find a solution?
Module not found: Error: Can't resolve 'antd/dist/antd.min.css' in 'C:\Users\user\Desktop\projet\src'
how can i fix this ?
Please help As local host 3000/ is not rendering page on this stage
Uncaught TypeError: globalStats is undefined
import React from 'react'; import {millify} from 'millify'; import { Typography, Row, Col, Statistic } from 'antd'; import { Link } from 'react-router-dom';
import { useGetCryptosQuery } from '../services/cryptoApi'; // ready to fetch
const {Title}= Typography;
const Homepage = () => { const { data, isFetching } = useGetCryptosQuery(); // after import in step-2 const globalStats = data?.data?.stats; if(isFetching) return 'Loading ...'; return ( <> <Title level={2} className="heading">Global Crypto State</Title> </> ) } export default Homepage
Render is not available anymore on version 18 of react use version 17!
Can anyone help?
Add middleware to it: import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { cryptoApi } from '../services/cryptoApi';
import { cryptoNewsApi } from '../services/cryptoNewsApi';
export default configureStore({
reducer: {
[cryptoApi.reducerPath]: cryptoApi.reducer,
[cryptoNewsApi.reducerPath]: cryptoNewsApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(
cryptoApi.middleware,
cryptoNewsApi.middleware,
),
});
![]()
![]()
![]()
Could someone be able to fix this problem or tell me how to fix it?well the case is switch isn't a part of react-router-dom anymore it has been replaced by "Routes" so import Routes and use it instead of Switch.
Thanks!
but now my content is not showing as it should be.may i ask did you solve this issue? i changed to Routes, but the content did not show up either.
ReactDOM.render( <React.StrictMode>
<Route path="/*" element={<Provider store={store}> <App /> </Provider>}> </Route> </Routes> </BrowserRouter> </React.StrictMode>, document.getElementById('root')
);
Use this
well u must be using react-router-dom version 6 or higher try to use the same version as used in the project
for your connivence you can run
npm i react-router-dom@5.2.1
it is the same version of react router dom as used in the project or u can use the routing syntax of version 6
Cannot read properties of undefined (reading 'name')
TypeError: Cannot read properties of undefined (reading 'name')
It keeps showing this error on cryptoDetails.jsx page
Services_cryptoApi__WEBPACK_IMPORTED_MODULE_2_.useGetCryptoQuery is not a function pls any resolve this issue
"category" is not a registered scale.
at Registry._get (http://localhost:3000/static/js/bundle.js:123625:13) please resolve issue in this LineChart.jsx file
I have successfully built this app. Listing some issues faced by me and how i solved it.
1> price is not defined error
Ans: use if (isFetching) return ; maybe you are trying to access before it fetches so this will prevent it., in the video ? is missing after cryptoDetails
or use this. { title: 'Price to USD', value: $ ${cryptoDetails?.price && millify(Number(cryptoDetails.price))}, icon: },
2> Cryptodetails for 24h is changed
sol: use this line in cryptodetails.jsx file { title: '24h Volume', value: $ ${cryptoDetails["24hVolume"] && millify(cryptoDetails["24hVolume"])}, icon: },
Tip: Console log data and match names of field fetched by api with the code and make changes accordingly
USE THIS UPDATED stats and generic stats
const stats = [
{ title: 'Price to USD', value: $ ${cryptoDetails?.price && millify(Number(cryptoDetails.price))}, icon: },
{ title: 'Rank', value: cryptoDetails?.rank, icon: },
{ title: '24h Volume', value: $ ${cryptoDetails["24hVolume"] && millify(cryptoDetails["24hVolume"])}, icon: },
{ title: 'Market Cap', value: $ ${cryptoDetails?.marketCap && millify(Number(cryptoDetails.marketCap))}, icon: },
{ title: 'All-time-high(daily avg.)', value: $ ${millify(Number((cryptoDetails?.allTimeHigh.price)))}, icon: },
];
const genericStats = [
{ title: 'Number Of Markets', value: cryptoDetails?.numberOfMarkets, icon: },
{ title: 'Number Of Exchanges', value: cryptoDetails?.numberOfExchanges, icon: },
{ title: 'Change', value: cryptoDetails?.change, icon : },
{ title: 'Total Supply', value: $ ${millify(Number((cryptoDetails?.supply.total)))}, icon: },
{ title: 'Circulating Supply', value: $ ${millify(Number((cryptoDetails?.supply.circulating)))}, icon: },
];
If chart is not from left to right then use this
const data = {
labels: coinTimestamp.reverse(),
datasets: [
{
label: "Price In USD",
data: coinPrice.reverse(),
fill: false,
backgroundColor: "#0071bd",
borderColor: "#0071bd",
},
],
};
here we are reversing values of array.
TIP: Go to my repo and copy the updated code wherever you are stuck 😉
3> History API should be written like this
getCryptoHistory:builder.query({
query: ({coinId,timePeriod}) => createRequest(/coin/${coinId}/history?timePeriod=${timePeriod})
})
4> ID has been changed to uuId so make changes in cryptocurrencies.jsx like this
5> Exchanges path is not paid in the api so you cant access with free api
6> LineChart.jsx not working? Copy it from my project ;)
If this helps then you may consider giving star to me 😊
I am encountering
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.
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
Did anyone solve this please?