diff --git a/notification_system/backend/config/db.js b/notification_system/backend/config/db.js new file mode 100644 index 0000000..f5b072b --- /dev/null +++ b/notification_system/backend/config/db.js @@ -0,0 +1,16 @@ +const mongoose = require('mongoose'); + +const connectDB = async () => { + try { + await mongoose.connect(process.env.MONGO_URI, { + useNewUrlParser: true, + useUnifiedTopology: true, + }); + console.log('MongoDB Connected'); + } catch (error) { + console.error(error.message); + process.exit(1); + } +}; + +module.exports = connectDB; diff --git a/notification_system/backend/controllers/notificationController.js b/notification_system/backend/controllers/notificationController.js new file mode 100644 index 0000000..1f09782 --- /dev/null +++ b/notification_system/backend/controllers/notificationController.js @@ -0,0 +1,31 @@ +const Notification = require('../models/Notification'); +const User = require('../models/User'); +const io = require('../server'); + +// Create new notification +const sendNotification = async (req, res) => { + const { userId, title, message, type } = req.body; + + const notification = new Notification({ + userId, + title, + message, + type, + }); + + await notification.save(); + + // Emit real-time notification to user via Socket.io + io.to(userId).emit('notification', { title, message, type }); + + res.status(201).json({ message: 'Notification sent successfully' }); +}; + +// Get notifications for user +const getUserNotifications = async (req, res) => { + const userId = req.params.userId; + const notifications = await Notification.find({ userId }); + res.json(notifications); +}; + +module.exports = { sendNotification, getUserNotifications }; diff --git a/notification_system/backend/models/Notification.js b/notification_system/backend/models/Notification.js new file mode 100644 index 0000000..9c93254 --- /dev/null +++ b/notification_system/backend/models/Notification.js @@ -0,0 +1,14 @@ +const mongoose = require('mongoose'); + +const notificationSchema = new mongoose.Schema({ + userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, + title: String, + message: String, + type: String, + read: { type: Boolean, default: false }, + createdAt: { type: Date, default: Date.now }, +}); + +const Notification = mongoose.model('Notification', notificationSchema); + +module.exports = Notification; diff --git a/notification_system/backend/models/User.js b/notification_system/backend/models/User.js new file mode 100644 index 0000000..28223b8 --- /dev/null +++ b/notification_system/backend/models/User.js @@ -0,0 +1,13 @@ +const mongoose = require('mongoose'); + +const userSchema = new mongoose.Schema({ + email: String, + notificationPreferences: { + type: Map, + of: Boolean, // Preferences for notifications like 'events', 'updates', etc. + }, +}); + +const User = mongoose.model('User', userSchema); + +module.exports = User; diff --git a/notification_system/backend/package.json b/notification_system/backend/package.json new file mode 100644 index 0000000..27fc53f --- /dev/null +++ b/notification_system/backend/package.json @@ -0,0 +1,26 @@ +{ + "name": "notification-backend", + "version": "1.0.0", + "description": "Notification system backend with Node.js, Express, Socket.io, MongoDB, and Nodemailer", + "main": "server.js", + "scripts": { + "start": "node server.js", + "dev": "nodemon server.js" + }, + "dependencies": { + "express": "^4.18.1", + "mongoose": "^6.0.0", + "nodemailer": "^6.7.2", + "socket.io": "^4.4.1", + "dotenv": "^16.0.1" + }, + "devDependencies": { + "nodemon": "^2.0.15" + }, + "engines": { + "node": ">=14.0.0" + }, + "author": "Your Name", + "license": "ISC" + } + \ No newline at end of file diff --git a/notification_system/backend/routes/notificationRoutes.js b/notification_system/backend/routes/notificationRoutes.js new file mode 100644 index 0000000..f874109 --- /dev/null +++ b/notification_system/backend/routes/notificationRoutes.js @@ -0,0 +1,11 @@ +const express = require('express'); +const { sendNotification, getUserNotifications } = require('../controllers/notificationController'); +const router = express.Router(); + +// POST route to send a notification +router.post('/send', sendNotification); + +// GET route to fetch user notifications +router.get('/:userId', getUserNotifications); + +module.exports = router; diff --git a/notification_system/backend/routes/userRoutes.js b/notification_system/backend/routes/userRoutes.js new file mode 100644 index 0000000..0d9d223 --- /dev/null +++ b/notification_system/backend/routes/userRoutes.js @@ -0,0 +1,14 @@ +const express = require('express'); +const User = require('../models/User'); +const router = express.Router(); + +// Update user notification preferences +router.put('/:userId/preferences', async (req, res) => { + const { userId } = req.params; + const preferences = req.body; + + await User.findByIdAndUpdate(userId, { notificationPreferences: preferences }); + res.json({ message: 'Preferences updated successfully' }); +}); + +module.exports = router; diff --git a/notification_system/backend/server.js b/notification_system/backend/server.js new file mode 100644 index 0000000..229a585 --- /dev/null +++ b/notification_system/backend/server.js @@ -0,0 +1,34 @@ +const express = require('express'); +const http = require('http'); +const { Server } = require('socket.io'); +const connectDB = require('./config/db'); +const notificationRoutes = require('./routes/notificationRoutes'); +const userRoutes = require('./routes/userRoutes'); + +const app = express(); +const server = http.createServer(app); +const io = new Server(server); + +app.use(express.json()); + +// Connect to MongoDB +connectDB(); + +// Use routes +app.use('/api/notifications', notificationRoutes); +app.use('/api/users', userRoutes); + +// Socket.io setup +io.on('connection', (socket) => { + console.log('User connected'); + + socket.on('disconnect', () => { + console.log('User disconnected'); + }); +}); + +const PORT = process.env.PORT || 5000; +server.listen(PORT, () => console.log(`Server running on port ${PORT}`)); + +module.exports = io; + diff --git a/notification_system/backend/services/emailServices.js b/notification_system/backend/services/emailServices.js new file mode 100644 index 0000000..3d856d1 --- /dev/null +++ b/notification_system/backend/services/emailServices.js @@ -0,0 +1,22 @@ +const nodemailer = require('nodemailer'); + +const sendEmail = async (email, subject, text) => { + let transporter = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: process.env.EMAIL_USER, + pass: process.env.EMAIL_PASS, + }, + }); + + let mailOptions = { + from: process.env.EMAIL_USER, + to: email, + subject, + text, + }; + + await transporter.sendMail(mailOptions); +}; + +module.exports = sendEmail; diff --git a/notification_system/frontend/package.json b/notification_system/frontend/package.json new file mode 100644 index 0000000..3d77651 --- /dev/null +++ b/notification_system/frontend/package.json @@ -0,0 +1,37 @@ +{ + "name": "notification-frontend", + "version": "1.0.0", + "private": true, + "dependencies": { + "axios": "^0.27.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "react-scripts": "5.0.0", + "socket.io-client": "^4.5.1" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } + } + \ No newline at end of file diff --git a/notification_system/frontend/public/service-worker.js b/notification_system/frontend/public/service-worker.js new file mode 100644 index 0000000..02fd72c --- /dev/null +++ b/notification_system/frontend/public/service-worker.js @@ -0,0 +1,9 @@ +self.addEventListener('push', function (event) { + const data = event.data.json(); + event.waitUntil( + self.registration.showNotification(data.title, { + body: data.message, + }) + ); + }); + \ No newline at end of file diff --git a/notification_system/frontend/src/app.js b/notification_system/frontend/src/app.js new file mode 100644 index 0000000..6c5401d --- /dev/null +++ b/notification_system/frontend/src/app.js @@ -0,0 +1,21 @@ +import React from 'react'; +import NotificationCenter from './components/NotificationCenter'; +import NotificationSettings from './components/NotificationSettings'; + +function App() { + const userId = 'USER_ID'; // Replace with actual user ID logic from auth + + return ( +
+

