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

S1-28_Walidacja_hasla_na_BE #41

Merged
merged 10 commits into from
Nov 26, 2024
19 changes: 8 additions & 11 deletions app/api/auth/signup/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@ import { NextResponse } from "next/server";
import bcrypt from "bcryptjs";
import connectDB from "@/lib/connectToDatabase";
import User from "@/models/User";
import { signUpFormSchema } from "@/lib/formSchemas/authFormSchemas";

export async function POST(request: Request) {
export async function POST(req: Request) {
try {
const { username, email, password } = await request.json();
const body = await req.json();

// Validate input
if (!username || !email || !password) {
const result = signUpFormSchema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{ message: "Missing required fields" },
{ message: "Invalid data", errors: result.error.flatten().fieldErrors },
{ status: 400 }
);
}

// Connect to database
await connectDB();
const { username, email, password } = result.data;

// Check if user already exists
await connectDB();
const existingUser = await User.findOne({
$or: [{ email }, { username }],
});
Expand All @@ -30,10 +30,8 @@ export async function POST(request: Request) {
);
}

// Hash password
const hashedPassword = await bcrypt.hash(password, 12);

// Create user
const user = await User.create({
username,
email,
Expand All @@ -43,7 +41,6 @@ export async function POST(request: Request) {
// Remove password from response
const { password: _, ...userWithoutPassword } = user.toObject();


return NextResponse.json(
{ message: "User created successfully", user: userWithoutPassword },
{ status: 201 }
Expand Down
29 changes: 8 additions & 21 deletions app/user/signin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { Tabs, TabsContent } from "@/components/ui/tabs";
import { Eye, EyeOff } from "lucide-react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { useRouter } from "next/navigation";
import {
Form,
FormControl,
Expand All @@ -18,39 +16,31 @@ import {
FormMessage,
} from "@/components/ui/form";
import { Logo } from "@/components/Logo";

//Form validation scheme
const formSchema = z.object({
email: z.string().email("Invalid email address."),
password: z.string().min(6, "Password must be at least 6 characters."),
});
import {
SignInFormData,
signInFormSchema,
} from "@/lib/formSchemas/authFormSchemas";

export default function Home() {
const router = useRouter();

//Use state to toggle password visibility
const [showPassword, setShowPassword] = useState(false);

//Define form
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
const form = useForm<SignInFormData>({
resolver: zodResolver(signInFormSchema),
defaultValues: {
email: "",
password: "",
},
});

//Define a submit handler
async function onSubmit(values: z.infer<typeof formSchema>) {
async function onSubmit(values: SignInFormData) {
const result = await signIn("credentials", {
redirect: false,
email: values.email,
password: values.password,
callbackUrl: "/",
});

if (result?.error) {
console.error(result.error);

form.setError("email", {
type: "manual",
message: "Invalid email or password",
Expand All @@ -63,9 +53,6 @@ export default function Home() {

return;
}

router.push("/");
router.refresh();
}

return (
Expand Down
53 changes: 19 additions & 34 deletions app/user/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
"use client";

import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Tabs, TabsContent } from "@/components/ui/tabs";
import { Eye, EyeOff } from "lucide-react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { useRouter } from "next/navigation";
import { z } from "zod";
import {
Form,
FormControl,
Expand All @@ -19,47 +16,35 @@ import {
} from "@/components/ui/form";
import { Logo } from "@/components/Logo";
import { signIn } from "next-auth/react";
import {
usernameSchema,
emailSchema,
passwordSchema,
} from "@/lib/formSchemas/authFormSchemas";
import { z } from "zod";

//Form validation scheme
const formSchema = z
const signUpFormSchemaWithConfirmPassword = z
.object({
username: z
.string()
.min(3, "Username must be at least 3 characters.")
.max(20, "Username cannot exceed 20 characters.")
.regex(
/^[a-zA-Z0-9_-]+$/,
"Username can only contain letters, numbers, dashes, and underscores."
),
email: z.string().email("Invalid email address."),
password: z
.string()
.min(8, "Password must be at least 8 characters.")
.regex(/[a-z]/, "Password must contain at least one lowercase letter.")
.regex(/[A-Z]/, "Password must contain at least one uppercase letter.")
.regex(
/[^a-zA-Z0-9]/,
"Password must contain at least one special character."
),
confirmPassword: z
.string()
.min(8, "Password confirmation must be at least 8 characters."),
username: usernameSchema,
email: emailSchema,
password: passwordSchema,
confirmPassword: z.string(),
})
.refine((data) => data.password === data.confirmPassword, {
message: "Passwords do not match",
path: ["confirmPassword"],
message: "Passwords do not match.",
});

export default function Home() {
const router = useRouter();
type SignUpFormWithConfirmPasswordData = z.infer<
typeof signUpFormSchemaWithConfirmPassword
>;

//Use state to toggle password visibility
export default function Home() {
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);

//Define form
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
const form = useForm<SignUpFormWithConfirmPasswordData>({
resolver: zodResolver(signUpFormSchemaWithConfirmPassword),
defaultValues: {
username: "",
email: "",
Expand All @@ -69,7 +54,7 @@ export default function Home() {
});

//Define a submit handler
async function onSubmit(values: z.infer<typeof formSchema>) {
async function onSubmit(values: SignUpFormWithConfirmPasswordData) {
try {
const response = await fetch("/api/auth/signup", {
method: "POST",
Expand Down
37 changes: 37 additions & 0 deletions lib/formSchemas/authFormSchemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { z } from "zod";

export const usernameSchema = z
.string()
.min(3, "Username must be at least 3 characters.")
.max(20, "Username cannot exceed 20 characters.")
.regex(
/^[a-zA-Z0-9_-]+$/,
"Username can only contain letters, numbers, dashes, and underscores."
);
export const emailSchema = z.string().email("Invalid email address.");
export const passwordSchema = z
.string()
.min(8, "Password must be at least 8 characters.")
.regex(/[a-z]/, "Password must contain at least one lowercase letter.")
.regex(/[A-Z]/, "Password must contain at least one uppercase letter.")
.regex(
/[^a-zA-Z0-9]/,
"Password must contain at least one special character."
);

// Sign In
export const signInFormSchema = z.object({
email: emailSchema,
password: passwordSchema,
});

// Sign Up
export const signUpFormSchema = z.object({
username: usernameSchema,
email: emailSchema,
password: passwordSchema,
});

// Types for form data
export type SignInFormData = z.infer<typeof signInFormSchema>;
export type SignUpFormData = z.infer<typeof signUpFormSchema>;