- 오늘 마감 할일은 완료해도 취소선으로 표시하며 유지 - 날짜가 지난 할일만 필터링하여 숨김 - 미완료 항목을 먼저 표시하도록 정렬 순서 변경 - 백엔드와 Flutter Mock 데이터 로직 동기화
112 lines
3.1 KiB
JavaScript
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 - only incomplete
|
|
// 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 - only incomplete
|
|
{ dueDate: { $exists: false }, completed: false },
|
|
{ dueDate: null, completed: false }
|
|
]
|
|
}).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;
|