diff --git a/components/LinkCard.tsx b/components/LinkCard.tsx index 1e26b78..0658ea7 100644 --- a/components/LinkCard.tsx +++ b/components/LinkCard.tsx @@ -20,6 +20,7 @@ import usePermissions from "@/hooks/usePermissions"; import { toast } from "react-hot-toast"; import isValidUrl from "@/lib/client/isValidUrl"; import Link from "next/link"; +import unescapeString from "@/lib/client/unescapeString"; type Props = { link: LinkIncludingShortenedCollectionAndTags; @@ -161,7 +162,7 @@ export default function LinkCard({ link, count, className }: Props) { {count + 1}

- {link.name || link.description} + {unescapeString(link.name || link.description)}

{count + 1}

- {link.name || link.description} + {unescapeString(link.name || link.description)}

- {link.description} + {unescapeString(link.description)}

diff --git a/components/SettingsSidebar.tsx b/components/SettingsSidebar.tsx index 3852b2e..795132a 100644 --- a/components/SettingsSidebar.tsx +++ b/components/SettingsSidebar.tsx @@ -34,7 +34,7 @@ export default function SettingsSidebar({ className }: { className?: string }) { return (
diff --git a/components/SubmitButton.tsx b/components/SubmitButton.tsx index 93d85c8..8a06eac 100644 --- a/components/SubmitButton.tsx +++ b/components/SubmitButton.tsx @@ -27,8 +27,8 @@ export default function SubmitButton({ if (!loading) onClick(); }} > - {icon && } -

{label}

+ {icon && } +

{label}

); } diff --git a/layouts/SettingsLayout.tsx b/layouts/SettingsLayout.tsx index ae5c08f..80a7ed8 100644 --- a/layouts/SettingsLayout.tsx +++ b/layouts/SettingsLayout.tsx @@ -5,7 +5,8 @@ import useModalStore from "@/store/modals"; import { useRouter } from "next/router"; import ClickAwayHandler from "@/components/ClickAwayHandler"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faBars } from "@fortawesome/free-solid-svg-icons"; +import { faBars, faChevronLeft } from "@fortawesome/free-solid-svg-icons"; +import Link from "next/link"; interface Props { children: ReactNode; @@ -38,12 +39,12 @@ export default function SettingsLayout({ children }: Props) { <> -
+
- +
-
+
+ + + +

{router.asPath.split("/").pop()} Settings

-
+
{children} {sidebar ? ( diff --git a/pages/_app.tsx b/pages/_app.tsx index 7e8dd7c..f5966b4 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -52,7 +52,7 @@ export default function App({ reverseOrder={false} toastOptions={{ className: - "border border-sky-100 dark:dark:border-neutral-700 dark:bg-neutral-900 dark:text-white", + "border border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 dark:text-white", }} /> diff --git a/pages/settings/profile.tsx b/pages/settings/profile.tsx index ae776ca..7cc3f8b 100644 --- a/pages/settings/profile.tsx +++ b/pages/settings/profile.tsx @@ -1,10 +1,183 @@ +import { useState, useEffect } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faClose, faPenToSquare } from "@fortawesome/free-solid-svg-icons"; +import useAccountStore from "@/store/account"; +import { AccountSettings } from "@/types/global"; +import { toast } from "react-hot-toast"; import SettingsLayout from "@/layouts/SettingsLayout"; -import React from "react"; +import TextInput from "@/components/TextInput"; +import { resizeImage } from "@/lib/client/resizeImage"; +import ProfilePhoto from "@/components/ProfilePhoto"; +import SubmitButton from "@/components/SubmitButton"; +import { useSession, signOut } from "next-auth/react"; export default function profile() { + const { update, data } = useSession(); + + const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER; + + const [profileStatus, setProfileStatus] = useState(true); + const [submitLoader, setSubmitLoader] = useState(false); + + const handleProfileStatus = (e: boolean) => { + setProfileStatus(!e); + }; + + const { account, updateAccount } = useAccountStore(); + + const [user, setUser] = useState({ + ...account, + }); + + useEffect(() => { + setUser({ ...account }); + }, [account]); + + const handleImageUpload = async (e: any) => { + const file: File = e.target.files[0]; + const fileExtension = file.name.split(".").pop()?.toLowerCase(); + const allowedExtensions = ["png", "jpeg", "jpg"]; + if (allowedExtensions.includes(fileExtension as string)) { + const resizedFile = await resizeImage(file); + if ( + resizedFile.size < 1048576 // 1048576 Bytes == 1MB + ) { + const reader = new FileReader(); + reader.onload = () => { + setUser({ ...user, profilePic: reader.result as string }); + }; + reader.readAsDataURL(resizedFile); + } else { + toast.error("Please select a PNG or JPEG file thats less than 1MB."); + } + } else { + toast.error("Invalid file format."); + } + }; + + const submit = async () => { + setSubmitLoader(true); + + const load = toast.loading("Applying..."); + + const response = await updateAccount({ + ...user, + }); + + toast.dismiss(load); + + if (response.ok) { + toast.success("Settings Applied!"); + + if (user.email !== account.email) { + update({ + id: data?.user.id, + }); + + signOut(); + } else if ( + user.username !== account.username || + user.name !== account.name + ) + update({ + id: data?.user.id, + }); + + setUser({ ...user, newPassword: undefined }); + } else toast.error(response.data as string); + setSubmitLoader(false); + }; + return ( -
profile
+
+
+
+
+

+ Display Name +

+ setUser({ ...user, name: e.target.value })} + /> +
+
+

+ Username +

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

Email

+ setUser({ ...user, email: e.target.value })} + /> +
+ ) : undefined} + + {user.email !== account.email ? ( +

+ You will need to log back in after you apply this Email. +

+ ) : undefined} +
+ +
+

+ Profile Photo +

+
+ + {profileStatus && ( +
+ setUser({ + ...user, + profilePic: "", + }) + } + className="absolute top-1 left-1 w-5 h-5 flex items-center justify-center border p-1 border-slate-200 dark:border-neutral-700 rounded-full bg-white dark:bg-neutral-800 text-center select-none cursor-pointer duration-100 hover:text-red-500" + > + +
+ )} +
+ +
+
+
+
+ + +
); }