diff --git a/components/SubmitButton.tsx b/components/SubmitButton.tsx index 8a06eac..6ee0a78 100644 --- a/components/SubmitButton.tsx +++ b/components/SubmitButton.tsx @@ -2,11 +2,12 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { IconProp } from "@fortawesome/fontawesome-svg-core"; type Props = { - onClick: Function; + onClick?: Function; icon?: IconProp; label: string; loading: boolean; className?: string; + type?: "button" | "submit" | "reset" | undefined; }; export default function SubmitButton({ @@ -15,20 +16,22 @@ export default function SubmitButton({ label, loading, className, + type, }: Props) { return ( -
{ - if (!loading) onClick(); + if (!loading && onClick) onClick(); }} > - {icon && } -

{label}

-
+ {icon && } +

{label}

+ ); } diff --git a/lib/api/controllers/users/postUser.ts b/lib/api/controllers/users/postUser.ts index 5025d4e..d9f24f9 100644 --- a/lib/api/controllers/users/postUser.ts +++ b/lib/api/controllers/users/postUser.ts @@ -54,10 +54,10 @@ export default async function postUser( const checkIfUserExists = await prisma.user.findFirst({ where: emailEnabled ? { - email: body.email?.toLowerCase(), + email: body.email?.toLowerCase().trim(), } : { - username: (body.username as string).toLowerCase(), + username: (body.username as string).toLowerCase().trim(), }, }); @@ -71,8 +71,8 @@ export default async function postUser( name: body.name, username: emailEnabled ? undefined - : (body.username as string).toLowerCase(), - email: emailEnabled ? body.email?.toLowerCase() : undefined, + : (body.username as string).toLowerCase().trim(), + email: emailEnabled ? body.email?.toLowerCase().trim() : undefined, password: hashedPassword, }, }); diff --git a/lib/api/controllers/users/userId/updateUserById.ts b/lib/api/controllers/users/userId/updateUserById.ts index b2229e3..c7ac3e8 100644 --- a/lib/api/controllers/users/userId/updateUserById.ts +++ b/lib/api/controllers/users/userId/updateUserById.ts @@ -29,6 +29,15 @@ export default async function updateUser( status: 400, }; + // Check email (if enabled) + const checkEmail = + /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + if (emailEnabled && !checkEmail.test(data.email?.toLowerCase() || "")) + return { + response: "Please enter a valid email.", + status: 400, + }; + const checkUsername = RegExp("^[a-z0-9_-]{3,31}$"); if (!checkUsername.test(data.username.toLowerCase())) @@ -58,11 +67,25 @@ export default async function updateUser( }, }); - if (userIsTaken) + if (userIsTaken) { + if (data.email?.toLowerCase().trim() === userIsTaken.email?.trim()) + return { + response: "Email is taken.", + status: 400, + }; + else if ( + data.username?.toLowerCase().trim() === userIsTaken.username?.trim() + ) + return { + response: "Username is taken.", + status: 400, + }; + return { response: "Username/Email is taken.", status: 400, }; + } // Avatar Settings @@ -105,8 +128,8 @@ export default async function updateUser( }, data: { name: data.name, - username: data.username.toLowerCase(), - email: data.email?.toLowerCase(), + username: data.username.toLowerCase().trim(), + email: data.email?.toLowerCase().trim(), isPrivate: data.isPrivate, archiveAsScreenshot: data.archiveAsScreenshot, archiveAsPDF: data.archiveAsPDF, diff --git a/pages/choose-username.tsx b/pages/choose-username.tsx index 75d6aa0..1b4d9be 100644 --- a/pages/choose-username.tsx +++ b/pages/choose-username.tsx @@ -1,6 +1,6 @@ import SubmitButton from "@/components/SubmitButton"; import { signOut } from "next-auth/react"; -import { useState } from "react"; +import { FormEvent, useState } from "react"; import { toast } from "react-hot-toast"; import { useSession } from "next-auth/react"; import useAccountStore from "@/store/account"; @@ -15,7 +15,9 @@ export default function ChooseUsername() { const { updateAccount, account } = useAccountStore(); - async function submitUsername() { + async function submitUsername(event: FormEvent) { + event.preventDefault(); + setSubmitLoader(true); const redirectionToast = toast.loading("Applying..."); @@ -38,50 +40,53 @@ export default function ChooseUsername() { return ( -
-

- Choose a Username (Last step) -

- -
-

- Username +

+
+

+ Choose a Username (Last step)

- setInputedUsername(e.target.value)} +
+

+ Username +

+ + setInputedUsername(e.target.value)} + /> +
+
+

+ Feel free to reach out to us at{" "} + + support@linkwarden.app + {" "} + in case of any issues. +

+
+ + -
-
-

- Feel free to reach out to us at{" "} - - support@linkwarden.app - {" "} - in case of any issues. -

