diff --git a/components/Modal/User/ChangePassword.tsx b/components/Modal/User/ChangePassword.tsx index 0cb2168..55e8c60 100644 --- a/components/Modal/User/ChangePassword.tsx +++ b/components/Modal/User/ChangePassword.tsx @@ -80,16 +80,16 @@ export default function ChangePassword({ value={newPassword} onChange={(e) => setNewPassword1(e.target.value)} type="password" - placeholder="*****************" + placeholder="***********" className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" /> -

Re-enter New Password

+

Confirm New Password

setNewPassword2(e.target.value)} type="password" - placeholder="*****************" + placeholder="***********" className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" /> diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index 5263ece..b576344 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -2,7 +2,6 @@ import useCollectionStore from "@/store/collections"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faFolder, - faBox, faHashtag, faChartSimple, faChevronDown, @@ -13,6 +12,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import { Disclosure, Transition } from "@headlessui/react"; +import Image from "next/image"; export default function Sidebar({ className }: { className?: string }) { const [tagDisclosure, setTagDisclosure] = useState(() => { @@ -53,55 +53,50 @@ export default function Sidebar({ className }: { className?: string }) {
-

- Linkwarden -

- -
- -
- -

Dashboard

-
+
+ + +

Dashboard

- -
- -

All Links

-
+ + +

All Links

- -
- -

All Collections

-
+ + +

+ All Collections +

diff --git a/layouts/AuthRedirect.tsx b/layouts/AuthRedirect.tsx index 916dc03..4fb32e5 100644 --- a/layouts/AuthRedirect.tsx +++ b/layouts/AuthRedirect.tsx @@ -20,14 +20,22 @@ export default function AuthRedirect({ children }: Props) { if (!router.pathname.startsWith("/public")) { if ( status === "authenticated" && - (router.pathname === "/login" || router.pathname === "/register") + (router.pathname === "/login" || + router.pathname === "/register" || + router.pathname === "/confirmation" || + router.pathname === "/forgot") ) { router.push("/").then(() => { setRedirect(false); }); } else if ( status === "unauthenticated" && - !(router.pathname === "/login" || router.pathname === "/register") + !( + router.pathname === "/login" || + router.pathname === "/register" || + router.pathname === "/confirmation" || + router.pathname === "/forgot" + ) ) { router.push("/login").then(() => { setRedirect(false); diff --git a/lib/api/sendVerificationRequest.ts b/lib/api/sendVerificationRequest.ts index 4cb85a2..b51db86 100644 --- a/lib/api/sendVerificationRequest.ts +++ b/lib/api/sendVerificationRequest.ts @@ -5,8 +5,6 @@ import { createTransport } from "nodemailer"; export default async function sendVerificationRequest( params: SendVerificationRequestParams ) { - console.log(params); - const { identifier, url, provider, theme } = params; const { host } = new URL(url); const transport = createTransport(provider.server); diff --git a/lib/client/addMemberToCollection.ts b/lib/client/addMemberToCollection.ts index bccd2d3..deb7fa0 100644 --- a/lib/client/addMemberToCollection.ts +++ b/lib/client/addMemberToCollection.ts @@ -19,7 +19,7 @@ const addMemberToCollection = async ( // member can't be empty memberUsername.trim() !== "" && // member can't be the owner - memberUsername.trim() !== ownerUsername + memberUsername.trim().toLowerCase() !== ownerUsername.toLowerCase() ) { // Lookup, get data/err, list ... const user = await getPublicUserDataByUsername( @@ -40,7 +40,7 @@ const addMemberToCollection = async ( }); } } else if (checkIfMemberAlreadyExists) toast.error("User already exists."); - else if (memberUsername.trim() === ownerUsername) + else if (memberUsername.trim().toLowerCase() === ownerUsername.toLowerCase()) toast.error("You are already the collection owner."); }; diff --git a/package.json b/package.json index 0ee6670..5e33803 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "@types/nodemailer": "^6.4.8", "@types/react": "18.2.14", "@types/react-dom": "18.2.6", - "bcrypt": "^5.1.0", "colorthief": "^2.4.0", "crypto-js": "^4.1.1", diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 3f2d8ef..fc66184 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -10,6 +10,8 @@ import { Adapter } from "next-auth/adapters"; import sendVerificationRequest from "@/lib/api/sendVerificationRequest"; import { Provider } from "next-auth/providers"; +let email; + const providers: Provider[] = [ CredentialsProvider({ type: "credentials", @@ -63,6 +65,7 @@ if (process.env.EMAIL_SERVER && process.env.EMAIL_FROM) from: process.env.EMAIL_FROM, maxAge: 600, sendVerificationRequest(params) { + email = params.identifier; sendVerificationRequest(params); }, }) @@ -76,6 +79,7 @@ export const authOptions: AuthOptions = { providers, pages: { signIn: "/login", + verifyRequest: "/confirmation", }, callbacks: { session: async ({ session, token }: { session: Session; token: JWT }) => { diff --git a/pages/collections/index.tsx b/pages/collections/index.tsx index adbe3bc..6c7c526 100644 --- a/pages/collections/index.tsx +++ b/pages/collections/index.tsx @@ -1,7 +1,7 @@ import useCollectionStore from "@/store/collections"; import { - faBox, faEllipsis, + faFolder, faPlus, faSort, } from "@fortawesome/free-solid-svg-icons"; @@ -36,7 +36,7 @@ export default function Collections() {

diff --git a/components/Modal/EmailConfirmaion.tsx b/pages/confirmation.tsx similarity index 69% rename from components/Modal/EmailConfirmaion.tsx rename to pages/confirmation.tsx index 966287b..1c9a657 100644 --- a/components/Modal/EmailConfirmaion.tsx +++ b/pages/confirmation.tsx @@ -1,23 +1,24 @@ import { signIn } from "next-auth/react"; import React from "react"; -export default function EmailConfirmaion({ email }: { email: string }) { +export default function EmailConfirmaion() { return (

-
+

Please check your email

A sign in link has been sent to your email address.

-
You can safely close this page.

+ {/*
signIn("email", { - email, + email: email, redirect: false, }) } className="mx-auto font-semibold mt-2 cursor-pointer w-fit" > Resend? -
+
*/}
); diff --git a/pages/forgot.tsx b/pages/forgot.tsx index 2ae2029..5d5557d 100644 --- a/pages/forgot.tsx +++ b/pages/forgot.tsx @@ -1,6 +1,6 @@ -import EmailConfirmaion from "@/components/Modal/EmailConfirmaion"; import SubmitButton from "@/components/SubmitButton"; import { signIn } from "next-auth/react"; +import Image from "next/image"; import Link from "next/link"; import { useState } from "react"; import { toast } from "react-hot-toast"; @@ -11,7 +11,6 @@ interface FormData { export default function Forgot() { const [submitLoader, setSubmitLoader] = useState(false); - const [showConfirmation, setShowConfirmation] = useState(false); const [form, setForm] = useState({ email: "", @@ -23,20 +22,16 @@ export default function Forgot() { const load = toast.loading("Sending login link..."); - const res = await signIn("email", { + await signIn("email", { email: form.email, - callbackUrl: window.location.origin, + callbackUrl: "/", }); - setShowConfirmation(true); - toast.dismiss(load); setSubmitLoader(false); - if (!res?.ok) { - toast.error("Invalid login."); - } + toast.success("Login link sent."); } else { toast.error("Please fill out all the fields."); } @@ -44,30 +39,35 @@ export default function Forgot() { return ( <> - {showConfirmation && form.email ? ( - - ) : undefined} -

- Linkwarden -

-
-
-

Password reset

+
+
+ Linkwarden +
+

Password Reset

+
-

Email

+
+

Email

- setForm({ ...form, email: e.target.value })} - className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" - /> - -

- Make sure to change your password in the profile settings afterwards. -

+ setForm({ ...form, email: e.target.value })} + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + /> +

+ Make sure to change your password in the profile settings + afterwards. +

+
-
-
- - Go back - +
+ + Go back + +
); diff --git a/pages/login.tsx b/pages/login.tsx index 89a9b85..24d7412 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -1,5 +1,6 @@ import SubmitButton from "@/components/SubmitButton"; import { signIn } from "next-auth/react"; +import Image from "next/image"; import Link from "next/link"; import { useState } from "react"; import { toast } from "react-hot-toast"; @@ -45,60 +46,72 @@ export default function Login() { return ( <> -

- Linkwarden -

-
-
-

Welcome back

-

- Sign in to your account -

+
+
+ Linkwarden +
+

Welcome back

+

+ Sign in to your account +

+
-

- Username - {EmailProvider ? " or Email" : undefined} -

+
+

+ Username + {EmailProvider ? "/Email" : undefined} +

- setForm({ ...form, username: e.target.value })} - className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" - /> + setForm({ ...form, username: e.target.value })} + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + /> +
-

Password

+
+

+ Password +

+ + setForm({ ...form, password: e.target.value })} + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + /> + {EmailProvider && ( +
+ + Forgot Password? + +
+ )} +
- setForm({ ...form, password: e.target.value })} - className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" - /> -
-
-

New here?

- - Sign Up - -
- {EmailProvider && ( -
-

Forgot your password?

- - Send login link +
+

New here?

+ + Sign Up
- )} +
); } diff --git a/pages/public/collections/[id].tsx b/pages/public/collections/[id].tsx index 2f06612..2f6e32f 100644 --- a/pages/public/collections/[id].tsx +++ b/pages/public/collections/[id].tsx @@ -63,9 +63,9 @@ export default function PublicCollections() { })}
-

+ {/*

List created with Linkwarden. -

+

*/}
) : ( <> diff --git a/pages/register.tsx b/pages/register.tsx index 8e22b76..60ee1fe 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import { toast } from "react-hot-toast"; import SubmitButton from "@/components/SubmitButton"; import { signIn } from "next-auth/react"; -import EmailConfirmaion from "@/components/Modal/EmailConfirmaion"; +import Image from "next/image"; const EmailProvider = process.env.NEXT_PUBLIC_EMAIL_PROVIDER; @@ -17,7 +17,6 @@ type FormData = { export default function Register() { const [submitLoader, setSubmitLoader] = useState(false); - const [showConfirmation, setShowConfirmation] = useState(false); const [form, setForm] = useState({ name: "", @@ -50,7 +49,7 @@ export default function Register() { const sendConfirmation = async () => { await signIn("email", { email: form.email, - redirect: false, + callbackUrl: "/", }); }; @@ -76,10 +75,7 @@ export default function Register() { setSubmitLoader(false); if (response.ok) { - if (form.email) { - await sendConfirmation(); - setShowConfirmation(true); - } + if (form.email) await sendConfirmation(); toast.success( EmailProvider @@ -99,89 +95,110 @@ export default function Register() { return ( <> - {showConfirmation && form.email ? ( - - ) : undefined} -

- Linkwarden -

-
-
-

Get started

-

- Create a new account -

+
+
+ Linkwarden +
+

Get started

+

+ Create a new account +

+
-

Display Name

+
+

+ Display Name +

- setForm({ ...form, name: e.target.value })} - className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" - /> + setForm({ ...form, name: e.target.value })} + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + /> +
-

Username

+
+

+ Username +

- setForm({ ...form, username: e.target.value })} - className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" - /> + setForm({ ...form, username: e.target.value })} + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + /> +
{EmailProvider ? ( - <> -

Email

+
+

+ Email +

setForm({ ...form, email: e.target.value })} - className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" /> - +
) : undefined} -

Password

+
+
+

+ Password +

- setForm({ ...form, password: e.target.value })} - className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" - /> + setForm({ ...form, password: e.target.value })} + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + /> +
-

- Re-enter Password -

+
+

+ Confirm Password +

- - setForm({ ...form, passwordConfirmation: e.target.value }) - } - className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" - /> + + setForm({ ...form, passwordConfirmation: e.target.value }) + } + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + /> +
+
-
-
-

Already have an account?

- - Login - +
+

Already have an account?

+ + Login + +
); diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png index e20c59d..1cb2d49 100644 Binary files a/public/android-chrome-192x192.png and b/public/android-chrome-192x192.png differ diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png index 6e77e38..a2045ff 100644 Binary files a/public/android-chrome-512x512.png and b/public/android-chrome-512x512.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index 962a140..4bd72ca 100644 Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png index 5fae853..6236e5c 100644 Binary files a/public/favicon-16x16.png and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png index 0fa9a5b..9509579 100644 Binary files a/public/favicon-32x32.png and b/public/favicon-32x32.png differ diff --git a/public/favicon.ico b/public/favicon.ico index 65bcb6d..40c5ef7 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/icon.png b/public/icon.png index e61f111..f55c193 100644 Binary files a/public/icon.png and b/public/icon.png differ diff --git a/public/linkwarden.png b/public/linkwarden.png new file mode 100644 index 0000000..7eed5ea Binary files /dev/null and b/public/linkwarden.png differ diff --git a/public/site.webmanifest b/public/site.webmanifest index fa99de7..45dc8a2 100644 --- a/public/site.webmanifest +++ b/public/site.webmanifest @@ -1,19 +1 @@ -{ - "name": "", - "short_name": "", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file