Skip to content

Built an wtodo from scratch for Homework #872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
node_modules
.env
config/config.env
4 changes: 0 additions & 4 deletions .vscode/settings.json

This file was deleted.

70 changes: 68 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,68 @@
npm install
add DB_STRING to .env file
# 📋 todo-list-express

A clean, minimalistic Todo List web app built with [Express.js](https://expressjs.com/) and [Bun](https://bun.sh). Quickly add, view, complete, and delete your daily tasks with zero distractions.

This is the **core backend-powered version** — a lightweight starting point before we evolve it into a **React-driven frontend**.

---

## 🚀 Features

- ✅ Add new todos
- 👀 View your task list
- 🔁 Mark tasks as complete or incomplete
- ❌ Delete tasks

---

## 🛠️ Tech Stack

- [Bun](https://bun.sh) — blazing-fast runtime & package manager
- [Express.js](https://expressjs.com/) — lightweight web framework
- TypeScript
- HTML, CSS, JavaScript (frontend)

---

## 📦 Getting Started

### Install dependencies

```bash
bun install
```

### Run the app

```bash
bun run start
```

The server will start at [http://localhost:5000](http://localhost:5000) (or your configured port).

---

## 📖 Usage

- **Add a Todo:** Type your task in the input field and click "Add".
- **Complete/Uncomplete:** Toggle the checkbox beside a task.
- **Delete:** Hit the trash icon to remove a task.

---

## 📝 Contributing

Pull requests are welcome!
For significant changes, open an issue first to discuss what you’d like to adjust.

> ⚙️ This project was scaffolded using `bun init` on **bun v1.2.15**.

---

## 📌 Roadmap

- [x] Minimal backend with basic CRUD operations
- [ ] Frontend refactor with **React** (coming soon)
- [ ] API integration & improved UI/UX

Stay tuned — this project’s about to level up.
34 changes: 34 additions & 0 deletions app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import express from 'express';
import connectDB from './config/db';
import dotenv from 'dotenv';
import indexRoutes from './routes/index.ts';
import todoRoutes from './routes/todo.ts'
import path from 'path';
import logger from './middlewares/logger.js'

const app = express()

// logging more stuff if in development mode with morgan
app.use(logger())

// load config
dotenv.config({ path: './config/config.env' })

// Body parser
app.use(express.urlencoded({ extended: false }))
app.use(express.json())

// connecting the DB
connectDB();

// routes
app.use('/', indexRoutes)
app.use('/todo', todoRoutes)

// Serve static files from the public directory
app.use(express.static(path.join(process.cwd(), 'public')));
app.use(express.static(path.join(process.cwd(), 'views')));

// making the app live
const PORT = process.env.PORT || 3000
app.listen(PORT, () => console.log(`server running in ${process.env.NODE_ENV} mode at port ${process.env.PORT}`))
257 changes: 257 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions config/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import mongoose from 'mongoose';

const connectDB = async () => {
try {
const mongoDbUri = process.env.mongoUri as string
const conn = await mongoose.connect(mongoDbUri)
if (!process.env.mongoUri) {
throw new Error('MongoDB_URI is not defined in environment variables.');
}
console.log(`MongoDB Connected: ${conn.connection.host}`)
} catch (err) {
console.error(err)
process.exit(1)
}
}

export default connectDB
48 changes: 48 additions & 0 deletions controller/todo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Request, Response } from 'express';
import Todo from '../models/todo';
import { validateTodoInput } from '../validators/todoValidator';

export default {
sendAllTodos: async (req: Request, res: Response) => {
try {
const todos = await Todo.find();
res.json(todos)
} catch (err) {
console.error(err)
}
},
addTodo: async (req: any, res: any) => {
const validation = validateTodoInput(req.body);
if (!validation.valid) {
return res.status(400).json({ error: validation.error });
}

try {
// Create and save the new todo
const todo = new Todo(req.body);
await todo.save();
res.status(201).json({ message: 'Todo created', todo });
} catch (err) {
res.status(500).json({ error: 'Database error', details: err });
}
},
toggleCompletion: async (req: Request, res: Response) => {
try {
const { id, state } = req.body;
await Todo.findByIdAndUpdate(id, { completed: state });
res.status(200).json({ success: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Database error', details: err });
}
},
deleteTodo: async (req: Request, res: Response) => {
try {
await Todo.findByIdAndDelete(req.params.id)
res.status(200).json({ success: true });
} catch (err) {
console.error('err')
res.status(500).json({ error: err });
}
}
}
6 changes: 6 additions & 0 deletions helpers/viewHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import path from 'path';
import type { Response } from 'express';

export function sendView(res: Response, file: string) {
res.sendFile(file, { root: path.join(process.cwd(), 'views') });
}
16 changes: 16 additions & 0 deletions middlewares/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import morgan from 'morgan'
import type { Request, Response, NextFunction } from 'express'

const logger = () => {
if (process.env.NODE_ENV === 'development') {
return morgan('dev', {
skip: (req: Request) =>
req.url.startsWith('/assets/') ||
req.url.startsWith('/css/') ||
req.url.startsWith('/js/')
})
}
return (req: Request, res: Response, next: NextFunction) => next()
}

export default logger
15 changes: 15 additions & 0 deletions models/todo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import mongoose, { Schema, Document } from 'mongoose';

export interface ITodo extends Document {
title: string;
completed: boolean;
createdAt: Date;
}

const TodoSchema: Schema = new Schema({
title: { type: String, required: true },
completed: { type: Boolean, default: false },
createdAt: { type: Date, default: Date.now }
});

export default mongoose.model<ITodo>('Todo', TodoSchema);
Loading