added task size management features and fixed trash recover feature
This commit is contained in:
+41
-15
@@ -32,6 +32,7 @@ export interface Task {
|
||||
dayOfMonth?: number; // For monthly (1-31)
|
||||
lastUncompleted?: string; // ISO date of last automatic reset
|
||||
};
|
||||
size?: number; // 0-10, task complexity/size
|
||||
}
|
||||
|
||||
export const checkRecurringTasks = () => {
|
||||
@@ -280,6 +281,11 @@ export const getCombinedScore = (task: Task): number => {
|
||||
});
|
||||
}
|
||||
|
||||
// Size adjustment: (size - 5) * -0.4
|
||||
// Small tasks (0-4) get a slight boost, large tasks (6-10) get a slight penalty
|
||||
const sizeScore = ((task.size ?? 5) - 5) * -0.4;
|
||||
baseScore += sizeScore;
|
||||
|
||||
return baseScore;
|
||||
};
|
||||
|
||||
@@ -303,7 +309,8 @@ const mapRecordToTask = (r: any): Task => {
|
||||
deletedAt: r.deletedAt ? new Date(r.deletedAt).getTime() : undefined,
|
||||
created: r.created,
|
||||
updated: r.updated,
|
||||
recurrence: r.recurrence
|
||||
recurrence: r.recurrence,
|
||||
size: (r.size === null || r.size === undefined) ? undefined : r.size
|
||||
};
|
||||
};
|
||||
|
||||
@@ -362,9 +369,24 @@ export const subscribeToRealtime = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal Task
|
||||
const updatedTask = mapRecordToTask(e.record);
|
||||
setStore("tasks", t => t.id === e.record.id, updatedTask);
|
||||
// Normal Task - only apply if incoming record is newer or equal
|
||||
const existingTask = store.tasks.find(t => t.id === e.record.id);
|
||||
if (existingTask) {
|
||||
const incomingUpdated = new Date(e.record.updated).getTime();
|
||||
const localUpdated = new Date(existingTask.updated).getTime();
|
||||
|
||||
// Only apply update if incoming is newer (or we don't have a timestamp)
|
||||
if (!existingTask.updated || incomingUpdated >= localUpdated) {
|
||||
const updatedTask = mapRecordToTask(e.record);
|
||||
setStore("tasks", t => t.id === e.record.id, updatedTask);
|
||||
} else {
|
||||
console.log("Skipping stale realtime update for task:", e.record.id);
|
||||
}
|
||||
} else {
|
||||
// Task doesn't exist locally, add it
|
||||
const updatedTask = mapRecordToTask(e.record);
|
||||
setStore("tasks", t => [updatedTask, ...t]);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.action === 'delete') {
|
||||
@@ -496,7 +518,7 @@ export const initStore = async () => {
|
||||
|
||||
// -- Actions --
|
||||
|
||||
export const addTask = async (title: string, options?: { dueDate?: Date | string, priority?: number, tags?: string[], content?: string }) => {
|
||||
export const addTask = async (title: string, options?: { dueDate?: Date | string, priority?: number, tags?: string[], content?: string, size?: number }) => {
|
||||
if (!pb.authStore.isValid) return;
|
||||
|
||||
// Default to ~24h from now if no date provided
|
||||
@@ -509,6 +531,7 @@ export const addTask = async (title: string, options?: { dueDate?: Date | string
|
||||
const priority = options?.priority ?? 5;
|
||||
const tags = options?.tags ?? ["work"];
|
||||
const content = options?.content ?? "";
|
||||
const size = options?.size ?? 5;
|
||||
|
||||
const tempId = "temp-" + Date.now();
|
||||
const newTask: Task = {
|
||||
@@ -520,6 +543,7 @@ export const addTask = async (title: string, options?: { dueDate?: Date | string
|
||||
completed: false,
|
||||
tags,
|
||||
content,
|
||||
size,
|
||||
created: new Date().toISOString(),
|
||||
updated: new Date().toISOString()
|
||||
};
|
||||
@@ -536,7 +560,8 @@ export const addTask = async (title: string, options?: { dueDate?: Date | string
|
||||
priority,
|
||||
completed: false,
|
||||
tags,
|
||||
content
|
||||
content,
|
||||
size
|
||||
});
|
||||
|
||||
// Replace temp task with real record (merging server fields like id, created, updated)
|
||||
@@ -572,7 +597,8 @@ export const copyTask = async (id: string) => {
|
||||
priority: original.priority,
|
||||
dueDate: original.dueDate,
|
||||
tags: [...(original.tags || [])],
|
||||
content: original.content
|
||||
content: original.content,
|
||||
size: original.size
|
||||
});
|
||||
|
||||
toast.success("Task duplicated");
|
||||
@@ -581,8 +607,12 @@ export const copyTask = async (id: string) => {
|
||||
export const updateTask = async (id: string, updates: Partial<Task>) => {
|
||||
if (!pb.authStore.isValid) return;
|
||||
|
||||
// Optimistic
|
||||
setStore("tasks", (t) => t.id === id, updates);
|
||||
// Optimistic update with timestamp to prevent stale realtime events
|
||||
const optimisticUpdates = {
|
||||
...updates,
|
||||
updated: new Date().toISOString()
|
||||
};
|
||||
setStore("tasks", (t) => t.id === id, optimisticUpdates);
|
||||
|
||||
try {
|
||||
// Map Task fields to PB fields if needed (dates are ISO strings, so should matches)
|
||||
@@ -674,12 +704,8 @@ export const removeTask = (id: string) => {
|
||||
};
|
||||
|
||||
export const restoreTask = (id: string) => {
|
||||
// This requires passing undefined or null to updateTask
|
||||
// createStore handles undefined ok.
|
||||
setStore("tasks", (t) => t.id === id, "deletedAt", undefined);
|
||||
|
||||
// For PB, we need to send null explicitly for date clear?
|
||||
// updateTask handles this check.
|
||||
// updateTask handles both optimistic update and PB sync
|
||||
// Pass undefined for deletedAt, updateTask will convert to null for PB
|
||||
updateTask(id, { deletedAt: undefined });
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user