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
40 changes: 40 additions & 0 deletions css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
29 changes: 22 additions & 7 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ <h2 id="auth-title" style="margin:0 0 8px; font-size:22px; font-weight:700;">Wel
<input id="auth-password" type="password" placeholder="Password" style="width:100%; padding:12px; border:1px solid #ddd; border-radius:8px; font-size:14px; margin-bottom:20px; box-sizing:border-box;">

<button id="auth-submit-btn" style="width:100%; padding:12px; background:#4f46e5; color:white; border:none; border-radius:8px; font-size:15px; font-weight:600; cursor:pointer;">
Sign In
</button>
Sign In
</button>

<p style="text-align:center; margin:16px 0 0; font-size:13px; color:#666;">
<span id="auth-toggle-text">Don't have an account?</span>
Expand Down Expand Up @@ -282,11 +282,12 @@ <h3 style="font-size:12px; font-weight:700; text-transform:uppercase; color:var(
document.getElementById('auth-toggle-btn').textContent = isLogin ? 'Sign Up' : 'Sign In';
document.getElementById('auth-error').style.display = 'none';
});

document.getElementById('auth-submit-btn').addEventListener('click', async () => {
const email = document.getElementById('auth-email').value.trim();
const password = document.getElementById('auth-password').value.trim();
const errorEl = document.getElementById('auth-error');


if (!email || !password) {
errorEl.textContent = 'Please fill in all fields';
Expand All @@ -296,7 +297,11 @@ <h3 style="font-size:12px; font-weight:700; text-transform:uppercase; color:var(

const endpoint = isLogin ? '/api/auth/login' : '/api/auth/signup';


errorEl.style.display = 'none';

try {

const res = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
Expand All @@ -306,17 +311,24 @@ <h3 style="font-size:12px; font-weight:700; text-transform:uppercase; color:var(

if (!res.ok) {
errorEl.textContent = data.error || 'Something went wrong';
errorEl.style.display = 'block';
errorEl.style.display = 'block';
return;
}

localStorage.setItem('studyplan_user', JSON.stringify({ email: data.email }));
document.getElementById('auth-modal').style.display = 'none';


localStorage.setItem(
'studyplan_user',
JSON.stringify({ email: data.email })
);

document.getElementById('auth-modal').style.display = 'none';

} catch (err) {
errorEl.textContent = 'Network error. Please try again.';
errorEl.style.display = 'block';
errorEl.style.display = 'block';
}

});

// Check if already logged in
Expand Down Expand Up @@ -450,6 +462,9 @@ <h3 style="margin:0 0 12px; font-size:18px; font-weight:600;">New task</h3>
<button id="new-task-save" class="btn btn-primary" style="padding:6px 12px;">Save</button>
</div>
</div>
</div>
<div id="toast-message" class="toast-message">

</div>
</body>
</html>
65 changes: 55 additions & 10 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '<span class="loader-spinner"></span>';

if (!text.trim()) {
showToast('Please enter some text first', 'error');
return;
}

extractBtn.innerHTML =
'<span class="loader-spinner"></span> 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', () => {
Expand Down
2 changes: 2 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,13 +417,15 @@ 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).
Each object must have: title (string), subject_name (string), due_at (ISO 8601 datetime), notes (string), confidence_score (number 0-100), priority ("low"|"medium"|"high"), icon (emoji).

Text: "${text}"
`;

const response = await ai.models.generateContent({
model: 'gemini-2.5-flash',
contents: prompt
Expand Down