Skip to content

Commit 5ab3486

Browse files
committed
Add Main Project Files
0 parents  commit 5ab3486

33 files changed

+9391
-0
lines changed

.eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

.gitignore

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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

README.md

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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.

components/DocumentRow.js

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import Button from "@material-tailwind/react/Button";
2+
import Icon from "@material-tailwind/react/Icon";
3+
import { useRouter } from "next/router";
4+
import Dropdown from "@material-tailwind/react/Dropdown";
5+
import DropdownLink from "@material-tailwind/react/DropdownLink";
6+
import { useState } from "react";
7+
import Modal from "@material-tailwind/react/Modal";
8+
import ModalHeader from "@material-tailwind/react/ModalHeader";
9+
import ModalBody from "@material-tailwind/react/ModalBody";
10+
import ModalFooter from "@material-tailwind/react/ModalFooter";
11+
12+
function DocumentRow({ id, fileName, date, deleteDocument }) {
13+
const router = useRouter();
14+
const [showModal, setShowModal] = useState(false);
15+
16+
const deleteModal = (
17+
<Modal
18+
size="regular"
19+
active={showModal}
20+
toggler={() => setShowModal(false)}
21+
>
22+
<ModalHeader toggler={() => setShowModal(false)}>
23+
Delete Document
24+
</ModalHeader>
25+
<ModalBody>
26+
<p className="text-base leading-relaxed text-gray-600 font-normal">
27+
Are you sure you want to permanently delete this Document?
28+
</p>
29+
</ModalBody>
30+
<ModalFooter>
31+
<Button
32+
color="gray"
33+
buttonType="link"
34+
onClick={() => setShowModal(false)}
35+
ripple="dark"
36+
>
37+
Close
38+
</Button>
39+
40+
<Button
41+
color="red"
42+
onClick={() => {
43+
deleteDocument(id);
44+
setShowModal(false);
45+
}}
46+
ripple="light"
47+
>
48+
Delete
49+
</Button>
50+
</ModalFooter>
51+
</Modal>
52+
);
53+
54+
return (
55+
<tr className="flex items-center row">
56+
<td
57+
className="col-1 flex items-center space-x-2 font-medium capitalize"
58+
onClick={(e) => router.push(`/doc/${id}`)}
59+
>
60+
<Icon name="article" size="2xl" color="blue" />
61+
<p className="flex-grow truncate">{fileName}</p>
62+
</td>
63+
64+
<td className="col-2">
65+
{`${date?.toDate().toString().slice(4, 10)}, ${date
66+
?.toDate()
67+
.toString()
68+
.slice(11, 15)}`}
69+
</td>
70+
71+
<td className="col-3 flex justify-center">
72+
<Dropdown
73+
color="darkgray"
74+
buttonText={<Icon name="more_vert" size="2xl" />}
75+
buttonType="outline"
76+
size="sm"
77+
rounded={true}
78+
ripple="light"
79+
className="mx-auto rounded-full !outline-none border-0"
80+
>
81+
<DropdownLink
82+
color="red"
83+
ripple="dark"
84+
onClick={() => setShowModal(true)}
85+
>
86+
Delete
87+
</DropdownLink>
88+
<DropdownLink
89+
color="blue"
90+
ripple="dark"
91+
onClick={() => window.open(`/doc/${id}`, "_blank")}
92+
>
93+
Open in new tab
94+
</DropdownLink>
95+
</Dropdown>
96+
</td>
97+
{deleteModal}
98+
</tr>
99+
);
100+
}
101+
102+
export default DocumentRow;

components/Header.js

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import React from "react";
2+
import Button from "@material-tailwind/react/Button";
3+
import Icon from "@material-tailwind/react/Icon";
4+
import Image from "next/image";
5+
import { signOut } from "next-auth/client";
6+
import { useSession } from "next-auth/client";
7+
8+
const Header = ({ darkMode, changeDarkMode, setShowSearchModal }) => {
9+
const [session] = useSession();
10+
11+
return (
12+
<header className="sticky top-0 z-50 flex items-center px-4 justify-between max-w-screen bg-white dark:bg-dark-extra dark:text-gray-200">
13+
<div className="flex items-center space-x-1">
14+
<Button
15+
color="darkgray"
16+
buttonType="outline"
17+
rounded={true}
18+
iconOnly={true}
19+
ripple="dark"
20+
className="border-0"
21+
>
22+
<Icon name="menu" size="2xl" />
23+
</Button>
24+
25+
<Icon name="description" size="4xl" color="blue" />
26+
<h1 className="hidden md:inline-flex text-gray-600 dark:text-gray-200 text-2xl ">
27+
Docs
28+
</h1>
29+
</div>
30+
31+
<Button
32+
className="px-5 sm:px-14 py-2 bg-[#F1F3F4] text-gray-600 rounded-md m-2 !shadow-none dark:bg-dark-mid dark:text-gray-200"
33+
onClick={() => setShowSearchModal(true)}
34+
>
35+
<Icon name="search" size="2xl" color="darkgray" />
36+
37+
</Button>
38+
39+
<div className="flex items-center space-x-1">
40+
<Button
41+
color="gray"
42+
buttonType="outline"
43+
rounded={true}
44+
iconOnly={true}
45+
ripple="dark"
46+
className="h-18 w-18 mr-1 border-0 dark:bg-dark-light"
47+
onClick={() => changeDarkMode(!darkMode)}
48+
>
49+
<Icon
50+
name={!darkMode ? "light_mode" : "dark_mode"}
51+
size="3xl"
52+
color="gray"
53+
/>
54+
</Button>
55+
56+
<div className="flex items-center space-x-2">
57+
<p className="hidden lg:inline-flex font-medium">
58+
{session?.user?.name}
59+
</p>
60+
<div
61+
className="relative cursor-pointer h-10 w-10 rounded-full group ring-4 ring-transparent lg:hover:ring-blue-400 active:ring-blue-400"
62+
onClick={signOut}
63+
>
64+
<Image
65+
className="rounded-full "
66+
layout="fill"
67+
alt={session?.user?.name}
68+
src={session?.user?.image}
69+
/>
70+
<p className="top-[10%] transition-all opacity-0 duration-200 lg:group-hover:opacity-100 lg:group-hover:-translate-x-14 absolute bg-gray-300 rounded-sm px-2 py-1 -right-2 dark:bg-dark-light">
71+
Logout
72+
</p>
73+
</div>
74+
</div>
75+
</div>
76+
</header>
77+
);
78+
};
79+
80+
export default Header;