-
- - -
signOut()} - className="w-fit mx-auto cursor-pointer text-gray-500 dark:text-gray-400 font-semibold " - > - Sign Out +
signOut()} + className="w-fit mx-auto cursor-pointer text-gray-500 dark:text-gray-400 font-semibold " + > + Sign Out +
-
+ ); } diff --git a/pages/forgot.tsx b/pages/forgot.tsx index eb60eb7..d2fc8c7 100644 --- a/pages/forgot.tsx +++ b/pages/forgot.tsx @@ -3,7 +3,7 @@ import TextInput from "@/components/TextInput"; import CenteredForm from "@/layouts/CenteredForm"; import { signIn } from "next-auth/react"; import Link from "next/link"; -import { useState } from "react"; +import { FormEvent, useState } from "react"; import { toast } from "react-hot-toast"; interface FormData { @@ -17,7 +17,9 @@ export default function Forgot() { email: "", }); - async function loginUser() { + async function sendConfirmation(event: FormEvent) { + event.preventDefault(); + if (form.email !== "") { setSubmitLoader(true); @@ -40,49 +42,52 @@ export default function Forgot() { return ( -
-

- Password Recovery -

-
-

- Enter your Email so we can send you a link to recover your account. - Make sure to change your password in the profile settings - afterwards. -

-

- You wont get logged in if you haven't created an account yet. -

-
-
-

- Email +

+
+

+ Password Recovery

+
+

+ Enter your Email so we can send you a link to recover your + account. Make sure to change your password in the profile settings + afterwards. +

+

+ You wont get logged in if you haven't created an account yet. +

+
+
+

+ Email +

- setForm({ ...form, email: e.target.value })} + setForm({ ...form, email: e.target.value })} + /> +
+ + +
+ + Go back + +
- - -
- - Go back - -
-
+ ); } diff --git a/pages/login.tsx b/pages/login.tsx index f6968cc..6c9c402 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -3,7 +3,7 @@ import TextInput from "@/components/TextInput"; import CenteredForm from "@/layouts/CenteredForm"; import { signIn } from "next-auth/react"; import Link from "next/link"; -import { useState } from "react"; +import { useState, FormEvent } from "react"; import { toast } from "react-hot-toast"; interface FormData { @@ -21,7 +21,9 @@ export default function Login() { password: "", }); - async function loginUser() { + async function loginUser(event: FormEvent) { + event.preventDefault(); + if (form.username !== "" && form.password !== "") { setSubmitLoader(true); @@ -47,67 +49,73 @@ export default function Login() { return ( -
-

- Enter your credentials -

- -
-

- Username - {emailEnabled ? " or Email" : undefined} +

+
+

+ Enter your credentials

- setForm({ ...form, username: e.target.value })} - /> -
+
+

+ Username + {emailEnabled ? " or Email" : undefined} +

-
-

- Password -

+ setForm({ ...form, username: e.target.value })} + /> +
- setForm({ ...form, password: e.target.value })} +
+

+ Password +

+ + setForm({ ...form, password: e.target.value })} + /> + {emailEnabled && ( +
+ + Forgot Password? + +
+ )} +
+ + - {emailEnabled && ( -
+ {process.env.NEXT_PUBLIC_DISABLE_REGISTRATION === + "true" ? undefined : ( +
+

+ New here? +

- Forgot Password? + Sign Up
)}
- - - {process.env.NEXT_PUBLIC_DISABLE_REGISTRATION === "true" ? undefined : ( -
-

New here?

- - Sign Up - -
- )} -
+
); } diff --git a/pages/register.tsx b/pages/register.tsx index c279e97..bd82b2e 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -1,5 +1,5 @@ import Link from "next/link"; -import { useState } from "react"; +import { useState, FormEvent } from "react"; import { toast } from "react-hot-toast"; import SubmitButton from "@/components/SubmitButton"; import { signIn } from "next-auth/react"; @@ -29,7 +29,9 @@ export default function Register() { passwordConfirmation: "", }); - async function registerUser() { + async function registerUser(event: FormEvent) { + event.preventDefault(); + const checkFields = () => { if (emailEnabled) { return ( @@ -107,134 +109,139 @@ export default function Register() {

) : ( -
-

- Enter your details -

-
-

- Display Name +

+
+

+ Enter your details

- - setForm({ ...form, name: e.target.value })} - /> -
- - {emailEnabled ? undefined : (

- Username + Display Name

setForm({ ...form, username: e.target.value })} + onChange={(e) => setForm({ ...form, name: e.target.value })} />
- )} - {emailEnabled ? ( -
-

- Email + {emailEnabled ? undefined : ( +

+

+ Username +

+ + + setForm({ ...form, username: e.target.value }) + } + /> +
+ )} + + {emailEnabled ? ( +
+

+ Email +

+ + setForm({ ...form, email: e.target.value })} + /> +
+ ) : undefined} + +
+

+ Password

setForm({ ...form, email: e.target.value })} + onChange={(e) => setForm({ ...form, password: e.target.value })} />
- ) : undefined} -
-

- Password -

- - setForm({ ...form, password: e.target.value })} - /> -
- -
-

- Confirm Password -

- - - setForm({ ...form, passwordConfirmation: e.target.value }) - } - /> -
- - {process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE ? ( -
-

- By signing up, you agree to our{" "} - - Terms of Service - {" "} - and{" "} - - Privacy Policy - - . -

-

- Need help?{" "} - - Get in touch - - . +

+

+ Confirm Password

+ + + setForm({ ...form, passwordConfirmation: e.target.value }) + } + />
- ) : undefined} - -
-

- Already have an account? -

- - Login - + {process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE ? ( +
+

+ By signing up, you agree to our{" "} + + Terms of Service + {" "} + and{" "} + + Privacy Policy + + . +

+

+ Need help?{" "} + + Get in touch + + . +

+
+ ) : undefined} + + +
+

+ Already have an account? +

+ + Login + +
-
+ )} );