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
48 changes: 48 additions & 0 deletions css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
}
8 changes: 8 additions & 0 deletions database.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 11 additions & 2 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
});
});
}
Expand Down
28 changes: 17 additions & 11 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,30 +553,36 @@ 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) => {
const { email, password } = req.body;
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.
Expand Down