Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 86 additions & 2 deletions src/createServer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,92 @@
/* eslint-disable no-console */
'use strict';

const http = require('http');
const path = require('path');
const fs = require('fs');
const { IncomingForm } = require('formidable');

function createServer() {
/* Write your code here */
// Return instance of http.Server class
const server = new http.Server();

server.on('request', (req, res) => {
if (req.method === 'GET' && req.url === '/') {
const clientPath = path.join(__dirname, './index.html');

fs.createReadStream(clientPath).pipe(res);

return;
}

if (req.url !== '/add-expense') {
res.writeHead(404);
res.end();

return;
}

const form = new IncomingForm({ multiples: false });

form.parse(req, (err, fields, files) => {
if (err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Something went wrong!');

return;
}

function getFieldValue(field) {
if (!field) {
return null;
}

if (Array.isArray(field)) {
return field.length > 0 ? field[0] : null;
}

return field;
}

const titleValue = getFieldValue(fields.title);
const amountValue = getFieldValue(fields.amount);
const dateValue = getFieldValue(fields.date);

if (
!titleValue ||
!amountValue ||
!dateValue ||
titleValue === '' ||
amountValue === '' ||
dateValue === ''
) {
res.statusCode = 400;
res.end('Not full data');

return;
}

const expense = {
title: titleValue,
amount: amountValue,
date: dateValue,
};

const dbPath = path.join(__dirname, '../', './db/expense.json');

fs.writeFileSync(dbPath, JSON.stringify(expense));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: Using fs.writeFileSync(dbPath, JSON.stringify(expense)); will overwrite the entire expense.json file with each new expense, so only the latest expense will be saved. If the task requires storing multiple expenses, you should read the existing data, append the new expense, and then write the updated array back to the file.


res.writeHead(200, { 'Content-Type': 'application/json' });

res.end(JSON.stringify(expense));
});
});

server.on('error', (err) => {
// eslint-disable-next-line no-console
console.error(err);
});

return server;
}

module.exports = {
Expand Down
140 changes: 140 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Expense Tracker</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 40px auto;
padding: 20px;
}
.form {
background: #f9f9f9;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #333;
}
input {
width: 100%;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
box-sizing: border-box;
}
button {
background-color: #007bff;
color: white;
padding: 12px 30px;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
width: 100%;
}
button:hover {
background-color: #0056b3;
}
.feedback-message {
margin-top: 15px;
padding: 10px;
border-radius: 4px;
font-weight: bold;
}
</style>
</head>
<body>
<h1>Expense Tracker</h1>
<form class="form">
<label for="title">Title</label>
<input type="text" id="title" name="title" required placeholder="Title" />

<label for="amount">Amount</label>
<input type="number" id="amount" name="amount" required placeholder="0" />

<label for="date">Date</label>
<input type="date" id="date" name="date" required />

<button type="submit">Add Expense</button>
</form>

<script>
document.addEventListener('DOMContentLoaded', () => {
const form = document.querySelector('.form');

if (!form) {
console.error("Error: Form with class 'form' not found in the DOM.");
return;
}

const dateInput = document.getElementById('date');

if (dateInput) {
dateInput.valueAsDate = new Date();
}

form.addEventListener('submit', async (event) => {
event.preventDefault();

const formData = new FormData(form);

try {
const response = await fetch('/add-expense', {
method: 'POST',
body: formData,
});

if (!response.ok) {
const errorText = await response.text();
console.error(
'Server responded with an error:',
response.status,
errorText,
);
displayFeedback('Submission failed!', 'error');
return;
}

displayFeedback('Expense added successfully!', 'success');
form.reset();
if (dateInput) {
dateInput.valueAsDate = new Date();
}
} catch (error) {
console.error('Network or fetch error:', error);
displayFeedback(`Network error: ${error.message}`, 'error');
}
});

function displayFeedback(message, type = 'success') {
const existingMessage = form.querySelector('.feedback-message');
if (existingMessage) {
existingMessage.remove();
}

const feedbackElement = document.createElement('p');
feedbackElement.textContent = message;
feedbackElement.classList.add('feedback-message');
feedbackElement.style.backgroundColor =
type === 'error' ? '#f8d7da' : '#d4edda';
feedbackElement.style.color =
type === 'error' ? '#721c24' : '#155724';
feedbackElement.style.border =
type === 'error' ? '1px solid #f5c6cb' : '1px solid #c3e6cb';

form.appendChild(feedbackElement);
}
});
</script>
</body>
</html>
Loading