Skip to content

Commit

Permalink
Merge pull request #20 from git-init-priyanshu/nextjs
Browse files Browse the repository at this point in the history
Redis
  • Loading branch information
git-init-priyanshu authored Sep 2, 2024
2 parents 1f064ef + f072d45 commit 7c2e790
Show file tree
Hide file tree
Showing 89 changed files with 2,064 additions and 10,391 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
11 changes: 6 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches:
- main
paths-ignore:
- 'README.md'
- "README.md"

permissions:
id-token: write
Expand All @@ -20,12 +20,13 @@ jobs:
uses: actions/checkout@v2

- name: Lint code
run: echo "Linting repository"
# You can add actual linting commands here to check code quality.
run: npm run lint

- name: Format code
run: npm run format

- name: Run unit tests
run: echo "Running unit tests"
# Add the commands to run your unit tests here.

# build-and-push-ecr-image:
# name: Build and Push to ECR
Expand Down Expand Up @@ -54,4 +55,4 @@ jobs:
# - name: Push Docker images to Amazon ECR
# run: |
# # Push the Docker images to Amazon ECR.
# docker compose -f D:\Projects\Google docs clone\docker-compose.yaml push
# docker compose -f D:\Projects\Google docs clone\docker-compose.yaml push
93 changes: 50 additions & 43 deletions app/(auth)/actions.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
'use server'
"use server";

import { cookies } from "next/headers"
import { z } from 'zod';
import { cookies } from "next/headers";
import { z } from "zod";
// @ts-ignore
import bcrypt from 'bcryptjs';
import bcrypt from "bcryptjs";

import prisma from "@/prisma/prismaClient";
import { signinSchema, signupSchema } from './zodSchema';
import { signinSchema, signupSchema } from "./zodSchema";
import { generateJWT } from "@/helpers/generateJWT";

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

// Hashing password
const salt = await bcrypt.genSalt(Number(process.env.SALT) || 10);
Expand All @@ -30,71 +31,77 @@ export const SignupAction = async (data: z.infer<typeof signupSchema>) => {
id: user?.id,
email: data.email,
name: user?.name,
picture: user?.picture
}
picture: user?.picture,
};
const authToken = await generateJWT(jwtPayload);

await prisma.user.upsert({
where: { email: data.email },
update: {
password: hashedPassword
password: hashedPassword,
},
create: {
name: data.name,
username: data.username,
email: data.email,
password: hashedPassword,
}
})
},
});

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

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

export const SigninAction = async (data: z.infer<typeof signinSchema>) => {
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",
};
if (!user.password) return {
success: false,
error: "Invalid credentials",
};
email: data.email,
},
});
if (!user)
return {
success: false,
error: "Looks like you don't have an account",
};
if (!user.password)
return {
success: false,
error: "Invalid credentials",
};

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

const jwtPayload = {
id: user?.id,
email: data.email,
name: user?.name,
picture: user?.picture
}
picture: user?.picture,
};
const authToken = await generateJWT(jwtPayload);

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

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

import SignInImage from '@/public/signin.webp'
import SignInImage from "@/public/signin.webp";

export default function AuthLayout({ children }: { children: React.ReactNode }) {
export default function AuthLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="w-full h-dvh lg:grid lg:grid-cols-2 overflow-hidden">
<div className="flex items-center justify-center py-12">
<div className="mx-auto grid w-[350px] gap-6">
{children}
</div>
<div className="mx-auto grid w-[350px] gap-6">{children}</div>
</div>
<div className="hidden bg-muted lg:block">
<Image
Expand All @@ -18,5 +20,5 @@ export default function AuthLayout({ children }: { children: React.ReactNode })
/>
</div>
</div>
)
);
}
8 changes: 4 additions & 4 deletions app/(auth)/signin/components/GoogleAuthButton.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
"use client"
"use client";

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

import Google from '@/public/google_icon.svg'
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" )}
onClick={() => signIn("google")}
>
<Image src={Google} alt="google" width={15} />
Continue with Google
</Button>
)
);
}
86 changes: 53 additions & 33 deletions app/(auth)/signin/components/SignInForm.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
import { useState } from "react"
import { useRouter } from "next/navigation"
import { useForm } from 'react-hook-form'
import Link from "next/link"
import { z } from 'zod'
"use client";

import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { Eye, EyeOff } from "lucide-react";
import { z } from "zod";

import { SigninAction } from "../../actions"
import { signinSchema } from '../../zodSchema'
import { toast } from "sonner"
import LoaderButton from "@/components/LoaderButton"
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import LoaderButton from "@/components/LoaderButton";

import { SigninAction } from "../../actions";
import { signinSchema } from "../../zodSchema";

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

const [isSubmitting, setIsSubmitting] = useState(false);
export default function CredentialsForm() {
const router = useRouter();

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

const [isSubmitting, setIsSubmitting] = useState(false);
const [isPasswordVisible, setIsPasswordVisible] = useState(false);

const submitForm = async (data: z.infer<typeof signinSchema>) => {
setIsSubmitting(true);
const parsedData = signinSchema.parse({
email: data.email,
password: data.password
})
password: data.password,
});
const response = await SigninAction(parsedData);
if (response.success) {
toast.success("login completed")
router.push('/')
toast.success("login completed");
router.push("/");
setIsSubmitting(false);
} else {
toast.error(response.error)
toast.error(response.error);
setIsSubmitting(false);
}
};
Expand All @@ -44,29 +46,47 @@ export default function LogInForm() {
<Input
type="email"
placeholder="[email protected]"
{...register('email', { required: true })}
{...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>
{/* <Link */}
{/* href="/forgot-password" */}
{/* className="ml-auto inline-block text-sm underline" */}
{/* > */}
{/* Forgot your password? */}
{/* </Link> */}
</div>
<div>
<Input
type={isPasswordVisible ? "text" : "password"}
className="relative"
{...register("password", { required: true })}
/>
{!isPasswordVisible ? (
<Eye
size={20}
onClick={() => setIsPasswordVisible(true)}
className="absolute transform -translate-y-[1.7rem] translate-x-80 cursor-pointer text-neutral-500 hover:text-black"
/>
) : (
<EyeOff
size={20}
onClick={() => setIsPasswordVisible(false)}
className="absolute transform -translate-y-[1.7rem] translate-x-80 cursor-pointer text-neutral-500 hover:text-black"
/>
)}
</div>
<Input
type="password"
{...register('password', { required: true })}
/>
</div>
<LoaderButton
className="w-full bg-blue-500 hover:bg-blue-600"
isLoading={isSubmitting}
type="submit"
>Sign in</LoaderButton>
>
Sign in
</LoaderButton>
</form>
)
);
}
11 changes: 4 additions & 7 deletions app/(auth)/signin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
"use client"
import Link from "next/link";

import Link from "next/link"

import SignInForm from "./components/SignInForm"
import GoogleAuthButton from "./components/GoogleAuthButton"
import SignInForm from "./components/SignInForm";
import GoogleAuthButton from "./components/GoogleAuthButton";

export default function Login() {

return (
<>
<div className="grid gap-2 text-center">
Expand All @@ -27,5 +24,5 @@ export default function Login() {
</p>
</div>
</>
)
);
}
Loading

0 comments on commit 7c2e790

Please sign in to comment.