Birmingham | 26-SDC-Mar | Chioma Okeke | Sprint 2 | Chat App#84
Birmingham | 26-SDC-Mar | Chioma Okeke | Sprint 2 | Chat App#84JanefrancessC wants to merge 6 commits into
Conversation
cjyuan
left a comment
There was a problem hiding this comment.
-
Code works well on normal circumstances. Well done.
-
Code could use some documentation (comments).
A useful rule of thumb is to ask yourself whether you could still explain or figure out how the code works few months from now. If the answer is uncertain, consider adding a comment to help future readers understand the intent and reasoning behind it.
-
The README has this requirement:
It must also support at least one additional feature.
In the PR description, can you list the extra features you implemented?
| const port = process.env.PORT || 3000; | ||
| let nextMessageId = 1; | ||
| const messages = [ |
There was a problem hiding this comment.
Better to declare global constants and variables before const app = express() because lines 5-6 are already logic to setup the server (app).
| }); | ||
|
|
||
| app.post("/", (req, res) => { | ||
| const { message, user } = req.body; |
There was a problem hiding this comment.
It's good practice to validate all request inputs.
Note: A more robust implementation
- Should also handle the case where
req.bodyisnull, which would causeconst { text, sender } = req.body;to throw.
In this exercise, let's assume the request is always coming from the code in script.js. So no change needed.
| !message.trim() || | ||
| !user.trim() | ||
| ) { | ||
| res.status(400).json({ error: `Message and user are required!` }); | ||
| return; | ||
| } | ||
|
|
||
| const newMessage = { | ||
| id: nextMessageId++, | ||
| message, | ||
| user, |
There was a problem hiding this comment.
It's a bit inconsistent that message containing only space characters are not allowed but leading and trailing space characters are acceptable.
| messages.push(newMessage); | ||
| while (callbacksForNewMessages.length > 0) { | ||
| const callback = callbacksForNewMessages.pop(); | ||
| callback([messages[messages.length - 1]]); |
There was a problem hiding this comment.
Wouldn't sending newMessage shorter in syntax?
| state.messages = state.messages.map((msg) => | ||
| msg.id === updatedMessage.id ? updatedMessage : msg, | ||
| ); |
There was a problem hiding this comment.
Note: Not very efficient approach to update one number. (Change is optional, as this is an extra feature).
There was a problem hiding this comment.
I didn't give it much thought since it's classwork, but I'll rectify this so I don't have to loop through all the messages to update one message.
| async function dislikeMessage(msgId) { | ||
| try { | ||
| const response = await fetch(`${serverURL}/${msgId}/dislike`, { | ||
| method: "POST", | ||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| feedbackEl.innerHTML = `<p>${await response.text()}</p>`; | ||
| return; | ||
| } | ||
| const updatedMessage = await response.json(); | ||
|
|
||
| state.messages = state.messages.map((msg) => | ||
| msg.id === updatedMessage.id ? updatedMessage : msg, | ||
| ); | ||
| displayMessages(); | ||
| } catch (error) { | ||
| console.error(error.message); | ||
| } | ||
| } |
There was a problem hiding this comment.
The code in dislikeMessage() and likeMessage() is nearly identical and could be refactored to reduce duplication.
The same also applies to their counterparts on the server side.
There was a problem hiding this comment.
I will also modify this by creating a generic function, then using a conditional statement to increment either the like or dislike button.
| (msg) => | ||
| `<div> | ||
| <p> | ||
| <strong>${msg.user}: ${msg.message} </strong> |
There was a problem hiding this comment.
What if the user's name or message contains characters like < or >? For example, <javascript src="..."></script>.
There was a problem hiding this comment.
This is quite interesting about innerHTML. Thank you for pointing this out; I never thought about users passing HTML tags. I will rectify this by creating DOM elements and assigning them values using textContent
| } | ||
| } | ||
|
|
||
| function displayMessages() { |
There was a problem hiding this comment.
If this function is design to accept messages as a parameter, it would make the rendering logic easier to develop and test independently.
As a general rule, prefer passing data through parameters instead of relying on global variables.
There was a problem hiding this comment.
I will modify this to accept messages as a parameter, rather than a global variable.
| feedbackEl.innerHTML = `<p>Message sent!</p>`; | ||
|
|
||
| setTimeout(() => { | ||
| feedbackEl.innerHTML = ""; | ||
| }, 3000); |
There was a problem hiding this comment.
Could consider isolating the logic for showing feedback in a function showFeedback(msg, timeoutDuration).
| if (longPoll) { | ||
| keepFetchingMessages(); | ||
| } else { | ||
| setTimeout(keepFetchingMessages, 2000); |
There was a problem hiding this comment.
2000 is a magic number and best practice is to represent all magic numbers as named constants.
Thank you for the thorough feedback. I have edited the PR to include the extra feature and will modify my code per the review. |
Learners, PR Template
Self checklist
Changelist
Backend link
Frontend link
Additional Feature