├── frontend ├── src │ ├── index.css │ ├── utils │ │ └── date.js │ ├── main.jsx │ ├── components │ │ ├── Input.jsx │ │ ├── FloatingShape.jsx │ │ ├── LoadingSpinner.jsx │ │ └── PasswordStrengthMeter.jsx │ ├── pages │ │ ├── LoginPage.jsx │ │ ├── DashboardPage.jsx │ │ ├── ResetPasswordPage.jsx │ │ ├── ForgotPasswordPage.jsx │ │ ├── SignUpPage.jsx │ │ └── EmailVerificationPage.jsx │ ├── store │ │ └── authStore.js │ └── App.jsx ├── postcss.config.js ├── vite.config.js ├── tailwind.config.js ├── .gitignore ├── index.html ├── .eslintrc.cjs ├── README.md ├── package.json └── public │ └── vite.svg ├── .env.example ├── backend ├── db │ └── connectDB.js ├── mailtrap │ ├── mailtrap.config.js │ ├── emails.js │ └── emailTemplates.js ├── utils │ └── generateTokenAndSetCookie.js ├── routes │ └── auth.route.js ├── middleware │ └── verifyToken.js ├── models │ └── user.model.js ├── index.js └── controllers │ └── auth.controller.js ├── .gitignore ├── package.json └── README.md /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vite.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | MONGO_URI=your_mongo_uri 2 | PORT=5000 3 | JWT_SECRET=your_jwt_secret 4 | NODE_ENV=development 5 | MAILTRAP_TOKEN=your_mailtrap_token 6 | MAILTRAP_ENDPOINT=your_mailtrap_endpoint 7 | 8 | CLIENT_URL=http://localhost:5173 -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /frontend/src/utils/date.js: -------------------------------------------------------------------------------- 1 | export const formatDate = (dateString) => { 2 | const date = new Date(dateString); 3 | if (isNaN(date.getTime())) { 4 | return "Invalid Date"; 5 | } 6 | 7 | return date.toLocaleString("en-US", { 8 | year: "numeric", 9 | month: "short", 10 | day: "numeric", 11 | hour: "2-digit", 12 | minute: "2-digit", 13 | hour12: true, 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /frontend/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | import "./index.css"; 5 | import { BrowserRouter } from "react-router-dom"; 6 | 7 | ReactDOM.createRoot(document.getElementById("root")).render( 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /backend/db/connectDB.js: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | export const connectDB = async () => { 4 | try { 5 | const conn = await mongoose.connect(process.env.MONGO_URI); 6 | console.log(`MongoDB Connected: ${conn.connection.host}`); 7 | } catch (error) { 8 | console.log("Error connection to MongoDB: ", error.message); 9 | process.exit(1); // 1 is failure, 0 status code is success 10 | } 11 | }; -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /backend/mailtrap/mailtrap.config.js: -------------------------------------------------------------------------------- 1 | import { MailtrapClient } from "mailtrap"; 2 | import dotenv from "dotenv"; 3 | dotenv.config(); 4 | 5 | const TOKEN = process.env.MAILTRAP_TOKEN; 6 | const ENDPOINT = process.env.MAILTRAP_ENDPOINT; 7 | 8 | export const mailtrapClient = new MailtrapClient({ 9 | endpoint: ENDPOINT, 10 | token: TOKEN, 11 | }); 12 | 13 | export const sender = { 14 | email: "hello@demomailtrap.co", 15 | name: "MERN_ADVANCED_AUTH", 16 | }; 17 | -------------------------------------------------------------------------------- /backend/utils/generateTokenAndSetCookie.js: -------------------------------------------------------------------------------- 1 | import jwt from "jsonwebtoken"; 2 | 3 | 4 | export const generateTokenAndSetCookie = (res, userId) => { 5 | const token = jwt.sign({ userId}, process.env.JWT_SECRET, { 6 | expiresIn: "7d", 7 | }); 8 | 9 | res.cookie("token", token, { 10 | httpOnly: true, 11 | secure: process.env.NODE_ENV === "production", 12 | sameSite: "strict", 13 | maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days 14 | }); 15 | 16 | return token; 17 | 18 | } -------------------------------------------------------------------------------- /frontend/src/components/Input.jsx: -------------------------------------------------------------------------------- 1 | const Input = ({ icon: Icon, ...props }) => { 2 | return ( 3 |
4 |
5 | 6 |
7 | 11 |
12 | ); 13 | }; 14 | export default Input; 15 | -------------------------------------------------------------------------------- /frontend/src/components/FloatingShape.jsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | 3 | const FloatingShape = ({ color, size, top, left, delay }) => { 4 | return ( 5 |