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
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,50 @@
# Coursework

Exercises to practice and solidify your understanding of the Decomposition module of the Software Development Course.

---

# Beeko Chat App

A real-time chat application where users can send and receive messages instantly without refreshing the page.

## Project Structure

```
chat-app/
client/ - Vite + React + TypeScript frontend
server/ - Node.js + Express backend
```

## Features

- Send a message to the chat
- See all messages when opening the chat
- New messages appear instantly for all connected users
- Message count display
- Username persisted across sessions

## How It Works

The frontend loads existing messages from the server on page load via a REST API. When a user sends a message, it is posted to the server which saves it and broadcasts it to all connected clients over a WebSocket channel. Every connected user receives the new message instantly without needing to refresh.

## Getting Started

**Backend**
```bash
cd server
npm install
node index.js
```

**Frontend**
```bash
cd client
npm install
npm run dev
```

## Deployment

- Backend is deployed as a Docker container
- Frontend is deployed as a static site via Nixpacks
24 changes: 24 additions & 0 deletions chat-app/client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
49 changes: 49 additions & 0 deletions chat-app/client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Frontend (`client/`)

Built with **Vite + React + TypeScript**

## Technologies

- **Vite** - build tool and dev server
- **React 19** - UI library
- **TypeScript** - type safety across all components

## Structure

```
src/
types.ts - shared Message interface
App.tsx / App.css - root component, state, API calls
components/
MessageList.tsx / .css - scrollable list of messages
MessageForm.tsx / .css - name input, message textarea, send button
```

## Implementation

`types.ts`

- Defines the `Message` interface with `id`, `name`, `text`, and `timestamp`

`App.tsx`

- Fetches all messages from `GET /messages` on page load
- Opens a WebSocket connection to listen for new messages in real time
- Persists the username in `localStorage` so it survives page refresh
- Passes `handleSend` down to `MessageForm` which calls `POST /messages`

`MessageList.tsx`

- Receives messages as props and renders each one with name, timestamp, and text
- Auto-scrolls to the latest message using a `ref` on the bottom of the list

`MessageForm.tsx`

- Controlled inputs for name and message
- Name is remembered between sessions, message clears after sending
- Send button is disabled if either field is empty
- Displays total message count as an additional feature

## What I Learned

Building this project showed how the frontend and backend need a clear contract to work together, the REST endpoints handle loading and sending data, while WebSocket handles the real-time layer, and understanding when to use each was the key challenge.
14 changes: 14 additions & 0 deletions chat-app/client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/src/App.css" />
<title>Beeko Chat App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading