(null),
10 | [email, setEmail] = useState(''),
11 | [valor, setValor] = useState(''),
12 | [mensagem, setMensagem] = useState('');
13 |
14 | useEffect(() => {
15 | ApiService.get('/pets')
16 | .then((resposta) => {
17 | setListaPets(resposta.data);
18 | })
19 | }, [])
20 |
21 | useEffect(() => {
22 | if(petSelecionado === null){
23 | limparFormulario();
24 | }
25 | }, [petSelecionado])
26 |
27 | function adotar(){
28 | if(petSelecionado !== null){
29 | if(validarDadosAdocao()){
30 | ApiService.post('/adocoes', {
31 | pet_id: petSelecionado.id,
32 | email,
33 | valor
34 | })
35 | .then(() => {
36 | setPetSelecionado(null);
37 | setMensagem('Pet adotado com sucesso!');
38 | // limparFormulario();
39 | })
40 | .catch((error: AxiosError) => {
41 | setMensagem(error.response?.data.message);
42 | })
43 | } else {
44 | setMensagem('Preencha todos os campos corretamente!')
45 | }
46 | }
47 | }
48 |
49 | function validarDadosAdocao(){
50 | return email.length > 0 && valor.length > 0;
51 | }
52 |
53 | function limparFormulario(){
54 | setEmail('');
55 | setValor('');
56 | }
57 |
58 | return {
59 | listaPets,
60 | petSelecionado,
61 | setPetSelecionado,
62 | email,
63 | setEmail,
64 | valor,
65 | setValor,
66 | mensagem,
67 | setMensagem,
68 | adotar
69 | };
70 | }
--------------------------------------------------------------------------------
/src/data/services/ApiService.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | export const ApiService = axios.create({
4 | baseURL: 'https://adote-um-pet-multistack.herokuapp.com/api',
5 | headers: {
6 | 'Content-Type': 'application/json'
7 | }
8 | })
9 |
10 |
--------------------------------------------------------------------------------
/src/data/services/TextService.ts:
--------------------------------------------------------------------------------
1 | export const TextService = {
2 | limitarTexto(texto: string, tamanhoMaximo: number): string{
3 | if(texto.length < tamanhoMaximo){
4 | return texto;
5 | }
6 | return texto.slice(0, tamanhoMaximo) + '...';
7 | }
8 | }
--------------------------------------------------------------------------------
/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '../ui/styles/globals.css'
2 | import type { AppProps } from 'next/app'
3 | import { ThemeProvider } from '@mui/material';
4 | import tema from '../ui/themes/tema';
5 | import Cabecalho from '../ui/components/Cabecalho/Cabecalho'
6 | import CabecalhoAdmin from '../ui/components/CabecalhoAdmin/CabecalhoAdmin'
7 | import { useRouter } from 'next/router';
8 |
9 | function MyApp({ Component, pageProps }: AppProps) {
10 | const router = useRouter();
11 |
12 | return (
13 |
14 | {router.pathname === '/' ? : }
15 |
16 |
17 | );
18 | }
19 |
20 | export default MyApp
21 |
--------------------------------------------------------------------------------
/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import type { NextPage } from 'next'
2 | import Titulo from '../ui/components/Titulo/Titulo';
3 | import Lista from '../ui/components/Lista/Lista'
4 | import { Dialog, TextField, Grid, DialogActions, Button, Snackbar } from '@mui/material'
5 | import { useIndex } from '../data/hooks/pages/useIndex';
6 |
7 | const Home: NextPage = () => {
8 | const {
9 | listaPets,
10 | petSelecionado,
11 | setPetSelecionado,
12 | email,
13 | setEmail,
14 | valor,
15 | setValor,
16 | mensagem,
17 | setMensagem,
18 | adotar
19 | } = useIndex();
20 |
21 | return (
22 |
23 |
27 | Com um pequeno valor mensal, você
28 | pode adotar um pet virtualmente
29 |
30 | } />
31 |
32 | setPetSelecionado(pet)}
35 | />
36 |
37 |
38 |
79 |
80 | 0}
82 | message={mensagem}
83 | autoHideDuration={2500}
84 | onClose={() => setMensagem('')}
85 | />
86 |
87 | )
88 | }
89 |
90 | export default Home
91 |
--------------------------------------------------------------------------------
/src/pages/pets/cadastro.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from 'next';
2 | import { useCadastro } from '../../data/hooks/pages/pets/useCadastro';
3 | import Titulo from '../../ui/components/Titulo/Titulo';
4 | import { Paper, Grid, TextField, Button, Snackbar } from '@mui/material';
5 |
6 |
7 | const Cadastro: NextPage = () => {
8 | const {
9 | nome,
10 | historia,
11 | foto,
12 | setNome,
13 | setHistoria,
14 | setFoto,
15 | cadastrar,
16 | mensagem,
17 | setMensagem
18 | } = useCadastro();
19 |
20 | return (
21 | <>
22 |
26 |
27 |
28 |
29 |
30 | setNome(e.target.value)}
33 | label={'Nome'}
34 | placeholder={'Digite o nome do pet'}
35 | fullWidth
36 | />
37 |
38 |
39 | setHistoria(e.target.value)}
42 | label={'História do Pet'}
43 | multiline
44 | fullWidth
45 | rows={4}
46 | />
47 |
48 |
49 | setFoto(e.target.value)}
52 | label={'Foto'}
53 | placeholder={'Digite o endereço da imagem'}
54 | fullWidth
55 | />
56 |
66 |
67 |
68 |
76 |
77 |
78 |
79 |
80 | 0}
82 | autoHideDuration={2500}
83 | onClose={() => setMensagem('')}
84 | message={mensagem}
85 | />
86 | >
87 | )
88 | }
89 |
90 | export default Cadastro;
--------------------------------------------------------------------------------
/src/pages/pets/relatorio.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from "next";
2 | import Titulo from '../../ui/components/Titulo/Titulo';
3 | import {
4 | Paper,
5 | TableContainer,
6 | Table,
7 | TableHead,
8 | TableRow,
9 | TableCell,
10 | TableBody
11 | } from '@mui/material';
12 | import { useRelatorio } from "../../data/hooks/pages/pets/useRelatorio";
13 |
14 | const Relatorio: NextPage = () => {
15 | const { listaRelatorio } = useRelatorio();
16 | return (
17 | <>
18 |
22 |
26 |
27 |
28 |
29 | Pet
30 | E-mail
31 | Valor Mensal
32 |
33 |
34 |
35 | {listaRelatorio.map((relatorio) => (
36 |
37 | {relatorio.pet.nome}
38 | {relatorio.email}
39 | {relatorio.valor}
40 |
41 | ))}
42 |
43 |
44 |
45 | >
46 | )
47 | }
48 |
49 | export default Relatorio;
--------------------------------------------------------------------------------
/src/ui/components/Cabecalho/Cabecalho.style.tsx:
--------------------------------------------------------------------------------
1 | import { styled } from '@mui/material';
2 |
3 | export const CabecalhoContainer = styled('header')`
4 | display: flex;
5 | justify-content: center;
6 | border-bottom: 1px solid #f0f0f0;
7 | padding: ${({theme}) => theme.spacing(6)};
8 | `;
9 |
10 |
11 |
12 | export const Logo = styled('img')`
13 | width: 230px;
14 | `;
--------------------------------------------------------------------------------
/src/ui/components/Cabecalho/Cabecalho.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | CabecalhoContainer,
3 | Logo
4 | } from './Cabecalho.style';
5 |
6 | export default function Cabecalho(){
7 | return(
8 |
9 |
10 |
11 | )
12 | }
--------------------------------------------------------------------------------
/src/ui/components/CabecalhoAdmin/CabecalhoAdmin.style.tsx:
--------------------------------------------------------------------------------
1 | import { styled } from '@mui/material';
2 |
3 | export const CabecalhoContainer = styled('header')`
4 | height: 115px;
5 | background-color: #f6f6f6;
6 | padding: ${({ theme }) => theme.spacing(2) };
7 |
8 | div {
9 | height: 100%;
10 | max-width: 970px;
11 | margin: 0 auto;
12 | display: flex;
13 | justify-content: space-between;
14 | align-items: center;
15 | gap: ${({ theme }) => theme.spacing(2) };
16 | }
17 |
18 | a{
19 | font-size: 14px;
20 | }
21 | `;
22 |
23 | export const Logo = styled('img')`
24 | width: 125px;
25 | `;
26 |
27 | export const LinksContainer = styled('nav')`
28 | display: flex;
29 | gap: ${({ theme }) => theme.spacing(2) };
30 | flex-wrap: wrap;
31 | justify-content: flex-end;
32 | `;
--------------------------------------------------------------------------------
/src/ui/components/CabecalhoAdmin/CabecalhoAdmin.tsx:
--------------------------------------------------------------------------------
1 | import { Link, Box } from '@mui/material';
2 | import NextLink from 'next/link';
3 | import {
4 | CabecalhoContainer,
5 | Logo,
6 | LinksContainer
7 | } from './CabecalhoAdmin.style';
8 |
9 | export default function CabecalhoAdmin(){
10 | return (
11 |
12 |
31 |
32 | )
33 | }
--------------------------------------------------------------------------------
/src/ui/components/Lista/Lista.style.tsx:
--------------------------------------------------------------------------------
1 | import { styled } from '@mui/material';
2 |
3 | export const ListaStyled = styled('ul')`
4 | width: 100%;
5 | max-width: 800px;
6 | margin: 0 auto;
7 | padding: ${({ theme }) => theme.spacing(2) };
8 | `
9 |
10 | export const ItemLista = styled('li')`
11 | display: grid;
12 | grid-template-columns: repeat(2, 1fr);
13 | gap: ${({ theme }) => theme.spacing(5) };
14 | margin-bottom: ${({ theme }) => theme.spacing(5) };
15 |
16 | ${({ theme }) => theme.breakpoints.down('md') } {
17 | grid-template-columns: 1fr;
18 | gap: ${({ theme }) => theme.spacing(2) };
19 | margin-bottom: ${({ theme }) => theme.spacing(10) };
20 | }
21 | `
22 |
23 | export const Foto = styled('img')`
24 | width: 100%;
25 | `
26 |
27 | export const Informacoes = styled('div')`
28 | display: flex;
29 | flex-direction: column;
30 | gap: ${({ theme }) => theme.spacing(2) };
31 | `
32 |
33 | export const Nome = styled('h2')`
34 | margin: 0;
35 | `;
36 |
37 | export const Descricao = styled('p')`
38 | margin: 0;
39 | word-break: break-word;
40 | `;
--------------------------------------------------------------------------------
/src/ui/components/Lista/Lista.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from '@mui/material'
2 | import {
3 | ListaStyled,
4 | ItemLista,
5 | Foto,
6 | Informacoes,
7 | Nome,
8 | Descricao
9 | } from './Lista.style'
10 | import { Pet } from '../../../data/@types/Pet'
11 | import { TextService } from '../../../data/services/TextService';
12 |
13 | interface ListaProps{
14 | pets: Pet[];
15 | onSelect: (pet: Pet) => void;
16 | }
17 |
18 | export default function Lista(props: ListaProps){
19 | const tamanhoMaximoTexto = 200;
20 |
21 | return (
22 |
23 | {props.pets.map(pet => (
24 |
25 |
26 |
27 | {pet.nome}
28 |
29 | {TextService.limitarTexto(pet.historia, tamanhoMaximoTexto)}
30 |
31 |
38 |
39 |
40 | ))}
41 |
42 | )
43 | }
--------------------------------------------------------------------------------
/src/ui/components/Titulo/Titulo.style.tsx:
--------------------------------------------------------------------------------
1 | import { styled } from '@mui/material';
2 |
3 | export const TituloStyled = styled('h1')`
4 | font-size: 20px;
5 | text-align: center;
6 | margin-top: ${({ theme }) => theme.spacing(5) };
7 | `;
8 |
9 | export const Subtitulo = styled('h2')`
10 | font-size: 18px;
11 | text-align: center;
12 | margin-bottom: ${({ theme }) => theme.spacing(5) };
13 | font-weight: normal;
14 | color: ${({ theme }) => theme.palette.text.secondary };
15 | `;
--------------------------------------------------------------------------------
/src/ui/components/Titulo/Titulo.tsx:
--------------------------------------------------------------------------------
1 | import { TituloStyled, Subtitulo } from "./Titulo.style";
2 |
3 | interface TituloProps {
4 | titulo: string;
5 | subtitulo?: string | JSX.Element;
6 | }
7 |
8 | export default function Titulo(props: TituloProps){
9 | return (
10 | <>
11 | {props.titulo}
12 | {props.subtitulo}
13 | >
14 | )
15 | }
--------------------------------------------------------------------------------
/src/ui/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
--------------------------------------------------------------------------------
/src/ui/themes/tema.ts:
--------------------------------------------------------------------------------
1 | import { createTheme } from '@mui/material';
2 |
3 | const tema = createTheme({
4 | palette: {
5 | primary: {
6 | main: '#AE0FEA',
7 | },
8 | secondary: {
9 | main: '#C5C5C5',
10 | },
11 | text: {
12 | primary: '#293845',
13 | secondary: '#9EADBA',
14 | },
15 | },
16 | typography: {
17 | fontFamily: 'Roboto, sans-serif',
18 | },
19 | shape: {
20 | borderRadius: '3px',
21 | },
22 | components: {
23 | MuiButton: {
24 | styleOverrides: {
25 | root: {
26 | textTransform: 'none',
27 | borderRadius: '5px',
28 | fontWeight: 'normal',
29 | },
30 | },
31 | },
32 | MuiPaper: {
33 | styleOverrides: {
34 | root: {
35 | boxShadow: '0px 0px 39px rgba(0, 0, 0, 0.05)',
36 | },
37 | },
38 | },
39 | MuiTextField: {
40 | defaultProps: {
41 | InputLabelProps: {
42 | required: false,
43 | },
44 | required: true,
45 | },
46 | },
47 | MuiTableHead: {
48 | styleOverrides: {
49 | root: {
50 | '& .MuiTableCell-root': {
51 | fontWeight: 'bold',
52 | },
53 | },
54 | },
55 | },
56 | MuiTableCell: {
57 | styleOverrides: {
58 | root: {
59 | border: '1px solid #D8D8D8',
60 | },
61 | },
62 | },
63 | },
64 | })
65 |
66 | export default tema;
67 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true
17 | },
18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
19 | "exclude": ["node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------