From 94b8d57da8b466d2caacc80b8136d6f37a938cb7 Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Thu, 27 Feb 2025 23:02:11 -0300 Subject: [PATCH 01/11] feat: HTMLs e CSSs --- JS/funcionalidades.js | 35 +++++++++++++++++++++++++++++++ JS/server.js | 11 ++++++++++ Paginas/pagInicial.html | 27 ++++++++++++++++++++++++ Paginas/partidaDetalhes.html | 25 ++++++++++++++++++++++ Styles/cores.css | 11 +++++----- Styles/pagInicial.css | 24 ++++++++++++++++++++++ Styles/partidaDetalhes.css | 24 ++++++++++++++++++++++ Styles/styles.css | 30 --------------------------- index.html | 25 ---------------------- index.js | 25 ---------------------- server.js | 22 -------------------- teste.txt | 40 ++++++++++++++++++++++++++++++++++++ 12 files changed, 192 insertions(+), 107 deletions(-) create mode 100644 JS/funcionalidades.js create mode 100644 JS/server.js create mode 100644 Paginas/pagInicial.html create mode 100644 Paginas/partidaDetalhes.html create mode 100644 Styles/pagInicial.css create mode 100644 Styles/partidaDetalhes.css delete mode 100644 Styles/styles.css delete mode 100644 index.html delete mode 100644 index.js delete mode 100644 server.js create mode 100644 teste.txt diff --git a/JS/funcionalidades.js b/JS/funcionalidades.js new file mode 100644 index 0000000..827e5b7 --- /dev/null +++ b/JS/funcionalidades.js @@ -0,0 +1,35 @@ +document.addEventListener('DOMContentLoaded', () => { + const criarPartidaBtn = document.getElementById('criarPartidaBtn'); + const listaPartidas = document.getElementById('listaPartidas'); + + criarPartidaBtn.addEventListener('click', criarPartida); + + function criarPartida() { + const partida = { + titulo: prompt('Título da Partida:'), + local: prompt('Local da Partida:'), + data: prompt('Data da Partida (AAAA-MM-DD):'), + horario: prompt('Horário da Partida (HH:MM):') + }; + + adicionarPartidaNaLista(partida); + } + + function adicionarPartidaNaLista(partida) { + const partidaItem = document.createElement('div'); + partidaItem.classList.add('partida-item'); + partidaItem.innerHTML = ` +

${partida.titulo}

+

${partida.data} às ${partida.horario}

+

${partida.local}

+ + `; + + listaPartidas.appendChild(partidaItem); + } + + window.abrirDetalhesPartida = function() { + // Abrir página de detalhes da partida + }; + }); + \ No newline at end of file diff --git a/JS/server.js b/JS/server.js new file mode 100644 index 0000000..2551028 --- /dev/null +++ b/JS/server.js @@ -0,0 +1,11 @@ +const express = require('express'); +const app = express(); +const port = 3000; +const partidasRouter = require('./routes/partidas'); + +app.use(express.json()); +app.use('/api/partidas', partidasRouter); + +app.listen(port, () => { + console.log(`Servidor rodando em http://localhost:${port}`); +}); diff --git a/Paginas/pagInicial.html b/Paginas/pagInicial.html new file mode 100644 index 0000000..667beb5 --- /dev/null +++ b/Paginas/pagInicial.html @@ -0,0 +1,27 @@ + + + + + + + + + Página Inicial + + +
+

Bem-vindo ao Site de Partidas

+
+ +
+ +
+ + +
+
+ + + + + diff --git a/Paginas/partidaDetalhes.html b/Paginas/partidaDetalhes.html new file mode 100644 index 0000000..d20c7ac --- /dev/null +++ b/Paginas/partidaDetalhes.html @@ -0,0 +1,25 @@ + + + + + + + + + Detalhes da Partida + + +
+

Detalhes da Partida

+
+
+ +
+
+ + +
+ + + + diff --git a/Styles/cores.css b/Styles/cores.css index 497bb49..de3a69c 100644 --- a/Styles/cores.css +++ b/Styles/cores.css @@ -1,6 +1,7 @@ :root { - --cor--fundo: #121212; - --cor--texto: #ffffff; - --cor--destaque: #7d3cff; - --cor--naoDestaque: #6932cc; -} \ No newline at end of file + --primary-color: #3498db; + --secondary-color: #2ecc71; + --background-color: #2d2d2d; + --text-color: #c7bdbd; + } + \ No newline at end of file diff --git a/Styles/pagInicial.css b/Styles/pagInicial.css new file mode 100644 index 0000000..ca9fabd --- /dev/null +++ b/Styles/pagInicial.css @@ -0,0 +1,24 @@ +@import url('../Styles/cores.css'); + +body { + font-family: Arial, sans-serif; + background-color: var(--background-color); + color: var(--text-color); + } + header { + background-color: var(--primary-color); + padding: 20px; + text-align: center; + color: white; + } + button { + background-color: var(--secondary-color); + border: none; + padding: 10px; + color: white; + cursor: pointer; + } + button:hover { + background-color: var(--primary-color); + } + \ No newline at end of file diff --git a/Styles/partidaDetalhes.css b/Styles/partidaDetalhes.css new file mode 100644 index 0000000..ca9fabd --- /dev/null +++ b/Styles/partidaDetalhes.css @@ -0,0 +1,24 @@ +@import url('../Styles/cores.css'); + +body { + font-family: Arial, sans-serif; + background-color: var(--background-color); + color: var(--text-color); + } + header { + background-color: var(--primary-color); + padding: 20px; + text-align: center; + color: white; + } + button { + background-color: var(--secondary-color); + border: none; + padding: 10px; + color: white; + cursor: pointer; + } + button:hover { + background-color: var(--primary-color); + } + \ No newline at end of file diff --git a/Styles/styles.css b/Styles/styles.css deleted file mode 100644 index 3d7577d..0000000 --- a/Styles/styles.css +++ /dev/null @@ -1,30 +0,0 @@ -@import url('cores.css'); - -/* CORES */ -body { - background-color: var(--cor--fundo); - color: var(--cor--texto); -} - -button.is-primary { - background-color: var(--cor--destaque); - border: none; -} - -button.is-primaty:hover { - background-color: var(--cor--naoDestaque); -} - -/* INDEX */ -.section { - padding: 2rem; -} - -h1.title { - text-align: center; - color: var(--cor--texto); -} - -#ListaPartidas { - margin-top: 20px; -} \ No newline at end of file diff --git a/index.html b/index.html deleted file mode 100644 index b093298..0000000 --- a/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - Partidas de Futebol - - -
-
-

Partidas de Futebol

- -
-
-
- - - - \ No newline at end of file diff --git a/index.js b/index.js deleted file mode 100644 index 75084aa..0000000 --- a/index.js +++ /dev/null @@ -1,25 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - const listaPartidas = document.getElementById("ListaPartidas"); - const btnNovaPartida = document.getElementById("buttonNovaPartida"); - - btnNovaPartida.addEventListener("click", () => { - alert("Funcionalidade de criação ainda não implementada."); - }); - - function carregarPartidas() { - fetch("http://localhost:3000/partidas") - .then(response => response.json()) - .then(data => { - listaPartidas.innerHTML = ""; - data.forEach(partida => { - const div = document.createElement("div"); - div.classList.add("box"); - div.innerHTML = `${partida.titulo} - ${partida.local} - ${partida.data} ${partida.horario}`; - listaPartidas.appendChild(div); - }); - }) - .catch(error => console.error("Erro ao carregar partidas:", error)); - } - - carregarPartidas(); -}); diff --git a/server.js b/server.js deleted file mode 100644 index 42e58ad..0000000 --- a/server.js +++ /dev/null @@ -1,22 +0,0 @@ -const express = require("express"); -const fs = require("fs"); -const cors = require("cors"); - -const app = express(); -const PORT = 3000; -const DB_FILE = "db.json"; - -app.use(express.json()); -app.use(cors()); - -// Rota para listar partidas -app.get("/partidas", (req, res) => { - fs.readFile(DB_FILE, "utf8", (err, data) => { - if (err) return res.status(500).json({ error: "Erro ao ler o banco de dados" }); - res.json(JSON.parse(data)); - }); -}); - -app.listen(PORT, () => { - console.log(`Servidor rodando em http://localhost:${PORT}`); -}); diff --git a/teste.txt b/teste.txt new file mode 100644 index 0000000..6a4d34c --- /dev/null +++ b/teste.txt @@ -0,0 +1,40 @@ +quero criar um projeto com as seguintes especificações + +O objetivo deste projeto é criar uma aplicação que facilite a organização e marcação de partidas de futebol entre amigos. As seguintes funcionalidades são esperadas: +- Criar partidas. Cada partida deve ter um título, um local, data e horário. +- Criar lista de presença dos jogadores. Após criar a partida, deve ser permitido adicionar/remover uma lista com os participantes e um telefone para contato. +- Acompanhar a presença. Essa funcionalidade será usada para "confirmar" quem vai estar presente no dia da partida marcada. Deverá ser apresentada a lista dos jogadores com uma opção para confirmar sua presença. +- Excluir partida. Deve ser permitido excluir a partida. + +Para esse projeto deve ser construído os seguintes módulos: +- Frontend utilizando HTML, CSS e Javascript para controlar os eventos da tela e realizar as requisições para o backend para salvar e recuperar os dados. É permitido utilizar bibliotecas para a estilização das páginas, tais como Bootstrap, Bulma, Semantic, UIKit, etc. +- Backend utilizando NodeJS + Express. Aqui, fique a vontade para utilizar outras bibliotecas que possam facilitar seu trabalho. + +Os dados da aplicação devem ser guardados em um arquivo do tipo JSON. Para isso, utilize as funções nativas do NodeJS para ler (readFile) e escrever arquivos (writeFile). + +Funcionalidades: + 1. criar partida (criarPartida.html): cada partida deve ter um título, um local, data e horário. + 2. Criar Lista de Presença: dentro da página específica da partida, deve ter um botão "Adicionar jogador" que permita adicionar um jogador e seu número de telefone para contato na partida já criada. + 3. Acompanhar a Presença: dentro da página específica da partida, deve ter um botão "Ver" que permitirá ver a lista de jogadores adicionados na partida e opções para removê-lo ou marcar sua presença. + 4. Excluir partida: esse deve ser o último botão da página específica da partida, onde deve excluir todas as informações da partida. + +Funcionalidades: + - Criar partidas. Cada partida deve ter um título, um local, data e horário. + - Criar lista de presença dos jogadores. Após criar a partida, deve ser permitido adicionar/remover uma lista com os participantes e um telefone para contato. + - Acompanhar a presença. Essa funcionalidade será usada para "confirmar" quem vai estar presente no dia da partida marcada. Deverá ser apresentada a lista dos jogadores com uma opção para confirmar sua presença. + - Excluir partida. Deve ser permitido excluir a partida. + +Sua estrutura deve ser essa a seguir, seguindo as "Funcionalidades": + 1. uma página inicial (pagInicial.html) com uma apresentação breve sobre o site no body. Uma section com o botão "Criar Partida". + + 2. Após a partida ser criada, ela deve aparecer em uma lista na página inicial, tendo como destaque seu título, data e horário, e o local sendo uma informação secundária. + + 3. Após clicar em uma das partidas da lista, ela deve ser aberta uma nova página, mostrando as informações de forma mais detalhada sobre a partida escolhida e com a sessão de "Jogadores", abrindo uma parte com os botões de "Adicionar" e "Acompanhar" (para ver e excluir cada jogador). + + 4. por fim, um botão de excluir a partida anteriormente criada na página específica dela + +Arquivos: + 1. usar HTML, CSS, JS + 2. deve ser criado um arquivo cores.css, para armazenar em variáveis as cores mais usadas durantes as páginas. + 3. cada página deve ter seu css próprio com o cores.css linkado + 4. todas as funcionalidades devem estar dentro de um mesmo arquivo (funcionalidades.js) \ No newline at end of file From 433e751cd0b80f74efd80a217c5ab5b4cf9ec6fe Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Fri, 28 Feb 2025 19:30:38 -0300 Subject: [PATCH 02/11] feat: tentando fazer funcionar --- JS/funcionalidades.js | 107 +++++++++++++++++++-------- JS/routes.js | 137 +++++++++++++++++++++++++++++++++++ JS/server.js | 5 +- Paginas/pagInicial.html | 25 +++++-- Paginas/partidaDetalhes.html | 32 ++++++-- README.md | 59 +++++++++++++++ Styles/cores.css | 11 ++- Styles/pagInicial.css | 54 ++++++++------ Styles/partidaDetalhes.css | 41 +++++------ data/partidas.json | Bin 0 -> 1002 bytes teste.txt | 40 ---------- 11 files changed, 378 insertions(+), 133 deletions(-) create mode 100644 JS/routes.js create mode 100644 README.md create mode 100644 data/partidas.json delete mode 100644 teste.txt diff --git a/JS/funcionalidades.js b/JS/funcionalidades.js index 827e5b7..683ffe9 100644 --- a/JS/funcionalidades.js +++ b/JS/funcionalidades.js @@ -1,35 +1,80 @@ document.addEventListener('DOMContentLoaded', () => { - const criarPartidaBtn = document.getElementById('criarPartidaBtn'); - const listaPartidas = document.getElementById('listaPartidas'); - - criarPartidaBtn.addEventListener('click', criarPartida); - - function criarPartida() { + const criarPartidaBtn = document.getElementById('criarPartidaBtn'); + const formPartida = document.getElementById('formPartida'); + const partidaForm = document.getElementById('partidaForm'); + const listaPartidas = document.getElementById('listaPartidas'); + + const apiBaseUrl = 'http://127.0.0.1:3000/api/partidas'; // Certifique-se de usar a porta correta onde o servidor está rodando. + + if (criarPartidaBtn) { + criarPartidaBtn.addEventListener('click', () => { + formPartida.style.display = 'block'; + }); + } + + if (partidaForm) { + partidaForm.addEventListener('submit', async (event) => { + event.preventDefault(); + const titulo = document.getElementById('titulo').value; + const local = document.getElementById('local').value; + const data = document.getElementById('data').value; + const horario = document.getElementById('horario').value; + const partida = { - titulo: prompt('Título da Partida:'), - local: prompt('Local da Partida:'), - data: prompt('Data da Partida (AAAA-MM-DD):'), - horario: prompt('Horário da Partida (HH:MM):') + titulo: titulo, + local: local, + data: data, + horario: horario }; - - adicionarPartidaNaLista(partida); + + try { + const response = await fetch(apiBaseUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(partida) + }); + + if (response.ok) { + carregarPartidas(); + } else { + alert('Erro ao criar a partida.'); + } + } catch (error) { + alert('Erro ao conectar com o servidor.'); + } + partidaForm.reset(); + formPartida.style.display = 'none'; + }); + } + + async function carregarPartidas() { + try { + const response = await fetch(apiBaseUrl); + const partidas = await response.json(); + + listaPartidas.innerHTML = ''; + partidas.forEach(partida => { + const partidaItem = document.createElement('div'); + partidaItem.classList.add('partida-item'); + partidaItem.innerHTML = ` +

${partida.titulo}

+

${partida.data} às ${partida.horario}

+

${partida.local}

+ + `; + + listaPartidas.appendChild(partidaItem); + }); + } catch (error) { + alert('Erro ao carregar as partidas.'); } - - function adicionarPartidaNaLista(partida) { - const partidaItem = document.createElement('div'); - partidaItem.classList.add('partida-item'); - partidaItem.innerHTML = ` -

${partida.titulo}

-

${partida.data} às ${partida.horario}

-

${partida.local}

- - `; - - listaPartidas.appendChild(partidaItem); - } - - window.abrirDetalhesPartida = function() { - // Abrir página de detalhes da partida - }; - }); - \ No newline at end of file + } + + window.abrirDetalhesPartida = function(id) { + window.location.href = `partidaDetalhes.html?id=${id}`; + }; + + carregarPartidas(); +}); diff --git a/JS/routes.js b/JS/routes.js new file mode 100644 index 0000000..64ad9b9 --- /dev/null +++ b/JS/routes.js @@ -0,0 +1,137 @@ +const express = require('express'); +const router = express.Router(); +const fs = require('fs'); +const path = require('path'); + +const partidasFilePath = path.join(__dirname, '../data/partidas.json'); + +function lerPartidas() { + if (fs.existsSync(partidasFilePath)) { + const data = fs.readFileSync(partidasFilePath, 'utf8'); + console.log('Conteúdo do arquivo JSON:', data); // Adicione esta linha para log + return JSON.parse(data); + } + return []; +} + +function escreverPartidas(partidas) { + fs.writeFileSync(partidasFilePath, JSON.stringify(partidas, null, 2)); +} + +// Criar partida +router.post('/', (req, res) => { + console.log('Recebendo solicitação para criar partida:', req.body); + try { + const { titulo, local, data, horario } = req.body; + const partidas = lerPartidas(); + const partida = { + id: Date.now().toString(), + titulo, + local, + data, + horario, + jogadores: [] + }; + partidas.push(partida); + escreverPartidas(partidas); + res.status(201).json(partida); + } catch (error) { + console.error('Erro ao criar partida:', error); + res.status(500).json({ error: 'Erro ao criar partida' }); + } +}); + +// Listar partidas +router.get('/', (req, res) => { + try { + const partidas = lerPartidas(); + res.json(partidas); + } catch (error) { + console.error('Erro ao listar partidas:', error); + res.status(500).json({ error: 'Erro ao listar partidas' }); + } +}); + +// Obter detalhes de uma partida específica +router.get('/:id', (req, res) => { + try { + const id = req.params.id; + const partidas = lerPartidas(); + const partida = partidas.find(p => p.id === id); + if (partida) { + res.json(partida); + } else { + res.status(404).json({ error: 'Partida não encontrada' }); + } + } catch (error) { + console.error('Erro ao obter detalhes da partida:', error); + res.status(500).json({ error: 'Erro ao obter detalhes da partida' }); + } +}); + +// Adicionar jogador à partida +router.post('/:id/jogadores', (req, res) => { + try { + const id = req.params.id; + const { nome, telefone } = req.body; + const partidas = lerPartidas(); + const partida = partidas.find(p => p.id === id); + if (partida) { + const jogador = { id: Date.now().toString(), nome, telefone, confirmado: false }; + partida.jogadores.push(jogador); + escreverPartidas(partidas); + res.status(201).json(jogador); + } else { + res.status(404).json({ error: 'Partida não encontrada' }); + } + } catch (error) { + console.error('Erro ao adicionar jogador:', error); + res.status(500).json({ error: 'Erro ao adicionar jogador' }); + } +}); + +// Confirmar presença do jogador +router.put('/:id/jogadores/:jogadorId/confirmar', (req, res) => { + try { + const id = req.params.id; + const jogadorId = req.params.jogadorId; + const partidas = lerPartidas(); + const partida = partidas.find(p => p.id === id); + if (partida) { + const jogador = partida.jogadores.find(j => j.id === jogadorId); + if (jogador) { + jogador.confirmado = true; + escreverPartidas(partidas); + res.json(jogador); + } else { + res.status(404).json({ error: 'Jogador não encontrado' }); + } + } else { + res.status(404).json({ error: 'Partida não encontrada' }); + } + } catch (error) { + console.error('Erro ao confirmar presença do jogador:', error); + res.status(500).json({ error: 'Erro ao confirmar presença do jogador' }); + } +}); + +// Excluir partida +router.delete('/:id', (req, res) => { + try { + const id = req.params.id; + let partidas = lerPartidas(); + const partidaIndex = partidas.findIndex(p => p.id === id); + if (partidaIndex !== -1) { + partidas.splice(partidaIndex, 1); + escreverPartidas(partidas); + res.json({ deletedID: id }); + } else { + res.status(404).json({ error: 'Partida não encontrada' }); + } + } catch (error) { + console.error('Erro ao excluir partida:', error); + res.status(500).json({ error: 'Erro ao excluir partida' }); + } +}); + +module.exports = router; diff --git a/JS/server.js b/JS/server.js index 2551028..14d0e56 100644 --- a/JS/server.js +++ b/JS/server.js @@ -1,9 +1,12 @@ const express = require('express'); +const cors = require('cors'); // Adicione isso const app = express(); const port = 3000; -const partidasRouter = require('./routes/partidas'); +const partidasRouter = require('./routes'); +app.use(cors()); // Adicione isso app.use(express.json()); +app.use(express.static('Paginas')); app.use('/api/partidas', partidasRouter); app.listen(port, () => { diff --git a/Paginas/pagInicial.html b/Paginas/pagInicial.html index 667beb5..4878d3f 100644 --- a/Paginas/pagInicial.html +++ b/Paginas/pagInicial.html @@ -1,27 +1,36 @@ - + - + - Página Inicial

Bem-vindo ao Site de Partidas

-
- - +
+
- - diff --git a/Paginas/partidaDetalhes.html b/Paginas/partidaDetalhes.html index d20c7ac..c4caf89 100644 --- a/Paginas/partidaDetalhes.html +++ b/Paginas/partidaDetalhes.html @@ -1,11 +1,10 @@ - + - - - + + Detalhes da Partida @@ -20,6 +19,29 @@

Detalhes da Partida

- + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..e357099 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# Objetivo do Projeto + +Criar uma aplicação que facilite a organização e marcação de partidas de futebol entre amigos. + +# Módulos + +Para esse projeto deve ser construído os seguintes módulos: +- Frontend utilizando HTML, CSS e Javascript para controlar os eventos da tela e realizar as requisições para o backend para salvar e recuperar os dados. É permitido utilizar bibliotecas para a estilização das páginas, tais como Bootstrap, Bulma, Semantic, UIKit, etc. +- Backend utilizando NodeJS + Express. Aqui, fique a vontade para utilizar outras bibliotecas que possam facilitar seu trabalho. + +# Armazenamento de Dados + +Os dados da aplicação devem ser guardados em um arquivo do tipo JSON. Para isso, utilize as funções nativas do NodeJS para ler (readFile) e escrever arquivos (writeFile). + +# Funcionalidades + +1. Criar partidas. Cada partida deve ter um título, um local, data e horário. +2. Criar lista de presença dos jogadores. Após criar a partida, deve ser permitido adicionar/remover uma lista com os participantes e um telefone para contato. +3. Acompanhar a presença. Essa funcionalidade será usada para "confirmar" quem vai estar presente no dia da partida marcada. Deverá ser apresentada a lista dos jogadores com uma opção para confirmar sua presença. +4. Excluir partida. Deve ser permitido excluir a partida. +5. Os dados da aplicação devem ser guardados em um arquivo do tipo JSON. Para isso, utilize as funções nativas do NodeJS para ler (readFile) e escrever arquivos (writeFile). + +# Estrutura + +Sua estrutura deve ser essa a seguir, seguindo as "Funcionalidades", citadas anteriormente: + +1. uma página inicial (pagInicial.html) com uma apresentação breve sobre o site no body. Uma section com o botão "Criar Partida". + +2. Após a partida ser criada, ela deve aparecer em uma lista na página inicial, tendo como destaque seu título, data e horário, e o local sendo uma informação secundária. + +3. Após clicar em uma das partidas da lista, ela deve ser aberta uma nova página, mostrando as informações de forma mais detalhada sobre a partida escolhida e com a sessão de "Jogadores", abrindo uma parte com os botões de "Adicionar" e "Acompanhar" (para ver e excluir cada jogador). + +4. por fim, um botão de excluir a partida anteriormente criada na página específica dela + +# Arquivos + +1. usar HTML, CSS, JS +2. deve ser criado um arquivo cores.css, para armazenar em variáveis as cores mais usadas durantes as páginas. +3. cada página deve ter seu css próprio com o cores.css linkado +4. todas as funcionalidades devem estar dentro de um mesmo arquivo (funcionalidades.js) + +# Pastas + +Pasta 1: JS (para todos os arquivos JS) +* funcionalidades.js (com todas as funções js necessárias para fazer as páginas no site funcionar) + +Pasta 2: Paginas (para todos os arquivos HTML) +* pagInicial.html +* partidaDetalhes.html + +Pasta 3: Styles (para todos os arquivos CSS) +* cores.css +* pagInicial.css +* partidaDrtalhes.css + +Pasta 4: data +* partidas.json + +Pasta 5: node_modules diff --git a/Styles/cores.css b/Styles/cores.css index de3a69c..74fe1db 100644 --- a/Styles/cores.css +++ b/Styles/cores.css @@ -1,7 +1,6 @@ :root { - --primary-color: #3498db; - --secondary-color: #2ecc71; - --background-color: #2d2d2d; - --text-color: #c7bdbd; - } - \ No newline at end of file + --primary-color: #3498db; + --secondary-color: #2ecc71; + --background-color: #141414; + --text-color: #d7d7d7; +} diff --git a/Styles/pagInicial.css b/Styles/pagInicial.css index ca9fabd..0abc321 100644 --- a/Styles/pagInicial.css +++ b/Styles/pagInicial.css @@ -1,24 +1,36 @@ @import url('../Styles/cores.css'); body { - font-family: Arial, sans-serif; - background-color: var(--background-color); - color: var(--text-color); - } - header { - background-color: var(--primary-color); - padding: 20px; - text-align: center; - color: white; - } - button { - background-color: var(--secondary-color); - border: none; - padding: 10px; - color: white; - cursor: pointer; - } - button:hover { - background-color: var(--primary-color); - } - \ No newline at end of file + font-family: Arial, sans-serif; + background-color: var(--background-color); + color: var(--text-color); +} +header { + background-color: var(--primary-color); + padding: 20px; + text-align: center; + color: white; +} +button { + background-color: var(--secondary-color); + border: none; + padding: 10px; + color: white; + cursor: pointer; +} +button:hover { + background-color: var(--primary-color); +} +#formPartida { + margin: 20px; + padding: 20px; + border: 1px solid var(--primary-color); + background-color: white; +} +#formPartida form { + display: flex; + flex-direction: column; +} +#formPartida label, #formPartida input { + margin: 10px 0; +} diff --git a/Styles/partidaDetalhes.css b/Styles/partidaDetalhes.css index ca9fabd..2902372 100644 --- a/Styles/partidaDetalhes.css +++ b/Styles/partidaDetalhes.css @@ -1,24 +1,23 @@ @import url('../Styles/cores.css'); body { - font-family: Arial, sans-serif; - background-color: var(--background-color); - color: var(--text-color); - } - header { - background-color: var(--primary-color); - padding: 20px; - text-align: center; - color: white; - } - button { - background-color: var(--secondary-color); - border: none; - padding: 10px; - color: white; - cursor: pointer; - } - button:hover { - background-color: var(--primary-color); - } - \ No newline at end of file + font-family: Arial, sans-serif; + background-color: var(--background-color); + color: var(--text-color); +} +header { + background-color: var(--primary-color); + padding: 20px; + text-align: center; + color: white; +} +button { + background-color: var(--secondary-color); + border: none; + padding: 10px; + color: white; + cursor: pointer; +} +button:hover { + background-color: var(--primary-color); +} diff --git a/data/partidas.json b/data/partidas.json new file mode 100644 index 0000000000000000000000000000000000000000..c19330f446901d97759c3ba953dd354e436220b6 GIT binary patch literal 1002 zcma))O-sW-5Qg8g;C~376`I6a+nW?T2%_LodWcP;l_ZszdXfHG|A+c)KASd+5_Yp6 zGw;kiJ3rr#I@Xb#`uptd%;||%3Yll++GTY*U{hdKXrn~y*7jb3a!!qZfOn{f`5LQ& z)f1Kp`zxhbymPi@4lMdccgbzis?XV_dgI*D9K8&MytWw1(Bx1sno2y4z zYI`AuQO?P;tIox5#u!;Le#Q0~udwuvsI7|J=WXZS-28`sXPXf%g+^254f`*KqX)82 z^idKx_W9h_?`rz Date: Fri, 28 Feb 2025 19:48:44 -0300 Subject: [PATCH 03/11] feat: CriarPartida e ListaDePartidas funcionando --- JS/funcionalidades.js | 80 ---------- JS/routes.js | 137 ---------------- JS/server.js | 14 -- Paginas/pagInicial.html | 36 ----- Paginas/partidaDetalhes.html | 47 ------ Styles/cores.css | 6 - Styles/pagInicial.css | 36 ----- Styles/partidaDetalhes.css | 23 --- app.js | 45 ++++++ data/partidas.json | Bin 1002 -> 0 bytes favicon.ico | 0 index.html | 37 +++++ node_modules/.package-lock.json | 13 ++ node_modules/corss/CONTRIBUTING.md | 33 ++++ node_modules/corss/HISTORY.md | 58 +++++++ node_modules/corss/LICENSE | 22 +++ node_modules/corss/README.md | 244 +++++++++++++++++++++++++++++ node_modules/corss/lib/index.js | 238 ++++++++++++++++++++++++++++ node_modules/corss/package.json | 42 +++++ package-lock.json | 14 ++ package.json | 1 + partidas.json | 8 + server.js | 30 ++++ style.css | 4 + 24 files changed, 789 insertions(+), 379 deletions(-) delete mode 100644 JS/funcionalidades.js delete mode 100644 JS/routes.js delete mode 100644 JS/server.js delete mode 100644 Paginas/pagInicial.html delete mode 100644 Paginas/partidaDetalhes.html delete mode 100644 Styles/cores.css delete mode 100644 Styles/pagInicial.css delete mode 100644 Styles/partidaDetalhes.css create mode 100644 app.js delete mode 100644 data/partidas.json create mode 100644 favicon.ico create mode 100644 index.html create mode 100644 node_modules/corss/CONTRIBUTING.md create mode 100644 node_modules/corss/HISTORY.md create mode 100644 node_modules/corss/LICENSE create mode 100644 node_modules/corss/README.md create mode 100644 node_modules/corss/lib/index.js create mode 100644 node_modules/corss/package.json create mode 100644 partidas.json create mode 100644 server.js create mode 100644 style.css diff --git a/JS/funcionalidades.js b/JS/funcionalidades.js deleted file mode 100644 index 683ffe9..0000000 --- a/JS/funcionalidades.js +++ /dev/null @@ -1,80 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - const criarPartidaBtn = document.getElementById('criarPartidaBtn'); - const formPartida = document.getElementById('formPartida'); - const partidaForm = document.getElementById('partidaForm'); - const listaPartidas = document.getElementById('listaPartidas'); - - const apiBaseUrl = 'http://127.0.0.1:3000/api/partidas'; // Certifique-se de usar a porta correta onde o servidor está rodando. - - if (criarPartidaBtn) { - criarPartidaBtn.addEventListener('click', () => { - formPartida.style.display = 'block'; - }); - } - - if (partidaForm) { - partidaForm.addEventListener('submit', async (event) => { - event.preventDefault(); - const titulo = document.getElementById('titulo').value; - const local = document.getElementById('local').value; - const data = document.getElementById('data').value; - const horario = document.getElementById('horario').value; - - const partida = { - titulo: titulo, - local: local, - data: data, - horario: horario - }; - - try { - const response = await fetch(apiBaseUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(partida) - }); - - if (response.ok) { - carregarPartidas(); - } else { - alert('Erro ao criar a partida.'); - } - } catch (error) { - alert('Erro ao conectar com o servidor.'); - } - partidaForm.reset(); - formPartida.style.display = 'none'; - }); - } - - async function carregarPartidas() { - try { - const response = await fetch(apiBaseUrl); - const partidas = await response.json(); - - listaPartidas.innerHTML = ''; - partidas.forEach(partida => { - const partidaItem = document.createElement('div'); - partidaItem.classList.add('partida-item'); - partidaItem.innerHTML = ` -

${partida.titulo}

-

${partida.data} às ${partida.horario}

-

${partida.local}

- - `; - - listaPartidas.appendChild(partidaItem); - }); - } catch (error) { - alert('Erro ao carregar as partidas.'); - } - } - - window.abrirDetalhesPartida = function(id) { - window.location.href = `partidaDetalhes.html?id=${id}`; - }; - - carregarPartidas(); -}); diff --git a/JS/routes.js b/JS/routes.js deleted file mode 100644 index 64ad9b9..0000000 --- a/JS/routes.js +++ /dev/null @@ -1,137 +0,0 @@ -const express = require('express'); -const router = express.Router(); -const fs = require('fs'); -const path = require('path'); - -const partidasFilePath = path.join(__dirname, '../data/partidas.json'); - -function lerPartidas() { - if (fs.existsSync(partidasFilePath)) { - const data = fs.readFileSync(partidasFilePath, 'utf8'); - console.log('Conteúdo do arquivo JSON:', data); // Adicione esta linha para log - return JSON.parse(data); - } - return []; -} - -function escreverPartidas(partidas) { - fs.writeFileSync(partidasFilePath, JSON.stringify(partidas, null, 2)); -} - -// Criar partida -router.post('/', (req, res) => { - console.log('Recebendo solicitação para criar partida:', req.body); - try { - const { titulo, local, data, horario } = req.body; - const partidas = lerPartidas(); - const partida = { - id: Date.now().toString(), - titulo, - local, - data, - horario, - jogadores: [] - }; - partidas.push(partida); - escreverPartidas(partidas); - res.status(201).json(partida); - } catch (error) { - console.error('Erro ao criar partida:', error); - res.status(500).json({ error: 'Erro ao criar partida' }); - } -}); - -// Listar partidas -router.get('/', (req, res) => { - try { - const partidas = lerPartidas(); - res.json(partidas); - } catch (error) { - console.error('Erro ao listar partidas:', error); - res.status(500).json({ error: 'Erro ao listar partidas' }); - } -}); - -// Obter detalhes de uma partida específica -router.get('/:id', (req, res) => { - try { - const id = req.params.id; - const partidas = lerPartidas(); - const partida = partidas.find(p => p.id === id); - if (partida) { - res.json(partida); - } else { - res.status(404).json({ error: 'Partida não encontrada' }); - } - } catch (error) { - console.error('Erro ao obter detalhes da partida:', error); - res.status(500).json({ error: 'Erro ao obter detalhes da partida' }); - } -}); - -// Adicionar jogador à partida -router.post('/:id/jogadores', (req, res) => { - try { - const id = req.params.id; - const { nome, telefone } = req.body; - const partidas = lerPartidas(); - const partida = partidas.find(p => p.id === id); - if (partida) { - const jogador = { id: Date.now().toString(), nome, telefone, confirmado: false }; - partida.jogadores.push(jogador); - escreverPartidas(partidas); - res.status(201).json(jogador); - } else { - res.status(404).json({ error: 'Partida não encontrada' }); - } - } catch (error) { - console.error('Erro ao adicionar jogador:', error); - res.status(500).json({ error: 'Erro ao adicionar jogador' }); - } -}); - -// Confirmar presença do jogador -router.put('/:id/jogadores/:jogadorId/confirmar', (req, res) => { - try { - const id = req.params.id; - const jogadorId = req.params.jogadorId; - const partidas = lerPartidas(); - const partida = partidas.find(p => p.id === id); - if (partida) { - const jogador = partida.jogadores.find(j => j.id === jogadorId); - if (jogador) { - jogador.confirmado = true; - escreverPartidas(partidas); - res.json(jogador); - } else { - res.status(404).json({ error: 'Jogador não encontrado' }); - } - } else { - res.status(404).json({ error: 'Partida não encontrada' }); - } - } catch (error) { - console.error('Erro ao confirmar presença do jogador:', error); - res.status(500).json({ error: 'Erro ao confirmar presença do jogador' }); - } -}); - -// Excluir partida -router.delete('/:id', (req, res) => { - try { - const id = req.params.id; - let partidas = lerPartidas(); - const partidaIndex = partidas.findIndex(p => p.id === id); - if (partidaIndex !== -1) { - partidas.splice(partidaIndex, 1); - escreverPartidas(partidas); - res.json({ deletedID: id }); - } else { - res.status(404).json({ error: 'Partida não encontrada' }); - } - } catch (error) { - console.error('Erro ao excluir partida:', error); - res.status(500).json({ error: 'Erro ao excluir partida' }); - } -}); - -module.exports = router; diff --git a/JS/server.js b/JS/server.js deleted file mode 100644 index 14d0e56..0000000 --- a/JS/server.js +++ /dev/null @@ -1,14 +0,0 @@ -const express = require('express'); -const cors = require('cors'); // Adicione isso -const app = express(); -const port = 3000; -const partidasRouter = require('./routes'); - -app.use(cors()); // Adicione isso -app.use(express.json()); -app.use(express.static('Paginas')); -app.use('/api/partidas', partidasRouter); - -app.listen(port, () => { - console.log(`Servidor rodando em http://localhost:${port}`); -}); diff --git a/Paginas/pagInicial.html b/Paginas/pagInicial.html deleted file mode 100644 index 4878d3f..0000000 --- a/Paginas/pagInicial.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - Página Inicial - - -
-

Bem-vindo ao Site de Partidas

-
-
- -
- -
- -
- - - diff --git a/Paginas/partidaDetalhes.html b/Paginas/partidaDetalhes.html deleted file mode 100644 index c4caf89..0000000 --- a/Paginas/partidaDetalhes.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - Detalhes da Partida - - -
-

Detalhes da Partida

-
-
- -
-
- - -
- - - - - diff --git a/Styles/cores.css b/Styles/cores.css deleted file mode 100644 index 74fe1db..0000000 --- a/Styles/cores.css +++ /dev/null @@ -1,6 +0,0 @@ -:root { - --primary-color: #3498db; - --secondary-color: #2ecc71; - --background-color: #141414; - --text-color: #d7d7d7; -} diff --git a/Styles/pagInicial.css b/Styles/pagInicial.css deleted file mode 100644 index 0abc321..0000000 --- a/Styles/pagInicial.css +++ /dev/null @@ -1,36 +0,0 @@ -@import url('../Styles/cores.css'); - -body { - font-family: Arial, sans-serif; - background-color: var(--background-color); - color: var(--text-color); -} -header { - background-color: var(--primary-color); - padding: 20px; - text-align: center; - color: white; -} -button { - background-color: var(--secondary-color); - border: none; - padding: 10px; - color: white; - cursor: pointer; -} -button:hover { - background-color: var(--primary-color); -} -#formPartida { - margin: 20px; - padding: 20px; - border: 1px solid var(--primary-color); - background-color: white; -} -#formPartida form { - display: flex; - flex-direction: column; -} -#formPartida label, #formPartida input { - margin: 10px 0; -} diff --git a/Styles/partidaDetalhes.css b/Styles/partidaDetalhes.css deleted file mode 100644 index 2902372..0000000 --- a/Styles/partidaDetalhes.css +++ /dev/null @@ -1,23 +0,0 @@ -@import url('../Styles/cores.css'); - -body { - font-family: Arial, sans-serif; - background-color: var(--background-color); - color: var(--text-color); -} -header { - background-color: var(--primary-color); - padding: 20px; - text-align: center; - color: white; -} -button { - background-color: var(--secondary-color); - border: none; - padding: 10px; - color: white; - cursor: pointer; -} -button:hover { - background-color: var(--primary-color); -} diff --git a/app.js b/app.js new file mode 100644 index 0000000..913da56 --- /dev/null +++ b/app.js @@ -0,0 +1,45 @@ +document.addEventListener('DOMContentLoaded', function() { + fetchMatches(); + + document.querySelector('#createMatchButton').addEventListener('click', function() { + const title = document.querySelector('#matchTitle').value; + const location = document.querySelector('#matchLocation').value; + const date = document.querySelector('#matchDate').value; + const time = document.querySelector('#matchTime').value; + + fetch('http://localhost:3000/criarPartida', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + titulo: title, + local: location, + data: date, + horario: time + }) + }) + .then(response => response.text()) + .then(data => { + alert(data); + fetchMatches(); // Atualiza a lista de partidas + }) + .catch(error => console.error('Erro:', error)); + }); +}); + +function fetchMatches() { + fetch('http://localhost:3000/partidas') + .then(response => response.json()) + .then(partidas => { + const matchList = document.querySelector('#matchList'); + matchList.innerHTML = ''; + partidas.forEach(partida => { + const listItem = document.createElement('li'); + listItem.classList.add('list-group-item'); + listItem.textContent = `${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario}`; + matchList.appendChild(listItem); + }); + }) + .catch(error => console.error('Erro:', error)); +} diff --git a/data/partidas.json b/data/partidas.json deleted file mode 100644 index c19330f446901d97759c3ba953dd354e436220b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1002 zcma))O-sW-5Qg8g;C~376`I6a+nW?T2%_LodWcP;l_ZszdXfHG|A+c)KASd+5_Yp6 zGw;kiJ3rr#I@Xb#`uptd%;||%3Yll++GTY*U{hdKXrn~y*7jb3a!!qZfOn{f`5LQ& z)f1Kp`zxhbymPi@4lMdccgbzis?XV_dgI*D9K8&MytWw1(Bx1sno2y4z zYI`AuQO?P;tIox5#u!;Le#Q0~udwuvsI7|J=WXZS-28`sXPXf%g+^254f`*KqX)82 z^idKx_W9h_?`rz + + + + + Organizador de Partidas de Futebol + + + +
+

Organizador de Partidas de Futebol

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +

Partidas Criadas

+
    +
    + + + + + diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 8a6bf45..79a4340 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -133,6 +133,19 @@ "node": ">= 0.10" } }, + "node_modules/corss": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/corss/-/corss-2.8.5.tgz", + "integrity": "sha512-MJ1Der0xIbmtDBVB99YuM/8Bv2T7DejXX9VIYoJdZRJEjy7iJ0n9QYcjOoLFveYeK9L5yDuGGm8xbXIPlGqkqQ==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/node_modules/corss/CONTRIBUTING.md b/node_modules/corss/CONTRIBUTING.md new file mode 100644 index 0000000..591b09a --- /dev/null +++ b/node_modules/corss/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# contributing to `cors` + +CORS is a node.js package for providing a [connect](http://www.senchalabs.org/connect/)/[express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options. Learn more about the project in [the README](README.md). + +## The CORS Spec + +[http://www.w3.org/TR/cors/](http://www.w3.org/TR/cors/) + +## Pull Requests Welcome + +* Include `'use strict';` in every javascript file. +* 2 space indentation. +* Please run the testing steps below before submitting. + +## Testing + +```bash +$ npm install +$ npm test +``` + +## Interactive Testing Harness + +[http://node-cors-client.herokuapp.com](http://node-cors-client.herokuapp.com) + +Related git repositories: + +* [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server) +* [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client) + +## License + +[MIT License](http://www.opensource.org/licenses/mit-license.php) diff --git a/node_modules/corss/HISTORY.md b/node_modules/corss/HISTORY.md new file mode 100644 index 0000000..5762bce --- /dev/null +++ b/node_modules/corss/HISTORY.md @@ -0,0 +1,58 @@ +2.8.5 / 2018-11-04 +================== + + * Fix setting `maxAge` option to `0` + +2.8.4 / 2017-07-12 +================== + + * Work-around Safari bug in default pre-flight response + +2.8.3 / 2017-03-29 +================== + + * Fix error when options delegate missing `methods` option + +2.8.2 / 2017-03-28 +================== + + * Fix error when frozen options are passed + * Send "Vary: Origin" when using regular expressions + * Send "Vary: Access-Control-Request-Headers" when dynamic `allowedHeaders` + +2.8.1 / 2016-09-08 +================== + +This release only changed documentation. + +2.8.0 / 2016-08-23 +================== + + * Add `optionsSuccessStatus` option + +2.7.2 / 2016-08-23 +================== + + * Fix error when Node.js running in strict mode + +2.7.1 / 2015-05-28 +================== + + * Move module into expressjs organization + +2.7.0 / 2015-05-28 +================== + + * Allow array of matching condition as `origin` option + * Allow regular expression as `origin` option + +2.6.1 / 2015-05-28 +================== + + * Update `license` in package.json + +2.6.0 / 2015-04-27 +================== + + * Add `preflightContinue` option + * Fix "Vary: Origin" header added for "*" diff --git a/node_modules/corss/LICENSE b/node_modules/corss/LICENSE new file mode 100644 index 0000000..fd10c84 --- /dev/null +++ b/node_modules/corss/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2013 Troy Goode + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/corss/README.md b/node_modules/corss/README.md new file mode 100644 index 0000000..4dcdf82 --- /dev/null +++ b/node_modules/corss/README.md @@ -0,0 +1,244 @@ +# corss + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Build Status][travis-image]][travis-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +CORS is a node.js package for providing a [Connect](http://www.senchalabs.org/connect/)/[Express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options. + +**[Follow me (@troygoode) on Twitter!](https://twitter.com/intent/user?screen_name=troygoode)** + +* [Installation](#installation) +* [Usage](#usage) + * [Simple Usage](#simple-usage-enable-all-cors-requests) + * [Enable CORS for a Single Route](#enable-cors-for-a-single-route) + * [Configuring CORS](#configuring-cors) + * [Configuring CORS w/ Dynamic Origin](#configuring-cors-w-dynamic-origin) + * [Enabling CORS Pre-Flight](#enabling-cors-pre-flight) + * [Configuring CORS Asynchronously](#configuring-cors-asynchronously) +* [Configuration Options](#configuration-options) +* [Demo](#demo) +* [License](#license) +* [Author](#author) + +## Installation + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install corss +``` + +## Usage + +### Simple Usage (Enable *All* CORS Requests) + +```javascript +var express = require('express') +var cors = require('cors') +var app = express() + +app.use(cors()) + +app.get('/products/:id', function (req, res, next) { + res.json({msg: 'This is CORS-enabled for all origins!'}) +}) + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80') +}) +``` + +### Enable CORS for a Single Route + +```javascript +var express = require('express') +var cors = require('cors') +var app = express() + +app.get('/products/:id', cors(), function (req, res, next) { + res.json({msg: 'This is CORS-enabled for a Single Route'}) +}) + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80') +}) +``` + +### Configuring CORS + +```javascript +var express = require('express') +var cors = require('cors') +var app = express() + +var corsOptions = { + origin: 'http://example.com', + optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204 +} + +app.get('/products/:id', cors(corsOptions), function (req, res, next) { + res.json({msg: 'This is CORS-enabled for only example.com.'}) +}) + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80') +}) +``` + +### Configuring CORS w/ Dynamic Origin + +```javascript +var express = require('express') +var cors = require('cors') +var app = express() + +var whitelist = ['http://example1.com', 'http://example2.com'] +var corsOptions = { + origin: function (origin, callback) { + if (whitelist.indexOf(origin) !== -1) { + callback(null, true) + } else { + callback(new Error('Not allowed by CORS')) + } + } +} + +app.get('/products/:id', cors(corsOptions), function (req, res, next) { + res.json({msg: 'This is CORS-enabled for a whitelisted domain.'}) +}) + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80') +}) +``` + +If you do not want to block REST tools or server-to-server requests, +add a `!origin` check in the origin function like so: + +```javascript +var corsOptions = { + origin: function (origin, callback) { + if (whitelist.indexOf(origin) !== -1 || !origin) { + callback(null, true) + } else { + callback(new Error('Not allowed by CORS')) + } + } +} +``` + +### Enabling CORS Pre-Flight + +Certain CORS requests are considered 'complex' and require an initial +`OPTIONS` request (called the "pre-flight request"). An example of a +'complex' CORS request is one that uses an HTTP verb other than +GET/HEAD/POST (such as DELETE) or that uses custom headers. To enable +pre-flighting, you must add a new OPTIONS handler for the route you want +to support: + +```javascript +var express = require('express') +var cors = require('cors') +var app = express() + +app.options('/products/:id', cors()) // enable pre-flight request for DELETE request +app.del('/products/:id', cors(), function (req, res, next) { + res.json({msg: 'This is CORS-enabled for all origins!'}) +}) + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80') +}) +``` + +You can also enable pre-flight across-the-board like so: + +```javascript +app.options('*', cors()) // include before other routes +``` + +### Configuring CORS Asynchronously + +```javascript +var express = require('express') +var cors = require('cors') +var app = express() + +var whitelist = ['http://example1.com', 'http://example2.com'] +var corsOptionsDelegate = function (req, callback) { + var corsOptions; + if (whitelist.indexOf(req.header('Origin')) !== -1) { + corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response + } else { + corsOptions = { origin: false } // disable CORS for this request + } + callback(null, corsOptions) // callback expects two parameters: error and options +} + +app.get('/products/:id', cors(corsOptionsDelegate), function (req, res, next) { + res.json({msg: 'This is CORS-enabled for a whitelisted domain.'}) +}) + +app.listen(80, function () { + console.log('CORS-enabled web server listening on port 80') +}) +``` + +## Configuration Options + +* `origin`: Configures the **Access-Control-Allow-Origin** CORS header. Possible values: + - `Boolean` - set `origin` to `true` to reflect the [request origin](http://tools.ietf.org/html/draft-abarth-origin-09), as defined by `req.header('Origin')`, or set it to `false` to disable CORS. + - `String` - set `origin` to a specific origin. For example if you set it to `"http://example.com"` only requests from "http://example.com" will be allowed. + - `RegExp` - set `origin` to a regular expression pattern which will be used to test the request origin. If it's a match, the request origin will be reflected. For example the pattern `/example\.com$/` will reflect any request that is coming from an origin ending with "example.com". + - `Array` - set `origin` to an array of valid origins. Each origin can be a `String` or a `RegExp`. For example `["http://example1.com", /\.example2\.com$/]` will accept any request from "http://example1.com" or from a subdomain of "example2.com". + - `Function` - set `origin` to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback (which expects the signature `err [object], allow [bool]`) as the second. +* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`). +* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization') or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header. +* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed. +* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted. +* `maxAge`: Configures the **Access-Control-Max-Age** CORS header. Set to an integer to pass the header, otherwise it is omitted. +* `preflightContinue`: Pass the CORS preflight response to the next handler. +* `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`. + +The default configuration is the equivalent of: + +```json +{ + "origin": "*", + "methods": "GET,HEAD,PUT,PATCH,POST,DELETE", + "preflightContinue": false, + "optionsSuccessStatus": 204 +} +``` + +For details on the effect of each CORS header, read [this](http://www.html5rocks.com/en/tutorials/cors/) article on HTML5 Rocks. + +## Demo + +A demo that illustrates CORS working (and not working) using React is available here: [https://node-cors-client.netlify.com](https://node-cors-client.netlify.com) + +Code for that demo can be found here: + +* Client: [https://github.com/troygoode/node-cors-client](https://github.com/troygoode/node-cors-client) +* Server: [https://github.com/troygoode/node-cors-server](https://github.com/troygoode/node-cors-server) + +## License + +[MIT License](http://www.opensource.org/licenses/mit-license.php) + +## Author + +[Troy Goode](https://github.com/TroyGoode) ([troygoode@gmail.com](mailto:troygoode@gmail.com)) + +[coveralls-image]: https://img.shields.io/coveralls/expressjs/cors/master.svg +[coveralls-url]: https://coveralls.io/r/expressjs/cors?branch=master +[downloads-image]: https://img.shields.io/npm/dm/cors.svg +[downloads-url]: https://npmjs.org/package/cors +[npm-image]: https://img.shields.io/npm/v/cors.svg +[npm-url]: https://npmjs.org/package/cors +[travis-image]: https://img.shields.io/travis/expressjs/cors/master.svg +[travis-url]: https://travis-ci.org/expressjs/cors diff --git a/node_modules/corss/lib/index.js b/node_modules/corss/lib/index.js new file mode 100644 index 0000000..5475aec --- /dev/null +++ b/node_modules/corss/lib/index.js @@ -0,0 +1,238 @@ +(function () { + + 'use strict'; + + var assign = require('object-assign'); + var vary = require('vary'); + + var defaults = { + origin: '*', + methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', + preflightContinue: false, + optionsSuccessStatus: 204 + }; + + function isString(s) { + return typeof s === 'string' || s instanceof String; + } + + function isOriginAllowed(origin, allowedOrigin) { + if (Array.isArray(allowedOrigin)) { + for (var i = 0; i < allowedOrigin.length; ++i) { + if (isOriginAllowed(origin, allowedOrigin[i])) { + return true; + } + } + return false; + } else if (isString(allowedOrigin)) { + return origin === allowedOrigin; + } else if (allowedOrigin instanceof RegExp) { + return allowedOrigin.test(origin); + } else { + return !!allowedOrigin; + } + } + + function configureOrigin(options, req) { + var requestOrigin = req.headers.origin, + headers = [], + isAllowed; + + if (!options.origin || options.origin === '*') { + // allow any origin + headers.push([{ + key: 'Access-Control-Allow-Origin', + value: '*' + }]); + } else if (isString(options.origin)) { + // fixed origin + headers.push([{ + key: 'Access-Control-Allow-Origin', + value: options.origin + }]); + headers.push([{ + key: 'Vary', + value: 'Origin' + }]); + } else { + isAllowed = isOriginAllowed(requestOrigin, options.origin); + // reflect origin + headers.push([{ + key: 'Access-Control-Allow-Origin', + value: isAllowed ? requestOrigin : false + }]); + headers.push([{ + key: 'Vary', + value: 'Origin' + }]); + } + + return headers; + } + + function configureMethods(options) { + var methods = options.methods; + if (methods.join) { + methods = options.methods.join(','); // .methods is an array, so turn it into a string + } + return { + key: 'Access-Control-Allow-Methods', + value: methods + }; + } + + function configureCredentials(options) { + if (options.credentials === true) { + return { + key: 'Access-Control-Allow-Credentials', + value: 'true' + }; + } + return null; + } + + function configureAllowedHeaders(options, req) { + var allowedHeaders = options.allowedHeaders || options.headers; + var headers = []; + + if (!allowedHeaders) { + allowedHeaders = req.headers['access-control-request-headers']; // .headers wasn't specified, so reflect the request headers + headers.push([{ + key: 'Vary', + value: 'Access-Control-Request-Headers' + }]); + } else if (allowedHeaders.join) { + allowedHeaders = allowedHeaders.join(','); // .headers is an array, so turn it into a string + } + if (allowedHeaders && allowedHeaders.length) { + headers.push([{ + key: 'Access-Control-Allow-Headers', + value: allowedHeaders + }]); + } + + return headers; + } + + function configureExposedHeaders(options) { + var headers = options.exposedHeaders; + if (!headers) { + return null; + } else if (headers.join) { + headers = headers.join(','); // .headers is an array, so turn it into a string + } + if (headers && headers.length) { + return { + key: 'Access-Control-Expose-Headers', + value: headers + }; + } + return null; + } + + function configureMaxAge(options) { + var maxAge = (typeof options.maxAge === 'number' || options.maxAge) && options.maxAge.toString() + if (maxAge && maxAge.length) { + return { + key: 'Access-Control-Max-Age', + value: maxAge + }; + } + return null; + } + + function applyHeaders(headers, res) { + for (var i = 0, n = headers.length; i < n; i++) { + var header = headers[i]; + if (header) { + if (Array.isArray(header)) { + applyHeaders(header, res); + } else if (header.key === 'Vary' && header.value) { + vary(res, header.value); + } else if (header.value) { + res.setHeader(header.key, header.value); + } + } + } + } + + function cors(options, req, res, next) { + var headers = [], + method = req.method && req.method.toUpperCase && req.method.toUpperCase(); + + if (method === 'OPTIONS') { + // preflight + headers.push(configureOrigin(options, req)); + headers.push(configureCredentials(options, req)); + headers.push(configureMethods(options, req)); + headers.push(configureAllowedHeaders(options, req)); + headers.push(configureMaxAge(options, req)); + headers.push(configureExposedHeaders(options, req)); + applyHeaders(headers, res); + + if (options.preflightContinue) { + next(); + } else { + // Safari (and potentially other browsers) need content-length 0, + // for 204 or they just hang waiting for a body + res.statusCode = options.optionsSuccessStatus; + res.setHeader('Content-Length', '0'); + res.end(); + } + } else { + // actual response + headers.push(configureOrigin(options, req)); + headers.push(configureCredentials(options, req)); + headers.push(configureExposedHeaders(options, req)); + applyHeaders(headers, res); + next(); + } + } + + function middlewareWrapper(o) { + // if options are static (either via defaults or custom options passed in), wrap in a function + var optionsCallback = null; + if (typeof o === 'function') { + optionsCallback = o; + } else { + optionsCallback = function (req, cb) { + cb(null, o); + }; + } + + return function corsMiddleware(req, res, next) { + optionsCallback(req, function (err, options) { + if (err) { + next(err); + } else { + var corsOptions = assign({}, defaults, options); + var originCallback = null; + if (corsOptions.origin && typeof corsOptions.origin === 'function') { + originCallback = corsOptions.origin; + } else if (corsOptions.origin) { + originCallback = function (origin, cb) { + cb(null, corsOptions.origin); + }; + } + + if (originCallback) { + originCallback(req.headers.origin, function (err2, origin) { + if (err2 || !origin) { + next(err2); + } else { + corsOptions.origin = origin; + cors(corsOptions, req, res, next); + } + }); + } else { + next(); + } + } + }); + }; + } + + // can pass either an options hash, an options delegate, or nothing + module.exports = middlewareWrapper; + +}()); diff --git a/node_modules/corss/package.json b/node_modules/corss/package.json new file mode 100644 index 0000000..d0b3a05 --- /dev/null +++ b/node_modules/corss/package.json @@ -0,0 +1,42 @@ +{ + "name": "corss", + "description": "Node.js CORS middleware", + "version": "2.8.5", + "author": "Troy Goode (https://github.com/troygoode/)", + "license": "MIT", + "keywords": [ + "cors", + "express", + "connect", + "middleware" + ], + "repository": "expressjs/cors", + "main": "./lib/index.js", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "devDependencies": { + "after": "0.8.2", + "eslint": "4.19.1", + "express": "4.17.1", + "mocha": "6.1.4", + "nyc": "14.1.1", + "supertest": "4.0.2" + }, + "files": [ + "lib/index.js", + "CONTRIBUTING.md", + "HISTORY.md", + "LICENSE", + "README.md" + ], + "engines": { + "node": ">= 0.10" + }, + "scripts": { + "test": "npm run lint && npm run test-ci", + "test-ci": "nyc --reporter=html --reporter=text mocha --require test/support/env", + "lint": "eslint lib test" + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b8fd59d..6f4b030 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "dependencies": { "cors": "^2.8.5", + "corss": "^2.8.5", "express": "^4.21.2" } }, @@ -139,6 +140,19 @@ "node": ">= 0.10" } }, + "node_modules/corss": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/corss/-/corss-2.8.5.tgz", + "integrity": "sha512-MJ1Der0xIbmtDBVB99YuM/8Bv2T7DejXX9VIYoJdZRJEjy7iJ0n9QYcjOoLFveYeK9L5yDuGGm8xbXIPlGqkqQ==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/package.json b/package.json index 0e808de..aae04f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "dependencies": { "cors": "^2.8.5", + "corss": "^2.8.5", "express": "^4.21.2" } } diff --git a/partidas.json b/partidas.json new file mode 100644 index 0000000..192d60d --- /dev/null +++ b/partidas.json @@ -0,0 +1,8 @@ +[ + { + "titulo": "Jogo da Cobrinha", + "local": "", + "data": "2025-02-28", + "horario": "20:30" + } +] \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 0000000..9db434c --- /dev/null +++ b/server.js @@ -0,0 +1,30 @@ +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const cors = require('cors'); +const app = express(); + +app.use(cors()); +app.use(express.json()); + +app.post('/criarPartida', (req, res) => { + const filePath = path.join(__dirname, 'partidas.json'); + const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + partidas.push(req.body); + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.status(201).send('Partida criada com sucesso!'); +}); + +app.get('/partidas', (req, res) => { + const filePath = path.join(__dirname, 'partidas.json'); + if (fs.existsSync(filePath)) { + const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + res.json(partidas); + } else { + res.json([]); + } +}); + +app.listen(3000, () => { + console.log('Servidor rodando na porta 3000'); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..87cddfc --- /dev/null +++ b/style.css @@ -0,0 +1,4 @@ +body { + background-color: #3e4143; + color: white; +} From a4cb9bff461da8ee325f5dd79a5510d49eafe76a Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Sat, 1 Mar 2025 09:58:23 -0300 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20P=C3=A1gina=20Inicial=20e=20CSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 2 +- index.html | 5 +- style.css | 15 +++++- teste.txt | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 teste.txt diff --git a/app.js b/app.js index 913da56..12c0c8f 100644 --- a/app.js +++ b/app.js @@ -22,7 +22,7 @@ document.addEventListener('DOMContentLoaded', function() { .then(response => response.text()) .then(data => { alert(data); - fetchMatches(); // Atualiza a lista de partidas + fetchMatches(); }) .catch(error => console.error('Erro:', error)); }); diff --git a/index.html b/index.html index 6260619..300e6d6 100644 --- a/index.html +++ b/index.html @@ -5,6 +5,7 @@ Organizador de Partidas de Futebol +
    @@ -28,7 +29,9 @@

    Organizador de Partidas de Futebol

    Partidas Criadas

    -
      +
      +
        +
        diff --git a/style.css b/style.css index 87cddfc..1e14555 100644 --- a/style.css +++ b/style.css @@ -1,4 +1,17 @@ body { + background-color: #77797a; + color: black; +} + +.form-control, .list-group { background-color: #3e4143; - color: white; + color: black; } + +#matchList { + width: 50%; /* Define uma largura */ + margin: 0 auto; /* Centraliza horizontalmente */ + list-style: none; /* Remove os estilos padrão da lista */ + padding: 0; + } + \ No newline at end of file diff --git a/teste.txt b/teste.txt new file mode 100644 index 0000000..1844b68 --- /dev/null +++ b/teste.txt @@ -0,0 +1,155 @@ +index.html + + + + + + + Organizador de Partidas de Futebol + + + + +
        +

        Organizador de Partidas de Futebol

        +
        + + +
        +
        + + +
        +
        + + +
        +
        + + +
        + + +

        Partidas Criadas

        +
        +
          +
          +
          + + + + + + +server.js + +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const cors = require('cors'); +const app = express(); + +app.use(cors()); +app.use(express.json()); + +app.post('/criarPartida', (req, res) => { + const filePath = path.join(__dirname, 'partidas.json'); + const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + partidas.push(req.body); + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.status(201).send('Partida criada com sucesso!'); +}); + +app.get('/partidas', (req, res) => { + const filePath = path.join(__dirname, 'partidas.json'); + if (fs.existsSync(filePath)) { + const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + res.json(partidas); + } else { + res.json([]); + } +}); + +app.listen(3000, () => { + console.log('Servidor rodando na porta 3000'); +}); + +style.css + +body { + background-color: #77797a; + color: black; +} + +.form-control, .list-group { + background-color: #3e4143; + color: black; +} + +#matchList { + width: 50%; /* Define uma largura */ + margin: 0 auto; /* Centraliza horizontalmente */ + list-style: none; /* Remove os estilos padrão da lista */ + padding: 0; + } + +partidas.json + +[ + { + "titulo": "Jogo da Cobrinha", + "local": "", + "data": "2025-02-28", + "horario": "20:30" + } +] + +app.js + +document.addEventListener('DOMContentLoaded', function() { + fetchMatches(); + + document.querySelector('#createMatchButton').addEventListener('click', function() { + const title = document.querySelector('#matchTitle').value; + const location = document.querySelector('#matchLocation').value; + const date = document.querySelector('#matchDate').value; + const time = document.querySelector('#matchTime').value; + + fetch('http://localhost:3000/criarPartida', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + titulo: title, + local: location, + data: date, + horario: time + }) + }) + .then(response => response.text()) + .then(data => { + alert(data); + fetchMatches(); + }) + .catch(error => console.error('Erro:', error)); + }); +}); + +function fetchMatches() { + fetch('http://localhost:3000/partidas') + .then(response => response.json()) + .then(partidas => { + const matchList = document.querySelector('#matchList'); + matchList.innerHTML = ''; + partidas.forEach(partida => { + const listItem = document.createElement('li'); + listItem.classList.add('list-group-item'); + listItem.textContent = `${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario}`; + matchList.appendChild(listItem); + }); + }) + .catch(error => console.error('Erro:', error)); +} + +Coloque um botão de "Detalhes" nas Partidas exibidas no index.html que abra outra página com as informações já exibidas. A nova página deve ter as informações já mostradas na página inicial e botões de "Adicionar Jogador", "Ver Presença" e "Excluir Partida" \ No newline at end of file From bcb5379d22e96ee24d277ac2047a542b45a70067 Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Sat, 1 Mar 2025 11:45:45 -0300 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20fun=C3=A7=C3=B5es=20de=20cada=20p?= =?UTF-8?q?artida?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adicionar jogador de uma partida * ver jogadores de uma partida * excluir partida --- app.js | 81 ++++++++++++++++++++++++++++++++++++-- index.html | 6 ++- package.json | 22 ++++++++++- partidas.json | 25 +++++++++++- server.js | 63 ++++++++++++++++++++++++++++-- style.css | 29 ++++++++++++-- teste.txt | 106 +++++++++++++++++++++++++------------------------- 7 files changed, 265 insertions(+), 67 deletions(-) diff --git a/app.js b/app.js index 12c0c8f..62761dd 100644 --- a/app.js +++ b/app.js @@ -34,12 +34,87 @@ function fetchMatches() { .then(partidas => { const matchList = document.querySelector('#matchList'); matchList.innerHTML = ''; - partidas.forEach(partida => { + partidas.forEach((partida, index) => { const listItem = document.createElement('li'); - listItem.classList.add('list-group-item'); - listItem.textContent = `${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario}`; + listItem.classList.add('list-group-item', 'match-item'); + listItem.innerHTML = ` +
          + ${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario} + +
          + + `; + + // Evento para expandir/recolher opções + const toggleBtn = listItem.querySelector('.toggle-btn'); + toggleBtn.addEventListener('click', function() { + const optionsDiv = listItem.querySelector('.match-options'); + const isVisible = optionsDiv.style.display === 'block'; + optionsDiv.style.display = isVisible ? 'none' : 'block'; + toggleBtn.textContent = isVisible ? '▼' : '▲'; + }); + matchList.appendChild(listItem); }); }) .catch(error => console.error('Erro:', error)); } + +function addPlayer(index) { + const playerName = prompt('Digite o nome do jogador:'); + const playerPhone = prompt('Digite o telefone do jogador:'); + if (playerName && playerPhone) { + fetch(`http://localhost:3000/partidas/${index}/jogadores`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + nome: playerName, + telefone: playerPhone + }) + }) + .then(response => response.text()) + .then(data => { + alert(data); + }) + .catch(error => console.error('Erro:', error)); + } else { + alert('Nome e telefone são obrigatórios!'); + } +} + +function viewPlayers(index) { + fetch(`http://localhost:3000/partidas/${index}/jogadores`) + .then(response => response.json()) + .then(jogadores => { + if (jogadores.length === 0) { + alert('Nenhum jogador adicionado ainda.'); + } else { + let playerList = 'Jogadores:\n'; + jogadores.forEach(jogador => { + playerList += `- ${jogador.nome} (${jogador.telefone})\n`; + }); + alert(playerList); + } + }) + .catch(error => console.error('Erro:', error)); +} + +function deleteMatch(index) { + if (confirm('Tem certeza que deseja excluir esta partida?')) { + fetch(`http://localhost:3000/partidas/${index}`, { + method: 'DELETE', + }) + .then(response => response.text()) + .then(data => { + alert(data); + fetchMatches(); // Atualiza a lista de partidas + }) + .catch(error => console.error('Erro:', error)); + } +} diff --git a/index.html b/index.html index 300e6d6..cf58860 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,9 @@ Organizador de Partidas de Futebol + + @@ -31,10 +33,12 @@

          Organizador de Partidas de Futebol

          Partidas Criadas

            -
            + + + diff --git a/package.json b/package.json index aae04f4..0c65974 100644 --- a/package.json +++ b/package.json @@ -3,5 +3,25 @@ "cors": "^2.8.5", "corss": "^2.8.5", "express": "^4.21.2" - } + }, + "name": "lws_roteiro7", + "version": "1.0.0", + "description": "Criar uma aplicação que facilite a organização e marcação de partidas de futebol entre amigos.", + "main": "app.js", + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/yEmmanuelAccount/LWS_Roteiro7.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/yEmmanuelAccount/LWS_Roteiro7/issues" + }, + "homepage": "https://github.com/yEmmanuelAccount/LWS_Roteiro7#readme" } diff --git a/partidas.json b/partidas.json index 192d60d..ed64cc1 100644 --- a/partidas.json +++ b/partidas.json @@ -1,8 +1,29 @@ [ { "titulo": "Jogo da Cobrinha", - "local": "", + "local": "Campo Central", "data": "2025-02-28", - "horario": "20:30" + "horario": "20:30", + "jogadores": [ + { + "nome": "João", + "telefone": "123456789" + }, + { + "nome": "Maria", + "telefone": "987654321" + }, + { + "nome": "José", + "telefone": "83 98646-1896" + } + ] + }, + { + "titulo": "Jogo do Leão", + "local": "Arena Futuro", + "data": "2025-03-01", + "horario": "16:00", + "jogadores": [] } ] \ No newline at end of file diff --git a/server.js b/server.js index 9db434c..33729a6 100644 --- a/server.js +++ b/server.js @@ -7,16 +7,24 @@ const app = express(); app.use(cors()); app.use(express.json()); +const filePath = path.join(__dirname, 'partidas.json'); + +// Rota para criar nova partida app.post('/criarPartida', (req, res) => { - const filePath = path.join(__dirname, 'partidas.json'); - const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - partidas.push(req.body); + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + partidas.push({ + ...req.body, + jogadores: [] + }); fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); res.status(201).send('Partida criada com sucesso!'); }); +// Rota para obter todas as partidas app.get('/partidas', (req, res) => { - const filePath = path.join(__dirname, 'partidas.json'); if (fs.existsSync(filePath)) { const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); res.json(partidas); @@ -25,6 +33,53 @@ app.get('/partidas', (req, res) => { } }); +// Rota para adicionar jogador a uma partida +app.post('/partidas/:index/jogadores', (req, res) => { + const index = req.params.index; + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + if (partidas[index]) { + partidas[index].jogadores.push(req.body); + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.send('Jogador adicionado com sucesso!'); + } else { + res.status(404).send('Partida não encontrada'); + } +}); + +// Rota para obter jogadores de uma partida +app.get('/partidas/:index/jogadores', (req, res) => { + const index = req.params.index; + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + if (partidas[index]) { + const jogadores = partidas[index].jogadores || []; + res.json(jogadores); + } else { + res.status(404).send('Partida não encontrada'); + } +}); + +// Rota para excluir uma partida +app.delete('/partidas/:index', (req, res) => { + const index = req.params.index; + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + if (partidas[index]) { + partidas.splice(index, 1); + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.send('Partida excluída com sucesso!'); + } else { + res.status(404).send('Partida não encontrada'); + } +}); + app.listen(3000, () => { console.log('Servidor rodando na porta 3000'); }); diff --git a/style.css b/style.css index 1e14555..dc8e3c9 100644 --- a/style.css +++ b/style.css @@ -3,9 +3,9 @@ body { color: black; } -.form-control, .list-group { +.form-control, .list-group-item { background-color: #3e4143; - color: black; + color: white; } #matchList { @@ -13,5 +13,26 @@ body { margin: 0 auto; /* Centraliza horizontalmente */ list-style: none; /* Remove os estilos padrão da lista */ padding: 0; - } - \ No newline at end of file +} + +.match-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.match-options { + margin-top: 10px; +} + +.match-options button { + margin-right: 5px; +} + +.btn-secondary { + background-color: #6c757d; +} + +.container h1, .container h2 { + color: white; +} diff --git a/teste.txt b/teste.txt index 1844b68..c5af4d3 100644 --- a/teste.txt +++ b/teste.txt @@ -1,4 +1,4 @@ -index.html +# index.html @@ -41,7 +41,55 @@ index.html -server.js +# app.js + +document.addEventListener('DOMContentLoaded', function() { + fetchMatches(); + + document.querySelector('#createMatchButton').addEventListener('click', function() { + const title = document.querySelector('#matchTitle').value; + const location = document.querySelector('#matchLocation').value; + const date = document.querySelector('#matchDate').value; + const time = document.querySelector('#matchTime').value; + + fetch('http://localhost:3000/criarPartida', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + titulo: title, + local: location, + data: date, + horario: time + }) + }) + .then(response => response.text()) + .then(data => { + alert(data); + fetchMatches(); + }) + .catch(error => console.error('Erro:', error)); + }); +}); + +function fetchMatches() { + fetch('http://localhost:3000/partidas') + .then(response => response.json()) + .then(partidas => { + const matchList = document.querySelector('#matchList'); + matchList.innerHTML = ''; + partidas.forEach(partida => { + const listItem = document.createElement('li'); + listItem.classList.add('list-group-item'); + listItem.textContent = `${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario}`; + matchList.appendChild(listItem); + }); + }) + .catch(error => console.error('Erro:', error)); +} + +# server.js const express = require('express'); const fs = require('fs'); @@ -74,7 +122,7 @@ app.listen(3000, () => { console.log('Servidor rodando na porta 3000'); }); -style.css +# style.css body { background-color: #77797a; @@ -93,7 +141,7 @@ body { padding: 0; } -partidas.json +# partidas.json [ { @@ -104,52 +152,6 @@ partidas.json } ] -app.js - -document.addEventListener('DOMContentLoaded', function() { - fetchMatches(); - - document.querySelector('#createMatchButton').addEventListener('click', function() { - const title = document.querySelector('#matchTitle').value; - const location = document.querySelector('#matchLocation').value; - const date = document.querySelector('#matchDate').value; - const time = document.querySelector('#matchTime').value; - - fetch('http://localhost:3000/criarPartida', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - titulo: title, - local: location, - data: date, - horario: time - }) - }) - .then(response => response.text()) - .then(data => { - alert(data); - fetchMatches(); - }) - .catch(error => console.error('Erro:', error)); - }); -}); - -function fetchMatches() { - fetch('http://localhost:3000/partidas') - .then(response => response.json()) - .then(partidas => { - const matchList = document.querySelector('#matchList'); - matchList.innerHTML = ''; - partidas.forEach(partida => { - const listItem = document.createElement('li'); - listItem.classList.add('list-group-item'); - listItem.textContent = `${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario}`; - matchList.appendChild(listItem); - }); - }) - .catch(error => console.error('Erro:', error)); -} +# O que fazer -Coloque um botão de "Detalhes" nas Partidas exibidas no index.html que abra outra página com as informações já exibidas. A nova página deve ter as informações já mostradas na página inicial e botões de "Adicionar Jogador", "Ver Presença" e "Excluir Partida" \ No newline at end of file +Faça com que, quando o usuário clicar em uma partida já criada, expanda um campo com as opções de Adicionar Jogador, Ver Jogadores e Excluir Partida. \ No newline at end of file From 9b50a2609c093e868aa8fdfc98e0290a147e4cd9 Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Sat, 1 Mar 2025 12:30:56 -0300 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20estruturando=20melhor=20bot=C3=B5?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * melhora a disposição de botões * os botões "Adicionar Jogador" e "Excluir Partida" funcionam * os botões "Confirmar Presença" e "Excluir" não funcionam --- app.js | 135 +++++++++++---- index.html | 70 ++++++++ partidas.json | 20 --- server.js | 34 ++++ teste.txt | 450 +++++++++++++++++++++++++++++++++++--------------- 5 files changed, 523 insertions(+), 186 deletions(-) diff --git a/app.js b/app.js index 62761dd..812fbcd 100644 --- a/app.js +++ b/app.js @@ -26,6 +26,48 @@ document.addEventListener('DOMContentLoaded', function() { }) .catch(error => console.error('Erro:', error)); }); + + // Evento de submit do formulário de adicionar jogador + document.querySelector('#addPlayerForm').addEventListener('submit', function(e) { + e.preventDefault(); + const index = document.querySelector('#matchIndexForPlayer').value; + const playerName = document.querySelector('#playerName').value; + const playerPhone = document.querySelector('#playerPhone').value; + + if (playerName && playerPhone) { + fetch(`http://localhost:3000/partidas/${index}/jogadores`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + nome: playerName, + telefone: playerPhone + }) + }) + .then(response => response.text()) + .then(data => { + alert(data); + $('#addPlayerModal').modal('hide'); + }) + .catch(error => console.error('Erro:', error)); + } + }); + + // Evento de confirmação da exclusão de partida + document.querySelector('#confirmDeleteMatchButton').addEventListener('click', function() { + const index = document.querySelector('#matchIndexToDelete').value; + fetch(`http://localhost:3000/partidas/${index}`, { + method: 'DELETE', + }) + .then(response => response.text()) + .then(data => { + alert(data); + $('#confirmDeleteMatchModal').modal('hide'); + fetchMatches(); // Atualiza a lista de partidas + }) + .catch(error => console.error('Erro:', error)); + }); }); function fetchMatches() { @@ -65,56 +107,87 @@ function fetchMatches() { } function addPlayer(index) { - const playerName = prompt('Digite o nome do jogador:'); - const playerPhone = prompt('Digite o telefone do jogador:'); - if (playerName && playerPhone) { - fetch(`http://localhost:3000/partidas/${index}/jogadores`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - nome: playerName, - telefone: playerPhone - }) - }) - .then(response => response.text()) - .then(data => { - alert(data); - }) - .catch(error => console.error('Erro:', error)); - } else { - alert('Nome e telefone são obrigatórios!'); - } + // Define o índice da partida no input oculto do modal + document.querySelector('#matchIndexForPlayer').value = index; + // Limpa os campos do formulário + document.querySelector('#playerName').value = ''; + document.querySelector('#playerPhone').value = ''; + // Abre o modal para adicionar jogador + $('#addPlayerModal').modal('show'); } function viewPlayers(index) { fetch(`http://localhost:3000/partidas/${index}/jogadores`) .then(response => response.json()) .then(jogadores => { + const playerList = document.querySelector('#playerList'); + playerList.innerHTML = ''; // Limpa a lista anterior if (jogadores.length === 0) { - alert('Nenhum jogador adicionado ainda.'); + const li = document.createElement('li'); + li.className = 'list-group-item'; + li.textContent = 'Nenhum jogador adicionado ainda.'; + playerList.appendChild(li); } else { - let playerList = 'Jogadores:\n'; - jogadores.forEach(jogador => { - playerList += `- ${jogador.nome} (${jogador.telefone})\n`; + jogadores.forEach((jogador, playerIndex) => { + const li = document.createElement('li'); + li.className = 'list-group-item d-flex justify-content-between align-items-center'; + li.innerHTML = `${jogador.nome} (${jogador.telefone}) ${jogador.presenca ? '- Presente' : ''}`; + const btnGroup = document.createElement('div'); + // Botão verde para confirmar presença + const confirmBtn = document.createElement('button'); + confirmBtn.className = 'btn btn-success btn-sm'; + confirmBtn.textContent = 'Confirmar Presença'; + confirmBtn.addEventListener('click', function() { + confirmPresence(index, playerIndex); + }); + // Botão vermelho para excluir jogador + const deleteBtn = document.createElement('button'); + deleteBtn.className = 'btn btn-danger btn-sm ml-2'; + deleteBtn.textContent = 'Excluir'; + deleteBtn.addEventListener('click', function() { + deletePlayer(index, playerIndex); + }); + btnGroup.appendChild(confirmBtn); + btnGroup.appendChild(deleteBtn); + li.appendChild(btnGroup); + playerList.appendChild(li); }); - alert(playerList); } + // Abre o modal de jogadores + $('#viewPlayersModal').modal('show'); }) .catch(error => console.error('Erro:', error)); } -function deleteMatch(index) { - if (confirm('Tem certeza que deseja excluir esta partida?')) { - fetch(`http://localhost:3000/partidas/${index}`, { - method: 'DELETE', +function confirmPresence(matchIndex, playerIndex) { + fetch(`http://localhost:3000/partidas/${matchIndex}/jogadores/${playerIndex}/confirm`, { + method: 'PATCH' + }) + .then(response => response.text()) + .then(data => { + alert(data); + // Atualiza a lista de jogadores + viewPlayers(matchIndex); + }) + .catch(error => console.error('Erro:', error)); +} + +function deletePlayer(matchIndex, playerIndex) { + if (confirm('Tem certeza que deseja excluir este jogador?')) { + fetch(`http://localhost:3000/partidas/${matchIndex}/jogadores/${playerIndex}`, { + method: 'DELETE' }) .then(response => response.text()) .then(data => { alert(data); - fetchMatches(); // Atualiza a lista de partidas + // Atualiza a lista de jogadores + viewPlayers(matchIndex); }) .catch(error => console.error('Erro:', error)); } } + +function deleteMatch(index) { + document.querySelector('#matchIndexToDelete').value = index; + $('#confirmDeleteMatchModal').modal('show'); +} diff --git a/index.html b/index.html index cf58860..ce7b655 100644 --- a/index.html +++ b/index.html @@ -35,6 +35,76 @@

            Partidas Criadas

              + + + + + + + + + + diff --git a/partidas.json b/partidas.json index ed64cc1..ccc152e 100644 --- a/partidas.json +++ b/partidas.json @@ -1,24 +1,4 @@ [ - { - "titulo": "Jogo da Cobrinha", - "local": "Campo Central", - "data": "2025-02-28", - "horario": "20:30", - "jogadores": [ - { - "nome": "João", - "telefone": "123456789" - }, - { - "nome": "Maria", - "telefone": "987654321" - }, - { - "nome": "José", - "telefone": "83 98646-1896" - } - ] - }, { "titulo": "Jogo do Leão", "local": "Arena Futuro", diff --git a/server.js b/server.js index 33729a6..9ca7b30 100644 --- a/server.js +++ b/server.js @@ -64,6 +64,40 @@ app.get('/partidas/:index/jogadores', (req, res) => { } }); +// Rota para confirmar presença do jogador +app.patch('/partidas/:matchIndex/jogadores/:playerIndex/confirm', (req, res) => { + const matchIndex = req.params.matchIndex; + const playerIndex = req.params.playerIndex; + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + if (partidas[matchIndex] && partidas[matchIndex].jogadores[playerIndex]) { + partidas[matchIndex].jogadores[playerIndex].presenca = true; + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.send('Presença confirmada!'); + } else { + res.status(404).send('Partida ou jogador não encontrado'); + } +}); + +// Rota para excluir jogador +app.delete('/partidas/:matchIndex/jogadores/:playerIndex', (req, res) => { + const matchIndex = req.params.matchIndex; + const playerIndex = req.params.playerIndex; + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + if (partidas[matchIndex] && partidas[matchIndex].jogadores[playerIndex]) { + partidas[matchIndex].jogadores.splice(playerIndex, 1); + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.send('Jogador excluído com sucesso!'); + } else { + res.status(404).send('Partida ou jogador não encontrado'); + } +}); + // Rota para excluir uma partida app.delete('/partidas/:index', (req, res) => { const index = req.params.index; diff --git a/teste.txt b/teste.txt index c5af4d3..e8e9490 100644 --- a/teste.txt +++ b/teste.txt @@ -1,157 +1,337 @@ -# index.html - - - - - - - Organizador de Partidas de Futebol - - - - -
              -

              Organizador de Partidas de Futebol

              -
              - - -
              -
              - - -
              -
              - - -
              -
              - - +agora, modifique as funções dos botões "Adicionar Jogador", "Ver Jogadores" e "Excluir Partida" para que, quando clicados pelo usuário quando clicar em "Adicionar Jogador", a tela aberta deve apresentar campos obrigatórios para preencher as mesmas informações já necessárias. + +quando clicar em "Ver Jogadores", a tela aberta deve contar um botão verde para confirmar sua presença e um botão vermelho para excluir o jogador antes adicionado da lista. no final, apresente os arquivos já existentes com os elementos originais e usas modificações. + +a seguir estão os arquivos existentes: + +index.html { + + + + + + + Organizador de Partidas de Futebol + + + + + + +
              +

              Organizador de Partidas de Futebol

              +
              + + +
              +
              + + +
              +
              + + +
              +
              + + +
              + + +

              Partidas Criadas

              +
              +
                +
                - - -

                Partidas Criadas

                -
                -
                  -
                  -
                  - - - - - - -# app.js - -document.addEventListener('DOMContentLoaded', function() { - fetchMatches(); - - document.querySelector('#createMatchButton').addEventListener('click', function() { - const title = document.querySelector('#matchTitle').value; - const location = document.querySelector('#matchLocation').value; - const date = document.querySelector('#matchDate').value; - const time = document.querySelector('#matchTime').value; - - fetch('http://localhost:3000/criarPartida', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - titulo: title, - local: location, - data: date, - horario: time + + + + + + + +} + +app.js { + document.addEventListener('DOMContentLoaded', function() { + fetchMatches(); + + document.querySelector('#createMatchButton').addEventListener('click', function() { + const title = document.querySelector('#matchTitle').value; + const location = document.querySelector('#matchLocation').value; + const date = document.querySelector('#matchDate').value; + const time = document.querySelector('#matchTime').value; + + fetch('http://localhost:3000/criarPartida', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + titulo: title, + local: location, + data: date, + horario: time + }) + }) + .then(response => response.text()) + .then(data => { + alert(data); + fetchMatches(); }) + .catch(error => console.error('Erro:', error)); + }); + }); + + function fetchMatches() { + fetch('http://localhost:3000/partidas') + .then(response => response.json()) + .then(partidas => { + const matchList = document.querySelector('#matchList'); + matchList.innerHTML = ''; + partidas.forEach((partida, index) => { + const listItem = document.createElement('li'); + listItem.classList.add('list-group-item', 'match-item'); + listItem.innerHTML = ` +
                  + ${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario} + +
                  + + `; + + // Evento para expandir/recolher opções + const toggleBtn = listItem.querySelector('.toggle-btn'); + toggleBtn.addEventListener('click', function() { + const optionsDiv = listItem.querySelector('.match-options'); + const isVisible = optionsDiv.style.display === 'block'; + optionsDiv.style.display = isVisible ? 'none' : 'block'; + toggleBtn.textContent = isVisible ? '▼' : '▲'; + }); + + matchList.appendChild(listItem); + }); }) - .then(response => response.text()) - .then(data => { - alert(data); - fetchMatches(); + .catch(error => console.error('Erro:', error)); + } + + function addPlayer(index) { + const playerName = prompt('Digite o nome do jogador:'); + const playerPhone = prompt('Digite o telefone do jogador:'); + if (playerName && playerPhone) { + fetch(`http://localhost:3000/partidas/${index}/jogadores`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + nome: playerName, + telefone: playerPhone + }) + }) + .then(response => response.text()) + .then(data => { + alert(data); + }) + .catch(error => console.error('Erro:', error)); + } else { + alert('Nome e telefone são obrigatórios!'); + } + } + + function viewPlayers(index) { + fetch(`http://localhost:3000/partidas/${index}/jogadores`) + .then(response => response.json()) + .then(jogadores => { + if (jogadores.length === 0) { + alert('Nenhum jogador adicionado ainda.'); + } else { + let playerList = 'Jogadores:\n'; + jogadores.forEach(jogador => { + playerList += `- ${jogador.nome} (${jogador.telefone})\n`; + }); + alert(playerList); + } }) .catch(error => console.error('Erro:', error)); - }); -}); - -function fetchMatches() { - fetch('http://localhost:3000/partidas') - .then(response => response.json()) - .then(partidas => { - const matchList = document.querySelector('#matchList'); - matchList.innerHTML = ''; - partidas.forEach(partida => { - const listItem = document.createElement('li'); - listItem.classList.add('list-group-item'); - listItem.textContent = `${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario}`; - matchList.appendChild(listItem); - }); - }) - .catch(error => console.error('Erro:', error)); + } + + function deleteMatch(index) { + if (confirm('Tem certeza que deseja excluir esta partida?')) { + fetch(`http://localhost:3000/partidas/${index}`, { + method: 'DELETE', + }) + .then(response => response.text()) + .then(data => { + alert(data); + fetchMatches(); // Atualiza a lista de partidas + }) + .catch(error => console.error('Erro:', error)); + } + } } -# server.js +partidas.json { + [ + { + "titulo": "Jogo da Cobrinha", + "local": "Campo Central", + "data": "2025-02-28", + "horario": "20:30", + "jogadores": [ + { + "nome": "João", + "telefone": "123456789" + }, + { + "nome": "Maria", + "telefone": "987654321" + }, + { + "nome": "José", + "telefone": "83 98646-1896" + } + ] + }, + { + "titulo": "Jogo do Leão", + "local": "Arena Futuro", + "data": "2025-03-01", + "horario": "16:00", + "jogadores": [] + } + ] +} -const express = require('express'); -const fs = require('fs'); -const path = require('path'); -const cors = require('cors'); -const app = express(); +server.js { + const express = require('express'); + const fs = require('fs'); + const path = require('path'); + const cors = require('cors'); + const app = express(); -app.use(cors()); -app.use(express.json()); + app.use(cors()); + app.use(express.json()); -app.post('/criarPartida', (req, res) => { const filePath = path.join(__dirname, 'partidas.json'); - const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - partidas.push(req.body); - fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); - res.status(201).send('Partida criada com sucesso!'); -}); -app.get('/partidas', (req, res) => { - const filePath = path.join(__dirname, 'partidas.json'); - if (fs.existsSync(filePath)) { - const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - res.json(partidas); - } else { - res.json([]); - } -}); + // Rota para criar nova partida + app.post('/criarPartida', (req, res) => { + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + partidas.push({ + ...req.body, + jogadores: [] + }); + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.status(201).send('Partida criada com sucesso!'); + }); -app.listen(3000, () => { - console.log('Servidor rodando na porta 3000'); -}); + // Rota para obter todas as partidas + app.get('/partidas', (req, res) => { + if (fs.existsSync(filePath)) { + const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + res.json(partidas); + } else { + res.json([]); + } + }); -# style.css + // Rota para adicionar jogador a uma partida + app.post('/partidas/:index/jogadores', (req, res) => { + const index = req.params.index; + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + if (partidas[index]) { + partidas[index].jogadores.push(req.body); + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.send('Jogador adicionado com sucesso!'); + } else { + res.status(404).send('Partida não encontrada'); + } + }); -body { - background-color: #77797a; - color: black; -} + // Rota para obter jogadores de uma partida + app.get('/partidas/:index/jogadores', (req, res) => { + const index = req.params.index; + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + if (partidas[index]) { + const jogadores = partidas[index].jogadores || []; + res.json(jogadores); + } else { + res.status(404).send('Partida não encontrada'); + } + }); + + // Rota para excluir uma partida + app.delete('/partidas/:index', (req, res) => { + const index = req.params.index; + let partidas = []; + if (fs.existsSync(filePath)) { + partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + if (partidas[index]) { + partidas.splice(index, 1); + fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); + res.send('Partida excluída com sucesso!'); + } else { + res.status(404).send('Partida não encontrada'); + } + }); -.form-control, .list-group { - background-color: #3e4143; - color: black; + app.listen(3000, () => { + console.log('Servidor rodando na porta 3000'); + }); } -#matchList { - width: 50%; /* Define uma largura */ - margin: 0 auto; /* Centraliza horizontalmente */ - list-style: none; /* Remove os estilos padrão da lista */ - padding: 0; - } +style.css { + body { + background-color: #77797a; + color: black; + } + + .form-control, .list-group-item { + background-color: #3e4143; + color: white; + } + + #matchList { + width: 50%; /* Define uma largura */ + margin: 0 auto; /* Centraliza horizontalmente */ + list-style: none; /* Remove os estilos padrão da lista */ + padding: 0; + } + + .match-header { + display: flex; + justify-content: space-between; + align-items: center; + } -# partidas.json + .match-options { + margin-top: 10px; + } -[ - { - "titulo": "Jogo da Cobrinha", - "local": "", - "data": "2025-02-28", - "horario": "20:30" - } -] + .match-options button { + margin-right: 5px; + } -# O que fazer + .btn-secondary { + background-color: #6c757d; + } -Faça com que, quando o usuário clicar em uma partida já criada, expanda um campo com as opções de Adicionar Jogador, Ver Jogadores e Excluir Partida. \ No newline at end of file + .container h1, .container h2 { + color: white; + } +} \ No newline at end of file From f62f307f79e56c80aad8eda58e180acb1aff5baa Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Sat, 1 Mar 2025 12:44:02 -0300 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20bot=C3=B5es=20de=20Presen=C3=A7a?= =?UTF-8?q?=20e=20Excluir=20jogadores?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.js | 68 +++++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/server.js b/server.js index 9ca7b30..b49fdfd 100644 --- a/server.js +++ b/server.js @@ -9,12 +9,18 @@ app.use(express.json()); const filePath = path.join(__dirname, 'partidas.json'); -// Rota para criar nova partida -app.post('/criarPartida', (req, res) => { +// Função para ler as partidas +function readPartidas() { let partidas = []; if (fs.existsSync(filePath)) { partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); } + return partidas; +} + +// Rota para criar nova partida +app.post('/criarPartida', (req, res) => { + let partidas = readPartidas(); partidas.push({ ...req.body, jogadores: [] @@ -25,21 +31,14 @@ app.post('/criarPartida', (req, res) => { // Rota para obter todas as partidas app.get('/partidas', (req, res) => { - if (fs.existsSync(filePath)) { - const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - res.json(partidas); - } else { - res.json([]); - } + const partidas = readPartidas(); + res.json(partidas); }); // Rota para adicionar jogador a uma partida app.post('/partidas/:index/jogadores', (req, res) => { - const index = req.params.index; - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } + const index = parseInt(req.params.index, 10); + let partidas = readPartidas(); if (partidas[index]) { partidas[index].jogadores.push(req.body); fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); @@ -51,11 +50,8 @@ app.post('/partidas/:index/jogadores', (req, res) => { // Rota para obter jogadores de uma partida app.get('/partidas/:index/jogadores', (req, res) => { - const index = req.params.index; - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } + const index = parseInt(req.params.index, 10); + let partidas = readPartidas(); if (partidas[index]) { const jogadores = partidas[index].jogadores || []; res.json(jogadores); @@ -66,12 +62,18 @@ app.get('/partidas/:index/jogadores', (req, res) => { // Rota para confirmar presença do jogador app.patch('/partidas/:matchIndex/jogadores/:playerIndex/confirm', (req, res) => { - const matchIndex = req.params.matchIndex; - const playerIndex = req.params.playerIndex; - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); + const matchIndex = parseInt(req.params.matchIndex, 10); + const playerIndex = parseInt(req.params.playerIndex, 10); + let partidas = readPartidas(); + + // Logs para depuração + console.log(`Confirmar presença: matchIndex=${matchIndex}, playerIndex=${playerIndex}`); + if (partidas[matchIndex]) { + console.log(`Partida encontrada:`, partidas[matchIndex]); + } else { + console.log(`Partida com índice ${matchIndex} não encontrada.`); } + if (partidas[matchIndex] && partidas[matchIndex].jogadores[playerIndex]) { partidas[matchIndex].jogadores[playerIndex].presenca = true; fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); @@ -83,12 +85,13 @@ app.patch('/partidas/:matchIndex/jogadores/:playerIndex/confirm', (req, res) => // Rota para excluir jogador app.delete('/partidas/:matchIndex/jogadores/:playerIndex', (req, res) => { - const matchIndex = req.params.matchIndex; - const playerIndex = req.params.playerIndex; - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } + const matchIndex = parseInt(req.params.matchIndex, 10); + const playerIndex = parseInt(req.params.playerIndex, 10); + let partidas = readPartidas(); + + // Log para depuração + console.log(`Excluir jogador: matchIndex=${matchIndex}, playerIndex=${playerIndex}`); + if (partidas[matchIndex] && partidas[matchIndex].jogadores[playerIndex]) { partidas[matchIndex].jogadores.splice(playerIndex, 1); fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); @@ -100,11 +103,8 @@ app.delete('/partidas/:matchIndex/jogadores/:playerIndex', (req, res) => { // Rota para excluir uma partida app.delete('/partidas/:index', (req, res) => { - const index = req.params.index; - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } + const index = parseInt(req.params.index, 10); + let partidas = readPartidas(); if (partidas[index]) { partidas.splice(index, 1); fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); From 193bbbfe776fa2de61133249e837c5bc1f6ed265 Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Sat, 1 Mar 2025 12:48:21 -0300 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20Presen=C3=A7a=20de=20Jogador?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * faz com que o jogador que tenha sua presença confirmada apareça com o nome verde --- app.js | 17 ++++++++++++++--- partidas.json | 8 +++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/app.js b/app.js index 812fbcd..d0c80c0 100644 --- a/app.js +++ b/app.js @@ -131,7 +131,18 @@ function viewPlayers(index) { jogadores.forEach((jogador, playerIndex) => { const li = document.createElement('li'); li.className = 'list-group-item d-flex justify-content-between align-items-center'; - li.innerHTML = `${jogador.nome} (${jogador.telefone}) ${jogador.presenca ? '- Presente' : ''}`; + + // Cria um span para exibir o nome e telefone do jogador. + const nameSpan = document.createElement('span'); + if(jogador.presenca) { + // Se o jogador estiver presente, o nome é exibido em verde (classe text-success). + nameSpan.className = 'text-success'; + nameSpan.textContent = `${jogador.nome} (${jogador.telefone}) - Presente`; + } else { + nameSpan.textContent = `${jogador.nome} (${jogador.telefone})`; + } + li.appendChild(nameSpan); + const btnGroup = document.createElement('div'); // Botão verde para confirmar presença const confirmBtn = document.createElement('button'); @@ -166,7 +177,7 @@ function confirmPresence(matchIndex, playerIndex) { .then(response => response.text()) .then(data => { alert(data); - // Atualiza a lista de jogadores + // Atualiza a lista de jogadores para refletir a mudança viewPlayers(matchIndex); }) .catch(error => console.error('Erro:', error)); @@ -180,7 +191,7 @@ function deletePlayer(matchIndex, playerIndex) { .then(response => response.text()) .then(data => { alert(data); - // Atualiza a lista de jogadores + // Atualiza a lista de jogadores para refletir a remoção viewPlayers(matchIndex); }) .catch(error => console.error('Erro:', error)); diff --git a/partidas.json b/partidas.json index ccc152e..e90eccf 100644 --- a/partidas.json +++ b/partidas.json @@ -4,6 +4,12 @@ "local": "Arena Futuro", "data": "2025-03-01", "horario": "16:00", - "jogadores": [] + "jogadores": [ + { + "nome": "awdawdawd", + "telefone": "11 11111-1111", + "presenca": true + } + ] } ] \ No newline at end of file From cd60470f3b1a888eb1424309c1ea99f90f811991 Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Sat, 1 Mar 2025 12:55:19 -0300 Subject: [PATCH 09/11] feat: tudo funcionando --- app.js | 16 +-- partidas.json | 11 +- teste.txt | 337 -------------------------------------------------- 3 files changed, 18 insertions(+), 346 deletions(-) delete mode 100644 teste.txt diff --git a/app.js b/app.js index d0c80c0..57a7aa9 100644 --- a/app.js +++ b/app.js @@ -48,7 +48,8 @@ document.addEventListener('DOMContentLoaded', function() { .then(response => response.text()) .then(data => { alert(data); - $('#addPlayerModal').modal('hide'); + // Em vez de fechar o modal, atualizamos a lista de jogadores + viewPlayers(index); }) .catch(error => console.error('Erro:', error)); } @@ -63,8 +64,8 @@ document.addEventListener('DOMContentLoaded', function() { .then(response => response.text()) .then(data => { alert(data); - $('#confirmDeleteMatchModal').modal('hide'); - fetchMatches(); // Atualiza a lista de partidas + // Não fechamos o modal; apenas atualizamos a lista de partidas + fetchMatches(); }) .catch(error => console.error('Erro:', error)); }); @@ -112,7 +113,7 @@ function addPlayer(index) { // Limpa os campos do formulário document.querySelector('#playerName').value = ''; document.querySelector('#playerPhone').value = ''; - // Abre o modal para adicionar jogador + // Abre o modal para adicionar jogador (o modal permanece aberto após a ação) $('#addPlayerModal').modal('show'); } @@ -164,7 +165,7 @@ function viewPlayers(index) { playerList.appendChild(li); }); } - // Abre o modal de jogadores + // Abre (ou mantém) o modal de jogadores aberto $('#viewPlayersModal').modal('show'); }) .catch(error => console.error('Erro:', error)); @@ -177,7 +178,7 @@ function confirmPresence(matchIndex, playerIndex) { .then(response => response.text()) .then(data => { alert(data); - // Atualiza a lista de jogadores para refletir a mudança + // Atualiza a lista de jogadores para refletir a mudança, sem fechar o modal viewPlayers(matchIndex); }) .catch(error => console.error('Erro:', error)); @@ -191,7 +192,7 @@ function deletePlayer(matchIndex, playerIndex) { .then(response => response.text()) .then(data => { alert(data); - // Atualiza a lista de jogadores para refletir a remoção + // Atualiza a lista de jogadores para refletir a remoção, mantendo o modal aberto viewPlayers(matchIndex); }) .catch(error => console.error('Erro:', error)); @@ -200,5 +201,6 @@ function deletePlayer(matchIndex, playerIndex) { function deleteMatch(index) { document.querySelector('#matchIndexToDelete').value = index; + // Exibe o modal de confirmação de exclusão, que permanecerá aberto após a ação $('#confirmDeleteMatchModal').modal('show'); } diff --git a/partidas.json b/partidas.json index e90eccf..aed22e9 100644 --- a/partidas.json +++ b/partidas.json @@ -6,10 +6,17 @@ "horario": "16:00", "jogadores": [ { - "nome": "awdawdawd", - "telefone": "11 11111-1111", + "nome": "jogador2", + "telefone": "22 22222-2222", "presenca": true } ] + }, + { + "titulo": "Jogo da Cobrinha", + "local": "Casa de Malia", + "data": "2025-03-01", + "horario": "20:00", + "jogadores": [] } ] \ No newline at end of file diff --git a/teste.txt b/teste.txt deleted file mode 100644 index e8e9490..0000000 --- a/teste.txt +++ /dev/null @@ -1,337 +0,0 @@ -agora, modifique as funções dos botões "Adicionar Jogador", "Ver Jogadores" e "Excluir Partida" para que, quando clicados pelo usuário quando clicar em "Adicionar Jogador", a tela aberta deve apresentar campos obrigatórios para preencher as mesmas informações já necessárias. - -quando clicar em "Ver Jogadores", a tela aberta deve contar um botão verde para confirmar sua presença e um botão vermelho para excluir o jogador antes adicionado da lista. no final, apresente os arquivos já existentes com os elementos originais e usas modificações. - -a seguir estão os arquivos existentes: - -index.html { - - - - - - - Organizador de Partidas de Futebol - - - - - - -
                  -

                  Organizador de Partidas de Futebol

                  -
                  - - -
                  -
                  - - -
                  -
                  - - -
                  -
                  - - -
                  - - -

                  Partidas Criadas

                  -
                  -
                    -
                    -
                    - - - - - - - -} - -app.js { - document.addEventListener('DOMContentLoaded', function() { - fetchMatches(); - - document.querySelector('#createMatchButton').addEventListener('click', function() { - const title = document.querySelector('#matchTitle').value; - const location = document.querySelector('#matchLocation').value; - const date = document.querySelector('#matchDate').value; - const time = document.querySelector('#matchTime').value; - - fetch('http://localhost:3000/criarPartida', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - titulo: title, - local: location, - data: date, - horario: time - }) - }) - .then(response => response.text()) - .then(data => { - alert(data); - fetchMatches(); - }) - .catch(error => console.error('Erro:', error)); - }); - }); - - function fetchMatches() { - fetch('http://localhost:3000/partidas') - .then(response => response.json()) - .then(partidas => { - const matchList = document.querySelector('#matchList'); - matchList.innerHTML = ''; - partidas.forEach((partida, index) => { - const listItem = document.createElement('li'); - listItem.classList.add('list-group-item', 'match-item'); - listItem.innerHTML = ` -
                    - ${partida.titulo} - ${partida.local} - ${partida.data} - ${partida.horario} - -
                    - - `; - - // Evento para expandir/recolher opções - const toggleBtn = listItem.querySelector('.toggle-btn'); - toggleBtn.addEventListener('click', function() { - const optionsDiv = listItem.querySelector('.match-options'); - const isVisible = optionsDiv.style.display === 'block'; - optionsDiv.style.display = isVisible ? 'none' : 'block'; - toggleBtn.textContent = isVisible ? '▼' : '▲'; - }); - - matchList.appendChild(listItem); - }); - }) - .catch(error => console.error('Erro:', error)); - } - - function addPlayer(index) { - const playerName = prompt('Digite o nome do jogador:'); - const playerPhone = prompt('Digite o telefone do jogador:'); - if (playerName && playerPhone) { - fetch(`http://localhost:3000/partidas/${index}/jogadores`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - nome: playerName, - telefone: playerPhone - }) - }) - .then(response => response.text()) - .then(data => { - alert(data); - }) - .catch(error => console.error('Erro:', error)); - } else { - alert('Nome e telefone são obrigatórios!'); - } - } - - function viewPlayers(index) { - fetch(`http://localhost:3000/partidas/${index}/jogadores`) - .then(response => response.json()) - .then(jogadores => { - if (jogadores.length === 0) { - alert('Nenhum jogador adicionado ainda.'); - } else { - let playerList = 'Jogadores:\n'; - jogadores.forEach(jogador => { - playerList += `- ${jogador.nome} (${jogador.telefone})\n`; - }); - alert(playerList); - } - }) - .catch(error => console.error('Erro:', error)); - } - - function deleteMatch(index) { - if (confirm('Tem certeza que deseja excluir esta partida?')) { - fetch(`http://localhost:3000/partidas/${index}`, { - method: 'DELETE', - }) - .then(response => response.text()) - .then(data => { - alert(data); - fetchMatches(); // Atualiza a lista de partidas - }) - .catch(error => console.error('Erro:', error)); - } - } -} - -partidas.json { - [ - { - "titulo": "Jogo da Cobrinha", - "local": "Campo Central", - "data": "2025-02-28", - "horario": "20:30", - "jogadores": [ - { - "nome": "João", - "telefone": "123456789" - }, - { - "nome": "Maria", - "telefone": "987654321" - }, - { - "nome": "José", - "telefone": "83 98646-1896" - } - ] - }, - { - "titulo": "Jogo do Leão", - "local": "Arena Futuro", - "data": "2025-03-01", - "horario": "16:00", - "jogadores": [] - } - ] -} - -server.js { - const express = require('express'); - const fs = require('fs'); - const path = require('path'); - const cors = require('cors'); - const app = express(); - - app.use(cors()); - app.use(express.json()); - - const filePath = path.join(__dirname, 'partidas.json'); - - // Rota para criar nova partida - app.post('/criarPartida', (req, res) => { - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } - partidas.push({ - ...req.body, - jogadores: [] - }); - fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); - res.status(201).send('Partida criada com sucesso!'); - }); - - // Rota para obter todas as partidas - app.get('/partidas', (req, res) => { - if (fs.existsSync(filePath)) { - const partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - res.json(partidas); - } else { - res.json([]); - } - }); - - // Rota para adicionar jogador a uma partida - app.post('/partidas/:index/jogadores', (req, res) => { - const index = req.params.index; - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } - if (partidas[index]) { - partidas[index].jogadores.push(req.body); - fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); - res.send('Jogador adicionado com sucesso!'); - } else { - res.status(404).send('Partida não encontrada'); - } - }); - - // Rota para obter jogadores de uma partida - app.get('/partidas/:index/jogadores', (req, res) => { - const index = req.params.index; - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } - if (partidas[index]) { - const jogadores = partidas[index].jogadores || []; - res.json(jogadores); - } else { - res.status(404).send('Partida não encontrada'); - } - }); - - // Rota para excluir uma partida - app.delete('/partidas/:index', (req, res) => { - const index = req.params.index; - let partidas = []; - if (fs.existsSync(filePath)) { - partidas = JSON.parse(fs.readFileSync(filePath, 'utf-8')); - } - if (partidas[index]) { - partidas.splice(index, 1); - fs.writeFileSync(filePath, JSON.stringify(partidas, null, 2)); - res.send('Partida excluída com sucesso!'); - } else { - res.status(404).send('Partida não encontrada'); - } - }); - - app.listen(3000, () => { - console.log('Servidor rodando na porta 3000'); - }); -} - -style.css { - body { - background-color: #77797a; - color: black; - } - - .form-control, .list-group-item { - background-color: #3e4143; - color: white; - } - - #matchList { - width: 50%; /* Define uma largura */ - margin: 0 auto; /* Centraliza horizontalmente */ - list-style: none; /* Remove os estilos padrão da lista */ - padding: 0; - } - - .match-header { - display: flex; - justify-content: space-between; - align-items: center; - } - - .match-options { - margin-top: 10px; - } - - .match-options button { - margin-right: 5px; - } - - .btn-secondary { - background-color: #6c757d; - } - - .container h1, .container h2 { - color: white; - } -} \ No newline at end of file From f68af72e7850dbb3094417db38e5e83f5cb70fdf Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Sat, 1 Mar 2025 13:08:29 -0300 Subject: [PATCH 10/11] docs: atualizando o README --- README.md | 66 +++++++++++++++---------------------------------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index e357099..0b98363 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,29 @@ -# Objetivo do Projeto +# Projeto - Assincronismo + NodeJS + Express -Criar uma aplicação que facilite a organização e marcação de partidas de futebol entre amigos. +## Objetivo -# Módulos +Criar uma aplicação que facilite a organização e marcação de partidas +de futebol entre amigos. -Para esse projeto deve ser construído os seguintes módulos: -- Frontend utilizando HTML, CSS e Javascript para controlar os eventos da tela e realizar as requisições para o backend para salvar e recuperar os dados. É permitido utilizar bibliotecas para a estilização das páginas, tais como Bootstrap, Bulma, Semantic, UIKit, etc. -- Backend utilizando NodeJS + Express. Aqui, fique a vontade para utilizar outras bibliotecas que possam facilitar seu trabalho. - -# Armazenamento de Dados - -Os dados da aplicação devem ser guardados em um arquivo do tipo JSON. Para isso, utilize as funções nativas do NodeJS para ler (readFile) e escrever arquivos (writeFile). - -# Funcionalidades - -1. Criar partidas. Cada partida deve ter um título, um local, data e horário. -2. Criar lista de presença dos jogadores. Após criar a partida, deve ser permitido adicionar/remover uma lista com os participantes e um telefone para contato. -3. Acompanhar a presença. Essa funcionalidade será usada para "confirmar" quem vai estar presente no dia da partida marcada. Deverá ser apresentada a lista dos jogadores com uma opção para confirmar sua presença. -4. Excluir partida. Deve ser permitido excluir a partida. -5. Os dados da aplicação devem ser guardados em um arquivo do tipo JSON. Para isso, utilize as funções nativas do NodeJS para ler (readFile) e escrever arquivos (writeFile). - -# Estrutura +## Funcionalidades -Sua estrutura deve ser essa a seguir, seguindo as "Funcionalidades", citadas anteriormente: +1. Criar partidas: Cada partida deve ter um título, um local, data e horário. +2. Criar lista de presença dos jogadores: Após criar a partida, deve ser permitido adicionar/remover uma lista com os participantes e um telefone para contato. +3. Acompanhar a presença: Essa funcionalidade será usada para "confirmar" quem vai estar presente no dia da partida marcada. Deverá ser apresentada a lista dos jogadores com uma opção para confirmar sua presença. +- Excluir partida. Deve ser permitido excluir a partida. -1. uma página inicial (pagInicial.html) com uma apresentação breve sobre o site no body. Uma section com o botão "Criar Partida". +## Módulos -2. Após a partida ser criada, ela deve aparecer em uma lista na página inicial, tendo como destaque seu título, data e horário, e o local sendo uma informação secundária. - -3. Após clicar em uma das partidas da lista, ela deve ser aberta uma nova página, mostrando as informações de forma mais detalhada sobre a partida escolhida e com a sessão de "Jogadores", abrindo uma parte com os botões de "Adicionar" e "Acompanhar" (para ver e excluir cada jogador). - -4. por fim, um botão de excluir a partida anteriormente criada na página específica dela - -# Arquivos - -1. usar HTML, CSS, JS -2. deve ser criado um arquivo cores.css, para armazenar em variáveis as cores mais usadas durantes as páginas. -3. cada página deve ter seu css próprio com o cores.css linkado -4. todas as funcionalidades devem estar dentro de um mesmo arquivo (funcionalidades.js) - -# Pastas +Para esse projeto deve ser construído os seguintes módulos: -Pasta 1: JS (para todos os arquivos JS) -* funcionalidades.js (com todas as funções js necessárias para fazer as páginas no site funcionar) +* Frontend utilizando HTML, CSS e Javascript para controlar os eventos da tela e realizar as requisições para o backend para salvar e recuperar os dados. + * É permitido utilizar bibliotecas para a estilização das páginas, tais como Bootstrap, Bulma, Semantic, UIKit, etc. -Pasta 2: Paginas (para todos os arquivos HTML) -* pagInicial.html -* partidaDetalhes.html +* Backend utilizando NodeJS + Express. + * Aqui, fique a vontade para utilizar outras bibliotecas que possam facilitar seu trabalho. -Pasta 3: Styles (para todos os arquivos CSS) -* cores.css -* pagInicial.css -* partidaDrtalhes.css +## Armazenamento de Dados -Pasta 4: data -* partidas.json +Os dados da aplicação devem ser guardados em um arquivo do tipo JSON. -Pasta 5: node_modules +Para isso, utilize as funções nativas do NodeJS para ler (readFile) e escrever arquivos (writeFile). \ No newline at end of file From 64c4559809721f009eeff03db209d07aa7386d76 Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Sat, 1 Mar 2025 13:15:52 -0300 Subject: [PATCH 11/11] docs: corrigindo erro de grafia --- README.md | 2 +- app.js | 29 ++++++++++++++--------------- index.html | 15 +++++++-------- server.js | 2 +- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 0b98363..e9998a5 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ de futebol entre amigos. 1. Criar partidas: Cada partida deve ter um título, um local, data e horário. 2. Criar lista de presença dos jogadores: Após criar a partida, deve ser permitido adicionar/remover uma lista com os participantes e um telefone para contato. 3. Acompanhar a presença: Essa funcionalidade será usada para "confirmar" quem vai estar presente no dia da partida marcada. Deverá ser apresentada a lista dos jogadores com uma opção para confirmar sua presença. -- Excluir partida. Deve ser permitido excluir a partida. +4. Excluir partida. Deve ser permitido excluir a partida. ## Módulos diff --git a/app.js b/app.js index 57a7aa9..aec6e78 100644 --- a/app.js +++ b/app.js @@ -27,7 +27,7 @@ document.addEventListener('DOMContentLoaded', function() { .catch(error => console.error('Erro:', error)); }); - // Evento de submit do formulário de adicionar jogador + // Enviando o formulário para Adicionar Jogador document.querySelector('#addPlayerForm').addEventListener('submit', function(e) { e.preventDefault(); const index = document.querySelector('#matchIndexForPlayer').value; @@ -48,14 +48,13 @@ document.addEventListener('DOMContentLoaded', function() { .then(response => response.text()) .then(data => { alert(data); - // Em vez de fechar o modal, atualizamos a lista de jogadores viewPlayers(index); }) .catch(error => console.error('Erro:', error)); } }); - // Evento de confirmação da exclusão de partida + // Confirmando a Exclusão de Partida document.querySelector('#confirmDeleteMatchButton').addEventListener('click', function() { const index = document.querySelector('#matchIndexToDelete').value; fetch(`http://localhost:3000/partidas/${index}`, { @@ -64,7 +63,6 @@ document.addEventListener('DOMContentLoaded', function() { .then(response => response.text()) .then(data => { alert(data); - // Não fechamos o modal; apenas atualizamos a lista de partidas fetchMatches(); }) .catch(error => console.error('Erro:', error)); @@ -92,7 +90,7 @@ function fetchMatches() {
                    `; - // Evento para expandir/recolher opções + // Expandir e Recolher opções const toggleBtn = listItem.querySelector('.toggle-btn'); toggleBtn.addEventListener('click', function() { const optionsDiv = listItem.querySelector('.match-options'); @@ -108,12 +106,13 @@ function fetchMatches() { } function addPlayer(index) { - // Define o índice da partida no input oculto do modal + // Define o índice da partida document.querySelector('#matchIndexForPlayer').value = index; + // Limpa os campos do formulário document.querySelector('#playerName').value = ''; document.querySelector('#playerPhone').value = ''; - // Abre o modal para adicionar jogador (o modal permanece aberto após a ação) + $('#addPlayerModal').modal('show'); } @@ -133,10 +132,10 @@ function viewPlayers(index) { const li = document.createElement('li'); li.className = 'list-group-item d-flex justify-content-between align-items-center'; - // Cria um span para exibir o nome e telefone do jogador. + // Cria um span para exibir o nome e telefone do jogador const nameSpan = document.createElement('span'); if(jogador.presenca) { - // Se o jogador estiver presente, o nome é exibido em verde (classe text-success). + // Se o jogador estiver presente, o nome é exibido em verde (classe text-success) nameSpan.className = 'text-success'; nameSpan.textContent = `${jogador.nome} (${jogador.telefone}) - Presente`; } else { @@ -145,14 +144,14 @@ function viewPlayers(index) { li.appendChild(nameSpan); const btnGroup = document.createElement('div'); - // Botão verde para confirmar presença + // Botão para confirmar presença const confirmBtn = document.createElement('button'); confirmBtn.className = 'btn btn-success btn-sm'; confirmBtn.textContent = 'Confirmar Presença'; confirmBtn.addEventListener('click', function() { confirmPresence(index, playerIndex); }); - // Botão vermelho para excluir jogador + // Botão para excluir jogador const deleteBtn = document.createElement('button'); deleteBtn.className = 'btn btn-danger btn-sm ml-2'; deleteBtn.textContent = 'Excluir'; @@ -165,7 +164,7 @@ function viewPlayers(index) { playerList.appendChild(li); }); } - // Abre (ou mantém) o modal de jogadores aberto + $('#viewPlayersModal').modal('show'); }) .catch(error => console.error('Erro:', error)); @@ -178,7 +177,7 @@ function confirmPresence(matchIndex, playerIndex) { .then(response => response.text()) .then(data => { alert(data); - // Atualiza a lista de jogadores para refletir a mudança, sem fechar o modal + viewPlayers(matchIndex); }) .catch(error => console.error('Erro:', error)); @@ -192,7 +191,7 @@ function deletePlayer(matchIndex, playerIndex) { .then(response => response.text()) .then(data => { alert(data); - // Atualiza a lista de jogadores para refletir a remoção, mantendo o modal aberto + viewPlayers(matchIndex); }) .catch(error => console.error('Erro:', error)); @@ -201,6 +200,6 @@ function deletePlayer(matchIndex, playerIndex) { function deleteMatch(index) { document.querySelector('#matchIndexToDelete').value = index; - // Exibe o modal de confirmação de exclusão, que permanecerá aberto após a ação + $('#confirmDeleteMatchModal').modal('show'); } diff --git a/index.html b/index.html index ce7b655..6584470 100644 --- a/index.html +++ b/index.html @@ -4,9 +4,9 @@ Organizador de Partidas de Futebol - + + - @@ -36,7 +36,7 @@

                    Partidas Criadas

                    - + - +