Node.js example

Find a meeting time.

GitHub Project

1. Prerequisites

Before starting, ensure you have the following:

  1. Ubuntu 24.04 installed.
  2. Node.js (v18 or later) and npm installed:
    sudo apt update
    sudo apt install -y nodejs npm
  3. MariaDB installed:
    sudo apt install -y mariadb-server mariadb-client
  4. Bootstrap (included via CDN for simplicity).

2. Set Up the Project

  1. Create a new project directory:
    mkdir meeting-time-app
    cd meeting-time-app
    npm init -y
  2. Install dependencies:
    npm install express mysql2 body-parser cors

3. Configure MariaDB

  1. Log into MariaDB:
    sudo mariadb
  2. Create a database and user:
    CREATE DATABASE meeting_app;
    CREATE USER 'meeting_user'@'localhost' IDENTIFIED BY 'Kenyon1824-348';
    GRANT ALL PRIVILEGES ON meeting_app.* TO 'meeting_user'@'localhost';
    FLUSH PRIVILEGES;
  3. Create the required table:
    USE meeting_app;
    CREATE TABLE meetings ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, link VARCHAR(255) NOT NULL UNIQUE, times TEXT NOT NULL, responses TEXT DEFAULT '{}' );

4. Back-End API with Node.js

Create a file index.js in the project directory:

const express = require('express');
const bodyParser = require('body-parser');
const mysql = require('mysql2');
const cors = require('cors');
const path = require('path');

const app = express();
app.use(bodyParser.json());
app.use(cors());

// Database connection
const db = mysql.createConnection({
host: 'localhost',
user: 'meeting_user',
password: 'Kenyon1824-348',
database: 'meeting_app',
});

console.log("Starting");
// Serve static files from the "public" directory
app.use(express.static(path.join(__dirname, 'public')));

// Serve "index.html" when accessing the root route "/"
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

// Endpoint to create a meeting
app.post('/api/meetings', (req, res) => {
const { title, times } = req.body;
console.log("Meeting:",title,times);
const link = Math.random().toString(36).substring(2, 15);
const query = 'INSERT INTO meetings (title, link, times) VALUES (?, ?, ?)';
db.execute(query, [title, link, JSON.stringify(times)], (err, result) => {
if (err) return res.status(500).send(err);
res.send({ link });
});
});

// Endpoint to get meeting details
app.get('/api/meetings/:link', (req, res) => {
const { link } = req.params;
const query = 'SELECT * FROM meetings WHERE link = ?';
db.execute(query, [link], (err, results) => {
if (err || results.length === 0) return res.status(404).send('Meeting not found');
res.send(results[0]);
});
});

// Endpoint to fetch all meetings
app.get('/api/meetings', (req, res) => {
const query = 'SELECT title, link FROM meetings';

db.execute(query, (err, results) => {
if (err) {
console.error("Database Error:", err);
return res.status(500).json({ error: "Failed to fetch meetings" });
}
res.json(results);
});
});

// Endpoint to submit availability
app.post('/api/meetings/:link/respond', (req, res) => {
const { link } = req.params;
const { name, selectedTimes } = req.body;

const query = 'SELECT * FROM meetings WHERE link = ?';
db.execute(query, [link], (err, results) => {
if (err || results.length === 0) return res.status(404).send('Meeting not found');

const meeting = results[0];
const responses = JSON.parse(meeting.responses || '{}');
responses[name] = selectedTimes;

const updateQuery = 'UPDATE meetings SET responses = ? WHERE link = ?';
db.execute(updateQuery, [JSON.stringify(responses), link], (updateErr) => {
if (updateErr) return res.status(500).send(updateErr);
res.send('Response submitted');
});
});
});

// Start the server
const PORT = 3000;
app.listen(PORT,'0.0.0.0', () => console.log(`Server running on http://0.0.0.0:${PORT}`));

5. Front-End with JavaScript and Bootstrap

Create a public directory for the front-end.

In the following code replace all occurance of “138.28.162.128” with the IP address of your server.

Add the following:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<title>Meeting Time App</title>
</head>
<body>
<div class="container mt-5">
<h1>Create a Meeting</h1>
<form id="createMeetingForm">
<div class="mb-3">
<label for="title" class="form-label">Meeting Title</label>
<input type="text" class="form-control" id="title" required>
</div>
<div class="mb-3">
<label for="times" class="form-label">Times (comma-separated)</label>
<input type="text" class="form-control" id="times" required>
</div>
<button type="submit" class="btn btn-primary">Create Meeting</button>
</form>
<div id="meetingLink" class="mt-3"></div>
</div>

<script>
document.getElementById('createMeetingForm').addEventListener('submit', async (e) => {
e.preventDefault();
const title = document.getElementById('title').value;
const times = document.getElementById('times').value.split(',');
const response = await fetch('http://
138.28.162.128:3000/api/meetings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, times })
});
const data = await response.json();
document.getElementById('meetingLink').innerHTML = `
<div class="alert alert-success">
Meeting created! Share this link: <a href="/meeting.html?link=${data.link}" target="_blank">View Meeting</a>
</div>
`;
});
</script>
</body>
</html>

meeting.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<title>Meeting Details</title>
</head>
<body>
<div class="container mt-5">
<h1 id="meetingTitle"></h1>
<form id="responseForm" class="mt-3">
<div id="timesList"></div>
<div class="mb-3">
<label for="name" class="form-label">Your Name</label>
<input type="text" class="form-control" id="name" required>
</div>
<button type="submit" class="btn btn-primary">Submit Response</button>
</form>
<div id="summary" class="mt-5"></div>
</div>

<script>
const urlParams = new URLSearchParams(window.location.search);
const link = urlParams.get('link');

async function fetchMeeting() {
const response = await fetch(`http://
138.28.162.128:3000/api/meetings/${link}`);
const data = await response.json();
document.getElementById('meetingTitle').textContent = data.title;

const times = JSON.parse(data.times);
const responses = JSON.parse(data.responses || '{}');
const summary = {};

document.getElementById('timesList').innerHTML = times.map((time, index) => {
summary[time] = 0;
for (const user in responses) {
if (responses[user].includes(time)) summary[time]++;
}
return `
<div class="form-check">
<input class="form-check-input" type="checkbox" value="${time}" id="time${index}">
<label class="form-check-label" for="time${index}">${time}</label>
</div>
`;
}).join('');

document.getElementById('summary').innerHTML = `
<h3>Summary</h3>
${Object.entries(summary).map(([time, count]) => `
<p>${time}: ${count} people available</p>
`).join('')}
`;
}

document.getElementById('responseForm').addEventListener('submit', async (e) => {
e.preventDefault();
const name = document.getElementById('name').value;
const selectedTimes = Array.from(document.querySelectorAll('input[type="checkbox"]:checked')).map(input => input.value);

await fetch(`http://
138.28.162.128:3000/api/meetings/${link}/respond`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, selectedTimes })
});
fetchMeeting();
});

fetchMeeting();
</script>
</body>
</html>

6. Run the Program

  1. Start the server:
    node index.js
  2. Open the front-end in a browser:
    • http://138.28.162.128:3000/public/index.html

7. Summary

This program allows users to:

  • Create a meeting with available times.
  • Share a unique link with others.
  • See who is available for each time slot in a summary.

You can extend this with features like user authentication, email notifications, or even calendar integration.

Scroll to Top