Skip to content

Commit

Permalink
Merge pull request #8 from git-init-priyanshu/nextjs
Browse files Browse the repository at this point in the history
Revamped codebase to NEXTjs
  • Loading branch information
git-init-priyanshu authored Aug 4, 2024
2 parents c3e4565 + b822c9a commit 082e0b8
Show file tree
Hide file tree
Showing 157 changed files with 14,930 additions and 33,932 deletions.
37 changes: 36 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

.env
dist
94 changes: 36 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,36 @@
# Google-docs-clone
A platform that replicates the collaborative and customizable features of Google Docs. Multiple users can work together in real time on documents. It offers font customization and color adjustments for a unique look. You can log in with your account, create docs, edit docs, manage docs, and share the docs with different users for collaboration. <br/>
Now with new and improved UI with many new features.

Tech Stack:
* Rect.js ( frontend )
* GraphQl ( backend )
* GraphQl - Subscriptions ( Real Time collaboration )
* TypeScript
* Docker
* Nginx

## Website link
[Visit Website](https://docx-git-init-priyanshu.vercel.app/)

## How it works:

* You need to sign up with your email id and password.

* After signing up, you will be redirected to the home page where you can see all your documents. If you are a new user, this section will be empty, and you will need to create a new document.

* To create a new document, click the button on the top right corner.

* Edit your document as you like; changes will be saved automatically.

* You can share your document with others for collaboration. To do this, click on the 'Share Doc' button located under the thumbnail of each document on the home page.

* After clicking the button, send the link to your friend. They will paste the link, and both of you can then edit the same document simultaneously.

## Screenshots

<div style="display: flex;">
<img width="480" alt="Screenshot 2023-12-10 123504" src="https://github.com/git-init-priyanshu/Docx/assets/110045644/ed80c831-698b-4cac-a3fb-61728f690e0e">
<img width="480" alt="image" src="https://github.com/git-init-priyanshu/Docx/assets/110045644/9374ba10-49af-4d1a-9290-a595be9e74b8">
</div>
<img width="960" alt="image" src="https://github.com/git-init-priyanshu/Docx/assets/110045644/a958a7e2-8903-4aeb-bac8-dd155a038b20">
<img width="960" alt="image" src="https://github.com/git-init-priyanshu/Docx/assets/110045644/14393200-d0fc-47ff-84ba-ed1ebb7e0417">
<img width="960" alt="image" src="https://github.com/git-init-priyanshu/Docx/assets/110045644/d9181f2f-783b-4bb6-bc9d-9edc71b8d2db">
<img width="960" alt="image" src="https://github.com/git-init-priyanshu/Docx/assets/110045644/bd403f84-5e71-48fa-9aec-52ec66e7c5a4">

## Features:
* User Registration: User can Sign up using their email and password for secure access.
* Secure: Passwords are encrypted in the database.
* Real-time Editing: Collaborate with others in real time on the same Doc.
* Sharing: Share Doc with others for seamless collaboration.
* Management: The owner of the Doc can manage who has access to collaborate and who does not.

## Installation:
* You need to install Docker.
* Fork this repo.
* Open git bash and paste these commands:
* `Git clone https://github.com/<YourGithubProfileName>/Docx.git`
* `cd Google-docs-clone`
* `code .`
* Open integrated terminal window and paste this command:
* `docker compose up -d`
* Wait for the docker containers to properly start.
* Then go to `localhost:80` and start contributing.
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).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

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.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
104 changes: 104 additions & 0 deletions app/(auth)/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use server'

import { cookies } from "next/headers"
import { z } from 'zod';
import { JWTPayload, SignJWT, importJWK } from 'jose';
// @ts-ignore
import bcrypt from 'bcryptjs';

import prisma from "@/prisma/prismaClient";
import { loginSchema, signinSchema } from './zodSchema';

const generateJWT = async (payload: JWTPayload) => {
const secret = process.env.JWT_SECRET || 'secret';

const jwk = await importJWK({ k: secret, alg: 'HS256', kty: 'oct' });

const jwt = await new SignJWT(payload)
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('365d')
.sign(jwk);

return jwt;
};

