Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 57 additions & 14 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,11 +431,30 @@ function renderTasks() {
completed.push(t);
return;
}

pending.push(t);

if (!t.due_at) {
thisWeek.push(t);
return;
}

const d = new Date(t.due_at);

// Ignore invalid dates
if (isNaN(d.getTime())) {
thisWeek.push(t);
return;
}

const diffDays = (d - now) / (1000 * 60 * 60 * 24);
if (diffDays <= 3) dueSoon.push(t);
else thisWeek.push(t);

// Due soon = upcoming within 3 days only
if (diffDays >= 0 && diffDays <= 3) {
dueSoon.push(t);
} else {
thisWeek.push(t);
}
});
}

Expand Down Expand Up @@ -751,6 +770,34 @@ function renderCalendar() {
});
}

function findSubjectForExtractedItem(item) {
const requested = String(item.subject_name || '').trim().toLowerCase();
const defaultSubject = store.subjects[0] || null;
if (!requested || requested === 'general') return defaultSubject;

return store.subjects.find(s => s.name.toLowerCase() === requested)
|| store.subjects.find(s => s.name.toLowerCase().includes(requested) || requested.includes(s.name.toLowerCase()))
|| defaultSubject;
}

function prepareExtractedTasksForSave(items) {
return (items || []).map(item => {
const sub = store.subjects.find(s => String(s.id) === String(item.subject_id))
|| findSubjectForExtractedItem(item);

return {
title: String(item.title || '').trim(),
subject_id: sub?.id,
due_at: item.due_at,
notes: item.notes || '',
priority: item.priority || 'medium',
confidence_score: item.confidence_score || 60,
status: item.status || 'Not Started',
archived: 0
};
}).filter(item => item.title && item.subject_id && item.due_at);
}

function renderExtraction() {
const pasteItems = store.currentPaste;
if (!pasteItems || pasteItems.length === 0) {
Expand All @@ -766,7 +813,8 @@ function renderExtraction() {
let html = `<div class="extract-title">Extracted — ${pasteItems.length} items</div>`;
pasteItems.forEach((item, index) => {
// try to match subject name
const sub = store.subjects.find(s => s.name.toLowerCase().includes((item.subject_name || '').toLowerCase())) || store.subjects[3];
const sub = findSubjectForExtractedItem(item);
if (!sub) return;
// Attach subject id to item so Add will work
item.subject_id = sub.id;

Expand Down Expand Up @@ -1036,13 +1084,6 @@ newTaskSave.addEventListener('click', async () => {
newTaskModal.style.display = 'none';
});

addItemsBtn.addEventListener('click', () => {
if (store.currentPaste) {
store.addTasks(store.currentPaste);
store.clearExtracted();
pasteInput.value = '';
}
});
});

extractBtn.addEventListener('click', async () => {
Expand All @@ -1065,11 +1106,13 @@ clearBtn.addEventListener('click', () => {
store.clearExtracted();
});

addItemsBtn.addEventListener('click', () => {
addItemsBtn.addEventListener('click', async () => {
if (store.currentPaste) {
store.addTasks(store.currentPaste);
store.clearExtracted();
pasteInput.value = '';
const added = await store.addTasks(prepareExtractedTasksForSave(store.currentPaste));
if (added) {
store.clearExtracted();
pasteInput.value = '';
}
}
});

Expand Down
18 changes: 15 additions & 3 deletions js/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,19 @@ export const store = {
// ================= UPDATED FUNCTION =================
async addTasks(newTasks) {
try {
const tasksToAdd = (Array.isArray(newTasks) ? newTasks : [newTasks])
.filter(Boolean)
.map(({ _isEditing, icon, subject_name, ...task }) => task);

if (tasksToAdd.length === 0) {
alert("No valid tasks to add");
return false;
}

const res = await fetch('/api/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newTasks)
body: JSON.stringify(tasksToAdd)
});

const data = await res.json(); // always parse response
Expand All @@ -77,7 +86,7 @@ export const store = {
// Backend error
alert(`❌ ${data.message || "Failed to add tasks"}`);
console.error('Add task error:', data);
return;
return false;
}

// ================= USER MESSAGES =================
Expand All @@ -102,6 +111,7 @@ export const store = {
const tasksRes = await fetch('/api/tasks');
this.tasks = await tasksRes.json();
this.notify();
return data.inserted > 0;

} catch (e) {
console.error('Failed to add tasks', e);
Expand Down Expand Up @@ -294,7 +304,9 @@ export const store = {
},

setExtracted(items) {
this.currentPaste = items.map(item => ({ ...item, _isEditing: false }));
this.currentPaste = Array.isArray(items)
? items.map(item => ({ ...item, _isEditing: false }))
: [];
this.notify();
},

Expand Down
26 changes: 25 additions & 1 deletion js/utils/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,33 @@ export async function extractTasksFromText(text) {
return [];
}

return await res.json();
return normalizeExtractedTasks(await res.json());
} catch (e) {
console.error('Error hitting extract endpoint', e);
return [];
}
}

function normalizeExtractedTasks(data) {
const items = Array.isArray(data)
? data
: Array.isArray(data?.tasks)
? data.tasks
: Array.isArray(data?.items)
? data.items
: data && typeof data === 'object'
? [data]
: [];

return items
.filter(item => item && typeof item === 'object')
.map(item => ({
...item,
title: String(item.title || '').trim(),
subject_name: String(item.subject_name || item.subject || 'General').trim(),
notes: String(item.notes || '').trim(),
confidence_score: Number(item.confidence_score ?? item.confidence ?? 60),
priority: item.priority || 'medium'
}))
.filter(item => item.title && item.due_at);
}
Loading