Skip to content

West Midlands | 26 March SDC | Iswat Bello | Sprint 2 | chat app#83

Open
Iswanna wants to merge 39 commits into
CodeYourFuture:mainfrom
Iswanna:feature/chat-app
Open

West Midlands | 26 March SDC | Iswat Bello | Sprint 2 | chat app#83
Iswanna wants to merge 39 commits into
CodeYourFuture:mainfrom
Iswanna:feature/chat-app

Conversation

@Iswanna
Copy link
Copy Markdown

@Iswanna Iswanna commented May 25, 2026

Learners, PR Template

Self checklist

  • I have titled my PR with Region | Cohort | FirstName LastName | Sprint | Assignment Title
  • My changes meet the requirements of the task
  • I have tested my changes
  • My changes follow the style guide

Changelist

This PR implements a fully functional real-time chat application with a Node.js/Express backend and vanilla JavaScript frontend. The application supports sending messages, viewing chat history, and liking messages with real-time updates using long polling.

Deployed sites

Additional Feature implemented

  • Interactive Reaction System: I implemented a "Like" button for each message. This required creating a custom API endpoint (/messages/:id/like) and logic to update the state of existing messages without re-rendering the entire chat.

  • Performance Optimisation (Long Polling): To make the chat feel "live" without overworking the server, I implemented Long Polling. This ensures messages appear instantly while reducing the number of empty requests.

Iswanna added 30 commits May 9, 2026 23:26
- Exclude node_modules/ and package-lock.json from version control
- Ignore environment variables (.env) and system files (.DS_Store)
- Exclude build artifacts (dist/, build/) and log files (*.log)
- Ignore VS Code workspace settings (.vscode/)
- Reduce repository size and prevent committing sensitive data
- Import Express library
- Create Express app instance
- Initialize messages array to store chat data
- Configure server port (default: 3000)
- Start server with app.listen()
- Add JSON body parsing middleware
- Implement POST /messages route with input validation
- Validate text and sender fields are provided and non-empty
- Create message object with id, sender, text, likes, and dislikes
- Store message in messages array
- Return created message with 201 status code
- Return 400 error for invalid requests
- Implement GET /messages route
- Return all messages from the messages array
- Enable clients to fetch chat history
- Add index.html with semantic HTML structure
- Include meta tags for charset and viewport
- Link external stylesheet (styles.css)
- Link deferred JavaScript file (script.js)
- Create form with sender name and message inputs
- Add submit button for sending messages
- Create messages container div for displaying chat history
- Create getAllMessages async function to fetch messages from backend
- Parse JSON response from /messages endpoint
- Clear message container and render new messages
- Display sender name and message text for each message
- Add error handling for fetch failures
- Call getAllMessages on page load to populate initial messages
- Import cors module for CORS support
- Fix environment variable casing (process.env.port → process.env.PORT)
- Add CORS middleware before other middleware
- Move message creation logic inside POST route handler
- Fix indentation for code inside route handlers
- Properly close POST route handler with closing brace
- Configure Node.js project with ES modules ("type": "module")
- Add Express 5.2.1 for HTTP server framework
- Add CORS 2.8.6 for cross-origin request handling
- Enable npm package management for backend
- Add id="chat-form" to form for JavaScript event listener access
- Change textarea to input element for message field
- Maintain labels and input structure for sender name and message
- Get form, sender input, and message input elements from DOM
- Add submit event listener to chat form
- Prevent default form submission behavior
- Extract sender name and message text from input values
- Send POST request to /messages endpoint with JSON payload
- Include Content-Type header for JSON data
- Refresh message list on successful submission
- Clear input fields after sending message
- Replace single getAllMessages() call with setInterval
- Fetch messages from backend every 5000ms (5 seconds)
- Enable live chat updates without manual refresh
- Keep frontend synchronized with backend message list
- Change mismatched textarea closing tag to self-closing input tag
- Add scripts section with start command
- Enable running backend with npm start instead of node server.js
- Simplify server startup process
- Remove trailing newline from file
- Change getAllMessages() fetch URL from localhost to Render production URL
- Update form submission fetch URL to production backend
- Enable frontend to communicate with deployed Render backend
- Remove dependency on local development server
…king

- Add lastIdSeen variable to track last viewed message ID
- Update getAllMessages() to use ?since query parameter
- Only fetch messages newer than lastIdSeen from backend
- Remove messageContainer.textContent clearing to prevent flicker
- Update lastIdSeen after each message is displayed
- Reduce data transfer by only fetching new messages
- Improve performance with incremental polling
- Parse since query parameter from request
- Convert since value to number, default to -1 if undefined
- Filter messages array to only return messages with id > sinceId
- Handle edge case where since=0 evaluates as falsy
- Enable pagination and incremental message loading
- Reduce payload size by sending only new messages
- Wrap form submission logic in try-catch block
- Handle network errors and fetch failures gracefully
- Log errors to console for debugging
- Prevent app from crashing on failed message submission
- Improve user experience with better error handling
- Reformat fetch call for better readability
- Replace setInterval with setTimeout for sequential polling
- Add setTimeout in try block to schedule next poll after successful fetch
- Add setTimeout in catch block to retry polling after error
- Call getAllMessages() once on page load instead of starting interval
- Ensure each poll waits for previous request to complete
- Prevent overlapping requests and race conditions
- Improve reliability with error recovery
- Add callBacksForNewMessages array to store pending response handlers
- Modify GET /messages endpoint to implement long polling
- When no new messages available (messagesSinceId.length === 0), store response callback
- When new messages arrive, send them immediately via callback
- Enable real-time message delivery without constant polling
- Reduce server load by holding requests until new data is available
…lopment

