added settings modal UI

This commit is contained in:
Daniel 2023-05-18 21:32:17 +03:30
parent a5d0d08c93
commit e3862188de
15 changed files with 74 additions and 24 deletions

View File

@ -5,12 +5,15 @@ import { ChangeEventHandler } from "react";
type Props = { type Props = {
label: string; label: string;
state: boolean; state: boolean;
className?: string;
onClick: ChangeEventHandler<HTMLInputElement>; onClick: ChangeEventHandler<HTMLInputElement>;
}; };
export default function Checkbox({ label, state, onClick }: Props) { export default function Checkbox({ label, state, className, onClick }: Props) {
return ( return (
<label className="cursor-pointer flex items-center gap-2 text-sky-500"> <label
className={`cursor-pointer flex items-center gap-2 text-sky-500 ${className}`}
>
<input <input
type="checkbox" type="checkbox"
checked={state} checked={state}

View File

@ -46,7 +46,7 @@ export default function AddCollection({ toggleCollectionModal }: Props) {
return ( return (
<div className="flex flex-col gap-3 sm:w-[35rem] w-80"> <div className="flex flex-col gap-3 sm:w-[35rem] w-80">
<p className="font-bold text-sky-300 mb-3 text-center">New Collection</p> <p className="text-xl text-sky-500 mb-2 text-center">New Collection</p>
<div className="flex flex-col sm:flex-row gap-3"> <div className="flex flex-col sm:flex-row gap-3">
<div className="w-full"> <div className="w-full">

View File

@ -78,7 +78,7 @@ export default function AddLink({ toggleLinkModal }: Props) {
return ( return (
<div className="flex flex-col gap-3 sm:w-[35rem] w-80"> <div className="flex flex-col gap-3 sm:w-[35rem] w-80">
<p className="font-bold text-sky-300 mb-2 text-center">New Link</p> <p className="text-xl text-sky-500 mb-2 text-center">New Link</p>
<div className="grid sm:grid-cols-2 gap-3"> <div className="grid sm:grid-cols-2 gap-3">
<div> <div>

View File

@ -11,12 +11,12 @@ import useCollectionStore from "@/store/collections";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
type Props = { type Props = {
toggleCollectionModal: Function; toggleDeleteCollectionModal: Function;
collection: ExtendedCollection; collection: ExtendedCollection;
}; };
export default function AddCollection({ export default function AddCollection({
toggleCollectionModal, toggleDeleteCollectionModal,
collection, collection,
}: Props) { }: Props) {
const [inputField, setInputField] = useState(""); const [inputField, setInputField] = useState("");
@ -28,14 +28,14 @@ export default function AddCollection({
const submit = async () => { const submit = async () => {
const response = await removeCollection(collection.id); const response = await removeCollection(collection.id);
if (response) { if (response) {
toggleCollectionModal(); toggleDeleteCollectionModal();
router.push("/collections"); router.push("/collections");
} }
}; };
return ( return (
<div className="flex flex-col gap-3 sm:w-[33rem] w-72"> <div className="flex flex-col gap-3 sm:w-[33rem] w-72">
<p className="font-bold text-sky-300 text-center">Delete Collection</p> <p className="text-xl text-sky-500 mb-2 text-center">Delete Collection</p>
<p className="text-sky-900 select-none text-center"> <p className="text-sky-900 select-none text-center">
To confirm, type " To confirm, type "

View File

@ -54,7 +54,7 @@ export default function EditCollection({
return ( return (
<div className="flex flex-col gap-3 sm:w-[35rem] w-80"> <div className="flex flex-col gap-3 sm:w-[35rem] w-80">
<p className="font-bold text-sky-300 mb-2 text-center">Edit Collection</p> <p className="text-xl text-sky-500 mb-2 text-center">Edit Collection</p>
<div className="flex flex-col sm:flex-row gap-3"> <div className="flex flex-col sm:flex-row gap-3">
<div className="w-full"> <div className="w-full">
@ -297,7 +297,7 @@ export default function EditCollection({
<Modal toggleModal={toggleDeleteCollectionModal}> <Modal toggleModal={toggleDeleteCollectionModal}>
<DeleteCollection <DeleteCollection
collection={activeCollection} collection={activeCollection}
toggleCollectionModal={toggleDeleteCollectionModal} toggleDeleteCollectionModal={toggleDeleteCollectionModal}
/> />
</Modal> </Modal>
) : null} ) : null}

View File

@ -49,7 +49,7 @@ export default function EditLink({ toggleLinkModal, link }: Props) {
return ( return (
<div className="flex flex-col gap-3 sm:w-96 w-80"> <div className="flex flex-col gap-3 sm:w-96 w-80">
<p className="font-bold text-sky-300 mb-2 text-center">Edit Link</p> <p className="text-xl text-sky-500 mb-2 text-center">Edit Link</p>
<p className="text-sky-700"> <p className="text-sky-700">
<b>{shortendURL}</b> | {link.title} <b>{shortendURL}</b> | {link.title}
</p> </p>

View File

@ -56,6 +56,7 @@ export default function () {
}; };
return ( return (
// lg:ml-64 xl:ml-80
<div className="flex justify-between gap-2 items-center px-5 py-2 border-solid border-b-sky-100 border-b"> <div className="flex justify-between gap-2 items-center px-5 py-2 border-solid border-b-sky-100 border-b">
<div <div
onClick={toggleSidebar} onClick={toggleSidebar}

View File

@ -5,21 +5,28 @@
import { prisma } from "@/lib/api/db"; import { prisma } from "@/lib/api/db";
export default async function (email: string) { export default async function (lookupEmail: string, isSelf: boolean) {
const user = await prisma.user.findUnique({ const user = await prisma.user.findUnique({
where: { where: {
email, email: lookupEmail,
}, },
}); });
const unsensitiveUserInfo = { const data = isSelf
? {
// If user is requesting its data
id: user?.id,
name: user?.name,
email: user?.email,
}
: {
// If user is requesting someone elses data
id: user?.id, id: user?.id,
name: user?.name, name: user?.name,
email: user?.email, email: user?.email,
createdAt: user?.createdAt,
}; };
const statusCode = user?.id ? 200 : 404; const statusCode = user?.id ? 200 : 404;
return { response: unsensitiveUserInfo || null, status: statusCode }; return { response: data || null, status: statusCode };
} }

View File

@ -8,18 +8,21 @@ import { useEffect } from "react";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import useTagStore from "@/store/tags"; import useTagStore from "@/store/tags";
import useLinkStore from "@/store/links"; import useLinkStore from "@/store/links";
import useAccountStore from "@/store/account";
export default function () { export default function () {
const { status } = useSession(); const { status, data } = useSession();
const { setCollections } = useCollectionStore(); const { setCollections } = useCollectionStore();
const { setTags } = useTagStore(); const { setTags } = useTagStore();
const { setLinks } = useLinkStore(); const { setLinks } = useLinkStore();
const { setAccount } = useAccountStore();
useEffect(() => { useEffect(() => {
if (status === "authenticated") { if (status === "authenticated") {
setCollections(); setCollections();
setTags(); setTags();
setLinks(); setLinks();
setAccount(data.user.email as string);
} }
}, [status]); }, [status]);
} }

View File

@ -15,9 +15,12 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
return res.status(401).json({ response: "You must be logged in." }); return res.status(401).json({ response: "You must be logged in." });
} }
const lookupEmail = req.query.email as string;
const isSelf = session.user.email === lookupEmail ? true : false;
// get unsensitive user info by email // get unsensitive user info by email
if (req.method === "GET") { if (req.method === "GET") {
const users = await getUsers(req.query.email as string); const users = await getUsers(lookupEmail, isSelf);
return res.status(users.status).json({ response: users.response }); return res.status(users.status).json({ response: users.response });
} }
} }

View File

@ -175,7 +175,7 @@ export default function () {
<Modal toggleModal={toggleDeleteCollectionModal}> <Modal toggleModal={toggleDeleteCollectionModal}>
<DeleteCollection <DeleteCollection
collection={activeCollection} collection={activeCollection}
toggleCollectionModal={toggleDeleteCollectionModal} toggleDeleteCollectionModal={toggleDeleteCollectionModal}
/> />
</Modal> </Modal>
) : null} ) : null}

View File

@ -0,0 +1,4 @@
-- AlterTable
ALTER TABLE "User" ADD COLUMN "collectionProtection" BOOLEAN NOT NULL DEFAULT true,
ADD COLUMN "profilePhotoPath" TEXT NOT NULL DEFAULT '',
ADD COLUMN "whitelistedUsers" TEXT[] DEFAULT ARRAY[]::TEXT[];

View File

@ -20,6 +20,9 @@ model User {
collections Collection[] collections Collection[]
tags Tag[] tags Tag[]
collectionsJoined UsersAndCollections[] collectionsJoined UsersAndCollections[]
collectionProtection Boolean @default(true)
whitelistedUsers String[] @default([])
profilePhotoPath String @default("")
createdAt DateTime @default(now()) createdAt DateTime @default(now())
} }

27
store/account.ts Normal file
View File

@ -0,0 +1,27 @@
// Copyright (C) 2022-present Daniel31x13 <daniel31x13@gmail.com>
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
import { create } from "zustand";
import { User } from "@prisma/client";
type AccountStore = {
account: User;
setAccount: (email: string) => void;
};
const useAccountStore = create<AccountStore>()((set) => ({
account: {} as User,
setAccount: async (email) => {
const response = await fetch(`/api/routes/users?email=${email}`);
const data = await response.json();
console.log(data);
if (response.ok) set({ account: data.response });
},
}));
export default useAccountStore;

View File

@ -5,7 +5,6 @@
import { create } from "zustand"; import { create } from "zustand";
import { Tag } from "@prisma/client"; import { Tag } from "@prisma/client";
import tags from "@/pages/api/routes/tags";
type TagStore = { type TagStore = {
tags: Tag[]; tags: Tag[];