├── src
├── index.css
├── redux
│ ├── store.js
│ └── appSlice.js
├── components
│ ├── Body.jsx
│ ├── Login.jsx
│ ├── Messages.jsx
│ ├── Message.jsx
│ ├── Sidebar.jsx
│ ├── SendEmail.jsx
│ ├── Inbox.jsx
│ ├── Navbar.jsx
│ └── Mail.jsx
├── main.jsx
├── firebase.js
├── App.jsx
└── assets
│ └── react.svg
├── .firebaserc
├── postcss.config.js
├── .firebase
├── hosting.YnVpbGQ.cache
└── hosting.ZGlzdA.cache
├── vite.config.js
├── tailwind.config.js
├── firebase.json
├── .gitignore
├── index.html
├── README.md
├── .eslintrc.cjs
├── package.json
└── public
└── vite.svg
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "clone-6dd4f"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/.firebase/hosting.YnVpbGQ.cache:
--------------------------------------------------------------------------------
1 | index.html,1716703506255,171519f644167f1bc5a0a4c15052ae48817a7c7b1f802c2052f4ea8f3b37f6e3
2 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ["./src/**/*.{html,js,jsx}"],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import appSlice from "./appSlice";
3 |
4 | const store = configureStore({
5 | reducer:{
6 | app:appSlice
7 | }
8 | });
9 |
10 | export default store;
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "dist",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ],
9 | "rewrites": [
10 | {
11 | "source": "**",
12 | "destination": "/index.html"
13 | }
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/Body.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Sidebar from './Sidebar'
3 | import { Outlet } from 'react-router-dom'
4 | import Navbar from './Navbar'
5 |
6 | const Body = () => {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
15 | export default Body
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.firebase/hosting.ZGlzdA.cache:
--------------------------------------------------------------------------------
1 | index.html,1716704170440,100e2c331ea44f0c698222d72699dc06db4ed1e520a142d21b5de349d567fa92
2 | vite.svg,1712510425607,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7
3 | assets/index-C60g72fR.css,1716704170440,1db27413a037c5b6f43a37435d052453f13344215b1a49953d4d625c285192ba
4 | assets/index-FEP9XdV2.js,1716704170440,58740b64ff4dae2d28175522c68c5b53022707f1f1b45df3bffd0398ef0c4e8c
5 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Gmail
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/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 { Provider } from 'react-redux';
6 | import store from './redux/store.js';
7 |
8 | ReactDOM.createRoot(document.getElementById('root')).render(
9 |
10 |
11 |
12 |
13 | ,
14 | )
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react/jsx-no-target-blank': 'off',
16 | 'react-refresh/only-export-components': [
17 | 'warn',
18 | { allowConstantExport: true },
19 | ],
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/src/firebase.js:
--------------------------------------------------------------------------------
1 | import { initializeApp } from "firebase/app";
2 | import { getAnalytics } from "firebase/analytics";
3 | import { getDatabase } from "firebase/database";
4 | import { GoogleAuthProvider,getAuth } from "firebase/auth";
5 | import { getFirestore } from "firebase/firestore";
6 |
7 | const firebaseConfig = {
8 | apiKey: "AIzaSyCCxklo4ehV_I5NwZWRkDReg46I-3Rpo5A",
9 | authDomain: "clone-6dd4f.firebaseapp.com",
10 | projectId: "clone-6dd4f",
11 | storageBucket: "clone-6dd4f.appspot.com",
12 | messagingSenderId: "781876226205",
13 | appId: "1:781876226205:web:0d4463c344d70c0994cc74",
14 | measurementId: "G-ZT3MWT0RX8"
15 | };
16 |
17 | // Initialize Firebase
18 | const app = initializeApp(firebaseConfig);
19 | const analytics = getAnalytics(app);
20 | export const auth = getAuth();
21 | export const db = getFirestore(app);
22 | export const provider = new GoogleAuthProvider();
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gmailclone",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@reduxjs/toolkit": "^2.2.5",
14 | "firebase": "^10.12.1",
15 | "framer-motion": "^11.2.6",
16 | "react": "^18.2.0",
17 | "react-avatar": "^5.0.3",
18 | "react-dom": "^18.2.0",
19 | "react-google-button": "^0.8.0",
20 | "react-icons": "^5.2.1",
21 | "react-redux": "^9.1.2",
22 | "react-router-dom": "^6.23.1"
23 | },
24 | "devDependencies": {
25 | "@types/react": "^18.2.66",
26 | "@types/react-dom": "^18.2.22",
27 | "@vitejs/plugin-react": "^4.2.1",
28 | "autoprefixer": "^10.4.19",
29 | "eslint": "^8.57.0",
30 | "eslint-plugin-react": "^7.34.1",
31 | "eslint-plugin-react-hooks": "^4.6.0",
32 | "eslint-plugin-react-refresh": "^0.4.6",
33 | "postcss": "^8.4.38",
34 | "tailwindcss": "^3.4.3",
35 | "vite": "^5.2.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/redux/appSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const appSlice = createSlice({
4 | name: "app",
5 | initialState: {
6 | open: false,
7 | selectedMail: null,
8 | searchText: "",
9 | emails: null, // This might need to be initialized as an array or object depending on your application logic
10 | authUser: null
11 | },
12 | reducers: {
13 | setOpen: (state, action) => {
14 | state.open = action.payload;
15 | },
16 | setSelectedMail: (state, action) => {
17 | state.selectedMail = action.payload;
18 | },
19 | setSearchText: (state, action) => {
20 | state.searchText = action.payload;
21 | },
22 | setEmails: (state, action) => {
23 | state.emails = action.payload;
24 | },
25 | setAuthUser: (state, action) => {
26 | state.authUser = action.payload;
27 | }
28 | }
29 | });
30 |
31 | export const {
32 | setOpen,
33 | setSelectedMail,
34 | setSearchText,
35 | setEmails,
36 | setAuthUser
37 | } = appSlice.actions;
38 |
39 | export default appSlice.reducer;
40 |
--------------------------------------------------------------------------------
/src/components/Login.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { signInWithPopup } from 'firebase/auth';
3 | import { auth, provider } from '../firebase';
4 | import GoogleButton from 'react-google-button';
5 | import { useDispatch } from 'react-redux';
6 | import { setAuthUser } from '../redux/appSlice';
7 |
8 | const Login = () => {
9 |
10 | const dispatch = useDispatch();
11 |
12 | const signInWithGoogle = async () => {
13 | try {
14 | const result = await signInWithPopup(auth, provider);
15 | dispatch(setAuthUser({
16 | displayName: result.user.displayName,
17 | email: result.user.email,
18 | photoURL: result.user.photoURL
19 | }));
20 | } catch (error) {
21 | console.log(error);
22 | }
23 | }
24 | return (
25 |
26 |
27 |
LOGIN
28 |
29 |
30 |
31 | )
32 | }
33 |
34 | export default Login
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Messages.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import Message from './Message'
3 | import { collection, getDocs, onSnapshot, orderBy, query } from 'firebase/firestore';
4 | import { db } from '../firebase';
5 | import { useDispatch, useSelector } from 'react-redux';
6 | import { setEmails } from '../redux/appSlice';
7 |
8 | const Messages = () => {
9 | const { searchText, emails } = useSelector(store => store.app);
10 | const [filterEmail, setFilterEmail] = useState(emails);
11 | const dispatch = useDispatch();
12 |
13 | useEffect(() => {
14 | const q = query(collection(db, "emails"), orderBy('createdAt', 'desc'));
15 | const unsubscribe = onSnapshot(q, (snapshot) => {
16 | const allEmails = snapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id }));
17 | dispatch(setEmails(allEmails));
18 | });
19 |
20 | return () => unsubscribe(); // Cleanup function to unsubscribe when component unmounts
21 | }, []);
22 |
23 | useEffect(() => {
24 | const filteredEmail = emails?.filter((email) => {
25 | return email.subject.toLowerCase().includes(searchText.toLowerCase()) || email.to.toLowerCase().includes(searchText.toLowerCase()) || email.message.toLowerCase().includes(searchText.toLowerCase())
26 | });
27 | setFilterEmail(filteredEmail);
28 | }, [searchText, emails]);
29 |
30 | return (
31 |
32 | {
33 | filterEmail?.map((email) => )
34 | }
35 |
36 |
37 | )
38 | }
39 |
40 | export default Messages
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import Navbar from './components/Navbar';
2 | import Inbox from './components/Inbox';
3 | import SendEmail from './components/SendEmail';
4 | import { createBrowserRouter, RouterProvider } from 'react-router-dom';
5 | import Mail from './components/Mail';
6 | import Body from './components/Body';
7 | import { useDispatch, useSelector } from 'react-redux';
8 | import Login from './components/Login';
9 | import { useEffect } from 'react';
10 | import { auth } from './firebase';
11 | import { setAuthUser } from './redux/appSlice';
12 |
13 | const router = createBrowserRouter([
14 | {
15 | path: '/',
16 | element: