├── backend
├── .babelrc
├── src
│ ├── utils
│ │ └── database.js
│ ├── index.js
│ ├── models
│ │ └── newsModel.js
│ ├── services
│ │ └── newsService.js
│ └── contollers
│ │ └── newsController.js
├── package.json
├── README.md
└── .gitignore
├── portal-noticias
├── public
│ ├── robots.txt
│ ├── logo.png
│ ├── favicon.ico
│ ├── manifest.json
│ └── index.html
├── src
│ ├── logo.png
│ ├── setupTests.js
│ ├── App.test.js
│ ├── index.css
│ ├── reportWebVitals.js
│ ├── index.js
│ ├── NoticiaDetalhada.js
│ ├── NoticiaDetalhada.css
│ ├── logo.svg
│ ├── FormularioNoticia.js
│ ├── App.js
│ └── App.css
├── .gitignore
├── package.json
└── README.md
├── README.md
└── .gitignore
/backend/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"]
3 | }
--------------------------------------------------------------------------------
/portal-noticias/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/portal-noticias/src/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbotelhoo/hackathon-fiap/HEAD/portal-noticias/src/logo.png
--------------------------------------------------------------------------------
/portal-noticias/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbotelhoo/hackathon-fiap/HEAD/portal-noticias/public/logo.png
--------------------------------------------------------------------------------
/portal-noticias/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbotelhoo/hackathon-fiap/HEAD/portal-noticias/public/favicon.ico
--------------------------------------------------------------------------------
/portal-noticias/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/portal-noticias/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render();
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/backend/src/utils/database.js:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 | import 'dotenv/config';
3 |
4 | const URI = process.env.DB_DATABASE;
5 |
6 | const databaseConnection = async () => {
7 | if(!global.mongoose){
8 | mongoose.set('strictQuery', false)
9 | global.mongoose = await mongoose.connect(URI)
10 | }
11 | }
12 |
13 | export default databaseConnection
--------------------------------------------------------------------------------
/portal-noticias/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/portal-noticias/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/portal-noticias/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/backend/src/index.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import bodyParser from 'body-parser';
3 | import newsController from './contollers/newsController';
4 | import 'dotenv/config';
5 |
6 | const app = express();
7 | const port = process.env.PORT;
8 | const cors = require('cors');
9 |
10 | app.use(bodyParser.json());
11 | app.use(cors());
12 | app.use('/news', newsController);
13 |
14 | app.listen(port, () => {
15 | console.log(`App rodando em http://localhost:${port}`);
16 | });
17 |
--------------------------------------------------------------------------------
/backend/src/models/newsModel.js:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 |
3 | const NewsSchema = new mongoose.Schema({
4 | titulo: { type: String, require: true },
5 | conteudo: {type: String, require: true},
6 | autor: {type: String, require: true},
7 | dataPublicacao: { type: Date, default: Date.now },
8 | categoria: {type: String, require: true},
9 | imagemUrl: {type: String, require: true}
10 | });
11 |
12 | export default mongoose.models.Noticia || mongoose.model('Noticia', NewsSchema);
--------------------------------------------------------------------------------
/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "backend",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "nodemon --exec babel-node src/index.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "babel-cli": "^6.26.0",
14 | "babel-preset-env": "^1.7.0",
15 | "body-parser": "^1.20.3",
16 | "cors": "^2.8.5",
17 | "dotenv": "^16.4.7",
18 | "express": "^4.18.2",
19 | "mongoose": "^8.10.0"
20 | },
21 | "devDependencies": {
22 | "nodemon": "^2.0.20"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/portal-noticias/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/portal-noticias/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/portal-noticias/src/NoticiaDetalhada.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useParams } from "react-router-dom";
3 | import "./NoticiaDetalhada.css";
4 |
5 | const NoticiaDetalhada = ({ noticias }) => {
6 | const { id } = useParams();
7 | const noticia = noticias.find((item) => item._id === id);
8 |
9 | if (!noticia) {
10 | return
Notícia não encontrada.
;
11 | }
12 |
13 | return (
14 |
15 |
{noticia.titulo}
16 |

17 |
18 | Por {noticia.autor} em {noticia.dataPublicacao}
19 |
20 |
{noticia.conteudo}
21 |
22 | );
23 | };
24 |
25 | export default NoticiaDetalhada;
--------------------------------------------------------------------------------
/backend/src/services/newsService.js:
--------------------------------------------------------------------------------
1 | import databaseConnection from "../utils/database.js";
2 | import newsModel from "../models/newsModel.js";
3 |
4 |
5 | export const listaNoticias = async () => {
6 | await databaseConnection();
7 | const noticias = await newsModel.find()
8 | return noticias;
9 | };
10 |
11 | export const createNoticia = async (noticia) => {
12 | await databaseConnection();
13 | const createNoticia = await newsModel.create(noticia);
14 | return createNoticia;
15 | };
16 |
17 | export const atualizaNoticia = async (id, noticia) => {
18 | await databaseConnection();
19 | const atualizaNoticia = await newsModel.findByIdAndUpdate(id, noticia, { new: true});
20 | return atualizaNoticia
21 | };
22 |
23 | export const deletaNoticia = async (id) => {
24 | await databaseConnection();
25 | const deletaNoticia = await newsModel.findByIdAndDelete(id);
26 | return deletaNoticia
27 | }
--------------------------------------------------------------------------------
/backend/README.md:
--------------------------------------------------------------------------------
1 | # Fiap News Backend
2 |
3 | Este é o backend do projeto Fiap News, uma API para gerenciar notícias.
4 |
5 | ## Funcionalidades
6 |
7 | - Listar todas as notícias
8 | - Filtrar notícias por categoria
9 | - Publicar uma nova notícia
10 |
11 | ## Rotas da API
12 |
13 | ### Listar todas as notícias
14 |
15 | **GET** `/news`
16 |
17 | #### Parâmetros de Query
18 |
19 | - `categoria` (opcional): Filtra as notícias pela categoria especificada.
20 |
21 | #### Respostas
22 |
23 | - `200 OK`: Retorna uma lista de notícias.
24 | - `404 Not Found`: Nenhuma notícia encontrada para a categoria especificada.
25 | - `500 Internal Server Error`: Erro interno do servidor.
26 |
27 | ### Publicar uma nova notícia
28 |
29 | **POST** `/news/publicarNoticia`
30 |
31 | #### Corpo da Requisição
32 |
33 | ```json
34 | {
35 | "titulo": "Título da notícia",
36 | "conteudo": "Conteúdo da notícia",
37 | "autor": "Autor da notícia",
38 | "categoria": "Categoria da notícia",
39 | "imagemUrl": "URL da imagem da notícia"
40 | }
--------------------------------------------------------------------------------
/portal-noticias/src/NoticiaDetalhada.css:
--------------------------------------------------------------------------------
1 | .noticia-detalhada {
2 | max-width: 800px;
3 | margin: 20px auto;
4 | padding: 20px;
5 | background: #fff; /* Branco */
6 | border-radius: 8px;
7 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .noticia-detalhada h1 {
11 | color: #333; /* Cinza escuro */
12 | margin-bottom: 20px;
13 | }
14 |
15 | .noticia-imagem {
16 | width: 100%;
17 | height: auto;
18 | border-radius: 8px;
19 | margin-bottom: 20px;
20 | }
21 |
22 | .noticia-meta {
23 | font-size: 0.9rem;
24 | color: #777; /* Cinza médio */
25 | margin-bottom: 20px;
26 | }
27 |
28 | .noticia-detalhada p {
29 | color: #555; /* Cinza escuro */
30 | line-height: 1.6;
31 | }
32 |
33 | .back-button {
34 | display: inline-block;
35 | margin-top: 20px;
36 | padding: 10px 20px;
37 | background: #333; /* Preto */
38 | color: #fff; /* Branco */
39 | text-decoration: none;
40 | border-radius: 5px;
41 | transition: background-color 0.3s ease;
42 | }
43 |
44 | .back-button:hover {
45 | background: #555; /* Cinza escuro */
46 | }
--------------------------------------------------------------------------------
/portal-noticias/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "portal-noticias",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/dom": "^10.4.0",
7 | "@testing-library/jest-dom": "^6.6.3",
8 | "@testing-library/react": "^16.2.0",
9 | "@testing-library/user-event": "^13.5.0",
10 | "react": "^19.0.0",
11 | "react-dom": "^19.0.0",
12 | "react-router-dom": "^7.1.5",
13 | "react-scripts": "5.0.1",
14 | "web-vitals": "^2.1.4"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test",
20 | "eject": "react-scripts eject"
21 | },
22 | "eslintConfig": {
23 | "extends": [
24 | "react-app",
25 | "react-app/jest"
26 | ]
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Projeto desenvolvido pelo Grupo 4 da PosTech FIAP
2 |
3 | Integrantes:
4 | Gustavo Chiarantano Godinho
5 | gustavogodinho2000@gmail.com
6 |
7 | Vitor Hugo Botelho
8 | vt.botelhoo@gmail.com
9 |
10 | Ronaldo Miranda Valenga
11 | ronaldovalenga95@gmail.com
12 |
13 | Lucas Napoleão Arantes de Sousa
14 | luknapoleao@hotmail.com
15 |
16 | José Rafael da Silva Ferreira
17 | josersf1@gmail.com
18 |
19 |
20 |
21 | PASSO A PASSO PARA INICIALIZAR O PROJETO:
22 |
23 | - Primeiramente configure as variaveis de ambiente necessárias com a utilização do .env dentro da pasta /backend
24 | - As variáveis que devem ser preenchidas são: PORT (porta que será iniciado o projeto backend - não utilizar a porta 3000) e DB_DATABASE (URI completa do banco de dados mongoDB)
25 | - Para fins de avaliação do projeto, será fornecido no portal do aluno o .env já configurado para utilização da avaliação.
26 |
27 | - Agora, navegando através do terminal, adentre a pasta /backend e incie o projeto com o comando 'npm run dev'
28 |
29 | - Após o backend estar ativo, abra um novo terminal e navegue até a pasta /portal-noticias e inicie o projeto com o comando 'npm start'
30 |
31 | - Com isso deve ser incializado o navegador na url http://localhost:3000/ com o projeto funcionando.
32 |
--------------------------------------------------------------------------------
/portal-noticias/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | FIAP Tech News
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/portal-noticias/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/src/contollers/newsController.js:
--------------------------------------------------------------------------------
1 | import { Router } from "express";
2 | import { listaNoticias, createNoticia, atualizaNoticia, deletaNoticia} from "../services/newsService.js";
3 |
4 | const router = Router();
5 |
6 | router.get('/', async (req, res) =>{
7 | try {
8 | // Chama a função listaNoticias para pegar todas as notícias do banco
9 | const noticias = await listaNoticias();
10 |
11 | // Verificando se foi passado um filtro pela categoria
12 | const categoriaFiltro = req.query.categoria;
13 |
14 | let noticiasFiltradas = noticias;
15 |
16 | // Se uma categoria for especificada, filtra as notícias pela categoria
17 | if (categoriaFiltro) {
18 | noticiasFiltradas = noticias.filter(n => n.categoria.toLowerCase() === categoriaFiltro.toLowerCase());
19 | }
20 |
21 | // Se houver notícias filtradas ou todas as notícias, retorna elas
22 | if (noticiasFiltradas.length > 0) {
23 | return res.status(200).json(noticiasFiltradas);
24 | } else {
25 | return res.status(404).json({ error: "Nenhuma notícia encontrada para a categoria especificada" });
26 | }
27 | } catch (error) {
28 | console.error('Erro ao processar a requisição:', error);
29 | return res.status(500).json({ error: "Erro interno do servidor" });
30 | }
31 | })
32 |
33 | router.post('/publicarNoticia', async (req, res) =>{
34 | try {
35 | const noticia = await createNoticia(req.body)
36 | res.status(201).send(noticia);
37 | } catch (error) {
38 | res.status(400).send(error)
39 | }
40 | })
41 |
42 | router.put('/atualizaNoticia/:id', async (req, res) => {
43 | try {
44 | const { id } = req.params;
45 | const atualizacao = req.body;
46 | const noticia = await atualizaNoticia(id, atualizacao)
47 |
48 | if (!noticia){
49 | return res.status(404).json({ mensagem: "Noticia não encontrada"});
50 | }
51 |
52 | res.status(201).send(noticia)
53 | } catch (error) {
54 | res.status(400).send(error)
55 | }
56 | }
57 | )
58 |
59 | router.delete('/deletaNoticia/:id', async (req, res) => {
60 | try {
61 | const { id } = req.params;
62 | const noticia = await deletaNoticia(id);
63 |
64 | if (!noticia) {
65 | return res.status(404).json({ mensagem: "Notícia não encontrada" });
66 | }
67 | res.status(200).json({ mensagem: "Notícia deletada com sucesso" });
68 | } catch (error) {
69 | res.status(400).send(error)
70 | }
71 | })
72 |
73 | export default router;
--------------------------------------------------------------------------------
/portal-noticias/src/FormularioNoticia.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | const FormularioNoticia = ({ onAdicionarNoticia }) => {
4 | const [titulo, setTitulo] = useState("");
5 | const [conteudo, setConteudo] = useState("");
6 | const [autor, setAutor] = useState("");
7 | const [categoria, setCategoria] = useState("");
8 | const [imagemUrl, setImagemUrl] = useState("");
9 |
10 | const handleSubmit = async (e) => {
11 | e.preventDefault();
12 | const novaNoticia = {
13 | titulo,
14 | conteudo,
15 | autor,
16 | categoria,
17 | imagemUrl,
18 | };
19 |
20 | try {
21 | const response = await fetch("http://localhost:3002/news/publicarNoticia", {
22 | method: "POST",
23 | headers: {
24 | "Content-Type": "application/json",
25 | },
26 | body: JSON.stringify(novaNoticia),
27 | });
28 |
29 | if (!response.ok) throw new Error("Erro ao adicionar notícia");
30 |
31 | onAdicionarNoticia(novaNoticia);
32 | alert("Notícia adicionada com sucesso!");
33 | } catch (error) {
34 | alert(error.message);
35 | }
36 | };
37 |
38 | return (
39 |
87 | );
88 | };
89 |
90 | export default FormularioNoticia;
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 | .pnpm-debug.log*
9 |
10 | # Diagnostic reports (https://nodejs.org/api/report.html)
11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12 |
13 | # Runtime data
14 | pids
15 | *.pid
16 | *.seed
17 | *.pid.lock
18 |
19 | # Directory for instrumented libs generated by jscoverage/JSCover
20 | lib-cov
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | *.lcov
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # Bower dependency directory (https://bower.io/)
33 | bower_components
34 |
35 | # node-waf configuration
36 | .lock-wscript
37 |
38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
39 | build/Release
40 |
41 | # Dependency directories
42 | node_modules/
43 | jspm_packages/
44 |
45 | # Snowpack dependency directory (https://snowpack.dev/)
46 | web_modules/
47 |
48 | # TypeScript cache
49 | *.tsbuildinfo
50 |
51 | # Optional npm cache directory
52 | .npm
53 |
54 | # Optional eslint cache
55 | .eslintcache
56 |
57 | # Optional stylelint cache
58 | .stylelintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variable files
76 | .env
77 | .env.development.local
78 | .env.test.local
79 | .env.production.local
80 | .env.local
81 |
82 | # parcel-bundler cache (https://parceljs.org/)
83 | .cache
84 | .parcel-cache
85 |
86 | # Next.js build output
87 | .next
88 | out
89 |
90 | # Nuxt.js build / generate output
91 | .nuxt
92 | dist
93 |
94 | # Gatsby files
95 | .cache/
96 | # Comment in the public line in if your project uses Gatsby and not Next.js
97 | # https://nextjs.org/blog/next-9-1#public-directory-support
98 | # public
99 |
100 | # vuepress build output
101 | .vuepress/dist
102 |
103 | # vuepress v2.x temp and cache directory
104 | .temp
105 | .cache
106 |
107 | # Docusaurus cache and generated files
108 | .docusaurus
109 |
110 | # Serverless directories
111 | .serverless/
112 |
113 | # FuseBox cache
114 | .fusebox/
115 |
116 | # DynamoDB Local files
117 | .dynamodb/
118 |
119 | # TernJS port file
120 | .tern-port
121 |
122 | # Stores VSCode versions used for testing VSCode extensions
123 | .vscode-test
124 |
125 | # yarn v2
126 | .yarn/cache
127 | .yarn/unplugged
128 | .yarn/build-state.yml
129 | .yarn/install-state.gz
130 | .pnp.*
131 |
--------------------------------------------------------------------------------
/backend/.gitignore:
--------------------------------------------------------------------------------
1 | <<<<<<< HEAD
2 | # Logs
3 | logs
4 | *.log
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 | lerna-debug.log*
9 | .pnpm-debug.log*
10 |
11 | # Diagnostic reports (https://nodejs.org/api/report.html)
12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13 |
14 | # Runtime data
15 | pids
16 | *.pid
17 | *.seed
18 | *.pid.lock
19 |
20 | # Directory for instrumented libs generated by jscoverage/JSCover
21 | lib-cov
22 |
23 | # Coverage directory used by tools like istanbul
24 | coverage
25 | *.lcov
26 |
27 | # nyc test coverage
28 | .nyc_output
29 |
30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
31 | .grunt
32 |
33 | # Bower dependency directory (https://bower.io/)
34 | bower_components
35 |
36 | # node-waf configuration
37 | .lock-wscript
38 |
39 | # Compiled binary addons (https://nodejs.org/api/addons.html)
40 | build/Release
41 |
42 | # Dependency directories
43 | node_modules/
44 | jspm_packages/
45 |
46 | # Snowpack dependency directory (https://snowpack.dev/)
47 | web_modules/
48 |
49 | # TypeScript cache
50 | *.tsbuildinfo
51 |
52 | # Optional npm cache directory
53 | .npm
54 |
55 | # Optional eslint cache
56 | .eslintcache
57 |
58 | # Optional stylelint cache
59 | .stylelintcache
60 |
61 | # Microbundle cache
62 | .rpt2_cache/
63 | .rts2_cache_cjs/
64 | .rts2_cache_es/
65 | .rts2_cache_umd/
66 |
67 | # Optional REPL history
68 | .node_repl_history
69 |
70 | # Output of 'npm pack'
71 | *.tgz
72 |
73 | # Yarn Integrity file
74 | .yarn-integrity
75 |
76 | # dotenv environment variable files
77 | .env
78 | .env.development.local
79 | .env.test.local
80 | .env.production.local
81 | .env.local
82 |
83 | # parcel-bundler cache (https://parceljs.org/)
84 | .cache
85 | .parcel-cache
86 |
87 | # Next.js build output
88 | .next
89 | out
90 |
91 | # Nuxt.js build / generate output
92 | .nuxt
93 | dist
94 |
95 | # Gatsby files
96 | .cache/
97 | # Comment in the public line in if your project uses Gatsby and not Next.js
98 | # https://nextjs.org/blog/next-9-1#public-directory-support
99 | # public
100 |
101 | # vuepress build output
102 | .vuepress/dist
103 |
104 | # vuepress v2.x temp and cache directory
105 | .temp
106 | .cache
107 |
108 | # Docusaurus cache and generated files
109 | .docusaurus
110 |
111 | # Serverless directories
112 | .serverless/
113 |
114 | # FuseBox cache
115 | .fusebox/
116 |
117 | # DynamoDB Local files
118 | .dynamodb/
119 |
120 | # TernJS port file
121 | .tern-port
122 |
123 | # Stores VSCode versions used for testing VSCode extensions
124 | .vscode-test
125 |
126 | # yarn v2
127 | .yarn/cache
128 | .yarn/unplugged
129 | .yarn/build-state.yml
130 | .yarn/install-state.gz
131 | .pnp.*
132 | =======
133 | node_modules
134 | >>>>>>> ceea8d9 (primeiro commit)
135 |
--------------------------------------------------------------------------------
/portal-noticias/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13 |
14 | The page will reload when you make changes.\
15 | You may also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!**
35 |
36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
39 |
40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
48 | ### Code Splitting
49 |
50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51 |
52 | ### Analyzing the Bundle Size
53 |
54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55 |
56 | ### Making a Progressive Web App
57 |
58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59 |
60 | ### Advanced Configuration
61 |
62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63 |
64 | ### Deployment
65 |
66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67 |
68 | ### `npm run build` fails to minify
69 |
70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
71 |
--------------------------------------------------------------------------------
/portal-noticias/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
3 | import "./App.css";
4 | import NoticiaDetalhada from "./NoticiaDetalhada";
5 | import FormularioNoticia from "./FormularioNoticia";
6 | import logo from "./logo.png";
7 |
8 | const App = () => {
9 | const [data, setData] = useState([]);
10 | const [loading, setLoading] = useState(true);
11 | const [error, setError] = useState(null);
12 | const [selectedCategory, setSelectedCategory] = useState("Todas");
13 |
14 | useEffect(() => {
15 | const fetchData = async () => {
16 | try {
17 | const response = await fetch("http://localhost:3002/news/");
18 | if (!response.ok) throw new Error("Erro ao buscar dados");
19 |
20 | const result = await response.json();
21 | setData(result);
22 | } catch (error) {
23 | setError(error.message);
24 | } finally {
25 | setLoading(false);
26 | }
27 | };
28 |
29 | fetchData();
30 | }, []);
31 |
32 | const categories = ["Todas", "Ultimas Novidades", "Front-end", "Backend", "Cloud", "Inteligência Artificial"];
33 |
34 | const shuffleArray = (array) => array.sort(() => Math.random() - 0.5);
35 |
36 | const filteredData =
37 | selectedCategory === "Todas"
38 | ? shuffleArray([...data])
39 | : selectedCategory === "Ultimas Novidades"
40 | ? [...data].sort((a, b) => new Date(b.dataPublicacao) - new Date(a.dataPublicacao))
41 | : data.filter((item) => item.categoria === selectedCategory);
42 |
43 | const handleAdicionarNoticia = (novaNoticia) => {
44 | setData([...data, novaNoticia]);
45 | };
46 |
47 | if (loading) return Carregando...
;
48 | if (error) return Erro: {error}
;
49 |
50 | return (
51 |
52 |
53 |
54 |
55 |
70 |
71 |
72 |
76 | {filteredData.map((item) => (
77 |
78 |
79 | {item.titulo}
80 |
81 | {item.autor} | {new Date(item.dataPublicacao).toLocaleDateString()}
82 |
83 | {item.conteudo.slice(0, 100)}...
84 |
85 | Leia mais
86 |
87 |
88 | ))}
89 |
90 | }
91 | />
92 | } />
93 | } />
94 |
95 |
98 |
99 |
100 | );
101 | };
102 |
103 | export default App;
--------------------------------------------------------------------------------
/portal-noticias/src/App.css:
--------------------------------------------------------------------------------
1 | /* Estilos gerais */
2 | .news-site {
3 | font-family: 'Arial', sans-serif;
4 | background-color: #f5f5f5; /* Cinza claro para o fundo */
5 | color: #333; /* Cinza escuro para o texto */
6 | min-height: 100vh;
7 | display: flex;
8 | flex-direction: column;
9 | }
10 |
11 | /* Cabeçalho */
12 | .header {
13 | background: #333; /* Preto */
14 | color: #fff; /* Branco */
15 | padding: 20px;
16 | text-align: center;
17 | }
18 |
19 | .header h1 {
20 | margin: 0;
21 | font-size: 2rem;
22 | }
23 |
24 | .logo {
25 | width: 450px; /* Ajuste conforme necessário */
26 | height: auto;
27 | margin-right: 10px;
28 | }
29 |
30 | /* Menu de categorias */
31 | .category-menu {
32 | display: flex;
33 | justify-content: center;
34 | flex-wrap: wrap;
35 | gap: 10px;
36 | margin: 20px 0;
37 | padding: 0 20px;
38 | }
39 |
40 | .category-button {
41 | background: #555; /* Cinza escuro */
42 | border: none;
43 | padding: 10px 20px;
44 | cursor: pointer;
45 | border-radius: 5px;
46 | color: #fff; /* Branco */
47 | transition: background-color 0.3s ease;
48 | text-decoration: none;
49 | font-size: 0.9rem;
50 | }
51 |
52 | .category-button.active {
53 | background: #333; /* Preto */
54 | }
55 |
56 | .category-button:hover {
57 | background: #444; /* Cinza intermediário */
58 | }
59 |
60 | /* Container de notícias */
61 | .news-container {
62 | display: grid;
63 | grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
64 | gap: 20px;
65 | padding: 20px;
66 | }
67 |
68 | /* Cartão de notícia */
69 | .news-card {
70 | background: #fff; /* Branco */
71 | border-radius: 8px;
72 | overflow: hidden;
73 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
74 | transition: transform 0.3s ease, box-shadow 0.3s ease;
75 | }
76 |
77 | .news-card:hover {
78 | transform: translateY(-5px);
79 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
80 | }
81 |
82 | .news-image {
83 | width: 100%;
84 | height: 200px;
85 | object-fit: cover;
86 | }
87 |
88 | .news-title {
89 | font-size: 1.2rem;
90 | margin: 10px;
91 | color: #333; /* Cinza escuro */
92 | }
93 |
94 | .news-meta {
95 | font-size: 0.9rem;
96 | color: #777; /* Cinza médio */
97 | margin: 0 10px 10px;
98 | }
99 |
100 | .news-body {
101 | margin: 0 10px 10px;
102 | color: #555; /* Cinza escuro */
103 | font-size: 0.9rem;
104 | }
105 |
106 | .read-more {
107 | display: block;
108 | margin: 10px;
109 | color: #333; /* Cinza escuro */
110 | text-decoration: none;
111 | font-weight: bold;
112 | transition: color 0.3s ease;
113 | }
114 |
115 | .read-more:hover {
116 | color: #000; /* Preto */
117 | text-decoration: underline;
118 | }
119 |
120 | /* Rodapé */
121 | .footer {
122 | text-align: center;
123 | padding: 20px;
124 | background: #333; /* Preto */
125 | color: #fff; /* Branco */
126 | margin-top: auto;
127 | }
128 |
129 | .formulario-noticia {
130 | max-width: 800px; /* Aumentei a largura máxima */
131 | margin: 10px auto;
132 | padding: 60px; /* Aumentei o padding */
133 | background: #fff;
134 | border-radius: 8px;
135 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
136 | }
137 |
138 | .formulario-noticia h2 {
139 | margin-top: 0;
140 | color: #333;
141 | font-size: 1.5rem; /* Aumentei o tamanho do título */
142 | }
143 |
144 | .formulario-noticia label {
145 | display: block;
146 | margin: 15px 0 5px; /* Aumentei o espaçamento */
147 | color: #555;
148 | font-size: 1rem; /* Aumentei o tamanho da fonte */
149 | }
150 |
151 | .formulario-noticia input,
152 | .formulario-noticia textarea {
153 | width: 100%;
154 | padding: 12px; /* Aumentei o padding dos inputs */
155 | margin-bottom: 15px; /* Aumentei o espaçamento */
156 | border: 1px solid #ddd;
157 | border-radius: 5px;
158 | font-size: 1rem; /* Aumentei o tamanho da fonte */
159 | }
160 |
161 | .formulario-noticia textarea {
162 | height: 150px; /* Defini uma altura fixa para o textarea */
163 | resize: vertical; /* Permite redimensionar verticalmente */
164 | }
165 |
166 | .formulario-noticia button {
167 | background: #333;
168 | color: #fff;
169 | border: none;
170 | padding: 12px 24px; /* Aumentei o padding do botão */
171 | cursor: pointer;
172 | border-radius: 5px;
173 | font-size: 1rem; /* Aumentei o tamanho da fonte */
174 | transition: background-color 0.3s ease;
175 | }
176 |
177 | .formulario-noticia button:hover {
178 | background: #555;
179 | }
180 |
181 | /* Responsividade */
182 | @media (max-width: 768px) {
183 | .category-menu {
184 | align-items: center;
185 | }
186 |
187 | .category-button {
188 | width: 100%;
189 | text-align: center;
190 | }
191 |
192 | .news-container {
193 | grid-template-columns: 1fr;
194 | }
195 | }
--------------------------------------------------------------------------------