DEV Community

Leonardo
Leonardo

Posted on

Application creation problem with express server

Hi everyone, I have a problem creating a server that uses express and socket.io, can you give me some advice on how I should proceed?

Top comments (1)

Collapse
 
emilixend profile image
EmiLix

hello this is my application that allows you to log in you can take inspiration

SERVER:

const express = require('express');
const fs = require('fs');
const http = require('http');
const socketIo = require('socket.io');
const path = require('path');

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

app.use(express.static('public'));
app.use(express.json());

let users = [];
let products = [];

// Funzionalità 1: Caricamento degli utenti dal file
fs.readFile('users.json', (err, data) => {
  if (err && err.code !== 'ENOENT') throw err;
  users = data ? JSON.parse(data) : [];
});

// Funzionalità 2: Caricamento dei prodotti dal file
fs.readFile('products.json', (err, data) => {
  if (err && err.code !== 'ENOENT') throw err;
  products = data ? JSON.parse(data) : [];
});

// Funzionalità 3: Salvataggio degli utenti nel file
const saveUsers = () => {
  fs.writeFile('users.json', JSON.stringify(users), (err) => {
    if (err) throw err;
  });
};

// Funzionalità 4: Salvataggio dei prodotti nel file
const saveProducts = () => {
  fs.writeFile('products.json', JSON.stringify(products), (err) => {
    if (err) throw err;
  });
};

// Funzionalità 5: Gestione registrazione
app.post('/register', (req, res) => {
  const { username, password } = req.body;
  if (users.find(user => user.username === username)) {
    return res.status(400).json({ error: 'User already exists' });
  }
  users.push({ username, password });
  saveUsers();
  res.status(201).json({ success: 'User registered' });
});

// Funzionalità 6: Gestione login
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  const user = users.find(user => user.username === username && user.password === password);
  if (!user) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  res.status(200).json({ success: 'Login successful', username });
});

// Funzionalità 7: Gestione aggiunta prodotto
app.post('/add-product', (req, res) => {
  const { name, description, price } = req.body;
  const product = { id: products.length + 1, name, description, price };
  products.push(product);
  saveProducts();
  io.emit('newProduct', product); // Notifica a tutti i client connessi
  res.status(201).json({ success: 'Product added', product });
});

// Funzionalità 8: Gestione rimozione prodotto
app.post('/remove-product', (req, res) => {
  const { id } = req.body;
  products = products.filter(product => product.id !== id);
  saveProducts();
  io.emit('removeProduct', id); // Notifica a tutti i client connessi
  res.status(200).json({ success: 'Product removed' });
});

// Funzionalità 9: Route per la pagina principale
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

