๐ ์ํ ์ ์
const todoList = ref([]);
const newTitle = ref("");
const editId = ref(null);
const editTitle = ref("");
const selectedDateObj = ref(new Date());
// ํ์ฌ ๋ฌ๋ ฅ์์ ๋ณด๊ณ ์๋ ์(YYYY-MM)
const currentMonth = ref(toMonthStr(new Date().getFullYear(), new Date().getMonth() + 1));
// summary map: YYYY-MM-DD -> { total, remaining }
const monthRemainingMap = ref({});
๐ ์ ํ ๋ ์ง ๋ฌธ์์ด(selectedDate)
const selectedDate = computed(() => {
const raw = selectedDateObj.value;
const d = raw instanceof Date ? raw : new Date(raw);
if (isNaN(d)) return new Date().toISOString().slice(0, 10);
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
});
๐ ์ ํ ๋ ์ง remaining ๊ณ์ฐ(remainingForSelectedDate)
const remainingForSelectedDate = computed(() => {
return monthRemainingMap.value[selectedDate.value]?.remaining ?? 0;
});
๐ ์บ๋ฆฐ๋ attribute ์์ฑ(calendarAttrs)
const calendarAttrs = computed(() => {
const attrs = [
{
key: "today",
dates: new Date(todayStr + "T00:00:00"),
highlight: { outline: true },
},
{
key: "selected",
dates:
selectedDateObj.value instanceof Date
? selectedDateObj.value
: new Date(selectedDateObj.value),
highlight: true,
},
];
for (const [dateStr, v] of Object.entries(monthRemainingMap.value)) {
const total = v?.total ?? 0;
const remaining = v?.remaining ?? 0;
if (total <= 0) continue;
attrs.push({
key: `rem-${dateStr}`,
dates: new Date(dateStr + "T00:00:00"),
dot: { color: remaining === 0 ? "green" : "red" },
});
}
return attrs;
});
๐ ๋ ์ง๋ณ Todo ์กฐํ(loadTodoList)
async function loadTodoList() {
if (!tokenRef.value) {
todoList.value = [];
return;
}
const res = await fetchTodosApi({
date: selectedDate.value,
authHeader: authHeaderFn(),
});
if (res?.__unauthorized) return onUnauthorized?.();
todoList.value = Array.isArray(res) ? res : [];
}
๐ ์ summary ์กฐํ(loadMonthSummary)
async function loadMonthSummary(monthStr) {
if (!tokenRef.value) return;
currentMonth.value = monthStr;
const data = await fetchMonthSummaryApi({
monthStr,
authHeader: authHeaderFn(),
});
if (data?.__unauthorized) return onUnauthorized?.();
const map = {};
(Array.isArray(data) ? data : []).forEach((row) => {
map[row.date] = { total: row.total, remaining: row.remaining };
});
monthRemainingMap.value = map;
}
๐ ์ถ๊ฐ(addTodo)
async function addTodo() {
if (!tokenRef.value) return;
const title = newTitle.value.trim();
if (!title) return;
const res = await addTodoApi({
title,
date: selectedDate.value,
authHeader: authHeaderFn(),
});
if (res?.__unauthorized) return onUnauthorized?.();
newTitle.value = "";
await loadTodoList();
await loadMonthSummary(currentMonth.value);
}
๐ ์๋ฃ(toggleTodo)
async function toggleTodo(todo) {
const res = await toggleTodoApi({
id: todo._id,
done: !todo.done,
authHeader: authHeaderFn(),
});
if (res?.__unauthorized) return onUnauthorized?.();
await loadTodoList();
await loadMonthSummary(currentMonth.value);
}
๐ ์์ (startEdit / cancelEdit / saveEdit)
๐ ์๋ฃ(toggleTodo)