export const SigninAction = async (data: z.infer<typeof signinSchema>) => {
try {
// User validation
const isUserExist = await prisma.user.findFirst({
where: {
email: data.email
}
})
if (isUserExist) return {
success: false,
error: "Looks like you already have an account",
};

// Hashing password
const salt = await bcrypt.genSalt(Number(process.env.SALT) || 10);
const hashedPassword = await bcrypt.hash(data.password, salt);

const authToken = await generateJWT({ email: data.email });

await prisma.user.create({
data: {
name: data.name,
username: data.username,
email: data.email,
password: hashedPassword,
isVerified: true,
verifyToken: authToken,
}
})

// Setting the cookie
cookies().set('token', authToken, { httpOnly: true });

return { success: true, data: authToken }
} catch (e) {
console.log(e);
return { success: false, error: "Internal server error" }
}
}

export const LoginAction = async (data: z.infer<typeof loginSchema>) => {
try {
// User validation
const user = await prisma.user.findFirst({
where: {
email: data.email
}
})
if (!user) return {
success: false,
error: "Looks like you don't have an account",
};

// Password validation
const isCorrectPassword = await bcrypt.compare(data.password, user.password);
if (!isCorrectPassword) return {
success: false,
error: "Invalid credentials",
}

const authToken = await generateJWT({ email: data.email });

await prisma.user.update({
where: { id: user.id },
data: {
isVerified: true,
verifyToken: authToken
}
})

// Setting the cookie
cookies().set('token', authToken, { httpOnly: true });

return { success: true, data: authToken }
} catch (e) {
console.log(e);
return { success: false, error: "Internal server error" }
}
}
22 changes: 22 additions & 0 deletions app/(auth)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Image from "next/image";

export default function AuthLayout({ children }: { children: React.ReactNode }) {
return (
<div className="w-full h-dvh lg:grid lg:grid-cols-2 ">
<div className="flex items-center justify-center py-12">
<div className="mx-auto grid w-[350px] gap-6">
{children}
</div>
</div>
<div className="hidden bg-muted lg:block">
<Image
src="/placeholder.svg"
alt="Image"
width="1920"
height="1080"
className="h-full w-full object-cover dark:brightness-[0.2] dark:grayscale"
/>
</div>
</div>
)
}
82 changes: 82 additions & 0 deletions app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use client"

import Link from "next/link"
import { useRouter } from "next/navigation"
import { useForm } from 'react-hook-form'
import { z } from 'zod'

import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

import { LoginAction } from "../actions"
import { loginSchema } from '../zodSchema'
import { toast } from "sonner"

export default function Login() {
const router = useRouter()

const { register, handleSubmit } = useForm<z.infer<typeof loginSchema>>();

const submitForm = async (data: z.infer<typeof loginSchema>) => {
const parsedData = loginSchema.parse({
email: data.email,
password: data.password
})
const response = await LoginAction(parsedData);
if(response.success){
toast.success("login completed")
router.push('/')
}else{
toast.error(response.error)
}
};

return (
<>
<div className="grid gap-2 text-center">
<h1 className="text-3xl font-bold text-blue-500">Login</h1>
<p className="text-balance text-muted-foreground">
Enter your email below to login to your account
</p>
</div>
<form className="grid gap-4" onSubmit={handleSubmit(submitForm)}>
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
type="email"
placeholder="[email protected]"
{...register('email', { required: true })}
/>
</div>
<div className="grid gap-2">
<div className="flex items-center">
<Label htmlFor="password">Password</Label>
<Link
href="/forgot-password"
className="ml-auto inline-block text-sm underline"
>
Forgot your password?
</Link>
</div>
<Input
type="password"
{...register('password', { required: true })}
/>
</div>
<Button type="submit" className="w-full bg-blue-500">
Login
</Button>
<Button variant="outline" className="w-full">
Login with Google
</Button>
</form>
<div className="mt-4 text-center text-sm">
Don&apos;t have an account?{" "}
<Link href="/signup" className="underline">
Sign up
</Link>
</div>
</>
)
}
20 changes: 20 additions & 0 deletions app/(auth)/signin/components/GoogleAuthButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use client"

import Image from "next/image";
import { signIn } from "next-auth/react";

import Google from '@/public/google_icon.svg'
import { Button } from "@/components/ui/button";

export default function GoogleAuthButton() {
return (
<Button
variant="outline"
className="w-full flex gap-2"
onClick={() => signIn("google", { redirect: true })}
>
<Image src={Google} alt="google" width={15} />
Sign in with Google
</Button>
)
}
Loading

0 comments on commit 082e0b8

Please sign in to comment.