Skip to content

Commit 3a1a9d6

Browse files
committed
carousel implementation
1 parent 802874e commit 3a1a9d6

File tree

2 files changed

+156
-52
lines changed

2 files changed

+156
-52
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,120 @@
1-
import * as React from 'react';
2-
import AspectRatio from '@mui/joy/AspectRatio';
1+
import React, { useState, useEffect } from 'react';
32
import Box from '@mui/joy/Box';
43
import Typography from '@mui/joy/Typography';
5-
import Card from '@mui/joy/Card';
6-
7-
const data = [
8-
{
9-
src: 'https://images.unsplash.com/photo-1502657877623-f66bf489d236',
10-
title: 'Night view',
11-
description: '4.21M views',
12-
},
13-
{
14-
src: 'https://images.unsplash.com/photo-1527549993586-dff825b37782',
15-
title: 'Lake view',
16-
description: '4.74M views',
17-
},
18-
{
19-
src: 'https://images.unsplash.com/photo-1532614338840-ab30cf10ed36',
20-
title: 'Mountain view',
21-
description: '3.98M views',
22-
},
4+
import { styled } from '@mui/joy/styles';
5+
import { keyframes } from '@emotion/react';
6+
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
7+
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
8+
9+
const currencyData = [
10+
{ code: 'USD', name: 'Dólar', emoji: '🇺🇸' },
11+
{ code: 'EUR', name: 'Euro', emoji: '🇪🇺' },
12+
{ code: 'BTC', name: 'Bitcoin', emoji: '₿' },
13+
{ code: 'GBP', name: 'Libra', emoji: '🇬🇧' },
14+
{ code: 'ARS', name: 'Peso Argentino', emoji: '🇦🇷' },
15+
{ code: 'CLP', name: 'Peso Chileno', emoji: '🇨🇱' },
16+
{ code: 'JPY', name: 'Iene', emoji: '🇯🇵' }
2317
];
2418

25-
export default function CarouselRatio() {
19+
const slideAnimation = keyframes`
20+
0% {
21+
transform: translateX(0);
22+
}
23+
100% {
24+
transform: translateX(-16%);
25+
}
26+
`;
27+
28+
const CarouselContainer = styled(Box)(({ theme }) => ({
29+
width: '100%',
30+
position: 'relative',
31+
overflow: 'hidden',
32+
height: '40px',
33+
}));
34+
35+
const CarouselTrack = styled(Box)({
36+
display: 'inline-flex',
37+
animation: `${slideAnimation} 30s linear infinite`,
38+
width: '300%',
39+
});
40+
41+
const CarouselCard = styled(Box)(({ theme }) => ({
42+
flexShrink: 0,
43+
width: 'auto',
44+
minWidth: '250px',
45+
marginRight: theme.spacing(2),
46+
height: '30px',
47+
display: 'flex',
48+
alignItems: 'center',
49+
justifyContent: 'space-around',
50+
whiteSpace: 'nowrap',
51+
}));
52+
53+
export default function CurrencyCarousel() {
54+
const [currencyRates, setCurrencyRates] = useState([]);
55+
56+
useEffect(() => {
57+
const fetchCurrencyRates = async () => {
58+
try {
59+
const response = await fetch('https://economia.awesomeapi.com.br/last/USD-BRL,EUR-BRL,BTC-BRL,GBP-BRL,ARS-BRL,CLP-BRL,JPY-BRL');
60+
const data = await response.json();
61+
62+
const formattedRates = currencyData.map(currency => {
63+
const key = `${currency.code}BRL`;
64+
const currencyInfo = data[key];
65+
66+
return {
67+
...currency,
68+
price: parseFloat(currencyInfo.bid),
69+
variation: parseFloat(currencyInfo.pctChange)
70+
};
71+
});
72+
73+
setCurrencyRates(formattedRates);
74+
} catch (error) {
75+
console.error('Erro ao buscar cotações:', error);
76+
}
77+
};
78+
79+
fetchCurrencyRates();
80+
81+
const intervalId = setInterval(fetchCurrencyRates, 30 * 60 * 1000); // 30 minutos
82+
83+
return () => clearInterval(intervalId);
84+
}, []);
85+
86+
// Triplica os rates para criar loop infinito
87+
const repeatedRates = [...currencyRates, ...currencyRates, ...currencyRates];
88+
2689
return (
27-
<Box
28-
sx={{
29-
display: 'flex',
30-
gap: 1,
31-
py: 1,
32-
overflow: 'auto',
33-
width: 343,
34-
scrollSnapType: 'x mandatory',
35-
'& > *': {
36-
scrollSnapAlign: 'center',
37-
},
38-
'::-webkit-scrollbar': { display: 'none' },
39-
}}
40-
>
41-
{data.map((item) => (
42-
<Card orientation="horizontal" size="sm" key={item.title} variant="outlined">
43-
<AspectRatio ratio="1" sx={{ minWidth: 60 }}>
44-
<img
45-
srcSet={`${item.src}?h=120&fit=crop&auto=format&dpr=2 2x`}
46-
src={`${item.src}?h=120&fit=crop&auto=format`}
47-
alt={item.title}
48-
/>
49-
</AspectRatio>
50-
<Box sx={{ whiteSpace: 'nowrap', mx: 1 }}>
51-
<Typography level="title-md">{item.title}</Typography>
52-
<Typography level="body-sm">{item.description}</Typography>
53-
</Box>
54-
</Card>
55-
))}
56-
</Box>
90+
<CarouselContainer>
91+
<CarouselTrack>
92+
{repeatedRates.map((currency, index) => (
93+
<CarouselCard key={`${currency.code}-${index}`}>
94+
<Box display="flex" alignItems="center" justifyContent="space-around" sx={{ padding: '10px' }}>
95+
<Box display="flex" alignItems="center" gap={1}>
96+
<Typography>{currency.emoji}</Typography>
97+
<Typography variant="body2" sx={{ fontWeight: 'bold' }}>
98+
{currency.price.toLocaleString('pt-BR', {
99+
style: 'currency',
100+
currency: 'BRL',
101+
minimumFractionDigits: currency.price <= 0.01 ? 4 : 2,
102+
maximumFractionDigits: currency.price <= 0.01 ? 4 : 2
103+
})}
104+
</Typography>
105+
{currency.variation !== 0 && (
106+
<Box display="flex" alignItems="center" color={currency.variation > 0 ? 'green' : 'red'}>
107+
{currency.variation > 0 ? <ArrowUpwardIcon /> : <ArrowDownwardIcon />}
108+
<Typography variant="body2" sx={{ fontWeight: 'bold' }}>
109+
{Math.abs(currency.variation)}%
110+
</Typography>
111+
</Box>
112+
)}
113+
</Box>
114+
</Box>
115+
</CarouselCard>
116+
))}
117+
</CarouselTrack>
118+
</CarouselContainer>
57119
);
58-
}
120+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { styled } from '@mui/joy/styles';
2+
import { keyframes } from '@emotion/react';
3+
import Box from '@mui/joy/Box';
4+
import Card from '@mui/joy/Card';
5+
6+
const slideLeft = keyframes`
7+
from {
8+
transform: translateX(0);
9+
}
10+
to {
11+
transform: translateX(-100%);
12+
}
13+
`;
14+
15+
export const CarouselContainer = styled(Box)(({ theme }) => ({
16+
width: '100%',
17+
display: 'flex',
18+
gap: theme.spacing(1),
19+
height: '40px',
20+
alignItems: 'center',
21+
justifyContent: 'center',
22+
position: 'absolute',
23+
top: 0,
24+
left: 0,
25+
backgroundColor: 'transparent',
26+
overflow: 'hidden',
27+
}));
28+
29+
export const CarouselCard = styled(Card)(({ theme }) => ({
30+
width: '100%',
31+
maxWidth: 400,
32+
marginRight: theme.spacing(1),
33+
height: '30px',
34+
display: 'flex',
35+
alignItems: 'center',
36+
justifyContent: 'space-around',
37+
boxShadow: 'none',
38+
border: 'none',
39+
backgroundColor: 'transparent',
40+
animation: `${slideLeft} 10s linear infinite`,
41+
whiteSpace: 'nowrap',
42+
}));

0 commit comments

Comments
 (0)