// Funzionalità 10: Gestione connessione socket.io
io.on('connection', (socket) => {
  console.log('A user connected');

  // Funzionalità 10.1: Invia la lista dei prodotti attuali al nuovo client
  socket.emit('productList', products);

  // Funzionalità 10.2: Gestione dei messaggi di chat
  socket.on('chatMessage', (msg) => {
    io.emit('chatMessage', msg);
  });
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Enter fullscreen mode Exit fullscreen mode

CLIENT

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Authentication and Chat</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="container">
    <h1>Authentication</h1>

    <!-- Funzionalità 1: Modulo di login -->
    <div id="login">
      <h2>Login</h2>
      <form id="loginForm">
        <label for="loginUsername">Username:</label>
        <input type="text" id="loginUsername" name="username" required>
        <br>
        <label for="loginPassword">Password:</label>
        <input type="password" id="loginPassword" name="password" required>
        <br>
        <button type="submit">Login</button>
      </form>
      <p id="loginMessage"></p>
      <p>Sei registrato? <a href="#" id="showRegister">Registrati</a></p>
    </div>

    <!-- Funzionalità 2: Modulo di registrazione -->
    <div id="register" style="display: none;">
      <h2>Register</h2>
      <form id="registerForm">
        <label for="registerUsername">Username:</label>
        <input type="text" id="registerUsername" name="username" required>
        <br>
        <label for="registerPassword">Password:</label>
        <input type="password" id="registerPassword" name="password" required>
        <br>
        <button type="submit">Register</button>
      </form>
      <p id="registerMessage"></p>
      <p>Hai già un account? <a href="#" id="showLogin">Login</a></p>
    </div>

    <!-- Funzionalità 3: Chat -->
    <div id="chat" style="display: none;">
      <h2>Chat</h2>
      <div id="messages"></div>
      <form id="chatForm">
        <input type="text" id="message" autocomplete="off" required>
        <button type="submit">Send</button>
      </form>
    </div>

    <!-- Funzionalità 4: Lista dei prodotti -->
    <div id="products" style="display: none;">
      <h2>Products</h2>
      <div id="productList"></div>
    </div>

    <!-- Funzionalità 5: Modulo di aggiunta prodotto -->
    <div id="addProduct" style="display: none;">
      <h2>Add Product</h2>
      <form id="addProductForm">
        <label for="productName">Name:</label>
        <input type="text" id="productName" name="name" required>
        <br>
        <label for="productDescription">Description:</label>
        <input type="text" id="productDescription" name="description" required>
        <br>
        <label for="productPrice">Price:</label>
        <input type="number" id="productPrice" name="price" required>
        <br>
        <button type="submit">Add Product</button>
      </form>
    </div>
  </div>

  <!-- Funzionalità 6: Modal per la visualizzazione dei dettagli del prodotto -->
  <div id="productModal" class="modal" style="display: none;">
    <div class="modal-content">
      <span class="close">&times;</span>
      <h2 id="modalProductName"></h2>
      <p id="modalProductDescription"></p>
      <p id="modalProductPrice"></p>
    </div>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script>
    const socket = io();

    let currentUser = '';

    // Funzionalità 1: Login
    const loginForm = document.getElementById('loginForm');
    const registerForm = document.getElementById('registerForm');
    const loginMessage = document.getElementById('loginMessage');
    const registerMessage = document.getElementById('registerMessage');
    const showRegisterLink = document.getElementById('showRegister');
    const showLoginLink = document.getElementById('showLogin');

    // Eventi per mostrare/nascondere moduli
    showRegisterLink.addEventListener('click', () => {
      document.getElementById('login').style.display = 'none';
      document.getElementById('register').style.display = 'block';
    });

    showLoginLink.addEventListener('click', () => {
      document.getElementById('register').style.display = 'none';
      document.getElementById('login').style.display = 'block';
    });

    // Login form submission
    loginForm.addEventListener('submit', (e) => {
      e.preventDefault();
      const username = loginForm.loginUsername.value;
      const password = loginForm.loginPassword.value;

      fetch('/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username, password }),
      })
      .then(response => response.json())
      .then(data => {
        if (data.error) {
          loginMessage.textContent = data.error;
        } else {
          loginMessage.textContent = data.success;
          currentUser = username;
          document.getElementById('login').style.display = 'none';
          document.getElementById('register').style.display = 'none';
          document.querySelector('.container').style.width = '800px';
          document.getElementById('chat').style.display = 'block';
          document.getElementById('products').style.display = 'block';
          document.getElementById('addProduct').style.display = 'block';
        }
      });
    });

    // Funzionalità 2: Registrazione
    registerForm.addEventListener('submit', (e) => {
      e.preventDefault();
      const username = registerForm.registerUsername.value;
      const password = registerForm.registerPassword.value;

      fetch('/register', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username, password }),
      })
      .then(response => response.json())
      .then(data => {
        if (data.error) {
          registerMessage.textContent = data.error;
        } else {
          registerMessage.textContent = data.success;
        }
      });
    });

    // Funzionalità 3: Chat
    const chatForm = document.getElementById('chatForm');
    const messageInput = document.getElementById('message');
    const messages = document.getElementById('messages');
    chatForm.addEventListener('submit', (e) => {
      e.preventDefault();
      const msg = { user: currentUser, text: messageInput.value };
      socket.emit('chatMessage', msg);
      messageInput.value = '';
    });

    socket.on('chatMessage', (msg) => {
      const item = document.createElement('div');
      item.textContent = `${msg.user}: ${msg.text}`;
      messages.appendChild(item);
    });

    // Funzionalità 4: Gestione prodotti
    const addProductForm = document.getElementById('addProductForm');
    const productList = document.getElementById('productList');
    addProductForm.addEventListener('submit', (e) => {
      e.preventDefault();
      const name = addProductForm.productName.value;
      const description = addProductForm.productDescription.value;
      const price = addProductForm.productPrice.value;

      fetch('/add-product', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ name, description, price }),
      })
      .then(response => response.json())
      .then(data => {
        if (data.success) {
          addProductToList(data.product);
          addProductForm.reset();
        }
      });
    });

    socket.on('newProduct', (product) => {
      addProductToList(product);
    });

    socket.on('removeProduct', (id) => {
      const productItem = document.getElementById(`product-${id}`);
      if (productItem) {
        productItem.remove();
      }
    });

    socket.on('productList', (products) => {
      productList.innerHTML = '';
      products.forEach(product => {
        addProductToList(product);
      });
    });

    function addProductToList(product) {
      if (!document.getElementById(`product-${product.id}`)) {
        const productItem = document.createElement('div');
        productItem.id = `product-${product.id}`;
        productItem.innerHTML = `
          <span class="product-name" data-id="${product.id}">${product.name}</span>
          <button onclick="removeProduct(${product.id})">Remove</button>
        `;
        productList.appendChild(productItem);

        const productNameElement = productItem.querySelector('.product-name');
        productNameElement.addEventListener('click', () => {
          showModal(product);
        });
      }
    }

    // Funzionalità 5: Modale per la visualizzazione del prodotto
    function showModal(product) {
      const modal = document.getElementById('productModal');
      document.getElementById('modalProductName').textContent = product.name;
      document.getElementById('modalProductDescription').textContent = `Description: ${product.description}`;
      document.getElementById('modalProductPrice').textContent = `Price: ${product.price}`;
      modal.style.display = 'block';

      const closeModal = document.querySelector('.close');
      closeModal.onclick = function() {
        modal.style.display = 'none';
      }

      window.onclick = function(event) {
        if (event.target === modal) {
          modal.style.display = 'none';
        }
      }
    }

    window.removeProduct = function(id) {
      fetch('/remove-product', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ id }),
      })
      .then(response => response.json())
      .then(data => {
        if (data.success) {
          const productItem = document.getElementById(`product-${id}`);
          if (productItem) {
            productItem.remove();
          }
        }
      });
    }
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

