Repository: rodrigorgtic/minha-carteira-dashboard Branch: master Commit: 85feee3561be Files: 59 Total size: 70.8 KB Directory structure: gitextract_4aoyh11l/ ├── .gitignore ├── README.md ├── package.json ├── public/ │ └── index.html ├── src/ │ ├── App.tsx │ ├── components/ │ │ ├── Aside/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── BarChartBox/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── Button/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── Content/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── ContentHeader/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── HistoryBox/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── HistoryFinanceCard/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── Input/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── Layout/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── MainHeader/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── MessageBox/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── PieChartBox/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── SelectInput/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── Toggle/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ └── WalletBox/ │ │ ├── index.tsx │ │ └── styles.ts │ ├── hooks/ │ │ ├── auth.tsx │ │ └── theme.tsx │ ├── index.tsx │ ├── pages/ │ │ ├── Dashboard/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── List/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ └── SignIn/ │ │ ├── index.tsx │ │ └── styles.ts │ ├── react-app-env.d.ts │ ├── repositories/ │ │ ├── expenses.ts │ │ └── gains.ts │ ├── routes/ │ │ ├── app.routes.tsx │ │ ├── auth.routes.tsx │ │ └── index.tsx │ ├── styles/ │ │ ├── GlobalStyles.ts │ │ ├── styled.d.ts │ │ └── themes/ │ │ ├── dark.ts │ │ └── light.ts │ └── utils/ │ ├── emojis.ts │ ├── formatCurrency.ts │ ├── formatDate.ts │ └── months.ts └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: README.md ================================================
Dashboard desenvolvido em **ReactJs** com **TypeScript** inteiramente componentizado com **componentes puros**.
Não há banco de dados. Os dados são carregados de 2 arquivos que contém arrays simulando os repositórios de dados. ### Layout & Componentes Responsivos
- [x] Link do prototipo desenvolvido no [**Figma**](https://www.figma.com/file/nOGmUkhcINJt6nd57R4ENu/Untitled?node-id=0%3A1). ### Layout & Componentes Responsivos - [x] Para os gráficos, foi utilizada a bibliteca [**Recharts**](http://recharts.org/en-US) que é opensource. - [x] Para efeito de número crescendo eu utilizei o [**React CountUp**](https://www.npmjs.com/package/react-countup).
Rodrigo Gonçalves Santana - 2020
================================================ FILE: package.json ================================================ { "name": "minha-carteira", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "@types/jest": "^24.0.0", "@types/node": "^12.0.0", "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", "@types/recharts": "^1.8.14", "react": "^16.13.1", "react-countup": "^4.3.3", "react-dom": "^16.13.1", "react-icons": "^3.10.0", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", "react-switch": "^5.0.1", "recharts": "^1.8.5", "styled-components": "^5.1.1", "typescript": "~3.7.2", "uuidv4": "^6.2.0" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "@types/react-router-dom": "^5.1.5", "@types/styled-components": "^5.1.1" } } ================================================ FILE: public/index.html ================================================ Minha Carteira
================================================ FILE: src/App.tsx ================================================ import React from 'react'; import { ThemeProvider } from 'styled-components'; import GlobalStyles from './styles/GlobalStyles'; import { useTheme } from './hooks/theme'; import Routes from './routes'; const App: React.FC = () => { const {theme} = useTheme(); return ( ); } export default App; ================================================ FILE: src/components/Aside/index.tsx ================================================ import React, {useState} from 'react'; import Toggle from '../Toggle'; import { MdDashboard, MdArrowDownward, MdArrowUpward, MdExitToApp, MdClose, MdMenu, } from 'react-icons/md'; import logoImg from '../../assets/logo.svg'; import { useAuth } from '../../hooks/auth'; import { useTheme } from '../../hooks/theme'; import { Container, Header, LogImg, Title, MenuContainer, MenuItemLink, MenuItemButton, ToggleMenu, ThemeToggleFooter, } from './styles'; const Aside: React.FC = () => { const { signOut } = useAuth(); const { toggleTheme, theme } = useTheme(); const [toggleMenuIsOpened, setToggleMenuIsOpened ] = useState(false); const [darkTheme, setDarkTheme] = useState(() => theme.title === 'dark' ? true : false); const handleToggleMenu = () => { setToggleMenuIsOpened(!toggleMenuIsOpened); } const handleChangeTheme = () => { setDarkTheme(!darkTheme); toggleTheme(); } return (
{ toggleMenuIsOpened ? : } Minha Carteira
Dashboard Entradas Saídas Sair
); } export default Aside; ================================================ FILE: src/components/Aside/styles.ts ================================================ import styled, { css } from 'styled-components'; interface IContainerProps { menuIsOpen: boolean; } interface IThemeToggleFooterProps { menuIsOpen: boolean; } export const Container = styled.div` grid-area: AS; background-color: ${props => props.theme.colors.secondary}; padding-left: 20px; border-right: 1px solid ${props => props.theme.colors.gray}; position: relative; @media(max-width: 600px){ padding-left: 20px; position: fixed; z-index: 2; width: 170px; height: ${props => props.menuIsOpen ? '100vh' : '70px'}; overflow: hidden; ${props => !props.menuIsOpen && css` border: none; border-bottom: 1px solid ${props => props.theme.colors.gray}; `}; } `; export const Header = styled.header` height: 70px; display: flex; align-items: center; `; export const LogImg = styled.img` height: 40px; width: 40px; @media(max-width: 600px){ display: none; } `; export const Title = styled.h3` color: ${props => props.theme.colors.white}; margin-left: 10px; @media(max-width: 600px){ display: none; } `; export const MenuContainer = styled.nav` display: flex; flex-direction: column; margin-top: 50px; `; export const MenuItemLink = styled.a` color: ${props => props.theme.colors.info}; text-decoration: none; margin: 7px 0; display: flex; align-items: center; transition: opacity .3s; &:hover { opacity: .7; } > svg { font-size: 18px; margin-right: 5px; } `; export const MenuItemButton = styled.button` font-size: 16px; color: ${props => props.theme.colors.info}; border: none; background: none; margin: 7px 0; display: flex; align-items: center; transition: opacity .3s; &:hover { opacity: .7; } > svg { font-size: 18px; margin-right: 5px; } `; export const ToggleMenu = styled.button` width: 40px; height: 40px; border-radius: 5px; font-size: 22px; background-color: ${props => props.theme.colors.warning}; color: ${props => props.theme.colors.white}; transition: opacity .3s; &:hover{ opacity: 0.7; } display: none; @media(max-width: 600px){ display: flex; justify-content: center; align-items: center; } `; export const ThemeToggleFooter = styled.footer` display: none; position: absolute; bottom: 30px; @media(max-width: 470px){ display: ${props => props.menuIsOpen ? 'flex' : 'none'}; } `; ================================================ FILE: src/components/BarChartBox/index.tsx ================================================ import React from 'react'; import { ResponsiveContainer, BarChart, Bar, Cell, Tooltip, } from 'recharts'; import formatCurrency from '../../utils/formatCurrency'; import { Container, SideLeft, SideRight, LegendContainer, Legend, } from './styles'; interface IBarChartProps { title: string; data: { name: string; amount: number; percent: number; color: string }[], } const BarChartBox: React.FC = ({ title, data }) => (

{title}

{ data.map((indicator) => (
{indicator.percent}%
{indicator.name}
)) }
{ data.map((indicator) => ( )) } formatCurrency(Number(value))} />
); export default BarChartBox; ================================================ FILE: src/components/BarChartBox/styles.ts ================================================ import styled, { keyframes } from 'styled-components'; interface ILegendProps { color: string; } const animate = keyframes` 0% { transform: translateX(100px); opacity: 0; } 50%{ opacity: .3; } 100%{ transform: translateX(0px); opacity: 1; } `; export const Container = styled.div` width: 48%; min-height: 260px; margin: 10px 0; background-color: ${props => props.theme.colors.tertiary}; color: ${props => props.theme.colors.white}; border-radius: 7px; display: flex; animation: ${animate} .5s; @media(max-width: 1200px){ display: flex; flex-direction: column; width: 100%; height: auto; } `; export const SideLeft = styled.aside` flex: 1; padding: 30px 20px; > h2 { padding-left: 16px; margin-bottom: 10px; } `; export const LegendContainer = styled.ul` list-style: none; height: 175px; padding-right: 15px; overflow-y: scroll; ::-webkit-scrollbar { width: 10px; } ::-webkit-scrollbar-thumb { background-color: ${props => props.theme.colors.secondary}; border-radius: 10px; } ::-webkit-scrollbar-track { background-color: ${props => props.theme.colors.tertiary}; } @media(max-width: 1200px){ display: flex; height: auto; } `; export const Legend = styled.li` display: flex; align-items: center; margin-bottom: 7px; padding-left: 16px; > div { background-color: ${props => props.color}; width: 40px; height: 40px; border-radius: 5px; font-size: 14px; line-height: 40px; text-align: center; } > span { margin-left: 5px; } @media(max-width: 1200px){ > div { width: 30px; height: 30px; font-size: 10px; line-height: 30px; } } `; export const SideRight = styled.main` flex: 1; min-height: 150px; display: flex; justify-content: center; padding-top: 35px; `; ================================================ FILE: src/components/Button/index.tsx ================================================ import React, { ButtonHTMLAttributes } from 'react'; import { Container } from './styles' type IButtonProps = ButtonHTMLAttributes; const Button: React.FC = ({children, ...rest }) => ( {children} ); export default Button; ================================================ FILE: src/components/Button/styles.ts ================================================ import styled from 'styled-components'; export const Container = styled.button` width: 100%; margin: 7px 0; padding: 10px; border-radius: 5px; font-weight: bold; color: ${props => props.theme.colors.white}; background-color: ${props => props.theme.colors.warning}; transition: opacity .3s; &:hover{ opacity: .7; } `; ================================================ FILE: src/components/Content/index.tsx ================================================ import React from 'react'; import { Container } from './styles'; const Content: React.FC = ({ children }) => ( {children} ); export default Content; ================================================ FILE: src/components/Content/styles.ts ================================================ import styled from 'styled-components'; export const Container = styled.div` grid-area: CT; color: ${props => props.theme.colors.white}; background-color: ${props => props.theme.colors.primary}; padding: 25px; height: calc(100vh - 70px); overflow-y: scroll; ::-webkit-scrollbar { width: 10px; } ::-webkit-scrollbar-thumb { background-color: ${props => props.theme.colors.secondary}; border-radius: 10px; } ::-webkit-scrollbar-track { background-color: ${props => props.theme.colors.tertiary}; } `; ================================================ FILE: src/components/ContentHeader/index.tsx ================================================ import React from 'react'; import { Container, TitleContainer, Controllers } from './styles'; interface IContentHeaderProps { title: string; lineColor: string; children: React.ReactNode; } const ContentHeader: React.FC = ({ title, lineColor, children }) => (

{title}

{children}
); export default ContentHeader; ================================================ FILE: src/components/ContentHeader/styles.ts ================================================ import styled from 'styled-components'; interface ITitleContainerProps { lineColor: string; } export const Container = styled.div` width: 100%; display: flex; justify-content: space-between; margin-bottom: 25px; @media(max-width: 320px){ flex-direction: column; } `; export const TitleContainer = styled.div` > h1 { color: ${props => props.theme.colors.white}; &::after { content: ''; display: block; width: 55px; border-bottom: 10px solid ${props => props.lineColor}; } } @media(max-width: 420px){ > h1 { font-size: 22px; &::after { content: ''; display: block; width: 55px; border-bottom: 5px solid ${props => props.lineColor}; } } } `; export const Controllers = styled.div` display: flex; @media(max-width: 320px){ width: 100%; justify-content: space-around; margin-top: 20px; } `; ================================================ FILE: src/components/HistoryBox/index.tsx ================================================ import React from 'react'; import { ResponsiveContainer, LineChart, Line, XAxis, CartesianGrid, Tooltip, } from 'recharts'; import formatCurrency from '../../utils/formatCurrency'; import { Container, ChartContainer, Header, LegendContainer, Legend, } from './styles'; interface IHistoryBoxProps { data: { month: string; amountEntry: number; amountOutput: number; }[], lineColorAmountEntry: string; lineColorAmountOutput: string; } const HistoryBox: React.FC = ({ data, lineColorAmountEntry, lineColorAmountOutput }) => (

Histórico de saldo

Entradas
Saídas
formatCurrency(Number(value))} />
) export default HistoryBox; ================================================ FILE: src/components/HistoryBox/styles.ts ================================================ import styled, {keyframes} from 'styled-components'; interface ILegendProps { color: string; } const animate = keyframes` 0% { transform: translateX(-100px); opacity: 0; } 50%{ opacity: .3; } 100%{ transform: translateX(0px); opacity: 1; } `; export const Container = styled.div` width: 100%; display: flex; flex-direction: column; background-color: ${props => props.theme.colors.tertiary}; color: ${props => props.theme.colors.white}; margin: 10px 0; padding: 30px 20px; border-radius: 7px; animation: ${animate} .5s; `; export const ChartContainer = styled.div` flex: 1; height: 260px; `; export const Header = styled.header` width: 100%; display: flex; justify-content: space-between; > h2 { margin-bottom: 20px; padding-left: 16px; } @media(max-width: 1200px){ flex-direction: column; } `; export const LegendContainer = styled.ul` list-style: none; display: flex; padding-right: 16px; `; export const Legend = styled.li` display: flex; align-items: center; margin-bottom: 7px; margin-left: 16px; > div { background-color: ${props => props.color}; width: 40px; height: 40px; border-radius: 5px; font-size: 14px; line-height: 40px; text-align: center; } > span { margin-left: 5px; } @media(max-width: 1280px){ > div { width: 30px; height: 30px; } } `; ================================================ FILE: src/components/HistoryFinanceCard/index.tsx ================================================ import React from 'react'; import { Container, Tag } from './styles'; interface IHistoryFinanceCardProps { tagColor: string; title: string; subtitle: string; amount: string; } const HistoryFinanceCard: React.FC = ({ tagColor, title, subtitle, amount }) => (
{title} {subtitle}

{amount}

); export default HistoryFinanceCard; ================================================ FILE: src/components/HistoryFinanceCard/styles.ts ================================================ import styled, { keyframes } from 'styled-components'; interface ITagProps { color: string; } const animate = keyframes` 0% { transform: translateX(-100px); opacity: 0; } 50%{ opacity: .3; } 100%{ transform: translateX(0px); opacity: 1; } `; export const Container = styled.li` background-color: ${props => props.theme.colors.tertiary}; list-style: none; border-radius: 10px; margin: 10px 0; padding: 12px 10px; display: flex; justify-content: space-between; align-items: center; cursor: pointer; transition: all .3s; position: relative; animation: ${animate} .5s ease; &:hover { opacity: .7; transform: translateX(10px); } > div { display: flex; flex-direction: column; justify-content: space-between; padding-left: 10px; } > div span { font-size: 22px; font-weight: 500; } `; export const Tag = styled.div` width: 13px; height: 60%; background-color: ${props => props.color}; position: absolute; left: 0; `; ================================================ FILE: src/components/Input/index.tsx ================================================ import React, { InputHTMLAttributes } from 'react'; import { Container } from './styles' type IInputProps = InputHTMLAttributes; const Input: React.FC = ({ ...rest }) => ( ); export default Input; ================================================ FILE: src/components/Input/styles.ts ================================================ import styled from 'styled-components'; export const Container = styled.input` width: 100%; margin: 7px 0; padding: 10px; border-radius: 5px; `; ================================================ FILE: src/components/Layout/index.tsx ================================================ import React from 'react'; import { Grid } from './styles'; import MainHeader from '../MainHeader'; import Aside from '../Aside'; import Content from '../Content'; const Layout: React.FC = ({ children }) => (