diff --git a/app.js b/app.js index 195887e..f40432c 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,8 @@ require('dotenv').config(); +console.log("โœ… MONGODB_URI from .env is:", process.env.MONGODB_URI); const express = require('express'); -const expressLayouts = require('express-ejs-layouts'); +const expressLayouts = require('express-ejs-layouts'); const methodOverride = require('method-override'); const connectDB = require('./server/config/db'); const session = require('express-session'); @@ -9,10 +10,10 @@ const passport = require('passport'); const MongoStore = require('connect-mongo'); const app = express(); -const port = 5000 || process.env.PORT; +const port = 5001 || process.env.PORT; app.use(session({ - secret:'keyboard cat', + secret: 'keyboard cat', resave: false, saveUninitialized: true, store: MongoStore.create({ @@ -23,8 +24,19 @@ app.use(session({ app.use(passport.initialize()); app.use(passport.session()); +// ๐Ÿงช MOCK USER: Use this ONLY for local testing +app.use((req, res, next) => { + req.user = { + name: "Test User", + email: "testuser@example.com", + id: "testuser123" + }; + next(); +}); + + //middlewares -app.use(express.urlencoded({extended:true})); +app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use(methodOverride("_method")); @@ -45,11 +57,10 @@ app.use('/', require('./server/routes/index')); app.use('/', require('./server/routes/dashboard')); //handle 404 -app.get('*',function(req,res) { - // res.status(404).send('404 page not found') - res.status(404).render('404'); +app.get('*', function (req, res) { + res.status(404).render('404'); }) app.listen(port, () => { console.log(`App listening on ${port}`); -}) \ No newline at end of file +}); diff --git a/server/controllers/dashboardController.js b/server/controllers/dashboardController.js index 740b04b..d7b62b4 100644 --- a/server/controllers/dashboardController.js +++ b/server/controllers/dashboardController.js @@ -18,21 +18,14 @@ exports.dashboard = async (req, res) => { try { // Mongoose "^7.0.0 Update - const notes = await Note.aggregate([ - { $sort: { updatedAt: -1 } }, - { $match: { user: new mongoose.Types.ObjectId(req.user.id) } }, - { - $project: { - title: { $substr: ["$title", 0, 30] }, - body: { $substr: ["$body", 0, 100] }, - }, - }, - ]) + const notes = await Note.find({ user: req.user.id, archived: false }) + .sort({ updatedAt: -1 }) .skip(perPage * page - perPage) .limit(perPage) .exec(); - const count = await Note.countDocuments(); + const count = await Note.countDocuments({ user: req.user.id, archived: false }); + const archivedCount = await Note.countDocuments({ user: req.user.id, archived: true }); res.render('dashboard/index', { userName: req.user.firstName, @@ -40,7 +33,8 @@ exports.dashboard = async (req, res) => { notes, layout: "../views/layouts/dashboard", current: page, - pages: Math.ceil(count / perPage) + pages: Math.ceil(count / perPage), + archivedCount }); } catch (error) { console.log(error); @@ -267,4 +261,70 @@ exports.dashboardSummarizeNote = async (req, res) => { } catch (error) { console.error('Summarize Error:', error.message); res.status(500).json({ summary: "Failed to generate summary." }); - }} + + } +}; + +// Archive a note +exports.archiveNote = async (req, res) => { + try { + const note = await Note.findOneAndUpdate( + { _id: req.params.id, user: req.user.id }, + { archived: true, archivedAt: new Date() }, + { new: true } + ); + if (!note) return res.status(404).send('Note not found'); + req.flash('success_msg', 'Note archived successfully.'); + res.redirect('/dashboard'); + } catch (err) { + res.status(500).send('Server Error'); + } +}; + +// Restore a note +exports.restoreNote = async (req, res) => { + try { + const note = await Note.findOneAndUpdate( + { _id: req.params.id, user: req.user.id }, + { archived: false, archivedAt: null }, + { new: true } + ); + if (!note) return res.status(404).send('Note not found'); + req.flash('success_msg', 'Note restored successfully.'); + res.redirect('/dashboard/archived'); + } catch (err) { + res.status(500).send('Server Error'); + } +}; + +// Permanently delete a note +exports.deleteNotePermanently = async (req, res) => { + try { + const note = await Note.findOneAndDelete({ _id: req.params.id, user: req.user.id, archived: true }); + if (!note) return res.status(404).send('Note not found or not archived'); + req.flash('success_msg', 'Note permanently deleted.'); + res.redirect('/dashboard/archived'); + } catch (err) { + res.status(500).send('Server Error'); + } +}; + +// GET /dashboard/archived - Show archived notes +exports.dashboardArchivedNotes = async (req, res) => { + try { + const archivedNotes = await Note.find({ user: req.user.id, archived: true }) + .sort({ archivedAt: -1 }) + .lean(); + const archivedCount = archivedNotes.length; + res.render('dashboard/archived', { + userName: req.user.firstName, + archivedNotes, + layout: '../views/layouts/dashboard', + archivedCount + }); + } catch (error) { + console.log(error); + res.status(500).send('Server Error'); + } +}; + diff --git a/server/models/Notes.js b/server/models/Notes.js index 0584f57..07c8937 100644 --- a/server/models/Notes.js +++ b/server/models/Notes.js @@ -18,6 +18,13 @@ const NoteSchema = new schema({ type: String, default: '', }, + archived: { + type: Boolean, + default: false + }, + archivedAt: { + type: Date + }, createdAt:{ type:Date, default: Date.now() diff --git a/server/routes/dashboard.js b/server/routes/dashboard.js index 4c6e275..5b510d1 100644 --- a/server/routes/dashboard.js +++ b/server/routes/dashboard.js @@ -16,10 +16,36 @@ router.post('/dashboard/add',isLoggedIn, dashboardController.dashboardAddNote); router.get('/dashboard/search',isLoggedIn, dashboardController.dashboardSearch); router.post('/dashboard/search',isLoggedIn, dashboardController.dashboardSearchSubmit); + +// Archived notes page +router.get('/dashboard/archived', isLoggedIn, dashboardController.dashboardArchivedNotes); + +// Archive a note +router.patch('/notes/:id/archive', dashboardController.archiveNote); +// Restore a note +router.patch('/notes/:id/restore', dashboardController.restoreNote); +// Permanently delete a note +router.delete('/notes/:id/permanent', dashboardController.deleteNotePermanently); + +// No authentication middleware here +router.post('/autosave', (req, res) => { + // Just log or mock-save the note + console.log('Auto-saving note:', req.body.content); + res.json({ success: true }); +}); + +router.post('/archived', (req, res) => { + // Just log or mock-archive the note + console.log('Archiving note:', req.body.content); + res.json({ success: true }); +}); + +======= // EXPORT FEATURE: Route to export all notes for the current user router.get('/dashboard/export',isLoggedIn, dashboardController.dashboardExport); // EXPORT FEATURE: Route to export individual note by ID router.get('/dashboard/export/:id',isLoggedIn, dashboardController.dashboardExportNote); + module.exports = router; \ No newline at end of file diff --git a/views/dashboard/archived.ejs b/views/dashboard/archived.ejs new file mode 100644 index 0000000..29c9120 --- /dev/null +++ b/views/dashboard/archived.ejs @@ -0,0 +1,40 @@ +
+
+
+

Archived Notes

+
+ +
+
+ <% if(archivedNotes.length > 0) { %> + <% archivedNotes.forEach(function(note) { %> +
+
+
+
<%= note.title %>
+

<%= note.body.length > 100 ? note.body.substring(0, 100) + '...' : note.body %>

+
+
+ +
+
+ +
+
+
+
+
+ <% }); %> + <% } else { %> +
+

No archived notes found.

+
+ <% } %> +
+
\ No newline at end of file diff --git a/views/dashboard/index.ejs b/views/dashboard/index.ejs index 8ac07d4..bef037d 100644 --- a/views/dashboard/index.ejs +++ b/views/dashboard/index.ejs @@ -15,8 +15,17 @@ <% for(var i = 0; i < notes.length; i++){ %>
+ +
+
+ +
+