diff --git a/package.json b/package.json index d77588f..28d1ed6 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "react": "^17.0.2", "react-chartjs-2": "^4.0.1", "react-dom": "^17.0.2", + "react-router-dom": "^5.2.0", "react-scripts": "5.0.0", "styled-components": "^5.3.3", "web-vitals": "^2.1.4" diff --git a/src/App.jsx b/src/App.jsx index 73c698e..2d997e0 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,42 +1,22 @@ import React, { useState } from 'react' import styled from 'styled-components' -import Loading from './components/Loading/Loading'; +import Loading from './components/CryptoGalleryLoading/CryptoGalleryLoading'; + +import { + BrowserRouter as Router, + Switch, + Route, + Link +} from "react-router-dom"; +import Crypto from './components/Crypto/Crypto'; function App() { - const Div = styled.div` + const GlobalStyles = styled.div` - /* height: 100%; */ - - background-image: radial-gradient( circle farthest-corner at 12.3% 19.3%, rgba(85,88,218,1) 0%, rgba(95,209,249,1) 100.2% ); - - .paths { - - height: 100%; - - position: absolute; - - top: 0; - left: 0; - - z-index: 1; - - .path { - - &::before { - - content: ""; - background: red; - } - - /* background: #ffffff45; */ - background: rgb(255,255,255); - background: linear-gradient(135deg, #ffffff4e 0%, #2e426965 100%); - - position: absolute; - } - }` + background-image: radial-gradient( circle farthest-corner at 12.3% 19.3%, rgba(85,88,218,1) 0%, rgba(95,209,249,1) 100.2% ); + ` const [loading, setLoading] = useState(true) @@ -47,14 +27,30 @@ function App() { document.body.style.overflow = "hidden" } else { + + setTimeout(() => { + + document.body.style.overflow = "visible" - document.body.style.overflow = "visible" - } + }, 2000); + + } //https://stackoverflow.com/questions/39962757/prevent-scrolling-using-css-on-react-rendered-components }, [loading]) + return ( -
- -
+ + + + + + + + + + + + + ); } diff --git a/src/components/Background/Background.jsx b/src/components/Background/Background.jsx index 61a7ece..c2bef38 100644 --- a/src/components/Background/Background.jsx +++ b/src/components/Background/Background.jsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import styled from 'styled-components'; import { CustomPath } from './CustomPath.styled'; const Background = ({loading}) => { @@ -97,6 +98,33 @@ const Background = ({loading}) => { transform: "rotate(40deg)" } ] + + const BackgroundStyles = styled.div` + + height: 100%; + + position: absolute; + + top: 0; + left: 0; + + z-index: 1; + + .path { + + &::before { + + content: ""; + background: red; + } + + /* background: #ffffff45; */ + background: rgb(255,255,255); + background: linear-gradient(135deg, #ffffff4e 0%, #2e426965 100%); + + position: absolute; + } + ` const pathFunction = () => { @@ -119,7 +147,7 @@ const Background = ({loading}) => { }, []) - return <> + return { seriesOfPaths.map(serie => ( @@ -152,7 +180,7 @@ const Background = ({loading}) => { )) } - + }; export default Background; diff --git a/src/components/Crypto/Crypto.jsx b/src/components/Crypto/Crypto.jsx new file mode 100644 index 0000000..d9638e4 --- /dev/null +++ b/src/components/Crypto/Crypto.jsx @@ -0,0 +1,363 @@ +import React, { useState } from 'react'; + +import moment from 'moment'; +import {useParams} from 'react-router-dom' + +import { Chart as ChartJS } from 'chart.js/auto' +import { Chart, Line } from 'react-chartjs-2' //WTF https://stackoverflow.com/questions/67727603/error-category-is-not-a-registered-scale +import { Grid, Button, capitalize } from '@mui/material'; +import styled from 'styled-components'; +import CryptoPricesModule from './CryptoPricesModule'; +import CryptoButtonModule from './CryptoButtonModule'; +import { Box } from '@mui/system'; +import Loading from './Loading'; + +const Crypto = () => { + + const CryptoStyles = styled(Grid)` + + height: 100vh; + + header { + + display: flex; + align-items: center; + + img { + margin: 1vw; + } + + h1 { + + font-family: 'Raleway', 'Arial'; + color: #fff; + + font-size: 2.5rem; + user-select: none; + } + } + + .line { + + margin-right: 5vw; + margin-top: 3vh; + } + + @media (max-width: 900px) { + + height: 100%; + + .line { + + margin: 1vw; + } + } + ` + + const StylesCryptoPricesModule = styled.div` + + .card { + + margin: 1vw; + background-color: #ffffff44; + } + ` + + const StylesCryptoButtonModule = styled(Button)` + + background-color: #555555 !important; + ` + + const BackToTheGalleryStyles = styled(Button)` + + width: 94%; + box-sizing: border-box; + + /* padding: 0 !important; */ + + background: #4CAF50 !important; + + svg { + + width: 30px; + } + + @media(max-width: 900px) { + + width: 98%; + } + ` + + const plugin = { + id: 'custom_canvas_background_color', + beforeDraw: (chart) => { + const ctx = chart.canvas.getContext('2d'); + ctx.save(); + ctx.globalCompositeOperation = 'destination-over'; + ctx.fillStyle = '#000'; + ctx.fillRect(0, 0, chart.width, chart.height); + ctx.restore(); + } + } + + + const cryptoID = useParams().cryptoID + + const [cryptoData, setCryptoData] = useState(false) + const [cryptoPrices, setCryptoPrices] = useState(false) + const [dates, setDates] = useState(false) + + const [loading, setLoading] = useState(true) + const [loadingURL, setLoadingURL] = useState('https://i.ibb.co/Dwygw0t/Logo-reduced.png') + const [contentLoaded, setContentLoaded] = useState(false) + + const [lineDatesInterval, setLineDatesInterval] = useState('week') + + const getCryptoData = async () => { + + try { + + let today = moment().format('l').split('/') + today = `${today[1]}-${today[0]}-${today[2]}` + + const requestData = await fetch(`https://api.coingecko.com/api/v3/coins/${cryptoID}/history?date=${today}`) + const data = await requestData.json() + return data + + } catch (error) { + console.log(error); + } + } + + const getCryptoPrice = async (days) => { + + if (typeof(days) === 'number') { + + days -= 1 + } + + console.log(days) + + try { + + const requestData = await fetch(`https://api.coingecko.com/api/v3/coins/${cryptoID}/market_chart?vs_currency=usd&days=${days}&interval=daily`) + const data = await requestData.json() + + return data.prices.map(arr => { + return arr[1] + }) + + } catch (error) { + console.log(error); + } + } + + const getDates = (days) => { + + let result = [] + + for (let i = 0; i < days; i++) { + + const day = moment().subtract(i, 'days').format('DD-MM-YY') + result.push(day) + } + + return result.reverse() + } + + const effectHandler = async () => { + + const data = await getCryptoData() + console.log(data); + + const cryptoPricesPrevious = {} + cryptoPricesPrevious.week = await getCryptoPrice(7) + cryptoPricesPrevious.month = await getCryptoPrice(30) + cryptoPricesPrevious.threeMonths = await getCryptoPrice(90) + cryptoPricesPrevious.year = await getCryptoPrice(365) + setCryptoPrices(cryptoPricesPrevious) + + const datesPrevious = {} + datesPrevious.week = getDates(7) + datesPrevious.month = getDates(30) + datesPrevious.threeMonths = getDates(90) + datesPrevious.year = getDates(365) + setDates(datesPrevious) + + console.log(dates); + + const maxValue = Math.max(...cryptoPricesPrevious.year) + const minValue = Math.min(...cryptoPricesPrevious.year) + + data.maxValue = { + price: maxValue, + date: datesPrevious.year[cryptoPricesPrevious.year.indexOf(maxValue)] + } + data.minValue = { + price: minValue, + date: datesPrevious.year[cryptoPricesPrevious.year.indexOf(minValue)] + } + + setCryptoData(data) + } + + React.useEffect(() => { + + effectHandler() + + }, []) + + React.useEffect(() => { + + if (cryptoData) { + + setLoadingURL(cryptoData.image.small) + } + + if (cryptoData && cryptoPrices && dates) { + + setLoading(false) + } + + }, [cryptoData, cryptoPrices, dates]) + + React.useEffect(() => { + + if (loading) { + + document.body.style.overflow = "hidden" + + } else { + + setTimeout(() => { + + document.body.style.overflow = "visible" + setContentLoaded(true) + }, 2000); + + } //https://stackoverflow.com/questions/39962757/prevent-scrolling-using-css-on-react-rendered-components + }, [loading]) + + return ( + <> + { + !contentLoaded ? + + : null + } + { + loading ? null : + + +
+ crypto +

{cryptoData.name}

+
+ + + window.location = '../../'} + sx={{ + // width: "100%", + margin: "0px 0px 0px 1vw" + }} + > + + + + + + + Back to the gallery + +
+ + + + { + [ + {text: "Week", propierty: "week"}, + {text: "Month", propierty: "month"}, + {text: "Three months", propierty: "threeMonths"}, + {text: "Year", propierty: "year"} + ].map((obj) => ( + + + )) + } + + +
+ } + + ) +}; + +export default Crypto; \ No newline at end of file diff --git a/src/components/Crypto/CryptoButtonModule.jsx b/src/components/Crypto/CryptoButtonModule.jsx new file mode 100644 index 0000000..14e63ad --- /dev/null +++ b/src/components/Crypto/CryptoButtonModule.jsx @@ -0,0 +1,24 @@ +import React from 'react'; + +const CryptoButtonModule = ({text, onClickFunction, value, Styles}) => { + + return ( + { + e.preventDefault() + onClickFunction(value) + + setTimeout(() => { + + window.scrollTo(0,document.body.scrollHeight); //https://stackoverflow.com/questions/11715646/scroll-automatically-to-the-bottom-of-the-page + + }, 50) + }} + variant="contained" + > + {text} + + ) +}; + +export default CryptoButtonModule; \ No newline at end of file diff --git a/src/components/Crypto/CryptoPricesModule.jsx b/src/components/Crypto/CryptoPricesModule.jsx new file mode 100644 index 0000000..876dce8 --- /dev/null +++ b/src/components/Crypto/CryptoPricesModule.jsx @@ -0,0 +1,39 @@ +import { Card, CardContent, List, ListItem, ListItemText, Typography } from '@mui/material'; +import React from 'react'; + +const CryptoPricesModule = ({text, price, date, Styles}) => { + + return ( + + + + + + {text} + + + + + + + + + + ) +}; + +export default CryptoPricesModule; diff --git a/src/components/Crypto/Loading.jsx b/src/components/Crypto/Loading.jsx new file mode 100644 index 0000000..0a88e8a --- /dev/null +++ b/src/components/Crypto/Loading.jsx @@ -0,0 +1,74 @@ +import styled from 'styled-components'; +import React, {useState} from 'react'; + +const Loading = ({loading, loadingURL}) => { + + const LoadingStyles = styled.div` + + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + + position: absolute; + + top: 0; + left: 0; + + width: 100%; + height: 100%; + + z-index: 10000; + + background-image: radial-gradient( circle farthest-corner at 10% 20%, rgba(90,92,106,1) 0%, rgba(32,45,58,1) 81.3% ); + + img { + + width: 108px; + + margin-bottom: 3vh; + + animation: imgRotate 2s linear infinite; + } + + h2 { + + color: #fff; + font-family: "Raleway" + } + + @keyframes imgRotate{ + 0% { + transform: rotate(0deg) + } + 100% { + transform: rotate(360deg) + } + } + + &.hidden { + + animation: hiddeLoading 2s ease-in-out forwards; + } + + @keyframes hiddeLoading { + 50%{ + transform: translate(0, 0%) + } + 100% { + transform: translate(0, -100%) + + } + } + ` + + return ( + + + loading +

Loading

+
+ ) +}; + +export default Loading; diff --git a/src/components/Cryptos/Cryptos.jsx b/src/components/CryptoGallery/CryptoGallery.jsx similarity index 99% rename from src/components/Cryptos/Cryptos.jsx rename to src/components/CryptoGallery/CryptoGallery.jsx index c05b034..eccc349 100644 --- a/src/components/Cryptos/Cryptos.jsx +++ b/src/components/CryptoGallery/CryptoGallery.jsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { Grid } from '@mui/material'; import styled from 'styled-components'; -import Crypto from './Crypto'; +import Crypto from './CryptoGalleryItem'; import moment from 'moment'; diff --git a/src/components/Cryptos/Crypto.jsx b/src/components/CryptoGallery/CryptoGalleryItem.jsx similarity index 94% rename from src/components/Cryptos/Crypto.jsx rename to src/components/CryptoGallery/CryptoGalleryItem.jsx index 70099c5..32c6b01 100644 --- a/src/components/Cryptos/Crypto.jsx +++ b/src/components/CryptoGallery/CryptoGalleryItem.jsx @@ -7,8 +7,12 @@ import { Chart, Line } from 'react-chartjs-2' //WTF https://stackover import Cookies from 'js-cookie'; import { borderRadius } from '@mui/system'; +import { withRouter, useHistory } from 'react-router-dom'; + const Crypto = ({CryptoStyles, data, cryptoPrices, dates, index, cryptoListLength, setLoading}) => { + const history = useHistory() + const plugin = { id: 'custom_canvas_background_color', beforeDraw: (chart) => { @@ -40,7 +44,13 @@ const Crypto = ({CryptoStyles, data, cryptoPrices, dates, index, cryptoListLengt return ( <> - + history.push(`/crypto/${data.id}`)} + > { @@ -53,11 +53,11 @@ const Loading = ({loading, setLoading}) => { &.hidden { - animation: hiddeLoading 1s ease-in-out forwards; + animation: hiddeLoading 2s ease-in-out forwards; } @keyframes hiddeLoading { - 0%{ + 50%{ transform: translate(0, 0%) } 100% {