refactor account store + much smoother collection listing updates

This commit is contained in:
daniel31x13 2024-07-30 23:19:29 -04:00
parent d1ed33b532
commit 5c5dd967c4
31 changed files with 260 additions and 259 deletions

View File

@ -5,12 +5,12 @@ import ProfilePhoto from "./ProfilePhoto";
import usePermissions from "@/hooks/usePermissions"; import usePermissions from "@/hooks/usePermissions";
import useLocalSettingsStore from "@/store/localSettings"; import useLocalSettingsStore from "@/store/localSettings";
import getPublicUserData from "@/lib/client/getPublicUserData"; import getPublicUserData from "@/lib/client/getPublicUserData";
import useAccountStore from "@/store/account";
import EditCollectionModal from "./ModalContent/EditCollectionModal"; import EditCollectionModal from "./ModalContent/EditCollectionModal";
import EditCollectionSharingModal from "./ModalContent/EditCollectionSharingModal"; import EditCollectionSharingModal from "./ModalContent/EditCollectionSharingModal";
import DeleteCollectionModal from "./ModalContent/DeleteCollectionModal"; import DeleteCollectionModal from "./ModalContent/DeleteCollectionModal";
import { dropdownTriggerer } from "@/lib/client/utils"; import { dropdownTriggerer } from "@/lib/client/utils";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useUser } from "@/hooks/store/users";
type Props = { type Props = {
collection: CollectionIncludingMembersAndLinkCount; collection: CollectionIncludingMembersAndLinkCount;
@ -20,7 +20,7 @@ type Props = {
export default function CollectionCard({ collection, className }: Props) { export default function CollectionCard({ collection, className }: Props) {
const { t } = useTranslation(); const { t } = useTranslation();
const { settings } = useLocalSettingsStore(); const { settings } = useLocalSettingsStore();
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const formattedDate = new Date(collection.createdAt as string).toLocaleString( const formattedDate = new Date(collection.createdAt as string).toLocaleString(
"en-US", "en-US",
@ -45,18 +45,18 @@ export default function CollectionCard({ collection, className }: Props) {
useEffect(() => { useEffect(() => {
const fetchOwner = async () => { const fetchOwner = async () => {
if (collection && collection.ownerId !== account.id) { if (collection && collection.ownerId !== user.id) {
const owner = await getPublicUserData(collection.ownerId as number); const owner = await getPublicUserData(collection.ownerId as number);
setCollectionOwner(owner); setCollectionOwner(owner);
} else if (collection && collection.ownerId === account.id) { } else if (collection && collection.ownerId === user.id) {
setCollectionOwner({ setCollectionOwner({
id: account.id as number, id: user.id as number,
name: account.name, name: user.name,
username: account.username as string, username: user.username as string,
image: account.image as string, image: user.image as string,
archiveAsScreenshot: account.archiveAsScreenshot as boolean, archiveAsScreenshot: user.archiveAsScreenshot as boolean,
archiveAsMonolith: account.archiveAsMonolith as boolean, archiveAsMonolith: user.archiveAsMonolith as boolean,
archiveAsPDF: account.archiveAsPDF as boolean, archiveAsPDF: user.archiveAsPDF as boolean,
}); });
} }
}; };

View File

@ -13,10 +13,10 @@ import { Collection } from "@prisma/client";
import Link from "next/link"; import Link from "next/link";
import { CollectionIncludingMembersAndLinkCount } from "@/types/global"; import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useAccountStore from "@/store/account";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useCollections, useUpdateCollection } from "@/hooks/store/collections"; import { useCollections, useUpdateCollection } from "@/hooks/store/collections";
import { useUpdateUser, useUser } from "@/hooks/store/users";
interface ExtendedTreeItem extends TreeItem { interface ExtendedTreeItem extends TreeItem {
data: Collection; data: Collection;
@ -25,54 +25,56 @@ interface ExtendedTreeItem extends TreeItem {
const CollectionListing = () => { const CollectionListing = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const updateCollection = useUpdateCollection(); const updateCollection = useUpdateCollection();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const { account, updateAccount } = useAccountStore(); const { data: user = [] } = useUser();
const updateUser = useUpdateUser();
const router = useRouter(); const router = useRouter();
const currentPath = router.asPath; const currentPath = router.asPath;
const [tree, setTree] = useState<TreeData | undefined>();
const initialTree = useMemo(() => { const initialTree = useMemo(() => {
if (collections.length > 0) { if (
// !tree &&
collections.length > 0
) {
return buildTreeFromCollections( return buildTreeFromCollections(
collections, collections,
router, router,
account.collectionOrder user.collectionOrder
); );
} } else return undefined;
return undefined; }, [collections, user, router]);
}, [collections, router]);
const [tree, setTree] = useState(initialTree);
useEffect(() => { useEffect(() => {
// if (!tree)
setTree(initialTree); setTree(initialTree);
}, [initialTree]); }, [initialTree]);
useEffect(() => { useEffect(() => {
if (account.username) { if (user.username) {
if ( if (
(!account.collectionOrder || account.collectionOrder.length === 0) && (!user.collectionOrder || user.collectionOrder.length === 0) &&
collections.length > 0 collections.length > 0
) )
updateAccount({ updateUser.mutate({
...account, ...user,
collectionOrder: collections collectionOrder: collections
.filter( .filter(
(e) => (e) =>
e.parentId === null || e.parentId === null ||
!collections.find((i) => i.id === e.parentId) !collections.find((i) => i.id === e.parentId)
) // Filter out collections with non-null parentId ) // Filter out collections with non-null parentId
.map((e) => e.id as number), // Use "as number" to assert that e.id is a number .map((e) => e.id as number),
}); });
else { else {
const newCollectionOrder: number[] = [ const newCollectionOrder: number[] = [...(user.collectionOrder || [])];
...(account.collectionOrder || []),
];
// Start with collections that are in both account.collectionOrder and collections // Start with collections that are in both account.collectionOrder and collections
const existingCollectionIds = collections.map((c) => c.id as number); const existingCollectionIds = collections.map((c) => c.id as number);
const filteredCollectionOrder = account.collectionOrder.filter((id) => const filteredCollectionOrder = user.collectionOrder.filter((id: any) =>
existingCollectionIds.includes(id) existingCollectionIds.includes(id)
); );
@ -80,7 +82,7 @@ const CollectionListing = () => {
collections.forEach((collection) => { collections.forEach((collection) => {
if ( if (
!filteredCollectionOrder.includes(collection.id as number) && !filteredCollectionOrder.includes(collection.id as number) &&
(!collection.parentId || collection.ownerId === account.id) (!collection.parentId || collection.ownerId === user.id)
) { ) {
filteredCollectionOrder.push(collection.id as number); filteredCollectionOrder.push(collection.id as number);
} }
@ -89,10 +91,10 @@ const CollectionListing = () => {
// check if the newCollectionOrder is the same as the old one // check if the newCollectionOrder is the same as the old one
if ( if (
JSON.stringify(newCollectionOrder) !== JSON.stringify(newCollectionOrder) !==
JSON.stringify(account.collectionOrder) JSON.stringify(user.collectionOrder)
) { ) {
updateAccount({ updateUser.mutateAsync({
...account, ...user,
collectionOrder: newCollectionOrder, collectionOrder: newCollectionOrder,
}); });
} }
@ -140,9 +142,9 @@ const CollectionListing = () => {
); );
if ( if (
(movedCollection?.ownerId !== account.id && (movedCollection?.ownerId !== user.id &&
destination.parentId !== source.parentId) || destination.parentId !== source.parentId) ||
(destinationCollection?.ownerId !== account.id && (destinationCollection?.ownerId !== user.id &&
destination.parentId !== "root") destination.parentId !== "root")
) { ) {
return toast.error(t("cant_change_collection_you_dont_own")); return toast.error(t("cant_change_collection_you_dont_own"));
@ -150,7 +152,7 @@ const CollectionListing = () => {
setTree((currentTree) => moveItemOnTree(currentTree!, source, destination)); setTree((currentTree) => moveItemOnTree(currentTree!, source, destination));
const updatedCollectionOrder = [...account.collectionOrder]; const updatedCollectionOrder = [...user.collectionOrder];
if (source.parentId !== destination.parentId) { if (source.parentId !== destination.parentId) {
await updateCollection.mutateAsync({ await updateCollection.mutateAsync({
@ -174,8 +176,8 @@ const CollectionListing = () => {
updatedCollectionOrder.splice(destination.index, 0, movedCollectionId); updatedCollectionOrder.splice(destination.index, 0, movedCollectionId);
await updateAccount({ await updateUser.mutateAsync({
...account, ...user,
collectionOrder: updatedCollectionOrder, collectionOrder: updatedCollectionOrder,
}); });
} else if ( } else if (
@ -184,8 +186,8 @@ const CollectionListing = () => {
) { ) {
updatedCollectionOrder.splice(destination.index, 0, movedCollectionId); updatedCollectionOrder.splice(destination.index, 0, movedCollectionId);
await updateAccount({ updateUser.mutate({
...account, ...user,
collectionOrder: updatedCollectionOrder, collectionOrder: updatedCollectionOrder,
}); });
} else if ( } else if (
@ -195,8 +197,8 @@ const CollectionListing = () => {
) { ) {
updatedCollectionOrder.splice(source.index, 1); updatedCollectionOrder.splice(source.index, 1);
await updateAccount({ await updateUser.mutateAsync({
...account, ...user,
collectionOrder: updatedCollectionOrder, collectionOrder: updatedCollectionOrder,
}); });
} }

View File

@ -24,8 +24,7 @@ export default function CollectionSelection({
showDefaultValue = true, showDefaultValue = true,
creatable = true, creatable = true,
}: Props) { }: Props) {
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const router = useRouter(); const router = useRouter();

View File

@ -15,12 +15,12 @@ import Link from "next/link";
import LinkIcon from "./LinkComponents/LinkIcon"; import LinkIcon from "./LinkComponents/LinkIcon";
import useOnScreen from "@/hooks/useOnScreen"; import useOnScreen from "@/hooks/useOnScreen";
import { generateLinkHref } from "@/lib/client/generateLinkHref"; import { generateLinkHref } from "@/lib/client/generateLinkHref";
import useAccountStore from "@/store/account";
import usePermissions from "@/hooks/usePermissions"; import usePermissions from "@/hooks/usePermissions";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import LinkTypeBadge from "./LinkComponents/LinkTypeBadge"; import LinkTypeBadge from "./LinkComponents/LinkTypeBadge";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useCollections } from "@/hooks/store/collections"; import { useCollections } from "@/hooks/store/collections";
import { useUser } from "@/hooks/store/users";
type Props = { type Props = {
link: LinkIncludingShortenedCollectionAndTags; link: LinkIncludingShortenedCollectionAndTags;
@ -34,10 +34,9 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) {
const { t } = useTranslation(); const { t } = useTranslation();
const viewMode = localStorage.getItem("viewMode") || "card"; const viewMode = localStorage.getItem("viewMode") || "card";
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore(); const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore();
@ -133,7 +132,7 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) {
<div <div
className="rounded-2xl cursor-pointer h-full flex flex-col justify-between" className="rounded-2xl cursor-pointer h-full flex flex-col justify-between"
onClick={() => onClick={() =>
!editMode && window.open(generateLinkHref(link, account), "_blank") !editMode && window.open(generateLinkHref(link, user), "_blank")
} }
> >
<div> <div>

View File

@ -9,9 +9,9 @@ import DeleteLinkModal from "@/components/ModalContent/DeleteLinkModal";
import PreservedFormatsModal from "@/components/ModalContent/PreservedFormatsModal"; import PreservedFormatsModal from "@/components/ModalContent/PreservedFormatsModal";
import useLinkStore from "@/store/links"; import useLinkStore from "@/store/links";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import useAccountStore from "@/store/account";
import { dropdownTriggerer } from "@/lib/client/utils"; import { dropdownTriggerer } from "@/lib/client/utils";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useUser } from "@/hooks/store/users";
type Props = { type Props = {
link: LinkIncludingShortenedCollectionAndTags; link: LinkIncludingShortenedCollectionAndTags;
@ -39,7 +39,7 @@ export default function LinkActions({
const [deleteLinkModal, setDeleteLinkModal] = useState(false); const [deleteLinkModal, setDeleteLinkModal] = useState(false);
const [preservedFormatsModal, setPreservedFormatsModal] = useState(false); const [preservedFormatsModal, setPreservedFormatsModal] = useState(false);
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const { removeLink, updateLink } = useLinkStore(); const { removeLink, updateLink } = useLinkStore();
@ -50,7 +50,7 @@ export default function LinkActions({
const response = await updateLink({ const response = await updateLink({
...link, ...link,
pinnedBy: isAlreadyPinned ? undefined : [{ id: account.id }], pinnedBy: isAlreadyPinned ? undefined : [{ id: user.id }],
}); });
toast.dismiss(load); toast.dismiss(load);

View File

@ -11,12 +11,12 @@ import LinkCollection from "@/components/LinkViews/LinkComponents/LinkCollection
import LinkIcon from "@/components/LinkViews/LinkComponents/LinkIcon"; import LinkIcon from "@/components/LinkViews/LinkComponents/LinkIcon";
import { isPWA } from "@/lib/client/utils"; import { isPWA } from "@/lib/client/utils";
import { generateLinkHref } from "@/lib/client/generateLinkHref"; import { generateLinkHref } from "@/lib/client/generateLinkHref";
import useAccountStore from "@/store/account";
import usePermissions from "@/hooks/usePermissions"; import usePermissions from "@/hooks/usePermissions";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import LinkTypeBadge from "./LinkComponents/LinkTypeBadge"; import LinkTypeBadge from "./LinkComponents/LinkTypeBadge";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useCollections } from "@/hooks/store/collections"; import { useCollections } from "@/hooks/store/collections";
import { useUser } from "@/hooks/store/users";
type Props = { type Props = {
link: LinkIncludingShortenedCollectionAndTags; link: LinkIncludingShortenedCollectionAndTags;
@ -33,10 +33,9 @@ export default function LinkCardCompact({
}: Props) { }: Props) {
const { t } = useTranslation(); const { t } = useTranslation();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const { links, setSelectedLinks, selectedLinks } = useLinkStore(); const { links, setSelectedLinks, selectedLinks } = useLinkStore();
useEffect(() => { useEffect(() => {
@ -121,7 +120,7 @@ export default function LinkCardCompact({
<div <div
className="flex items-center cursor-pointer w-full" className="flex items-center cursor-pointer w-full"
onClick={() => onClick={() =>
!editMode && window.open(generateLinkHref(link, account), "_blank") !editMode && window.open(generateLinkHref(link, user), "_blank")
} }
> >
<div className="shrink-0"> <div className="shrink-0">

View File

@ -15,12 +15,12 @@ import Link from "next/link";
import LinkIcon from "./LinkComponents/LinkIcon"; import LinkIcon from "./LinkComponents/LinkIcon";
import useOnScreen from "@/hooks/useOnScreen"; import useOnScreen from "@/hooks/useOnScreen";
import { generateLinkHref } from "@/lib/client/generateLinkHref"; import { generateLinkHref } from "@/lib/client/generateLinkHref";
import useAccountStore from "@/store/account";
import usePermissions from "@/hooks/usePermissions"; import usePermissions from "@/hooks/usePermissions";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import LinkTypeBadge from "./LinkComponents/LinkTypeBadge"; import LinkTypeBadge from "./LinkComponents/LinkTypeBadge";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useCollections } from "@/hooks/store/collections"; import { useCollections } from "@/hooks/store/collections";
import { useUser } from "@/hooks/store/users";
type Props = { type Props = {
link: LinkIncludingShortenedCollectionAndTags; link: LinkIncludingShortenedCollectionAndTags;
@ -33,9 +33,8 @@ type Props = {
export default function LinkMasonry({ link, flipDropdown, editMode }: Props) { export default function LinkMasonry({ link, flipDropdown, editMode }: Props) {
const { t } = useTranslation(); const { t } = useTranslation();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections(); const { data: user = [] } = useUser();
const { account } = useAccountStore();
const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore(); const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore();
@ -131,7 +130,7 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) {
<div <div
className="rounded-2xl cursor-pointer" className="rounded-2xl cursor-pointer"
onClick={() => onClick={() =>
!editMode && window.open(generateLinkHref(link, account), "_blank") !editMode && window.open(generateLinkHref(link, user), "_blank")
} }
> >
<div className="relative rounded-t-2xl overflow-hidden"> <div className="relative rounded-t-2xl overflow-hidden">

View File

@ -3,7 +3,6 @@ import TextInput from "@/components/TextInput";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { CollectionIncludingMembersAndLinkCount, Member } from "@/types/global"; import { CollectionIncludingMembersAndLinkCount, Member } from "@/types/global";
import getPublicUserData from "@/lib/client/getPublicUserData"; import getPublicUserData from "@/lib/client/getPublicUserData";
import useAccountStore from "@/store/account";
import usePermissions from "@/hooks/usePermissions"; import usePermissions from "@/hooks/usePermissions";
import ProfilePhoto from "../ProfilePhoto"; import ProfilePhoto from "../ProfilePhoto";
import addMemberToCollection from "@/lib/client/addMemberToCollection"; import addMemberToCollection from "@/lib/client/addMemberToCollection";
@ -11,6 +10,7 @@ import Modal from "../Modal";
import { dropdownTriggerer } from "@/lib/client/utils"; import { dropdownTriggerer } from "@/lib/client/utils";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useUpdateCollection } from "@/hooks/store/collections"; import { useUpdateCollection } from "@/hooks/store/collections";
import { useUser } from "@/hooks/store/users";
type Props = { type Props = {
onClose: Function; onClose: Function;
@ -46,7 +46,7 @@ export default function EditCollectionSharingModal({
} }
}; };
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const permissions = usePermissions(collection.id as number); const permissions = usePermissions(collection.id as number);
const currentURL = new URL(document.URL); const currentURL = new URL(document.URL);
@ -158,7 +158,7 @@ export default function EditCollectionSharingModal({
onKeyDown={(e) => onKeyDown={(e) =>
e.key === "Enter" && e.key === "Enter" &&
addMemberToCollection( addMemberToCollection(
account.username as string, user.username as string,
memberUsername || "", memberUsername || "",
collection, collection,
setMemberState, setMemberState,
@ -170,7 +170,7 @@ export default function EditCollectionSharingModal({
<div <div
onClick={() => onClick={() =>
addMemberToCollection( addMemberToCollection(
account.username as string, user.username as string,
memberUsername || "", memberUsername || "",
collection, collection,
setMemberState, setMemberState,

View File

@ -4,8 +4,6 @@ import { HexColorPicker } from "react-colorful";
import { Collection } from "@prisma/client"; import { Collection } from "@prisma/client";
import Modal from "../Modal"; import Modal from "../Modal";
import { CollectionIncludingMembersAndLinkCount } from "@/types/global"; import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
import useAccountStore from "@/store/account";
import { useSession } from "next-auth/react";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useCreateCollection } from "@/hooks/store/collections"; import { useCreateCollection } from "@/hooks/store/collections";
@ -24,8 +22,6 @@ export default function NewCollectionModal({ onClose, parent }: Props) {
} as Partial<Collection>; } as Partial<Collection>;
const [collection, setCollection] = useState<Partial<Collection>>(initial); const [collection, setCollection] = useState<Partial<Collection>>(initial);
const { setAccount } = useAccountStore();
const { data } = useSession();
useEffect(() => { useEffect(() => {
setCollection(initial); setCollection(initial);

View File

@ -43,8 +43,7 @@ export default function NewLinkModal({ onClose }: Props) {
const [submitLoader, setSubmitLoader] = useState(false); const [submitLoader, setSubmitLoader] = useState(false);
const [optionsExpanded, setOptionsExpanded] = useState(false); const [optionsExpanded, setOptionsExpanded] = useState(false);
const router = useRouter(); const router = useRouter();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const setCollection = (e: any) => { const setCollection = (e: any) => {
if (e?.__isNew__) e.value = null; if (e?.__isNew__) e.value = null;

View File

@ -16,10 +16,10 @@ import {
screenshotAvailable, screenshotAvailable,
} from "@/lib/shared/getArchiveValidity"; } from "@/lib/shared/getArchiveValidity";
import PreservedFormatRow from "@/components/PreserverdFormatRow"; import PreservedFormatRow from "@/components/PreserverdFormatRow";
import useAccountStore from "@/store/account";
import getPublicUserData from "@/lib/client/getPublicUserData"; import getPublicUserData from "@/lib/client/getPublicUserData";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { BeatLoader } from "react-spinners"; import { BeatLoader } from "react-spinners";
import { useUser } from "@/hooks/store/users";
type Props = { type Props = {
onClose: Function; onClose: Function;
@ -30,7 +30,7 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
const { t } = useTranslation(); const { t } = useTranslation();
const session = useSession(); const session = useSession();
const { getLink } = useLinkStore(); const { getLink } = useLinkStore();
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const [link, setLink] = const [link, setLink] =
useState<LinkIncludingShortenedCollectionAndTags>(activeLink); useState<LinkIncludingShortenedCollectionAndTags>(activeLink);
const router = useRouter(); const router = useRouter();
@ -49,20 +49,20 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
useEffect(() => { useEffect(() => {
const fetchOwner = async () => { const fetchOwner = async () => {
if (link.collection.ownerId !== account.id) { if (link.collection.ownerId !== user.id) {
const owner = await getPublicUserData( const owner = await getPublicUserData(
link.collection.ownerId as number link.collection.ownerId as number
); );
setCollectionOwner(owner); setCollectionOwner(owner);
} else if (link.collection.ownerId === account.id) { } else if (link.collection.ownerId === user.id) {
setCollectionOwner({ setCollectionOwner({
id: account.id as number, id: user.id as number,
name: account.name, name: user.name,
username: account.username as string, username: user.username as string,
image: account.image as string, image: user.image as string,
archiveAsScreenshot: account.archiveAsScreenshot as boolean, archiveAsScreenshot: user.archiveAsScreenshot as boolean,
archiveAsMonolith: account.archiveAsScreenshot as boolean, archiveAsMonolith: user.archiveAsScreenshot as boolean,
archiveAsPDF: account.archiveAsPDF as boolean, archiveAsPDF: user.archiveAsPDF as boolean,
}); });
} }
}; };

View File

@ -49,8 +49,7 @@ export default function UploadFileModal({ onClose }: Props) {
const [submitLoader, setSubmitLoader] = useState(false); const [submitLoader, setSubmitLoader] = useState(false);
const [optionsExpanded, setOptionsExpanded] = useState(false); const [optionsExpanded, setOptionsExpanded] = useState(false);
const router = useRouter(); const router = useRouter();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const setCollection = (e: any) => { const setCollection = (e: any) => {
if (e?.__isNew__) e.value = null; if (e?.__isNew__) e.value = null;

View File

@ -1,17 +1,17 @@
import useLocalSettingsStore from "@/store/localSettings"; import useLocalSettingsStore from "@/store/localSettings";
import { dropdownTriggerer } from "@/lib/client/utils"; import { dropdownTriggerer } from "@/lib/client/utils";
import ProfilePhoto from "./ProfilePhoto"; import ProfilePhoto from "./ProfilePhoto";
import useAccountStore from "@/store/account";
import Link from "next/link"; import Link from "next/link";
import { signOut } from "next-auth/react"; import { signOut } from "next-auth/react";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useUser } from "@/hooks/store/users";
export default function ProfileDropdown() { export default function ProfileDropdown() {
const { t } = useTranslation(); const { t } = useTranslation();
const { settings, updateSettings } = useLocalSettingsStore(); const { settings, updateSettings } = useLocalSettingsStore();
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const isAdmin = account.id === Number(process.env.NEXT_PUBLIC_ADMIN || 1); const isAdmin = user.id === Number(process.env.NEXT_PUBLIC_ADMIN || 1);
const handleToggle = () => { const handleToggle = () => {
const newTheme = settings.theme === "dark" ? "light" : "dark"; const newTheme = settings.theme === "dark" ? "light" : "dark";
@ -27,7 +27,7 @@ export default function ProfileDropdown() {
className="btn btn-circle btn-ghost" className="btn btn-circle btn-ghost"
> >
<ProfilePhoto <ProfilePhoto
src={account.image ? account.image : undefined} src={user.image ? user.image : undefined}
priority={true} priority={true}
/> />
</div> </div>

View File

@ -46,8 +46,7 @@ export default function ReadableView({ link }: Props) {
const router = useRouter(); const router = useRouter();
const { getLink } = useLinkStore(); const { getLink } = useLinkStore();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const collection = useMemo(() => { const collection = useMemo(() => {
return collections.find( return collections.find(

View File

@ -22,8 +22,7 @@ export default function Sidebar({ className }: { className?: string }) {
} }
); );
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const { tags } = useTagStore(); const { tags } = useTagStore();
const [active, setActive] = useState(""); const [active, setActive] = useState("");

View File

@ -6,12 +6,10 @@ import toast from "react-hot-toast";
const useCollections = () => { const useCollections = () => {
return useQuery({ return useQuery({
queryKey: ["collections"], queryKey: ["collections"],
queryFn: async (): Promise<{ queryFn: async (): Promise<CollectionIncludingMembersAndLinkCount[]> => {
response: CollectionIncludingMembersAndLinkCount[];
}> => {
const response = await fetch("/api/v1/collections"); const response = await fetch("/api/v1/collections");
const data = await response.json(); const data = await response.json();
return data; return data.response;
}, },
}); });
}; };
@ -21,11 +19,11 @@ const useCreateCollection = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async (data: any) => { mutationFn: async (body: any) => {
const load = toast.loading(t("creating")); const load = toast.loading(t("creating"));
const response = await fetch("/api/v1/collections", { const response = await fetch("/api/v1/collections", {
body: JSON.stringify(data), body: JSON.stringify(body),
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
@ -34,14 +32,18 @@ const useCreateCollection = () => {
toast.dismiss(load); toast.dismiss(load);
return response.json(); const data = await response.json();
if (!response.ok) throw new Error(data.response);
return data.response;
}, },
onSuccess: (data) => { onSuccess: (data) => {
toast.success(t("created")); toast.success(t("created"));
return queryClient.setQueryData(["collections"], (oldData: any) => { return queryClient.setQueryData(["collections"], (oldData: any) => {
return { console.log([...oldData, data]);
response: [...oldData.response, data.response],
}; return [...oldData, data];
}); });
}, },
onError: (error) => { onError: (error) => {
@ -55,33 +57,43 @@ const useUpdateCollection = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async (data: any) => { mutationFn: async (body: any) => {
const load = toast.loading(t("updating_collection")); const load = toast.loading(t("updating_collection"));
const response = await fetch(`/api/v1/collections/${data.id}`, { const response = await fetch(`/api/v1/collections/${body.id}`, {
method: "PUT", method: "PUT",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify(data), body: JSON.stringify(body),
}); });
toast.dismiss(load); toast.dismiss(load);
return response.json(); const data = await response.json();
if (!response.ok) throw new Error(data.response);
return data.response;
}, },
onSuccess: (data) => { onSuccess: (data) => {
{ {
toast.success(t("updated")); toast.success(t("updated"));
return queryClient.setQueryData(["collections"], (oldData: any) => { return queryClient.setQueryData(["collections"], (oldData: any) => {
return { return oldData.map((collection: any) =>
response: oldData.response.map((collection: any) => collection.id === data.id ? data : collection
collection.id === data.response.id ? data.response : collection );
),
};
}); });
} }
}, },
// onMutate: async (data) => {
// await queryClient.cancelQueries({ queryKey: ["collections"] });
// queryClient.setQueryData(["collections"], (oldData: any) => {
// return oldData.map((collection: any) =>
// collection.id === data.id ? data : collection
// )
// });
// },
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
@ -105,16 +117,16 @@ const useDeleteCollection = () => {
toast.dismiss(load); toast.dismiss(load);
return response.json(); const data = await response.json();
if (!response.ok) throw new Error(data.response);
return data.response;
}, },
onSuccess: (data) => { onSuccess: (data) => {
toast.success(t("deleted")); toast.success(t("deleted"));
return queryClient.setQueryData(["collections"], (oldData: any) => { return queryClient.setQueryData(["collections"], (oldData: any) => {
return { return oldData.filter((collection: any) => collection.id !== data.id);
response: oldData.response.filter(
(collection: any) => collection.id !== data.response.id
),
};
}); });
}, },
onError: (error) => { onError: (error) => {

63
hooks/store/users.tsx Normal file
View File

@ -0,0 +1,63 @@
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import toast from "react-hot-toast";
import { useTranslation } from "next-i18next";
import { useSession } from "next-auth/react";
const useUser = () => {
const { data } = useSession();
const userId = data?.user.id;
return useQuery({
queryKey: ["user"],
queryFn: async () => {
const response = await fetch(`/api/v1/users/${userId}`);
if (!response.ok) throw new Error("Failed to fetch user data.");
const data = await response.json();
return data.response;
},
enabled: !!userId,
});
};
const useUpdateUser = () => {
const { t } = useTranslation();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (user: any) => {
const load = toast.loading(t("applying_settings"));
const response = await fetch(`/api/v1/users/${user.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(user),
});
const data = await response.json();
toast.dismiss(load);
if (!response.ok) throw new Error(data.response);
return data;
},
onSuccess: (data) => {
toast.success(t("settings_applied"));
queryClient.setQueryData(["user"], data.response);
},
onMutate: async (user) => {
await queryClient.cancelQueries({ queryKey: ["user"] });
queryClient.setQueryData(["user"], (oldData: any) => {
return { ...oldData, ...user };
});
},
onError: (error) => {
toast.error(error.message);
},
});
};
export { useUser, useUpdateUser };

View File

@ -1,13 +1,12 @@
import useAccountStore from "@/store/account";
import { Member } from "@/types/global"; import { Member } from "@/types/global";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useCollections } from "./store/collections"; import { useCollections } from "./store/collections";
import { useUser } from "./store/users";
export default function useCollectivePermissions(collectionIds: number[]) { export default function useCollectivePermissions(collectionIds: number[]) {
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const [permissions, setPermissions] = useState<Member | true>(); const [permissions, setPermissions] = useState<Member | true>();
useEffect(() => { useEffect(() => {
@ -16,7 +15,7 @@ export default function useCollectivePermissions(collectionIds: number[]) {
if (collection) { if (collection) {
let getPermission: Member | undefined = collection.members.find( let getPermission: Member | undefined = collection.members.find(
(e) => e.userId === account.id (e) => e.userId === user.id
); );
if ( if (
@ -26,10 +25,10 @@ export default function useCollectivePermissions(collectionIds: number[]) {
) )
getPermission = undefined; getPermission = undefined;
setPermissions(account.id === collection.ownerId || getPermission); setPermissions(user.id === collection.ownerId || getPermission);
} }
} }
}, [account, collections, collectionIds]); }, [user, collections, collectionIds]);
return permissions; return permissions;
} }

View File

@ -1,33 +1,29 @@
import { useEffect } from "react"; 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 useAccountStore from "@/store/account";
import useLocalSettingsStore from "@/store/localSettings"; import useLocalSettingsStore from "@/store/localSettings";
import { useUser } from "./store/users";
export default function useInitialData() { export default function useInitialData() {
const { status, data } = useSession(); const { status, data } = useSession();
// const { setCollections } = useCollectionStore(); // const { setCollections } = useCollectionStore();
const { setTags } = useTagStore(); const { setTags } = useTagStore();
// const { setLinks } = useLinkStore(); // const { setLinks } = useLinkStore();
const { account, setAccount } = useAccountStore(); const { data: user = [] } = useUser();
const { setSettings } = useLocalSettingsStore(); const { setSettings } = useLocalSettingsStore();
useEffect(() => { useEffect(() => {
setSettings(); setSettings();
if (status === "authenticated") {
// Get account info
setAccount(data?.user.id as number);
}
}, [status, data]); }, [status, data]);
// Get the rest of the data // Get the rest of the data
useEffect(() => { useEffect(() => {
if (account.id && (!process.env.NEXT_PUBLIC_STRIPE || account.username)) { if (user.id && (!process.env.NEXT_PUBLIC_STRIPE || user.username)) {
// setCollections(); // setCollections();
setTags(); setTags();
// setLinks(); // setLinks();
} }
}, [account]); }, [user]);
return status; return status;
} }

View File

@ -1,13 +1,12 @@
import useAccountStore from "@/store/account";
import { Member } from "@/types/global"; import { Member } from "@/types/global";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useCollections } from "./store/collections"; import { useCollections } from "./store/collections";
import { useUser } from "./store/users";
export default function usePermissions(collectionId: number) { export default function usePermissions(collectionId: number) {
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const [permissions, setPermissions] = useState<Member | true>(); const [permissions, setPermissions] = useState<Member | true>();
useEffect(() => { useEffect(() => {
@ -15,7 +14,7 @@ export default function usePermissions(collectionId: number) {
if (collection) { if (collection) {
let getPermission: Member | undefined = collection.members.find( let getPermission: Member | undefined = collection.members.find(
(e) => e.userId === account.id (e) => e.userId === user.id
); );
if ( if (
@ -25,9 +24,9 @@ export default function usePermissions(collectionId: number) {
) )
getPermission = undefined; getPermission = undefined;
setPermissions(account.id === collection.ownerId || getPermission); setPermissions(user.id === collection.ownerId || getPermission);
} }
}, [account, collections, collectionId]); }, [user, collections, collectionId]);
return permissions; return permissions;
} }

View File

View File

@ -2,7 +2,7 @@ import { ReactNode, useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import useInitialData from "@/hooks/useInitialData"; import useInitialData from "@/hooks/useInitialData";
import useAccountStore from "@/store/account"; import { useUser } from "@/hooks/store/users";
interface Props { interface Props {
children: ReactNode; children: ReactNode;
@ -14,7 +14,7 @@ export default function AuthRedirect({ children }: Props) {
const router = useRouter(); const router = useRouter();
const { status } = useSession(); const { status } = useSession();
const [shouldRenderChildren, setShouldRenderChildren] = useState(false); const [shouldRenderChildren, setShouldRenderChildren] = useState(false);
const { account } = useAccountStore(); const { data: user = [] } = useUser();
useInitialData(); useInitialData();
@ -23,7 +23,7 @@ export default function AuthRedirect({ children }: Props) {
const isUnauthenticated = status === "unauthenticated"; const isUnauthenticated = status === "unauthenticated";
const isPublicPage = router.pathname.startsWith("/public"); const isPublicPage = router.pathname.startsWith("/public");
const hasInactiveSubscription = const hasInactiveSubscription =
account.id && !account.subscription?.active && stripeEnabled; user.id && !user.subscription?.active && stripeEnabled;
// There are better ways of doing this... but this one works for now // There are better ways of doing this... but this one works for now
const routes = [ const routes = [
@ -63,7 +63,7 @@ export default function AuthRedirect({ children }: Props) {
setShouldRenderChildren(true); setShouldRenderChildren(true);
} }
} }
}, [status, account, router.pathname]); }, [status, user, router.pathname]);
function redirectTo(destination: string) { function redirectTo(destination: string) {
router.push(destination).then(() => setShouldRenderChildren(true)); router.push(destination).then(() => setShouldRenderChildren(true));

View File

@ -12,7 +12,6 @@ import useLinks from "@/hooks/useLinks";
import usePermissions from "@/hooks/usePermissions"; import usePermissions from "@/hooks/usePermissions";
import NoLinksFound from "@/components/NoLinksFound"; import NoLinksFound from "@/components/NoLinksFound";
import useLocalSettingsStore from "@/store/localSettings"; import useLocalSettingsStore from "@/store/localSettings";
import useAccountStore from "@/store/account";
import getPublicUserData from "@/lib/client/getPublicUserData"; import getPublicUserData from "@/lib/client/getPublicUserData";
import EditCollectionModal from "@/components/ModalContent/EditCollectionModal"; import EditCollectionModal from "@/components/ModalContent/EditCollectionModal";
import EditCollectionSharingModal from "@/components/ModalContent/EditCollectionSharingModal"; import EditCollectionSharingModal from "@/components/ModalContent/EditCollectionSharingModal";
@ -26,6 +25,7 @@ import getServerSideProps from "@/lib/client/getServerSideProps";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import LinkListOptions from "@/components/LinkListOptions"; import LinkListOptions from "@/components/LinkListOptions";
import { useCollections } from "@/hooks/store/collections"; import { useCollections } from "@/hooks/store/collections";
import { useUser } from "@/hooks/store/users";
export default function Index() { export default function Index() {
const { t } = useTranslation(); const { t } = useTranslation();
@ -34,8 +34,7 @@ export default function Index() {
const router = useRouter(); const router = useRouter();
const { links } = useLinkStore(); const { links } = useLinkStore();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const [sortBy, setSortBy] = useState<Sort>(Sort.DateNewestFirst); const [sortBy, setSortBy] = useState<Sort>(Sort.DateNewestFirst);
@ -52,7 +51,7 @@ export default function Index() {
); );
}, [router, collections]); }, [router, collections]);
const { account } = useAccountStore(); const { data: user = [] } = useUser();
const [collectionOwner, setCollectionOwner] = useState({ const [collectionOwner, setCollectionOwner] = useState({
id: null as unknown as number, id: null as unknown as number,
@ -66,20 +65,20 @@ export default function Index() {
useEffect(() => { useEffect(() => {
const fetchOwner = async () => { const fetchOwner = async () => {
if (activeCollection && activeCollection.ownerId !== account.id) { if (activeCollection && activeCollection.ownerId !== user.id) {
const owner = await getPublicUserData( const owner = await getPublicUserData(
activeCollection.ownerId as number activeCollection.ownerId as number
); );
setCollectionOwner(owner); setCollectionOwner(owner);
} else if (activeCollection && activeCollection.ownerId === account.id) { } else if (activeCollection && activeCollection.ownerId === user.id) {
setCollectionOwner({ setCollectionOwner({
id: account.id as number, id: user.id as number,
name: account.name, name: user.name,
username: account.username as string, username: user.username as string,
image: account.image as string, image: user.image as string,
archiveAsScreenshot: account.archiveAsScreenshot as boolean, archiveAsScreenshot: user.archiveAsScreenshot as boolean,
archiveAsMonolith: account.archiveAsScreenshot as boolean, archiveAsMonolith: user.archiveAsScreenshot as boolean,
archiveAsPDF: account.archiveAsPDF as boolean, archiveAsPDF: user.archiveAsPDF as boolean,
}); });
} }
}; };

View File

@ -13,8 +13,7 @@ import { useCollections } from "@/hooks/store/collections";
export default function Collections() { export default function Collections() {
const { t } = useTranslation(); const { t } = useTranslation();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const [sortBy, setSortBy] = useState<Sort>(Sort.DateNewestFirst); const [sortBy, setSortBy] = useState<Sort>(Sort.DateNewestFirst);
const [sortedCollections, setSortedCollections] = useState(collections); const [sortedCollections, setSortedCollections] = useState(collections);

View File

@ -22,8 +22,7 @@ import { useCollections } from "@/hooks/store/collections";
export default function Dashboard() { export default function Dashboard() {
const { t } = useTranslation(); const { t } = useTranslation();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const { links } = useLinkStore(); const { links } = useLinkStore();
const { tags } = useTagStore(); const { tags } = useTagStore();

View File

@ -32,8 +32,7 @@ export default function PublicCollections() {
const { settings } = useLocalSettingsStore(); const { settings } = useLocalSettingsStore();
const { data: { response: collections } = { response: [] } } = const { data: collections = [] } = useCollections();
useCollections();
const router = useRouter(); const router = useRouter();

View File

@ -1,5 +1,4 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import useAccountStore from "@/store/account";
import { AccountSettings } from "@/types/global"; import { AccountSettings } from "@/types/global";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import SettingsLayout from "@/layouts/SettingsLayout"; import SettingsLayout from "@/layouts/SettingsLayout";
@ -17,6 +16,7 @@ import Button from "@/components/ui/Button";
import { i18n } from "next-i18next.config"; import { i18n } from "next-i18next.config";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import getServerSideProps from "@/lib/client/getServerSideProps"; import getServerSideProps from "@/lib/client/getServerSideProps";
import { useUpdateUser, useUser } from "@/hooks/store/users";
const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER; const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER;
@ -24,7 +24,8 @@ export default function Account() {
const [emailChangeVerificationModal, setEmailChangeVerificationModal] = const [emailChangeVerificationModal, setEmailChangeVerificationModal] =
useState(false); useState(false);
const [submitLoader, setSubmitLoader] = useState(false); const [submitLoader, setSubmitLoader] = useState(false);
const { account, updateAccount } = useAccountStore(); const { data: account = [] } = useUser();
const updateUser = useUpdateUser();
const [user, setUser] = useState<AccountSettings>( const [user, setUser] = useState<AccountSettings>(
!objectIsEmpty(account) !objectIsEmpty(account)
? account ? account
@ -78,25 +79,22 @@ export default function Account() {
const submit = async (password?: string) => { const submit = async (password?: string) => {
setSubmitLoader(true); setSubmitLoader(true);
const load = toast.loading(t("applying_settings"));
const response = await updateAccount({ await updateUser.mutateAsync(
{
...user, ...user,
// @ts-ignore
password: password ? password : undefined, password: password ? password : undefined,
}); },
{
toast.dismiss(load); onSuccess: (data) => {
if (data.response.email !== user.email) {
if (response.ok) {
const emailChanged = account.email !== user.email;
toast.success(t("settings_applied"));
if (emailChanged) {
toast.success(t("email_change_request")); toast.success(t("email_change_request"));
setEmailChangeVerificationModal(false); setEmailChangeVerificationModal(false);
} }
} else toast.error(response.data as string); },
}
);
setSubmitLoader(false); setSubmitLoader(false);
}; };

View File

@ -1,11 +1,11 @@
import SettingsLayout from "@/layouts/SettingsLayout"; import SettingsLayout from "@/layouts/SettingsLayout";
import { useState } from "react"; import { useState } from "react";
import useAccountStore from "@/store/account";
import SubmitButton from "@/components/SubmitButton"; import SubmitButton from "@/components/SubmitButton";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import TextInput from "@/components/TextInput"; import TextInput from "@/components/TextInput";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import getServerSideProps from "@/lib/client/getServerSideProps"; import getServerSideProps from "@/lib/client/getServerSideProps";
import { useUpdateUser, useUser } from "@/hooks/store/users";
export default function Password() { export default function Password() {
const { t } = useTranslation(); const { t } = useTranslation();
@ -13,7 +13,8 @@ export default function Password() {
const [oldPassword, setOldPassword] = useState(""); const [oldPassword, setOldPassword] = useState("");
const [newPassword, setNewPassword] = useState(""); const [newPassword, setNewPassword] = useState("");
const [submitLoader, setSubmitLoader] = useState(false); const [submitLoader, setSubmitLoader] = useState(false);
const { account, updateAccount } = useAccountStore(); const { data: account = [] } = useUser();
const updateUser = useUpdateUser();
const submit = async () => { const submit = async () => {
if (newPassword === "" || oldPassword === "") { if (newPassword === "" || oldPassword === "") {
@ -23,23 +24,19 @@ export default function Password() {
setSubmitLoader(true); setSubmitLoader(true);
const load = toast.loading(t("applying_changes")); await updateUser.mutateAsync(
{
const response = await updateAccount({
...account, ...account,
newPassword, newPassword,
oldPassword, oldPassword,
}); },
{
toast.dismiss(load); onSuccess: () => {
if (response.ok) {
toast.success(t("settings_applied"));
setNewPassword(""); setNewPassword("");
setOldPassword(""); setOldPassword("");
} else { },
toast.error(response.data as string);
} }
);
setSubmitLoader(false); setSubmitLoader(false);
}; };

View File

@ -1,6 +1,5 @@
import SettingsLayout from "@/layouts/SettingsLayout"; import SettingsLayout from "@/layouts/SettingsLayout";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import useAccountStore from "@/store/account";
import SubmitButton from "@/components/SubmitButton"; import SubmitButton from "@/components/SubmitButton";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import Checkbox from "@/components/Checkbox"; import Checkbox from "@/components/Checkbox";
@ -8,12 +7,14 @@ import useLocalSettingsStore from "@/store/localSettings";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import getServerSideProps from "@/lib/client/getServerSideProps"; // Import getServerSideProps for server-side data fetching import getServerSideProps from "@/lib/client/getServerSideProps"; // Import getServerSideProps for server-side data fetching
import { LinksRouteTo } from "@prisma/client"; import { LinksRouteTo } from "@prisma/client";
import { useUpdateUser, useUser } from "@/hooks/store/users";
export default function Appearance() { export default function Appearance() {
const { t } = useTranslation(); const { t } = useTranslation();
const { updateSettings } = useLocalSettingsStore(); const { updateSettings } = useLocalSettingsStore();
const [submitLoader, setSubmitLoader] = useState(false); const [submitLoader, setSubmitLoader] = useState(false);
const { account, updateAccount } = useAccountStore(); const { data: account = [] } = useUser();
const updateUser = useUpdateUser();
const [user, setUser] = useState(account); const [user, setUser] = useState(account);
const [preventDuplicateLinks, setPreventDuplicateLinks] = useState<boolean>( const [preventDuplicateLinks, setPreventDuplicateLinks] = useState<boolean>(
@ -73,17 +74,8 @@ export default function Appearance() {
const submit = async () => { const submit = async () => {
setSubmitLoader(true); setSubmitLoader(true);
const load = toast.loading(t("applying_changes")); await updateUser.mutateAsync({ ...user });
const response = await updateAccount({ ...user });
toast.dismiss(load);
if (response.ok) {
toast.success(t("settings_applied"));
} else {
toast.error(response.data as string);
}
setSubmitLoader(false); setSubmitLoader(false);
}; };

View File

@ -7,7 +7,7 @@ import { Plan } from "@/types/global";
import Button from "@/components/ui/Button"; import Button from "@/components/ui/Button";
import getServerSideProps from "@/lib/client/getServerSideProps"; import getServerSideProps from "@/lib/client/getServerSideProps";
import { Trans, useTranslation } from "next-i18next"; import { Trans, useTranslation } from "next-i18next";
import useAccountStore from "@/store/account"; import { useUser } from "@/hooks/store/users";
const stripeEnabled = process.env.NEXT_PUBLIC_STRIPE === "true"; const stripeEnabled = process.env.NEXT_PUBLIC_STRIPE === "true";
@ -20,11 +20,11 @@ export default function Subscribe() {
const router = useRouter(); const router = useRouter();
const { account } = useAccountStore(); const { data: user = [] } = useUser();
useEffect(() => { useEffect(() => {
const hasInactiveSubscription = const hasInactiveSubscription =
account.id && !account.subscription?.active && stripeEnabled; user.id && !user.subscription?.active && stripeEnabled;
if (session.status === "authenticated" && !hasInactiveSubscription) { if (session.status === "authenticated" && !hasInactiveSubscription) {
router.push("/dashboard"); router.push("/dashboard");

View File

@ -1,41 +0,0 @@
import { create } from "zustand";
import { AccountSettings } from "@/types/global";
type ResponseObject = {
ok: boolean;
data: Omit<AccountSettings, "password"> | object | string;
};
type AccountStore = {
account: AccountSettings;
setAccount: (id: number) => void;
updateAccount: (user: AccountSettings) => Promise<ResponseObject>;
};
const useAccountStore = create<AccountStore>()((set) => ({
account: {} as AccountSettings,
setAccount: async (id) => {
const response = await fetch(`/api/v1/users/${id}`);
const data = await response.json();
if (response.ok) set({ account: { ...data.response } });
},
updateAccount: async (user) => {
const response = await fetch(`/api/v1/users/${user.id}`, {
method: "PUT",
body: JSON.stringify(user),
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
if (response.ok) set({ account: { ...data.response } });
return { ok: response.ok, data: data.response };
},
}));
export default useAccountStore;