diff --git a/css/index.css b/css/index.css index 24a20f7..773bd71 100644 --- a/css/index.css +++ b/css/index.css @@ -2159,4 +2159,44 @@ body { .smart-highlight { color: #ffcc66; font-weight: 600; +} +.spinner { + width: 14px; + height: 14px; + border: 2px solid white; + border-top: 2px solid transparent; + border-radius: 50%; + display: inline-block; + animation: spin 0.6s linear infinite; + margin-left: 8px; + vertical-align: middle; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} +.toast-message { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: #1f2937; + color: white; + padding: 14px 24px; + border-radius: 10px; + font-size: 15px; + font-weight: 500; + z-index: 9999; + display: none; + box-shadow: 0 4px 15px rgba(0,0,0,0.2); +} + +.toast-success { + background: #16a34a; +} + +.toast-error { + background: #dc2626; } \ No newline at end of file diff --git a/index.html b/index.html index da78416..87ad130 100644 --- a/index.html +++ b/index.html @@ -21,8 +21,8 @@

Wel + Sign In +

Don't have an account? @@ -282,11 +282,12 @@

New task

+ +
+
diff --git a/js/app.js b/js/app.js index 9bfd993..ba0c341 100644 --- a/js/app.js +++ b/js/app.js @@ -1045,19 +1045,64 @@ addItemsBtn.addEventListener('click', () => { }); }); +function showToast(message, type = 'success') { + const toast = document.getElementById('toast-message'); + + toast.textContent = message; + + toast.className = 'toast-message'; + + if (type === 'success') { + toast.classList.add('toast-success'); + } else { + toast.classList.add('toast-error'); + } + + toast.style.display = 'block'; + + setTimeout(() => { + toast.style.display = 'none'; + }, 1000); +} + extractBtn.addEventListener('click', async () => { const text = pasteInput.value; - if (!text.trim()) return; - - extractBtn.innerHTML = ''; + + if (!text.trim()) { + showToast('Please enter some text first', 'error'); + return; + } + + extractBtn.innerHTML = + ' Extracting...'; + extractBtn.disabled = true; - - const items = await extractTasksFromText(text); - - extractBtn.innerHTML = 'Extract with AI →'; - extractBtn.disabled = false; - - store.setExtracted(items); + + try { + + const items = await extractTasksFromText(text); + + if (!items || items.length === 0) { + showToast('Extraction failed', 'error'); + return; + } + + store.setExtracted(items); + + showToast('Tasks extracted successfully!', 'success'); + + } catch (err) { + + console.error(err); + + showToast('Something went wrong', 'error'); + + } finally { + + extractBtn.innerHTML = 'Extract with AI →'; + + extractBtn.disabled = false; + } }); clearBtn.addEventListener('click', () => { diff --git a/server.js b/server.js index 877f766..5e333d6 100644 --- a/server.js +++ b/server.js @@ -417,6 +417,7 @@ app.post('/api/extract', async (req, res) => { if (ai) { try { + const prompt = ` You are an AI study planner assistant. Extract ALL tasks and deadlines from the text below. Return ONLY a raw JSON array (no markdown, no backticks, no explanation). @@ -424,6 +425,7 @@ Each object must have: title (string), subject_name (string), due_at (ISO 8601 d Text: "${text}" `; + const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: prompt