Fix: CardDAV sync broke when todo items didn't have a creation date. Also fixed todos without a due date not being displays and wrong calculation of warning badge states.

This commit is contained in:
2026-05-25 15:31:29 +02:00
parent 2324ad95bf
commit da3ceeaff3
5 changed files with 95 additions and 45 deletions
+56 -33
View File
@@ -23,46 +23,69 @@ onMounted(() => {
}
})
// Define a type for the key-value pairs
type GroupedTodos = Array<{ key: string; todos: Todo[] }>;
const groupedTodos = computed(() => {
const groups: Record<string, Todo[]> = {};
if (todos.value) {
for (let todo of todos.value) {
if (!todo.dueDate) continue
if (todo.dueDate) {
let dueDate = new Date(todo.dueDate)
let dueDate = new Date(todo.dueDate)
// today
if (isToday(dueDate)) {
if (!groups['today']) groups['today'] = []
groups['today'].push(todo)
}
// tomorrow
else if (daysFromNow(dueDate) === 1) {
if (!groups['tomorrow']) groups['tomorrow'] = []
groups['tomorrow'].push(todo)
}
// overdue
else if (daysFromNow(dueDate) < 0) {
if (!groups['overdue']) groups['overdue'] = []
groups['overdue'].push(todo)
}
// by month
else {
let month = dueDate.toLocaleDateString('de-DE', { month: 'long' })
if (!groups[month]) groups[month] = []
groups[month].push(todo)
// today
if (isToday(dueDate)) {
if (!groups['today']) groups['today'] = []
groups['today'].push(todo)
}
// tomorrow
else if (daysFromNow(dueDate) === 1) {
if (!groups['tomorrow']) groups['tomorrow'] = []
groups['tomorrow'].push(todo)
}
// overdue
else if (daysFromNow(dueDate) < 0) {
if (!groups['overdue']) groups['overdue'] = []
groups['overdue'].push(todo)
}
// by month
else {
let month = dueDate.toLocaleDateString('de-DE', { month: 'long' })
if (!groups[month]) groups[month] = []
groups[month].push(todo)
}
} else {
if (!groups['noDueDate']) groups['noDueDate'] = []
groups['noDueDate'].push(todo)
}
}
}
return groups
// Convert the groupedTodos object to an array of key-value pairs
const entries = Object.entries(groups);
// Sort the entries so that 'noDueDate' is always last
entries.sort((a, b) => {
if (a[0] === 'noDueDate') return 1;
if (b[0] === 'noDueDate') return -1;
return 0;
});
// Convert the sorted array to an array of key-value pairs
const sortedGroupedTodos: GroupedTodos = entries.map(([key, todos]) => ({
key,
todos,
}));
return sortedGroupedTodos;
})
const groupNameForKey = (key: string) => {
if (key === 'today') return 'Heute'
if (key === 'tomorrow') return 'Morgen'
if (key === 'overdue') return 'Überfällig'
if (key === 'noDueDate') return 'Ohne Fälligkeitsdatum'
return key
}
@@ -105,20 +128,20 @@ const shouldDisplay = (todo: Todo) => {
</script>
<template>
<div v-if="todos" v-for="(todos, groupKey) in groupedTodos" :key="groupKey">
<div v-if="!todosEmpty(todos)">
<div v-if="todos" v-for="group in groupedTodos">
<div v-if="!todosEmpty(group.todos)">
<!-- Group header -->
<h3 class="mt-4 mb-2 text-sm text-muted-foreground" :class="{
'text-destructive! font-bold': groupKey === 'overdue',
'text-warning! font-bold': groupKey === 'today'
'text-destructive! font-bold': group.key === 'overdue',
'text-warning! font-bold': group.key === 'today'
}">
{{ groupNameForKey(groupKey) }}
{{ groupNameForKey(group.key) }}
</h3>
<hr>
<ul>
<li v-for="todo in todos" class="flex gap-3 items-baseline py-2.5 pr-1 transition-all"
<li v-for="todo in group.todos" class="flex gap-3 items-baseline py-2.5 pr-1 transition-all"
:class="{ 'scale-y-0 h-0 py-0! my-0 origin-top': !shouldDisplay(todo) }">
<!-- Check mark -->
@@ -148,11 +171,11 @@ const shouldDisplay = (todo: Todo) => {
<div class="text-xs text-muted-foreground flex gap-3 items-center mt-1">
<Badge v-if="props.showTodoable && todoBadge(todo.title)" variant="outline">{{
todoBadge(todo.title)
}}
}}
</Badge>
<span v-if="todo.dueDate" :class="{
'text-destructive! font-bold': groupKey === 'overdue',
'text-warning! font-bold': groupKey === 'today'
'text-destructive! font-bold': group.key === 'overdue',
'text-warning! font-bold': group.key === 'today'
}">
{{ toDuration(todo.dueDate) }}</span>
<Repeat v-if="todo.recurring" stroke-width="2" :size="14" />