components/Login.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Image from "next/image";
2+
import Button from "@material-tailwind/react/Button";
3+
import { signIn } from "next-auth/client";
4+
import Icon from "@material-tailwind/react/Icon";
5+
6+
function Login({ providers }) {
7+
const { google } = providers;
8+
return (
9+
<div className="flex flex-col items-center justify-center min-h-screen py-2 dark:bg-dark-mid">
10+
<Image
11+
src="https://rb.gy/rreijn"
12+
width="550"
13+
height="300"
14+
objectFit="contain"
15+
alt="docs"
16+
/>
17+
18+
<Button
19+
className="mt-10 capitalize bg-blue-500"
20+
buttonType="filled"
21+
ripple="dark"
22+
onClick={() => signIn(google.id)}
23+
>
24+
<Icon name="lock" size="xl" />
25+
Sign in with Google
26+
</Button>
27+
</div>
28+
);
29+
}
30+
31+
export default Login;

components/TextEditor.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import dynamic from "next/dynamic";
2+
import { useEffect, useState } from "react";
3+
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
4+
import { EditorState } from "draft-js";
5+
import { db } from "../firebase";
6+
import { useRouter } from "next/dist/client/router";
7+
import { convertFromRaw, convertToRaw } from "draft-js";
8+
import { useSession } from "next-auth/client";
9+
10+
const Editor = dynamic(
11+
() => import("react-draft-wysiwyg").then((module) => module.Editor),
12+
{
13+
ssr: false,
14+
}
15+
);
16+
17+
function TextEditor({ snapshot }) {
18+
// Setting editors state, session, router, id
19+
const [editorState, setEditorState] = useState(EditorState.createEmpty());
20+
const [session] = useSession();
21+
const router = useRouter();
22+
const { id } = router.query;
23+
24+
useEffect(() => {
25+
if (snapshot?.data()?.editorState) {
26+
setEditorState(
27+
EditorState.createWithContent(
28+
convertFromRaw(snapshot?.data()?.editorState)
29+
)
30+
);
31+
}
32+
}, [snapshot]);
33+
34+
const onEditorStateChange = (editorState) => {
35+
setEditorState(editorState);
36+
37+
db.collection("userDocs")
38+
.doc(session?.user?.email)
39+
.collection("docs")
40+
.doc(id)
41+
.set(
42+
{
43+
editorState: convertToRaw(editorState.getCurrentContent()),
44+
},
45+
{
46+
merge: true,
47+
}
48+
);
49+
};
50+
51+
return (
52+
<div className="bg-[#F1F3F4] dark:bg-dark-extra min-h-screen pb-16 print:pb-0 ">
53+
<Editor
54+
editorState={editorState}
55+
onEditorStateChange={onEditorStateChange}
56+
toolbarClassName="flex sticky top-0 z-50 sm:!justify-center print:!hidden dark:!bg-dark-mid !border-0"
57+
editorClassName="mt-4 print:!m-0 print:!mx-auto sm:mt-6 py-1 sm:py-5 px-4 sm:px-10 bg-white shadow-md print:!shadow-none max-w-[90%] sm:max-w-3xl !min-h-[1024px] mx-auto ring-1 print:ring-0 ring-gray-300 print:block"
58+
/>
59+
</div>
60+
);
61+
}
62+
63+
export default TextEditor;

firebase.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import firebase from "firebase/compat/app";
2+
import "firebase/compat/firestore";
3+
4+
const firebaseConfig = {
5+
apiKey: "AIzaSyCHBMV2tiygMBaW_aqp7HGqXnewVSxfmho",
6+
authDomain: "easy-docs-da86b.firebaseapp.com",
7+
projectId: "easy-docs-da86b",
8+
storageBucket: "easy-docs-da86b.appspot.com",
9+
messagingSenderId: "199268974789",
10+
appId: "1:199268974789:web:0b5e4d7f55f472404fb0ac"
11+
};
12+
13+
14+
15+
// checking whether the app is already initialize or not
16+
const app = !firebase.apps.length
17+
? firebase.initializeApp(firebaseConfig)
18+
: firebase.app();
19+
20+
// initialize db
21+
const db = app.firestore();
22+
23+
// exporting db
24+
export { db, firebaseConfig };

0 commit comments

Comments
 (0)