Welcome to the Notification System

+ + {/* Notification Center Component */} + + + {/* Notification Settings Component */} + +
+ ); +} + +export default App; diff --git a/notification_system/frontend/src/components/NotificationCentre.js b/notification_system/frontend/src/components/NotificationCentre.js new file mode 100644 index 0000000..04b52d8 --- /dev/null +++ b/notification_system/frontend/src/components/NotificationCentre.js @@ -0,0 +1,41 @@ +import React, { useEffect, useState } from 'react'; +import axios from 'axios'; +import { io } from 'socket.io-client'; + +const NotificationCenter = ({ userId }) => { + const [notifications, setNotifications] = useState([]); + + useEffect(() => { + // Fetch notifications from API + const fetchNotifications = async () => { + const { data } = await axios.get(`/api/notifications/${userId}`); + setNotifications(data); + }; + + fetchNotifications(); + + // Socket.io connection for real-time notifications + const socket = io(); + + socket.on('notification', (notification) => { + setNotifications((prev) => [...prev, notification]); + }); + + return () => socket.disconnect(); + }, [userId]); + + return ( +
+

Notification Center

+ +
+ ); +}; + +export default NotificationCenter; diff --git a/notification_system/frontend/src/components/NotificationSettings.js b/notification_system/frontend/src/components/NotificationSettings.js new file mode 100644 index 0000000..6f6eb99 --- /dev/null +++ b/notification_system/frontend/src/components/NotificationSettings.js @@ -0,0 +1,49 @@ +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; + +const NotificationSettings = ({ userId }) => { + const [preferences, setPreferences] = useState({ + events: true, + updates: true, + }); + + useEffect(() => { + // Fetch user preferences from the backend + const fetchPreferences = async () => { + const { data } = await axios.get(`/api/users/${userId}/preferences`); + setPreferences(data.notificationPreferences); + }; + + fetchPreferences(); + }, [userId]); + + const handleSave = async () => { + await axios.put(`/api/users/${userId}/preferences`, preferences); + alert('Preferences saved'); + }; + + return ( +
+

Notification Settings

+ + + +
+ ); +}; + +export default NotificationSettings; diff --git a/notification_system/frontend/src/index.js b/notification_system/frontend/src/index.js new file mode 100644 index 0000000..d7cd52b --- /dev/null +++ b/notification_system/frontend/src/index.js @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; + +// Register service worker for push notifications +if ('serviceWorker' in navigator) { + navigator.serviceWorker.register('/service-worker.js').then((registration) => { + console.log('Service worker registered:', registration); + }).catch((error) => { + console.log('Service worker registration failed:', error); + }); +} + +ReactDOM.render(, document.getElementById('root'));