refactoring

This commit is contained in:
UserX 2023-08-10 18:53:35 +03:00
parent 7d3f76d230
commit 54cafda3c4
17 changed files with 498 additions and 425 deletions

View File

@ -1,111 +1,3 @@
body {
background: #e5e5e5;
}
.converter {
max-width: 630px;
margin: 50px auto;
background: #fff;
padding: 15px;
border-radius: 10px;
&__head {
font-weight: 700;
font-size: 25px;
text-align: center;
margin: 0 0 50px 0;
}
&__body {
width: 100%;
height: 60px;
display: flex;
align-items: center;
gap: 10px;
margin: 0 0 25px 0;
justify-content: center;
@media (max-width: 768px) {
flex-direction: column;
height: auto;
}
}
&__row {
border-radius: 10px;
height: 100%;
font-size: 24px;
display: flex;
align-items: center;
position: relative;
justify-content: center;
@media (max-width: 908px) {
font-size: 20px;
}
@media (max-width: 768px) {
font-size: inherit;
}
}
&__crypto-name {
height: 100%;
vertical-align: middle;
position: relative;
cursor: pointer;
display: flex;
align-items: center;
font-size: 12px;
line-height: 15px;
justify-content: center;
padding: 0 15px;
border-left: 2px solid rgba(7, 28, 71, 0.12);
font-weight: 700;
border: 2px solid rgba(7, 28, 71, 0.12);
border-left: none;
border-radius: 0 10px 10px 0;
&-title {
display: flex;
align-items: center;
flex-direction: column;
gap: 3px;
}
img {
width: 40px;
height: 20px;
}
}
&__arrow {
height: 35px;
object-fit: contain;
cursor: pointer;
width: 20px;
background: #999;
-webkit-mask: url(//yastatic.net/s3/web4static/_/v2/static/media/Swap_16.c0236c02.svg)
no-repeat center;
mask: url(//yastatic.net/s3/web4static/_/v2/static/media/Swap_16.c0236c02.svg)
no-repeat center;
}
&__input {
border: 2px solid rgba(7, 28, 71, 0.12);
border-radius: 10px 0 0 10px;
height: 100%;
font-family: HelveticaNeue-Light, 'Helvetica Neue Light', Helvetica, Arial,
sans-serif;
font-size: inherit;
text-align: right;
width: 201px;
color: #000;
position: relative;
top: 0;
padding: 0 10px 0 0;
outline: none;
@media (max-width: 768px) {
border-width: 0;
}
}
&__footer {
font-size: 18px;
}
}

View File

@ -1,237 +1,9 @@
import { ChangeEvent, useEffect, useRef, useState } from 'react'
import btc from '../src/assets/images/btc.svg'
import usdt from '../src/assets/images/usdt.svg'
import eth from '../src/assets/images/eth.svg'
import useOnClickOutside from './hooks/useOnClickOutside'
import { PopupConverter } from './Components/popup-converter/Popup-converter'
import { convert } from '.'
import { IValutions } from './models/IValutions'
import { Converter } from './Components/Converter/Converter'
import './App.scss'
function App() {
const valuations: IValutions[] = [
{
title: 'BTC',
img: btc,
alt: 'Bitcoin'
},
{
title: 'USDT',
img: usdt,
alt: 'Tether'
},
{
title: 'ETH',
img: eth,
alt: 'Ethereum'
}
]
const ref = useRef<HTMLDivElement>(null)
const [firstValue, setFirstValue] = useState<string>('1')
const [secondValue, setSecondValue] = useState<string>('1')
const [firstValuation, setFirstValuation] = useState<IValutions>(
valuations[0]
)
const [secondValuation, setSecondValuation] = useState<IValutions>(
valuations[1]
)
const [showFirstValuation, setShowFirstValuation] = useState<boolean>()
const [showSecondValuation, setShowSecondValuation] = useState<boolean>()
const [isSwap, setSwap] = useState(true)
const regexInput = (e: ChangeEvent<HTMLInputElement>) => {
let [_, sign, integer, decimals]: any = e.target.value
.replace(/[^\d\.\-]/g, '')
.replace(/(\..*?)\./g, '$1')
.replace(/(.+)-/g, '$1')
.match(/^(-?)(.*?)((?:\.\d*)?)$/)
let pos: number = Number(e.target.selectionStart) - 1
if (!integer && decimals) pos += 2
if (integer || decimals) {
integer = +integer
}
const formatted = sign + integer + decimals
if (formatted !== e.target.value) {
e.target.value = formatted
e.target.setSelectionRange(pos, pos)
}
}
const handlerInputOne = (e: ChangeEvent<HTMLInputElement>) => {
regexInput(e)
setFirstValue(e.target.value)
getSecondValuation(+e.target.value || 0)
}
const handlerInputTwo = (e: ChangeEvent<HTMLInputElement>) => {
regexInput(e)
setSecondValue(e.target.value)
getFirstValuation(+e.target.value || 0)
}
const openFirstListValuation = () => setShowFirstValuation(true)
const openSecondListValuation = () => setShowSecondValuation(true)
const getSecondValuation = async (value: number) => {
await convert.ready()
setSecondValue(
convert[firstValuation.title][secondValuation.title](value) || 0
)
}
const getFirstValuation = async (value: number) => {
await convert.ready()
setFirstValue(
convert[secondValuation.title][firstValuation.title](value) || 0
)
}
const swap = () => {
setSwap(true)
setSecondValuation(firstValuation)
setFirstValuation(secondValuation)
}
useOnClickOutside(ref, () => {
setShowSecondValuation(false)
setShowFirstValuation(false)
})
useEffect(() => {
getSecondValuation(+firstValue)
}, [firstValuation])
useEffect(() => {
if (isSwap) {
setSwap(false)
return
}
getFirstValuation(+secondValue)
}, [secondValuation])
useEffect(() => {
const interval = setInterval(() => {
getSecondValuation(+firstValue)
}, 25000)
return () => clearInterval(interval)
}, [])
const getValuations = () =>
`${firstValue || 0} ${firstValuation.title} = ${secondValue || 0} ${
secondValuation.title
}`
return (
<div className='converter'>
<div className='converter__body'>
<div className='converter__row converter__row_border'>
<input
className='converter__input'
type='text'
value={firstValue}
onChange={handlerInputOne}
/>
<span
className='converter__crypto-name'
onClick={openFirstListValuation}
>
<div className={'converter__crypto-name-title'}>
<img src={firstValuation.img} alt='' />
{firstValuation.title}
</div>
<div>
<svg
focusable='false'
xmlns='http://www.w3.org/2000/svg'
width='8'
height='14'
>
<path d='M4 0l4 6H0l4-6zm0 14l4-6H0l4 6z' />
</svg>
</div>
</span>
{showFirstValuation && (
<div className='converter__popup popup-converter' ref={ref}>
{valuations.map((item, index) => (
<PopupConverter
key={index}
item={item}
setValuation={setFirstValuation}
valuation={firstValuation.title}
/>
))}
</div>
)}
</div>
<div className='converter__row'>
<div className={'converter__arrow'} onClick={swap} />
</div>
<div className='converter__row converter__row_border'>
<input
className='converter__input'
min={0}
type='text'
maxLength={20}
value={secondValue}
onChange={handlerInputTwo}
/>
<span
className='converter__crypto-name'
onClick={openSecondListValuation}
>
<div className={'converter__crypto-name-title'}>
<img src={secondValuation.img} alt='' />
{secondValuation.title}
</div>
<div>
<svg
focusable='false'
xmlns='http://www.w3.org/2000/svg'
width='8'
height='14'
>
<path d='M4 0l4 6H0l4-6zm0 14l4-6H0l4 6z' />
</svg>
</div>
</span>
{showSecondValuation && (
<div className='converter__popup popup-converter' ref={ref}>
{valuations.map((item, index) => (
<PopupConverter
key={index}
item={item}
valuation={secondValuation.title}
setValuation={setSecondValuation}
/>
))}
</div>
)}
</div>
</div>
<footer className='converter__footer'>
<b>{getValuations()}</b>
<br />
Данные носят ознакомительный характер {'\t'}
<b>
{new Date(convert.lastUpdated).toLocaleDateString() +
' ' +
new Date(convert.lastUpdated).getHours() +
':' +
new Date(convert.lastUpdated)
.getMinutes()
.toString()
.padStart(2, '0')}
</b>
</footer>
</div>
)
return <Converter />
}
export default App

View File

@ -0,0 +1,111 @@
.converter {
max-width: 640px;
margin: 50px auto;
background: #fff;
padding: 15px;
border-radius: 10px;
&__head {
font-weight: 700;
font-size: 25px;
text-align: center;
margin: 0 0 50px 0;
}
&__body {
width: 100%;
height: 60px;
display: flex;
align-items: center;
gap: 10px;
margin: 0 0 25px 0;
justify-content: center;
@media (max-width: 768px) {
flex-direction: column;
height: auto;
}
}
&__row {
border-radius: 10px;
height: 100%;
font-size: 24px;
display: flex;
align-items: center;
position: relative;
justify-content: center;
@media (max-width: 908px) {
font-size: 20px;
}
@media (max-width: 768px) {
font-size: inherit;
}
}
&__crypto-name {
height: 100%;
vertical-align: middle;
position: relative;
cursor: pointer;
display: flex;
align-items: center;
font-size: 12px;
line-height: 15px;
justify-content: center;
padding: 0 15px;
font-weight: 700;
border: 2px solid rgba(7, 28, 71, 0.12);
border-left: none;
border-radius: 0 10px 10px 0;
gap: 5px;
&-title {
display: flex;
align-items: center;
flex-direction: column;
gap: 3px;
}
}
&__crypto-icon {
width: 40px;
height: 20px;
}
&__arrow {
height: 35px;
object-fit: contain;
cursor: pointer;
width: 20px;
background: #999;
-webkit-mask: url(//yastatic.net/s3/web4static/_/v2/static/media/Swap_16.c0236c02.svg)
no-repeat center;
mask: url(//yastatic.net/s3/web4static/_/v2/static/media/Swap_16.c0236c02.svg)
no-repeat center;
}
&__input {
border: 2px solid rgba(7, 28, 71, 0.12);
border-radius: 10px 0 0 10px;
height: 100%;
font-family: HelveticaNeue-Light, 'Helvetica Neue Light', Helvetica, Arial,
sans-serif;
font-size: inherit;
text-align: right;
width: 201px;
color: #000;
position: relative;
top: 0;
padding: 0 10px 0 0;
outline: none;
@media (max-width: 768px) {
height: 38px;
}
}
&__footer {
font-size: 14px;
}
&__title {
font-size: 18px;
font-weight: bold;
}
}

View File

@ -0,0 +1,108 @@
import { useEffect, useState } from 'react'
import { IValutions } from '../../models/IValutions'
import { valuations } from '../../utils/Constants'
import { ConverterInput } from './ConverterInput/ConverterInput'
import { actualDate, getRelationToCurrency } from '../../utils/HelperFunctions'
import './Converter.scss'
export const Converter = () => {
const [isFocus, setFocus] = useState<1 | 2>(1)
const [firstValue, setFirstValue] = useState<string>('1')
const [secondValue, setSecondValue] = useState<string>('1')
const [firstValuation, setFirstValuation] = useState<IValutions>(
valuations[0]
)
const [secondValuation, setSecondValuation] = useState<IValutions>(
valuations[1]
)
const swap = () => {
setSecondValuation(firstValuation)
setFirstValuation(secondValuation)
}
useEffect(() => {
if (isFocus === 1) {
getRelationToCurrency(
firstValuation.title,
secondValuation.title,
+firstValue,
setSecondValue
)
} else if (isFocus === 2) {
getRelationToCurrency(
secondValuation.title,
firstValuation.title,
+secondValue,
setFirstValue
)
}
}, [isFocus, firstValue, firstValuation, secondValue, secondValuation])
useEffect(() => {
if (firstValuation.title === secondValuation.title) {
let index = valuations.findIndex(
(item) => item.title !== firstValuation.title
)
setSecondValuation(valuations[index])
}
}, [firstValuation])
useEffect(() => {
if (secondValuation.title === firstValuation.title) {
let index = valuations.findIndex(
(item) => item.title !== secondValuation.title
)
setFirstValuation(valuations[index])
}
}, [secondValuation])
useEffect(() => {
const interval = setInterval(() => {
getRelationToCurrency(
firstValuation.title,
secondValuation.title,
+firstValue,
setSecondValue
)
}, 25000)
return () => clearInterval(interval)
}, [])
const outputResult = () =>
`${firstValue || 0} ${firstValuation.title} = ${secondValue || 0} ${
secondValuation.title
}`
return (
<div className='converter'>
<div className='converter__body'>
<ConverterInput
valuation={firstValuation}
value={firstValue}
setValuation={setFirstValuation}
setValue={setFirstValue}
index={1}
setFocus={setFocus}
/>
<div className='converter__row'>
<div className={'converter__arrow'} onClick={swap} />
</div>
<ConverterInput
valuation={secondValuation}
value={secondValue}
setValuation={setSecondValuation}
setValue={setSecondValue}
index={2}
setFocus={setFocus}
/>
</div>
<footer className='converter__footer'>
<div className='converter__title'>{outputResult()}</div>
Данные носят ознакомительный характер · {'\t'}
<b>{actualDate()}</b>
</footer>
</div>
)
}

View File

@ -0,0 +1,87 @@
import { ChangeEvent, Dispatch, FC, useEffect, useRef, useState } from 'react'
import { ConverterPopup } from '../ConverterPopup/ConverterPopup'
import arrowDoubleVertical from '../../../assets/images/arrow-double-vertical.svg'
import { IValutions } from '../../../models/IValutions'
import { valuations } from '../../../utils/Constants'
import useOnClickOutside from '../../../hooks/useOnClickOutside'
import { regexInput } from '../../../utils/HelperFunctions'
interface IConverterInput {
index: 1 | 2
value: string
setValue: Dispatch<string>
valuation: IValutions
setValuation: Dispatch<IValutions>
setFocus: Dispatch<1 | 2>
}
export const ConverterInput: FC<IConverterInput> = ({
index,
setValue,
value,
valuation,
setValuation,
setFocus
}) => {
const [showPopup, setShowPopup] = useState<boolean>()
const ref = useRef<HTMLDivElement>(null)
const handlerInput = (e: ChangeEvent<HTMLInputElement>) => {
regexInput(e)
setValue(e.target.value)
}
useOnClickOutside(ref, () => {
setShowPopup(false)
})
useEffect(() => {
setShowPopup(false)
}, [valuation])
return (
<div className='converter__row converter__row_border'>
<input
className='converter__input'
type='text'
maxLength={20}
value={value}
onFocus={() => setFocus(index)}
onChange={handlerInput}
/>
<span
className='converter__crypto-name'
onClick={() => setShowPopup((prev) => !prev)}
>
<div className={'converter__crypto-name-title'}>
<img
src={valuation.img}
alt=''
className={'converter__crypto-icon'}
/>
{valuation.title}
</div>
<div>
<img
src={arrowDoubleVertical}
alt=''
className={'converter__crypto-name-arrow'}
/>
</div>
</span>
{showPopup && (
<div className='converter-popup' ref={ref}>
{valuations.map((item, index) => (
<ConverterPopup
key={index}
item={item}
valuation={valuation}
setValuation={setValuation}
/>
))}
</div>
)}
</div>
)
}

View File

@ -1,4 +1,4 @@
.popup-converter {
.converter-popup {
position: absolute;
z-index: 2;
inset: 75px auto auto 0;
@ -37,6 +37,8 @@
}
}
&__button {
display: flex;
align-items: center;
background: transparent;
transition: 0.3s all ease;
// padding: 10px;

View File

@ -0,0 +1,36 @@
import { FC, MouseEvent } from 'react'
import { IListValuationsName } from '../../../models/IListValutionsName'
import checkIcon from '../../../assets/images/check.svg'
import './ConverterPopup.scss'
export const ConverterPopup: FC<IListValuationsName> = ({
item,
valuation,
setValuation
}) => {
const setActiveValuation = (e: MouseEvent<HTMLDivElement>) => {
setValuation({
img: item.img,
title: item.title
})
}
return (
<div className={'converter-popup__container'} onClick={setActiveValuation}>
<div className={'converter-popup__check'}>
{valuation.title === item.title && <img src={checkIcon} alt='check' />}
</div>
<div className={'converter-popup__body'}>
<img src={item.img} alt='' className={'converter-popup__img'} />
<button
type='button'
className={'converter-popup__button'}
value={item.title}
>
{item.title} <span>{item.alt}</span>
</button>
</div>
</div>
)
}

View File

@ -1,43 +0,0 @@
import { FC, MouseEvent } from 'react'
import { IListValuationsName } from '../../models/IListValutionsName'
import './Popup-converter.scss'
export const PopupConverter: FC<IListValuationsName> = ({
item,
valuation,
setValuation
}) => {
const setActiveValuation = (e: MouseEvent<HTMLDivElement>) => {
setValuation({
img: item.img,
title: item.title
})
}
return (
<div className={'popup-converter__container'} onClick={setActiveValuation}>
<div className={'popup-converter__check'}>
{valuation === item.title && (
<svg
focusable='false'
xmlns='http://www.w3.org/2000/svg'
width='16'
height='10'
>
<path d='M7.207 7.506L3.629 3.81 2.343 4.939l4.841 5.002 8.462-8.428L14.382.362z' />
</svg>
)}
</div>
<div className={'popup-converter__body'}>
<img className={'popup-converter__img'} src={item.img} alt='icon' />
<button
type='button'
className={'popup-converter__button'}
value={item.title}
>
{item.title} <span>{item.alt}</span>
</button>
</div>
</div>
)
}

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.2427 5.6568C16.6332 5.26627 16.6332 4.63311 16.2427 4.24258L13.4142 1.41416C12.6332 0.633107 11.3669 0.633107 10.5858 1.41416L7.75737 4.24268C7.36685 4.6332 7.36685 5.26637 7.75737 5.65689C8.1479 6.04741 8.78106 6.04741 9.17158 5.65689L11 3.82847V8.99998C11 9.55227 11.4477 9.99998 12 9.99998C12.5523 9.99998 13 9.55227 13 8.99998V3.82835L14.8284 5.6568C15.219 6.04732 15.8521 6.04732 16.2427 5.6568Z" fill="#0F0F0F"/>
<path d="M7.7574 18.3429C7.36688 18.7334 7.36688 19.3666 7.7574 19.7571L10.5858 22.5856C11.3669 23.3666 12.6332 23.3668 13.4143 22.5857L16.2427 19.7573C16.6332 19.3668 16.6332 18.7336 16.2427 18.3431C15.8522 17.9526 15.219 17.9526 14.8285 18.3431L13 20.1716L13 15C13 14.4477 12.5523 14 12 14C11.4477 14 11 14.4477 11 15L11 20.1713L9.17161 18.3429C8.78109 17.9524 8.14792 17.9524 7.7574 18.3429Z" fill="#0F0F0F"/>
<svg
focusable='false'
xmlns='http://www.w3.org/2000/svg'
width='8'
height='14'
>
<path d='M4 0l4 6H0l4-6zm0 14l4-6H0l4 6z'/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 175 B

View File

@ -1,8 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#F7931A"/>
<path fill="#FFF" fill-rule="nonzero" d="M23.189 14.02c.314-2.096-1.283-3.223-3.465-3.975l.708-2.84-1.728-.43-.69 2.765c-.454-.114-.92-.22-1.385-.326l.695-2.783L15.596 6l-.708 2.839c-.376-.086-.746-.17-1.104-.26l.002-.009-2.384-.595-.46 1.846s1.283.294 1.256.312c.7.175.826.638.805 1.006l-.806 3.235c.048.012.11.03.18.057l-.183-.045-1.13 4.532c-.086.212-.303.531-.793.41.018.025-1.256-.313-1.256-.313l-.858 1.978 2.25.561c.418.105.828.215 1.231.318l-.715 2.872 1.727.43.708-2.84c.472.127.93.245 1.378.357l-.706 2.828 1.728.43.715-2.866c2.948.558 5.164.333 6.097-2.333.752-2.146-.037-3.385-1.588-4.192 1.13-.26 1.98-1.003 2.207-2.538zm-3.95 5.538c-.533 2.147-4.148.986-5.32.695l.95-3.805c1.172.293 4.929.872 4.37 3.11zm.535-5.569c-.487 1.953-3.495.96-4.47.717l.86-3.45c.975.243 4.118.696 3.61 2.733z"/>
</g>
</svg>
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#F7931A"/>
<path fill="#FFF" fill-rule="nonzero" d="M23.189 14.02c.314-2.096-1.283-3.223-3.465-3.975l.708-2.84-1.728-.43-.69 2.765c-.454-.114-.92-.22-1.385-.326l.695-2.783L15.596 6l-.708 2.839c-.376-.086-.746-.17-1.104-.26l.002-.009-2.384-.595-.46 1.846s1.283.294 1.256.312c.7.175.826.638.805 1.006l-.806 3.235c.048.012.11.03.18.057l-.183-.045-1.13 4.532c-.086.212-.303.531-.793.41.018.025-1.256-.313-1.256-.313l-.858 1.978 2.25.561c.418.105.828.215 1.231.318l-.715 2.872 1.727.43.708-2.84c.472.127.93.245 1.378.357l-.706 2.828 1.728.43.715-2.866c2.948.558 5.164.333 6.097-2.333.752-2.146-.037-3.385-1.588-4.192 1.13-.26 1.98-1.003 2.207-2.538zm-3.95 5.538c-.533 2.147-4.148.986-5.32.695l.95-3.805c1.172.293 4.929.872 4.37 3.11zm.535-5.569c-.487 1.953-3.495.96-4.47.717l.86-3.45c.975.243 4.118.696 3.61 2.733z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,8 @@
<svg
focusable='false'
xmlns='http://www.w3.org/2000/svg'
width='16'
height='10'
>
<path d='M7.207 7.506L3.629 3.81 2.343 4.939l4.841 5.002 8.462-8.428L14.382.362z'/>
</svg>

After

Width:  |  Height:  |  Size: 216 B

View File

@ -1,15 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#627EEA"/>
<g fill="#FFF" fill-rule="nonzero">
<path fill-opacity=".602" d="M16.498 4v8.87l7.497 3.35z"/>
<path d="M16.498 4L9 16.22l7.498-3.35z"/>
<path fill-opacity=".602" d="M16.498 21.968v6.027L24 17.616z"/>
<path d="M16.498 27.995v-6.028L9 17.616z"/>
<path fill-opacity=".2" d="M16.498 20.573l7.497-4.353-7.497-3.348z"/>
<path fill-opacity=".602" d="M9 16.22l7.498 4.353v-7.701z"/>
</g>
</g>
</svg>
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#627EEA"/>
<g fill="#FFF" fill-rule="nonzero">
<path fill-opacity=".602" d="M16.498 4v8.87l7.497 3.35z"/>
<path d="M16.498 4L9 16.22l7.498-3.35z"/>
<path fill-opacity=".602" d="M16.498 21.968v6.027L24 17.616z"/>
<path d="M16.498 27.995v-6.028L9 17.616z"/>
<path fill-opacity=".2" d="M16.498 20.573l7.497-4.353-7.497-3.348z"/>
<path fill-opacity=".602" d="M9 16.22l7.498 4.353v-7.701z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 699 B

After

Width:  |  Height:  |  Size: 699 B

View File

@ -1,8 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#26A17B"/>
<path fill="#FFF" d="M17.922 17.383v-.002c-.11.008-.677.042-1.942.042-1.01 0-1.721-.03-1.971-.042v.003c-3.888-.171-6.79-.848-6.79-1.658 0-.809 2.902-1.486 6.79-1.66v2.644c.254.018.982.061 1.988.061 1.207 0 1.812-.05 1.925-.06v-2.643c3.88.173 6.775.85 6.775 1.658 0 .81-2.895 1.485-6.775 1.657m0-3.59v-2.366h5.414V7.819H8.595v3.608h5.414v2.365c-4.4.202-7.709 1.074-7.709 2.118 0 1.044 3.309 1.915 7.709 2.118v7.582h3.913v-7.584c4.393-.202 7.694-1.073 7.694-2.116 0-1.043-3.301-1.914-7.694-2.117"/>
</g>
</svg>
<g fill="none" fill-rule="evenodd">
<circle cx="16" cy="16" r="16" fill="#26A17B"/>
<path fill="#FFF" d="M17.922 17.383v-.002c-.11.008-.677.042-1.942.042-1.01 0-1.721-.03-1.971-.042v.003c-3.888-.171-6.79-.848-6.79-1.658 0-.809 2.902-1.486 6.79-1.66v2.644c.254.018.982.061 1.988.061 1.207 0 1.812-.05 1.925-.06v-2.643c3.88.173 6.775.85 6.775 1.658 0 .81-2.895 1.485-6.775 1.657m0-3.59v-2.366h5.414V7.819H8.595v3.608h5.414v2.365c-4.4.202-7.709 1.074-7.709 2.118 0 1.044 3.309 1.915 7.709 2.118v7.582h3.913v-7.584c4.393-.202 7.694-1.073 7.694-2.116 0-1.043-3.301-1.914-7.694-2.117"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 808 B

After

Width:  |  Height:  |  Size: 808 B

View File

@ -1,21 +1,14 @@
import ReactDOM from 'react-dom/client'
import './index.css'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const CryptoConvert = require('crypto-convert').default
import App from './App'
import reportWebVitals from './reportWebVitals'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const CryptoConvert = require('crypto-convert').default
import { convertConfig } from './utils/Constants'
export const convert = new CryptoConvert({
cryptoInterval: 20000, //Crypto prices update interval in ms (default 5 seconds on Node.js & 15 seconds on Browsers)
fiatInterval: 60 * 1e3 * 60, //Fiat prices update interval (default every 1 hour)
calculateAverage: true, //Calculate the average crypto price from exchanges
binance: true, //Use binance rates
bitfinex: true, //Use bitfinex rates
coinbase: true, //Use coinbase rates
kraken: true, //Use kraken rates
HTTPAgent: null //HTTP Agent for server-side proxies (Node.js only)
})
import './index.css'
export const convert = new CryptoConvert(convertConfig)
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
const queryClient = new QueryClient()

View File

@ -4,5 +4,5 @@ import { IValutions } from './IValutions'
export interface IListValuationsName {
item: IValutions
setValuation: Dispatch<IValutions>
valuation: string
valuation: IValutions
}

34
src/utils/Constants.ts Normal file
View File

@ -0,0 +1,34 @@
import { IValutions } from '../models/IValutions'
import btc from '../assets/images/btc.svg'
import usdt from '../assets/images/usdt.svg'
import eth from '../assets/images/eth.svg'
export const valuations: IValutions[] = [
{
title: 'BTC',
img: btc,
alt: 'Bitcoin'
},
{
title: 'USDT',
img: usdt,
alt: 'Tether'
},
{
title: 'ETH',
img: eth,
alt: 'Ethereum'
}
]
export const convertConfig = {
cryptoInterval: 20000, // Crypto prices update interval in ms (default 5 seconds on Node.js & 15 seconds on Browsers)
fiatInterval: 60 * 1e3 * 60, // Fiat prices update interval (default every 1 hour)
calculateAverage: true, // Calculate the average crypto price from exchanges
binance: true, // Use binance rates
bitfinex: true, // Use bitfinex rates
coinbase: true, // Use coinbase rates
kraken: true, // Use kraken rates
HTTPAgent: null // HTTP Agent for server-side proxies (Node.js only)
}

View File

@ -0,0 +1,45 @@
import { ChangeEvent, Dispatch } from 'react'
import { convert } from '../index'
export const regexInput = (e: ChangeEvent<HTMLInputElement>) => {
let [_, sign, integer, decimals]: any = e.target.value
.replace(/[^\d\.\-]/g, '')
.replace(/(\..*?)\./g, '$1')
.replace(/(.+)-/g, '$1')
.match(/^(-?)(.*?)((?:\.\d*)?)$/)
let pos: number = Number(e.target.selectionStart) - 1
if (!integer && decimals) pos += 2
if (integer || decimals) {
integer = +integer
}
const formatted = sign + integer + decimals
if (formatted !== e.target.value) {
e.target.value = formatted
e.target.setSelectionRange(pos, pos)
}
}
export const getRelationToCurrency = async (
from: string,
to: string,
value: number,
setValue: Dispatch<string>
) => {
await convert.ready()
setValue(convert[from][to](value) || 0)
}
export const actualDate = () => `
${new Date(convert.lastUpdated).toLocaleDateString()}
${new Date(convert.lastUpdated)
.getHours()
.toString()
.padStart(2, '0')}:${new Date(convert.lastUpdated)
.getMinutes()
.toString()
.padStart(2, '0')}
`