Files
bini-google-tv/backend/routes/todos.js
kihong.kim a2b2e81703 fix: 마감일 없는 할일도 완료 여부와 상관없이 표시
- 마감일이 없는 할일은 특정 날짜에 속하지 않으므로 항상 표시
- 완료 체크 시 목록에서 사라지는 버그 수정
2026-02-01 01:39:39 +09:00

112 lines
3.1 KiB
JavaScript

const express = require("express");
const { DateTime } = require("luxon");
const Todo = require("../models/Todo");
const router = express.Router();
// Korea Standard Time zone
const KST_TIMEZONE = "Asia/Seoul";
// Get day range in Korea Standard Time (Asia/Seoul)
const getDayRange = () => {
// Get current time in KST
const nowKst = DateTime.now().setZone(KST_TIMEZONE);
// Start of day in KST (00:00:00.000)
const startOfDayKst = nowKst.startOf("day");
// End of day in KST (23:59:59.999)
const endOfDayKst = nowKst.endOf("day");
// Convert to JavaScript Date objects (UTC) for MongoDB query
const start = startOfDayKst.toJSDate();
const end = endOfDayKst.toJSDate();
return { start, end };
};
router.get("/", async (req, res) => {
try {
const todos = await Todo.find().sort({ dueDate: 1, createdAt: -1 });
res.json(todos);
} catch (error) {
res.status(500).json({ message: "Failed to fetch todos" });
}
});
router.get("/today", async (req, res) => {
try {
const { start, end } = getDayRange();
// Show todos that are:
// 1. Due today (between start and end of today) - both completed and incomplete
// 2. Due in the future (not yet due) - only incomplete
// 3. Have no due date set - both completed and incomplete (always show)
// Filter out: overdue todos (due date before today)
const todos = await Todo.find({
$or: [
// Today's todos (completed or not) - show with strikethrough if completed
{ dueDate: { $gte: start, $lte: end } },
// Future todos - only incomplete
{ dueDate: { $gt: end }, completed: false },
// No due date - always show (completed or not)
{ dueDate: { $exists: false } },
{ dueDate: null }
]
}).sort({
completed: 1, // Incomplete first
dueDate: 1,
createdAt: -1,
});
res.json(todos);
} catch (error) {
res.status(500).json({ message: "Failed to fetch today todos" });
}
});
router.post("/", async (req, res) => {
try {
const todo = await Todo.create(req.body);
res.status(201).json(todo);
} catch (error) {
res.status(400).json({ message: "Failed to create todo" });
}
});
router.get("/:id", async (req, res) => {
try {
const todo = await Todo.findById(req.params.id);
if (!todo) {
return res.status(404).json({ message: "Todo not found" });
}
res.json(todo);
} catch (error) {
res.status(400).json({ message: "Failed to fetch todo" });
}
});
router.put("/:id", async (req, res) => {
try {
const todo = await Todo.findByIdAndUpdate(req.params.id, req.body, { new: true });
if (!todo) {
return res.status(404).json({ message: "Todo not found" });
}
res.json(todo);
} catch (error) {
res.status(400).json({ message: "Failed to update todo" });
}
});
router.delete("/:id", async (req, res) => {
try {
const todo = await Todo.findByIdAndDelete(req.params.id);
if (!todo) {
return res.status(404).json({ message: "Todo not found" });
}
res.json({ ok: true });
} catch (error) {
res.status(400).json({ message: "Failed to delete todo" });
}
});
module.exports = router;