- Change getAllMessages() fetch URL from Render to localhost:3000
- Change form submission fetch URL from Render to localhost:3000
- Remove getAllMessages() call after successful message submission
- Rely on long polling to fetch new messages automatically
- Enable local development workflow
- Simplify form submission logic
- Create route to handle message like requests
- Extract message ID from URL parameter
- Convert ID string to number for comparison
- Find message by ID in messages array
- Increment likes count for the message
- Enable users to like messages in real-time
…like

- Check if messageWithIdAsNumber exists after incrementing likes
- Notify all waiting clients via callBacksForNewMessages callbacks
- Send updated message with 200 status on success
- Return 404 error if message not found
- Enable real-time like updates via long polling
- Improve error handling for invalid message IDs
- Extract current like count from likeSpan text content
- Increment likes count immediately when user clicks Like button
- Update UI before server response for instant feedback
- Maintain consistency with backend data on next poll
- Improve user experience with responsive interface
- Style message containers with border, padding, and rounded corners
- Add light gray background color (#f9f9f9) to messages
- Add spacing between message elements with margin-right
- Style buttons with blue background (#007bff) and white text
- Add cursor pointer and rounded corners to buttons
- Improve visual presentation of chat interface
- Change getAllMessages() fetch URL from Render to CodeYourFuture hosting
- Update like button fetch URL to CodeYourFuture backend
- Update form submission fetch URL to CodeYourFuture backend
- Enable frontend to communicate with CodeYourFuture deployed backend
- Replace Render production URL with CodeYourFuture hosting domain
- Remove npm start script configuration
- Simplify package.json to only include dependencies
- Users will run server with direct node command instead
@Iswanna Iswanna added 📅 Sprint 2 Assigned during Sprint 2 of this module Needs Review Trainee to add when requesting review. PRs without this label will not be reviewed. Module-Decomposition The name of the module. labels May 25, 2026
@cjyuan
Copy link
Copy Markdown

cjyuan commented May 27, 2026

  • The content in the "Changes Made" section is better kept in a .md file.

  • Can you include these in the PR description (as requested in the spec)?

    • A link to the deployed frontend on the CYF hosting environment
    • A link to the deployed backend on the CYF hosting environment
  • Can you also list the extra features you implemented? (The spec says the app must also support at least one additional feature)

Comment thread chat-app/backend/server.js
Comment thread chat-app/frontend/script.js Outdated
Comment thread chat-app/frontend/script.js Outdated
Comment thread chat-app/backend/server.js
Comment thread chat-app/backend/server.js Outdated
const messagesSinceId = messages.filter((message) => message.id > sinceId);

if (messagesSinceId.length === 0) {
callBacksForNewMessages.push((value) => res.send(value));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

What do you expect to happen if no new message arrives within 30 minutes?

Comment on lines +86 to +88
callback([messageWithIdAsNumber]);
}
res.status(200).send(messageWithIdAsNumber);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Some of the message properties are not needed to update likes count. Can you improve this code to send only the necessary data?

Comment on lines +76 to +78
const messageWithIdAsNumber = messages.find(
(message) => message.id === idAsNumber,
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is there a more efficient way to locate the desired message object by its id?

@cjyuan cjyuan added Reviewed Volunteer to add when completing a review with trainee action still to take. and removed Needs Review Trainee to add when requesting review. PRs without this label will not be reviewed. labels May 27, 2026
@Iswanna
Copy link
Copy Markdown
Author

Iswanna commented May 27, 2026

  • The content in the "Changes Made" section is better kept in a .md file.

  • Can you include these in the PR description (as requested in the spec)?

    • A link to the deployed frontend on the CYF hosting environment
    • A link to the deployed backend on the CYF hosting environment
  • Can you also list the extra features you implemented? (The spec says the app must also support at least one additional feature)

I have updated the PR description based on your feedback. Thank you.

Iswanna added 6 commits May 27, 2026 21:58
- Add check for req.body existence before destructuring
- Add type validation to ensure text and sender are strings
- Replace simple falsy check with .trim() for whitespace validation
- Return specific error messages for each validation failure
- Improve error handling clarity with separate validation steps
- Prevent type coercion errors and invalid data submission
- Trim whitespace from sender and message inputs
- Prevent empty submissions and show alert if fields are blank
- Return early from submit handler when validation fails
- Improve UX and prevent sending invalid messages
- Add API_BASE_URL placeholder constant
- Replace hardcoded production URLs with `${API_BASE_URL}` for:
  - GET /messages
  - POST /messages/:id/like
  - POST /messages (form submission)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Module-Decomposition The name of the module. Reviewed Volunteer to add when completing a review with trainee action still to take. 📅 Sprint 2 Assigned during Sprint 2 of this module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants