· last year · Feb 14, 2024, 11:40 PM
1//server.js
2const express = require('express');
3const passport = require('passport');
4const session = require('express-session');
5const flash = require('connect-flash');
6const pool = require('./config/dbConfig');
7const swaggerUi = require('swagger-ui-express');
8const YAML = require('js-yaml');
9const fs = require('fs');
10const cors = require('cors');
11const authRoutes = require('./routes/authRoutes');
12const userRoutes = require('./routes/userRoutes');
13const productRoutes = require('./routes/productRoutes');
14const cartRoutes = require('./routes/cartRoutes');
15const checkoutRoutes = require('./routes/checkoutRoutes');
16const orderRoutes = require('./routes/orderRoutes');
17const authController = require('./controllers/authController');
18const pgSession = require('connect-pg-simple')(session);
19const path = require('path');
20
21
22if (process.env.NODE_ENV === 'development') {
23 require('dotenv').config({ debug: true })
24}
25
26
27
28const app = express();
29
30
31
32const port = process.env.PORT;
33const swaggerDocument = YAML.load(fs.readFileSync('./swagger.yaml', 'utf8'));
34
35app.use(function (req, res, next) {
36 const origin = req.headers.origin;
37
38 console.log('Request Origin:', origin); // Debugging: Log the request's origin
39
40 // List of allowed origins
41 const allowedOrigins = [
42 'https://e-shop-frontend-8ylf.onrender.com',
43 'https://e-shop-backend-plfz.onrender.com',
44 'https://merchant-ui-api.stripe.com/elements/wallet-config',
45 `${process.env.REACT_APP_FRONTEND_URL}`,
46 `${process.env.REACT_APP_BACKEND_URL}`
47 ];
48
49 if (allowedOrigins.includes(origin)) {
50 console.log('Origin allowed:', origin); // Debugging: Confirm origin is allowed
51 res.header("Access-Control-Allow-Origin", origin);
52 res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT,DELETE");
53 res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
54 res.header("Access-Control-Allow-Credentials", true);
55 } else {
56 console.log('Origin not allowed:', origin); // Debugging: Log if origin is not allowed
57 }
58 next();
59});
60
61
62console.log(`${process.env.REACT_APP_FRONTEND_URL}`,
63 `${process.env.REACT_APP_BACKEND_URL}`,
64 `${process.env.LOCALHOST}`,
65 `${process.env.REACT_APP_FRONTEND_URL}:${process.env.REACT_APP_LOCAL_PORT}`,
66 `${process.env.REACT_APP_BACKEND_URL}:${process.env.REACT_APP_LOCAL_PORT}`)
67
68app.use(session({
69 store: new pgSession({
70 pool : pool, // Connection pool
71 tableName: 'session', // Use this table to store sessions
72 conString: process.env.DATABASE_URL
73 }),
74 secret: process.env.SECRET,
75 resave: false,
76 saveUninitialized: false,
77 cookie: {
78 maxAge: 30 * 24 * 60 * 60 * 1000,
79 secure: true,
80 sameSite: 'None',
81 domain: `${process.env.REACT_APP_BACKEND_URL}`
82 } // 30 days
83}));
84
85app.use(flash());
86app.use(passport.initialize());
87app.use(passport.session());
88app.use(express.json({ limit: '10mb' }));
89app.use(express.static(path.join(__dirname, 'dist')));
90app.use(express.static(path.join(__dirname, 'public')));
91
92app.use((req, res, next) => {
93 next();
94});
95
96app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
97authController.initializePassport(passport);
98
99app.use(authRoutes);
100app.use(userRoutes);
101app.use(productRoutes);
102app.use(cartRoutes);
103app.use(checkoutRoutes);
104app.use(orderRoutes);
105
106app.get('/', (req, res) => {
107 res.send('Hello, this is the E-commerce API!');
108});
109
110app.get('/check-auth', (req, res) => {
111 if (req.isAuthenticated()) {
112 res.json({ isAuthenticated: true, user: { name: req.user.name } });
113 } else {
114 res.json({ isAuthenticated: false });
115 }
116});
117
118app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
119app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/login' }), (req, res) => {
120 if (req.user && req.user.address) {
121 res.redirect(`${process.env.REACT_APP_FRONTEND_URL}/products`);
122 } else {
123 res.redirect(`${process.env.REACT_APP_FRONTEND_URL}/profilecompletion/${req.user.userid}`);
124 }
125});
126
127app.get('/profilecompletion', (req, res) => {
128 const html = `
129 <!DOCTYPE html>
130 <html>
131 <head>
132 <title>Profile Completion</title>
133 <!-- Add your head content here -->
134 </head>
135 <body>
136 <div id="root"></div>
137 <!-- Include your client-side scripts here -->
138 <!-- <script src="/server-bundle.js"></script> -->
139 <!-- <script src="/client-bundle.js"></script> -->
140 <script>
141 // JavaScript code to render the ProfileCompletion component on the client-side
142 // This code should be included in your client-side scripts
143 // Example:
144 const rootElement = document.getElementById('root');
145 ReactDOM.render(<ProfileCompletion />, rootElement);
146 </script>
147 </body>
148 </html>
149 `;
150
151 res.status(200).send(html);
152});
153
154app.get('*', (req, res) => {
155 res.sendFile(path.join(__dirname, 'public', 'index.html'));
156});
157
158app.post('/update-user-details', (req, res) => {
159 const { userid, address, phonenumber } = req.body;
160
161 // Update user details in the database
162 pool.query(
163 'UPDATE Users SET address = $1, phonenumber = $2 WHERE userid = $3',
164 [address, phonenumber, userid],
165 (error, results) => {
166 if (error) {
167 res.status(500).send('Error updating user details');
168 } else {
169 res.status(200).send('User details updated successfully');
170 }
171 }
172 );
173});
174
175
176
177// Facebook OAuth routes
178// app.get('/auth/facebook', passport.authenticate('facebook'));
179// app.get('/auth/facebook/callback', passport.authenticate('facebook', { failureRedirect: '/login' }), (req, res) => {
180// res.redirect('/'); // Redirect after successful authentication
181// });
182
183app.listen(port, () => {
184 console.log(`Server is running on ${port}`);
185});
186
187// controllers/authController.js
188const jwt = require('jsonwebtoken');
189const secretKey = process.env.JWT_SECRET;
190const LocalStrategy = require('passport-local').Strategy;
191const GoogleStrategy = require('passport-google-oauth20').Strategy;
192const bcrypt = require('bcrypt');
193const pool = require('../config/dbConfig');
194
195const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID;
196const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET;
197
198const initializePassport = (passport) => {
199 passport.use(new LocalStrategy(
200 { usernameField: 'email' },
201 async (email, password, done) => {
202 try {
203 const res = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
204 if (res.rows.length === 0) {
205 return done(null, false, { message: 'Incorrect email.' });
206 }
207
208 const user = res.rows[0];
209 console.log('The user is in localstrtaegy:', user.userid)
210 const match = await bcrypt.compare(password, user.password);
211
212 if (match) {
213 return done (null, { ...user, userid: user.userid, email: user.email, username: user.name });
214 } else {
215 return done(null, false, { message: 'Incorrect password.' });
216 }
217 } catch (err) {
218 return done(err);
219 }
220 }
221 ));
222
223 passport.use(new GoogleStrategy({
224 clientID: GOOGLE_CLIENT_ID,
225 clientSecret: GOOGLE_CLIENT_SECRET,
226 callbackURL: '/auth/google/callback'
227 },
228 async (accessToken, refreshToken, profile, done) => {
229 try {
230 const email = profile.emails[0].value;
231 let userResult = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
232 let user = userResult.rows[0];
233
234 if (!user) {
235 // User does not exist, create a new user
236 const newUserResult = await pool.query(
237 'INSERT INTO users (name, email, refresh_token, phonenumber, address) VALUES ($1, $2, $3, $4, $5) RETURNING *',
238 [profile.displayName, email, refreshToken, null, null]
239 );
240 user = newUserResult.rows[0];
241 }
242
243 // Include userid in the user object
244 if (user) {
245
246 return done(null, { ...user, userid: user.userid, email: user.email, username: user.name });
247
248 } else {
249 return done(null, false, { message: 'Unable to retrieve user id.' });
250 }
251 } catch (error) {
252 return done(error);
253 }
254
255 }
256));
257
258
259 passport.serializeUser((user, done) => {
260 done(null, user.userid);
261});
262
263passport.deserializeUser((userid, done) => {
264 pool.query('SELECT * FROM users WHERE userid = $1', [userid], (err, results) => {
265 if (err) {
266 return done(err);
267 }
268 done(null, results.rows[0]);
269 });
270});
271
272};
273
274const login = (passport) => (req, res, next) => {
275 if (req.isAuthenticated()) {
276 return res.status(400).send('You are already logged in.');
277 }
278
279 passport.authenticate('local', (err, user, info) => {
280 if (err) {
281 return next(err);
282 }
283 if (!user) {
284 return res.status(401).send('Authentication failed');
285 }
286 req.login(user, (loginErr) => {
287 if (loginErr) {
288 return next(loginErr);
289 }
290 return res.status(200).json({ message: 'Authentication successful', user: { name: user.name, email: user.email, userid: user.userid } });
291 });
292 })(req, res, next);
293};
294
295const logout = (req, res, next) => {
296 if (!req.isAuthenticated()) {
297 return res.status(400).send('No user to log out.');
298 }
299
300 // Destroy the session on the server-side
301 req.session.destroy((err) => {
302 if (err) {
303 return res.status(500).json({ message: 'Logout failed' });
304 }
305
306 // Remove the session record from the database
307 pool.query('DELETE FROM session WHERE sid = $1', [req.sessionID], (err, result) => {
308 if (err) {
309 console.error('Error deleting session from database:', err);
310 // You might want to handle this error differently in production
311 }
312 res.status(200).json({ message: 'Logged out successfully' });
313 });
314 });
315};
316
317
318const authenticateToken = (req, res, next) => {
319 const token = req.header('Authorization');
320
321 if (!token) {
322 return res.status(401).json({ message: 'Unauthorized' });
323 }
324
325 jwt.verify(token, secretKey, (err, user) => {
326 if (err) {
327 return res.status(403).json({ message: 'Invalid token' });
328 }
329
330 req.user = user; // Set the authenticated user in the request object
331 next();
332 });
333};
334
335
336const logoutPage = (req, res) => {
337 res.send('logout page');
338};
339
340module.exports = {
341 initializePassport,
342 login,
343 logout,
344 logoutPage,
345 authenticateToken
346};
347const express = require('express');
348const router = express.Router();
349const passport = require('passport');
350const authController = require('../controllers/authController');
351const isAuthenticated = require('../middleware/isAuthenticated');
352const isAuthorised = require('../middleware/isAuthorised');
353
354router.post('/login', authController.login(passport));
355router.post('/logout', isAuthenticated, authController.logout);
356router.get('/logoutPage', authController.logoutPage);
357
358module.exports = router;
359
360
361//controllers\userController.js
362const Joi = require('joi');
363const bcrypt = require('bcrypt');
364const pool = require('../config/dbConfig'); // Adjusted path
365const isAuthenticated = require('../middleware/isAuthenticated');
366
367const userSchema = Joi.object({
368 name: Joi.string().alphanum().min(3).max(30).required(),
369 email: Joi.string().email().required(),
370 password: Joi.string().min(5).required(),
371 address: Joi.string().required(),
372 phonenumber: Joi.string().pattern(new RegExp('^[0-9+\\-\\s]+$')).required()
373});
374
375const register = async (req, res) => {
376 const { error, value } = userSchema.validate(req.body);
377 if (error) {
378 return res.status(400).send(error.details[0].message);
379 }
380
381 try {
382 const { name, email, password, address, phonenumber } = value;
383 const existingUser = await pool.query("SELECT * FROM users WHERE email = $1", [email]);
384 if (existingUser.rows.length > 0) {
385 return res.status(400).send("User already exists.");
386 }
387
388 const salt = await bcrypt.genSalt(10);
389 const hashedPassword = await bcrypt.hash(password, salt);
390
391 const newUser = await pool.query(
392 "INSERT INTO users (name, email, password, address, phonenumber) VALUES ($1, $2, $3, $4, $5) RETURNING *",
393 [name, email, hashedPassword, address, phonenumber]
394 );
395
396 const userid = newUser.rows[0].userid;
397
398 await pool.query(
399 "INSERT INTO carts (userid, totalprice) VALUES ($1, 0)",
400 [userid]
401 );
402
403 res.status(201).send("User registered successfully and cart created");
404 } catch (err) {
405 console.error(err.message);
406 res.status(500).send("Server error");
407 }
408};
409
410const getUserById = async (req, res) => {
411 const userid = req.user.userid;
412 try {
413 // Check if req.user exists and if the userid matches the requested userid
414 if (!req.params || parseInt(req.user.userid) !== parseInt(userid)) {
415 return res.status(403).send("Not authorized to view other users' accounts");
416 }
417 const result = await pool.query('SELECT name, email, address, phonenumber, userid FROM users WHERE userid = $1', [userid]);
418 if (result.rows.length > 0) {
419 res.json(result.rows[0]);
420 } else {
421 res.status(404).send('User not found');
422 }
423 } catch (err) {
424 console.error('Error in getUserById:', err.message);
425 res.status(500).send('Internal Server Error: ' + err.message);
426 }
427};
428
429
430const updateUser = async (req, res) => {
431 const userid = req.user.userid;
432 const { name, email, password, address, phonenumber } = req.body;
433
434 if (!userid) {
435 return res.status(401).send("User not authenticated");
436 }
437
438 try {
439 if (!req.params || parseInt(req.user.userid) !== parseInt(userid)) {
440 return res.status(403).send("Not authorized to change other users' accounts");
441 }
442
443 let hashedPassword;
444 if (password) {
445 const salt = await bcrypt.genSalt(10);
446 hashedPassword = await bcrypt.hash(password, salt);
447 } else {
448 // Fetch current password if not changing
449 const currentUser = await pool.query('SELECT password FROM users WHERE userid = $1', [userid]);
450 hashedPassword = currentUser.rows[0].password;
451 }
452
453 const result = await pool.query(
454 'UPDATE users SET name = $1, email = $2, password = $3, address = $4, phonenumber = $5 WHERE userid = $6 RETURNING *',
455 [name, email, hashedPassword, address, phonenumber, parseInt(userid)]
456 );
457
458 if (result.rows.length > 0) {
459 res.json(result.rows[0]);
460 } else {
461 res.status(404).send('User not found');
462 }
463 } catch (err) {
464 console.error('Error in updateUser:', err.message);
465 res.status(500).send('Internal Server Error');
466 }
467};
468
469
470async function getUserCurrentPassword(userid) {
471 // Function to get the current password from the database
472 const result = await pool.query('SELECT password FROM users WHERE userid = $1', [userid]);
473 return result.rows[0].password;
474}
475
476const deleteUser = async (req, res) => {
477 const { userid } = req.params;
478 try {
479 if (!req.user || parseInt(req.user.userid) !== parseInt(userid)) {
480 return res.status(403).send("Not authorized to delete other users' accounts");
481 }
482 await pool.query('DELETE FROM users WHERE userid = $1', [userid]);
483 res.status(204).send();
484 } catch (err) {
485 res.status(500).send(err.message);
486 }
487};
488
489const checkAuth = (req, res) => {
490 if (req.isAuthenticated()) {
491 // Assuming req.user contains user details after authentication
492 res.json({ isAuthenticated: true, user: req.user });
493 } else {
494 res.json({ isAuthenticated: false });
495 }
496};
497
498module.exports = {
499 register,
500 getUserById,
501 updateUser,
502 deleteUser,
503 checkAuth
504};
505// routes\userRoutes.js
506const express = require('express');
507const router = express.Router();
508const userController = require('../controllers/userController');
509const isAuthenticated = require('../middleware/isAuthenticated');
510const isAuthorised = require('../middleware/isAuthorised');
511
512
513router.post('/register', userController.register);
514router.get('/users/:userid',isAuthenticated, userController.getUserById);
515router.get('/users/user-profile/:userid',isAuthenticated, userController.getUserById);
516router.put('/users/:userid',isAuthenticated, userController.updateUser);
517router.delete('/users/:userid',isAuthenticated, userController.deleteUser);
518router.get('/check-auth',isAuthenticated, userController.checkAuth);
519
520module.exports = router;
521// AuthCheck.js
522import { useEffect } from 'react';
523import { checkAuth } from '../../services/authServices';
524
525const AuthCheck = () => {
526 useEffect(() => {
527 checkAuth();
528 }, []);
529
530 return null; // This component doesn't render anything
531};
532
533export default AuthCheck;
534
535// LoginPage.js
536import React, { useState, useEffect } from 'react';
537import { useSelector, useDispatch } from 'react-redux';
538import { useNavigate } from 'react-router-dom';
539import { login } from '../../services/authServices';
540import { loginSuccess } from '../../store/actions/authActions';
541import axios from 'axios';
542import './LoginPage.css'
543
544const LoginPage = () => {
545 const [credentials, setCredentials] = useState({ email: '', password: '' });
546 const navigate = useNavigate();
547 const dispatch = useDispatch();
548 const isAuthenticated = useSelector(state => state.auth.isAuthenticated);
549
550 useEffect(() => {
551 const getGoogleLoginToken = () => {
552 const urlParams = new URLSearchParams(window.location.search);
553 return urlParams.get('token');
554 };
555
556 const handleGoogleLogin = async () => {
557 const googleLoginToken = getGoogleLoginToken();
558 if (googleLoginToken) {
559 try {
560 const response = await axios.get(`${process.env.REACT_APP_BACKEND_URL}/auth/google/callback?token=${googleLoginToken}`);
561 const { name, userid, email } = response.data.user;
562 dispatch(loginSuccess(name, userid, email));
563 navigate('/products');
564 } catch (error) {
565 console.error('Error handling Google login:', error);
566 }
567 }
568};
569
570 if (isAuthenticated) {
571 navigate('/products');
572 } else {
573 handleGoogleLogin();
574 }
575 }, [isAuthenticated, navigate, dispatch]);
576
577
578 const handleChange = (e) => {
579 setCredentials({ ...credentials, [e.target.name]: e.target.value });
580 };
581
582 const handleSubmit = async (e) => {
583 e.preventDefault();
584 login(credentials); // Using the authService's login function
585 };
586
587 return (
588 <div className="login-container">
589 <h2>Login</h2>
590 <form onSubmit={handleSubmit} className="login-form">
591 <input
592 type="email"
593 name="email"
594 value={credentials.email}
595 onChange={handleChange}
596 placeholder="Email"
597 required
598 />
599 <input
600 type="password"
601 name="password"
602 value={credentials.password}
603 onChange={handleChange}
604 placeholder="Password"
605 required
606 />
607 <button type="submit">Login</button>
608 </form>
609 <div className="google-login-button">
610 <a href={`${process.env.REACT_APP_BACKEND_URL}/auth/google`}>
611 <span>Login with Google</span>
612 </a>
613 </div>
614 <p>
615 Don't have an account? <a href="/register">Register</a>
616 </p>
617 </div>
618 );
619};
620
621export default LoginPage;
622
623// LogoutPage.js
624import React from 'react';
625import { useNavigate } from 'react-router-dom';
626import axios from 'axios';
627import './LogoutPage.css';
628
629const LogoutPage = ({ onLogout }) => {
630 const navigate = useNavigate();
631
632 const handleLogout = async () => {
633 try {
634 const response = await axios.post(`${process.env.REACT_APP_BACKEND_URL}/logout`, {}, { withCredentials: true });
635 if (response.status === 200) {
636 onLogout();
637 navigate('/login');
638 console.log('Successfully logged out!')
639 } else {
640 console.error('Logout failed:', response.data.message);
641 }
642 } catch (error) {
643 console.error('Logout error:', error.response.data.message);
644 }
645};
646
647
648 return (
649 <div className="logout-container">
650 <h2>Are you sure you want to logout?</h2>
651 <button onClick={handleLogout} className="logout-button">Logout</button>
652 </div>
653);
654};
655
656export default LogoutPage;
657//view\src\components\auth\RegisterPage.js
658import React, { useState } from 'react';
659import { useNavigate } from 'react-router-dom';
660import axios from 'axios';
661import './RegisterPage.css';
662
663const RegisterPage = () => {
664 const [formData, setFormData] = useState({
665 name: '',
666 email: '',
667 password: '',
668 address: '',
669 phonenumber: ''
670 });
671 const navigate = useNavigate();
672
673 const handleChange = (e) => {
674 setFormData({ ...formData, [e.target.name]: e.target.value });
675 };
676
677 const handleSubmit = async (e) => {
678 e.preventDefault();
679 try {
680 const url = `${process.env.REACT_APP_BACKEND_URL}/register`;
681 const response = await axios.post(url, formData);
682 console.log(response.data);
683 navigate('/login');
684 } catch (error) {
685 if (error.response) {
686 // The request was made and the server responded with a status code
687 // that falls out of the range of 2xx
688 console.error('Error data:', error.response.data);
689 console.error('Error status:', error.response.status);
690 } else {
691 // Something happened in setting up the request that triggered an Error
692 console.error('Error message:', error.message);
693 }
694
695
696 }
697 };
698
699 return (
700 <div className="register-container">
701 <h2>Register</h2>
702 <form onSubmit={handleSubmit} className="register-form">
703 <input
704 type="text"
705 name="name"
706 value={formData.name}
707 onChange={handleChange}
708 placeholder="Name"
709 required
710 />
711 <input
712 type="email"
713 name="email"
714 value={formData.email}
715 onChange={handleChange}
716 placeholder="Email"
717 required
718 />
719 <input
720 type="password"
721 name="password"
722 value={formData.password}
723 onChange={handleChange}
724 placeholder="Password"
725 required
726 />
727 <input
728 type="text"
729 name="address"
730 value={formData.address}
731 onChange={handleChange}
732 placeholder="Address"
733 required
734 />
735 <input
736 type="text"
737 name="phonenumber"
738 value={formData.phonenumber.toString()}
739 onChange={handleChange}
740 placeholder="Phone Number"
741 required
742 />
743 <button type="submit">Register</button>
744 <a href={`${process.env.REACT_APP_BACKEND_URL}/auth/google`} className="google-auth-button">
745 Register with Google
746 </a>
747 <h3>
748 Already have an account?
749 </h3>
750 <p>
751 <a href="/login" className="login-link-button">Login</a>
752 </p>
753
754 </form>
755
756 </div>
757 );
758};
759
760export default RegisterPage;
761import axios from 'axios';
762
763// Set the default base URL for your API
764axios.defaults.baseURL = `${process.env.REACT_APP_BACKEND_URL}`;
765
766// Function to set the authentication token in the Axios header
767const setAuthToken = (token) => {
768 if (token) {
769 axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
770 } else {
771 delete axios.defaults.headers.common['Authorization'];
772 }
773};
774
775export default setAuthToken;
776
777// services/authServices.js
778import axios from 'axios';
779import { store } from '../store/store';
780import { loginSuccess, logout } from '../store/actions/authActions';
781import { fetchCartItems } from '../store/actions/cartActions'; // Import the action
782
783
784const login = async (credentials) => {
785 try {
786 const response = await axios.post(`${process.env.REACT_APP_BACKEND_URL}/login`, credentials, { withCredentials: true });
787 const { name, userid, email } = response.data.user;
788 if (name && userid !== undefined) {
789 console.log(store.dispatch(loginSuccess(name, userid, email)))
790 store.dispatch(loginSuccess(name, userid, email), );
791 store.dispatch(fetchCartItems()); // Fetch cart items after successful login
792 } else {
793 console.error('Login failed: User ID is missing in the response');
794 }
795 } catch (error) {
796 console.error('Login error:', error);
797 }
798};
799
800
801const checkAuth = async () => {
802 try {
803 const response = await axios.get(`${process.env.REACT_APP_BACKEND_URL}/check-auth`, { withCredentials: true });
804 const userData = response.data.user;
805 if (response.data.isAuthenticated && userData && userData.email !== undefined) {
806 store.dispatch(loginSuccess(userData.name, userData.userid, userData.email));
807 store.dispatch(fetchCartItems());
808 } else {
809 store.dispatch(logout());
810 }
811 } catch (error) {
812 console.error('Error checking authentication:', error);
813 }
814};
815
816export { login, checkAuth };
817
818//view\src\store\actions\authActions.js
819export const loginSuccess = (username, userid, email) => {
820 return {
821 type: 'LOGIN_SUCCESS',
822 payload: { username, userid, email }
823 };
824};
825
826export const setAuth = (isAuthenticated, username, userid, email, userNeedsProfileCompletion) => {
827 return {
828 type: 'SET_AUTH',
829 payload: { isAuthenticated, username, userid, email, userNeedsProfileCompletion }
830 };
831};
832
833
834export const logout = () => ({ type: 'LOGOUT' });
835export const registerSuccess = (username) => ({ type: 'REGISTER_SUCCESS', payload: username });
836
837//view\src\store\actions\userActions.js
838export const REGISTER_REQUEST = 'REGISTER_REQUEST';
839export const REGISTER_SUCCESS = 'REGISTER_SUCCESS';
840export const REGISTER_FAILURE = 'REGISTER_FAILURE';
841
842// Action Creators
843export const registerRequest = () => ({ type: REGISTER_REQUEST });
844export const registerSuccess = (username) => ({ type: REGISTER_SUCCESS, payload: username });
845export const registerFailure = (error) => ({ type: REGISTER_FAILURE, payload: error });
846
847// src/reducers/authReducer.js
848const initialState = {
849 isAuthenticated: false,
850 userid: null,
851 username: '',
852 email: '',
853 userNeedsProfileCompletion: false
854};
855
856export default function authReducer(state = initialState, action) {
857 console.log('Dispatched Action:', action);
858
859 switch (action.type) {
860 case 'LOGIN_SUCCESS':
861 console.log('LOGIN_SUCCESS payload:', action.payload);
862 return {
863 ...state,
864 isAuthenticated: true,
865 userid: action.payload.userid,
866 username: action.payload.username,
867 email: action.payload.email
868 };
869 case 'SET_AUTH':
870 return {
871 ...state,
872 isAuthenticated: action.payload.isAuthenticated,
873 userid: action.payload.userid,
874 username: action.payload.username,
875 email: action.payload.email,
876 userNeedsProfileCompletion: action.payload.userNeedsProfileCompletion
877 };
878 case 'LOGOUT':
879 return initialState;
880 default:
881 return state;
882 }
883}
884
885
886// src/reducers/userReducer.js
887const initialState = {
888 isLoggedIn: false,
889 userid: null,
890 email: ''
891};
892
893const userReducer = (state = initialState, action) => {
894 switch (action.type) {
895 case 'LOGIN':
896 return {
897 ...state,
898 isLoggedIn: true,
899 userid: action.payload.userid,
900 email: action.payload.email
901 };
902 case 'LOGOUT':
903 return {
904 ...state,
905 isLoggedIn: false,
906 userid: null
907 };
908 default:
909 return state;
910 }
911};
912
913export default userReducer;
914
915// App.js
916import React, { useEffect } from 'react';
917import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
918import { Provider, useSelector, useDispatch } from 'react-redux';
919import { store } from './store/store';
920import axios from 'axios';
921
922import LoginPage from './components/auth/LoginPage';
923import LogoutPage from './components/auth/LogoutPage';
924import RegisterPage from './components/auth/RegisterPage';
925import ProfileCompletion from './components/users/ProfileCompletion';
926import UserProfile from './components/users/UserProfile';
927import ProductsList from './components/products/ProductsList';
928import ProductDetailsPage from './components/products/ProductDetailsPage';
929import Cart from './components/cart/Cart';
930import Checkout from './components/checkout/Checkout';
931import OrderHistory from './components/orders/OrderHistory';
932import Header from './components/layout/Header';
933
934
935import { loginSuccess, logout } from './store/actions/authActions';
936
937const App = () => {
938 const dispatch = useDispatch();
939 const { isAuthenticated, username } = useSelector(state => state.auth);
940
941 useEffect(() => {
942 const checkUserAuthentication = async () => {
943 try {
944 const response = await axios.get(`${process.env.REACT_APP_BACKEND_URL}/check-auth`, { withCredentials: true })
945 if(response.data.isAuthenticated) {
946 dispatch(loginSuccess(response.data.user.name, response.data.user.userid));
947 } else {
948 dispatch(logout());
949 }
950 } catch (error) {
951 console.error('Error checking authentication:', error);
952 }
953 };
954
955 checkUserAuthentication();
956 }, [dispatch]);
957
958
959
960 const setAuthToken = (token) => {
961 if (token) {
962 axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
963
964 } else {
965 delete axios.defaults.headers.common['Authorization'];
966 }
967 };
968
969 const handleLogin = (user) => {
970 setAuthToken(user.token);
971 dispatch(loginSuccess(user.name, user.userid, user.email));
972 };
973
974 const handleLogout = () => {
975 setAuthToken(null);
976 dispatch(logout());
977 };
978
979const url = `${process.env.REACT_APP_BACKEND_URL}/products`;
980console.log("Request URL:", url);
981
982
983
984 return (
985 <Provider store={store}>
986 <Router>
987 <Header isAuthenticated={isAuthenticated} username={username} />
988 <Routes>
989 <Route path="/" element={<ProductsList />} />
990 <Route path="/login" element={<LoginPage onLogin={handleLogin} />} />
991 <Route path="/logout" element={<LogoutPage onLogout={handleLogout} />} />
992 <Route path="/register" element={<RegisterPage />} />
993 <Route path="/products" element={<ProductsList />} />
994 <Route path="/product/:productid" element={<ProductDetailsPage />} />
995 <Route path="/cart" element={<Cart />} />
996 <Route path="/checkout" element={<Checkout />} />
997 <Route path="/order-history" element={<OrderHistory />} />
998 <Route path="/user-profile" element={<UserProfile />} />
999 <Route path="/user-profile/:userid" element={<UserProfile />} />
1000 <Route path="/profilecompletion/:userid" element={<ProfileCompletion />} />
1001 </Routes>
1002 </Router>
1003 </Provider>
1004 );
1005}
1006
1007export default App;
1008import React from 'react';
1009import { createRoot } from 'react-dom/client';
1010import { Provider } from 'react-redux';
1011import { PersistGate } from 'redux-persist/integration/react';
1012import { store, persistor } from './store/store'; // Adjust path as necessary
1013import App from './App';
1014
1015const container = document.getElementById('root');
1016const root = createRoot(container);
1017
1018root.render(
1019 <Provider store={store}>
1020 <PersistGate loading={null} persistor={persistor}>
1021 <App />
1022 </PersistGate>
1023 </Provider>
1024);
1025
1026// services/authServices.js
1027import axios from 'axios';
1028import { store } from '../store/store';
1029import { loginSuccess, logout } from '../store/actions/authActions';
1030import { fetchCartItems } from '../store/actions/cartActions'; // Import the action
1031
1032
1033const login = async (credentials) => {
1034 try {
1035 const response = await axios.post(`${process.env.REACT_APP_BACKEND_URL}/login`, credentials, { withCredentials: true });
1036 const { name, userid, email } = response.data.user;
1037 if (name && userid !== undefined) {
1038 console.log(store.dispatch(loginSuccess(name, userid, email)))
1039 store.dispatch(loginSuccess(name, userid, email), );
1040 store.dispatch(fetchCartItems()); // Fetch cart items after successful login
1041 } else {
1042 console.error('Login failed: User ID is missing in the response');
1043 }
1044 } catch (error) {
1045 console.error('Login error:', error);
1046 }
1047};
1048
1049
1050const checkAuth = async () => {
1051 try {
1052 const response = await axios.get(`${process.env.REACT_APP_BACKEND_URL}/check-auth`, { withCredentials: true });
1053 const userData = response.data.user;
1054 if (response.data.isAuthenticated && userData && userData.email !== undefined) {
1055 store.dispatch(loginSuccess(userData.name, userData.userid, userData.email));
1056 store.dispatch(fetchCartItems());
1057 } else {
1058 store.dispatch(logout());
1059 }
1060 } catch (error) {
1061 console.error('Error checking authentication:', error);
1062 }
1063};
1064
1065export { login, checkAuth };
1066
1067
1068
1069//.env file
1070DB_USER=postgres
1071DB_PASSWORD=falloutX11
1072DB_HOST=localhost
1073DB_PORT=5432
1074DB_DATABASE=ecommerce
1075SECRET=r2smw2u2
1076JWT_SECRET=r2smw2u2
1077REFRESH_TOKEN_SECRET=r2smw2u2
1078GOOGLE_CLIENT_ID=445920566732-otsajr3r7i3uv7vk9r1vtub7fmtri0f7.apps.googleusercontent.com
1079GOOGLE_CLIENT_SECRET=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
1080LOCALHOST=http://localhost:3000
1081CHATGPT_API_VSCODE=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
1082REACT_APP_STRIPE_SECRET_KEY=sk_test_51Ao5lVAsQsqu4WY6X8Y5NFKELLsdLY5s48FGfJqhtb1v1UTs1ROQZaWgRbYyaxMOJtGaudNMCCdCHlghYxavBWJL00T2jBMSd3
1083REACT_APP_STRIPE_PUBLIC_KEY=pk_test_51Ao5lVAsQsqu4WY6xWkHFFPUGiyiWKb5Ap9boxONCD33jRN4vuYkdoXo4XQP2FMZuq85y7UUTQbXrpAwtW4Y3Hhr00isSg2ra1
1084REACT_APP_BACKEND_URL=https://e-shop-backend-plfz.onrender.com
1085REACT_APP_FRONTEND_URL=https://e-shop-frontend-8ylf.onrender.com
1086
1087# REACT_APP_SUPABASE_URL=https://dgxfyraurqoackwkaxoe.supabase.co
1088# REACT_APP_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRneGZ5cmF1cnFvYWNrd2theG9lIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDc1ODk2NzcsImV4cCI6MjAyMzE2NTY3N30.BqxexaEdGGO2DLP2hfBHeNVBPH8vcVbOUt8rcnZdgok
1089
1090
1091