diff options
-rw-r--r-- | server/config/db.js | 2 | ||||
-rw-r--r-- | server/models/User.js | 14 | ||||
-rw-r--r-- | server/routes/auth.js | 63 | ||||
-rw-r--r-- | server/server.js | 20 | ||||
-rw-r--r-- | src/App.js | 21 | ||||
-rw-r--r-- | src/components/Dashboard.js | 83 | ||||
-rw-r--r-- | src/components/Login.js | 39 | ||||
-rw-r--r-- | src/components/PrivateRoute.js | 17 | ||||
-rw-r--r-- | src/firebase/firebaseConfig.js | 20 | ||||
-rw-r--r-- | src/index.js | 16 |
10 files changed, 194 insertions, 101 deletions
diff --git a/server/config/db.js b/server/config/db.js index c1f628a..9ae3c6b 100644 --- a/server/config/db.js +++ b/server/config/db.js @@ -1,4 +1,6 @@ const mongoose = require('mongoose'); +require('dotenv').config(); + const connectDB = async () => { try { await mongoose.connect(process.env.MONGO_URI, { diff --git a/server/models/User.js b/server/models/User.js index 6773c64..968673e 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -1,7 +1,15 @@ const mongoose = require('mongoose'); + const UserSchema = new mongoose.Schema({ - username: { type: String, reauired: true, unique: true }, - password: { type: String, required: true }, - role: { type: String, default: 'admin' }, + email: { + type: String, + required: true, + unique: true, + }, + password: { + type: String, + required: true, + }, }); + module.exports = mongoose.model('User', UserSchema); diff --git a/server/routes/auth.js b/server/routes/auth.js index 3fb0986..04a9d5b 100644 --- a/server/routes/auth.js +++ b/server/routes/auth.js @@ -1,57 +1,46 @@ const express = require('express'); const bcrypt = require('bcryptjs'); -const jwt = require('jsonwebtoken'); +const jwt = require('jwt-simple'); const User = require('../models/User'); +require('dotenv').config(); + const router = express.Router(); +const secret = process.env.JWT_SECRET; -// Register +// Register new user router.post('/register', async (req, res) => { - const { username, password } = req.body; + const { email, password } = req.body; try { - let user = await User.findOne({ username }); - if (user) { - return res.status(400).json({ msg: 'User already exists' }); - } - user = new User({ - username, - password, - }); + const user = await User.findOne({ email }); + if (user) return res.status(400).json({ msg: 'User already exists' }); + + const newUser = new User({ email, password }); const salt = await bcrypt.genSalt(10); - user.password = await bcrypt.hash(password, salt); - await user.save(); - res.status(200).send('User registered'); + newUser.password = await bcrypt.hash(password, salt); + await newUser.save(); + + const payload = { id: newUser.id }; + const token = jwt.encode(payload, secret); + res.json({ token }); } catch (err) { console.error(err.message); res.status(500).send('Server error'); } }); -// Login +// Login user router.post('/login', async (req, res) => { - const { username, password } = req.body; + const { email, password } = req.body; try { - const user = await User.findOne({ username }); - if (!user) { - return res.status(400).json({ msg: 'Invalid credentials' }); - } + const user = await User.findOne({ email }); + if (!user) return res.status(400).json({ msg: 'Invalid credentials' }); + const isMatch = await bcrypt.compare(password, user.password); - if (!isMatch) { - return res.status(400).json({ msg: 'Invalid credentials' }); - } - const payload = { - user: { - id: user.id, - }, - }; - jwt.sign( - payload, - process.env.JWT_SECRET, - { expiresIn: '1h' }, - (err, token) => { - if (err) throw err; - res.json({ token }); - } - ); + if (!isMatch) return res.status(400).json({ msg: 'Invalid credentials' }); + + const payload = { id: user.id }; + const token = jwt.encode(payload, secret); + res.json({ token }); } catch (err) { console.error(err.message); res.status(500).send('Server error'); diff --git a/server/server.js b/server/server.js index caf4d9c..fcd02f6 100644 --- a/server/server.js +++ b/server/server.js @@ -1,14 +1,22 @@ const express = require('express'); -const connectDB = require('./config/db'); const cors = require('cors'); -const app = express(); +const bodyParser = require('body-parser'); +const connectDB = require('./config/db'); +const authRoutes = require('./routes/auth'); + require('dotenv').config(); -connectDB(); +const app = express(); +const PORT = process.env.PORT || 8080; + +// Middleware app.use(cors()); -app.use(express.json()); +app.use(bodyParser.json()); -app.use('/api/auth', require('./routes/auth')); +// Connect to MongoDB +connectDB(); + +// Routes +app.use('/api/auth', authRoutes); -const PORT = process.env.PORT || 8080; app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); @@ -1,19 +1,18 @@ -import React, { useState } from 'react'; +import React from 'react'; +import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import Login from './components/Login'; +import Dashboard from './components/Dashboard'; +import PrivateRoute from './components/PrivateRoute'; const App = () => { - const [isAuth, setIsAuth] = useState(false); - return ( - <div className="App"> - {isAuth ? <AdminPanel /> : <Login setAuth={setIsAuth} />} - </div> + <Router> + <Switch> + <Route path="/login" component={Login} /> + <PrivateRoute path="/dashboard" component={Dashboard} /> + </Switch> + </Router> ); }; -const AdminPanel = () => { - // Admin panel logic - return <div>Admin Panel</div>; -}; - export default App; diff --git a/src/components/Dashboard.js b/src/components/Dashboard.js new file mode 100644 index 0000000..cb14e26 --- /dev/null +++ b/src/components/Dashboard.js @@ -0,0 +1,83 @@ +import React, { useState, useEffect } from 'react'; +import { useHistory } from 'react-router-dom'; +import { auth, firestore } from '../firebase/firebaseConfig'; +import { getStorage, ref, uploadBytes, deleteObject } from "firebase/storage"; +import { collection, getDocs, addDoc, deleteDoc, doc } from "firebase/firestore"; +import { Bar } from 'react-chartjs-2'; + +const Dashboard = () => { + const history = useHistory(); + const [ads, setAds] = useState([]); + const [views, setViews] = useState([]); + const storage = getStorage(); + const adsCollectionRef = collection(firestore, "ads"); + + useEffect(() => { + const fetchAds = async () => { + const adsSnapshot = await getDocs(adsCollectionRef); + setAds(adsSnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id }))); + }; + + const fetchViews = async () => { + // Assume we have a 'views' collection to track ad views + const viewsSnapshot = await getDocs(collection(firestore, "views")); + setViews(viewsSnapshot.docs.map(doc => doc.data())); + }; + + fetchAds(); + fetchViews(); + }, []); + + const handleLogout = () => { + auth.signOut(); + localStorage.removeItem('token'); + history.push('/login'); + }; + + const handleUpload = async (event) => { + const file = event.target.files[0]; + const storageRef = ref(storage, `ads/${file.name}`); + await uploadBytes(storageRef, file); + await addDoc(adsCollectionRef, { name: file.name, url: `ads/${file.name}` }); + setAds([...ads, { name: file.name, url: `ads/${file.name}` }]); + }; + + const handleDelete = async (id, url) => { + const storageRef = ref(storage, url); + await deleteObject(storageRef); + await deleteDoc(doc(firestore, "ads", id)); + setAds(ads.filter(ad => ad.id !== id)); + }; + + const viewData = { + labels: ads.map(ad => ad.name), + datasets: [ + { + label: 'Ad Views', + data: views.map(view => view.count), + backgroundColor: 'rgba(75, 192, 192, 0.6)', + }, + ], + }; + + return ( + <div> + <h2>Dashboard</h2> + <button onClick={handleLogout}>Logout</button> + <input type="file" onChange={handleUpload} /> + <div> + {ads.map(ad => ( + <div key={ad.id}> + <p>{ad.name}</p> + <button onClick={() => handleDelete(ad.id, ad.url)}>Delete</button> + </div> + ))} + </div> + <div> + <Bar data={viewData} /> + </div> + </div> + ); +}; + +export default Dashboard; diff --git a/src/components/Login.js b/src/components/Login.js index 9a67051..64539c6 100644 --- a/src/components/Login.js +++ b/src/components/Login.js @@ -1,33 +1,32 @@ import React, { useState } from 'react'; import axios from 'axios'; +import { useHistory } from 'react-router-dom'; -const Login = ({ setAuth }) => { - const [formData, setFormData] = useState({ - username: '', - password: '', - }); +const Login = () => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const history = useHistory(); - const { username, password } = formData; - - const onChange = (e) => setFormData({ ...formData, [e.target.name]: e.target.value }); - - const onSubmit = async (e) => { + const handleSubmit = async (e) => { e.preventDefault(); try { - const res = await axios.post('/api/auth/login', formData); - localStorage.setItem('token', res.data.token); - setAuth(true); - } catch (err) { - console.error(err.response.data); + const response = await axios.post('/api/auth/login', { email, password }); + localStorage.setItem('token', response.data.token); + history.push('/dashboard'); + } catch (error) { + console.error('Error logging in:', error); } }; return ( - <form onSubmit={onSubmit}> - <input type="text" name="username" value={username} onChange={onChange} required /> - <input type="password" name="password" value={password} onChange={onChange} required /> - <button type="submit">Login</button> - </form> + <div> + <h2>Login</h2> + <form onSubmit={handleSubmit}> + <input type="email" placeholder="Email" value={email} onChange={(e) => setEmail(e.target.value)} required /> + <input type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} required /> + <button type="submit">Login</button> + </form> + </div> ); }; diff --git a/src/components/PrivateRoute.js b/src/components/PrivateRoute.js new file mode 100644 index 0000000..1296935 --- /dev/null +++ b/src/components/PrivateRoute.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { Route, Redirect } from 'react-router-dom'; + +const PrivateRoute = ({ component: Component, ...rest }) => { + const isAuthenticated = !!localStorage.getItem('token'); + + return ( + <Route + {...rest} + render={(props) => + isAuthenticated ? <Component {...props} /> : <Redirect to="/login" /> + } + /> + ); +}; + +export default PrivateRoute; diff --git a/src/firebase/firebaseConfig.js b/src/firebase/firebaseConfig.js index 12f2a35..87546fd 100644 --- a/src/firebase/firebaseConfig.js +++ b/src/firebase/firebaseConfig.js @@ -1,17 +1,17 @@ import firebase from 'firebase/app'; -import 'firebase/storage'; +import 'firebase/auth'; +import 'firebase/firestore'; const firebaseConfig = { - apiKey: process.env.REACT_APP_FIREBASE_API_KEY, - authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN, - projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID, - storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET, - messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID, - appId: process.env.REACT_APP_FIREBASE_APP_ID, + apiKey: "YOUR_API_KEY", + authDomain: "YOUR_AUTH_DOMAIN", + projectId: "YOUR_PROJECT_ID", + storageBucket: "YOUR_STORAGE_BUCKET", + messagingSenderId: "YOUR_MESSAGING_SENDER_ID", + appId: "YOUR_APP_ID" }; firebase.initializeApp(firebaseConfig); -const storage = firebase.storage(); - -export { storage, firebase as default }; +export const auth = firebase.auth(); +export const firestore = firebase.firestore(); diff --git a/src/index.js b/src/index.js index d563c0f..b597a44 100644 --- a/src/index.js +++ b/src/index.js @@ -1,17 +1,5 @@ import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; +import ReactDOM from 'react-dom'; import App from './App'; -import reportWebVitals from './reportWebVitals'; -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - <React.StrictMode> - <App /> - </React.StrictMode> -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); +ReactDOM.render(<App />, document.getElementById('root')); |