├── .eslintrc.json
├── .gitignore
├── README.md
├── components
├── Footer.js
├── Header.js
├── Layout.js
└── Todo.js
├── context
└── AuthContext.js
├── firebase.js
├── next.config.js
├── package-lock.json
├── package.json
├── pages
├── _app.js
├── _document.js
├── api
│ └── hello.js
├── index.js
├── login.js
└── userDashboard.js
├── postcss.config.js
├── public
└── images
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── dog.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ └── site.webmanifest
├── styles
├── Home.module.css
└── globals.css
└── tailwind.config.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 |
17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
18 |
19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20 |
21 | ## Learn More
22 |
23 | To learn more about Next.js, take a look at the following resources:
24 |
25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27 |
28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29 |
30 | ## Deploy on Vercel
31 |
32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33 |
34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
35 |
--------------------------------------------------------------------------------
/components/Footer.js:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 | import React from "react";
3 |
4 | const Footer = () => {
5 | return (
6 |
7 |
11 | {" "}
12 |
13 |
14 |
15 |
16 |
17 | {" "}
18 |
19 |
20 | );
21 | };
22 |
23 | export default Footer;
24 |
--------------------------------------------------------------------------------
/components/Header.js:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 | import React, { useState } from "react";
3 | import { useAuth } from "../context/AuthContext";
4 |
5 | const Header = () => {
6 | const { currentUser } = useAuth();
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | RTTDA
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 | };
23 |
24 | export default Header;
25 |
--------------------------------------------------------------------------------
/components/Layout.js:
--------------------------------------------------------------------------------
1 | import Footer from "./Footer";
2 | import Header from "./Header";
3 |
4 | export default function Layout(props) {
5 | const { children } = props;
6 | return (
7 | <>
8 |
9 |
10 | {children}
11 |
12 |
13 | >
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/components/Todo.js:
--------------------------------------------------------------------------------
1 | import { deleteDoc, doc, serverTimestamp, setDoc } from "firebase/firestore";
2 | import React, { useRef, useState } from "react";
3 | import { db } from "../firebase";
4 |
5 | const Todo = ({ todo, id }) => {
6 | const [edit, setEdit] = useState(false);
7 | const [edittedTodo, setEdditedTodo] = useState(todo);
8 | const inputRef = useRef(null);
9 |
10 | function setWritingCursor() {
11 | setEdit(true);
12 | // ? setting the writing cursor to the last word of the input tag
13 | setTimeout(() => {
14 | if (inputRef.current) {
15 | inputRef.current.focus();
16 | inputRef.current.selectionStart = inputRef.current.value.length;
17 | inputRef.current.selectionEnd = inputRef.current.value.length;
18 | }
19 | }, 0); // add a delay of 1 second
20 | }
21 |
22 | async function editTodo() {
23 | // ? logic to make changes to the firestore db
24 | await setDoc(
25 | doc(db, "todos", id),
26 | {
27 | task: edittedTodo,
28 | },
29 | { merge: true }
30 | );
31 | setEdit(false);
32 | }
33 |
34 | async function deleteTodo() {
35 | try {
36 | await deleteDoc(doc(db, "todos", id));
37 | } catch (error) {
38 | console("error while deleting: ", error);
39 | }
40 | }
41 |
42 | return (
43 | <>
44 |
45 | {edit ? (
46 |
setEdditedTodo(e.target.value)}
54 | />
55 | ) : (
56 |
62 | {todo}
63 |
64 | )}
65 |
66 | {/* tools div */}
67 |
68 | {edit ? (
69 |
73 | ) : (
74 |
78 | )}{" "}
79 |
83 |
84 |
85 | >
86 | );
87 | };
88 |
89 | export default Todo;
90 |
--------------------------------------------------------------------------------
/context/AuthContext.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState, useEffect, useRef } from "react";
2 | import { auth, db } from "../firebase";
3 | import {
4 | signInWithEmailAndPassword,
5 | createUserWithEmailAndPassword,
6 | signOut,
7 | onAuthStateChanged,
8 | } from "firebase/auth";
9 | import { doc, getDoc } from "firebase/firestore";
10 |
11 | const AuthContext = React.createContext();
12 |
13 | export function useAuth() {
14 | return useContext(AuthContext);
15 | }
16 |
17 | export function AuthProvider({ children }) {
18 | const [currentUser, setCurrentUser] = useState(null);
19 | const [loading, setLoading] = useState(true);
20 | const userInfo = useRef();
21 |
22 | async function signUp(email, password) {
23 | await createUserWithEmailAndPassword(auth, email, password);
24 | return;
25 | }
26 | async function login(email, password) {
27 | await signInWithEmailAndPassword(auth, email, password);
28 | return;
29 | }
30 | async function logout() {
31 | await signOut(auth);
32 | return;
33 | }
34 |
35 | useEffect(() => {
36 | const unsubscribe = onAuthStateChanged(auth, async (user) => {
37 | setCurrentUser(user);
38 | setLoading(false);
39 | });
40 | return unsubscribe; // * this is the cleanup function of the useeffect
41 | }, []);
42 |
43 | const value = {
44 | currentUser,
45 | login,
46 | signUp,
47 | logout,
48 | userInfo,
49 | };
50 |
51 | return (
52 |
53 | {/* Below code means that return the children iff the loading state is false */}
54 | {!loading && children}
55 |
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/firebase.js:
--------------------------------------------------------------------------------
1 | import { initializeApp } from "firebase/app";
2 | import { getAuth } from "firebase/auth";
3 | import { getFirestore } from "firebase/firestore";
4 |
5 | const firebaseConfig = {
6 | apiKey: process.env.NEXT_PUBLIC_APIKEY,
7 | authDomain: process.env.NEXT_PUBLIC_AUTHDOMAIN,
8 | projectId: process.env.NEXT_PUBLIC_PROJECTID,
9 | storageBucket: process.env.NEXT_PUBLIC_STORAGEBUCKET,
10 | messagingSenderId: process.env.NEXT_PUBLIC_MESSAGINGSENDERID,
11 | appId: process.env.NEXT_PUBLIC_APPID,
12 | };
13 |
14 | const app = initializeApp(firebaseConfig);
15 | export const auth = getAuth(app);
16 | export const db = getFirestore(app);
17 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | swcMinify: true,
5 | eslint: {
6 | ignoreDuringBuilds: true,
7 | },
8 | };
9 |
10 | module.exports = nextConfig;
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rttda",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "firebase": "^9.17.1",
13 | "next": "13.1.6",
14 | "react": "18.2.0",
15 | "react-beautiful-dnd": "^13.1.1",
16 | "react-dom": "18.2.0",
17 | "react-icons": "^4.7.1"
18 | },
19 | "devDependencies": {
20 | "autoprefixer": "^10.4.13",
21 | "eslint": "8.34.0",
22 | "eslint-config-next": "13.1.6",
23 | "postcss": "^8.4.21",
24 | "tailwind-scrollbar": "^2.1.0",
25 | "tailwindcss": "^3.2.6"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import Layout from "../components/Layout";
2 | import { AuthProvider } from "../context/AuthContext";
3 | import "../styles/globals.css";
4 |
5 | function MyApp({ Component, pageProps }) {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default MyApp;
16 |
--------------------------------------------------------------------------------
/pages/_document.js:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from "next/document";
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
7 | {/* GOOGLE FONTS MONSERRAT FAMILY IMPORT */}
8 |
9 |
10 |
14 | {/* FAVICON *** Not working right now*/}
15 |
20 |
26 |
32 |
33 | {/* FONT AWESOME ICONS CDN IMPORT */}
34 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/pages/api/hello.js:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | export default function handler(req, res) {
4 | res.status(200).json({ name: 'John Doe' })
5 | }
6 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 | import { useEffect, useState } from "react";
3 | import Todo from "../components/Todo";
4 | import { db } from "../firebase";
5 | import {
6 | collection,
7 | addDoc,
8 | serverTimestamp,
9 | onSnapshot,
10 | query,
11 | where,
12 | orderBy,
13 | } from "firebase/firestore";
14 | import { useAuth } from "../context/AuthContext";
15 | import { useRouter } from "next/router";
16 | import { AiOutlineLoading3Quarters } from "react-icons/ai";
17 | import { VscLoading } from "react-icons/vsc";
18 | import thinkDog from "../public/images/dog.png";
19 | import Image from "next/image";
20 |
21 | export default function Home() {
22 | const [todo, setTodo] = useState("");
23 | const [todos, setTodos] = useState([]);
24 | const { currentUser } = useAuth();
25 | const [loading, setLoading] = useState(false);
26 | const router = useRouter();
27 | const [todoLoading, setTodoLoading] = useState(false);
28 |
29 | async function handleToDoAdd() {
30 | setLoading(true);
31 | if (!todo) {
32 | return;
33 | }
34 | try {
35 | await addDoc(collection(db, "todos"), {
36 | task: todo,
37 | uid: currentUser.uid,
38 | timestamp: serverTimestamp(),
39 | });
40 | setLoading(false);
41 | } catch (error) {
42 | console.log("error in adding doc: ", error);
43 | }
44 | }
45 |
46 | {
47 | currentUser &&
48 | useEffect(() => {
49 | setTodoLoading(true);
50 | const unsubscribe = onSnapshot(
51 | query(
52 | collection(db, "todos"),
53 | where("uid", "==", currentUser?.uid),
54 | orderBy("timestamp", "desc")
55 | ),
56 | (snapshot) => {
57 | setTodos(snapshot.docs);
58 | setTodoLoading(false);
59 | }
60 | );
61 | return unsubscribe; // ? clean up function
62 | }, [db]);
63 | }
64 |
65 | // ! chat GPT code ---> helped a lot really(firebase indexing was causing issues)
66 | // useEffect(() => {
67 | // const unsubscribe = onSnapshot(collection(db, "todos"), (snapshot) => {
68 | // console.log(snapshot.docs);
69 | // setTodos(
70 | // snapshot.docs
71 | // .filter((doc) => doc.data().uid === currentUser.uid)
72 | // .sort((a, b) => b.data().timestamp - a.data().timestamp)
73 | // );
74 | // });
75 | // return unsubscribe; // ? clean up function
76 | // }, [db, currentUser.uid]);
77 |
78 | return (
79 | <>
80 |
81 | RTTDA
82 |
83 |
84 |
85 |
86 | {/* BELOW IS ADD TODO DIV */}
87 |
88 | setTodo(e.target.value)}
94 | />
95 |
109 |
110 |
117 | {/* TODOS DIV */}
118 | {todoLoading ? (
119 |
120 |
121 |
122 | ) : todos.length > 0 ? (
123 | todos.map((item) => {
124 | return (
125 |
126 | );
127 | })
128 | ) : (
129 |
130 |
131 | No Todos Yet
132 |
133 | )}
134 |
135 |
136 | >
137 | );
138 | }
139 |
--------------------------------------------------------------------------------
/pages/login.js:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 | import { useRouter } from "next/router";
3 | import React, { useState } from "react";
4 | import { useAuth } from "../context/AuthContext";
5 |
6 | const Login = () => {
7 | const [email, setEmail] = useState("");
8 | const [password, setPassword] = useState("");
9 | const [error, setError] = useState(null);
10 | const [isLoggingIn, setIsLoggingIn] = useState(true);
11 | const { login, signUp } = useAuth(); // ? using firebase login functions via the auth context
12 | const router = useRouter();
13 |
14 | async function handleSubmit(e) {
15 | e.preventDefault();
16 | if (!email || !password) {
17 | setError(
18 | !email && !password
19 | ? "Please enter email & password"
20 | : !email
21 | ? "Please enter email"
22 | : "Please enter password"
23 | );
24 | return;
25 | }
26 | if (isLoggingIn) {
27 | try {
28 | await login(email, password);
29 | setEmail("");
30 | setPassword("");
31 | router.push("/");
32 | } catch (error) {
33 | // ? the user will only reach this state if he or she is filling the wrong credentials
34 | setError("Incorrect email or password");
35 | }
36 | return;
37 | }
38 | // ? if user is not logging in it means that he is registering for the first time so he will signUp
39 | try {
40 | await signUp(email, password);
41 | setEmail("");
42 | setPassword("");
43 | router.push("/");
44 | } catch (error) {
45 | if (error.code == "auth/weak-password") {
46 | setError("Password length should be atleast 6");
47 | }
48 | }
49 | return;
50 | }
51 | return (
52 | <>
53 |
54 | RTTDA Login
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | {isLoggingIn ? "Login" : "Sign Up"}
63 |
64 | {error && (
65 |
66 | {error}
67 |
68 | )}
69 |
70 | {/* LOGIN WITH CREDENTIALS DIV */}
71 |
102 | {/* LOGIN WITH GOOGLE DIV */}
103 | {/*
104 | OR
105 |
108 |
*/}
109 | setIsLoggingIn(!isLoggingIn)}
111 | className="active:scale-105 duration-200 transition transform ease-in-out"
112 | >
113 | {isLoggingIn ? "Sign Up" : "Login"}
114 |
115 |
116 |
117 | >
118 | );
119 | };
120 |
121 | export default Login;
122 |
--------------------------------------------------------------------------------
/pages/userDashboard.js:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 | import { useRouter } from "next/router";
3 | import React from "react";
4 | import { useAuth } from "../context/AuthContext";
5 |
6 | const UserDashboard = () => {
7 | const router = useRouter();
8 | const { currentUser, logout } = useAuth();
9 | const email = currentUser?.email; // ? did this so as to remove flicker of the email when the user logs out
10 | return (
11 | <>
12 |
13 | RTTDA User Profile
14 |
15 |
16 |
17 | Signed in as: {email}
18 |
19 |
29 |
30 | >
31 | );
32 | };
33 |
34 | export default UserDashboard;
35 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/images/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-ansh-007/RTTDA/43ca6d5d01e9c99c6b8d4c465aa05fb81b5bbc81/public/images/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/images/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-ansh-007/RTTDA/43ca6d5d01e9c99c6b8d4c465aa05fb81b5bbc81/public/images/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/images/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-ansh-007/RTTDA/43ca6d5d01e9c99c6b8d4c465aa05fb81b5bbc81/public/images/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/images/dog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-ansh-007/RTTDA/43ca6d5d01e9c99c6b8d4c465aa05fb81b5bbc81/public/images/dog.png
--------------------------------------------------------------------------------
/public/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-ansh-007/RTTDA/43ca6d5d01e9c99c6b8d4c465aa05fb81b5bbc81/public/images/favicon-16x16.png
--------------------------------------------------------------------------------
/public/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-ansh-007/RTTDA/43ca6d5d01e9c99c6b8d4c465aa05fb81b5bbc81/public/images/favicon-32x32.png
--------------------------------------------------------------------------------
/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-ansh-007/RTTDA/43ca6d5d01e9c99c6b8d4c465aa05fb81b5bbc81/public/images/favicon.ico
--------------------------------------------------------------------------------
/public/images/site.webmanifest:
--------------------------------------------------------------------------------
1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
--------------------------------------------------------------------------------
/styles/Home.module.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-ansh-007/RTTDA/43ca6d5d01e9c99c6b8d4c465aa05fb81b5bbc81/styles/Home.module.css
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | * {
6 | font-family: "Montserrat", sans-serif;
7 | color: #a5a5a5;
8 | }
9 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./app/**/*.{js,ts,jsx,tsx}",
5 | "./pages/**/*.{js,ts,jsx,tsx}",
6 | "./components/**/*.{js,ts,jsx,tsx}",
7 |
8 | // Or if using `src` directory:
9 | "./src/**/*.{js,ts,jsx,tsx}",
10 | ],
11 | theme: {
12 | extend: {},
13 | },
14 | plugins: [require("tailwind-scrollbar")],
15 | };
16 |
--------------------------------------------------------------------------------