Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Email otp signon user #770

Merged
merged 3 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 136 additions & 84 deletions app/(Customer)/auth/components/signupPage.tsx
Original file line number Diff line number Diff line change
@@ -1,77 +1,130 @@
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { AtSign, Phone, User, Eye, EyeOff } from "lucide-react"; // Import Eye and EyeOff
import { AtSign, Phone, User} from "lucide-react"; // Import Eye and EyeOff
import React, { useState } from "react";
import toast from "react-hot-toast";
import axios from "axios"
import axios from "axios";
import { Spinner } from "@/components/ui/spinner";
import { z } from "zod";
import {
InputOTP,
InputOTPGroup,
InputOTPSlot,
} from "@/components/ui/input-otp";

import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { signIn } from "next-auth/react";

interface SignupPageProps {
switchCss: boolean;
setSwitchCss: (value: boolean) => void;
setError: (value: string) => void;
loading:boolean,
setloading:(value:boolean)=>void;
loading: boolean;
setloading: (value: boolean) => void;
}

const SignupPage: React.FC<SignupPageProps> =({ switchCss, setSwitchCss,setError ,loading,setloading}) => {
// form schema otp
const FormSchema = z.object({
pin: z.string().min(6, {
message: "Your one-time password must be 6 characters.",
}),
});

const SignupPage: React.FC<SignupPageProps> = ({
switchCss,
setSwitchCss,
setError,
loading,
setloading,
}) => {
const [otpOpen, setOtpOpen] = useState(false);
// State for form fields
const [fullname, setFullname] = useState("");
const [mobileNumber, setmobileNumber] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");

// State for showing passwords
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);

// form definition otp
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
pin: "",
},
});

async function onOTPSubmit(data: z.infer<typeof FormSchema>) {
// console.log(data.pin+email);
setloading(true);

const result = await signIn("credentials", {
email,
otp: data.pin,
role: "user",
redirect: false,
});
console.log(result);
if (!result?.ok) {
setError("Invalid email or otp");
} else {
toast.success(`Welcome!`);

setTimeout(() => {
window.location.href = "/"; // Redirect on success
}, 2000);
}
setloading(false);
}

