From 66aa8b46ce4141a255bc81778f6a9af347897b20 Mon Sep 17 00:00:00 2001 From: Anuja Pawar Date: Wed, 10 Jun 2026 00:00:34 +0530 Subject: [PATCH] Fix: Add confirmation dialog before deleting subject and persist user auth --- css/index.css | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ database.js | 8 ++++++++ js/app.js | 13 +++++++++++-- server.js | 28 +++++++++++++++++----------- 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/css/index.css b/css/index.css index 28fbfd3..634d0c4 100644 --- a/css/index.css +++ b/css/index.css @@ -5022,3 +5022,51 @@ body { .subject-sidebar-item:hover .delete-subject-btn { opacity: 1; } + +/* ============================================================ + Custom Confirm Modal (used by Toast.confirm()) + ============================================================ */ + +.custom-confirm-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 9999; + display: flex; + align-items: center; + justify-content: center; + padding: 24px; +} + +.custom-confirm-modal { + width: min(420px, 100%); + padding: 28px; +} + +.modal-card { + background: var(--color-background-primary); + border: 1px solid var(--color-border-secondary); + border-radius: 16px; + box-shadow: 0 24px 60px rgba(0, 0, 0, 0.2); +} + +/* Animations */ +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes fadeOut { + from { opacity: 1; } + to { opacity: 0; } +} + +@keyframes slideUp { + from { opacity: 0; transform: translateY(24px) scale(0.97); } + to { opacity: 1; transform: translateY(0) scale(1); } +} + +@keyframes slideDown { + from { opacity: 1; transform: translateY(0) scale(1); } + to { opacity: 0; transform: translateY(24px) scale(0.97); } +} diff --git a/database.js b/database.js index 33a1b17..12fec19 100644 --- a/database.js +++ b/database.js @@ -5,6 +5,14 @@ const db = new sqlite3.Database(path.join(__dirname, 'studyplan.db')); function initDb() { db.serialize(() => { + // Users Table + db.run(`CREATE TABLE IF NOT EXISTS users ( + id TEXT PRIMARY KEY, + email TEXT NOT NULL UNIQUE, + password TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + )`); + // Subjects Table db.run(`CREATE TABLE IF NOT EXISTS subjects ( id TEXT PRIMARY KEY, diff --git a/js/app.js b/js/app.js index 2bc3bce..b8bef13 100644 --- a/js/app.js +++ b/js/app.js @@ -199,12 +199,21 @@ return ` document.querySelectorAll('.delete-subject-btn') .forEach(btn => { - btn.addEventListener('click', (e) => { + btn.addEventListener('click', async (e) => { e.stopPropagation(); const subjectId = btn.dataset.subjectId; + const subject = store.subjects.find(s => s.id === subjectId); + const subjectName = subject ? subject.name : 'this subject'; + + const confirmed = await Toast.confirm( + `Are you sure you want to delete "${subjectName}"? All associated tasks will also be permanently removed. This action cannot be undone.` + ); - store.deleteSubject(subjectId); + if (confirmed) { + store.deleteSubject(subjectId); + Toast.show(`"${subjectName}" has been deleted.`, 'success'); + } }); }); } diff --git a/server.js b/server.js index 68dadff..8a13163 100644 --- a/server.js +++ b/server.js @@ -553,18 +553,22 @@ Text: "${text}" return res.json(tasks); }); // ================= AUTH ================= -const users = {}; // Simple in-memory user store +// Users are now stored in SQLite so they persist across server restarts app.post('/api/auth/signup', (req, res) => { const { email, password } = req.body; if (!email || !password) { return res.status(400).json({ error: 'Email and password required' }); } - if (users[email]) { - return res.status(400).json({ error: 'User already exists' }); - } - users[email] = { email, password }; - res.json({ success: true, message: 'Account created successfully' }); + db.get('SELECT * FROM users WHERE LOWER(email) = LOWER(?)', [email], (err, row) => { + if (err) return res.status(500).json({ error: err.message }); + if (row) return res.status(400).json({ error: 'User already exists' }); + const id = 'user_' + Date.now() + Math.random().toString(36).slice(2, 7); + db.run('INSERT INTO users (id, email, password) VALUES (?, ?, ?)', [id, email, password], function (insertErr) { + if (insertErr) return res.status(500).json({ error: insertErr.message }); + res.json({ success: true, message: 'Account created successfully' }); + }); + }); }); app.post('/api/auth/login', (req, res) => { @@ -572,11 +576,13 @@ app.post('/api/auth/login', (req, res) => { if (!email || !password) { return res.status(400).json({ error: 'Email and password required' }); } - const user = users[email]; - if (!user || user.password !== password) { - return res.status(401).json({ error: 'Invalid email or password' }); - } - res.json({ success: true, email: user.email }); + db.get('SELECT * FROM users WHERE LOWER(email) = LOWER(?)', [email], (err, user) => { + if (err) return res.status(500).json({ error: err.message }); + if (!user || user.password !== password) { + return res.status(401).json({ error: 'Invalid email or password' }); + } + res.json({ success: true, email: user.email }); + }); }); // Intentional test route for verifying server error page behavior.