STYLE:

/* Funzionalità 1: Stile per il corpo della pagina */
body {
  font-family: 'Arial', sans-serif;
  background: linear-gradient(to right, #ff7e5f, #feb47b);
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
}

/* Funzionalità 2: Stile per il container principale */
.container {
  background-color: #fff;
  padding: 40px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  border-radius: 15px;
  width: 400px;
  text-align: center;
  transition: all 0.3s ease-in-out;
}

.container:hover {
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}

/* Funzionalità 3: Stile per gli header */
h1 {
  margin-bottom: 20px;
  font-size: 24px;
  color: #333;
}

h2 {
  margin-bottom: 20px;
  font-size: 20px;
  color: #333;
}

/* Funzionalità 4: Stile per gli input di testo e password */
input[type="text"], input[type="password"] {
  width: calc(100% - 40px);
  padding: 10px;
  margin: 10px 0;
  border: 1px solid #ccc;
  border-radius: 25px;
  box-sizing: border-box;
  transition: all 0.3s ease-in-out;
}

input[type="text"]:focus, input[type="password"]:focus {
  border-color: #ff7e5f;
  box-shadow: 0 0 8px rgba(255, 126, 95, 0.2);
  outline: none;
}

/* Funzionalità 5: Stile per i pulsanti */
button {
  width: calc(100% - 40px);
  padding: 10px;
  background-color: #ff7e5f;
  border: none;
  border-radius: 25px;
  color: #fff;
  cursor: pointer;
  margin: 20px 0;
  transition: all 0.3s ease-in-out;
}

button:hover {
  background-color: #feb47b;
}

/* Funzionalità 6: Stile per i paragrafi */
p {
  margin: 10px 0 0;
  color: #555;
}

/* Funzionalità 7: Stile per i link */
a {
  color: #ff7e5f;
  text-decoration: none;
  transition: color 0.3s ease-in-out;
}

a:hover {
  color: #feb47b;
  text-decoration: underline;
}

/* Funzionalità 8: Stile per la chat */
.chat-container {
  text-align: left;
}

#messages {
  list-style-type: none;
  padding: 0;
  margin: 0;
  height: 200px;
  overflow-y: scroll;
  border: 1px solid #ccc;
  border-radius: 10px;
  padding: 10px;
}

#messages div {
  padding: 5px 10px;
  border-bottom: 1px solid #eee;
}

#message {
  width: calc(100% - 40px);
  padding: 10px;
  margin: 10px 0;
  border: 1px solid #ccc;
  border-radius: 25px;
  box-sizing: border-box;
  transition: all 0.3s ease-in-out;
}

/* Funzionalità 9: Stile per la lista dei prodotti */
#productList {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

#productList div {
  padding: 10px;
  border-bottom: 1px solid #ccc;
  display: flex;
  justify-content: space-between;
}

#productList div span {
  cursor: pointer;
  color: #ff7e5f;
}

#productList div span:hover {
  text-decoration: underline;
}

/* Funzionalità 10: Stile per la modale */
.modal {
  display: none;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: rgb(0,0,0);
  background-color: rgba(0,0,0,0.4);
  padding-top: 60px;
}

.modal-content {
  background-color: #fefefe;
  margin: 5% auto;
  padding: 20px;
  border: 1px solid #888;
  width: 80%;
  border-radius: 15px;
}

.close {
  color: #aaa;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
}

Enter fullscreen mode Exit fullscreen mode