// Handle form submission
const handleSubmit = async(e: React.FormEvent) => {
setloading(true)
const handleSubmit = async (e: React.FormEvent) => {
setloading(true);
e.preventDefault();

// Basic validation
if (!fullname || !mobileNumber || !email || !password || !confirmPassword) {
if (!fullname || !mobileNumber || !email) {
setError("All fields are required.");
setloading(false)
return;
}
if (password !== confirmPassword) {
setError("Passwords do not match.");
setloading(false)
setloading(false);
return;
}


const result = await axios.post('/api/auth/signup',{
try {
const result = await axios.post("/api/auth/signup", {
email,
password,
name:fullname,
mobileNumber
})
console.log(result)
if (!result) setError("Invalid email or password");
else {
toast.success(`Successful, you can login now.`)
// ${session.data?.user?.name}
window.location.href = "/login"; // Redirect on success
name: fullname,
mobileNumber,
});
console.log(result);
} catch (err) {
if (axios.isAxiosError(err)) {
setError("Invalid email or number, axios error");
} else {
setError("Invalid email or number");
}
//
console.log(err);
setloading(false);
return;
}

// Reset form fields after submission
setOtpOpen(true);
setFullname("");
setmobileNumber("");
setEmail("");
setPassword("");
setConfirmPassword("");

setloading(false)
setloading(false);
};

return (
<>
{!switchCss && (
<div className="flex flex-col dark:text-gray-200 z-10 items-center justify-start pt-12 pl-14 gap-4 w-2/4">
{!switchCss && !otpOpen && (
<div className="flex flex-col dark:text-gray-200 z-10 items-center justify-start pt-20 pl-14 gap-4 w-2/4">
<div className="font-nunito text-4xl text-customTeal dark:text-Green font-extrabold">
Sign Up
</div>
Expand Down Expand Up @@ -109,52 +162,11 @@ const SignupPage: React.FC<SignupPageProps> =({ switchCss, setSwitchCss,setError
/>
<AtSign className="h-7 w-7 text-customTeal dark:text-Yellow" />
</div>
<div className="flex items-center w-4/5 justify-center mb-4 relative">
{" "}
{/* Added relative for positioning */}
<Input
className="rounded-full pr-12" // Added padding for the icon
type={showPassword ? "text" : "password"} // Toggle password visibility
placeholder="Enter Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<div
className=" cursor-pointer"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? (
<EyeOff className="h-7 w-7 text-customTeal dark:text-Yellow" />
) : (
<Eye className="h-7 w-7 text-customTeal dark:text-Yellow" />
)}
</div>
</div>
<div className="flex items-center w-4/5 justify-center mb-4 relative">
{" "}
{/* Added relative for positioning */}
<Input
className="rounded-full pr-12" // Added padding for the icon
type={showConfirmPassword ? "text" : "password"} // Toggle password visibility
placeholder="Confirm Password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
<div
className="cursor-pointer"
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
>
{showConfirmPassword ? (
<EyeOff className="h-7 w-7 text-customTeal dark:text-Yellow" />
) : (
<Eye className="h-7 w-7 text-customTeal dark:text-Yellow" />
)}
</div>
</div>

<Button
className="rounded-full h-10 w-4/5 font-bold bg-customTeal dark:bg-Green"
type="submit"
disabled
// disabled
>
{loading ? <Spinner /> : "Sign Up"}
</Button>
Expand All @@ -170,6 +182,46 @@ const SignupPage: React.FC<SignupPageProps> =({ switchCss, setSwitchCss,setError
</div>
</div>
)}
{!switchCss && otpOpen && (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onOTPSubmit)}
className="flex flex-col dark:text-gray-200 z-10 items-start justify-center pl-14 gap-4 w-2/4"
>
<FormField
control={form.control}
name="pin"
render={({ field }) => (
<FormItem className="flex items-start justify-center flex-col">
<FormLabel className="text-2xl text-customTeal dark:text-Green font-bold">
One-Time Password
</FormLabel>
<FormControl>
<InputOTP maxLength={6} {...field}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
</FormControl>
<FormDescription>
Please enter the one-time password sent to your email.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>

<Button className="bg-customTeal dark:bg-Green" type="submit">
Submit
</Button>
</form>
</Form>
)}
</>
);
};
Expand Down
58 changes: 58 additions & 0 deletions app/(Customer)/auth/role/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ChevronDown } from "lucide-react";
import Link from "next/link";


const Login = () => {
return (
<div className="dark:bg-DarkGray ">
{/* <div className="bg-slate-700 h-100 w-100">{switchCss ? "1" : "0"}</div>
<Button onClick={() => setSwitchCss(!switchCss)}>Toggle CSS</Button> */}
<div className="flex h-screen w-full items-center justify-center">
<div className="flex rounded-2xl justify-between shadow-xl shadow-black dark:shadow-Green relative lg:h-4/6 lg:w-2/4 border overflow-hidden">
{/* First background div */}
<div
className={`w-full h-full absolute left-60 bottom-[9.5rem] rotate-45 transition-opacity duration-1000 ease-in-out bg-customTeal dark:bg-gradient-to-r from-Green to-Yellow `}
></div>
<DropdownMenu>
<DropdownMenuTrigger className="flex bg-customTeal dark:bg-Green rounded-full p-5 ml-20 mt-40 h-10 items-center justify-center">
Proceed as a
<ChevronDown className="h-5 w-5" />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel className="bg-gray-200 dark:bg-DarkGray">
Role
</DropdownMenuLabel>
<DropdownMenuSeparator />
<Link href="/auth/customer">
<DropdownMenuItem>Customer</DropdownMenuItem>
</Link>
<Link href="/auth/seller">
<DropdownMenuItem>Seller</DropdownMenuItem>
</Link>

</DropdownMenuContent>
</DropdownMenu>

<div
className={`text-white flex pt-10 px-4 flex-col w-2/4 z-10 h-full`}
>
<div className="text-7xl text-right font-handlee font-bold ">
Welcome to EzyShop!
</div>
</div>
</div>
</div>
</div>
);
};

export default Login;
13 changes: 8 additions & 5 deletions app/api/auth/signup/route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { NextResponse } from 'next/server';
import { PrismaClient } from '@prisma/client';
import bcrypt from 'bcrypt';
import { generateAndSendOTP } from '@/lib/auth';

const prisma = new PrismaClient();

export async function POST(request: Request) {
const { email, password , mobileNumber,name } = await request.json();
const { email, mobileNumber,name } = await request.json();

// Check if the user already exists
const existingUser = await prisma.user.findUnique({
Expand All @@ -17,19 +17,22 @@ export async function POST(request: Request) {
}

// Hash the password
const passwordHash = await bcrypt.hash(password, 10);
// const passwordHash = await bcrypt.hash(password, 10);

// Create the user
const user = await prisma.user.create({
data: {
email,
passwordHash,
mobileNumber,
name
},
});

generateAndSendOTP(email,"user");


return NextResponse.json({ message: 'Signup successful!',user });



return NextResponse.json({ message: 'aCCOUNT CREATED, VERIFY EMAIL VIA OTP',user });
}
Loading