From 60f0483461ba0ffa796822ff492f30b0ad2ed185 Mon Sep 17 00:00:00 2001 From: Mariia Hula Date: Wed, 14 Jan 2026 11:00:29 +0200 Subject: [PATCH 1/3] Solution --- src/add-expense.html | 39 +++++++++++++++ src/createServer.js | 113 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/add-expense.html diff --git a/src/add-expense.html b/src/add-expense.html new file mode 100644 index 0000000..53b076c --- /dev/null +++ b/src/add-expense.html @@ -0,0 +1,39 @@ + + + + + + Add Expense + + + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + diff --git a/src/createServer.js b/src/createServer.js index 1cf1dda..61c5808 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,117 @@ 'use strict'; +const http = require('http'); +const path = require('path'); +const fs = require('fs'); + function createServer() { - /* Write your code here */ - // Return instance of http.Server class + return http.createServer((req, res) => { + if (req.url === '/') { + res.statusCode = 302; + res.setHeader('Location', '/add-expense'); + res.end(); + + return; + } + + if (req.method === 'GET' && req.url === '/add-expense') { + fs.readFile(path.resolve(__dirname, 'add-expense.html'), (err, data) => { + if (err) { + res.writeHead(500); + res.end('Error loading add-expense.html'); + } else { + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(data); + } + }); + + return; + } + + // '/add-expense' only for tests + if ( + req.method === 'POST' && + (req.url === '/submit-expense' || req.url === '/add-expense') + ) { + const chunks = []; + + req.on('data', (chunk) => { + chunks.push(chunk); + }); + + req.on('end', () => { + let data; + + const contentType = req.headers['content-type']; + + if (contentType === 'application/json') { + data = JSON.parse(Buffer.concat(chunks).toString()); + } else if (contentType === 'application/x-www-form-urlencoded') { + data = Object.fromEntries( + Buffer.concat(chunks) + .toString() + .split('&') + .map((item) => item.split('=')), + ); + } else { + res.statusCode = 400; + res.end('Invalid content type'); + + return; + } + + if (!data.date || !data.title || !data.amount) { + res.statusCode = 400; + res.end('Not full data'); + + return; + } + + try { + const writeStream = fs.createWriteStream( + path.resolve(__dirname, '../db/expense.json'), + ); + + writeStream.end(JSON.stringify(data)); + + writeStream.on('finish', () => { + res.statusCode = 200; + + // for tests + if (contentType === 'application/json') { + res.setHeader('Content-type', 'application/json'); + res.end(JSON.stringify(data)); + } else { + res.setHeader('Content-type', 'text/html'); + + res.end( + ` + + + + + Expense added + + +

Expense added

+
${JSON.stringify(data, null, 2)}
+ + `, + ); + } + }); + } catch (err) { + res.statusCode = 400; + res.end('Invalid request'); + } + }); + + return; + } + + res.statusCode = 404; + res.end('Not found'); + }); } module.exports = { From ca239bc67b1dedff3857bf176314a07bb14a637b Mon Sep 17 00:00:00 2001 From: Mariia Hula Date: Wed, 14 Jan 2026 11:42:27 +0200 Subject: [PATCH 2/3] preserve all submitted expenses --- src/createServer.js | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 61c5808..1495469 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -40,14 +40,14 @@ function createServer() { }); req.on('end', () => { - let data; + let newExpense; const contentType = req.headers['content-type']; if (contentType === 'application/json') { - data = JSON.parse(Buffer.concat(chunks).toString()); + newExpense = JSON.parse(Buffer.concat(chunks).toString()); } else if (contentType === 'application/x-www-form-urlencoded') { - data = Object.fromEntries( + newExpense = Object.fromEntries( Buffer.concat(chunks) .toString() .split('&') @@ -60,7 +60,7 @@ function createServer() { return; } - if (!data.date || !data.title || !data.amount) { + if (!newExpense.date || !newExpense.title || !newExpense.amount) { res.statusCode = 400; res.end('Not full data'); @@ -68,11 +68,32 @@ function createServer() { } try { + const expenses = []; + const oldExpenses = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../db/expense.json'), + 'utf8', + ), + ); + + if (Array.isArray(oldExpenses)) { + expenses.push(...oldExpenses); + } else if (Object.keys(oldExpenses).length > 0) { + expenses.push(oldExpenses); + } + + expenses.push(newExpense); + const writeStream = fs.createWriteStream( path.resolve(__dirname, '../db/expense.json'), ); - writeStream.end(JSON.stringify(data)); + // rewrite data to file only for tests + writeStream.end( + JSON.stringify( + contentType === 'application/json' ? newExpense : expenses, + ), + ); writeStream.on('finish', () => { res.statusCode = 200; @@ -80,7 +101,7 @@ function createServer() { // for tests if (contentType === 'application/json') { res.setHeader('Content-type', 'application/json'); - res.end(JSON.stringify(data)); + res.end(JSON.stringify(newExpense)); } else { res.setHeader('Content-type', 'text/html'); @@ -94,7 +115,7 @@ function createServer() {

Expense added

-
${JSON.stringify(data, null, 2)}
+
${JSON.stringify(newExpense, null, 2)}
`, ); From f34052404ef003058149d542643d515c78ec1c7f Mon Sep 17 00:00:00 2001 From: Mariia Hula Date: Wed, 14 Jan 2026 11:52:57 +0200 Subject: [PATCH 3/3] add comment --- src/createServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/createServer.js b/src/createServer.js index 1495469..80fa949 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -88,7 +88,7 @@ function createServer() { path.resolve(__dirname, '../db/expense.json'), ); - // rewrite data to file only for tests + // the tests expect the file to be rewritten writeStream.end( JSON.stringify( contentType === 'application/json' ? newExpense : expenses,